diff --git a/CHANGES.md b/CHANGES.md index 75428f428c..4796e069cf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,100 +1,170 @@ -# 1.6.2 (future) -- IOS: Fix GL regression - 32bit color format cores were no longer rendering +# 1.6.8 (future) +- GUI: (MaterialUI) Skip querying and drawing items that are not visible; Cache content height and bbox calculation. +- GUI: (XMB) Skip drawing the fading list when it is already transparent. Optimization. +- GUI: (XMB) Comment out visible item calculation in xmb_draw_items(). +- GUI: (RGUI) Prevent crashes when using a non-English language reliant on UTF8. +- LINUX/PI: Broadcom VC4: Add Videocore config option +- NETPLAY: Fix disconnection not fully deinitializing Netplay. +- COMMON: Fix clear/free loop conditionals in playlists. +- WINDOWS/GDI: Fix flickering of text. +- WINDOWS/WGL: Try to use wglSwapLayerBuffers instead of SwapBuffers if possible (for more optimal performance). +- WII: Use custom, embedded libogc SDK. +- WIIU: Initial touchscreen support for WiiU gamepad. + +# 1.6.7 +- SCANNER: Fix directory scanning. +- SCANNER: Fix file scanning. +- COMMON: Fix 'Disk Image Append' option. +- FREEBSD: Compatibility fixes for Video4Linux2 camera driver. +- GUI: (MaterialUI) Add disk image append icons. +- GUI: (MaterialUI) Improve word wrapping when menu icons are enabled. +- GUI: (MaterialUI) Add User Interface -> Appearance -> Menu Icons Enable. You can turn on/off the icons on the lefthand side of the menu entries. +- GUI: Performance optimizations for XMB menu driver - only calculates visible items. +- LOCALIZATION: Update Italian translation. + +# 1.6.6 (future) +- 3DS: Fixes serious performance regression that affected every core; rewind was always implicitly enabled. +- AUDIO: MOD/S3M/XM sound should now be properly mixed in with the core's sound. +- GUI: Visual makeover of MaterialUI. +- GUI: Added 'Music', 'Images' and 'Video' collection options to RGUI/MaterialUI. +- GUI: Allow the user to add 'Favorites'. +- GUI: Allow the user to rename entries. +- GUI: Performance optimizations for XMB menu driver. +- LOCALIZATION: Update Italian translation +- INPUT: Overlay controller response - when we press buttons on the gamepad or keyboard, the corresponding buttons on the overlay will be highlighted as well. +- NETBSD: Silence some compilation warnings. +- COMMON: Fixed bug 'Deleting an entry from a playlist would not update the list view inside XMB'. +- COMMON: Fix inet_ntop_compat on *nix +- LOBBY: Add skeleton to add help descriptions to lobbies + +# 1.6.5 +Skipped this one. + +# 1.6.4 + +- ANDROID: Fire Stick & Fire TV remote overrides gamepad port 0 on button press and viceversa like SHIELD devices +- ANDROID: Provide default save / system / state / screenshot locations +- AUDIO: Audio mixer supports MOD/S3M/XM file types now! +- INPUT: input swap override flag (for remotes) is cleared correctly +- INPUT: allow specifying libretro device in remap files +- INPUT: allow specifying analog dpad mode in remap files +- INPUT: allow saving libretro device to remap files +- INPUT: allow saving analog dpad mode to remap files +- INPUT: allow removing core and game remap files from the menu +- COMMON: Cores can now request to set a 'shared context'. You no longer need to explicitly enable 'Shared Hardware Context' for Citra/OpenLara/Dolphin. +- COMMON: Add 'Delete Core' option to Core Information menu. +- COMMON: Allow Max Timing Skew to be set to 0. +- COMMON: Change the "content dir" behavior so it works on either a flag or an empty directory setting, now platform drivers can provide defaults for save / system / state / screenshot dirs and still allow the content dir functionality, these settings are under settings / saving and flagged as advanced +- GUI: You can turn on/off 'Horizontal Animation' now for the XMB menu. Turning animations off can result in a performance boost. +- GUI: Fix sublabel word-wrapping in XMB where multi-byte languages were cut off too soon +- LOCALIZATION: Update Dutch translation +- LOCALIZATION: Update Traditional Chinese translation +- LOCALIZATION: Update Italian translation +- LOCALIZATION: Update Russian translation +- WINDOWS: Provide default save / system / state / screenshot locations +- LOBBIES: Show what country the host is in +- MENU: Enable OSD text rendering for gdi and libcaca drivers +- WINDOWS 98/ME/2K: Set default directory for MSVC 2005 RetroArch version. +- WII: Better V-Sync handling, backported from SuperrSonic. +- WIIU: Exception handler rewritten. + +# 1.6.3 +- IOS: Fix GL regression - 32bit color format cores were no longer rendering - CHEEVOS: Add support for N64 cheevos and other small fixes. - CHEEVOS: Add 'Achievements -> Achievements Verbose Mode'. Ability to display cheevos related messages in OSD, useful for RetroAchievements users. -- AUDIO: Mute now no longer disables/enables audio but instead properly mutes the audio volume. - Mute is also independent from the audio mixer volume. - AUDIO: Audio mixer's volume can now be independently increased/decreased, and muted. -- SDL2: Fix 'SDL2 driver does not see the hat on wired Xbox 360 controller" -- SCANNING: Fix PS1 game scanning -- SCANNING: Move content list builder into scanner task with progress, fixes menu freeze with large playlists -- VITA: Add support for external USB if mounted -- VITA: Add cheevos support -- MENU: Add 'User Interface -> Views'. Ability to display/hide online updater and core updater -options. -- LINUX: Add a tinyalsa audio driver. Doesn't require asoundlib, should be self-contained and -lower-level. +- AUDIO: Mute now no longer disables/enables audio but instead properly mutes the audio volume. Mute is also independent from the audio mixer volume. +- INPUT: Add mouse index selection; ability now to select between different mice +- INPUT: Fix 'All Users Control Menu' setting +- LINUX: Add a tinyalsa audio driver. Doesn't require asoundlib, should be self-contained and lower-level. +- LOBBIES: Announce the RetroArch version too - LOCALIZATION: Add Traditional Chinese translation - LOCALIZATION: Update French translation - LOCALIZATION: Update Italian translation - LOCALIZATION: Update Japanese translation - LOCALIZATION: Update Russian translation +- MENU: Add 'User Interface -> Views'. Ability to display/hide online updater and core updater options. +- NETPLAY: Disconnecting one client shouldn't cause everyone to disconnect anymore +- NETWORK: SSL/TLS support, disabled by default +- SCANNER: Fix PS1 game scanning +- SCANNER: Move content list builder into scanner task with progress, fixes menu freeze with large playlists +- SDL2: Fix 'SDL2 driver does not see the hat on wired Xbox 360 controller" +- SETTINGS: Fix regression 'Custom Viewport is no longer overridable per-core or per-game' +- VITA: Add cheevos support +- VITA: Add support for external USB if mounted - WAYLAND: Fix menu mouse input - WII: Add support for single-port 'PS1/PS2 to USB controller adapter' -- INPUT: Fix 'All Users Control Menu' setting -- INPUT: Add mouse index selection; ability now to select between different mice -- SETTINGS: Fix regression 'Custom Viewport is no longer overridable per-core or per-game' # 1.6.0 -- AUTOSAVE/SRAM - Fix bug #3829 / #4820 (https://github.com/libretro/RetroArch/issues/3829) -- ENDIANNESS: Fixed database scanning. Should fix scanning on PS3/WiiU/Wii, etc. -- NET: Fix bug #4703 (https://github.com/libretro/RetroArch/issues/4703) -- ANDROID: Runtime permission checking +- ANDROID: Allow remotes to retain OK/Cancel position when menu_swap_ok_cancel is enabled - ANDROID: Improve autoconf fallback - ANDROID: Improve shield portable/gamepad device grouping workaround -- ANDROID: Allow remotes to retain OK/Cancel position when menu_swap_ok_cancel is enabled -- LOCALIZATION: Update/finish French translation -- LOCALIZATION: Update German translation -- LOCALIZATION: Update Japanese translation -- LOCALIZATION/GUI: Korean font should display properly now with XMB/MaterialUI's default font -- LOCALIZATION: Update Russian translation -- MENU: Improved rendering for XMB ribbon; using additive blending (Vulkan/GL) -- OSX/MACOS: Fixes serious memory leak -- WINDOWS: Added WASAPI audio driver for low-latency audio. Both shared and exclusive mode. -- WINDOWS: Added RawInput input driver for low-latency, low-level input. -- WINDOWS: Core mouse input should be relative again in cores -- MISC: Various frontend optimizations. -- VIDEO: Fix threaded video regression; tickering of menu entries would no longer work. -- WII: Fix crashing issues which could occur with the dummy core -- WIIU: HID Controller support -- WIIU: XMB/MaterialUI menu driver support -- WIIU: Initial network/netplay support +- ANDROID: Runtime permission checking +- AUDIO: Audio mixer support. Mix up to 8 streams with the game's audio. +- AUTOSAVE/SRAM - Fix bug #3829 / #4820 (https://github.com/libretro/RetroArch/issues/3829) +- ENDIANNESS: Fixed database scanning. Should fix scanning on PS3/WiiU/Wii, etc. - LOBBIES: Fallback to filename based matching if no CRC matches are found (for people making playlists by hand) - LOBBIES: GUI refinement, show stop hosting when a host has been started, show disconnect when playing as client - LOBBIES: if the game is already loaded it will try to connect directly instead of re-loading content (non-fullpath cores only) - LOBBIES: unify both netplay menus +- LOCALIZATION/GUI: Korean font should display properly now with XMB/MaterialUI's default font +- LOCALIZATION: Update German translation +- LOCALIZATION: Update Japanese translation +- LOCALIZATION: Update Russian translation +- LOCALIZATION: Update/finish French translation +- MENU: Improved rendering for XMB ribbon; using additive blending (Vulkan/GL) +- MISC: Various frontend optimizations. +- NET: Fix bug #4703 (https://github.com/libretro/RetroArch/issues/4703) +- OSX/MACOS: Fixes serious memory leak - THUMBNAILS: Thumbnails show up now in Load Content -> Collection, Information -> Database -- VITA: Fix slow I/O +- VIDEO: Fix threaded video regression; tickering of menu entries would no longer work. - VITA: Fix 30fps menu (poke into input now instead of reading the entire input buffer which apparently is slow) - VITA: Fix frame throttle -- VULKAN: Unicode font rendering support. Should fix bad character encoding for French characters, etc. +- VITA: Fix slow I/O - VULKAN: Fix some crashes on loading some thumbnails -- AUDIO: Audio mixer support. Mix up to 8 streams with the game's audio. +- VULKAN: Unicode font rendering support. Should fix bad character encoding for French characters, etc. +- WII: Fix crashing issues which could occur with the dummy core +- WIIU: HID Controller support +- WIIU: Initial network/netplay support +- WIIU: XMB/MaterialUI menu driver support +- WINDOWS: Added RawInput input driver for low-latency, low-level input. +- WINDOWS: Added WASAPI audio driver for low-latency audio. Both shared and exclusive mode. +- WINDOWS: Core mouse input should be relative again in cores # 1.5.0 -- MOBILE: Single-tap for menu entry selection -- MOBILE: Long-tap a setting to reset to default - ANDROID: Autoconf fallback - ANDROID: Mouse support / Emulated mouse support - AUTOCONF: Fix partial matches for pad name - CHEEVOS: Fix crashes in the cheevos description menu - CHEEVOS: WIP leaderboards support -- COMMON: Threading fixes - COMMON: 9-slice texture drawing support +- COMMON: Threading fixes - CORETEXT/APPLE: Ability to load menu display font drivers and loading of custom font. - DOS: Add keyboard driver - DOS: Improve color accuracy and scaling -- GUI: Various settings are now only visible when advanced settings is enabled -- GUI: Allow changing icon theme on the fly - GUI: Add a symbol page in the OSK +- GUI: Allow changing icon theme on the fly - GUI: Better dialogs for XMB +- GUI: Various settings are now only visible when advanced settings is enabled - LOCALIZATION: Add/update Korean translation - LOCALIZATION: Rewrite German translation - LOCALIZATION: Update several English sublabels - LOCALIZATION: Update several Japanese labels +- MOBILE: Long-tap a setting to reset to default +- MOBILE: Single-tap for menu entry selection - NET: Allow manual netplay content loading - NET: Announcing network games to the public lobby is optional now - NET: Bake in miniupnpc - NET: Fix netplay join for contentless cores +- NET: Fix netplay rooms being pushed on the wrong tab - NET: Lan games show next to lobbies with (lan) and connect via the private IP address - NET: Use new lobby system with MITM support -- NET: Fix netplay rooms being pushed on the wrong tab - NUKLEAR: Update to current version - SCANNER: Always add 7z & zip to supported extensions -- VULKAN: Find supported composite alpha in swapchain - VULKAN: Add snow/bokeh shader pipeline effects - at parity with GL now +- VULKAN: Find supported composite alpha in swapchain - WIIU: Keyboard support -- WINDOWS: Logging to file no longer spawns an empty window - WINDOWS: Fix loading of core/content via file menu +- WINDOWS: Logging to file no longer spawns an empty window # 1.4.1 diff --git a/Makefile.common b/Makefile.common index 8e6f3c3379..00bd4f74dd 100644 --- a/Makefile.common +++ b/Makefile.common @@ -91,7 +91,7 @@ ifeq ($(HAVE_SHADERPIPELINE), 1) CFLAGS += -DHAVE_SHADERPIPELINE endif -CFLAGS += -I$(LIBRETRO_COMM_DIR)/include +CFLAGS += -I$(LIBRETRO_COMM_DIR)/include -I$(DEPS_DIR) # Switches @@ -175,6 +175,7 @@ OBJ += frontend/frontend.o \ $(LIBRETRO_COMM_DIR)/file/retro_dirent.o \ $(LIBRETRO_COMM_DIR)/streams/stdin_stream.o \ $(LIBRETRO_COMM_DIR)/streams/file_stream.o \ + $(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.o \ $(LIBRETRO_COMM_DIR)/streams/interface_stream.o \ $(LIBRETRO_COMM_DIR)/streams/memory_stream.o \ $(LIBRETRO_COMM_DIR)/lists/string_list.o \ @@ -338,107 +339,103 @@ ifneq ($(C89_BUILD), 1) HAVE_LIBUI = 0 HAVE_GTKPLUS = 0 +ifeq ($(HAVE_SSL), 1) +DEFINES += -DHAVE_SSL +DEFINES += -DMBEDTLS_SSL_DEBUG_ALL + +# MinGW requires this for some reason, even though the include paths are relative to the source +INCLUDE_DIRS += -Ideps/mbedtls + +OBJS_TLS_CRYPTO = deps/mbedtls/aes.o deps/mbedtls/aesni.o deps/mbedtls/arc4.o \ + deps/mbedtls/asn1parse.o deps/mbedtls/asn1write.o deps/mbedtls/base64.o \ + deps/mbedtls/bignum.o deps/mbedtls/blowfish.o deps/mbedtls/camellia.o \ + deps/mbedtls/ccm.o deps/mbedtls/cipher.o deps/mbedtls/cipher_wrap.o \ + deps/mbedtls/cmac.o deps/mbedtls/ctr_drbg.o deps/mbedtls/des.o \ + deps/mbedtls/dhm.o deps/mbedtls/ecdh.o deps/mbedtls/ecdsa.o \ + deps/mbedtls/ecjpake.o deps/mbedtls/ecp.o \ + deps/mbedtls/ecp_curves.o deps/mbedtls/entropy.o deps/mbedtls/entropy_poll.o \ + deps/mbedtls/error.o deps/mbedtls/gcm.o deps/mbedtls/havege.o \ + deps/mbedtls/hmac_drbg.o deps/mbedtls/md.o deps/mbedtls/md2.o \ + deps/mbedtls/md4.o deps/mbedtls/md5.o deps/mbedtls/md_wrap.o \ + deps/mbedtls/memory_buffer_alloc.o deps/mbedtls/oid.o \ + deps/mbedtls/padlock.o deps/mbedtls/pem.o deps/mbedtls/pk.o \ + deps/mbedtls/pk_wrap.o deps/mbedtls/pkcs12.o deps/mbedtls/pkcs5.o \ + deps/mbedtls/pkparse.o deps/mbedtls/pkwrite.o deps/mbedtls/platform.o \ + deps/mbedtls/ripemd160.o deps/mbedtls/rsa.o deps/mbedtls/sha1.o \ + deps/mbedtls/sha256.o deps/mbedtls/sha512.o deps/mbedtls/threading.o \ + deps/mbedtls/timing.o deps/mbedtls/version.o \ + deps/mbedtls/version_features.o deps/mbedtls/xtea.o + +OBJS_TLS_X509 = deps/mbedtls/certs.o deps/mbedtls/pkcs11.o deps/mbedtls/x509.o \ + deps/mbedtls/x509_create.o deps/mbedtls/x509_crl.o deps/mbedtls/x509_crt.o \ + deps/mbedtls/x509_csr.o deps/mbedtls/x509write_crt.o deps/mbedtls/x509write_csr.o + +OBJS_TLS = deps/mbedtls/debug.o deps/mbedtls/net_sockets.o \ + deps/mbedtls/ssl_cache.o deps/mbedtls/ssl_ciphersuites.o \ + deps/mbedtls/ssl_cli.o deps/mbedtls/ssl_cookie.o \ + deps/mbedtls/ssl_srv.o deps/mbedtls/ssl_ticket.o \ + deps/mbedtls/ssl_tls.o + +OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS) +endif + ifeq ($(HAVE_LIBUI), 1) -ifeq ($(HAVE_GTKPLUS), 1) -CFLAGS += -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/atk-1.0 -LIBS += -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -OBJ += deps/libui/gtk/alloc.o \ - deps/libui/gtk/area.o \ - deps/libui/gtk/box.o \ - deps/libui/gtk/button.o \ - deps/libui/gtk/cellrendererbutton.o \ - deps/libui/gtk/checkbox.o \ - deps/libui/gtk/child.o \ - deps/libui/gtk/colorbutton.o \ - deps/libui/gtk/combobox.o \ - deps/libui/gtk/control.o \ - deps/libui/gtk/datetimepicker.o \ - deps/libui/gtk/debug.o \ - deps/libui/gtk/draw.o \ - deps/libui/gtk/drawmatrix.o \ - deps/libui/gtk/drawpath.o \ - deps/libui/gtk/drawtext.o \ - deps/libui/gtk/editablecombo.o \ - deps/libui/gtk/entry.o \ - deps/libui/gtk/fontbutton.o \ - deps/libui/gtk/form.o \ - deps/libui/gtk/future.o \ - deps/libui/gtk/graphemes.o \ - deps/libui/gtk/grid.o \ - deps/libui/gtk/group.o \ - deps/libui/gtk/image.o \ - deps/libui/gtk/label.o \ - deps/libui/gtk/main.o \ - deps/libui/gtk/menu.o \ - deps/libui/gtk/multilineentry.o \ - deps/libui/gtk/progressbar.o \ - deps/libui/gtk/radiobuttons.o \ - deps/libui/gtk/separator.o \ - deps/libui/gtk/slider.o \ - deps/libui/gtk/spinbox.o \ - deps/libui/gtk/stddialogs.o \ - deps/libui/gtk/tab.o \ - deps/libui/gtk/text.o \ - deps/libui/gtk/util.o \ - deps/libui/gtk/window.o -endif - +DEFINES += -DHAVE_LIBUI ifneq ($(findstring Win32,$(OS)),) -OBJ += deps/libui/win32/alloc.o \ - deps/libui/win32/area.o \ - deps/libui/win32/areadraw.o \ - deps/libui/win32/areaevents.o \ - deps/libui/win32/areascroll.o \ - deps/libui/win32/areautil.o \ - deps/libui/win32/box.o \ - deps/libui/win32/button.o \ - deps/libui/win32/checkbox.o \ - deps/libui/win32/colorbutton.o \ - deps/libui/win32/colordialog.o \ - deps/libui/win32/combobox.o \ - deps/libui/win32/container.o \ - deps/libui/win32/control.o \ - deps/libui/win32/d2dscratch.o \ - deps/libui/win32/datetimepicker.o \ - deps/libui/win32/debug.o \ - deps/libui/win32/draw.o \ - deps/libui/win32/drawmatrix.o \ - deps/libui/win32/drawpath.o \ - deps/libui/win32/drawtext.o \ - deps/libui/win32/dwrite.o \ - deps/libui/win32/editablecombo.o \ - deps/libui/win32/entry.o \ - deps/libui/win32/events.o \ - deps/libui/win32/fontbutton.o \ - deps/libui/win32/fontdialog.o \ - deps/libui/win32/form.o \ - deps/libui/win32/graphemes.o \ - deps/libui/win32/grid.o \ - deps/libui/win32/group.o \ - deps/libui/win32/init.o \ - deps/libui/win32/label.o \ - deps/libui/win32/main.o \ - deps/libui/win32/menu.o \ - deps/libui/win32/multilineentry.o \ - deps/libui/win32/parent.o \ - deps/libui/win32/progressbar.o \ - deps/libui/win32/radiobuttons.o \ - deps/libui/win32/separator.o \ - deps/libui/win32/sizing.o \ - deps/libui/win32/slider.o \ - deps/libui/win32/spinbox.o \ - deps/libui/win32/stddialogs.o \ - deps/libui/win32/tab.o \ - deps/libui/win32/tabpage.o \ - deps/libui/win32/text.o \ - deps/libui/win32/utf16.o \ - deps/libui/win32/utilwin.o \ - deps/libui/win32/window.o \ - deps/libui/win32/winpublic.o \ - deps/libui/win32/winutil.o +OBJ += deps/libui/windows/alloc.o \ + deps/libui/windows/area.o \ + deps/libui/windows/areadraw.o \ + deps/libui/windows/areaevents.o \ + deps/libui/windows/areascroll.o \ + deps/libui/windows/areautil.o \ + deps/libui/windows/box.o \ + deps/libui/windows/button.o \ + deps/libui/windows/checkbox.o \ + deps/libui/windows/colorbutton.o \ + deps/libui/windows/colordialog.o \ + deps/libui/windows/combobox.o \ + deps/libui/windows/container.o \ + deps/libui/windows/control.o \ + deps/libui/windows/d2dscratch.o \ + deps/libui/windows/datetimepicker.o \ + deps/libui/windows/debug.o \ + deps/libui/windows/draw.o \ + deps/libui/windows/drawmatrix.o \ + deps/libui/windows/drawpath.o \ + deps/libui/windows/drawtext.o \ + deps/libui/windows/dwrite.o \ + deps/libui/windows/editablecombo.o \ + deps/libui/windows/entry.o \ + deps/libui/windows/events.o \ + deps/libui/windows/fontbutton.o \ + deps/libui/windows/fontdialog.o \ + deps/libui/windows/form.o \ + deps/libui/windows/graphemes.o \ + deps/libui/windows/grid.o \ + deps/libui/windows/group.o \ + deps/libui/windows/init.o \ + deps/libui/windows/label.o \ + deps/libui/windows/main.o \ + deps/libui/windows/menu.o \ + deps/libui/windows/multilineentry.o \ + deps/libui/windows/parent.o \ + deps/libui/windows/progressbar.o \ + deps/libui/windows/radiobuttons.o \ + deps/libui/windows/separator.o \ + deps/libui/windows/sizing.o \ + deps/libui/windows/slider.o \ + deps/libui/windows/spinbox.o \ + deps/libui/windows/stddialogs.o \ + deps/libui/windows/tab.o \ + deps/libui/windows/tabpage.o \ + deps/libui/windows/text.o \ + deps/libui/windows/utf16.o \ + deps/libui/windows/utilwin.o \ + deps/libui/windows/window.o \ + deps/libui/windows/winpublic.o \ + deps/libui/windows/winutil.o LIBS += -luxtheme -ld2d1 -ldwrite -lusp10 -endif - +else ifneq ($(findstring Darwin,$(OS)),) OBJ += deps/libui/darwin/alloc.o \ deps/libui/darwin/area.o \ @@ -478,6 +475,49 @@ OBJ += deps/libui/darwin/alloc.o \ deps/libui/darwin/util.o \ deps/libui/darwin/window.o \ deps/libui/darwin/winmoveresize.o +else +CFLAGS += -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/atk-1.0 +LIBS += -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 +OBJ += deps/libui/unix/alloc.o \ + deps/libui/unix/area.o \ + deps/libui/unix/box.o \ + deps/libui/unix/button.o \ + deps/libui/unix/cellrendererbutton.o \ + deps/libui/unix/checkbox.o \ + deps/libui/unix/child.o \ + deps/libui/unix/colorbutton.o \ + deps/libui/unix/combobox.o \ + deps/libui/unix/control.o \ + deps/libui/unix/datetimepicker.o \ + deps/libui/unix/debug.o \ + deps/libui/unix/draw.o \ + deps/libui/unix/drawmatrix.o \ + deps/libui/unix/drawpath.o \ + deps/libui/unix/drawtext.o \ + deps/libui/unix/editablecombo.o \ + deps/libui/unix/entry.o \ + deps/libui/unix/fontbutton.o \ + deps/libui/unix/form.o \ + deps/libui/unix/future.o \ + deps/libui/unix/graphemes.o \ + deps/libui/unix/grid.o \ + deps/libui/unix/group.o \ + deps/libui/unix/image.o \ + deps/libui/unix/label.o \ + deps/libui/unix/main.o \ + deps/libui/unix/menu.o \ + deps/libui/unix/multilineentry.o \ + deps/libui/unix/progressbar.o \ + deps/libui/unix/radiobuttons.o \ + deps/libui/unix/separator.o \ + deps/libui/unix/slider.o \ + deps/libui/unix/spinbox.o \ + deps/libui/unix/stddialogs.o \ + deps/libui/unix/tab.o \ + deps/libui/unix/text.o \ + deps/libui/unix/util.o \ + deps/libui/unix/window.o +endif endif OBJ += deps/libui/common/areaevents.o \ @@ -1283,6 +1323,11 @@ ifeq ($(HAVE_RBMP), 1) OBJ += $(LIBRETRO_COMM_DIR)/formats/bmp/rbmp.o endif +ifeq ($(HAVE_IBXM), 1) + DEFINES += -DHAVE_IBXM + OBJ += $(DEPS_DIR)/ibxm/ibxm.o +endif + OBJ += $(LIBRETRO_COMM_DIR)/formats/bmp/rbmp_encode.o \ $(LIBRETRO_COMM_DIR)/formats/json/jsonsax.o \ $(LIBRETRO_COMM_DIR)/formats/json/jsonsax_full.o \ @@ -1341,6 +1386,10 @@ ifeq ($(HAVE_NETWORKING), 1) tasks/task_wifi.o \ tasks/task_netplay_find_content.o + ifeq ($(HAVE_SSL), 1) + OBJ += $(LIBRETRO_COMM_DIR)/net/net_socket_ssl.o + endif + ifneq ($(HAVE_SOCKET_LEGACY),1) OBJ += $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o endif diff --git a/Makefile.ctr.salamander b/Makefile.ctr.salamander index 91d13691dc..98ce0ea170 100644 --- a/Makefile.ctr.salamander +++ b/Makefile.ctr.salamander @@ -25,6 +25,7 @@ OBJ := ctr/ctr_system.o \ frontend/frontend_driver.o \ frontend/drivers/platform_ctr.o \ frontend/drivers/platform_null.o \ + libretro-common/encodings/encoding_utf.o \ libretro-common/compat/compat_strcasestr.o \ libretro-common/file/file_path.o \ libretro-common/string/stdstring.o \ diff --git a/Makefile.griffin b/Makefile.griffin index 201ca49a7d..4790d931b3 100644 --- a/Makefile.griffin +++ b/Makefile.griffin @@ -82,6 +82,7 @@ else ifeq ($(platform), ps3-cobra) # NGC/Wii - libogc else ifeq ($(libogc_platform), 1) +EXTERNAL_LIBOGC=0 CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT) LD = $(DEVKITPPC)/bin/powerpc-eabi-ld$(EXE_EXT) @@ -89,15 +90,36 @@ else ifeq ($(libogc_platform), 1) EXT_TARGET := $(TARGET_NAME)_$(platform).dol EXT_INTER_TARGET := $(TARGET_NAME)_$(platform).elf - INCLUDE += -I. -I$(DEVKITPRO)/libogc/include -Ideps/libz + INCLUDE += -I. -I$(DEVKITPRO)/libogc/include -Ideps/libz -Iwii/libogc/include + +ifeq ($(EXTERNAL_LIBOGC), 1) + CFLAGS += -DEXTERNAL_LIBOGC + CXXFLAGS += -DEXTERNAL_LIBOGC + +ifeq ($(platform), ngc) +LIBDIRS += -L$(DEVKITPRO)/libogc/lib/cube +else ifeq ($(platform), wii) +LIBDIRS += -L$(DEVKITPRO)/libogc/lib/wii +endif + +else + CFLAGS += -DINTERNAL_LIBOGC + CXXFLAGS += -DINTERNAL_LIBOGC + +ifeq ($(platform), ngc) +LIBDIRS += -Lwii/libogc/libs/cube +else ifeq ($(platform), wii) +LIBDIRS += -Lwii/libogc/libs/wii +endif + +endif ifeq ($(platform), ngc) - LIBDIRS += -L$(DEVKITPRO)/libogc/lib/cube MACHDEP := -DHW_DOL -mogc else ifeq ($(platform), wii) - LIBDIRS += -L$(DEVKITPRO)/libogc/lib/wii MACHDEP := -DHW_RVL -mrvl endif + LIBDIRS += -L. MACHDEP += -DGEKKO -mcpu=750 -meabi -mhard-float -DMSB_FIRST @@ -112,7 +134,10 @@ ifeq ($(BIG_STACK), 1) LDFLAGS += -T bootstrap/gx/rvl.ld endif endif - LIBS += -lfat -logc + LIBS += -logc +ifeq ($(EXTERNAL_LIBOGC), 1) + LIBS += -lfat +endif ifeq ($(platform), wii) LIBS += -lwiiuse -lbte @@ -133,6 +158,7 @@ endif HAVE_RJPEG := 1 HAVE_RBMP := 1 HAVE_RTGA := 1 + HAVE_IBXM := 1 HAVE_OVERLAY := 1 HAVE_ZLIB := 1 WANT_ZLIB := 1 diff --git a/Makefile.libogc b/Makefile.libogc new file mode 100644 index 0000000000..77d3bf6c5f --- /dev/null +++ b/Makefile.libogc @@ -0,0 +1,358 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPro") +endif + +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +export PATH := $(DEVKITPPC)/bin:$(PATH) + +ifeq ($(PLATFORM),) +PLATFORM=wii +endif + +#--------------------------------------------------------------------------------- +# change shell on Snow Leopard +#--------------------------------------------------------------------------------- +UNAME_S := $(shell uname -s) +UNAME_R := $(shell uname -r) + +ifneq (,$(findstring Darwin,$(UNAME_S))) + ifneq (,$(findstring 10.8.0,$(UNAME_R))) + export SHELL=/bin/bash + endif +endif + +#--------------------------------------------------------------------------------- +# path to tools +#--------------------------------------------------------------------------------- +export PORTLIBS := $(DEVKITPRO)/portlibs/ppc +export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) + +#--------------------------------------------------------------------------------- +# the prefix on the compiler executables +#--------------------------------------------------------------------------------- +PREFIX := powerpc-eabi- + +export AS := $(PREFIX)as +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy + + +ISVC=$(or $(VCBUILDHELPER_COMMAND),$(MSBUILDEXTENSIONSPATH32),$(MSBUILDEXTENSIONSPATH)) + +#--------------------------------------------------------------------------------- +%.a: +#--------------------------------------------------------------------------------- + @rm -f $@ + $(AR) -rc $@ $^ + +#--------------------------------------------------------------------------------- +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o: %.m + $(CC) $(OBJCFLAGS) -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o: %.s + $(CC) -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o: %.S + $(CC) -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + bin2s -a 32 $< | $(AS) -o $(@) + echo "extern const u8" `(echo $( `(echo $(> `(echo $(> `(echo $(bufsize); break; + case AUDIO_MIXER_TYPE_MOD: + handle = audio_mixer_load_mod(buf, (int32_t)params->bufsize); + break; case AUDIO_MIXER_TYPE_NONE: free(buf); return false; diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c index 2f0acb88b1..9514236f4a 100644 --- a/audio/drivers/dsound.c +++ b/audio/drivers/dsound.c @@ -322,7 +322,11 @@ static void *dsound_init(const char *device, unsigned rate, unsigned latency, RARCH_LOG("DirectSound devices:\n"); #ifndef _XBOX - DirectSoundEnumerate(enumerate_cb, &dev); +#ifdef UNICODE + DirectSoundEnumerate((LPDSENUMCALLBACKW)enumerate_cb, &dev); +#else + DirectSoundEnumerate((LPDSENUMCALLBACKA)enumerate_cb, &dev); +#endif #endif if (DirectSoundCreate(dev.guid, &ds->ds, NULL) != DS_OK) diff --git a/audio/drivers/tinyalsa.c b/audio/drivers/tinyalsa.c index 9f2b06c044..08e8ea4a1a 100644 --- a/audio/drivers/tinyalsa.c +++ b/audio/drivers/tinyalsa.c @@ -1523,7 +1523,7 @@ static struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, flags & PCM_IN ? 'c' : 'p'); - fd = open(fn, O_RDWR); + fd = open(fn, O_RDWR|O_NONBLOCK); if (fd < 0) { fprintf(stderr, "cannot open device '%s'\n", fn); @@ -2203,12 +2203,12 @@ static void * tinyalsa_init(const char *devicestr, unsigned rate, { RARCH_WARN("[TINYALSA]: Sample rate cannot be larger than %uHz "\ "or smaller than %uHz.\n", max_rate, min_rate); - RARCH_WARN("[TINYALSA]: Trying the default rate or else max rate.\n"); - - if (max_rate >= 48000) - rate = 48000; - else + RARCH_WARN("[TINYALSA]: Trying to set a valid sample rate.\n"); + + if (rate > max_rate) rate = max_rate; + else if (rate < min_rate) + rate = min_rate; } if (orig_rate != rate) diff --git a/audio/drivers/wasapi.c b/audio/drivers/wasapi.c index 117d0f3fb4..089bee8978 100644 --- a/audio/drivers/wasapi.c +++ b/audio/drivers/wasapi.c @@ -741,9 +741,9 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) for (writen = 0, ir = -1; writen < size; writen += ir) { if (w->exclusive) - ir = wasapi_write_ex(w, data + writen, size - writen); + ir = wasapi_write_ex(w, (char*)data + writen, size - writen); else - ir = wasapi_write_sh(w, data + writen, size - writen); + ir = wasapi_write_sh(w, (char*)data + writen, size - writen); if (ir == -1) return -1; } diff --git a/camera/drivers/video4linux2.c b/camera/drivers/video4linux2.c index 20960d0b16..2be990821e 100644 --- a/camera/drivers/video4linux2.c +++ b/camera/drivers/video4linux2.c @@ -16,7 +16,9 @@ */ #include +#if !defined(__FreeBSD__) || __FreeBSD__ < 5 #include +#endif #include #include #include @@ -28,7 +30,9 @@ #include #include +#ifndef __FreeBSD__ #include +#endif #include #include diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 0d3b7ba0f9..d3d82891fb 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -921,7 +921,7 @@ static unsigned cheevos_prefix_to_comp_size(char prefix) { /* Careful not to use ABCDEF here, this denotes part of an actual variable! */ - switch( toupper( prefix ) ) + switch( toupper( (unsigned char)prefix ) ) { case 'M': return CHEEVOS_VAR_SIZE_BIT_0; @@ -1141,13 +1141,13 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr) const char *str = *memaddr; unsigned base = 16; - if (toupper(*str) == 'D' && str[1] == '0' && toupper(str[2]) == 'X') + if (toupper((unsigned char)*str) == 'D' && str[1] == '0' && toupper((unsigned char)str[2]) == 'X') { /* d0x + 4 hex digits */ str += 3; var->type = CHEEVOS_VAR_TYPE_DELTA_MEM; } - else if (*str == '0' && toupper(str[1]) == 'X') + else if (*str == '0' && toupper((unsigned char)str[1]) == 'X') { /* 0x + 4 hex digits */ str += 2; @@ -1157,11 +1157,11 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr) { var->type = CHEEVOS_VAR_TYPE_VALUE_COMP; - if (toupper(*str) == 'H') + if (toupper((unsigned char)*str) == 'H') str++; else { - if (toupper(*str) == 'V') + if (toupper((unsigned char)*str) == 'V') str++; base = 10; @@ -1372,9 +1372,7 @@ static void cheevos_free_condition(cheevos_condition_t* condition) if (condition->condsets) { for (i = 0; i < condition->count; i++) - { free((void*)condition->condsets[i].conds); - } free((void*)condition->condsets); } @@ -2074,7 +2072,7 @@ static void cheevos_url_encode(const char *str, char *encoded, size_t len) { while (*str) { - if ( isalnum(*str) || *str == '-' + if ( isalnum((unsigned char)*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~') { @@ -2652,44 +2650,45 @@ bool cheevos_toggle_hardcore_mode(void) static void cheevos_patch_addresses(cheevoset_t* set) { + unsigned i, j, k; cheevo_t* cheevo = set->cheevos; - for (unsigned i = set->count; i != 0; i--, cheevo++) + for (i = set->count; i != 0; i--, cheevo++) { cheevos_condset_t* condset = cheevo->condition.condsets; - for (unsigned j = cheevo->condition.count; j != 0; j--, condset++) + for (j = cheevo->condition.count; j != 0; j--, condset++) { cheevos_cond_t* cond = condset->conds; - for (unsigned k = condset->count; k != 0; k--, cond++) + for (k = condset->count; k != 0; k--, cond++) { switch (cond->source.type) { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_parse_guest_addr(&cond->source, cond->source.value); - #ifdef CHEEVOS_DUMP_ADDRS - RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->source.bank_id + 1, cond->source.value); - #endif - break; + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_parse_guest_addr(&cond->source, cond->source.value); +#ifdef CHEEVOS_DUMP_ADDRS + RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->source.bank_id + 1, cond->source.value); +#endif + break; - default: - break; + default: + break; } switch (cond->target.type) { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_parse_guest_addr(&cond->target, cond->target.value); - #ifdef CHEEVOS_DUMP_ADDRS - RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->target.bank_id + 1, cond->target.value); - #endif - break; + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_parse_guest_addr(&cond->target, cond->target.value); +#ifdef CHEEVOS_DUMP_ADDRS + RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->target.bank_id + 1, cond->target.value); +#endif + break; - default: - break; + default: + break; } } } diff --git a/command.c b/command.c index 845a1e5b7f..b443ee5520 100644 --- a/command.c +++ b/command.c @@ -1,5 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2015-2017 - Andrés Suárez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -1053,6 +1054,7 @@ static void command_event_deinit_core(bool reinit) command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL); command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL); + command_event(CMD_EVENT_RESTORE_REMAPS, NULL); } static void command_event_init_cheats(void) @@ -1226,7 +1228,7 @@ static bool command_event_init_core(enum rarch_core_type *data) rarch_ctl(RARCH_CTL_UNSET_OVERRIDES_ACTIVE, NULL); } - /* Auto-remap: apply shader preset files */ + /* Auto-shaders: apply shader preset files */ if(settings->bools.auto_shaders_enable) config_load_shader_preset(); @@ -1287,6 +1289,12 @@ static void command_event_restore_default_shader_preset(void) path_clear(RARCH_PATH_DEFAULT_SHADER_PRESET); } +static void command_event_restore_remaps(void) +{ + if (rarch_ctl(RARCH_CTL_IS_REMAPS_GAME_ACTIVE, NULL)) + input_remapping_set_defaults(); +} + static bool command_event_save_auto_state(void) { char savestate_name_auto[PATH_MAX_LENGTH] = {0}; @@ -1797,6 +1805,7 @@ bool command_event(enum event_command cmd, void *data) command_event(CMD_EVENT_AUTOSAVE_STATE, NULL); command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL); command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL); + command_event(CMD_EVENT_RESTORE_REMAPS, NULL); if (is_inited) if (!task_push_start_dummy_core(&content_info)) @@ -1856,9 +1865,17 @@ bool command_event(enum event_command cmd, void *data) if (settings->bools.cheevos_hardcore_mode_enable) return false; #endif - if (settings->bools.rewind_enable) - state_manager_event_init((unsigned)settings->rewind_buffer_size); + { +#ifdef HAVE_NETWORKING + /* Only enable state manager if netplay is not underway +TODO: Add a setting for these tweaks */ + if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) +#endif + { + state_manager_event_init((unsigned)settings->rewind_buffer_size); + } + } } break; case CMD_EVENT_REWIND_TOGGLE: @@ -1880,10 +1897,21 @@ bool command_event(enum event_command cmd, void *data) case CMD_EVENT_AUTOSAVE_INIT: command_event(CMD_EVENT_AUTOSAVE_DEINIT, NULL); #ifdef HAVE_THREADS - if (autosave_init()) - runloop_set(RUNLOOP_ACTION_AUTOSAVE); - else - runloop_unset(RUNLOOP_ACTION_AUTOSAVE); + { +#ifdef HAVE_NETWORKING + /* Only enable state manager if netplay is not underway + TODO: Add a setting for these tweaks */ + settings_t *settings = config_get_ptr(); + if (settings->uints.autosave_interval != 0 + && !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) +#endif + { + if (autosave_init()) + runloop_set(RUNLOOP_ACTION_AUTOSAVE); + else + runloop_unset(RUNLOOP_ACTION_AUTOSAVE); + } + } #endif break; case CMD_EVENT_AUTOSAVE_STATE: @@ -1967,6 +1995,13 @@ bool command_event(enum event_command cmd, void *data) } g_defaults.content_history = NULL; + if (g_defaults.content_favorites) + { + playlist_write_file(g_defaults.content_favorites); + playlist_free(g_defaults.content_favorites); + } + g_defaults.content_favorites = NULL; + if (g_defaults.music_history) { playlist_write_file(g_defaults.music_history); @@ -2010,6 +2045,13 @@ bool command_event(enum event_command cmd, void *data) settings->paths.path_content_history, content_history_size); + RARCH_LOG("%s: [%s].\n", + msg_hash_to_str(MSG_LOADING_HISTORY_FILE), + settings->paths.path_content_favorites); + g_defaults.content_favorites = playlist_init( + settings->paths.path_content_favorites, + content_history_size); + RARCH_LOG("%s: [%s].\n", msg_hash_to_str(MSG_LOADING_HISTORY_FILE), settings->paths.path_content_music_history); @@ -2109,7 +2151,7 @@ bool command_event(enum event_command cmd, void *data) * need to make sure to keep a copy */ struct retro_hw_render_callback hwr_copy; struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); - const struct retro_hw_render_context_negotiation_interface *iface = + const struct retro_hw_render_context_negotiation_interface *iface = video_driver_get_context_negotiation_interface(); memcpy(&hwr_copy, hwr, sizeof(hwr_copy)); @@ -2142,6 +2184,19 @@ bool command_event(enum event_command cmd, void *data) if (ui_companion_is_on_foreground()) ui_companion_driver_toggle(); break; + case CMD_EVENT_ADD_TO_FAVORITES: + playlist_push( + g_defaults.content_favorites, + path_get(RARCH_PATH_CONTENT), + NULL, + file_path_str(FILE_PATH_DETECT), + file_path_str(FILE_PATH_DETECT), + NULL, + NULL + ); + playlist_write_file(g_defaults.content_favorites); + runloop_msg_queue_push(msg_hash_to_str(MSG_ADDED_TO_FAVORITES), 1, 180, true); + break; case CMD_EVENT_RESTART_RETROARCH: if (!frontend_driver_set_fork(FRONTEND_FORK_RESTART)) return false; @@ -2182,7 +2237,7 @@ bool command_event(enum event_command cmd, void *data) RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); command_event(CMD_EVENT_AUDIO_STOP, NULL); - runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1, + runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1, 1, true); if (!is_idle) @@ -2265,13 +2320,20 @@ bool command_event(enum event_command cmd, void *data) command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); - if (!init_netplay(NULL, hostname ? hostname : + if (!init_netplay(NULL, hostname ? hostname : settings->paths.netplay_server, settings->uints.netplay_port)) { command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); return false; } + + /* Disable rewind & sram autosave if it was enabled + TODO: Add a setting for these tweaks */ + state_manager_event_deinit(); +#ifdef HAVE_THREADS + autosave_deinit(); +#endif } break; /* init netplay via lobby when content is loaded */ @@ -2284,12 +2346,12 @@ bool command_event(enum event_command cmd, void *data) command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); - RARCH_LOG("[netplay] connecting to %s:%d\n", - hostname->elems[0].data, !string_is_empty(hostname->elems[1].data) + RARCH_LOG("[netplay] connecting to %s:%d\n", + hostname->elems[0].data, !string_is_empty(hostname->elems[1].data) ? atoi(hostname->elems[1].data) : 55435); - if (!init_netplay(NULL, hostname->elems[0].data, - !string_is_empty(hostname->elems[1].data) + if (!init_netplay(NULL, hostname->elems[0].data, + !string_is_empty(hostname->elems[1].data) ? atoi(hostname->elems[1].data) : 55435)) { command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); @@ -2298,6 +2360,13 @@ bool command_event(enum event_command cmd, void *data) } string_list_free(hostname); + + /* Disable rewind if it was enabled + TODO: Add a setting for these tweaks */ + state_manager_event_deinit(); +#ifdef HAVE_THREADS + autosave_deinit(); +#endif } break; /* init netplay via lobby when content is not loaded */ @@ -2310,12 +2379,12 @@ bool command_event(enum event_command cmd, void *data) command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); - RARCH_LOG("[netplay] connecting to %s:%d\n", - hostname->elems[0].data, !string_is_empty(hostname->elems[1].data) + RARCH_LOG("[netplay] connecting to %s:%d\n", + hostname->elems[0].data, !string_is_empty(hostname->elems[1].data) ? atoi(hostname->elems[1].data) : 55435); if (!init_netplay_deferred(hostname->elems[0].data, - !string_is_empty(hostname->elems[1].data) + !string_is_empty(hostname->elems[1].data) ? atoi(hostname->elems[1].data) : 55435)) { command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); @@ -2324,6 +2393,13 @@ bool command_event(enum event_command cmd, void *data) } string_list_free(hostname); + + /* Disable rewind if it was enabled + TODO: Add a setting for these tweaks */ + state_manager_event_deinit(); +#ifdef HAVE_THREADS + autosave_deinit(); +#endif } break; case CMD_EVENT_NETPLAY_FLIP_PLAYERS: @@ -2495,7 +2571,7 @@ bool command_event(enum event_command cmd, void *data) { static bool game_focus_state = false; intptr_t mode = (intptr_t)data; - + /* mode = -1: restores current game focus state * mode = 1: force set game focus, instead of toggling * any other: toggle @@ -2553,11 +2629,14 @@ bool command_event(enum event_command cmd, void *data) case CMD_EVENT_DISABLE_OVERRIDES: command_event_disable_overrides(); break; + case CMD_EVENT_RESTORE_REMAPS: + command_event_restore_remaps(); + break; case CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET: command_event_restore_default_shader_preset(); break; case CMD_EVENT_LIBUI_TEST: -#if 0 +#if HAVE_LIBUI libui_main(); #endif break; diff --git a/command.h b/command.h index 8cd7ec2132..4709d3f404 100644 --- a/command.h +++ b/command.h @@ -134,6 +134,8 @@ enum event_command CMD_EVENT_REBOOT, /* Resume RetroArch when in menu. */ CMD_EVENT_RESUME, + /* Add a playlist entry to favorites. */ + CMD_EVENT_ADD_TO_FAVORITES, /* Toggles pause. */ CMD_EVENT_PAUSE_TOGGLE, /* Pauses RetroArch. */ @@ -218,6 +220,7 @@ enum event_command CMD_EVENT_MIXER_VOLUME_UP, CMD_EVENT_MIXER_VOLUME_DOWN, CMD_EVENT_DISABLE_OVERRIDES, + CMD_EVENT_RESTORE_REMAPS, CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, CMD_EVENT_LIBUI_TEST }; diff --git a/config.def.h b/config.def.h index 162a72a73b..6e30fe126c 100644 --- a/config.def.h +++ b/config.def.h @@ -58,6 +58,10 @@ static bool bundle_assets_extract_enable = true; static bool bundle_assets_extract_enable = false; #endif +#ifdef HAVE_MATERIALUI +static bool materialui_icons_enable = true; +#endif + static const bool def_history_list_enable = true; static const bool def_playlist_entry_remove = true; @@ -250,6 +254,7 @@ static bool xmb_shadows_enable = false; static bool xmb_shadows_enable = true; #endif static bool xmb_show_settings = true; +static bool xmb_show_favorites = true; #ifdef HAVE_IMAGEVIEWER static bool xmb_show_images = true; #endif @@ -266,6 +271,8 @@ static bool xmb_show_add = true; #endif #endif +static float menu_framebuffer_opacity = 0.900; + static float menu_wallpaper_opacity = 0.300; static float menu_footer_opacity = 1.000; @@ -295,6 +302,11 @@ static bool default_auto_shaders_enable = true; static bool default_sort_savefiles_enable = false; static bool default_sort_savestates_enable = false; +static bool default_savestates_in_content_dir = false; +static bool default_savefiles_in_content_dir = false; +static bool default_systemfiles_in_content_dir = false; +static bool default_screenshots_in_content_dir = false; + #if defined(__CELLOS_LV2__) || defined(_XBOX1) || defined(_XBOX360) static unsigned menu_toggle_gamepad_combo = INPUT_TOGGLE_L3_R3; #elif defined(VITA) @@ -308,6 +320,8 @@ static unsigned input_backtouch_enable = false; static unsigned input_backtouch_toggle = false; #endif +static bool show_physical_inputs = true; + static bool all_users_control_menu = false; #if defined(ANDROID) || defined(_WIN32) @@ -610,11 +624,17 @@ static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/window #elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_IX86) || defined(_M_IA64) static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/windows-msvc2010/x86/latest/"; #endif +#elif _MSC_VER == 1400 +#if defined(__x86_64__) +static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/windows-msvc2005/x86_64/latest/"; +#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_IX86) || defined(_M_IA64) +static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/windows-msvc2005/x86/latest/"; +#endif #else #if defined(__x86_64__) -static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/win-x86_64/latest/"; +static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/windows/x86_64/latest/"; #elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_IX86) || defined(_M_IA64) -static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/win-x86/latest/"; +static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/windows/x86/latest/"; #endif #endif #elif defined(__linux__) diff --git a/configuration.c b/configuration.c index 1704386fbb..cf37d12a05 100644 --- a/configuration.c +++ b/configuration.c @@ -2,6 +2,7 @@ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2015-2017 - Andrés Suárez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -52,7 +53,7 @@ /* All config related settings go here. */ struct config_bool_setting -{ +{ const char *ident; bool *ptr; bool def_enable; @@ -61,7 +62,7 @@ struct config_bool_setting }; struct config_int_setting -{ +{ const char *ident; int *ptr; bool def_enable; @@ -70,7 +71,7 @@ struct config_int_setting }; struct config_uint_setting -{ +{ const char *ident; unsigned *ptr; bool def_enable; @@ -79,7 +80,7 @@ struct config_uint_setting }; struct config_float_setting -{ +{ const char *ident; float *ptr; bool def_enable; @@ -88,7 +89,7 @@ struct config_float_setting }; struct config_array_setting -{ +{ const char *ident; char *ptr; bool def_enable; @@ -97,7 +98,7 @@ struct config_array_setting }; struct config_path_setting -{ +{ const char *ident; char *ptr; bool def_enable; @@ -485,7 +486,7 @@ static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_NULL; tmp[count].def = default_setting; \ tmp[count].handle = handle_setting; \ count++; \ -} +} #define SETTING_BOOL(key, configval, default_enable, default_setting, handle_setting) \ GENERAL_SETTING(key, configval, default_enable, default_setting, struct config_bool_setting, handle_setting) @@ -1014,11 +1015,13 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, SETTING_PATH("cheat_database_path", settings->paths.path_cheat_database, false, NULL, true); #ifdef HAVE_MENU - SETTING_PATH("menu_wallpaper", + SETTING_PATH("menu_wallpaper", settings->paths.path_menu_wallpaper, false, NULL, true); #endif SETTING_PATH("content_history_path", settings->paths.path_content_history, false, NULL, true); + SETTING_PATH("content_favorites_path", + settings->paths.path_content_favorites, false, NULL, true); SETTING_PATH("content_music_history_path", settings->paths.path_content_music_history, false, NULL, true); SETTING_PATH("content_video_history_path", @@ -1033,7 +1036,7 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, settings->paths.path_font, false, NULL, true); SETTING_PATH("cursor_directory", settings->paths.directory_cursor, false, NULL, true); - SETTING_PATH("content_history_dir", + SETTING_PATH("content_history_dir", settings->paths.directory_content_history, false, NULL, true); SETTING_PATH("screenshot_directory", settings->paths.directory_screenshot, true, NULL, true); @@ -1063,7 +1066,7 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, settings->paths.directory_autoconfig, false, NULL, true); SETTING_PATH("audio_filter_dir", settings->paths.directory_audio_filter, true, NULL, true); - SETTING_PATH("savefile_directory", + SETTING_PATH("savefile_directory", dir_get_ptr(RARCH_DIR_SAVEFILE), true, NULL, false); SETTING_PATH("savestate_directory", dir_get_ptr(RARCH_DIR_SAVESTATE), true, NULL, false); @@ -1078,11 +1081,11 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, settings->paths.directory_overlay, true, NULL, true); #endif #ifndef HAVE_DYNAMIC - SETTING_PATH("libretro_path", + SETTING_PATH("libretro_path", path_get_ptr(RARCH_PATH_CORE), false, NULL, false); #endif SETTING_PATH( - "screenshot_directory", + "screenshot_directory", settings->paths.directory_screenshot, true, NULL, false); if (global) @@ -1180,6 +1183,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, #endif SETTING_BOOL("menu_throttle_framerate", &settings->bools.menu_throttle_framerate, true, true, false); SETTING_BOOL("menu_linear_filter", &settings->bools.menu_linear_filter, true, true, false); + SETTING_BOOL("menu_horizontal_animation", &settings->bools.menu_horizontal_animation, true, true, false); SETTING_BOOL("dpi_override_enable", &settings->bools.menu_dpi_override_enable, true, menu_dpi_override_enable, false); SETTING_BOOL("menu_pause_libretro", &settings->bools.menu_pause_libretro, true, true, false); SETTING_BOOL("menu_mouse_enable", &settings->bools.menu_mouse_enable, true, def_mouse_enable, false); @@ -1188,9 +1192,13 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("menu_battery_level_enable", &settings->bools.menu_battery_level_enable, true, true, false); SETTING_BOOL("menu_core_enable", &settings->bools.menu_core_enable, true, true, false); SETTING_BOOL("menu_dynamic_wallpaper_enable", &settings->bools.menu_dynamic_wallpaper_enable, true, false, false); +#ifdef HAVE_MATERIALUI + SETTING_BOOL("materialui_icons_enable", &settings->bools.menu_materialui_icons_enable, true, materialui_icons_enable, false); +#endif #ifdef HAVE_XMB SETTING_BOOL("xmb_shadows_enable", &settings->bools.menu_xmb_shadows_enable, true, xmb_shadows_enable, false); SETTING_BOOL("xmb_show_settings", &settings->bools.menu_xmb_show_settings, true, xmb_show_settings, false); + SETTING_BOOL("xmb_show_favorites", &settings->bools.menu_xmb_show_favorites, true, xmb_show_favorites, false); #ifdef HAVE_IMAGEVIEWER SETTING_BOOL("xmb_show_images", &settings->bools.menu_xmb_show_images, true, xmb_show_images, false); #endif @@ -1204,14 +1212,14 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("xmb_show_netplay", &settings->bools.menu_xmb_show_netplay, true, xmb_show_netplay, false); #endif SETTING_BOOL("xmb_show_history", &settings->bools.menu_xmb_show_history, true, xmb_show_history, false); -#ifdef HAVE_LIBRETRODB +#ifdef HAVE_LIBRETRODB SETTING_BOOL("xmb_show_add", &settings->bools.menu_xmb_show_add, true, xmb_show_add, false); #endif #endif SETTING_BOOL("filter_by_current_core", &settings->bools.filter_by_current_core, false, false /* TODO */, false); SETTING_BOOL("rgui_show_start_screen", &settings->bools.menu_show_start_screen, false, false /* TODO */, false); SETTING_BOOL("menu_navigation_wraparound_enable", &settings->bools.menu_navigation_wraparound_enable, true, true, false); - SETTING_BOOL("menu_navigation_browser_filter_supported_extensions_enable", + SETTING_BOOL("menu_navigation_browser_filter_supported_extensions_enable", &settings->bools.menu_navigation_browser_filter_supported_extensions_enable, true, true, false); SETTING_BOOL("menu_show_advanced_settings", &settings->bools.menu_show_advanced_settings, true, show_advanced_settings, false); #endif @@ -1224,6 +1232,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, #ifdef HAVE_OVERLAY SETTING_BOOL("input_overlay_enable", &settings->bools.input_overlay_enable, true, config_overlay_enable_default(), false); SETTING_BOOL("input_overlay_enable_autopreferred", &settings->bools.input_overlay_enable_autopreferred, true, true, false); + SETTING_BOOL("input_overlay_show_physical_inputs", &settings->bools.input_overlay_show_physical_inputs, true, false, false); SETTING_BOOL("input_overlay_hide_in_menu", &settings->bools.input_overlay_hide_in_menu, true, overlay_hide_in_menu, false); #endif #ifdef HAVE_COMMAND @@ -1258,6 +1267,11 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("audio_wasapi_float_format", &settings->bools.audio_wasapi_float_format, true, wasapi_float_format, false); #endif + SETTING_BOOL("savestates_in_content_dir", &settings->bools.savestates_in_content_dir, true, default_savestates_in_content_dir, false); + SETTING_BOOL("savefiles_in_content_dir", &settings->bools.savefiles_in_content_dir, true, default_savefiles_in_content_dir, false); + SETTING_BOOL("systemfiles_in_content_dir", &settings->bools.systemfiles_in_content_dir, true, default_systemfiles_in_content_dir, false); + SETTING_BOOL("screenshots_in_content_dir", &settings->bools.screenshots_in_content_dir, true, default_screenshots_in_content_dir, false); + if (global) { SETTING_BOOL("custom_bgm_enable", &global->console.sound.system_bgm_enable, true, false, false); @@ -1286,6 +1300,7 @@ static struct config_float_setting *populate_settings_float(settings_t *settings #endif #ifdef HAVE_MENU SETTING_FLOAT("menu_wallpaper_opacity", &settings->floats.menu_wallpaper_opacity, true, menu_wallpaper_opacity, false); + SETTING_FLOAT("menu_framebuffer_opacity", &settings->floats.menu_framebuffer_opacity, true, menu_framebuffer_opacity, false); SETTING_FLOAT("menu_footer_opacity", &settings->floats.menu_footer_opacity, true, menu_footer_opacity, false); SETTING_FLOAT("menu_header_opacity", &settings->floats.menu_header_opacity, true, menu_header_opacity, false); #endif @@ -1366,6 +1381,7 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, #endif SETTING_UINT("bundle_assets_extract_version_current", &settings->uints.bundle_assets_extract_version_current, true, 0, false); SETTING_UINT("bundle_assets_extract_last_version", &settings->uints.bundle_assets_extract_last_version, true, 0, false); + SETTING_UINT("input_overlay_show_physical_inputs_port", &settings->uints.input_overlay_show_physical_inputs_port, true, 0, false); *size = count; @@ -1646,6 +1662,7 @@ static void config_set_defaults(void) *settings->paths.path_core_options = '\0'; *settings->paths.path_content_history = '\0'; + *settings->paths.path_content_favorites = '\0'; *settings->paths.path_content_music_history = '\0'; *settings->paths.path_content_image_history = '\0'; *settings->paths.path_content_video_history = '\0'; @@ -1923,7 +1940,7 @@ static config_file_t *open_default_config_file(void) RARCH_WARN("Created new config file in: \"%s\".\n", conf_path); } #elif !defined(RARCH_CONSOLE) - bool has_application_data = + bool has_application_data = fill_pathname_application_data(application_data, sizeof(application_data)); @@ -2099,7 +2116,7 @@ static bool check_shader_compatibility(enum file_path_enum enum_idx) return true; } - if (string_is_equal_fast(settings->arrays.video_driver, "gl", 2) || + if (string_is_equal_fast(settings->arrays.video_driver, "gl", 2) || string_is_equal_fast(settings->arrays.video_driver, "d3d", 3) ) { @@ -2170,7 +2187,7 @@ static void config_get_hex_base(config_file_t *conf, * Loads a config file and reads all the values into memory. * */ -static bool config_load_file(const char *path, bool set_defaults, +static bool config_load_file(const char *path, bool set_defaults, settings_t *settings) { unsigned i; @@ -2473,6 +2490,25 @@ static bool config_load_file(const char *path, bool set_defaults, } } + if (string_is_empty(settings->paths.path_content_favorites)) + { + if (string_is_empty(settings->paths.directory_content_history)) + { + fill_pathname_resolve_relative( + settings->paths.path_content_favorites, + path_get(RARCH_PATH_CONFIG), + file_path_str(FILE_PATH_CONTENT_FAVORITES), + sizeof(settings->paths.path_content_favorites)); + } + else + { + fill_pathname_join(settings->paths.path_content_favorites, + settings->paths.directory_content_history, + file_path_str(FILE_PATH_CONTENT_FAVORITES), + sizeof(settings->paths.path_content_favorites)); + } + } + if (string_is_empty(settings->paths.path_content_music_history)) { if (string_is_empty(settings->paths.directory_content_history)) @@ -2706,10 +2742,10 @@ end: * This function only has an effect if a game-specific or core-specific * configuration file exists at respective locations. * - * core-specific: $CONFIG_DIR/$CORE_NAME/$CORE_NAME.cfg + * core-specific: $CONFIG_DIR/$CORE_NAME/$CORE_NAME.cfg * fallback: $CURRENT_CFG_LOCATION/$CORE_NAME/$CORE_NAME.cfg * - * game-specific: $CONFIG_DIR/$CORE_NAME/$ROM_NAME.cfg + * game-specific: $CONFIG_DIR/$CORE_NAME/$ROM_NAME.cfg * fallback: $CURRENT_CFG_LOCATION/$CORE_NAME/$GAME_NAME.cfg * * Returns: false if there was an error or no action was performed. @@ -2805,7 +2841,7 @@ bool config_load_override(void) /* Re-load the configuration with any overrides that might have been found */ buf[0] = '\0'; - /* Store the libretro_path we're using since it will be + /* Store the libretro_path we're using since it will be * overwritten by the override when reloading. */ strlcpy(buf, path_get(RARCH_PATH_CORE), sizeof(buf)); @@ -2925,6 +2961,7 @@ bool config_load_remap(void) if (input_remapping_load_file(new_conf, game_path)) { runloop_msg_queue_push("Game remap file loaded.", 1, 100, true); + rarch_ctl(RARCH_CTL_SET_REMAPS_GAME_ACTIVE, NULL); return true; } } @@ -2944,6 +2981,7 @@ bool config_load_remap(void) if (input_remapping_load_file(new_conf, core_path)) { runloop_msg_queue_push("Core remap file loaded.", 1, 100, true); + rarch_ctl(RARCH_CTL_SET_REMAPS_CORE_ACTIVE, NULL); return true; } } @@ -3252,7 +3290,7 @@ static void save_keybinds_user(config_file_t *conf, unsigned user) */ void config_load(void) { - /* Flush out some states that could have been + /* Flush out some states that could have been * set by core environment variables */ core_unset_input_descriptors(); @@ -3442,7 +3480,7 @@ bool config_save_file(const char *path) #ifdef HAVE_MENU config_set_path(conf, "xmb_font", - !string_is_empty(settings->paths.path_menu_xmb_font) + !string_is_empty(settings->paths.path_menu_xmb_font) ? settings->paths.path_menu_xmb_font : ""); #endif @@ -3633,7 +3671,7 @@ bool config_save_overrides(int override_type) fill_pathname_application_special(config_directory, sizeof(config_directory), APPLICATION_SPECIAL_DIRECTORY_CONFIG); - fill_pathname_join(override_directory, config_directory, core_name, + fill_pathname_join(override_directory, config_directory, core_name, sizeof(override_directory)); if(!path_file_exists(override_directory)) @@ -3690,9 +3728,9 @@ bool config_save_overrides(int override_type) { if ((*bool_settings[i].ptr) != (*bool_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%d\n", + RARCH_LOG(" original: %s=%d\n", bool_settings[i].ident, (*bool_settings[i].ptr)); - RARCH_LOG(" override: %s=%d\n", + RARCH_LOG(" override: %s=%d\n", bool_overrides[i].ident, (*bool_overrides[i].ptr)); config_set_bool(conf, bool_overrides[i].ident, (*bool_overrides[i].ptr)); @@ -3702,9 +3740,9 @@ bool config_save_overrides(int override_type) { if ((*int_settings[i].ptr) != (*int_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%d\n", + RARCH_LOG(" original: %s=%d\n", int_settings[i].ident, (*int_settings[i].ptr)); - RARCH_LOG(" override: %s=%d\n", + RARCH_LOG(" override: %s=%d\n", int_overrides[i].ident, (*int_overrides[i].ptr)); config_set_int(conf, int_overrides[i].ident, (*int_overrides[i].ptr)); @@ -3714,9 +3752,9 @@ bool config_save_overrides(int override_type) { if ((*uint_settings[i].ptr) != (*uint_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%d\n", + RARCH_LOG(" original: %s=%d\n", uint_settings[i].ident, (*uint_settings[i].ptr)); - RARCH_LOG(" override: %s=%d\n", + RARCH_LOG(" override: %s=%d\n", uint_overrides[i].ident, (*uint_overrides[i].ptr)); config_set_int(conf, uint_overrides[i].ident, (*uint_overrides[i].ptr)); @@ -3726,9 +3764,9 @@ bool config_save_overrides(int override_type) { if ((*float_settings[i].ptr) != (*float_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%f\n", + RARCH_LOG(" original: %s=%f\n", float_settings[i].ident, *float_settings[i].ptr); - RARCH_LOG(" override: %s=%f\n", + RARCH_LOG(" override: %s=%f\n", float_overrides[i].ident, *float_overrides[i].ptr); config_set_float(conf, float_overrides[i].ident, *float_overrides[i].ptr); @@ -3739,9 +3777,9 @@ bool config_save_overrides(int override_type) { if (!string_is_equal(array_settings[i].ptr, array_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%s\n", + RARCH_LOG(" original: %s=%s\n", array_settings[i].ident, array_settings[i].ptr); - RARCH_LOG(" override: %s=%s\n", + RARCH_LOG(" override: %s=%s\n", array_overrides[i].ident, array_overrides[i].ptr); config_set_string(conf, array_overrides[i].ident, array_overrides[i].ptr); @@ -3752,9 +3790,9 @@ bool config_save_overrides(int override_type) { if (!string_is_equal(path_settings[i].ptr, path_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%s\n", + RARCH_LOG(" original: %s=%s\n", path_settings[i].ident, path_settings[i].ptr); - RARCH_LOG(" override: %s=%s\n", + RARCH_LOG(" override: %s=%s\n", path_overrides[i].ident, path_overrides[i].ptr); config_set_path(conf, path_overrides[i].ident, path_overrides[i].ptr); @@ -3776,7 +3814,8 @@ bool config_save_overrides(int override_type) snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1); config_set_int(conf, cfg, overrides->uints.input_joypad_map[i]); } - if (input_config_get_device(i) != overrides->uints.input_libretro_device[i]) + + if (settings->uints.input_libretro_device[i] != overrides->uints.input_libretro_device[i]) { snprintf(cfg, sizeof(cfg), "input_libretro_device_p%u", i + 1); config_set_int(conf, cfg, overrides->uints.input_libretro_device[i]); diff --git a/configuration.h b/configuration.h index 8d20c8daaf..3f72595181 100644 --- a/configuration.h +++ b/configuration.h @@ -88,6 +88,7 @@ typedef struct settings bool input_overlay_enable; bool input_overlay_enable_autopreferred; bool input_overlay_hide_in_menu; + bool input_overlay_show_physical_inputs; bool input_descriptor_label_show; bool input_descriptor_hide_unbound; bool input_all_users_control_menu; @@ -119,10 +120,13 @@ typedef struct settings bool menu_show_advanced_settings; bool menu_throttle_framerate; bool menu_linear_filter; + bool menu_horizontal_animation; bool menu_show_online_updater; bool menu_show_core_updater; + bool menu_materialui_icons_enable; bool menu_xmb_shadows_enable; bool menu_xmb_show_settings; + bool menu_xmb_show_favorites; bool menu_xmb_show_images; bool menu_xmb_show_music; bool menu_xmb_show_video; @@ -209,6 +213,11 @@ typedef struct settings bool sort_savestates_enable; bool config_save_on_exit; bool show_hidden_files; + + bool savefiles_in_content_dir; + bool savestates_in_content_dir; + bool screenshots_in_content_dir; + bool systemfiles_in_content_dir; #ifdef HAVE_LAKKA bool ssh_enable; bool samba_enable; @@ -230,6 +239,7 @@ typedef struct settings float video_msg_color_b; float menu_wallpaper_opacity; + float menu_framebuffer_opacity; float menu_footer_opacity; float menu_header_opacity; @@ -322,6 +332,8 @@ typedef struct settings unsigned camera_width; unsigned camera_height; + + unsigned input_overlay_show_physical_inputs_port; } uints; struct @@ -373,6 +385,7 @@ typedef struct settings char path_softfilter_plugin[PATH_MAX_LENGTH]; char path_core_options[PATH_MAX_LENGTH]; char path_content_history[PATH_MAX_LENGTH]; + char path_content_favorites[PATH_MAX_LENGTH]; char path_content_music_history[PATH_MAX_LENGTH]; char path_content_image_history[PATH_MAX_LENGTH]; char path_content_video_history[PATH_MAX_LENGTH]; @@ -389,6 +402,7 @@ typedef struct settings char directory_video_filter[PATH_MAX_LENGTH]; char directory_video_shader[PATH_MAX_LENGTH]; char directory_content_history[PATH_MAX_LENGTH]; + char directory_content_favorites[PATH_MAX_LENGTH]; char directory_libretro[PATH_MAX_LENGTH]; char directory_cursor[PATH_MAX_LENGTH]; char directory_input_remapping[PATH_MAX_LENGTH]; diff --git a/defaults.h b/defaults.h index 80306a797c..66940f307e 100644 --- a/defaults.h +++ b/defaults.h @@ -102,6 +102,7 @@ struct defaults #ifndef IS_SALAMANDER playlist_t *content_history; + playlist_t *content_favorites; #ifdef HAVE_IMAGEVIEWER playlist_t *image_history; #endif diff --git a/deps/ibxm/README b/deps/ibxm/README new file mode 100644 index 0000000000..7acec1a9b5 --- /dev/null +++ b/deps/ibxm/README @@ -0,0 +1,21 @@ + +Micromod (c)2017 mumart@gmail.com + +A good-quality player library for the ProTracker MOD music format +for Javascript (HTML5 Web Audio), Java, ANSI C (SDL) and Pascal (SDL). + +Also hosted here is IBXM, a player library for the ProTracker MOD, +Scream Tracker 3 S3M, and FastTracker 2 XM music formats for Javascript +(HTML5 Web Audio), Java and ANSI C. + +The Java version of Micromod contains a powerful command-line tool for +the creation of MOD files from textual MT files and WAV samples. +There is some basic documentation built-in to the tool and some example +MT files are contained in the songs directory. Some knowledge of the +ProTracker MOD format, audio synthesis and "tracking" is assumed. + +If you have any questions or feedback please feel free to +contact me at the above email address! + +Cheers, +Martin diff --git a/deps/ibxm/ibxm.c b/deps/ibxm/ibxm.c new file mode 100644 index 0000000000..6dff819bd9 --- /dev/null +++ b/deps/ibxm/ibxm.c @@ -0,0 +1,1922 @@ + +#include "stdlib.h" +#include "string.h" + +#include "ibxm.h" + +const char *IBXM_VERSION = "ibxm/ac mod/xm/s3m replay 20170704 (c)mumart@gmail.com"; + +static const int FP_SHIFT = 15, FP_ONE = 32768, FP_MASK = 32767; + +static const int exp2_table[] = { + 32768, 32946, 33125, 33305, 33486, 33667, 33850, 34034, + 34219, 34405, 34591, 34779, 34968, 35158, 35349, 35541, + 35734, 35928, 36123, 36319, 36516, 36715, 36914, 37114, + 37316, 37518, 37722, 37927, 38133, 38340, 38548, 38757, + 38968, 39180, 39392, 39606, 39821, 40037, 40255, 40473, + 40693, 40914, 41136, 41360, 41584, 41810, 42037, 42265, + 42495, 42726, 42958, 43191, 43425, 43661, 43898, 44137, + 44376, 44617, 44859, 45103, 45348, 45594, 45842, 46091, + 46341, 46593, 46846, 47100, 47356, 47613, 47871, 48131, + 48393, 48655, 48920, 49185, 49452, 49721, 49991, 50262, + 50535, 50810, 51085, 51363, 51642, 51922, 52204, 52488, + 52773, 53059, 53347, 53637, 53928, 54221, 54515, 54811, + 55109, 55408, 55709, 56012, 56316, 56622, 56929, 57238, + 57549, 57861, 58176, 58491, 58809, 59128, 59449, 59772, + 60097, 60423, 60751, 61081, 61413, 61746, 62081, 62419, + 62757, 63098, 63441, 63785, 64132, 64480, 64830, 65182, + 65536 +}; + +static const short sine_table[] = { + 0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253, + 255, 253, 250, 244, 235, 224, 212, 197, 180, 161, 141, 120, 97, 74, 49, 24 +}; + +struct note { + unsigned char key, instrument, volume, effect, param; +}; + +struct channel { + struct replay *replay; + struct instrument *instrument; + struct sample *sample; + struct note note; + int id, key_on, random_seed, pl_row; + int sample_off, sample_idx, sample_fra, freq, ampl, pann; + int volume, panning, fadeout_vol, vol_env_tick, pan_env_tick; + int period, porta_period, retrig_count, fx_count, av_count; + int porta_up_param, porta_down_param, tone_porta_param, offset_param; + int fine_porta_up_param, fine_porta_down_param, xfine_porta_param; + int arpeggio_param, vol_slide_param, gvol_slide_param, pan_slide_param; + int fine_vslide_up_param, fine_vslide_down_param; + int retrig_volume, retrig_ticks, tremor_on_ticks, tremor_off_ticks; + int vibrato_type, vibrato_phase, vibrato_speed, vibrato_depth; + int tremolo_type, tremolo_phase, tremolo_speed, tremolo_depth; + int tremolo_add, vibrato_add, arpeggio_add; +}; + +struct replay { + int sample_rate, interpolation, global_vol; + int seq_pos, break_pos, row, next_row, tick; + int speed, tempo, pl_count, pl_chan; + int *ramp_buf; + char **play_count; + struct channel *channels; + struct module *module; +}; + +static int exp_2( int x ) { + int c, m, y; + int x0 = ( x & FP_MASK ) >> ( FP_SHIFT - 7 ); + c = exp2_table[ x0 ]; + m = exp2_table[ x0 + 1 ] - c; + y = ( m * ( x & ( FP_MASK >> 7 ) ) >> 8 ) + c; + return ( y << FP_SHIFT ) >> ( FP_SHIFT - ( x >> FP_SHIFT ) ); +} + +static int log_2( int x ) { + int step; + int y = 16 << FP_SHIFT; + for( step = y; step > 0; step >>= 1 ) { + if( exp_2( y - step ) >= x ) { + y -= step; + } + } + return y; +} + +static char* data_ascii( struct data *data, int offset, int length, char *dest ) { + int idx, chr; + memset( dest, 32, length ); + if( offset > data->length ) { + offset = data->length; + } + if( offset + length > data->length ) { + length = data->length - offset; + } + for( idx = 0; idx < length; idx++ ) { + chr = data->buffer[ offset + idx ] & 0xFF; + if( chr > 32 ) { + dest[ idx ] = chr; + } + } + return dest; +} + +static int data_s8( struct data *data, int offset ) { + int value = 0; + if( offset < data->length ) { + value = data->buffer[ offset ]; + value = ( value & 0x7F ) - ( value & 0x80 ); + } + return value; +} + +static int data_u8( struct data *data, int offset ) { + int value = 0; + if( offset < data->length ) { + value = data->buffer[ offset ] & 0xFF; + } + return value; +} + +static int data_u16be( struct data *data, int offset ) { + int value = 0; + if( offset + 1 < data->length ) { + value = ( ( data->buffer[ offset ] & 0xFF ) << 8 ) + | ( data->buffer[ offset + 1 ] & 0xFF ); + } + return value; +} + +static int data_u16le( struct data *data, int offset ) { + int value = 0; + if( offset + 1 < data->length ) { + value = ( data->buffer[ offset ] & 0xFF ) + | ( ( data->buffer[ offset + 1 ] & 0xFF ) << 8 ); + } + return value; +} + +static unsigned int data_u32le( struct data *data, int offset ) { + unsigned int value = 0; + if( offset + 3 < data->length ) { + value = ( data->buffer[ offset ] & 0xFF ) + | ( ( data->buffer[ offset + 1 ] & 0xFF ) << 8 ) + | ( ( data->buffer[ offset + 2 ] & 0xFF ) << 16 ) + | ( ( data->buffer[ offset + 3 ] & 0xFF ) << 24 ); + } + return value; +} + +static void data_sam_s8( struct data *data, int offset, int count, short *dest ) { + int idx, amp, length = data->length; + char *buffer = data->buffer; + if( offset > length ) { + offset = length; + } + if( offset + count > length ) { + count = length - offset; + } + for( idx = 0; idx < count; idx++ ) { + amp = ( buffer[ offset + idx ] & 0xFF ) << 8; + dest[ idx ] = ( amp & 0x7FFF ) - ( amp & 0x8000 ); + } +} + +static void data_sam_s16le( struct data *data, int offset, int count, short *dest ) { + int idx, amp, length = data->length; + char *buffer = data->buffer; + if( offset > length ) { + offset = length; + } + if( offset + count * 2 > length ) { + count = ( length - offset ) / 2; + } + for( idx = 0; idx < count; idx++ ) { + amp = ( buffer[ offset + idx * 2 ] & 0xFF ) | ( buffer[ offset + idx * 2 + 1 ] << 8 ); + dest[ idx ] = ( amp & 0x7FFF ) - ( amp & 0x8000 ); + } +} + +static int envelope_next_tick( struct envelope *envelope, int tick, int key_on ) { + tick++; + if( envelope->looped && tick >= envelope->loop_end_tick ) { + tick = envelope->loop_start_tick; + } + if( envelope->sustain && key_on && tick >= envelope->sustain_tick ) { + tick = envelope->sustain_tick; + } + return tick; +} + +static int envelope_calculate_ampl( struct envelope *envelope, int tick ) { + int idx, point, dt, da; + int ampl = envelope->points_ampl[ envelope->num_points - 1 ]; + if( tick < envelope->points_tick[ envelope->num_points - 1 ] ) { + point = 0; + for( idx = 1; idx < envelope->num_points; idx++ ) { + if( envelope->points_tick[ idx ] <= tick ) { + point = idx; + } + } + dt = envelope->points_tick[ point + 1 ] - envelope->points_tick[ point ]; + da = envelope->points_ampl[ point + 1 ] - envelope->points_ampl[ point ]; + ampl = envelope->points_ampl[ point ]; + ampl += ( ( da << 24 ) / dt ) * ( tick - envelope->points_tick[ point ] ) >> 24; + } + return ampl; +} + +static void sample_ping_pong( struct sample *sample ) { + int idx; + int loop_start = sample->loop_start; + int loop_length = sample->loop_length; + int loop_end = loop_start + loop_length; + short *sample_data = sample->data; + short *new_data = (short*)calloc( loop_end + loop_length + 1, sizeof( short ) ); + if( new_data ) { + memcpy( new_data, sample_data, loop_end * sizeof( short ) ); + for( idx = 0; idx < loop_length; idx++ ) { + new_data[ loop_end + idx ] = sample_data[ loop_end - idx - 1 ]; + } + free( sample->data ); + sample->data = new_data; + sample->loop_length *= 2; + sample->data[ loop_start + sample->loop_length ] = sample->data[ loop_start ]; + } +} + +/* Deallocate the specified module. */ +void dispose_module( struct module *module ) { + int idx, sam; + struct instrument *instrument; + free( module->default_panning ); + free( module->sequence ); + if( module->patterns ) { + for( idx = 0; idx < module->num_patterns; idx++ ) { + free( module->patterns[ idx ].data ); + } + free( module->patterns ); + } + if( module->instruments ) { + for( idx = 0; idx <= module->num_instruments; idx++ ) { + instrument = &module->instruments[ idx ]; + if( instrument->samples ) { + for( sam = 0; sam < instrument->num_samples; sam++ ) { + free( instrument->samples[ sam ].data ); + } + free( instrument->samples ); + } + } + free( module->instruments ); + } + free( module ); +} + +static struct module* module_load_xm( struct data *data, char *message ) { + int delta_env, offset, next_offset, idx, entry; + int num_rows, num_notes, pat_data_len, pat_data_offset; + int sam, sam_head_offset, sam_data_bytes, sam_data_samples; + int num_samples, sam_loop_start, sam_loop_length, amp; + int note, flags, key, ins, vol, fxc, fxp; + int point, point_tick, point_offset; + int looped, ping_pong, sixteen_bit; + char ascii[ 16 ], *pattern_data; + struct instrument *instrument; + struct sample *sample; + struct module *module = (struct module*)calloc( 1, sizeof( struct module ) ); + if( module ) { + if( data_u16le( data, 58 ) != 0x0104 ) { + strcpy( message, "XM format version must be 0x0104!" ); + dispose_module( module ); + return NULL; + } + data_ascii( data, 17, 20, module->name ); + delta_env = !memcmp( data_ascii( data, 38, 15, ascii ), "DigiBooster Pro", 15 ); + offset = 60 + data_u32le( data, 60 ); + module->sequence_len = data_u16le( data, 64 ); + module->restart_pos = data_u16le( data, 66 ); + module->num_channels = data_u16le( data, 68 ); + module->num_patterns = data_u16le( data, 70 ); + module->num_instruments = data_u16le( data, 72 ); + module->linear_periods = data_u16le( data, 74 ) & 0x1; + module->default_gvol = 64; + module->default_speed = data_u16le( data, 76 ); + module->default_tempo = data_u16le( data, 78 ); + module->c2_rate = 8363; + module->gain = 64; + module->default_panning = (unsigned char*)calloc( module->num_channels, sizeof( unsigned char ) ); + if( !module->default_panning ) { + dispose_module( module ); + return NULL; + } + for( idx = 0; idx < module->num_channels; idx++ ) { + module->default_panning[ idx ] = 128; + } + module->sequence = (unsigned char*)calloc( module->sequence_len, sizeof( unsigned char ) ); + if( !module->sequence ) { + dispose_module( module ); + return NULL; + } + for( idx = 0; idx < module->sequence_len; idx++ ) { + entry = data_u8( data, 80 + idx ); + module->sequence[ idx ] = entry < module->num_patterns ? entry : 0; + } + module->patterns = (struct pattern*)calloc( module->num_patterns, sizeof( struct pattern ) ); + if( !module->patterns ) { + dispose_module( module ); + return NULL; + } + for( idx = 0; idx < module->num_patterns; idx++ ) { + if( data_u8( data, offset + 4 ) ) { + strcpy( message, "Unknown pattern packing type!" ); + dispose_module( module ); + return NULL; + } + num_rows = data_u16le( data, offset + 5 ); + if( num_rows < 1 ) { + num_rows = 1; + } + pat_data_len = data_u16le( data, offset + 7 ); + offset += data_u32le( data, offset ); + next_offset = offset + pat_data_len; + num_notes = num_rows * module->num_channels; + pattern_data = (char*)calloc( num_notes, 5 ); + if( !pattern_data ) { + dispose_module( module ); + return NULL; + } + module->patterns[ idx ].num_channels = module->num_channels; + module->patterns[ idx ].num_rows = num_rows; + module->patterns[ idx ].data = pattern_data; + if( pat_data_len > 0 ) { + pat_data_offset = 0; + for( note = 0; note < num_notes; note++ ) { + flags = data_u8( data, offset ); + if( ( flags & 0x80 ) == 0 ) { + flags = 0x1F; + } else { + offset++; + } + key = ( flags & 0x01 ) > 0 ? data_u8( data, offset++ ) : 0; + pattern_data[ pat_data_offset++ ] = key; + ins = ( flags & 0x02 ) > 0 ? data_u8( data, offset++ ) : 0; + pattern_data[ pat_data_offset++ ] = ins; + vol = ( flags & 0x04 ) > 0 ? data_u8( data, offset++ ) : 0; + pattern_data[ pat_data_offset++ ] = vol; + fxc = ( flags & 0x08 ) > 0 ? data_u8( data, offset++ ) : 0; + fxp = ( flags & 0x10 ) > 0 ? data_u8( data, offset++ ) : 0; + if( fxc >= 0x40 ) { + fxc = fxp = 0; + } + pattern_data[ pat_data_offset++ ] = fxc; + pattern_data[ pat_data_offset++ ] = fxp; + } + } + offset = next_offset; + } + module->instruments = (struct instrument*)calloc( module->num_instruments + 1, sizeof( struct instrument ) ); + if( !module->instruments ) { + dispose_module( module ); + return NULL; + } + instrument = &module->instruments[ 0 ]; + instrument->samples = (struct sample*)calloc( 1, sizeof( struct sample ) ); + if( !instrument->samples ) { + dispose_module( module ); + return NULL; + } + for( ins = 1; ins <= module->num_instruments; ins++ ) { + instrument = &module->instruments[ ins ]; + data_ascii( data, offset + 4, 22, instrument->name ); + num_samples = data_u16le( data, offset + 27 ); + instrument->num_samples = ( num_samples > 0 ) ? num_samples : 1; + instrument->samples = (struct sample*)calloc( instrument->num_samples, sizeof( struct sample ) ); + if( !instrument->samples ) { + dispose_module( module ); + return NULL; + } + if( num_samples > 0 ) { + for( key = 0; key < 96; key++ ) { + instrument->key_to_sample[ key + 1 ] = data_u8( data, offset + 33 + key ); + } + point_tick = 0; + for( point = 0; point < 12; point++ ) { + point_offset = offset + 129 + ( point * 4 ); + point_tick = ( delta_env ? point_tick : 0 ) + data_u16le( data, point_offset ); + instrument->vol_env.points_tick[ point ] = point_tick; + instrument->vol_env.points_ampl[ point ] = data_u16le( data, point_offset + 2 ); + } + point_tick = 0; + for( point = 0; point < 12; point++ ) { + point_offset = offset + 177 + ( point * 4 ); + point_tick = ( delta_env ? point_tick : 0 ) + data_u16le( data, point_offset ); + instrument->pan_env.points_tick[ point ] = point_tick; + instrument->pan_env.points_ampl[ point ] = data_u16le( data, point_offset + 2 ); + } + instrument->vol_env.num_points = data_u8( data, offset + 225 ); + if( instrument->vol_env.num_points > 12 ) { + instrument->vol_env.num_points = 0; + } + instrument->pan_env.num_points = data_u8( data, offset + 226 ); + if( instrument->pan_env.num_points > 12 ) { + instrument->pan_env.num_points = 0; + } + instrument->vol_env.sustain_tick = instrument->vol_env.points_tick[ data_u8( data, offset + 227 ) & 0xF ]; + instrument->vol_env.loop_start_tick = instrument->vol_env.points_tick[ data_u8( data, offset + 228 ) & 0xF ]; + instrument->vol_env.loop_end_tick = instrument->vol_env.points_tick[ data_u8( data, offset + 229 ) & 0xF ]; + instrument->pan_env.sustain_tick = instrument->pan_env.points_tick[ data_u8( data, offset + 230 ) & 0xF ]; + instrument->pan_env.loop_start_tick = instrument->pan_env.points_tick[ data_u8( data, offset + 231 ) & 0xF ]; + instrument->pan_env.loop_end_tick = instrument->pan_env.points_tick[ data_u8( data, offset + 232 ) & 0xF ]; + instrument->vol_env.enabled = instrument->vol_env.num_points > 0 && ( data_u8( data, offset + 233 ) & 0x1 ); + instrument->vol_env.sustain = ( data_u8( data, offset + 233 ) & 0x2 ) > 0; + instrument->vol_env.looped = ( data_u8( data, offset + 233 ) & 0x4 ) > 0; + instrument->pan_env.enabled = instrument->pan_env.num_points > 0 && ( data_u8( data, offset + 234 ) & 0x1 ); + instrument->pan_env.sustain = ( data_u8( data, offset + 234 ) & 0x2 ) > 0; + instrument->pan_env.looped = ( data_u8( data, offset + 234 ) & 0x4 ) > 0; + instrument->vib_type = data_u8( data, offset + 235 ); + instrument->vib_sweep = data_u8( data, offset + 236 ); + instrument->vib_depth = data_u8( data, offset + 237 ); + instrument->vib_rate = data_u8( data, offset + 238 ); + instrument->vol_fadeout = data_u16le( data, offset + 239 ); + } + offset += data_u32le( data, offset ); + sam_head_offset = offset; + offset += num_samples * 40; + for( sam = 0; sam < num_samples; sam++ ) { + sample = &instrument->samples[ sam ]; + sam_data_bytes = data_u32le( data, sam_head_offset ); + sam_loop_start = data_u32le( data, sam_head_offset + 4 ); + sam_loop_length = data_u32le( data, sam_head_offset + 8 ); + sample->volume = data_u8( data, sam_head_offset + 12 ); + sample->fine_tune = data_s8( data, sam_head_offset + 13 ); + looped = ( data_u8( data, sam_head_offset + 14 ) & 0x3 ) > 0; + ping_pong = ( data_u8( data, sam_head_offset + 14 ) & 0x2 ) > 0; + sixteen_bit = ( data_u8( data, sam_head_offset + 14 ) & 0x10 ) > 0; + sample->panning = data_u8( data, sam_head_offset + 15 ) + 1; + sample->rel_note = data_s8( data, sam_head_offset + 16 ); + data_ascii( data, sam_head_offset + 18, 22, sample->name ); + sam_head_offset += 40; + sam_data_samples = sam_data_bytes; + if( sixteen_bit ) { + sam_data_samples = sam_data_samples >> 1; + sam_loop_start = sam_loop_start >> 1; + sam_loop_length = sam_loop_length >> 1; + } + if( !looped || ( sam_loop_start + sam_loop_length ) > sam_data_samples ) { + sam_loop_start = sam_data_samples; + sam_loop_length = 0; + } + sample->loop_start = sam_loop_start; + sample->loop_length = sam_loop_length; + sample->data = (short*)calloc( sam_data_samples + 1, sizeof( short ) ); + if( sample->data ) { + if( sixteen_bit ) { + data_sam_s16le( data, offset, sam_data_samples, sample->data ); + } else { + data_sam_s8( data, offset, sam_data_samples, sample->data ); + } + amp = 0; + for( idx = 0; idx < sam_data_samples; idx++ ) { + amp = amp + sample->data[ idx ]; + amp = ( amp & 0x7FFF ) - ( amp & 0x8000 ); + sample->data[ idx ] = amp; + } + sample->data[ sam_loop_start + sam_loop_length ] = sample->data[ sam_loop_start ]; + if( ping_pong ) { + sample_ping_pong( sample ); + } + } else { + dispose_module( module ); + return NULL; + } + offset += sam_data_bytes; + } + } + } + return module; +} + +static struct module* module_load_s3m( struct data *data, char *message ) { + int idx, module_data_idx, inst_offset, flags; + int version, sixteen_bit, tune, signed_samples; + int stereo_mode, default_pan, channel_map[ 32 ]; + int sample_offset, sample_length, loop_start, loop_length; + int pat_offset, note_offset, row, chan, token; + int key, ins, volume, effect, param, panning; + char *pattern_data; + struct instrument *instrument; + struct sample *sample; + struct module *module = (struct module*)calloc( 1, sizeof( struct module ) ); + if( module ) { + data_ascii( data, 0, 28, module->name ); + module->sequence_len = data_u16le( data, 32 ); + module->num_instruments = data_u16le( data, 34 ); + module->num_patterns = data_u16le( data, 36 ); + flags = data_u16le( data, 38 ); + version = data_u16le( data, 40 ); + module->fast_vol_slides = ( ( flags & 0x40 ) == 0x40 ) || version == 0x1300; + signed_samples = data_u16le( data, 42 ) == 1; + if( data_u32le( data, 44 ) != 0x4d524353 ) { + strcpy( message, "Not an S3M file!" ); + dispose_module( module ); + return NULL; + } + module->default_gvol = data_u8( data, 48 ); + module->default_speed = data_u8( data, 49 ); + module->default_tempo = data_u8( data, 50 ); + module->c2_rate = 8363; + module->gain = data_u8( data, 51 ) & 0x7F; + stereo_mode = ( data_u8( data, 51 ) & 0x80 ) == 0x80; + default_pan = data_u8( data, 53 ) == 0xFC; + for( idx = 0; idx < 32; idx++ ) { + channel_map[ idx ] = -1; + if( data_u8( data, 64 + idx ) < 16 ) { + channel_map[ idx ] = module->num_channels++; + } + } + module->sequence = (unsigned char*)calloc( module->sequence_len, sizeof( unsigned char ) ); + if( !module->sequence ){ + dispose_module( module ); + return NULL; + } + for( idx = 0; idx < module->sequence_len; idx++ ) { + module->sequence[ idx ] = data_u8( data, 96 + idx ); + } + module_data_idx = 96 + module->sequence_len; + module->instruments = (struct instrument*)calloc( module->num_instruments + 1, sizeof( struct instrument ) ); + if( !module->instruments ) { + dispose_module( module ); + return NULL; + } + instrument = &module->instruments[ 0 ]; + instrument->num_samples = 1; + instrument->samples = (struct sample*)calloc( 1, sizeof( struct sample ) ); + if( !instrument->samples ) { + dispose_module( module ); + return NULL; + } + for( ins = 1; ins <= module->num_instruments; ins++ ) { + instrument = &module->instruments[ ins ]; + instrument->num_samples = 1; + instrument->samples = (struct sample*)calloc( 1, sizeof( struct sample ) ); + if( !instrument->samples ) { + dispose_module( module ); + return NULL; + } + sample = &instrument->samples[ 0 ]; + inst_offset = data_u16le( data, module_data_idx ) << 4; + module_data_idx += 2; + data_ascii( data, inst_offset + 48, 28, instrument->name ); + if( data_u8( data, inst_offset ) == 1 && data_u16le( data, inst_offset + 76 ) == 0x4353 ) { + sample_offset = ( data_u8( data, inst_offset + 13 ) << 20 ) + + ( data_u16le( data, inst_offset + 14 ) << 4 ); + sample_length = data_u32le( data, inst_offset + 16 ); + loop_start = data_u32le( data, inst_offset + 20 ); + loop_length = data_u32le( data, inst_offset + 24 ) - loop_start; + sample->volume = data_u8( data, inst_offset + 28 ); + if( data_u8( data, inst_offset + 30 ) != 0 ) { + strcpy( message, "Packed samples not supported!" ); + dispose_module( module ); + return NULL; + } + if( loop_start + loop_length > sample_length ) { + loop_length = sample_length - loop_start; + } + if( loop_length < 1 || !( data_u8( data, inst_offset + 31 ) & 0x1 ) ) { + loop_start = sample_length; + loop_length = 0; + } + sample->loop_start = loop_start; + sample->loop_length = loop_length; + /* stereo = data_u8( data, inst_offset + 31 ) & 0x2; */ + sixteen_bit = data_u8( data, inst_offset + 31 ) & 0x4; + tune = ( log_2( data_u32le( data, inst_offset + 32 ) ) - log_2( module->c2_rate ) ) * 12; + sample->rel_note = tune >> FP_SHIFT; + sample->fine_tune = ( tune & FP_MASK ) >> ( FP_SHIFT - 7 ); + sample->data = (short*)calloc( sample_length + 1, sizeof( short ) ); + if( sample->data ) { + if( sixteen_bit ) { + data_sam_s16le( data, sample_offset, sample_length, sample->data ); + } else { + data_sam_s8( data, sample_offset, sample_length, sample->data ); + } + if( !signed_samples ) { + for( idx = 0; idx < sample_length; idx++ ) { + sample->data[ idx ] = ( sample->data[ idx ] & 0xFFFF ) - 32768; + } + } + sample->data[ loop_start + loop_length ] = sample->data[ loop_start ]; + } else { + dispose_module( module ); + return NULL; + } + } + } + module->patterns = (struct pattern*)calloc( module->num_patterns, sizeof( struct pattern ) ); + if( !module->patterns ) { + dispose_module( module ); + return NULL; + } + for( idx = 0; idx < module->num_patterns; idx++ ) { + module->patterns[ idx ].num_channels = module->num_channels; + module->patterns[ idx ].num_rows = 64; + pattern_data = (char*)calloc( module->num_channels * 64, 5 ); + if( !pattern_data ) { + dispose_module( module ); + return NULL; + } + module->patterns[ idx ].data = pattern_data; + pat_offset = ( data_u16le( data, module_data_idx ) << 4 ) + 2; + row = 0; + while( row < 64 ) { + token = data_u8( data, pat_offset++ ); + if( token ) { + key = ins = 0; + if( ( token & 0x20 ) == 0x20 ) { + /* Key + Instrument.*/ + key = data_u8( data, pat_offset++ ); + ins = data_u8( data, pat_offset++ ); + if( key < 0xFE ) { + key = ( key >> 4 ) * 12 + ( key & 0xF ) + 1; + } else if( key == 0xFF ) { + key = 0; + } + } + volume = 0; + if( ( token & 0x40 ) == 0x40 ) { + /* Volume Column.*/ + volume = ( data_u8( data, pat_offset++ ) & 0x7F ) + 0x10; + if( volume > 0x50 ) { + volume = 0; + } + } + effect = param = 0; + if( ( token & 0x80 ) == 0x80 ) { + /* Effect + Param.*/ + effect = data_u8( data, pat_offset++ ); + param = data_u8( data, pat_offset++ ); + if( effect < 1 || effect >= 0x40 ) { + effect = param = 0; + } else if( effect > 0 ) { + effect += 0x80; + } + } + chan = channel_map[ token & 0x1F ]; + if( chan >= 0 ) { + note_offset = ( row * module->num_channels + chan ) * 5; + pattern_data[ note_offset ] = key; + pattern_data[ note_offset + 1 ] = ins; + pattern_data[ note_offset + 2 ] = volume; + pattern_data[ note_offset + 3 ] = effect; + pattern_data[ note_offset + 4 ] = param; + } + } else { + row++; + } + } + module_data_idx += 2; + } + module->default_panning = (unsigned char*)calloc( module->num_channels, sizeof( unsigned char ) ); + if( module->default_panning ) { + for( chan = 0; chan < 32; chan++ ) { + if( channel_map[ chan ] >= 0 ) { + panning = 7; + if( stereo_mode ) { + panning = 12; + if( data_u8( data, 64 + chan ) < 8 ) { + panning = 3; + } + } + if( default_pan ) { + flags = data_u8( data, module_data_idx + chan ); + if( ( flags & 0x20 ) == 0x20 ) { + panning = flags & 0xF; + } + } + module->default_panning[ channel_map[ chan ] ] = panning * 17; + } + } + } else { + dispose_module( module ); + return NULL; + } + } + return module; +} + +static struct module* module_load_mod( struct data *data, char *message ) { + int idx, pat, module_data_idx, pat_data_len, pat_data_idx; + int period, key, ins, effect, param, fine_tune; + int sample_length, loop_start, loop_length; + char *pattern_data; + struct instrument *instrument; + struct sample *sample; + struct module *module = (struct module*)calloc( 1, sizeof( struct module ) ); + if( module ) { + data_ascii( data, 0, 20, module->name ); + module->sequence_len = data_u8( data, 950 ) & 0x7F; + module->restart_pos = data_u8( data, 951 ) & 0x7F; + if( module->restart_pos >= module->sequence_len ) { + module->restart_pos = 0; + } + module->sequence = (unsigned char*)calloc( 128, sizeof( unsigned char ) ); + if( !module->sequence ){ + dispose_module( module ); + return NULL; + } + for( idx = 0; idx < 128; idx++ ) { + pat = data_u8( data, 952 + idx ) & 0x7F; + module->sequence[ idx ] = pat; + if( pat >= module->num_patterns ) { + module->num_patterns = pat + 1; + } + } + switch( data_u16be( data, 1082 ) ) { + case 0x4b2e: /* M.K. */ + case 0x4b21: /* M!K! */ + case 0x5434: /* FLT4 */ + module->num_channels = 4; + module->c2_rate = 8287; + module->gain = 64; + break; + case 0x484e: /* xCHN */ + module->num_channels = data_u8( data, 1080 ) - 48; + module->c2_rate = 8363; + module->gain = 32; + break; + case 0x4348: /* xxCH */ + module->num_channels = ( data_u8( data, 1080 ) - 48 ) * 10; + module->num_channels += data_u8( data, 1081 ) - 48; + module->c2_rate = 8363; + module->gain = 32; + break; + default: + strcpy( message, "MOD Format not recognised!" ); + dispose_module( module ); + return NULL; + } + module->default_gvol = 64; + module->default_speed = 6; + module->default_tempo = 125; + module->default_panning = (unsigned char*)calloc( module->num_channels, sizeof( unsigned char ) ); + if( !module->default_panning ) { + dispose_module( module ); + return NULL; + } + for( idx = 0; idx < module->num_channels; idx++ ) { + module->default_panning[ idx ] = 51; + if( ( idx & 3 ) == 1 || ( idx & 3 ) == 2 ) { + module->default_panning[ idx ] = 204; + } + } + module_data_idx = 1084; + module->patterns = (struct pattern*)calloc( module->num_patterns, sizeof( struct pattern ) ); + if( !module->patterns ) { + dispose_module( module ); + return NULL; + } + pat_data_len = module->num_channels * 64 * 5; + for( pat = 0; pat < module->num_patterns; pat++ ) { + module->patterns[ pat ].num_channels = module->num_channels; + module->patterns[ pat ].num_rows = 64; + pattern_data = (char*)calloc( 1, pat_data_len ); + if( !pattern_data ) { + dispose_module( module ); + return NULL; + } + module->patterns[ pat ].data = pattern_data; + for( pat_data_idx = 0; pat_data_idx < pat_data_len; pat_data_idx += 5 ) { + period = ( data_u8( data, module_data_idx ) & 0xF ) << 8; + period = ( period | data_u8( data, module_data_idx + 1 ) ) * 4; + if( period >= 112 && period <= 6848 ) { + key = -12 * log_2( ( period << FP_SHIFT ) / 29021 ); + key = ( key + ( key & ( FP_ONE >> 1 ) ) ) >> FP_SHIFT; + pattern_data[ pat_data_idx ] = key; + } + ins = ( data_u8( data, module_data_idx + 2 ) & 0xF0 ) >> 4; + ins = ins | ( data_u8( data, module_data_idx ) & 0x10 ); + pattern_data[ pat_data_idx + 1 ] = ins; + effect = data_u8( data, module_data_idx + 2 ) & 0x0F; + param = data_u8( data, module_data_idx + 3 ); + if( param == 0 && ( effect < 3 || effect == 0xA ) ) { + effect = 0; + } + if( param == 0 && ( effect == 5 || effect == 6 ) ) { + effect -= 2; + } + if( effect == 8 && module->num_channels == 4 ) { + effect = param = 0; + } + pattern_data[ pat_data_idx + 3 ] = effect; + pattern_data[ pat_data_idx + 4 ] = param; + module_data_idx += 4; + } + } + module->num_instruments = 31; + module->instruments = (struct instrument*)calloc( module->num_instruments + 1, sizeof( struct instrument ) ); + if( !module->instruments ) { + dispose_module( module ); + return NULL; + } + instrument = &module->instruments[ 0 ]; + instrument->num_samples = 1; + instrument->samples = (struct sample*)calloc( 1, sizeof( struct sample ) ); + if( !instrument->samples ) { + dispose_module( module ); + return NULL; + } + for( ins = 1; ins <= module->num_instruments; ins++ ) { + instrument = &module->instruments[ ins ]; + instrument->num_samples = 1; + instrument->samples = (struct sample*)calloc( 1, sizeof( struct sample ) ); + if( !instrument->samples ) { + dispose_module( module ); + return NULL; + } + sample = &instrument->samples[ 0 ]; + data_ascii( data, ins * 30 - 10, 22, instrument->name ); + sample_length = data_u16be( data, ins * 30 + 12 ) * 2; + fine_tune = ( data_u8( data, ins * 30 + 14 ) & 0xF ) << 4; + sample->fine_tune = ( fine_tune & 0x7F ) - ( fine_tune & 0x80 ); + sample->volume = data_u8( data, ins * 30 + 15 ) & 0x7F; + if( sample->volume > 64 ) { + sample->volume = 64; + } + loop_start = data_u16be( data, ins * 30 + 16 ) * 2; + loop_length = data_u16be( data, ins * 30 + 18 ) * 2; + if( loop_start + loop_length > sample_length ) { + loop_length = sample_length - loop_start; + } + if( loop_length < 4 ) { + loop_start = sample_length; + loop_length = 0; + } + sample->loop_start = loop_start; + sample->loop_length = loop_length; + sample->data = (short*)calloc( sample_length + 1, sizeof( short ) ); + if( sample->data ) { + data_sam_s8( data, module_data_idx, sample_length, sample->data ); + sample->data[ loop_start + loop_length ] = sample->data[ loop_start ]; + } else { + dispose_module( module ); + return NULL; + } + module_data_idx += sample_length; + } + } + return module; +} + +/* Allocate and initialize a module from the specified data, returns NULL on error. + Message should point to a 64-character buffer to receive error messages. */ +struct module* module_load( struct data *data, char *message ) { + char ascii[ 16 ]; + struct module* module; + if( !memcmp( data_ascii( data, 0, 16, ascii ), "Extended Module:", 16 ) ) { + module = module_load_xm( data, message ); + } else if( !memcmp( data_ascii( data, 44, 4, ascii ), "SCRM", 4 ) ) { + module = module_load_s3m( data, message ); + } else { + module = module_load_mod( data, message ); + } + return module; +} + +static void pattern_get_note( struct pattern *pattern, int row, int chan, struct note *dest ) { + int offset = ( row * pattern->num_channels + chan ) * 5; + if( offset >= 0 && row < pattern->num_rows && chan < pattern->num_channels ) { + dest->key = pattern->data[ offset ]; + dest->instrument = pattern->data[ offset + 1 ]; + dest->volume = pattern->data[ offset + 2 ]; + dest->effect = pattern->data[ offset + 3 ]; + dest->param = pattern->data[ offset + 4 ]; + } else { + memset( dest, 0, sizeof( struct note ) ); + } +} + +static void channel_init( struct channel *channel, struct replay *replay, int idx ) { + memset( channel, 0, sizeof( struct channel ) ); + channel->replay = replay; + channel->id = idx; + channel->panning = replay->module->default_panning[ idx ]; + channel->instrument = &replay->module->instruments[ 0 ]; + channel->sample = &channel->instrument->samples[ 0 ]; + channel->random_seed = ( idx + 1 ) * 0xABCDEF; +} + +static void channel_volume_slide( struct channel *channel ) { + int up = channel->vol_slide_param >> 4; + int down = channel->vol_slide_param & 0xF; + if( down == 0xF && up > 0 ) { + /* Fine slide up.*/ + if( channel->fx_count == 0 ) { + channel->volume += up; + } + } else if( up == 0xF && down > 0 ) { + /* Fine slide down.*/ + if( channel->fx_count == 0 ) { + channel->volume -= down; + } + } else if( channel->fx_count > 0 || channel->replay->module->fast_vol_slides ) { + /* Normal.*/ + channel->volume += up - down; + } + if( channel->volume > 64 ) { + channel->volume = 64; + } + if( channel->volume < 0 ) { + channel->volume = 0; + } +} + +static void channel_porta_up( struct channel *channel, int param ) { + switch( param & 0xF0 ) { + case 0xE0: /* Extra-fine porta.*/ + if( channel->fx_count == 0 ) { + channel->period -= param & 0xF; + } + break; + case 0xF0: /* Fine porta.*/ + if( channel->fx_count == 0 ) { + channel->period -= ( param & 0xF ) << 2; + } + break; + default:/* Normal porta.*/ + if( channel->fx_count > 0 ) { + channel->period -= param << 2; + } + break; + } + if( channel->period < 0 ) { + channel->period = 0; + } +} + +static void channel_porta_down( struct channel *channel, int param ) { + if( channel->period > 0 ) { + switch( param & 0xF0 ) { + case 0xE0: /* Extra-fine porta.*/ + if( channel->fx_count == 0 ) { + channel->period += param & 0xF; + } + break; + case 0xF0: /* Fine porta.*/ + if( channel->fx_count == 0 ) { + channel->period += ( param & 0xF ) << 2; + } + break; + default:/* Normal porta.*/ + if( channel->fx_count > 0 ) { + channel->period += param << 2; + } + break; + } + if( channel->period > 65535 ) { + channel->period = 65535; + } + } +} + +static void channel_tone_porta( struct channel *channel ) { + if( channel->period > 0 ) { + if( channel->period < channel->porta_period ) { + channel->period += channel->tone_porta_param << 2; + if( channel->period > channel->porta_period ) { + channel->period = channel->porta_period; + } + } else { + channel->period -= channel->tone_porta_param << 2; + if( channel->period < channel->porta_period ) { + channel->period = channel->porta_period; + } + } + } +} + +static int channel_waveform( struct channel *channel, int phase, int type ) { + int amplitude = 0; + switch( type ) { + default: /* Sine. */ + amplitude = sine_table[ phase & 0x1F ]; + if( ( phase & 0x20 ) > 0 ) { + amplitude = -amplitude; + } + break; + case 6: /* Saw Up.*/ + amplitude = ( ( ( phase + 0x20 ) & 0x3F ) << 3 ) - 255; + break; + case 1: case 7: /* Saw Down. */ + amplitude = 255 - ( ( ( phase + 0x20 ) & 0x3F ) << 3 ); + break; + case 2: case 5: /* Square. */ + amplitude = ( phase & 0x20 ) > 0 ? 255 : -255; + break; + case 3: case 8: /* Random. */ + amplitude = ( channel->random_seed >> 20 ) - 255; + channel->random_seed = ( channel->random_seed * 65 + 17 ) & 0x1FFFFFFF; + break; + } + return amplitude; +} + +static void channel_vibrato( struct channel *channel, int fine ) { + int wave = channel_waveform( channel, channel->vibrato_phase, channel->vibrato_type & 0x3 ); + channel->vibrato_add = wave * channel->vibrato_depth >> ( fine ? 7 : 5 ); +} + +static void channel_tremolo( struct channel *channel ) { + int wave = channel_waveform( channel, channel->tremolo_phase, channel->tremolo_type & 0x3 ); + channel->tremolo_add = wave * channel->tremolo_depth >> 6; +} + +static void channel_tremor( struct channel *channel ) { + if( channel->retrig_count >= channel->tremor_on_ticks ) { + channel->tremolo_add = -64; + } + if( channel->retrig_count >= ( channel->tremor_on_ticks + channel->tremor_off_ticks ) ) { + channel->tremolo_add = channel->retrig_count = 0; + } +} + +static void channel_retrig_vol_slide( struct channel *channel ) { + if( channel->retrig_count >= channel->retrig_ticks ) { + channel->retrig_count = channel->sample_idx = channel->sample_fra = 0; + switch( channel->retrig_volume ) { + case 0x1: channel->volume = channel->volume - 1; break; + case 0x2: channel->volume = channel->volume - 2; break; + case 0x3: channel->volume = channel->volume - 4; break; + case 0x4: channel->volume = channel->volume - 8; break; + case 0x5: channel->volume = channel->volume - 16; break; + case 0x6: channel->volume = channel->volume * 2 / 3; break; + case 0x7: channel->volume = channel->volume >> 1; break; + case 0x8: /* ? */ break; + case 0x9: channel->volume = channel->volume + 1; break; + case 0xA: channel->volume = channel->volume + 2; break; + case 0xB: channel->volume = channel->volume + 4; break; + case 0xC: channel->volume = channel->volume + 8; break; + case 0xD: channel->volume = channel->volume + 16; break; + case 0xE: channel->volume = channel->volume * 3 / 2; break; + case 0xF: channel->volume = channel->volume << 1; break; + } + if( channel->volume < 0 ) { + channel->volume = 0; + } + if( channel->volume > 64 ) { + channel->volume = 64; + } + } +} + +static void channel_trigger( struct channel *channel ) { + int key, sam, porta, period, fine_tune, ins = channel->note.instrument; + struct sample *sample; + if( ins > 0 && ins <= channel->replay->module->num_instruments ) { + channel->instrument = &channel->replay->module->instruments[ ins ]; + key = channel->note.key < 97 ? channel->note.key : 0; + sam = channel->instrument->key_to_sample[ key ]; + sample = &channel->instrument->samples[ sam ]; + channel->volume = sample->volume >= 64 ? 64 : sample->volume & 0x3F; + if( sample->panning > 0 ) { + channel->panning = ( sample->panning - 1 ) & 0xFF; + } + if( channel->period > 0 && sample->loop_length > 1 ) { + /* Amiga trigger.*/ + channel->sample = sample; + } + channel->sample_off = 0; + channel->vol_env_tick = channel->pan_env_tick = 0; + channel->fadeout_vol = 32768; + channel->key_on = 1; + } + if( channel->note.effect == 0x09 || channel->note.effect == 0x8F ) { + /* Set Sample Offset. */ + if( channel->note.param > 0 ) { + channel->offset_param = channel->note.param; + } + channel->sample_off = channel->offset_param << 8; + } + if( channel->note.volume >= 0x10 && channel->note.volume < 0x60 ) { + channel->volume = channel->note.volume < 0x50 ? channel->note.volume - 0x10 : 64; + } + switch( channel->note.volume & 0xF0 ) { + case 0x80: /* Fine Vol Down.*/ + channel->volume -= channel->note.volume & 0xF; + if( channel->volume < 0 ) { + channel->volume = 0; + } + break; + case 0x90: /* Fine Vol Up.*/ + channel->volume += channel->note.volume & 0xF; + if( channel->volume > 64 ) { + channel->volume = 64; + } + break; + case 0xA0: /* Set Vibrato Speed.*/ + if( ( channel->note.volume & 0xF ) > 0 ) { + channel->vibrato_speed = channel->note.volume & 0xF; + } + break; + case 0xB0: /* Vibrato.*/ + if( ( channel->note.volume & 0xF ) > 0 ) { + channel->vibrato_depth = channel->note.volume & 0xF; + } + channel_vibrato( channel, 0 ); + break; + case 0xC0: /* Set Panning.*/ + channel->panning = ( channel->note.volume & 0xF ) * 17; + break; + case 0xF0: /* Tone Porta.*/ + if( ( channel->note.volume & 0xF ) > 0 ) { + channel->tone_porta_param = channel->note.volume & 0xF; + } + break; + } + if( channel->note.key > 0 ) { + if( channel->note.key > 96 ) { + channel->key_on = 0; + } else { + porta = ( channel->note.volume & 0xF0 ) == 0xF0 || + channel->note.effect == 0x03 || channel->note.effect == 0x05 || + channel->note.effect == 0x87 || channel->note.effect == 0x8C; + if( !porta ) { + ins = channel->instrument->key_to_sample[ channel->note.key ]; + channel->sample = &channel->instrument->samples[ ins ]; + } + fine_tune = channel->sample->fine_tune; + if( channel->note.effect == 0x75 || channel->note.effect == 0xF2 ) { + /* Set Fine Tune. */ + fine_tune = ( ( channel->note.param & 0xF ) << 4 ) - 128; + } + key = channel->note.key + channel->sample->rel_note; + if( key < 1 ) { + key = 1; + } + if( key > 120 ) { + key = 120; + } + period = ( key << 6 ) + ( fine_tune >> 1 ); + if( channel->replay->module->linear_periods ) { + channel->porta_period = 7744 - period; + } else { + channel->porta_period = 29021 * exp_2( ( period << FP_SHIFT ) / -768 ) >> FP_SHIFT; + } + if( !porta ) { + channel->period = channel->porta_period; + channel->sample_idx = channel->sample_off; + channel->sample_fra = 0; + if( channel->vibrato_type < 4 ) { + channel->vibrato_phase = 0; + } + if( channel->tremolo_type < 4 ) { + channel->tremolo_phase = 0; + } + channel->retrig_count = channel->av_count = 0; + } + } + } +} + +static void channel_update_envelopes( struct channel *channel ) { + if( channel->instrument->vol_env.enabled ) { + if( !channel->key_on ) { + channel->fadeout_vol -= channel->instrument->vol_fadeout; + if( channel->fadeout_vol < 0 ) { + channel->fadeout_vol = 0; + } + } + channel->vol_env_tick = envelope_next_tick( &channel->instrument->vol_env, + channel->vol_env_tick, channel->key_on ); + } + if( channel->instrument->pan_env.enabled ) { + channel->pan_env_tick = envelope_next_tick( &channel->instrument->pan_env, + channel->pan_env_tick, channel->key_on ); + } +} + +static void channel_auto_vibrato( struct channel *channel ) { + int sweep, rate, type, wave; + int depth = channel->instrument->vib_depth & 0x7F; + if( depth > 0 ) { + sweep = channel->instrument->vib_sweep & 0x7F; + rate = channel->instrument->vib_rate & 0x7F; + type = channel->instrument->vib_type; + if( channel->av_count < sweep ) { + depth = depth * channel->av_count / sweep; + } + wave = channel_waveform( channel, channel->av_count * rate >> 2, type + 4 ); + channel->vibrato_add += wave * depth >> 8; + channel->av_count++; + } +} + +static void channel_calculate_freq( struct channel *channel ) { + int per = channel->period + channel->vibrato_add; + if( channel->replay->module->linear_periods ) { + per = per - ( channel->arpeggio_add << 6 ); + if( per < 28 || per > 7680 ) { + per = 7680; + } + channel->freq = ( ( channel->replay->module->c2_rate >> 4 ) + * exp_2( ( ( 4608 - per ) << FP_SHIFT ) / 768 ) ) >> ( FP_SHIFT - 4 ); + } else { + if( per > 29021 ) { + per = 29021; + } + per = ( per << FP_SHIFT ) / exp_2( ( channel->arpeggio_add << FP_SHIFT ) / 12 ); + if( per < 28 ) { + per = 29021; + } + channel->freq = channel->replay->module->c2_rate * 1712 / per; + } +} + +static void channel_calculate_ampl( struct channel *channel ) { + int vol, range, env_pan = 32, env_vol = channel->key_on ? 64 : 0; + if( channel->instrument->vol_env.enabled ) { + env_vol = envelope_calculate_ampl( &channel->instrument->vol_env, channel->vol_env_tick ); + } + vol = channel->volume + channel->tremolo_add; + if( vol > 64 ) { + vol = 64; + } + if( vol < 0 ) { + vol = 0; + } + vol = ( vol * channel->replay->module->gain * FP_ONE ) >> 13; + vol = ( vol * channel->fadeout_vol ) >> 15; + channel->ampl = ( vol * channel->replay->global_vol * env_vol ) >> 12; + if( channel->instrument->pan_env.enabled ) { + env_pan = envelope_calculate_ampl( &channel->instrument->pan_env, channel->pan_env_tick ); + } + range = ( channel->panning < 128 ) ? channel->panning : ( 255 - channel->panning ); + channel->pann = channel->panning + ( range * ( env_pan - 32 ) >> 5 ); +} + +static void channel_tick( struct channel *channel ) { + channel->vibrato_add = 0; + channel->fx_count++; + channel->retrig_count++; + if( !( channel->note.effect == 0x7D && channel->fx_count <= channel->note.param ) ) { + switch( channel->note.volume & 0xF0 ) { + case 0x60: /* Vol Slide Down.*/ + channel->volume -= channel->note.volume & 0xF; + if( channel->volume < 0 ) { + channel->volume = 0; + } + break; + case 0x70: /* Vol Slide Up.*/ + channel->volume += channel->note.volume & 0xF; + if( channel->volume > 64 ) { + channel->volume = 64; + } + break; + case 0xB0: /* Vibrato.*/ + channel->vibrato_phase += channel->vibrato_speed; + channel_vibrato( channel, 0 ); + break; + case 0xD0: /* Pan Slide Left.*/ + channel->panning -= channel->note.volume & 0xF; + if( channel->panning < 0 ) { + channel->panning = 0; + } + break; + case 0xE0: /* Pan Slide Right.*/ + channel->panning += channel->note.volume & 0xF; + if( channel->panning > 255 ) { + channel->panning = 255; + } + break; + case 0xF0: /* Tone Porta.*/ + channel_tone_porta( channel ); + break; + } + } + switch( channel->note.effect ) { + case 0x01: case 0x86: /* Porta Up. */ + channel_porta_up( channel, channel->porta_up_param ); + break; + case 0x02: case 0x85: /* Porta Down. */ + channel_porta_down( channel, channel->porta_down_param ); + break; + case 0x03: case 0x87: /* Tone Porta. */ + channel_tone_porta( channel ); + break; + case 0x04: case 0x88: /* Vibrato. */ + channel->vibrato_phase += channel->vibrato_speed; + channel_vibrato( channel, 0 ); + break; + case 0x05: case 0x8C: /* Tone Porta + Vol Slide. */ + channel_tone_porta( channel ); + channel_volume_slide( channel ); + break; + case 0x06: case 0x8B: /* Vibrato + Vol Slide. */ + channel->vibrato_phase += channel->vibrato_speed; + channel_vibrato( channel, 0 ); + channel_volume_slide( channel ); + break; + case 0x07: case 0x92: /* Tremolo. */ + channel->tremolo_phase += channel->tremolo_speed; + channel_tremolo( channel ); + break; + case 0x0A: case 0x84: /* Vol Slide. */ + channel_volume_slide( channel ); + break; + case 0x11: /* Global Volume Slide. */ + channel->replay->global_vol = channel->replay->global_vol + + ( channel->gvol_slide_param >> 4 ) + - ( channel->gvol_slide_param & 0xF ); + if( channel->replay->global_vol < 0 ) { + channel->replay->global_vol = 0; + } + if( channel->replay->global_vol > 64 ) { + channel->replay->global_vol = 64; + } + break; + case 0x19: /* Panning Slide. */ + channel->panning = channel->panning + + ( channel->pan_slide_param >> 4 ) + - ( channel->pan_slide_param & 0xF ); + if( channel->panning < 0 ) { + channel->panning = 0; + } + if( channel->panning > 255 ) { + channel->panning = 255; + } + break; + case 0x1B: case 0x91: /* Retrig + Vol Slide. */ + channel_retrig_vol_slide( channel ); + break; + case 0x1D: case 0x89: /* Tremor. */ + channel_tremor( channel ); + break; + case 0x79: /* Retrig. */ + if( channel->fx_count >= channel->note.param ) { + channel->fx_count = 0; + channel->sample_idx = channel->sample_fra = 0; + } + break; + case 0x7C: case 0xFC: /* Note Cut. */ + if( channel->note.param == channel->fx_count ) { + channel->volume = 0; + } + break; + case 0x7D: case 0xFD: /* Note Delay. */ + if( channel->note.param == channel->fx_count ) { + channel_trigger( channel ); + } + break; + case 0x8A: /* Arpeggio. */ + if( channel->fx_count == 1 ) { + channel->arpeggio_add = channel->arpeggio_param >> 4; + } else if( channel->fx_count == 2 ) { + channel->arpeggio_add = channel->arpeggio_param & 0xF; + } else { + channel->arpeggio_add = channel->fx_count = 0; + } + break; + case 0x95: /* Fine Vibrato. */ + channel->vibrato_phase += channel->vibrato_speed; + channel_vibrato( channel, 1 ); + break; + } + channel_auto_vibrato( channel ); + channel_calculate_freq( channel ); + channel_calculate_ampl( channel ); + channel_update_envelopes( channel ); +} + +static void channel_row( struct channel *channel, struct note *note ) { + channel->note = *note; + channel->retrig_count++; + channel->vibrato_add = channel->tremolo_add = channel->arpeggio_add = channel->fx_count = 0; + if( !( ( note->effect == 0x7D || note->effect == 0xFD ) && note->param > 0 ) ) { + /* Not note delay.*/ + channel_trigger( channel ); + } + switch( channel->note.effect ) { + case 0x01: case 0x86: /* Porta Up. */ + if( channel->note.param > 0 ) { + channel->porta_up_param = channel->note.param; + } + channel_porta_up( channel, channel->porta_up_param ); + break; + case 0x02: case 0x85: /* Porta Down. */ + if( channel->note.param > 0 ) { + channel->porta_down_param = channel->note.param; + } + channel_porta_down( channel, channel->porta_down_param ); + break; + case 0x03: case 0x87: /* Tone Porta. */ + if( channel->note.param > 0 ) { + channel->tone_porta_param = channel->note.param; + } + break; + case 0x04: case 0x88: /* Vibrato. */ + if( ( channel->note.param >> 4 ) > 0 ) { + channel->vibrato_speed = channel->note.param >> 4; + } + if( ( channel->note.param & 0xF ) > 0 ) { + channel->vibrato_depth = channel->note.param & 0xF; + } + channel_vibrato( channel, 0 ); + break; + case 0x05: case 0x8C: /* Tone Porta + Vol Slide. */ + if( channel->note.param > 0 ) { + channel->vol_slide_param = channel->note.param; + } + channel_volume_slide( channel ); + break; + case 0x06: case 0x8B: /* Vibrato + Vol Slide. */ + if( channel->note.param > 0 ) { + channel->vol_slide_param = channel->note.param; + } + channel_vibrato( channel, 0 ); + channel_volume_slide( channel ); + break; + case 0x07: case 0x92: /* Tremolo. */ + if( ( channel->note.param >> 4 ) > 0 ) { + channel->tremolo_speed = channel->note.param >> 4; + } + if( ( channel->note.param & 0xF ) > 0 ) { + channel->tremolo_depth = channel->note.param & 0xF; + } + channel_tremolo( channel ); + break; + case 0x08: /* Set Panning.*/ + channel->panning = ( channel->note.param < 128 ) ? ( channel->note.param << 1 ) : 255; + break; + case 0x0A: case 0x84: /* Vol Slide. */ + if( channel->note.param > 0 ) { + channel->vol_slide_param = channel->note.param; + } + channel_volume_slide( channel ); + break; + case 0x0C: /* Set Volume. */ + channel->volume = channel->note.param >= 64 ? 64 : channel->note.param & 0x3F; + break; + case 0x10: case 0x96: /* Set Global Volume. */ + channel->replay->global_vol = channel->note.param >= 64 ? 64 : channel->note.param & 0x3F; + break; + case 0x11: /* Global Volume Slide. */ + if( channel->note.param > 0 ) { + channel->gvol_slide_param = channel->note.param; + } + break; + case 0x14: /* Key Off. */ + channel->key_on = 0; + break; + case 0x15: /* Set Envelope Tick. */ + channel->vol_env_tick = channel->pan_env_tick = channel->note.param & 0xFF; + break; + case 0x19: /* Panning Slide. */ + if( channel->note.param > 0 ) { + channel->pan_slide_param = channel->note.param; + } + break; + case 0x1B: case 0x91: /* Retrig + Vol Slide. */ + if( ( channel->note.param >> 4 ) > 0 ) { + channel->retrig_volume = channel->note.param >> 4; + } + if( ( channel->note.param & 0xF ) > 0 ) { + channel->retrig_ticks = channel->note.param & 0xF; + } + channel_retrig_vol_slide( channel ); + break; + case 0x1D: case 0x89: /* Tremor. */ + if( ( channel->note.param >> 4 ) > 0 ) { + channel->tremor_on_ticks = channel->note.param >> 4; + } + if( ( channel->note.param & 0xF ) > 0 ) { + channel->tremor_off_ticks = channel->note.param & 0xF; + } + channel_tremor( channel ); + break; + case 0x21: /* Extra Fine Porta. */ + if( channel->note.param > 0 ) { + channel->xfine_porta_param = channel->note.param; + } + switch( channel->xfine_porta_param & 0xF0 ) { + case 0x10: + channel_porta_up( channel, 0xE0 | ( channel->xfine_porta_param & 0xF ) ); + break; + case 0x20: + channel_porta_down( channel, 0xE0 | ( channel->xfine_porta_param & 0xF ) ); + break; + } + break; + case 0x71: /* Fine Porta Up. */ + if( channel->note.param > 0 ) { + channel->fine_porta_up_param = channel->note.param; + } + channel_porta_up( channel, 0xF0 | ( channel->fine_porta_up_param & 0xF ) ); + break; + case 0x72: /* Fine Porta Down. */ + if( channel->note.param > 0 ) { + channel->fine_porta_down_param = channel->note.param; + } + channel_porta_down( channel, 0xF0 | ( channel->fine_porta_down_param & 0xF ) ); + break; + case 0x74: case 0xF3: /* Set Vibrato Waveform. */ + if( channel->note.param < 8 ) { + channel->vibrato_type = channel->note.param; + } + break; + case 0x77: case 0xF4: /* Set Tremolo Waveform. */ + if( channel->note.param < 8 ) { + channel->tremolo_type = channel->note.param; + } + break; + case 0x7A: /* Fine Vol Slide Up. */ + if( channel->note.param > 0 ) { + channel->fine_vslide_up_param = channel->note.param; + } + channel->volume += channel->fine_vslide_up_param; + if( channel->volume > 64 ) { + channel->volume = 64; + } + break; + case 0x7B: /* Fine Vol Slide Down. */ + if( channel->note.param > 0 ) { + channel->fine_vslide_down_param = channel->note.param; + } + channel->volume -= channel->fine_vslide_down_param; + if( channel->volume < 0 ) { + channel->volume = 0; + } + break; + case 0x7C: case 0xFC: /* Note Cut. */ + if( channel->note.param <= 0 ) { + channel->volume = 0; + } + break; + case 0x8A: /* Arpeggio. */ + if( channel->note.param > 0 ) { + channel->arpeggio_param = channel->note.param; + } + break; + case 0x95: /* Fine Vibrato.*/ + if( ( channel->note.param >> 4 ) > 0 ) { + channel->vibrato_speed = channel->note.param >> 4; + } + if( ( channel->note.param & 0xF ) > 0 ) { + channel->vibrato_depth = channel->note.param & 0xF; + } + channel_vibrato( channel, 1 ); + break; + case 0xF8: /* Set Panning. */ + channel->panning = channel->note.param * 17; + break; + } + channel_auto_vibrato( channel ); + channel_calculate_freq( channel ); + channel_calculate_ampl( channel ); + channel_update_envelopes( channel ); +} + +static void channel_resample( struct channel *channel, int *mix_buf, + int offset, int count, int sample_rate, int interpolate ) { + struct sample *sample = channel->sample; + int l_gain, r_gain, sam_idx, sam_fra, step; + int loop_len, loop_end, out_idx, out_end, y, m, c; + short *sample_data = channel->sample->data; + if( channel->ampl > 0 ) { + l_gain = channel->ampl * ( 255 - channel->pann ) >> 8; + r_gain = channel->ampl * channel->pann >> 8; + sam_idx = channel->sample_idx; + sam_fra = channel->sample_fra; + step = ( channel->freq << ( FP_SHIFT - 3 ) ) / ( sample_rate >> 3 ); + loop_len = sample->loop_length; + loop_end = sample->loop_start + loop_len; + out_idx = offset * 2; + out_end = ( offset + count ) * 2; + if( interpolate ) { + while( out_idx < out_end ) { + if( sam_idx >= loop_end ) { + if( loop_len > 1 ) { + while( sam_idx >= loop_end ) { + sam_idx -= loop_len; + } + } else { + break; + } + } + c = sample_data[ sam_idx ]; + m = sample_data[ sam_idx + 1 ] - c; + y = ( ( m * sam_fra ) >> FP_SHIFT ) + c; + mix_buf[ out_idx++ ] += ( y * l_gain ) >> FP_SHIFT; + mix_buf[ out_idx++ ] += ( y * r_gain ) >> FP_SHIFT; + sam_fra += step; + sam_idx += sam_fra >> FP_SHIFT; + sam_fra &= FP_MASK; + } + } else { + while( out_idx < out_end ) { + if( sam_idx >= loop_end ) { + if( loop_len > 1 ) { + while( sam_idx >= loop_end ) { + sam_idx -= loop_len; + } + } else { + break; + } + } + y = sample_data[ sam_idx ]; + mix_buf[ out_idx++ ] += ( y * l_gain ) >> FP_SHIFT; + mix_buf[ out_idx++ ] += ( y * r_gain ) >> FP_SHIFT; + sam_fra += step; + sam_idx += sam_fra >> FP_SHIFT; + sam_fra &= FP_MASK; + } + } + } +} + +static void channel_update_sample_idx( struct channel *channel, int count, int sample_rate ) { + struct sample *sample = channel->sample; + int step = ( channel->freq << ( FP_SHIFT - 3 ) ) / ( sample_rate >> 3 ); + channel->sample_fra += step * count; + channel->sample_idx += channel->sample_fra >> FP_SHIFT; + if( channel->sample_idx > sample->loop_start ) { + if( sample->loop_length > 1 ) { + channel->sample_idx = sample->loop_start + + ( channel->sample_idx - sample->loop_start ) % sample->loop_length; + } else { + channel->sample_idx = sample->loop_start; + } + } + channel->sample_fra &= FP_MASK; +} + +static void replay_row( struct replay *replay ) { + int idx, count; + struct note note; + struct pattern *pattern; + struct channel *channel; + struct module *module = replay->module; + if( replay->next_row < 0 ) { + replay->break_pos = replay->seq_pos + 1; + replay->next_row = 0; + } + if( replay->break_pos >= 0 ) { + if( replay->break_pos >= module->sequence_len ) { + replay->break_pos = replay->next_row = 0; + } + while( module->sequence[ replay->break_pos ] >= module->num_patterns ) { + replay->break_pos++; + if( replay->break_pos >= module->sequence_len ) { + replay->break_pos = replay->next_row = 0; + } + } + replay->seq_pos = replay->break_pos; + for( idx = 0; idx < module->num_channels; idx++ ) { + replay->channels[ idx ].pl_row = 0; + } + replay->break_pos = -1; + } + pattern = &module->patterns[ module->sequence[ replay->seq_pos ] ]; + replay->row = replay->next_row; + if( replay->row >= pattern->num_rows ) { + replay->row = 0; + } + if( replay->play_count && replay->play_count[ 0 ] ) { + count = replay->play_count[ replay->seq_pos ][ replay->row ]; + if( replay->pl_count < 0 && count < 127 ) { + replay->play_count[ replay->seq_pos ][ replay->row ] = count + 1; + } + } + replay->next_row = replay->row + 1; + if( replay->next_row >= pattern->num_rows ) { + replay->next_row = -1; + } + for( idx = 0; idx < module->num_channels; idx++ ) { + channel = &replay->channels[ idx ]; + pattern_get_note( pattern, replay->row, idx, ¬e ); + if( note.effect == 0xE ) { + note.effect = 0x70 | ( note.param >> 4 ); + note.param &= 0xF; + } + if( note.effect == 0x93 ) { + note.effect = 0xF0 | ( note.param >> 4 ); + note.param &= 0xF; + } + if( note.effect == 0 && note.param > 0 ) { + note.effect = 0x8A; + } + channel_row( channel, ¬e ); + switch( note.effect ) { + case 0x81: /* Set Speed. */ + if( note.param > 0 ) { + replay->tick = replay->speed = note.param; + } + break; + case 0xB: case 0x82: /* Pattern Jump.*/ + if( replay->pl_count < 0 ) { + replay->break_pos = note.param; + replay->next_row = 0; + } + break; + case 0xD: case 0x83: /* Pattern Break.*/ + if( replay->pl_count < 0 ) { + if( replay->break_pos < 0 ) { + replay->break_pos = replay->seq_pos + 1; + } + replay->next_row = ( note.param >> 4 ) * 10 + ( note.param & 0xF ); + } + break; + case 0xF: /* Set Speed/Tempo.*/ + if( note.param > 0 ) { + if( note.param < 32 ) { + replay->tick = replay->speed = note.param; + } else { + replay->tempo = note.param; + } + } + break; + case 0x94: /* Set Tempo.*/ + if( note.param > 32 ) { + replay->tempo = note.param; + } + break; + case 0x76: case 0xFB : /* Pattern Loop.*/ + if( note.param == 0 ) { + /* Set loop marker on this channel. */ + channel->pl_row = replay->row; + } + if( channel->pl_row < replay->row && replay->break_pos < 0 ) { + /* Marker valid. */ + if( replay->pl_count < 0 ) { + /* Not already looping, begin. */ + replay->pl_count = note.param; + replay->pl_chan = idx; + } + if( replay->pl_chan == idx ) { + /* Next Loop.*/ + if( replay->pl_count == 0 ) { + /* Loop finished. Invalidate current marker. */ + channel->pl_row = replay->row + 1; + } else { + /* Loop. */ + replay->next_row = channel->pl_row; + } + replay->pl_count--; + } + } + break; + case 0x7E: case 0xFE: /* Pattern Delay.*/ + replay->tick = replay->speed + replay->speed * note.param; + break; + } + } +} + +static int replay_tick( struct replay *replay ) { + int idx, num_channels, count = 1; + if( --replay->tick <= 0 ) { + replay->tick = replay->speed; + replay_row( replay ); + } else { + num_channels = replay->module->num_channels; + for( idx = 0; idx < num_channels; idx++ ) { + channel_tick( &replay->channels[ idx ] ); + } + } + if( replay->play_count && replay->play_count[ 0 ] ) { + count = replay->play_count[ replay->seq_pos ][ replay->row ] - 1; + } + return count; +} + +static int module_init_play_count( struct module *module, char **play_count ) { + int idx, pat, rows, len = 0; + for( idx = 0; idx < module->sequence_len; idx++ ) { + pat = module->sequence[ idx ]; + rows = ( pat < module->num_patterns ) ? module->patterns[ pat ].num_rows : 0; + if( play_count ) { + play_count[ idx ] = play_count[ 0 ] ? &play_count[ 0 ][ len ] : NULL; + } + len += rows; + } + return len; +} + +/* Set the pattern in the sequence to play. The tempo is reset to the default. */ +void replay_set_sequence_pos( struct replay *replay, int pos ) { + int idx; + struct module *module = replay->module; + if( pos >= module->sequence_len ) { + pos = 0; + } + replay->break_pos = pos; + replay->next_row = 0; + replay->tick = 1; + replay->global_vol = module->default_gvol; + replay->speed = module->default_speed > 0 ? module->default_speed : 6; + replay->tempo = module->default_tempo > 0 ? module->default_tempo : 125; + replay->pl_count = replay->pl_chan = -1; + if( replay->play_count ) { + free( replay->play_count[ 0 ] ); + free( replay->play_count ); + } + replay->play_count = (char**)calloc( module->sequence_len, sizeof( char * ) ); + if( replay->play_count ) { + replay->play_count[ 0 ] = (char*)calloc( module_init_play_count( module, NULL ), sizeof( char ) ); + module_init_play_count( module, replay->play_count ); + } + for( idx = 0; idx < module->num_channels; idx++ ) { + channel_init( &replay->channels[ idx ], replay, idx ); + } + memset( replay->ramp_buf, 0, 128 * sizeof( int ) ); + replay_tick( replay ); +} + +/* Deallocate the specified replay. */ +void dispose_replay( struct replay *replay ) { + if( replay->play_count ) { + free( replay->play_count[ 0 ] ); + free( replay->play_count ); + } + free( replay->ramp_buf ); + free( replay->channels ); + free( replay ); +} + +/* Allocate and initialize a replay with the specified sampling rate and interpolation. */ +struct replay* new_replay( struct module *module, int sample_rate, int interpolation ) { + struct replay *replay = (struct replay*)calloc( 1, sizeof( struct replay ) ); + if( replay ) { + replay->module = module; + replay->sample_rate = sample_rate; + replay->interpolation = interpolation; + replay->ramp_buf = (int*)calloc( 128, sizeof( int ) ); + replay->channels = (struct channel*)calloc( module->num_channels, sizeof( struct channel ) ); + if( replay->ramp_buf && replay->channels ) { + replay_set_sequence_pos( replay, 0 ); + } else { + dispose_replay( replay ); + replay = NULL; + } + } + return replay; +} + +static int calculate_tick_len( int tempo, int sample_rate ) { + return ( sample_rate * 5 ) / ( tempo * 2 ); +} + +/* Returns the length of the output buffer required by replay_get_audio(). */ +int calculate_mix_buf_len( int sample_rate ) { + return ( calculate_tick_len( 32, sample_rate ) + 65 ) * 4; +} + +/* Returns the song duration in samples at the current sampling rate. */ +int replay_calculate_duration( struct replay *replay ) { + int count = 0, duration = 0; + replay_set_sequence_pos( replay, 0 ); + while( count < 1 ) { + duration += calculate_tick_len( replay->tempo, replay->sample_rate ); + count = replay_tick( replay ); + } + replay_set_sequence_pos( replay, 0 ); + return duration; +} + +/* Seek to approximately the specified sample position. + The actual sample position reached is returned. */ +int replay_seek( struct replay *replay, int sample_pos ) { + int idx, tick_len, current_pos = 0; + replay_set_sequence_pos( replay, 0 ); + tick_len = calculate_tick_len( replay->tempo, replay->sample_rate ); + while( ( sample_pos - current_pos ) >= tick_len ) { + for( idx = 0; idx < replay->module->num_channels; idx++ ) { + channel_update_sample_idx( &replay->channels[ idx ], + tick_len * 2, replay->sample_rate * 2 ); + } + current_pos += tick_len; + replay_tick( replay ); + tick_len = calculate_tick_len( replay->tempo, replay->sample_rate ); + } + return current_pos; +} + +static void replay_volume_ramp( struct replay *replay, int *mix_buf, int tick_len ) { + int idx, a1, a2, ramp_rate = 256 * 2048 / replay->sample_rate; + for( idx = 0, a1 = 0; a1 < 256; idx += 2, a1 += ramp_rate ) { + a2 = 256 - a1; + mix_buf[ idx ] = ( mix_buf[ idx ] * a1 + replay->ramp_buf[ idx ] * a2 ) >> 8; + mix_buf[ idx + 1 ] = ( mix_buf[ idx + 1 ] * a1 + replay->ramp_buf[ idx + 1 ] * a2 ) >> 8; + } + memcpy( replay->ramp_buf, &mix_buf[ tick_len * 2 ], 128 * sizeof( int ) ); +} + +/* 2:1 downsampling with simple but effective anti-aliasing. Buf must contain count * 2 + 1 stereo samples. */ +static void downsample( int *buf, int count ) { + int idx, out_idx, out_len = count * 2; + for( idx = 0, out_idx = 0; out_idx < out_len; idx += 4, out_idx += 2 ) { + buf[ out_idx ] = ( buf[ idx ] >> 2 ) + ( buf[ idx + 2 ] >> 1 ) + ( buf[ idx + 4 ] >> 2 ); + buf[ out_idx + 1 ] = ( buf[ idx + 1 ] >> 2 ) + ( buf[ idx + 3 ] >> 1 ) + ( buf[ idx + 5 ] >> 2 ); + } +} + +/* Generates audio and returns the number of stereo samples written into mix_buf. */ +int replay_get_audio( struct replay *replay, int *mix_buf ) { + struct channel *channel; + int idx, num_channels, tick_len = calculate_tick_len( replay->tempo, replay->sample_rate ); + /* Clear output buffer. */ + memset( mix_buf, 0, ( tick_len + 65 ) * 4 * sizeof( int ) ); + /* Resample. */ + num_channels = replay->module->num_channels; + for( idx = 0; idx < num_channels; idx++ ) { + channel = &replay->channels[ idx ]; + channel_resample( channel, mix_buf, 0, ( tick_len + 65 ) * 2, + replay->sample_rate * 2, replay->interpolation ); + channel_update_sample_idx( channel, tick_len * 2, replay->sample_rate * 2 ); + } + downsample( mix_buf, tick_len + 64 ); + replay_volume_ramp( replay, mix_buf, tick_len ); + replay_tick( replay ); + return tick_len; +} diff --git a/deps/ibxm/ibxm.h b/deps/ibxm/ibxm.h new file mode 100644 index 0000000000..0949b2c6ca --- /dev/null +++ b/deps/ibxm/ibxm.h @@ -0,0 +1,71 @@ + +/* ibxm/ac mod/xm/s3m replay (c)mumart@gmail.com */ + +#ifndef __IBXM_H__ +#define __IBXM_H__ + +extern const char *IBXM_VERSION; + +struct data { + char *buffer; + int length; +}; + +struct sample { + char name[ 32 ]; + int loop_start, loop_length; + short volume, panning, rel_note, fine_tune, *data; +}; + +struct envelope { + char enabled, sustain, looped, num_points; + short sustain_tick, loop_start_tick, loop_end_tick; + short points_tick[ 16 ], points_ampl[ 16 ]; +}; + +struct instrument { + int num_samples, vol_fadeout; + char name[ 32 ], key_to_sample[ 97 ]; + char vib_type, vib_sweep, vib_depth, vib_rate; + struct envelope vol_env, pan_env; + struct sample *samples; +}; + +struct pattern { + int num_channels, num_rows; + char *data; +}; + +struct module { + char name[ 32 ]; + int num_channels, num_instruments; + int num_patterns, sequence_len, restart_pos; + int default_gvol, default_speed, default_tempo, c2_rate, gain; + int linear_periods, fast_vol_slides; + unsigned char *default_panning, *sequence; + struct pattern *patterns; + struct instrument *instruments; +}; + +/* Allocate and initialize a module from the specified data, returns NULL on error. + Message should point to a 64-character buffer to receive error messages. */ +struct module* module_load( struct data *data, char *message ); +/* Deallocate the specified module. */ +void dispose_module( struct module *module ); +/* Allocate and initialize a replay with the specified module and sampling rate. */ +struct replay* new_replay( struct module *module, int sample_rate, int interpolation ); +/* Deallocate the specified replay. */ +void dispose_replay( struct replay *replay ); +/* Returns the song duration in samples at the current sampling rate. */ +int replay_calculate_duration( struct replay *replay ); +/* Seek to approximately the specified sample position. + The actual sample position reached is returned. */ +int replay_seek( struct replay *replay, int sample_pos ); +/* Set the pattern in the sequence to play. The tempo is reset to the default. */ +void replay_set_sequence_pos( struct replay *replay, int pos ); +/* Generates audio and returns the number of stereo samples written into mix_buf. */ +int replay_get_audio( struct replay *replay, int *mix_buf ); +/* Returns the length of the output buffer required by replay_get_audio(). */ +int calculate_mix_buf_len( int sample_rate ); + +#endif diff --git a/deps/ibxm/licence.txt b/deps/ibxm/licence.txt new file mode 100644 index 0000000000..1001af7c4d --- /dev/null +++ b/deps/ibxm/licence.txt @@ -0,0 +1,37 @@ +--- +Copyright (c) 2015, Martin Cameron +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 the organization 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. +--- diff --git a/deps/libui/LICENSE b/deps/libui/LICENSE new file mode 100644 index 0000000000..2351d66d93 --- /dev/null +++ b/deps/libui/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) 2014 Pietro Gagliardi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 is called the MIT License or Expat License; see http://www.opensource.org/licenses/MIT) diff --git a/deps/libui/common/CMakeLists.txt b/deps/libui/common/CMakeLists.txt new file mode 100644 index 0000000000..91d794936f --- /dev/null +++ b/deps/libui/common/CMakeLists.txt @@ -0,0 +1,16 @@ +# 3 june 2016 + +list(APPEND _LIBUI_SOURCES + common/areaevents.c + common/control.c + common/debug.c + common/matrix.c + common/shouldquit.c + common/userbugs.c +) +set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) + +list(APPEND _LIBUI_INCLUDEDIRS + common +) +set(_LIBUI_INCLUDEDIRS ${_LIBUI_INCLUDEDIRS} PARENT_SCOPE) diff --git a/deps/libui/common/control.c b/deps/libui/common/control.c index 0f4a9499be..2806646168 100644 --- a/deps/libui/common/control.c +++ b/deps/libui/common/control.c @@ -61,9 +61,11 @@ void uiControlDisable(uiControl *c) uiControl *uiAllocControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr) { - uiControl *c = (uiControl *) uiAlloc(size, typenamestr); - c->Signature = uiControlSignature; - c->OSSignature = OSsig; + uiControl *c; + + c = (uiControl *) uiAlloc(size, typenamestr); + c->Signature = uiControlSignature; + c->OSSignature = OSsig; c->TypeSignature = typesig; return c; } @@ -90,11 +92,10 @@ void uiControlVerifySetParent(uiControl *c, uiControl *parent) int uiControlEnabledToUser(uiControl *c) { - while (c != NULL) - { - if (!uiControlEnabled(c)) - return 0; - c = uiControlParent(c); - } + while (c != NULL) { + if (!uiControlEnabled(c)) + return 0; + c = uiControlParent(c); + } return 1; } diff --git a/deps/libui/common/controlsigs.h b/deps/libui/common/controlsigs.h index 14507e7b8d..1cbf18d5da 100644 --- a/deps/libui/common/controlsigs.h +++ b/deps/libui/common/controlsigs.h @@ -1,4 +1,4 @@ -/* 24 april 2016 */ +// 24 april 2016 #define uiAreaSignature 0x41726561 #define uiBoxSignature 0x426F784C diff --git a/deps/libui/common/matrix.c b/deps/libui/common/matrix.c index 4e44681a7b..676885d1bf 100644 --- a/deps/libui/common/matrix.c +++ b/deps/libui/common/matrix.c @@ -1,4 +1,4 @@ -/* 11 october 2015 */ +// 11 october 2015 #include #include "../ui.h" #include "uipriv.h" @@ -13,17 +13,17 @@ void uiDrawMatrixSetIdentity(uiDrawMatrix *m) m->M32 = 0; } -/* The rest of this file provides basic utilities in case the platform doesn't provide any of its own for these tasks. - * Keep these as minimal as possible. They should generally not call other fallbacks. +// The rest of this file provides basic utilities in case the platform doesn't provide any of its own for these tasks. +// Keep these as minimal as possible. They should generally not call other fallbacks. - * see https://msdn.microsoft.com/en-us/library/windows/desktop/ff684171%28v=vs.85%29.aspx#skew_transform - * TODO see if there's a way we can avoid the multiplication */ +// see https://msdn.microsoft.com/en-us/library/windows/desktop/ff684171%28v=vs.85%29.aspx#skew_transform +// TODO see if there's a way we can avoid the multiplication void fallbackSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) { uiDrawMatrix n; uiDrawMatrixSetIdentity(&n); - /* TODO explain this */ + // TODO explain this n.M12 = tan(yamount); n.M21 = tan(xamount); n.M31 = -y * tan(xamount); @@ -37,13 +37,13 @@ void scaleCenter(double xCenter, double yCenter, double *x, double *y) *y = yCenter - (*y * yCenter); } -/* the basic algorithm is from cairo - * but it's the same algorithm as the transform point, - * just without M31 and M32 taken into account, so let's just do that instead */ +// the basic algorithm is from cairo +// but it's the same algorithm as the transform point, just without M31 and M32 taken into account, so let's just do that instead void fallbackTransformSize(uiDrawMatrix *m, double *x, double *y) { - uiDrawMatrix m2 = *m; + uiDrawMatrix m2; + m2 = *m; m2.M31 = 0; m2.M32 = 0; uiDrawMatrixTransformPoint(&m2, x, y); diff --git a/deps/libui/common/uipriv.h b/deps/libui/common/uipriv.h index e7c9940a83..d6b54e89ad 100644 --- a/deps/libui/common/uipriv.h +++ b/deps/libui/common/uipriv.h @@ -1,4 +1,4 @@ -/* 6 april 2015 */ +// 6 april 2015 #ifdef __cplusplus extern "C" { #endif @@ -13,7 +13,7 @@ extern void *uiAlloc(size_t, const char *); extern void *uiRealloc(void *, size_t, const char *); extern void uiFree(void *); -/* ugh, this was only introduced in MSVC 2015... */ +// ugh, this was only introduced in MSVC 2015... #ifdef _MSC_VER #define __func__ __FUNCTION__ #endif @@ -25,17 +25,16 @@ extern void _implbug(const char *file, const char *line, const char *func, const extern void _userbug(const char *file, const char *line, const char *func, const char *format, ...); #define userbug(...) _userbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__) -/* control.c */ +// control.c extern uiControl *newControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr); -/* shouldquit.c */ +// shouldquit.c extern int shouldQuit(void); -/* areaevents.c */ +// areaevents.c typedef struct clickCounter clickCounter; - -/* you should call Reset() to zero-initialize a new instance - * it doesn't matter that all the non-count fields are zero: the first click will fail the curButton test straightaway, so it'll return 1 and set the rest of the structure accordingly */ +// you should call Reset() to zero-initialize a new instance +// it doesn't matter that all the non-count fields are zero: the first click will fail the curButton test straightaway, so it'll return 1 and set the rest of the structure accordingly struct clickCounter { int curButton; int rectX0; @@ -49,7 +48,7 @@ int clickCounterClick(clickCounter *c, int button, int x, int y, uintptr_t time, extern void clickCounterReset(clickCounter *); extern int fromScancode(uintptr_t, uiAreaKeyEvent *); -/* matrix.c */ +// matrix.c extern void fallbackSkew(uiDrawMatrix *, double, double, double, double); extern void scaleCenter(double, double, double *, double *); extern void fallbackTransformSize(uiDrawMatrix *, double *, double *); diff --git a/deps/libui/darwin/CMakeLists.txt b/deps/libui/darwin/CMakeLists.txt new file mode 100644 index 0000000000..dbef5d432c --- /dev/null +++ b/deps/libui/darwin/CMakeLists.txt @@ -0,0 +1,79 @@ +# 3 june 2016 + +list(APPEND _LIBUI_SOURCES + darwin/alloc.m + darwin/area.m + darwin/areaevents.m + darwin/autolayout.m + darwin/box.m + darwin/button.m + darwin/checkbox.m + darwin/colorbutton.m + darwin/combobox.m + darwin/control.m + darwin/datetimepicker.m + darwin/debug.m + darwin/draw.m + darwin/drawtext.m + darwin/editablecombo.m + darwin/entry.m + darwin/fontbutton.m + darwin/form.m + darwin/grid.m + darwin/group.m + darwin/image.m + darwin/label.m + darwin/main.m + darwin/map.m + darwin/menu.m + darwin/multilineentry.m + darwin/progressbar.m + darwin/radiobuttons.m + darwin/scrollview.m + darwin/separator.m + darwin/slider.m + darwin/spinbox.m + darwin/stddialogs.m + darwin/tab.m + darwin/text.m + darwin/util.m + darwin/window.m + darwin/winmoveresize.m +) +set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) + +list(APPEND _LIBUI_INCLUDEDIRS + darwin +) +set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) + +set(_LIBUINAME libui PARENT_SCOPE) +if(NOT BUILD_SHARED_LIBS) + set(_LIBUINAME libui-temporary PARENT_SCOPE) +endif() +# thanks to Mr-Hide in irc.freenode.net/#cmake +macro(_handle_static) + set_target_properties(${_LIBUINAME} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") + set(_aname $) + set(_lname libui-combined.list) + set(_oname libui-combined.o) + add_custom_command( + OUTPUT ${_oname} + COMMAND + nm -m ${_aname} | sed -E -n "'s/^[0-9a-f]* \\([A-Z_]+,[a-z_]+\\) external //p'" > ${_lname} + COMMAND + ld -exported_symbols_list ${_lname} -r -all_load ${_aname} -o ${_oname} + COMMENT "Removing hidden symbols") + add_library(libui STATIC ${_oname}) + # otherwise cmake won't know which linker to use + set_target_properties(libui PROPERTIES + LINKER_LANGUAGE C) + set(_aname) + set(_lname) + set(_oname) +endmacro() + +set(_LIBUI_LIBS + objc "-framework Foundation" "-framework AppKit" +PARENT_SCOPE) diff --git a/deps/libui/ui.h b/deps/libui/ui.h index b6c9e728a8..5a2069e8a7 100644 --- a/deps/libui/ui.h +++ b/deps/libui/ui.h @@ -1,6 +1,6 @@ -/* 6 april 2015 */ +// 6 april 2015 -/* TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls */ +// TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls #ifndef __LIBUI_UI_H__ #define __LIBUI_UI_H__ @@ -12,7 +12,7 @@ extern "C" { #endif -/* this macro is generated by cmake */ +// this macro is generated by cmake #ifdef libui_EXPORTS #ifdef _WIN32 #define _UI_EXTERN __declspec(dllexport) extern @@ -20,19 +20,19 @@ extern "C" { #define _UI_EXTERN __attribute__((visibility("default"))) extern #endif #else -/* TODO add __declspec(dllimport) on windows, but only if not static */ +// TODO add __declspec(dllimport) on windows, but only if not static #define _UI_EXTERN extern #endif -/* C++ is really really really really really really dumb about enums, so screw that and just make them anonymous - * This has the advantage of being ABI-able should we ever need an ABI... */ +// C++ is really really really really really really dumb about enums, so screw that and just make them anonymous +// This has the advantage of being ABI-able should we ever need an ABI... #define _UI_ENUM(s) typedef unsigned int s; enum -/* This constant is provided because M_PI is nonstandard. - * This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796. */ +// This constant is provided because M_PI is nonstandard. +// This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796. #define uiPi 3.14159265358979323846264338327950288419716939937510582097494459 -/* TODO uiBool? */ +// TODO uiBool? typedef struct uiInitOptions uiInitOptions; @@ -73,7 +73,7 @@ struct uiControl { void (*Enable)(uiControl *); void (*Disable)(uiControl *); }; -/* TOOD add argument names to all arguments */ +// TOOD add argument names to all arguments #define uiControl(this) ((uiControl *) (this)) _UI_EXTERN void uiControlDestroy(uiControl *); _UI_EXTERN uintptr_t uiControlHandle(uiControl *); @@ -90,7 +90,7 @@ _UI_EXTERN void uiControlDisable(uiControl *); _UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr); _UI_EXTERN void uiFreeControl(uiControl *); -/* TODO make sure all controls have these */ +// TODO make sure all controls have these _UI_EXTERN void uiControlVerifySetParent(uiControl *, uiControl *); _UI_EXTERN int uiControlEnabledToUser(uiControl *); @@ -174,11 +174,10 @@ _UI_EXTERN int uiGroupMargined(uiGroup *g); _UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined); _UI_EXTERN uiGroup *uiNewGroup(const char *title); -/* spinbox/slider rules: - * setting value outside of range will automatically clamp - * initial value is minimum - * complaint if min >= max? - */ +// spinbox/slider rules: +// setting value outside of range will automatically clamp +// initial value is minimum +// complaint if min >= max? typedef struct uiSpinbox uiSpinbox; #define uiSpinbox(this) ((uiSpinbox *) (this)) @@ -218,7 +217,7 @@ typedef struct uiEditableCombobox uiEditableCombobox; _UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text); _UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c); _UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text); -/* TODO what do we call a function that sets the currently selected item and fills the text field with it? editable comboboxes have no consistent concept of selected item */ +// TODO what do we call a function that sets the currently selected item and fills the text field with it? editable comboboxes have no consistent concept of selected item _UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data); _UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void); @@ -236,7 +235,7 @@ _UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void); _UI_EXTERN uiDateTimePicker *uiNewDatePicker(void); _UI_EXTERN uiDateTimePicker *uiNewTimePicker(void); -/* TODO provide a facility for entering tab stops? */ +// TODO provide a facility for entering tab stops? typedef struct uiMultilineEntry uiMultilineEntry; #define uiMultilineEntry(this) ((uiMultilineEntry *) (this)) _UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e); @@ -292,8 +291,7 @@ struct uiAreaHandler { // TODO RTL layouts? // TODO reconcile edge and corner naming -_UI_ENUM(uiWindowResizeEdge) -{ +_UI_ENUM(uiWindowResizeEdge) { uiWindowResizeEdgeLeft, uiWindowResizeEdgeTop, uiWindowResizeEdgeRight, @@ -301,10 +299,10 @@ _UI_ENUM(uiWindowResizeEdge) uiWindowResizeEdgeTopLeft, uiWindowResizeEdgeTopRight, uiWindowResizeEdgeBottomLeft, - uiWindowResizeEdgeBottomRight - /* TODO have one for keyboard resizes? - * TODO GDK doesn't seem to have any others, including for keyboards... - * TODO way to bring up the system menu instead? */ + uiWindowResizeEdgeBottomRight, + // TODO have one for keyboard resizes? + // TODO GDK doesn't seem to have any others, including for keyboards... + // TODO way to bring up the system menu instead? }; #define uiArea(this) ((uiArea *) (this)) @@ -348,29 +346,29 @@ _UI_ENUM(uiDrawBrushType) { uiDrawBrushTypeSolid, uiDrawBrushTypeLinearGradient, uiDrawBrushTypeRadialGradient, - uiDrawBrushTypeImage + uiDrawBrushTypeImage, }; _UI_ENUM(uiDrawLineCap) { uiDrawLineCapFlat, uiDrawLineCapRound, - uiDrawLineCapSquare + uiDrawLineCapSquare, }; _UI_ENUM(uiDrawLineJoin) { uiDrawLineJoinMiter, uiDrawLineJoinRound, - uiDrawLineJoinBevel + uiDrawLineJoinBevel, }; -/* this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions) - * Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value - * so we're good to use it too! */ +// this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions) +// Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value +// so we're good to use it too! #define uiDrawDefaultMiterLimit 10.0 _UI_ENUM(uiDrawFillMode) { uiDrawFillModeWinding, - uiDrawFillModeAlternate + uiDrawFillModeAlternate, }; struct uiDrawMatrix { @@ -385,13 +383,13 @@ struct uiDrawMatrix { struct uiDrawBrush { uiDrawBrushType Type; - /* solid brushes */ + // solid brushes double R; double G; double B; double A; - /* gradient brushes */ + // gradient brushes double X0; // linear: start X, radial: start X double Y0; // linear: start Y, radial: start Y double X1; // linear: end X, radial: outer circle center X @@ -504,13 +502,13 @@ _UI_ENUM(uiDrawTextWeight) { uiDrawTextWeightBold, uiDrawTextWeightUltraBold, uiDrawTextWeightHeavy, - uiDrawTextWeightUltraHeavy + uiDrawTextWeightUltraHeavy, }; _UI_ENUM(uiDrawTextItalic) { uiDrawTextItalicNormal, uiDrawTextItalicOblique, - uiDrawTextItalicItalic + uiDrawTextItalicItalic, }; _UI_ENUM(uiDrawTextStretch) { @@ -522,7 +520,7 @@ _UI_ENUM(uiDrawTextStretch) { uiDrawTextStretchSemiExpanded, uiDrawTextStretchExpanded, uiDrawTextStretchExtraExpanded, - uiDrawTextStretchUltraExpanded + uiDrawTextStretchUltraExpanded, }; struct uiDrawTextFontDescriptor { @@ -563,10 +561,10 @@ _UI_EXTERN void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar _UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout); _UI_ENUM(uiModifiers) { - uiModifierCtrl = 1 << 0, - uiModifierAlt = 1 << 1, + uiModifierCtrl = 1 << 0, + uiModifierAlt = 1 << 1, uiModifierShift = 1 << 2, - uiModifierSuper = 1 << 3 + uiModifierSuper = 1 << 3, }; // TODO document drag captures @@ -628,7 +626,7 @@ _UI_ENUM(uiExtKey) { uiExtKeyNAdd, uiExtKeyNSubtract, uiExtKeyNMultiply, - uiExtKeyNDivide + uiExtKeyNDivide, }; struct uiAreaKeyEvent { @@ -643,9 +641,9 @@ struct uiAreaKeyEvent { typedef struct uiFontButton uiFontButton; #define uiFontButton(this) ((uiFontButton *) (this)) -/* TODO document this returns a new font */ +// TODO document this returns a new font _UI_EXTERN uiDrawTextFont *uiFontButtonFont(uiFontButton *b); -/* TOOD SetFont, mechanics */ +// TOOD SetFont, mechanics _UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data); _UI_EXTERN uiFontButton *uiNewFontButton(void); @@ -668,14 +666,14 @@ _UI_ENUM(uiAlign) { uiAlignFill, uiAlignStart, uiAlignCenter, - uiAlignEnd + uiAlignEnd, }; _UI_ENUM(uiAt) { uiAtLeading, uiAtTop, uiAtTrailing, - uiAtBottom + uiAtBottom, }; typedef struct uiGrid uiGrid; diff --git a/deps/libui/ui_unix.h b/deps/libui/ui_unix.h index 091965e7a7..5a91257bdd 100644 --- a/deps/libui/ui_unix.h +++ b/deps/libui/ui_unix.h @@ -1,4 +1,4 @@ -/* 7 april 2015 */ +// 7 april 2015 /* This file assumes that you have included and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Unix systems that use GTK+ to provide their UI (currently all except Mac OS X). @@ -19,7 +19,7 @@ struct uiUnixControl { void (*SetContainer)(uiUnixControl *, GtkContainer *, gboolean); }; #define uiUnixControl(this) ((uiUnixControl *) (this)) -/* TODO document */ +// TODO document _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gboolean); #define uiUnixControlDefaultDestroy(type) \ @@ -80,7 +80,7 @@ _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gbool { \ gtk_widget_set_sensitive(type(c)->widget, FALSE); \ } -/* TODO this whole addedBefore stuff is a MASSIVE HACK. */ +// TODO this whole addedBefore stuff is a MASSIVE HACK. #define uiUnixControlDefaultSetContainer(type) \ static void type ## SetContainer(uiUnixControl *c, GtkContainer *container, gboolean remove) \ { \ @@ -112,7 +112,7 @@ _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gbool uiUnixControlDefaultDestroy(type) \ uiUnixControlAllDefaultsExceptDestroy(type) -/* TODO document */ +// TODO document #define uiUnixNewControl(type, var) \ var = type(uiUnixAllocControl(sizeof (type), type ## Signature, #type)); \ uiControl(var)->Destroy = type ## Destroy; \ @@ -127,10 +127,10 @@ _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gbool uiControl(var)->Enable = type ## Enable; \ uiControl(var)->Disable = type ## Disable; \ uiUnixControl(var)->SetContainer = type ## SetContainer; -/* TODO document */ +// TODO document _UI_EXTERN uiUnixControl *uiUnixAllocControl(size_t n, uint32_t typesig, const char *typenamestr); -/* uiUnixStrdupText() takes the given string and produces a copy of it suitable for being freed by uiFreeText(). */ +// uiUnixStrdupText() takes the given string and produces a copy of it suitable for being freed by uiFreeText(). _UI_EXTERN char *uiUnixStrdupText(const char *); #ifdef __cplusplus diff --git a/deps/libui/unix/CMakeLists.txt b/deps/libui/unix/CMakeLists.txt new file mode 100644 index 0000000000..9300bcb701 --- /dev/null +++ b/deps/libui/unix/CMakeLists.txt @@ -0,0 +1,85 @@ +# 3 june 2016 + +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED gtk+-3.0) + +list(APPEND _LIBUI_SOURCES + unix/alloc.c + unix/area.c + unix/box.c + unix/button.c + unix/cellrendererbutton.c + unix/checkbox.c + unix/child.c + unix/colorbutton.c + unix/combobox.c + unix/control.c + unix/datetimepicker.c + unix/debug.c + unix/draw.c + unix/drawmatrix.c + unix/drawpath.c + unix/drawtext.c + unix/editablecombo.c + unix/entry.c + unix/fontbutton.c + unix/form.c + unix/future.c + unix/graphemes.c + unix/grid.c + unix/group.c + unix/image.c + unix/label.c + unix/main.c + unix/menu.c + unix/multilineentry.c + unix/progressbar.c + unix/radiobuttons.c + unix/separator.c + unix/slider.c + unix/spinbox.c + unix/stddialogs.c + unix/tab.c + unix/text.c + unix/util.c + unix/window.c +) +set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) + +list(APPEND _LIBUI_INCLUDEDIRS + unix +) +set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) + +set(_LIBUINAME libui PARENT_SCOPE) +if(NOT BUILD_SHARED_LIBS) + set(_LIBUINAME libui-temporary PARENT_SCOPE) +endif() +macro(_handle_static) + set_target_properties(${_LIBUINAME} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") + set(_aname $) + set(_oname libui-combined.o) + add_custom_command( + OUTPUT ${_oname} + COMMAND + ld -r --whole-archive ${_aname} -o ${_oname} + COMMAND + objcopy --localize-hidden ${_oname} + COMMENT "Removing hidden symbols") + add_library(libui STATIC ${_oname}) + # otherwise cmake won't know which linker to use + set_target_properties(libui PROPERTIES + LINKER_LANGUAGE C) + set(_aname) + set(_oname) +endmacro() + +# TODO the other variables don't work? +set(_LIBUI_CFLAGS + ${GTK_CFLAGS} +PARENT_SCOPE) + +set(_LIBUI_LIBS + ${GTK_LDFLAGS} m ${CMAKE_DL_LIBS} +PARENT_SCOPE) diff --git a/deps/libui/gtk/alloc.c b/deps/libui/unix/alloc.c similarity index 89% rename from deps/libui/gtk/alloc.c rename to deps/libui/unix/alloc.c index 53f2e7aa5b..2561efa6e2 100644 --- a/deps/libui/gtk/alloc.c +++ b/deps/libui/unix/alloc.c @@ -1,4 +1,4 @@ -/* 7 april 2015 */ +// 7 april 2015 #include #include "uipriv_unix.h" @@ -20,8 +20,8 @@ void initAlloc(void) static void uninitComplain(gpointer ptr, gpointer data) { - char *str2 = NULL; - char **str = (char **)data; + char **str = (char **) data; + char *str2; if (*str == NULL) *str = g_strdup_printf(""); @@ -34,12 +34,10 @@ void uninitAlloc(void) { char *str = NULL; - if (allocations->len == 0) - { - g_ptr_array_free(allocations, TRUE); - return; - } - + if (allocations->len == 0) { + g_ptr_array_free(allocations, TRUE); + return; + } g_ptr_array_foreach(allocations, uninitComplain, &str); userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", str); g_free(str); @@ -47,8 +45,9 @@ void uninitAlloc(void) void *uiAlloc(size_t size, const char *type) { - void *out = g_malloc0(EXTRA + size); + void *out; + out = g_malloc0(EXTRA + size); *SIZE(out) = size; *TYPE(out) = type; g_ptr_array_add(allocations, out); diff --git a/deps/libui/gtk/area.c b/deps/libui/unix/area.c similarity index 70% rename from deps/libui/gtk/area.c rename to deps/libui/unix/area.c index 11089bbb9a..c46447cc33 100644 --- a/deps/libui/gtk/area.c +++ b/deps/libui/unix/area.c @@ -114,10 +114,10 @@ static void loadAreaSize(uiArea *a, double *width, double *height) static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr) { + areaWidget *aw = areaWidget(w); + uiArea *a = aw->a; uiAreaDrawParams dp; double clipX0, clipY0, clipX1, clipY1; - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; dp.Context = newContext(cr); @@ -129,30 +129,25 @@ static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr) dp.ClipWidth = clipX1 - clipX0; dp.ClipHeight = clipY1 - clipY0; - /* no need to save or restore the graphics state - * to reset transformations; GTK+ does that for us */ + // no need to save or restore the graphics state to reset transformations; GTK+ does that for us (*(a->ah->Draw))(a->ah, a, &dp); freeContext(dp.Context); return FALSE; } -/* to do this properly for scrolling areas, we need to - * - return the same value for min and nat - * - call gtk_widget_queue_resize() when the size changes - * thanks to Company in irc.gimp.net/#gtk+ */ -static void areaWidget_get_preferred_height(GtkWidget *w, - gint *min, gint *nat) +// to do this properly for scrolling areas, we need to +// - return the same value for min and nat +// - call gtk_widget_queue_resize() when the size changes +// thanks to Company in irc.gimp.net/#gtk+ +static void areaWidget_get_preferred_height(GtkWidget *w, gint *min, gint *nat) { areaWidget *aw = areaWidget(w); uiArea *a = aw->a; // always chain up just in case - GTK_WIDGET_CLASS(areaWidget_parent_class)-> - get_preferred_height(w, min, nat); - - if (a->scrolling) - { + GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_height(w, min, nat); + if (a->scrolling) { *min = a->scrollHeight; *nat = a->scrollHeight; } @@ -163,54 +158,51 @@ static void areaWidget_get_preferred_width(GtkWidget *w, gint *min, gint *nat) areaWidget *aw = areaWidget(w); uiArea *a = aw->a; - /* always chain up just in case */ + // always chain up just in case GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_width(w, min, nat); - if (a->scrolling) - { - *min = a->scrollWidth; - *nat = a->scrollWidth; - } + if (a->scrolling) { + *min = a->scrollWidth; + *nat = a->scrollWidth; + } } static guint translateModifiers(guint state, GdkWindow *window) { - GdkModifierType statetype; + GdkModifierType statetype; - /* GDK doesn't initialize the modifier flags fully; we have to - * explicitly tell it to (thanks to Daniel_S and daniels - * (two different people) in irc.gimp.net/#gtk+) */ - statetype = state; - gdk_keymap_add_virtual_modifiers( - gdk_keymap_get_for_display(gdk_window_get_display(window)), - &statetype); - return statetype; + // GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+) + statetype = state; + gdk_keymap_add_virtual_modifiers( + gdk_keymap_get_for_display(gdk_window_get_display(window)), + &statetype); + return statetype; } static uiModifiers toModifiers(guint state) { - uiModifiers m = 0; + uiModifiers m; - if ((state & GDK_CONTROL_MASK) != 0) - m |= uiModifierCtrl; - if ((state & GDK_META_MASK) != 0) - m |= uiModifierAlt; - /* GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c) */ - if ((state & GDK_MOD1_MASK) != 0) - m |= uiModifierAlt; - if ((state & GDK_SHIFT_MASK) != 0) - m |= uiModifierShift; - if ((state & GDK_SUPER_MASK) != 0) - m |= uiModifierSuper; - return m; + m = 0; + if ((state & GDK_CONTROL_MASK) != 0) + m |= uiModifierCtrl; + if ((state & GDK_META_MASK) != 0) + m |= uiModifierAlt; + if ((state & GDK_MOD1_MASK) != 0) // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c) + m |= uiModifierAlt; + if ((state & GDK_SHIFT_MASK) != 0) + m |= uiModifierShift; + if ((state & GDK_SUPER_MASK) != 0) + m |= uiModifierSuper; + return m; } -/* capture on drag is done automatically on GTK+ */ +// capture on drag is done automatically on GTK+ static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble x, gdouble y, guint state, GdkWindow *window) { - /* on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake */ + // on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake if (mb >= 4 && mb <= 7) return; - /* if the button ID >= 8, continue counting from 4, as in the MouseEvent spec */ + // if the button ID >= 8, continue counting from 4, as in the MouseEvent spec if (me->Down >= 8) me->Down -= 4; if (me->Up >= 8) @@ -219,7 +211,7 @@ static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble state = translateModifiers(state, window); me->Modifiers = toModifiers(state); - /* the mb != # checks exclude the Up/Down button from Held */ + // the mb != # checks exclude the Up/Down button from Held me->Held1To64 = 0; if (mb != 1 && (state & GDK_BUTTON1_MASK) != 0) me->Held1To64 |= 1 << 0; @@ -227,19 +219,12 @@ static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble me->Held1To64 |= 1 << 1; if (mb != 3 && (state & GDK_BUTTON3_MASK) != 0) me->Held1To64 |= 1 << 2; + // don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those are for the scrolling buttons mentioned above + // GDK expressly does not support any more buttons in the GdkModifierType; see https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkdevice-xi2.c#n763 (thanks mclasen in irc.gimp.net/#gtk+) - /* don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those - * are for the scrolling buttons mentioned above - * - * GDK expressly does not support any more buttons in the - * GdkModifierType; see - * https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkdevice-xi2.c#n763 - * (thanks mclasen in irc.gimp.net/#gtk+) - */ - - /* these are already in drawing space coordinates - * the size of drawing space has the same value as the widget allocation - * thanks to tristan in irc.gimp.net/#gtk+ */ + // these are already in drawing space coordinates + // the size of drawing space has the same value as the widget allocation + // thanks to tristan in irc.gimp.net/#gtk+ me->X = x; me->Y = y; @@ -250,43 +235,37 @@ static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble static gboolean areaWidget_button_press_event(GtkWidget *w, GdkEventButton *e) { + areaWidget *aw = areaWidget(w); + uiArea *a = aw->a; gint maxTime, maxDistance; + GtkSettings *settings; uiAreaMouseEvent me; - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; - GtkSettings *settings = NULL; - /* clicking doesn't automatically transfer keyboard focus; - * we must do so manually (thanks tristan in irc.gimp.net/#gtk+) */ + // clicking doesn't automatically transfer keyboard focus; we must do so manually (thanks tristan in irc.gimp.net/#gtk+) gtk_widget_grab_focus(w); - /* we handle multiple clicks ourselves here, - * in the same way as we do on Windows */ - - /* ignore GDK's generated double-clicks and beyond */ + // we handle multiple clicks ourselves here, in the same way as we do on Windows if (e->type != GDK_BUTTON_PRESS) + // ignore GDK's generated double-clicks and beyond return GDK_EVENT_PROPAGATE; - settings = gtk_widget_get_settings(w); - g_object_get(settings, "gtk-double-click-time", &maxTime, "gtk-double-click-distance", &maxDistance, NULL); - - /* don't unref settings; it's transfer-none (thanks gregier in irc.gimp.net/#gtk+) - * e->time is guint32 - * e->x and e->y are floating-point; just make them 32-bit integers - * maxTime and maxDistance... are gint, which *should* fit, hopefully... */ + // don't unref settings; it's transfer-none (thanks gregier in irc.gimp.net/#gtk+) + // e->time is guint32 + // e->x and e->y are floating-point; just make them 32-bit integers + // maxTime and maxDistance... are gint, which *should* fit, hopefully... me.Count = clickCounterClick(a->cc, me.Down, e->x, e->y, e->time, maxTime, maxDistance, maxDistance); me.Down = e->button; - me.Up = 0; + me.Up = 0; - /* and set things up for window drags */ + // and set things up for window drags a->dragevent = e; finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); a->dragevent = NULL; @@ -295,37 +274,32 @@ static gboolean areaWidget_button_press_event(GtkWidget *w, GdkEventButton *e) static gboolean areaWidget_button_release_event(GtkWidget *w, GdkEventButton *e) { - uiAreaMouseEvent me; - areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; + areaWidget *aw = areaWidget(w); + uiArea *a = aw->a; + uiAreaMouseEvent me; - me.Down = 0; - me.Up = e->button; - me.Count = 0; - finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); - return GDK_EVENT_PROPAGATE; + me.Down = 0; + me.Up = e->button; + me.Count = 0; + finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); + return GDK_EVENT_PROPAGATE; } static gboolean areaWidget_motion_notify_event(GtkWidget *w, GdkEventMotion *e) { - uiAreaMouseEvent me; areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; + uiArea *a = aw->a; + uiAreaMouseEvent me; - me.Down = 0; - me.Up = 0; - me.Count = 0; + me.Down = 0; + me.Up = 0; + me.Count = 0; finishMouseEvent(a, &me, 0, e->x, e->y, e->state, e->window); return GDK_EVENT_PROPAGATE; } -/* we want switching away from the control to reset the double-click counter, - * like with WM_ACTIVATE on Windows - * - * according to tristan in irc.gimp.net/#gtk+, doing this on both - * enter-notify-event and leave-notify-event is correct (and it seems to be - * true in my own tests; plus the events DO get sent when switching programs - * with the keyboard (just pointing that out)) */ +// we want switching away from the control to reset the double-click counter, like with WM_ACTIVATE on Windows +// according to tristan in irc.gimp.net/#gtk+, doing this on both enter-notify-event and leave-notify-event is correct (and it seems to be true in my own tests; plus the events DO get sent when switching programs with the keyboard (just pointing that out)) static gboolean onCrossing(areaWidget *aw, int left) { uiArea *a = aw->a; @@ -345,15 +319,11 @@ static gboolean areaWidget_leave_notify_event(GtkWidget *w, GdkEventCrossing *e) return onCrossing(areaWidget(w), 1); } -/* note: there is no equivalent to WM_CAPTURECHANGED on GTK+; there literally - * is no way to break a grab like that (at least not on X11 and Wayland) - * - * even if I invoke the task switcher and switch processes, the mouse grab will - * still be held until I let go of all buttons - * therefore, no DragBroken() - * - * we use GDK_KEY_Print as a sentinel because libui will never support the print screen key; that key belongs to the user - */ +// note: there is no equivalent to WM_CAPTURECHANGED on GTK+; there literally is no way to break a grab like that (at least not on X11 and Wayland) +// even if I invoke the task switcher and switch processes, the mouse grab will still be held until I let go of all buttons +// therefore, no DragBroken() + +// we use GDK_KEY_Print as a sentinel because libui will never support the print screen key; that key belongs to the user static const struct { guint keyval; @@ -382,7 +352,7 @@ static const struct { { GDK_KEY_F10, uiExtKeyF10 }, { GDK_KEY_F11, uiExtKeyF11 }, { GDK_KEY_F12, uiExtKeyF12 }, - /* numpad numeric keys and . are handled in events.c */ + // numpad numeric keys and . are handled in events.c { GDK_KEY_KP_Enter, uiExtKeyNEnter }, { GDK_KEY_KP_Add, uiExtKeyNAdd }, { GDK_KEY_KP_Subtract, uiExtKeyNSubtract }, @@ -424,25 +394,23 @@ static int areaKeyEvent(uiArea *a, int up, GdkEventKey *e) ke.Up = up; for (i = 0; extKeys[i].keyval != GDK_KEY_Print; i++) - if (extKeys[i].keyval == e->keyval) - { + if (extKeys[i].keyval == e->keyval) { ke.ExtKey = extKeys[i].extkey; goto keyFound; } for (i = 0; modKeys[i].keyval != GDK_KEY_Print; i++) - if (modKeys[i].keyval == e->keyval) - { - ke.Modifier = modKeys[i].mod; - /* don't include the modifier in ke.Modifiers */ - ke.Modifiers &= ~ke.Modifier; - goto keyFound; - } + if (modKeys[i].keyval == e->keyval) { + ke.Modifier = modKeys[i].mod; + // don't include the modifier in ke.Modifiers + ke.Modifiers &= ~ke.Modifier; + goto keyFound; + } if (fromScancode(e->hardware_keycode - 8, &ke)) goto keyFound; - /* no supported key found; treat as unhandled */ + // no supported key found; treat as unhandled return 0; keyFound: @@ -452,7 +420,7 @@ keyFound: static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e) { areaWidget *aw = areaWidget(w); - uiArea *a = aw->a; + uiArea *a = aw->a; if (areaKeyEvent(a, 0, e)) return GDK_EVENT_STOP; @@ -478,16 +446,15 @@ static GParamSpec *pspecArea; static void areaWidget_set_property(GObject *obj, guint prop, const GValue *value, GParamSpec *pspec) { - areaWidget *aw = areaWidget(obj); + areaWidget *aw = areaWidget(obj); - switch (prop) - { - case pArea: - aw->a = (uiArea *) g_value_get_pointer(value); - aw->a->cc = &(aw->cc); - return; - } - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec); + switch (prop) { + case pArea: + aw->a = (uiArea *) g_value_get_pointer(value); + aw->a->cc = &(aw->cc); + return; + } + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec); } static void areaWidget_get_property(GObject *obj, guint prop, GValue *value, GParamSpec *pspec) @@ -541,8 +508,8 @@ void uiAreaQueueRedrawAll(uiArea *a) void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) { - /* TODO - * TODO adjust adjustments and find source for that */ + // TODO + // TODO adjust adjustments and find source for that } void uiAreaBeginUserWindowMove(uiArea *a) @@ -551,23 +518,25 @@ void uiAreaBeginUserWindowMove(uiArea *a) if (a->dragevent == NULL) userbug("cannot call uiAreaBeginUserWindowMove() outside of a Mouse() with Down != 0"); - /* TODO don't we have a libui function for this? did I scrap it? - * TODO widget or areaWidget? */ + // TODO don't we have a libui function for this? did I scrap it? + // TODO widget or areaWidget? toplevel = gtk_widget_get_toplevel(a->widget); - // TODO - if (toplevel == NULL) + if (toplevel == NULL) { + // TODO return; - /* the docs say to do this */ - - /* TODO */ - if (!gtk_widget_is_toplevel(toplevel)) + } + // the docs say to do this + if (!gtk_widget_is_toplevel(toplevel)) { + // TODO return; - /* TODO */ - if (!GTK_IS_WINDOW(toplevel)) + } + if (!GTK_IS_WINDOW(toplevel)) { + // TODO return; + } gtk_window_begin_move_drag(GTK_WINDOW(toplevel), a->dragevent->button, - a->dragevent->x_root, /* TODO are these correct? */ + a->dragevent->x_root, // TODO are these correct? a->dragevent->y_root, a->dragevent->time); } @@ -589,25 +558,26 @@ void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge) if (a->dragevent == NULL) userbug("cannot call uiAreaBeginUserWindowResize() outside of a Mouse() with Down != 0"); - /* TODO don't we have a libui function for this? did I scrap it? - * TODO widget or areaWidget? */ + // TODO don't we have a libui function for this? did I scrap it? + // TODO widget or areaWidget? toplevel = gtk_widget_get_toplevel(a->widget); - - /* TODO */ - if (toplevel == NULL) + if (toplevel == NULL) { + // TODO return; - /* the docs say to do this */ - - /* TODO */ - if (!gtk_widget_is_toplevel(toplevel)) + } + // the docs say to do this + if (!gtk_widget_is_toplevel(toplevel)) { + // TODO return; - /* TODO */ - if (!GTK_IS_WINDOW(toplevel)) + } + if (!GTK_IS_WINDOW(toplevel)) { + // TODO return; + } gtk_window_begin_resize_drag(GTK_WINDOW(toplevel), edges[edge], a->dragevent->button, - a->dragevent->x_root, /* TODO are these correct? */ + a->dragevent->x_root, // TODO are these correct? a->dragevent->y_root, a->dragevent->time); } @@ -656,8 +626,7 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) a->widget = a->swidget; gtk_container_add(a->scontainer, a->areaWidget); - /* and make the area visible; only the scrolled - * window's visibility is controlled by libui */ + // and make the area visible; only the scrolled window's visibility is controlled by libui gtk_widget_show(a->areaWidget); return a; diff --git a/deps/libui/gtk/box.c b/deps/libui/unix/box.c similarity index 76% rename from deps/libui/gtk/box.c rename to deps/libui/unix/box.c index 6c716930e7..23fb7f7c6c 100644 --- a/deps/libui/gtk/box.c +++ b/deps/libui/unix/box.c @@ -1,26 +1,24 @@ // 7 april 2015 #include "uipriv_unix.h" -struct boxChild -{ - uiControl *c; - int stretchy; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; +struct boxChild { + uiControl *c; + int stretchy; + gboolean oldhexpand; + GtkAlign oldhalign; + gboolean oldvexpand; + GtkAlign oldvalign; }; -struct uiBox -{ - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkBox *box; - GArray *controls; - int vertical; - int padded; - GtkSizeGroup *stretchygroup; /* ensures all stretchy controls have the same size */ +struct uiBox { + uiUnixControl c; + GtkWidget *widget; + GtkContainer *container; + GtkBox *box; + GArray *controls; + int vertical; + int padded; + GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size }; uiUnixControlAllDefaultsExceptDestroy(uiBox) @@ -33,19 +31,18 @@ static void uiBoxDestroy(uiControl *c) struct boxChild *bc; guint i; - /* kill the size group */ + // kill the size group g_object_unref(b->stretchygroup); - /* free all controls */ - for (i = 0; i < b->controls->len; i++) - { - bc = ctrl(b, i); - uiControlSetParent(bc->c, NULL); - /* and make sure the widget itself stays alive */ - uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); - uiControlDestroy(bc->c); - } + // free all controls + for (i = 0; i < b->controls->len; i++) { + bc = ctrl(b, i); + uiControlSetParent(bc->c, NULL); + // and make sure the widget itself stays alive + uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); + uiControlDestroy(bc->c); + } g_array_free(b->controls, TRUE); - /* and then ourselves */ + // and then ourselves g_object_unref(b->widget); uiFreeControl(uiControl(b)); } @@ -53,7 +50,7 @@ static void uiBoxDestroy(uiControl *c) void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) { struct boxChild bc; - GtkWidget *widget = NULL; + GtkWidget *widget; bc.c = c; bc.stretchy = stretchy; @@ -77,7 +74,7 @@ void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) gtk_widget_set_vexpand(widget, FALSE); else gtk_widget_set_hexpand(widget, FALSE); - /* and make them fill the opposite direction */ + // and make them fill the opposite direction if (b->vertical) { gtk_widget_set_hexpand(widget, TRUE); gtk_widget_set_halign(widget, GTK_ALIGN_FILL); @@ -93,8 +90,11 @@ void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) void uiBoxDelete(uiBox *b, int index) { - struct boxChild *bc = ctrl(b, index); - GtkWidget *widget = GTK_WIDGET(uiControlHandle(bc->c)); + struct boxChild *bc; + GtkWidget *widget; + + bc = ctrl(b, index); + widget = GTK_WIDGET(uiControlHandle(bc->c)); uiControlSetParent(bc->c, NULL); uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); diff --git a/deps/libui/gtk/button.c b/deps/libui/unix/button.c similarity index 94% rename from deps/libui/gtk/button.c rename to deps/libui/unix/button.c index 44266ee893..00a87f491a 100644 --- a/deps/libui/gtk/button.c +++ b/deps/libui/unix/button.c @@ -1,8 +1,7 @@ // 10 june 2015 #include "uipriv_unix.h" -struct uiButton -{ +struct uiButton { uiUnixControl c; GtkWidget *widget; GtkButton *button; @@ -21,7 +20,7 @@ static void onClicked(GtkButton *button, gpointer data) static void defaultOnClicked(uiButton *b, void *data) { - /* do nothing */ + // do nothing } char *uiButtonText(uiButton *b) @@ -36,7 +35,7 @@ void uiButtonSetText(uiButton *b, const char *text) void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data) { - b->onClicked = f; + b->onClicked = f; b->onClickedData = data; } diff --git a/deps/libui/gtk/cellrendererbutton.c b/deps/libui/unix/cellrendererbutton.c similarity index 100% rename from deps/libui/gtk/cellrendererbutton.c rename to deps/libui/unix/cellrendererbutton.c diff --git a/deps/libui/gtk/checkbox.c b/deps/libui/unix/checkbox.c similarity index 100% rename from deps/libui/gtk/checkbox.c rename to deps/libui/unix/checkbox.c diff --git a/deps/libui/gtk/child.c b/deps/libui/unix/child.c similarity index 94% rename from deps/libui/gtk/child.c rename to deps/libui/unix/child.c index 636495b97b..b4a0967740 100644 --- a/deps/libui/gtk/child.c +++ b/deps/libui/unix/child.c @@ -28,7 +28,7 @@ struct child { struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer) { - struct child *c = NULL; + struct child *c; if (child == NULL) return NULL; @@ -51,8 +51,8 @@ struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parent struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined) { - struct child *c = NULL; - GtkWidget *box = NULL; + struct child *c; + GtkWidget *box; if (child == NULL) return NULL; @@ -87,11 +87,11 @@ void childRemove(struct child *c) void childDestroy(struct child *c) { - uiControl *child = NULL; + uiControl *child; - child = c->c; - childRemove(c); - uiControlDestroy(child); + child = c->c; + childRemove(c); + uiControlDestroy(child); } GtkWidget *childWidget(struct child *c) diff --git a/deps/libui/gtk/colorbutton.c b/deps/libui/unix/colorbutton.c similarity index 100% rename from deps/libui/gtk/colorbutton.c rename to deps/libui/unix/colorbutton.c diff --git a/deps/libui/gtk/combobox.c b/deps/libui/unix/combobox.c similarity index 100% rename from deps/libui/gtk/combobox.c rename to deps/libui/unix/combobox.c diff --git a/deps/libui/gtk/control.c b/deps/libui/unix/control.c similarity index 100% rename from deps/libui/gtk/control.c rename to deps/libui/unix/control.c diff --git a/deps/libui/gtk/datetimepicker.c b/deps/libui/unix/datetimepicker.c similarity index 81% rename from deps/libui/gtk/datetimepicker.c rename to deps/libui/unix/datetimepicker.c index 315150a3d9..19689a2205 100644 --- a/deps/libui/gtk/datetimepicker.c +++ b/deps/libui/unix/datetimepicker.c @@ -14,31 +14,30 @@ typedef struct dateTimePickerWidget dateTimePickerWidget; typedef struct dateTimePickerWidgetClass dateTimePickerWidgetClass; -struct dateTimePickerWidget -{ - GtkToggleButton parent_instance; +struct dateTimePickerWidget { + GtkToggleButton parent_instance; - gulong toggledSignal; + gulong toggledSignal; - gboolean hasTime; - gboolean hasDate; + gboolean hasTime; + gboolean hasDate; - GtkWidget *window; - GtkWidget *box; - GtkWidget *calendar; - GtkWidget *timebox; - GtkWidget *hours; - GtkWidget *minutes; - GtkWidget *seconds; - GtkWidget *ampm; + GtkWidget *window; + GtkWidget *box; + GtkWidget *calendar; + GtkWidget *timebox; + GtkWidget *hours; + GtkWidget *minutes; + GtkWidget *seconds; + GtkWidget *ampm; - gulong hoursBlock; - gulong minutesBlock; - gulong secondsBlock; - gulong ampmBlock; + gulong hoursBlock; + gulong minutesBlock; + gulong secondsBlock; + gulong ampmBlock; - GdkDevice *keyboard; - GdkDevice *mouse; + GdkDevice *keyboard; + GdkDevice *mouse; }; struct dateTimePickerWidgetClass { @@ -49,7 +48,9 @@ G_DEFINE_TYPE(dateTimePickerWidget, dateTimePickerWidget, GTK_TYPE_TOGGLE_BUTTON static int realSpinValue(GtkSpinButton *spinButton) { - GtkAdjustment *adj = gtk_spin_button_get_adjustment(spinButton); + GtkAdjustment *adj; + + adj = gtk_spin_button_get_adjustment(spinButton); return (int) gtk_adjustment_get_value(adj); } @@ -69,14 +70,11 @@ static GDateTime *selected(dateTimePickerWidget *d) guint year = 1970, month = 1, day = 1; guint hour = 0, minute = 0, second = 0; - if (d->hasDate) - { + if (d->hasDate) { gtk_calendar_get_date(GTK_CALENDAR(d->calendar), &year, &month, &day); - month++; /* GtkCalendar/GDateTime differences */ + month++; // GtkCalendar/GDateTime differences } - - if (d->hasTime) - { + if (d->hasTime) { hour = realSpinValue(GTK_SPIN_BUTTON(d->hours)); if (realSpinValue(GTK_SPIN_BUTTON(d->ampm)) != 0) hour += 12; @@ -88,22 +86,21 @@ static GDateTime *selected(dateTimePickerWidget *d) static void setLabel(dateTimePickerWidget *d) { - char *fmt = NULL; - char *msg = NULL; - GDateTime *dt = selected(d); - gboolean free = FALSE; + GDateTime *dt; + char *fmt; + char *msg; + gboolean free; - if (d->hasDate && d->hasTime) - { - /* don't use D_T_FMT; that's too verbose */ - fmt = g_strdup_printf("%s %s", nl_langinfo(D_FMT), nl_langinfo(T_FMT)); + dt = selected(d); + free = FALSE; + if (d->hasDate && d->hasTime) { + // don't use D_T_FMT; that's too verbose + fmt = g_strdup_printf("%s %s", nl_langinfo(D_FMT), nl_langinfo(T_FMT)); free = TRUE; - } - else if (d->hasDate) - fmt = nl_langinfo(D_FMT); + } else if (d->hasDate) + fmt = nl_langinfo(D_FMT); else fmt = nl_langinfo(T_FMT); - msg = g_date_time_format(dt, fmt); gtk_button_set_label(GTK_BUTTON(d), msg); g_free(msg); @@ -147,31 +144,32 @@ static void hidePopup(dateTimePickerWidget *d) // this consolidates a good chunk of what GtkComboBox does static gboolean startGrab(dateTimePickerWidget *d) { + GdkDevice *dev; guint32 time; - GdkWindow *window = NULL; - GdkDevice *keyboard = NULL; - GdkDevice *mouse = NULL; - GdkDevice *dev = gtk_get_current_event_device(); + GdkWindow *window; + GdkDevice *keyboard, *mouse; - if (dev == NULL) - { + dev = gtk_get_current_event_device(); + if (dev == NULL) { // this is what GtkComboBox does // since no device was set, just use the first available "master device" - GdkDisplay *disp = gtk_widget_get_display(GTK_WIDGET(d)); - GdkDeviceManager *dm = gdk_display_get_device_manager(disp); - GList *list = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_MASTER); + GdkDisplay *disp; + GdkDeviceManager *dm; + GList *list; + + disp = gtk_widget_get_display(GTK_WIDGET(d)); + dm = gdk_display_get_device_manager(disp); + list = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_MASTER); dev = (GdkDevice *) (list->data); g_list_free(list); } - time = gtk_get_current_event_time(); + time = gtk_get_current_event_time(); keyboard = dev; - mouse = gdk_device_get_associated_device(dev); - - if (gdk_device_get_source(dev) != GDK_SOURCE_KEYBOARD) - { - dev = mouse; - mouse = keyboard; + mouse = gdk_device_get_associated_device(dev); + if (gdk_device_get_source(dev) != GDK_SOURCE_KEYBOARD) { + dev = mouse; + mouse = keyboard; keyboard = dev; } @@ -198,7 +196,7 @@ static gboolean startGrab(dateTimePickerWidget *d) return TRUE; } -/* based on gtk_combo_box_list_position() in the GTK+ source code */ +// based on gtk_combo_box_list_position() in the GTK+ source code static void allocationToScreen(dateTimePickerWidget *d, gint *x, gint *y) { GdkWindow *window; @@ -279,17 +277,15 @@ static gboolean grabBroken(GtkWidget *w, GdkEventGrabBroken *e, gpointer data) static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data) { + dateTimePickerWidget *d = dateTimePickerWidget(data); int winx, winy; GtkAllocation wina; gboolean in; - dateTimePickerWidget *d = dateTimePickerWidget(data); gtk_widget_get_allocation(d->window, &wina); winx = 0; winy = 0; - - if (!gtk_widget_get_has_window(d->window)) - { + if (!gtk_widget_get_has_window(d->window)) { winx = wina.x; winy = wina.y; } @@ -311,9 +307,11 @@ static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data) static gint hoursSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) { double *out = (double *) ptr; - const gchar *text = gtk_entry_get_text(GTK_ENTRY(sb)); - int value = (int) g_strtod(text, NULL); + const gchar *text; + int value; + text = gtk_entry_get_text(GTK_ENTRY(sb)); + value = (int) g_strtod(text, NULL); if (value < 0 || value > 12) return GTK_INPUT_ERROR; if (value == 12) // 12 to the user is 0 internally @@ -324,9 +322,10 @@ static gint hoursSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) static gboolean hoursSpinboxOutput(GtkSpinButton *sb, gpointer data) { - gchar *text = NULL; - int value = realSpinValue(sb); + gchar *text; + int value; + value = realSpinValue(sb); if (value == 0) // 0 internally is 12 to the user value = 12; text = g_strdup_printf("%d", value); @@ -337,9 +336,11 @@ static gboolean hoursSpinboxOutput(GtkSpinButton *sb, gpointer data) static gboolean zeroPadSpinbox(GtkSpinButton *sb, gpointer data) { - int value = realSpinValue(sb); - gchar *text = g_strdup_printf("%02d", value); + gchar *text; + int value; + value = realSpinValue(sb); + text = g_strdup_printf("%02d", value); gtk_entry_set_text(GTK_ENTRY(sb), text); g_free(text); return TRUE; @@ -348,20 +349,19 @@ static gboolean zeroPadSpinbox(GtkSpinButton *sb, gpointer data) // this is really hacky but we can't use GtkCombobox here :( static gint ampmSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) { - double *out = (double *) ptr; - const gchar *text = gtk_entry_get_text(GTK_ENTRY(sb)); - // LONGTERM don't use ASCII here for case insensitivity - char firstAM = g_ascii_tolower(nl_langinfo(AM_STR)[0]); - char firstPM = g_ascii_tolower(nl_langinfo(PM_STR)[0]); + double *out = (double *) ptr; + const gchar *text; + char firstAM, firstPM; + text = gtk_entry_get_text(GTK_ENTRY(sb)); + // LONGTERM don't use ASCII here for case insensitivity + firstAM = g_ascii_tolower(nl_langinfo(AM_STR)[0]); + firstPM = g_ascii_tolower(nl_langinfo(PM_STR)[0]); for (; *text != '\0'; text++) - if (g_ascii_tolower(*text) == firstAM) - { + if (g_ascii_tolower(*text) == firstAM) { *out = 0; return TRUE; - } - else if (g_ascii_tolower(*text) == firstPM) - { + } else if (g_ascii_tolower(*text) == firstPM) { *out = 1; return TRUE; } @@ -387,21 +387,20 @@ static void spinboxChanged(GtkSpinButton *sb, gpointer data) dateTimeChanged(d); } -static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, - gint (*input)(GtkSpinButton *, gpointer, gpointer), - gboolean (*output)(GtkSpinButton *, gpointer), gulong *block) +static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, gint (*input)(GtkSpinButton *, gpointer, gpointer), gboolean (*output)(GtkSpinButton *, gpointer), gulong *block) { - GtkWidget *sb = gtk_spin_button_new_with_range(min, max, 1); + GtkWidget *sb; - gtk_spin_button_set_digits(GTK_SPIN_BUTTON(sb), 0); - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(sb), TRUE); - gtk_orientable_set_orientation(GTK_ORIENTABLE(sb), GTK_ORIENTATION_VERTICAL); - *block = g_signal_connect(sb, "value-changed", G_CALLBACK(spinboxChanged), d); - if (input != NULL) - g_signal_connect(sb, "input", G_CALLBACK(input), NULL); - if (output != NULL) - g_signal_connect(sb, "output", G_CALLBACK(output), NULL); - return sb; + sb = gtk_spin_button_new_with_range(min, max, 1); + gtk_spin_button_set_digits(GTK_SPIN_BUTTON(sb), 0); + gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(sb), TRUE); + gtk_orientable_set_orientation(GTK_ORIENTABLE(sb), GTK_ORIENTATION_VERTICAL); + *block = g_signal_connect(sb, "value-changed", G_CALLBACK(spinboxChanged), d); + if (input != NULL) + g_signal_connect(sb, "input", G_CALLBACK(input), NULL); + if (output != NULL) + g_signal_connect(sb, "output", G_CALLBACK(output), NULL); + return sb; } static void dateChanged(GtkCalendar *c, gpointer data) @@ -537,14 +536,18 @@ static void dateTimePickerWidget_class_init(dateTimePickerWidgetClass *class) static GtkWidget *newDTP(void) { - GtkWidget *w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); + GtkWidget *w; + + w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); setLabel(dateTimePickerWidget(w)); return w; } static GtkWidget *newDP(void) { - GtkWidget *w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); + GtkWidget *w; + + w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); setDateOnly(dateTimePickerWidget(w)); setLabel(dateTimePickerWidget(w)); return w; @@ -552,17 +555,18 @@ static GtkWidget *newDP(void) static GtkWidget *newTP(void) { - GtkWidget *w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); + GtkWidget *w; + + w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); setTimeOnly(dateTimePickerWidget(w)); setLabel(dateTimePickerWidget(w)); return w; } -struct uiDateTimePicker -{ - uiUnixControl c; - GtkWidget *widget; - dateTimePickerWidget *d; +struct uiDateTimePicker { + uiUnixControl c; + GtkWidget *widget; + dateTimePickerWidget *d; }; uiUnixControlAllDefaults(uiDateTimePicker) @@ -574,7 +578,7 @@ uiDateTimePicker *finishNewDateTimePicker(GtkWidget *(*fn)(void)) uiUnixNewControl(uiDateTimePicker, d); d->widget = (*fn)(); - d->d = dateTimePickerWidget(d->widget); + d->d = dateTimePickerWidget(d->widget); return d; } diff --git a/deps/libui/gtk/debug.c b/deps/libui/unix/debug.c similarity index 100% rename from deps/libui/gtk/debug.c rename to deps/libui/unix/debug.c diff --git a/deps/libui/gtk/draw.c b/deps/libui/unix/draw.c similarity index 100% rename from deps/libui/gtk/draw.c rename to deps/libui/unix/draw.c diff --git a/deps/libui/gtk/draw.h b/deps/libui/unix/draw.h similarity index 100% rename from deps/libui/gtk/draw.h rename to deps/libui/unix/draw.h diff --git a/deps/libui/gtk/drawmatrix.c b/deps/libui/unix/drawmatrix.c similarity index 100% rename from deps/libui/gtk/drawmatrix.c rename to deps/libui/unix/drawmatrix.c diff --git a/deps/libui/gtk/drawpath.c b/deps/libui/unix/drawpath.c similarity index 100% rename from deps/libui/gtk/drawpath.c rename to deps/libui/unix/drawpath.c diff --git a/deps/libui/gtk/drawtext.c b/deps/libui/unix/drawtext.c similarity index 100% rename from deps/libui/gtk/drawtext.c rename to deps/libui/unix/drawtext.c diff --git a/deps/libui/gtk/editablecombo.c b/deps/libui/unix/editablecombo.c similarity index 100% rename from deps/libui/gtk/editablecombo.c rename to deps/libui/unix/editablecombo.c diff --git a/deps/libui/gtk/entry.c b/deps/libui/unix/entry.c similarity index 100% rename from deps/libui/gtk/entry.c rename to deps/libui/unix/entry.c diff --git a/deps/libui/gtk/fontbutton.c b/deps/libui/unix/fontbutton.c similarity index 100% rename from deps/libui/gtk/fontbutton.c rename to deps/libui/unix/fontbutton.c diff --git a/deps/libui/gtk/form.c b/deps/libui/unix/form.c similarity index 77% rename from deps/libui/gtk/form.c rename to deps/libui/unix/form.c index c2e479526f..54422b3d40 100644 --- a/deps/libui/gtk/form.c +++ b/deps/libui/unix/form.c @@ -1,27 +1,25 @@ // 8 june 2016 #include "uipriv_unix.h" -struct formChild -{ - uiControl *c; - int stretchy; - GtkWidget *label; - gboolean oldhexpand; - GtkAlign oldhalign; - gboolean oldvexpand; - GtkAlign oldvalign; - GBinding *labelBinding; +struct formChild { + uiControl *c; + int stretchy; + GtkWidget *label; + gboolean oldhexpand; + GtkAlign oldhalign; + gboolean oldvexpand; + GtkAlign oldvalign; + GBinding *labelBinding; }; -struct uiForm -{ - uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkGrid *grid; - GArray *children; - int padded; - GtkSizeGroup *stretchygroup; /* ensures all stretchy controls have the same size */ +struct uiForm { + uiUnixControl c; + GtkWidget *widget; + GtkContainer *container; + GtkGrid *grid; + GArray *children; + int padded; + GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size }; uiUnixControlAllDefaultsExceptDestroy(uiForm) @@ -34,19 +32,18 @@ static void uiFormDestroy(uiControl *c) struct formChild *fc; guint i; - /* kill the size group */ + // kill the size group g_object_unref(f->stretchygroup); - /* free all controls */ - for (i = 0; i < f->children->len; i++) - { - fc = ctrl(f, i); - uiControlSetParent(fc->c, NULL); - uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); - uiControlDestroy(fc->c); - gtk_widget_destroy(fc->label); - } + // free all controls + for (i = 0; i < f->children->len; i++) { + fc = ctrl(f, i); + uiControlSetParent(fc->c, NULL); + uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); + uiControlDestroy(fc->c); + gtk_widget_destroy(fc->label); + } g_array_free(f->children, TRUE); - /* and then ourselves */ + // and then ourselves g_object_unref(f->widget); uiFreeControl(uiControl(f)); } @@ -71,7 +68,7 @@ void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) gtk_size_group_add_widget(f->stretchygroup, widget); } else gtk_widget_set_vexpand(widget, FALSE); - /* and make them fill horizontally */ + // and make them fill horizontally gtk_widget_set_hexpand(widget, TRUE); gtk_widget_set_halign(widget, GTK_ALIGN_FILL); @@ -88,7 +85,7 @@ void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) gtk_grid_attach(f->grid, fc.label, 0, row, 1, 1); - /* and make them share visibility so if the control is hidden, so is its label */ + // and make them share visibility so if the control is hidden, so is its label fc.labelBinding = g_object_bind_property(GTK_WIDGET(uiControlHandle(fc.c)), "visible", fc.label, "visible", G_BINDING_SYNC_CREATE); @@ -97,7 +94,7 @@ void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) uiUnixControlSetContainer(uiUnixControl(fc.c), f->container, FALSE); g_array_append_val(f->children, fc); - /* move the widget to the correct place */ + // move the widget to the correct place gtk_container_child_set(f->container, widget, "left-attach", 1, "top-attach", row, diff --git a/deps/libui/gtk/future.c b/deps/libui/unix/future.c similarity index 100% rename from deps/libui/gtk/future.c rename to deps/libui/unix/future.c diff --git a/deps/libui/gtk/graphemes.c b/deps/libui/unix/graphemes.c similarity index 100% rename from deps/libui/gtk/graphemes.c rename to deps/libui/unix/graphemes.c diff --git a/deps/libui/gtk/grid.c b/deps/libui/unix/grid.c similarity index 100% rename from deps/libui/gtk/grid.c rename to deps/libui/unix/grid.c diff --git a/deps/libui/gtk/group.c b/deps/libui/unix/group.c similarity index 100% rename from deps/libui/gtk/group.c rename to deps/libui/unix/group.c diff --git a/deps/libui/gtk/image.c b/deps/libui/unix/image.c similarity index 88% rename from deps/libui/gtk/image.c rename to deps/libui/unix/image.c index 742128f4ff..a79e550f93 100644 --- a/deps/libui/gtk/image.c +++ b/deps/libui/unix/image.c @@ -52,10 +52,8 @@ void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, in cs = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, pixelWidth, pixelHeight, cstride); - - /* TODO */ - if (cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { } - + if (cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) + /* TODO */; cairo_surface_flush(cs); g_ptr_array_add(i->images, cs); } @@ -69,7 +67,7 @@ struct matcher { gboolean foundLarger; }; -/* TODO is this the right algorithm? */ +// TODO is this the right algorithm? static void match(gpointer surface, gpointer data) { cairo_surface_t *cs = (cairo_surface_t *) surface; @@ -83,11 +81,11 @@ static void match(gpointer surface, gpointer data) goto writeMatch; if (x < m->targetX && y < m->targetY) - if (m->foundLarger) /* always prefer larger ones */ + if (m->foundLarger) + // always prefer larger ones return; - - /* we set foundLarger below */ if (x >= m->targetX && y >= m->targetY && !m->foundLarger) + // we set foundLarger below goto writeMatch; x2 = abs(m->targetX - x); @@ -95,11 +93,11 @@ static void match(gpointer surface, gpointer data) if (x2 < m->distX && y2 < m->distY) goto writeMatch; - /* TODO weight one dimension? threshhold? */ + // TODO weight one dimension? threshhold? return; writeMatch: - /* must set this here too; otherwise the first image will never have ths set */ + // must set this here too; otherwise the first image will never have ths set if (x >= m->targetX && y >= m->targetY && !m->foundLarger) m->foundLarger = TRUE; m->best = cs; diff --git a/deps/libui/gtk/label.c b/deps/libui/unix/label.c similarity index 100% rename from deps/libui/gtk/label.c rename to deps/libui/unix/label.c diff --git a/deps/libui/gtk/main.c b/deps/libui/unix/main.c similarity index 66% rename from deps/libui/gtk/main.c rename to deps/libui/unix/main.c index 199c9184ca..2998bf3194 100644 --- a/deps/libui/gtk/main.c +++ b/deps/libui/unix/main.c @@ -6,15 +6,14 @@ uiInitOptions options; const char *uiInit(uiInitOptions *o) { GError *err = NULL; + const char *msg; - options = *o; - - if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) - { - const char *msg = g_strdup(err->message); - g_error_free(err); - return msg; - } + options = *o; + if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) { + msg = g_strdup(err->message); + g_error_free(err); + return msg; + } initAlloc(); loadFutures(); return NULL; @@ -41,9 +40,8 @@ void uiMain(void) static gboolean stepsQuit = FALSE; -/* the only difference is we ignore the return value from gtk_main_iteration_do(), - * since it will always be TRUE if gtk_main() was never called - * gtk_main_iteration_do() will still run the main loop regardless */ +// the only difference is we ignore the return value from gtk_main_iteration_do(), since it will always be TRUE if gtk_main() was never called +// gtk_main_iteration_do() will still run the main loop regardless static gboolean stepsIteration(gboolean block) { gtk_main_iteration_do(block); @@ -57,7 +55,9 @@ void uiMainSteps(void) int uiMainStep(int wait) { - gboolean block = FALSE; + gboolean block; + + block = FALSE; if (wait) block = TRUE; return (*iteration)(block) == FALSE; @@ -70,8 +70,7 @@ static gboolean quit(gpointer data) { if (iteration == stepsIteration) stepsQuit = TRUE; - /* TODO run a gtk_main() here just to do the cleanup steps of - * syncing the clipboard and other stuff gtk_main() does before it returns */ + // TODO run a gtk_main() here just to do the cleanup steps of syncing the clipboard and other stuff gtk_main() does before it returns else gtk_main_quit(); return FALSE; @@ -98,12 +97,12 @@ static gboolean doqueued(gpointer data) void uiQueueMain(void (*f)(void *data), void *data) { - struct queued *q = g_new0(struct queued, 1); + struct queued *q; - /* we have to use g_new0()/g_free() because uiAlloc() - * is only safe to call on the main thread - * for some reason it didn't affect me, but it did affect krakjoe */ - q->f = f; + // we have to use g_new0()/g_free() because uiAlloc() is only safe to call on the main thread + // for some reason it didn't affect me, but it did affect krakjoe + q = g_new0(struct queued, 1); + q->f = f; q->data = data; gdk_threads_add_idle(doqueued, q); } diff --git a/deps/libui/gtk/menu.c b/deps/libui/unix/menu.c similarity index 86% rename from deps/libui/gtk/menu.c rename to deps/libui/unix/menu.c index 6f6906a056..5ccb4a51a3 100644 --- a/deps/libui/gtk/menu.c +++ b/deps/libui/unix/menu.c @@ -121,8 +121,10 @@ int uiMenuItemChecked(uiMenuItem *item) void uiMenuItemSetChecked(uiMenuItem *item, int checked) { - /* use explicit values */ - gboolean c = FALSE; + gboolean c; + + // use explicit values + c = FALSE; if (checked) c = TRUE; setChecked(item, c); @@ -130,55 +132,55 @@ void uiMenuItemSetChecked(uiMenuItem *item, int checked) static uiMenuItem *newItem(uiMenu *m, int type, const char *name) { - uiMenuItem *item; + uiMenuItem *item; - if (menusFinalized) - userbug("You cannot create a new menu item after menus have been finalized."); + if (menusFinalized) + userbug("You cannot create a new menu item after menus have been finalized."); - item = uiNew(uiMenuItem); + item = uiNew(uiMenuItem); - g_array_append_val(m->items, item); + g_array_append_val(m->items, item); - item->type = type; - switch (item->type) { - case typeQuit: - item->name = g_strdup("Quit"); - break; - case typePreferences: - item->name = g_strdup("Preferences..."); - break; - case typeAbout: - item->name = g_strdup("About"); - break; - case typeSeparator: - break; - default: - item->name = g_strdup(name); - break; - } + item->type = type; + switch (item->type) { + case typeQuit: + item->name = g_strdup("Quit"); + break; + case typePreferences: + item->name = g_strdup("Preferences..."); + break; + case typeAbout: + item->name = g_strdup("About"); + break; + case typeSeparator: + break; + default: + item->name = g_strdup(name); + break; + } - if (item->type == typeQuit) { - // can't call uiMenuItemOnClicked() here - item->onClicked = onQuitClicked; - item->onClickedData = NULL; - } else - uiMenuItemOnClicked(item, defaultOnClicked, NULL); + if (item->type == typeQuit) { + // can't call uiMenuItemOnClicked() here + item->onClicked = onQuitClicked; + item->onClickedData = NULL; + } else + uiMenuItemOnClicked(item, defaultOnClicked, NULL); - switch (item->type) { - case typeCheckbox: - item->gtype = GTK_TYPE_CHECK_MENU_ITEM; - break; - case typeSeparator: - item->gtype = GTK_TYPE_SEPARATOR_MENU_ITEM; - break; - default: - item->gtype = GTK_TYPE_MENU_ITEM; - break; - } + switch (item->type) { + case typeCheckbox: + item->gtype = GTK_TYPE_CHECK_MENU_ITEM; + break; + case typeSeparator: + item->gtype = GTK_TYPE_SEPARATOR_MENU_ITEM; + break; + default: + item->gtype = GTK_TYPE_MENU_ITEM; + break; + } - item->windows = g_hash_table_new(g_direct_hash, g_direct_equal); + item->windows = g_hash_table_new(g_direct_hash, g_direct_equal); - return item; + return item; } uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name) diff --git a/deps/libui/gtk/multilineentry.c b/deps/libui/unix/multilineentry.c similarity index 100% rename from deps/libui/gtk/multilineentry.c rename to deps/libui/unix/multilineentry.c diff --git a/deps/libui/gtk/progressbar.c b/deps/libui/unix/progressbar.c similarity index 100% rename from deps/libui/gtk/progressbar.c rename to deps/libui/unix/progressbar.c diff --git a/deps/libui/gtk/radiobuttons.c b/deps/libui/unix/radiobuttons.c similarity index 100% rename from deps/libui/gtk/radiobuttons.c rename to deps/libui/unix/radiobuttons.c diff --git a/deps/libui/gtk/separator.c b/deps/libui/unix/separator.c similarity index 100% rename from deps/libui/gtk/separator.c rename to deps/libui/unix/separator.c diff --git a/deps/libui/gtk/slider.c b/deps/libui/unix/slider.c similarity index 100% rename from deps/libui/gtk/slider.c rename to deps/libui/unix/slider.c diff --git a/deps/libui/gtk/spinbox.c b/deps/libui/unix/spinbox.c similarity index 77% rename from deps/libui/gtk/spinbox.c rename to deps/libui/unix/spinbox.c index 8ca01f774a..90a5d3c1db 100644 --- a/deps/libui/gtk/spinbox.c +++ b/deps/libui/unix/spinbox.c @@ -32,10 +32,9 @@ int uiSpinboxValue(uiSpinbox *s) void uiSpinboxSetValue(uiSpinbox *s, int value) { - /* we need to inhibit sending of ::value-changed - * because this WILL send a ::value-changed otherwise */ + // we need to inhibit sending of ::value-changed because this WILL send a ::value-changed otherwise g_signal_handler_block(s->spinButton, s->onChangedSignal); - /* this clamps for us */ + // this clamps for us gtk_spin_button_set_value(s->spinButton, (gdouble) value); g_signal_handler_unblock(s->spinButton, s->onChangedSignal); } @@ -48,23 +47,22 @@ void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *, void *), void *data uiSpinbox *uiNewSpinbox(int min, int max) { + uiSpinbox *s; int temp; - uiSpinbox *s = NULL; - if (min >= max) - { - temp = min; - min = max; - max = temp; - } + if (min >= max) { + temp = min; + min = max; + max = temp; + } uiUnixNewControl(uiSpinbox, s); - s->widget = gtk_spin_button_new_with_range(min, max, 1); - s->entry = GTK_ENTRY(s->widget); + s->widget = gtk_spin_button_new_with_range(min, max, 1); + s->entry = GTK_ENTRY(s->widget); s->spinButton = GTK_SPIN_BUTTON(s->widget); - /* ensure integers, just to be safe */ + // ensure integers, just to be safe gtk_spin_button_set_digits(s->spinButton, 0); s->onChangedSignal = g_signal_connect(s->spinButton, "value-changed", G_CALLBACK(onChanged), s); diff --git a/deps/libui/gtk/stddialogs.c b/deps/libui/unix/stddialogs.c similarity index 100% rename from deps/libui/gtk/stddialogs.c rename to deps/libui/unix/stddialogs.c diff --git a/deps/libui/gtk/tab.c b/deps/libui/unix/tab.c similarity index 67% rename from deps/libui/gtk/tab.c rename to deps/libui/unix/tab.c index 30699e5c64..552e0e31a5 100644 --- a/deps/libui/gtk/tab.c +++ b/deps/libui/unix/tab.c @@ -15,18 +15,16 @@ uiUnixControlAllDefaultsExceptDestroy(uiTab) static void uiTabDestroy(uiControl *c) { + uiTab *t = uiTab(c); guint i; - uiTab *t = uiTab(c); - struct child *page = NULL; + struct child *page; - for (i = 0; i < t->pages->len; i++) - { + for (i = 0; i < t->pages->len; i++) { page = g_array_index(t->pages, struct child *, i); childDestroy(page); } - g_array_free(t->pages, TRUE); - /* and free ourselves */ + // and free ourselves g_object_unref(t->widget); uiFreeControl(uiControl(t)); } @@ -38,8 +36,10 @@ void uiTabAppend(uiTab *t, const char *name, uiControl *child) void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) { - /* this will create a tab, because of gtk_container_add() */ - struct child *page = newChildWithBox(child, uiControl(t), t->container, 0); + struct child *page; + + // this will create a tab, because of gtk_container_add() + page = newChildWithBox(child, uiControl(t), t->container, 0); gtk_notebook_set_tab_label_text(t->notebook, childBox(page), name); gtk_notebook_reorder_child(t->notebook, childBox(page), n); @@ -49,10 +49,10 @@ void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) void uiTabDelete(uiTab *t, int n) { - struct child *page = g_array_index(t->pages, struct child *, n); - /* this will remove the tab, - * because gtk_widget_destroy() calls gtk_container_remove() */ + struct child *page; + page = g_array_index(t->pages, struct child *, n); + // this will remove the tab, because gtk_widget_destroy() calls gtk_container_remove() childRemove(page); g_array_remove_index(t->pages, n); } @@ -64,28 +64,30 @@ int uiTabNumPages(uiTab *t) int uiTabMargined(uiTab *t, int n) { - struct child *page = g_array_index(t->pages, struct child *, n); + struct child *page; + page = g_array_index(t->pages, struct child *, n); return childFlag(page); } void uiTabSetMargined(uiTab *t, int n, int margined) { - struct child *page = g_array_index(t->pages, struct child *, n); + struct child *page; + page = g_array_index(t->pages, struct child *, n); childSetFlag(page, margined); childSetMargined(page, childFlag(page)); } uiTab *uiNewTab(void) { - uiTab *t = NULL;; + uiTab *t; uiUnixNewControl(uiTab, t); - t->widget = gtk_notebook_new(); + t->widget = gtk_notebook_new(); t->container = GTK_CONTAINER(t->widget); - t->notebook = GTK_NOTEBOOK(t->widget); + t->notebook = GTK_NOTEBOOK(t->widget); gtk_notebook_set_scrollable(t->notebook, TRUE); diff --git a/deps/libui/gtk/text.c b/deps/libui/unix/text.c similarity index 100% rename from deps/libui/gtk/text.c rename to deps/libui/unix/text.c diff --git a/deps/libui/gtk/uipriv_unix.h b/deps/libui/unix/uipriv_unix.h similarity index 89% rename from deps/libui/gtk/uipriv_unix.h rename to deps/libui/unix/uipriv_unix.h index 3015c30172..33ff1e3553 100644 --- a/deps/libui/gtk/uipriv_unix.h +++ b/deps/libui/unix/uipriv_unix.h @@ -1,11 +1,11 @@ -/* 22 april 2015 */ +// 22 april 2015 #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40 #define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40 #define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10 #define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10 #include #include -#include /* see drawtext.c */ +#include // see drawtext.c #include #include #include @@ -18,19 +18,19 @@ #define gtkXPadding 12 #define gtkYPadding 6 -/* menu.c */ +// menu.c extern GtkWidget *makeMenubar(uiWindow *); extern void freeMenubar(GtkWidget *); extern void uninitMenus(void); -/* alloc.c */ +// alloc.c extern void initAlloc(void); extern void uninitAlloc(void); -/* util.c */ +// util.c extern void setMargined(GtkContainer *, int); -/* child.c */ +// child.c extern struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer); extern struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined); extern void childRemove(struct child *c); @@ -41,25 +41,25 @@ extern void childSetFlag(struct child *c, int flag); extern GtkWidget *childBox(struct child *c); extern void childSetMargined(struct child *c, int margined); -/* draw.c */ +// draw.c extern uiDrawContext *newContext(cairo_t *); extern void freeContext(uiDrawContext *); -/* drawtext.c */ +// drawtext.c extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add); extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc); -/* graphemes.c */ +// graphemes.c extern ptrdiff_t *graphemes(const char *text, PangoContext *context); -/* image.c */ +// image.c /*TODO remove this*/typedef struct uiImage uiImage; extern cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w); -/* cellrendererbutton.c */ +// cellrendererbutton.c extern GtkCellRenderer *newCellRendererButton(void); -/* future.c */ +// future.c extern void loadFutures(void); extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha); extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name); diff --git a/deps/libui/gtk/util.c b/deps/libui/unix/util.c similarity index 100% rename from deps/libui/gtk/util.c rename to deps/libui/unix/util.c diff --git a/deps/libui/gtk/window.c b/deps/libui/unix/window.c similarity index 81% rename from deps/libui/gtk/window.c rename to deps/libui/unix/window.c index 0251f64943..ea9ba370f4 100644 --- a/deps/libui/gtk/window.c +++ b/deps/libui/unix/window.c @@ -1,43 +1,40 @@ // 11 june 2015 #include "uipriv_unix.h" -struct uiWindow -{ - uiUnixControl c; +struct uiWindow { + uiUnixControl c; - GtkWidget *widget; - GtkContainer *container; - GtkWindow *window; + GtkWidget *widget; + GtkContainer *container; + GtkWindow *window; - GtkWidget *vboxWidget; - GtkContainer *vboxContainer; - GtkBox *vbox; + GtkWidget *vboxWidget; + GtkContainer *vboxContainer; + GtkBox *vbox; - GtkWidget *childHolderWidget; - GtkContainer *childHolderContainer; + GtkWidget *childHolderWidget; + GtkContainer *childHolderContainer; - GtkWidget *menubar; + GtkWidget *menubar; - uiControl *child; - int margined; + uiControl *child; + int margined; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - void (*onContentSizeChanged)(uiWindow *, void *); - void *onContentSizeChangedData; - gboolean fullscreen; + int (*onClosing)(uiWindow *, void *); + void *onClosingData; + void (*onContentSizeChanged)(uiWindow *, void *); + void *onContentSizeChangedData; + gboolean fullscreen; }; static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) { uiWindow *w = uiWindow(data); - /* manually destroy the window ourselves; don't let - * the delete-event handler do it */ + // manually destroy the window ourselves; don't let the delete-event handler do it if ((*(w->onClosing))(w, w->onClosingData)) uiControlDestroy(uiControl(w)); - /* don't continue to the default delete-event handler; - * we destroyed the window by now */ + // don't continue to the default delete-event handler; we destroyed the window by now return TRUE; } @@ -45,7 +42,7 @@ static void onSizeAllocate(GtkWidget *widget, GdkRectangle *allocation, gpointer { uiWindow *w = uiWindow(data); - /* TODO deal with spurious size-allocates */ + // TODO deal with spurious size-allocates (*(w->onContentSizeChanged))(w, w->onContentSizeChangedData); } @@ -56,30 +53,28 @@ static int defaultOnClosing(uiWindow *w, void *data) static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data) { - /* do nothing */ + // do nothing } static void uiWindowDestroy(uiControl *c) { uiWindow *w = uiWindow(c); - /* first hide ourselves */ + // first hide ourselves gtk_widget_hide(w->widget); - /* now destroy the child */ - if (w->child != NULL) - { - uiControlSetParent(w->child, NULL); - uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE); - uiControlDestroy(w->child); - } - /* now destroy the menus, if any */ + // now destroy the child + if (w->child != NULL) { + uiControlSetParent(w->child, NULL); + uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE); + uiControlDestroy(w->child); + } + // now destroy the menus, if any if (w->menubar != NULL) freeMenubar(w->menubar); gtk_widget_destroy(w->childHolderWidget); gtk_widget_destroy(w->vboxWidget); - /* and finally free ourselves - * use gtk_widget_destroy() instead of g_object_unref() - * because GTK+ has internal references (see #165) */ + // and finally free ourselves + // use gtk_widget_destroy() instead of g_object_unref() because GTK+ has internal references (see #165) gtk_widget_destroy(w->widget); uiFreeControl(uiControl(w)); } @@ -107,11 +102,9 @@ static void uiWindowShow(uiControl *c) { uiWindow *w = uiWindow(c); - /* don't use gtk_widget_show_all() as that - * will show all children, regardless of user settings - * don't use gtk_widget_show(); that doesn't bring to - * front or give keyboard focus - * (gtk_window_present() does call gtk_widget_show() though) */ + // don't use gtk_widget_show_all() as that will show all children, regardless of user settings + // don't use gtk_widget_show(); that doesn't bring to front or give keyboard focus + // (gtk_window_present() does call gtk_widget_show() though) gtk_window_present(w->window); } @@ -119,8 +112,7 @@ uiUnixControlDefaultHide(uiWindow) uiUnixControlDefaultEnabled(uiWindow) uiUnixControlDefaultEnable(uiWindow) uiUnixControlDefaultDisable(uiWindow) - -/* TODO? */ +// TODO? uiUnixControlDefaultSetContainer(uiWindow) char *uiWindowTitle(uiWindow *w) diff --git a/deps/libui/win32/datetimepicker.cpp b/deps/libui/win32/datetimepicker.cpp deleted file mode 100644 index c14359379d..0000000000 --- a/deps/libui/win32/datetimepicker.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* 22 may 2015 */ -#include "uipriv_windows.hpp" - -struct uiDateTimePicker { - uiWindowsControl c; - HWND hwnd; -}; - -#ifndef DTM_GETIDEALSIZE -#define DTM_GETIDEALSIZE 0x100f -#endif - -/* utility functions */ - -#define GLI(what, buf, n) GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, what, buf, n) - -/* The real date/time picker does a manual replacement of "yy" with "yyyy" for DTS_SHORTDATECENTURYFORMAT. - * Because we're also duplicating its functionality (see below), we have to do it too. */ -static WCHAR *expandYear(WCHAR *dts, int n) -{ - WCHAR *p = NULL; - int ny = 0; - - /* allocate more than we need to be safe */ - WCHAR *out = (WCHAR *) uiAlloc((n * 3) * sizeof (WCHAR), "WCHAR[]"); - WCHAR *q = out; - - for (p = dts; *p != L'\0'; p++) - { - /* first, if the current character is a y, increment the number of consecutive ys - * otherwise, stop counting, and if there were only two, add two more to make four */ - if (*p != L'y') { - if (ny == 2) { - *q++ = L'y'; - *q++ = L'y'; - } - ny = 0; - } else - ny++; - /* next, handle quoted blocks - * we do this AFTER the above so yy'abc' becomes yyyy'abc' and not yy'abc'yy - * this handles the case of 'a''b' elegantly as well */ - if (*p == L'\'') { - /* copy the opening quote */ - *q++ = *p; - /* copy the contents */ - for (;;) { - p++; - if (*p == L'\'') - break; - if (*p == L'\0') - implbug("unterminated quote in system-provided locale date string in expandYear()"); - *q++ = *p; - } - /* and fall through to copy the closing quote */ - } - /* copy the current character */ - *q++ = *p; - } - /* handle trailing yy */ - if (ny == 2) { - *q++ = L'y'; - *q++ = L'y'; - } - *q++ = L'\0'; - return out; -} - -/* Windows has no combined date/time prebuilt constant; - * we have to build the format string ourselves - * TODO use a default format if one fails */ -static void setDateTimeFormat(HWND hwnd) -{ - WCHAR *unexpandedDate, *date; - WCHAR *time; - WCHAR *datetime; - int ntime; - int ndate = GLI(LOCALE_SSHORTDATE, NULL, 0); - - if (ndate == 0) - logLastError(L"error getting date string length"); - date = (WCHAR *) uiAlloc(ndate * sizeof (WCHAR), "WCHAR[]"); - if (GLI(LOCALE_SSHORTDATE, date, ndate) == 0) - logLastError(L"error geting date string"); - unexpandedDate = date; /* so we can free it */ - date = expandYear(unexpandedDate, ndate); - uiFree(unexpandedDate); - - ntime = GLI(LOCALE_STIMEFORMAT, NULL, 0); - if (ndate == 0) - logLastError(L"error getting time string length"); - time = (WCHAR *) uiAlloc(ntime * sizeof (WCHAR), "WCHAR[]"); - if (GLI(LOCALE_STIMEFORMAT, time, ntime) == 0) - logLastError(L"error geting time string"); - - datetime = strf(L"%s %s", date, time); - if (SendMessageW(hwnd, DTM_SETFORMAT, 0, (LPARAM) datetime) == 0) - logLastError(L"error applying format string to date/time picker"); - - uiFree(datetime); - uiFree(time); - uiFree(date); -} - -/* control implementation */ - -static void uiDateTimePickerDestroy(uiControl *c) -{ - uiDateTimePicker *d = uiDateTimePicker(c); - - uiWindowsUnregisterReceiveWM_WININICHANGE(d->hwnd); - uiWindowsEnsureDestroyWindow(d->hwnd); - uiFreeControl(uiControl(d)); -} - -uiWindowsControlAllDefaultsExceptDestroy(uiDateTimePicker) - -/* the height returned from DTM_GETIDEALSIZE is unreliable; see http://stackoverflow.com/questions/30626549/what-is-the-proper-use-of-dtm-getidealsize-treating-the-returned-size-as-pixels - * from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing */ -#define entryHeight 14 - -static void uiDateTimePickerMinimumSize(uiWindowsControl *c, int *width, int *height) -{ - SIZE s; - uiWindowsSizing sizing; - uiDateTimePicker *d = uiDateTimePicker(c); - int y; - - s.cx = 0; - s.cy = 0; - SendMessageW(d->hwnd, DTM_GETIDEALSIZE, 0, (LPARAM) (&s)); - *width = s.cx; - - y = entryHeight; - uiWindowsGetSizing(d->hwnd, &sizing); - uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y); - *height = y; -} - -static uiDateTimePicker *finishNewDateTimePicker(DWORD style) -{ - uiDateTimePicker *d; - - uiWindowsNewControl(uiDateTimePicker, d); - - d->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, - DATETIMEPICK_CLASSW, L"", - style | WS_TABSTOP, - hInstance, NULL, - TRUE); - - /* automatically update date/time format when user changes locale settings - * for the standard styles, this is in the date-time picker itself - * for our date/time mode, we do it in a subclass assigned in uiNewDateTimePicker() */ - uiWindowsRegisterReceiveWM_WININICHANGE(d->hwnd); - - return d; -} - -static LRESULT CALLBACK datetimepickerSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, - LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - switch (uMsg) - { - case WM_WININICHANGE: - // we can optimize this by only doing it when the real date/time picker does it - // unfortunately, I don't know when that is :/ - // hopefully this won't hurt - setDateTimeFormat(hwnd); - return 0; - case WM_NCDESTROY: - if (RemoveWindowSubclass(hwnd, datetimepickerSubProc, uIdSubclass) == FALSE) - logLastError(L"error removing date-time picker locale change handling subclass"); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -uiDateTimePicker *uiNewDateTimePicker(void) -{ - uiDateTimePicker *d = finishNewDateTimePicker(0); - - setDateTimeFormat(d->hwnd); - if (SetWindowSubclass(d->hwnd, datetimepickerSubProc, 0, (DWORD_PTR) d) == FALSE) - logLastError(L"error subclassing date-time-picker to assist in locale change handling"); - /* TODO set a suitable default in this case */ - return d; -} - -uiDateTimePicker *uiNewDatePicker(void) -{ - return finishNewDateTimePicker(DTS_SHORTDATECENTURYFORMAT); -} - -uiDateTimePicker *uiNewTimePicker(void) -{ - return finishNewDateTimePicker(DTS_TIMEFORMAT); -} diff --git a/deps/libui/win32/text.cpp b/deps/libui/win32/text.cpp deleted file mode 100644 index d3e0131eab..0000000000 --- a/deps/libui/win32/text.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* 9 april 2015 */ -#include "uipriv_windows.hpp" - -WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len) -{ - WCHAR *text = NULL; - LRESULT n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); - - if (len != NULL) - *len = n; - /* WM_GETTEXTLENGTH does not include the null terminator */ - text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); - /* note the comparison: the size includes the - * null terminator, but the return does not */ - if (GetWindowTextW(hwnd, text, n + 1) != n) - { - logLastError(L"error getting window text"); - /* on error, return an empty string to be safe */ - *text = L'\0'; - if (len != NULL) - *len = 0; - } - return text; -} - -WCHAR *windowText(HWND hwnd) -{ - return windowTextAndLen(hwnd, NULL); -} - -void setWindowText(HWND hwnd, WCHAR *wtext) -{ - if (SetWindowTextW(hwnd, wtext) == 0) - logLastError(L"error setting window text"); -} - -void uiFreeText(char *text) -{ - uiFree(text); -} - -int uiWindowsWindowTextWidth(HWND hwnd) -{ - LRESULT len; - HDC dc; - HFONT prevfont; - SIZE size; - WCHAR *text = windowTextAndLen(hwnd, &len); - - size.cx = 0; - size.cy = 0; - - if (len == 0) /* no text; nothing to do */ - goto noTextOrError; - - /* now we can do the calculations */ - dc = GetDC(hwnd); - if (dc == NULL) - { - logLastError(L"error getting DC"); - /* on any error, assume no text */ - goto noTextOrError; - } - prevfont = (HFONT) SelectObject(dc, hMessageFont); - if (prevfont == NULL) - { - logLastError(L"error loading control font into device context"); - ReleaseDC(hwnd, dc); - goto noTextOrError; - } - if (GetTextExtentPoint32W(dc, text, len, &size) == 0) - { - logLastError(L"error getting text extent point"); - /* continue anyway, assuming size is 0 */ - size.cx = 0; - size.cy = 0; - } - /* continue on errors; we got what we want */ - if (SelectObject(dc, prevfont) != hMessageFont) - logLastError(L"error restoring previous font into device context"); - if (ReleaseDC(hwnd, dc) == 0) - logLastError(L"error releasing DC"); - - uiFree(text); - return size.cx; - -noTextOrError: - uiFree(text); - return 0; -} - -char *uiWindowsWindowText(HWND hwnd) -{ - WCHAR *wtext = windowText(hwnd); - char *text = toUTF8(wtext); - uiFree(wtext); - return text; -} - -void uiWindowsSetWindowText(HWND hwnd, const char *text) -{ - WCHAR *wtext = toUTF16(text); - setWindowText(hwnd, wtext); - uiFree(wtext); -} diff --git a/deps/libui/win32/utilwin.cpp b/deps/libui/win32/utilwin.cpp deleted file mode 100644 index 9b9a3ac8f4..0000000000 --- a/deps/libui/win32/utilwin.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* 14 may 2015 */ -#include "uipriv_windows.hpp" -#include "../../verbosity.h" - -/* The utility window is a special window that performs certain tasks internal to libui. - * It is not a message-only window, and it is always hidden and disabled. - * Its roles: - * - It is the initial parent of all controls. When a control loses its parent, it also becomes that control's parent. - * - It handles WM_QUERYENDSESSION and console end session requests. - * - It handles WM_WININICHANGE and forwards the message to any child windows that request it. - * - It handles executing functions queued to run by uiQueueMain(). - */ - -#define utilWindowClass L"libui_utilWindowClass" - -HWND utilWindow; - -static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - void (*qf)(void *); - LRESULT lResult; - - if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) - return lResult; - - switch (uMsg) - { - case WM_QUERYENDSESSION: - /* TODO block handler */ - if (shouldQuit()) - { - uiQuit(); - return TRUE; - } - return FALSE; - case WM_WININICHANGE: - issueWM_WININICHANGE(wParam, lParam); - return 0; - case msgQueued: - qf = (void (*)(void *)) wParam; - (*qf)((void *) lParam); - return 0; - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = utilWindowClass; - wc.lpfnWndProc = utilWindowWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - if (RegisterClass(&wc) == 0) - { - RARCH_ERR("Cannot register class.\n"); - /* see init.cpp for an explanation of the =s */ - return "=registering utility window class"; - } - - utilWindow = CreateWindowExW(0, - utilWindowClass, L"libui utility window", - WS_OVERLAPPEDWINDOW, - 0, 0, 100, 100, - NULL, NULL, hInstance, NULL); - if (utilWindow == NULL) - { - RARCH_ERR("Cannot create window.\n"); - return "=creating utility window"; - } - /* and just to be safe */ - EnableWindow(utilWindow, FALSE); - - return NULL; -} - -void uninitUtilWindow(void) -{ - if (DestroyWindow(utilWindow) == 0) - logLastError(L"error destroying utility window"); - if (UnregisterClass(utilWindowClass, hInstance) == 0) - logLastError(L"error unregistering utility window class"); -} diff --git a/deps/libui/win32/winextra.h b/deps/libui/win32/winextra.h deleted file mode 100644 index 6d0bb3ee7d..0000000000 --- a/deps/libui/win32/winextra.h +++ /dev/null @@ -1,150 +0,0 @@ -/* This file contains some Vista SDK stuff that is missing from the current - mingw-w64 headers */ - -#ifndef WINEXTRA_H -#define WINEXTRA_H - -/* winuser.h */ - -#if (_WIN32_WINNT >= 0x0600) - WINUSERAPI WINBOOL WINAPI SetProcessDPIAware(VOID); - WINUSERAPI WINBOOL WINAPI IsProcessDPIAware(VOID); -#endif - -/* commctrl.h */ - -#ifndef NOTASKDIALOG -#if (NTDDI_VERSION >= NTDDI_VISTA) -#include -#define TD_WARNING_ICON MAKEINTRESOURCEW(-1) -#define TD_ERROR_ICON MAKEINTRESOURCEW(-2) -#define TD_INFORMATION_ICON MAKEINTRESOURCEW(-3) -#define TD_SHIELD_ICON MAKEINTRESOURCEW(-4) - - typedef HRESULT (CALLBACK *PFTASKDIALOGCALLBACK)(HWND hwnd,UINT uNotification,WPARAM wParam,LPARAM lParam,LONG_PTR dwRefData); - - enum _TASKDIALOG_FLAGS { - TDF_ENABLE_HYPERLINKS = 0x0001, - TDF_USE_HICON_MAIN = 0x0002, - TDF_USE_HICON_FOOTER = 0x0004, - TDF_ALLOW_DIALOG_CANCELLATION = 0x0008, - TDF_USE_COMMAND_LINKS = 0x0010, - TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020, - TDF_EXPAND_FOOTER_AREA = 0x0040, - TDF_EXPANDED_BY_DEFAULT = 0x0080, - TDF_VERIFICATION_FLAG_CHECKED = 0x0100, - TDF_SHOW_PROGRESS_BAR = 0x0200, - TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400, - TDF_CALLBACK_TIMER = 0x0800, - TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000, - TDF_RTL_LAYOUT = 0x2000, - TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000, - TDF_CAN_BE_MINIMIZED = 0x8000, - TDIF_SIZE_TO_CONTENT = 0x1000000, - TDF_SIZE_TO_CONTENT = 0x1000000 - }; - typedef int TASKDIALOG_FLAGS; - - enum _TASKDIALOG_COMMON_BUTTON_FLAGS { - TDCBF_OK_BUTTON = 0x01, - TDCBF_YES_BUTTON = 0x02, - TDCBF_NO_BUTTON = 0x04, - TDCBF_CANCEL_BUTTON = 0x08, - TDCBF_RETRY_BUTTON = 0x10, - TDCBF_CLOSE_BUTTON = 0x20 - }; - typedef int TASKDIALOG_COMMON_BUTTON_FLAGS; - - typedef enum _TASKDIALOG_NOTIFICATIONS { - TDN_CREATED = 0, - TDN_NAVIGATED = 1, - TDN_BUTTON_CLICKED = 2, - TDN_HYPERLINK_CLICKED = 3, - TDN_TIMER = 4, - TDN_DESTROYED = 5, - TDN_RADIO_BUTTON_CLICKED = 6, - TDN_DIALOG_CONSTRUCTED = 7, - TDN_VERIFICATION_CLICKED = 8, - TDN_HELP = 9, - TDN_EXPANDO_BUTTON_CLICKED = 10 - } TASKDIALOG_NOTIFICATIONS; - - typedef enum _TASKDIALOG_MESSAGES { - TDM_NAVIGATE_PAGE = WM_USER + 101, - TDM_CLICK_BUTTON = WM_USER + 102, - TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103, - TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104, - TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105, - TDM_SET_PROGRESS_BAR_POS = WM_USER + 106, - TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107, - TDM_SET_ELEMENT_TEXT = WM_USER + 108, - TDM_CLICK_RADIO_BUTTON = WM_USER + 110, - TDM_ENABLE_BUTTON = WM_USER + 111, - TDM_ENABLE_RADIO_BUTTON = WM_USER + 112, - TDM_CLICK_VERIFICATION = WM_USER + 113, - TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114, - TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115, - TDM_UPDATE_ICON = WM_USER + 116 - } TASKDIALOG_MESSAGES; - - typedef enum _TASKDIALOG_ELEMENTS { - TDE_CONTENT, - TDE_EXPANDED_INFORMATION, - TDE_FOOTER, - TDE_MAIN_INSTRUCTION - } TASKDIALOG_ELEMENTS; - - typedef enum _TASKDIALOG_ICON_ELEMENTS { - TDIE_ICON_MAIN, - TDIE_ICON_FOOTER - } TASKDIALOG_ICON_ELEMENTS; - - typedef struct _TASKDIALOG_BUTTON { - int nButtonID; - PCWSTR pszButtonText; - } TASKDIALOG_BUTTON; - - typedef struct _TASKDIALOGCONFIG { - UINT cbSize; - HWND hwndParent; - HINSTANCE hInstance; - TASKDIALOG_FLAGS dwFlags; - TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons; - PCWSTR pszWindowTitle; - __C89_NAMELESS union { - HICON hMainIcon; - PCWSTR pszMainIcon; - } DUMMYUNIONNAME; - PCWSTR pszMainInstruction; - PCWSTR pszContent; - UINT cButtons; - const TASKDIALOG_BUTTON *pButtons; - int nDefaultButton; - UINT cRadioButtons; - const TASKDIALOG_BUTTON *pRadioButtons; - int nDefaultRadioButton; - PCWSTR pszVerificationText; - PCWSTR pszExpandedInformation; - PCWSTR pszExpandedControlText; - PCWSTR pszCollapsedControlText; - __C89_NAMELESS union { - HICON hFooterIcon; - PCWSTR pszFooterIcon; - } DUMMYUNIONNAME2; - PCWSTR pszFooter; - PFTASKDIALOGCALLBACK pfCallback; - LONG_PTR lpCallbackData; - UINT cxWidth; - } TASKDIALOGCONFIG; - - WINCOMMCTRLAPI HRESULT WINAPI TaskDialog(HWND hwndParent,HINSTANCE hInstance,PCWSTR pszWindowTitle,PCWSTR pszMainInstruction,PCWSTR pszContent,TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons,PCWSTR pszIcon,int *pnButton); - WINCOMMCTRLAPI HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig,int *pnButton,int *pnRadioButton,BOOL *pfVerificationFlagChecked); -#include -#endif -#endif - -/* dwmapi.h */ - -HRESULT WINAPI DwmFlush(VOID); - -#endif diff --git a/deps/libui/windows/CMakeLists.txt b/deps/libui/windows/CMakeLists.txt new file mode 100644 index 0000000000..4695eb4f6e --- /dev/null +++ b/deps/libui/windows/CMakeLists.txt @@ -0,0 +1,91 @@ +# 3 june 2016 + +list(APPEND _LIBUI_SOURCES + windows/alloc.cpp + windows/area.cpp + windows/areadraw.cpp + windows/areaevents.cpp + windows/areascroll.cpp + windows/areautil.cpp + windows/box.cpp + windows/button.cpp + windows/checkbox.cpp + windows/colorbutton.cpp + windows/colordialog.cpp + windows/combobox.cpp + windows/container.cpp + windows/control.cpp + windows/d2dscratch.cpp + windows/datetimepicker.cpp + windows/debug.cpp + windows/draw.cpp + windows/drawmatrix.cpp + windows/drawpath.cpp + windows/drawtext.cpp + windows/dwrite.cpp + windows/editablecombo.cpp + windows/entry.cpp + windows/events.cpp + windows/fontbutton.cpp + windows/fontdialog.cpp + windows/form.cpp + windows/graphemes.cpp + windows/grid.cpp + windows/group.cpp + windows/init.cpp + windows/label.cpp + windows/main.cpp + windows/menu.cpp + windows/multilineentry.cpp + windows/parent.cpp + windows/progressbar.cpp + windows/radiobuttons.cpp + windows/separator.cpp + windows/sizing.cpp + windows/slider.cpp + windows/spinbox.cpp + windows/stddialogs.cpp + windows/tab.cpp + windows/tabpage.cpp + windows/text.cpp + windows/utf16.cpp + windows/utilwin.cpp + windows/window.cpp + windows/winpublic.cpp + windows/winutil.cpp + windows/resources.rc +) +set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) + +list(APPEND _LIBUI_INCLUDEDIRS + windows +) +set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) + +# Windows won't link resources in static libraries; we need to provide the libui.res file in this case. +set(_LIBUINAME libui PARENT_SCOPE) +if(NOT BUILD_SHARED_LIBS) + set(_LIBUI_STATIC_RES ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/libui.res PARENT_SCOPE) +endif() +macro(_handle_static) + # TODO this full path feels hacky + add_custom_command( + TARGET libui POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E copy $/CMakeFiles/libui.dir/windows/resources.rc.* ${_LIBUI_STATIC_RES} + COMMENT "Copying libui.res") +endmacro() + +# notice that usp10 comes before gdi32 +# TODO prune this list +set(_LIBUI_LIBS + user32 kernel32 usp10 gdi32 comctl32 uxtheme msimg32 comdlg32 d2d1 dwrite ole32 oleaut32 oleacc uuid +PARENT_SCOPE) + +if(NOT MSVC) + if(BUILD_SHARED_LIBS) + message(FATAL_ERROR + "Sorry, but libui for Windows can currently only be built as a static library with MinGW. You will need to either build as a static library or switch to MSVC." + ) + endif() +endif() diff --git a/deps/libui/win32/_uipriv_migrate.hpp b/deps/libui/windows/_uipriv_migrate.hpp similarity index 100% rename from deps/libui/win32/_uipriv_migrate.hpp rename to deps/libui/windows/_uipriv_migrate.hpp diff --git a/deps/libui/win32/alloc.cpp b/deps/libui/windows/alloc.cpp similarity index 100% rename from deps/libui/win32/alloc.cpp rename to deps/libui/windows/alloc.cpp diff --git a/deps/libui/win32/area.cpp b/deps/libui/windows/area.cpp similarity index 100% rename from deps/libui/win32/area.cpp rename to deps/libui/windows/area.cpp diff --git a/deps/libui/win32/area.hpp b/deps/libui/windows/area.hpp similarity index 100% rename from deps/libui/win32/area.hpp rename to deps/libui/windows/area.hpp diff --git a/deps/libui/win32/areadraw.cpp b/deps/libui/windows/areadraw.cpp similarity index 100% rename from deps/libui/win32/areadraw.cpp rename to deps/libui/windows/areadraw.cpp diff --git a/deps/libui/win32/areaevents.cpp b/deps/libui/windows/areaevents.cpp similarity index 100% rename from deps/libui/win32/areaevents.cpp rename to deps/libui/windows/areaevents.cpp diff --git a/deps/libui/win32/areascroll.cpp b/deps/libui/windows/areascroll.cpp similarity index 99% rename from deps/libui/win32/areascroll.cpp rename to deps/libui/windows/areascroll.cpp index 1797063a9d..f18d0ad874 100644 --- a/deps/libui/win32/areascroll.cpp +++ b/deps/libui/windows/areascroll.cpp @@ -100,10 +100,11 @@ static void scroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, static void wheelscroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam) { + int delta; int lines; UINT scrollAmount; - int delta = GET_WHEEL_DELTA_WPARAM(wParam); + delta = GET_WHEEL_DELTA_WPARAM(wParam); if (SystemParametersInfoW(p->wheelSPIAction, 0, &scrollAmount, 0) == 0) // TODO use scrollAmount == 3 (for both v and h) instead? logLastError(L"error getting area wheel scroll amount"); diff --git a/deps/libui/win32/areautil.cpp b/deps/libui/windows/areautil.cpp similarity index 100% rename from deps/libui/win32/areautil.cpp rename to deps/libui/windows/areautil.cpp diff --git a/deps/libui/win32/box.cpp b/deps/libui/windows/box.cpp similarity index 100% rename from deps/libui/win32/box.cpp rename to deps/libui/windows/box.cpp diff --git a/deps/libui/win32/button.cpp b/deps/libui/windows/button.cpp similarity index 100% rename from deps/libui/win32/button.cpp rename to deps/libui/windows/button.cpp diff --git a/deps/libui/win32/checkbox.cpp b/deps/libui/windows/checkbox.cpp similarity index 100% rename from deps/libui/win32/checkbox.cpp rename to deps/libui/windows/checkbox.cpp diff --git a/deps/libui/win32/colorbutton.cpp b/deps/libui/windows/colorbutton.cpp similarity index 100% rename from deps/libui/win32/colorbutton.cpp rename to deps/libui/windows/colorbutton.cpp diff --git a/deps/libui/win32/colordialog.cpp b/deps/libui/windows/colordialog.cpp similarity index 100% rename from deps/libui/win32/colordialog.cpp rename to deps/libui/windows/colordialog.cpp diff --git a/deps/libui/win32/combobox.cpp b/deps/libui/windows/combobox.cpp similarity index 100% rename from deps/libui/win32/combobox.cpp rename to deps/libui/windows/combobox.cpp diff --git a/deps/libui/win32/compilerver.hpp b/deps/libui/windows/compilerver.hpp similarity index 100% rename from deps/libui/win32/compilerver.hpp rename to deps/libui/windows/compilerver.hpp diff --git a/deps/libui/win32/container.cpp b/deps/libui/windows/container.cpp similarity index 100% rename from deps/libui/win32/container.cpp rename to deps/libui/windows/container.cpp diff --git a/deps/libui/win32/control.cpp b/deps/libui/windows/control.cpp similarity index 100% rename from deps/libui/win32/control.cpp rename to deps/libui/windows/control.cpp diff --git a/deps/libui/win32/d2dscratch.cpp b/deps/libui/windows/d2dscratch.cpp similarity index 100% rename from deps/libui/win32/d2dscratch.cpp rename to deps/libui/windows/d2dscratch.cpp diff --git a/deps/libui/windows/datetimepicker.cpp b/deps/libui/windows/datetimepicker.cpp new file mode 100644 index 0000000000..e105c2fdb7 --- /dev/null +++ b/deps/libui/windows/datetimepicker.cpp @@ -0,0 +1,191 @@ +// 22 may 2015 +#include "uipriv_windows.hpp" + +struct uiDateTimePicker { + uiWindowsControl c; + HWND hwnd; +}; + +// utility functions + +#define GLI(what, buf, n) GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, what, buf, n) + +// The real date/time picker does a manual replacement of "yy" with "yyyy" for DTS_SHORTDATECENTURYFORMAT. +// Because we're also duplicating its functionality (see below), we have to do it too. +static WCHAR *expandYear(WCHAR *dts, int n) +{ + WCHAR *out; + WCHAR *p, *q; + int ny = 0; + + // allocate more than we need to be safe + out = (WCHAR *) uiAlloc((n * 3) * sizeof (WCHAR), "WCHAR[]"); + q = out; + for (p = dts; *p != L'\0'; p++) { + // first, if the current character is a y, increment the number of consecutive ys + // otherwise, stop counting, and if there were only two, add two more to make four + if (*p != L'y') { + if (ny == 2) { + *q++ = L'y'; + *q++ = L'y'; + } + ny = 0; + } else + ny++; + // next, handle quoted blocks + // we do this AFTER the above so yy'abc' becomes yyyy'abc' and not yy'abc'yy + // this handles the case of 'a''b' elegantly as well + if (*p == L'\'') { + // copy the opening quote + *q++ = *p; + // copy the contents + for (;;) { + p++; + if (*p == L'\'') + break; + if (*p == L'\0') + implbug("unterminated quote in system-provided locale date string in expandYear()"); + *q++ = *p; + } + // and fall through to copy the closing quote + } + // copy the current character + *q++ = *p; + } + // handle trailing yy + if (ny == 2) { + *q++ = L'y'; + *q++ = L'y'; + } + *q++ = L'\0'; + return out; +} + +// Windows has no combined date/time prebuilt constant; we have to build the format string ourselves +// TODO use a default format if one fails +static void setDateTimeFormat(HWND hwnd) +{ + WCHAR *unexpandedDate, *date; + WCHAR *time; + WCHAR *datetime; + int ndate, ntime; + + ndate = GLI(LOCALE_SSHORTDATE, NULL, 0); + if (ndate == 0) + logLastError(L"error getting date string length"); + date = (WCHAR *) uiAlloc(ndate * sizeof (WCHAR), "WCHAR[]"); + if (GLI(LOCALE_SSHORTDATE, date, ndate) == 0) + logLastError(L"error geting date string"); + unexpandedDate = date; // so we can free it + date = expandYear(unexpandedDate, ndate); + uiFree(unexpandedDate); + + ntime = GLI(LOCALE_STIMEFORMAT, NULL, 0); + if (ndate == 0) + logLastError(L"error getting time string length"); + time = (WCHAR *) uiAlloc(ntime * sizeof (WCHAR), "WCHAR[]"); + if (GLI(LOCALE_STIMEFORMAT, time, ntime) == 0) + logLastError(L"error geting time string"); + + datetime = strf(L"%s %s", date, time); + if (SendMessageW(hwnd, DTM_SETFORMAT, 0, (LPARAM) datetime) == 0) + logLastError(L"error applying format string to date/time picker"); + + uiFree(datetime); + uiFree(time); + uiFree(date); +} + +// control implementation + +static void uiDateTimePickerDestroy(uiControl *c) +{ + uiDateTimePicker *d = uiDateTimePicker(c); + + uiWindowsUnregisterReceiveWM_WININICHANGE(d->hwnd); + uiWindowsEnsureDestroyWindow(d->hwnd); + uiFreeControl(uiControl(d)); +} + +uiWindowsControlAllDefaultsExceptDestroy(uiDateTimePicker) + +// the height returned from DTM_GETIDEALSIZE is unreliable; see http://stackoverflow.com/questions/30626549/what-is-the-proper-use-of-dtm-getidealsize-treating-the-returned-size-as-pixels +// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing +#define entryHeight 14 + +static void uiDateTimePickerMinimumSize(uiWindowsControl *c, int *width, int *height) +{ + uiDateTimePicker *d = uiDateTimePicker(c); + SIZE s; + uiWindowsSizing sizing; + int y; + + s.cx = 0; + s.cy = 0; + SendMessageW(d->hwnd, DTM_GETIDEALSIZE, 0, (LPARAM) (&s)); + *width = s.cx; + + y = entryHeight; + uiWindowsGetSizing(d->hwnd, &sizing); + uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y); + *height = y; +} + +static uiDateTimePicker *finishNewDateTimePicker(DWORD style) +{ + uiDateTimePicker *d; + + uiWindowsNewControl(uiDateTimePicker, d); + + d->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, + DATETIMEPICK_CLASSW, L"", + style | WS_TABSTOP, + hInstance, NULL, + TRUE); + + // automatically update date/time format when user changes locale settings + // for the standard styles, this is in the date-time picker itself + // for our date/time mode, we do it in a subclass assigned in uiNewDateTimePicker() + uiWindowsRegisterReceiveWM_WININICHANGE(d->hwnd); + + return d; +} + +static LRESULT CALLBACK datetimepickerSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + switch (uMsg) { + case WM_WININICHANGE: + // we can optimize this by only doing it when the real date/time picker does it + // unfortunately, I don't know when that is :/ + // hopefully this won't hurt + setDateTimeFormat(hwnd); + return 0; + case WM_NCDESTROY: + if (RemoveWindowSubclass(hwnd, datetimepickerSubProc, uIdSubclass) == FALSE) + logLastError(L"error removing date-time picker locale change handling subclass"); + break; + } + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +uiDateTimePicker *uiNewDateTimePicker(void) +{ + uiDateTimePicker *d; + + d = finishNewDateTimePicker(0); + setDateTimeFormat(d->hwnd); + if (SetWindowSubclass(d->hwnd, datetimepickerSubProc, 0, (DWORD_PTR) d) == FALSE) + logLastError(L"error subclassing date-time-picker to assist in locale change handling"); + // TODO set a suitable default in this case + return d; +} + +uiDateTimePicker *uiNewDatePicker(void) +{ + return finishNewDateTimePicker(DTS_SHORTDATECENTURYFORMAT); +} + +uiDateTimePicker *uiNewTimePicker(void) +{ + return finishNewDateTimePicker(DTS_TIMEFORMAT); +} diff --git a/deps/libui/win32/debug.cpp b/deps/libui/windows/debug.cpp similarity index 100% rename from deps/libui/win32/debug.cpp rename to deps/libui/windows/debug.cpp diff --git a/deps/libui/win32/draw.cpp b/deps/libui/windows/draw.cpp similarity index 100% rename from deps/libui/win32/draw.cpp rename to deps/libui/windows/draw.cpp diff --git a/deps/libui/win32/draw.hpp b/deps/libui/windows/draw.hpp similarity index 100% rename from deps/libui/win32/draw.hpp rename to deps/libui/windows/draw.hpp diff --git a/deps/libui/win32/drawmatrix.cpp b/deps/libui/windows/drawmatrix.cpp similarity index 100% rename from deps/libui/win32/drawmatrix.cpp rename to deps/libui/windows/drawmatrix.cpp diff --git a/deps/libui/win32/drawpath.cpp b/deps/libui/windows/drawpath.cpp similarity index 100% rename from deps/libui/win32/drawpath.cpp rename to deps/libui/windows/drawpath.cpp diff --git a/deps/libui/win32/drawtext.cpp b/deps/libui/windows/drawtext.cpp similarity index 100% rename from deps/libui/win32/drawtext.cpp rename to deps/libui/windows/drawtext.cpp diff --git a/deps/libui/win32/dwrite.cpp b/deps/libui/windows/dwrite.cpp similarity index 100% rename from deps/libui/win32/dwrite.cpp rename to deps/libui/windows/dwrite.cpp diff --git a/deps/libui/win32/editablecombo.cpp b/deps/libui/windows/editablecombo.cpp similarity index 100% rename from deps/libui/win32/editablecombo.cpp rename to deps/libui/windows/editablecombo.cpp diff --git a/deps/libui/win32/entry.cpp b/deps/libui/windows/entry.cpp similarity index 100% rename from deps/libui/win32/entry.cpp rename to deps/libui/windows/entry.cpp diff --git a/deps/libui/win32/events.cpp b/deps/libui/windows/events.cpp similarity index 100% rename from deps/libui/win32/events.cpp rename to deps/libui/windows/events.cpp diff --git a/deps/libui/win32/fontbutton.cpp b/deps/libui/windows/fontbutton.cpp similarity index 100% rename from deps/libui/win32/fontbutton.cpp rename to deps/libui/windows/fontbutton.cpp diff --git a/deps/libui/win32/fontdialog.cpp b/deps/libui/windows/fontdialog.cpp similarity index 100% rename from deps/libui/win32/fontdialog.cpp rename to deps/libui/windows/fontdialog.cpp diff --git a/deps/libui/win32/form.cpp b/deps/libui/windows/form.cpp similarity index 100% rename from deps/libui/win32/form.cpp rename to deps/libui/windows/form.cpp diff --git a/deps/libui/win32/graphemes.cpp b/deps/libui/windows/graphemes.cpp similarity index 100% rename from deps/libui/win32/graphemes.cpp rename to deps/libui/windows/graphemes.cpp diff --git a/deps/libui/win32/grid.cpp b/deps/libui/windows/grid.cpp similarity index 100% rename from deps/libui/win32/grid.cpp rename to deps/libui/windows/grid.cpp diff --git a/deps/libui/win32/group.cpp b/deps/libui/windows/group.cpp similarity index 100% rename from deps/libui/win32/group.cpp rename to deps/libui/windows/group.cpp diff --git a/deps/libui/win32/init.cpp b/deps/libui/windows/init.cpp similarity index 80% rename from deps/libui/win32/init.cpp rename to deps/libui/windows/init.cpp index a8a7ce05c0..228741653c 100644 --- a/deps/libui/win32/init.cpp +++ b/deps/libui/windows/init.cpp @@ -1,6 +1,5 @@ // 6 april 2015 #include "uipriv_windows.hpp" -#include "../../verbosity.h" HINSTANCE hInstance; int nCmdShow; @@ -75,107 +74,61 @@ const char *uiInit(uiInitOptions *o) hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION); if (hDefaultIcon == NULL) - { - RARCH_ERR("error loading default icon for window classes\n"); return ieLastErr("loading default icon for window classes"); - } hDefaultCursor = LoadCursorW(NULL, IDC_ARROW); if (hDefaultCursor == NULL) - { - RARCH_ERR("error loading default cursor for window classes\n"); return ieLastErr("loading default cursor for window classes"); - } - RARCH_LOG("Initializing initUtilWindow.\n"); ce = initUtilWindow(hDefaultIcon, hDefaultCursor); if (ce != NULL) - { - RARCH_ERR("Failed initializing util window.\n"); return initerr(ce, L"GetLastError() ==", GetLastError()); - } if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0) - { - RARCH_ERR("failed registering uiWindow window class.\n"); return ieLastErr("registering uiWindow window class"); - } ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW)); ncm.cbSize = sizeof (NONCLIENTMETRICSW); if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) - { - RARCH_ERR("Error getting default fonts.\n"); return ieLastErr("getting default fonts"); - } hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont)); if (hMessageFont == NULL) - { - RARCH_ERR("loading default messagebox font; this is the default UI font\n"); return ieLastErr("loading default messagebox font; this is the default UI font"); - } if (initContainer(hDefaultIcon, hDefaultCursor) == 0) - { - RARCH_ERR("initializing uiWindowsMakeContainer() window class\n"); return ieLastErr("initializing uiWindowsMakeContainer() window class"); - } hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); if (hollowBrush == NULL) - { - RARCH_ERR("getting hollow brush\n"); return ieLastErr("getting hollow brush"); - } ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); icc.dwSize = sizeof (INITCOMMONCONTROLSEX); icc.dwICC = wantedICCClasses; if (InitCommonControlsEx(&icc) == 0) - { - RARCH_ERR("initializing Common Controls\n"); return ieLastErr("initializing Common Controls"); - } hr = CoInitialize(NULL); if (hr != S_OK && hr != S_FALSE) - { - RARCH_ERR("initializing COM\n"); return ieHRESULT("initializing COM", hr); - } // LONGTERM initialize COM security // LONGTERM (windows vista) turn off COM exception handling hr = initDraw(); if (hr != S_OK) - { - RARCH_ERR("initializing Direct2D\n"); return ieHRESULT("initializing Direct2D", hr); - } hr = initDrawText(); if (hr != S_OK) - { - RARCH_ERR("initializing DirectWrite\n"); return ieHRESULT("initializing DirectWrite", hr); - } if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0) - { - RARCH_ERR("registering uiArea window class\n"); return ieLastErr("registering uiArea window class"); - } if (registerMessageFilter() == 0) - { - RARCH_ERR("registering libui message filter\n"); return ieLastErr("registering libui message filter"); - } if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0) - { - RARCH_ERR("initializing D2D scratch window class\n"); return ieLastErr("initializing D2D scratch window class"); - } return NULL; } @@ -205,3 +158,10 @@ void uiFreeInitError(const char *err) if (*(err - 1) == '-') uiFree((void *) (err - 1)); } + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + hInstance = hinstDLL; + return TRUE; +} diff --git a/deps/libui/win32/label.cpp b/deps/libui/windows/label.cpp similarity index 100% rename from deps/libui/win32/label.cpp rename to deps/libui/windows/label.cpp diff --git a/deps/libui/win32/libui.manifest b/deps/libui/windows/libui.manifest similarity index 100% rename from deps/libui/win32/libui.manifest rename to deps/libui/windows/libui.manifest diff --git a/deps/libui/win32/main.cpp b/deps/libui/windows/main.cpp similarity index 100% rename from deps/libui/win32/main.cpp rename to deps/libui/windows/main.cpp diff --git a/deps/libui/win32/menu.cpp b/deps/libui/windows/menu.cpp similarity index 100% rename from deps/libui/win32/menu.cpp rename to deps/libui/windows/menu.cpp diff --git a/deps/libui/win32/multilineentry.cpp b/deps/libui/windows/multilineentry.cpp similarity index 100% rename from deps/libui/win32/multilineentry.cpp rename to deps/libui/windows/multilineentry.cpp diff --git a/deps/libui/win32/notes b/deps/libui/windows/notes similarity index 100% rename from deps/libui/win32/notes rename to deps/libui/windows/notes diff --git a/deps/libui/win32/parent.cpp b/deps/libui/windows/parent.cpp similarity index 52% rename from deps/libui/win32/parent.cpp rename to deps/libui/windows/parent.cpp index 6de8cda341..bde6fb94e4 100644 --- a/deps/libui/win32/parent.cpp +++ b/deps/libui/windows/parent.cpp @@ -1,26 +1,26 @@ -/* 26 april 2015 */ +// 26 april 2015 #include "uipriv_windows.hpp" -/* This contains code used by all uiControls that contain other controls. - * It also contains the code to draw the background of a container.c container, as that is a variant of the WM_CTLCOLORxxx handler code. */ +// This contains code used by all uiControls that contain other controls. +// It also contains the code to draw the background of a container.c container, as that is a variant of the WM_CTLCOLORxxx handler code. static HBRUSH parentBrush = NULL; static HWND parentWithBackground(HWND hwnd) { - int cls; - HWND parent = hwnd; + HWND parent; + int cls; - for (;;) - { - parent = parentOf(parent); - /* skip groupboxes; they're (supposed to be) transparent - * skip uiContainers; they don't draw anything */ - cls = windowClassOf(parent, L"button", containerClass, NULL); - if (cls != 0 && cls != 1) - break; - } - return parent; + parent = hwnd; + for (;;) { + parent = parentOf(parent); + // skip groupboxes; they're (supposed to be) transparent + // skip uiContainers; they don't draw anything + cls = windowClassOf(parent, L"button", containerClass, NULL); + if (cls != 0 && cls != 1) + break; + } + return parent; } struct parentDraw { @@ -49,7 +49,7 @@ static HRESULT parentDraw(HDC dc, HWND parent, struct parentDraw *pd) static void endParentDraw(struct parentDraw *pd) { - /* continue in case of any error */ + // continue in case of any error if (pd->prevbitmap != NULL) if (((HBITMAP) SelectObject(pd->cdc, pd->prevbitmap)) != pd->bitmap) logLastError(L"error selecting previous bitmap back into compatible DC"); @@ -61,7 +61,7 @@ static void endParentDraw(struct parentDraw *pd) logLastError(L"error deleting compatible DC"); } -/* see http://www.codeproject.com/Articles/5978/Correctly-drawn-themed-dialogs-in-WinXP */ +// see http://www.codeproject.com/Articles/5978/Correctly-drawn-themed-dialogs-in-WinXP static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc) { HWND parent; @@ -83,11 +83,10 @@ static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc) } endParentDraw(&pd); - /* now figure out where the control is relative to the parent - * so we can align the brush properly - * if anything fails, give up and return the brush as-is */ + // now figure out where the control is relative to the parent so we can align the brush properly + // if anything fails, give up and return the brush as-is uiWindowsEnsureGetWindowRect(hwnd, &hwndScreenRect); - /* this will be in screen coordinates; convert to parent coordinates */ + // this will be in screen coordinates; convert to parent coordinates mapWindowRect(NULL, parent, &hwndScreenRect); if (SetBrushOrgEx(dc, -hwndScreenRect.left, -hwndScreenRect.top, NULL) == 0) logLastError(L"error setting brush origin"); @@ -97,18 +96,19 @@ static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc) void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect) { + HWND parent; RECT paintRectParent; struct parentDraw pd; - HWND parent = parentWithBackground(hwnd); - HRESULT hr = parentDraw(dc, parent, &pd); + HRESULT hr; - if (hr != S_OK) /* we couldn't get it; draw nothing */ + parent = parentWithBackground(hwnd); + hr = parentDraw(dc, parent, &pd); + if (hr != S_OK) // we couldn't get it; draw nothing return; paintRectParent = *paintRect; mapWindowRect(hwnd, parent, &paintRectParent); - if (BitBlt(dc, paintRect->left, paintRect->top, - paintRect->right - paintRect->left, paintRect->bottom - paintRect->top, + if (BitBlt(dc, paintRect->left, paintRect->top, paintRect->right - paintRect->left, paintRect->bottom - paintRect->top, pd.cdc, paintRectParent.left, paintRectParent.top, SRCCOPY) == 0) logLastError(L"error drawing parent background over uiContainer"); @@ -116,31 +116,29 @@ void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect) endParentDraw(&pd); } -/* TODO make this public if we want custom containers - * why have this to begin with? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx */ +// TODO make this public if we want custom containers +// why have this to begin with? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx BOOL handleParentMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) { - switch (uMsg) - { - case WM_COMMAND: - return runWM_COMMAND(wParam, lParam, lResult); - case WM_NOTIFY: - return runWM_NOTIFY(wParam, lParam, lResult); - case WM_HSCROLL: - return runWM_HSCROLL(wParam, lParam, lResult); - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORBTN: - if (parentBrush != NULL) - if (DeleteObject(parentBrush) == 0) - logLastError(L"error deleting old background brush()"); /* but continue anyway; we will leak a brush but whatever */ - if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) - logLastError(L"error setting transparent background mode to controls"); /* but continue anyway; text will be wrong */ - parentBrush = getControlBackgroundBrush((HWND) lParam, (HDC) wParam); - if (parentBrush == NULL) /* failed; just do default behavior */ - return FALSE; - *lResult = (LRESULT) parentBrush; - return TRUE; - } - - return FALSE; + switch (uMsg) { + case WM_COMMAND: + return runWM_COMMAND(wParam, lParam, lResult); + case WM_NOTIFY: + return runWM_NOTIFY(wParam, lParam, lResult); + case WM_HSCROLL: + return runWM_HSCROLL(wParam, lParam, lResult); + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORBTN: + if (parentBrush != NULL) + if (DeleteObject(parentBrush) == 0) + logLastError(L"error deleting old background brush()"); // but continue anyway; we will leak a brush but whatever + if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) + logLastError(L"error setting transparent background mode to controls"); // but continue anyway; text will be wrong + parentBrush = getControlBackgroundBrush((HWND) lParam, (HDC) wParam); + if (parentBrush == NULL) // failed; just do default behavior + return FALSE; + *lResult = (LRESULT) parentBrush; + return TRUE; + } + return FALSE; } diff --git a/deps/libui/win32/progressbar.cpp b/deps/libui/windows/progressbar.cpp similarity index 100% rename from deps/libui/win32/progressbar.cpp rename to deps/libui/windows/progressbar.cpp diff --git a/deps/libui/win32/radiobuttons.cpp b/deps/libui/windows/radiobuttons.cpp similarity index 100% rename from deps/libui/win32/radiobuttons.cpp rename to deps/libui/windows/radiobuttons.cpp diff --git a/deps/libui/win32/resources.hpp b/deps/libui/windows/resources.hpp similarity index 100% rename from deps/libui/win32/resources.hpp rename to deps/libui/windows/resources.hpp diff --git a/deps/libui/win32/resources.rc b/deps/libui/windows/resources.rc similarity index 100% rename from deps/libui/win32/resources.rc rename to deps/libui/windows/resources.rc diff --git a/deps/libui/win32/separator.cpp b/deps/libui/windows/separator.cpp similarity index 100% rename from deps/libui/win32/separator.cpp rename to deps/libui/windows/separator.cpp diff --git a/deps/libui/win32/sizing.cpp b/deps/libui/windows/sizing.cpp similarity index 100% rename from deps/libui/win32/sizing.cpp rename to deps/libui/windows/sizing.cpp diff --git a/deps/libui/win32/slider.cpp b/deps/libui/windows/slider.cpp similarity index 96% rename from deps/libui/win32/slider.cpp rename to deps/libui/windows/slider.cpp index b388ebc635..5c671dda09 100644 --- a/deps/libui/win32/slider.cpp +++ b/deps/libui/windows/slider.cpp @@ -1,10 +1,6 @@ // 20 may 2015 #include "uipriv_windows.hpp" -#ifndef TBS_TRANSPARENTBKGND -#define TBS_TRANSPARENTBKGND 0x1000 -#endif - struct uiSlider { uiWindowsControl c; HWND hwnd; diff --git a/deps/libui/win32/spinbox.cpp b/deps/libui/windows/spinbox.cpp similarity index 100% rename from deps/libui/win32/spinbox.cpp rename to deps/libui/windows/spinbox.cpp diff --git a/deps/libui/win32/stddialogs.cpp b/deps/libui/windows/stddialogs.cpp similarity index 69% rename from deps/libui/win32/stddialogs.cpp rename to deps/libui/windows/stddialogs.cpp index 07678542c0..89d26bacd7 100644 --- a/deps/libui/win32/stddialogs.cpp +++ b/deps/libui/windows/stddialogs.cpp @@ -1,26 +1,18 @@ -/* 22 may 2015 */ -#include +// 22 may 2015 #include "uipriv_windows.hpp" -#ifndef _MSC_VER -#include "winextra.h" -#endif -static dylib_t comctl_dll_handle = NULL; /* Handle to Comctl32 */ +// TODO document all this is what we want +// TODO do the same for font and color buttons -/* - * TODO document all this is what we want - * TODO do the same for font and color buttons +// notes: +// - FOS_SUPPORTSTREAMABLEITEMS doesn't seem to be supported on windows vista, or at least not with the flags we use +// - even with FOS_NOVALIDATE the dialogs will reject invalid filenames (at least on Vista, anyway) +// - lack of FOS_NOREADONLYRETURN doesn't seem to matter on Windows 7 - * notes: - * - FOS_SUPPORTSTREAMABLEITEMS doesn't seem to be supported on windows vista, or at least not with the flags we use - * - even with FOS_NOVALIDATE the dialogs will reject invalid filenames (at least on Vista, anyway) - * - lack of FOS_NOREADONLYRETURN doesn't seem to matter on Windows 7 - - * TODO - * - http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx - * - when a dialog is active, tab navigation in other windows stops working - * - when adding uiOpenFolder(), use IFileDialog as well - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115%28v=vs.85%29.aspx - */ +// TODO +// - http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx +// - when a dialog is active, tab navigation in other windows stops working +// - when adding uiOpenFolder(), use IFileDialog as well - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115%28v=vs.85%29.aspx #define windowHWND(w) ((HWND) uiControlHandle(uiControl(w))) @@ -109,28 +101,19 @@ char *uiSaveFile(uiWindow *parent) } // TODO switch to TaskDialogIndirect()? -typedef HRESULT (WINAPI *TaskDialogProc)(HWND hwndParent,HINSTANCE hInstance,PCWSTR pszWindowTitle,PCWSTR pszMainInstruction,PCWSTR pszContent,TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons,PCWSTR pszIcon,int *pnButton); -static TaskDialogProc task_dialog_proc; -static void msgbox(HWND parent, const char *title, const char *description, - TASKDIALOG_COMMON_BUTTON_FLAGS buttons, PCWSTR icon) +static void msgbox(HWND parent, const char *title, const char *description, TASKDIALOG_COMMON_BUTTON_FLAGS buttons, PCWSTR icon) { - HRESULT hr = E_FAIL; - WCHAR *wtitle = toUTF16(title); - WCHAR *wdescription = toUTF16(description); + WCHAR *wtitle, *wdescription; + HRESULT hr; - comctl_dll_handle = dylib_load("comctl32.lib"); - - task_dialog_proc = (TaskDialogProc)GetProcAddress((HINSTANCE)comctl_dll_handle, "TaskDialog"); - - if (task_dialog_proc) - hr = task_dialog_proc(parent, NULL, NULL, wtitle, wdescription, buttons, icon, NULL); + wtitle = toUTF16(title); + wdescription = toUTF16(description); + hr = TaskDialog(parent, NULL, NULL, wtitle, wdescription, buttons, icon, NULL); if (hr != S_OK) logHRESULT(L"error showing task dialog", hr); - dylib_close(comctl_dll_handle); - uiFree(wdescription); uiFree(wtitle); } diff --git a/deps/libui/win32/tab.cpp b/deps/libui/windows/tab.cpp similarity index 74% rename from deps/libui/win32/tab.cpp rename to deps/libui/windows/tab.cpp index 505b504926..365f5a1fa9 100644 --- a/deps/libui/win32/tab.cpp +++ b/deps/libui/windows/tab.cpp @@ -1,18 +1,18 @@ -/* 16 may 2015 */ +// 16 may 2015 #include "uipriv_windows.hpp" -/* You don't add controls directly to a tab control on Windows; instead you make them siblings and swap between them on a TCN_SELCHANGING/TCN_SELCHANGE notification pair. - * In addition, you use dialogs because they can be textured properly; other controls cannot. (Things will look wrong if the tab background in the current theme is fancy if you just use the tab background by itself; see http://stackoverflow.com/questions/30087540/why-are-my-programss-tab-controls-rendering-their-background-in-a-blocky-way-b.) */ +// You don't add controls directly to a tab control on Windows; instead you make them siblings and swap between them on a TCN_SELCHANGING/TCN_SELCHANGE notification pair. +// In addition, you use dialogs because they can be textured properly; other controls cannot. (Things will look wrong if the tab background in the current theme is fancy if you just use the tab background by itself; see http://stackoverflow.com/questions/30087540/why-are-my-programss-tab-controls-rendering-their-background-in-a-blocky-way-b.) struct uiTab { uiWindowsControl c; - HWND hwnd; /* of the outer container */ - HWND tabHWND; /* of the tab control itself */ + HWND hwnd; // of the outer container + HWND tabHWND; // of the tab control itself std::vector *pages; HWND parent; }; -/* utility functions */ +// utility functions static LRESULT curpage(uiTab *t) { @@ -26,14 +26,11 @@ static struct tabPage *tabPage(uiTab *t, int i) static void tabPageRect(uiTab *t, RECT *r) { - /* this rect needs to be in parent window coordinates, but TCM_ADJUSTRECT - * wants a window rect, which is screen coordinates - * because we have each page as a sibling of the tab, use the tab's - * own rect as the input rect */ + // this rect needs to be in parent window coordinates, but TCM_ADJUSTRECT wants a window rect, which is screen coordinates + // because we have each page as a sibling of the tab, use the tab's own rect as the input rect uiWindowsEnsureGetWindowRect(t->tabHWND, r); SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) FALSE, (LPARAM) r); - - /* and get it in terms of the container instead of the screen */ + // and get it in terms of the container instead of the screen mapWindowRect(NULL, t->hwnd, r); } @@ -42,11 +39,11 @@ static void tabRelayout(uiTab *t) struct tabPage *page; RECT r; - /* first move the tab control itself */ + // first move the tab control itself uiWindowsEnsureGetClientRect(t->hwnd, &r); uiWindowsEnsureMoveWindowDuringResize(t->tabHWND, r.left, r.top, r.right - r.left, r.bottom - r.top); - /* then the current page */ + // then the current page if (t->pages->size() == 0) return; page = tabPage(t, curpage(t)); @@ -56,22 +53,21 @@ static void tabRelayout(uiTab *t) static void showHidePage(uiTab *t, LRESULT which, int hide) { - struct tabPage *page = NULL; + struct tabPage *page; if (which == (LRESULT) (-1)) return; page = tabPage(t, which); if (hide) ShowWindow(page->hwnd, SW_HIDE); - else - { - ShowWindow(page->hwnd, SW_SHOW); - /* we only resize the current page, so we have to resize it; before we can do that, we need to make sure we are of the right size */ - uiWindowsControlMinimumSizeChanged(uiWindowsControl(t)); - } + else { + ShowWindow(page->hwnd, SW_SHOW); + // we only resize the current page, so we have to resize it; before we can do that, we need to make sure we are of the right size + uiWindowsControlMinimumSizeChanged(uiWindowsControl(t)); + } } -/* control implementation */ +// control implementation static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult) { @@ -133,23 +129,22 @@ uiWindowsControlDefaultSetParentHWND(uiTab) static void uiTabMinimumSize(uiWindowsControl *c, int *width, int *height) { + uiTab *t = uiTab(c); + int pagewid, pageht; + struct tabPage *page; RECT r; - struct tabPage *page = NULL; - uiTab *t = uiTab(c); - /* only consider the current page */ - int pagewid = 0; - int pageht = 0; - - if (t->pages->size() != 0) - { + // only consider the current page + pagewid = 0; + pageht = 0; + if (t->pages->size() != 0) { page = tabPage(t, curpage(t)); tabPageMinimumSize(page, &pagewid, &pageht); } - r.left = 0; - r.top = 0; - r.right = pagewid; + r.left = 0; + r.top = 0; + r.right = pagewid; r.bottom = pageht; // this also includes the tabs themselves SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) TRUE, (LPARAM) (&r)); @@ -159,14 +154,13 @@ static void uiTabMinimumSize(uiWindowsControl *c, int *width, int *height) static void uiTabMinimumSizeChanged(uiWindowsControl *c) { - uiTab *t = uiTab(c); + uiTab *t = uiTab(c); - if (uiWindowsControlTooSmall(uiWindowsControl(t))) - { - uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(t)); - return; - } - tabRelayout(t); + if (uiWindowsControlTooSmall(uiWindowsControl(t))) { + uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(t)); + return; + } + tabRelayout(t); } uiWindowsControlDefaultLayoutRect(uiTab) @@ -174,16 +168,16 @@ uiWindowsControlDefaultAssignControlIDZOrder(uiTab) static void uiTabChildVisibilityChanged(uiWindowsControl *c) { - /* TODO eliminate the redundancy */ + // TODO eliminate the redundancy uiWindowsControlMinimumSizeChanged(c); } static void tabArrangePages(uiTab *t) { LONG_PTR controlID = 100; - HWND insertAfter = NULL; + HWND insertAfter = NULL; - /* TODO is this first or last? */ + // TODO is this first or last? uiWindowsEnsureAssignControlIDZOrder(t->tabHWND, &controlID, &insertAfter); for (struct tabPage *&page : *(t->pages)) uiWindowsEnsureAssignControlIDZOrder(page->hwnd, &controlID, &insertAfter); @@ -197,11 +191,12 @@ void uiTabAppend(uiTab *t, const char *name, uiControl *child) void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) { struct tabPage *page; - LRESULT show; + LRESULT hide, show; TCITEMW item; WCHAR *wname; - /* see below */ - LRESULT hide = curpage(t); + + // see below + hide = curpage(t); if (child != NULL) uiControlSetParent(child, uiControl(t)); @@ -219,12 +214,9 @@ void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) logLastError(L"error adding tab to uiTab"); uiFree(wname); - /* we need to do this because adding the first tab - * doesn't send a TCN_SELCHANGE; it just shows the page */ + // we need to do this because adding the first tab doesn't send a TCN_SELCHANGE; it just shows the page show = curpage(t); - - if (show != hide) - { + if (show != hide) { showHidePage(t, hide, 1); showHidePage(t, show, 0); } @@ -234,12 +226,12 @@ void uiTabDelete(uiTab *t, int n) { struct tabPage *page; - /* first delete the tab from the tab control - * if this is the current tab, no tab will be selected, which is good */ + // first delete the tab from the tab control + // if this is the current tab, no tab will be selected, which is good if (SendMessageW(t->tabHWND, TCM_DELETEITEM, (WPARAM) n, 0) == FALSE) logLastError(L"error deleting uiTab tab"); - /* now delete the page itself */ + // now delete the page itself page = tabPage(t, n); if (page->child != NULL) uiControlSetParent(page->child, NULL); @@ -259,13 +251,11 @@ int uiTabMargined(uiTab *t, int n) void uiTabSetMargined(uiTab *t, int n, int margined) { - struct tabPage *page = tabPage(t, n); + struct tabPage *page; + page = tabPage(t, n); page->margined = margined; - - /* even if the page doesn't have a child it might still - * have a new minimum size with margins; this is the - * easiest way to verify it */ + // even if the page doesn't have a child it might still have a new minimum size with margins; this is the easiest way to verify it uiWindowsControlMinimumSizeChanged(uiWindowsControl(t)); } diff --git a/deps/libui/win32/tabpage.cpp b/deps/libui/windows/tabpage.cpp similarity index 100% rename from deps/libui/win32/tabpage.cpp rename to deps/libui/windows/tabpage.cpp diff --git a/deps/libui/windows/text.cpp b/deps/libui/windows/text.cpp new file mode 100644 index 0000000000..af79fb8078 --- /dev/null +++ b/deps/libui/windows/text.cpp @@ -0,0 +1,107 @@ +// 9 april 2015 +#include "uipriv_windows.hpp" + +WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len) +{ + LRESULT n; + WCHAR *text; + + n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); + if (len != NULL) + *len = n; + // WM_GETTEXTLENGTH does not include the null terminator + text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); + // note the comparison: the size includes the null terminator, but the return does not + if (GetWindowTextW(hwnd, text, n + 1) != n) { + logLastError(L"error getting window text"); + // on error, return an empty string to be safe + *text = L'\0'; + if (len != NULL) + *len = 0; + } + return text; +} + +WCHAR *windowText(HWND hwnd) +{ + return windowTextAndLen(hwnd, NULL); +} + +void setWindowText(HWND hwnd, WCHAR *wtext) +{ + if (SetWindowTextW(hwnd, wtext) == 0) + logLastError(L"error setting window text"); +} + +void uiFreeText(char *text) +{ + uiFree(text); +} + +int uiWindowsWindowTextWidth(HWND hwnd) +{ + LRESULT len; + WCHAR *text; + HDC dc; + HFONT prevfont; + SIZE size; + + size.cx = 0; + size.cy = 0; + + text = windowTextAndLen(hwnd, &len); + if (len == 0) // no text; nothing to do + goto noTextOrError; + + // now we can do the calculations + dc = GetDC(hwnd); + if (dc == NULL) { + logLastError(L"error getting DC"); + // on any error, assume no text + goto noTextOrError; + } + prevfont = (HFONT) SelectObject(dc, hMessageFont); + if (prevfont == NULL) { + logLastError(L"error loading control font into device context"); + ReleaseDC(hwnd, dc); + goto noTextOrError; + } + if (GetTextExtentPoint32W(dc, text, len, &size) == 0) { + logLastError(L"error getting text extent point"); + // continue anyway, assuming size is 0 + size.cx = 0; + size.cy = 0; + } + // continue on errors; we got what we want + if (SelectObject(dc, prevfont) != hMessageFont) + logLastError(L"error restoring previous font into device context"); + if (ReleaseDC(hwnd, dc) == 0) + logLastError(L"error releasing DC"); + + uiFree(text); + return size.cx; + +noTextOrError: + uiFree(text); + return 0; +} + +char *uiWindowsWindowText(HWND hwnd) +{ + WCHAR *wtext; + char *text; + + wtext = windowText(hwnd); + text = toUTF8(wtext); + uiFree(wtext); + return text; +} + +void uiWindowsSetWindowText(HWND hwnd, const char *text) +{ + WCHAR *wtext; + + wtext = toUTF16(text); + setWindowText(hwnd, wtext); + uiFree(wtext); +} diff --git a/deps/libui/win32/uipriv_windows.hpp b/deps/libui/windows/uipriv_windows.hpp similarity index 97% rename from deps/libui/win32/uipriv_windows.hpp rename to deps/libui/windows/uipriv_windows.hpp index 8235dd529f..6ffe09f1ad 100644 --- a/deps/libui/win32/uipriv_windows.hpp +++ b/deps/libui/windows/uipriv_windows.hpp @@ -1,4 +1,4 @@ -/* 21 april 2016 */ +// 21 april 2016 #include "winapi.hpp" #include "../ui.h" #include "../ui_windows.h" @@ -6,15 +6,15 @@ #include "resources.hpp" #include "compilerver.hpp" -/* ui internal window messages */ +// ui internal window messages enum { - /* redirected WM_COMMAND and WM_NOTIFY */ + // redirected WM_COMMAND and WM_NOTIFY msgCOMMAND = WM_APP + 0x40, // start offset just to be safe msgNOTIFY, msgHSCROLL, msgQueued, msgD2DScratchPaint, - msgD2DScratchLButtonDown + msgD2DScratchLButtonDown, }; // alloc.cpp diff --git a/deps/libui/win32/utf16.cpp b/deps/libui/windows/utf16.cpp similarity index 61% rename from deps/libui/win32/utf16.cpp rename to deps/libui/windows/utf16.cpp index 1ae7e13489..98954d0ada 100644 --- a/deps/libui/win32/utf16.cpp +++ b/deps/libui/windows/utf16.cpp @@ -1,7 +1,7 @@ -/* 21 april 2016 */ +// 21 april 2016 #include "uipriv_windows.hpp" -/* see http://stackoverflow.com/a/29556509/3408572 */ +// see http://stackoverflow.com/a/29556509/3408572 #define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz) @@ -18,10 +18,9 @@ WCHAR *toUTF16(const char *str) return emptyUTF16(); } wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); - if (MBTWC(str, wstr, n) != n) - { + if (MBTWC(str, wstr, n) != n) { logLastError(L"error converting from UTF-8 to UTF-16"); - /* and return an empty string */ + // and return an empty string *wstr = L'\0'; } return wstr; @@ -34,7 +33,7 @@ char *toUTF8(const WCHAR *wstr) char *str; int n; - if (*wstr == L'\0') /* empty string */ + if (*wstr == L'\0') // empty string return emptyUTF8(); n = WCTMB(wstr, NULL, 0); if (n == 0) { @@ -42,20 +41,21 @@ char *toUTF8(const WCHAR *wstr) return emptyUTF8(); } str = (char *) uiAlloc(n * sizeof (char), "char[]"); - if (WCTMB(wstr, str, n) != n) - { - logLastError(L"error converting from UTF-16 to UTF-8"); - /* and return an empty string */ - *str = '\0'; - } + if (WCTMB(wstr, str, n) != n) { + logLastError(L"error converting from UTF-16 to UTF-8"); + // and return an empty string + *str = '\0'; + } return str; } WCHAR *utf16dup(const WCHAR *orig) { - size_t len = wcslen(orig); - WCHAR *out = (WCHAR *) uiAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]"); + WCHAR *out; + size_t len; + len = wcslen(orig); + out = (WCHAR *) uiAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]"); wcscpy_s(out, len + 1, orig); return out; } @@ -83,27 +83,27 @@ WCHAR *vstrf(const WCHAR *format, va_list ap) va_copy(ap2, ap); n = _vscwprintf(format, ap2); va_end(ap2); - n++; /* terminating L'\0' */ + n++; // terminating L'\0' buf = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); - /* includes terminating L'\0' according - * to example in https://msdn.microsoft.com/en-us/library/xa1a1a6z.aspx */ + // includes terminating L'\0' according to example in https://msdn.microsoft.com/en-us/library/xa1a1a6z.aspx vswprintf_s(buf, n, format, ap); return buf; } -/* Let's shove these utility routines here too. - * Prerequisite: lfonly is UTF-8. */ +// Let's shove these utility routines here too. +// Prerequisite: lfonly is UTF-8. char *LFtoCRLF(const char *lfonly) { - size_t i; - size_t len = strlen(lfonly); - char *crlf = (char *) uiAlloc((len * 2 + 1) * sizeof (char), "char[]"); - char *out = crlf; + char *crlf; + size_t i, len; + char *out; - for (i = 0; i < len; i++) - { + len = strlen(lfonly); + crlf = (char *) uiAlloc((len * 2 + 1) * sizeof (char), "char[]"); + out = crlf; + for (i = 0; i < len; i++) { if (*lfonly == '\n') *crlf++ = '\r'; *crlf++ = *lfonly++; @@ -112,43 +112,42 @@ char *LFtoCRLF(const char *lfonly) return out; } -/* Prerequisite: s is UTF-8. */ +// Prerequisite: s is UTF-8. void CRLFtoLF(char *s) { char *t = s; - for (; *s != '\0'; s++) - { - /* be sure to preserve \rs that are genuinely there */ + for (; *s != '\0'; s++) { + // be sure to preserve \rs that are genuinely there if (*s == '\r' && *(s + 1) == '\n') continue; *t++ = *s; } *t = '\0'; - /* pad out the rest of t, just to be safe */ + // pad out the rest of t, just to be safe while (t != s) *t++ = '\0'; } -/* std::to_string() always uses %f; we want %g - * fortunately std::iostream seems to use %g by default so */ +// std::to_string() always uses %f; we want %g +// fortunately std::iostream seems to use %g by default so WCHAR *ftoutf16(double d) { std::wostringstream ss; std::wstring s; ss << d; - s = ss.str(); /* to be safe */ + s = ss.str(); // to be safe return utf16dup(s.c_str()); } -/* to complement the above */ +// to complement the above WCHAR *itoutf16(int i) { std::wostringstream ss; std::wstring s; ss << i; - s = ss.str(); /* to be safe */ + s = ss.str(); // to be safe return utf16dup(s.c_str()); } diff --git a/deps/libui/windows/utilwin.cpp b/deps/libui/windows/utilwin.cpp new file mode 100644 index 0000000000..414ae83aba --- /dev/null +++ b/deps/libui/windows/utilwin.cpp @@ -0,0 +1,76 @@ +// 14 may 2015 +#include "uipriv_windows.hpp" + +// The utility window is a special window that performs certain tasks internal to libui. +// It is not a message-only window, and it is always hidden and disabled. +// Its roles: +// - It is the initial parent of all controls. When a control loses its parent, it also becomes that control's parent. +// - It handles WM_QUERYENDSESSION and console end session requests. +// - It handles WM_WININICHANGE and forwards the message to any child windows that request it. +// - It handles executing functions queued to run by uiQueueMain(). + +#define utilWindowClass L"libui_utilWindowClass" + +HWND utilWindow; + +static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + void (*qf)(void *); + LRESULT lResult; + + if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) + return lResult; + switch (uMsg) { + case WM_QUERYENDSESSION: + // TODO block handler + if (shouldQuit()) { + uiQuit(); + return TRUE; + } + return FALSE; + case WM_WININICHANGE: + issueWM_WININICHANGE(wParam, lParam); + return 0; + case msgQueued: + qf = (void (*)(void *)) wParam; + (*qf)((void *) lParam); + return 0; + } + return DefWindowProcW(hwnd, uMsg, wParam, lParam); +} + +const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor) +{ + WNDCLASSW wc; + + ZeroMemory(&wc, sizeof (WNDCLASSW)); + wc.lpszClassName = utilWindowClass; + wc.lpfnWndProc = utilWindowWndProc; + wc.hInstance = hInstance; + wc.hIcon = hDefaultIcon; + wc.hCursor = hDefaultCursor; + wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + if (RegisterClass(&wc) == 0) + // see init.cpp for an explanation of the =s + return "=registering utility window class"; + + utilWindow = CreateWindowExW(0, + utilWindowClass, L"libui utility window", + WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, + NULL, NULL, hInstance, NULL); + if (utilWindow == NULL) + return "=creating utility window"; + // and just to be safe + EnableWindow(utilWindow, FALSE); + + return NULL; +} + +void uninitUtilWindow(void) +{ + if (DestroyWindow(utilWindow) == 0) + logLastError(L"error destroying utility window"); + if (UnregisterClass(utilWindowClass, hInstance) == 0) + logLastError(L"error unregistering utility window class"); +} diff --git a/deps/libui/win32/winapi.hpp b/deps/libui/windows/winapi.hpp similarity index 100% rename from deps/libui/win32/winapi.hpp rename to deps/libui/windows/winapi.hpp diff --git a/deps/libui/win32/window.cpp b/deps/libui/windows/window.cpp similarity index 100% rename from deps/libui/win32/window.cpp rename to deps/libui/windows/window.cpp diff --git a/deps/libui/win32/winpublic.cpp b/deps/libui/windows/winpublic.cpp similarity index 63% rename from deps/libui/win32/winpublic.cpp rename to deps/libui/windows/winpublic.cpp index 1ef77f18f5..397a3b54c9 100644 --- a/deps/libui/win32/winpublic.cpp +++ b/deps/libui/windows/winpublic.cpp @@ -1,4 +1,4 @@ -/* 6 april 2015 */ +// 6 april 2015 #include "uipriv_windows.hpp" void uiWindowsEnsureDestroyWindow(HWND hwnd) @@ -35,30 +35,27 @@ void uiWindowsEnsureMoveWindowDuringResize(HWND hwnd, int x, int y, int width, i logLastError(L"error moving window"); } -/* do these function even error out in any case - * other than invalid parameters?! I thought all windows had rects */ +// do these function even error out in any case other than invalid parameters?! I thought all windows had rects void uiWindowsEnsureGetClientRect(HWND hwnd, RECT *r) { - if (GetClientRect(hwnd, r) == 0) - { - logLastError(L"error getting window client rect"); - /* zero out the rect on error just to be safe */ - r->left = 0; - r->top = 0; - r->right = 0; - r->bottom = 0; - } + if (GetClientRect(hwnd, r) == 0) { + logLastError(L"error getting window client rect"); + // zero out the rect on error just to be safe + r->left = 0; + r->top = 0; + r->right = 0; + r->bottom = 0; + } } void uiWindowsEnsureGetWindowRect(HWND hwnd, RECT *r) { - if (GetWindowRect(hwnd, r) == 0) - { - logLastError(L"error getting window rect"); - /* zero out the rect on error just to be safe */ - r->left = 0; - r->top = 0; - r->right = 0; - r->bottom = 0; - } + if (GetWindowRect(hwnd, r) == 0) { + logLastError(L"error getting window rect"); + // zero out the rect on error just to be safe + r->left = 0; + r->top = 0; + r->right = 0; + r->bottom = 0; + } } diff --git a/deps/libui/win32/winutil.cpp b/deps/libui/windows/winutil.cpp similarity index 100% rename from deps/libui/win32/winutil.cpp rename to deps/libui/windows/winutil.cpp diff --git a/deps/mbedtls/aes.c b/deps/mbedtls/aes.c new file mode 100644 index 0000000000..58603849cc --- /dev/null +++ b/deps/mbedtls/aes.c @@ -0,0 +1,1508 @@ +/* + * 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" +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 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 + +#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 + +#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 + +#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 + +#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]; +static uint32_t FT1[256]; +static uint32_t FT2[256]; +static uint32_t FT3[256]; + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static uint32_t RT0[256]; +static uint32_t RT1[256]; +static uint32_t RT2[256]; +static uint32_t RT3[256]; + +/* + * 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 ); + + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); + + 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 ); + + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); + } +} + +#endif /* MBEDTLS_AES_ROM_TABLES */ + +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +/* + * 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; + +#if !defined(MBEDTLS_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + + } +#endif + + 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_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; + + 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++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ + RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ + RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ + RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_aes_free( &cty ); + + return( ret ); +} +#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */ + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ + FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ + FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y0 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ + FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ + FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y2 >> 24 ) & 0xFF ]; \ +} + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ + RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ + RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y2 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ + RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ + RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y0 >> 24 ) & 0xFF ]; \ +} + +/* + * 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 */ + +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_encrypt( ctx, input, output ); +} + +/* + * 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 */ + +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_decrypt( ctx, input, output ); +} + +/* + * 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] ) +{ +#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]; + + 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_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 = *iv_off; + + 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]; + + 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_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 = *nc_off; + + 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_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 */ + +/* + * Checkup routine + */ +int mbedtls_aes_self_test( int verbose ) +{ + int ret = 0, i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; +#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) + size_t offset; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + int len; + 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; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-ECB-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 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( " AES-CBC-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[16]; + + mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 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" ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); + + offset = 0; + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 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" ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#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( " AES-CTR-128 (%s): ", + ( v == 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; + mbedtls_aes_setkey_enc( &ctx, key, 128 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_ct[u], len ); + + mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_pt[u], len ); + + mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, aes_test_ctr_ct[u], len ) != 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" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + ret = 0; + +exit: + mbedtls_aes_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_AES_C */ diff --git a/deps/mbedtls/aesni.c b/deps/mbedtls/aesni.c new file mode 100644 index 0000000000..1ca3c3ef5b --- /dev/null +++ b/deps/mbedtls/aesni.c @@ -0,0 +1,464 @@ +/* + * 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) + +#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/deps/mbedtls/arc4.c b/deps/mbedtls/arc4.c new file mode 100644 index 0000000000..05b33d3fdb --- /dev/null +++ b/deps/mbedtls/arc4.c @@ -0,0 +1,205 @@ +/* + * 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 + +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +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_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/deps/mbedtls/asn1parse.c b/deps/mbedtls/asn1parse.c new file mode 100644 index 0000000000..4dd65c03c0 --- /dev/null +++ b/deps/mbedtls/asn1parse.c @@ -0,0 +1,393 @@ +/* + * 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 + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 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_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_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/deps/mbedtls/asn1write.c b/deps/mbedtls/asn1write.c new file mode 100644 index 0000000000..69b61b205f --- /dev/null +++ b/deps/mbedtls/asn1write.c @@ -0,0 +1,390 @@ +/* + * 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( len <= 0xFFFFFFFF ) + { + 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 ); + } + + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); +} + +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; + + // TODO negative values and values larger than 128 + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + 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_printable_string( unsigned char **p, unsigned char *start, + 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, MBEDTLS_ASN1_PRINTABLE_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + 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, MBEDTLS_ASN1_IA5_STRING ) ); + + return( (int) len ); +} + +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; + + size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 ); + + // Calculate byte length + // + if( *p < start || (size_t)( *p - start ) < size + 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size + 1; + (*p) -= size; + memcpy( *p, buf, size ); + + // Write unused bits + // + *--(*p) = (unsigned char) (size * 8 - 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 ); +} + +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 = mbedtls_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/deps/mbedtls/base64.c b/deps/mbedtls/base64.c new file mode 100644 index 0000000000..f06b57b31f --- /dev/null +++ b/deps/mbedtls/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/deps/mbedtls/bignum.c b/deps/mbedtls/bignum.c new file mode 100644 index 0000000000..d3a150c3c1 --- /dev/null +++ b/deps/mbedtls/bignum.c @@ -0,0 +1,2447 @@ +/* + * 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 + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) { + volatile mbedtls_mpi_uint *p = v; while( n-- ) *p++ = 0; +} + +#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 ) ) + +/* + * Initialize one MPI + */ +void mbedtls_mpi_init( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + 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; + + 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; + + /* 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; + size_t i; + + 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; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * 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; + + 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; + + /* 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; + + 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; + + 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 ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); +} + +/* + * 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; + + 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; + + 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; + + 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 ) +{ + int ret; + mbedtls_mpi_uint r; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) ); + + if( mbedtls_mpi_cmp_int( X, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +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; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = mbedtls_mpi_bitlen( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + /* + * Round up the buffer length to an even value to ensure that there is + * enough room for hexadecimal values that can be represented in an odd + * number of digits. + */ + n += 3 + ( ( n + 1 ) & 1 ); + + if( buflen < n ) + { + *olen = n; + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = buf; + mbedtls_mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + 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 ) ); + } + + *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 ]; + + 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 ]; + + 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 */ + +/* + * 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 i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * 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 i, j, n; + + n = mbedtls_mpi_size( X ); + + if( buflen < n ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + 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; + + 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; + + 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; + + 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; + + 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]; + + *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; + + 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; i++; 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; + + 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 = 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 = 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]; + + 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]; + + 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; + + 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( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, 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]; + + _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; + + 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]; + + 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; + + 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; + + 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; + + 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( wsize > MBEDTLS_MPI_WINDOW_SIZE ) + wsize = MBEDTLS_MPI_WINDOW_SIZE; + + 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; + + 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; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( size > MBEDTLS_MPI_MAX_SIZE ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); + +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; + + 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, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count; + size_t i, j, k, n, s; + mbedtls_mpi W, R, T, A, RR; + + 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 ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + 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) { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) ); + } + + 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( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi XX; + + 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, f_rng, p_rng ) ); +} + +/* + * Prime number generation + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t k, n; + mbedtls_mpi_uint r; + mbedtls_mpi Y; + + if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + + k = mbedtls_mpi_bitlen( X ); + if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) ); + + mbedtls_mpi_set_bit( X, nbits-1, 1 ); + + X->p[0] |= 1; + + if( dh_flag == 0 ) + { + while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) ); + } + } + 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, f_rng, p_rng ) ) == 0 && + ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 ) + { + break; + } + + 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/deps/mbedtls/blowfish.c b/deps/mbedtls/blowfish.c new file mode 100644 index 0000000000..9003f0dfeb --- /dev/null +++ b/deps/mbedtls/blowfish.c @@ -0,0 +1,656 @@ +/* + * 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 + +#if !defined(MBEDTLS_BLOWFISH_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 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 ) +{ + memset( ctx, 0, sizeof( mbedtls_blowfish_context ) ); +} + +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_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; + + if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS || + ( keybits % 8 ) ) + { + return( MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH ); + } + + 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; + + 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]; + + 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 = *iv_off; + + 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 = *nc_off; + + 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/deps/mbedtls/cacert.h b/deps/mbedtls/cacert.h new file mode 100644 index 0000000000..d1d57171d7 --- /dev/null +++ b/deps/mbedtls/cacert.h @@ -0,0 +1,3805 @@ +/* CA certificates extracted from Mozilla + * https://curl.haxx.se/docs/caextract.html + * NOTE: Newlines are necessary for the file to be parsed correctly! + */ +static const char cacert_pem[] = { +"##\n" +"## Bundle of CA Root Certificates\n" +"##\n" +"## Certificate data from Mozilla as of: Wed Jun 7 03:12:05 2017 GMT\n" +"##\n" +"## This is a bundle of X.509 certificates of public Certificate Authorities\n" +"## (CA). These were automatically extracted from Mozilla's root certificates\n" +"## file (certdata.txt). This file can be found in the mozilla source tree:\n" +"## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt\n" +"##\n" +"## It contains the certificates in PEM format and therefore\n" +"## can be directly used with curl / libcurl / php_curl, or with\n" +"## an Apache+mod_ssl webserver for SSL client authentication.\n" +"## Just configure this file as the SSLCACertificateFile.\n" +"##\n" +"## Conversion done with mk-ca-bundle.pl version 1.27.\n" +"## SHA256: 93753268e1c596aee21893fb1c6975338389132f15c942ed65fc394a904371d7\n" +"##\n" +"GlobalSign Root CA\n" +"==================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\n" +"GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\n" +"b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\n" +"BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\n" +"VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\n" +"DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\n" +"THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\n" +"Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\n" +"c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\n" +"gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" +"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\n" +"AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\n" +"Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\n" +"j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\n" +"hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\n" +"X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n" +"-----END CERTIFICATE-----\n" +"GlobalSign Root CA - R2\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv\n" +"YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh\n" +"bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT\n" +"aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln\n" +"bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6\n" +"ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp\n" +"s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN\n" +"S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL\n" +"TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C\n" +"ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\n" +"FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i\n" +"YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN\n" +"BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp\n" +"9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu\n" +"01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7\n" +"9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n" +"TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n" +"-----END CERTIFICATE-----\n" +"Verisign Class 3 Public Primary Certification Authority - G3\n" +"============================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV\n" +"UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv\n" +"cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl\n" +"IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh\n" +"dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw\n" +"CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" +"dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv\n" +"cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg\n" +"Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +"ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1\n" +"EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc\n" +"cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw\n" +"EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj\n" +"055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA\n" +"ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f\n" +"j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC\n" +"/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0\n" +"xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa\n" +"t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n" +"-----END CERTIFICATE-----\n" +"Entrust.net Premium 2048 Secure Server CA\n" +"=========================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u\n" +"ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp\n" +"bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV\n" +"BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx\n" +"NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3\n" +"d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl\n" +"MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u\n" +"ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +"MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL\n" +"Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr\n" +"hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW\n" +"nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi\n" +"VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E\n" +"BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ\n" +"KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy\n" +"T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf\n" +"zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT\n" +"J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e\n" +"nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=\n" +"-----END CERTIFICATE-----\n" +"Baltimore CyberTrust Root\n" +"=========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE\n" +"ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li\n" +"ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC\n" +"SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs\n" +"dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME\n" +"uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB\n" +"UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C\n" +"G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9\n" +"XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr\n" +"l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI\n" +"VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB\n" +"BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh\n" +"cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5\n" +"hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa\n" +"Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H\n" +"RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" +"-----END CERTIFICATE-----\n" +"AddTrust Low-Value Services Root\n" +"================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\n" +"QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU\n" +"cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw\n" +"CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO\n" +"ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB\n" +"AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6\n" +"54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr\n" +"oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1\n" +"Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui\n" +"GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w\n" +"HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD\n" +"AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT\n" +"RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw\n" +"HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt\n" +"ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph\n" +"iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY\n" +"eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr\n" +"mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj\n" +"ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=\n" +"-----END CERTIFICATE-----\n" +"AddTrust External Root\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\n" +"QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD\n" +"VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw\n" +"NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU\n" +"cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg\n" +"Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821\n" +"+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw\n" +"Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo\n" +"aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy\n" +"2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7\n" +"7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P\n" +"BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL\n" +"VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk\n" +"VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB\n" +"IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl\n" +"j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5\n" +"6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355\n" +"e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u\n" +"G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=\n" +"-----END CERTIFICATE-----\n" +"AddTrust Public Services Root\n" +"=============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\n" +"QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU\n" +"cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ\n" +"BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l\n" +"dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF\n" +"AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu\n" +"nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i\n" +"d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG\n" +"Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw\n" +"HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G\n" +"A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\n" +"/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux\n" +"FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G\n" +"A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4\n" +"JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL\n" +"+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao\n" +"GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9\n" +"Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H\n" +"EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=\n" +"-----END CERTIFICATE-----\n" +"AddTrust Qualified Certificates Root\n" +"====================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\n" +"QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU\n" +"cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx\n" +"CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ\n" +"IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG\n" +"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx\n" +"64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3\n" +"KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o\n" +"L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR\n" +"wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU\n" +"MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/\n" +"BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE\n" +"BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y\n" +"azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD\n" +"ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG\n" +"GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X\n" +"dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze\n" +"RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB\n" +"iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\n" +"-----END CERTIFICATE-----\n" +"Entrust Root Certification Authority\n" +"====================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV\n" +"BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw\n" +"b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG\n" +"A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0\n" +"MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu\n" +"MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu\n" +"Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v\n" +"dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +"ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz\n" +"A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww\n" +"Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68\n" +"j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN\n" +"rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw\n" +"DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1\n" +"MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH\n" +"hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\n" +"A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM\n" +"Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa\n" +"v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS\n" +"W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0\n" +"tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8\n" +"-----END CERTIFICATE-----\n" +"GeoTrust Global CA\n" +"==================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK\n" +"Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw\n" +"MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j\n" +"LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +"CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo\n" +"BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet\n" +"8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc\n" +"T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU\n" +"vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD\n" +"AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk\n" +"DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q\n" +"zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4\n" +"d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2\n" +"mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p\n" +"XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm\n" +"Mw==\n" +"-----END CERTIFICATE-----\n" +"GeoTrust Global CA 2\n" +"====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN\n" +"R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw\n" +"MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j\n" +"LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" +"ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/\n" +"NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k\n" +"LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA\n" +"Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b\n" +"HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF\n" +"MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH\n" +"K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7\n" +"srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh\n" +"ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL\n" +"OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC\n" +"x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF\n" +"H4z1Ir+rzoPz4iIprn2DQKi6bA==\n" +"-----END CERTIFICATE-----\n" +"GeoTrust Universal CA\n" +"=====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN\n" +"R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1\n" +"MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu\n" +"Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\n" +"ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t\n" +"JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e\n" +"RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs\n" +"7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d\n" +"8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V\n" +"qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga\n" +"Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB\n" +"Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu\n" +"KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08\n" +"ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0\n" +"XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB\n" +"hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc\n" +"aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2\n" +"qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL\n" +"oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK\n" +"xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF\n" +"KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2\n" +"DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK\n" +"xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU\n" +"p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI\n" +"P/rmMuGNG2+k5o7Y+SlIis5z/iw=\n" +"-----END CERTIFICATE-----\n" +"GeoTrust Universal CA 2\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN\n" +"R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0\n" +"MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg\n" +"SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA\n" +"A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0\n" +"DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17\n" +"j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q\n" +"JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a\n" +"QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2\n" +"WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP\n" +"20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn\n" +"ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC\n" +"SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG\n" +"8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2\n" +"+/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E\n" +"BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z\n" +"dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ\n" +"4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+\n" +"mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq\n" +"A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg\n" +"Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP\n" +"pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d\n" +"FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp\n" +"gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm\n" +"X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS\n" +"-----END CERTIFICATE-----\n" +"Visa eCommerce Root\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG\n" +"EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug\n" +"QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2\n" +"WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm\n" +"VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv\n" +"bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL\n" +"F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b\n" +"RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0\n" +"TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI\n" +"/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs\n" +"GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG\n" +"MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc\n" +"CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW\n" +"YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz\n" +"zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu\n" +"YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt\n" +"398znM/jra6O1I7mT1GvFpLgXPYHDw==\n" +"-----END CERTIFICATE-----\n" +"Certum Root CA\n" +"==============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK\n" +"ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla\n" +"Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u\n" +"by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x\n" +"wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL\n" +"kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ\n" +"89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K\n" +"Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P\n" +"NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" +"hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+\n" +"GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg\n" +"GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/\n" +"0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS\n" +"qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==\n" +"-----END CERTIFICATE-----\n" +"Comodo AAA Services root\n" +"========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS\n" +"R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg\n" +"TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw\n" +"MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl\n" +"c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\n" +"BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +"ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG\n" +"C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs\n" +"i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW\n" +"Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH\n" +"Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK\n" +"Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f\n" +"BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl\n" +"cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz\n" +"LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm\n" +"7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\n" +"Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z\n" +"8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C\n" +"12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n" +"-----END CERTIFICATE-----\n" +"Comodo Secure Services root\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS\n" +"R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg\n" +"TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw\n" +"MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu\n" +"Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi\n" +"BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +"ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP\n" +"9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc\n" +"rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC\n" +"oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V\n" +"p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E\n" +"FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w\n" +"gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj\n" +"YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm\n" +"aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm\n" +"4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj\n" +"Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL\n" +"DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw\n" +"pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H\n" +"RR3B7Hzs/Sk=\n" +"-----END CERTIFICATE-----\n" +"Comodo Trusted Services root\n" +"============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS\n" +"R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg\n" +"TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw\n" +"MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h\n" +"bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw\n" +"IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +"AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7\n" +"3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y\n" +"/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6\n" +"juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS\n" +"ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud\n" +"DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\n" +"/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp\n" +"ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl\n" +"cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw\n" +"uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32\n" +"pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA\n" +"BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l\n" +"R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O\n" +"9y5Xt5hwXsjEeLBi\n" +"-----END CERTIFICATE-----\n" +"QuoVadis Root CA\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE\n" +"ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0\n" +"eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz\n" +"MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp\n" +"cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD\n" +"EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF\n" +"AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk\n" +"J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL\n" +"F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL\n" +"YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen\n" +"AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w\n" +"PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y\n" +"ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7\n" +"MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj\n" +"YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs\n" +"ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh\n" +"Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW\n" +"Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu\n" +"BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw\n" +"FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0\n" +"aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6\n" +"tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo\n" +"fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul\n" +"LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x\n" +"gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi\n" +"5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi\n" +"5nrQNiOKSnQ2+Q==\n" +"-----END CERTIFICATE-----\n" +"QuoVadis Root CA 2\n" +"==================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\n" +"EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx\n" +"ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\n" +"aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC\n" +"DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6\n" +"XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk\n" +"lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB\n" +"lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy\n" +"lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt\n" +"66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn\n" +"wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh\n" +"D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy\n" +"BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie\n" +"J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud\n" +"DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU\n" +"a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT\n" +"ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv\n" +"Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3\n" +"UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm\n" +"VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK\n" +"+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW\n" +"IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1\n" +"WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X\n" +"f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II\n" +"4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8\n" +"VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u\n" +"-----END CERTIFICATE-----\n" +"QuoVadis Root CA 3\n" +"==================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\n" +"EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx\n" +"OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\n" +"aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\n" +"DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg\n" +"DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij\n" +"KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K\n" +"DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv\n" +"BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp\n" +"p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8\n" +"nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX\n" +"MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM\n" +"Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz\n" +"uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT\n" +"BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj\n" +"YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0\n" +"aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB\n" +"BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD\n" +"VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4\n" +"ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE\n" +"AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV\n" +"qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s\n" +"hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z\n" +"POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2\n" +"Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp\n" +"8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC\n" +"bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu\n" +"g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p\n" +"vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr\n" +"qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=\n" +"-----END CERTIFICATE-----\n" +"Security Communication Root CA\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP\n" +"U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw\n" +"HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP\n" +"U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw\n" +"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw\n" +"8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM\n" +"DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX\n" +"5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd\n" +"DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2\n" +"JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw\n" +"DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g\n" +"0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a\n" +"mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ\n" +"s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ\n" +"6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi\n" +"FL39vmwLAw==\n" +"-----END CERTIFICATE-----\n" +"Sonera Class 2 Root CA\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG\n" +"U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw\n" +"NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh\n" +"IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3\n" +"/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT\n" +"dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG\n" +"f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P\n" +"tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH\n" +"nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT\n" +"XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt\n" +"0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI\n" +"cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph\n" +"Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx\n" +"EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH\n" +"llpwrN9M\n" +"-----END CERTIFICATE-----\n" +"UTN USERFirst Hardware Root CA\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE\n" +"BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl\n" +"IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd\n" +"BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx\n" +"OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0\n" +"eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz\n" +"ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3\n" +"DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI\n" +"wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd\n" +"tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8\n" +"i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf\n" +"Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw\n" +"gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF\n" +"lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF\n" +"UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF\n" +"BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM\n" +"//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW\n" +"XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2\n" +"lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn\n" +"iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67\n" +"nfhmqA==\n" +"-----END CERTIFICATE-----\n" +"Camerfirma Chambers of Commerce Root\n" +"====================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe\n" +"QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i\n" +"ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx\n" +"NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp\n" +"cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn\n" +"MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC\n" +"AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU\n" +"xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH\n" +"NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW\n" +"DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV\n" +"d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud\n" +"EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v\n" +"cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P\n" +"AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh\n" +"bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD\n" +"VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz\n" +"aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi\n" +"fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD\n" +"L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN\n" +"UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n\n" +"ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1\n" +"erfutGWaIZDgqtCYvDi1czyL+Nw=\n" +"-----END CERTIFICATE-----\n" +"Camerfirma Global Chambersign Root\n" +"==================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe\n" +"QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i\n" +"ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx\n" +"NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt\n" +"YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg\n" +"MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw\n" +"ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J\n" +"1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O\n" +"by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl\n" +"6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c\n" +"8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/\n" +"BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j\n" +"aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B\n" +"Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj\n" +"aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y\n" +"ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh\n" +"bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA\n" +"PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y\n" +"gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ\n" +"PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4\n" +"IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes\n" +"t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==\n" +"-----END CERTIFICATE-----\n" +"XRamp Global CA Root\n" +"====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE\n" +"BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj\n" +"dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB\n" +"dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx\n" +"HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg\n" +"U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\n" +"dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu\n" +"IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx\n" +"foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE\n" +"zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs\n" +"AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry\n" +"xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud\n" +"EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap\n" +"oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC\n" +"AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc\n" +"/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt\n" +"qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n\n" +"nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz\n" +"8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=\n" +"-----END CERTIFICATE-----\n" +"Go Daddy Class 2 CA\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY\n" +"VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp\n" +"ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG\n" +"A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g\n" +"RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD\n" +"ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv\n" +"2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32\n" +"qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j\n" +"YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY\n" +"vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O\n" +"BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o\n" +"atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu\n" +"MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG\n" +"A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim\n" +"PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt\n" +"I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\n" +"HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI\n" +"Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b\n" +"vZ8=\n" +"-----END CERTIFICATE-----\n" +"Starfield Class 2 CA\n" +"====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc\n" +"U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg\n" +"Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo\n" +"MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG\n" +"A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG\n" +"SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY\n" +"bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ\n" +"JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm\n" +"epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN\n" +"F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF\n" +"MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f\n" +"hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo\n" +"bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g\n" +"QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs\n" +"afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM\n" +"PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n" +"xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD\n" +"KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3\n" +"QBFGmh95DmK/D5fs4C8fF5Q=\n" +"-----END CERTIFICATE-----\n" +"StartCom Certification Authority\n" +"================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN\n" +"U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu\n" +"ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0\n" +"NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk\n" +"LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg\n" +"U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" +"ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y\n" +"o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/\n" +"Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d\n" +"eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt\n" +"2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z\n" +"6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ\n" +"osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/\n" +"untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc\n" +"UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT\n" +"37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE\n" +"FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0\n" +"Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj\n" +"YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH\n" +"AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw\n" +"Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg\n" +"U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5\n" +"LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl\n" +"cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh\n" +"cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT\n" +"dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC\n" +"AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh\n" +"3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm\n" +"vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk\n" +"fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3\n" +"fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ\n" +"EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq\n" +"yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl\n" +"1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/\n" +"lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro\n" +"g14=\n" +"-----END CERTIFICATE-----\n" +"Taiwan GRCA\n" +"===========\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG\n" +"EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X\n" +"DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv\n" +"dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD\n" +"ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN\n" +"w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5\n" +"BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O\n" +"1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO\n" +"htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov\n" +"J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7\n" +"Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t\n" +"B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB\n" +"O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8\n" +"lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV\n" +"HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2\n" +"09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ\n" +"TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj\n" +"Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2\n" +"Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU\n" +"D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz\n" +"DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk\n" +"Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk\n" +"7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ\n" +"CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy\n" +"+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS\n" +"-----END CERTIFICATE-----\n" +"Swisscom Root CA 1\n" +"==================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG\n" +"EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy\n" +"dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4\n" +"MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln\n" +"aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC\n" +"IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM\n" +"MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF\n" +"NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe\n" +"AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC\n" +"b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn\n" +"7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN\n" +"cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp\n" +"WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5\n" +"haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY\n" +"MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw\n" +"HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j\n" +"BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9\n" +"MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn\n" +"jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ\n" +"MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H\n" +"VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl\n" +"vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl\n" +"OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3\n" +"1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq\n" +"nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy\n" +"x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW\n" +"NY6E0F/6MBr1mmz0DlP5OlvRHA==\n" +"-----END CERTIFICATE-----\n" +"DigiCert Assured ID Root CA\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG\n" +"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\n" +"IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx\n" +"MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\n" +"ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew\n" +"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO\n" +"9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy\n" +"UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW\n" +"/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy\n" +"oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf\n" +"GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF\n" +"66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq\n" +"hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc\n" +"EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn\n" +"SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i\n" +"8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\n" +"+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n" +"-----END CERTIFICATE-----\n" +"DigiCert Global Root CA\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\n" +"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\n" +"HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw\n" +"MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\n" +"dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq\n" +"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn\n" +"TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5\n" +"BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H\n" +"4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y\n" +"7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB\n" +"o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm\n" +"8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF\n" +"BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr\n" +"EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt\n" +"tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886\n" +"UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" +"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" +"-----END CERTIFICATE-----\n" +"DigiCert High Assurance EV Root CA\n" +"==================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG\n" +"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw\n" +"KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw\n" +"MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ\n" +"MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu\n" +"Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t\n" +"Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS\n" +"OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3\n" +"MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ\n" +"NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe\n" +"h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB\n" +"Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY\n" +"JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ\n" +"V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp\n" +"myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK\n" +"mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" +"vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K\n" +"-----END CERTIFICATE-----\n" +"Certplus Class 2 Primary CA\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE\n" +"BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN\n" +"OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy\n" +"dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +"ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR\n" +"5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ\n" +"Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO\n" +"YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e\n" +"e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME\n" +"CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ\n" +"YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t\n" +"L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD\n" +"P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R\n" +"TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+\n" +"7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW\n" +"//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7\n" +"l7+ijrRU\n" +"-----END CERTIFICATE-----\n" +"DST Root CA X3\n" +"==============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK\n" +"ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X\n" +"DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1\n" +"cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD\n" +"ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT\n" +"rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9\n" +"UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy\n" +"xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d\n" +"utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T\n" +"AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ\n" +"MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug\n" +"dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE\n" +"GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw\n" +"RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS\n" +"fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" +"-----END CERTIFICATE-----\n" +"DST ACES CA X6\n" +"==============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG\n" +"EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT\n" +"MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha\n" +"MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE\n" +"CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +"AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI\n" +"DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa\n" +"pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow\n" +"GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy\n" +"MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud\n" +"EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu\n" +"Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy\n" +"dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU\n" +"CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2\n" +"5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t\n" +"Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq\n" +"nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs\n" +"vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3\n" +"oKfN5XozNmr6mis=\n" +"-----END CERTIFICATE-----\n" +"SwissSign Gold CA - G2\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw\n" +"EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN\n" +"MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp\n" +"c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B\n" +"AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq\n" +"t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C\n" +"jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg\n" +"vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF\n" +"ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR\n" +"AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend\n" +"jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO\n" +"peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR\n" +"7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi\n" +"GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw\n" +"AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64\n" +"OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov\n" +"L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm\n" +"5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr\n" +"44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf\n" +"Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m\n" +"Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp\n" +"mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk\n" +"vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf\n" +"KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br\n" +"NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj\n" +"viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ\n" +"-----END CERTIFICATE-----\n" +"SwissSign Silver CA - G2\n" +"========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT\n" +"BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X\n" +"DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3\n" +"aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG\n" +"9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644\n" +"N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm\n" +"+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH\n" +"6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu\n" +"MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h\n" +"qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5\n" +"FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs\n" +"ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc\n" +"celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X\n" +"CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\n" +"BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB\n" +"tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0\n" +"cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P\n" +"4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F\n" +"kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L\n" +"3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx\n" +"/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa\n" +"DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP\n" +"e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu\n" +"WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ\n" +"DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub\n" +"DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u\n" +"-----END CERTIFICATE-----\n" +"GeoTrust Primary Certification Authority\n" +"========================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG\n" +"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD\n" +"ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx\n" +"CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ\n" +"cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +"CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN\n" +"b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9\n" +"nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge\n" +"RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt\n" +"tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n" +"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI\n" +"hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K\n" +"Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN\n" +"NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa\n" +"Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG\n" +"1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=\n" +"-----END CERTIFICATE-----\n" +"thawte Primary Root CA\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE\n" +"BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2\n" +"aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv\n" +"cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3\n" +"MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg\n" +"SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv\n" +"KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT\n" +"FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs\n" +"oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ\n" +"1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc\n" +"q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K\n" +"aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p\n" +"afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD\n" +"VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF\n" +"AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE\n" +"uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX\n" +"xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89\n" +"jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH\n" +"z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==\n" +"-----END CERTIFICATE-----\n" +"VeriSign Class 3 Public Primary Certification Authority - G5\n" +"============================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" +"BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO\n" +"ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk\n" +"IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp\n" +"ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB\n" +"yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln\n" +"biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh\n" +"dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt\n" +"YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" +"ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz\n" +"j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD\n" +"Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/\n" +"Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r\n" +"fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/\n" +"BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv\n" +"Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\n" +"aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG\n" +"SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+\n" +"X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE\n" +"KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC\n" +"Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE\n" +"ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n" +"-----END CERTIFICATE-----\n" +"SecureTrust CA\n" +"==============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG\n" +"EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy\n" +"dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe\n" +"BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC\n" +"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX\n" +"OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t\n" +"DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH\n" +"GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b\n" +"01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH\n" +"ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/\n" +"BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj\n" +"aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ\n" +"KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu\n" +"SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf\n" +"mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ\n" +"nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR\n" +"3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=\n" +"-----END CERTIFICATE-----\n" +"Secure Global CA\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG\n" +"EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH\n" +"bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg\n" +"MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg\n" +"Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx\n" +"YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ\n" +"bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g\n" +"8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV\n" +"HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi\n" +"0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud\n" +"EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn\n" +"oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA\n" +"MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+\n" +"OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn\n" +"CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5\n" +"3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc\n" +"f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW\n" +"-----END CERTIFICATE-----\n" +"COMODO Certification Authority\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE\n" +"BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\n" +"A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1\n" +"dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb\n" +"MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD\n" +"T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n" +"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH\n" +"+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww\n" +"xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV\n" +"4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA\n" +"1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI\n" +"rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E\n" +"BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k\n" +"b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC\n" +"AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP\n" +"OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/\n" +"RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc\n" +"IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN\n" +"+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==\n" +"-----END CERTIFICATE-----\n" +"Network Solutions Certificate Authority\n" +"=======================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG\n" +"EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr\n" +"IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx\n" +"MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu\n" +"MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G\n" +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx\n" +"jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT\n" +"aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT\n" +"crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc\n" +"/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB\n" +"AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP\n" +"BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv\n" +"bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA\n" +"A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q\n" +"4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/\n" +"GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv\n" +"wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD\n" +"ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey\n" +"-----END CERTIFICATE-----\n" +"COMODO ECC Certification Authority\n" +"==================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC\n" +"R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\n" +"ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB\n" +"dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix\n" +"GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\n" +"Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo\n" +"b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X\n" +"4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni\n" +"wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E\n" +"BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG\n" +"FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA\n" +"U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n" +"-----END CERTIFICATE-----\n" +"Security Communication EV RootCA1\n" +"=================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc\n" +"U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh\n" +"dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE\n" +"BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl\n" +"Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" +"AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO\n" +"/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX\n" +"WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z\n" +"ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4\n" +"bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK\n" +"9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG\n" +"SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm\n" +"iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG\n" +"Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW\n" +"mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW\n" +"T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490\n" +"-----END CERTIFICATE-----\n" +"OISTE WISeKey Global Root GA CA\n" +"===============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE\n" +"BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG\n" +"A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH\n" +"bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD\n" +"VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw\n" +"IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5\n" +"IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9\n" +"Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg\n" +"Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD\n" +"d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ\n" +"/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R\n" +"LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw\n" +"AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ\n" +"KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm\n" +"MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4\n" +"+vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa\n" +"hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY\n" +"okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=\n" +"-----END CERTIFICATE-----\n" +"Certigna\n" +"========\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw\n" +"EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3\n" +"MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI\n" +"Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q\n" +"XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH\n" +"GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p\n" +"ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg\n" +"DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf\n" +"Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ\n" +"tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ\n" +"BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J\n" +"SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA\n" +"hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+\n" +"ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu\n" +"PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY\n" +"1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw\n" +"WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==\n" +"-----END CERTIFICATE-----\n" +"Deutsche Telekom Root CA 2\n" +"==========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT\n" +"RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG\n" +"A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5\n" +"MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G\n" +"A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS\n" +"b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5\n" +"bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI\n" +"KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY\n" +"AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK\n" +"Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV\n" +"jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV\n" +"HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr\n" +"E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy\n" +"zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8\n" +"rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G\n" +"dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU\n" +"Cm26OWMohpLzGITY+9HPBVZkVw==\n" +"-----END CERTIFICATE-----\n" +"Cybertrust Global Root\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li\n" +"ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4\n" +"MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD\n" +"ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +"+Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW\n" +"0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL\n" +"AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin\n" +"89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT\n" +"8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP\n" +"BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2\n" +"MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G\n" +"A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO\n" +"lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi\n" +"5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2\n" +"hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T\n" +"X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW\n" +"WL1WMRJOEcgh4LMRkWXbtKaIOM5V\n" +"-----END CERTIFICATE-----\n" +"ePKI Root Certification Authority\n" +"=================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG\n" +"EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg\n" +"Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx\n" +"MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq\n" +"MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B\n" +"AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs\n" +"IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi\n" +"lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv\n" +"qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX\n" +"12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O\n" +"WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+\n" +"ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao\n" +"lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/\n" +"vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi\n" +"Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi\n" +"MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH\n" +"ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0\n" +"1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq\n" +"KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV\n" +"xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP\n" +"NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r\n" +"GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE\n" +"xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx\n" +"gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy\n" +"sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD\n" +"BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=\n" +"-----END CERTIFICATE-----\n" +"T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3\n" +"=============================================================================================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH\n" +"DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q\n" +"aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry\n" +"b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV\n" +"BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg\n" +"S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4\n" +"MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl\n" +"IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF\n" +"n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl\n" +"IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft\n" +"dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl\n" +"cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B\n" +"AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO\n" +"Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1\n" +"xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR\n" +"6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL\n" +"hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd\n" +"BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n" +"MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4\n" +"N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT\n" +"y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh\n" +"LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M\n" +"dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=\n" +"-----END CERTIFICATE-----\n" +"certSIGN ROOT CA\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD\n" +"VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa\n" +"Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE\n" +"CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I\n" +"JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH\n" +"rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2\n" +"ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD\n" +"0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943\n" +"AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" +"Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB\n" +"AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8\n" +"SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0\n" +"x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt\n" +"vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz\n" +"TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD\n" +"-----END CERTIFICATE-----\n" +"CNNIC ROOT\n" +"==========\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE\n" +"ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw\n" +"OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw\n" +"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD\n" +"o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz\n" +"VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT\n" +"VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or\n" +"czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK\n" +"y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC\n" +"wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S\n" +"lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5\n" +"Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM\n" +"O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8\n" +"BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2\n" +"G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m\n" +"mxE=\n" +"-----END CERTIFICATE-----\n" +"GeoTrust Primary Certification Authority - G3\n" +"=============================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE\n" +"BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0\n" +"IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy\n" +"eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz\n" +"NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo\n" +"YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT\n" +"LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" +"hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j\n" +"K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE\n" +"c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C\n" +"IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu\n" +"dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC\n" +"MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr\n" +"2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9\n" +"cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE\n" +"Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD\n" +"AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s\n" +"t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt\n" +"-----END CERTIFICATE-----\n" +"thawte Primary Root CA - G2\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC\n" +"VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu\n" +"IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg\n" +"Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV\n" +"MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG\n" +"b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt\n" +"IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS\n" +"LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5\n" +"8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU\n" +"mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN\n" +"G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K\n" +"rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==\n" +"-----END CERTIFICATE-----\n" +"thawte Primary Root CA - G3\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE\n" +"BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2\n" +"aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv\n" +"cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w\n" +"ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh\n" +"d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD\n" +"VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG\n" +"A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +"MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At\n" +"P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC\n" +"+BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY\n" +"7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW\n" +"vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E\n" +"BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ\n" +"KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK\n" +"A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu\n" +"t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC\n" +"8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm\n" +"er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=\n" +"-----END CERTIFICATE-----\n" +"GeoTrust Primary Certification Authority - G2\n" +"=============================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC\n" +"VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu\n" +"Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD\n" +"ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1\n" +"OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg\n" +"MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl\n" +"b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG\n" +"BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc\n" +"KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD\n" +"VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+\n" +"EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m\n" +"ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2\n" +"npaqBA+K\n" +"-----END CERTIFICATE-----\n" +"VeriSign Universal Root Certification Authority\n" +"===============================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE\n" +"BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO\n" +"ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk\n" +"IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u\n" +"IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV\n" +"UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv\n" +"cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl\n" +"IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0\n" +"aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj\n" +"1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP\n" +"MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72\n" +"9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I\n" +"AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR\n" +"tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G\n" +"CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O\n" +"a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud\n" +"DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3\n" +"Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx\n" +"Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx\n" +"P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P\n" +"wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4\n" +"mJO37M2CYfE45k+XmCpajQ==\n" +"-----END CERTIFICATE-----\n" +"VeriSign Class 3 Public Primary Certification Authority - G4\n" +"============================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC\n" +"VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3\n" +"b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz\n" +"ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj\n" +"YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL\n" +"MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\n" +"cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo\n" +"b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5\n" +"IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8\n" +"Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz\n" +"rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB\n" +"/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw\n" +"HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u\n" +"Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD\n" +"A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx\n" +"AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==\n" +"-----END CERTIFICATE-----\n" +"NetLock Arany (Class Gold) Főtanúsítvány\n" +"========================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G\n" +"A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610\n" +"dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB\n" +"cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx\n" +"MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO\n" +"ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv\n" +"biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6\n" +"c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu\n" +"0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw\n" +"/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk\n" +"H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw\n" +"fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1\n" +"neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB\n" +"BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW\n" +"qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta\n" +"YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC\n" +"bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna\n" +"NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu\n" +"dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=\n" +"-----END CERTIFICATE-----\n" +"Staat der Nederlanden Root CA - G2\n" +"==================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE\n" +"CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g\n" +"Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC\n" +"TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l\n" +"ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ\n" +"5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn\n" +"vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj\n" +"CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil\n" +"e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR\n" +"OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI\n" +"CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65\n" +"48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi\n" +"trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737\n" +"qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB\n" +"AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC\n" +"ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV\n" +"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA\n" +"A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz\n" +"+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj\n" +"f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN\n" +"kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk\n" +"CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF\n" +"URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb\n" +"CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h\n" +"oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV\n" +"IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm\n" +"66+KAQ==\n" +"-----END CERTIFICATE-----\n" +"Hongkong Post Root CA 1\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT\n" +"DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx\n" +"NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n\n" +"IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF\n" +"AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1\n" +"ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr\n" +"auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh\n" +"qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY\n" +"V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV\n" +"HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i\n" +"h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio\n" +"l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei\n" +"IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps\n" +"T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT\n" +"c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==\n" +"-----END CERTIFICATE-----\n" +"SecureSign RootCA11\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi\n" +"SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS\n" +"b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw\n" +"KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1\n" +"cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL\n" +"TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO\n" +"wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq\n" +"g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP\n" +"O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA\n" +"bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX\n" +"t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh\n" +"OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r\n" +"bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ\n" +"Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01\n" +"y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061\n" +"lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=\n" +"-----END CERTIFICATE-----\n" +"ACEDICOM Root\n" +"=============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD\n" +"T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4\n" +"MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG\n" +"A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF\n" +"AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk\n" +"WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD\n" +"YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew\n" +"MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb\n" +"m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk\n" +"HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT\n" +"xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2\n" +"3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9\n" +"2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq\n" +"TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz\n" +"4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU\n" +"9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv\n" +"bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg\n" +"aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP\n" +"eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk\n" +"zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1\n" +"ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI\n" +"KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq\n" +"nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE\n" +"I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp\n" +"MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o\n" +"tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==\n" +"-----END CERTIFICATE-----\n" +"Microsec e-Szigno Root CA 2009\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER\n" +"MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv\n" +"c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o\n" +"dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE\n" +"BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt\n" +"U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw\n" +"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA\n" +"fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG\n" +"0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA\n" +"pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm\n" +"1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC\n" +"AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf\n" +"QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE\n" +"FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o\n" +"lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX\n" +"I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775\n" +"tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02\n" +"yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi\n" +"LXpUq3DDfSJlgnCW\n" +"-----END CERTIFICATE-----\n" +"GlobalSign Root CA - R3\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv\n" +"YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh\n" +"bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT\n" +"aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln\n" +"bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt\n" +"iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ\n" +"0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3\n" +"rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl\n" +"OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2\n" +"xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\n" +"FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7\n" +"lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8\n" +"EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E\n" +"bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18\n" +"YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r\n" +"kpeDMdmztcpHWD9f\n" +"-----END CERTIFICATE-----\n" +"Autoridad de Certificacion Firmaprofesional CIF A62634068\n" +"=========================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA\n" +"BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2\n" +"MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw\n" +"QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB\n" +"NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD\n" +"Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P\n" +"B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY\n" +"7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH\n" +"ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI\n" +"plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX\n" +"MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX\n" +"LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK\n" +"bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU\n" +"vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud\n" +"EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH\n" +"DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp\n" +"cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA\n" +"bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx\n" +"ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx\n" +"51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk\n" +"R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP\n" +"T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f\n" +"Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl\n" +"osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR\n" +"crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR\n" +"saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD\n" +"KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi\n" +"6Et8Vcad+qMUu2WFbm5PEn4KPJ2V\n" +"-----END CERTIFICATE-----\n" +"Izenpe.com\n" +"==========\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG\n" +"EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz\n" +"MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu\n" +"QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ\n" +"03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK\n" +"ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU\n" +"+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC\n" +"PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT\n" +"OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK\n" +"F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK\n" +"0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+\n" +"0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB\n" +"leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID\n" +"AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+\n" +"SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG\n" +"NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx\n" +"MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\n" +"BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l\n" +"Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga\n" +"kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q\n" +"hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs\n" +"g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5\n" +"aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5\n" +"nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC\n" +"ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo\n" +"Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z\n" +"WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==\n" +"-----END CERTIFICATE-----\n" +"Chambers of Commerce Root - 2008\n" +"================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD\n" +"MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv\n" +"bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu\n" +"QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy\n" +"Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl\n" +"ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF\n" +"EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl\n" +"cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n" +"AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA\n" +"XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj\n" +"h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/\n" +"ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk\n" +"NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g\n" +"D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331\n" +"lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ\n" +"0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj\n" +"ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2\n" +"EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI\n" +"G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ\n" +"BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh\n" +"bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh\n" +"bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC\n" +"CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH\n" +"AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1\n" +"wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH\n" +"3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU\n" +"RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6\n" +"M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1\n" +"YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF\n" +"9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK\n" +"zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG\n" +"nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg\n" +"OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ\n" +"-----END CERTIFICATE-----\n" +"Global Chambersign Root - 2008\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD\n" +"MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv\n" +"bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu\n" +"QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx\n" +"NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg\n" +"Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ\n" +"QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD\n" +"aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf\n" +"VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf\n" +"XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0\n" +"ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB\n" +"/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA\n" +"TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M\n" +"H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe\n" +"Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF\n" +"HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh\n" +"wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB\n" +"AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT\n" +"BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE\n" +"BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm\n" +"aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm\n" +"aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp\n" +"1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0\n" +"dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG\n" +"/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6\n" +"ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s\n" +"dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg\n" +"9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH\n" +"foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du\n" +"qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr\n" +"P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq\n" +"c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z\n" +"09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B\n" +"-----END CERTIFICATE-----\n" +"Go Daddy Root Certificate Authority - G2\n" +"========================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\n" +"B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu\n" +"MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5\n" +"MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n" +"b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G\n" +"A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI\n" +"hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq\n" +"9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD\n" +"+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd\n" +"fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl\n" +"NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC\n" +"MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9\n" +"BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac\n" +"vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r\n" +"5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV\n" +"N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\n" +"LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1\n" +"-----END CERTIFICATE-----\n" +"Starfield Root Certificate Authority - G2\n" +"=========================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\n" +"B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\n" +"b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0\n" +"eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw\n" +"DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg\n" +"VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB\n" +"dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv\n" +"W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs\n" +"bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk\n" +"N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf\n" +"ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU\n" +"JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" +"AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol\n" +"TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx\n" +"4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw\n" +"F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n" +"pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ\n" +"c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n" +"-----END CERTIFICATE-----\n" +"Starfield Services Root Certificate Authority - G2\n" +"==================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\n" +"B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\n" +"b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl\n" +"IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV\n" +"BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT\n" +"dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg\n" +"Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" +"AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2\n" +"h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa\n" +"hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP\n" +"LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB\n" +"rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw\n" +"AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG\n" +"SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP\n" +"E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy\n" +"xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd\n" +"iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza\n" +"YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6\n" +"-----END CERTIFICATE-----\n" +"AffirmTrust Commercial\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS\n" +"BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw\n" +"MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\n" +"bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF\n" +"AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb\n" +"DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV\n" +"C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6\n" +"BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww\n" +"MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV\n" +"HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" +"AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG\n" +"hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi\n" +"qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv\n" +"0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh\n" +"sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\n" +"-----END CERTIFICATE-----\n" +"AffirmTrust Networking\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS\n" +"BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw\n" +"MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\n" +"bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF\n" +"AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE\n" +"Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI\n" +"dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24\n" +"/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb\n" +"h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV\n" +"HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" +"AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu\n" +"UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6\n" +"12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23\n" +"WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9\n" +"/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\n" +"-----END CERTIFICATE-----\n" +"AffirmTrust Premium\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS\n" +"BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy\n" +"OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy\n" +"dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\n" +"MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn\n" +"BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV\n" +"5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs\n" +"+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd\n" +"GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R\n" +"p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI\n" +"S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04\n" +"6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5\n" +"/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo\n" +"+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB\n" +"/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv\n" +"MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg\n" +"Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC\n" +"6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S\n" +"L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK\n" +"+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV\n" +"BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg\n" +"IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60\n" +"g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb\n" +"zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==\n" +"-----END CERTIFICATE-----\n" +"AffirmTrust Premium ECC\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV\n" +"BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx\n" +"MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U\n" +"cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA\n" +"IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ\n" +"N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW\n" +"BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK\n" +"BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X\n" +"57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM\n" +"eQ==\n" +"-----END CERTIFICATE-----\n" +"Certum Trusted Network CA\n" +"=========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK\n" +"ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv\n" +"biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy\n" +"MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU\n" +"ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n" +"MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +"AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC\n" +"l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J\n" +"J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4\n" +"fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0\n" +"cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB\n" +"Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw\n" +"DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj\n" +"jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1\n" +"mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj\n" +"Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI\n" +"03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=\n" +"-----END CERTIFICATE-----\n" +"Certinomis - Autorité Racine\n" +"============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK\n" +"Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg\n" +"LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG\n" +"A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw\n" +"JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD\n" +"ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa\n" +"wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly\n" +"Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw\n" +"2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N\n" +"jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q\n" +"c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC\n" +"lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb\n" +"xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g\n" +"530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna\n" +"4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\n" +"A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ\n" +"KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x\n" +"WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva\n" +"R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40\n" +"nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B\n" +"CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv\n" +"JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE\n" +"qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b\n" +"WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE\n" +"wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/\n" +"vgt2Fl43N+bYdJeimUV5\n" +"-----END CERTIFICATE-----\n" +"TWCA Root Certification Authority\n" +"=================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ\n" +"VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh\n" +"dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG\n" +"EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB\n" +"IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" +"AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx\n" +"QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC\n" +"oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP\n" +"4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r\n" +"y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB\n" +"BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG\n" +"9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC\n" +"mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW\n" +"QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY\n" +"T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny\n" +"Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==\n" +"-----END CERTIFICATE-----\n" +"Security Communication RootCA2\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc\n" +"U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh\n" +"dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC\n" +"SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy\n" +"aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +"ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++\n" +"+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R\n" +"3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV\n" +"spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K\n" +"EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8\n" +"QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB\n" +"CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj\n" +"u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk\n" +"3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q\n" +"tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29\n" +"mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03\n" +"-----END CERTIFICATE-----\n" +"EC-ACC\n" +"======\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE\n" +"BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w\n" +"ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD\n" +"VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE\n" +"CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT\n" +"BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7\n" +"MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt\n" +"SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl\n" +"Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh\n" +"cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND\n" +"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK\n" +"w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT\n" +"ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4\n" +"HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a\n" +"E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw\n" +"0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E\n" +"BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD\n" +"VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0\n" +"Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l\n" +"dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ\n" +"lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa\n" +"Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe\n" +"l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2\n" +"E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D\n" +"5EI=\n" +"-----END CERTIFICATE-----\n" +"Hellenic Academic and Research Institutions RootCA 2011\n" +"=======================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT\n" +"O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y\n" +"aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z\n" +"IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT\n" +"AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z\n" +"IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo\n" +"IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +"AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI\n" +"1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa\n" +"71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u\n" +"8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH\n" +"3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/\n" +"MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8\n" +"MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu\n" +"b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt\n" +"XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8\n" +"TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD\n" +"/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N\n" +"7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4\n" +"-----END CERTIFICATE-----\n" +"Actalis Authentication Root CA\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM\n" +"BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE\n" +"AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky\n" +"MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz\n" +"IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290\n" +"IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ\n" +"wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa\n" +"by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6\n" +"zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f\n" +"YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2\n" +"oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l\n" +"EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7\n" +"hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8\n" +"EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5\n" +"jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY\n" +"iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt\n" +"ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI\n" +"WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0\n" +"JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx\n" +"K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+\n" +"Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC\n" +"4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo\n" +"2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz\n" +"lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem\n" +"OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9\n" +"vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==\n" +"-----END CERTIFICATE-----\n" +"Trustis FPS Root CA\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG\n" +"EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290\n" +"IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV\n" +"BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ\n" +"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ\n" +"RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk\n" +"H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa\n" +"cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt\n" +"o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA\n" +"AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd\n" +"BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c\n" +"GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC\n" +"yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P\n" +"8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV\n" +"l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl\n" +"iB6XzCGcKQENZetX2fNXlrtIzYE=\n" +"-----END CERTIFICATE-----\n" +"StartCom Certification Authority\n" +"================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN\n" +"U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu\n" +"ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0\n" +"NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk\n" +"LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg\n" +"U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" +"ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y\n" +"o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/\n" +"Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d\n" +"eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt\n" +"2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z\n" +"6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ\n" +"osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/\n" +"untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc\n" +"UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT\n" +"37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD\n" +"VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ\n" +"Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0\n" +"dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu\n" +"c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv\n" +"bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0\n" +"aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0\n" +"aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t\n" +"L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG\n" +"cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5\n" +"fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm\n" +"N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN\n" +"Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T\n" +"tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX\n" +"e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA\n" +"2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs\n" +"HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE\n" +"JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib\n" +"D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=\n" +"-----END CERTIFICATE-----\n" +"StartCom Certification Authority G2\n" +"===================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN\n" +"U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\n" +"RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE\n" +"ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp\n" +"dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O\n" +"o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG\n" +"4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi\n" +"Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul\n" +"Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs\n" +"O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H\n" +"vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L\n" +"nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS\n" +"FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa\n" +"z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E\n" +"BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ\n" +"KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K\n" +"2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk\n" +"J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+\n" +"JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG\n" +"/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc\n" +"nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld\n" +"blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc\n" +"l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm\n" +"7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm\n" +"obp573PYtlNXLfbQ4ddI\n" +"-----END CERTIFICATE-----\n" +"Buypass Class 2 Root CA\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\n" +"QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X\n" +"DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\n" +"eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw\n" +"DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1\n" +"g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn\n" +"9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b\n" +"/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU\n" +"CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff\n" +"awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI\n" +"zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn\n" +"Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX\n" +"Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs\n" +"M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\n" +"VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\n" +"AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s\n" +"A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI\n" +"osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S\n" +"aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd\n" +"DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD\n" +"LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0\n" +"oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC\n" +"wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS\n" +"CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN\n" +"rJgWVqA=\n" +"-----END CERTIFICATE-----\n" +"Buypass Class 3 Root CA\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\n" +"QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X\n" +"DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\n" +"eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw\n" +"DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH\n" +"sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR\n" +"5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh\n" +"7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ\n" +"ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH\n" +"2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV\n" +"/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ\n" +"RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA\n" +"Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq\n" +"j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\n" +"VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\n" +"AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV\n" +"cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G\n" +"uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG\n" +"Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8\n" +"ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2\n" +"KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz\n" +"6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug\n" +"UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe\n" +"eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi\n" +"Cp/HuZc=\n" +"-----END CERTIFICATE-----\n" +"T-TeleSec GlobalRoot Class 3\n" +"============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\n" +"IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\n" +"cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx\n" +"MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\n" +"dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\n" +"ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3\n" +"DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK\n" +"9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU\n" +"NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF\n" +"iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W\n" +"0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA\n" +"MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr\n" +"AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb\n" +"fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT\n" +"ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h\n" +"P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml\n" +"e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==\n" +"-----END CERTIFICATE-----\n" +"EE Certification Centre Root CA\n" +"===============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG\n" +"EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy\n" +"dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw\n" +"MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB\n" +"UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy\n" +"ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" +"DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM\n" +"TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2\n" +"rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw\n" +"93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN\n" +"P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T\n" +"AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ\n" +"MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF\n" +"BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj\n" +"xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM\n" +"lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u\n" +"uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU\n" +"3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM\n" +"dcGWxZ0=\n" +"-----END CERTIFICATE-----\n" +"TURKTRUST Certificate Services Provider Root 2007\n" +"=================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF\n" +"bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP\n" +"MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg\n" +"QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X\n" +"DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl\n" +"a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN\n" +"BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp\n" +"bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw\n" +"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N\n" +"YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv\n" +"KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya\n" +"KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT\n" +"rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC\n" +"AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP\n" +"BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s\n" +"Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I\n" +"aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO\n" +"Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb\n" +"BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK\n" +"poRq0Tl9\n" +"-----END CERTIFICATE-----\n" +"D-TRUST Root Class 3 CA 2 2009\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK\n" +"DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe\n" +"Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE\n" +"LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw\n" +"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD\n" +"ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA\n" +"BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv\n" +"KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z\n" +"p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC\n" +"AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ\n" +"4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y\n" +"eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw\n" +"MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G\n" +"PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw\n" +"OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm\n" +"2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0\n" +"o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV\n" +"dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph\n" +"X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=\n" +"-----END CERTIFICATE-----\n" +"D-TRUST Root Class 3 CA 2 EV 2009\n" +"=================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\n" +"DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\n" +"OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\n" +"DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\n" +"OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS\n" +"egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh\n" +"zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T\n" +"7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60\n" +"sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35\n" +"11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv\n" +"cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v\n" +"ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El\n" +"MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp\n" +"b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh\n" +"c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+\n" +"PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05\n" +"nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX\n" +"ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA\n" +"NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv\n" +"w9y4AyHqnxbxLFS1\n" +"-----END CERTIFICATE-----\n" +"PSCProcert\n" +"==========\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk\n" +"ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ\n" +"MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz\n" +"dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl\n" +"cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw\n" +"IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw\n" +"MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w\n" +"DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD\n" +"ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp\n" +"Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw\n" +"DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC\n" +"wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA\n" +"3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh\n" +"RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO\n" +"EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2\n" +"0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH\n" +"0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU\n" +"td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw\n" +"Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp\n" +"r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/\n" +"AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz\n" +"Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId\n" +"xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp\n" +"ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH\n" +"EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h\n" +"Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k\n" +"ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG\n" +"9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG\n" +"MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG\n" +"LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52\n" +"ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy\n" +"YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v\n" +"Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o\n" +"dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq\n" +"T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN\n" +"g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q\n" +"uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1\n" +"n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn\n" +"FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo\n" +"5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq\n" +"3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5\n" +"poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y\n" +"eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km\n" +"-----END CERTIFICATE-----\n" +"China Internet Network Information Center EV Certificates Root\n" +"==============================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV\n" +"BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D\n" +"aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg\n" +"Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG\n" +"A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM\n" +"PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl\n" +"cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y\n" +"jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV\n" +"98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H\n" +"klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23\n" +"KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC\n" +"7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV\n" +"HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD\n" +"glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5\n" +"0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM\n" +"7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws\n" +"ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0\n" +"5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=\n" +"-----END CERTIFICATE-----\n" +"Swisscom Root CA 2\n" +"==================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG\n" +"EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy\n" +"dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2\n" +"MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln\n" +"aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC\n" +"IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM\n" +"LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo\n" +"ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ\n" +"wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH\n" +"Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a\n" +"SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS\n" +"NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab\n" +"mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY\n" +"Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3\n" +"qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw\n" +"HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O\n" +"BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu\n" +"MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO\n" +"v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ\n" +"82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz\n" +"o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs\n" +"a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx\n" +"OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW\n" +"mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o\n" +"+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC\n" +"rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX\n" +"5OfNeOI5wSsSnqaeG8XmDtkx2Q==\n" +"-----END CERTIFICATE-----\n" +"Swisscom Root EV CA 2\n" +"=====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE\n" +"BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl\n" +"cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN\n" +"MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT\n" +"HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg\n" +"Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz\n" +"o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy\n" +"Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti\n" +"GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li\n" +"qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH\n" +"Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG\n" +"alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa\n" +"m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox\n" +"bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi\n" +"xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/\n" +"BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED\n" +"MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB\n" +"bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL\n" +"j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU\n" +"wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7\n" +"XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH\n" +"59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/\n" +"23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq\n" +"J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA\n" +"HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi\n" +"uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW\n" +"l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=\n" +"-----END CERTIFICATE-----\n" +"CA Disig Root R1\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw\n" +"EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp\n" +"ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx\n" +"EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp\n" +"c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy\n" +"3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8\n" +"u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2\n" +"m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk\n" +"CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa\n" +"YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6\n" +"vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL\n" +"LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX\n" +"ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is\n" +"XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV\n" +"HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ\n" +"04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR\n" +"xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B\n" +"LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM\n" +"CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb\n" +"VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85\n" +"YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS\n" +"ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix\n" +"lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N\n" +"UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ\n" +"a7+h89n07eLw4+1knj0vllJPgFOL\n" +"-----END CERTIFICATE-----\n" +"CA Disig Root R2\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw\n" +"EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp\n" +"ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx\n" +"EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp\n" +"c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC\n" +"w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia\n" +"xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7\n" +"A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S\n" +"GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV\n" +"g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa\n" +"5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE\n" +"koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A\n" +"Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i\n" +"Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV\n" +"HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u\n" +"Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM\n" +"tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV\n" +"sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je\n" +"dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8\n" +"1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx\n" +"mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01\n" +"utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0\n" +"sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg\n" +"UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV\n" +"7+ZtsH8tZ/3zbBt1RqPlShfppNcL\n" +"-----END CERTIFICATE-----\n" +"ACCVRAIZ1\n" +"=========\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB\n" +"SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1\n" +"MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH\n" +"UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\n" +"DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM\n" +"jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0\n" +"RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD\n" +"aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ\n" +"0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG\n" +"WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7\n" +"8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR\n" +"5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J\n" +"9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK\n" +"Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw\n" +"Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu\n" +"Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2\n" +"VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM\n" +"Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA\n" +"QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh\n" +"AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA\n" +"YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj\n" +"AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA\n" +"IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk\n" +"aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0\n" +"dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2\n" +"MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI\n" +"hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E\n" +"R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN\n" +"YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49\n" +"nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ\n" +"TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3\n" +"sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h\n" +"I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg\n" +"Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd\n" +"3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p\n" +"EfbRD0tVNEYqi4Y7\n" +"-----END CERTIFICATE-----\n" +"TWCA Global Root CA\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT\n" +"CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD\n" +"QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK\n" +"EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg\n" +"Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C\n" +"nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV\n" +"r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR\n" +"Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV\n" +"tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W\n" +"KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99\n" +"sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p\n" +"yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn\n" +"kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI\n" +"zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC\n" +"AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g\n" +"cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn\n" +"LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M\n" +"8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg\n" +"/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg\n" +"lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP\n" +"A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m\n" +"i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8\n" +"EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3\n" +"zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=\n" +"-----END CERTIFICATE-----\n" +"TeliaSonera Root CA v1\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE\n" +"CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4\n" +"MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW\n" +"VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+\n" +"6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA\n" +"3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k\n" +"B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn\n" +"Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH\n" +"oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3\n" +"F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ\n" +"oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7\n" +"gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc\n" +"TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB\n" +"AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW\n" +"DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm\n" +"zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx\n" +"0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW\n" +"pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV\n" +"G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc\n" +"c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT\n" +"JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2\n" +"qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6\n" +"Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems\n" +"WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=\n" +"-----END CERTIFICATE-----\n" +"E-Tugra Certification Authority\n" +"===============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w\n" +"DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls\n" +"ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN\n" +"ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw\n" +"NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx\n" +"QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl\n" +"cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD\n" +"DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\n" +"MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd\n" +"hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K\n" +"CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g\n" +"ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ\n" +"BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0\n" +"E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz\n" +"rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq\n" +"jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn\n" +"rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5\n" +"dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB\n" +"/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG\n" +"MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK\n" +"kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO\n" +"XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807\n" +"VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo\n" +"a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc\n" +"dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV\n" +"KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT\n" +"Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0\n" +"8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G\n" +"C7TbO6Orb1wdtn7os4I07QZcJA==\n" +"-----END CERTIFICATE-----\n" +"T-TeleSec GlobalRoot Class 2\n" +"============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\n" +"IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\n" +"cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx\n" +"MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\n" +"dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\n" +"ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3\n" +"DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ\n" +"SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F\n" +"vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970\n" +"2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV\n" +"WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA\n" +"MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy\n" +"YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4\n" +"r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf\n" +"vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR\n" +"3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN\n" +"9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==\n" +"-----END CERTIFICATE-----\n" +"Atos TrustedRoot 2011\n" +"=====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU\n" +"cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4\n" +"MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG\n" +"A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV\n" +"hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr\n" +"54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+\n" +"DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320\n" +"HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR\n" +"z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R\n" +"l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ\n" +"bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\n" +"CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h\n" +"k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh\n" +"TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9\n" +"61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G\n" +"3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed\n" +"-----END CERTIFICATE-----\n" +"QuoVadis Root CA 1 G3\n" +"=====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG\n" +"A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\n" +"b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN\n" +"MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg\n" +"RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE\n" +"PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm\n" +"PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6\n" +"Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN\n" +"ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l\n" +"g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV\n" +"7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX\n" +"9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f\n" +"iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg\n" +"t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n" +"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI\n" +"hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC\n" +"MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3\n" +"GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct\n" +"Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP\n" +"+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh\n" +"3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa\n" +"wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6\n" +"O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0\n" +"FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV\n" +"hMJKzRwuJIczYOXD\n" +"-----END CERTIFICATE-----\n" +"QuoVadis Root CA 2 G3\n" +"=====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG\n" +"A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\n" +"b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN\n" +"MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg\n" +"RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh\n" +"ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY\n" +"NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t\n" +"oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o\n" +"MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l\n" +"V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo\n" +"L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ\n" +"sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD\n" +"6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh\n" +"lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n" +"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI\n" +"hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66\n" +"AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K\n" +"pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9\n" +"x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz\n" +"dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X\n" +"U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw\n" +"mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD\n" +"zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN\n" +"JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr\n" +"O3jtZsSOeWmD3n+M\n" +"-----END CERTIFICATE-----\n" +"QuoVadis Root CA 3 G3\n" +"=====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG\n" +"A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\n" +"b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN\n" +"MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg\n" +"RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286\n" +"IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL\n" +"Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe\n" +"6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3\n" +"I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U\n" +"VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7\n" +"5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi\n" +"Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM\n" +"dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt\n" +"rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n" +"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI\n" +"hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px\n" +"KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS\n" +"t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ\n" +"TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du\n" +"DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib\n" +"Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD\n" +"hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX\n" +"0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW\n" +"dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2\n" +"PpxxVJkES/1Y+Zj0\n" +"-----END CERTIFICATE-----\n" +"DigiCert Assured ID Root G2\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG\n" +"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\n" +"IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw\n" +"MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\n" +"ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw\n" +"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH\n" +"35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq\n" +"bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw\n" +"VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP\n" +"YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn\n" +"lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO\n" +"w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv\n" +"0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz\n" +"d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW\n" +"hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M\n" +"jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo\n" +"IhNzbM8m9Yop5w==\n" +"-----END CERTIFICATE-----\n" +"DigiCert Assured ID Root G3\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV\n" +"UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD\n" +"VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\n" +"MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" +"d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ\n" +"BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb\n" +"RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs\n" +"KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF\n" +"UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy\n" +"YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy\n" +"1vUhZscv6pZjamVFkpUBtA==\n" +"-----END CERTIFICATE-----\n" +"DigiCert Global Root G2\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG\n" +"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\n" +"HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx\n" +"MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\n" +"dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq\n" +"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ\n" +"kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO\n" +"3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV\n" +"BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM\n" +"UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB\n" +"o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu\n" +"5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr\n" +"F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U\n" +"WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH\n" +"QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/\n" +"iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n" +"MrY=\n" +"-----END CERTIFICATE-----\n" +"DigiCert Global Root G3\n" +"=======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV\n" +"UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD\n" +"VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw\n" +"MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k\n" +"aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C\n" +"AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O\n" +"YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP\n" +"BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp\n" +"Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y\n" +"3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34\n" +"VOKa5Vt8sycX\n" +"-----END CERTIFICATE-----\n" +"DigiCert Trusted Root G4\n" +"========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG\n" +"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw\n" +"HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\n" +"MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" +"d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G\n" +"CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp\n" +"pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o\n" +"k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa\n" +"vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY\n" +"QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6\n" +"MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm\n" +"mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7\n" +"f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH\n" +"dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8\n" +"oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\n" +"DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD\n" +"ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY\n" +"ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr\n" +"yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy\n" +"7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah\n" +"ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN\n" +"5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb\n" +"/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa\n" +"5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK\n" +"G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP\n" +"82Z+\n" +"-----END CERTIFICATE-----\n" +"WoSign\n" +"======\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG\n" +"EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g\n" +"QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ\n" +"BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh\n" +"dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA\n" +"vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO\n" +"CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX\n" +"2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5\n" +"KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR\n" +"+ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez\n" +"EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk\n" +"lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2\n" +"8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY\n" +"yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C\n" +"AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R\n" +"8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1\n" +"LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq\n" +"T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj\n" +"y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC\n" +"2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes\n" +"5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/\n" +"EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh\n" +"mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx\n" +"kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi\n" +"kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w==\n" +"-----END CERTIFICATE-----\n" +"WoSign China\n" +"============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG\n" +"EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv\n" +"geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD\n" +"VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN\n" +"BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k\n" +"8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5\n" +"uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85\n" +"dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5\n" +"Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy\n" +"b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc\n" +"76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m\n" +"+Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6\n" +"yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX\n" +"GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud\n" +"EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA\n" +"A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6\n" +"yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY\n" +"r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115\n" +"j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A\n" +"kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97\n" +"qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y\n" +"jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB\n" +"ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv\n" +"T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO\n" +"kI26oQ==\n" +"-----END CERTIFICATE-----\n" +"COMODO RSA Certification Authority\n" +"==================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE\n" +"BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\n" +"A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv\n" +"biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC\n" +"R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\n" +"ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB\n" +"dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn\n" +"dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ\n" +"FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+\n" +"5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG\n" +"x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX\n" +"2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL\n" +"OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3\n" +"sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C\n" +"GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5\n" +"WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\n" +"FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w\n" +"DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt\n" +"rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+\n" +"nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg\n" +"tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW\n" +"sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp\n" +"pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA\n" +"zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq\n" +"ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52\n" +"7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I\n" +"LaZRfyHBNVOFBkpdn627G190\n" +"-----END CERTIFICATE-----\n" +"USERTrust RSA Certification Authority\n" +"=====================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE\n" +"BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\n" +"ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\n" +"dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE\n" +"BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\n" +"ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\n" +"dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz\n" +"0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j\n" +"Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn\n" +"RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O\n" +"+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq\n" +"/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE\n" +"Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM\n" +"lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8\n" +"yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+\n" +"eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\n" +"BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n" +"MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW\n" +"FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ\n" +"7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ\n" +"Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM\n" +"8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi\n" +"FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi\n" +"yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c\n" +"J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw\n" +"sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx\n" +"Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9\n" +"-----END CERTIFICATE-----\n" +"USERTrust ECC Certification Authority\n" +"=====================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC\n" +"VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n" +"aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\n" +"biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC\n" +"VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n" +"aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\n" +"biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2\n" +"0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez\n" +"nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV\n" +"HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB\n" +"HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu\n" +"9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n" +"-----END CERTIFICATE-----\n" +"GlobalSign ECC Root CA - R4\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb\n" +"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\n" +"EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb\n" +"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\n" +"EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl\n" +"OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P\n" +"AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV\n" +"MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF\n" +"JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=\n" +"-----END CERTIFICATE-----\n" +"GlobalSign ECC Root CA - R5\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb\n" +"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\n" +"EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb\n" +"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\n" +"EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6\n" +"SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS\n" +"h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd\n" +"BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx\n" +"uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7\n" +"yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3\n" +"-----END CERTIFICATE-----\n" +"Staat der Nederlanden Root CA - G3\n" +"==================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE\n" +"CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g\n" +"Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC\n" +"TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l\n" +"ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y\n" +"olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t\n" +"x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy\n" +"EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K\n" +"Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur\n" +"mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5\n" +"1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp\n" +"07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo\n" +"FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE\n" +"41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB\n" +"AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu\n" +"yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD\n" +"U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq\n" +"KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1\n" +"v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA\n" +"8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b\n" +"8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r\n" +"mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq\n" +"1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI\n" +"JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV\n" +"tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=\n" +"-----END CERTIFICATE-----\n" +"Staat der Nederlanden EV Root CA\n" +"================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE\n" +"CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g\n" +"RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M\n" +"MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl\n" +"cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk\n" +"SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW\n" +"O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r\n" +"0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8\n" +"Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV\n" +"XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr\n" +"08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV\n" +"0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd\n" +"74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx\n" +"fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC\n" +"MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa\n" +"ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI\n" +"eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu\n" +"c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq\n" +"5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN\n" +"b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN\n" +"f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi\n" +"5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4\n" +"WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK\n" +"DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy\n" +"eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==\n" +"-----END CERTIFICATE-----\n" +"IdenTrust Commercial Root CA 1\n" +"==============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG\n" +"EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS\n" +"b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES\n" +"MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB\n" +"IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld\n" +"hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/\n" +"mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi\n" +"1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C\n" +"XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl\n" +"3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy\n" +"NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV\n" +"WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg\n" +"xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix\n" +"uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC\n" +"AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI\n" +"hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH\n" +"6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg\n" +"ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt\n" +"ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV\n" +"YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX\n" +"feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro\n" +"kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe\n" +"2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz\n" +"Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R\n" +"cGzM7vRX+Bi6hG6H\n" +"-----END CERTIFICATE-----\n" +"IdenTrust Public Sector Root CA 1\n" +"=================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG\n" +"EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv\n" +"ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV\n" +"UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS\n" +"b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy\n" +"P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6\n" +"Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI\n" +"rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf\n" +"qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS\n" +"mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn\n" +"ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh\n" +"LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v\n" +"iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL\n" +"4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B\n" +"Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw\n" +"DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj\n" +"t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A\n" +"mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt\n" +"GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt\n" +"m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx\n" +"NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4\n" +"Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI\n" +"ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC\n" +"ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ\n" +"3Wl9af0AVqW3rLatt8o+Ae+c\n" +"-----END CERTIFICATE-----\n" +"Entrust Root Certification Authority - G2\n" +"=========================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV\n" +"BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy\n" +"bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug\n" +"b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw\n" +"HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT\n" +"DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx\n" +"OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s\n" +"eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi\n" +"MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP\n" +"/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz\n" +"HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU\n" +"s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y\n" +"TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx\n" +"AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6\n" +"0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z\n" +"iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\n" +"Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi\n" +"nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+\n" +"vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO\n" +"e4pIb4tF9g==\n" +"-----END CERTIFICATE-----\n" +"Entrust Root Certification Authority - EC1\n" +"==========================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx\n" +"FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn\n" +"YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl\n" +"ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n" +"IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw\n" +"FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs\n" +"LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg\n" +"dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt\n" +"IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy\n" +"AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef\n" +"9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\n" +"FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h\n" +"vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8\n" +"kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G\n" +"-----END CERTIFICATE-----\n" +"CFCA EV ROOT\n" +"============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE\n" +"CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB\n" +"IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw\n" +"MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD\n" +"DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV\n" +"BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD\n" +"7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN\n" +"uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW\n" +"ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7\n" +"xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f\n" +"py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K\n" +"gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol\n" +"hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ\n" +"tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf\n" +"BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB\n" +"/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB\n" +"ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q\n" +"ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua\n" +"4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG\n" +"E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX\n" +"BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn\n" +"aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy\n" +"PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX\n" +"kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C\n" +"ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su\n" +"-----END CERTIFICATE-----\n" +"TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5\n" +"====================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN\n" +"BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp\n" +"bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg\n" +"RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw\n" +"ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w\n" +"SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE\n" +"n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp\n" +"ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +"CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537\n" +"jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m\n" +"ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP\n" +"9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV\n" +"4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH\n" +"HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI\n" +"hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo\n" +"BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq\n" +"URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl\n" +"lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8\n" +"B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU=\n" +"-----END CERTIFICATE-----\n" +"Certinomis - Root CA\n" +"====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK\n" +"Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg\n" +"LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx\n" +"EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD\n" +"ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos\n" +"P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo\n" +"d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap\n" +"z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00\n" +"8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x\n" +"RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE\n" +"6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t\n" +"FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV\n" +"PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH\n" +"i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj\n" +"YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I\n" +"6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF\n" +"AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV\n" +"WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw\n" +"Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX\n" +"lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ\n" +"y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9\n" +"Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng\n" +"DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi\n" +"I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM\n" +"cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr\n" +"hkIGuUE=\n" +"-----END CERTIFICATE-----\n" +"OISTE WISeKey Global Root GB CA\n" +"===============================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG\n" +"EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl\n" +"ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw\n" +"MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD\n" +"VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds\n" +"b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX\n" +"scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP\n" +"rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk\n" +"9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o\n" +"Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg\n" +"GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB\n" +"/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI\n" +"hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD\n" +"dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0\n" +"VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui\n" +"HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic\n" +"Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=\n" +"-----END CERTIFICATE-----\n" +"Certification Authority of WoSign G2\n" +"====================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG\n" +"EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g\n" +"QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx\n" +"CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm\n" +"aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +"CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai\n" +"XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du\n" +"W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9\n" +"5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK\n" +"v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC\n" +"AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI\n" +"hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY\n" +"P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3\n" +"TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu\n" +"+sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+\n" +"7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg=\n" +"-----END CERTIFICATE-----\n" +"CA WoSign ECC Root\n" +"==================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD\n" +"TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v\n" +"dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK\n" +"ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI\n" +"zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU\n" +"t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw\n" +"QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R\n" +"MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0\n" +"Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu\n" +"a/GRspBl9JrmkO5K\n" +"-----END CERTIFICATE-----\n" +"SZAFIR ROOT CA2\n" +"===============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG\n" +"A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV\n" +"BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ\n" +"BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD\n" +"VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q\n" +"qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK\n" +"DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE\n" +"2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ\n" +"ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi\n" +"ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\n" +"AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC\n" +"AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5\n" +"O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67\n" +"oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul\n" +"4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6\n" +"+/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==\n" +"-----END CERTIFICATE-----\n" +"Certum Trusted Network CA 2\n" +"===========================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE\n" +"BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1\n" +"bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y\n" +"ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ\n" +"TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl\n" +"cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB\n" +"IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9\n" +"7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o\n" +"CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b\n" +"Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p\n" +"uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130\n" +"GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ\n" +"9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB\n" +"Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye\n" +"hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM\n" +"BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n" +"AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI\n" +"hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW\n" +"Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA\n" +"L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo\n" +"clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM\n" +"pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb\n" +"w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo\n" +"J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm\n" +"ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX\n" +"is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7\n" +"zAYspsbiDrW5viSP\n" +"-----END CERTIFICATE-----\n" +"Hellenic Academic and Research Institutions RootCA 2015\n" +"=======================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT\n" +"BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0\n" +"aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl\n" +"YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx\n" +"MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg\n" +"QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV\n" +"BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw\n" +"MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv\n" +"bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh\n" +"iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+\n" +"6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd\n" +"FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr\n" +"i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F\n" +"GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2\n" +"fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu\n" +"iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc\n" +"Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n" +"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI\n" +"hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+\n" +"D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM\n" +"d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y\n" +"d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn\n" +"82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb\n" +"davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F\n" +"Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt\n" +"J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa\n" +"JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q\n" +"p/UsQu0yrbYhnr68\n" +"-----END CERTIFICATE-----\n" +"Hellenic Academic and Research Institutions ECC RootCA 2015\n" +"===========================================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0\n" +"aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u\n" +"cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj\n" +"aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw\n" +"MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj\n" +"IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD\n" +"VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290\n" +"Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP\n" +"dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK\n" +"Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\n" +"BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA\n" +"GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn\n" +"dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR\n" +"-----END CERTIFICATE-----\n" +"Certplus Root CA G1\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV\n" +"BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe\n" +"Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD\n" +"ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD\n" +"ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN\n" +"r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx\n" +"Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj\n" +"BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv\n" +"LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2\n" +"z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc\n" +"4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd\n" +"4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj\n" +"jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+\n" +"ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G\n" +"A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY\n" +"lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh\n" +"66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG\n" +"YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/\n" +"2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F\n" +"6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX\n" +"CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe\n" +"tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC\n" +"VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/\n" +"+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+\n" +"qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=\n" +"-----END CERTIFICATE-----\n" +"Certplus Root CA G2\n" +"===================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT\n" +"AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x\n" +"NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0\n" +"cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA\n" +"BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN\n" +"Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD\n" +"AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud\n" +"IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV\n" +"HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl\n" +"vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==\n" +"-----END CERTIFICATE-----\n" +"OpenTrust Root CA G1\n" +"====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV\n" +"BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx\n" +"MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM\n" +"CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB\n" +"AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa\n" +"Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87\n" +"ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO\n" +"YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9\n" +"xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO\n" +"9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq\n" +"3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi\n" +"n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9\n" +"URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr\n" +"TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\n" +"/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px\n" +"N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E\n" +"PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv\n" +"uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK\n" +"n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh\n" +"X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80\n" +"nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm\n" +"GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/\n" +"bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o\n" +"4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA\n" +"OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx\n" +"-----END CERTIFICATE-----\n" +"OpenTrust Root CA G2\n" +"====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV\n" +"BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy\n" +"MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM\n" +"CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB\n" +"AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+\n" +"Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz\n" +"4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV\n" +"eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt\n" +"UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz\n" +"3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj\n" +"3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz\n" +"9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0\n" +"0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT\n" +"y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\n" +"/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59\n" +"M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz\n" +"Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI\n" +"mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG\n" +"S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp\n" +"EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ\n" +"6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr\n" +"gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo\n" +"SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0\n" +"YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm\n" +"u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK\n" +"-----END CERTIFICATE-----\n" +"OpenTrust Root CA G3\n" +"====================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT\n" +"AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X\n" +"DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w\n" +"ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA\n" +"IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B\n" +"ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB\n" +"/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf\n" +"BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM\n" +"BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta\n" +"3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB\n" +"-----END CERTIFICATE-----\n" +"ISRG Root X1\n" +"============\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE\n" +"BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD\n" +"EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG\n" +"EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT\n" +"DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r\n" +"Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1\n" +"3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K\n" +"b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN\n" +"Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ\n" +"4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf\n" +"1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu\n" +"hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH\n" +"usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r\n" +"OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G\n" +"A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY\n" +"9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" +"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV\n" +"0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt\n" +"hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw\n" +"TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx\n" +"e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA\n" +"JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD\n" +"YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n\n" +"JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ\n" +"m+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" +"-----END CERTIFICATE-----\n" +"AC RAIZ FNMT-RCM\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT\n" +"AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw\n" +"MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD\n" +"TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\n" +"ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf\n" +"qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr\n" +"btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL\n" +"j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou\n" +"08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw\n" +"WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT\n" +"tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ\n" +"47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC\n" +"ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa\n" +"i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n" +"FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o\n" +"dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD\n" +"nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s\n" +"D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ\n" +"j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT\n" +"Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW\n" +"+YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7\n" +"Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d\n" +"8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm\n" +"5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG\n" +"rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=\n" +"-----END CERTIFICATE-----\n" +"Amazon Root CA 1\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD\n" +"VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1\n" +"MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\n" +"bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +"ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH\n" +"FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ\n" +"gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t\n" +"dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce\n" +"VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\n" +"/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3\n" +"DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM\n" +"CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy\n" +"8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa\n" +"2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2\n" +"xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5\n" +"-----END CERTIFICATE-----\n" +"Amazon Root CA 2\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD\n" +"VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1\n" +"MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\n" +"bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\n" +"ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4\n" +"kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp\n" +"N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9\n" +"AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd\n" +"fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx\n" +"kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS\n" +"btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0\n" +"Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN\n" +"c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+\n" +"3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw\n" +"DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA\n" +"A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY\n" +"+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE\n" +"YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW\n" +"xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ\n" +"gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW\n" +"aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV\n" +"Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3\n" +"KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi\n" +"JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=\n" +"-----END CERTIFICATE-----\n" +"Amazon Root CA 3\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG\n" +"EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy\n" +"NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\n" +"MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB\n" +"f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr\n" +"Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43\n" +"rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc\n" +"eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==\n" +"-----END CERTIFICATE-----\n" +"Amazon Root CA 4\n" +"================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG\n" +"EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy\n" +"NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\n" +"MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN\n" +"/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri\n" +"83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" +"HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA\n" +"MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1\n" +"AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==\n" +"-----END CERTIFICATE-----\n" +"LuxTrust Global Root 2\n" +"======================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQELBQAwRjELMAkG\n" +"A1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNVBAMMFkx1eFRydXN0IEdsb2Jh\n" +"bCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUwMzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEW\n" +"MBQGA1UECgwNTHV4VHJ1c3QgUy5BLjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCC\n" +"AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wm\n" +"Kb3FibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTemhfY7RBi2\n" +"xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1EMShduxq3sVs35a0VkBC\n" +"wGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsnXpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm\n" +"1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkm\n" +"FRseTJIpgp7VkoGSQXAZ96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niF\n" +"wpN6cj5mj5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4gDEa/\n" +"a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+8kPREd8vZS9kzl8U\n" +"ubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2jX5t/Lax5Gw5CMZdjpPuKadUiDTSQ\n" +"MC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmHhFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB\n" +"/zBCBgNVHSAEOzA5MDcGByuBKwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5\n" +"Lmx1eHRydXN0Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT\n" +"+Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQELBQADggIBAGoZ\n" +"FO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9BzZAcg4atmpZ1gDlaCDdLnIN\n" +"H2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTOjFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW\n" +"7MM3LGVYvlcAGvI1+ut7MV3CwRI9loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIu\n" +"ZY+kt9J/Z93I055cqqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWA\n" +"VWe+2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/JEAdemrR\n" +"TxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKrezrnK+T+Tb/mjuuqlPpmt\n" +"/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQfLSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc\n" +"7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31I\n" +"iyBMz2TWuJdGsE7RKlY6oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr\n" +"-----END CERTIFICATE-----\n" +"TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1\n" +"=============================================\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT\n" +"D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr\n" +"IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g\n" +"TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp\n" +"ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD\n" +"VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt\n" +"c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth\n" +"bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11\n" +"IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +"MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8\n" +"6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc\n" +"wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0\n" +"3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9\n" +"WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU\n" +"ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ\n" +"KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh\n" +"AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc\n" +"lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R\n" +"e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j\n" +"q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=\n" +"-----END CERTIFICATE-----\n" +}; diff --git a/deps/mbedtls/camellia.c b/deps/mbedtls/camellia.c new file mode 100644 index 0000000000..ac6f96a83a --- /dev/null +++ b/deps/mbedtls/camellia.c @@ -0,0 +1,1072 @@ +/* + * 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 + +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 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 ) +{ + memset( ctx, 0, sizeof( mbedtls_camellia_context ) ); +} + +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_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]; + + 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_INVALID_KEY_LENGTH ); + } + + 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; + + 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]; + + ( (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]; + + 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 = *iv_off; + + 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 = *nc_off; + + 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/deps/mbedtls/ccm.c b/deps/mbedtls/ccm.c new file mode 100644 index 0000000000..13a8fd1a24 --- /dev/null +++ b/deps/mbedtls/ccm.c @@ -0,0 +1,464 @@ +/* + * 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 + +#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 */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +#define CCM_ENCRYPT 0 +#define CCM_DECRYPT 1 + +/* + * Initialize context + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) +{ + 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; + + 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 ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_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 ) \ + 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]; + +/* + * 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) + */ + if( tag_len < 4 || 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_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 ) +{ + return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, + add, add_len, input, output, tag, tag_len ) ); +} + +/* + * Authenticated decryption + */ +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 ) +{ + int ret; + unsigned char check_tag[16]; + unsigned char i; + int diff; + + 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_zeroize( output, length ); + return( MBEDTLS_ERR_CCM_AUTH_FAILED ); + } + + return( 0 ); +} + + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * Examples 1 to 3 from SP800-38C Appendix C + */ + +#define NB_TESTS 3 + +/* + * The data is the same for all tests, only the used length changes + */ +static const unsigned char key[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f +}; + +static const unsigned char iv[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b +}; + +static const unsigned char ad[] = { + 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[] = { + 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 [NB_TESTS] = { 7, 8, 12 }; +static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; +static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; +static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; + +static const unsigned char res[NB_TESTS][32] = { + { 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; + unsigned char out[32]; + size_t i; + int ret; + + mbedtls_ccm_init( &ctx ); + + if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 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 ); + + ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + msg, out, + out + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + res[i], out, + res[i] + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, msg, msg_len[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/deps/mbedtls/certs.c b/deps/mbedtls/certs.c new file mode 100644 index 0000000000..f1379b8cb1 --- /dev/null +++ b/deps/mbedtls/certs.c @@ -0,0 +1,403 @@ +/* + * 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" + +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 + +static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256; + +#endif + +#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" + +#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 + +static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1; + +#endif + +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_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\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/f8wDQYJKoZIhvcNAQEFBQADggEBAJxnXClY\r\n" +"oHkbp70cqBrsGXLybA74czbO5RdLEgFs7rHVS9r+c293luS/KdliLScZqAzYVylw\r\n" +"UfRWvKMoWhHYKp3dEIS4xTXk6/5zXxhv9Rw8SGc8qn6vITHk1S1mPevtekgasY5Y\r\n" +"iWQuM3h4YVlRH3HHEMAD1TnAexfXHHDFQGe+Bd1iAbz1/sH9H8l4StwX6egvTK3M\r\n" +"wXRwkKkvjKaEDA9ATbZx0mI8LGsxSuCqe9r9dyjmttd47J1p1Rulz3CLzaRcVIuS\r\n" +"RRQfaD8neM9c1S/iJ/amTVqJxA1KOdOS5780WhPfSArA+g4qAmSjelc3p4wWpha8\r\n" +"zhuYwjVuX6JHG0c=\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa ); + +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 ); + +const char mbedtls_test_cli_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDhTCCAm2gAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTcwNTA1MTMwNzU5WhcNMjcwNTA2MTMwNzU5WjA8MQswCQYDVQQGEwJOTDERMA8G\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" +"o4GSMIGPMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITBjBgNVHSMEXDBa\r\n" +"gBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNV\r\n" +"BAoMCFBvbGFyU1NMMRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBggEAMAkGA1Ud\r\n" +"EwQCMAAwDQYJKoZIhvcNAQELBQADggEBAC7yO786NvcHpK8UovKIG9cB32oSQQom\r\n" +"LoR0eHDRzdqEkoq7yGZufHFiRAAzbMqJfogRtxlrWAeB4y/jGaMBV25IbFOIcH2W\r\n" +"iCEaMMbG+VQLKNvuC63kmw/Zewc9ThM6Pa1Hcy0axT0faf1B/U01j0FIcw/6mTfK\r\n" +"D8w48OIwc1yr0JtutCVjig5DC0yznGMt32RyseOLcUe+lfq005v2PAiCozr5X8rE\r\n" +"ofGZpiM2NqRPePgYy+Vc75Zk28xkRQq1ncprgQb3S4vTsZdScpM9hLf+eMlrgqlj\r\n" +"c5PLSkXBeLE5+fedkyfTaLxxQlgCpuoOhKBm04/R1pWNzUHyqagjO9Q=\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa ); + +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/deps/mbedtls/cipher.c b/deps/mbedtls/cipher.c new file mode 100644 index 0000000000..e9e0b223e5 --- /dev/null +++ b/deps/mbedtls/cipher.c @@ -0,0 +1,917 @@ +/** + * \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 +#include + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CMAC_C) +#include "mbedtls/cmac.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +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 ) +{ + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); +} + +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_CMAC_C) + if( ctx->cmac_ctx ) + { + mbedtls_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_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); +} + +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) +{ + if( NULL == cipher_info || NULL == ctx ) + 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 ); +} + +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, + int key_bitlen, const mbedtls_operation_t operation ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + 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 CFB and CTR mode always use the encryption key schedule + */ + if( MBEDTLS_ENCRYPT == operation || + MBEDTLS_MODE_CFB == 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; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* 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 ); + } + + memcpy( ctx->iv, iv, actual_iv_size ); + ctx->iv_size = actual_iv_size; + + return( 0 ); +} + +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + ctx->unprocessed_len = 0; + + return( 0 ); +} + +#if defined(MBEDTLS_GCM_C) +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + 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 ); + } + + return( 0 ); +} +#endif /* MBEDTLS_GCM_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 = 0; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *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 ( 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 && + 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; + } + + copy_len = ilen % block_size; + if( copy_len == 0 && ctx->operation == MBEDTLS_DECRYPT ) + 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_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_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 = 0xFF; + *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] ^ 0x80 ) | ( 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 ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *olen = 0; + + if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode || + MBEDTLS_MODE_GCM == ctx->cipher_info->mode || + MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) + { + 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 ) +{ + if( NULL == ctx || + MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + 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) +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_ENCRYPT != ctx->operation ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len ); + + return( 0 ); +} + +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ) +{ + int ret; + + if( NULL == ctx || NULL == ctx->cipher_info || + MBEDTLS_DECRYPT != ctx->operation ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + unsigned char check_tag[16]; + size_t i; + int diff; + + 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" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } + + return( 0 ); +} +#endif /* MBEDTLS_GCM_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; + + 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 ) +{ +#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 */ + + 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 ) +{ +#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 */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/deps/mbedtls/cipher_wrap.c b/deps/mbedtls/cipher_wrap.c new file mode 100644 index 0000000000..dc76af8ff4 --- /dev/null +++ b/deps/mbedtls/cipher_wrap.c @@ -0,0 +1,1451 @@ +/** + * \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_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_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.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_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_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 */ + +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_CTR) + aes_crypt_ctr_wrap, +#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", + 16, + 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", + 16, + 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", + 16, + 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_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_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_CTR) + 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_CTR) + 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_CTR) + camellia_crypt_ctr_wrap, +#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_CTR) + 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_CTR) + 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_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_CTR) + 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_CTR) + 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_CTR) + 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_CTR) + blowfish_crypt_ctr_wrap, +#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_CTR) + 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_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_CTR) + 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) */ + +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_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_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_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_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/deps/mbedtls/cmac.c b/deps/mbedtls/cmac.c new file mode 100644 index 0000000000..035ad071d4 --- /dev/null +++ b/deps/mbedtls/cmac.c @@ -0,0 +1,1074 @@ +/** + * \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 + + +#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 */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 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_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_zeroize( L, sizeof( L ) ); + + return( ret ); +} + +static void cmac_xor_block( unsigned char *output, const unsigned char *input1, + const unsigned char *input2, + const size_t block_size ) +{ + size_t index; + + for( index = 0; index < block_size; index++ ) + output[ index ] = input1[ index ] ^ input2[ index ]; +} + +/* + * 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_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_zeroize( K1, sizeof( K1 ) ); + mbedtls_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_zeroize( K1, sizeof( K1 ) ); + mbedtls_zeroize( K2, sizeof( K2 ) ); + + cmac_ctx->unprocessed_len = 0; + mbedtls_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + + mbedtls_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_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + mbedtls_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_zeroize( int_key, sizeof( int_key ) ); + + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +#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; + 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 ); + } + + 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; + 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" ); + } + +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/deps/mbedtls/ctr_drbg.c b/deps/mbedtls/ctr_drbg.c new file mode 100644 index 0000000000..55612c7fc9 --- /dev/null +++ b/deps/mbedtls/ctr_drbg.c @@ -0,0 +1,594 @@ +/* + * 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 publucation. + * + * 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 + +#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 */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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) + */ +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 + */ + mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ); + + 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_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 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; + + mbedtls_aes_setkey_enc( &aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ); + + /* + * 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; + + mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, chain, chain ); + } + + memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ + mbedtls_aes_setkey_enc( &aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ); + iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE; + p = output; + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + mbedtls_aes_free( &aes_ctx ); + + return( 0 ); +} + +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; + + 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 + */ + mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ); + + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ ) + tmp[i] ^= data[i]; + + /* + * Update key and counter + */ + mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ); + memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + return( 0 ); +} + +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + + if( add_len > 0 ) + { + /* 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; + + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } +} + +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; + + 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 + */ + block_cipher_df( seed, seed, seedlen ); + + /* + * Update state + */ + ctr_drbg_update_internal( ctx, seed ); + ctx->reseed_counter = 1; + + return( 0 ); +} + +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 ) + { + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } + + 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 + */ + mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ); + + 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; + } + + ctr_drbg_update_internal( ctx, add_input ); + + ctx->reseed_counter++; + + 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; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_ctr_drbg_update( ctx, buf, n ); + + 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/deps/mbedtls/debug.c b/deps/mbedtls/debug.c new file mode 100644 index 0000000000..4931f1b9e3 --- /dev/null +++ b/deps/mbedtls/debug.c @@ -0,0 +1,374 @@ +/* + * 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 +#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 ) + return; + if( NULL == ssl->conf ) + return; + if( NULL == ssl->conf->f_dbg ) + return; + if( level > debug_threshold ) + return; + + va_start( argp, format ); +#if defined(_WIN32) +#if defined(_TRUNCATE) + ret = _vsnprintf_s( str, DEBUG_BUF_SIZE, _TRUNCATE, format, argp ); +#else + ret = _vsnprintf( str, DEBUG_BUF_SIZE, format, argp ); + if( ret < 0 || (size_t) ret == DEBUG_BUF_SIZE ) + { + str[DEBUG_BUF_SIZE-1] = '\0'; + ret = -1; + } +#endif +#else + ret = vsnprintf( str, DEBUG_BUF_SIZE, format, argp ); +#endif + 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( ssl->conf == NULL || ssl->conf->f_dbg == NULL || 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( ssl->conf == NULL || ssl->conf->f_dbg == NULL || 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( ssl->conf == NULL || ssl->conf->f_dbg == NULL || 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( ssl->conf == NULL || ssl->conf->f_dbg == NULL || X == NULL || 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( ssl->conf == NULL || ssl->conf->f_dbg == NULL || crt == NULL || 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 */ + +#endif /* MBEDTLS_DEBUG_C */ diff --git a/deps/mbedtls/des.c b/deps/mbedtls/des.c new file mode 100644 index 0000000000..09f95cfc3b --- /dev/null +++ b/deps/mbedtls/des.c @@ -0,0 +1,1061 @@ +/* + * 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 + +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 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) \ +{ \ + 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; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + 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); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + 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 ]; \ +} + +#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 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_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_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_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_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_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_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/deps/mbedtls/dhm.c b/deps/mbedtls/dhm.c new file mode 100644 index 0000000000..bec52a11df --- /dev/null +++ b/deps/mbedtls/dhm.c @@ -0,0 +1,627 @@ +/* + * 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 + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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 + * + * 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 = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; + + 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 = 0; + } + +cleanup: + mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U ); + return( ret ); +} + +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) +{ + 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; + + 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; + + 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) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \ + *p++ = (unsigned char)( n >> 8 ); \ + *p++ = (unsigned char)( n ); p += n; + + 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 ); +} + +/* + * 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; + + if( ctx == NULL || 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; + + if( ctx == NULL || 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; + + if( ctx == NULL || 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 ) +{ + 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_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; + + 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_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; + + if( ( ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#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/deps/mbedtls/ecdh.c b/deps/mbedtls/ecdh.c new file mode 100644 index 0000000000..c0a8147312 --- /dev/null +++ b/deps/mbedtls/ecdh.c @@ -0,0 +1,264 @@ +/* + * 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 + +/* + * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair + */ +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 ) +{ + return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); +} + +/* + * 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 ) +{ + int ret; + mbedtls_ecp_point P; + + mbedtls_ecp_point_init( &P ); + + /* + * Make sure Q is a valid pubkey before using it + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); + + 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 ); +} + +/* + * Initialize context + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); +} + +/* + * Free context + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_group_free( &ctx->grp ); + mbedtls_ecp_point_free( &ctx->Q ); + mbedtls_ecp_point_free( &ctx->Qp ); + mbedtls_ecp_point_free( &ctx->Vi ); + mbedtls_ecp_point_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->d ); + mbedtls_mpi_free( &ctx->z ); + mbedtls_mpi_free( &ctx->_d ); +} + +/* + * 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 ret; + size_t grp_len, pt_len; + + if( ctx == NULL || ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) + != 0 ) + return( ret ); + + 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, ctx->point_format, + &pt_len, buf, blen ) ) != 0 ) + return( ret ); + + *olen = grp_len + pt_len; + return( 0 ); +} + +/* + * 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; + + if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) + != 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; + + if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ) + return( 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 ); +} + +/* + * 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 ret; + + if( ctx == NULL || ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) + != 0 ) + return( ret ); + + return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, + olen, buf, blen ); +} + +/* + * Parse and import the client's public value + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + int ret; + const unsigned char *p = buf; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + 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 ); +} + +/* + * 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 ret; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + if( mbedtls_mpi_size( &ctx->z ) > blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 ); + return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); +} + +#endif /* MBEDTLS_ECDH_C */ diff --git a/deps/mbedtls/ecdsa.c b/deps/mbedtls/ecdsa.c new file mode 100644 index 0000000000..4156f3c3c4 --- /dev/null +++ b/deps/mbedtls/ecdsa.c @@ -0,0 +1,448 @@ +/* + * 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 + +/* + * 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 ); +} + +/* + * Compute ECDSA signature of a hashed message (SEC1 4.1.3) + * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash 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 ) +{ + int ret, key_tries, sign_tries, blind_tries; + mbedtls_ecp_point R; + mbedtls_mpi k, e, t; + + /* 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 ); + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); + + sign_tries = 0; + do + { + /* + * Steps 1-3: generate a suitable ephemeral keypair + * and set r = xR mod n + */ + key_tries = 0; + do + { + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); + + if( key_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); + + /* + * 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. + */ + blind_tries = 0; + do + { + size_t n_size = ( grp->nbits + 7 ) / 8; + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); + + /* See mbedtls_ecp_gen_keypair() */ + if( ++blind_tries > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 ); + + /* + * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, 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( &k, &k, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); + + if( sign_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); + + return( ret ); +} + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * 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 ) +{ + int ret; + mbedtls_hmac_drbg_context 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 ); + + /* 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( &rng_ctx, md_info, data, 2 * grp_len ); + + ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, &rng_ctx ); + +cleanup: + mbedtls_hmac_drbg_free( &rng_ctx ); + mbedtls_mpi_free( &h ); + + return( ret ); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/* + * Verify ECDSA signature of hashed message (SEC1 4.1.4) + * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash 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) +{ + int ret; + mbedtls_mpi e, s_inv, u1, u2; + mbedtls_ecp_point R; + + 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 ); + + /* + * 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; + } + + /* + * Additional precaution: make sure Q is valid + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + + /* + * 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 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) ); + + /* + * Step 5: R = u1 G + u2 Q + * + * Since we're not using any secret data, no need to pass a RNG to + * mbedtls_ecp_mul() for countermesures. + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) ); + + 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 ); + + return( ret ); +} + +/* + * 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( 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 ) +{ + int ret; + mbedtls_mpi r, s; + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + (void) f_rng; + (void) p_rng; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg ) ); +#else + (void) md_alg; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng ) ); +#endif + + MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +#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 ) +{ + 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 ) +{ + int ret; + unsigned char *p = (unsigned char *) sig; + const unsigned char *end = sig + slen; + size_t len; + mbedtls_mpi r, s; + + 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( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, + &ctx->Q, &r, &s ) ) != 0 ) + goto cleanup; + + if( p != end ) + ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +/* + * 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 ) +{ + return( mbedtls_ecp_group_load( &ctx->grp, gid ) || + mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ); +} + +/* + * Set context from an mbedtls_ecp_keypair + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) +{ + int ret; + + 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 ) +{ + mbedtls_ecp_keypair_init( ctx ); +} + +/* + * Free context + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) +{ + mbedtls_ecp_keypair_free( ctx ); +} + +#endif /* MBEDTLS_ECDSA_C */ diff --git a/deps/mbedtls/ecjpake.c b/deps/mbedtls/ecjpake.c new file mode 100644 index 0000000000..1fa1c2d801 --- /dev/null +++ b/deps/mbedtls/ecjpake.c @@ -0,0 +1,1103 @@ +/* + * 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 + +/* + * 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 ) +{ + if( ctx == NULL ) + return; + + 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; + + 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 ) +{ + 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 ) +{ + 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 ) +{ + 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 */ + + 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; + + 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; + + *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 + + +#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 correponding 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/deps/mbedtls/ecp.c b/deps/mbedtls/ecp.c new file mode 100644 index 0000000000..5ad6863987 --- /dev/null +++ b/deps/mbedtls/ecp.c @@ -0,0 +1,2197 @@ +/* + * 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 + * + * [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 + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" +#include "mbedtls/threading.h" + +#include + +#if !defined(MBEDTLS_ECP_ALT) + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#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_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) +#define ECP_MONTGOMERY +#endif + +/* + * Curve types: internal for now, might be exposed later + */ +typedef enum +{ + ECP_TYPE_NONE = 0, + ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} ecp_curve_type; + +/* + * 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; + + 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 + */ +static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp ) +{ + if( grp->G.X.p == NULL ) + return( ECP_TYPE_NONE ); + + if( grp->G.Y.p == NULL ) + return( ECP_TYPE_MONTGOMERY ); + else + return( ECP_TYPE_SHORT_WEIERSTRASS ); +} + +/* + * Initialize (the components of) a point + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + 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 ) +{ + if( grp == NULL ) + return; + + memset( grp, 0, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Initialize (the components of) a key pair + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + 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_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; + + 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 ) +{ + return mbedtls_ecp_group_load( dst, src->id ); +} + +/* + * Set point to zero + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) +{ + int ret; + + 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 ) +{ + return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ); +} + +/* + * Compare two points lazyly + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ) +{ + 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; + + 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) + */ +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 = 0; + size_t plen; + + if( format != MBEDTLS_ECP_PF_UNCOMPRESSED && + format != MBEDTLS_ECP_PF_COMPRESSED ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * 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 ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + 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 ) ); + } + +cleanup: + return( ret ); +} + +/* + * Import a point from unsigned binary data (SEC1 2.3.4) + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char *buf, size_t ilen ) +{ + int ret; + size_t plen; + + if( ilen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( buf[0] == 0x00 ) + { + if( ilen == 1 ) + return( mbedtls_ecp_set_zero( pt ) ); + else + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + 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 ) ); + +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; + + /* + * 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; + + /* + * 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 ) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + + /* + * 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 ); + + return mbedtls_ecp_group_load( grp, curve_info->grp_id ); +} + +/* + * 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; + + 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_len ) +{ + int ret; + size_t i; + mbedtls_mpi *c, u, Zi, ZZi; + + if( t_len < 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_len); + } +#endif + + if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL ) + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + 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_len; 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_len-1], &grp->P ) ); + + for( i = t_len - 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_len; 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. + * + * Also, for the sake of compactness, only the seven low-order bits of x[i] + * are used to represent K_i, and the msb of x[i] encodes the 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_fixed( 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 comb method + * + * If i = i_{w-1} ... i_1 is the binary representation of i, then + * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P + * + * T must be able to hold 2^{w - 1} elements + * + * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) + */ +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 ) +{ + int ret; + unsigned char i, k; + size_t j; + mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1]; + + /* + * 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 ) ); + + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + cur = T + i; + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) ); + for( j = 0; j < d; j++ ) + MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) ); + + TT[k++] = cur; + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + + /* + * Compute the remaining ones using the minimal number of additions + * Be careful to update T[2^l] only after using it! + */ + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + j = i; + while( j-- ) + { + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) ); + TT[k++] = &T[i + j]; + } + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + +cleanup: + + return( ret ); +} + +/* + * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] + */ +static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char t_len, + 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_len; 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_len, + const unsigned char x[], size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point Txi; + size_t i; + + mbedtls_ecp_point_init( &Txi ); + + /* Start with a non-zero point and randomize its coordinates */ + i = d; + MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, 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_MPI_CHK( ecp_double_jac( grp, R, R ) ); + MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); + } + +cleanup: + + mbedtls_ecp_point_free( &Txi ); + + return( ret ); +} + +/* + * Multiplication using the comb method, + * for curves in short Weierstrass form + */ +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 ) +{ + int ret; + unsigned char w, m_is_odd, p_eq_g, pre_len, i; + size_t d; + unsigned char k[COMB_MAX_D + 1]; + mbedtls_ecp_point *T; + mbedtls_mpi M, mm; + + mbedtls_mpi_init( &M ); + mbedtls_mpi_init( &mm ); + + /* we need N to be odd to trnaform m in an odd number, check now */ + if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * 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 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 ); + if( p_eq_g ) + w++; +#else + p_eq_g = 0; +#endif + + /* + * 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; + + /* Other sizes that depend on w */ + pre_len = 1U << ( w - 1 ); + d = ( grp->nbits + w - 1 ) / w; + + /* + * Prepare precomputed points: if P == G we want to + * use grp->T if already initialized, or initialize it. + */ + T = p_eq_g ? grp->T : NULL; + + if( T == NULL ) + { + T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) ); + if( T == NULL ) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) ); + + if( p_eq_g ) + { + grp->T = T; + grp->T_size = pre_len; + } + } + + /* + * Make sure M is odd (M = m or M = N - m, since N is odd) + * using the fact that m * P = - (N - m) * P + */ + m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 ); + 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, ! m_is_odd ) ); + + /* + * Go for comb multiplication, R = M * P + */ + ecp_comb_fixed( k, d, w, &M ); + MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) ); + + /* + * Now get m * P from M * P and normalize it + */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +cleanup: + + if( T != NULL && ! p_eq_g ) + { + for( i = 0; i < pre_len; i++ ) + mbedtls_ecp_point_free( &T[i] ); + mbedtls_free( T ); + } + + mbedtls_mpi_free( &M ); + mbedtls_mpi_free( &mm ); + + if( ret != 0 ) + mbedtls_ecp_point_free( R ); + + 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 */ + +/* + * 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 ) +{ + int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + char is_grp_capable = 0; +#endif + + /* Common sanity checks */ + if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 || + ( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 ) + return( ret ); + +#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(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + ret = ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ); + +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + ret = ecp_mul_comb( grp, R, m, P, f_rng, p_rng ); + +#endif +#if defined(MBEDTLS_ECP_INTERNAL_ALT) +cleanup: + + if ( is_grp_capable ) + { + mbedtls_internal_ecp_free( grp ); + } + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + return( ret ); +} + +#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 ) +{ + 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( grp, R, m, P, NULL, NULL ) ); + } + +cleanup: + 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 ) +{ + int ret; + mbedtls_ecp_point mP; +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + char is_grp_capable = 0; +#endif + + if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + mbedtls_ecp_point_init( &mP ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R, n, Q ) ); + +#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 */ + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +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 ); + + return( ret ); +} + + +#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 */ + 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 ) +{ + /* Must use affine coordinates */ + if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + return( ecp_check_pubkey_mx( grp, pt ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == 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 ) +{ +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* see [Curve25519] page 5 */ + if( mbedtls_mpi_get_bit( d, 0 ) != 0 || + mbedtls_mpi_get_bit( d, 1 ) != 0 || + mbedtls_mpi_get_bit( d, 2 ) != 0 || + mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */ + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == 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 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; + size_t n_size = ( grp->nbits + 7 ) / 8; + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == 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 three bits are unset */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + } + else +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* SEC1 3.2.1: Generate d such that 1 <= n < N */ + int count = 0; + unsigned char rnd[MBEDTLS_ECP_MAX_BYTES]; + + /* + * 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( f_rng( p_rng, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, rnd, n_size ) ); + 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 ); + } + else +#endif /* ECP_SHORTWEIERSTRASS */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +cleanup: + if( ret != 0 ) + return( ret ); + + return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); +} + +/* + * 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 ) +{ + 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; + + 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 ) ); +} + +/* + * 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; + + 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/deps/mbedtls/ecp_curves.c b/deps/mbedtls/ecp_curves.c new file mode 100644 index 0000000000..df5ac3eea5 --- /dev/null +++ b/deps/mbedtls/ecp_curves.c @@ -0,0 +1,1329 @@ +/* + * 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 + +#if !defined(MBEDTLS_ECP_ALT) + +#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_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 ); + + /* Y intentionaly 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 */ + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) +{ + 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 */ + + 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 ) + M.n = P255_WIDTH + 1; + 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_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/deps/mbedtls/entropy.c b/deps/mbedtls/entropy.c new file mode 100644 index 0000000000..d4d1b27b7f --- /dev/null +++ b/deps/mbedtls/entropy.c @@ -0,0 +1,655 @@ +/* + * 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 + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) +{ + memset( ctx, 0, sizeof(mbedtls_entropy_context) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_starts( &ctx->accumulator, 0 ); +#else + mbedtls_sha256_starts( &ctx->accumulator, 0 ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_init( &ctx->havege_data ); +#endif + +#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 ); +#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 + mbedtls_zeroize( ctx, sizeof( mbedtls_entropy_context ) ); +} + +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 index, ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + index = ctx->source_count; + if( index >= MBEDTLS_ENTROPY_MAX_SOURCES ) + { + ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; + goto exit; + } + + ctx->source[index].f_source = f_source; + ctx->source[index].p_source = p_source; + ctx->source[index].threshold = threshold; + ctx->source[index].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; + + if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + { +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512( data, len, tmp, 0 ); +#else + mbedtls_sha256( data, len, tmp, 0 ); +#endif + p = tmp; + use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_update( &ctx->accumulator, header, 2 ); + mbedtls_sha512_update( &ctx->accumulator, p, use_len ); +#else + mbedtls_sha256_update( &ctx->accumulator, header, 2 ); + mbedtls_sha256_update( &ctx->accumulator, p, use_len ); +#endif + + return( 0 ); +} + +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 ) + { + return( ret ); + } + + /* + * Add if we actually gathered something + */ + if( olen > 0 ) + { + entropy_update( ctx, (unsigned char) i, buf, olen ); + ctx->source[i].size += olen; + } + } + + if( have_one_strong == 0 ) + return( MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE ); + + return( 0 ); +} + +/* + * 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) + mbedtls_sha512_finish( &ctx->accumulator, buf ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( mbedtls_sha512_context ) ); + mbedtls_sha512_starts( &ctx->accumulator, 0 ); + mbedtls_sha512_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + /* + * Perform second SHA-512 on entropy + */ + mbedtls_sha512( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); +#else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + mbedtls_sha256_finish( &ctx->accumulator, buf ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( mbedtls_sha256_context ) ); + mbedtls_sha256_starts( &ctx->accumulator, 0 ); + mbedtls_sha256_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + /* + * Perform second SHA-256 on entropy + */ + mbedtls_sha256( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); +#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: +#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_MAX_SEED_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 ); + mbedtls_entropy_update_manual( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + return( 0 ); +} +#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: + fclose( f ); + return( ret ); +} + +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + 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 ) + { + fclose( f ); + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_entropy_update_manual( ctx, buf, n ); + + 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/deps/mbedtls/entropy_poll.c b/deps/mbedtls/entropy_poll.c new file mode 100644 index 0000000000..a116e605d2 --- /dev/null +++ b/deps/mbedtls/entropy_poll.c @@ -0,0 +1,268 @@ +/* + * 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(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#if defined(MBEDTLS_TIMING_C) +#include +#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) +#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 + +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 ) ); +} + +#include +/* Check if version is at least 3.17.0 */ +static int check_version_3_17_plus( void ) +{ + int minor; + struct utsname un; + const char *ver; + + /* Get version information */ + uname(&un); + ver = un.release; + + /* Check major version; assume a single digit */ + if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) + return( -1 ); + + if( ver[0] - '0' > 3 ) + return( 0 ); + + /* Ok, so now we know major == 3, check minor. + * Assume 1 or 2 digits. */ + if( ver[2] < '0' || ver[2] > '9' ) + return( -1 ); + + minor = ver[2] - '0'; + + if( ver[3] >= '0' && ver[3] <= '9' ) + minor = 10 * minor + ver[3] - '0'; + else if( ver [3] != '.' ) + return( -1 ); + + if( minor < 17 ) + return( -1 ); + + return( 0 ); +} +static int has_getrandom = -1; +#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; + ((void) data); + +#if defined(HAVE_GETRANDOM) + if( has_getrandom == -1 ) + has_getrandom = ( check_version_3_17_plus() == 0 ); + + if( has_getrandom ) + { + int ret; + + if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = ret; + return( 0 ); + } +#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/deps/mbedtls/error.c b/deps/mbedtls/error.c new file mode 100644 index 0000000000..dd2db0c45c --- /dev/null +++ b/deps/mbedtls/error.c @@ -0,0 +1,707 @@ +/* + * 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_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_CIPHER_C) +#include "mbedtls/cipher.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_HMAC_DRBG_C) +#include "mbedtls/hmac_drbg.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_NET_C) +#include "mbedtls/net_sockets.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_RSA_C) +#include "mbedtls/rsa.h" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl.h" +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + +#if defined(MBEDTLS_XTEA_C) +#include "mbedtls/xtea.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 to function" ); + 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, eg because it was free()ed" ); +#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 to function" ); + 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/write of file 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 - Requested curve not available" ); + 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 - Signature is valid but shorter than the user-supplied length" ); +#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" ); +#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 signature is valid but its length is less than expected" ); +#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 library's validity check" ); + 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" ); +#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 - Connection requires a read call" ); + 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" ); +#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" ); +#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" ); +#endif /* MBEDTLS_AES_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_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); +#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 function" ); + if( use_ret == -(MBEDTLS_ERR_CCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CCM - Authenticated decryption failed" ); +#endif /* MBEDTLS_CCM_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 - Too many random requested in single call" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Read/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" ); +#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_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" ); +#endif /* MBEDTLS_GCM_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_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" ); +#endif /* MBEDTLS_NET_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_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" ); +#endif /* MBEDTLS_XTEA_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/deps/mbedtls/gcm.c b/deps/mbedtls/gcm.c new file mode 100644 index 0000000000..fccb092bdd --- /dev/null +++ b/deps/mbedtls/gcm.c @@ -0,0 +1,954 @@ +/* + * 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 + +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#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 */ + +/* + * 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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialize a context + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ) +{ + 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; + + 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; + + /* 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; + + 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 = ctx->len * 8; + uint64_t 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; + + 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; + + 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_zeroize( output, length ); + return( MBEDTLS_ERR_GCM_AUTH_FAILED ); + } + + return( 0 ); +} + +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_gcm_context ) ); +} + +#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[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char key[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[MAX_TESTS] = + { 12, 12, 12, 12, 8, 60 }; + +static const int iv_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 2 }; + +static const unsigned char iv[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[MAX_TESTS] = + { 0, 0, 0, 20, 20, 20 }; + +static const int add_index[MAX_TESTS] = + { 0, 0, 0, 1, 1, 1 }; + +static const unsigned char additional[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[MAX_TESTS] = + { 0, 16, 64, 60, 60, 60 }; + +static const int pt_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char pt[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[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[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; + + mbedtls_gcm_init( &ctx ); + + for( j = 0; j < 3; j++ ) + { + int key_len = 128 + 64 * j; + + for( i = 0; i < MAX_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "enc" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + pt[pt_index[i]], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "dec" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + ct[j * 6 + i], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "enc" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32, + buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "dec" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32, + buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len[i], ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + } + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_GCM_C */ diff --git a/deps/mbedtls/havege.c b/deps/mbedtls/havege.c new file mode 100644 index 0000000000..2b75ef7bd8 --- /dev/null +++ b/deps/mbedtls/havege.c @@ -0,0 +1,245 @@ +/** + * \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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* ------------------------------------------------------------------------ + * 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_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/deps/mbedtls/hmac_drbg.c b/deps/mbedtls/hmac_drbg.c new file mode 100644 index 0000000000..bf5f9b5bd3 --- /dev/null +++ b/deps/mbedtls/hmac_drbg.c @@ -0,0 +1,529 @@ +/* + * 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 + +#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 */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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) + */ +void mbedtls_hmac_drbg_update( 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]; + + for( sep[0] = 0; sep[0] < rounds; sep[0]++ ) + { + /* Step 1 or 4 */ + mbedtls_md_hmac_reset( &ctx->md_ctx ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 ); + if( rounds == 2 ) + mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, K ); + + /* Step 2 or 5 */ + mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + } +} + +/* + * 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. + */ + mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) ); + memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) ); + + mbedtls_hmac_drbg_update( ctx, data, data_len ); + + 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; + + /* 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( 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 */ + mbedtls_hmac_drbg_update( ctx, seed, seedlen ); + + /* 3. Reset reseed_counter */ + ctx->reseed_counter = 1; + + /* 4. Done */ + return( 0 ); +} + +/* + * 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. + */ + mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ); + 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 ) + mbedtls_hmac_drbg_update( ctx, additional, add_len ); + + /* 3, 4, 5. Generate bytes */ + while( left != 0 ) + { + size_t use_len = left > md_len ? md_len : left; + + mbedtls_md_hmac_reset( &ctx->md_ctx ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + + memcpy( out, ctx->V, use_len ); + out += use_len; + left -= use_len; + } + + /* 6. Update */ + mbedtls_hmac_drbg_update( ctx, additional, add_len ); + + /* 7. Update reseed counter */ + ctx->reseed_counter++; + + /* 8. Done */ + return( 0 ); +} + +/* + * 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_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 ); + return( ret ); +} + +int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + { + fclose( f ); + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_hmac_drbg_update( ctx, buf, n ); + + 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/deps/mbedtls/mbedtls/aes.h b/deps/mbedtls/mbedtls/aes.h new file mode 100644 index 0000000000..1829f72402 --- /dev/null +++ b/deps/mbedtls/mbedtls/aes.h @@ -0,0 +1,343 @@ +/** + * \file aes.h + * + * \brief AES 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_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 +#define MBEDTLS_AES_DECRYPT 0 + +#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#if !defined(MBEDTLS_AES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES context structure + * + * \note buf is able to hold 32 extra bytes, which can be used: + * - for alignment purposes if VIA padlock is used, and/or + * - to simplify key expansion in the 256-bit case by + * generating an extra round key + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t *rk; /*!< AES round keys */ + uint32_t buf[68]; /*!< unaligned data */ +} +mbedtls_aes_context; + +/** + * \brief Initialize AES context + * + * \param ctx AES context to be initialized + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ); + +/** + * \brief Clear AES context + * + * \param ctx AES context to be cleared + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ); + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \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 successful + */ +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 AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \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 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 successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + */ +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_CFB) +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a 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 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 AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \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 + */ +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 AES-CFB8 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a 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 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 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 successful + */ +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_CTR) +/** + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \param ctx AES context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +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 + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_ENCRYPT_ALT) + * + * \param ctx AES context + * \param input Plaintext block + * \param output Output (ciphertext) block + * + * \return 0 if successful + */ +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_DECRYPT_ALT) + * + * \param ctx AES context + * \param input Ciphertext block + * \param output Output (plaintext) block + * + * \return 0 if successful + */ +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_aes_encrypt_ext() in 2.5.0 + * + * \param ctx AES context + * \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_aes_decrypt_ext() in 2.5.0 + * + * \param ctx AES context + * \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 */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_AES_ALT */ +#include "aes_alt.h" +#endif /* MBEDTLS_AES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/deps/mbedtls/mbedtls/aesni.h b/deps/mbedtls/mbedtls/aesni.h new file mode 100644 index 0000000000..b1b7f1cdec --- /dev/null +++ b/deps/mbedtls/mbedtls/aesni.h @@ -0,0 +1,111 @@ +/** + * \file aesni.h + * + * \brief AES-NI for hardware AES acceleration on some Intel processors + * + * 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 + +#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 AES-NI features detection routine + * + * \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 AES-NI AES-ECB block en(de)cryption + * + * \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 GCM multiplication: c = a * b in GF(2^128) + * + * \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 Compute decryption round keys from encryption round keys + * + * \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 Perform key expansion (for encryption) + * + * \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/deps/mbedtls/mbedtls/arc4.h b/deps/mbedtls/mbedtls/arc4.h new file mode 100644 index 0000000000..5fc5395a8c --- /dev/null +++ b/deps/mbedtls/mbedtls/arc4.h @@ -0,0 +1,113 @@ +/** + * \file arc4.h + * + * \brief The ARCFOUR stream 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_ARC4_H +#define MBEDTLS_ARC4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if !defined(MBEDTLS_ARC4_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +mbedtls_arc4_context; + +/** + * \brief Initialize ARC4 context + * + * \param ctx ARC4 context to be initialized + */ +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ); + +/** + * \brief Clear ARC4 context + * + * \param ctx ARC4 context to be cleared + */ +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 + */ +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 + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_ARC4_ALT */ +#include "arc4_alt.h" +#endif /* MBEDTLS_ARC4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_arc4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* arc4.h */ diff --git a/deps/mbedtls/mbedtls/asn1.h b/deps/mbedtls/mbedtls/asn1.h new file mode 100644 index 0000000000..082832c87f --- /dev/null +++ b/deps/mbedtls/mbedtls/asn1.h @@ -0,0 +1,342 @@ +/** + * \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 DER encoded the ANS1 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 +/* \} 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/deps/mbedtls/mbedtls/asn1write.h b/deps/mbedtls/mbedtls/asn1write.h new file mode 100644 index 0000000000..73ff32b669 --- /dev/null +++ b/deps/mbedtls/mbedtls/asn1write.h @@ -0,0 +1,239 @@ +/** + * \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 + +#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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param len the length to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ); + +/** + * \brief Write a ASN.1 tag in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param tag the tag to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, + unsigned char tag ); + +/** + * \brief Write raw buffer 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 buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +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 big number (MBEDTLS_ASN1_INTEGER) in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param X the MPI to write + * + * \return the length written or a negative error code + */ +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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * + * \return the length written or a negative error code + */ +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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID to write + * \param oid_len length of the OID + * + * \return the length written or a negative error code + */ +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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID of the algorithm + * \param oid_len length of the OID + * \param par_len length of parameters, which must be already written. + * If 0, NULL parameters are added + * + * \return the length written or a negative error code + */ +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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param boolean 0 or 1 + * + * \return the length written or a negative error code + */ +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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param val the integer value + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ); + +/** + * \brief Write a printable string tag (MBEDTLS_ASN1_PRINTABLE_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write an IA5 string tag (MBEDTLS_ASN1_IA5_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf the bitstring + * \param bits the total number of bits in the bitstring + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_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: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +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 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 Size of the OID + * \param val Data to store (can be NULL if you want to fill it by hand) + * \param val_len Minimum length of the data buffer needed + * + * \return NULL if if there was a memory allocation error, or a pointer + * to the new / existing entry. + */ +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/deps/mbedtls/mbedtls/base64.h b/deps/mbedtls/mbedtls/base64.h new file mode 100644 index 0000000000..352c652db9 --- /dev/null +++ b/deps/mbedtls/mbedtls/base64.h @@ -0,0 +1,88 @@ +/** + * \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 + +#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 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_base64_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/deps/mbedtls/mbedtls/bignum.h b/deps/mbedtls/mbedtls/bignum.h new file mode 100644 index 0000000000..456a804204 --- /dev/null +++ b/deps/mbedtls/mbedtls/bignum.h @@ -0,0 +1,761 @@ +/** + * \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 results temporarily 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 +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + mbedtls_mpi_uint *p; /*!< pointer to limbs */ +} +mbedtls_mpi; + +/** + * \brief Initialize one MPI (make internal references valid) + * This just makes it ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X One MPI to initialize. + */ +void mbedtls_mpi_init( mbedtls_mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mbedtls_mpi_free( mbedtls_mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Resize down, keeping at least the specified number of limbs + * + * \param X MPI to shrink + * \param nblimbs The minimum number of limbs to keep + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); + +/** + * \brief Safe conditional assignement X = Y if assign is 1 + * + * \param X MPI to conditionally assign to + * \param Y Value to be assigned + * \param assign 1: perform the assignment, 0: keep X's original value + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \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). + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Safe conditional swap X <-> Y if swap is 1 + * + * \param X First mbedtls_mpi value + * \param Y Second mbedtls_mpi value + * \param assign 1: perform the swap, 0: keep X and Y's original values + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \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). + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ); + +/** + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of zero-bits before the least significant + * '1' bit + * + * Note: Thus also the zero-based index of the least significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant '1' bit' + * + * Note: Thus also the one-based index of the most significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param buf Buffer to write the string to + * \param buflen Length of buf + * \param olen Length of the string written, including final NUL byte + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with buflen = 0 to obtain the + * minimum required buffer size in *olen. + */ +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 MPI from a line in an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * MBEDTLS_ERR_MPI_XXX error code + * + * \note On success, this function advances the file stream + * to the end of the current line or to EOF. + * + * The function returns 0 on an empty line. + * + * Leading whitespaces are ignored, as is a + * '0x' prefix for radix 16. + * + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_read_binary( 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 Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Unsigned subtraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed subtraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Signed subtraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The unsigned integer value to multiply with + * + * \note b is unsigned + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ); + +/** + * \brief Division by mbedtls_mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination mbedtls_mpi_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or + * if E is negative + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +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 X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is <= 1, + MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N. + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits + * ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/deps/mbedtls/mbedtls/blowfish.h b/deps/mbedtls/mbedtls/blowfish.h new file mode 100644 index 0000000000..34626eef48 --- /dev/null +++ b/deps/mbedtls/mbedtls/blowfish.h @@ -0,0 +1,203 @@ +/** + * \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 + +#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 */ + +#define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH -0x0016 /**< Invalid key length. */ +#define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_BLOWFISH_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Blowfish context structure + */ +typedef struct +{ + uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2]; /*!< Blowfish round keys */ + uint32_t S[4][256]; /*!< key dependent S-boxes */ +} +mbedtls_blowfish_context; + +/** + * \brief Initialize Blowfish context + * + * \param ctx Blowfish context to be initialized + */ +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ); + +/** + * \brief Clear Blowfish context + * + * \param ctx Blowfish context to be cleared + */ +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ); + +/** + * \brief Blowfish key schedule + * + * \param ctx Blowfish context to be initialized + * \param key encryption key + * \param keybits must be between 32 and 448 bits + * + * \return 0 if successful, or MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Blowfish-ECB block encryption/decryption + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +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 Blowfish-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (8 bytes) + * + * \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 Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_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_BLOWFISH_INVALID_INPUT_LENGTH + */ +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 Blowfish CFB 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 Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \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 + */ +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 Blowfish-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * \param ctx Blowfish context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 64-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +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 + +#else /* MBEDTLS_BLOWFISH_ALT */ +#include "blowfish_alt.h" +#endif /* MBEDTLS_BLOWFISH_ALT */ + +#endif /* blowfish.h */ diff --git a/deps/mbedtls/mbedtls/bn_mul.h b/deps/mbedtls/mbedtls/bn_mul.h new file mode 100644 index 0000000000..cac3f14577 --- /dev/null +++ b/deps/mbedtls/mbedtls/bn_mul.h @@ -0,0 +1,885 @@ +/** + * \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 + +#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 ) +#if defined(__i386__) + +#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", "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", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( \ + "xorq %%r8, %%r8 \n\t" + +#define MULADDC_CORE \ + "movq (%%rsi), %%rax \n\t" \ + "mulq %%rbx \n\t" \ + "addq $8, %%rsi \n\t" \ + "addq %%rcx, %%rax \n\t" \ + "movq %%r8, %%rcx \n\t" \ + "adcq $0, %%rdx \n\t" \ + "nop \n\t" \ + "addq %%rax, (%%rdi) \n\t" \ + "adcq %%rdx, %%rcx \n\t" \ + "addq $8, %%rdi \n\t" + +#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 */ + +/* + * 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. Unfortunately, + * passing that option is not easy when building with yotta. + * + * 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" \ + ); + +#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" \ + ); + +#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/deps/mbedtls/mbedtls/camellia.h b/deps/mbedtls/mbedtls/camellia.h new file mode 100644 index 0000000000..0424d623fb --- /dev/null +++ b/deps/mbedtls/mbedtls/camellia.h @@ -0,0 +1,235 @@ +/** + * \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 + +#define MBEDTLS_CAMELLIA_ENCRYPT 1 +#define MBEDTLS_CAMELLIA_DECRYPT 0 + +#define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH -0x0024 /**< Invalid key length. */ +#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_CAMELLIA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CAMELLIA context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t rk[68]; /*!< CAMELLIA round keys */ +} +mbedtls_camellia_context; + +/** + * \brief Initialize CAMELLIA context + * + * \param ctx CAMELLIA context to be initialized + */ +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ); + +/** + * \brief Clear CAMELLIA context + * + * \param ctx CAMELLIA context to be cleared + */ +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ); + +/** + * \brief CAMELLIA key schedule (encryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA key schedule (decryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA-ECB block encryption/decryption + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +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 CAMELLIA-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \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 CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_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_CAMELLIA_INVALID_INPUT_LENGTH + */ +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 CAMELLIA-CFB128 buffer encryption/decryption + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and CAMELLIE_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 CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \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_CAMELLIA_INVALID_INPUT_LENGTH + */ +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 CAMELLIA-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and MBEDTLS_CAMELLIA_DECRYPT. + * + * \param ctx CAMELLIA context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +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 */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_CAMELLIA_ALT */ +#include "camellia_alt.h" +#endif /* MBEDTLS_CAMELLIA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_camellia_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* camellia.h */ diff --git a/deps/mbedtls/mbedtls/ccm.h b/deps/mbedtls/mbedtls/ccm.h new file mode 100644 index 0000000000..ef75839baa --- /dev/null +++ b/deps/mbedtls/mbedtls/ccm.h @@ -0,0 +1,141 @@ +/** + * \file ccm.h + * + * \brief Counter with CBC-MAC (CCM) for 128-bit block ciphers + * + * 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_CCM_H +#define MBEDTLS_CCM_H + +#include "cipher.h" + +#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CCM context structure + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx; /*!< cipher context used */ +} +mbedtls_ccm_context; + +/** + * \brief Initialize CCM context (just makes references valid) + * Makes the context ready for mbedtls_ccm_setkey() or + * mbedtls_ccm_free(). + * + * \param ctx CCM context to initialize + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ); + +/** + * \brief CCM initialization (encryption and decryption) + * + * \param ctx CCM context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits key size in bits (must be acceptable by the cipher) + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Free a CCM context and underlying cipher sub-context + * + * \param ctx CCM context to free + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ); + +/** + * \brief CCM buffer encryption + * + * \param ctx CCM context + * \param length length of the input data in bytes + * \param iv nonce (initialization vector) + * \param iv_len length of IV in bytes + * must be 2, 3, 4, 5, 6, 7 or 8 + * \param add additional data + * \param add_len length of additional data in bytes + * must be less than 2^16 - 2^8 + * \param input buffer holding the input data + * \param output buffer for holding the output data + * must be at least 'length' bytes wide + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate in bytes + * must be 4, 6, 8, 10, 14 or 16 + * + * \note The tag is written to a separate buffer. To get the tag + * concatenated with the output as in the CCM spec, use + * tag = output + length and make sure the output buffer is + * at least length + tag_len wide. + * + * \return 0 if successful + */ +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 CCM buffer authenticated decryption + * + * \param ctx CCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match + */ +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 ); + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ccm_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CCM_H */ diff --git a/deps/mbedtls/mbedtls/certs.h b/deps/mbedtls/mbedtls/certs.h new file mode 100644 index 0000000000..ca49086e4f --- /dev/null +++ b/deps/mbedtls/mbedtls/certs.h @@ -0,0 +1,99 @@ +/** + * \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 + +#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/deps/mbedtls/mbedtls/check_config.h b/deps/mbedtls/mbedtls/check_config.h new file mode 100644 index 0000000000..fa72454e53 --- /dev/null +++ b/deps/mbedtls/mbedtls/check_config.h @@ -0,0 +1,669 @@ +/** + * \file check_config.h + * + * \brief Consistency checks for configuration options + * + * 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) + */ + +/* + * 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 +#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_CMAC_C) && \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C) +#error "MBEDTLS_CMAC_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_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_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_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_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_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_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_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 emtpy translation units. + */ +typedef int mbedtls_iso_c_forbids_empty_translation_units; + +#endif /* MBEDTLS_CHECK_CONFIG_H */ diff --git a/deps/mbedtls/mbedtls/cipher.h b/deps/mbedtls/mbedtls/cipher.h new file mode 100644 index 0000000000..b12e38843a --- /dev/null +++ b/deps/mbedtls/mbedtls/cipher.h @@ -0,0 +1,709 @@ +/** + * \file cipher.h + * + * \brief Generic cipher wrapper. + * + * \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_H +#define MBEDTLS_CIPHER_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_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) +#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 to function. */ +#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, eg because it was free()ed. */ + +#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 + +typedef enum { + MBEDTLS_CIPHER_ID_NONE = 0, + MBEDTLS_CIPHER_ID_NULL, + MBEDTLS_CIPHER_ID_AES, + MBEDTLS_CIPHER_ID_DES, + MBEDTLS_CIPHER_ID_3DES, + MBEDTLS_CIPHER_ID_CAMELLIA, + MBEDTLS_CIPHER_ID_BLOWFISH, + MBEDTLS_CIPHER_ID_ARC4, +} mbedtls_cipher_id_t; + +typedef enum { + MBEDTLS_CIPHER_NONE = 0, + MBEDTLS_CIPHER_NULL, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_CIPHER_AES_128_CBC, + MBEDTLS_CIPHER_AES_192_CBC, + MBEDTLS_CIPHER_AES_256_CBC, + MBEDTLS_CIPHER_AES_128_CFB128, + MBEDTLS_CIPHER_AES_192_CFB128, + MBEDTLS_CIPHER_AES_256_CFB128, + MBEDTLS_CIPHER_AES_128_CTR, + MBEDTLS_CIPHER_AES_192_CTR, + MBEDTLS_CIPHER_AES_256_CTR, + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_CIPHER_DES_ECB, + MBEDTLS_CIPHER_DES_CBC, + MBEDTLS_CIPHER_DES_EDE_ECB, + MBEDTLS_CIPHER_DES_EDE_CBC, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_CIPHER_DES_EDE3_CBC, + MBEDTLS_CIPHER_BLOWFISH_ECB, + MBEDTLS_CIPHER_BLOWFISH_CBC, + MBEDTLS_CIPHER_BLOWFISH_CFB64, + MBEDTLS_CIPHER_BLOWFISH_CTR, + MBEDTLS_CIPHER_ARC4_128, + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_CIPHER_CAMELLIA_256_CCM, +} mbedtls_cipher_type_t; + +typedef enum { + MBEDTLS_MODE_NONE = 0, + MBEDTLS_MODE_ECB, + MBEDTLS_MODE_CBC, + MBEDTLS_MODE_CFB, + MBEDTLS_MODE_OFB, /* Unused! */ + MBEDTLS_MODE_CTR, + MBEDTLS_MODE_GCM, + MBEDTLS_MODE_STREAM, + MBEDTLS_MODE_CCM, +} mbedtls_cipher_mode_t; + +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; + +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 cipher functions to be called in a generic way. + */ +typedef struct { + /** Full cipher identifier (e.g. MBEDTLS_CIPHER_AES_256_CBC) */ + mbedtls_cipher_type_t type; + + /** Cipher mode (e.g. MBEDTLS_MODE_CBC) */ + mbedtls_cipher_mode_t mode; + + /** Cipher key length, in bits (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/NONCE size, in bytes. + * For cipher that accept many sizes: recommended size */ + unsigned int iv_size; + + /** Flags for variable IV size, variable key size, etc. */ + int flags; + + /** block size, in bytes */ + unsigned int block_size; + + /** Base cipher information and functions */ + const mbedtls_cipher_base_t *base; + +} mbedtls_cipher_info_t; + +/** + * Generic cipher context. + */ +typedef struct { + /** Information about the associated cipher */ + const mbedtls_cipher_info_t *cipher_info; + + /** Key length to use */ + int key_bitlen; + + /** Operation that the context's key has been initialised for */ + mbedtls_operation_t operation; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /** Padding functions to use, if relevant for 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 data that hasn't been encrypted yet */ + unsigned char unprocessed_data[MBEDTLS_MAX_BLOCK_LENGTH]; + + /** Number of bytes that still need processing */ + size_t unprocessed_len; + + /** Current IV or NONCE_COUNTER for CTR-mode */ + unsigned char iv[MBEDTLS_MAX_IV_LENGTH]; + + /** IV size in bytes (for ciphers with variable-length IVs) */ + size_t iv_size; + + /** Cipher-specific context */ + void *cipher_ctx; + +#if defined(MBEDTLS_CMAC_C) + /** CMAC Specific context */ + mbedtls_cmac_context_t *cmac_ctx; +#endif +} mbedtls_cipher_context_t; + +/** + * \brief Returns the list of ciphers supported by the generic cipher module. + * + * \return a statically allocated array of ciphers, the last entry + * is 0. + */ +const int *mbedtls_cipher_list( void ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_name, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ); + +/** + * \brief Returns 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 cipher_type, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher id, key size and mode. + * + * \param cipher_id Id of the cipher to search for + * (e.g. MBEDTLS_CIPHER_ID_AES) + * \param key_bitlen Length of the key in bits + * \param mode Cipher mode (e.g. MBEDTLS_MODE_CBC) + * + * \return the cipher information structure associated with the + * given cipher_type, or NULL if 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 Initialize a cipher_context (as NONE) + */ +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Free and clear the cipher-specific context of ctx. + * Freeing ctx itself remains the responsibility of the + * caller. + */ +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Initialises and fills the cipher context structure with + * the appropriate values. + * + * \note Currently also clears structure. In future versions you + * will be required to call mbedtls_cipher_init() on the structure + * first. + * + * \param ctx context to initialise. May not be NULL. + * \param cipher_info cipher to use. + * + * \return 0 on success, + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter failure, + * MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context failed. + */ +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ); + +/** + * \brief Returns the block size of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return size of the cipher's blocks, or 0 if ctx has not been + * initialised. + */ +static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->block_size; +} + +/** + * \brief Returns the mode of operation for the cipher. + * (e.g. MBEDTLS_MODE_CBC) + * + * \param ctx cipher's context. Must have been initialised. + * + * \return mode of operation, or MBEDTLS_MODE_NONE if ctx + * has not been initialised. + */ +static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_MODE_NONE; + + return ctx->cipher_info->mode; +} + +/** + * \brief Returns the size of the cipher's IV/NONCE in bytes. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return If IV has not been set yet: (recommended) IV size + * (0 for ciphers not using IV/NONCE). + * If IV has already been set: actual size. + */ +static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + if( ctx->iv_size != 0 ) + return (int) ctx->iv_size; + + return (int) ctx->cipher_info->iv_size; +} + +/** + * \brief Returns the type of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return type of the cipher, or MBEDTLS_CIPHER_NONE if ctx has + * not been initialised. + */ +static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_CIPHER_NONE; + + return ctx->cipher_info->type; +} + +/** + * \brief Returns the name of the given cipher, as a string. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return name of the cipher, or NULL if ctx was not initialised. + */ +static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->name; +} + +/** + * \brief Returns the key length of the cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return cipher's key length, in bits, or + * MBEDTLS_KEY_LENGTH_NONE if ctx has not been + * initialised. + */ +static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_KEY_LENGTH_NONE; + + return (int) ctx->cipher_info->key_bitlen; +} + +/** + * \brief Returns the operation of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return operation (MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT), + * or MBEDTLS_OPERATION_NONE if ctx has not been + * initialised. + */ +static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_OPERATION_NONE; + + return ctx->operation; +} + +/** + * \brief Set the key to use with the given context. + * + * \param ctx generic cipher context. May not be NULL. Must have been + * initialised using cipher_context_from_type or + * cipher_context_from_string. + * \param key The key to use. + * \param key_bitlen key length to use, in bits. + * \param operation Operation that the key will be used for, either + * MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails or a cipher specific + * error code. + */ +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 Set padding mode, for cipher modes that use padding. + * (Default: PKCS7 padding.) + * + * \param ctx generic cipher context + * \param mode padding mode + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE + * if selected padding mode is not supported, or + * 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 Set the initialization vector (IV) or nonce + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * + * \returns 0 on success, or MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA + * + * \note Some ciphers don't use IVs nor NONCE. For these + * ciphers, this function has no effect. + */ +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ); + +/** + * \brief Finish preparation of the given context + * + * \param ctx generic cipher context + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ); + +#if defined(MBEDTLS_GCM_C) +/** + * \brief Add additional data (for AEAD ciphers). + * Currently only supported with GCM. + * Must be called exactly once, after mbedtls_cipher_reset(). + * + * \param ctx generic cipher context + * \param ad Additional data to use. + * \param ad_len Length of ad. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ); +#endif /* MBEDTLS_GCM_C */ + +/** + * \brief Generic cipher update function. Encrypts/decrypts + * using the given cipher context. Writes as many block + * size'd blocks of data as possible to output. Any data + * that cannot be written immediately will either be added + * to the next block, or flushed when cipher_final is + * called. + * Exception: for MBEDTLS_MODE_ECB, expects single block + * in size (e.g. 16 bytes for AES) + * + * \param ctx generic cipher context + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher or a cipher specific + * error code. + * + * \note If the underlying cipher is GCM, all calls to this + * function, except the last one before mbedtls_cipher_finish(), + * must have ilen a multiple of the block size. + */ +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ); + +/** + * \brief Generic cipher finalisation function. If data still + * needs to be flushed from an incomplete block, data + * contained within it will be padded with the size of + * the last block, and written to the output buffer. + * + * \param ctx Generic cipher context + * \param output buffer to write data to. Needs block_size available. + * \param olen length of the data written to the output buffer. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, + * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting or a cipher specific error code. + */ +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_GCM_C) +/** + * \brief Write tag for AEAD ciphers. + * Currently only supported with GCM. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx Generic cipher context + * \param tag buffer to write the tag + * \param tag_len Length of the tag to write + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ); + +/** + * \brief Check tag for AEAD ciphers. + * Currently only supported with GCM. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx Generic cipher context + * \param tag Buffer holding the tag + * \param tag_len Length of the tag to check + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_GCM_C */ + +/** + * \brief Generic all-in-one encryption/decryption + * (for all ciphers except AEAD constructs). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \note Some ciphers don't use IVs nor NONCE. For these + * ciphers, use iv = NULL and iv_len = 0. + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, or + * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting, or + * a cipher specific error code. + */ +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 Generic autenticated encryption (AEAD ciphers). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param ad Additional data to authenticate. + * \param ad_len Length of ad. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. + * Should be able to hold at least ilen. + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * \param tag buffer for the authentication tag + * \param tag_len desired tag length + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * a cipher specific error code. + */ +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 Generic autenticated decryption (AEAD ciphers). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param ad Additional data to be authenticated. + * \param ad_len Length of ad. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. + * Should be able to hold at least ilen. + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * \param tag buffer holding the authentication tag + * \param tag_len length of the authentication tag + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * MBEDTLS_ERR_CIPHER_AUTH_FAILED if data isn't authentic, + * or a cipher specific error code. + * + * \note If the data is not authentic, then the output buffer + * is zeroed out to prevent the unauthentic plaintext to + * be used by mistake, making this interface safer. + */ +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/deps/mbedtls/mbedtls/cipher_internal.h b/deps/mbedtls/mbedtls/cipher_internal.h new file mode 100644 index 0000000000..6c58bcc525 --- /dev/null +++ b/deps/mbedtls/mbedtls/cipher_internal.h @@ -0,0 +1,109 @@ +/** + * \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" + +#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_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_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; + +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/deps/mbedtls/mbedtls/cmac.h b/deps/mbedtls/mbedtls/cmac.h new file mode 100644 index 0000000000..9a2b96bc92 --- /dev/null +++ b/deps/mbedtls/mbedtls/cmac.h @@ -0,0 +1,170 @@ +/** + * \file cmac.h + * + * \brief Cipher-based Message Authentication Code (CMAC) Mode for + * Authentication + * + * Copyright (C) 2015-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_CMAC_H +#define MBEDTLS_CMAC_H + +#include "mbedtls/cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MBEDTLS_AES_BLOCK_SIZE 16 +#define MBEDTLS_DES3_BLOCK_SIZE 8 + +#if defined(MBEDTLS_AES_C) +#define MBEDTLS_CIPHER_BLKSIZE_MAX 16 /* longest used by CMAC is AES */ +#else +#define MBEDTLS_CIPHER_BLKSIZE_MAX 8 /* longest used by CMAC is 3DES */ +#endif + +/** + * CMAC context structure - Contains internal state information only + */ +struct mbedtls_cmac_context_t +{ + /** 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 to be processed, or the final block */ + unsigned char unprocessed_block[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + /** Length of data pending to be processed */ + size_t unprocessed_len; +}; + +/** + * \brief Set the CMAC key and prepare to authenticate the input + * data. + * Should be called with an initialized cipher context. + * + * \param ctx Cipher context. This should be a cipher context, + * initialized to be 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 CMAC key + * \param keybits length of the CMAC key in bits + * (must be acceptable by the cipher) + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits ); + +/** + * \brief Generic CMAC process buffer. + * Called between mbedtls_cipher_cmac_starts() or + * mbedtls_cipher_cmac_reset() and + * mbedtls_cipher_cmac_finish(). + * May be called repeatedly. + * + * \param ctx CMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, 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 Output CMAC. + * Called after mbedtls_cipher_cmac_update(). + * Usually followed by mbedtls_cipher_cmac_reset(), then + * mbedtls_cipher_cmac_starts(), or mbedtls_cipher_free(). + * + * \param ctx CMAC context + * \param output Generic CMAC checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output ); + +/** + * \brief Prepare to authenticate a new message with the same key. + * Called after mbedtls_cipher_cmac_finish() and before + * mbedtls_cipher_cmac_update(). + * + * \param ctx CMAC context to be reset + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Output = Generic_CMAC( cmac key, input buffer ) + * + * \param cipher_info message digest info + * \param key CMAC key + * \param keylen length of the CMAC key in bits + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic CMAC-result + * + * \returns 0 on success, 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 AES-CMAC-128-PRF + * Implementation of (AES-CMAC-PRF-128), as defined in RFC 4615 + * + * \param key PRF key + * \param key_len PRF key length in bytes + * \param input buffer holding the input data + * \param in_len length of the input data in bytes + * \param output buffer holding the generated pseudorandom output (16 bytes) + * + * \return 0 if successful + */ +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 Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +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/deps/mbedtls/mbedtls/compat-1.3.h b/deps/mbedtls/mbedtls/compat-1.3.h new file mode 100644 index 0000000000..bba1d2c247 --- /dev/null +++ b/deps/mbedtls/mbedtls/compat-1.3.h @@ -0,0 +1,2523 @@ +/** + * \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_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_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/deps/mbedtls/mbedtls/config.h b/deps/mbedtls/mbedtls/config.h new file mode 100644 index 0000000000..47c7196402 --- /dev/null +++ b/deps/mbedtls/mbedtls/config.h @@ -0,0 +1,2719 @@ +/** + * \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-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_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/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * 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_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 and time(), gmtime() and the clock is correct. + * The time needs to be correct (not necesarily 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. + */ +#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_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 + +/* \} 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. + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_XTEA_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_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 overriden, 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. + */ +//#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 + +/** + * \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_deinit( 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_deinit 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 + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +//#define MBEDTLS_AES_ROM_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_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 + */ +//#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_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 + +/** + * \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_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 + */ +#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 + */ +#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_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_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_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 + * + * Disable 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. + */ +#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 (maintainance 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_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_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_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 a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * 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/ssl_tls.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/ssl_tls.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 + */ +#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/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/ssl_tls.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_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_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-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 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/ssl_tls.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. + */ +#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 + */ +#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_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_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. + */ +//#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. + */ +//#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 and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#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_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 + * 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. + */ +#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 */ + +/* 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 correclty 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 correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf 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 */ + +/* 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 */ +//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +//#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 generte SHA-1 collisions, however + * this may be safe for legacy infrastructure where additional controls apply. + */ +// #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 + * for compatibility with existing peers. + */ +#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE + +/* \} name SECTION: Customisation configuration options */ + +/* Target and application specific configurations */ +//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "mbedtls/target_config.h" + +#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE +#endif + +/* + * Allow user to override any previous default. + * + * Use two macro names for that, as: + * - with yotta the prefix YOTTA_CFG_ is forced + * - without yotta is looks weird to have a YOTTA prefix. + */ +#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE +#elif defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/deps/mbedtls/mbedtls/ctr_drbg.h b/deps/mbedtls/mbedtls/ctr_drbg.h new file mode 100644 index 0000000000..059d3c5c9a --- /dev/null +++ b/deps/mbedtls/mbedtls/ctr_drbg.h @@ -0,0 +1,290 @@ +/** + * \file ctr_drbg.h + * + * \brief CTR_DRBG 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) + */ +#ifndef MBEDTLS_CTR_DRBG_H +#define MBEDTLS_CTR_DRBG_H + +#include "aes.h" + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/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 /**< Too many random requested in single call. */ +#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */ +#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */ + +#define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< Block size used by the cipher */ +#define MBEDTLS_CTR_DRBG_KEYSIZE 32 /**< Key size used by the cipher */ +#define MBEDTLS_CTR_DRBG_KEYBITS ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) +#define MBEDTLS_CTR_DRBG_SEEDLEN ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) + /**< The seed length (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 on 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 /**< 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 /**< Interval before reseed is performed by default */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_REQUEST) +#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_CTR_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define MBEDTLS_CTR_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CTR_DRBG context structure + */ +typedef struct +{ + unsigned char counter[16]; /*!< counter (V) */ + int reseed_counter; /*!< reseed counter */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + size_t entropy_len; /*!< amount of entropy grabbed on each + (re)seed */ + int reseed_interval; /*!< reseed interval */ + + mbedtls_aes_context aes_ctx; /*!< AES context */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + + void *p_entropy; /*!< context for the entropy function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ctr_drbg_context; + +/** + * \brief CTR_DRBG context initialization + * Makes the context ready for mbedtls_ctr_drbg_seed() or + * mbedtls_ctr_drbg_free(). + * + * \param ctx CTR_DRBG context to be initialized + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief CTR_DRBG initial seeding + * Seed and setup 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 CTR_DRBG context to be seeded + * \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 + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +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 Clear CTR_CRBG context data + * + * \param ctx CTR_DRBG context to clear + */ +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ); + +/** + * \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 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 Set the amount of entropy grabbed on each (re)seed + * (Default: MBEDTLS_CTR_DRBG_ENTROPY_LEN) + * + * \param ctx CTR_DRBG context + * \param len Amount of entropy to grab + */ +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: MBEDTLS_CTR_DRBG_RESEED_INTERVAL) + * + * \param ctx CTR_DRBG context + * \param interval Reseed interval + */ +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, + int interval ); + +/** + * \brief CTR_DRBG reseeding (extracts data from entropy source) + * + * \param ctx CTR_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_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief CTR_DRBG update state + * + * \param ctx CTR_DRBG context + * \param additional Additional data to update state with + * \param add_len Length of additional data + * + * \note If 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 ones are silently discarded. + */ +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_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 + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +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 CTR_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx CTR_DRBG context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param ctx CTR_DRBG context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG + */ +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ctr_drbg_self_test( int verbose ); + +/* 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/deps/mbedtls/mbedtls/debug.h b/deps/mbedtls/mbedtls/debug.h new file mode 100644 index 0000000000..2957996407 --- /dev/null +++ b/deps/mbedtls/mbedtls/debug.h @@ -0,0 +1,228 @@ +/** + * \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 + +#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 ) + +#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 + +#ifdef __cplusplus +} +#endif + +#endif /* debug.h */ + diff --git a/deps/mbedtls/mbedtls/des.h b/deps/mbedtls/mbedtls/des.h new file mode 100644 index 0000000000..5ca2ecf2e0 --- /dev/null +++ b/deps/mbedtls/mbedtls/des.h @@ -0,0 +1,306 @@ +/** + * \file des.h + * + * \brief DES 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_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. */ + +#define MBEDTLS_DES_KEY_SIZE 8 + +#if !defined(MBEDTLS_DES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES context structure + */ +typedef struct +{ + uint32_t sk[32]; /*!< DES subkeys */ +} +mbedtls_des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +mbedtls_des3_context; + +/** + * \brief Initialize DES context + * + * \param ctx DES context to be initialized + */ +void mbedtls_des_init( mbedtls_des_context *ctx ); + +/** + * \brief Clear DES context + * + * \param ctx DES context to be cleared + */ +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 + */ +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. + */ +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. + */ +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 + */ +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 + */ +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 + */ +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 + */ +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 + */ +void mbedtls_des_setkey( uint32_t SK[32], + const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_DES_ALT */ +#include "des_alt.h" +#endif /* MBEDTLS_DES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/deps/mbedtls/mbedtls/dhm.h b/deps/mbedtls/mbedtls/dhm.h new file mode 100644 index 0000000000..d7ab1522ec --- /dev/null +++ b/deps/mbedtls/mbedtls/dhm.h @@ -0,0 +1,305 @@ +/** + * \file dhm.h + * + * \brief 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) + */ +#ifndef MBEDTLS_DHM_H +#define MBEDTLS_DHM_H + +#include "bignum.h" + +/* + * DHM Error codes + */ +#define MBEDTLS_ERR_DHM_BAD_INPUT_DATA -0x3080 /**< Bad input parameters to function. */ +#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/write of file failed. */ + +/** + * RFC 3526 defines a number of standardized Diffie-Hellman groups + * for IKE. + * RFC 5114 defines a number of standardized Diffie-Hellman groups + * that can be used. + * + * Some are included here for convenience. + * + * Included are: + * RFC 3526 3. 2048-bit MODP Group + * RFC 3526 4. 3072-bit MODP Group + * RFC 3526 5. 4096-bit MODP Group + * RFC 5114 2.2. 2048-bit MODP Group with 224-bit Prime Order Subgroup + */ +#define MBEDTLS_DHM_RFC3526_MODP_2048_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_2048_G "02" + +#define MBEDTLS_DHM_RFC3526_MODP_3072_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_3072_G "02" + +#define MBEDTLS_DHM_RFC3526_MODP_4096_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \ + "FFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_4096_G "02" + +#define MBEDTLS_DHM_RFC5114_MODP_2048_P \ + "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1" \ + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" \ + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212" \ + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" \ + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708" \ + "B3BF8A317091883681286130BC8985DB1602E714415D9330" \ + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D" \ + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" \ + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763" \ + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" \ + "CF9DE5384E71B81C0AC4DFFE0C10E64F" + +#define MBEDTLS_DHM_RFC5114_MODP_2048_G \ + "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"\ + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA"\ + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"\ + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A"\ + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"\ + "F180EB34118E98D119529A45D6F834566E3025E316A330EF"\ + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"\ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381"\ + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"\ + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179"\ + "81BC087F2A7065B384B890D3191F2BFA" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DHM context structure + */ +typedef struct +{ + size_t len; /*!< size(P) in chars */ + mbedtls_mpi P; /*!< prime modulus */ + mbedtls_mpi G; /*!< generator */ + mbedtls_mpi X; /*!< secret value */ + mbedtls_mpi GX; /*!< self = G^X mod P */ + mbedtls_mpi GY; /*!< peer = G^Y mod P */ + mbedtls_mpi K; /*!< key = GY^X mod P */ + mbedtls_mpi RP; /*!< cached R^2 mod P */ + mbedtls_mpi Vi; /*!< blinding value */ + mbedtls_mpi Vf; /*!< un-blinding value */ + mbedtls_mpi pX; /*!< previous X */ +} +mbedtls_dhm_context; + +/** + * \brief Initialize DHM context + * + * \param ctx DHM context to be initialized + */ +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ); + +/** + * \brief Parse the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param p &(start of input buffer) + * \param end end of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief Setup and write the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen number of chars written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->P and ctx->G + * have already been properly set (for example + * using mbedtls_mpi_read_string or mbedtls_mpi_read_binary). + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +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 Import the peer's public value G^Y + * + * \param ctx DHM context + * \param input input buffer + * \param ilen size of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief Create own private value X and export G^X + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen must be at least equal to the size of P, ctx->len + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +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 Derive and export the shared secret (G^Y)^X mod P + * + * \param ctx DHM context + * \param output destination buffer + * \param output_size size of the destination buffer + * \param olen on exit, holds the actual number of bytes written + * \param f_rng RNG function, for blinding purposes + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + * + * \note If non-NULL, f_rng is used to blind the input as + * countermeasure against timing attacks. Blinding is + * automatically used if and only if our secret value X is + * re-used and costs nothing otherwise, so it is recommended + * to always pass a non-NULL f_rng argument. + */ +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 Free and clear the components of a DHM key + * + * \param ctx DHM context to free and clear + */ +void mbedtls_dhm_free( mbedtls_dhm_context *ctx ); + +#if defined(MBEDTLS_ASN1_PARSE_C) +/** \ingroup x509_module */ +/** + * \brief Parse DHM parameters in PEM or DER format + * + * \param dhm DHM context to be initialized + * \param dhmin input buffer + * \param dhminlen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific DHM or PEM error code + */ +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 Load and parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param path filename to read the DHM Parameters from + * + * \return 0 if successful, or a specific DHM or PEM error code + */ +int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_dhm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* dhm.h */ diff --git a/deps/mbedtls/mbedtls/ecdh.h b/deps/mbedtls/mbedtls/ecdh.h new file mode 100644 index 0000000000..625a281923 --- /dev/null +++ b/deps/mbedtls/mbedtls/ecdh.h @@ -0,0 +1,214 @@ +/** + * \file ecdh.h + * + * \brief 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) + */ +#ifndef MBEDTLS_ECDH_H +#define MBEDTLS_ECDH_H + +#include "ecp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * When importing from an EC key, select if it is our key or the peer's key + */ +typedef enum +{ + MBEDTLS_ECDH_OURS, + MBEDTLS_ECDH_THEIRS, +} mbedtls_ecdh_side; + +/** + * \brief ECDH context structure + */ +typedef struct +{ + mbedtls_ecp_group grp; /*!< elliptic curve used */ + mbedtls_mpi d; /*!< our secret value (private key) */ + mbedtls_ecp_point Q; /*!< our public value (public key) */ + mbedtls_ecp_point Qp; /*!< peer's public value (public key) */ + mbedtls_mpi z; /*!< shared secret */ + int point_format; /*!< format for point export in TLS messages */ + mbedtls_ecp_point Vi; /*!< blinding value (for later) */ + mbedtls_ecp_point Vf; /*!< un-blinding value (for later) */ + mbedtls_mpi _d; /*!< previous d (for later) */ +} +mbedtls_ecdh_context; + +/** + * \brief Generate a public key. + * Raw function that only does the core computation. + * + * \param grp ECP group + * \param d Destination MPI (secret exponent, aka private key) + * \param Q Destination point (public key) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +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 Compute shared secret + * Raw function that only does the core computation. + * + * \param grp ECP group + * \param z Destination MPI (shared secret) + * \param Q Public key from other party + * \param d Our secret exponent (private key) + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note If f_rng is not NULL, it is used to implement + * countermeasures against potential elaborate timing + * attacks, see \c mbedtls_ecp_mul() for details. + */ +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 Initialize context + * + * \param ctx Context to initialize + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ); + +/** + * \brief Free context + * + * \param ctx Context to free + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ); + +/** + * \brief Generate a public key and a TLS ServerKeyExchange payload. + * (First function used by a TLS server for ECDHE.) + * + * \param ctx ECDH context + * \param olen number of chars written + * \param buf destination buffer + * \param blen length of buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->grp has already been + * properly set (for example using mbedtls_ecp_group_load). + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +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 Parse and procress a TLS ServerKeyExhange payload. + * (First function used by a TLS client for ECDHE.) + * + * \param ctx ECDH context + * \param buf pointer to start of input buffer + * \param end one past end of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, const unsigned char *end ); + +/** + * \brief Setup an ECDH context from an EC key. + * (Used by clients and servers in place of the + * ServerKeyEchange for static ECDH: import ECDH parameters + * from a certificate's EC key information.) + * + * \param ctx ECDH constext to set + * \param key EC key to use + * \param side Is it our key (1) or the peer's key (0) ? + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ); + +/** + * \brief Generate a public key and a TLS ClientKeyExchange payload. + * (Second function used by a TLS client for ECDH(E).) + * + * \param ctx ECDH context + * \param olen number of bytes actually written + * \param buf destination buffer + * \param blen size of destination buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +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 Parse and process a TLS ClientKeyExchange payload. + * (Second function used by a TLS server for ECDH(E).) + * + * \param ctx ECDH context + * \param buf start of input buffer + * \param blen length of input buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ); + +/** + * \brief Derive and export the shared secret. + * (Last function used by both TLS client en servers.) + * + * \param ctx ECDH context + * \param olen number of bytes written + * \param buf destination buffer + * \param blen buffer length + * \param f_rng RNG function, see notes for \c mbedtls_ecdh_compute_shared() + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +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 ); + +#ifdef __cplusplus +} +#endif + +#endif /* ecdh.h */ diff --git a/deps/mbedtls/mbedtls/ecdsa.h b/deps/mbedtls/mbedtls/ecdsa.h new file mode 100644 index 0000000000..a277715b3d --- /dev/null +++ b/deps/mbedtls/mbedtls/ecdsa.h @@ -0,0 +1,272 @@ +/** + * \file ecdsa.h + * + * \brief 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) + */ +#ifndef MBEDTLS_ECDSA_H +#define MBEDTLS_ECDSA_H + +#include "ecp.h" +#include "md.h" + +/* + * RFC 4492 page 20: + * + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * Size is at most + * 1 (tag) + 1 (len) + 1 (initial 0) + ECP_MAX_BYTES for each of r and s, + * twice that + 1 (tag) + 2 (len) for the sequence + * (assuming ECP_MAX_BYTES is less than 126 for r and s, + * and less than 124 (total len <= 255) for the sequence) + */ +#if MBEDTLS_ECP_MAX_BYTES > 124 +#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" +#endif +/** Maximum size of an ECDSA signature in bytes */ +#define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) ) + +/** + * \brief ECDSA context structure + */ +typedef mbedtls_ecp_keypair mbedtls_ecdsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Compute ECDSA signature of a previously hashed message + * + * \note The deterministic version is usually prefered. + * + * \param grp ECP group + * \param r First output integer + * \param s Second output integer + * \param d Private signing key + * \param buf Message hash + * \param blen Length of buf + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +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 Compute ECDSA signature of a previously hashed message, + * deterministic version (RFC 6979). + * + * \param grp ECP group + * \param r First output integer + * \param s Second output integer + * \param d Private signing key + * \param buf Message hash + * \param blen Length of buf + * \param md_alg MD algorithm used to hash the message + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +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 Verify ECDSA signature of a previously hashed message + * + * \param grp ECP group + * \param buf Message hash + * \param blen Length of buf + * \param Q Public key to use for verification + * \param r First integer of the signature + * \param s Second integer of the signature + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.4 step 3. + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +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 Compute ECDSA signature and write it to buffer, + * serialized as defined in RFC 4492 page 20. + * (Not thread-safe to use same context in multiple threads) + * + * \note The deterministic version (RFC 6979) is used if + * MBEDTLS_ECDSA_DETERMINISTIC is defined. + * + * \param ctx ECDSA context + * \param md_alg Algorithm that was used to hash the message + * \param hash Message hash + * \param hlen Length of hash + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note The "sig" buffer must be at least as large as twice the + * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit + * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or + * MBEDTLS_ERR_ASN1_XXX error code + */ +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 ); + +#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 Compute ECDSA signature and write it to buffer, + * serialized as defined in RFC 4492 page 20. + * Deterministic version, RFC 6979. + * (Not thread-safe to use same context in multiple threads) + * + * \deprecated Superseded by mbedtls_ecdsa_write_signature() in 2.0.0 + * + * \param ctx ECDSA context + * \param hash Message hash + * \param hlen Length of hash + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param md_alg MD algorithm used to hash the message + * + * \note The "sig" buffer must be at least as large as twice the + * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit + * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or + * MBEDTLS_ERR_ASN1_XXX error code + */ +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 Read and verify an ECDSA signature + * + * \param ctx ECDSA context + * \param hash Message hash + * \param hlen Size of hash + * \param sig Signature to read and verify + * \param slen Size of sig + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.4 step 3. + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid, + * MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if the signature is + * valid but its actual length is less than siglen, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ); + +/** + * \brief Generate an ECDSA keypair on the given curve + * + * \param ctx ECDSA context in which the keypair should be stored + * \param gid Group (elliptic curve) to use. One of the various + * MBEDTLS_ECP_DP_XXX macros depending on configuration. + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 on success, or a MBEDTLS_ERR_ECP_XXX code. + */ +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 Set an ECDSA context from an EC key pair + * + * \param ctx ECDSA context to set + * \param key EC key to use + * + * \return 0 on success, or a MBEDTLS_ERR_ECP_XXX code. + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ); + +/** + * \brief Initialize context + * + * \param ctx Context to initialize + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ); + +/** + * \brief Free context + * + * \param ctx Context to free + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* ecdsa.h */ diff --git a/deps/mbedtls/mbedtls/ecjpake.h b/deps/mbedtls/mbedtls/ecjpake.h new file mode 100644 index 0000000000..161a5b213f --- /dev/null +++ b/deps/mbedtls/mbedtls/ecjpake.h @@ -0,0 +1,238 @@ +/** + * \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. + */ + +#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; + +/** + * 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 +{ + 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; + +/** + * \brief Initialize a context + * (just makes it ready for setup() or free()). + * + * \param ctx context to initialize + */ +void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ); + +/** + * \brief Set up a 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 context to set up + * \param role Our role: client or server + * \param hash hash function to use (MBEDTLS_MD_XXX) + * \param curve elliptic curve identifier (MBEDTLS_ECP_DP_XXX) + * \param secret pre-shared secret (passphrase) + * \param len length of the shared secret + * + * \return 0 if successfull, + * a negative error code otherwise + */ +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 a context is ready for use + * + * \param ctx Context to check + * + * \return 0 if the context is ready for use, + * 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 Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +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 Context to use + * \param buf Pointer to extension contents + * \param len Extension length + * + * \return 0 if successfull, + * a negative error code otherwise + */ +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 Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +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 Context to use + * \param buf Pointer to the message + * \param len Message length + * + * \return 0 if successfull, + * a negative error code otherwise + */ +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 Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +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 Free a context's content + * + * \param ctx context to free + */ +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 + +#ifdef __cplusplus +} +#endif + +#endif /* ecjpake.h */ diff --git a/deps/mbedtls/mbedtls/ecp.h b/deps/mbedtls/mbedtls/ecp.h new file mode 100644 index 0000000000..bf9abeff6b --- /dev/null +++ b/deps/mbedtls/mbedtls/ecp.h @@ -0,0 +1,684 @@ +/** + * \file ecp.h + * + * \brief Elliptic curves over GF(p) + * + * 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_ECP_H +#define MBEDTLS_ECP_H + +#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 /**< Requested curve not available. */ +#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 /**< Signature is valid but shorter than the user-supplied length. */ + +#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.) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Domain parameters (curve, subgroup and generator) identifiers. + * + * Only curves over prime fields are supported. + * + * \warning This library does not support validation of arbitrary domain + * parameters. Therefore, only well-known domain parameters from trusted + * sources should be used. See mbedtls_ecp_group_load(). + */ +typedef enum +{ + MBEDTLS_ECP_DP_NONE = 0, + MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ + MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ + MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ + MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */ + MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */ + MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */ + MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */ +} mbedtls_ecp_group_id; + +/** + * Number of supported curves (plus one for NONE). + * + * (Montgomery curves excluded for now.) + */ +#define MBEDTLS_ECP_DP_MAX 12 + +/** + * Curve information for use by other modules + */ +typedef struct +{ + mbedtls_ecp_group_id grp_id; /*!< Internal identifier */ + uint16_t tls_id; /*!< TLS NamedCurve identifier */ + uint16_t bit_size; /*!< Curve size in bits */ + const char *name; /*!< Human-friendly name */ +} mbedtls_ecp_curve_info; + +/** + * \brief ECP point structure (jacobian coordinates) + * + * \note All functions expect and return points satisfying + * the following condition: Z == 0 or Z == 1. (Other + * values of Z are used by internal functions only.) + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, X and Y are its standard (affine) coordinates. + */ +typedef struct +{ + mbedtls_mpi X; /*!< the point's X coordinate */ + mbedtls_mpi Y; /*!< the point's Y coordinate */ + mbedtls_mpi Z; /*!< the point's Z coordinate */ +} +mbedtls_ecp_point; + +/** + * \brief ECP group structure + * + * We consider two types of curves equations: + * 1. Short Weierstrass y^2 = x^3 + A x + B mod P (SEC1 + RFC 4492) + * 2. Montgomery, y^2 = x^3 + A x^2 + x mod P (Curve25519 + draft) + * In both cases, a generator G for a prime-order subgroup is fixed. In the + * short weierstrass, this subgroup is actually the whole curve, and its + * cardinal is denoted by N. + * + * In the case of Short Weierstrass curves, our code requires that N is an odd + * prime. (Use odd in mbedtls_ecp_mul() and prime in mbedtls_ecdsa_sign() for blinding.) + * + * In the case of Montgomery curves, we don't store A but (A + 2) / 4 which is + * the quantity actually used in the formulas. Also, nbits is not the size of N + * but the required size for private keys. + * + * If modp is NULL, reduction modulo P is done using a generic algorithm. + * Otherwise, it must point to a function that takes an mbedtls_mpi in the range + * 0..2^(2*pbits)-1 and transforms it in-place in an integer of little more + * than pbits, so that the integer may be efficiently brought in the 0..P-1 + * range by a few additions or substractions. It must return 0 on success and + * non-zero on failure. + */ +typedef struct +{ + mbedtls_ecp_group_id id; /*!< internal group identifier */ + mbedtls_mpi P; /*!< prime modulus of the base field */ + mbedtls_mpi A; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + mbedtls_mpi B; /*!< 1. B in the equation, or 2. unused */ + mbedtls_ecp_point G; /*!< generator of the (sub)group used */ + mbedtls_mpi N; /*!< 1. the order of G, or 2. unused */ + size_t pbits; /*!< number of bits in P */ + size_t nbits; /*!< number of bits in 1. P, or 2. private keys */ + unsigned int h; /*!< internal: 1 if the constants are static */ + int (*modp)(mbedtls_mpi *); /*!< function for fast reduction mod P */ + 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; /*!< number for pre-computed points */ +} +mbedtls_ecp_group; + +/** + * \brief ECP key pair structure + * + * A generic key pair that could be used for ECDSA, fixed ECDH, etc. + * + * \note Members purposefully in the same order as struc mbedtls_ecdsa_context. + */ +typedef struct +{ + 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; + +/** + * \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_ECP_MAX_BITS) +/** + * Maximum size of the groups (that is, of N and P) + */ +#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +#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 /**< 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 */ + +/* + * 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 /**< ECCurveType's named_curve */ + +/** + * \brief Get the list of supported curves in order of preferrence + * (full information) + * + * \return A statically allocated array, the last entry is 0. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); + +/** + * \brief Get the list of supported curves in order of preferrence + * (grp_id only) + * + * \return A statically allocated array, + * terminated with MBEDTLS_ECP_DP_NONE. + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ); + +/** + * \brief Get curve information from an internal group identifier + * + * \param grp_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ); + +/** + * \brief Get curve information from a TLS NamedCurve value + * + * \param tls_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ); + +/** + * \brief Get curve information from a human-readable name + * + * \param name The name + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ); + +/** + * \brief Initialize a point (as zero) + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ); + +/** + * \brief Initialize a group (to something meaningless) + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ); + +/** + * \brief Initialize a key pair (as an invalid one) + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ); + +/** + * \brief Free the components of a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ); + +/** + * \brief Free the components of an ECP group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ); + +/** + * \brief Free the components of a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ); + +/** + * \brief Copy the contents of point Q into P + * + * \param P Destination point + * \param Q Source point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); + +/** + * \brief Copy the contents of a group object + * + * \param dst Destination group + * \param src Source group + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ); + +/** + * \brief Set a point to zero + * + * \param pt Destination point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Tell if a point is zero + * + * \param pt Point to test + * + * \return 1 if point is zero, 0 otherwise + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Compare two points + * + * \note This assumes the points are normalized. Otherwise, + * they may compare as "not equal" even if they are. + * + * \param P First point to compare + * \param Q Second point to compare + * + * \return 0 if the points are equal, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); + +/** + * \brief Import a non-zero point from two ASCII strings + * + * \param P Destination point + * \param radix Input numeric base + * \param x First affine coordinate as a null-terminated string + * \param y Second affine coordinate as a null-terminated string + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ); + +/** + * \brief Export a point into unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to export + * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro + * \param olen Length of the actual output + * \param buf Output buffer + * \param buflen Length of the output buffer + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +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 Import a point from unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to import + * \param buf Input buffer + * \param ilen Actual length of input + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * is not implemented. + * + * \note This function does NOT check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() for + * that. + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen ); + +/** + * \brief Import a point from a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Destination point + * \param buf $(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after the ECPoint on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * 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 Export a point as a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Point to export + * \param format Export format + * \param olen length of data written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +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 Set a group using well-known domain parameters + * + * \param grp Destination group + * \param index Index in the list of well-known domain parameters + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups + * + * \note Index should be a value of RFC 4492's enum NamedCurve, + * usually in the form of a MBEDTLS_ECP_DP_XXX macro. + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id index ); + +/** + * \brief Set a group from a TLS ECParameters record + * + * \param grp Destination group + * \param buf &(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after ECParameters on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ); + +/** + * \brief Write the TLS ECParameters record for a group + * + * \param grp ECP group used + * \param olen Number of bytes actually written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief Multiplication by an integer: R = m * P + * (Not thread-safe to use same group in multiple threads) + * + * \note In order to prevent timing attacks, this function + * executes the exact same sequence of (base field) + * operations for any valid m. It avoids any if-branch or + * array index depending on the value of m. + * + * \note If f_rng is not NULL, it is used to randomize intermediate + * results in order to prevent potential timing attacks + * targeting these results. It is recommended to always + * provide a non-NULL f_rng (the overhead is negligible). + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply + * \param P Point to multiply + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m is not a valid privkey + * or P is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +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 Multiplication and addition of two points by integers: + * R = m * P + n * Q + * (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 ECP group + * \param R Destination point + * \param m Integer by which to multiply P + * \param P Point to multiply by m + * \param n Integer by which to multiply Q + * \param Q Point to be multiplied by n + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m or n is not a valid privkey + * or P or Q is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +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 Check that a point is a valid public key on this curve + * + * \param grp Curve/group the point should belong to + * \param pt Point to check + * + * \return 0 if point is a valid public key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note This function only checks the point is non-zero, has valid + * coordinates and lies on the curve, but not that it is + * indeed a multiple of G. This is additional check is more + * expensive, isn't required by standards, and shouldn't 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 Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ); + +/** + * \brief Check that an mbedtls_mpi is a valid private key for this curve + * + * \param grp Group used + * \param d Integer to check + * + * \return 0 if point is a valid private key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ); + +/** + * \brief Generate a keypair with configurable base point + * + * \param grp ECP group + * \param G Chosen base point + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +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 Generate a keypair + * + * \param grp ECP group + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +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 Generate a keypair + * + * \param grp_id ECP group identifier + * \param key Destination keypair + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +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 Check a public-private key pair + * + * \param pub Keypair structure holding a public key + * \param prv Keypair structure holding a private (plus public) key + * + * \return 0 if successful (keys are valid and match), or + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA, or + * a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX code. + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecp_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_ECP_ALT */ +#include "ecp_alt.h" +#endif /* MBEDTLS_ECP_ALT */ + +#endif /* ecp.h */ diff --git a/deps/mbedtls/mbedtls/ecp_internal.h b/deps/mbedtls/mbedtls/ecp_internal.h new file mode 100644 index 0000000000..2991e26dd9 --- /dev/null +++ b/deps/mbedtls/mbedtls/ecp_internal.h @@ -0,0 +1,292 @@ +/** + * \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_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/deps/mbedtls/mbedtls/entropy.h b/deps/mbedtls/mbedtls/entropy.h new file mode 100644 index 0000000000..747aca4dfa --- /dev/null +++ b/deps/mbedtls/mbedtls/entropy.h @@ -0,0 +1,287 @@ +/** + * \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_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 +{ +#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 + * MBEDTSL_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/deps/mbedtls/mbedtls/entropy_poll.h b/deps/mbedtls/mbedtls/entropy_poll.h new file mode 100644 index 0000000000..81258d5f39 --- /dev/null +++ b/deps/mbedtls/mbedtls/entropy_poll.h @@ -0,0 +1,109 @@ +/** + * \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/deps/mbedtls/mbedtls/error.h b/deps/mbedtls/mbedtls/error.h new file mode 100644 index 0000000000..5e549f6b6a --- /dev/null +++ b/deps/mbedtls/mbedtls/error.h @@ -0,0 +1,107 @@ +/** + * \file error.h + * + * \brief Error to string translation + * + * 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_ERROR_H +#define MBEDTLS_ERROR_H + +#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 2 0x0012-0x0014 + * BLOWFISH 2 0x0016-0x0018 + * THREADING 3 0x001A-0x001E + * AES 2 0x0020-0x0022 + * CAMELLIA 2 0x0024-0x0026 + * XTEA 1 0x0028-0x0028 + * BASE64 2 0x002A-0x002C + * OID 1 0x002E-0x002E 0x000B-0x000B + * PADLOCK 1 0x0030-0x0030 + * DES 1 0x0032-0x0032 + * CTR_DBRG 4 0x0034-0x003A + * ENTROPY 3 0x003C-0x0040 0x003D-0x003F + * NET 11 0x0042-0x0052 0x0043-0x0045 + * ASN1 7 0x0060-0x006C + * PBKDF2 1 0x007C-0x007C + * HMAC_DRBG 4 0x0003-0x0009 + * CCM 2 0x000D-0x000F + * + * 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 19 + * PKCS5 2 4 (Started from top) + * DHM 3 9 + * PK 3 14 (Started from top) + * RSA 4 9 + * ECP 4 8 (Started from top) + * MD 5 4 + * CIPHER 6 6 + * SSL 6 17 (Started from top) + * SSL 7 31 + * + * 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/deps/mbedtls/mbedtls/gcm.h b/deps/mbedtls/mbedtls/gcm.h new file mode 100644 index 0000000000..1b77aaedd4 --- /dev/null +++ b/deps/mbedtls/mbedtls/gcm.h @@ -0,0 +1,220 @@ +/** + * \file gcm.h + * + * \brief Galois/Counter mode for 128-bit block ciphers + * + * 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_GCM_H +#define MBEDTLS_GCM_H + +#include "cipher.h" + +#include + +#define MBEDTLS_GCM_ENCRYPT 1 +#define MBEDTLS_GCM_DECRYPT 0 + +#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */ +#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief GCM context structure + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx;/*!< cipher context used */ + uint64_t HL[16]; /*!< Precalculated HTable */ + uint64_t HH[16]; /*!< Precalculated HTable */ + uint64_t len; /*!< Total data length */ + uint64_t add_len; /*!< Total add length */ + unsigned char base_ectr[16];/*!< First ECTR for tag */ + unsigned char y[16]; /*!< Y working value */ + unsigned char buf[16]; /*!< buf working value */ + int mode; /*!< Encrypt or Decrypt */ +} +mbedtls_gcm_context; + +/** + * \brief Initialize GCM context (just makes references valid) + * Makes the context ready for mbedtls_gcm_setkey() or + * mbedtls_gcm_free(). + * + * \param ctx GCM context to initialize + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ); + +/** + * \brief GCM initialization (encryption) + * + * \param ctx GCM context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief GCM buffer encryption/decryption using a block cipher + * + * \note On encryption, the output buffer can be the same as the input buffer. + * On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param mode MBEDTLS_GCM_ENCRYPT or MBEDTLS_GCM_DECRYPT + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag_len length of the tag to generate + * \param tag buffer for holding the tag + * + * \return 0 if successful + */ +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 GCM buffer authenticated decryption using a block cipher + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_GCM_AUTH_FAILED if tag does not match + */ +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 Generic GCM stream start function + * + * \param ctx GCM context + * \param mode MBEDTLS_GCM_ENCRYPT or MBEDTLS_GCM_DECRYPT + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data (or NULL if length is 0) + * \param add_len length of additional data + * + * \return 0 if successful + */ +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 Generic GCM update function. Encrypts/decrypts using the + * given GCM context. Expects input to be a multiple of 16 + * bytes! Only the last call before mbedtls_gcm_finish() can be less + * than 16 bytes! + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful or MBEDTLS_ERR_GCM_BAD_INPUT + */ +int mbedtls_gcm_update( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic GCM finalisation function. Wraps up the GCM stream + * and generates the tag. The tag can have a maximum length of + * 16 bytes. + * + * \param ctx GCM context + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate (must be at least 4) + * + * \return 0 if successful or MBEDTLS_ERR_GCM_BAD_INPUT + */ +int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ); + +/** + * \brief Free a GCM context and underlying cipher sub-context + * + * \param ctx GCM context to free + */ +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_gcm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* gcm.h */ diff --git a/deps/mbedtls/mbedtls/havege.h b/deps/mbedtls/mbedtls/havege.h new file mode 100644 index 0000000000..dac5d31138 --- /dev/null +++ b/deps/mbedtls/mbedtls/havege.h @@ -0,0 +1,74 @@ +/** + * \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 + +#include + +#define MBEDTLS_HAVEGE_COLLECT_SIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief HAVEGE state structure + */ +typedef struct +{ + 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/deps/mbedtls/mbedtls/hmac_drbg.h b/deps/mbedtls/mbedtls/hmac_drbg.h new file mode 100644 index 0000000000..e010558028 --- /dev/null +++ b/deps/mbedtls/mbedtls/hmac_drbg.h @@ -0,0 +1,299 @@ +/** + * \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 + +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/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 +{ + /* Working state: the key K is not stored explicitely, + * 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 + * + * \note Additional data is optional, pass NULL and 0 as second + * third argument if no additional data is being used. + */ +void mbedtls_hmac_drbg_update( 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_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/deps/mbedtls/mbedtls/md.h b/deps/mbedtls/mbedtls/md.h new file mode 100644 index 0000000000..9b996a951b --- /dev/null +++ b/deps/mbedtls/mbedtls/md.h @@ -0,0 +1,354 @@ +/** + * \file md.h + * + * \brief Generic message digest wrapper + * + * \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_H +#define MBEDTLS_MD_H + +#include + +#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. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MBEDTLS_MD_NONE=0, + MBEDTLS_MD_MD2, + MBEDTLS_MD_MD4, + MBEDTLS_MD_MD5, + MBEDTLS_MD_SHA1, + MBEDTLS_MD_SHA224, + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA384, + MBEDTLS_MD_SHA512, + MBEDTLS_MD_RIPEMD160, +} 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 + +/** + * Opaque struct defined in md_internal.h + */ +typedef struct mbedtls_md_info_t mbedtls_md_info_t; + +/** + * Generic message digest context. + */ +typedef struct { + /** Information about the associated message digest */ + const mbedtls_md_info_t *md_info; + + /** Digest-specific context */ + void *md_ctx; + + /** HMAC part of the context */ + void *hmac_ctx; +} mbedtls_md_context_t; + +/** + * \brief Returns the list of digests supported by the generic digest module. + * + * \return a statically allocated array of digests, the last entry + * is 0. + */ +const int *mbedtls_md_list( void ); + +/** + * \brief Returns the message digest information associated with the + * given digest name. + * + * \param md_name Name of the digest to search for. + * + * \return The message digest information associated with md_name or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); + +/** + * \brief Returns the message digest information associated with the + * given digest type. + * + * \param md_type type of digest to search for. + * + * \return The message digest information associated with md_type or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ); + +/** + * \brief Initialize a md_context (as NONE) + * This should always be called first. + * Prepares the context for mbedtls_md_setup() or mbedtls_md_free(). + */ +void mbedtls_md_init( mbedtls_md_context_t *ctx ); + +/** + * \brief Free and clear the internal structures of ctx. + * Can be called at any time after mbedtls_md_init(). + * Mandatory once mbedtls_md_setup() has been called. + */ +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 Select MD to use and allocate internal structures. + * 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 Context to set up. + * \param md_info Message digest to use. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED 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 Select MD to use and allocate internal structures. + * Should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \param ctx Context to set up. + * \param md_info Message digest to use. + * \param hmac 0 to save some memory if HMAC will not be used, + * non-zero is HMAC is going to be used with this context. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + */ +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); + +/** + * \brief Clone the state of an MD context + * + * \note The two contexts must have been setup to the same type + * (cloning from SHA-256 to SHA-512 make no sense). + * + * \warning Only clones the MD state, not the HMAC state! (for now) + * + * \param dst The destination context + * \param src The context to be cloned + * + * \return \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure. + */ +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ); + +/** + * \brief Returns the size of the message digest output. + * + * \param md_info message digest info + * + * \return size of the message digest output in bytes. + */ +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the type of the message digest output. + * + * \param md_info message digest info + * + * \return type of the message digest output. + */ +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the name of the message digest output. + * + * \param md_info message digest info + * + * \return name of the message digest output. + */ +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ); + +/** + * \brief Prepare the context to digest a new message. + * Generally called after mbedtls_md_setup() or mbedtls_md_finish(). + * Followed by mbedtls_md_update(). + * + * \param ctx generic message digest context. + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_starts( mbedtls_md_context_t *ctx ); + +/** + * \brief Generic message digest process buffer + * Called between mbedtls_md_starts() and mbedtls_md_finish(). + * May be called repeatedly. + * + * \param ctx Generic message digest context + * \param input buffer holding the datal + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic message digest final digest + * Called after mbedtls_md_update(). + * Usually followed by mbedtls_md_free() or mbedtls_md_starts(). + * + * \param ctx Generic message digest context + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); + +/** + * \brief Output = message_digest( input buffer ) + * + * \param md_info message digest info + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +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 Output = message_digest( file contents ) + * + * \param md_info message digest info + * \param path input file name + * \param output generic message digest checksum result + * + * \return 0 if successful, + * MBEDTLS_ERR_MD_FILE_IO_ERROR if file input failed, + * MBEDTLS_ERR_MD_BAD_INPUT_DATA if 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 Set HMAC key and prepare to authenticate a new message. + * Usually called after mbedtls_md_setup() or mbedtls_md_hmac_finish(). + * + * \param ctx HMAC context + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, + size_t keylen ); + +/** + * \brief Generic HMAC process buffer. + * Called between mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset() + * and mbedtls_md_hmac_finish(). + * May be called repeatedly. + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief Output HMAC. + * Called after mbedtls_md_hmac_update(). + * Usually followed by mbedtls_md_hmac_reset(), + * mbedtls_md_hmac_starts(), or mbedtls_md_free(). + * + * \param ctx HMAC context + * \param output Generic HMAC checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); + +/** + * \brief Prepare to authenticate a new message with the same key. + * Called after mbedtls_md_hmac_finish() and before + * mbedtls_md_hmac_update(). + * + * \param ctx HMAC context to be reset + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); + +/** + * \brief Output = Generic_HMAC( hmac key, input buffer ) + * + * \param md_info message digest info + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic HMAC-result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +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/deps/mbedtls/mbedtls/md2.h b/deps/mbedtls/mbedtls/md2.h new file mode 100644 index 0000000000..0f93fbf427 --- /dev/null +++ b/deps/mbedtls/mbedtls/md2.h @@ -0,0 +1,136 @@ +/** + * \file md2.h + * + * \brief MD2 message digest algorithm (hash function) + * + * 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 + +#if !defined(MBEDTLS_MD2_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD2 context structure + */ +typedef struct +{ + 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; + +/** + * \brief Initialize MD2 context + * + * \param ctx MD2 context to be initialized + */ +void mbedtls_md2_init( mbedtls_md2_context *ctx ); + +/** + * \brief Clear MD2 context + * + * \param ctx MD2 context to be cleared + */ +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 + */ +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ); + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md2_starts( 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 + */ +void mbedtls_md2_update( mbedtls_md2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + */ +void mbedtls_md2_finish( mbedtls_md2_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD2_ALT */ +#include "md2_alt.h" +#endif /* MBEDTLS_MD2_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + */ +void mbedtls_md2( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md2_self_test( int verbose ); + +/* Internal use */ +void mbedtls_md2_process( mbedtls_md2_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md2.h */ diff --git a/deps/mbedtls/mbedtls/md4.h b/deps/mbedtls/mbedtls/md4.h new file mode 100644 index 0000000000..45214d41d9 --- /dev/null +++ b/deps/mbedtls/mbedtls/md4.h @@ -0,0 +1,136 @@ +/** + * \file md4.h + * + * \brief MD4 message digest algorithm (hash function) + * + * 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 + +#if !defined(MBEDTLS_MD4_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context structure + */ +typedef struct +{ + 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; + +/** + * \brief Initialize MD4 context + * + * \param ctx MD4 context to be initialized + */ +void mbedtls_md4_init( mbedtls_md4_context *ctx ); + +/** + * \brief Clear MD4 context + * + * \param ctx MD4 context to be cleared + */ +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 + */ +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ); + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md4_starts( 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 + */ +void mbedtls_md4_update( mbedtls_md4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void mbedtls_md4_finish( mbedtls_md4_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD4_ALT */ +#include "md4_alt.h" +#endif /* MBEDTLS_MD4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void mbedtls_md4( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md4_self_test( int verbose ); + +/* Internal use */ +void mbedtls_md4_process( mbedtls_md4_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md4.h */ diff --git a/deps/mbedtls/mbedtls/md5.h b/deps/mbedtls/mbedtls/md5.h new file mode 100644 index 0000000000..5a64061aa0 --- /dev/null +++ b/deps/mbedtls/mbedtls/md5.h @@ -0,0 +1,136 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * 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 + +#if !defined(MBEDTLS_MD5_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context structure + */ +typedef struct +{ + 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; + +/** + * \brief Initialize MD5 context + * + * \param ctx MD5 context to be initialized + */ +void mbedtls_md5_init( mbedtls_md5_context *ctx ); + +/** + * \brief Clear MD5 context + * + * \param ctx MD5 context to be cleared + */ +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 + */ +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ); + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md5_starts( 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 + */ +void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ); + +/* Internal use */ +void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD5_ALT */ +#include "md5_alt.h" +#endif /* MBEDTLS_MD5_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md5.h */ diff --git a/deps/mbedtls/mbedtls/md_internal.h b/deps/mbedtls/mbedtls/md_internal.h new file mode 100644 index 0000000000..e2441bbc49 --- /dev/null +++ b/deps/mbedtls/mbedtls/md_internal.h @@ -0,0 +1,114 @@ +/** + * \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 */ + void (*starts_func)( void *ctx ); + + /** Digest update function */ + void (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + void (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + void (*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 */ + void (*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/deps/mbedtls/mbedtls/memory_buffer_alloc.h b/deps/mbedtls/mbedtls/memory_buffer_alloc.h new file mode 100644 index 0000000000..d5df316fdd --- /dev/null +++ b/deps/mbedtls/mbedtls/memory_buffer_alloc.h @@ -0,0 +1,150 @@ +/** + * \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/deps/mbedtls/mbedtls/net.h b/deps/mbedtls/mbedtls/net.h new file mode 100644 index 0000000000..774559b3cf --- /dev/null +++ b/deps/mbedtls/mbedtls/net.h @@ -0,0 +1,31 @@ +/** + * \file net.h + * + * \brief Deprecated header file that includes 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) + * + * \deprecated Superseded by mbedtls/net_sockets.h + */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#include "mbedtls/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/deps/mbedtls/mbedtls/net_sockets.h b/deps/mbedtls/mbedtls/net_sockets.h new file mode 100644 index 0000000000..de335526fe --- /dev/null +++ b/deps/mbedtls/mbedtls/net_sockets.h @@ -0,0 +1,225 @@ +/** + * \file net_sockets.h + * + * \brief Network communication 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_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_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 */ + +#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 +{ + 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 + * \param buf_size Size of the client_ip buffer + * \param ip_len Will receive the size of the client IP written + * + * \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 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/deps/mbedtls/mbedtls/oid.h b/deps/mbedtls/mbedtls/oid.h new file mode 100644 index 0000000000..fcecdafdca --- /dev/null +++ b/deps/mbedtls/mbedtls/oid.h @@ -0,0 +1,570 @@ +/** + * \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 + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "x509.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 */ + +/* + * 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} */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define MBEDTLS_OID_PKIX MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD "\x01\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 } */ + +/* + * 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 } */ + +/* + * 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_GOV "\x03\x04\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_GOV "\x03\x04\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_GOV "\x03\x04\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_GOV "\x03\x04\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_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */ + +/* + * 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 } */ + +/* + * 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 { + 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 ); + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/** + * \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 ); +#endif + +/** + * \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 ); +#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 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/deps/mbedtls/mbedtls/padlock.h b/deps/mbedtls/mbedtls/padlock.h new file mode 100644 index 0000000000..2045a5ab64 --- /dev/null +++ b/deps/mbedtls/mbedtls/padlock.h @@ -0,0 +1,107 @@ +/** + * \file padlock.h + * + * \brief VIA PadLock ACE for HW encryption/decryption supported by some + * processors + * + * 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 + +#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 PadLock detection routine + * + * \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 PadLock AES-ECB block en(de)cryption + * + * \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 PadLock AES-CBC buffer en(de)cryption + * + * \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/deps/mbedtls/mbedtls/pem.h b/deps/mbedtls/mbedtls/pem.h new file mode 100644 index 0000000000..54dc02d7cd --- /dev/null +++ b/deps/mbedtls/mbedtls/pem.h @@ -0,0 +1,129 @@ +/** + * \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 + +#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 +{ + 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/deps/mbedtls/mbedtls/pk.h b/deps/mbedtls/mbedtls/pk.h new file mode 100644 index 0000000000..f9f9b9bb09 --- /dev/null +++ b/deps/mbedtls/mbedtls/pk.h @@ -0,0 +1,616 @@ +/** + * \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(__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 signature is valid but its length is less than expected. */ + +#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_type_t; + +/** + * \brief Options for RSASSA-PSS signature verification. + * See \c mbedtls_rsa_rsassa_pss_verify_ext() + */ +typedef struct +{ + 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_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 +{ + const mbedtls_pk_info_t * pk_info; /**< Public key informations */ + void * pk_ctx; /**< Underlying public key context */ +} mbedtls_pk_context; + +#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) + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ); + +/** + * \brief Free a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ); + +/** + * \brief Initialize a PK context with the information given + * and allocates the type-specific PK subcontext. + * + * \param ctx Context to initialize. Must be empty (type 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_PK_RSA_ALT_SUPPORT) +/** + * \brief Initialize an RSA-alt context + * + * \param ctx Context to initialize. Must be empty (type 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 Context to use + * + * \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 Context to use + * + * \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 Context to test + * \param type Target type + * + * \return 0 if context can't do the operations, + * 1 otherwise. + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); + +/** + * \brief Verify signature (including padding if relevant). + * + * \param ctx PK context to use + * \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 the signature is + * valid but its actual length is less than sig_len, + * 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 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 PK context to use + * \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 the signature is + * valid but its actual length is less than sig_len, + * 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 PK context to use - must hold 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 Decrypt message (including padding if relevant). + * + * \param ctx PK context to use - must hold 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 PK context to use + * \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 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); + +/** + * \brief Export debug information + * + * \param ctx Context to use + * \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 Context to use + * + * \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 Context to use + * + * \return Type on success, or MBEDTLS_PK_NONE + */ +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 key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \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 key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * + * \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 key to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be 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_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *password ); + +/** \ingroup pk_module */ +/** + * \brief Load and parse a public key + * + * \param ctx key to be initialized + * \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 private to write away + * \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 public key to write away + * \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 public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \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 private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \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 key to fill + * + * \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 public key to write away + * + * \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 + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PK_H */ diff --git a/deps/mbedtls/mbedtls/pk_internal.h b/deps/mbedtls/mbedtls/pk_internal.h new file mode 100644 index 0000000000..01d0f214bc --- /dev/null +++ b/deps/mbedtls/mbedtls/pk_internal.h @@ -0,0 +1,114 @@ +/** + * \file pk.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 ); + + /** 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 ); + + /** 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 + +#endif /* MBEDTLS_PK_WRAP_H */ diff --git a/deps/mbedtls/mbedtls/pkcs11.h b/deps/mbedtls/mbedtls/pkcs11.h new file mode 100644 index 0000000000..2e88928137 --- /dev/null +++ b/deps/mbedtls/mbedtls/pkcs11.h @@ -0,0 +1,173 @@ +/** + * \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 { + 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/deps/mbedtls/mbedtls/pkcs12.h b/deps/mbedtls/mbedtls/pkcs12.h new file mode 100644 index 0000000000..9b2d904591 --- /dev/null +++ b/deps/mbedtls/mbedtls/pkcs12.h @@ -0,0 +1,119 @@ +/** + * \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 + +#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 + +/** + * \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 ); + +/** + * \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/deps/mbedtls/mbedtls/pkcs5.h b/deps/mbedtls/mbedtls/pkcs5.h new file mode 100644 index 0000000000..ec5cb9e744 --- /dev/null +++ b/deps/mbedtls/mbedtls/pkcs5.h @@ -0,0 +1,94 @@ +/** + * \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 + +#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 + +/** + * \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 ); + +/** + * \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 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_pkcs5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs5.h */ diff --git a/deps/mbedtls/mbedtls/platform.h b/deps/mbedtls/mbedtls/platform.h new file mode 100644 index 0000000000..35010f8852 --- /dev/null +++ b/deps/mbedtls/mbedtls/platform.h @@ -0,0 +1,343 @@ +/** + * \file platform.h + * + * \brief mbed TLS 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) + */ +#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 "mbedtls/platform_time.h" +#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. + * \{ + */ + +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#include +#include +#include +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +#if defined(_WIN32) +#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< Default snprintf to use */ +#else +#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use */ +#endif +#endif +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_TIME) +#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS) +#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS /**< Default exit value to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE) +#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE /**< 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 Set your own memory implementation function pointers + * + * \param calloc_func the calloc function implementation + * \param free_func the free function implementation + * + * \return 0 if successful + */ +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 Set your own fprintf function pointer + * + * \param fprintf_func the fprintf function implementation + * + * \return 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 Set your own printf function pointer + * + * \param printf_func the printf function implementation + * + * \return 0 + */ +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(_WIN32) +/* 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 Set your own snprintf function pointer + * + * \param snprintf_func the snprintf function implementation + * + * \return 0 + */ +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 snprintf +#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +/* + * The function pointers for exit + */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +extern void (*mbedtls_exit)( int status ); + +/** + * \brief Set your own exit function pointer + * + * \param exit_func the exit function implementation + * + * \return 0 + */ +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 Set your own seed file writing/reading functions + * + * \param nv_seed_read_func the seed reading function implementation + * \param nv_seed_write_func the seed writing function implementation + * + * \return 0 + */ +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 Platform context structure + * + * \note This structure may be used to assist platform-specific + * setup/teardown operations. + */ +typedef struct { + char dummy; /**< Placeholder member as empty structs are not portable */ +} +mbedtls_platform_context; + +#else +#include "platform_alt.h" +#endif /* !MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */ + +/** + * \brief Perform any platform initialisation operations + * + * \param ctx mbed TLS context + * + * \return 0 if successful + * + * \note This function is intended to allow platform specific initialisation, + * and should be called before any other library functions. Its + * implementation is platform specific, and by default, unless platform + * specific code is provided, it does nothing. + * + * Its use and whether its necessary to be called is dependent on the + * platform. + */ +int mbedtls_platform_setup( mbedtls_platform_context *ctx ); +/** + * \brief Perform any platform teardown operations + * + * \param ctx mbed TLS context + * + * \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 by default, unless + * platform specific code is provided, it does nothing. + * + * Its use and whether its necessary to be called is dependent on the + * platform. + */ +void mbedtls_platform_teardown( mbedtls_platform_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* platform.h */ diff --git a/deps/mbedtls/mbedtls/platform_time.h b/deps/mbedtls/mbedtls/platform_time.h new file mode 100644 index 0000000000..abb3431420 --- /dev/null +++ b/deps/mbedtls/mbedtls/platform_time.h @@ -0,0 +1,81 @@ +/** + * \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/deps/mbedtls/mbedtls/ripemd160.h b/deps/mbedtls/mbedtls/ripemd160.h new file mode 100644 index 0000000000..7083fc8599 --- /dev/null +++ b/deps/mbedtls/mbedtls/ripemd160.h @@ -0,0 +1,138 @@ +/** + * \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 + +#if !defined(MBEDTLS_RIPEMD160_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RIPEMD-160 context structure + */ +typedef struct +{ + 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; + +/** + * \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 + */ +void mbedtls_ripemd160_starts( 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 + */ +void mbedtls_ripemd160_update( 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 + */ +void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_ripemd160_process( mbedtls_ripemd160_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_RIPEMD160_ALT */ +#include "ripemd160.h" +#endif /* MBEDTLS_RIPEMD160_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \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 + */ +void mbedtls_ripemd160( const unsigned char *input, size_t ilen, + unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ripemd160_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_ripemd160.h */ diff --git a/deps/mbedtls/mbedtls/rsa.h b/deps/mbedtls/mbedtls/rsa.h new file mode 100644 index 0000000000..7d7469d509 --- /dev/null +++ b/deps/mbedtls/mbedtls/rsa.h @@ -0,0 +1,670 @@ +/** + * \file rsa.h + * + * \brief 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) + */ +#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 library's validity check. */ +#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. */ + +/* + * RSA constants + */ +#define MBEDTLS_RSA_PUBLIC 0 +#define MBEDTLS_RSA_PRIVATE 1 + +#define MBEDTLS_RSA_PKCS_V15 0 +#define MBEDTLS_RSA_PKCS_V21 1 + +#define MBEDTLS_RSA_SIGN 1 +#define MBEDTLS_RSA_CRYPT 2 + +#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. + */ +#if defined(MBEDTLS_RSA_C) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RSA context structure + */ +typedef struct +{ + int ver; /*!< always 0 */ + size_t len; /*!< size(N) in chars */ + + mbedtls_mpi N; /*!< public modulus */ + mbedtls_mpi E; /*!< public exponent */ + + mbedtls_mpi D; /*!< private exponent */ + mbedtls_mpi P; /*!< 1st prime factor */ + mbedtls_mpi Q; /*!< 2nd 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; /*!< cached blinding value */ + mbedtls_mpi Vf; /*!< cached un-blinding value */ + + int padding; /*!< MBEDTLS_RSA_PKCS_V15 for 1.5 padding and + MBEDTLS_RSA_PKCS_v21 for OAEP/PSS */ + int hash_id; /*!< Hash identifier of mbedtls_md_type_t as + specified in the mbedtls_md.h header file + for the EME-OAEP and EMSA-PSS + encoding */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex */ +#endif +} +mbedtls_rsa_context; + +/** + * \brief Initialize an RSA context + * + * Note: Set padding to MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP + * encryption scheme and the RSASSA-PSS signature scheme. + * + * \param ctx RSA context to be initialized + * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21 + * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier + * + * \note The hash_id parameter is actually ignored + * when using MBEDTLS_RSA_PKCS_V15 padding. + * + * \note 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's merely + * a default value, which can be overriden by calling specific + * rsa_rsaes_xxx or rsa_rsassa_xxx functions. + * + * \note The chosen hash is always used for OEAP encryption. + * For PSS signatures, it's always used for making signatures, + * but can be overriden (and always is, if set to + * MBEDTLS_MD_NONE) for verifying them. + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id); + +/** + * \brief Set padding for an already initialized RSA context + * See \c mbedtls_rsa_init() for details. + * + * \param ctx RSA context to be set + * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21 + * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id); + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context that will hold the key + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * + * \note mbedtls_rsa_init() must be called beforehand to setup + * the RSA context. + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +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 Check a public RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief Check a private RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief Check a public-private RSA key pair. + * Check each of the contexts, and make sure they match. + * + * \param pub RSA context holding the public key + * \param prv RSA context holding the private key + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv ); + +/** + * \brief Do an RSA public key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note This function does NOT take care of message + * padding. Also, be sure to set input[0] = 0 or ensure that + * input is smaller than N. + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA private key operation + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for blinding) + * \param p_rng RNG parameter + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +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 Generic wrapper to perform a PKCS#1 encryption using the + * mode from the context. Add the message padding, then do an + * RSA operation. + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding + * and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \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). + */ +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 Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \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). + */ +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 Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding + * and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \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). + */ +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 Generic wrapper to perform a PKCS#1 decryption using the + * mode from the context. Do an RSA operation, then remove + * the message padding + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \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 length \c output_max_len should be + * as large as the size ctx->len of ctx->N (eg. 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 will return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \note The input buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +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 Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \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 length \c output_max_len should be + * as large as the size ctx->len of ctx->N (eg. 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 will return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \note The input buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +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 Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \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 length \c output_max_len should be + * as large as the size ctx->len of ctx->N (eg. 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 will return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \note The input buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +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 Generic wrapper to perform a PKCS#1 signature using the + * mode from the context. Do a private RSA operation to sign + * a message digest + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for + * MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \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). + * + * \note In case of PKCS#1 v2.1 encoding, see comments on + * \note \c mbedtls_rsa_rsassa_pss_sign() for details on md_alg and hash_id. + */ +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 Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \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_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 Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for + * MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \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). + * + * \note The hash_id in the RSA context is the one used for the + * encoding. md_alg in the function call is the type of hash + * that is encoded. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +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 Generic wrapper to perform a PKCS#1 verification using the + * mode from the context. Do a public RSA operation and check + * the message digest + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \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 holding the ciphertext + * + * \return 0 if the verify 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). + * + * \note In case of PKCS#1 v2.1 encoding, see comments on + * \c mbedtls_rsa_rsassa_pss_verify() about md_alg and hash_id. + */ +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 Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \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 holding the ciphertext + * + * \return 0 if the verify 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_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 Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) + * (This is the "simple" version.) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \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 holding the ciphertext + * + * \return 0 if the verify 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). + * + * \note The hash_id in the RSA context is the one used for the + * verification. md_alg in the function call is the type of + * hash that is verified. According to RFC 3447 it is advised to + * keep both hashes the same. If hash_id in the RSA context is + * unset, the md_alg from the function call is used. + */ +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 Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) + * (This is the version with "full" options.) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \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 mgf1_hash_id message digest used for mask generation + * \param expected_salt_len Length of the salt used in padding, use + * MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify 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). + * + * \note The hash_id in the RSA context is ignored. + */ +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 Copy the components of an RSA context + * + * \param dst Destination context + * \param src Source context + * + * \return 0 on success, + * MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ); + +/** + * \brief Free the components of an RSA key + * + * \param ctx RSA Context to free + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_RSA_C */ + +#endif /* rsa.h */ diff --git a/deps/mbedtls/mbedtls/sha1.h b/deps/mbedtls/mbedtls/sha1.h new file mode 100644 index 0000000000..7a67c6c1fb --- /dev/null +++ b/deps/mbedtls/mbedtls/sha1.h @@ -0,0 +1,136 @@ +/** + * \file sha1.h + * + * \brief SHA-1 cryptographic hash function + * + * 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_SHA1_H +#define MBEDTLS_SHA1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA1_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* MBEDTLS_SHA1_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha1.h */ diff --git a/deps/mbedtls/mbedtls/sha256.h b/deps/mbedtls/mbedtls/sha256.h new file mode 100644 index 0000000000..f8041adf08 --- /dev/null +++ b/deps/mbedtls/mbedtls/sha256.h @@ -0,0 +1,141 @@ +/** + * \file sha256.h + * + * \brief SHA-224 and SHA-256 cryptographic hash function + * + * 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_SHA256_H +#define MBEDTLS_SHA256_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA256_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +mbedtls_sha256_context; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-256 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ); + +/* Internal use */ +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA256_ALT */ +#include "sha256_alt.h" +#endif /* MBEDTLS_SHA256_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha256_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha256.h */ diff --git a/deps/mbedtls/mbedtls/sha512.h b/deps/mbedtls/mbedtls/sha512.h new file mode 100644 index 0000000000..627694f425 --- /dev/null +++ b/deps/mbedtls/mbedtls/sha512.h @@ -0,0 +1,141 @@ +/** + * \file sha512.h + * + * \brief SHA-384 and SHA-512 cryptographic hash function + * + * 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_SHA512_H +#define MBEDTLS_SHA512_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA512_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + uint64_t total[2]; /*!< number of bytes processed */ + uint64_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[128]; /*!< data block being processed */ + int is384; /*!< 0 => SHA-512, else SHA-384 */ +} +mbedtls_sha512_context; + +/** + * \brief Initialize SHA-512 context + * + * \param ctx SHA-512 context to be initialized + */ +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ); + +/** + * \brief Clear SHA-512 context + * + * \param ctx SHA-512 context to be cleared + */ +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-512 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ); + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, unsigned char output[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA512_ALT */ +#include "sha512_alt.h" +#endif /* MBEDTLS_SHA512_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void mbedtls_sha512( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha512_self_test( int verbose ); + +/* Internal use */ +void mbedtls_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha512.h */ diff --git a/deps/mbedtls/mbedtls/ssl.h b/deps/mbedtls/mbedtls/ssl.h new file mode 100644 index 0000000000..51c1c60d7e --- /dev/null +++ b/deps/mbedtls/mbedtls/ssl.h @@ -0,0 +1,2583 @@ +/** + * \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) +#include "zlib.h" +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif + +/* + * 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 /**< Connection requires a read call. */ +#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 */ + +/* + * 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_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 + +/* + * Maxium 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 + +/* \} 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_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 + +#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; + +/** + * \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 + +/* + * 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) + mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ +#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 ); + void *p_export_keys; /*!< context for key export callback */ +#endif + +#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 */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#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) + unsigned char *psk; /*!< pre-shared key */ + size_t psk_len; /*!< length of the pre-shared key */ + unsigned char *psk_identity; /*!< identity for PSK negotiation */ + size_t psk_identity_len;/*!< length of identity */ +#endif + +#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 +}; + + +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 + + 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_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 */ + 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 +#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 + + 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? */ + + /* + * 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 */ + 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 */ + +#if defined(MBEDTLS_ZLIB_SUPPORT) + unsigned char *compress_buf; /*!< zlib data buffer */ +#endif +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + signed char split_done; /*!< current record already splitted? */ +#endif + + /* + * 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 + +#if defined(MBEDTLS_SSL_ALPN) + const char *alpn_chosen; /*!< negotiated protocol */ +#endif + + /* + * 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 + + /* + * 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 +}; + +#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 Returns the list of ciphersuites supported by the SSL/TLS module. + * + * \return a statically allocated array of ciphersuites, the last + * entry is 0. + */ +const int *mbedtls_ssl_list_ciphersuites( void ); + +/** + * \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 Modifying the conf structure after it has been used in this + * function is unsupported! + * + * \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 verify callback is called for each + * certificate in the chain. For implementation + * information, please see \c x509parse_verify() + * + * \param conf SSL configuration + * \param f_vrfy verification function + * \param p_vrfy verification parameter + */ +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 ); + +/** + * \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 ); +#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 ); +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +/** + * \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 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 ); + +/** + * \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 + * + * \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 ); + +/** + * \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 mutliple 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. + * + * \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 Set the Pre Shared Key (PSK) and the expected identity name + * + * \note This is mainly useful for clients. Servers will usually + * want to use \c mbedtls_ssl_conf_psk_cb() instead. + * + * \note Currently clients can only register one pre-shared key. + * In other words, the servers' identity hint is ignored. + * 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 SSL configuration + * \param psk pointer to the pre-shared key + * \param psk_len pre-shared key length + * \param psk_identity pointer to the pre-shared key identity + * \param psk_identity_len identity key length + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +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 ); + + +/** + * \brief Set the Pre Shared Key (PSK) for the current handshake + * + * \note This should only be called inside the PSK callback, + * ie the function passed to \c mbedtls_ssl_conf_psk_cb(). + * + * \param ssl SSL context + * \param psk pointer to the pre-shared key + * \param psk_len pre-shared key length + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, + const unsigned char *psk, size_t psk_len ); + +/** + * \brief Set the PSK callback (server-side only). + * + * If set, the PSK callback is called for each + * handshake where a PSK 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: (void *parameter, + * mbedtls_ssl_context *ssl, const unsigned char *psk_identity, + * size_t identity_len) + * If a valid PSK identity is found, the callback should use + * \c mbedtls_ssl_set_hs_psk() on the ssl context to set the + * correct PSK and return 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 SSL configuration + * \param f_psk PSK identity function + * \param p_psk PSK identity parameter + */ +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) +/** + * \brief Set the Diffie-Hellman public P and G values, + * read as hexadecimal strings (server-side only) + * (Default: MBEDTLS_DHM_RFC5114_MODP_2048_[PG]) + * + * \param conf SSL configuration + * \param dhm_P Diffie-Hellman-Merkle modulus + * \param dhm_G Diffie-Hellman-Merkle generator + * + * \return 0 if successful + */ +int mbedtls_ssl_conf_dh_param( mbedtls_ssl_config *conf, const char *dhm_P, const char *dhm_G ); + +/** + * \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 the hostname to check against the received server + * certificate. It sets the ServerName TLS extension too, + * if the extension is enabled. + * (client-side only) + * + * \param ssl SSL context + * \param hostname the server hostname + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +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 + * (Default: MBEDTLS_SSL_MAX_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) + * + * \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 ingoing) 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 Return the number of data bytes available to read + * + * \param ssl SSL context + * + * \return how many bytes are available in the read buffer + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the result of the certificate verification + * + * \param ssl SSL context + * + * \return 0 if successful, + * -1 if result is not available (eg because the handshake was + * aborted too early), or + * a combination of BADCERT_xxx and BADCRL_xxx 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) + * + * \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. + * + * \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. + * + * \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 */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Return the peer certificate from the current connection + * + * Note: Can be NULL in case no certificate was sent during + * the handshake. Different calls for the same connection can + * return the same or different pointers for the same + * certificate and even a different certificate altogether. + * The peer cert CAN change in a single connection if + * renegotiation is performed. + * + * \param ssl SSL context + * + * \return the current peer certificate + */ +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. + * + * \warning Currently, peer certificate is lost in the operation. + * + * \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_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 0 if successful, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED (see below), or + * a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should 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. + */ +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 execution of this function. Do not + * call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should 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. + * + * \param ssl SSL context + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * a specific SSL error code. + */ +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. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should 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 number of bytes read, or + * 0 for EOF, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT (see below), or + * another negative error code. + * + * \note If this function returns something other than a positive + * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE or + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT, then the ssl context + * becomes unusable, and you should 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 return 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 beeen reset internally). Either way, you + * should 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! + */ +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 number of bytes actually written (may be less than len), + * or MBEDTLS_ERR_SSL_WANT_WRITE or MBEDTLS_ERR_SSL_WANT_READ, + * or another negative error code. + * + * \note If this function returns something other than a positive + * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE, the ssl context + * becomes unusable, and you should 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 positive value. + * + * \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. + */ +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, then the ssl context + * becomes unusable, and you should 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, then the ssl context + * becomes unusable, and you should 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 relevent 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 + * + * \param session SSL session + */ +void mbedtls_ssl_session_free( mbedtls_ssl_session *session ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl.h */ diff --git a/deps/mbedtls/mbedtls/ssl_cache.h b/deps/mbedtls/mbedtls/ssl_cache.h new file mode 100644 index 0000000000..3734bb7274 --- /dev/null +++ b/deps/mbedtls/mbedtls/ssl_cache.h @@ -0,0 +1,143 @@ +/** + * \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 + +#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) + 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/deps/mbedtls/mbedtls/ssl_ciphersuites.h b/deps/mbedtls/mbedtls/ssl_ciphersuites.h new file mode 100644 index 0000000000..9101d9cc7c --- /dev/null +++ b/deps/mbedtls/mbedtls/ssl_ciphersuites.h @@ -0,0 +1,485 @@ +/** + * \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 + +#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_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 */ + +/* 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 ); + } +} + +#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/deps/mbedtls/mbedtls/ssl_cookie.h b/deps/mbedtls/mbedtls/ssl_cookie.h new file mode 100644 index 0000000000..037e1c3112 --- /dev/null +++ b/deps/mbedtls/mbedtls/ssl_cookie.h @@ -0,0 +1,108 @@ +/** + * \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 + +#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_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/deps/mbedtls/mbedtls/ssl_internal.h b/deps/mbedtls/mbedtls/ssl_internal.h new file mode 100644 index 0000000000..756360b181 --- /dev/null +++ b/deps/mbedtls/mbedtls/ssl_internal.h @@ -0,0 +1,617 @@ +/** + * \file ssl_ticket.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 + +#include "ssl.h" + +#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(__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 */ + +/* 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 */ + +#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_MODE_CBC) +/* 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 +/* 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 + +#define MBEDTLS_SSL_BUFFER_LEN ( MBEDTLS_SSL_MAX_CONTENT_LEN \ + + MBEDTLS_SSL_COMPRESSION_ADD \ + + 29 /* counter + header + IV */ \ + + MBEDTLS_SSL_MAC_ADD \ + + MBEDTLS_SSL_PADDING_ADD \ + ) + +/* + * 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 */ + +/* + * 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 */ +#endif +#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) + unsigned char *psk; /*!< PSK from the callback */ + size_t psk_len; /*!< Length of PSK from callback */ +#endif +#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_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 */ + + unsigned char *hs_msg; /*!< Reassembled handshake message */ + + 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 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 */ +#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) + mbedtls_sha256_context fin_sha256; +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_context fin_sha512; +#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); + int (*tls_prf)(const unsigned char *, size_t, const char *, + const unsigned char *, size_t, + unsigned char *, size_t); + + 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 +}; + +/* + * This structure contains a full set of runtime transform parameters + * either in negotiation or active. + */ +struct mbedtls_ssl_transform +{ + /* + * Session specific crypto layer + */ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + /*!< Chosen cipersuite_info */ + unsigned int keylen; /*!< symmetric key length (bytes) */ + size_t minlen; /*!< min. ciphertext length */ + size_t ivlen; /*!< IV length */ + size_t fixed_ivlen; /*!< Fixed part of IV (AEAD) */ + size_t maclen; /*!< MAC length */ + + unsigned char iv_enc[16]; /*!< IV (encryption) */ + unsigned char iv_dec[16]; /*!< IV (decryption) */ + +#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) */ + + mbedtls_cipher_context_t cipher_ctx_enc; /*!< encryption context */ + mbedtls_cipher_context_t cipher_ctx_dec; /*!< decryption context */ + + /* + * Session specific compression layer + */ +#if defined(MBEDTLS_ZLIB_SUPPORT) + z_stream ctx_deflate; /*!< compression context */ + z_stream ctx_inflate; /*!< decompression context */ +#endif +}; + +#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 handshake SSL handshake context + */ +void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ); + +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_read_record_layer( 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 SSL context to use + * + * \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 ); +int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ); + +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ); +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_hdr_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 13 ); +#else + ((void) ssl); +#endif + return( 5 ); +} + +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 ); +#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 + +/* constant-time buffer comparison */ +static inline int mbedtls_ssl_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 ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_internal.h */ diff --git a/deps/mbedtls/mbedtls/ssl_ticket.h b/deps/mbedtls/mbedtls/ssl_ticket.h new file mode 100644 index 0000000000..7c6bc61bfb --- /dev/null +++ b/deps/mbedtls/mbedtls/ssl_ticket.h @@ -0,0 +1,135 @@ +/** + * \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 + +/* + * 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 +{ + 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_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 mbedlts_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 mbedlts_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/deps/mbedtls/mbedtls/threading.h b/deps/mbedtls/mbedtls/threading.h new file mode 100644 index 0000000000..b0c34ecc74 --- /dev/null +++ b/deps/mbedtls/mbedtls/threading.h @@ -0,0 +1,106 @@ +/** + * \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 + +#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 +{ + 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 + */ +extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex; +extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex; +#endif /* MBEDTLS_THREADING_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* threading.h */ diff --git a/deps/mbedtls/mbedtls/timing.h b/deps/mbedtls/mbedtls/timing.h new file mode 100644 index 0000000000..ae7a713e7a --- /dev/null +++ b/deps/mbedtls/mbedtls/timing.h @@ -0,0 +1,141 @@ +/** + * \file timing.h + * + * \brief 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) + */ +#ifndef MBEDTLS_TIMING_H +#define MBEDTLS_TIMING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if !defined(MBEDTLS_TIMING_ALT) +// Regular implementation +// + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief timer structure + */ +struct mbedtls_timing_hr_time +{ + unsigned char opaque[32]; +}; + +/** + * \brief Context for mbedtls_timing_set/get_delay() + */ +typedef struct +{ + struct mbedtls_timing_hr_time timer; + uint32_t int_ms; + uint32_t fin_ms; +} mbedtls_timing_delay_context; + +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. + */ +unsigned long mbedtls_timing_hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset if set to 1, the timer is restarted + */ +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 + * + * \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. + * \param fin_ms Second (final) delay in milliseconds. + * Pass 0 to cancel the current delay. + */ +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 ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_TIMING_ALT */ +#include "timing_alt.h" +#endif /* MBEDTLS_TIMING_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +#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/deps/mbedtls/mbedtls/version.h b/deps/mbedtls/mbedtls/version.h new file mode 100644 index 0000000000..45486a995c --- /dev/null +++ b/deps/mbedtls/mbedtls/version.h @@ -0,0 +1,111 @@ +/** + * \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 5 +#define MBEDTLS_VERSION_PATCH 1 + +/** + * The single version number has the following structure: + * MMNNPP00 + * Major version | Minor version | Patch version + */ +#define MBEDTLS_VERSION_NUMBER 0x02050100 +#define MBEDTLS_VERSION_STRING "2.5.1" +#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.5.1" + +#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/deps/mbedtls/mbedtls/x509.h b/deps/mbedtls/mbedtls/x509.h new file mode 100644 index 0000000000..f219bf128a --- /dev/null +++ b/deps/mbedtls/mbedtls/x509.h @@ -0,0 +1,331 @@ +/** + * \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. */ +/* \} 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 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. + */ +#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define MBEDTLS_X509_EXT_KEY_USAGE (1 << 2) +#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES (1 << 3) +#define MBEDTLS_X509_EXT_POLICY_MAPPINGS (1 << 4) +#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME (1 << 5) /* Supported (DNS) */ +#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME (1 << 6) +#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS (1 << 8) /* Supported */ +#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS (1 << 9) +#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS (1 << 10) +#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE (1 << 11) +#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define MBEDTLS_X509_EXT_FRESHEST_CRL (1 << 14) + +#define MBEDTLS_X509_EXT_NS_CERT_TYPE (1 << 16) + +/* + * 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 time mbedtls_x509_time to check + * + * \return 1 if the given time is in the past or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_past( const mbedtls_x509_time *time ); + +/** + * \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 time mbedtls_x509_time to check + * + * \return 1 if the given time is in the future or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_future( const mbedtls_x509_time *time ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_x509_self_test( int verbose ); + +/* + * 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 *time ); +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/deps/mbedtls/mbedtls/x509_crl.h b/deps/mbedtls/mbedtls/x509_crl.h new file mode 100644 index 0000000000..7988439900 --- /dev/null +++ b/deps/mbedtls/mbedtls/x509_crl.h @@ -0,0 +1,173 @@ +/** + * \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 Mutliple 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 Mutliple 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/deps/mbedtls/mbedtls/x509_crt.h b/deps/mbedtls/mbedtls/x509_crt.h new file mode 100644 index 0000000000..383e484f71 --- /dev/null +++ b/deps/mbedtls/mbedtls/x509_crt.h @@ -0,0 +1,654 @@ +/** + * \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 +{ + 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_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 Subject Alternative Names (Only dNSName supported). */ + + 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; + +/** + * 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 +{ + 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; + +#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 chained list. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate DER data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ); + +/** + * \brief Parse 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 buf buffer holding the certificate data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \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( 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 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 the certificate signature + * + * 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 but a fatal error. + * + * \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. + * + * \param crt a certificate (chain) to be verified + * \param trust_ca the list of trusted CAs + * \param ca_crl the list of CRLs for trusted CAs (see note above) + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or MBEDTLS_ERR_X509_CERT_VERIFY_FAILED + * in which case *flags will have one or more + * MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX flags + * set, + * or another error 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 the certificate signature according to 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 a 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 security profile for verification + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or MBEDTLS_ERR_X509_CERT_VERIFY_FAILED + * in which case *flags will have one or more + * MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX flags + * set, + * or another error 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 ); + +#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 extentedJeyUsage. + * + * \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 ); +#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/deps/mbedtls/mbedtls/x509_csr.h b/deps/mbedtls/mbedtls/x509_csr.h new file mode 100644 index 0000000000..fe9843cb54 --- /dev/null +++ b/deps/mbedtls/mbedtls/x509_csr.h @@ -0,0 +1,298 @@ +/** + * \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 + */ +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/deps/mbedtls/mbedtls/xtea.h b/deps/mbedtls/mbedtls/xtea.h new file mode 100644 index 0000000000..b073f84efa --- /dev/null +++ b/deps/mbedtls/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. */ + +#if !defined(MBEDTLS_XTEA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief XTEA context structure + */ +typedef struct +{ + uint32_t k[4]; /*!< key */ +} +mbedtls_xtea_context; + +/** + * \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 */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_XTEA_ALT */ +#include "xtea_alt.h" +#endif /* MBEDTLS_XTEA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_xtea_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* xtea.h */ diff --git a/deps/mbedtls/md.c b/deps/mbedtls/md.c new file mode 100644 index 0000000000..eda98f6361 --- /dev/null +++ b/deps/mbedtls/md.c @@ -0,0 +1,471 @@ +/** + * \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" + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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_zeroize( ctx->hmac_ctx, 2 * ctx->md_info->block_size ); + mbedtls_free( ctx->hmac_ctx ); + } + + mbedtls_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 ); + + ctx->md_info->starts_func( ctx->md_ctx ); + + return( 0 ); +} + +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 ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +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 ); + + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +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 ); + + md_info->digest_func( input, ilen, output ); + + return( 0 ); +} + +#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; + + md_info->starts_func( ctx.md_ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + md_info->update_func( ctx.md_ctx, buf, n ); + + if( ferror( f ) != 0 ) + { + ret = MBEDTLS_ERR_MD_FILE_IO_ERROR; + goto cleanup; + } + + md_info->finish_func( ctx.md_ctx, output ); + +cleanup: + 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 ) +{ + 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 ) + { + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, key, keylen ); + ctx->md_info->finish_func( ctx->md_ctx, sum ); + + 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] ); + } + + mbedtls_zeroize( sum, sizeof( sum ) ); + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +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 ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + 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; + + ctx->md_info->finish_func( ctx->md_ctx, tmp ); + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, opad, ctx->md_info->block_size ); + ctx->md_info->update_func( ctx->md_ctx, tmp, ctx->md_info->size ); + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ) +{ + 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; + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +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 ) + return( ret ); + + mbedtls_md_hmac_starts( &ctx, key, keylen ); + mbedtls_md_hmac_update( &ctx, input, ilen ); + mbedtls_md_hmac_finish( &ctx, output ); + + mbedtls_md_free( &ctx ); + + return( 0 ); +} + +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 ); + + ctx->md_info->process_func( ctx->md_ctx, data ); + + return( 0 ); +} + +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/deps/mbedtls/md2.c b/deps/mbedtls/md2.c new file mode 100644 index 0000000000..95cbcce658 --- /dev/null +++ b/deps/mbedtls/md2.c @@ -0,0 +1,288 @@ +/* + * 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 + +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +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_zeroize( ctx, sizeof( mbedtls_md2_context ) ); +} + +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ) +{ + *dst = *src; +} + +/* + * MD2 context setup + */ +void mbedtls_md2_starts( mbedtls_md2_context *ctx ) +{ + memset( ctx->cksum, 0, 16 ); + memset( ctx->state, 0, 46 ); + memset( ctx->buffer, 0, 16 ); + ctx->left = 0; +} + +#if !defined(MBEDTLS_MD2_PROCESS_ALT) +void mbedtls_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]; + } +} +#endif /* !MBEDTLS_MD2_PROCESS_ALT */ + +/* + * MD2 process buffer + */ +void mbedtls_md2_update( mbedtls_md2_context *ctx, const unsigned char *input, size_t ilen ) +{ + 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; + mbedtls_md2_process( ctx ); + } + } +} + +/* + * MD2 final digest + */ +void mbedtls_md2_finish( mbedtls_md2_context *ctx, unsigned char output[16] ) +{ + size_t i; + unsigned char x; + + x = (unsigned char)( 16 - ctx->left ); + + for( i = ctx->left; i < 16; i++ ) + ctx->buffer[i] = x; + + mbedtls_md2_process( ctx ); + + memcpy( ctx->buffer, ctx->cksum, 16 ); + mbedtls_md2_process( ctx ); + + memcpy( output, ctx->state, 16 ); +} + +#endif /* !MBEDTLS_MD2_ALT */ + +/* + * output = MD2( input buffer ) + */ +void mbedtls_md2( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md2_context ctx; + + mbedtls_md2_init( &ctx ); + mbedtls_md2_starts( &ctx ); + mbedtls_md2_update( &ctx, input, ilen ); + mbedtls_md2_finish( &ctx, output ); + mbedtls_md2_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1319 test vectors + */ +static const char md2_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +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; + unsigned char md2sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD2 test #%d: ", i + 1 ); + + mbedtls_md2( (unsigned char *) md2_test_str[i], + strlen( md2_test_str[i] ), md2sum ); + + if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD2_C */ diff --git a/deps/mbedtls/md4.c b/deps/mbedtls/md4.c new file mode 100644 index 0000000000..11a77e3ae4 --- /dev/null +++ b/deps/mbedtls/md4.c @@ -0,0 +1,384 @@ +/* + * 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 + +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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_zeroize( ctx, sizeof( mbedtls_md4_context ) ); +} + +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ) +{ + *dst = *src; +} + +/* + * MD4 context setup + */ +void mbedtls_md4_starts( 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; +} + +#if !defined(MBEDTLS_MD4_PROCESS_ALT) +void mbedtls_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) { a += F(b,c,d) + x; a = S(a,s); } + + 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) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } + + 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) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } + + 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; +} +#endif /* !MBEDTLS_MD4_PROCESS_ALT */ + +/* + * MD4 process buffer + */ +void mbedtls_md4_update( mbedtls_md4_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + 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 ); + mbedtls_md4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_md4_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +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 + */ +void mbedtls_md4_finish( mbedtls_md4_context *ctx, unsigned char output[16] ) +{ + 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 ); + + mbedtls_md4_update( ctx, (unsigned char *) md4_padding, padn ); + mbedtls_md4_update( ctx, msglen, 8 ); + + 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 ); +} + +#endif /* !MBEDTLS_MD4_ALT */ + +/* + * output = MD4( input buffer ) + */ +void mbedtls_md4( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md4_context ctx; + + mbedtls_md4_init( &ctx ); + mbedtls_md4_starts( &ctx ); + mbedtls_md4_update( &ctx, input, ilen ); + mbedtls_md4_finish( &ctx, output ); + mbedtls_md4_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1320 test vectors + */ +static const char md4_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +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; + unsigned char md4sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD4 test #%d: ", i + 1 ); + + mbedtls_md4( (unsigned char *) md4_test_str[i], + strlen( md4_test_str[i] ), md4sum ); + + if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD4_C */ diff --git a/deps/mbedtls/md5.c b/deps/mbedtls/md5.c new file mode 100644 index 0000000000..5d972dc9dd --- /dev/null +++ b/deps/mbedtls/md5.c @@ -0,0 +1,404 @@ +/* + * 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 + +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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_zeroize( ctx, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +void mbedtls_md5_starts( 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; +} + +#if !defined(MBEDTLS_MD5_PROCESS_ALT) +void mbedtls_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) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + 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; +} +#endif /* !MBEDTLS_MD5_PROCESS_ALT */ + +/* + * MD5 process buffer + */ +void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + 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 ); + mbedtls_md5_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_md5_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const unsigned char md5_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 +}; + +/* + * MD5 final digest + */ +void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ) +{ + 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 ); + + mbedtls_md5_update( ctx, md5_padding, padn ); + mbedtls_md5_update( ctx, msglen, 8 ); + + 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 ); +} + +#endif /* !MBEDTLS_MD5_ALT */ + +/* + * output = MD5( input buffer ) + */ +void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md5_context ctx; + + mbedtls_md5_init( &ctx ); + mbedtls_md5_starts( &ctx ); + mbedtls_md5_update( &ctx, input, ilen ); + mbedtls_md5_finish( &ctx, output ); + mbedtls_md5_free( &ctx ); +} + +#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 int 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; + unsigned char md5sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD5 test #%d: ", i + 1 ); + + mbedtls_md5( md5_test_buf[i], md5_test_buflen[i], md5sum ); + + if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD5_C */ diff --git a/deps/mbedtls/md_wrap.c b/deps/mbedtls/md_wrap.c new file mode 100644 index 0000000000..2cfcae200e --- /dev/null +++ b/deps/mbedtls/md_wrap.c @@ -0,0 +1,575 @@ +/** + * \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 void md2_starts_wrap( void *ctx ) +{ + mbedtls_md2_starts( (mbedtls_md2_context *) ctx ); +} + +static void md2_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md2_update( (mbedtls_md2_context *) ctx, input, ilen ); +} + +static void md2_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md2_finish( (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 void md2_process_wrap( void *ctx, const unsigned char *data ) +{ + ((void) data); + + mbedtls_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, + md2_ctx_alloc, + md2_ctx_free, + md2_clone_wrap, + md2_process_wrap, +}; + +#endif /* MBEDTLS_MD2_C */ + +#if defined(MBEDTLS_MD4_C) + +static void md4_starts_wrap( void *ctx ) +{ + mbedtls_md4_starts( (mbedtls_md4_context *) ctx ); +} + +static void md4_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md4_update( (mbedtls_md4_context *) ctx, input, ilen ); +} + +static void md4_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md4_finish( (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 void md4_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_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, + md4_ctx_alloc, + md4_ctx_free, + md4_clone_wrap, + md4_process_wrap, +}; + +#endif /* MBEDTLS_MD4_C */ + +#if defined(MBEDTLS_MD5_C) + +static void md5_starts_wrap( void *ctx ) +{ + mbedtls_md5_starts( (mbedtls_md5_context *) ctx ); +} + +static void md5_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md5_update( (mbedtls_md5_context *) ctx, input, ilen ); +} + +static void md5_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md5_finish( (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 void md5_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_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, + md5_ctx_alloc, + md5_ctx_free, + md5_clone_wrap, + md5_process_wrap, +}; + +#endif /* MBEDTLS_MD5_C */ + +#if defined(MBEDTLS_RIPEMD160_C) + +static void ripemd160_starts_wrap( void *ctx ) +{ + mbedtls_ripemd160_starts( (mbedtls_ripemd160_context *) ctx ); +} + +static void ripemd160_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_ripemd160_update( (mbedtls_ripemd160_context *) ctx, input, ilen ); +} + +static void ripemd160_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_ripemd160_finish( (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 void ripemd160_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_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, + ripemd160_ctx_alloc, + ripemd160_ctx_free, + ripemd160_clone_wrap, + ripemd160_process_wrap, +}; + +#endif /* MBEDTLS_RIPEMD160_C */ + +#if defined(MBEDTLS_SHA1_C) + +static void sha1_starts_wrap( void *ctx ) +{ + mbedtls_sha1_starts( (mbedtls_sha1_context *) ctx ); +} + +static void sha1_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha1_update( (mbedtls_sha1_context *) ctx, input, ilen ); +} + +static void sha1_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha1_finish( (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 void sha1_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_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, + 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 void sha224_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 1 ); +} + +static void sha224_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha256_update( (mbedtls_sha256_context *) ctx, input, ilen ); +} + +static void sha224_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha256_finish( (mbedtls_sha256_context *) ctx, output ); +} + +static void sha224_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( 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 void sha224_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_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 void sha256_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 0 ); +} + +static void sha256_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( 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 void sha384_starts_wrap( void *ctx ) +{ + mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 1 ); +} + +static void sha384_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha512_update( (mbedtls_sha512_context *) ctx, input, ilen ); +} + +static void sha384_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha512_finish( (mbedtls_sha512_context *) ctx, output ); +} + +static void sha384_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha512( 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 void sha384_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_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 void sha512_starts_wrap( void *ctx ) +{ + mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 0 ); +} + +static void sha512_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha512( 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/deps/mbedtls/memory_buffer_alloc.c b/deps/mbedtls/memory_buffer_alloc.c new file mode 100644 index 0000000000..545d5a2c32 --- /dev/null +++ b/deps/mbedtls/memory_buffer_alloc.c @@ -0,0 +1,745 @@ +/* + * 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 + +#if defined(MBEDTLS_MEMORY_BACKTRACE) +#include +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#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() +{ + 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() +{ + memory_header *prv = heap.first, *cur = heap.first->next; + + if( verify_header( heap.first ) != 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 ); + } + + 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 && len / n != size ) + 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() +{ + return verify_chain(); +} + +#if defined(MBEDTLS_MEMORY_DEBUG) +void mbedtls_memory_buffer_alloc_status() +{ + 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) ); + memset( buf, 0, len ); + +#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( (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; + } + + 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() +{ +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &heap.mutex ); +#endif + mbedtls_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( ) +{ + 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/deps/mbedtls/net_sockets.c b/deps/mbedtls/net_sockets.c new file mode 100644 index 0000000000..7877e94362 --- /dev/null +++ b/deps/mbedtls/net_sockets.c @@ -0,0 +1,616 @@ +/* + * 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) + */ + +/* Modifications Copyright (C) 2017 - Brad Parker + * - added socket functions for PS3/Vita/WiiU + */ + +#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) +#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) + +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +/* Enables getaddrinfo() & Co */ +#define _WIN32_WINNT 0x0501 +#include + +#include +#include + +#if defined(__CELLOS_LV2__) || defined(WIIU) +#define close(fd) socketclose(fd) +#elif defined(VITA) +#define close(fd) sceNetSocketClose(fd) +#elif 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 + +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* Some MS functions want int and MSVC warns if we pass size_t, + * but the standard fucntions 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 ) +{ + /* + * Never return 'WOULD BLOCK' on a non-blocking socket + */ + if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK ) + return( 0 ); + + switch( errno ) + { +#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(__CELLOS_LV2__) || defined(VITA) || defined(WIIU) + int i = 0; + setsockopt(ctx->fd, SOL_SOCKET, SO_NBIO, &i, sizeof(int)); + return 1; +#elif ( 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(__CELLOS_LV2__) || defined(VITA) || defined(WIIU) + int i = 1; + setsockopt(ctx->fd, SOL_SOCKET, SO_NBIO, &i, sizeof(int)); + return 1; +#elif ( 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 +} + +/* + * 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; + +#if defined(__CELLOS_LV2__) + ret = socketselect(fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv); +#elif defined(VITA) + extern int retro_epoll_fd; + SceNetEpollEvent ev = {0}; + + ev.events = SCE_NET_EPOLLIN | SCE_NET_EPOLLHUP; + ev.data.fd = fd + 1; + + if((sceNetEpollControl(retro_epoll_fd, SCE_NET_EPOLL_CTL_ADD, fd + 1, &ev))) + { + int ret = sceNetEpollWait(retro_epoll_fd, &ev, 1, 0); + sceNetEpollControl(retro_epoll_fd, SCE_NET_EPOLL_CTL_DEL, fd + 1, NULL); +#else + ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); +#endif + /* 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/deps/mbedtls/oid.c b/deps/mbedtls/oid.c new file mode 100644 index 0000000000..f13826ed74 --- /dev/null +++ b/deps/mbedtls/oid.c @@ -0,0 +1,710 @@ +/** + * \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 + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#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 ); \ +} + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/* + * 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_X509_EXT_BASIC_CONSTRAINTS, + }, + { + { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, + MBEDTLS_X509_EXT_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, + MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, + MBEDTLS_X509_EXT_SUBJECT_ALT_NAME, + }, + { + { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, + MBEDTLS_X509_EXT_NS_CERT_TYPE, + }, + { + { 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" }, + { 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) +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + +#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 */ + { + { 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) +#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/deps/mbedtls/padlock.c b/deps/mbedtls/padlock.c new file mode 100644 index 0000000000..b85ff9cd2c --- /dev/null +++ b/deps/mbedtls/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/deps/mbedtls/pem.c b/deps/mbedtls/pem.c new file mode 100644 index 0000000000..8dd86a4ac9 --- /dev/null +++ b/deps/mbedtls/pem.c @@ -0,0 +1,449 @@ +/* + * 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 + +#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) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +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 void 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; + + mbedtls_md5_init( &md5_ctx ); + + /* + * key[ 0..15] = MD5(pwd || IV) + */ + mbedtls_md5_starts( &md5_ctx ); + mbedtls_md5_update( &md5_ctx, pwd, pwdlen ); + mbedtls_md5_update( &md5_ctx, iv, 8 ); + mbedtls_md5_finish( &md5_ctx, md5sum ); + + if( keylen <= 16 ) + { + memcpy( key, md5sum, keylen ); + + mbedtls_md5_free( &md5_ctx ); + mbedtls_zeroize( md5sum, 16 ); + return; + } + + memcpy( key, md5sum, 16 ); + + /* + * key[16..23] = MD5(key[ 0..15] || pwd || IV]) + */ + mbedtls_md5_starts( &md5_ctx ); + mbedtls_md5_update( &md5_ctx, md5sum, 16 ); + mbedtls_md5_update( &md5_ctx, pwd, pwdlen ); + mbedtls_md5_update( &md5_ctx, iv, 8 ); + mbedtls_md5_finish( &md5_ctx, md5sum ); + + use_len = 16; + if( keylen < 32 ) + use_len = keylen - 16; + + memcpy( key + 16, md5sum, use_len ); + + mbedtls_md5_free( &md5_ctx ); + mbedtls_zeroize( md5sum, 16 ); +} + +#if defined(MBEDTLS_DES_C) +/* + * Decrypt with DES-CBC, using PBKDF1 for key derivation + */ +static void 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]; + + mbedtls_des_init( &des_ctx ); + + pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ); + + mbedtls_des_setkey_dec( &des_ctx, des_key ); + mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen, + des_iv, buf, buf ); + + mbedtls_des_free( &des_ctx ); + mbedtls_zeroize( des_key, 8 ); +} + +/* + * Decrypt with 3DES-CBC, using PBKDF1 for key derivation + */ +static void 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]; + + mbedtls_des3_init( &des3_ctx ); + + pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ); + + mbedtls_des3_set3key_dec( &des3_ctx, des3_key ); + mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen, + des3_iv, buf, buf ); + + mbedtls_des3_free( &des3_ctx ); + mbedtls_zeroize( des3_key, 24 ); +} +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* + * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation + */ +static void 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]; + + mbedtls_aes_init( &aes_ctx ); + + pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ); + + mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ); + mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen, + aes_iv, buf, buf ); + + mbedtls_aes_free( &aes_ctx ); + mbedtls_zeroize( aes_key, keylen ); +} +#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_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_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); + } + +#if defined(MBEDTLS_DES_C) + if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC ) + pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_DES_CBC ) + 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 ) + pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC ) + pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC ) + pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_AES_C */ + + /* + * 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 heurisitic to try detecting password mismatchs. + */ + if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) + { + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); + } +#else + 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 ) +{ + mbedtls_free( ctx->buf ); + mbedtls_free( ctx->info ); + + mbedtls_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, *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( ( 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/deps/mbedtls/pk.c b/deps/mbedtls/pk.c new file mode 100644 index 0000000000..8d13bc5ce3 --- /dev/null +++ b/deps/mbedtls/pk.c @@ -0,0 +1,383 @@ +/* + * 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/bignum.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 + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialise a mbedtls_pk_context + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL ) + return; + + 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 || ctx->pk_info == NULL ) + return; + + ctx->pk_info->ctx_free_func( ctx->pk_ctx ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_pk_context ) ); +} + +/* + * 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 ) +{ + if( ctx == NULL || 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_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; + + if( ctx == 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; + + 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 ) +{ + /* null or NONE context can't do anything */ + 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 ); +} + +/* + * 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 ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + 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 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 ) +{ + if( ctx == NULL || 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 defined(MBEDTLS_HAVE_INT64) + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + 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 + */ +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 ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + 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 ) ); +} + +/* + * 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 ) +{ + if( ctx == NULL || 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 ) +{ + if( ctx == NULL || 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 ) +{ + if( pub == NULL || pub->pk_info == NULL || + prv == NULL || prv->pk_info == NULL || + prv->pk_info->check_pair_func == NULL ) + { + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + } + + 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 ) +{ + 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 ) +{ + if( ctx == NULL || 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 ); +} + +#endif /* MBEDTLS_PK_C */ diff --git a/deps/mbedtls/pk_wrap.c b/deps/mbedtls/pk_wrap.c new file mode 100644 index 0000000000..db6274cbf9 --- /dev/null +++ b/deps/mbedtls/pk_wrap.c @@ -0,0 +1,513 @@ +/* + * 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 "mbedtls/bignum.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_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#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 ) +{ + return( 8 * ((const mbedtls_rsa_context *) ctx)->len ); +} + +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; + +#if defined(MBEDTLS_HAVE_INT64) + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + if( sig_len < ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_rsa_pkcs1_verify( (mbedtls_rsa_context *) ctx, NULL, NULL, + MBEDTLS_RSA_PUBLIC, md_alg, + (unsigned int) hash_len, hash, sig ) ) != 0 ) + return( ret ); + + if( sig_len > ((mbedtls_rsa_context *) ctx)->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 ) +{ +#if defined(MBEDTLS_HAVE_INT64) + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + *sig_len = ((mbedtls_rsa_context *) ctx)->len; + + return( mbedtls_rsa_pkcs1_sign( (mbedtls_rsa_context *) ctx, 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 ) +{ + if( ilen != ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( mbedtls_rsa_pkcs1_decrypt( (mbedtls_rsa_context *) ctx, 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 ) +{ + *olen = ((mbedtls_rsa_context *) ctx)->len; + + if( *olen > osize ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + return( mbedtls_rsa_pkcs1_encrypt( (mbedtls_rsa_context *) ctx, + 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, + rsa_decrypt_wrap, + rsa_encrypt_wrap, + rsa_check_pair_wrap, + rsa_alloc_wrap, + rsa_free_wrap, + 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 ); +} + +#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, +#else + NULL, + NULL, +#endif + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, + eckey_free_wrap, + 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, + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, /* Same underlying key structure */ + eckey_free_wrap, /* Same underlying key structure */ + 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 ); +} + +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 ); +} + +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 ) ); +} + +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 ); +} + +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, + NULL, + NULL, + eckey_check_pair, /* Compatible key structures */ + ecdsa_alloc_wrap, + ecdsa_free_wrap, + 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 defined(MBEDTLS_HAVE_INT64) + if( UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + *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_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, + 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, + NULL, +}; + +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +#endif /* MBEDTLS_PK_C */ diff --git a/deps/mbedtls/pkcs11.c b/deps/mbedtls/pkcs11.c new file mode 100644 index 0000000000..0ea64252ee --- /dev/null +++ b/deps/mbedtls/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/deps/mbedtls/pkcs12.c b/deps/mbedtls/pkcs12.c new file mode 100644 index 0000000000..c603a13577 --- /dev/null +++ b/deps/mbedtls/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 + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +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_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_zeroize( key, sizeof( key ) ); + mbedtls_zeroize( iv, sizeof( iv ) ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} + +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_zeroize( salt_block, sizeof( salt_block ) ); + mbedtls_zeroize( pwd_block, sizeof( pwd_block ) ); + mbedtls_zeroize( hash_block, sizeof( hash_block ) ); + mbedtls_zeroize( hash_output, sizeof( hash_output ) ); + + mbedtls_md_free( &md_ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_PKCS12_C */ diff --git a/deps/mbedtls/pkcs5.c b/deps/mbedtls/pkcs5.c new file mode 100644 index 0000000000..e28d5a8473 --- /dev/null +++ b/deps/mbedtls/pkcs5.c @@ -0,0 +1,406 @@ +/** + * \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" +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +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_CMP( MBEDTLS_OID_HMAC_SHA1, &prf_alg_oid ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + *md_type = MBEDTLS_MD_SHA1; + + 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 ); +} + +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( iteration_count > 0xFFFFFFFF ) + return( MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA ); + + 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[MAX_TESTS] = + { 8, 8, 8, 24, 9 }; + +static const unsigned char password[MAX_TESTS][32] = +{ + "password", + "password", + "password", + "passwordPASSWORDpassword", + "pass\0word", +}; + +static const size_t slen[MAX_TESTS] = + { 4, 4, 4, 36, 5 }; + +static const unsigned char salt[MAX_TESTS][40] = +{ + "salt", + "salt", + "salt", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + "sa\0lt", +}; + +static const uint32_t it_cnt[MAX_TESTS] = + { 1, 2, 4096, 4096, 4096 }; + +static const uint32_t key_len[MAX_TESTS] = + { 20, 20, 20, 25, 16 }; + +static const unsigned char result_key[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[i], plen[i], salt[i], + slen[i], it_cnt[i], key_len[i], key ); + if( ret != 0 || + memcmp( result_key[i], key, key_len[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/deps/mbedtls/pkparse.c b/deps/mbedtls/pkparse.c new file mode 100644 index 0000000000..efdf437466 --- /dev/null +++ b/deps/mbedtls/pkparse.c @@ -0,0 +1,1293 @@ +/* + * 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 + +#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 + +#if defined(MBEDTLS_FS_IO) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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; + + 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_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; + + 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_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; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_pk_parse_public_key( ctx, buf, n ); + + mbedtls_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; + + /* 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 ); + + if( ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->N ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->E ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + + rsa->len = mbedtls_mpi_size( &rsa->N ); + + 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; + + 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; + size_t len; + unsigned char *p, *end; + + 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, &rsa->ver ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( rsa->ver != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + } + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->N ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->E ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->D ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->P ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->Q ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 ) + { + mbedtls_rsa_free( rsa ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + rsa->len = mbedtls_mpi_size( &rsa->N ); + + if( p != end ) + { + mbedtls_rsa_free( rsa ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( ( ret = mbedtls_rsa_check_privkey( rsa ) ) != 0 ) + { + mbedtls_rsa_free( rsa ); + return( ret ); + } + + return( 0 ); +} +#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 ); + } + + /* + * 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 + */ +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 PrivatKeyInfo 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 + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) +static int pk_parse_key_pkcs8_encrypted_der( + mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret, decrypted = 0; + size_t len; + unsigned char buf[2048]; + 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 + + memset( buf, 0, sizeof( buf ) ); + + p = (unsigned char *) key; + end = p + keylen; + + if( pwdlen == 0 ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + + /* + * This function parses the EncryptedPrivatKeyInfo 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 ); + + if( len > sizeof( buf ) ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* + * Decrypt EncryptedData with appropriate PDE + */ +#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; + + mbedtls_pem_init( &pem ); + +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || 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 ) + { + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + 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( keylen == 0 || 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 ) + { + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + 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( keylen == 0 || 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( keylen == 0 || 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) ret); + ((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) + if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, + pwd, pwdlen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( 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 ); + +#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( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), key, keylen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); +#endif /* MBEDTLS_ECP_C */ + + 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_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || 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 + */ + key = pem.buf; + keylen = pem.buflen; + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } +#endif /* MBEDTLS_PEM_PARSE_C */ + p = (unsigned char *) key; + + ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_free( &pem ); +#endif + + return( ret ); +} + +#endif /* MBEDTLS_PK_PARSE_C */ diff --git a/deps/mbedtls/pkwrite.c b/deps/mbedtls/pkwrite.c new file mode 100644 index 0000000000..83b798c119 --- /dev/null +++ b/deps/mbedtls/pkwrite.c @@ -0,0 +1,439 @@ +/* + * 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 + +#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_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#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_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( p, start, &rsa->E ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( p, start, &rsa->N ) ); + + 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; + +#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 + 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; + const char *oid; + + 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 ) ); + + if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ), + &oid, &oid_len ) ) != 0 ) + { + return( ret ); + } + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) ); + } +#endif + + 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 = buf + size; + size_t len = 0; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *key ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->QP ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->DQ ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->DP ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->Q ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->P ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->D ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->E ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->N ) ); + 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; + + 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; + + 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/deps/mbedtls/platform.c b/deps/mbedtls/platform.c new file mode 100644 index 0000000000..af3b2f15ec --- /dev/null +++ b/deps/mbedtls/platform.c @@ -0,0 +1,327 @@ +/* + * 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" + +#if defined(MBEDTLS_PLATFORM_MEMORY) +#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 */ + +void * (*mbedtls_calloc)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC; +void (*mbedtls_free)( void * ) = MBEDTLS_PLATFORM_STD_FREE; + +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ) +{ + mbedtls_calloc = calloc_func; + mbedtls_free = free_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_MEMORY */ + +#if defined(_WIN32) +#include +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ) +{ + int ret; + va_list argp; + + /* Avoid calling the invalid parameter handler by checking ourselves */ + if( s == NULL || n == 0 || fmt == NULL ) + return( -1 ); + + va_start( argp, fmt ); +#if defined(_TRUNCATE) + ret = _vsnprintf_s( s, n, _TRUNCATE, fmt, argp ); +#else + ret = _vsnprintf( s, n, fmt, argp ); + if( ret < 0 || (size_t) ret == n ) + { + s[n-1] = '\0'; + ret = -1; + } +#endif + 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_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 ); + 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/deps/mbedtls/ripemd160.c b/deps/mbedtls/ripemd160.c new file mode 100644 index 0000000000..cdb0a63c0f --- /dev/null +++ b/deps/mbedtls/ripemd160.c @@ -0,0 +1,467 @@ +/* + * 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 + +#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 */ + +/* + * 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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +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_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 + */ +void mbedtls_ripemd160_starts( 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; +} + +#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) +/* + * Process one block + */ +void mbedtls_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 ) \ + a += f( b, c, d ) + X[r] + k; \ + a = S( a, s ) + e; \ + c = S( c, 10 ); + +#define P2( a, b, c, d, e, r, s, rp, sp ) \ + 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 ); + +#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; +} +#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ + +/* + * RIPEMD-160 process buffer + */ +void mbedtls_ripemd160_update( mbedtls_ripemd160_context *ctx, + const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + 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 ); + mbedtls_ripemd160_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_ripemd160_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +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 + */ +void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx, unsigned char output[20] ) +{ + 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 ); + + mbedtls_ripemd160_update( ctx, ripemd160_padding, padn ); + mbedtls_ripemd160_update( ctx, msglen, 8 ); + + 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 ); +} + +/* + * output = RIPEMD-160( input buffer ) + */ +void mbedtls_ripemd160( const unsigned char *input, size_t ilen, + unsigned char output[20] ) +{ + mbedtls_ripemd160_context ctx; + + mbedtls_ripemd160_init( &ctx ); + mbedtls_ripemd160_starts( &ctx ); + mbedtls_ripemd160_update( &ctx, input, ilen ); + mbedtls_ripemd160_finish( &ctx, output ); + mbedtls_ripemd160_free( &ctx ); +} + +#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 +#define KEYS 2 +static const char *ripemd160_test_input[TESTS] = +{ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", +}; + +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; + 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 ); + + mbedtls_ripemd160( (const unsigned char *) ripemd160_test_input[i], + strlen( ripemd160_test_input[i] ), + output ); + + if( memcmp( output, ripemd160_test_md[i], 20 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RIPEMD160_C */ diff --git a/deps/mbedtls/rsa.c b/deps/mbedtls/rsa.c new file mode 100644 index 0000000000..bdd2538c3a --- /dev/null +++ b/deps/mbedtls/rsa.c @@ -0,0 +1,1872 @@ +/* + * 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/oid.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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * Initialize an RSA context + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id ) +{ + 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 ) +{ + ctx->padding = padding; + ctx->hash_id = hash_id; +} + +#if defined(MBEDTLS_GENPRIME) + +/* + * Generate an RSA keypair + */ +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 P1, Q1, H, G; + + if( f_rng == NULL || nbits < 128 || exponent < 3 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( nbits % 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &H ); mbedtls_mpi_init( &G ); + + /* + * find primes P and Q with Q < P so that: + * GCD( E, (P-1)*(Q-1) ) == 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) ); + + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, 0, + f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, 0, + f_rng, p_rng ) ); + + if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) + continue; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + if( mbedtls_mpi_bitlen( &ctx->N ) != nbits ) + continue; + + if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) + mbedtls_mpi_swap( &ctx->P, &ctx->Q ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + } + while( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ); + + /* + * D = E^-1 mod ((P-1)*(Q-1)) + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); + + ctx->len = ( mbedtls_mpi_bitlen( &ctx->N ) + 7 ) >> 3; + +cleanup: + + mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &G ); + + 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 ) +{ + if( !ctx->N.p || !ctx->E.p ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( ( ctx->N.p[0] & 1 ) == 0 || + ( ctx->E.p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( mbedtls_mpi_bitlen( &ctx->N ) < 128 || + mbedtls_mpi_bitlen( &ctx->N ) > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( 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 a private RSA key + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) +{ + int ret; + mbedtls_mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; + + if( ( ret = mbedtls_rsa_check_pubkey( ctx ) ) != 0 ) + return( ret ); + + if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + mbedtls_mpi_init( &PQ ); mbedtls_mpi_init( &DE ); mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &H ); mbedtls_mpi_init( &I ); mbedtls_mpi_init( &G ); mbedtls_mpi_init( &G2 ); + mbedtls_mpi_init( &L1 ); mbedtls_mpi_init( &L2 ); mbedtls_mpi_init( &DP ); mbedtls_mpi_init( &DQ ); + mbedtls_mpi_init( &QP ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G2, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L1, &L2, &H, &G2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &I, &DE, &L1 ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DP, &ctx->D, &P1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); + /* + * Check for a valid PKCS1v2 private key + */ + if( mbedtls_mpi_cmp_mpi( &PQ, &ctx->N ) != 0 || + mbedtls_mpi_cmp_mpi( &DP, &ctx->DP ) != 0 || + mbedtls_mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 || + mbedtls_mpi_cmp_mpi( &QP, &ctx->QP ) != 0 || + mbedtls_mpi_cmp_int( &L2, 0 ) != 0 || + mbedtls_mpi_cmp_int( &I, 1 ) != 0 || + mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + +cleanup: + mbedtls_mpi_free( &PQ ); mbedtls_mpi_free( &DE ); mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); + mbedtls_mpi_free( &H ); mbedtls_mpi_free( &I ); mbedtls_mpi_free( &G ); mbedtls_mpi_free( &G2 ); + mbedtls_mpi_free( &L1 ); mbedtls_mpi_free( &L2 ); mbedtls_mpi_free( &DP ); mbedtls_mpi_free( &DQ ); + mbedtls_mpi_free( &QP ); + + if( ret == MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ) + return( ret ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + ret ); + + 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 ) +{ + 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; + + 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; + mbedtls_mpi T, T1, T2; + mbedtls_mpi P1, Q1, R; +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi D_blind; + mbedtls_mpi *D = &ctx->D; +#else + mbedtls_mpi DP_blind, DQ_blind; + mbedtls_mpi *DP = &ctx->DP; + mbedtls_mpi *DQ = &ctx->DQ; +#endif + + /* Make sure we have private key info, prevent possible misuse */ + if( ctx->P.p == NULL || ctx->Q.p == NULL || ctx->D.p == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); + 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_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; + } + + 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 + * + * T1 = input ^ dP mod P + * T2 = input ^ dQ mod Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T1, &T, DP, &ctx->P, &ctx->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T2, &T, DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (T1 - T2) * (Q^-1 mod P) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T1, &T2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T1, &ctx->P ) ); + + /* + * T = T2 + T * Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &T2, &T1 ) ); +#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 ) ); + } + + 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( &T ); mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); + 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 + } + + 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 void 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; + + 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; + + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, src, slen ); + mbedtls_md_update( md_ctx, counter, 4 ); + mbedtls_md_finish( md_ctx, mask ); + + for( i = 0; i < use_len; ++i ) + *p++ ^= mask[i]; + + counter[3]++; + + dlen -= use_len; + } + + mbedtls_zeroize( mask, sizeof( mask ) ); +} +#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; + + 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 */ + mbedtls_md( md_info, label, label_len, p ); + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + memcpy( p, input, ilen ); + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + return( ret ); + } + + /* maskedDB: Apply dbMask to DB */ + mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, + &md_ctx ); + + /* maskedSeed: Apply seedMask to seed */ + mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, + &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + 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; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + // We don't check p_rng because it won't be dereferenced here + if( f_rng == NULL || input == NULL || output == NULL ) + 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 ) + { + *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; + 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 ) +{ + 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; + + /* + * 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; + } + + + /* Generate lHash */ + mbedtls_md( md_info, label, label_len, lhash ); + + /* seed: Apply seedMask to maskedSeed */ + mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + &md_ctx ); + + /* DB: Apply dbMask to maskedDB */ + mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + /* + * 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); + memcpy( output, p, *olen ); + ret = 0; + +cleanup: + mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_zeroize( lhash, sizeof( lhash ) ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * 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, pad_count = 0, i; + unsigned char *p, bad, pad_done = 0; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + 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; + + p = buf; + bad = 0; + + /* + * Check and get padding len in "constant-time" + */ + bad |= *p++; /* First byte must be 0 */ + + /* This test does not depend on secret data */ + if( mode == MBEDTLS_RSA_PRIVATE ) + { + bad |= *p++ ^ MBEDTLS_RSA_CRYPT; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1; + pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + else + { + bad |= *p++ ^ MBEDTLS_RSA_SIGN; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ( p[i] != 0xFF ); + pad_count += ( pad_done == 0 ); + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + + bad |= ( pad_count < 8 ); + + if( bad ) + { + 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); + memcpy( output, p, *olen ); + ret = 0; + +cleanup: + mbedtls_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) +{ + 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]; + unsigned int slen, hlen, offset = 0; + int ret; + size_t msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + 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 ); + slen = hlen; + + if( olen < hlen + slen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + 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 * 2 - 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 ) + { + mbedtls_md_free( &md_ctx ); + /* No need to zeroize salt: we didn't use it. */ + return( ret ); + } + + /* Generate H = Hash( M' ) */ + mbedtls_md_starts( &md_ctx ); + mbedtls_md_update( &md_ctx, p, 8 ); + mbedtls_md_update( &md_ctx, hash, hashlen ); + mbedtls_md_update( &md_ctx, salt, slen ); + mbedtls_md_finish( &md_ctx, p ); + mbedtls_zeroize( salt, sizeof( salt ) ); + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + offset = 1; + + /* maskedDB: Apply dbMask to DB */ + mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + sig[0] &= 0xFF >> ( olen * 8 - msb ); + + p += hlen; + *p++ = 0xBC; + + 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 + */ +/* + * 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 ) +{ + size_t nb_pad, olen, oid_size = 0; + unsigned char *p = sig; + const char *oid = NULL; + unsigned char *sig_try = NULL, *verif = NULL; + size_t i; + unsigned char diff; + volatile unsigned char diff_no_optimize; + int ret; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + nb_pad = olen - 3; + + 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 ); + + nb_pad -= 10 + oid_size; + + hashlen = mbedtls_md_get_size( md_info ); + } + + nb_pad -= hashlen; + + if( ( nb_pad < 8 ) || ( nb_pad > olen ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + *p++ = 0; + *p++ = MBEDTLS_RSA_SIGN; + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + if( md_alg == MBEDTLS_MD_NONE ) + { + memcpy( p, hash, hashlen ); + } + else + { + /* + * 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( mode == MBEDTLS_RSA_PUBLIC ) + return( mbedtls_rsa_public( ctx, sig, sig ) ); + + /* + * 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 ) ); + + /* Compare in constant time just in case */ + for( diff = 0, i = 0; i < ctx->len; i++ ) + diff |= verif[i] ^ sig[i]; + diff_no_optimize = diff; + + if( diff_no_optimize != 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 ) +{ + 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 result[MBEDTLS_MD_MAX_SIZE]; + unsigned char zeros[8]; + unsigned int hlen; + size_t slen, msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + 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 ); + slen = siglen - hlen - 1; /* Currently length of salt + padding */ + + memset( zeros, 0, 8 ); + + /* + * Note: EMSA-PSS verification is over the length of N - 1 bits + */ + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + { + p++; + siglen -= 1; + } + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + return( ret ); + } + + mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx ); + + buf[0] &= 0xFF >> ( siglen * 8 - msb ); + + while( p < buf + siglen && *p == 0 ) + p++; + + if( p == buf + siglen || + *p++ != 0x01 ) + { + mbedtls_md_free( &md_ctx ); + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + /* Actual salt len */ + slen -= p - buf; + + if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY && + slen != (size_t) expected_salt_len ) + { + mbedtls_md_free( &md_ctx ); + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + /* + * Generate H = Hash( M' ) + */ + mbedtls_md_starts( &md_ctx ); + mbedtls_md_update( &md_ctx, zeros, 8 ); + mbedtls_md_update( &md_ctx, hash, hashlen ); + mbedtls_md_update( &md_ctx, p, slen ); + mbedtls_md_finish( &md_ctx, result ); + + mbedtls_md_free( &md_ctx ); + + if( memcmp( p + slen, result, hlen ) == 0 ) + return( 0 ); + else + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); +} + +/* + * 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 = ( 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; + size_t len, siglen, asn1_len; + unsigned char *p, *p0, *end; + mbedtls_md_type_t msg_md_alg; + const mbedtls_md_info_t *md_info; + mbedtls_asn1_buf oid; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + 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( *p++ != 0 || *p++ != MBEDTLS_RSA_SIGN ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + while( *p != 0 ) + { + if( p >= buf + siglen - 1 || *p != 0xFF ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + p++; + } + p++; /* skip 00 byte */ + + /* We've read: 00 01 PS 00 where PS must be at least 8 bytes */ + if( p - buf < 11 ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + len = siglen - ( p - buf ); + + if( len == hashlen && md_alg == MBEDTLS_MD_NONE ) + { + if( memcmp( p, hash, hashlen ) == 0 ) + return( 0 ); + else + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + } + + 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 ); + + end = p + len; + + /* + * Parse the ASN.1 structure inside the PKCS#1 v1.5 structure. + * Insist on 2-byte length tags, to protect against variants of + * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification. + */ + p0 = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 || asn1_len + 2 != len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + p0 = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 || asn1_len + 6 + hashlen != len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + p0 = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + oid.p = p; + p += oid.len; + + if( mbedtls_oid_get_md_alg( &oid, &msg_md_alg ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( md_alg != msg_md_alg ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + /* + * assume the algorithm parameters must be NULL + */ + p0 = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_NULL ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + p0 = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 || asn1_len != hashlen ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( memcmp( p, hash, hashlen ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + p += hashlen; + + if( p != end ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + return( 0 ); +} +#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 ) +{ + 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; + + 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 ) ); + 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->RN, &src->RN ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RP, &src->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RQ, &src->RQ ) ); + + 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 ) +{ + mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->RQ ); mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->RN ); + mbedtls_mpi_free( &ctx->QP ); mbedtls_mpi_free( &ctx->DQ ); mbedtls_mpi_free( &ctx->DP ); + mbedtls_mpi_free( &ctx->Q ); mbedtls_mpi_free( &ctx->P ); mbedtls_mpi_free( &ctx->D ); + mbedtls_mpi_free( &ctx->E ); mbedtls_mpi_free( &ctx->N ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif +} + +#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 RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" + +#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" + +#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + +#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_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 ); + + rsa.len = KEY_LEN; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.N , 16, RSA_N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.E , 16, RSA_E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.D , 16, RSA_D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.P , 16, RSA_P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.Q , 16, RSA_Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DP, 16, RSA_DP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DQ, 16, RSA_DQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.QP, 16, RSA_QP ) ); + + 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" ); + + return( 1 ); + } + + 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" ); + + return( 1 ); + } + + 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" ); + + return( 1 ); + } + + if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +#if defined(MBEDTLS_SHA1_C) + if( verbose != 0 ) + mbedtls_printf( " PKCS#1 data sign : " ); + + mbedtls_sha1( rsa_plaintext, PT_LEN, sha1sum ); + + 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" ); + + return( 1 ); + } + + 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" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); +#endif /* MBEDTLS_SHA1_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +cleanup: + 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/deps/mbedtls/sha1.c b/deps/mbedtls/sha1.c new file mode 100644 index 0000000000..2ccf2a2f52 --- /dev/null +++ b/deps/mbedtls/sha1.c @@ -0,0 +1,448 @@ +/* + * 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 + +#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_SHA1_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 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 ) +{ + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +void mbedtls_sha1_starts( mbedtls_sha1_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; +} + +#if !defined(MBEDTLS_SHA1_PROCESS_ALT) +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp, W[16], A, B, C, D, E; + + 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) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + 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; +} +#endif /* !MBEDTLS_SHA1_PROCESS_ALT */ + +/* + * SHA-1 process buffer + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + 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 ); + mbedtls_sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_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 +}; + +/* + * SHA-1 final digest + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ) +{ + 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_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha1_update( ctx, sha1_padding, padn ); + mbedtls_sha1_update( ctx, msglen, 8 ); + + 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 ); +} + +#endif /* !MBEDTLS_SHA1_ALT */ + +/* + * output = SHA-1( input buffer ) + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + mbedtls_sha1_starts( &ctx ); + mbedtls_sha1_update( &ctx, input, ilen ); + mbedtls_sha1_finish( &ctx, output ); + mbedtls_sha1_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static const unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int 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 ); + + mbedtls_sha1_starts( &ctx ); + + if( i == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha1_update( &ctx, buf, buflen ); + } + else + mbedtls_sha1_update( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + + mbedtls_sha1_finish( &ctx, sha1sum ); + + if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 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_sha1_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA1_C */ diff --git a/deps/mbedtls/sha256.c b/deps/mbedtls/sha256.c new file mode 100644 index 0000000000..ad25d38333 --- /dev/null +++ b/deps/mbedtls/sha256.c @@ -0,0 +1,458 @@ +/* + * 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 + +#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 */ + +#if !defined(MBEDTLS_SHA256_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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 ) +{ + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ) +{ + 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; +} + +#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) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + + 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]; +} +#endif /* !MBEDTLS_SHA256_PROCESS_ALT */ + +/* + * SHA-256 process buffer + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + 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 ); + mbedtls_sha256_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha256_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha256_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 +}; + +/* + * SHA-256 final digest + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ) +{ + 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_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha256_update( ctx, sha256_padding, padn ); + mbedtls_sha256_update( ctx, msglen, 8 ); + + 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 ); +} + +#endif /* !MBEDTLS_SHA256_ALT */ + +/* + * output = SHA-256( input buffer ) + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + mbedtls_sha256_context ctx; + + mbedtls_sha256_init( &ctx ); + mbedtls_sha256_starts( &ctx, is224 ); + mbedtls_sha256_update( &ctx, input, ilen ); + mbedtls_sha256_finish( &ctx, output ); + mbedtls_sha256_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha256_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int 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 ); + + mbedtls_sha256_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha256_update( &ctx, buf, buflen ); + } + else + mbedtls_sha256_update( &ctx, sha256_test_buf[j], + sha256_test_buflen[j] ); + + mbedtls_sha256_finish( &ctx, sha256sum ); + + if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 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_sha256_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA256_C */ diff --git a/deps/mbedtls/sha512.c b/deps/mbedtls/sha512.c new file mode 100644 index 0000000000..724522ac68 --- /dev/null +++ b/deps/mbedtls/sha512.c @@ -0,0 +1,514 @@ +/* + * 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" + +#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 */ + +#if !defined(MBEDTLS_SHA512_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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 ) +{ + memset( ctx, 0, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ) +{ + *dst = *src; +} + +/* + * SHA-512 context setup + */ +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, int is384 ) +{ + 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; +} + +#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) +}; + +void mbedtls_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; + +#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) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + 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; +} +#endif /* !MBEDTLS_SHA512_PROCESS_ALT */ + +/* + * SHA-512 process buffer + */ +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + unsigned int left; + + if( ilen == 0 ) + return; + + 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 ); + mbedtls_sha512_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + mbedtls_sha512_process( ctx, input ); + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha512_padding[128] = +{ + 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, + 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, 0 +}; + +/* + * SHA-512 final digest + */ +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, unsigned char output[64] ) +{ + size_t last, padn; + uint64_t high, low; + unsigned char msglen[16]; + + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, msglen, 0 ); + PUT_UINT64_BE( low, msglen, 8 ); + + last = (size_t)( ctx->total[0] & 0x7F ); + padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last ); + + mbedtls_sha512_update( ctx, sha512_padding, padn ); + mbedtls_sha512_update( ctx, msglen, 16 ); + + 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 ); + } +} + +#endif /* !MBEDTLS_SHA512_ALT */ + +/* + * output = SHA-512( input buffer ) + */ +void mbedtls_sha512( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ) +{ + mbedtls_sha512_context ctx; + + mbedtls_sha512_init( &ctx ); + mbedtls_sha512_starts( &ctx, is384 ); + mbedtls_sha512_update( &ctx, input, ilen ); + mbedtls_sha512_finish( &ctx, output ); + mbedtls_sha512_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha512_test_buf[3][113] = +{ + { "abc" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" }, + { "" } +}; + +static const int 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 ); + + mbedtls_sha512_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha512_update( &ctx, buf, buflen ); + } + else + mbedtls_sha512_update( &ctx, sha512_test_buf[j], + sha512_test_buflen[j] ); + + mbedtls_sha512_finish( &ctx, sha512sum ); + + if( memcmp( sha512sum, sha512_test_sum[i], 64 - k * 16 ) != 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_sha512_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA512_C */ diff --git a/deps/mbedtls/ssl_cache.c b/deps/mbedtls/ssl_cache.c new file mode 100644 index 0000000000..9b62de2dcc --- /dev/null +++ b/deps/mbedtls/ssl_cache.c @@ -0,0 +1,326 @@ +/* + * 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 + +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; + + memcpy( session->master, entry->session.master, 48 ); + + session->verify_result = entry->session.verify_result; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * Restore peer certificate (without rest of the original chain) + */ + if( entry->peer_cert.p != 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 */ + + 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 = 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 + } + + memcpy( &cur->session, session, sizeof( mbedtls_ssl_session ) ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * 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) ); + } + + /* + * Store peer certificate + */ + if( session->peer_cert != NULL ) + { + cur->peer_cert.p = mbedtls_calloc( 1, session->peer_cert->raw.len ); + if( cur->peer_cert.p == NULL ) + { + ret = 1; + goto exit; + } + + memcpy( cur->peer_cert.p, session->peer_cert->raw.p, + session->peer_cert->raw.len ); + cur->peer_cert.len = session->peer_cert->raw.len; + + cur->session.peer_cert = NULL; + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + 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) + mbedtls_free( prv->peer_cert.p ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + mbedtls_free( prv ); + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &cache->mutex ); +#endif +} + +#endif /* MBEDTLS_SSL_CACHE_C */ diff --git a/deps/mbedtls/ssl_ciphersuites.c b/deps/mbedtls/ssl_ciphersuites.c new file mode 100644 index 0000000000..95e6163ccc --- /dev/null +++ b/deps/mbedtls/ssl_ciphersuites.c @@ -0,0 +1,1875 @@ +/** + * \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, 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: + * AES-256 > Camellia-256 > AES-128 > Camellia-128 > 3DES + * 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 + /* 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 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 remaining >= 128-bit ephemeral 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, + + /* The PSK ephemeral suites */ + 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_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_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + + /* 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 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 remaining >= 128-bit suites */ + 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, + + /* The RSA PSK suites */ + 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, + + /* The PSK suites */ + 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_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_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_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 */ + + { 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; + +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++ ) + { +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + const mbedtls_ssl_ciphersuite_t *cs_info; + if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL && + cs_info->cipher != MBEDTLS_CIPHER_ARC4_128 ) +#else + if( mbedtls_ssl_ciphersuite_from_id( *p ) != NULL ) +#endif + *(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) +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: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#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/deps/mbedtls/ssl_cli.c b/deps/mbedtls/ssl_cli.c new file mode 100644 index 0000000000..a2b9f8cfe1 --- /dev/null +++ b/deps/mbedtls/ssl_cli.c @@ -0,0 +1,3489 @@ +/* + * 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" + +#include + +#include + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#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_MAX_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; + } + + /* + * 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_MAX_CONTENT_LEN; + + *olen = 0; + + 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_MAX_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_MAX_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_MAX_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_MAX_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_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_MAX_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_MAX_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_MAX_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_MAX_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_MAX_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_MAX_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 ); +} + +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; + + 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( ciphersuite_info == NULL ) + continue; + + if( ciphersuite_info->min_minor_ver > ssl->conf->max_minor_ver || + ciphersuite_info->max_minor_ver < ssl->conf->min_minor_ver ) + continue; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) ) + continue; +#endif + +#if defined(MBEDTLS_ARC4_C) + if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED && + ciphersuite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + continue; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE && + mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + continue; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %04x", + ciphersuites[i] ) ); + + n++; + *p++ = (unsigned char)( ciphersuites[i] >> 8 ); + *p++ = (unsigned char)( ciphersuites[i] ); + } + + /* + * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + *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 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + offer_compress = 1; +#else + offer_compress = 0; +#endif + + /* + * We don't support compression with DTLS right now: is 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 + +#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) + 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_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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + 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_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; + + list_size = buf[0]; + if( list_size + 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 ); + } + + 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->transform_negotiate->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; +#if defined(MBEDTLS_DEBUG_C) + uint32_t t; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) ); + + buf = ssl->in_msg; + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + /* No alert on a read error. */ + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + 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 ); + } + +#if defined(MBEDTLS_DEBUG_C) + t = ( (uint32_t) buf[2] << 24 ) + | ( (uint32_t) buf[3] << 16 ) + | ( (uint32_t) buf[4] << 8 ) + | ( (uint32_t) buf[5] ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); +#endif + + 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->transform_negotiate->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + + if( ssl->transform_negotiate->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->transform_negotiate->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] ) ); + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( suite_info == NULL +#if defined(MBEDTLS_ARC4_C) + || ( ssl->conf->arc4_disabled && + suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) +#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 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) ); + + 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; + } + } + + 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_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; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.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, ssl->handshake->ecdh_ctx.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_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.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_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 ); + 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>; + */ + len = (*p)[0] << 8 | (*p)[1]; + *p += 2; + + if( (*p) + len > end ) + { + 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; + + if( offset + len_bytes > MBEDTLS_SSL_MAX_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( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * Now write it out, encrypted + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->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( &ssl->session_negotiate->peer_cert->pk, + p, ssl->handshake->pmslen, + ssl->out_msg + offset + len_bytes, olen, + MBEDTLS_SSL_MAX_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 + + 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; + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->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( ssl->session_negotiate->peer_cert->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 ); + } + + 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->transform_negotiate->ciphersuite_info; + unsigned char *p, *end; + + 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( ( ret = mbedtls_ssl_read_record( ssl ) ) != 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 ); + } + + 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_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; + + /* + * 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 + */ + sig_len = ( p[0] << 8 ) | p[1]; + p += 2; + + if( end != p + 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 ) + { + mbedtls_md5_context mbedtls_md5; + mbedtls_sha1_context mbedtls_sha1; + + mbedtls_md5_init( &mbedtls_md5 ); + mbedtls_sha1_init( &mbedtls_sha1 ); + + hashlen = 36; + + /* + * 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); + */ + mbedtls_md5_starts( &mbedtls_md5 ); + mbedtls_md5_update( &mbedtls_md5, ssl->handshake->randbytes, 64 ); + mbedtls_md5_update( &mbedtls_md5, params, params_len ); + mbedtls_md5_finish( &mbedtls_md5, hash ); + + mbedtls_sha1_starts( &mbedtls_sha1 ); + mbedtls_sha1_update( &mbedtls_sha1, ssl->handshake->randbytes, 64 ); + mbedtls_sha1_update( &mbedtls_sha1, params, params_len ); + mbedtls_sha1_finish( &mbedtls_sha1, hash + 16 ); + + mbedtls_md5_free( &mbedtls_md5 ); + mbedtls_sha1_free( &mbedtls_sha1 ); + } + 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 ) + { + mbedtls_md_context_t ctx; + + mbedtls_md_init( &ctx ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + if( ( ret = mbedtls_md_setup( &ctx, + mbedtls_md_info_from_type( md_alg ), 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + return( ret ); + } + + mbedtls_md_starts( &ctx ); + mbedtls_md_update( &ctx, ssl->handshake->randbytes, 64 ); + mbedtls_md_update( &ctx, params, params_len ); + mbedtls_md_finish( &ctx, hash ); + mbedtls_md_free( &ctx ); + } + 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 != 0 ? hashlen : + (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * Verify signature + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->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( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk, + md_alg, hash, hashlen, p, sig_len ) ) != 0 ) + { + 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 ); + return( ret ); + } + } +#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->transform_negotiate->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->transform_negotiate->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 ) ) != 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 */ + cert_type_len = buf[mbedtls_ssl_hs_hdr_len( ssl )]; + n = cert_type_len; + + 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 = buf + mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n; + size_t i; + + 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; + + 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 ); + } + } +#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 ) ) != 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 i, n; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->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 + */ + n = ssl->handshake->dhm_ctx.len; + + ssl->out_msg[4] = (unsigned char)( n >> 8 ); + ssl->out_msg[5] = (unsigned char)( n ); + i = 6; + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[i], n, + 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_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 + */ + i = 4; + + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, + &n, + &ssl->out_msg[i], 1000, + 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_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + + 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( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.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->psk == NULL || ssl->conf->psk_identity == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key for PSK" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + i = 4; + n = ssl->conf->psk_identity_len; + + if( i + 2 + n > MBEDTLS_SSL_MAX_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[i++] = (unsigned char)( n >> 8 ); + ssl->out_msg[i++] = (unsigned char)( n ); + + memcpy( ssl->out_msg + i, ssl->conf->psk_identity, ssl->conf->psk_identity_len ); + i += ssl->conf->psk_identity_len; + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) + { + n = 0; + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 2 ) ) != 0 ) + return( ret ); + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + /* + * ClientDiffieHellmanPublic public (DHM send G^X mod P) + */ + n = ssl->handshake->dhm_ctx.len; + + if( i + 2 + n > MBEDTLS_SSL_MAX_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[i++] = (unsigned char)( n >> 8 ); + ssl->out_msg[i++] = (unsigned char)( n ); + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[i], n, + 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 ) + { + /* + * ClientECDiffieHellmanPublic public; + */ + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, &n, + &ssl->out_msg[i], MBEDTLS_SSL_MAX_CONTENT_LEN - i, + 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_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + 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 ) + { + i = 4; + if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 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 ) + { + i = 4; + + ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, + ssl->out_msg + i, MBEDTLS_SSL_MAX_CONTENT_LEN - i, &n, + 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 = i + n; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client key exchange" ) ); + + return( 0 ); +} + +#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) +static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->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( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + 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 +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->transform_negotiate->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; + + 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( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + 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 an RSA signature of the handshake digests + */ + 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->transform_negotiate->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( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash_start, hashlen, + ssl->out_msg + 6 + offset, &n, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + 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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_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 ) ) != 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 = ( 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 ); + + mbedtls_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_resend( ssl ) ) != 0 ) + return( ret ); + } +#endif + + /* 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/deps/mbedtls/ssl_cookie.c b/deps/mbedtls/ssl_cookie.c new file mode 100644 index 0000000000..caf119990d --- /dev/null +++ b/deps/mbedtls/ssl_cookie.c @@ -0,0 +1,260 @@ +/* + * 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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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_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_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/deps/mbedtls/ssl_srv.c b/deps/mbedtls/ssl_srv.c new file mode 100644 index 0000000000..f137c3dce6 --- /dev/null +++ b/deps/mbedtls/ssl_srv.c @@ -0,0 +1,4136 @@ +/* + * 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 + +#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_SESSION_TICKETS) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#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" ) ); + + 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 > 0 ) + { + 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 */ + +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; + + 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; + + 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; + + list_size = buf[0]; + if( list_size + 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 ); + } + + 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_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_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 ); + } + + /* + * Use our order of preference + */ + start = buf + 2; + end = buf + len; + for( ours = ssl->conf->alpn_list; *ours != NULL; ours++ ) + { + ours_len = strlen( *ours ); + for( theirs = start; theirs != end; theirs += cur_len ) + { + /* If the list is well formed, we should get equality first */ + if( theirs > end ) + { + 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 ); + } + + cur_len = *theirs++; + + /* 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 ); + } + + 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->key, 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->key, 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->f_psk == NULL && + ( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL || + ssl->conf->psk_identity_len == 0 || ssl->conf->psk_len == 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->transform_negotiate->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_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->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_MAX_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_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_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 ommitted) 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 = ( ( 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 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" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + break; +#endif + 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_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->transform_negotiate->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_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_EXTENDED_MS_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_MAX_CONTENT_LEN; + size_t kkpp_len; + + *olen = 0; + + /* Skip costly computation if not needed */ + if( ssl->transform_negotiate->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_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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + 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_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) + 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_record( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ret ); +} + +#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) +static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + 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 || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + 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 +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->transform_negotiate->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_MAX_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( 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 || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || + 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 ) + { +#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_record( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_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 */ + +static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t n = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) + unsigned char *p = ssl->out_msg + 4; + size_t len; +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + unsigned char *dig_signed = p; + size_t dig_signed_len = 0; +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); + + /* + * + * Part 1: Extract static ECDH parameters and abort + * if ServerKeyExchange not needed. + * + */ + + /* 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. */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) + if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */ + + /* + * + * Part 2: 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 ) + { + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p, &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 ); + } + + p += len; + n += 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 ) + { + *(p++) = 0x00; + *(p++) = 0x00; + + n += 2; + } +#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 ) ) + { + 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_mpi_copy( &ssl->handshake->dhm_ctx.P, &ssl->conf->dhm_P ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ssl->handshake->dhm_ctx.G, &ssl->conf->dhm_G ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_mpi_copy", ret ); + return( ret ); + } + + if( ( ret = mbedtls_dhm_make_params( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + p, &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 = p; + dig_signed_len = len; +#endif + + p += len; + n += 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; + + /* 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_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, + (*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, + p, MBEDTLS_SSL_MAX_CONTENT_LEN - n, + 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 = p; + dig_signed_len = len; +#endif + + p += len; + n += len; + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ + + /* + * + * Part 3: 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 signature_len = 0; + unsigned int hashlen = 0; + unsigned char hash[64]; + + /* + * 3.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 ) ); + + /* + * 3.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 ) + { + 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); + */ + + mbedtls_md5_starts( &mbedtls_md5 ); + mbedtls_md5_update( &mbedtls_md5, ssl->handshake->randbytes, 64 ); + mbedtls_md5_update( &mbedtls_md5, dig_signed, dig_signed_len ); + mbedtls_md5_finish( &mbedtls_md5, hash ); + + mbedtls_sha1_starts( &mbedtls_sha1 ); + mbedtls_sha1_update( &mbedtls_sha1, ssl->handshake->randbytes, 64 ); + mbedtls_sha1_update( &mbedtls_sha1, dig_signed, dig_signed_len ); + mbedtls_sha1_finish( &mbedtls_sha1, hash + 16 ); + + hashlen = 36; + + mbedtls_md5_free( &mbedtls_md5 ); + mbedtls_sha1_free( &mbedtls_sha1 ); + } + 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 ) + { + mbedtls_md_context_t ctx; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + + mbedtls_md_init( &ctx ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + + /* + * 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 ); + return( ret ); + } + + mbedtls_md_starts( &ctx ); + mbedtls_md_update( &ctx, ssl->handshake->randbytes, 64 ); + mbedtls_md_update( &ctx, dig_signed, dig_signed_len ); + mbedtls_md_finish( &ctx, hash ); + mbedtls_md_free( &ctx ); + } + 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 != 0 ? hashlen : + (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + + /* + * 3.3: Compute and add the signature + */ + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + +#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; + * + */ + + *(p++) = mbedtls_ssl_hash_from_md_alg( md_alg ); + *(p++) = mbedtls_ssl_sig_from_pk_alg( sig_alg ); + + n += 2; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash, hashlen, + p + 2 , &signature_len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + + *(p++) = (unsigned char)( signature_len >> 8 ); + *(p++) = (unsigned char)( signature_len ); + n += 2; + + MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", p, signature_len ); + + n += signature_len; + } +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + + /* Done with actual work; add header and send. */ + + ssl->out_msglen = 4 + n; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", 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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + 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) +static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, + const unsigned char *p, + const unsigned char *end, + size_t pms_offset ) +{ + int ret; + size_t len = mbedtls_pk_get_len( mbedtls_ssl_own_key( ssl ) ); + 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; + + if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * 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++ != ( ( 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 ); + } + + mbedtls_ssl_write_version( ssl->handshake->max_major_ver, + ssl->handshake->max_minor_ver, + ssl->conf->transport, ver ); + + /* + * 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. + * Also, avoid data-dependant branches here to protect against + * timing-based variants. + */ + ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_pk_decrypt( mbedtls_ssl_own_key( ssl ), p, len, + peer_pms, &peer_pmslen, + sizeof( peer_pms ), + ssl->conf->f_rng, ssl->conf->p_rng ); + + diff = (unsigned int) ret; + diff |= peer_pmslen ^ 48; + diff |= peer_pms[0] ^ ver[0]; + diff |= peer_pms[1] ^ ver[1]; + +#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; + + /* 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 + + 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->f_psk == NULL && + ( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL || + ssl->conf->psk_identity_len == 0 || ssl->conf->psk_len == 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( *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( n < 1 || n > 65535 || *p + n > end ) + { + 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->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 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_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.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_MPI( 3, "ECDH: z ", &ssl->handshake->ecdh_ctx.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( ( 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( ( 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_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( 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 ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.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_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) +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + 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_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + 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 +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->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + 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_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || + ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + /* Read the message without adding it to the checksum */ + do { + + if( ( ret = mbedtls_ssl_read_record_layer( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); + return( ret ); + } + + ret = mbedtls_ssl_handle_message_type( ssl ); + + } while( MBEDTLS_ERR_SSL_NON_FATAL == ret ); + + if( 0 != ret ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), 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 ); + + /* + * 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( &ssl->session_negotiate->peer_cert->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( &ssl->session_negotiate->peer_cert->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( &ssl->session_negotiate->peer_cert->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_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_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_MAX_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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", 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_resend( ssl ) ) != 0 ) + return( ret ); + } +#endif + + 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/deps/mbedtls/ssl_ticket.c b/deps/mbedtls/ssl_ticket.c new file mode 100644 index 0000000000..4d9116d214 --- /dev/null +++ b/deps/mbedtls/ssl_ticket.c @@ -0,0 +1,489 @@ +/* + * 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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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 */ + +/* + * 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_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( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 || + ( 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: + * 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 + */ +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) + size_t cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( left < sizeof( mbedtls_ssl_session ) ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + 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( 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 ); + + if( session->peer_cert != NULL ) + memcpy( p, session->peer_cert->raw.p, cert_len ); + + p += cert_len; +#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) + size_t cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( p + sizeof( mbedtls_ssl_session ) > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( session, p, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( p + 3 > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; + p += 3; + + if( cert_len == 0 ) + { + session->peer_cert = NULL; + } + else + { + int ret; + + if( p + cert_len > end ) + 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; + } +#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 + 4; + unsigned char *state_len_bytes = iv + 12; + unsigned char *state = state_len_bytes + 2; + 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 < 4 + 12 + 2 + 16 ) + 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, 4 ); + + if( ( ret = ctx->f_rng( ctx->p_rng, iv, 12 ) ) != 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, 12, key_name, 4 + 12 + 2, + state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 ) + { + goto cleanup; + } + if( ciph_len != clear_len ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + *tlen = 4 + 12 + 2 + 16 + 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 + 4; + unsigned char *enc_len_p = iv + 12; + unsigned char *ticket = enc_len_p + 2; + unsigned char *tag; + size_t enc_len, clear_len; + + if( ctx == NULL || ctx->f_rng == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* See mbedtls_ssl_ticket_write() */ + if( len < 4 + 12 + 2 + 16 ) + 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 != 4 + 12 + 2 + enc_len + 16 ) + { + 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, 12, + key_name, 4 + 12 + 2, ticket, enc_len, + ticket, &clear_len, tag, 16 ) ) != 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_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); +} + +#endif /* MBEDTLS_SSL_TICKET_C */ diff --git a/deps/mbedtls/ssl_tls.c b/deps/mbedtls/ssl_tls.c new file mode 100644 index 0000000000..661ae7065b --- /dev/null +++ b/deps/mbedtls/ssl_tls.c @@ -0,0 +1,8035 @@ +/* + * 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 + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include "mbedtls/oid.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* 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 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * 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 ); + + 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 mfl_code_to_length[MBEDTLS_SSL_MAX_FRAG_LEN_INVALID] = +{ + MBEDTLS_SSL_MAX_CONTENT_LEN, /* MBEDTLS_SSL_MAX_FRAG_LEN_NONE */ + 512, /* MBEDTLS_SSL_MAX_FRAG_LEN_512 */ + 1024, /* MBEDTLS_SSL_MAX_FRAG_LEN_1024 */ + 2048, /* MBEDTLS_SSL_MAX_FRAG_LEN_2048 */ + 4096, /* MBEDTLS_SSL_MAX_FRAG_LEN_4096 */ +}; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_CLI_C) +static int 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( 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 ); + } + } +#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 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +#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 ) +{ + 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 ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, padding, 1 + i ); + mbedtls_sha1_update( &sha1, secret, slen ); + mbedtls_sha1_update( &sha1, random, rlen ); + mbedtls_sha1_finish( &sha1, sha1sum ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, secret, slen ); + mbedtls_md5_update( &md5, sha1sum, 20 ); + mbedtls_md5_finish( &md5, dstbuf + i * 16 ); + } + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padding, sizeof( padding ) ); + mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); + + return( 0 ); +} +#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[128]; + 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 ); + + if( sizeof( tmp ) < 20 + strlen( label ) + rlen ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + 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 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + 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 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + 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] ); + } + + mbedtls_md_free( &md_ctx ); + + mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_zeroize( h_i, sizeof( h_i ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +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[128]; + 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 ); + + if( sizeof( tmp ) < md_len + strlen( label ) + rlen ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + 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 ) + return( ret ); + + 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]; + } + + mbedtls_md_free( &md_ctx ); + + mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_zeroize( h_i, sizeof( h_i ) ); + + return( 0 ); +} + +#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 */ + +int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + unsigned char tmp[64]; + unsigned char keyblk[256]; + unsigned char *key1; + unsigned char *key2; + unsigned char *mac_enc; + unsigned char *mac_dec; + size_t iv_copy_len; + const mbedtls_cipher_info_t *cipher_info; + const mbedtls_md_info_t *md_info; + + 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" ) ); + + cipher_info = mbedtls_cipher_info_from_type( transform->ciphersuite_info->cipher ); + if( cipher_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %d not found", + transform->ciphersuite_info->cipher ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + md_info = mbedtls_md_info_from_type( transform->ciphersuite_info->mac ); + if( md_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %d not found", + transform->ciphersuite_info->mac ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * 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 && + transform->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_BUF( 3, "premaster secret", handshake->premaster, + handshake->pmslen ); + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED ) + { + unsigned char session_hash[48]; + size_t hash_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) ); + + 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( ssl->transform_negotiate->ciphersuite_info->mac == + MBEDTLS_MD_SHA384 ) + { + hash_len = 48; + } + else +#endif + hash_len = 32; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + hash_len = 36; + + MBEDTLS_SSL_DEBUG_BUF( 3, "session hash", session_hash, hash_len ); + + ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, + "extended master secret", + session_hash, hash_len, + session->master, 48 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + } + else +#endif + ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, + "master secret", + handshake->randbytes, 64, + session->master, 48 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + mbedtls_zeroize( handshake->premaster, sizeof(handshake->premaster) ); + } + else + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); + + /* + * 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_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 ); + + mbedtls_zeroize( handshake->randbytes, sizeof( handshake->randbytes ) ); + + /* + * Determine the appropriate key, IV and MAC length. + */ + + transform->keylen = cipher_info->key_bitlen / 8; + + if( cipher_info->mode == MBEDTLS_MODE_GCM || + cipher_info->mode == MBEDTLS_MODE_CCM ) + { + transform->maclen = 0; + + transform->ivlen = 12; + transform->fixed_ivlen = 4; + + /* Minimum length is expicit IV + tag */ + transform->minlen = transform->ivlen - transform->fixed_ivlen + + ( transform->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16 ); + } + else + { + /* 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 ); + return( ret ); + } + + /* Get MAC length */ + transform->maclen = mbedtls_md_get_size( md_info ); + +#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; +#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" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "keylen: %d, minlen: %d, ivlen: %d, maclen: %d", + transform->keylen, transform->minlen, transform->ivlen, + 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 + transform->maclen * 2; + key2 = keyblk + transform->maclen * 2 + transform->keylen; + + mac_enc = keyblk; + mac_dec = keyblk + transform->maclen; + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_enc, key2 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_dec, key2 + transform->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 + transform->maclen * 2 + transform->keylen; + key2 = keyblk + transform->maclen * 2; + + mac_enc = keyblk + transform->maclen; + 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 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_enc, key1 + transform->keylen + iv_copy_len, + iv_copy_len ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( transform->maclen > sizeof transform->mac_enc ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( transform->mac_enc, mac_enc, transform->maclen ); + memcpy( transform->mac_dec, mac_dec, transform->maclen ); + } + 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 ) + { + mbedtls_md_hmac_starts( &transform->md_ctx_enc, mac_enc, transform->maclen ); + mbedtls_md_hmac_starts( &transform->md_ctx_dec, mac_dec, transform->maclen ); + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#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, transform->keylen, + transform->iv_enc, transform->iv_dec, + iv_copy_len, + mac_enc, mac_dec, + transform->maclen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_init", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#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, + transform->maclen, transform->keylen, + iv_copy_len ); + } +#endif + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + 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 ); + return( ret ); + } + + 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 ); + return( ret ); + } + +#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 ); + return( ret ); + } + + 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 ); + return( ret ); + } + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + mbedtls_zeroize( keyblk, sizeof( keyblk ) ); + +#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_BUFFER_LEN ); + if( ssl->compress_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + MBEDTLS_SSL_BUFFER_LEN ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + } + + 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" ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + } +#endif /* MBEDTLS_ZLIB_SUPPORT */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); + + return( 0 ); +} + +#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( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update( &md5, pad_1, 48 ); + mbedtls_md5_finish( &md5, hash ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update( &md5, pad_2, 48 ); + mbedtls_md5_update( &md5, hash, 16 ); + mbedtls_md5_finish( &md5, hash ); + + mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update( &sha1, pad_1, 40 ); + mbedtls_sha1_finish( &sha1, hash + 16 ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update( &sha1, pad_2, 40 ); + mbedtls_sha1_update( &sha1, hash + 16, 20 ); + mbedtls_sha1_finish( &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( &md5, hash ); + mbedtls_sha1_finish( &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] ) +{ + 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( &sha256, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha256_free( &sha256 ); + + return; +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] ) +{ + 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( &sha512, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha512_free( &sha512 ); + + 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 + */ + *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_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.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 + */ +static void ssl_mac( mbedtls_md_context_t *md_ctx, unsigned char *secret, + unsigned char *buf, size_t len, + unsigned char *ctr, int type ) +{ + 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, buf + len ); + + 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, buf + len, md_size ); + mbedtls_md_finish( md_ctx, buf + len ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ + ( defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) ) +#define SSL_SOME_MODES_USE_MAC +#endif + +/* + * Encryption/decryption functions + */ +static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) +{ + mbedtls_cipher_mode_t mode; + int auth_done = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); + + if( ssl->session_out == NULL || ssl->transform_out == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", + ssl->out_msg, ssl->out_msglen ); + + /* + * Add MAC before if needed + */ +#if defined(SSL_SOME_MODES_USE_MAC) + if( mode == MBEDTLS_MODE_STREAM || + ( mode == MBEDTLS_MODE_CBC +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + && ssl->session_out->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED +#endif + ) ) + { +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl_mac( &ssl->transform_out->md_ctx_enc, + ssl->transform_out->mac_enc, + ssl->out_msg, ssl->out_msglen, + ssl->out_ctr, ssl->out_msgtype ); + } + else +#endif +#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 ) + { + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 8 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_hdr, 3 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_len, 2 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, + ssl->out_msg, ssl->out_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, + ssl->out_msg + ssl->out_msglen ); + mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", + ssl->out_msg + ssl->out_msglen, + ssl->transform_out->maclen ); + + ssl->out_msglen += ssl->transform_out->maclen; + auth_done++; + } +#endif /* AEAD not the only option */ + + /* + * Encrypt + */ +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + int ret; + size_t olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + ssl->out_msg, ssl->out_msglen, + ssl->out_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( ssl->out_msglen != 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) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM ) + { + int ret; + size_t enc_msglen, olen; + unsigned char *enc_msg; + unsigned char add_data[13]; + unsigned char taglen = ssl->transform_out->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + + memcpy( add_data, ssl->out_ctr, 8 ); + add_data[8] = ssl->out_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, add_data + 9 ); + add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->out_msglen & 0xFF; + + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + + /* + * Generate IV + */ + if( ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen != 8 ) + { + /* 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 ); + } + + memcpy( ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, + ssl->out_ctr, 8 ); + memcpy( ssl->out_iv, ssl->out_ctr, 8 ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->out_iv, + ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + /* + * Encrypt and authenticate + */ + if( ( ret = mbedtls_cipher_auth_encrypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + add_data, 13, + enc_msg, enc_msglen, + enc_msg, &olen, + enc_msg + enc_msglen, taglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret ); + return( ret ); + } + + if( olen != enc_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msglen += taglen; + auth_done++; + + MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", enc_msg + enc_msglen, taglen ); + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) + if( mode == MBEDTLS_MODE_CBC ) + { + int ret; + unsigned char *enc_msg; + size_t enc_msglen, padlen, olen = 0, i; + + padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) % + ssl->transform_out->ivlen; + if( padlen == ssl->transform_out->ivlen ) + padlen = 0; + + for( i = 0; i <= padlen; i++ ) + ssl->out_msg[ssl->out_msglen + i] = (unsigned char) padlen; + + ssl->out_msglen += padlen + 1; + + enc_msglen = ssl->out_msglen; + enc_msg = ssl->out_msg; + +#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( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Generate IV + */ + ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + if( ret != 0 ) + return( ret ); + + memcpy( ssl->out_iv, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->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", + ssl->out_msglen, ssl->transform_out->ivlen, + padlen + 1 ) ); + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + enc_msg, enc_msglen, + enc_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( enc_msglen != 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( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( ssl->transform_out->iv_enc, + ssl->transform_out->cipher_ctx_enc.iv, + ssl->transform_out->ivlen ); + } +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( auth_done == 0 ) + { + /* + * 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)); + */ + unsigned char pseudo_hdr[13]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + + memcpy( pseudo_hdr + 0, ssl->out_ctr, 8 ); + memcpy( pseudo_hdr + 8, ssl->out_hdr, 3 ); + pseudo_hdr[11] = (unsigned char)( ( ssl->out_msglen >> 8 ) & 0xFF ); + pseudo_hdr[12] = (unsigned char)( ( ssl->out_msglen ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); + + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, pseudo_hdr, 13 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, + ssl->out_iv, ssl->out_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, + ssl->out_iv + ssl->out_msglen ); + mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + + ssl->out_msglen += ssl->transform_out->maclen; + auth_done++; + } +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_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 ); +} + +#define SSL_MAX_MAC_SIZE 48 + +static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) +{ + size_t i; + mbedtls_cipher_mode_t mode; + int auth_done = 0; +#if defined(SSL_SOME_MODES_USE_MAC) + size_t padlen = 0, correct = 1; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) ); + + if( ssl->session_in == NULL || ssl->transform_in == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_in->cipher_ctx_dec ); + + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "in_msglen (%d) < minlen (%d)", + ssl->in_msglen, ssl->transform_in->minlen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + int ret; + size_t olen = 0; + + padlen = 0; + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + ssl->in_msg, ssl->in_msglen, + ssl->in_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( ssl->in_msglen != 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) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM ) + { + int ret; + size_t dec_msglen, olen; + unsigned char *dec_msg; + unsigned char *dec_msg_result; + unsigned char add_data[13]; + unsigned char taglen = ssl->transform_in->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + size_t explicit_iv_len = ssl->transform_in->ivlen - + ssl->transform_in->fixed_ivlen; + + if( ssl->in_msglen < explicit_iv_len + taglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) " + "+ taglen (%d)", ssl->in_msglen, + explicit_iv_len, taglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + dec_msglen = ssl->in_msglen - explicit_iv_len - taglen; + + dec_msg = ssl->in_msg; + dec_msg_result = ssl->in_msg; + ssl->in_msglen = dec_msglen; + + memcpy( add_data, ssl->in_ctr, 8 ); + add_data[8] = ssl->in_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, add_data + 9 ); + add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->in_msglen & 0xFF; + + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + + memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen, + ssl->in_iv, + ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec, + ssl->transform_in->ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, taglen ); + + /* + * Decrypt and authenticate + */ + if( ( ret = mbedtls_cipher_auth_decrypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + add_data, 13, + dec_msg, dec_msglen, + dec_msg_result, &olen, + dec_msg + dec_msglen, 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 != dec_msglen ) + { + 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) ) + if( mode == MBEDTLS_MODE_CBC ) + { + /* + * Decrypt and check the padding + */ + int ret; + unsigned char *dec_msg; + unsigned char *dec_msg_result; + size_t dec_msglen; + size_t minlen = 0; + size_t olen = 0; + + /* + * Check immediate ciphertext sanity + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + minlen += ssl->transform_in->ivlen; +#endif + + if( ssl->in_msglen < minlen + ssl->transform_in->ivlen || + ssl->in_msglen < minlen + ssl->transform_in->maclen + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) " + "+ 1 ) ( + expl IV )", ssl->in_msglen, + ssl->transform_in->ivlen, + ssl->transform_in->maclen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + + dec_msglen = ssl->in_msglen; + dec_msg = ssl->in_msg; + dec_msg_result = ssl->in_msg; + + /* + * Authenticate before decrypt if enabled + */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( ssl->session_in->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) + { + unsigned char computed_mac[SSL_MAX_MAC_SIZE]; + unsigned char pseudo_hdr[13]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + + dec_msglen -= ssl->transform_in->maclen; + ssl->in_msglen -= ssl->transform_in->maclen; + + memcpy( pseudo_hdr + 0, ssl->in_ctr, 8 ); + memcpy( pseudo_hdr + 8, ssl->in_hdr, 3 ); + pseudo_hdr[11] = (unsigned char)( ( ssl->in_msglen >> 8 ) & 0xFF ); + pseudo_hdr[12] = (unsigned char)( ( ssl->in_msglen ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); + + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, pseudo_hdr, 13 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, + ssl->in_iv, ssl->in_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, computed_mac ); + mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", ssl->in_iv + ssl->in_msglen, + ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", computed_mac, + ssl->transform_in->maclen ); + + if( mbedtls_ssl_safer_memcmp( ssl->in_iv + ssl->in_msglen, computed_mac, + ssl->transform_in->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( ssl->in_msglen % ssl->transform_in->ivlen != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0", + ssl->in_msglen, ssl->transform_in->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( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + dec_msglen -= ssl->transform_in->ivlen; + ssl->in_msglen -= ssl->transform_in->ivlen; + + for( i = 0; i < ssl->transform_in->ivlen; i++ ) + ssl->transform_in->iv_dec[i] = ssl->in_iv[i]; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + dec_msg, dec_msglen, + dec_msg_result, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( dec_msglen != 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( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( ssl->transform_in->iv_dec, + ssl->transform_in->cipher_ctx_dec.iv, + ssl->transform_in->ivlen ); + } +#endif + + padlen = 1 + ssl->in_msg[ssl->in_msglen - 1]; + + if( ssl->in_msglen < ssl->transform_in->maclen + padlen && + auth_done == 0 ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)", + ssl->in_msglen, ssl->transform_in->maclen, padlen ) ); +#endif + padlen = 0; + correct = 0; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( padlen > ssl->transform_in->ivlen ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, " + "should be no more than %d", + padlen, ssl->transform_in->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( ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * TLSv1+: always check the padding up to the first failure + * and fake check up to 256 bytes of padding + */ + size_t pad_count = 0, real_count = 1; + size_t padding_idx = ssl->in_msglen - padlen - 1; + + /* + * Padding is guaranteed to be incorrect if: + * 1. padlen >= ssl->in_msglen + * + * 2. padding_idx >= MBEDTLS_SSL_MAX_CONTENT_LEN + + * ssl->transform_in->maclen + * + * In both cases we reset padding_idx to a safe value (0) to + * prevent out-of-buffer reads. + */ + correct &= ( ssl->in_msglen >= padlen + 1 ); + correct &= ( padding_idx < MBEDTLS_SSL_MAX_CONTENT_LEN + + ssl->transform_in->maclen ); + + padding_idx *= correct; + + for( i = 1; i <= 256; i++ ) + { + real_count &= ( i <= padlen ); + pad_count += real_count * + ( ssl->in_msg[padding_idx + i] == padlen - 1 ); + } + + correct &= ( pad_count == padlen ); /* Only 1 on correct padding */ + +#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 ); + } + + ssl->in_msglen -= padlen; + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "raw buffer after decryption", + ssl->in_msg, ssl->in_msglen ); + + /* + * Authenticate if not done yet. + * Compute the MAC regardless of the padding result (RFC4346, CBCTIME). + */ +#if defined(SSL_SOME_MODES_USE_MAC) + if( auth_done == 0 ) + { + unsigned char tmp[SSL_MAX_MAC_SIZE]; + + ssl->in_msglen -= ssl->transform_in->maclen; + + ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 ); + ssl->in_len[1] = (unsigned char)( ssl->in_msglen ); + + memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl_mac( &ssl->transform_in->md_ctx_dec, + ssl->transform_in->mac_dec, + ssl->in_msg, ssl->in_msglen, + ssl->in_ctr, ssl->in_msgtype ); + } + 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_0 ) + { + /* + * Process MAC and always update for padlen afterwards to make + * total time independent of padlen + * + * extra_run compensates MAC check for padlen + * + * Known timing attacks: + * - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf) + * + * 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) + */ + size_t j, extra_run = 0; + extra_run = ( 13 + ssl->in_msglen + padlen + 8 ) / 64 - + ( 13 + ssl->in_msglen + 8 ) / 64; + + extra_run &= correct * 0xFF; + + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_ctr, 8 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_hdr, 3 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_len, 2 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_msg, + ssl->in_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, + ssl->in_msg + ssl->in_msglen ); + /* Call mbedtls_md_process at least once due to cache attacks */ + for( j = 0; j < extra_run + 1; j++ ) + mbedtls_md_process( &ssl->transform_in->md_ctx_dec, ssl->in_msg ); + + mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); + } + 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( 4, "message mac", tmp, ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ); + + if( mbedtls_ssl_safer_memcmp( tmp, ssl->in_msg + ssl->in_msglen, + ssl->transform_in->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 /* 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( ssl->in_msglen == 0 ) + { + 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" ) ); + 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 + { + 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 ); + } + } + + 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; + 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_BUFFER_LEN; + + 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_BUFFER_LEN - + ssl->transform_out->ctx_deflate.avail_out; + + 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; + 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_MAX_CONTENT_LEN; + + 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_MAX_CONTENT_LEN - + ssl->transform_in->ctx_inflate.avail_out; + + 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_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 accross 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 ) + ret = MBEDTLS_ERR_SSL_TIMEOUT; + else + { + len = MBEDTLS_SSL_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 ); + + 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, i; + + 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_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) ); + + buf = ssl->out_hdr + mbedtls_ssl_hdr_len( ssl ) + + ssl->out_msglen - 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 ); + + ssl->out_left -= ret; + } + + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->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 ); + } + + 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; + + /* 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; + } + + 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->out_ctr, 8 ); + memcpy( ssl->out_ctr, ssl->handshake->alt_out_ctr, 8 ); + memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 ); + + /* Adjust to the newly activated transform */ + if( ssl->transform_out != NULL && + ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; + +#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. + * + * 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_resend( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) ); + + if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise resending" ) ); + + ssl->handshake->cur_msg = ssl->handshake->flight; + ssl_swap_epochs( ssl ); + + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING; + } + + while( ssl->handshake->cur_msg != NULL ) + { + int ret; + mbedtls_ssl_flight_item *cur = ssl->handshake->cur_msg; + + /* 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( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && + cur->p[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl_swap_epochs( ssl ); + } + + memcpy( ssl->out_msg, cur->p, cur->len ); + ssl->out_msglen = cur->len; + ssl->out_msgtype = cur->type; + + ssl->handshake->cur_msg = cur->next; + + MBEDTLS_SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 ); + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + } + + 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_resend" ) ); + + 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; + + /* 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 */ + +/* + * Record layer functions + */ + +/* + * Write current record. + * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg. + */ +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) +{ + int ret, done = 0, out_msg_type; + size_t len = ssl->out_msglen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) ); + +#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 ) + { + ; /* Skip special handshake treatment when resending */ + } + else +#endif + if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + out_msg_type = ssl->out_msg[0]; + + if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST && + ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 ); + ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 ); + ssl->out_msg[3] = (unsigned char)( ( len - 4 ) ); + + /* + * 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 */ + memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 ); + ssl->out_msglen += 8; + len += 8; + + /* Write message_seq and update it, except for HelloRequest */ + if( out_msg_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; + } + + /* We don't fragment, so frag_offset = 0 and frag_len = len */ + memset( ssl->out_msg + 6, 0x00, 3 ); + memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + ssl->handshake->update_checksum( ssl, ssl->out_msg, len ); + } + + /* Save handshake and CCS messages for resending */ +#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 && + ( ssl->out_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC || + ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) ) + { + if( ( ret = ssl_flight_append( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_flight_append", ret ); + return( ret ); + } + } +#endif + +#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 ) + { + ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, ssl->out_hdr + 1 ); + + ssl->out_len[0] = (unsigned char)( len >> 8 ); + ssl->out_len[1] = (unsigned char)( len ); + + if( ssl->transform_out != NULL ) + { + if( ( ret = ssl_encrypt_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + ssl->out_len[0] = (unsigned char)( len >> 8 ); + ssl->out_len[1] = (unsigned char)( len ); + } + + ssl->out_left = mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen; + + 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], + ( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network", + ssl->out_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen ); + } + + if( ( 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) +/* + * 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 ); +} + +/* + * Reassemble fragmented DTLS handshake messages. + * + * Use a temporary buffer for reassembly, divided in two parts: + * - the first holds the reassembled message (including handshake header), + * - the second holds a bitmask indicating which parts of the message + * (excluding headers) have been received so far. + */ +static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl ) +{ + unsigned char *msg, *bitmask; + size_t frag_len, frag_off; + size_t msg_len = ssl->in_hslen - 12; /* Without headers */ + + if( ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* + * For first fragment, check size and allocate buffer + */ + if( ssl->handshake->hs_msg == NULL ) + { + size_t alloc_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d", + msg_len ) ); + + if( ssl->in_hslen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too large" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* The bitmask needs one bit per byte of message excluding header */ + alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 ); + + ssl->handshake->hs_msg = mbedtls_calloc( 1, alloc_len ); + if( ssl->handshake->hs_msg == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", alloc_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Prepare final header: copy msg_type, length and message_seq, + * then add standardised fragment_offset and fragment_length */ + memcpy( ssl->handshake->hs_msg, ssl->in_msg, 6 ); + memset( ssl->handshake->hs_msg + 6, 0, 3 ); + memcpy( ssl->handshake->hs_msg + 9, + ssl->handshake->hs_msg + 1, 3 ); + } + else + { + /* Make sure msg_type and length are consistent */ + if( memcmp( ssl->handshake->hs_msg, ssl->in_msg, 4 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment header mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + + msg = ssl->handshake->hs_msg + 12; + bitmask = msg + msg_len; + + /* + * Check and copy current fragment + */ + frag_off = ( ssl->in_msg[6] << 16 ) | + ( ssl->in_msg[7] << 8 ) | + ssl->in_msg[8]; + frag_len = ( ssl->in_msg[9] << 16 ) | + ( ssl->in_msg[10] << 8 ) | + ssl->in_msg[11]; + + if( frag_off + frag_len > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment offset/len: %d + %d > %d", + frag_off, frag_len, msg_len ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( frag_len + 12 > ssl->in_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment length: %d + 12 > %d", + frag_len, ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + 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 ); + ssl_bitmask_set( bitmask, frag_off, frag_len ); + + /* + * Do we have the complete message by now? + * If yes, finalize it, else ask to read the next record. + */ + if( ssl_bitmask_check( bitmask, msg_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message is not complete yet" ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake message completed" ) ); + + if( frag_len + 12 < ssl->in_msglen ) + { + /* + * We'got more handshake messages in the same record. + * This case is not handled now because no know implementation does + * that and it's hard to test, so we prefer to fail cleanly for now. + */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "last fragment not alone in its record" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + if( ssl->in_left > ssl->next_record_offset ) + { + /* + * We've got more data in the buffer after the current record, + * that we don't want to overwrite. Move it before writing the + * reassembled message, and adjust in_left and next_record_offset. + */ + unsigned char *cur_remain = ssl->in_hdr + ssl->next_record_offset; + unsigned char *new_remain = ssl->in_msg + ssl->in_hslen; + size_t remain_len = ssl->in_left - ssl->next_record_offset; + + /* First compute and check new lengths */ + ssl->next_record_offset = new_remain - ssl->in_hdr; + ssl->in_left = ssl->next_record_offset + remain_len; + + if( ssl->in_left > MBEDTLS_SSL_BUFFER_LEN - + (size_t)( ssl->in_hdr - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "reassembled message too large for buffer" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + memmove( new_remain, cur_remain, remain_len ); + } + + memcpy( ssl->in_msg, ssl->handshake->hs_msg, ssl->in_hslen ); + + mbedtls_free( ssl->handshake->hs_msg ); + ssl->handshake->hs_msg = NULL; + + MBEDTLS_SSL_DEBUG_BUF( 3, "reassembled handshake message", + ssl->in_msg, ssl->in_hslen ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +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->in_msg[1] << 16 ) | + ( ssl->in_msg[2] << 8 ) | + ssl->in_msg[3] ); + + 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]; + + /* ssl->handshake is NULL when receiving ClientHello for renego */ + if( ssl->handshake != NULL && + recv_msg_seq != ssl->handshake->in_msg_seq ) + { + /* 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_WANT_READ ); + } + /* Wait until message completion to increment in_msg_seq */ + + /* Reassemble if current message is fragmented or reassembly is + * already in progress */ + 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 || + ( ssl->handshake != NULL && ssl->handshake->hs_msg != NULL ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) ); + + if( ( ret = ssl_reassemble_dtls_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_reassemble_dtls_handshake", ret ); + return( ret ); + } + } + } + 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 ) +{ + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->handshake != 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 ) + { + ssl->handshake->in_msg_seq++; + } +#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_MAX_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 */ + +/* + * 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; + + MBEDTLS_SSL_DEBUG_BUF( 4, "input record header", ssl->in_hdr, mbedtls_ssl_hdr_len( ssl ) ); + + ssl->in_msgtype = ssl->in_hdr[0]; + ssl->in_msglen = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, ssl->in_hdr + 1 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "input record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->in_msgtype, + major_ver, minor_ver, ssl->in_msglen ) ); + + /* Check record type */ + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msgtype != MBEDTLS_SSL_MSG_ALERT && + ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && + ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); + 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 ); + } + + /* Check length against the size of our buffer */ + if( ssl->in_msglen > MBEDTLS_SSL_BUFFER_LEN + - (size_t)( ssl->in_msg - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* 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_MAX_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_MAX_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_MAX_CONTENT_LEN + 256 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif + } + + /* + * DTLS-related tests done last, because most of them may result in + * silently dropping the record (but not the whole datagram), and we only + * want to consider that after ensuring that the "basic" fields (type, + * version, length) are sane. + */ +#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]; + + /* Drop unexpected ChangeCipherSpec messages */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + + /* 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_UNEXPECTED_RECORD ); + } + + /* 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 */ + 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 */ + + 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_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 ) + { + if( ( ret = ssl_decrypt_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", + ssl->in_msg, ssl->in_msglen ); + + if( ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + +#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. + * + */ +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read record" ) ); + + if( ssl->keep_current_message == 0 ) + { + do { + + if( ( ret = mbedtls_ssl_read_record_layer( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); + return( ret ); + } + + ret = mbedtls_ssl_handle_message_type( ssl ); + + } while( MBEDTLS_ERR_SSL_NON_FATAL == ret ); + + if( 0 != ret ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); + return( ret ); + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + 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 ); +} + +int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) +{ + int ret; + + /* + * Step A + * + * 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. + * + * NOTE: This needs to be fixed, since like for + * handshake messages it is allowed to have + * multiple alerts witin a single record. + * Internal reference IOTSSL-1321. + * + * (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. Internal reference IOTSSL-1414. + * (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; + } + + /* + * Step B + * + * Fetch and decode new record if current one is fully consumed. + * + */ + + if( ssl->in_msglen > 0 ) + { + /* There's something left to be processed in the current record. */ + return( 0 ); + } + + /* Need to fetch a new record */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +read_record_header: +#endif + + /* Current record either fully processed or to be discarded. */ + + if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) ) ) != 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_UNEXPECTED_RECORD ) + { + /* Skip unexpected record (but not whole datagram) */ + ssl->next_record_offset = ssl->in_msglen + + mbedtls_ssl_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 */ + goto read_record_header; + } +#endif + return( ret ); + } + + /* + * Read and optionally decrypt the message contents + */ + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_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_hdr_len( ssl ); + 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_RECORD || + 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)" ) ); + goto read_record_header; + } + + 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 ); + } + } + + /* + * When we sent the last flight of the handshake, we MUST respond to a + * retransmit of the peer's previous flight with a retransmit. (In + * practice, only the Finished message will make it, other messages + * including CCS use the old transform so they're dropped as invalid.) + * + * If the record we received is not a handshake message, however, it + * means the peer received our last flight so we can clean up + * handshake info. + * + * This check needs to be done before prepare_handshake() due to an edge + * case: if the client immediately requests renegotiation, this + * finishes the current handshake first, avoiding the new ClientHello + * being mistaken for an ancient message in the current handshake. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received retransmit of last flight" ) ); + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + else + { + ssl_handshake_wrapup_free_hs_transform( ssl ); + } + } +#endif + + 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_ALERT ) + { + 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_cert" ) ); + /* 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; + } + + 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 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); + + return( 0 ); +} + +/* + * Handshake functions + */ +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_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_ECDH_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +/* No certificate support -> dummy functions */ +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + 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->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + 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 +/* 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->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + 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_MAX_CONTENT_LEN - 3 - i ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", + i + 3 + n, MBEDTLS_SSL_MAX_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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + + return( ret ); +} + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, n; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + int authmode = ssl->conf->authmode; + uint8_t alert; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; +#endif + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } +#endif + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 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 ); + return( ret ); + } + + ssl->state++; + +#if defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * Check if the client sent an empty certificate + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + 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" ) ); + + /* The client was asked for a certificate but didn't send + one. The client should know what's going on, so we + don't send an alert. */ + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } +#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->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + 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" ) ); + + /* The client was asked for a certificate but didn't send + one. The client should know what's going on, so we + don't send an alert. */ + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_SRV_C */ + + 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 ); + } + + /* In case we tried to reuse a session but it failed */ + if( ssl->session_negotiate->peer_cert != NULL ) + { + mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert ); + mbedtls_free( ssl->session_negotiate->peer_cert ); + } + + if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1, + sizeof( mbedtls_x509_crt ) ) ) == 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 ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert ); + + i += 3; + + while( i < ssl->in_hslen ) + { + 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 ); + } + + 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 ); + } + + ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert, + ssl->in_msg + i, n ); + 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", ssl->session_negotiate->peer_cert ); + + /* + * On client, make sure the server cert doesn't change during renego to + * avoid "triple handshake" attack: https://secure-resumption.com/ + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + if( ssl->session->peer_cert == NULL ) + { + 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 ); + } + + if( ssl->session->peer_cert->raw.len != + ssl->session_negotiate->peer_cert->raw.len || + memcmp( ssl->session->peer_cert->raw.p, + ssl->session_negotiate->peer_cert->raw.p, + ssl->session->peer_cert->raw.len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server cert changed 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 ); + } + } +#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ + + if( authmode != MBEDTLS_SSL_VERIFY_NONE ) + { + 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; + } + + /* + * Main check: verify certificate + */ + ret = mbedtls_x509_crt_verify_with_profile( + ssl->session_negotiate->peer_cert, + ca_chain, ca_crl, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + } + + /* + * Secondary checks: always done, but change 'ret' only if it was 0 + */ + +#if defined(MBEDTLS_ECP_C) + { + const mbedtls_pk_context *pk = &ssl->session_negotiate->peer_cert->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( ssl->session_negotiate->peer_cert, + 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( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; + } + + if( ret != 0 ) + { + /* 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 */ + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", 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 ) ) != 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 ); + } + + if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 ) + { + 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_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + /* + * 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 ); + + /* + * Set the in_msg pointer to the correct location based on IV length + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen - + ssl->transform_negotiate->fixed_ivlen; + } + else + ssl->in_msg = ssl->in_iv; + +#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( &ssl->handshake->fin_md5 ); + mbedtls_sha1_starts( &ssl->handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_starts( &ssl->handshake->fin_sha256, 0 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_starts( &ssl->handshake->fin_sha512, 1 ); +#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( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update( &ssl->handshake->fin_sha1, buf, len ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); +#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( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update( &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 ) +{ + mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); +} +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); +} +#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( &md5, (const unsigned char *) sender, 4 ); + mbedtls_md5_update( &md5, session->master, 48 ); + mbedtls_md5_update( &md5, padbuf, 48 ); + mbedtls_md5_finish( &md5, md5sum ); + + mbedtls_sha1_update( &sha1, (const unsigned char *) sender, 4 ); + mbedtls_sha1_update( &sha1, session->master, 48 ); + mbedtls_sha1_update( &sha1, padbuf, 40 ); + mbedtls_sha1_finish( &sha1, sha1sum ); + + memset( padbuf, 0x5C, 48 ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, session->master, 48 ); + mbedtls_md5_update( &md5, padbuf, 48 ); + mbedtls_md5_update( &md5, md5sum, 16 ); + mbedtls_md5_finish( &md5, buf ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, session->master, 48 ); + mbedtls_sha1_update( &sha1, padbuf , 40 ); + mbedtls_sha1_update( &sha1, sha1sum, 20 ); + mbedtls_sha1_finish( &sha1, buf + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, 36 ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_zeroize( md5sum, sizeof( md5sum ) ); + mbedtls_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( &md5, padbuf ); + mbedtls_sha1_finish( &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_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; + mbedtls_sha256_context sha256; + unsigned char padbuf[32]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + 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 + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_sha256_finish( &sha256, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 32, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_sha256_free( &sha256 ); + + mbedtls_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; + mbedtls_sha512_context sha512; + unsigned char padbuf[48]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + 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 + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_sha512_finish( &sha512, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 48, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_sha512_free( &sha512 ); + + mbedtls_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->handshake ); + 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" ) ); + + /* + * Set the out_msg pointer to the correct location based on IV length + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + ssl->transform_negotiate->ivlen - + ssl->transform_negotiate->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; + + 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->out_ctr, 8 ); + + /* Set sequence_number to zero */ + memset( ssl->out_ctr + 2, 0, 6 ); + + /* Increment epoch */ + for( i = 2; i > 0; i-- ) + if( ++ssl->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->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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + 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 ) ) != 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( &handshake->fin_md5 ); + mbedtls_sha1_starts( &handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_init( &handshake->fin_sha256 ); + mbedtls_sha256_starts( &handshake->fin_sha256, 0 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_init( &handshake->fin_sha512 ); + mbedtls_sha512_starts( &handshake->fin_sha512, 1 ); +#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_SERVER_NAME_INDICATION) + handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET; +#endif +} + +static void 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 ); + + mbedtls_md_init( &transform->md_ctx_enc ); + mbedtls_md_init( &transform->md_ctx_dec ); +} + +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->handshake ); + + /* + * 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 ); + 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 */ + +/* + * Initialize an SSL context + */ +void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) +{ + memset( ssl, 0, sizeof( mbedtls_ssl_context ) ); +} + +/* + * Setup an SSL context + */ +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ) +{ + int ret; + const size_t len = MBEDTLS_SSL_BUFFER_LEN; + + ssl->conf = conf; + + /* + * Prepare base structures + */ + if( ( ssl-> in_buf = mbedtls_calloc( 1, len ) ) == NULL || + ( ssl->out_buf = mbedtls_calloc( 1, len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", len ) ); + mbedtls_free( ssl->in_buf ); + ssl->in_buf = NULL; + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + ssl->out_ctr = ssl->out_buf + 3; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_hdr = ssl->in_buf; + ssl->in_ctr = ssl->in_buf + 3; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + else +#endif + { + ssl->out_ctr = ssl->out_buf; + ssl->out_hdr = ssl->out_buf + 8; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_ctr = ssl->in_buf; + ssl->in_hdr = ssl->in_buf + 8; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + + 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. + * + * 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; + + 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->in_msg = ssl->in_buf + 13; + ssl->in_msgtype = 0; + ssl->in_msglen = 0; + if( partial == 0 ) + ssl->in_left = 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_msg = ssl->out_buf + 13; + 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 + + ssl->transform_in = NULL; + ssl->transform_out = NULL; + + memset( ssl->out_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); + if( partial == 0 ) + memset( ssl->in_buf, 0, MBEDTLS_SSL_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( partial == 0 ) + { + 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_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; +} + +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 = 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; + + new = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); + if( new == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + new->cert = cert; + new->key = key; + new->next = NULL; + + /* Update head is the list was null, else add to the end */ + if( *head == NULL ) + { + *head = new; + } + else + { + mbedtls_ssl_key_cert *cur = *head; + while( cur->next != NULL ) + cur = cur->next; + cur->next = new; + } + + 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; +} +#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_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) +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( psk == NULL || psk_identity == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( psk_len > MBEDTLS_PSK_MAX_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* Identity len will be encoded on two bytes */ + if( ( psk_identity_len >> 16 ) != 0 || + psk_identity_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( conf->psk != NULL || conf->psk_identity != NULL ) + { + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk = NULL; + conf->psk_identity = NULL; + } + + if( ( conf->psk = mbedtls_calloc( 1, psk_len ) ) == NULL || + ( conf->psk_identity = mbedtls_calloc( 1, psk_identity_len ) ) == NULL ) + { + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk = NULL; + conf->psk_identity = NULL; + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + conf->psk_len = psk_len; + conf->psk_identity_len = psk_identity_len; + + memcpy( conf->psk, psk, conf->psk_len ); + memcpy( conf->psk_identity, psk_identity, conf->psk_identity_len ); + + return( 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 ); + + if( ssl->handshake->psk != NULL ) + mbedtls_free( ssl->handshake->psk ); + + 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 ); +} + +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) +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 ); +} + +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 + +#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 + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) +{ + size_t hostname_len; + + if( hostname == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + hostname_len = strlen( hostname ); + + if( hostname_len + 1 == 0 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( hostname_len > MBEDTLS_SSL_MAX_HOST_NAME_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + 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 + +#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 || + mfl_code_to_length[mfl_code] > MBEDTLS_SSL_MAX_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; +} +#endif + +/* + * SSL get accessors + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) +{ + return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); +} + +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; + const mbedtls_ssl_transform *transform = ssl->transform_out; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->session_out->compression != MBEDTLS_SSL_COMPRESS_NULL ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif + + if( transform == NULL ) + return( (int) mbedtls_ssl_hdr_len( ssl ) ); + + switch( mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ) ) + { + case MBEDTLS_MODE_GCM: + case MBEDTLS_MODE_CCM: + case MBEDTLS_MODE_STREAM: + transform_expansion = transform->minlen; + break; + + case MBEDTLS_MODE_CBC: + transform_expansion = transform->maclen + + mbedtls_cipher_get_block_size( &transform->cipher_ctx_enc ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( (int)( mbedtls_ssl_hdr_len( ssl ) + 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 = mfl_code_to_length[ssl->conf->mfl_code]; + + /* + * Check if a smaller max length was negotiated + */ + if( ssl->session_out != NULL && + mfl_code_to_length[ssl->session_out->mfl_code] < max_len ) + { + max_len = mfl_code_to_length[ssl->session_out->mfl_code]; + } + + return max_len; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#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 ); + + return( ssl->session->peer_cert ); +} +#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( 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_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", 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->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_resend( 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 ); + } + } + + /* + * TODO + * + * The logic should be streamlined here: + * + * Instead of + * + * - Manually checking whether ssl->in_offt is NULL + * - Fetching a new record if yes + * - Setting ssl->in_offt if one finds an application record + * - Resetting keep_current_message after handling the application data + * + * one should + * + * - Adapt read_record to set ssl->in_offt automatically + * when a new application data record is processed. + * - Always call mbedtls_ssl_read_record here. + * + * This way, the logic of ssl_read would be much clearer: + * + * (1) Always call record layer and see what kind of record is on + * and have it ready for consumption (in particular, in_offt + * properly set for application data records). + * (2) If it's application data (either freshly fetched + * or something already being partially processed), + * serve the read request from it. + * (3) If it's something different from application data, + * handle it accordingly, e.g. potentially start a + * renegotiation. + * + * This will also remove the need to manually reset + * ssl->keep_current_message = 0 below. + * + */ + + if( 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 ) ) != 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 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + 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 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#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 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + /* 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 ) ) + { + /* + * 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 ); + } + } + else + { + /* + * 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 ); + } + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + 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 + */ +static int ssl_write_real( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + size_t max_len = mbedtls_ssl_get_max_frag_len( ssl ); + + 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; + } +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + if( ssl->out_left != 0 ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); + } + } + else + { + 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 ) ) != 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 wether 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 ); + + mbedtls_md_free( &transform->md_ctx_enc ); + mbedtls_md_free( &transform->md_ctx_dec ); + + mbedtls_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 */ + +void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ) +{ + if( handshake == NULL ) + return; + +#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) + mbedtls_sha256_free( &handshake->fin_sha256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_free( &handshake->fin_sha512 ); +#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_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_PROTO_DTLS) + mbedtls_free( handshake->verify_cookie ); + mbedtls_free( handshake->hs_msg ); + ssl_flight_free( handshake->flight ); +#endif + + mbedtls_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) + if( session->peer_cert != NULL ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + } +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_free( session->ticket ); +#endif + + mbedtls_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_zeroize( ssl->out_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->out_buf ); + } + + if( ssl->in_buf != NULL ) + { + mbedtls_zeroize( ssl->in_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->in_buf ); + } + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->compress_buf != NULL ) + { + mbedtls_zeroize( ssl->compress_buf, MBEDTLS_SSL_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->handshake ); + 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_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_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 ) + { + if( ( ret = mbedtls_ssl_conf_dh_param( conf, + MBEDTLS_DHM_RFC5114_MODP_2048_P, + MBEDTLS_DHM_RFC5114_MODP_2048_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_MAJOR_VERSION_3; + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_1; /* TLS 1.0 */ + 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_zeroize( conf->psk, conf->psk_len ); + mbedtls_zeroize( conf->psk_identity, conf->psk_identity_len ); + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk_len = 0; + conf->psk_identity_len = 0; + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + ssl_key_cert_free( conf->key_cert ); +#endif + + mbedtls_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 */ +} + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/deps/mbedtls/threading.c b/deps/mbedtls/threading.c new file mode 100644 index 0000000000..07586756f2 --- /dev/null +++ b/deps/mbedtls/threading.c @@ -0,0 +1,137 @@ +/* + * 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) + */ + +#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_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; + + mbedtls_mutex_init( &mbedtls_threading_readdir_mutex ); + mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex ); +} + +/* + * Free global mutexes + */ +void mbedtls_threading_free_alt( void ) +{ + mbedtls_mutex_free( &mbedtls_threading_readdir_mutex ); + mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex ); +} +#endif /* MBEDTLS_THREADING_ALT */ + +/* + * Define global mutexes + */ +#ifndef MUTEX_INIT +#define MUTEX_INIT +#endif +mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT; +mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT; + +#endif /* MBEDTLS_THREADING_C */ diff --git a/deps/mbedtls/timing.c b/deps/mbedtls/timing.c new file mode 100644 index 0000000000..a7c7ff0279 --- /dev/null +++ b/deps/mbedtls/timing.c @@ -0,0 +1,525 @@ +/* + * 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) +#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 + +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 ) +{ + unsigned long delta; + LARGE_INTEGER offset, hfreq; + struct _hr_time *t = (struct _hr_time *) val; + + QueryPerformanceCounter( &offset ); + QueryPerformanceFrequency( &hfreq ); + + delta = (unsigned long)( ( 1000 * + ( offset.QuadPart - t->start.QuadPart ) ) / + hfreq.QuadPart ); + + if( reset ) + QueryPerformanceCounter( &t->start ); + + return( delta ); +} + +/* It's OK to use a global because alarm() is supposed to be global anyway */ +static DWORD alarmMs; + +static DWORD WINAPI TimerProc( LPVOID TimerContext ) +{ + ((void) TimerContext); + Sleep( alarmMs ); + mbedtls_timing_alarmed = 1; + return( TRUE ); +} + +void mbedtls_set_alarm( int seconds ) +{ + DWORD ThreadId; + + mbedtls_timing_alarmed = 0; + alarmMs = seconds * 1000; + CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); +} + +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + unsigned long delta; + struct timeval offset; + struct _hr_time *t = (struct _hr_time *) val; + + gettimeofday( &offset, NULL ); + + if( reset ) + { + t->start.tv_sec = offset.tv_sec; + t->start.tv_usec = offset.tv_usec; + return( 0 ); + } + + delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 + + ( offset.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 ); +} + +#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\n" ); \ + \ + 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, ratio; + unsigned long millisecs, secs; + int hardfail; + struct mbedtls_timing_hr_time hires; + uint32_t a, b; + 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): " ); + + for( secs = 1; secs <= 3; secs++ ) + { + (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 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); + + for( a = 200; a <= 400; a += 200 ) + { + for( b = 200; b <= 400; b += 200 ) + { + mbedtls_timing_set_delay( &ctx, a, a + b ); + + busy_msleep( a - a / 8 ); + if( mbedtls_timing_get_delay( &ctx ) != 0 ) + FAIL; + + busy_msleep( a / 4 ); + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( b - a / 8 - b / 8 ); + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( 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. + */ + hardfail = 0; + +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/deps/mbedtls/version.c b/deps/mbedtls/version.c new file mode 100644 index 0000000000..6ca80d4695 --- /dev/null +++ b/deps/mbedtls/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() +{ + 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/deps/mbedtls/version_features.c b/deps/mbedtls/version_features.c new file mode 100644 index 0000000000..5cbe8aca37 --- /dev/null +++ b/deps/mbedtls/version_features.c @@ -0,0 +1,683 @@ +/* + * 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_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_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_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_BLOWFISH_ALT) + "MBEDTLS_BLOWFISH_ALT", +#endif /* MBEDTLS_BLOWFISH_ALT */ +#if defined(MBEDTLS_CAMELLIA_ALT) + "MBEDTLS_CAMELLIA_ALT", +#endif /* MBEDTLS_CAMELLIA_ALT */ +#if defined(MBEDTLS_DES_ALT) + "MBEDTLS_DES_ALT", +#endif /* MBEDTLS_DES_ALT */ +#if defined(MBEDTLS_XTEA_ALT) + "MBEDTLS_XTEA_ALT", +#endif /* MBEDTLS_XTEA_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_RIPEMD160_ALT) + "MBEDTLS_RIPEMD160_ALT", +#endif /* MBEDTLS_RIPEMD160_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_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_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_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_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_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_NIST_OPTIM) + "MBEDTLS_ECP_NIST_OPTIM", +#endif /* MBEDTLS_ECP_NIST_OPTIM */ +#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_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_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_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_THREADING_ALT) + "MBEDTLS_THREADING_ALT", +#endif /* MBEDTLS_THREADING_ALT */ +#if defined(MBEDTLS_THREADING_PTHREAD) + "MBEDTLS_THREADING_PTHREAD", +#endif /* MBEDTLS_THREADING_PTHREAD */ +#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_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_CCM_C) + "MBEDTLS_CCM_C", +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CERTS_C) + "MBEDTLS_CERTS_C", +#endif /* MBEDTLS_CERTS_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_HMAC_DRBG_C) + "MBEDTLS_HMAC_DRBG_C", +#endif /* MBEDTLS_HMAC_DRBG_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_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/deps/mbedtls/x509.c b/deps/mbedtls/x509.c new file mode 100644 index 0000000000..88e32b067e --- /dev/null +++ b/deps/mbedtls/x509.c @@ -0,0 +1,1098 @@ +/* + * 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(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) +#include +#if !defined(_WIN32) +#include +#include +#include +#endif +#endif + +#define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); } +#define CHECK_RANGE(min, max, val) if( val < min || val > max ){ return( ret ); } + +/* + * 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) paramaters + */ +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 *time) +{ + int ret = MBEDTLS_ERR_X509_INVALID_DATE; + + CHECK_RANGE( 0, 9999, time->year ); + CHECK_RANGE( 0, 23, time->hour ); + CHECK_RANGE( 0, 59, time->min ); + CHECK_RANGE( 0, 59, time->sec ); + + switch( time->mon ) + { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + CHECK_RANGE( 1, 31, time->day ); + break; + case 4: case 6: case 9: case 11: + CHECK_RANGE( 1, 30, time->day ); + break; + case 2: + CHECK_RANGE( 1, 28 + (time->year % 4 == 0), time->day ); + break; + default: + return( ret ); + } + + 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 *time ) +{ + 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, &time->year ) ); + if ( 2 == yearlen ) + { + if ( time->year < 50 ) + time->year += 100; + + time->year += 1900; + } + + CHECK( x509_parse_int( p, 2, &time->mon ) ); + CHECK( x509_parse_int( p, 2, &time->day ) ); + CHECK( x509_parse_int( p, 2, &time->hour ) ); + CHECK( x509_parse_int( p, 2, &time->min ) ); + + /* + * Parse seconds if present + */ + if ( len >= 2 ) + { + CHECK( x509_parse_int( p, 2, &time->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( time ) ); + + return ( 0 ); +} + +/* + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *time ) +{ + 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, time ); +} + +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. + */ +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + SYSTEMTIME st; + + GetSystemTime( &st ); + + now->year = st.wYear; + now->mon = st.wMonth; + now->day = st.wDay; + now->hour = st.wHour; + now->min = st.wMinute; + now->sec = st.wSecond; + + return( 0 ); +} +#else +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + struct tm *lt; + mbedtls_time_t tt; + int ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + tt = mbedtls_time( NULL ); + lt = gmtime( &tt ); + + 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; + } + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * 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 ) +{ +#if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C) + int ret; + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + + if( verbose != 0 ) + mbedtls_printf( " X.509 certificate load: " ); + + 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" ); + + return( ret ); + } + + mbedtls_x509_crt_init( &cacert ); + + 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" ); + + return( ret ); + } + + 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" ); + + return( ret ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n"); + + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); + + return( 0 ); +#else + ((void) verbose); + return( 0 ); +#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_X509_USE_C */ diff --git a/deps/mbedtls/x509_create.c b/deps/mbedtls/x509_create.c new file mode 100644 index 0000000000..df20ec8ebd --- /dev/null +++ b/deps/mbedtls/x509_create.c @@ -0,0 +1,340 @@ +/* + * 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 + +typedef struct { + const char *name; + size_t name_len; + const char*oid; +} x509_attr_descriptor_t; + +#define ADD_STRLEN( s ) s, sizeof( s ) - 1 + +static const x509_attr_descriptor_t x509_attrs[] = +{ + { ADD_STRLEN( "CN" ), MBEDTLS_OID_AT_CN }, + { ADD_STRLEN( "commonName" ), MBEDTLS_OID_AT_CN }, + { ADD_STRLEN( "C" ), MBEDTLS_OID_AT_COUNTRY }, + { ADD_STRLEN( "countryName" ), MBEDTLS_OID_AT_COUNTRY }, + { ADD_STRLEN( "O" ), MBEDTLS_OID_AT_ORGANIZATION }, + { ADD_STRLEN( "organizationName" ), MBEDTLS_OID_AT_ORGANIZATION }, + { ADD_STRLEN( "L" ), MBEDTLS_OID_AT_LOCALITY }, + { ADD_STRLEN( "locality" ), MBEDTLS_OID_AT_LOCALITY }, + { ADD_STRLEN( "R" ), MBEDTLS_OID_PKCS9_EMAIL }, + { ADD_STRLEN( "OU" ), MBEDTLS_OID_AT_ORG_UNIT }, + { ADD_STRLEN( "organizationalUnitName" ), MBEDTLS_OID_AT_ORG_UNIT }, + { ADD_STRLEN( "ST" ), MBEDTLS_OID_AT_STATE }, + { ADD_STRLEN( "stateOrProvinceName" ), MBEDTLS_OID_AT_STATE }, + { ADD_STRLEN( "emailAddress" ), MBEDTLS_OID_PKCS9_EMAIL }, + { ADD_STRLEN( "serialNumber" ), MBEDTLS_OID_AT_SERIAL_NUMBER }, + { ADD_STRLEN( "postalAddress" ), MBEDTLS_OID_AT_POSTAL_ADDRESS }, + { ADD_STRLEN( "postalCode" ), MBEDTLS_OID_AT_POSTAL_CODE }, + { ADD_STRLEN( "dnQualifier" ), MBEDTLS_OID_AT_DN_QUALIFIER }, + { ADD_STRLEN( "title" ), MBEDTLS_OID_AT_TITLE }, + { ADD_STRLEN( "surName" ), MBEDTLS_OID_AT_SUR_NAME }, + { ADD_STRLEN( "SN" ), MBEDTLS_OID_AT_SUR_NAME }, + { ADD_STRLEN( "givenName" ), MBEDTLS_OID_AT_GIVEN_NAME }, + { ADD_STRLEN( "GN" ), MBEDTLS_OID_AT_GIVEN_NAME }, + { ADD_STRLEN( "initials" ), MBEDTLS_OID_AT_INITIALS }, + { ADD_STRLEN( "pseudonym" ), MBEDTLS_OID_AT_PSEUDONYM }, + { ADD_STRLEN( "generationQualifier" ), MBEDTLS_OID_AT_GENERATION_QUALIFIER }, + { ADD_STRLEN( "domainComponent" ), MBEDTLS_OID_DOMAIN_COMPONENT }, + { ADD_STRLEN( "DC" ), MBEDTLS_OID_DOMAIN_COMPONENT }, + { NULL, 0, NULL } +}; + +static const char *x509_at_oid_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; + + return( cur->oid ); +} + +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; + 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( ( oid = x509_at_oid_from_name( s, c - s ) ) == NULL ) + { + ret = MBEDTLS_ERR_X509_UNKNOWN_OID; + goto exit; + } + + 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 ) ) + { + if( mbedtls_asn1_store_named_data( head, oid, strlen( oid ), + (unsigned char *) data, + d - data ) == NULL ) + { + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + 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, + const char *oid, size_t oid_len, + const unsigned char *name, size_t name_len ) +{ + int ret; + size_t len = 0; + + // Write PrintableString for all except MBEDTLS_OID_PKCS9_EMAIL + // + if( MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_EMAIL ) == oid_len && + memcmp( oid, MBEDTLS_OID_PKCS9_EMAIL, oid_len ) == 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_ia5_string( p, start, + (const char *) name, + name_len ) ); + } + else + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_printable_string( p, start, + (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, (char *) cur->oid.p, + cur->oid.len, + cur->val.p, cur->val.len ) ); + 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/deps/mbedtls/x509_crl.c b/deps/mbedtls/x509_crl.c new file mode 100644 index 0000000000..76c49f1353 --- /dev/null +++ b/deps/mbedtls/x509_crl.c @@ -0,0 +1,723 @@ +/* + * 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 + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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 (no extensions parsed yet.) + */ +static int x509_get_crl_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* Get explicit tag */ + 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 ) + { + 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 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, *end; + 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( ( p = mbedtls_calloc( 1, buflen ) ) == 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 ); + } + + crl->version++; + + if( crl->version > 2 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_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_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_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_zeroize( entry_prv, sizeof( mbedtls_x509_crl_entry ) ); + mbedtls_free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + mbedtls_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_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/deps/mbedtls/x509_crt.c b/deps/mbedtls/x509_crt.c new file mode 100644 index 0000000000..a6dce95ba2 --- /dev/null +++ b/deps/mbedtls/x509_crt.c @@ -0,0 +1,2409 @@ +/* + * 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 + */ + +#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 +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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 ), +#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 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( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check pk_alg against profile + * Return 0 if pk_alg 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( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check key against profile + * Return 0 if pk_alg acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, + mbedtls_pk_type_t pk_alg, + const mbedtls_pk_context *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 ) + { + mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; + + if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) + return( 0 ); + + return( -1 ); + } +#endif + + return( -1 ); +} + +/* + * 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 only parse and use dNSName 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 ) + { + 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_CONTEXT_SPECIFIC ) != MBEDTLS_ASN1_CONTEXT_SPECIFIC ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + /* Skip everything but DNS name */ + if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) + { + *p += tag_len; + continue; + } + + /* 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 ); +} + +/* + * 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 */ + extn_oid.tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &extn_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + extn_oid.p = *p; + *p += extn_oid.len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* 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; + + default: + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + } + } + + 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 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 ); + } + + if( len > (size_t) ( end - p ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + crt_end = p + len; + + // Create and populate a new buffer for the raw field + crt->raw.len = crt_end - buf; + crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, crt->raw.len ); + + // Direct pointers to the new buffer + p += crt->raw.len - len; + end = crt_end = p + len; + + /* + * 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 ); + } + + crt->version++; + + if( crt->version > 3 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_UNKNOWN_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 + */ + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * 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 + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ) +{ + 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 ) ) != 0 ) + { + if( prev ) + prev->next = NULL; + + if( crt != chain ) + mbedtls_free( crt ); + + return( ret ); + } + + return( 0 ); +} + +/* + * 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_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 */ + +static int x509_info_subject_alt_name( char **buf, size_t *size, + const mbedtls_x509_sequence *subject_alt_name ) +{ + size_t i; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = subject_alt_name; + const char *sep = ""; + size_t sep_len = 0; + + while( cur != NULL ) + { + if( cur->buf.len + sep_len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + n -= cur->buf.len + sep_len; + for( i = 0; i < sep_len; i++ ) + *p++ = sep[i]; + for( i = 0; i < cur->buf.len; i++ ) + *p++ = cur->buf.p[i]; + + sep = ", "; + sep_len = 2; + + cur = cur->next; + } + + *p = '\0'; + + *size = n; + *buf = p; + + 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 ); +} + +/* + * 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 ) ) != 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 ); + } + + 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 is 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 || + crl_list->issuer_raw.len != ca->subject_raw.len || + memcmp( crl_list->issuer_raw.p, ca->subject_raw.p, + crl_list->issuer_raw.len ) != 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( md_info == NULL ) + { + /* + * Cannot check 'unknown' hash + */ + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ); + + if( x509_profile_check_key( profile, crl_list->sig_pk, &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 */ + +/* + * 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, mbedtls_x509_buf *name ) +{ + size_t i; + size_t cn_idx = 0, cn_len = strlen( cn ); + + if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + return( 0 ); + + 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 ); +} + +/* + * 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 + * bottom means child is the end entity cert + */ +static int x509_crt_check_parent( const mbedtls_x509_crt *child, + const mbedtls_x509_crt *parent, + int top, int bottom ) +{ + 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; + + /* Exception: self-signed end-entity certs that are locally trusted. */ + if( top && bottom && + child->raw.len == parent->raw.len && + memcmp( child->raw.p, parent->raw.p, child->raw.len ) == 0 ) + { + 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 ); +} + +static int x509_crt_verify_top( + mbedtls_x509_crt *child, mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + int path_cnt, int self_cnt, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + uint32_t ca_flags = 0; + int check_path_cnt; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + mbedtls_x509_crt *future_past_ca = NULL; + + 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; + + 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; + + /* + * Child is the top of the chain. Check against the trust_ca list. + */ + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown', no need to try any CA + */ + trust_ca = NULL; + } + else + mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); + + for( /* trust_ca */ ; trust_ca != NULL; trust_ca = trust_ca->next ) + { + if( x509_crt_check_parent( child, trust_ca, 1, path_cnt == 0 ) != 0 ) + continue; + + check_path_cnt = path_cnt + 1; + + /* + * Reduce check_path_cnt to check against if top of the chain is + * the same as the trusted CA + */ + if( child->subject_raw.len == trust_ca->subject_raw.len && + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) == 0 ) + { + check_path_cnt--; + } + + /* Self signed certificates do not count towards the limit */ + if( trust_ca->max_pathlen > 0 && + trust_ca->max_pathlen < check_path_cnt - self_cnt ) + { + continue; + } + + if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &trust_ca->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) != 0 ) + { + continue; + } + + if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) || + mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) + { + if ( future_past_ca == NULL ) + future_past_ca = trust_ca; + + continue; + } + + break; + } + + if( trust_ca != NULL || ( trust_ca = future_past_ca ) != NULL ) + { + /* + * Top of chain is signed by a trusted CA + */ + *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + } + + /* + * If top of chain is not the same as the trusted CA send a verify request + * to the callback for any issues with validity and CRL presence for the + * trusted CA certificate. + */ + if( trust_ca != NULL && + ( child->subject_raw.len != trust_ca->subject_raw.len || + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) != 0 ) ) + { +#if defined(MBEDTLS_X509_CRL_PARSE_C) + /* Check trusted CA's CRL for the chain's top crt */ + *flags |= x509_crt_verifycrl( child, trust_ca, ca_crl, profile ); +#else + ((void) ca_crl); +#endif + + if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) ) + ca_flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) + ca_flags |= MBEDTLS_X509_BADCERT_FUTURE; + + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, + &ca_flags ) ) != 0 ) + { + return( ret ); + } + } + } + + /* Call callback on top cert */ + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + } + + *flags |= ca_flags; + + return( 0 ); +} + +static int x509_crt_verify_child( + mbedtls_x509_crt *child, mbedtls_x509_crt *parent, + mbedtls_x509_crt *trust_ca, mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + int path_cnt, int self_cnt, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + uint32_t parent_flags = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + mbedtls_x509_crt *grandparent; + const mbedtls_md_info_t *md_info; + + /* Counting intermediate self signed certificates */ + if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + self_cnt++; + + /* path_cnt is 0 for the first intermediate CA */ + if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + } + + 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; + + 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; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown' hash + */ + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + } + else + { + mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); + + if( x509_profile_check_key( profile, child->sig_pk, &parent->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + } + } + +#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 ); +#endif + + /* Look for a grandparent in trusted CAs */ + for( grandparent = trust_ca; + grandparent != NULL; + grandparent = grandparent->next ) + { + if( x509_crt_check_parent( parent, grandparent, + 0, path_cnt == 0 ) == 0 ) + break; + } + + if( grandparent != NULL ) + { + ret = x509_crt_verify_top( parent, grandparent, ca_crl, profile, + path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + /* Look for a grandparent upwards the chain */ + for( grandparent = parent->next; + grandparent != NULL; + grandparent = grandparent->next ) + { + /* +2 because the current step is not yet accounted for + * and because max_pathlen is one higher than it should be. + * Also self signed certificates do not count to the limit. */ + if( grandparent->max_pathlen > 0 && + grandparent->max_pathlen < 2 + path_cnt - self_cnt ) + { + continue; + } + + if( x509_crt_check_parent( parent, grandparent, + 0, path_cnt == 0 ) == 0 ) + break; + } + + /* Is our parent part of the chain or at the top? */ + if( grandparent != NULL ) + { + ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, + profile, path_cnt + 1, self_cnt, &parent_flags, + f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509_crt_verify_top( parent, trust_ca, ca_crl, profile, + path_cnt + 1, self_cnt, &parent_flags, + f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + } + + /* child is verified to be a child of the parent, call verify callback */ + if( NULL != f_vrfy ) + if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + + *flags |= parent_flags; + + return( 0 ); +} + +/* + * Verify the certificate validity + */ +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( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl, + &mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) ); +} + + +/* + * Verify the certificate validity, with profile + */ +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 ) +{ + size_t cn_len; + int ret; + int pathlen = 0, selfsigned = 0; + mbedtls_x509_crt *parent; + mbedtls_x509_name *name; + mbedtls_x509_sequence *cur = NULL; + mbedtls_pk_type_t pk_type; + + if( profile == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + *flags = 0; + + if( cn != NULL ) + { + name = &crt->subject; + cn_len = strlen( cn ); + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + cur = &crt->subject_alt_names; + + while( cur != NULL ) + { + if( cur->buf.len == cn_len && + x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) + break; + + if( cur->buf.len > 2 && + memcmp( cur->buf.p, "*.", 2 ) == 0 && + x509_check_wildcard( cn, &cur->buf ) == 0 ) + { + break; + } + + cur = cur->next; + } + + if( cur == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + else + { + while( name != NULL ) + { + if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 ) + { + if( name->val.len == cn_len && + x509_memcasecmp( name->val.p, cn, cn_len ) == 0 ) + break; + + if( name->val.len > 2 && + memcmp( name->val.p, "*.", 2 ) == 0 && + x509_check_wildcard( cn, &name->val ) == 0 ) + break; + } + + name = name->next; + } + + if( name == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + } + + /* 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 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + if( x509_profile_check_key( profile, pk_type, &crt->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + /* Look for a parent in trusted CAs */ + for( parent = trust_ca; parent != NULL; parent = parent->next ) + { + if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) + break; + } + + if( parent != NULL ) + { + ret = x509_crt_verify_top( crt, parent, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + /* Look for a parent upwards the chain */ + for( parent = crt->next; parent != NULL; parent = parent->next ) + if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) + break; + + /* Are we part of the chain or at the top? */ + if( parent != NULL ) + { + ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + } + + if( *flags != 0 ) + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + + return( 0 ); +} + +/* + * 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_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_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_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_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + if( cert_cur->raw.p != NULL ) + { + mbedtls_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_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); + if( cert_prv != crt ) + mbedtls_free( cert_prv ); + } + while( cert_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRT_PARSE_C */ diff --git a/deps/mbedtls/x509_csr.c b/deps/mbedtls/x509_csr.c new file mode 100644 index 0000000000..f92b66c58f --- /dev/null +++ b/deps/mbedtls/x509_csr.c @@ -0,0 +1,423 @@ +/* + * 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 + +#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 + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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 ); + } + + csr->version++; + + if( csr->version != 1 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_UNKNOWN_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) + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( buf[buflen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE REQUEST-----", + "-----END CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded, parse the result + */ + if( ( ret = mbedtls_x509_csr_parse_der( csr, pem.buf, pem.buflen ) ) != 0 ) + return( ret ); + + mbedtls_pem_free( &pem ); + return( 0 ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + else +#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_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_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + if( csr->raw.p != NULL ) + { + mbedtls_zeroize( csr->raw.p, csr->raw.len ); + mbedtls_free( csr->raw.p ); + } + + mbedtls_zeroize( csr, sizeof( mbedtls_x509_csr ) ); +} + +#endif /* MBEDTLS_X509_CSR_PARSE_C */ diff --git a/deps/mbedtls/x509write_crt.c b/deps/mbedtls/x509write_crt.c new file mode 100644 index 0000000000..d1d9a22a7e --- /dev/null +++ b/deps/mbedtls/x509write_crt.c @@ -0,0 +1,459 @@ +/* + * 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 + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif /* MBEDTLS_PEM_WRITE_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +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_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 ) ); + + mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + 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 ) ); + + mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + 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[4], ku; + unsigned char *c; + int ret; + + /* We currently only support 7 bits, from 0x80 to 0x02 */ + if( ( key_usage & ~0xfe ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + + c = buf + 4; + ku = (unsigned char) key_usage; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + 1, buf, 4 ); + 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; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + 0, buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +static int x509_write_time( unsigned char **p, unsigned char *start, + const char *time, size_t size ) +{ + int ret; + size_t len = 0; + + /* + * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) + */ + if( time[0] == '2' && time[1] == '0' && time [2] < '5' ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) time + 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 *) time, + 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 */ + pk_alg = mbedtls_pk_get_type( ctx->issuer_key ); + if( pk_alg == MBEDTLS_PK_ECKEY ) + pk_alg = MBEDTLS_PK_ECDSA; + + 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 + */ + 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) } + */ + 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 + */ + mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); + + 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/deps/mbedtls/x509write_csr.c b/deps/mbedtls/x509write_csr.c new file mode 100644 index 0000000000..8fd856b2a2 --- /dev/null +++ b/deps/mbedtls/x509write_csr.c @@ -0,0 +1,259 @@ +/* + * 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 +#include + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +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_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; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + buf, 4 ); + 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; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + buf, 4 ); + 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; + + /* + * 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 + */ + mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); + + pk_alg = mbedtls_pk_get_type( ctx->key ); + if( pk_alg == MBEDTLS_PK_ECKEY ) + pk_alg = MBEDTLS_PK_ECDSA; + + if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 || + ( 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/deps/mbedtls/xtea.c b/deps/mbedtls/xtea.c new file mode 100644 index 0000000000..fe0a3509f6 --- /dev/null +++ b/deps/mbedtls/xtea.c @@ -0,0 +1,281 @@ +/* + * 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 + +#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) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 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_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/dist-scripts/dist-cores.sh b/dist-scripts/dist-cores.sh index 360eb879b6..dd708f539b 100755 --- a/dist-scripts/dist-cores.sh +++ b/dist-scripts/dist-cores.sh @@ -1,6 +1,6 @@ #!/bin/sh -RARCH_VERSION=1.3.6 +RARCH_VERSION=1.6.7 PLATFORM=$1 SALAMANDER=no MAKEFILE_GRIFFIN=no @@ -90,6 +90,8 @@ SCETOOL_PATH=${PS3TOOLS_PATH}/scetool/scetool.exe SCETOOL_FLAGS_CORE="--sce-type=SELF --compress-data=TRUE --skip-sections=TRUE --key-revision=04 --self-auth-id=1010000001000003 --self-vendor-id=01000002 --self-type=APP --self-app-version=0001000000000000 --self-fw-version=0003004100000000 --encrypt" SCETOOL_FLAGS_EBOOT="--sce-type=SELF --compress-data=TRUE --skip-sections=TRUE --key-revision=04 --self-auth-id=1010000001000003 --self-vendor-id=01000002 --self-type=NPDRM --self-fw-version=0003004100000000 --np-license-type=FREE --np-content-id=UP0001-SSNE10000_00-0000000000000001 --np-app-type=EXEC --self-app-version=0001000000000000 --np-real-fname=EBOOT.BIN --encrypt" +cp -rfv ${PS3TOOLS_PATH}/scetool/data . + # ODE PS3 elif [ $PLATFORM = "ode-ps3" ]; then #For this script to work correctly, you must place scetool.exe and the "data" folder containing your ps3 keys for scetool to use in the dist-scripts folder. @@ -418,6 +420,8 @@ if [ $PLATFORM = "dex-ps3" ] ; then elif [ $PLATFORM = "cex-ps3" ] ; then $SCETOOL_PATH $SCETOOL_FLAGS_EBOOT ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN rm -rf ../retroarch-salamander_${platform}.elf + (cd ../tools/ps3/ps3py && python2 setup.py build) + find ../tools/ps3/ps3py/build -name '*.dll' -exec cp {} ../tools/ps3/ps3py \; ../tools/ps3/ps3py/pkg.py --contentid UP0001-SSNE10000_00-0000000000000001 ../pkg/${platform}/SSNE10000/ ../pkg/${platform}/RetroArch.PS3.CEX.PS3.pkg elif [ $PLATFORM = "ode-ps3" ] ; then $SCETOOL_PATH $SCETOOL_FLAGS_ODE ../retroarch-salamander_${platform}.elf ../pkg/${platform}_iso/PS3_GAME/USRDIR/EBOOT.BIN diff --git a/dynamic.c b/dynamic.c index 6e07579230..873ca7316b 100644 --- a/dynamic.c +++ b/dynamic.c @@ -92,8 +92,9 @@ static dylib_t lib_handle; #define SYMBOL_VIDEOPROCESSOR(x) current_core->x = libretro_videoprocessor_##x #endif -static bool ignore_environment_cb = false; -static bool *load_no_content_hook = NULL; +static bool ignore_environment_cb = false; +static bool core_set_shared_context = false; +static bool *load_no_content_hook = NULL; const struct retro_subsystem_info *libretro_find_subsystem_info( const struct retro_subsystem_info *info, unsigned num_info, @@ -632,6 +633,11 @@ bool init_libretro_sym(enum rarch_core_type type, struct retro_core_t *current_c return true; } +bool libretro_get_shared_context(void) +{ + return core_set_shared_context; +} + /** * uninit_libretro_sym: * @@ -651,6 +657,8 @@ void uninit_libretro_sym(struct retro_core_t *current_core) memset(current_core, 0, sizeof(struct retro_core_t)); + core_set_shared_context = false; + rarch_ctl(RARCH_CTL_CORE_OPTIONS_DEINIT, NULL); rarch_ctl(RARCH_CTL_SYSTEM_INFO_FREE, NULL); rarch_ctl(RARCH_CTL_FRAME_TIME_FREE, NULL); @@ -1016,7 +1024,7 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: - if (string_is_empty(settings->paths.directory_system)) + if (string_is_empty(settings->paths.directory_system) || settings->bools.systemfiles_in_content_dir) { const char *fullpath = path_get(RARCH_PATH_CONTENT); if (!string_is_empty(fullpath)) @@ -1025,8 +1033,9 @@ bool rarch_environment_cb(unsigned cmd, void *data) temp_path[0] = '\0'; - RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", - fullpath); + if (string_is_empty(settings->paths.directory_system)) + RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", + fullpath); fill_pathname_basedir(temp_path, fullpath, sizeof(temp_path)); dir_set(RARCH_DIR_SYSTEM, temp_path); } @@ -1633,6 +1642,12 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; } + case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT: + { + core_set_shared_context = true; + break; + } + /* Default */ default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); diff --git a/dynamic.h b/dynamic.h index 6999486be8..d2b529520b 100644 --- a/dynamic.h +++ b/dynamic.h @@ -117,6 +117,8 @@ struct retro_core_t uint64_t serialization_quirks_v; }; +bool libretro_get_shared_context(void); + /** * init_libretro_sym: * @type : Type of core to be loaded. diff --git a/file_path_special.h b/file_path_special.h index ef72101d49..e763f78a7f 100644 --- a/file_path_special.h +++ b/file_path_special.h @@ -34,6 +34,7 @@ enum file_path_enum FILE_PATH_LOG_ERROR, FILE_PATH_LOG_INFO, FILE_PATH_CONTENT_HISTORY, + FILE_PATH_CONTENT_FAVORITES, FILE_PATH_CONTENT_MUSIC_HISTORY, FILE_PATH_CONTENT_VIDEO_HISTORY, FILE_PATH_CONTENT_IMAGE_HISTORY, @@ -82,6 +83,9 @@ enum file_path_enum FILE_PATH_7Z_EXTENSION, FILE_PATH_OGG_EXTENSION, FILE_PATH_WAV_EXTENSION, + FILE_PATH_MOD_EXTENSION, + FILE_PATH_S3M_EXTENSION, + FILE_PATH_XM_EXTENSION, FILE_PATH_CONFIG_EXTENSION, FILE_PATH_CORE_INFO_EXTENSION }; diff --git a/file_path_str.c b/file_path_str.c index c66af6d97a..ce976bf261 100644 --- a/file_path_str.c +++ b/file_path_str.c @@ -107,6 +107,15 @@ const char *file_path_str(enum file_path_enum enum_idx) case FILE_PATH_WAV_EXTENSION: str = ".wav"; break; + case FILE_PATH_MOD_EXTENSION: + str = ".mod"; + break; + case FILE_PATH_S3M_EXTENSION: + str = ".s3m"; + break; + case FILE_PATH_XM_EXTENSION: + str = ".xm"; + break; case FILE_PATH_JPEG_EXTENSION: str = ".jpeg"; break; @@ -185,6 +194,9 @@ const char *file_path_str(enum file_path_enum enum_idx) case FILE_PATH_CONTENT_HISTORY: str = "content_history.lpl"; break; + case FILE_PATH_CONTENT_FAVORITES: + str = "content_favorites.lpl"; + break; case FILE_PATH_CONTENT_MUSIC_HISTORY: str = "content_music_history.lpl"; break; diff --git a/frontend/drivers/platform_gx.c b/frontend/drivers/platform_gx.c index 986d8b80e2..8443348c63 100644 --- a/frontend/drivers/platform_gx.c +++ b/frontend/drivers/platform_gx.c @@ -76,29 +76,29 @@ enum #if defined(HAVE_LOGGER) || defined(HAVE_FILE_LOGGER) static devoptab_t dotab_stdout = { - "stdout", // device name - 0, // size of file structure - NULL, // device open - NULL, // device close - NULL, // device write - NULL, // device read - NULL, // device seek - NULL, // device fstat - NULL, // device stat - NULL, // device link - NULL, // device unlink - NULL, // device chdir - NULL, // device rename - NULL, // device mkdir - 0, // dirStateSize - NULL, // device diropen_r - NULL, // device dirreset_r - NULL, // device dirnext_r - NULL, // device dirclose_r - NULL, // device statvfs_r - NULL, // device ftrunctate_r - NULL, // device fsync_r - NULL, // deviceData; + "stdout", /* device name */ + 0, /* size of file structure */ + NULL, /* device open */ + NULL, /* device close */ + NULL, /* device write */ + NULL, /* device read */ + NULL, /* device seek */ + NULL, /* device fstat */ + NULL, /* device stat */ + NULL, /* device link */ + NULL, /* device unlink */ + NULL, /* device chdir */ + NULL, /* device rename */ + NULL, /* device mkdir */ + 0, /* dirStateSize */ + NULL, /* device diropen_r */ + NULL, /* device dirreset_r */ + NULL, /* device dirnext_r */ + NULL, /* device dirclose_r */ + NULL, /* device statvfs_r */ + NULL, /* device ftrunctate_r */ + NULL, /* device fsync_r */ + NULL, /* deviceData; */ }; #endif @@ -309,7 +309,9 @@ static void frontend_gx_init(void *data) __exception_setreload(8); #endif +#ifdef HW_RVL fatInitDefault(); +#endif #ifdef HAVE_LOGGER devoptab_list[STD_OUT] = &dotab_stdout; diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index b53cf33e35..eddd9a99eb 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -1557,18 +1557,6 @@ static void frontend_unix_get_env(int *argc, fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS], app_dir, "assets/wallpapers", sizeof(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS])); - if(!string_is_empty(downloads_dir) && test_permissions(downloads_dir)) - { - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], - downloads_dir, "", - sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); - } - else - { - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], - app_dir, "downloads", - sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); - } __android_log_print(ANDROID_LOG_INFO, "RetroArch", "[ENV]: default download folder: [%s]", @@ -1576,8 +1564,7 @@ static void frontend_unix_get_env(int *argc, switch (perms) { - /* Set defaults for this since we can't guarantee - * saving on content dir will work in this case */ + /* only sdcard/Android/data/com.retroarch is writable */ case INTERNAL_STORAGE_APPDIR_WRITABLE: fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], internal_storage_app_path, "saves", @@ -1605,11 +1592,11 @@ static void frontend_unix_get_env(int *argc, internal_storage_app_path, "cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); - if( !string_is_empty(screenshot_dir) - && test_permissions(screenshot_dir)) + if(!string_is_empty(screenshot_dir) + && test_permissions(screenshot_dir)) { fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], - screenshot_dir, "", + screenshot_dir, "RetroArch", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } else @@ -1619,10 +1606,24 @@ static void frontend_unix_get_env(int *argc, sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } + if(!string_is_empty(downloads_dir) + && test_permissions(downloads_dir)) + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + downloads_dir, "RetroArch", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + else + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + internal_storage_app_path, "downloads", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + break; + + /* only the internal app dir is writable, this should never happen*/ case INTERNAL_STORAGE_NOT_WRITABLE: - /* Set defaults for this since we can't guarantee - * saving on content dir will work in this case. */ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], app_dir, "saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); @@ -1653,7 +1654,7 @@ static void frontend_unix_get_env(int *argc, && test_permissions(screenshot_dir)) { fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], - screenshot_dir, "", + screenshot_dir, "RetroArch", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } else @@ -1663,10 +1664,40 @@ static void frontend_unix_get_env(int *argc, sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } + if(!string_is_empty(downloads_dir) + && test_permissions(downloads_dir)) + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + downloads_dir, "RetroArch", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + else + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + app_dir, "downloads", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + break; + /* sdcard is writable, this should be the case most of the time*/ case INTERNAL_STORAGE_WRITABLE: - /* Don't set defaults for saves, states, system or screenshots - in this case to be able to honour saving on content dir */ + + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], + internal_storage_path, "RetroArch/saves", + sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], + internal_storage_path, "RetroArch/states", + sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + internal_storage_path, "RetroArch/system", + sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], + internal_storage_path, "RetroArch/screenshots", + sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + internal_storage_path, "RetroArch/downloads", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], internal_storage_path, "RetroArch/config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); diff --git a/frontend/drivers/platform_wii.c b/frontend/drivers/platform_wii.c index c50a2902a9..ac5ebfaea3 100644 --- a/frontend/drivers/platform_wii.c +++ b/frontend/drivers/platform_wii.c @@ -73,10 +73,15 @@ static void dol_copy_argv_path(const char *dolpath, const char *argpath) len += t_len; } /* a relative path */ - else if (strstr(dolpath, "sd:/") != dolpath && strstr(dolpath, "usb:/") != dolpath && - strstr(dolpath, "carda:/") != dolpath && strstr(dolpath, "cardb:/") != dolpath) + else if ( + (strstr(dolpath, "sd:/") != dolpath) && + (strstr(dolpath, "usb:/") != dolpath) && + (strstr(dolpath, "carda:/") != dolpath) && + (strstr(dolpath, "cardb:/") != dolpath) + ) { - fill_pathname_parent_dir(tmp, __system_argv->argv[0], sizeof(tmp)); + fill_pathname_parent_dir(tmp, + __system_argv->argv[0], sizeof(tmp)); t_len = strlen(tmp); memcpy(cmdline, tmp, t_len); len += t_len; diff --git a/frontend/drivers/platform_wiiu.c b/frontend/drivers/platform_wiiu.c index 50323f295b..eb489d750c 100644 --- a/frontend/drivers/platform_wiiu.c +++ b/frontend/drivers/platform_wiiu.c @@ -48,7 +48,6 @@ #include "system/dynamic.h" #include "system/memory.h" #include "system/exception_handler.h" -#include "system/exception.h" #include #include @@ -408,11 +407,7 @@ static bool swap_is_pending(void* start_time) int main(int argc, char **argv) { -#if 1 setup_os_exceptions(); -#else - InstallExceptionHandler(); -#endif ProcUIInit(&SaveCallback); #ifdef IS_SALAMANDER diff --git a/frontend/drivers/platform_win32.c b/frontend/drivers/platform_win32.c index 5133f0c27e..02ae1dd7d3 100644 --- a/frontend/drivers/platform_win32.c +++ b/frontend/drivers/platform_win32.c @@ -46,6 +46,9 @@ */ static dylib_t dwmlib; +static dylib_t shell32lib; + +VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); static bool dwm_composition_disabled; @@ -55,25 +58,39 @@ static void gfx_dwm_shutdown(void) { if (dwmlib) dylib_close(dwmlib); - dwmlib = NULL; + if (shell32lib) + dylib_close(shell32lib); + dwmlib = NULL; + shell32lib = NULL; } static bool gfx_init_dwm(void) { + HRESULT (WINAPI *mmcss)(BOOL); static bool inited = false; if (inited) return true; + atexit(gfx_dwm_shutdown); + + shell32lib = dylib_load("shell32.dll"); + if (!shell32lib) + { + RARCH_WARN("Did not find shell32.dll.\n"); + } + dwmlib = dylib_load("dwmapi.dll"); if (!dwmlib) { - RARCH_LOG("Did not find dwmapi.dll.\n"); + RARCH_WARN("Did not find dwmapi.dll.\n"); return false; } - atexit(gfx_dwm_shutdown); - HRESULT (WINAPI *mmcss)(BOOL) = + DragAcceptFiles_func = + (VOID (WINAPI*)(HWND, BOOL))dylib_proc(shell32lib, "DragAcceptFiles"); + + mmcss = (HRESULT (WINAPI*)(BOOL))dylib_proc(dwmlib, "DwmEnableMMCSS"); if (mmcss) { @@ -88,6 +105,7 @@ static bool gfx_init_dwm(void) static void gfx_set_dwm(void) { HRESULT ret; + HRESULT (WINAPI *composition_enable)(UINT); settings_t *settings = config_get_ptr(); if (!gfx_init_dwm()) @@ -96,7 +114,7 @@ static void gfx_set_dwm(void) if (settings->bools.video_disable_composition == dwm_composition_disabled) return; - HRESULT (WINAPI *composition_enable)(UINT) = + composition_enable = (HRESULT (WINAPI*)(UINT))dylib_proc(dwmlib, "DwmEnableComposition"); if (!composition_enable) { @@ -278,9 +296,9 @@ static void frontend_win32_environment_get(int *argc, char *argv[], fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], ":\\playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG], - ":\\records_config", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG])); + ":\\config\\record", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT], - ":\\records", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT])); + ":\\recordings", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], ":\\config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_REMAP], @@ -303,6 +321,12 @@ static void frontend_win32_environment_get(int *argc, char *argv[], ":\\downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], ":\\screenshots", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SRAM], + ":\\saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], + ":\\states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + ":\\system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); #ifdef HAVE_MENU #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) diff --git a/gfx/common/gdi_common.h b/gfx/common/gdi_common.h index 5abf72d35f..0b7872ab4d 100644 --- a/gfx/common/gdi_common.h +++ b/gfx/common/gdi_common.h @@ -21,6 +21,14 @@ typedef struct gdi { WNDCLASSEX wndclass; + HDC winDC; + HDC memDC; + HBITMAP bmp; + HBITMAP bmp_old; + unsigned video_width; + unsigned video_height; + unsigned screen_width; + unsigned screen_height; } gdi_t; #endif diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index b8f6c32fac..e2c64f2ffc 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -772,9 +772,12 @@ static void vulkan_check_dynamic_state( if (vk->tracker.dirty & VULKAN_DIRTY_DYNAMIC_BIT) { - const VkRect2D sci = { - { vk->vp.x, vk->vp.y }, - { vk->vp.width, vk->vp.height }}; + VkRect2D sci; + + sci.offset.x = vk->vp.x; + sci.offset.y = vk->vp.y; + sci.extent.width = vk->vp.width; + sci.extent.height = vk->vp.height; vkCmdSetViewport(vk->cmd, 0, 1, &vk->vk_vp); vkCmdSetScissor (vk->cmd, 0, 1, &sci); @@ -1144,8 +1147,15 @@ struct vk_buffer_chain vulkan_buffer_chain_init( VkDeviceSize alignment, VkBufferUsageFlags usage) { - struct vk_buffer_chain chain = { - block_size, alignment, 0, usage, NULL, NULL }; + struct vk_buffer_chain chain; + + chain.block_size = block_size; + chain.alignment = alignment; + chain.offset = 0; + chain.usage = usage; + chain.head = NULL; + chain.current = NULL; + return chain; } @@ -1487,12 +1497,13 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) for (i = 0; i < queue_count; i++) { + VkQueueFlags required; VkBool32 supported = VK_FALSE; vkGetPhysicalDeviceSurfaceSupportKHR( vk->context.gpu, i, vk->vk_surface, &supported); - VkQueueFlags required = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; + required = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; if (supported && ((queue_properties[i].queueFlags & required) == required)) { vk->context.graphics_queue_index = i; @@ -1573,6 +1584,7 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, { unsigned i; VkResult res; + PFN_vkGetInstanceProcAddr GetInstanceProcAddr; VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; @@ -1647,7 +1659,7 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, RARCH_LOG("Vulkan dynamic library loaded.\n"); - PFN_vkGetInstanceProcAddr GetInstanceProcAddr = + GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dylib_proc(vulkan_library, "vkGetInstanceProcAddr"); if (!GetInstanceProcAddr) @@ -2018,10 +2030,11 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk, case VULKAN_WSI_WIN32: #ifdef _WIN32 { + VkWin32SurfaceCreateInfoKHR surf_info; PFN_vkCreateWin32SurfaceKHR create; + if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateWin32SurfaceKHR", create)) return false; - VkWin32SurfaceCreateInfoKHR surf_info; memset(&surf_info, 0, sizeof(surf_info)); diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.c similarity index 79% rename from gfx/common/win32_common.cpp rename to gfx/common/win32_common.c index 3801f92700..f987602bfc 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.c @@ -21,6 +21,7 @@ #endif #include "win32_common.h" +#include "gdi_common.h" #include "../../frontend/frontend_driver.h" #include "../../configuration.h" #include "../../verbosity.h" @@ -50,20 +51,12 @@ #include "../../menu/menu_driver.h" #endif -#ifndef _MSC_VER -extern "C" { -#endif - #include -LRESULT win32_menu_loop(HWND owner, WPARAM wparam); - -#ifndef _MSC_VER -} -#endif +extern LRESULT win32_menu_loop(HWND owner, WPARAM wparam); #ifdef HAVE_D3D9 -extern "C" bool dinput_handle_message(void *dinput, UINT message, +extern bool dinput_handle_message(void *dinput, UINT message, WPARAM wParam, LPARAM lParam); extern void *dinput_gdi; extern void *dinput_wgl; @@ -128,18 +121,15 @@ static HMONITOR win32_monitor_last; static HMONITOR win32_monitor_all[MAX_MONITORS]; static unsigned win32_monitor_count = 0; -extern "C" +bool doubleclick_on_titlebar_pressed(void) { - bool doubleclick_on_titlebar_pressed(void) - { - return doubleclick_on_titlebar; - } + return doubleclick_on_titlebar; +} - void unset_doubleclick_on_titlebar(void) - { - doubleclick_on_titlebar = false; - } -}; +void unset_doubleclick_on_titlebar(void) +{ + doubleclick_on_titlebar = false; +} INT_PTR CALLBACK PickCoreProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) @@ -184,10 +174,12 @@ INT_PTR CALLBACK PickCoreProc(HWND hDlg, UINT message, { case LBN_SELCHANGE: { - int lbItem; const core_info_t *info = NULL; - HWND hwndList = GetDlgItem(hDlg, ID_CORELISTBOX); - lbItem = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0); + HWND hwndList = GetDlgItem( + hDlg, ID_CORELISTBOX); + int lbItem = (int) + SendMessage(hwndList, LB_GETCURSEL, 0, 0); + core_info_get_list(&core_info_list); core_info_list_get_supported_cores(core_info_list, path_get(RARCH_PATH_CONTENT), &core_info, &list_size); @@ -214,8 +206,12 @@ static BOOL CALLBACK win32_monitor_enum_proc(HMONITOR hMonitor, void win32_monitor_from_window(void) { #ifndef _XBOX - win32_monitor_last = MonitorFromWindow(main_window.hwnd, MONITOR_DEFAULTTONEAREST); - const ui_window_t *window = ui_companion_driver_get_window_ptr(); + ui_window_t *window = NULL; + + win32_monitor_last = + MonitorFromWindow(main_window.hwnd, MONITOR_DEFAULTTONEAREST); + + window = (ui_window_t*)ui_companion_driver_get_window_ptr(); if (window) window->destroy(&main_window); @@ -229,23 +225,23 @@ void win32_monitor_get_info(void) memset(¤t_mon, 0, sizeof(current_mon)); current_mon.cbSize = sizeof(MONITORINFOEX); - GetMonitorInfo(win32_monitor_last, (MONITORINFOEX*)¤t_mon); + GetMonitorInfo(win32_monitor_last, (LPMONITORINFO)¤t_mon); ChangeDisplaySettingsEx(current_mon.szDevice, NULL, NULL, 0, NULL); } void win32_monitor_info(void *data, void *hm_data, unsigned *mon_id) { unsigned i; - settings_t *settings = config_get_ptr(); - MONITORINFOEX *mon = (MONITORINFOEX*)data; - HMONITOR *hm_to_use = (HMONITOR*)hm_data; - unsigned fs_monitor = settings->uints.video_monitor_index; + settings_t *settings = config_get_ptr(); + MONITORINFOEX *mon = (MONITORINFOEX*)data; + HMONITOR *hm_to_use = (HMONITOR*)hm_data; + unsigned fs_monitor = settings->uints.video_monitor_index; if (!win32_monitor_last) win32_monitor_last = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST); - *hm_to_use = win32_monitor_last; + *hm_to_use = win32_monitor_last; if (fs_monitor && fs_monitor <= win32_monitor_count && win32_monitor_all[fs_monitor - 1]) @@ -267,7 +263,7 @@ void win32_monitor_info(void *data, void *hm_data, unsigned *mon_id) memset(mon, 0, sizeof(*mon)); mon->cbSize = sizeof(MONITORINFOEX); - GetMonitorInfo(*hm_to_use, (MONITORINFOEX*)mon); + GetMonitorInfo(*hm_to_use, (LPMONITORINFO)mon); } /* Get the count of the files dropped */ @@ -480,14 +476,14 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, { g_resize_width = LOWORD(lparam); g_resize_height = HIWORD(lparam); - g_resized = true; + g_resized = true; } *quit = true; break; case WM_COMMAND: { settings_t *settings = config_get_ptr(); - if (settings->bools.ui_menubar_enable) + if (settings && settings->bools.ui_menubar_enable) win32_menu_loop(main_window.hwnd, wparam); } break; @@ -495,7 +491,13 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, return 0; } -extern void ui_window_win32_set_droppable(void *data, bool droppable); +extern VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); + +static void win32_set_droppable(ui_window_win32_t *window, bool droppable) +{ + if (DragAcceptFiles_func != NULL) + DragAcceptFiles_func(window->hwnd, droppable); +} #ifdef HAVE_D3D9 LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message, @@ -533,12 +535,13 @@ LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message, win32_window.hwnd = hwnd; - ui_window_win32_set_droppable(&win32_window, true); + win32_set_droppable(&win32_window, true); } return 0; } - if (dinput && dinput_handle_message(dinput, message, wparam, lparam)) + if (dinput && dinput_handle_message(dinput, + message, wparam, lparam)) return 0; return DefWindowProc(hwnd, message, wparam, lparam); } @@ -568,7 +571,8 @@ LRESULT CALLBACK WndProcGL(HWND hwnd, UINT message, case WM_QUIT: case WM_SIZE: case WM_COMMAND: - ret = WndProcCommon(&quit, hwnd, message, wparam, lparam); + ret = WndProcCommon(&quit, + hwnd, message, wparam, lparam); if (quit) return ret; break; @@ -579,13 +583,14 @@ LRESULT CALLBACK WndProcGL(HWND hwnd, UINT message, create_graphics_context(hwnd, &g_quit); - ui_window_win32_set_droppable(&win32_window, true); + win32_set_droppable(&win32_window, true); } return 0; } #ifdef HAVE_D3D9 - if (dinput_wgl && dinput_handle_message(dinput_wgl, message, wparam, lparam)) + if (dinput_wgl && dinput_handle_message(dinput_wgl, + message, wparam, lparam)) return 0; #endif return DefWindowProc(hwnd, message, wparam, lparam); @@ -605,41 +610,47 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, { case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); + gdi_t *gdi = (gdi_t*)video_driver_get_ptr(false); + + if (gdi && gdi->memDC) + { + gdi->bmp_old = (HBITMAP)SelectObject(gdi->memDC, gdi->bmp); #ifdef HAVE_MENU - if (menu_driver_is_alive() && !gdi_has_menu_frame()) - { - RECT rect; - TRIVERTEX vertex[2]; - GRADIENT_RECT gRect; + if (menu_driver_is_alive() && !gdi_has_menu_frame()) + { + /* draw menu contents behind a gradient background */ + if (gdi && gdi->memDC) + { + RECT rect; + GetClientRect(hwnd, &rect); - GetClientRect(hwnd, &rect); + StretchBlt(gdi->winDC, + 0, 0, + gdi->screen_width, gdi->screen_height, + gdi->memDC, 0, 0, gdi->video_width, gdi->video_height, SRCCOPY); - vertex[0].x = rect.left; - vertex[0].y = rect.top; - vertex[0].Red = 1 << 8; - vertex[0].Green = 81 << 8; - vertex[0].Blue = 127 << 8; - vertex[0].Alpha = 0; - - vertex[1].x = rect.right; - vertex[1].y = rect.bottom; - vertex[1].Red = 0; - vertex[1].Green = 1 << 8; - vertex[1].Blue = 33 << 8; - vertex[1].Alpha = 0; - - gRect.LowerRight = 0; - gRect.UpperLeft = 1; - - GradientFill(hdc, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_V); - } + HBRUSH brush = CreateSolidBrush(RGB(1,81,127)); + FillRect(gdi->memDC, &rect, brush); + DeleteObject(brush); + } + } + else #endif + { + /* draw video content */ + gdi->bmp_old = (HBITMAP)SelectObject(gdi->memDC, gdi->bmp); - EndPaint(hwnd, &ps); - break; + StretchBlt(gdi->winDC, + 0, 0, + gdi->screen_width, gdi->screen_height, + gdi->memDC, 0, 0, gdi->video_width, gdi->video_height, SRCCOPY); + } + + SelectObject(gdi->memDC, gdi->bmp_old); + } + + break; } case WM_DROPFILES: case WM_SYSCOMMAND: @@ -664,13 +675,14 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, create_gdi_context(hwnd, &g_quit); - ui_window_win32_set_droppable(&win32_window, true); + win32_set_droppable(&win32_window, true); } return 0; } #ifdef HAVE_D3D9 - if (dinput_gdi && dinput_handle_message(dinput_gdi, message, wparam, lparam)) + if (dinput_gdi && dinput_handle_message(dinput_gdi, + message, wparam, lparam)) return 0; #endif return DefWindowProc(hwnd, message, wparam, lparam); @@ -681,7 +693,8 @@ bool win32_window_create(void *data, unsigned style, unsigned height, bool fullscreen) { #ifndef _XBOX - main_window.hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", + main_window.hwnd = CreateWindowEx(0, + "RetroArch", "RetroArch", style, fullscreen ? mon_rect->left : g_pos_x, fullscreen ? mon_rect->top : g_pos_y, @@ -738,13 +751,15 @@ void win32_monitor_init(void) { #ifndef _XBOX win32_monitor_count = 0; - EnumDisplayMonitors(NULL, NULL, win32_monitor_enum_proc, 0); + EnumDisplayMonitors(NULL, NULL, + win32_monitor_enum_proc, 0); #endif g_quit = false; } -static bool win32_monitor_set_fullscreen(unsigned width, unsigned height, +static bool win32_monitor_set_fullscreen( + unsigned width, unsigned height, unsigned refresh, char *dev_name) { #ifndef _XBOX @@ -755,7 +770,8 @@ static bool win32_monitor_set_fullscreen(unsigned width, unsigned height, devmode.dmPelsWidth = width; devmode.dmPelsHeight = height; devmode.dmDisplayFrequency = refresh; - devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + devmode.dmFields = DM_PELSWIDTH + | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; RARCH_LOG("Setting fullscreen to %ux%u @ %uHz on device %s.\n", width, height, refresh, dev_name); @@ -797,10 +813,7 @@ void win32_check_window(bool *quit, bool *resize, bool win32_suppress_screensaver(void *data, bool enable) { -#ifdef _XBOX - return false; -#else - +#ifndef _XBOX if(enable) { int major, minor; @@ -849,9 +862,9 @@ bool win32_suppress_screensaver(void *data, bool enable) return true; } } +#endif return false; -#endif } /* FIXME: It should not be necessary to add the W after MONITORINFOEX, but linking fails without it. */ @@ -887,7 +900,7 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, {} /* Display settings might have changed, get new coordinates. */ - GetMonitorInfo(*hm_to_use, (MONITORINFOEX*)current_mon); + GetMonitorInfo(*hm_to_use, (LPMONITORINFO)current_mon); *mon_rect = current_mon->rcMonitor; } } @@ -949,10 +962,10 @@ bool win32_set_video_mode(void *data, DWORD style; MSG msg; RECT mon_rect; - unsigned mon_id; - MONITORINFOEX current_mon; - bool windowed_full; RECT rect; + MONITORINFOEX current_mon; + unsigned mon_id = 0; + bool windowed_full = false; HMONITOR hm_to_use = NULL; settings_t *settings = config_get_ptr(); int res = 0; @@ -964,23 +977,26 @@ bool win32_set_video_mode(void *data, win32_monitor_info(¤t_mon, &hm_to_use, &mon_id); - mon_rect = current_mon.rcMonitor; - g_resize_width = width; - g_resize_height = height; + mon_rect = current_mon.rcMonitor; + g_resize_width = width; + g_resize_height = height; - windowed_full = settings->bools.video_windowed_fullscreen; + windowed_full = settings->bools.video_windowed_fullscreen; win32_set_style(¤t_mon, &hm_to_use, &width, &height, fullscreen, windowed_full, &rect, &mon_rect, &style); - if (!win32_window_create(data, style, &mon_rect, width, height, fullscreen)) + if (!win32_window_create(data, style, + &mon_rect, width, height, fullscreen)) return false; - win32_set_window(&width, &height, fullscreen, windowed_full, &rect); + win32_set_window(&width, &height, + fullscreen, windowed_full, &rect); /* Wait until context is created (or failed to do so ...). * Please don't remove the (res = ) as GetMessage can return -1. */ - while (!g_inited && !g_quit && (res = GetMessage(&msg, main_window.hwnd, 0, 0)) != 0) + while (!g_inited && !g_quit + && (res = GetMessage(&msg, main_window.hwnd, 0, 0)) != 0) { if (res == -1) { @@ -1020,19 +1036,20 @@ BOOL IsIconic(HWND hwnd) bool win32_has_focus(void) { -#ifndef _XBOX - const ui_window_t *window = ui_companion_driver_get_window_ptr(); -#endif - if (!g_inited) - return false; - + if (g_inited) + { #ifdef _XBOX - return GetForegroundWindow() == main_window.hwnd; + if (GetForegroundWindow() == main_window.hwnd) + return true; #else - if (window) - return window->focused(&main_window); - return false; + const ui_window_t *window = + ui_companion_driver_get_window_ptr(); + if (window) + return window->focused(&main_window); #endif + } + + return false; } HWND win32_get_window(void) @@ -1053,3 +1070,90 @@ void win32_destroy_window(void) #endif main_window.hwnd = NULL; } + +void win32_get_video_output_prev( + unsigned *width, unsigned *height) +{ + DEVMODE dm; + int iModeNum; + bool found = false; + unsigned prev_width = 0; + unsigned prev_height = 0; + unsigned curr_width = 0; + unsigned curr_height = 0; + + memset(&dm, 0, sizeof(dm)); + + dm.dmSize = sizeof(dm); + + win32_get_video_output_size(&curr_width, &curr_height); + + for (iModeNum = 0; + EnumDisplaySettings(NULL, iModeNum, &dm) != 0; + iModeNum++) + { + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) + { + if ( prev_width != curr_width + && prev_height != curr_height) + { + found = true; + break; + } + } + + prev_width = dm.dmPelsWidth; + prev_height = dm.dmPelsHeight; + } + + if (found) + { + *width = prev_width; + *height = prev_height; + } +} + +void win32_get_video_output_next( + unsigned *width, unsigned *height) +{ + DEVMODE dm; + int iModeNum; + bool found = false; + unsigned curr_width = 0; + unsigned curr_height = 0; + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + + win32_get_video_output_size(&curr_width, &curr_height); + + for (iModeNum = 0; + EnumDisplaySettings(NULL, iModeNum, &dm) != 0; + iModeNum++) + { + if (found) + { + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + break; + } + + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) + found = true; + } +} + +void win32_get_video_output_size(unsigned *width, unsigned *height) +{ + DEVMODE dm; + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) + { + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + } +} diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index a5c8b1f722..975eb5caf8 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -31,12 +31,16 @@ #ifdef _XBOX #include "../../defines/xdk_defines.h" +#else +#include "../../ui/drivers/ui_win32_resource.h" +#include "../../ui/drivers/ui_win32.h" +#endif + +#ifdef __cplusplus +extern "C" { #endif #ifndef _XBOX -#include "../../ui/drivers/ui_win32_resource.h" -#include "../../ui/drivers/ui_win32.h" - extern unsigned g_resize_width; extern unsigned g_resize_height; extern bool g_inited; @@ -51,13 +55,7 @@ void create_graphics_context(HWND hwnd, bool *quit); void create_gdi_context(HWND hwnd, bool *quit); -#ifdef __cplusplus -extern "C" { -#endif bool gdi_has_menu_frame(void); -#ifdef __cplusplus -} -#endif bool win32_shader_dlg_init(void); void shader_dlg_show(HWND parent_hwnd); @@ -91,13 +89,7 @@ bool win32_get_metrics(void *data, void win32_show_cursor(bool state); -#ifdef __cplusplus -extern "C" { -#endif HWND win32_get_window(void); -#ifdef __cplusplus -} -#endif bool win32_has_focus(void); @@ -113,6 +105,15 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, RECT *rect, RECT *mon_rect, DWORD *style); #endif +void win32_get_video_output_size( + unsigned *width, unsigned *height); + +void win32_get_video_output_prev( + unsigned *width, unsigned *height); + +void win32_get_video_output_next( + unsigned *width, unsigned *height); + void win32_window_reset(void); void win32_destroy_window(void); @@ -134,4 +135,8 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, BOOL IsIconic(HWND hwnd); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/gfx/drivers/caca_gfx.c b/gfx/drivers/caca_gfx.c index fd5e86ad8e..c558602666 100644 --- a/gfx/drivers/caca_gfx.c +++ b/gfx/drivers/caca_gfx.c @@ -94,7 +94,7 @@ static void *caca_gfx_init(const video_info_t *video, } if (video->font_enable) - font_driver_init_osd(NULL, false, video->is_threaded, + font_driver_init_osd(caca, false, video->is_threaded, FONT_DRIVER_RENDER_CACA); return caca; diff --git a/gfx/drivers/gdi_gfx.c b/gfx/drivers/gdi_gfx.c index c65b9f752c..0b21886553 100644 --- a/gfx/drivers/gdi_gfx.c +++ b/gfx/drivers/gdi_gfx.c @@ -140,7 +140,7 @@ static void *gdi_gfx_init(const video_info_t *video, video_context_driver_input_driver(&inp); if (settings->bools.video_font_enable) - font_driver_init_osd(NULL, false, + font_driver_init_osd(gdi, false, video->is_threaded, FONT_DRIVER_RENDER_GDI); @@ -160,7 +160,6 @@ static bool gdi_gfx_frame(void *data, const void *frame, unsigned pitch, const char *msg, video_frame_info_t *video_info) { gfx_ctx_mode_t mode; - RECT rect; const void *frame_to_copy = frame; unsigned width = 0; unsigned height = 0; @@ -207,66 +206,77 @@ static bool gdi_gfx_frame(void *data, const void *frame, draw = false; } - GetClientRect(hwnd, &rect); + if (hwnd && !gdi->winDC) + { + gdi->winDC = GetDC(hwnd); + gdi->memDC = CreateCompatibleDC(gdi->winDC); + gdi->video_width = width; + gdi->video_height = height; + gdi->bmp = CreateCompatibleBitmap(gdi->winDC, gdi->video_width, gdi->video_height); + } + + gdi->bmp_old = (HBITMAP)SelectObject(gdi->memDC, gdi->bmp); + + if (gdi->video_width != width || gdi->video_height != height) + { + SelectObject(gdi->memDC, gdi->bmp_old); + DeleteObject(gdi->bmp); + + gdi->video_width = width; + gdi->video_height = height; + gdi->bmp = CreateCompatibleBitmap(gdi->winDC, gdi->video_width, gdi->video_height); + gdi->bmp_old = (HBITMAP)SelectObject(gdi->memDC, gdi->bmp); + } + video_context_driver_get_video_size(&mode); + gdi->screen_width = mode.width; + gdi->screen_height = mode.height; + + BITMAPINFO *info = (BITMAPINFO*)calloc(1, sizeof(*info) + (3 * sizeof(RGBQUAD))); + + info->bmiHeader.biBitCount = bits; + info->bmiHeader.biWidth = pitch / (bits / 8); + info->bmiHeader.biHeight = -height; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) + (3 * sizeof(RGBQUAD)); + info->bmiHeader.biSizeImage = 0; + + if (bits == 16) + { + unsigned *masks = (unsigned*)info->bmiColors; + + info->bmiHeader.biCompression = BI_BITFIELDS; + + /* default 16-bit format on Windows is XRGB1555 */ + if (frame_to_copy == gdi_menu_frame) + { + /* map RGB444 color bits for RGUI */ + masks[0] = 0xF000; + masks[1] = 0x0F00; + masks[2] = 0x00F0; + } + else + { + /* map RGB565 color bits for core */ + masks[0] = 0xF800; + masks[1] = 0x07E0; + masks[2] = 0x001F; + } + } + else + info->bmiHeader.biCompression = BI_RGB; + if (draw) { - HDC winDC = GetDC(hwnd); - HDC memDC = CreateCompatibleDC(winDC); - HBITMAP bmp = CreateCompatibleBitmap(winDC, width, height); - BITMAPINFO *info = (BITMAPINFO*)calloc(1, sizeof(*info) + (3 * sizeof(RGBQUAD))); - HBITMAP bmp_old = (HBITMAP)SelectObject(memDC, bmp); - - info->bmiHeader.biBitCount = bits; - info->bmiHeader.biWidth = pitch / (bits / 8); - info->bmiHeader.biHeight = -height; - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) + (3 * sizeof(RGBQUAD)); - info->bmiHeader.biSizeImage = 0; - - if (bits == 16) - { - unsigned *masks = (unsigned*)info->bmiColors; - - info->bmiHeader.biCompression = BI_BITFIELDS; - - /* default 16-bit format on Windows is XRGB1555 */ - if (frame_to_copy == gdi_menu_frame) - { - /* map RGB444 color bits for RGUI */ - masks[0] = 0xF000; - masks[1] = 0x0F00; - masks[2] = 0x00F0; - } - else - { - /* map RGB565 color bits for core */ - masks[0] = 0xF800; - masks[1] = 0x07E0; - masks[2] = 0x001F; - } - } - else - info->bmiHeader.biCompression = BI_RGB; - - StretchDIBits(memDC, 0, 0, width, height, 0, 0, width, height, + StretchDIBits(gdi->memDC, 0, 0, width, height, 0, 0, width, height, frame_to_copy, info, DIB_RGB_COLORS, SRCCOPY); - - StretchBlt(winDC, - 0, 0, - mode.width, mode.height, - memDC, 0, 0, width, height, SRCCOPY); - - SelectObject(memDC, bmp_old); - - DeleteObject(bmp); - DeleteDC(memDC); - ReleaseDC(hwnd, winDC); - - free(info); } + SelectObject(gdi->memDC, gdi->bmp_old); + + free(info); + if (msg) font_driver_render_msg(video_info, NULL, msg, NULL); @@ -330,6 +340,7 @@ static bool gdi_gfx_has_windowed(void *data) static void gdi_gfx_free(void *data) { gdi_t *gdi = (gdi_t*)data; + HWND hwnd = win32_get_window(); if (gdi_menu_frame) { @@ -340,6 +351,19 @@ static void gdi_gfx_free(void *data) if (!gdi) return; + if (gdi->memDC) + { + DeleteObject(gdi->bmp); + DeleteDC(gdi->memDC); + gdi->memDC = 0; + } + + if (hwnd && gdi->winDC) + { + ReleaseDC(hwnd, gdi->winDC); + gdi->winDC = 0; + } + font_driver_free_osd(); video_context_driver_free(); free(gdi); diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index ed694fd727..391836a9bc 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -43,6 +43,7 @@ #include "../drivers_renderchain/gl_legacy_renderchain.h" #include "../../configuration.h" +#include "../../dynamic.h" #include "../../record/record_driver.h" #include "../../retroarch.h" @@ -1658,6 +1659,9 @@ static const gfx_ctx_driver_t *gl_get_context(gl_t *gl) gl_shared_context_use = settings->bools.video_shared_context && hwr->context_type != RETRO_HW_CONTEXT_NONE; + if (libretro_get_shared_context() && (hwr->context_type != RETRO_HW_CONTEXT_NONE)) + gl_shared_context_use = true; + return video_context_driver_init_first(gl, settings->arrays.video_context_driver, api, major, minor, gl_shared_context_use); } diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index f7f6cfeef8..3f36723efd 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -42,6 +42,37 @@ #include "../../configuration.h" #include "../../driver.h" +#ifndef _CPU_ISR_Disable +#define _CPU_ISR_Disable( _isr_cookie ) \ + { register u32 _disable_mask = 0; \ + _isr_cookie = 0; \ + __asm__ __volatile__ ( \ + "mfmsr %0\n" \ + "rlwinm %1,%0,0,17,15\n" \ + "mtmsr %1\n" \ + "extrwi %0,%0,1,16" \ + : "=&r" ((_isr_cookie)), "=&r" ((_disable_mask)) \ + : "0" ((_isr_cookie)), "1" ((_disable_mask)) \ + ); \ + } +#endif + +#ifndef _CPU_ISR_Restore +#define _CPU_ISR_Restore( _isr_cookie ) \ + { register u32 _enable_mask = 0; \ + __asm__ __volatile__ ( \ + " cmpwi %0,0\n" \ + " beq 1f\n" \ + " mfmsr %1\n" \ + " ori %1,%1,0x8000\n" \ + " mtmsr %1\n" \ + "1:" \ + : "=r"((_isr_cookie)),"=&r" ((_enable_mask)) \ + : "0"((_isr_cookie)),"1" ((_enable_mask)) \ + ); \ + } +#endif + extern syssram* __SYS_LockSram(void); extern u32 __SYS_UnlockSram(u32 write); @@ -92,6 +123,9 @@ static volatile bool g_draw_done = false; static bool g_vsync = false; static uint32_t g_orientation = 0; +static uint32_t retraceCount; +static uint32_t referenceRetraceCount; + static uint8_t gx_fifo[256 * 1024] ATTRIBUTE_ALIGN(32); static uint8_t display_list[1024] ATTRIBUTE_ALIGN(32); static size_t display_list_size; @@ -213,9 +247,15 @@ unsigned menu_gx_resolutions[][2] = { static void retrace_callback(u32 retrace_count) { + u32 level = 0; + (void)retrace_count; + g_draw_done = true; OSSignalCond(g_video_cond); + _CPU_ISR_Disable(level); + retraceCount = retrace_count; + _CPU_ISR_Restore(level); } static bool gx_isValidXOrigin(int origin) @@ -249,7 +289,7 @@ static void gx_set_video_mode(void *data, unsigned fbWidth, unsigned lines, VIDEO_SetPostRetraceCallback(NULL); g_draw_done = false; /* wait for next even field */ - /* this prevents screen artefacts when switching + /* this prevents screen artifacts when switching * between interlaced & non-interlaced modes */ do VIDEO_WaitVSync(); while (!VIDEO_GetNextField()); @@ -293,13 +333,13 @@ static void gx_set_video_mode(void *data, unsigned fbWidth, unsigned lines, max_height = VI_MAX_HEIGHT_MPAL; break; case VI_EURGB60: - max_width = VI_MAX_WIDTH_NTSC; - max_height = VI_MAX_HEIGHT_NTSC; + max_width = VI_MAX_WIDTH_EURGB60; + max_height = VI_MAX_HEIGHT_EURGB60; break; default: tvmode = VI_NTSC; - max_width = VI_MAX_WIDTH_EURGB60; - max_height = VI_MAX_HEIGHT_EURGB60; + max_width = VI_MAX_WIDTH_NTSC; + max_height = VI_MAX_HEIGHT_NTSC; break; } @@ -575,6 +615,10 @@ static void init_vtx(void *data, const video_info_t *video) { Mtx44 m; gx_video_t *gx = (gx_video_t*)data; + u32 level = 0; + _CPU_ISR_Disable(level); + referenceRetraceCount = retraceCount; + _CPU_ISR_Restore(level); GX_SetCullMode(GX_CULL_NONE); GX_SetClipMode(GX_CLIP_DISABLE); @@ -1440,6 +1484,7 @@ static bool gx_frame(void *data, const void *frame, char fps_text_buf[128]; gx_video_t *gx = (gx_video_t*)data; u8 clear_efb = GX_FALSE; + u32 level = 0; fps_text_buf[0] = '\0'; @@ -1524,6 +1569,12 @@ static bool gx_frame(void *data, const void *frame, gx_render_overlay(gx); #endif + _CPU_ISR_Disable(level); + if (referenceRetraceCount > retraceCount) + VIDEO_WaitVSync(); + referenceRetraceCount = retraceCount; + _CPU_ISR_Restore(level); + GX_DrawDone(); if (video_info->fps_show) @@ -1564,6 +1615,10 @@ static bool gx_frame(void *data, const void *frame, VIDEO_SetNextFramebuffer(gx->framebuf[g_current_framebuf]); VIDEO_Flush(); + _CPU_ISR_Disable(level); + ++referenceRetraceCount; + _CPU_ISR_Restore(level); + return true; } diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index 65732b7a95..01e4196e86 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -1194,12 +1194,12 @@ error: static void vulkan_update_filter_chain(vk_t *vk) { - const struct vulkan_filter_chain_swapchain_info info = { - vk->vk_vp, - vk->context->swapchain_format, - vk->render_pass, - vk->context->num_swapchain_images, - }; + struct vulkan_filter_chain_swapchain_info info; + + info.viewport = vk->vk_vp; + info.format = vk->context->swapchain_format; + info.render_pass = vk->render_pass; + info.num_indices = vk->context->num_swapchain_images; if (!vulkan_filter_chain_update_swapchain_info((vulkan_filter_chain_t*)vk->filter_chain, &info)) RARCH_ERR("Failed to update filter chain info. This will probably lead to a crash ...\n"); @@ -1346,9 +1346,10 @@ static void vulkan_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { - (void)data; gfx_ctx_mode_t mode; + (void)data; + mode.width = width; mode.height = height; mode.fullscreen = fullscreen; diff --git a/gfx/drivers_context/gdi_ctx.cpp b/gfx/drivers_context/gdi_ctx.c similarity index 98% rename from gfx/drivers_context/gdi_ctx.cpp rename to gfx/drivers_context/gdi_ctx.c index f4f1a9c265..9721530311 100644 --- a/gfx/drivers_context/gdi_ctx.cpp +++ b/gfx/drivers_context/gdi_ctx.c @@ -19,7 +19,7 @@ /* necessary for mingw32 multimon defines: */ #ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0500 //_WIN32_WINNT_WIN2K +#define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */ #endif #include @@ -104,9 +104,10 @@ static void gfx_ctx_gdi_update_window_title(void *data, void *data2) static void gfx_ctx_gdi_get_video_size(void *data, unsigned *width, unsigned *height) { - (void)data; HWND window = win32_get_window(); + (void)data; + if (!window) { RECT mon_rect; @@ -126,7 +127,8 @@ static void gfx_ctx_gdi_get_video_size(void *data, } } -static void *gfx_ctx_gdi_init(video_frame_info_t *video_info, void *video_driver) +static void *gfx_ctx_gdi_init( + video_frame_info_t *video_info, void *video_driver) { WNDCLASSEX wndclass = {0}; @@ -218,9 +220,10 @@ static void gfx_ctx_gdi_input_driver(void *data, const char *joypad_name, const input_driver_t **input, void **input_data) { - (void)data; settings_t *settings = config_get_ptr(); + (void)data; + #if _WIN32_WINNT >= 0x0501 /* winraw only available since XP */ if (string_is_equal_fast(settings->arrays.input_driver, "raw", 4)) diff --git a/gfx/drivers_context/khr_display_ctx.c b/gfx/drivers_context/khr_display_ctx.c index fd69cb1620..745d770055 100644 --- a/gfx/drivers_context/khr_display_ctx.c +++ b/gfx/drivers_context/khr_display_ctx.c @@ -113,6 +113,7 @@ static bool gfx_ctx_khr_display_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { + struct vulkan_display_surface_info info; khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; if (!fullscreen) @@ -121,7 +122,9 @@ static bool gfx_ctx_khr_display_set_video_mode(void *data, height = 0; } - struct vulkan_display_surface_info info = { width, height }; + info.width = width; + info.height = height; + if (!vulkan_surface_create(&khr->vk, VULKAN_WSI_DISPLAY, &info, NULL, 0, 0, khr->swap_interval)) { diff --git a/gfx/drivers_context/wgl_ctx.cpp b/gfx/drivers_context/wgl_ctx.c similarity index 96% rename from gfx/drivers_context/wgl_ctx.cpp rename to gfx/drivers_context/wgl_ctx.c index 9e6ebef484..64c4be8a09 100644 --- a/gfx/drivers_context/wgl_ctx.cpp +++ b/gfx/drivers_context/wgl_ctx.c @@ -23,7 +23,10 @@ #define _WIN32_WINNT 0x0500 //_WIN32_WINNT_WIN2K #endif +#if !defined(_MSC_VER) || _MSC_VER > 1400 #define UNICODE +#endif + #include #include @@ -270,14 +273,21 @@ void create_graphics_context(HWND hwnd, bool *quit) { #ifdef HAVE_VULKAN RECT rect; - unsigned width = rect.right - rect.left; - unsigned height = rect.bottom - rect.top; + HINSTANCE instance; + unsigned width = 0; + unsigned height = 0; + GetClientRect(hwnd, &rect); - HINSTANCE instance = GetModuleHandle(NULL); + + instance = GetModuleHandle(NULL); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + if (!vulkan_surface_create(&win32_vk, VULKAN_WSI_WIN32, &instance, &hwnd, width, height, win32_interval)) *quit = true; + g_inited = true; #endif } @@ -357,11 +367,8 @@ static void gfx_ctx_wgl_swap_buffers(void *data, void *data2) switch (win32_api) { case GFX_CTX_OPENGL_API: -#ifdef HAVE_OPENGL SwapBuffers(win32_hdc); -#endif break; - case GFX_CTX_VULKAN_API: #ifdef HAVE_VULKAN vulkan_present(&win32_vk, win32_vk.context.current_swapchain_index); @@ -425,9 +432,10 @@ static void gfx_ctx_wgl_update_title(void *data, void *data2) static void gfx_ctx_wgl_get_video_size(void *data, unsigned *width, unsigned *height) { - (void)data; HWND window = win32_get_window(); + (void)data; + if (!window) { RECT mon_rect; @@ -702,6 +710,20 @@ static void gfx_ctx_wgl_set_flags(void *data, uint32_t flags) win32_core_hw_context_enable = true; } +static void gfx_ctx_wgl_get_video_output_size(void *data, + unsigned *width, unsigned *height) +{ + win32_get_video_output_size(width, height); +} + +static void gfx_ctx_wgl_get_video_output_prev(void *data) +{ +} + +static void gfx_ctx_wgl_get_video_output_next(void *data) +{ +} + const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_wgl_init, gfx_ctx_wgl_destroy, @@ -709,9 +731,9 @@ const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_wgl_swap_interval, gfx_ctx_wgl_set_video_mode, gfx_ctx_wgl_get_video_size, - NULL, /* get_video_output_size */ - NULL, /* get_video_output_prev */ - NULL, /* get_video_output_next */ + gfx_ctx_wgl_get_video_output_size, + gfx_ctx_wgl_get_video_output_prev, + gfx_ctx_wgl_get_video_output_next, gfx_ctx_wgl_get_metrics, NULL, gfx_ctx_wgl_update_title, diff --git a/gfx/drivers_font/caca_font.c b/gfx/drivers_font/caca_font.c index dfe0f9c91f..af2e17cf29 100644 --- a/gfx/drivers_font/caca_font.c +++ b/gfx/drivers_font/caca_font.c @@ -45,8 +45,6 @@ static void *caca_init_font(void *data, font->caca = (caca_t*)data; - font_size = 1; - if (!font_renderer_create_default((const void**)&font->caca_font_driver, &font->caca_font_data, font_path, font_size)) { diff --git a/gfx/drivers_font/d3d_w32_font.cpp b/gfx/drivers_font/d3d_w32_font.cpp index 1eff6798c0..6347bb5bf2 100644 --- a/gfx/drivers_font/d3d_w32_font.cpp +++ b/gfx/drivers_font/d3d_w32_font.cpp @@ -27,6 +27,8 @@ #include "../include/d3d9/d3dx9core.h" #endif +#include + typedef struct { d3d_video_t *d3d; @@ -47,11 +49,7 @@ static void *d3dfonts_w32_init_font(void *video_data, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_PITCH, -#if defined(_MSC_VER) /* MSVC needs w_char* */ - L"Verdana" /* Hardcode FTL */ -#else - "Verdana" -#endif + _T("Verdana") /* Hardcode FTL */ }; d3dfonts = (d3dfonts_t*)calloc(1, sizeof(*d3dfonts)); diff --git a/gfx/drivers_font/gdi_font.c b/gfx/drivers_font/gdi_font.c index 9e43be5072..e59d5b845a 100644 --- a/gfx/drivers_font/gdi_font.c +++ b/gfx/drivers_font/gdi_font.c @@ -51,8 +51,6 @@ static void *gdi_init_font(void *data, font->gdi = (gdi_t*)data; - font_size = 1; - if (!font_renderer_create_default((const void**)&font->gdi_font_driver, &font->gdi_font_data, font_path, font_size)) { @@ -86,13 +84,11 @@ static void gdi_render_msg( void *data, const char *msg, const void *userdata) { - HDC hdc; float x, y, scale; gdi_raster_t *font = (gdi_raster_t*)data; unsigned newX, newY, len; unsigned align; const struct font_params *params = (const struct font_params*)userdata; - HWND hwnd = win32_get_window(); unsigned width = video_info->width; unsigned height = video_info->height; @@ -135,12 +131,18 @@ static void gdi_render_msg( } newY = height - (y * height * scale); - hdc = GetDC(hwnd); - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, RGB(255,255,255)); - TextOut(hdc, newX, newY, msg, len); - ReleaseDC(hwnd, hdc); + uint64_t frame_count = 0; + bool is_alive = false; + bool is_focused = false; + + video_driver_get_status(&frame_count, &is_alive, &is_focused); + + font->gdi->bmp_old = (HBITMAP)SelectObject(font->gdi->memDC, font->gdi->bmp); + SetBkMode(font->gdi->memDC, TRANSPARENT); + SetTextColor(font->gdi->memDC, RGB(255,255,255)); + TextOut(font->gdi->memDC, newX, newY, msg, len); + SelectObject(font->gdi->memDC, font->gdi->bmp_old); } static void gdi_font_flush_block(unsigned width, unsigned height, void* data) diff --git a/gfx/drivers_font/vulkan_raster_font.c b/gfx/drivers_font/vulkan_raster_font.c index c1036d217d..871c5f6e4c 100644 --- a/gfx/drivers_font/vulkan_raster_font.c +++ b/gfx/drivers_font/vulkan_raster_font.c @@ -271,15 +271,15 @@ static void vulkan_raster_font_render_message( static void vulkan_raster_font_flush(vulkan_raster_t *font) { - const struct vk_draw_triangles call = { - font->vk->pipelines.font, - &font->texture_optimal, - font->vk->samplers.mipmap_linear, - &font->vk->mvp, - sizeof(font->vk->mvp), - &font->range, - font->vertices, - }; + struct vk_draw_triangles call; + + call.pipeline = font->vk->pipelines.font; + call.texture = &font->texture_optimal; + call.sampler = font->vk->samplers.mipmap_linear; + call.uniform = &font->vk->mvp; + call.uniform_size = sizeof(font->vk->mvp); + call.vbo = &font->range; + call.vertices = font->vertices; if(font->needs_update) { diff --git a/gfx/drivers_shader/shader_glsl.c b/gfx/drivers_shader/shader_glsl.c index 48b082823f..40f5ed78ce 100644 --- a/gfx/drivers_shader/shader_glsl.c +++ b/gfx/drivers_shader/shader_glsl.c @@ -162,7 +162,7 @@ static GLint gl_glsl_get_uniform(glsl_shader_data_t *glsl, { unsigned i; GLint loc; - char buf[64]; + char buf[80]; buf[0] = '\0'; @@ -187,7 +187,7 @@ static GLint gl_glsl_get_attrib(glsl_shader_data_t *glsl, { unsigned i; GLint loc; - char buf[64]; + char buf[80]; buf[0] = '\0'; diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 277a1b2c22..1d3ed375e4 100644 --- a/gfx/font_driver.c +++ b/gfx/font_driver.c @@ -34,7 +34,7 @@ static const font_renderer_driver_t *font_backends[] = { &coretext_font_renderer, #endif #ifdef HAVE_STB_FONT -#if defined(VITA) || defined(WIIU) || defined(ANDROID) || defined(_WIN32) && !defined(_XBOX) +#if defined(VITA) || defined(WIIU) || defined(ANDROID) || defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) || defined(_WIN32) && !defined(_XBOX) && defined(_MSC_VER) && _MSC_VER > 1400 &stb_unicode_font_renderer, #else &stb_font_renderer, diff --git a/gfx/include/vulkan/vk_platform.h b/gfx/include/vulkan/vk_platform.h index 5d0fc766ec..3771c169e1 100644 --- a/gfx/include/vulkan/vk_platform.h +++ b/gfx/include/vulkan/vk_platform.h @@ -1,6 +1,7 @@ -// -// File: vk_platform.h -// +/* + * File: vk_platform.h + */ + /* ** Copyright (c) 2014-2015 The Khronos Group Inc. ** @@ -24,7 +25,7 @@ #ifdef __cplusplus extern "C" { -#endif // __cplusplus +#endif /* __cplusplus */ /* *************************************************************************************************** @@ -47,22 +48,22 @@ extern "C" * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); */ #if defined(_WIN32) - // On Windows, Vulkan commands use the stdcall convention + /* On Windows, Vulkan commands use the stdcall convention */ #define VKAPI_ATTR #define VKAPI_CALL __stdcall #define VKAPI_PTR VKAPI_CALL #elif defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) - // Android does not support Vulkan in native code using the "armeabi" ABI. + /* Android does not support Vulkan in native code using the "armeabi" ABI. */ #error "Vulkan requires the 'armeabi-v7a' or 'armeabi-v7a-hard' ABI on 32-bit ARM CPUs" #elif defined(__ANDROID__) && defined(__ARM_ARCH_7A__) - // On Android/ARMv7a, Vulkan functions use the armeabi-v7a-hard calling - // convention, even if the application's native code is compiled with the - // armeabi-v7a calling convention. + /* On Android/ARMv7a, Vulkan functions use the armeabi-v7a-hard calling + * convention, even if the application's native code is compiled with the + * armeabi-v7a calling convention. */ #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) #define VKAPI_CALL #define VKAPI_PTR VKAPI_ATTR #else - // On other platforms, use the default calling convention + /* On other platforms, use the default calling convention */ #define VKAPI_ATTR #define VKAPI_CALL #define VKAPI_PTR @@ -83,15 +84,15 @@ extern "C" #else #include #endif -#endif // !defined(VK_NO_STDINT_H) +#endif /* !defined(VK_NO_STDINT_H) */ #ifdef __cplusplus -} // extern "C" -#endif // __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ -// Platform-specific headers required by platform window system extensions. -// These are enabled prior to #including "vulkan.h". The same enable then -// controls inclusion of the extension interfaces in vulkan.h. +/* Platform-specific headers required by platform window system extensions. + * These are enabled prior to #including "vulkan.h". The same enable then + * controls inclusion of the extension interfaces in vulkan.h. */ #ifdef VK_USE_PLATFORM_ANDROID_KHR #include diff --git a/gfx/include/vulkan/vk_sdk_platform.h b/gfx/include/vulkan/vk_sdk_platform.h index ef9a000fb2..29653774ff 100644 --- a/gfx/include/vulkan/vk_sdk_platform.h +++ b/gfx/include/vulkan/vk_sdk_platform.h @@ -1,6 +1,7 @@ -// -// File: vk_sdk_platform.h -// +/* + * File: vk_sdk_platform.h + */ + /* * Copyright (c) 2015-2016 The Khronos Group Inc. * Copyright (c) 2015-2016 Valve Corporation @@ -27,20 +28,20 @@ #ifndef __cplusplus #undef inline #define inline __inline -#endif // __cplusplus +#endif /* __cplusplus */ #if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) -// C99: -// Microsoft didn't implement C99 in Visual Studio; but started adding it with -// VS2013. However, VS2013 still didn't have snprintf(). The following is a -// work-around (Note: The _CRT_SECURE_NO_WARNINGS macro must be set in the -// "CMakeLists.txt" file). -// NOTE: This is fixed in Visual Studio 2015. +/* C99: + * Microsoft didn't implement C99 in Visual Studio; but started adding it with + * VS2013. However, VS2013 still didn't have snprintf(). The following is a + * work-around (Note: The _CRT_SECURE_NO_WARNINGS macro must be set in the + * "CMakeLists.txt" file). + * NOTE: This is fixed in Visual Studio 2015. */ #define snprintf _snprintf #endif #define strdup _strdup -#endif // _WIN32 +#endif /* _WIN32 */ -#endif // VK_SDK_PLATFORM_H +#endif /* VK_SDK_PLATFORM_H */ diff --git a/gfx/include/vulkan/vulkan.h b/gfx/include/vulkan/vulkan.h index 9b91e62973..121738c08f 100644 --- a/gfx/include/vulkan/vulkan.h +++ b/gfx/include/vulkan/vulkan.h @@ -33,16 +33,18 @@ extern "C" { #define VK_MAKE_VERSION(major, minor, patch) \ (((major) << 22) | ((minor) << 12) | (patch)) -// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. -//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) +/* DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. */ +#if 0 +#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) +#endif -// Vulkan 1.0 version number +/* Vulkan 1.0 version number */ #define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0) #define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) -// Version of this file +/* Version of this file */ #define VK_HEADER_VERSION 17 diff --git a/gfx/include/vulkan/vulkan_intel.h b/gfx/include/vulkan/vulkan_intel.h index 1f77128961..15b5a02ad0 100644 --- a/gfx/include/vulkan/vulkan_intel.h +++ b/gfx/include/vulkan/vulkan_intel.h @@ -29,16 +29,16 @@ #ifdef __cplusplus extern "C" { -#endif // __cplusplus +#endif /* __cplusplus */ #define VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL 1024 typedef struct VkDmaBufImageCreateInfo_ { - VkStructureType sType; // Must be VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL - const void* pNext; // Pointer to next structure. + VkStructureType sType; /* Must be VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL */ + const void* pNext; /* Pointer to next structure. */ int fd; VkFormat format; - VkExtent3D extent; // Depth must be 1 + VkExtent3D extent; /* Depth must be 1 */ uint32_t strideInBytes; } VkDmaBufImageCreateInfo; @@ -56,7 +56,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateDmaBufImageINTEL( #endif #ifdef __cplusplus -} // extern "C" -#endif // __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ -#endif // __VULKAN_INTEL_H__ +#endif /* __VULKAN_INTEL_H__ */ diff --git a/gfx/video_driver.c b/gfx/video_driver.c index d420786bb7..a43cbe13af 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -35,6 +35,8 @@ #include "../config.h" #endif +#include "../dynamic.h" + #ifdef HAVE_THREADS #include #endif @@ -2463,6 +2465,8 @@ void video_driver_build_info(video_frame_info_t *video_info) bool is_slowmotion = false; settings_t *settings = NULL; video_viewport_t *custom_vp = NULL; + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); #ifdef HAVE_THREADS bool is_threaded = video_driver_is_threaded(); video_driver_threaded_lock(is_threaded); @@ -2483,6 +2487,10 @@ void video_driver_build_info(video_frame_info_t *video_info) video_info->fullscreen = settings->bools.video_fullscreen; video_info->monitor_index = settings->uints.video_monitor_index; video_info->shared_context = settings->bools.video_shared_context; + + if (libretro_get_shared_context() && hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) + video_info->shared_context = true; + video_info->font_enable = settings->bools.video_font_enable; video_info->font_msg_pos_x = settings->floats.video_msg_pos_x; video_info->font_msg_pos_y = settings->floats.video_msg_pos_y; @@ -2516,7 +2524,8 @@ void video_driver_build_info(video_frame_info_t *video_info) video_info->battery_level_enable = settings->bools.menu_battery_level_enable; video_info->xmb_shadows_enable = settings->bools.menu_xmb_shadows_enable; video_info->xmb_alpha_factor = settings->uints.menu_xmb_alpha_factor; - video_info->menu_wallpaper_opacity = settings->floats.menu_wallpaper_opacity; + video_info->menu_wallpaper_opacity = settings->floats.menu_wallpaper_opacity; + video_info->menu_framebuffer_opacity = settings->floats.menu_framebuffer_opacity; video_info->libretro_running = core_is_game_loaded(); #else @@ -2531,6 +2540,7 @@ void video_driver_build_info(video_frame_info_t *video_info) video_info->battery_level_enable = false; video_info->xmb_shadows_enable = false; video_info->xmb_alpha_factor = 0.0f; + video_info->menu_framebuffer_opacity = 0.0f; video_info->menu_wallpaper_opacity = 0.0f; #endif diff --git a/gfx/video_driver.h b/gfx/video_driver.h index cb816346a5..c2e72857e7 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -447,14 +447,15 @@ typedef struct video_frame_info unsigned custom_vp_full_height; float menu_wallpaper_opacity; + float menu_framebuffer_opacity; + float menu_header_opacity; + float menu_footer_opacity; float refresh_rate; float font_msg_pos_x; float font_msg_pos_y; float font_msg_color_r; float font_msg_color_g; float font_msg_color_b; - float menu_header_opacity; - float menu_footer_opacity; float xmb_alpha_factor; char fps_text[128]; diff --git a/gfx/video_filters/Makefile b/gfx/video_filters/Makefile index cfcf75911b..81c04b8f82 100644 --- a/gfx/video_filters/Makefile +++ b/gfx/video_filters/Makefile @@ -3,6 +3,8 @@ extra_flags := use_neon := 0 release := release DYLIB := so +PREFIX := /usr +INSTALLDIR := $(PREFIX)/lib/retroarch/filters/video ifeq ($(platform),) platform = unix @@ -89,3 +91,10 @@ clean: strip: strip -s *.$(DYLIB) + +install: + mkdir -p $(DESTDIR)$(INSTALLDIR) + cp -t $(DESTDIR)$(INSTALLDIR) $(objects) *.filt + +test-install: + DESTDIR=/tmp/build $(MAKE) install diff --git a/gfx/video_filters/configure b/gfx/video_filters/configure new file mode 100755 index 0000000000..6a5e320762 --- /dev/null +++ b/gfx/video_filters/configure @@ -0,0 +1,3 @@ +#!/bin/sh + +PACKAGE_NAME=retroarch-filters-video diff --git a/griffin/griffin.c b/griffin/griffin.c index ab73487352..9eeebde565 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -14,6 +14,8 @@ * If not, see . */ +#define HAVE_IBXM 1 + #if defined(HAVE_CG) || defined(HAVE_HLSL) || defined(HAVE_GLSL) #define HAVE_SHADERS #endif @@ -43,6 +45,21 @@ CONSOLE EXTENSIONS #include "../memory/ngc/ssaram.c" #endif +#ifdef INTERNAL_LIBOGC +#ifdef HW_RVL +#include "../wii/libogc/libfat/cache.c" +#include "../wii/libogc/libfat/directory.c" +#include "../wii/libogc/libfat/disc.c" +#include "../wii/libogc/libfat/fatdir.c" +#include "../wii/libogc/libfat/fatfile.c" +#include "../wii/libogc/libfat/file_allocation_table.c" +#include "../wii/libogc/libfat/filetime.c" +#include "../wii/libogc/libfat/libfat.c" +#include "../wii/libogc/libfat/lock.c" +#include "../wii/libogc/libfat/partition.c" +#endif +#endif + #endif /*============================================================ @@ -151,11 +168,36 @@ CHEATS #include "../managers/cheat_manager.c" #include "../libretro-common/hash/rhash.c" +/*============================================================ +UI COMMON CONTEXT +============================================================ */ +#if defined(_WIN32) && !defined(_XBOX) +#include "../gfx/common/win32_common.c" +#endif + /*============================================================ VIDEO CONTEXT ============================================================ */ #include "../gfx/drivers_context/gfx_null_ctx.c" +#if defined(_WIN32) && !defined(_XBOX) + +#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) +#include "../gfx/drivers_context/wgl_ctx.c" +#endif + +#if defined(_WIN32) && !defined(_XBOX) +#include "../gfx/drivers_context/gdi_ctx.c" +#endif + +#if defined(HAVE_FFMPEG) +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES3) +#include "../cores/libretro-ffmpeg/ffmpeg_fft.c" +#endif +#endif + +#endif + #if defined(__CELLOS_LV2__) #include "../gfx/drivers_context/ps3_ctx.c" #elif defined(ANDROID) @@ -350,6 +392,8 @@ VIDEO DRIVER #include "../gfx/drivers/gdi_gfx.c" #endif +#include "../deps/ibxm/ibxm.c" + /*============================================================ FONTS ============================================================ */ @@ -739,6 +783,7 @@ FILE #include "../setting_list.c" #include "../libretro-common/file/retro_dirent.c" #include "../libretro-common/streams/file_stream.c" +#include "../libretro-common/streams/file_stream_transforms.c" #include "../libretro-common/streams/interface_stream.c" #include "../libretro-common/streams/memory_stream.c" #include "../list_special.c" diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 2a5a6c8733..53a538109e 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -97,29 +97,6 @@ AUDIO #include "../audio/drivers/xaudio.cpp" #endif -/*============================================================ -UI COMMON CONTEXT -============================================================ */ -#if defined(_WIN32) && !defined(_XBOX) -#include "../gfx/common/win32_common.cpp" - -#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) -#include "../gfx/drivers_context/wgl_ctx.cpp" -#endif - -#if defined(_WIN32) && !defined(_XBOX) -#include "../gfx/drivers_context/gdi_ctx.cpp" -#endif - -#if defined(HAVE_FFMPEG) -#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES3) -#include "../cores/libretro-ffmpeg/fft/fft.cpp" -#endif -#endif - -#endif - - /*============================================================ MENU ============================================================ */ diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index 70f80f75b9..adf3f18404 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -1072,6 +1072,32 @@ static void handle_hotplug(android_input_t *android, } } + /* Amazon Fire TV & Fire stick */ + else if(strstr(device_model, "AFTB") || strstr(device_model, "AFTT") || + strstr(device_model, "AFTS") || strstr(device_model, "AFTM") || + strstr(device_model, "AFTRS")) + { + RARCH_LOG("Special Device Detected: %s\n", device_model); + { + /* always map remote to port #0 */ + if (strstr(device_name, "Amazon Fire TV Remote")) + { + android->pads_connected = 0; + *port = 0; + strlcpy(name_buf, device_name, sizeof(name_buf)); + } + /* remove the remote when a gamepad enters */ + else if(strstr(android->pad_states[0].name,"Amazon Fire TV Remote")) + { + android->pads_connected = 0; + *port = 0; + strlcpy(name_buf, device_name, sizeof(name_buf)); + } + else + strlcpy(name_buf, device_name, sizeof(name_buf)); + } + } + /* Other uncommon devices * These are mostly remote control type devices, bind them always to port 0 * And overwrite the binding whenever a controller button is pressed diff --git a/input/drivers/dinput.c b/input/drivers/dinput.c index 4f78febd2f..b1b34051c8 100644 --- a/input/drivers/dinput.c +++ b/input/drivers/dinput.c @@ -51,7 +51,6 @@ #include "../../gfx/video_driver.h" #include "../../verbosity.h" -#include "../../tasks/tasks_internal.h" /* Keep track of which pad indexes are 360 controllers. * Not static, will be read in xinput_joypad.c @@ -102,7 +101,6 @@ void dinput_destroy_context(void) bool dinput_init_context(void) { - bool context_initialized = false; if (g_dinput_ctx) return true; @@ -110,16 +108,16 @@ bool dinput_init_context(void) /* Who said we shouldn't have same call signature in a COM API? <_< */ #ifdef __cplusplus - context_initialized = (SUCCEEDED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, - (void**)&g_dinput_ctx, NULL))); + if (!(SUCCEEDED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, + IID_IDirectInput8, + (void**)&g_dinput_ctx, NULL)))) #else - context_initialized = (SUCCEEDED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8, - (void**)&g_dinput_ctx, NULL))); + if (!(SUCCEEDED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, + &IID_IDirectInput8, + (void**)&g_dinput_ctx, NULL)))) #endif - - if (!context_initialized) goto error; return true; @@ -149,29 +147,32 @@ static void *dinput_init(const char *joypad_driver) di->joypad_driver_name = strdup(joypad_driver); #ifdef __cplusplus - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, GUID_SysKeyboard, &di->keyboard, NULL))) + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + GUID_SysKeyboard, + &di->keyboard, NULL))) +#else + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + &GUID_SysKeyboard, + &di->keyboard, NULL))) +#endif { RARCH_ERR("[DINPUT]: Failed to create keyboard device.\n"); di->keyboard = NULL; } - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, GUID_SysMouse, &di->mouse, NULL))) - { - RARCH_ERR("[DINPUT]: Failed to create mouse device.\n"); - di->mouse = NULL; - } +#ifdef __cplusplus + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + GUID_SysMouse, + &di->mouse, NULL))) #else - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, &GUID_SysKeyboard, &di->keyboard, NULL))) - { - RARCH_ERR("[DINPUT]: Failed to create keyboard device.\n"); - di->keyboard = NULL; - } - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, &GUID_SysMouse, &di->mouse, NULL))) + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + &GUID_SysMouse, + &di->mouse, NULL))) +#endif { RARCH_ERR("[DINPUT]: Failed to create mouse device.\n"); di->mouse = NULL; } -#endif if (di->keyboard) { @@ -195,17 +196,9 @@ static void *dinput_init(const char *joypad_driver) return di; } -#if __cplusplus -extern "C" { -#endif - bool doubleclick_on_titlebar_pressed(void); void unset_doubleclick_on_titlebar(void); -#if __cplusplus -} -#endif - static void dinput_poll(void *data) { struct dinput_input *di = (struct dinput_input*)data; @@ -229,6 +222,8 @@ static void dinput_poll(void *data) if (di->mouse) { DIMOUSESTATE2 mouse_state; + POINT point = {0}; + memset(&mouse_state, 0, sizeof(mouse_state)); if (FAILED(IDirectInputDevice8_GetDeviceState( @@ -244,8 +239,8 @@ static void dinput_poll(void *data) di->mouse_rel_y = mouse_state.lY; - if (!mouse_state.rgbButtons[0]) - unset_doubleclick_on_titlebar(); + if (!mouse_state.rgbButtons[0]) + unset_doubleclick_on_titlebar(); if (doubleclick_on_titlebar_pressed()) di->mouse_l = 0; else @@ -255,7 +250,6 @@ static void dinput_poll(void *data) /* No simple way to get absolute coordinates * for RETRO_DEVICE_POINTER. Just use Win32 APIs. */ - POINT point = {0}; GetCursorPos(&point); ScreenToClient((HWND)video_driver_window_get(), &point); di->mouse_x = point.x; @@ -601,9 +595,6 @@ static void dinput_clear_pointers(struct dinput_input *di) } } -#ifdef __cplusplus -extern "C" -#endif bool dinput_handle_message(void *dinput, UINT message, WPARAM wParam, LPARAM lParam) { struct dinput_input *di = (struct dinput_input *)dinput; diff --git a/input/drivers/wiiu_input.c b/input/drivers/wiiu_input.c index dcf19bbc2e..2fb3a6736f 100644 --- a/input/drivers/wiiu_input.c +++ b/input/drivers/wiiu_input.c @@ -22,6 +22,7 @@ #include #include +#include #ifdef HAVE_CONFIG_H #include "../../config.h" @@ -96,18 +97,37 @@ void kb_key_callback(KBDKeyEvent *key) RETRO_DEVICE_KEYBOARD); } +/* TODO: emulate a relative mouse. This is suprisingly + hard to get working nicely. +*/ + +static int16_t wiiu_pointer_device_state(wiiu_input_t* wiiu, unsigned id) +{ + switch (id) + { + case RETRO_DEVICE_ID_POINTER_PRESSED: + return wiiu->joypad->get_buttons(0) & VPAD_BUTTON_TOUCH; + case RETRO_DEVICE_ID_POINTER_X: + return wiiu->joypad->axis(0, 0xFFFF0004UL); + case RETRO_DEVICE_ID_POINTER_Y: + return wiiu->joypad->axis(0, 0xFFFF0005UL); + } + + return 0; +} + static void wiiu_input_poll(void *data) { wiiu_input_t *wiiu = (wiiu_input_t*)data; - if (wiiu->joypad) - wiiu->joypad->poll(); + if (wiiu && wiiu->joypad) + wiiu->joypad->poll(); } static bool wiiu_key_pressed(int key) { bool ret = false; - + if (key >= RETROK_LAST) return false; @@ -127,7 +147,7 @@ static int16_t wiiu_input_state(void *data, if(!wiiu || !(port < MAX_PADS) || !binds || !binds[port]) return 0; - + switch (device) { case RETRO_DEVICE_JOYPAD: @@ -140,6 +160,9 @@ static int16_t wiiu_input_state(void *data, return input_joypad_analog(wiiu->joypad, joypad_info, port, idx, id, binds[port]); break; + case RETRO_DEVICE_POINTER: + case RARCH_DEVICE_POINTER_SCREEN: + return wiiu_pointer_device_state(wiiu, id); } return 0; @@ -151,7 +174,7 @@ static void wiiu_input_free_input(void *data) if (wiiu && wiiu->joypad) wiiu->joypad->destroy(); - + KBDTeardown(); free(data); @@ -165,10 +188,10 @@ static void* wiiu_input_init(const char *joypad_driver) DEBUG_STR(joypad_driver); wiiu->joypad = input_joypad_init_driver(joypad_driver, wiiu); - + KBDSetup(&kb_connection_callback, &kb_disconnection_callback,&kb_key_callback); - + input_keymaps_init_keyboard_lut(rarch_key_map_wiiu); return wiiu; @@ -186,9 +209,10 @@ static uint64_t wiiu_input_get_capabilities(void *data) { (void)data; - return (1 << RETRO_DEVICE_JOYPAD) | - (1 << RETRO_DEVICE_ANALOG) | - (1 << RETRO_DEVICE_KEYBOARD); + return (1 << RETRO_DEVICE_JOYPAD) | + (1 << RETRO_DEVICE_ANALOG) | + (1 << RETRO_DEVICE_KEYBOARD) | + (1 << RETRO_DEVICE_POINTER); } static const input_device_driver_t *wiiu_input_get_joypad_driver(void *data) diff --git a/input/drivers/winraw_input.c b/input/drivers/winraw_input.c index 19d70b686a..738d033f6c 100644 --- a/input/drivers/winraw_input.c +++ b/input/drivers/winraw_input.c @@ -132,6 +132,22 @@ static bool winraw_set_keyboard_input(HWND window) return true; } +static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) +{ + char name[256]; + UINT name_size = sizeof(name); + UINT r; + unsigned i; + + for (i = 0; i < mouse_cnt; ++i) + { + r = GetRawInputDeviceInfoA(mice[i].hnd, RIDI_DEVICENAME, name, &name_size); + if (r == (UINT)-1 || r == 0) + name[0] = '\0'; + RARCH_LOG("[WINRAW]: Mouse #%u %s.\n", i, name); + } +} + static bool winraw_init_devices(winraw_mouse_t **mice, unsigned *mouse_cnt) { UINT r, i; @@ -191,6 +207,8 @@ static bool winraw_init_devices(winraw_mouse_t **mice, unsigned *mouse_cnt) mice_r[mouse_cnt_r++].hnd = devs[i].hDevice; } + winraw_log_mice_info(mice_r, mouse_cnt_r); + *mice = mice_r; *mouse_cnt = mouse_cnt_r; diff --git a/input/drivers_joypad/dinput_joypad.c b/input/drivers_joypad/dinput_joypad.c index fb02db9a8a..7541cf0dbb 100644 --- a/input/drivers_joypad/dinput_joypad.c +++ b/input/drivers_joypad/dinput_joypad.c @@ -225,8 +225,8 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p) #endif return DIENUM_CONTINUE; - g_pads[g_joypad_cnt].joy_name = strdup(inst->tszProductName); - g_pads[g_joypad_cnt].joy_friendly_name = strdup(inst->tszInstanceName); + g_pads[g_joypad_cnt].joy_name = strdup((const char*)inst->tszProductName); + g_pads[g_joypad_cnt].joy_friendly_name = strdup((const char*)inst->tszInstanceName); /* there may be more useful info in the GUID so leave this here for a while */ #if 0 @@ -294,8 +294,8 @@ static bool dinput_joypad_init(void *data) for (i = 0; i < MAX_USERS; ++i) { - g_xinput_pad_indexes[i] = -1; - g_pads[i].joy_name = NULL; + g_xinput_pad_indexes[i] = -1; + g_pads[i].joy_name = NULL; g_pads[i].joy_friendly_name = NULL; } diff --git a/input/drivers_joypad/gx_joypad.c b/input/drivers_joypad/gx_joypad.c index 46347e6f54..348884e833 100644 --- a/input/drivers_joypad/gx_joypad.c +++ b/input/drivers_joypad/gx_joypad.c @@ -324,6 +324,7 @@ static void gx_joypad_poll(void) if (g_quit) { rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL); + g_quit = false; return; } diff --git a/input/drivers_joypad/wiiu_joypad.c b/input/drivers_joypad/wiiu_joypad.c index 4b59c909eb..33d2da4d7b 100644 --- a/input/drivers_joypad/wiiu_joypad.c +++ b/input/drivers_joypad/wiiu_joypad.c @@ -29,6 +29,7 @@ #include "../../tasks/tasks_internal.h" #include "../../retroarch.h" #include "../../command.h" +#include "../../gfx/video_driver.h" #include "string.h" #include "wiiu_dbg.h" @@ -57,7 +58,8 @@ static uint8_t pad_type[KPAD_COUNT] = {WIIUINPUT_TYPE_NONE, WIIUINPUT_TYPE_NONE, static uint8_t hid_status[HID_COUNT]; static InputData hid_data[HID_COUNT]; -static int16_t analog_state[MAX_PADS][2][2]; +/* 3 axis - one for touch/future IR support? */ +static int16_t analog_state[MAX_PADS][3][2]; static bool wiiu_pad_inited = false; static char hidName[HID_COUNT][255]; @@ -135,12 +137,12 @@ static int16_t wiiu_joypad_axis(unsigned port_num, uint32_t joyaxis) if (joyaxis == AXIS_NONE || port_num >= MAX_PADS) return 0; - if (AXIS_NEG_GET(joyaxis) < 4) + if (AXIS_NEG_GET(joyaxis) < 6) { axis = AXIS_NEG_GET(joyaxis); is_neg = true; } - else if (AXIS_POS_GET(joyaxis) < 4) + else if (AXIS_POS_GET(joyaxis) < 6) { axis = AXIS_POS_GET(joyaxis); is_pos = true; @@ -163,6 +165,14 @@ static int16_t wiiu_joypad_axis(unsigned port_num, uint32_t joyaxis) case 3: val = analog_state[port_num][1][1]; break; + + case 4: + val = analog_state[port_num][2][0]; + break; + + case 5: + val = analog_state[port_num][2][1]; + break; } if (is_neg && val > 0) @@ -173,6 +183,12 @@ static int16_t wiiu_joypad_axis(unsigned port_num, uint32_t joyaxis) return val; } +static float scaleTP(float oldMin, float oldMax, float newMin, float newMax, float val) { + float oldRange = (oldMax - oldMin); + float newRange = (newMax - newMin); + return (((val - oldMin) * newRange) / oldRange) + newMin; +} + static void wiiu_joypad_poll(void) { int i, c, result; @@ -183,7 +199,7 @@ static void wiiu_joypad_poll(void) if (!vpadError) { - pad_state[0] = vpad.hold & ~0x7F800000; /* clear out emulated analog sticks */ + pad_state[0] = vpad.hold & VPAD_MASK_BUTTONS; /* buttons only */ analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_X] = vpad.leftStick.x * 0x7FF0; analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_Y] = vpad.leftStick.y * 0x7FF0; analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = vpad.rightStick.x * 0x7FF0; @@ -191,8 +207,28 @@ static void wiiu_joypad_poll(void) BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE); - if ((vpad.tpNormal.touched) && (vpad.tpNormal.x > 200) && (vpad.tpNormal.validity) == 0) - BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE); + /* You can only call VPADData once every loop, else the second one + won't get any data. Thus; I had to hack touch support into the existing + joystick API. Woo-hoo? Misplaced requests for touch axis are filtered + out in wiiu_input. + */ + if (vpad.tpNormal.touched && vpad.tpNormal.validity == VPAD_VALID) { + struct video_viewport vp = {0}; + video_driver_get_viewport_info(&vp); + VPADTouchData cal = {0}; + /* Calibrates data to a 720p screen, seems to clamp outer 12px */ + VPADGetTPCalibratedPoint(0, &cal, &(vpad.tpNormal)); + /* Calibrate to viewport and save as axis 2 (idx 4,5) */ + analog_state[0][2][0] = (int16_t)scaleTP(12.0f, 1268.0f, 0.0f, (float)(vp.full_width), (float)cal.x); + analog_state[0][2][1] = (int16_t)scaleTP(12.0f, 708.0f, 0.0f, (float)(vp.full_height), (float)cal.y); + + /* Emulating a button for touch; lets people assign it to menu + for that traditional RetroArch Wii U feel */ + pad_state[0] |= VPAD_BUTTON_TOUCH; + } else { + /* This is probably 0 anyway */ + pad_state[0] &= ~VPAD_BUTTON_TOUCH; + } /* panic button */ if ((vpad.hold & (VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_STICK_L)) diff --git a/input/drivers_joypad/xinput_joypad.c b/input/drivers_joypad/xinput_joypad.c index 3c77f48547..eacba9e370 100644 --- a/input/drivers_joypad/xinput_joypad.c +++ b/input/drivers_joypad/xinput_joypad.c @@ -375,11 +375,11 @@ static bool xinput_joypad_button(unsigned port_num, uint16_t joykey) static int16_t xinput_joypad_axis (unsigned port_num, uint32_t joyaxis) { int xuser; - int16_t val = 0; - int axis = -1; - - bool is_neg = false; - bool is_pos = false; + int16_t val = 0; + int axis = -1; + bool is_neg = false; + bool is_pos = false; + XINPUT_GAMEPAD* pad = NULL; if (joyaxis == AXIS_NONE) return 0; @@ -404,7 +404,7 @@ static int16_t xinput_joypad_axis (unsigned port_num, uint32_t joyaxis) is_pos = true; } - XINPUT_GAMEPAD* pad = &(g_xinput_states[xuser].xstate.Gamepad); + pad = &(g_xinput_states[xuser].xstate.Gamepad); switch (axis) { diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index f49c4dc5cc..5931bb2c76 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -19,6 +19,8 @@ #include "../config.h" #endif +#include + #include "../tasks/tasks_internal.h" #include "input_config.h" @@ -498,6 +500,7 @@ const char* const input_builtin_autoconfs[] = #if defined(_WIN32) && defined(_XBOX) DECL_AUTOCONF_DEVICE("XInput Controller", "xdk", XINPUT_DEFAULT_BINDS), #elif defined(_WIN32) +#if !defined(__STDC_C89__) && !defined(__STDC_C89_AMENDMENT_1__) DECL_AUTOCONF_DEVICE("XInput Controller (User 1)", "xinput", XINPUT_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE("XInput Controller (User 2)", "xinput", XINPUT_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE("XInput Controller (User 3)", "xinput", XINPUT_DEFAULT_BINDS), @@ -507,6 +510,7 @@ const char* const input_builtin_autoconfs[] = DECL_AUTOCONF_DEVICE("XBOX One Controller (User 3)", "xinput", XINPUT_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE("XBOX One Controller (User 4)", "xinput", XINPUT_DEFAULT_BINDS), #endif +#endif #ifdef HAVE_SDL2 DECL_AUTOCONF_DEVICE("Standard Gamepad", "sdl2", SDL2_DEFAULT_BINDS), #endif diff --git a/input/input_overlay.c b/input/input_overlay.c index 5cb48e6c50..eed239fabc 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -24,6 +24,7 @@ #ifdef HAVE_CONFIG_H #include "../config.h" #endif +#include "../configuration.h" #ifdef HAVE_MENU #include "../menu/menu_driver.h" @@ -31,8 +32,6 @@ #include "../verbosity.h" #include "../gfx/video_driver.h" - -#include "input_driver.h" #include "input_overlay.h" #define OVERLAY_GET_KEY(state, key) (((state)->keys[(key) / 32] >> ((key) % 32)) & 1) @@ -69,6 +68,8 @@ struct input_overlay input_overlay_t *overlay_ptr = NULL; +static bool input_overlay_add_inputs(input_overlay_t *ol, + unsigned port, unsigned analog_dpad_mode); /** * input_overlay_scale: * @ol : Overlay handle. @@ -573,8 +574,10 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad rarch_joypad_info_t joypad_info; input_overlay_state_t old_key_state; unsigned i, j, device; + settings_t *settings = config_get_ptr(); uint16_t key_mod = 0; bool polled = false; + bool button_pressed = false; input_overlay_state_t *ol_state = &ol->overlay_state; if (!ol_state) @@ -703,7 +706,11 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad break; } - if (polled) + if(settings->bools.input_overlay_show_physical_inputs) + { + button_pressed = input_overlay_add_inputs(ol, settings->uints.input_overlay_show_physical_inputs_port, analog_dpad_mode); + } + if (button_pressed || polled) input_overlay_post_poll(ol, opacity); else input_overlay_poll_clear(ol, opacity); @@ -745,4 +752,98 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret, break; } } +/** + * input_overlay_add_inputs: + * @ol : pointer to overlay + * @port : the user to show the inputs of + * + * Adds inputs from current_input to the overlay, so it's displayed + * returns true if an input that is pressed will change the overlay + */ +static bool input_overlay_add_inputs(input_overlay_t *ol, + unsigned port, unsigned analog_dpad_mode) +{ + unsigned i; + uint64_t mask; + int id; + bool button_pressed = false; + bool current_button_pressed = false; + input_overlay_state_t *ol_state = &ol->overlay_state; + if(!ol_state) + return false; + + for(i = 0; i < ol->active->size; i++) + { + overlay_desc_t *desc = &(ol->active->descs[i]); + switch(desc->type) + { + case OVERLAY_TYPE_BUTTONS: + mask = desc->key_mask; + id = RETRO_DEVICE_ID_JOYPAD_B; + /* Need to check all bits in the mask, + * multiple ones can be pressed */ + current_button_pressed = false; + while(mask) + { + /* Get the next button ID */ + while(mask && (mask & 1) == 0) + { + id+=1; + mask = mask >> 1; + } + /* Light up the button if pressed */ + if(input_state(port, RETRO_DEVICE_JOYPAD, 0, id)) + { + current_button_pressed = true; + desc->updated = true; + + id+=1; + mask = mask >> 1; + } + else + { + /* One of the buttons not pressed */ + current_button_pressed = false; + desc->updated = false; + break; + } + } + button_pressed = button_pressed || current_button_pressed; + break; + case OVERLAY_TYPE_ANALOG_LEFT: + case OVERLAY_TYPE_ANALOG_RIGHT: + { + float analog_x, analog_y; + float dx, dy; + unsigned int index = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ? + RETRO_DEVICE_INDEX_ANALOG_RIGHT : RETRO_DEVICE_INDEX_ANALOG_LEFT; + + analog_x = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_X); + analog_y = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_Y); + dx = (analog_x/0x8000)*(desc->range_x/2); + dy = (analog_y/0x8000)*(desc->range_y/2); + + desc->delta_x = dx; + desc->delta_y = dy; + /*Maybe use some option here instead of 0, only display + changes greater than some magnitude. + */ + if((dx*dx) > 0 || (dy*dy) > 0) + button_pressed = true; + } + break; + case OVERLAY_TYPE_KEYBOARD: + if(input_state(port, RETRO_DEVICE_KEYBOARD, 0, (unsigned)desc->key_mask)) + { + desc->updated = true; + button_pressed = true; + } + break; + default: + break; + } + } + + return button_pressed; +} diff --git a/input/input_overlay.h b/input/input_overlay.h index 93f3c83e91..af4305702a 100644 --- a/input/input_overlay.h +++ b/input/input_overlay.h @@ -24,6 +24,8 @@ #include #include +#include "input_driver.h" + RETRO_BEGIN_DECLS #define BOX_RADIAL 0x18df06d2U diff --git a/input/input_remapping.c b/input/input_remapping.c index 17aae07ab3..6ca86e7270 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -1,5 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2015-2017 - Andrés Suárez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -23,6 +24,9 @@ #include "../configuration.h" #include "../retroarch.h" +static unsigned old_analog_dpad_mode[MAX_USERS]; +static unsigned old_libretro_device[MAX_USERS]; + /** * input_remapping_load_file: * @data : Path to config file. @@ -54,6 +58,9 @@ bool input_remapping_load_file(void *data, const char *path) "a", "x", "l", "r", "l2", "r2", "l3", "r3", "l_x", "l_y", "r_x", "r_y" }; + old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i]; + old_libretro_device[i] = settings->uints.input_libretro_device[i]; + snprintf(buf, sizeof(buf), "input_player%u", i + 1); for (j = 0; j < RARCH_FIRST_CUSTOM_BIND + 4; j++) @@ -82,6 +89,12 @@ bool input_remapping_load_file(void *data, const char *path) settings->uints.input_remap_ids[i][RARCH_FIRST_CUSTOM_BIND + j] = key_remap; } + + snprintf(buf, sizeof(buf), "input_player%u_analog_dpad_mode", i + 1); + CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[i], buf); + + snprintf(buf, sizeof(buf), "input_libretro_device_p%u", i + 1); + CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], buf); } config_file_free(conf); @@ -158,6 +171,10 @@ bool input_remapping_save_file(const char *path) config_unset(conf,key_ident[j]); } } + snprintf(buf, sizeof(buf), "input_libretro_device_p%u", i + 1); + config_set_int(conf, buf, input_config_get_device(i)); + snprintf(buf, sizeof(buf), "input_player%u_analog_dpad_mode", i + 1); + config_set_int(conf, buf, settings->uints.input_analog_dpad_mode[i]); } ret = config_file_write(conf, remap_file); @@ -166,6 +183,22 @@ bool input_remapping_save_file(const char *path) return ret; } +bool input_remapping_remove_file(const char *path) +{ + char buf[PATH_MAX_LENGTH]; + char remap_file[PATH_MAX_LENGTH]; + settings_t *settings = config_get_ptr(); + + buf[0] = remap_file[0] = '\0'; + + fill_pathname_join(buf, settings->paths.directory_input_remapping, + path, sizeof(buf)); + + fill_pathname_noext(remap_file, buf, ".rmp", sizeof(remap_file)); + + return remove(remap_file) == 0 ? true : false; +} + void input_remapping_set_defaults(void) { unsigned i, j; @@ -175,10 +208,16 @@ void input_remapping_set_defaults(void) { for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++) { - const struct retro_keybind *keybind = &input_config_binds[i][j]; - settings->uints.input_remap_ids[i][j] = keybind->id; + const struct retro_keybind *keybind = &input_config_binds[i][j]; + if (keybind) + settings->uints.input_remap_ids[i][j] = keybind->id; } for (j = 0; j < 4; j++) settings->uints.input_remap_ids[i][RARCH_FIRST_CUSTOM_BIND + j] = j; + + if (old_analog_dpad_mode[i]) + settings->uints.input_analog_dpad_mode[i] = old_analog_dpad_mode[i]; + if (old_libretro_device[i]) + settings->uints.input_libretro_device[i] = old_libretro_device[i]; } } diff --git a/input/input_remapping.h b/input/input_remapping.h index 3c988ad2c5..d2bdec05ac 100644 --- a/input/input_remapping.h +++ b/input/input_remapping.h @@ -44,6 +44,8 @@ bool input_remapping_load_file(void *data, const char *path); **/ bool input_remapping_save_file(const char *path); +bool input_remapping_remove_file(const char *path); + void input_remapping_set_defaults(void); RETRO_END_DECLS diff --git a/intl/msg_hash_chs.c b/intl/msg_hash_chs.c index 5b13c06aca..061b084b08 100644 --- a/intl/msg_hash_chs.c +++ b/intl/msg_hash_chs.c @@ -1,4 +1,4 @@ -/* RetroArch - A frontend for libretro. +/* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -279,6 +279,9 @@ int menu_hash_get_help_chs_enum(enum msg_hash_enums msg, char *s, size_t len) "截图文件将会存放在 \n" "截图目录之中."); break; + case MENU_ENUM_LABEL_ADD_TO_FAVORITES: + snprintf(s, len, "添加到收藏夹."); + break; case MENU_ENUM_LABEL_RUN: snprintf(s, len, "启动内容."); break; diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 84605f079d..7d78d479e4 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -2033,6 +2033,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Cheat Filename") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Preset Filename") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "接口") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -2974,7 +2976,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -3009,3 +3011,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_cht.c b/intl/msg_hash_cht.c index d04cfc834d..a08736ee89 100644 --- a/intl/msg_hash_cht.c +++ b/intl/msg_hash_cht.c @@ -127,7 +127,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case RARCH_OVERLAY_NEXT: snprintf(s, len, - "切換到下一個屏幕覆層。將會循環選擇。"); + "切換到下一個營幕覆層。將會循環選擇。"); break; case RARCH_DISK_EJECT_TOGGLE: snprintf(s, len, @@ -210,21 +210,21 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) switch (msg) { case MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS: - snprintf(s, len, "你的登陸信息 \n" - "Retro Achievements 賬號. \n" + snprintf(s, len, "你的登入訊息 \n" + "Retro Achievements 帳號. \n" " \n" "訪問 retroachievements.org 並註冊 \n" - "以獲取一個免費賬號. \n" + "以獲取一個免費帳號. \n" " \n" "在你註冊以後, 你需要 \n" "在RetroArch輸入你的 \n" - "賬號以及密碼."); + "帳號以及密碼."); break; case MENU_ENUM_LABEL_CHEEVOS_USERNAME: - snprintf(s, len, "你的Retro Achievements賬號的用戶名。"); + snprintf(s, len, "你的Retro Achievements帳號的用戶名。"); break; case MENU_ENUM_LABEL_CHEEVOS_PASSWORD: - snprintf(s, len, "你的Retro Achievements賬號的密碼。"); + snprintf(s, len, "你的Retro Achievements帳號的密碼。"); break; case MENU_ENUM_LABEL_USER_LANGUAGE: snprintf(s, len, "依據選擇的語言來本地化菜單和其他屏顯消息。 \n" @@ -242,7 +242,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "自動加載遊戲內容指定的核心選項."); break; case MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE: - snprintf(s, len, "自動加載覆蓋配置。"); + snprintf(s, len, "自動加載覆蓋設定。"); break; case MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE: snprintf(s, len, "自動加載輸入重映射文件."); @@ -280,26 +280,26 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) "截圖目錄之中."); break; case MENU_ENUM_LABEL_RUN: - snprintf(s, len, "啟動內容."); + snprintf(s, len, "啟動遊戲."); break; case MENU_ENUM_LABEL_INFORMATION: - snprintf(s, len, "顯示本內容的額外 \n" - "元數據信息."); + snprintf(s, len, "顯示本遊戲的額外 \n" + "元數據訊息."); break; case MENU_ENUM_LABEL_FILE_BROWSER_CONFIG: - snprintf(s, len, "配置文件."); + snprintf(s, len, "設定文件."); break; case MENU_ENUM_LABEL_FILE_BROWSER_COMPRESSED_ARCHIVE: snprintf(s, len, "壓縮歸檔文件."); break; case MENU_ENUM_LABEL_FILE_BROWSER_RECORD_CONFIG: - snprintf(s, len, "記錄配置文件."); + snprintf(s, len, "錄製設定文件."); break; case MENU_ENUM_LABEL_FILE_BROWSER_CURSOR: snprintf(s, len, "數據庫指針文件。"); break; case MENU_ENUM_LABEL_FILE_CONFIG: - snprintf(s, len, "配置文件."); + snprintf(s, len, "設定文件."); break; case MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY: snprintf(s, len, @@ -319,15 +319,15 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY: snprintf(s, len, - "縮略圖目錄. \n" + "縮圖目錄. \n" " \n" "用以存放縮略圖."); break; case MENU_ENUM_LABEL_LIBRETRO_INFO_PATH: snprintf(s, len, - "核心Core信息目錄. \n" + "核心Core訊息目錄. \n" " \n" - "用於搜索libretro核心信息 \n" + "用於搜索libretro核心訊息 \n" "的目錄。"); break; case MENU_ENUM_LABEL_PLAYLIST_DIRECTORY: @@ -400,9 +400,9 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_FILE_BROWSER_MOVIE_OPEN: snprintf(s, len, - "視頻 \n" + "視訊 \n" " \n" - "選擇文件並使用視頻播放器打開。"); + "選擇文件並使用視訊播放器打開。"); break; case MENU_ENUM_LABEL_FILE_BROWSER_MUSIC_OPEN: snprintf(s, len, @@ -476,8 +476,8 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE: snprintf(s, len, - "顯示器的視頻刷新率。 \n" - "可被用來計算一個合適的音頻輸入率。"); + "顯示器的視訊刷新率。 \n" + "可被用來計算一個合適的聲音輸入率。"); break; case MENU_ENUM_LABEL_VIDEO_FORCE_SRGB_DISABLE: snprintf(s, len, @@ -488,11 +488,11 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_AUDIO_ENABLE: snprintf(s, len, - "啟用音頻輸出。"); + "啟用聲音輸出。"); break; case MENU_ENUM_LABEL_AUDIO_SYNC: snprintf(s, len, - "同步音頻(推薦)。"); + "同步聲音(推薦)。"); break; case MENU_ENUM_LABEL_AUDIO_LATENCY: snprintf(s, len, @@ -514,8 +514,8 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_CONTENT_HISTORY_SIZE: snprintf(s, len, - "Number of entries that will be kept in \n" - "content history playlist."); + "可存放在歷史遊戲清單的數量 \n" + "."); break; case MENU_ENUM_LABEL_VIDEO_WINDOWED_FULLSCREEN: snprintf(s, len, @@ -524,7 +524,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_FONT_SIZE: snprintf(s, len, - "屏顯信息的字體大小."); + "屏顯訊息的字體大小."); break; case MENU_ENUM_LABEL_SAVESTATE_AUTO_INDEX: snprintf(s, len, @@ -540,7 +540,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_FONT_ENABLE: snprintf(s, len, - "顯示/隱藏屏顯信息."); + "顯示/隱藏屏顯訊息."); break; case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_X: case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_Y: @@ -550,7 +550,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_INPUT_OVERLAY_ENABLE: snprintf(s, len, - "Enable or disable the current overlay."); + "啟用或取消目前的 overlay."); break; case MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU: snprintf(s, len, @@ -577,7 +577,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_AUDIO_OUTPUT_RATE: snprintf(s, len, - "音頻輸出採樣率."); + "聲音輸出採樣率."); break; case MENU_ENUM_LABEL_VIDEO_SHARED_CONTEXT: snprintf(s, len, @@ -752,12 +752,12 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_DRIVER: snprintf(s, len, - "當前視頻驅動."); + "當前視訊驅動."); if (string_is_equal_fast(settings->arrays.video_driver, "gl", 2)) { snprintf(s, len, - "OpenGL視頻驅動. \n" + "OpenGL視訊驅動. \n" " \n" "This driver allows libretro GL cores to \n" "be used in addition to software-rendered \n" @@ -771,7 +771,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "sdl2", 4)) { snprintf(s, len, - "SDL 2 視頻驅動.\n" + "SDL 2 視訊驅動.\n" " \n" "This is an SDL 2 software-rendered video \n" "driver.\n" @@ -783,7 +783,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "sdl1", 4)) { snprintf(s, len, - "SDL 視頻驅動.\n" + "SDL 視訊驅動.\n" " \n" "This is an SDL 1.2 software-rendered video \n" "driver.\n" @@ -794,7 +794,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "d3d", 3)) { snprintf(s, len, - "Direct3D 視頻驅動. \n" + "Direct3D 視訊驅動. \n" " \n" "Performance for software-rendered cores \n" "is dependent on your graphic card's \n" @@ -803,7 +803,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "exynos", 6)) { snprintf(s, len, - "Exynos-G2D 視頻驅動. \n" + "Exynos-G2D 視訊驅動. \n" " \n" "This is a low-level Exynos video driver. \n" "Uses the G2D block in Samsung Exynos SoC \n" @@ -815,7 +815,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "drm", 3)) { snprintf(s, len, - "Plain DRM 視頻驅動. \n" + "Plain DRM 視訊驅動. \n" " \n" "This is a low-level video driver using. \n" "libdrm for hardware scaling using \n" @@ -824,7 +824,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "sunxi", 5)) { snprintf(s, len, - "Sunxi-G2D 視頻驅動. \n" + "Sunxi-G2D 視訊驅動. \n" " \n" "This is a low-level Sunxi video driver. \n" "Uses the G2D block in Allwinner SoCs."); @@ -832,7 +832,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN: snprintf(s, len, - "音頻DSP插件.\n" + "聲音DSP插件.\n" " Processes audio before it's sent to \n" "the driver." ); @@ -1311,7 +1311,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_VSYNC: snprintf(s, len, - "視頻垂直同步.\n"); + "視訊垂直同步.\n"); break; case MENU_ENUM_LABEL_VIDEO_HARD_SYNC: snprintf(s, len, @@ -1332,7 +1332,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_SCREENSHOT: snprintf(s, len, - "Take screenshot."); + "營幕快照."); break; case MENU_ENUM_LABEL_VIDEO_FRAME_DELAY: snprintf(s, len, @@ -1379,7 +1379,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) "'Save Configuration on Exit' is enabled.\n"); break; case MENU_ENUM_LABEL_VIDEO_FULLSCREEN: - snprintf(s, len, "Toggles fullscreen."); + snprintf(s, len, "啟用全營幕."); break; case MENU_ENUM_LABEL_BLOCK_SRAM_OVERWRITE: snprintf(s, len, @@ -1483,7 +1483,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) ); break; case MENU_ENUM_LABEL_INPUT_TOUCH_ENABLE: - snprintf(s, len, "Enable touch support."); + snprintf(s, len, "啟用觸控支援."); break; case MENU_ENUM_LABEL_INPUT_PREFER_FRONT_TOUCH: snprintf(s, len, "Use front instead of back touch."); @@ -1563,27 +1563,27 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, - "Shows current date and/or time inside menu."); + "在選單內顯示當前日期或時間."); break; case MENU_ENUM_LABEL_CORE_ENABLE: snprintf(s, len, - "Shows current core inside menu."); + "在選單內顯示當前使用遊戲核心."); break; case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: snprintf(s, len, - "Enables Netplay in host (server) mode."); + "啟用連線遊戲模式 (主機端) ."); break; case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: snprintf(s, len, - "Enables Netplay in client mode."); + "啟用連線遊戲模式 (連線端) ."); break; case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: snprintf(s, len, - "Disconnects an active Netplay connection."); + "中斷使用中的連線遊戲模式."); break; case MENU_ENUM_LABEL_NETPLAY_SETTINGS: snprintf(s, len, - "Setting related to Netplay."); + "連線遊戲模式相關設定."); break; case MENU_ENUM_LABEL_NETPLAY_LAN_SCAN_SETTINGS: snprintf(s, len, @@ -1713,11 +1713,11 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_OSK_ENABLE: snprintf(s, len, - "Enable/disable on-screen keyboard."); + "開啟或取消營幕的虛擬鍵盤."); break; case MENU_ENUM_LABEL_AUDIO_MUTE: snprintf(s, len, - "Mute/unmute audio."); + "開啟或關閉靜音."); break; case MENU_ENUM_LABEL_REWIND: snprintf(s, len, @@ -1739,15 +1739,15 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_LOAD_STATE: snprintf(s, len, - "Loads state."); + "載入即時存檔."); break; case MENU_ENUM_LABEL_SAVE_STATE: snprintf(s, len, - "Saves state."); + "儲存即時存檔."); break; case MENU_ENUM_LABEL_NETPLAY_FLIP_PLAYERS: snprintf(s, len, - "Netplay flip users."); + "踢掉連線遊戲的使用者."); break; case MENU_ENUM_LABEL_CHEAT_INDEX_PLUS: snprintf(s, len, @@ -1767,7 +1767,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_RESET: snprintf(s, len, - "Reset the content.\n"); + "重設遊戲.\n"); break; case MENU_ENUM_LABEL_PAUSE_TOGGLE: snprintf(s, len, diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index 4a51682c8a..41c0f34a4e 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -8,15 +8,15 @@ MSG_HASH( ) MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT, - "設備已從端口上斷開" + "設備已從連接口上移開" ) MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "接收到未知的聯機遊戲指令" + "接收到未知的連線遊戲指令" ) MSG_HASH( MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, - "文件已存在。保存到備份緩衝區" + "文件已存在。儲存到備份至緩衝區" ) MSG_HASH( MSG_GOT_CONNECTION_FROM, @@ -32,15 +32,15 @@ MSG_HASH( ) MSG_HASH( MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "未提供參數也沒有內建菜單,顯示幫助..." + "未提供參數也沒有內建選單,顯示幫助..." ) MSG_HASH( MSG_NETPLAY_USERS_HAS_FLIPPED, - "聯機遊戲用戶已被踢出" + "連線遊戲用戶已被踢出" ) MSG_HASH( MSG_SETTING_DISK_IN_TRAY, - "Setting disk in tray" + "設定光碟機裡光碟" ) MSG_HASH( MSG_WAITING_FOR_CLIENT, @@ -56,7 +56,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_IMPLEMENTATIONS_DIFFER, - "實現有差異。確保正在使用的RetroArch和核心是同版本的。" + "執行時錯誤發生。請確保雙方的所使用的RetroArch跟核心是同版本的。" ) MSG_HASH( MSG_NETPLAY_ENDIAN_DEPENDENT, @@ -64,11 +64,11 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_PLATFORM_DEPENDENT, - "This core does not support inter-architecture netplay" + "此模擬器且不支援此兩種架構下的連線遊戲模式" ) MSG_HASH( MSG_NETPLAY_ENTER_PASSWORD, - "輸入聯機遊戲服務器的密碼:" + "輸入連線遊戲服務器的密碼:" ) MSG_HASH( MSG_NETPLAY_INCORRECT_PASSWORD, @@ -76,15 +76,15 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_SERVER_NAMED_HANGUP, - "\"%s\" 已斷開連接" + "\"%s\" 已斷開連線" ) MSG_HASH( MSG_NETPLAY_SERVER_HANGUP, - "一個聯機遊戲客戶端已斷開" + "連線遊戲客戶端已離開" ) MSG_HASH( MSG_NETPLAY_CLIENT_HANGUP, - "聯機遊戲已斷開" + "已離開連線遊戲模式" ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, @@ -92,7 +92,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, - "已無空閒插槽" /*FIXME:"There are no free player slots"*/ + "連線遊戲人數已滿" /*FIXME:"There are no free player slots"*/ ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY, @@ -100,7 +100,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_PEER_PAUSED, - "聯機遊戲對方 \"%s\" 暫停" + "連線遊戲對方 \"%s\" 已暫停" ) MSG_HASH( MSG_NETPLAY_CHANGED_NICK, @@ -108,11 +108,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Give hardware-rendered cores their own private context. Avoids having to assume hardware state changes inbetween frames." + "使用模擬器硬體渲染私人內容時可避免硬體在各frames時的狀態改變." ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "調整菜單屏幕相關的設置。" + "調整選單顯示的相關設定。" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, @@ -120,20 +120,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "以延遲和視頻撕裂為代價換取高性能,當且僅當能\n" + "以延遲和視訊撕裂為代價換取高性能,當且僅當能\n" "達到全速模擬時使用。" ) MSG_HASH( MSG_AUDIO_VOLUME, - "音頻音量" + "聲音音量" ) MSG_HASH( MSG_AUTODETECT, - "自動檢測" + "自動偵測" ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FROM, - "自動加載存檔從" + "自動載入存檔從" ) MSG_HASH( MSG_CAPABILITIES, @@ -141,11 +141,11 @@ MSG_HASH( ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "連接到聯機遊戲主機" + "連線到連線遊戲主機" ) MSG_HASH( MSG_CONNECTING_TO_PORT, - "連接到端口" + "連接到連接口" ) MSG_HASH( MSG_CONNECTION_SLOT, @@ -153,18 +153,18 @@ MSG_HASH( ) MSG_HASH( MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "對不起,未實現:核心未請求內容,無法加入聯機遊戲。" + "對不起,錯誤發生:模擬器核心未請求內容,無法加入連線遊戲。" ) MSG_HASH( MSG_FAILED_TO_SET_DISK, - "設置磁盤失敗") + "設定磁盤失敗") MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, "密碼" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Cheevos賬戶" /*FIXME:"Accounts Cheevos"*/ + "Cheevos帳戶" /*FIXME:"Accounts Cheevos"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, @@ -172,11 +172,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, - "賬戶" + "帳戶" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, - "賬戶列表終端" + "帳戶列表終端" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, @@ -189,7 +189,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "成就列表(硬核)" /*FIXME:"Achievement List (Hardcore)"*/ + "成就列表(專家模式)" /*FIXME:"Achievement List (Hardcore)"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, @@ -197,7 +197,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "配置" + "設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TAB, @@ -205,7 +205,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "聯機遊戲房間" + "連線遊戲房間" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, @@ -221,23 +221,23 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, - "音頻設備" + "聲音設備" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, - "音頻驅動" + "聲音驅動程式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, - "音頻DSP插件" + "聲音DSP插件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, - "啟用音頻" + "啟用聲音" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, - "音頻過濾器目錄" + "聲音過濾器目錄" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, @@ -245,55 +245,55 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - "音頻時延(ms)" + "聲音時延(ms)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, - "音頻最大採樣間隔" + "聲音最大採樣間隔" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "音頻靜音" + "聲音靜音" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, - "音頻輸出碼率(Hz)" + "聲音輸出碼率(Hz)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, - "音頻碼率控制間隔" + "動態聲音碼率控制間隔" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, - "音頻重採樣驅動" + "聲音重採樣驅動程式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, - "音頻" + "聲音" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, - "啟用音頻同步" + "啟用聲音同步" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "音頻音量級別(dB)" + "聲音音量級別(dB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "SaveRAM自動保存間隔" + "SaveRAM自動儲存間隔" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, - "自動加載覆寫文件" + "自動載入覆寫文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, - "自動加載重映射文件" + "自動戴入重映射文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, - "自動加載Shader預設" + "自動戴入Shader預設" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, @@ -305,7 +305,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "信息" + "訊息" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, @@ -329,11 +329,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "切換菜單" + "切換選單" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "基本菜單控制" + "基本選單控制" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, @@ -341,7 +341,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, - "信息" + "訊息" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, @@ -361,11 +361,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "切換菜單" + "切換選單" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "加載保存狀態時不覆蓋SaveRAM" + "載入儲存狀態時不覆蓋SaveRAM" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, @@ -377,7 +377,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, - "緩存目錄" + "緩沖目錄" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, @@ -385,7 +385,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, - "相機驅動" + "相機驅動程式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT, @@ -393,7 +393,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, - "應用金手指修改" + "執行金手指修改" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, @@ -405,11 +405,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "加載金手指文件" + "載入金手指文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "另存為金手指文件" + "另存金手指文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, @@ -422,7 +422,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, /* FIXME? Translate 'Achievements Hardcore Mode' */ - "專家模式" + "成就-專家模式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, @@ -439,7 +439,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, /* FIXME? Translate 'Test Unofficial Achievements' */ - "非官方測試" + "非官方測試成就" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, @@ -455,19 +455,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG, - "配置" + "設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "加載配置" + "載入設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, - "配置" + "設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, - "退出時保存配置" + "退出時儲存設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIRM_ON_EXIT, @@ -491,7 +491,7 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, "允許移除記錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "快捷菜單") + "快捷選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, "下載目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, @@ -503,7 +503,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, "顯示核心名稱") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, - "核心信息") + "核心訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, "作者") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, @@ -513,7 +513,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, "核心名稱") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, - "固件") + "韌體") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, "許可證") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, @@ -527,7 +527,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "控制") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_LIST, - "加載核心") + "戴入核心") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, @@ -573,11 +573,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, "Disk Cycle Tray Status") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, - "追加光盤鏡像") + "追加光碟鏡像") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_INDEX, - "光盤索引") + "光碟索引") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, - "光盤控制") + "光碟控制") MSG_HASH(MENU_ENUM_LABEL_VALUE_DONT_CARE, "不關心") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, @@ -594,22 +594,22 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, "驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, /* FIXME? Translate 'Load Dummy on Core Shutdown' */ - "核心關閉時加載虛擬程序") + "核心關閉時戴入虛擬程序") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, - "加載前檢查丟失的固件") /*FIXME: "Check for Missing Firmware Before Loading"*/ + "載入前檢查韌體/BIOS是否存在") /*FIXME: "Check for Missing Firmware Before Loading"*/ MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "動態壁紙") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, "動態壁紙目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, /* FIXME? Translate 'Enable Achievements' */ - "啟用") + "啟用成就系統") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, - "菜單項懸停顏色") + "選單項懸停顏色") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, - "菜單項正常顏色") + "選單項正常顏色") MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, - "假") + "取消") MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, "最大運行速度") MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, @@ -621,7 +621,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, "前端計數器") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "自動加載遊戲內容特定的核心選項") + "自動戴入遊戲內容特定的核心選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, "創建遊戲選項文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, @@ -629,15 +629,15 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, "幫助") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "音頻/視頻故障排除") + "聲音/視訊故障排除") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, "變更虛擬遊戲控制器覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, - "基本菜單控制") + "基本選單控制") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST, "幫助") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, - "加載遊戲內容") + "戴入遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, "掃瞄遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, @@ -647,17 +647,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_TAB, "歷史") MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, - "水平化菜單") + "水平化選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, "圖像") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION, - "信息") + "訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, - "信息") + "訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, "手柄輸入轉數字選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "所有用戶都能控制菜單") + "所有用戶都能控制選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, "左搖桿X") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, @@ -683,11 +683,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, "右搖桿Y+ (下)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, - "啟用自動配置") + "啟用自動設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, "輸入軸閾值") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "菜單切換 確定/取消 按鈕") /*FIXME:"Menu Swap OK & Cancel Buttons"*/ + "選單切換 確定/取消 按鈕") /*FIXME:"Menu Swap OK & Cancel Buttons"*/ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, "綁定全部") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, @@ -749,7 +749,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, "最大用戶數") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "遊戲控制器菜單切出組合鍵") + "遊戲控制器選單切出組合鍵") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, "金手指索引 -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, @@ -759,9 +759,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, "光驅出倉切換") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, - "下一張光盤") + "下一張光碟") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, - "上一張光盤") + "上一張光碟") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, "啟用熱鍵") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, @@ -771,25 +771,25 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "幀提前量") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, - "切換全屏幕") + "切換全營幕") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "鼠標捕獲開關") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, - "Game focus toggle") + "切換遊戲焦距") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "加載狀態") + "戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, - "切換菜單") + "切換選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, - "視頻錄製開關") + "視訊錄製開關") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, "靜音開關") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, - "聯機遊戲踢出用戶") + "連線遊戲踢出用戶") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "聯機遊戲切換 遊戲/圍觀 模式") + "連線遊戲切換 遊戲/圍觀 模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, - "切換屏幕鍵盤") + "切換營幕鍵盤") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, "下一個覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, @@ -801,9 +801,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, "回溯") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "保存狀態") + "儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, - "屏幕截圖") + "營幕截圖") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, "下一個Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, @@ -823,7 +823,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OSK_OVERLAY_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, "顯示覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, - "在菜單中隱藏覆層") + "在選單中隱藏覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, "輪詢類型行為") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, @@ -839,7 +839,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, "啟用綁定重映射") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, - "保存自動設置") + "儲存自動設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, "輸入") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, @@ -855,7 +855,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, MSG_HASH(MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, "內部存儲狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "輸入設備自動配置目錄") + "輸入設備自動設定目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, "手柄驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, @@ -897,19 +897,19 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, "核心目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "核心信息目錄") + "核心訊息目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, "核心日誌級別") MSG_HASH(MENU_ENUM_LABEL_VALUE_LINEAR, "線性") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, - "使用核心加載壓縮包") + "使用核心戴入壓縮包") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, - "加載最近的遊戲內容") + "戴入最近的遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, "載入遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_STATE, - "加載狀態") + "戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, "允許使用位置") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, @@ -919,11 +919,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, "完整日誌記錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_MAIN_MENU, - "主菜單") + "主選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_MANAGEMENT, - "數據庫設置") + "數據庫設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, - "菜單顏色主題") + "選單顏色主題") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, "藍色") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, @@ -943,17 +943,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, "頂部不透明度") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DRIVER, - "菜單驅動") + "選單驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, - "限制菜單幀率") + "限制選單幀率") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, /* TODO/FIXME - update */ - "菜單文件瀏覽器") + "選單文件瀏覽器") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, - "菜單線性過濾") + "選單線性過濾") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "菜單") + "選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, - "菜單壁紙") + "選單壁紙") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, "壁紙不透明度") MSG_HASH(MENU_ENUM_LABEL_VALUE_MISSING, @@ -973,57 +973,57 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, MSG_HASH(MENU_ENUM_LABEL_VALUE_NEAREST, "最近") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY, - "在線遊戲") + "連線遊戲") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, - "在線遊戲檢查幀數") + "連線遊戲檢查幀數") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CLIENT_SWAP_INPUT, - "在線玩家P2使用C1") + "連線玩家P2使用C1") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "在線遊戲延遲幀數") + "連線遊戲延遲幀數") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, "斷開連接") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, - "啟用在線遊戲") + "啟用連線遊戲") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, "連接到遊戲主機") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, "作為遊戲主機") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Stop netplay host") + "停止連線主機") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, "服務器地址") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, - "掃瞄本地網絡") + "掃瞄本地網路") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "啟用在線遊戲客戶端") + "啟用連線遊戲客戶端") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "用戶名") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, "服務器密碼") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "在線遊戲設置") + "連線遊戲設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "聯機無狀態模式") + "連線遊戲無狀態模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, "服務器圍觀的密碼") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "啟用在線遊戲旁觀者") + "啟用連線遊戲旁觀者") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "在線遊戲TCP/UDP端口") + "連線遊戲TCP/UDP端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "聯機NAT遍歷") + "連線遊戲使用NAT穿透技術") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, - "網絡命令") + "網路命令") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, - "網絡命令端口") + "網路命令端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, - "網絡信息") + "網路訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, - "網絡遊戲控制器") + "網路遊戲控制器") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, - "網絡遠端基本端口") + "網路遠端基本端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, - "網絡") + "網路") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO, "否") MSG_HASH(MENU_ENUM_LABEL_VALUE_NONE, @@ -1037,7 +1037,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, "沒有可用的核心。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, - "沒有可用的核心信息。") + "沒有可用的核心訊息。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, "沒有可用的核心選項。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, @@ -1045,13 +1045,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, "沒有可用的歷史記錄。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, - "沒有可用的信息。") + "沒有可用的訊息。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS, "沒有條目。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, - "未發現聯機遊戲主機。") + "未發現連線遊戲主機。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, - "未發現網絡。") + "未發現網路。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, "沒有性能計數器。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, @@ -1059,7 +1059,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, "沒有可用的遊戲列表項目。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, - "沒有找到設置。") + "沒有找到設定。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, "沒有Shader參數.") MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, @@ -1067,15 +1067,15 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, MSG_HASH(MENU_ENUM_LABEL_VALUE_ON, "開") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, - "在線更新器") + "連線更新器") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, - "屏幕顯示") + "營幕顯示") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, - "屏幕覆層") + "營幕覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, "以文件夾形式打開壓縮包") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, - "屏幕通知") + "營幕通知") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPTIONAL, "任意") MSG_HASH(MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_DIRECTORY, @@ -1083,7 +1083,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY, "覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, - "自動加載最佳的覆層") + "自動戴入最佳的覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, "覆層目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, @@ -1093,13 +1093,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, "覆層縮放比例") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, - "屏幕覆層") + "營幕覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, "使用PAL60模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, "上一級目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, - "當菜單激活時暫停") + "當選單激活時暫停") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, "禁止後台運行") MSG_HASH(MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, @@ -1111,7 +1111,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, "遊戲列表") MSG_HASH(MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, - "觸摸支持") + "觸控支援") MSG_HASH(MENU_ENUM_LABEL_VALUE_PORT, "端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_PRESENT, @@ -1179,17 +1179,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, "重啟") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, - "錄像配置目錄") + "錄影設定目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, - "錄像輸出目錄") + "錄影輸出目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, - "錄像") + "錄影") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "錄像配置") + "錄影設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, - "錄像驅動") + "錄影驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, - "啟用錄像") + "啟用錄影") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, "輸出文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, @@ -1197,11 +1197,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE, "重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, - "加載重映射文件") + "戴入重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, - "保存核心重映射文件") + "儲存核心重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, - "保存遊戲重映射文件") + "儲存遊戲重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, "必須") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -1215,7 +1215,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, "Retro鍵盤") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD, - "Retro觸摸板") + "Retro觸控板") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, "RetroPad w/ Analog") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, @@ -1229,9 +1229,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, "文件瀏覽器目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, - "配置目錄") + "設定目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, - "顯示開始屏幕") + "顯示開始營幕") MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, "右側搖桿") MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, @@ -1241,25 +1241,25 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, "存檔文件目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, - "自動索引保存狀態") + "自動索引儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "自動加載狀態") + "自動戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "自動保存狀態") + "自動儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, "狀態存儲目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Savestate Thumbnails") + "既時存檔縮圖") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, - "保存當前配置") + "儲存當前設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "保存核心覆寫") + "儲存核心覆寫") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "保存遊戲覆寫") + "儲存遊戲覆寫") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, - "保存新配置") + "儲存新設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, - "保存狀態") + "儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, "存檔") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, @@ -1269,17 +1269,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, "<掃瞄當前目錄>") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, - "屏幕截圖目錄") + "營幕截圖目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - "屏幕分辨率") + "營幕分辨率") MSG_HASH(MENU_ENUM_LABEL_VALUE_SEARCH, "搜索:") MSG_HASH(MENU_ENUM_LABEL_VALUE_SECONDS, "秒") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS, - "設置") + "設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - "設置") + "設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER, "Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, @@ -1295,7 +1295,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, "Snow") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, - "顯示高級設置") + "顯示高級設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, "顯示隱藏的文件和文件夾") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHUTDOWN, @@ -1313,7 +1313,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, MSG_HASH(MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, "啟動遠程的RetroPad") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, - "啟動視頻處理") + "啟動視訊處理") MSG_HASH(MENU_ENUM_LABEL_VALUE_STATE_SLOT, "狀態存儲槽") MSG_HASH(MENU_ENUM_LABEL_VALUE_STATUS, @@ -1329,7 +1329,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, "系統/BIOS目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "系統信息") + "系統訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, "7zip 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, @@ -1359,7 +1359,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, "動態鏈接庫支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, - "運行時動態加載libretro庫") + "運行時動態戴入libretro庫") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, "EGL 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, @@ -1393,9 +1393,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, "Netplay (點對點) 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, - "網絡控制台支持") + "網路控制台支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, - "網絡控制器支持") + "網路控制器支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, "OpenAL 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, @@ -1453,7 +1453,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, - "視頻上下文驅動") + "視訊上下文驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, @@ -1467,7 +1467,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, "Zlib 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, - "截取屏幕") + "截取營幕") MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, /* TODO/FIXME - update */ "啟用多線程數據執行循環") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS, @@ -1485,7 +1485,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, MSG_HASH(MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, "顯示時間日期") MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, - "菜單標題顏色") + "選單標題顏色") MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, "真") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, @@ -1497,9 +1497,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, "無法讀取壓縮的文件。") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, - "撤銷加載狀態") + "撤銷戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, - "撤銷保存狀態") + "撤銷儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNKNOWN, "未知") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, @@ -1507,13 +1507,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, "更新資源") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "更新自動配置檔案") + "更新自動設定檔案") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, "更新CG Shader效果文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, "更新金手指") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "更新核心信息文件") + "更新核心訊息文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, "更新數據庫") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, @@ -1541,9 +1541,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, "允許旋轉") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, - "自動選擇視口比例") + "自動選擇畫面比例") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, - "視口比例選項") + "畫面比例選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "黑色幀補間") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, @@ -1551,11 +1551,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, "禁用桌面元素") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, - "視頻驅動") + "視訊驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, - "視頻濾鏡") + "視訊濾鏡") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, - "視頻濾鏡目錄") + "視訊濾鏡目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, "閃爍過濾器") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, @@ -1565,7 +1565,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "屏顯消息(OSD)大小") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, - "強制視口比例") + "強制畫面比例") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, "強制禁止sRGB幀緩衝") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, @@ -1573,9 +1573,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, "使用全屏模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - "視頻Gamma") + "視訊Gamma") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, - "啟用GPU錄像") + "啟用GPU錄影") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, "啟用GPU截屏") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, @@ -1591,7 +1591,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, "顯示器索引") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, - "啟用錄像後期濾鏡") + "啟用錄影後期濾鏡") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, "刷新率") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, @@ -1603,23 +1603,23 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, "整數化縮放量") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, - "視頻") + "視訊") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, - "視頻Shader目錄") + "視訊Shader目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, "Shader渲染遍數") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, "預覽Shader參數") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, - "加載Shader預設") + "戴入Shader預設") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_PARAMETERS, - "菜單Shader參數") + "選單Shader參數") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, - "保存Shader預設為") + "儲存Shader預設為") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, - "保存核心預設") + "儲存核心預設") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, - "保存遊戲預設") + "儲存遊戲預設") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, "啟用硬件共享上下文") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, @@ -1629,21 +1629,21 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, "垂直同步交換間隔") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_TAB, - "視頻") + "視訊") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, "多線程渲染") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, "降低閃爍") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "自定義視口高度") + "自定義畫面高度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "自定義視口寬度") + "自定義畫面寬度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, - "自定義視口X") + "自定義畫面X") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, - "自定義視口Y") + "自定義畫面Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "設置 VI 屏幕寬度") + "設定 VI 營幕寬度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, "垂直同步") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, @@ -1657,9 +1657,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, "Wi-Fi") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, - "菜單透明度因子") + "選單透明度因子") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_FONT, - "菜單字體") + "選單字體") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, "自定義") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, @@ -1677,7 +1677,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, "Dot-Art") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, - "菜單顏色主題") + "選單顏色主題") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, "蘋果綠") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, @@ -1699,9 +1699,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, "火山紅") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, - "菜單Shader管線") + "選單Shader管線") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, - "菜單縮放因子") + "選單縮放因子") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, "啟用圖標陰影") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_HISTORY, @@ -1713,11 +1713,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_IMAGES, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_MUSIC, "顯示音樂頁") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_SETTINGS, - "顯示設置頁") + "顯示設定頁") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_VIDEO, - "顯示視頻頁") + "顯示視訊頁") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_THEME, - "菜單圖標主題") + "選單圖標主題") MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, "是") MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, @@ -1729,69 +1729,69 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, "為所有遊戲打開或關閉存檔、金手指、回退、快進、暫停和慢動作。") MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "修改驅動設置。") + "修改驅動設定。") MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "修改成就設置。") + "修改成就設定。") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "修改核心設置。") + "修改核心設定。") MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "修改錄製的設置。") + "修改錄製的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "修改顯示覆蓋、鍵盤覆蓋和屏幕通知的設置。") + "修改顯示覆蓋、鍵盤覆蓋和營幕通知的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "修改回滾、快進和慢動作的設置。") + "修改回滾、快進和慢動作的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "修改存檔設置。") + "修改存檔設定。") MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "修改日誌設置。") + "修改日誌設定。") MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "修改用戶界面設置。") + "修改用戶界面設定。") MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, "修改帳號、用戶名和語言。") MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "修改你的隱私設置。") + "修改你的隱私設定。") MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, "修改此系統的默認目錄。") MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "修改遊戲列表設置。") + "修改遊戲列表設定。") MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, - "修改網絡設置。") + "修改網路設定。") MSG_HASH(MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, "下載且/或者掃瞄遊戲內容,並將其加入你的收藏中。") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "調整音頻輸出的選項。") + "調整聲音輸出的選項。") MSG_HASH(MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, "啟用或者禁止藍牙。") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "程序將在退出時保存修改到配置文件。") + "程序將在退出時儲存修改到設定文件。") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, - "修改配置文件的默認設置。") + "修改設定文件的默認設定。") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, - "管理和創建配置文件。") + "管理和創建設定文件。") MSG_HASH(MENU_ENUM_SUBLABEL_CPU_CORES, "CPU擁有的核心總數。") MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, - "在屏幕上顯示當前每秒的幀率。") + "在營幕上顯示當前每秒的幀率。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "配置熱鍵選項。") + "設定熱鍵選項。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "控制器用來切出菜單的組合鍵。") + "控制器用來切出選單的組合鍵。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "調整遊戲控制器、鍵盤和鼠標的設置。") + "調整遊戲控制器、鍵盤和鼠標的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, - "配置該用戶的控制選項。") + "設定該用戶的控制選項。") MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, "啟用或禁止向控制台打印日誌。") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, - "加入或者開啟一個在線多人遊戲的會話。") + "加入或者開啟一個連線多人遊戲的會話。") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, "在局域網內搜索並連接聯網遊戲的主機。") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "顯示核心、網絡和系統的信息。顯示數據庫和光標的管理器。") + "顯示核心、網路和系統的訊息。顯示數據庫和光標的管理器。") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "下載並更新RetroArch的附加插件和組件。") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, - "啟用或者禁止網絡文件夾共享(SAMBA)。") + "啟用或者禁止網路文件夾共享(SAMBA)。") MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, "管理操作系統層級的服務。") MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, @@ -1799,9 +1799,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, "啟用或者禁止遠程終端訪問(SSH)。") MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "阻止系統激活屏幕保護程序。") + "阻止系統激活營幕保護程序。") MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "設置用戶界面的語言。") + "設定用戶界面的語言。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, "在幀與幀之間插入黑色的中間幀,通常用於消除在\n" "120Hz刷新率的顯示器上運行60Hz的遊戲內容帶來\n" @@ -1810,7 +1810,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, "以增加畫面卡頓的風險換取低延時,在垂直同步後增加\n" "時延(毫秒)。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "設置當開啟「強制GPU同步」時CPU可以預先GPU多少幀。") + "設定當開啟「強制GPU同步」時CPU可以預先GPU多少幀。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "強制顯示驅動程序使用特定的緩衝模式。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, @@ -1818,9 +1818,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, "估算的顯示器刷新率(Hz)。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "調整視頻輸出的選項。") + "調整視訊輸出的選項。") MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, - "掃瞄無線網絡並且建立連接。") + "掃瞄無線網路並且建立連接。") MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, "學習更多關於其是如何工作的。") MSG_HASH(MSG_APPENDED_DISK, @@ -1828,27 +1828,27 @@ MSG_HASH(MSG_APPENDED_DISK, MSG_HASH(MSG_APPLICATION_DIR, "應用程序目錄") MSG_HASH(MSG_APPLYING_SHADER, - "Applying shader") + "載入 shader") MSG_HASH(MSG_AUDIO_MUTED, "靜音。") MSG_HASH(MSG_AUDIO_UNMUTED, "取消靜音。") MSG_HASH(MSG_AUTOCONFIG_FILE_ERROR_SAVING, - "保存 autoconf 文件錯誤。") + "儲存 autoconf 文件錯誤。") MSG_HASH(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, - "自動配置文件保存成功。") + "自動設定文件儲存成功。") MSG_HASH(MSG_AUTOSAVE_FAILED, - "無法初始化自動保存。") + "無法初始化自動儲存。") MSG_HASH(MSG_AUTO_SAVE_STATE_TO, - "自動保存狀態至") + "自動儲存狀態至") MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, "阻止 SRAM 覆蓋") MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, - "Bringing up command interface on port") + "啟用通訊埠上的指令介面") MSG_HASH(MSG_BYTES, "字節") MSG_HASH(MSG_CANNOT_INFER_NEW_CONFIG_PATH, - "無法推斷新的配置路徑,使用當前時間。") + "無法推斷新的設定路徑,使用當前時間。") MSG_HASH(MSG_CHEEVOS_HARDCORE_MODE_ENABLE, "硬核模式開啟:及時存檔和回放被禁用.") MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, @@ -1856,21 +1856,21 @@ MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, MSG_HASH(MSG_COMPILED_AGAINST_API, "Compiled against API") MSG_HASH(MSG_CONFIG_DIRECTORY_NOT_SET, - "未設置配置目錄,無法保存新的配置。") + "未設定設定目錄,無法儲存新的設定。") MSG_HASH(MSG_CONNECTED_TO, "連接至") MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, "內容的CRC32s不同。無法使用不同的遊戲。") MSG_HASH(MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, - "跳過內容加載。實現將自行加載。") + "跳過內容戴入。實現將自行戴入。") MSG_HASH(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "核心不支持保存狀態。") + "核心不支持儲存狀態。") MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, - "Core options file created successfully.") + "模擬器核心設定檔建立成功.") MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, - "Could not find any next driver") + "無法找到磁碟") MSG_HASH(MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, - "Could not find compatible system.") + "無法找到相容系統.") MSG_HASH(MSG_COULD_NOT_FIND_VALID_DATA_TRACK, "無法找到有效的數據軌") MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, @@ -1878,9 +1878,9 @@ MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, MSG_HASH(MSG_COULD_NOT_READ_CONTENT_FILE, "無法讀取內容文件") MSG_HASH(MSG_COULD_NOT_READ_MOVIE_HEADER, - "無法讀取視頻頭部信息.") + "無法讀取視訊頭部訊息.") MSG_HASH(MSG_COULD_NOT_READ_STATE_FROM_MOVIE, - "無法讀取視頻狀態.") + "無法讀取視訊狀態.") MSG_HASH(MSG_CRC32_CHECKSUM_MISMATCH, "CRC32 checksum mismatch between content file and saved content checksum in replay file header; replay highly likely to desync on playback.") MSG_HASH(MSG_CUSTOM_TIMING_GIVEN, @@ -1892,9 +1892,9 @@ MSG_HASH(MSG_DECOMPRESSION_FAILED, MSG_HASH(MSG_DETECTED_VIEWPORT_OF, "Detected viewport of") MSG_HASH(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, - "Did not find a valid content patch.") + "無法找到任何有效的內容位置.") MSG_HASH(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, - "Disconnect device from a valid port.") + "從連接埠離開.") MSG_HASH(MSG_DISK_CLOSED, "已關閉") MSG_HASH(MSG_DISK_EJECTED, @@ -1924,17 +1924,17 @@ MSG_HASH(MSG_EXTRACTING, MSG_HASH(MSG_EXTRACTING_FILE, "解壓文件") MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, - "無法保存配置到") + "無法儲存設定到") MSG_HASH(MSG_FAILED_TO, "Failed to") MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, - "Failed to accept incoming spectator.") + "無法讓觀眾加入.") MSG_HASH(MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, - "Failed to allocate memory for patched content...") + "無法配置記憶體給已俢改的遊戲") MSG_HASH(MSG_FAILED_TO_APPLY_SHADER, - "Failed to apply shader.") + "無法載入 shader.") MSG_HASH(MSG_FAILED_TO_BIND_SOCKET, - "Failed to bind socket.") + "無法連接通訊埠.") MSG_HASH(MSG_FAILED_TO_CREATE_THE_DIRECTORY, "創建目錄失敗。") MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, @@ -1942,37 +1942,37 @@ MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, MSG_HASH(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, "從客戶端獲取暱稱失敗.") MSG_HASH(MSG_FAILED_TO_LOAD, - "無法加載") + "無法戴入") MSG_HASH(MSG_FAILED_TO_LOAD_CONTENT, "載入內容失敗") MSG_HASH(MSG_FAILED_TO_LOAD_MOVIE_FILE, - "載入視頻文件失敗") + "載入視訊文件失敗") MSG_HASH(MSG_FAILED_TO_LOAD_OVERLAY, - "Failed to load overlay.") + "無法戴入 overlay.") MSG_HASH(MSG_FAILED_TO_LOAD_STATE, - "Failed to load state from") + "無法戴入 state ") MSG_HASH(MSG_FAILED_TO_OPEN_LIBRETRO_CORE, "打開libretro核心失敗") MSG_HASH(MSG_FAILED_TO_PATCH, "補丁應用失敗") MSG_HASH(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, - "Failed to receive header from client.") + "無法接收連線端的資訊") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME, - "Failed to receive nickname.") + "無法接收暱稱.") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, - "Failed to receive nickname from host.") + "無法接收主控端的暱稱.") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, - "Failed to receive nickname size from host.") + "無法接收主控端的暱稱大小.") MSG_HASH(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, - "Failed to receive SRAM data from host.") + "無法接收主控端 SRAM 資料.") MSG_HASH(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, - "Failed to remove disk from tray.") + "移除光碟失敗.") MSG_HASH(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, "移除臨時文件失敗") MSG_HASH(MSG_FAILED_TO_SAVE_SRAM, - "Failed to save SRAM") + "SRAM 存檔失敗") MSG_HASH(MSG_FAILED_TO_SAVE_STATE_TO, - "Failed to save state to") + "即時存檔儲存失敗") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME, "發送暱稱失敗.") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, @@ -1980,17 +1980,17 @@ MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, "發送暱稱至客戶端失敗.") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, - "發送暱稱至宿主端失敗.") + "發送暱稱至主控端失敗.") MSG_HASH(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, "發送SRAM數據至客戶端失敗.") MSG_HASH(MSG_FAILED_TO_START_AUDIO_DRIVER, - "音頻驅動啟動失敗,將在無音頻模式下繼續啟動。") + "聲音驅動啟動失敗,將在無聲音模式下繼續啟動。") MSG_HASH(MSG_FAILED_TO_START_MOVIE_RECORD, - "啟動視頻錄製失敗.") + "啟動視訊錄製失敗.") MSG_HASH(MSG_FAILED_TO_START_RECORDING, - "Failed to start recording.") + "建用錄製視訊失敗.") MSG_HASH(MSG_FAILED_TO_TAKE_SCREENSHOT, - "Failed to take screenshot.") + "營幕快照失敗.") MSG_HASH(MSG_FAILED_TO_UNDO_LOAD_STATE, "Failed to undo load state.") MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, @@ -2030,17 +2030,19 @@ MSG_HASH(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, MSG_HASH(MSG_INPUT_CHEAT, "輸入金手指") MSG_HASH(MSG_INPUT_CHEAT_FILENAME, - "Cheat Filename") + "金手指檔案") MSG_HASH(MSG_INPUT_PRESET_FILENAME, - "Preset Filename") + "目前檔案") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "接口") MSG_HASH(MSG_INTERNAL_STORAGE, "內部存儲") MSG_HASH(MSG_REMOVABLE_STORAGE, - "Removable Storage") + "可移除的儲存空間") MSG_HASH(MSG_INVALID_NICKNAME_SIZE, - "Invalid nickname size.") + "不合法暱稱大小.") MSG_HASH(MSG_IN_BYTES, "(字節)") MSG_HASH(MSG_IN_GIGABYTES, @@ -2052,15 +2054,15 @@ MSG_HASH(MSG_LIBRETRO_ABI_BREAK, MSG_HASH(MSG_LIBRETRO_FRONTEND, "為libretro而設計的前端") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, - "加載狀態從槽 #%d.") + "戴入狀態從槽 #%d.") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, - "加載狀態從槽 #-1 (auto).") + "戴入狀態從槽 #-1 (auto).") MSG_HASH(MSG_LOADING, - "正在加載") + "正在戴入") MSG_HASH(MSG_FIRMWARE, "一個或多個固件文件丟失") MSG_HASH(MSG_LOADING_CONTENT_FILE, - "正在加載內容文件") + "正在戴入內容文件") MSG_HASH(MSG_LOADING_HISTORY_FILE, "正在讀取歷史文件") MSG_HASH(MSG_LOADING_STATE, @@ -2068,25 +2070,25 @@ MSG_HASH(MSG_LOADING_STATE, MSG_HASH(MSG_MEMORY, "內存") MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, - "視頻不是有效的BSV1文件。") + "視訊不是有效的BSV1文件。") MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, - "視頻格式看起來使用了不同的序列化版本。很有可能失敗。") + "視訊格式看起來使用了不同的序列化版本。很有可能失敗。") MSG_HASH(MSG_MOVIE_PLAYBACK_ENDED, - "視頻回放結束.") + "視訊回放結束.") MSG_HASH(MSG_MOVIE_RECORD_STOPPED, - "停止視頻錄製。") + "停止視訊錄製。") MSG_HASH(MSG_NETPLAY_FAILED, - "初始化聯機遊戲失敗。") + "初始化連線遊戲失敗。") MSG_HASH(MSG_NO_CONTENT_STARTING_DUMMY_CORE, "沒有內容,啟動虛擬核心。") MSG_HASH(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, "未覆蓋任何存檔。") MSG_HASH(MSG_NO_STATE_HAS_BEEN_LOADED_YET, - "沒有加載任何存檔。") + "沒有戴入任何存檔。") MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, - "保存覆蓋錯誤。") + "儲存覆蓋錯誤。") MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, - "覆蓋保存成功。") + "覆蓋儲存成功。") MSG_HASH(MSG_PAUSED, "暫停。") MSG_HASH(MSG_PROGRAM, @@ -2134,15 +2136,15 @@ MSG_HASH(MSG_REWIND_INIT_FAILED_THREADED_AUDIO, MSG_HASH(MSG_REWIND_REACHED_END, "到達回放緩存末端.") MSG_HASH(MSG_SAVED_NEW_CONFIG_TO, - "已保存新配置到") + "已儲存新設定到") MSG_HASH(MSG_SAVED_STATE_TO_SLOT, - "保存狀態至槽 #%d.") + "儲存狀態至槽 #%d.") MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, - "保存狀態至槽 #-1 (auto).") + "儲存狀態至槽 #-1 (auto).") MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, - "成功保存至") + "成功儲存至") MSG_HASH(MSG_SAVING_RAM_TYPE, - "保存 RAM 類型") + "儲存 RAM 類型") MSG_HASH(MSG_SAVING_STATE, "存檔中") MSG_HASH(MSG_SCANNING, @@ -2158,19 +2160,19 @@ MSG_HASH(MSG_SHADER, MSG_HASH(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, "Shader preset saved successfully.") MSG_HASH(MSG_SKIPPING_SRAM_LOAD, - "跳過 SRAM 加載。") + "跳過 SRAM 戴入。") MSG_HASH(MSG_SLOW_MOTION, "慢動作。") MSG_HASH(MSG_SLOW_MOTION_REWIND, "慢動作回溯。") MSG_HASH(MSG_SRAM_WILL_NOT_BE_SAVED, - "SRAM will not be saved.") + "SRAM 將不會被儲存.") MSG_HASH(MSG_STARTING_MOVIE_PLAYBACK, - "視頻回放.") + "視訊回放.") MSG_HASH(MSG_STARTING_MOVIE_RECORD_TO, "Starting movie record to") MSG_HASH(MSG_STATE_SIZE, - "State size") + "即時存檔大小") MSG_HASH(MSG_STATE_SLOT, "狀態存檔槽") MSG_HASH(MSG_TAKING_SCREENSHOT, @@ -2178,7 +2180,7 @@ MSG_HASH(MSG_TAKING_SCREENSHOT, MSG_HASH(MSG_TO, "到") MSG_HASH(MSG_UNDID_LOAD_STATE, - "已撤銷加載狀態。") + "已撤銷戴入狀態。") MSG_HASH(MSG_UNDOING_SAVE_STATE, "撤銷即時存檔") MSG_HASH(MSG_UNKNOWN, @@ -2223,7 +2225,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, - "Maximum amount of users supported by RetroArch." + "RetroArch 最大遊戲支援人數" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, @@ -2231,15 +2233,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Allows any user to control the menu. If disabled, only User 1 can control the menu." + "允許任何使用者去控制選單,如果取消,將只會有1個人可以控制選單." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Audio volume (in dB). 0 dB is normal volume, no gain applied." + "音量大小 (in dB). 0 dB 是標準大小." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "同步音頻。推薦。" + "同步聲音。推薦。" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, @@ -2259,7 +2261,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "同步顯卡的視頻輸出到屏幕刷新率。推薦。" + "同步顯卡的視訊輸出到營幕刷新率。推薦。" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, @@ -2271,7 +2273,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, - "Check if all the required firmware is present before attempting to load content." + "載入遊戲前檢查必要的韌體/BIOS是否存在." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, @@ -2279,7 +2281,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_ENABLE, - "啟用音頻輸出。" + "啟用聲音輸出。" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, @@ -2295,11 +2297,11 @@ MSG_HASH( ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, - "未配置" + "未設定" ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED_FALLBACK, - "not configured, using fallback" + "未設定,將使用內定值" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, @@ -2351,29 +2353,29 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, "數據庫 - 過濾器 : Edge Magazine Rating") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, - "數據庫信息") + "數據庫訊息") MSG_HASH(MSG_WIFI_SCAN_COMPLETE, "Wi-Fi 掃瞄完成。") MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS, - "掃瞄無線網絡...") + "掃瞄無線網路...") MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, - "聯機遊戲主機掃瞄完成。") + "連線遊戲主機掃瞄完成。") MSG_HASH(MSG_NETPLAY_LAN_SCANNING, - "掃瞄聯機遊戲主機...") + "掃瞄連線遊戲主機...") MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, "當窗口失去焦點時暫停遊戲。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, "Enable or disable composition (Windows only).") MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, - "為遊戲、圖片、音樂和視頻啟用/禁用歷史記錄。") + "為遊戲、圖片、音樂和視訊啟用/禁用歷史記錄。") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, - "遊戲、圖片、音樂和視頻歷史記錄的數量限制。") + "遊戲、圖片、音樂和視訊歷史記錄的數量限制。") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, - "統一菜單控制") + "統一選單控制") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, "Use the same controls for both the menu and the game. Applies to the keyboard.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "顯示屏幕消息。") + "顯示營幕消息。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, "用戶 %d 遠程允許") MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, @@ -2387,9 +2389,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, "刻度") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "聯機遊戲將在內容加載後開始。") + "連線遊戲將在內容戴入後開始。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, - "無法找到合適的核心或內容文件,手動加載。") + "無法找到合適的核心或內容文件,手動戴入。") MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, "瀏覽URL" @@ -2405,13 +2407,13 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, "Bokeh") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Refresh Room List") + "更新 Room 列表") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, - "Nickname: %s") + "暱稱: %s") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, - "Nickname (lan): %s") + "暱稱 (lan): %s") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, - "Compatible content found") + "找到相容遊戲") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, "Cuts off a few pixels around the edges of the image customarily left blank by developers which sometimes also contain garbage pixels.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, @@ -2419,9 +2421,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, "Apply a CPU-powered video filter. NOTE: Might come at a high performance cost. Some video filters might only work for cores that use 32bit or 16bit color.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, - "Input the username of your Retro Achievements account.") + "輸入Retro Achievements 的帳號.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, - "Input the password of your Retro Achievements account.") + "輸入Retro Achievements 的密碼.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, "Input your user name here. This will be used for netplay sessions, among other things.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, @@ -2435,7 +2437,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, "Show information specific to the device.") MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, - "Quit the program.") + "離開程式.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, "Set the custom width size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, @@ -2974,7 +2976,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -3009,3 +3011,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index b526b4033a..39e671f9c0 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -2033,6 +2033,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Cheat-Dateiname") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Vorlagen-Dateiname") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Netzwerk-Karte") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -3003,3 +3005,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_eo.h b/intl/msg_hash_eo.h index 4fce47a371..f3fddd60a1 100644 --- a/intl/msg_hash_eo.h +++ b/intl/msg_hash_eo.h @@ -860,8 +860,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "Menu File Browser") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Menu Linear Filter") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Horizontal Animation") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menu") + "Appearance") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, "Background") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, @@ -1401,7 +1403,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, "Update Assets") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Update Autoconfig Profiles") + "Update Joypad Profiles") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, "Update Cg Shaders") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, @@ -1920,6 +1922,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Cheat Filename") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Preset Filename") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Interface") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -2708,6 +2712,8 @@ MSG_HASH(MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, "Select an animated background effect. Can be GPU-intensive depending on the effect. If performance is unsatisfactory, either turn this off or revert to a simpler effect.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_FONT, "Select a different main font to be used by the menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_FAVORITES, + "Show the favourites tab inside the main menu.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_IMAGES, "Show the image tab inside the main menu.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_MUSIC, @@ -2833,7 +2839,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -2868,3 +2874,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 2cc2b36762..e93f65c2f4 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -950,7 +950,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Filtre linéaire pour le menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menu") + "Appearance") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, "Fond d'écran") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, @@ -2053,6 +2053,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Nom du fichier de triche") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Nom du fichier de pré-réglage") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Interface") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -3006,7 +3008,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -3041,3 +3043,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Afficher les mises à jour des cœurs") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 0f363da56f..7e0c748e15 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -32,7 +32,7 @@ MSG_HASH( ) MSG_HASH( MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "Nessun argomento fornito e nessun menu incorporato, che mostra aiuto ..." + "Nessun argomento fornito e nessun menu incorporato, visualizzazione della guida..." ) MSG_HASH( MSG_NETPLAY_USERS_HAS_FLIPPED, @@ -40,7 +40,7 @@ MSG_HASH( ) MSG_HASH( MSG_SETTING_DISK_IN_TRAY, - "Setting disk in tray" + "impostazioni del disco nel cassetto" ) MSG_HASH( MSG_WAITING_FOR_CLIENT, @@ -52,7 +52,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, - "Sei diventato un giocatore %d" + "Sei entrato come giocatore %d" ) MSG_HASH( MSG_NETPLAY_IMPLEMENTATIONS_DIFFER, @@ -68,7 +68,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_ENTER_PASSWORD, - "Inserisci la password del netplay server :" + "inserisci la password del server netplay:" ) MSG_HASH( MSG_NETPLAY_INCORRECT_PASSWORD, @@ -92,23 +92,23 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, - "Non ci sono slot liberi per i giocatori " + "Non ci sono slot liberi per i giocatori" ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY, - "Impossibile passare alla modalità di riproduzione" + "Non è possibile passare in modalità gioco" ) MSG_HASH( MSG_NETPLAY_PEER_PAUSED, - "Netplay peer \"%s\" in pausa" + "Netplay peer \"%s\"in pausa" ) MSG_HASH( MSG_NETPLAY_CHANGED_NICK, - "Il tuo nickname è stato cambiato in \"%s\"" + "Il tuo nickname è cambiato in \"%s\"" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Fornire i core hardware resi nel proprio contesto privato. Evita di assumere cambiamenti di stato hardware tra i fotogrammi." + "Fornisce i core hardware nel proprio contesto privato. Evita di assumere cambiamenti di stato hardware tra i fotogrammi." ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, @@ -116,7 +116,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, - "Sincronizzare duramente la CPU e la GPU. Riduce la latenza al costo della prestazione." + "Sincronizzare duramente la CPU e la GPU. Riduce la latenza al costo delle prestazioni." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, @@ -124,11 +124,11 @@ MSG_HASH( ) MSG_HASH( MSG_AUDIO_VOLUME, - "Volume Audio" + "Volume audio" ) MSG_HASH( MSG_AUTODETECT, - "Torvato automaticamente" + "Trovato automaticamente" ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FROM, @@ -136,11 +136,11 @@ MSG_HASH( ) MSG_HASH( MSG_CAPABILITIES, - "Capabilities" + "Funzionalità" ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "Connessione al host del netplay " + "Connessione al host del netplay" ) MSG_HASH( MSG_CONNECTING_TO_PORT, @@ -152,111 +152,195 @@ MSG_HASH( ) MSG_HASH( MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "Spiacente, non è stato implementato: i core che non richiedono contenuti non possono partecipare al netplay." + "Spiacente, non è stato implementato: i core che non richiedono contenuti non possono partecipare al netplay" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, "Password" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Obiettivi dell'account") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, - "Nome utente") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, + "Accounts Cheevos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, + "Nome utente" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, "Accounts" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, - "Lista degli account") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, - "Retro Obiettivi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Lista Obiettivi") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, + "Accounts List Endpoint" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Retro Achievements" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, + "Lista Achievement" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Lista dei Achievement (Hardcore)" + "Lista Achievement(Hardcore)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, + "Scansione Dei Contenuti" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, + "Configurazioni" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TAB, + "Importa contenuto" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, - "Aggiungi Contenuto") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "Carica Configurazione") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TAB, - "Aggiungi scheda") MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "Stanze Netplay " + "Camere Netplay " + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, + "Invita" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, + "Assets" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, + "Blocchi Frame" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, + "Dispositivo audio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, + "Driver audio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, + "Plugin Audio DSP " + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, + "Audio Abilitato" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, + "Filtro Audio" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, - "Chiedi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, - "Directory degli asset") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, - "Blocco fotogrammi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, - "Dispositivo audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, - "Driver Audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, - "Plugin audio DSP") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, - "Abilita audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, - "Filtro Audio") MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, "Turbo/Deadzone" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - "Latenza audio (ms)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, - "Variazione massima di sincronia dell'audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "Silenzia audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, - "Frequenza audio di output (Hz)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, - "Controllo Delta per la frequenza audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, - "Driver di ricampionamento Audio") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, + "Latenza audio (ms)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, + "Temporizzazione massima audio Skew" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, + "Disattiva Audio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, + "Frequenza audio di output (Hz)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, + "Audio Dinamico di controllo Delta " + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, + "Audio Resampler Driver" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, "Audio" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, - "Sincro audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "Livello volume audio (dB)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "Intervallo di autosalvataggio SaveRAM") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, - "Carica file di override automaticamente") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, - "Carica file di rimappatura automaticamente") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, + "Sincronizzazione Audio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, + "Livello del Volume Audio (dB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, + "WASAPI Modalità Esclusiva" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, + "WASAPI Float Format" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "WASAPI ha condiviso la lunghezza del Buffer" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, + "Intervallo di salvataggio automatico SaveRAM" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Carica automaticamente il file Override" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, + "Carica automaticamente i file remap" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, - "Carica Shader Presets Automaticamente" + "Carica Shader predefiniti automaticamente" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, + "Indietro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, + "Conferma" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, + "Info" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, + "Abbandona" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, + "Scorrere verso il basso" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, + "Scorrere verso l'alto" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, + "Avvia" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, + "Pulsante Tastiera" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, + "Pulsante Menu" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, - "Indietro") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, - "Conferma/OK") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "Info") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, - "Esci") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, - "Scorri verso il basso") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, - "Scorri verso l'alto") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, - "Predefinito") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, - "Tastiera a comparsa") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "Menù a comparsa") MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "Controlli del menu di base" + "Controlli di base del menu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, @@ -268,11 +352,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, - "Annulla" + "Abbandona" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Scorrere verso l'alto" + "Scorri verso l'alto" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, @@ -280,107 +364,149 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, - "Toggle Tastiera" + "Pulsante Keyboard" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "Toggle Menu" + "Pulsante Menu" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, + "Non sovrascrivere il SaveRAM durante il caricamento del salvataggio" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "Non sovrascrivere il SaveRAM al caricamento degli stati di salvataggio") MSG_HASH( MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Bluetooth Attivato" + "Bluetooth Abilitato" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, + "URL degli asset Buildbot" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, - "Indirizzo Buildbot Assets") MSG_HASH( MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, "Cache" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, - "Consenti fotocamera") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, - "Driver Fotocamera") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT, - "Trucchi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, - "Applica i cambiamenti nei trucchi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, - "Trucchi") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, + "Consenti Fotocamera" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, + "Driver della Fotocamera" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT, + "Cheat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, + "Applica i cambiamenti" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, + "File Cheat " + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE, - "Cheat File" + "File Cheat " + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, + "Carica File Cheat " + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, + "Salva il file cheat come" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, + "Cheat Passes" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Carica i trucchi") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "Salva i trucchi come") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, - "Trucchi usati") MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, "Descrizione" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, - /* FIXME? Translate 'Achievements Hardcore Mode' */ - "Modalità Hardcore") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, - "Obiettivi bloccati:") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, + "Modalità Achievements Hardcore" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, + "Achievements Bloccati:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, "Bloccato" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, - "Retro Obiettivi" + "Retro Achievements" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - /* FIXME? Translate 'Test Unofficial Achievements' */ - "Prova non ufficiali") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, - "Obiettivi sbloccati,") + "Testa gli Achievements non ufficiali" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, + "Modalità Achievements Verbose " + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, + "Achievements sbloccati:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, "Sbloccato" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, - "Chiudi") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, + "Chiudi contenuto" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG, "Configurazione" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "Carica Configurazione") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, - "Configurazione") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, - "Salva configurazione all'uscita") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, - "Collezione") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, - "Directory del database") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, + "Carica Configurazione" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, + "Configurazione" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, + "Salva la configurazione all' uscita" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, + "Collezioni" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, + "Database" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_DIR, "Contenuto" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, - "Dimensione della cronologia") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, + "Dimensione dell'elenco cronologia") MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, - "Consenti di rimuovere le voci") + "Rimuovi le voci") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "Menù rapido") + "Menu Rapido") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, - "Download") + "Downloads") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - "Download") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, /* UPDATE/FIXME */ - "Opzione dei trucchi per il core") + "Downloads") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, + "Cheats") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, - "Contatore dei core") + "Contatori di core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, - "Mostra nome dei core") + "Visualizza il nome del core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, "Informazioni del core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, @@ -388,23 +514,23 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, "Categorie") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, - "Etichetta core") + "Etichetta Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, - "Nome core") + "Nome del Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, - "Firmware(s)") + "Firmware") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, "Licenza(e)") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, - "Permessi") + "Autorizzazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, "Estensioni supportate") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, - "Produttore del sitema") + "Produttore del sistema") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, "Nome del sistema") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, - "Opzioni di rimappatura degli input del core") + "Controlli") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_LIST, "Carica Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, @@ -412,37 +538,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, "Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, - "Avvia automaticamente un core") + "Avvia automaticamente un Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "Estrai automaticamente gli archivi scaricati") + "Estrarre automaticamente l'archivio scaricato") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, - "Indirizzo Buildbot Core") + "Buildbot Cores URL") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, - "Aggiorna i core") + "Aggiorna Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, "Aggiorna") MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, - "Architettura CPU:") + "Architettura della CPU:") MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_CORES, - "CPU Cores:") + "CPU dei Core:") MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, "Cursore") MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, - "Gestore cursori") + "Gestore del Cursore") MSG_HASH(MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, - "Frequenza personalizzata") + "Custom Ratio") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, - "Gestore database") + "Gestore Database ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, - "Seleziona Database ") + "Selezione del database") MSG_HASH(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, "Rimuovi") MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES, - "Seleziona il file ed intercetta il core") /* TODO/FIXME - update */ + "Avvia da directory") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, - "") + "") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, - "") + "") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, "") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, @@ -450,96 +576,97 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, "Directory") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, - "Stato del vassoio del disco") + "Stato del ciclo nel vassoio del disco") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, - "Aggiungi immagine disco") + "Aggiungere Immagine disco") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_INDEX, - "Indice del disco") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, /* UPDATE/FIXME */ - "Opzioni disco") + "Indice del Disco ") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, + "Controllo del Disco ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DONT_CARE, - "Non considerare") + "Non importa") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, - "Scarica sulle directories") + "Downloads") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, - "Download Core...") + "Scarica Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, - "Scarica contenuto") + "Content Downloader") MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, - "Abilita DPI Override") + "DPI Override Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, "DPI Override") MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, "Driver") MSG_HASH(MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, - "Valore fittizio sull'arresto del core") + "Carica Dummy alla chiusura del Core ") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, "Controlla il firmware mancante prima del caricamento") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Sfondo dinamico") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, - "Directory degli sfondi dinamici") + "Sfondi dinamici") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - /* FIXME? Translate 'Enable Achievements' */ - "Attivare") + "Abilita Achievements") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, - "Colore evidenziato delle voci dei menù") + "Colore al passaggio del mouse") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, - "Colore normale della voce dei menù") + "Voce di Menu con colore normale") MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, "Falso") MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, - "Velocità massima di caricamento") + "Velocità massima di esercizio") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + "Preferiti") MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, - "Mostra frequenza dei fotogrammi") + "Visualizzazione framerate") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, - "Limita la velocità massima di caricamento") + "Limita la velocità massima di esercizio") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, - "Aumenta fotogrammi") + "Riavvolgimento e Fotogrammi") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, - "Contatori Frontend") + "Frontend Counters") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "Usa opzioni core per gioco se disponibili") + "Carica il Contenuto Specifico delle opzioni del Core Automaticamente") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, - "Crea file opzioni di gioco") + "Crea file delle opzioni di gioco") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, - "Game-options file") + "File delle opzioni di gioco") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, "Aiuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "Problemi Audio/Video") + "Risoluzione dei problemi audio/video") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, - "Cambia i settaggi del gamepad virtuale") + "Cambia la sovrapposizione virtuale del gamepad") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, - "Menù di base dei controlli") + "Controlli del menu di base") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST, "Aiuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, - "Carica Contenuto") + "Caricamento del contenuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, - "Scansiona per contenuto") + "Scansione del contenuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, - "Che cosa è un core?") + "Che cos'è un core?") MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, - "Abilita cronologia") + "Abilita l'elenco della cronologia") MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_TAB, - "Cronologia scheda") + "Cronologia") MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, - "Menú orizzontale") + "Menu Orizzontale") MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, - "Image") + "Immagini") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION, - "Information") + "Informazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, "Informazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, - "Analog To Digital Type") + "Da analogico a digitale") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "Menù di controllo per tutti gli utenti") + "Menu di controllo di tutti gli utenti") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, "Analogico sinistro X") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, - "Analogico sinistro X- (sinistra)") + "Analogico sinistro X- (sinistro)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, "Analogico sinistro X+ (destra)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, @@ -547,49 +674,51 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, "Analogico sinistro Y- (su)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, - "Analogico sinistro Y+ (giu')") + "Analogico sinistro Y+ (giù)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, - "Analogico destro X") + "Analogico Destro X") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, - "Analogico destro X- (sinistra)") + "Analogico Destro X- (sinistro)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, - "Analogico destro X+ (destra)") + "Analogico Destro X+ (destra)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, - "Analogico destro Y") + "Analogico Destro Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, - "Analogico destro Y- (su)") + "Analogico Destro Y- (su)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, - "Analogico destro Y+ (giù)") + "Analogico Destro Y+ (giù)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, - "Abilita autoconfigurazione") + "Abilita Autoconfigurazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, - "Soglia Input Axis") + "Deadzone dello stick analogico") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "Scambia i pulsanti OK e Annulla") + "Scambia i pulsanti OK & Annulla ") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, "Bind All") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, "Bind Default All") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, - "Cambia Timeout") + "Bind Timeout") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, - "Nascondi la descrizione del core non caricata") + "Nascondi i descrittori di input di core non legati") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, - "Mostra le etichette descrittive degli input del core") + "Visualizza le etichette descrittori di input") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, - "Device Index") + "Indice del dispositivo") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, "Tipo di dispositivo") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, + "Indice del mouse") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, - "Driver di Input") + "Driver di input") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Ciclo dati") + "Ciclo di lavoro") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, - "Imposta tasti di scelta rapida di input") + "Input Hotkey Binds") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, - "Abilita mappatura gamepad tastiera") + "Mappatura del Gamepad su tastiera Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, - "Pulsante A (destro)") + "Pulsante A (destra)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, "Pulsante B (giù)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, @@ -607,139 +736,143 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, "Pulsante R3 (thumb)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, - "Pulsante R (shoulder)") + "Pulsante R(shoulder)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, - "D-pad destro") + "D-pad Destro") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, - "Pulsante Select ") + "Pulsante Select") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, "Pulsante Start") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, "D-pad su") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, - "Pulsante X (top)") + "Pulsante X (in alto)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, - "Pulsante Y (sinistra)") + "Pulsante Y (sinistro)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, - "(Key: %s)") + "(Tasto: %s)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, - "Tipologia di mappatura gamepad tastiera") + "Tipo di mappatura del gamepad della tastiera") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, - "Utenti massimi") + "Massimo numero di Utenti") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Combo gamepad per il menù a comparsa") + "Pulsanti Combo gamepad per il menù a comparsa") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, - "Cheat index -") + "Indice dei Cheat -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, - "Cheat index +") + "Indice dei Cheat +") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, - "Cheat toggle") + "Pulsante Cheat ") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, - "Toggle espulsione disco") + "Pulsante espulsione Disco") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, - "Disk next") + "Disco successivo") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, - "Disk prev") + "Disco precedente") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, - "Abilitare hotkeys") + "Abilita hotkeys") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, - "Tenere premuto in avanti") + "Andare avanti veloce") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, - "Toggle per andare avanti veloce") + "Pulsante per avanzamento veloce ") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, - "Frame avanzato") + "Frameadvance") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, - "Toggle per lo shermo intero") + "Pulsante per lo schermo intero ") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, - "Toggle per il tocco del mouse") + "Pulsante per il tocco del mouse") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, - "Game focus toggle") + "Pulsante Game focus ") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "Carica stato") + "Carica Stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, - "Toggle per il menu") + "Pulsante per il Menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, - "Toggle per la registrazione del film") + "Pulsante registratore Film") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, - "Toggle per l' audio in modalità muto") + "Pulsante per disattivare l'audio ") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, "Netplay flip users") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "Netplay toggle play/spectate mode") + "Pulsante Netplay per la modalità giocatore/spettatore") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, - "Toggle per la tastiera su schermo") + "Pulsante per la tastiera su schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, - "Overlay next") + "Overlay successivo") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, - "Pause toggle") + "Pulsante Pausa") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, - "Esci da RetroArch") + "Pulsante per uscire da RetroArch") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, "Resetta il gioco") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, - "Rewind") + "Riavvolgimento") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "Salva stato") + "Salva Stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, - "Effettua screenshot") + "Effettua uno screenshot") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, - "Next shader") + "Shader successivo") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, - "Previous shader") + "Shader Precedente") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION, "Slow motion") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, - "Slot del Salva stato -") + "Slot di Salvataggio -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, - "Slot del Salva stato +") + "Slot di Salvataggio +") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, "Volume -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, "Volume +") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, - "Mostra Overlay") + "Visualizza Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, - "Nascondi overlay nel menù") + "Nascondi Overlay nel Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Visualizza Inputs su Overlay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Visualizza Inputs Listen Port") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, - "Tipo di ritardo") + "Poll Type Behavior") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, - "Presto") + "Anticipato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, - "Tardi") + "Ritardato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, "Normale") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, - "Prefer Front Touch") + "Preferisco il Touch frontale") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, - "Directory per la rimappatura dei dispositivi di input") + "Input di rimappatura") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, - "Abilita rimappatura dei controlli") + "Rimappa Binds Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, - "Salva automaticamente la configurazione") + "Salva file Autoconfig") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, "Input") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, - "Abilita tastiera ridotta") + "Piccola Tastiera Abilitata") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, "Touch Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, "Turbo Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, - "Modalità Turbo") + "Turbo Periodico") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, - "Modifica Input Utente %u") + "Input utente %u Binds") MSG_HASH(MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, - "Stato di archiviazione interno") + "Stato di archiviazione interna") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "Directory per l'autoconfigurazione dei dispositivi di input") + "Input Autoconfig") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, - "Driver del Joypad") + "Driver del Joypad ") MSG_HASH(MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, "Servizi") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, "Cinese (Semplificato)") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, - "Cinese (Tradizionale)") + "Chinese (Tradizionale)") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_DUTCH, "Olandese") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, @@ -759,9 +892,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_KOREAN, MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_POLISH, "Polacco") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, - "Portoghese (Brazil)") + "Portoghese (Brasiliano)") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, - "Portoghese (Portugal)") + "Portoghese (Portogallo)") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, "Russo") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH, @@ -771,41 +904,41 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, "Analogico sinistro") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, - "Directory dei core") + "Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "Directory di informazione dei core") + "Informazione sul Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, - "Livello dei log del core") + "Core Logging Level") MSG_HASH(MENU_ENUM_LABEL_VALUE_LINEAR, "Lineare") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, - "Carica archivio con il core") /* TODO/FIXME */ + "Carica Archivio") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, "Carica Recenti") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, "Carica Contenuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_STATE, - "Carica stato") + "Carica Stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, - "Consenti posizionamento") + "Consenti Posizione") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, - "Driver di Posizione") + "Posizione del Driver") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, "Logging") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, - "Dettaglio dei log") + "Logging Verbosity") MSG_HASH(MENU_ENUM_LABEL_VALUE_MAIN_MENU, - "Menú principale") + "Menu principale") MSG_HASH(MENU_ENUM_LABEL_VALUE_MANAGEMENT, - "Settaggi del database") + "Impostazioni del Database ") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, - "Colore tema del menù") + "Colore del tema di Menu ") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, - "Blu") + "Blue") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, - "Blu Grigio") + "Blue Grigio") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, - "Blu ") + "Blue scuro") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, "Verde") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, @@ -815,29 +948,31 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, "Giallo") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, - "Opacità testo fondo pagina") + "Opacità di piè di pagina") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, - "Opacità testo inizio pagina") + "Opacità di intestazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DRIVER, - "Driver Menù") + "Driver del Menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, - "Frequenza fotogrammi del menù") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, /* TODO/FIXME - update */ - "Seleziona file") + "Frequenza dei fotogrammi nel menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, + "Impostazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, - "Filtro lineare del menù") + "Filtro lineare del Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Animazione orizzontale") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menù") + "Impostazioni Aspetto") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, - "Menù sfondi") + "Sfondo") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, - "Opacità dello sfondo") + "Opacità Sfondo") MSG_HASH(MENU_ENUM_LABEL_VALUE_MISSING, - "Mancante") + "Manca") MSG_HASH(MENU_ENUM_LABEL_VALUE_MORE, "...") MSG_HASH(MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, - "Supporto mouse") + "Supporto del Mouse") MSG_HASH(MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, "Multimedia") MSG_HASH(MENU_ENUM_LABEL_VALUE_MUSIC_TAB, @@ -845,59 +980,71 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MUSIC_TAB, MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtra estensioni sconosciute") MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, - "Navigazione avvolgente") + "Navigazione Wrap-Around") MSG_HASH(MENU_ENUM_LABEL_VALUE_NEAREST, - "Più vicino") + "Nearest") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY, - "Rete") + "Netplay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, + "Attiva modalità Client Slave") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, - "Controlla fotogrammi in rete") + "Controllo Netplay Frames") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Input della latenza del Frames") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Input Latency Frames Range") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CLIENT_SWAP_INPUT, - "Giocatore 2 usa Controller 1 in rete") + "Netplay P2 Utilizza C1") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "Mostra fotogrammi in rete") + "Netplay Delay Frames") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, - "Disconnetti") + "Scollegare dall'host netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, - "Abilita Rete") + "Netplay Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, - "Connetti alla rete ospite") + "Connetti all'host netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Comincia ad ospitare") + "Avvia l'host netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Stop netplay host") + "Ferma l'host netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, "Indirizzo Server") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, - "Scan local network") + "Scansione della rete locale") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "Abilita Client di rete") + "Netplay Client Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "Nome utente") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, - "Server Password") + "Password del Server") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + "Annuncia pubblicamente il Netplay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, + "Disattiva i client in modalità non slave") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "Settaggi di rete") + "Impostazioni Netplay ") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, + "Modalità Spettatore Netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "Netplay Stateless Mode") + "Modalità senza stato del Netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, "Server Spectate-Only Password") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "Abilita spettatore in rete") + "Netplay Spettatore Abilitato") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "Porta TCP/UDP Rete") + "Netplay TCP Port") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, "Netplay NAT Traversal") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, "Comandi di rete") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, - "Porta dei comandi di rete") + "Comando della porta di rete") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, - "Informazione di rete") + "Informazioni sulla rete") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, - "Network Gamepad") + "Rete Gamepad") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, - "Network Remote Base Port") + "Porta di rete remota di Base") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, "Rete") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO, @@ -905,9 +1052,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO, MSG_HASH(MENU_ENUM_LABEL_VALUE_NONE, "Nessuno") MSG_HASH(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE, - "N/D") + "N/A") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, - "Nessun Achievements da mostrare.") + "Nessun achievements da visualizzare.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE, "Nessun Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, @@ -915,29 +1062,29 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, "Nessuna informazione sul core disponibile.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, - "Nessuna opzione per il core disponibile.") + "Nessuna opzione del core disponibile.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, - "Nessuna voce da mostrare.") + "Nessuna voce da visualizzare.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, - "Nessuna storia disponibile.") + "Nessuna cronologia disponibile.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, "Nessuna informazione disponibile.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS, - "Nessun oggetto.") + "Nessun elemento.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, "Nessun host netplay trovato.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, "Nessuna rete trovata.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, - "Nessun contatore di performance.") + "Nessun contatore delle prestazioni.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, "Nessuna playlists.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, "Nessuna voce della playlist disponibile.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, - "Nessun settaggio trovato.") + "Nessuna impostazione trovata.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, - "Nessun parametro shader.") + "Nessun parametro shader trovato.") MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, "OFF") MSG_HASH(MENU_ENUM_LABEL_VALUE_ON, @@ -951,9 +1098,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, "Overlay sullo schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, - "Onscreen Notifications") + "Notifiche sullo schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, - "Apri archivio come cartella") /* TODO/FIXME */ + "Apri archivio") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPTIONAL, "Opzionale") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY, @@ -961,9 +1108,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, "Autocarica overlay preferito") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, - "Directory Overlay") + "Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, - "Opacità Overlay") + "Opacità Overlay ") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, "Overlay Predefinito") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, @@ -971,21 +1118,21 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, "Overlay sullo schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, - "Usa modalità PAL60") + "Usa modalità PAL60 ") MSG_HASH(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, - "Directory precedente") + "Directory principale") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, - "In pausa quando il menù è attivato") + "Pausa quando il menu è attivato") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, - "Non caricare in background") + "Non eseguire in background") MSG_HASH(MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, - "Contatore performance") + "Contatori di prestazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, - "Scheda Playlist") + "Playlists") MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, - "Directory della playlist") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, "Playlist") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, + "Playlists") MSG_HASH(MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, "Supporto touch") MSG_HASH(MENU_ENUM_LABEL_VALUE_PORT, @@ -999,9 +1146,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, "Analogici supportati") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, - "BBFC Rating") + "Classificazione BBFC") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, - "CERO Rating") + "Classificazione CERO") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, "Co-op supportato") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, @@ -1013,17 +1160,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, "Edge Magazine Issue") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, - "Edge Magazine Rating") + "Valutazione di Edge Magazine ") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, "Edge Magazine Review") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, - "ELSPA Rating") + "Valutazione ELSPA ") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, - "Enhancement Hardware") + "Miglioramento Hardware") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, - "ESRB Rating") + "Valutazione ESRB ") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, - "Famitsu Magazine Rating") + "Valutazione Famitsu Magazine ") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, "Franchise") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, @@ -1033,9 +1180,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, "Nome") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, - "Origine") + "Origin") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, - "PEGI Rating") + "Valutazione PEGI ") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, "Editore") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, @@ -1043,41 +1190,45 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, "Anno di uscita") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, - "Rumble supported") + "Rumble supportato") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, "Seriale") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, "SHA1") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, - "Avvia contenuto") + "Avvia il contenuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, - "TGDB Rating") + "Valutazione TGDB ") MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, "Riavvia") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, - "Directory della configurazione di registrazione") + "Configurazione per la registrazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, - "Directory di output per la registrazione") + "Output per la registrazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, "Registrazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "Configura registrazione") + "Carica configurazione di registrazione.") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, - "Driver di Registrazione") + "Driver per la registrazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, - "Abilita registrazione") + "Abilita Registrazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, - "File di Output") + "Salva la registrazione di Output come...") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, - "Usa Directory di Output") + "Salva la registrazione di Output nella Directory") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE, - "Rimappa File") + "File Remap") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, - "Carica file di rimappatura") + "Carica File Remap ") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, - "Salva rimappatura file del core") + "Salva Core del file di Remap ") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, - "Salva rimappatura file di gioco") + "Salva il file di Remap del gioco ") +MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, + "Cancella il file di Remap del Core ") +MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, + "Cancella il file di Remap del gioco") MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, "Richiesto") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -1093,125 +1244,137 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD, "RetroPad") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, - "RetroPad w/ Analog") + "RetroPad w/ Analogico") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, "Achievements") MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, - "Abilita riavvolgi") + "Abilita riavvolgimento") MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, - "Livello della funzione riavvolgi") + "Livello di riavvolgimento") MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, - "Riavvolgi") + "Riavvolgimento") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Directory di selezione file") + "File Browser") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, - "Directory di configurazione") + "Configurazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, - "Mostra schermata di avvio") + "Visualizzazione schermata Start") MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, - "Analogico destro") + "Analogico Destro") +MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, + "Aggiungi a Preferiti") MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, "Avvia") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_MUSIC, + "Avvia") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, - "SAMBA Abilitato") + "Abilita SAMBA") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, - "Directory dei file di salvataggio") + "Salvare il file") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, - "Cataloga automaticamente gli stati di salvataggio") + "Indice del salva stato automatico") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "Carica automaticamente gli stati di salvataggio") + "Carica automaticamente i salvataggi") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "Salva stato automaticamente") + "Salva stato automatico") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, - "Directory degli stati di salvataggio") + "Salva Stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Salva stato in Thumbnails") + "Miniature del Salva stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, - "Salva configurazione attuale") + "Salva la configurazione corrente") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "Salva override del core") + "Salva gli Override dei core") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Salva override di gioco") + "Salva gli Override dei giochi") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, - "Salva nuova configurazione") + "Salva la nuova configurazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, - "Salva stato") + "Salva Stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, "Salvataggi") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, - "Scansiona directory") + "Scansione della Directory") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, - "Scansione dei file") + "Scansione dei File") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, - "") + "") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, - "Directory delle screenshot") + "Screenshot") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, "Risoluzione schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_SEARCH, - "Cerca") + "Ricerca") MSG_HASH(MENU_ENUM_LABEL_VALUE_SECONDS, "secondi") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS, - "Settaggi") + "Impostazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - "Settaggi scheda") + "Impostazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER, "Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, - "Applica i cambiamenti negli shader") + "Applica le modifiche") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, "Shaders") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, - "Nastro") + "Onda") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, - "Nastro (semplificato)") + "Onda (semplificata)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, "Neve semplice") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, "Neve") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, - "Mostra settaggi avanzati") + "Visualizza impostazioni avanzate") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, - "Mostra files e cartelle nascoste") + "Visualizza cartelle e file nascosti") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHUTDOWN, - "Spegni") + "Arresta il sistema") MSG_HASH(MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, - "Rapporto di slow-motion") + "Rapporto Slow-Motion ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, - "Ordina i salvataggi nelle cartelle") + "Ordina il Salvataggio in Cartelle") MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, - "Ordina gli stati di salvataggio nelle cartelle") + "Ordina i Salvataggi in Cartelle") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "Scrivi i salvataggi nella directory") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "Scrivi il salvataggio nella directory") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "I file di sistema sono contenuti nella directory") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "Scrivi gli Screenshots contenuti nella directory") MSG_HASH(MENU_ENUM_LABEL_VALUE_SSH_ENABLE, - "SSH Enable") + "Abilita SSH") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, "Avvia Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, - "Avvia Retropad remoto") + "Avvia RetroPad Remoto") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, - "Avvia processore video") + "Avvia Video Processore") MSG_HASH(MENU_ENUM_LABEL_VALUE_STATE_SLOT, - "Slot di stato") + "Slot di salvataggio") MSG_HASH(MENU_ENUM_LABEL_VALUE_STATUS, "Stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, - "Comandi stdin") + "Commandi stdin ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, - "Cores suggeriti") + "Core Suggeriti") MSG_HASH(MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, - "Spegni salvaschermo") + "Sospendi Screensaver") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, - "Abilita musica di sistema") + "Abilita Sistema BGM ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, "Sistema/BIOS") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "Informazione di sistema") + "Informazioni di sistema") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, "Supporto 7zip") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, "Supporto ALSA") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE, - "Data della build") + "Data di costruzione") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT, "Supporto Cg") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT, @@ -1221,137 +1384,139 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT, "Supporto CoreText") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES, - "Caratteristiche CPU") + "Caratteristiche CPU ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, - "Mostra DPI") + "Visualizza DPI metrica") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, - "Mostra altezza (mm)") + "Visualizza l'altezza metrica (mm)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, - "Mostra larghezza (mm)") + "Visualizza la larghezza metrica (mm)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, - "Supporto DirectSound") + "Supporto DirectSound ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, - "Supporto WASAPI") + "Supporto WASAPI ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, - "Supporto libreria dinamica") + "Supporto libreria Dinamica ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, "Caricamento run-time dinamico della libreria libretro") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, - "Supporto EGL") + "Supporto EGL ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, "Supporto render-to-texture (multi-pass shaders) OpenGL/Direct3D") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT, - "Supporto FFmpeg") + "Supporto FFmpeg ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT, - "Supporto FreeType") + "Supporto FreeType ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, "Identificatore frontend") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, "Nome frontend") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS, - "OS Frontend") + "Frontend OS") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION, - "Versione git") + "Versione Git") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT, - "Supporto GLSL") + "Supporto GLSL ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT, - "Supporto HLSL") + "Supporto HLSL ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, - "Supporto JACK") + "Supporto JACK ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, - "Supporto KMS/EGL") + "Supporto KMS/EGL ") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, + "Versione Lakka") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, - "Supporto LibretroDB") + "Supporto LibretroDB ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, - "Supporto Libusb") + "Supporto Libusb ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, - "Supporto analisi XML libxml2 XML") + "Supporto libxml2 XML parsing ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, "Supporto Netplay (peer-to-peer) ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, - "Supporto interfaccia comando di rete") + "Supporto dell'interfaccia di comando di rete") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, "Supporto Gamepad di rete") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, - "Supporto OpenAL") + "Supporto OpenAL ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, - "Supporto OpenGL ES") + "Suppporto OpenGL ES ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT, - "Supporto OpenGL") + "Supporto OpenGL ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT, - "Supporto OpenSL") + "Supporto OpenSL ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT, - "Supporto OpenVG") + "Supporto OpenVG ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT, - "Supporto OSS") + "Supporto OSS ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT, - "Supporto overlay") + "Supporto Overlay ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE, "Fonte di alimentazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, "Caricato") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, - "Caricando") + "Caricamento") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, - "Scarico") + "Scaricamento") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, "Nessuna fonte") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, - "Supporto PulseAudio") + "Supporto PulseAudio ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, - "Supporto Python (supporto script in shaders) ") + "Supporto Python (script support in shaders) ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, "Supporto BMP (RBMP)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, - "Livello di RetroRating") + "Livello RetroRating ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, "Supporto JPEG (RJPEG)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, - "Supporto RoarAudio") + "Supporto RoarAudio ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, "Supporto PNG (RPNG)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, - "Supporto RSound") + "Supporto RSound ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, - "Supporto RTGA (RTGA)") + "Supporto TGA (RTGA)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, - "Supporto SDL2") + "Supporto SDL2 ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, - "Supporto immagine SDL") + "Supporto immagine SDL ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, - "Supporto SDL1.2") + "Supporto SDL1.2 ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, - "Slang support") + "Supporto Slang ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, - "Supporto Threading") + "Supporto Threading ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, - "Supporto Udev") + "Supporto Udev ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, - "Supporto Video4Linux2") + "Supporto Video4Linux2 ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, - "Contesto driver video") + "Video context driver") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, - "Supporto Vulkan") + "Supporto Vulkan ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, - "Supporto Wayland") + "Supporto Wayland ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, - "Supporto X11") + "Supporto X11 ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT, - "Supporto XAudio2") + "Supporto XAudio2 ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, - "Supporto XVideo") + "Supporto XVideo ") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, - "Supporto Zlib") + "Supporto Zlib ") MSG_HASH(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, - "Cattura Screenshot") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, /* TODO/FIXME - update */ - "Carica ciclo di dati nei thread") + "Effettua Screenshot") +MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, + "Threaded tasks") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS, "Miniature") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, - "Directory delle miniature") + "Miniature") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, - "Aggiorna miniature") + "Aggiorna Miniature") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, "Boxarts") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, @@ -1359,9 +1524,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, "Title Screens") MSG_HASH(MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, - "Mostra ora / data") + "Visualizza data / ora") MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, - "Colore dei titoli dei menù") + "Colore titolo del Menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, "Vero") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, @@ -1369,9 +1534,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, "Abilita UI Companion all'avvio") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, - "Barra dei menù") + "Menubar") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, - "Incapace di leggere i file compressi.") + "Impossibile leggere il file compresso.") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, "Annulla carica stato") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, @@ -1379,131 +1544,133 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, MSG_HASH(MENU_ENUM_LABEL_VALUE_UNKNOWN, "Sconosciuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, - "Aggiorna") + "Aggiornamento") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, - "Aggiorna Asset") + "Aggiorna risorse") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Aggiorna profili di autoconfigurazione") + "Aggiorna i profili del Joypad") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, - "Aggiorna Cg Shader") + "Aggiorna Cg Shaders") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, - "Aggiorna Trucchi") + "Aggiorna Cheats") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "Aggiorna le info dei core") + "Aggiona i file di informazione del Core ") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, - "Aggiorna Database") + "Aggiorna i Database") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, - "Aggiorna GLSL Shader") + "Aggiorna GLSL Shaders") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, - "Update Lakka") + "Aggiorna Lakka") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, - "Aggiorna Overlay") + "Aggiorna gli Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, - "Update Slang Shaders") + "Aggiorna Slang Shaders") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER, "Utente") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, - "Interfaccia Utente") + "Interfaccia utente") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, "Linguaggio") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_SETTINGS, "Utente") MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usa il visualizzatore di immagini interno") + "Utilizza Visualizzatore immagini integrato") MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usa Media Player interno") + "Use Media Player integrato") MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, "") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, - "Permetti rotazione") + "Consenti la rotazione") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, + "Configura Rapporto d'aspetto") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, - "Aspect ratio automatico") + "Rapporto d'aspetto Automatico") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, - "Aspect ratio") + "Rapporto d'aspetto") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, - "Inserimento cornice nera") + "Inserimento Frame nero") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, - "Riduci Overscan (Riavvia)") + "Crop Overscan (Ricarica)") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, - "Disattiva composizione desktop") + "Disattiva composizione del Desktop") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, "Driver Video") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, "Filtro Video") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, - "Filtro Video") + "Filtro Video ") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, - "Filtro per il flickering") + "Filtro sfarfallio ") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, - "Mostra messaggi sullo schermo") + "Abilita le notifiche sullo schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, - "Carattere per i messaggi sullo schermo") + "Font delle notifiche su schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, - "Dimensione messaggi sullo schermo") + "Dimensioni delle notifiche su schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, - "Forza aspect ratio") + "Forza Rapporto d'aspetto") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, - "Forza-disattiva sRGB FBO") + "Forza-disabilita sRGB FBO") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, - "Ritarda fotogramma") + "Ritardo del Frame ") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, - "Usa modalità a schermo intero") + "Utilizza la modalità a schermo intero") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - "Gamma video") + "Video Gamma") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, - "Abilita registrazione GPU") + "Utilizza la registrazione da GPU ") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, - "Abilita Screenshot GPU") + "Abilita Screenshot da GPU") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, - "Sincronizza GPU") + "Sincronizzazione GPU forzata") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, - "Sincronizza fotogrammi GPU") + "Sincronizzazione dei fotogrammi della GPU forzata") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Massimo swapchain di immagini") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, - "Posizione X per i messaggi sullo schermo") + "Posizione X delle notifiche su schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, - "Posizione Y per i messaggi sullo schermo") + "Posizione Y delle notifiche su schermo") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, "Indice del monitor") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, - "Abilita registrazione post-filtro") + "Utilizza registrazione Post Filtro") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, - "Frequenza di aggiornamento") + "Frequenza di aggiornamento verticale") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, - "Fotogrammi stimati del monitor") + "Framerate dello schermo stimato") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, "Rotazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, - "Scala a finestra") + "Scala con finestra") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, - "Scala a numero intero") + "Scala Integer ") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, "Video") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, - "Shader Video") + "Video Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, - "Passaggi dello shader") + "Shader Passes") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, - "Antemprima Parametri Shader") + "Anteprima dei parametri Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, - "Carica Shader Preimpostati") + "Carica Shader Preset") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_PARAMETERS, - "Parametri shader del menù") + "Parametri Shader del menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, - "Salva Shader Preimpostati come") + "Salvare Preset Shader come") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, "Salva Core Preset") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, "Salva Game Preset") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, - "Abilita contesto condiviso HW") + "Abilita il contesto condiviso Hardware") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, - "Filtro bilineare hardware") + "Filtro Bilineare") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, - "Abilita filtro leggero") + "Abilita il filtro morbido ") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, - "Intervallo di swap vsync") + "Vertical Sync (Vsync) Swap Interval") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_TAB, "Video") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, @@ -1511,31 +1678,35 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, "Deflicker") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Personalizza l'altezza del Viewport ") + "Personalizza Rapporto d'aspetto in Altezza") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Personalizza la larghezza del Viewport ") + "Personalizza Rapporto d'aspetto in Larghezza") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, - "Personalizza la posizione X del Viewport ") + "Personalizza Rapporto d'aspetto in una posizione X.") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, - "Personalizza la posizione Y del Viewport ") + "Personalizza Rapporto d'aspetto in una posizione Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "Imposta la larghezza dello schermo") + "Impostare la larghezza dello schermo VI") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, - "Vertical Sync (Vsync)") + "Sincronizzazione verticale (Vsync)") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, - "Modalità a schermo intero con finestra") + "Modalità finestra a schermo intero") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, "Larghezza della finestra") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, - "Altezza della finestra ") + "Altezza della finestra") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, + "Larghezza a schermo intero") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, + "Altezza a schermo intero") MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, - "Driver Wi-Fi ") + "Driver Wi-Fi") MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, "Wi-Fi") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, - "Fattore alpha del menù") + "Menu del fattore Alfa") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_FONT, - "Carattere del menù") + "Font del Menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, "Personalizzato") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, @@ -1553,79 +1724,85 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, "Dot-Art") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, - "Colore tema del menù") + "Colore del menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, - "Verde mela") + "Mela Verde") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, "Scuro") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, - "Viola scuro") + "Viola Scuro") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, - "Blu elettrico") + "Blu Elettrico") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, "Oro") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, - "Rosso Legacy") + "Rosso Legacy ") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, - "Blu mezzanotte") + "Blu notte") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, - "Piatto") + "Pianura") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, - "Fondale marino") + "Sottomarino") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, "Rosso vulcanico") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, "Menu Shader Pipeline") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, - "Fattore di scala del menù") + "Menu Scale Factor") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, - "Abilità ombre per l'icona") + "Abilita Ombre delle Icone") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_HISTORY, - "Mostra scheda storia") + "Visualizza la colonna cronologia") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_ADD, - "Display Import content Tab") + "Visualizza colonna Importa contenuto") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_FAVORITES, + "Visualizza colonna Preferiti") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_IMAGES, - "Mostra scheda immagini") + "Visualizza colonna Immagini") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_MUSIC, - "Mostra scheda musica") + "Visualizza colonna Musica") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_SETTINGS, - "Mostra scheda settaggi") + "Visualizza colonna Impostazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_VIDEO, - "Mostra scheda video") + "Visualizza colonna Video") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_NETPLAY, + "Visualizza colonna Stanze Netplay ") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_THEME, - "Icona a tema del menù") + "Icone del Menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, - "Sì") + "Si") MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, "Shader Preset") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Abilita o disabilita achievements. Per maggiori informazioni, visita http://retroachievements.org") + "Abilita o disabilita achievements. Per maggiori informazioni, visitare il sito http://retroachievements.org") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, - "Enable or disable unofficial achievements and/or beta features for testing purposes.") + "Abilita o disabilita gli achievements non ufficiali e/o funzionalità beta per scopi di test.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Abilita o disabilita i salvataggi, cheats, rewind, fast-forward, pausa, e slow-motion per tutti i giochi.") + "Abilita o disabilita i salvataggi,cheats,la funzione riavvolgimento, avanzamento rapido, pausa, e slow-motion per tutti i giochi.") +MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, + "Abilita o disabilita OSD verbosity per gli achievements.") MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "Modifica i driver per questo sistema.") + "Modifica i driver utilizzati dal sistema.") MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Modifica le impostazioni per gli achievements.") + "Modifica le impostazioni degli achievement .") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "Modifica le impostazioni del core.") + "Modifica le impostazioni dei core .") MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Modifica le impostazioni per la registrazione.") + "Modifica le impostazioni di registrazione.") MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, "Modifica le impostazioni per l'overlay del display, l'overlay della tastiera e le notifiche dello schermo.") MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "Modifica le impostazioni per il riavvolgimento, fast-forwarding, e slow-motion.") + "Modifica le impostazioni per il riavvolgimento, avanzamento rapido e slow-motion") MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "Modifica le impostazioni per i salvataggi.") + "Modifica le impostazioni per i salvataggi") MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, "Modifica le impostazioni per il login.") MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, "Modifica le impostazioni per l'interfaccia utente.") MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, - "Modifica accounts, username, e linguaggio.") + "Modifica accounts, nome utente, e linguaggio.") MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "Modifica le tue impostazioni della privacy .") + "Modifica le tue impostazioni della privacy.") MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, "Modifica le directory predefinite per questo sistema.") MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, @@ -1633,115 +1810,117 @@ MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, "Configura il server e le impostazioni di rete.") MSG_HASH(MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, - "Scansione dei contenuti per aggiungerli al database.") + "Effettua la scansione del contenuto e li aggiunge al database.") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "Regola le impostazioni per l'uscita audio.") + "Modifica le impostazioni per l'uscita audio.") MSG_HASH(MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, "Abilita o disabilita il bluetooth.") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "Salva le modifiche al file di configurazione all'uscita.") + "Salva le modifiche al file di configurazione all'uscita del programma.") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, "Modifica le impostazioni predefinite per i file di configurazione.") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, "Gestione e creazione di file di configurazione.") MSG_HASH(MENU_ENUM_SUBLABEL_CPU_CORES, - "Quantità di core che la CPU ha.") + "Quantità di core che la CPU possiede.") MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, - "Visualizza il framerate corrente al secondo sullo schermo.") + "Consente di visualizzare la frequenza dei fotogrammi corrente al secondo sullo schermo.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "Configura le impostazioni hotkey .") + "Configura le impostazioni hotkey ") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, "Combinazioni dei pulsanti del Gamepad per attivare il menu.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "Regola le impostazioni per joypad, tastiera e mouse.") + "Modifica le impostazioni per joypad, tastiera e mouse") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, "Configura i controlli per questo utente.") MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, - "Abilitare o disattivare la registrazione dal terminale.") + "Abilita o disabilita la registrazione al terminale.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, "Unisci o ospita una sessione di netplay.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, - "Cerca e connetti all' host netplay sulla rete locale.") + "Ricerca e connetti all' host netplay sulla rete locale.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Visualizzare le informazioni dei core, di rete e di sistema.") + "Visualizza le informazioni dei core, di rete e di sistema.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Scarica i componenti aggiuntivi, i componenti e il contenuto di RetroArch.") + "Scarica add-ons, componenti, e contenuti per RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, - "Attiva o disattiva la condivisione di rete delle cartelle.") + "Attiva o disattiva la condivisione di rete delle tue cartelle") MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, "Gestire i servizi del livello di sistema operativo.") MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, "Mostra file / directory nascoste all'interno del file browser.") MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, - "Attiva o disattiva l'accesso alla riga di comando remota.") + "Abilita o disabilita l'accesso alla riga di comando remota.") MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "Impedisce che il salvaschermo del sistema diventi attivo.") + "Impedisce che lo screensaver del tuo sistema diventi attivo.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, - "Imposta la dimensione della finestra rispetto alla dimensione principale della vista. In alternativa, puoi impostare una larghezza e un'altezza della finestra sotto per una dimensione della finestra fissa") + "Imposta la dimensione della finestra rispetto alla dimensione principale della vista. In alternativa, puoi impostare una larghezza e un'altezza della finestra sotto ,con una dimensione della finestra fissa") MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, "Imposta la lingua dell'interfaccia.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, "Inserisce una cornice nera tra i fotogrammi. Utile per gli utenti che hanno schermi da 120 Hz e vogliono riprodurre il materiale da 60 Hz con l' eliminazione dell'effetto ghosting.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, - "Riduce la latenza a costo di un più alto rischio di stuttering video. Aggiunge un ritardo dopo V-Sync (in ms).") + "Riduce la latenza a costo di un più alto rischio di sfarfallio video. Aggiunge un ritardo dopo V-Sync (in ms).") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "Sets how many frames the CPU can run ahead of the GPU when using 'Hard GPU Sync'.") + "Imposta quanti frame la CPU può eseguire dinanzi alla GPU quando utilizza 'Hard GPU Sync'.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Indica al driver video di utilizzare esplicitamente una modalità di buffering specifica.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, - "Seleziona quale schermo da utilizzare.") + "Seleziona lo schermo da utilizzare.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, "La stima precisa di aggiornamento dello schermo in Hz.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "Regola le impostazioni per l'uscita video.") + "Cambia le impostazioni per l'uscita video.") MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, - "Esegue la scansione per le reti wireless e stabilisce la connessione.") + "Effettua una scansione delle reti wireless e stabilisce la connessione.") MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, - "Ulteriori informazioni su come funziona.") + "Ulteriori informazioni su come funziona il programma.") +MSG_HASH(MSG_ADDED_TO_FAVORITES, + "Aggiunto ai Preferiti") MSG_HASH(MSG_APPENDED_DISK, - "Appended disk") + "Disco aggiunto") MSG_HASH(MSG_APPLICATION_DIR, - "Directory app") + "Applicazione in corso della Directory") MSG_HASH(MSG_APPLYING_CHEAT, - "Applying cheat changes.") + "Applicazione dei trucchi/cheat in corso") MSG_HASH(MSG_APPLYING_SHADER, - "Applying shader") + "Applicazione dello shader in corso") MSG_HASH(MSG_AUDIO_MUTED, - "MUTO.") + "Audio disattivato.") MSG_HASH(MSG_AUDIO_UNMUTED, - "MUTO Disattivato.") + "Audio attivato.") MSG_HASH(MSG_AUTOCONFIG_FILE_ERROR_SAVING, - "Error saving autoconf file.") + "Errore durante il salvataggio del file autoconf.") MSG_HASH(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, - "Il file Autoconfig è stato salvato correttamente.") + "Il file di autoconfigurazione è stato salvato correttamente.") MSG_HASH(MSG_AUTOSAVE_FAILED, - "Impossibile inizializzare l'auto-salvataggio.") + "Impossibile inizializzare il salvataggio automatico.") MSG_HASH(MSG_AUTO_SAVE_STATE_TO, - "Auto save state to") + "Salva stato automatico su") MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, - "Bloccare SRAM Overwrite") + "Bloccare la sovrascrittura della SRAM") MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, "Bringing up command interface on port") MSG_HASH(MSG_BYTES, "bytes") MSG_HASH(MSG_CANNOT_INFER_NEW_CONFIG_PATH, - "Cannot infer new config path. Use current time.") + "Impossibile dedurre il nuovo percorso di configurazione. Verrà utilizzato quello corrente .") MSG_HASH(MSG_CHEEVOS_HARDCORE_MODE_ENABLE, - "Hardcore Mode Enabled, savestate & rewind were disabled.") + "Attivata la modalità hardcore.I salvataggi e la funzione riavvolgimento sono stati disattivati.") MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, - "Comparing with known magic numbers...") + "Confronto in corso con i numeri magici conosciuti...") MSG_HASH(MSG_COMPILED_AGAINST_API, - "Compiled against API") + "Compilate con API") MSG_HASH(MSG_CONFIG_DIRECTORY_NOT_SET, - "Config directory not set. Cannot save new config.") + "Non è stata impostata nessuna directory per la configurazione. Non è possibile salvare la nuova configurazione.") MSG_HASH(MSG_CONNECTED_TO, "Collegato a") MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, - "Content CRC32s differ. Cannot use different games.") + "Contenuti CRC32 differenti. Non è possibile utilizzare diversi giochi.") MSG_HASH(MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, - "Content loading skipped. Implementation will load it on its own.") + "Il caricamento del contenuto è stato saltato.Le Implemenzioni verranno caricati in proprio.") MSG_HASH(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "Core does not support save states.") + "Il Core non supporta gli salva stati.") MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, "Il file delle opzioni dei core è stato creato correttamente.") MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, @@ -1749,75 +1928,77 @@ MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, MSG_HASH(MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, "Impossibile trovare un sistema compatibile.") MSG_HASH(MSG_COULD_NOT_FIND_VALID_DATA_TRACK, - "Could not find valid data track") + "Impossibile trovare una traccia di dati valida") MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, - "could not open data track") + "Impossibile aprire la traccia dati") MSG_HASH(MSG_COULD_NOT_READ_CONTENT_FILE, - "Could not read content file") + "Impossibile leggere il contenuto del file") MSG_HASH(MSG_COULD_NOT_READ_MOVIE_HEADER, - "Could not read movie header.") + "Impossibile leggere l'intestazione del filmato.") MSG_HASH(MSG_COULD_NOT_READ_STATE_FROM_MOVIE, - "Could not read state from movie.") + "Impossibile leggere lo stato dal filmato.") MSG_HASH(MSG_CRC32_CHECKSUM_MISMATCH, - "CRC32 checksum mismatch between content file and saved content checksum in replay file header) replay highly likely to desync on playback.") + "La mancata corrispondenza del checksum CRC32 tra il file di contenuto e il checksum del contenuto salvato nell'intestazione del file di replay, riproduce molto probabilmente il desync sulla riproduzione.") MSG_HASH(MSG_CUSTOM_TIMING_GIVEN, "Custom timing given") MSG_HASH(MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, - "Decompression already in progress.") + "Decompressione già in corso.") MSG_HASH(MSG_DECOMPRESSION_FAILED, - "Decompression failed.") + "La decompressione non è riuscita.") MSG_HASH(MSG_DETECTED_VIEWPORT_OF, "Detected viewport of") MSG_HASH(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, "Did not find a valid content patch.") MSG_HASH(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, - "Disconnect device from a valid port.") + "Disconnessione del dispositivo da una porta valida") MSG_HASH(MSG_DISK_CLOSED, "Chiuso") MSG_HASH(MSG_DISK_EJECTED, - "Espulso") + "Espulsione") MSG_HASH(MSG_DOWNLOADING, - "Downloading") + "Scaricamento in corso del file") MSG_HASH(MSG_DOWNLOAD_FAILED, "Download fallito") MSG_HASH(MSG_ERROR, "Errore") MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, - "Il core Libretro richiede contenuti, ma niente è stato fornito.") + "Il core Libretro richiede contenuti, ma nessun dato è stato fornito..") MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, - "Libretro core requires special content, but none were provided.") + "I core Libretro richiedono contenuti speciali, ma nessun dato è stato fornito.") MSG_HASH(MSG_ERROR_PARSING_ARGUMENTS, - "Errore parsing arguments.") + "Errore durante l'analisi di argomenti.") MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, - "Errore saving core options file.") + "Errore nel salvataggio del file delle opzioni del core.") MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, - "Errore saving remap file.") + "Errore nel salvataggio del file remap.") +MSG_HASH(MSG_ERROR_REMOVING_REMAP_FILE, + "Errore durante la rimozione del file remap.") MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, - "Errore saving shader preset.") + "Errore durante il salvataggio delle preimpostazioni di shader.") MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, - "Directory app esterna") + "Directory dell'applicazione esterna") MSG_HASH(MSG_EXTRACTING, - "Estrazione") + "Estrazione in corso del file") MSG_HASH(MSG_EXTRACTING_FILE, - "Extracting file") + "Estrazione del file") MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, - "Failed saving config to") + "Non è riuscito il salvataggio della configurazione per") MSG_HASH(MSG_FAILED_TO, "Non è riuscito a") MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, - "Failed to accept incoming spectator.") + "Impossibile accettare lo spettatore.") MSG_HASH(MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, - "Failed to allocate memory for patched content...") + "Impossibile allocare la memoria per il contenuto patchato...") MSG_HASH(MSG_FAILED_TO_APPLY_SHADER, - "Failed to apply shader.") + "Impossibile applicare lo shader.") MSG_HASH(MSG_FAILED_TO_BIND_SOCKET, - "Failed to bind socket.") + "Impossibile collegare il socket.") MSG_HASH(MSG_FAILED_TO_CREATE_THE_DIRECTORY, - "Failed to create the directory.") + "Impossibile creare la directory") MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, - "Failed to extract content from compressed file") + "Impossibile estrarre il contenuto dal file compresso") MSG_HASH(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, - "Failed to get nickname from client.") + "Impossibile ottenere il nome utente dal client.") MSG_HASH(MSG_FAILED_TO_LOAD, "Caricamento fallito") MSG_HASH(MSG_FAILED_TO_LOAD_CONTENT, @@ -1825,75 +2006,75 @@ MSG_HASH(MSG_FAILED_TO_LOAD_CONTENT, MSG_HASH(MSG_FAILED_TO_LOAD_MOVIE_FILE, "Impossibile caricare il file del filmato") MSG_HASH(MSG_FAILED_TO_LOAD_OVERLAY, - "Failed to load overlay.") + "Impossibile caricare l'overlay.") MSG_HASH(MSG_FAILED_TO_LOAD_STATE, - "Failed to load state from") + "Impossibile caricare lo stato da") MSG_HASH(MSG_FAILED_TO_OPEN_LIBRETRO_CORE, "Impossibile aprire il core libretro ") MSG_HASH(MSG_FAILED_TO_PATCH, - "Failed to patch") + "Non è riuscito a patchare") MSG_HASH(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, - "Failed to receive header from client.") + "Impossibile ricevere intestazione dal client.") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME, - "Failed to receive nickname.") + "Impossibile ricevere il nome utente.") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, - "Failed to receive nickname from host.") + "Impossibile ricevere il nome utente dall'host") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, - "Failed to receive nickname size from host.") + "Impossibile ricevere la dimensione del nome utente dall'host.") MSG_HASH(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, - "Failed to receive SRAM data from host.") + "Impossibile ricevere dati SRAM dall'host.") MSG_HASH(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, - "Failed to remove disk from tray.") + "Impossibile rimuovere il disco dal vassoio.") MSG_HASH(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, "Impossibile rimuovere il file temporaneo") MSG_HASH(MSG_FAILED_TO_SAVE_SRAM, - "Failed to save SRAM") + "Impossibile salvare la SRAM") MSG_HASH(MSG_FAILED_TO_SAVE_STATE_TO, - "Failed to save state to") + "Impossibile salvare lo stato") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME, - "Impossibile inviare il nickname.") + "Impossibile inviare il nome utente.") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, - "Failed to send nickname size.") + "Impossibile inviare la dimensione del nome utente.") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, - "Failed to send nickname to client.") + "Impossibile inviare il nome utente al client.") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, - "Failed to send nickname to host.") + "Impossibile inviare il nome utente all' host.") MSG_HASH(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, - "Failed to send SRAM data to client.") + "Impossibile inviare i dati SRAM al client.") MSG_HASH(MSG_FAILED_TO_START_AUDIO_DRIVER, - "Failed to start audio driver. Will continue without audio.") + "Impossibile avviare il driver audio.Il contenuto continuerà senza audio.") MSG_HASH(MSG_FAILED_TO_START_MOVIE_RECORD, - "Failed to start movie record.") + "Impossibile avviare la registrazione del film") MSG_HASH(MSG_FAILED_TO_START_RECORDING, - "Failed to start recording.") + "Impossibile avviare la registrazione.") MSG_HASH(MSG_FAILED_TO_TAKE_SCREENSHOT, - "Failed to take screenshot.") + "Impossibile eseguire lo screenshot.") MSG_HASH(MSG_FAILED_TO_UNDO_LOAD_STATE, - "Failed to undo load state.") + "Impossibile annullare il caricamento dello stato .") MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, - "Failed to undo save state.") + "Impossibile annullare il salvataggio.") MSG_HASH(MSG_FAILED_TO_UNMUTE_AUDIO, - "Failed to unmute audio.") + "Impossibile disattivare l'audio.") MSG_HASH(MSG_FATAL_ERROR_RECEIVED_IN, - "Fatal error received in") + "Errore irreversibile ricevuto in") MSG_HASH(MSG_FILE_NOT_FOUND, "File non trovato") MSG_HASH(MSG_FOUND_AUTO_SAVESTATE_IN, - "Found auto savestate in") + "Trovato salva stato automatico in") MSG_HASH(MSG_FOUND_DISK_LABEL, - "Found disk label") + "Trovata Etichetta del disco ") MSG_HASH(MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, - "Found first data track on file") + "Trovata la prima traccia dati su file") MSG_HASH(MSG_FOUND_LAST_STATE_SLOT, - "Found last state slot") + "Trovato l'ultimo slot di salvataggio") MSG_HASH(MSG_FOUND_SHADER, - "Found shader") + "Trovato shader") MSG_HASH(MSG_FRAMES, "Frames") MSG_HASH(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, "Per-Game Options: game-specific core options found at") MSG_HASH(MSG_GOT_INVALID_DISK_INDEX, - "Got invalid disk index.") + "Indice del disco non valida.") MSG_HASH(MSG_GRAB_MOUSE_STATE, "Grab mouse state") MSG_HASH(MSG_GAME_FOCUS_ON, @@ -1903,21 +2084,23 @@ MSG_HASH(MSG_GAME_FOCUS_OFF, MSG_HASH(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, "Libretro core is hardware rendered. Must use post-shaded recording as well.") MSG_HASH(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, - "Inflated checksum did not match CRC32.") + "Il checksum inserito non corrisponde a CRC32.") MSG_HASH(MSG_INPUT_CHEAT, "Input Cheat") MSG_HASH(MSG_INPUT_CHEAT_FILENAME, - "Cheat Filename") + "Immettere il nome del file cheat") MSG_HASH(MSG_INPUT_PRESET_FILENAME, - "Preset Filename") + "Nome del file predefinito") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rinomina Titolo") MSG_HASH(MSG_INTERFACE, "Interfaccia") MSG_HASH(MSG_INTERNAL_STORAGE, - "Memoria interna") + "Archiviazione interna") MSG_HASH(MSG_REMOVABLE_STORAGE, - "Removable Storage") + "Spazio di archiviazione rimovibile") MSG_HASH(MSG_INVALID_NICKNAME_SIZE, - "Dimensione del nickname non valido.") + "Dimensione del nome utente non valido.") MSG_HASH(MSG_IN_BYTES, "in bytes") MSG_HASH(MSG_IN_GIGABYTES, @@ -1929,39 +2112,39 @@ MSG_HASH(MSG_LIBRETRO_ABI_BREAK, MSG_HASH(MSG_LIBRETRO_FRONTEND, "Frontend per libretro") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, - "Loaded state from slot #%d.") + "Caricamento del salvataggio dallo slot #%d.") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, - "Loaded state from slot #-1 (auto).") + "Caricamento del salvataggio dallo slot #-1 (automatico).") MSG_HASH(MSG_LOADING, - "Caricamento") + "Caricamento in corso") MSG_HASH(MSG_FIRMWARE, - "One or more firmware files are missing") + "Mancano uno o più file del firmware") MSG_HASH(MSG_LOADING_CONTENT_FILE, - "Loading content file") + "Caricamento dei file di contenuto") MSG_HASH(MSG_LOADING_HISTORY_FILE, - "Loading history file") + "Caricamento dei file della cronologia") MSG_HASH(MSG_LOADING_STATE, "Caricamento dello stato") MSG_HASH(MSG_MEMORY, "Memoria") MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, - "Movie file is not a valid BSV1 file.") + "Il File del filmato non è un file valido di BSV1.") MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, - "Movie format seems to have a different serializer version. Will most likely fail.") + "Il formato del film sembra avere una versione di serializzazione diversa. Molto probabilmente non verrà avviato.") MSG_HASH(MSG_MOVIE_PLAYBACK_ENDED, - "Movie playback ended.") + "La riproduzione del film è terminata.") MSG_HASH(MSG_MOVIE_RECORD_STOPPED, - "Stopping movie record.") + "Arresto in corso della registrazione del film.") MSG_HASH(MSG_NETPLAY_FAILED, - "Failed to initialize netplay.") + "Impossibile inizializzare il netplay.") MSG_HASH(MSG_NO_CONTENT_STARTING_DUMMY_CORE, - "No content, starting dummy core.") + "Nessun contenuto, avvio dummy core.") MSG_HASH(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, - "No save state has been overwritten yet.") + "Nessun salvataggio è stato ancora sovrascritto.") MSG_HASH(MSG_NO_STATE_HAS_BEEN_LOADED_YET, - "No state has been loaded yet.") + "Nessun salvataggio è stato ancora caricato") MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, - "Error saving overrides.") + "Errore durante il salvataggio degli override.") MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, "Overrides saved successfully.") MSG_HASH(MSG_PAUSED, @@ -1973,37 +2156,39 @@ MSG_HASH(MSG_READING_FIRST_DATA_TRACK, MSG_HASH(MSG_RECEIVED, "ricevuto") MSG_HASH(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, - "Recording terminated due to resize.") + "La registrazione è terminata a causa del ridimensionamento.") MSG_HASH(MSG_RECORDING_TO, - "Recording to") + "Registrazione su") MSG_HASH(MSG_REDIRECTING_CHEATFILE_TO, - "Redirecting cheat file to") + "Reindirizzare il file cheat su") MSG_HASH(MSG_REDIRECTING_SAVEFILE_TO, - "Redirecting save file to") + "Reindirizzare il file di salvataggio su") MSG_HASH(MSG_REDIRECTING_SAVESTATE_TO, - "Redirecting savestate to") + "Reindirizzare il salva stato su") MSG_HASH(MSG_REMAP_FILE_SAVED_SUCCESSFULLY, - "Remap file saved successfully.") + "Il file Remap è stato salvato con successo ") +MSG_HASH(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, + "Il file Remap è stato rimosso con successo ") MSG_HASH(MSG_REMOVED_DISK_FROM_TRAY, - "Removed disk from tray.") + "Rimosso il disco dal vassoio.") MSG_HASH(MSG_REMOVING_TEMPORARY_CONTENT_FILE, - "Removing temporary content file") + "Rimosso un file di contenuto temporaneo") MSG_HASH(MSG_RESET, - "Reset") + "Resetta") MSG_HASH(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, "Restarting recording due to driver reinit.") MSG_HASH(MSG_RESTORED_OLD_SAVE_STATE, - "Restored old save state.") + "Ripristinato un vecchio salva stato.") MSG_HASH(MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, - "Shaders: restoring default shader preset to") + "Shader: ripristino dello shader predefinito preimpostato su") MSG_HASH(MSG_REVERTING_SAVEFILE_DIRECTORY_TO, - "Reverting savefile directory to") + "Ripristino della directory dei file di salvataggio su") MSG_HASH(MSG_REVERTING_SAVESTATE_DIRECTORY_TO, - "Reverting savestate directory to") + "Ripristino directory del salva stato su") MSG_HASH(MSG_REWINDING, - "Rewinding.") + "Riavvolgimento in corso.") MSG_HASH(MSG_REWIND_INIT, - "Initializing rewind buffer with size") + "Inizializzazione del buffer di riavvolgimento con dimensione") MSG_HASH(MSG_REWIND_INIT_FAILED, "Failed to initialize rewind buffer. Rewinding will be disabled.") MSG_HASH(MSG_REWIND_INIT_FAILED_THREADED_AUDIO, @@ -2011,67 +2196,67 @@ MSG_HASH(MSG_REWIND_INIT_FAILED_THREADED_AUDIO, MSG_HASH(MSG_REWIND_REACHED_END, "Reached end of rewind buffer.") MSG_HASH(MSG_SAVED_NEW_CONFIG_TO, - "Saved new config to") + "Salvata la nuova configurazione su") MSG_HASH(MSG_SAVED_STATE_TO_SLOT, "Saved state to slot #%d.") MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, "Saved state to slot #-1 (auto).") MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, - "Saved successfully to") + "Salvato con successo su") MSG_HASH(MSG_SAVING_RAM_TYPE, "Saving RAM type") MSG_HASH(MSG_SAVING_STATE, - "Saving state") + "Salvataggio dello stato") MSG_HASH(MSG_SCANNING, - "Scanning") + "Scansione in corso") MSG_HASH(MSG_SCANNING_OF_DIRECTORY_FINISHED, - "Scanning of directory finished") + "Scansione della directory completata") MSG_HASH(MSG_SENDING_COMMAND, - "Sending command") + "Invio del comando") MSG_HASH(MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, - "Several patches are explicitly defined, ignoring all...") + "Diverse patch sono definite esplicitamente, ignorando tutti...") MSG_HASH(MSG_SHADER, "Shader") MSG_HASH(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, - "Shader preset saved successfully.") + "Shader predefinito salvato con successo.") MSG_HASH(MSG_SKIPPING_SRAM_LOAD, "Skipping SRAM load.") MSG_HASH(MSG_SLOW_MOTION, "Slow motion.") MSG_HASH(MSG_SLOW_MOTION_REWIND, - "Slow motion rewind.") + "Riavvolgimento lento.") MSG_HASH(MSG_SRAM_WILL_NOT_BE_SAVED, - "SRAM will not be saved.") + "La SRAM non verrà salvata.") MSG_HASH(MSG_STARTING_MOVIE_PLAYBACK, - "Starting movie playback.") + "Avvia la riproduzione del filmato.") MSG_HASH(MSG_STARTING_MOVIE_RECORD_TO, - "Starting movie record to") + "Avvio della registrazione del film su") MSG_HASH(MSG_STATE_SIZE, - "State size") + "Dimensione dello stato") MSG_HASH(MSG_STATE_SLOT, - "State slot") + "Slot dello stato") MSG_HASH(MSG_TAKING_SCREENSHOT, - "Taking screenshot.") + "Effettua screenshot.") MSG_HASH(MSG_TO, "to") MSG_HASH(MSG_UNDID_LOAD_STATE, - "Annullato carica stato.") + "Annullamento del caricamento del salvataggio") MSG_HASH(MSG_UNDOING_SAVE_STATE, - "Undoing save state") + "Annullamento del salvataggio") MSG_HASH(MSG_UNKNOWN, "Sconosciuto") MSG_HASH(MSG_UNPAUSED, "Unpaused.") MSG_HASH(MSG_UNRECOGNIZED_COMMAND, - "Unrecognized command") + "Comando non riconosciuto") MSG_HASH(MSG_USING_CORE_NAME_FOR_NEW_CONFIG, - "Using core name for new config.") + "Utilizzo del nome di un core per la nuova configurazione.") MSG_HASH(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, "Using libretro dummy core. Skipping recording.") MSG_HASH(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, - "Connect device from a valid port.") + "Collegare il dispositivo a una porta valida.") MSG_HASH(MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, - "Disconnecting device from port") + "Scollegamento del dispositivo dalla porta") MSG_HASH(MSG_VALUE_REBOOTING, "Riavvio in corso...") MSG_HASH(MSG_VALUE_SHUTTING_DOWN, @@ -2079,48 +2264,60 @@ MSG_HASH(MSG_VALUE_SHUTTING_DOWN, MSG_HASH(MSG_VERSION_OF_LIBRETRO_API, "Versione delle API di libretro ") MSG_HASH(MSG_VIEWPORT_SIZE_CALCULATION_FAILED, - "Viewport size calculation failed! Will continue using raw data. This will probably not work right ...") + "Il calcolo della dimensione di visualizzazione è fallito! Continuerà ad utilizzare dati grezzi. Questo probabilmente non funzionerà correttamente") MSG_HASH(MSG_VIRTUAL_DISK_TRAY, - "virtual disk tray.") + "Vassoio del disco virtuale.") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_LATENCY, - "Desired audio latency in milliseconds. Might not be honored if the audio driver can't provide given latency.") + "Latenza audio desiderata in millisecondi. Potrebbe non essere visualizzato se il driver audio non è in grado di fornire una latenza .") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Audio Muto/non Muto .") + "Attiva/disattiva audio.") MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, - "Helps smooth out imperfections in timing when synchronizing audio and video at the same time. Be aware that if disabled, proper synchronization is nearly impossible to obtain." + "Aiuta a eliminare le imperfezioni nei tempi durante la sincronizzazione di audio e video. Siate consapevoli che se disattivato, la corretta sincronizzazione è quasi impossibile da ottenere." ) MSG_HASH( MENU_ENUM_SUBLABEL_CAMERA_ALLOW, - "Allow or disallow camera access by cores." + "Consente o non consente l'accesso alla fotocamera da core." ) MSG_HASH( MENU_ENUM_SUBLABEL_LOCATION_ALLOW, - "Allow or disallow location services access by cores." + "Consente o non consente l'accesso alla posizione dei servizi da core." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, - "Massima quantità di utenti supportati da RetroArch." + "Numero massimo di utenti supportati da RetroArch." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, - "Influence how input polling is done inside RetroArch. Setting it to 'Early' or 'Late' can result in less latency, depending on your configuration." + "Influisce come il polling degli input che viene fatto all'interno di RetroArch. L'impostazione 'Anticipato' o 'Ritardato' può causare una minore latenza, a seconda della configurazione." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Allows any user to control the menu. If disabled, only User 1 can control the menu." + "Consente a qualsiasi utente di controllare il menu. Se disattivato, solo l'utente 1 può controllare il menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Audio volume (in dB). 0 dB è un volume normale , nessun guadagno applicato." + "Volume audio (in dB). 0 dB è un volume normale , nessun guadagno applicato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, + "Consente al driver WASAPI di prendere il controllo esclusivo del dispositivo audio. Se disabilitato, utilizzerà la modalità condivisa ." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, + "Utilizza il formato del float per il driver WASAPI, se supportato dal dispositivo audio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "La lunghezza del buffer intermedio (in fotogrammi) quando si utilizza il driver WASAPI in modalità condivisa." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "Sincronizzare l'audio. Consigliato." + "Sincronizza l'audio. Consigliato." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, - "How far an axis must be tilted to result in a button press." + "Quanto lontano deve essere inclinato un asse per provocare una pressione del pulsante." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, @@ -2128,39 +2325,39 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Describes the period of which turbo-enabled buttons toggle. Numbers are described in frames." + "Descrive il periodo in cui i tasti turbo-abilitati vengono commutati. I numeri sono descritti in fotogrammi." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Describes how long the period of a turbo-enabled button should be. Numbers are described in frames." + "Descrive quanto tempo dovrebbe essere il periodo di un pulsante turbo-abilitato. I numeri sono descritti in fotogrammi." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "Synchronizes the output video of the graphics card to the refresh rate of the screen. Recommended." + "Sincronizza il video di uscita della scheda grafica alla frequenza di aggiornamento dello schermo. Consigliato" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, - "Allow cores to set rotation. When disabled, rotation requests are ignored. Useful for setups where one manually rotates the screen." + "Consente ai core di impostare la rotazione. Se disattivato, le richieste di rotazione vengono ignorate. Utile per le impostazioni in cui ruota manualmente lo schermo." ) MSG_HASH( MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, - "Some cores might have a shutdown feature. If enabled, it will prevent the core from shutting RetroArch down. Instead, it loads a dummy core." + "Alcuni core potrebbero avere una funzione di arresto. Se abilitato, impedirà al core di arrestare RetroArch. Al contrario, carica un core dummy." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, - "Check if all the required firmware is present before attempting to load content." + "Controlla che il firmware richiesto sia presente prima di tentare di caricare il contenuto." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, - "Vertical refresh rate of your screen. Used to calculate a suitable audio input rate. NOTE: This will be ignored if 'Threaded Video' is enabled." + "Frequenza di aggiornamento verticale dello schermo.Viene utilizzato per calcolare un'adeguata frequenza di ingresso audio. NOTA: questo verrà ignorata se è abilitato 'Threaded Video' ." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_ENABLE, - "Abilita audio output." + "Abilita l'uscita audio." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, - "The maximum change in audio input rate. You may want to increase this to enable very large changes in timing, for example running PAL cores on NTSC displays, at the cost of inaccurate audio pitch." + "La variazione massima della frequenza di ingresso audio. Aumentando il valore, è possibile modificare molto velocemente la temporizzazione al costo dell' audio che diventa impreciso (ad esempio, eseguire core PAL in display NTSC)." ) MSG_HASH( MSG_FAILED, @@ -2168,7 +2365,7 @@ MSG_HASH( ) MSG_HASH( MSG_SUCCEEDED, - "Riuscito" + "ha avuto successo" ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, @@ -2176,22 +2373,24 @@ MSG_HASH( ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED_FALLBACK, - "not configured, using fallback" + "non configurata, utilizza fallback" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, - "Database Cursor List" + "Elenco dei cursori del database" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, - "Database - Filter : Developer" + "Database - Filtro : Sviluppatore" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, - "Database - Filter : Publisher" + "Database - Filtro : Editore" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISABLED, + "Disabilitato" ) -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISABLED, - "Disattivato") MSG_HASH( MENU_ENUM_LABEL_VALUE_ENABLED, "Abilitato" @@ -2206,17 +2405,17 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, "Database - Filtro : Franchise") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, - "Database - Filtro : ESRB Rating") + "Database - Filtro : Valutazione ESRB ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, - "Database - Filtro : ELSPA Rating") + "Database - Filtro : Valutazione ELSPA ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, - "Database - Filtro : PEGI Rating") + "Database - Filtro : Valutazione PEGI ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, - "Database - Filtro : CERO Rating") + "Database - Filtro : Valutazione CERO ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, - "Database - Filtro : BBFC Rating") + "Database - Filtro : Valutazione BBFC ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, - "Database - Filtro : Max Users") + "Database - Filtro : Massimo numero di utenti") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, "Database - Filtro : Releasedate By Month") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, @@ -2224,47 +2423,47 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, "Database - Filtro : Edge Magazine Issue") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, - "Database - Filtro : Edge Magazine Rating") + "Database - Filtro : Valutazione Edge Magazine ") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, - "Database Info") + "Informazione del Database ") MSG_HASH(MSG_WIFI_SCAN_COMPLETE, - "Scansione della Wi-Fi completa.") + "Scansione completata delle reti Wi-Fi .") MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS, "Scansione delle reti wireless in corso...") MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, - "Scansione Netplay completa.") + "Scansione completata delle camere Netplay .") MSG_HASH(MSG_NETPLAY_LAN_SCANNING, - "Scanning for netplay hosts...") + "Scansione hosts netplay in corso...") MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, - "Pause gameplay when window focus is lost.") + "Sospende il gioco quando RetroArch non ha una finestra attiva.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, - "Abilita o disattiva la composizione (solo Windows).") + "Attiva o disattiva la composizione (solo Windows).") MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, - "Attiva o disattiva la playlist recente per i giochi, le immagini, la musica e i video.") + "Abilita o disabilita la playlist recente per giochi, immagini, musica e video.") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, - "Limit the number of entries in recent playlist for games, images, music, and videos.") + "Limita il numero di voci nella playlist recente per giochi, immagini, musica e video.") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, - "Unified Menu Controls") + "Controlli del Menu Unificati") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, - "Use the same controls for both the menu and the game. Applies to the keyboard.") + "Utilizzare gli stessi controlli per il menu e il gioco. Si applica alla tastiera.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "Show onscreen messages.") + "Visualizza i messaggi sullo schermo.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, - "User %d Remote Enable") + "Abilita Utente %d da remoto") MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, "Visualizza il livello della batteria") MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FILE, "Seleziona File") MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, - "Seleziona da una Collezione") + "Seleziona da collezione") MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, - "Filtro") + "Filtra") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, "Scala") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "Netplay will start when content is loaded.") + "Il Netplay verrà avviato quando il contenuto sarà caricato.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, - "Couldn't find a suitable core or content file, load manually.") + "Non è possibile trovare un core o un file di contenuto adatto, caricare manualmente.") MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, "Browse URL" @@ -2275,39 +2474,660 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_START, - "Start" + "Avvia" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, "Bokeh") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Ricarica la lista delle Stanze") + "Aggiorna la lista delle camere") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, "Nickname: %s") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, "Nickname (lan): %s") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, + "Contenuto compatibile trovato") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, + "Taglia alcuni pixel intorno ai bordi dell'immagine generalmente lasciati vuoti dagli sviluppatori che a volte contengono anche i pixel che non vengono utilizzati.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, + "Aggiunge una leggera sfocatura dell'immagine per togliere il bordo del pixel. Questa opzione ha un piccolo impatto sulle prestazioni.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, + "Applica un filtro video, aumentando la potenza della CPU. NOTA: Potrebbe avere un costo sul rendimento. Alcuni filtri video potrebbero funzionare solo per i core che utilizzano un colore a 32 bit o 16 bit.") +MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, + "Inserisci il nome utente del tuo account Retro Achievements.") +MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, + "Inserisci la password del tuo account Retro Achievements.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, + "Inserisci il tuo nome utente qui. Questo sarà utilizzato per le sessioni netplay e altre cose.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, + "Cattura l'immagine dopo che vengono applicati i filtri (ma non shader). Il tuo video sarà simile a quello che vedi sul tuo schermo.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_LIST, + "Seleziona il core da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, + "Seleziona il contenuto da avviare.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, + "Mostra l'interfaccia di rete e gli indirizzi IP associati.") +MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, + "Visualizza le informazioni specifiche per quel dispositivo.") +MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, + "Chiude il programma.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, + "Imposta la dimensione personalizzata della finestra di visualizzazione. Lasciando il valore a 0 tenterà di scalare la finestra il più grande possibile.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, + "Imposta le dimensioni dell'altezza personalizzata per la finestra del display. Lasciando il valore a 0 tenterà di scalare la finestra il più grande possibile.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, + "Imposta la dimensione personalizzata della larghezza per la modalità a schermo intero senza finestra. Lasciandolo a 0 utilizzerà la risoluzione del desktop.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, + "Imposta la dimensione personalizzata dell'altezza per la modalità a schermo intero senza finestra. Lasciandolo a 0 utilizzerà la risoluzione del desktop") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, + "Specifica la posizione personalizzata dell'asse X per il testo sullo schermo.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, + "Specifica la posizione personalizzata dell'asse Y per il testo sullo schermo.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, + "Specifica la dimensione del carattere in punti.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, + "Nasconde l'overlay all'interno del menu e verrà mostrata nuovamente all'uscita.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Mostra gli input della tastiera/controller sull'overlay tramite lo schermo") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Select the port for the overlay to listen to if Show Inputs On Overlay is enabled.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, + "Qui vengono visualizzati i contenuti scansionati." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Permette di scalare solo il video per intero. La dimensione base dipende dalla geometria e dall' Aspect Ratio riportati dal sistema. Se non è impostata l'opzione 'Force Aspect', X / Y sarà scalato indipendentemente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, + "Schermata di output del materiale ombreggiato GPU se disponibile." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ROTATION, + "Forza una certa rotazione dello schermo. La rotazione sarà impostata dal core ." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, + "Forza la disattivazione del supporto sRGB FBO. Alcuni driver Intel OpenGL su Windows presentano problemi video se è abilitato sRGB FBO." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, + "Avvia a schermo intero. Può essere modificato in fase di runtime." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, + "Se è a schermo intero e si preferisce utilizzare una modalità a schermo intero a finestre." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, + "Registra l'output del materiale ombreggiato GPU se disponibile." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, + "Quando si effettua un salvataggio, viene salvato automaticamente l'indice del salvataggio prima di essere salvato. Quando carichi il contenuto, l'indice sarà impostato al valore più alto esistente." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, + "Blocca il salvataggio della SRAM da sovrascrittura durante il caricamento degli stati di salvataggio. Potenzialmente può portare a buggare i giochi." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, + "La velocità massima in cui il contenuto verrà eseguito quando si utilizza l'avanzamento veloce (ad esempio, 5,0x per 60 fps = 300 fps). Se impostato a 0.0x, il rapporto dell'avanzamneto veloce è illimitato (nessun cap FPS)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, + "In slow motion, il contenuto verrà rallentato dal valore specificato / impostato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_ENABLE, + "Attiva il riavvolgimento.Richiederà maggiori prestazioni durante il gioco." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, + "Quando si riavvolge un numero definito di fotogrammi, è possibile riavvolgere più fotogrammi alla volta, aumentando la velocità di riavvolgimento." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, + "Imposta il livello di registro per i core. Se un livello di registro emesso da un core è inferiore a questo valore, verrà ignorato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, + "Abilita i contatori delle prestazioni per RetroArch (e core)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Esegue automaticamente un salvataggio alla fine del runtime di RetroArch. RetroArch caricherà automaticamente questo salvataggio se è abilitato 'Carica automaticamente i Salvataggi'." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, + "Carica automaticamente i salvataggi all'avvio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, + "Visualizza le miniature degli stati di salvataggio all'interno del menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, + "Salva automaticamente la memoria RAM non volatile ad un intervallo regolare. Questa impostazione è disabilitata per impostazione predefinita, L'intervallo è misurato in secondi. Un valore 0 disabilita il salvataggio automatico." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, + "Se abilitato, gli input dell'override si legano con i bind rimappati impostati per il core corrente" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, + "Attiva il rilevamento automatico degli input. Tenterà di autoconfigurare i joypad,stile Plug-and-Play ." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, + "Scambia i pulsanti OK / Annulla. Disabilitato è l'orientamento per gli utenti giapponesi, abilitato è l'orientamento per gli utenti occidentali." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, + "Se disattivato, il contenuto continuerà a funzionare in background quando il menu di RetroArch è attivato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_DRIVER, + "Indica il driver video utilizzato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DRIVER, + "Indica il driver audio utilizzato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DRIVER, + "Indica il Driver di input utilizzato. A seconda del driver video, potrebbe forzare un diverso driver di input." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "Indica il driver del JoyPad utilizzato" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, + "Indica il driver audio resampler utilizzato" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CAMERA_DRIVER, + "Indica il driver della fotocamera utilizzato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOCATION_DRIVER, + "Indica il driver della posizione utilizzato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_DRIVER, + "Indica il driver del Menu utilizzato." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORD_DRIVER, + "Indica il driver per la registrazione utilizzato" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_WIFI_DRIVER, + "Indica il driver della WiFi utilizzato" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filtra i file visualizzati nel filebrowser da estensioni supportate." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WALLPAPER, + "Seleziona un'immagine da impostare come sfondo nel menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, + "Carica dinamicamente un nuovo sfondo in base al contesto." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DEVICE, + "Sovrascrive il dispositivo audio predefinito utilizzato dal driver audio. Questo è dipendente dal driver." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, + "Plugin Audio DSP che elabora l'audio prima di essere inviato al driver." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, + "Frequenza di campionamento dell'uscita audio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, + "Opacità di tutti gli elementi UI dell'overlay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE, + "Scala di tutti gli elementi dell'interfaccia utente dell'overlay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, + "Abilita l'overlay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Seleziona un overlay dal file browser." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, + "Indirizzo dell'host per connettersi." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, + "La porta dell'indirizzo IP dell' host. Può essere una porta TCP o UDP." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, + "La password per il collegamento all'host netplay. Utilizzato solo in modalità host." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, + "Permette di annunciare i giochi del netplay pubblicamente. Se disattivato, i client devono connettersi manualmente anziché utilizzare la lobby pubblica." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, + "La password per il collegamento all'host netplay con solo privilegi da spettatore. Utilizzato solo in modalità host." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_START_AS_SPECTATOR, + "Avvia il netplay nella modalità spettatore." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, + "Permette di connettersi in modalità slave. La modalità slave per i client richiede una piccola potenza di elaborazione su entrambi i lati, ma soffre significativamente della latenza di rete." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, + "Non consente le connessioni che non sono in modalità slave . Non raccomandato tranne per reti molto veloci con macchine molto deboli." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, + "Whether to run netplay in a mode not requiring save states. If set to true, a very fast network is required, but no rewinding is performed, so there will be no netplay jitter." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, + "La frequenza dei fotogrammi con cui il netplay verificherà che l'host e il client sono sincronizzati." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, + "When hosting, attempt to listen for connections from the public Internet, using UPnP or similar technologies to escape LANs." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, + "Abilita l'interfaccia di comando stdin." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MOUSE_ENABLE, + "Abilita i controlli del mouse all'interno del menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_POINTER_ENABLE, + "Abilita i controlli tramite Touch all'interno del menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS, + "Tipo di miniatura da visualizzare." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, + "Mostra la data e/o l'ora attuale nel menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, + "Mostra il livello di carica della batteria all'interno del menu." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, + "Wrap-around to beginning and/or end if boundary of list is reached horizontally or vertically." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, + "Abilita il Netplay in modalità host (server).." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, + "Abilita il netplay in modalità client.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, + "Disconnette da una connessione Netplay attiva") +MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, + "Effettua la scansione di una directory per i file compatibili e li aggiunge alla raccolta.") +MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_FILE, + "Esegue la scansione di un file compatibile e li aggiunge alla raccolta.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, + "Utilizza un intervallo di scambio personalizzato per Vsync. Impostando un valore corretto dimezza la frequenza di aggiornamento del monitor." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, + "Ordina i file salvati in cartelle dopo che un core viene utilizzato." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, + "Ordina i salva stati in cartelle dopo che un core viene utilizzato." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_CLIENT_SWAP_INPUT, + "Quando sei un client su netplay, utilizza i tasti di comando per il giocatore 1.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, + "URL alla directory di aggiornamento del core nel buildbot di Libretro.") +MSG_HASH(MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, + "URL della directory di aggiornamento delle risorse nel buildbot Libretro.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Dopo il download, estrae automaticamente i file contenuti negli archivi scaricati." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, + "Scansiona nuove camere.") +MSG_HASH(MENU_ENUM_SUBLABEL_DELETE_ENTRY, + "Rimuovi questo titolo dalla collezione") +MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION, + "Visualizza ulteriori informazioni sul contenuto.") +MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, + "Aggiunge il titolo ai tuoi preferiti.") +MSG_HASH(MENU_ENUM_SUBLABEL_RUN, + "Avvia il contenuto.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Regola le impostazioni del filebrowser.") +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, + "Abilita i controlli personalizzati per impostazione predefinita all'avvio." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, + "Abilita la configurazione personalizzata per impostazione predefinita all'avvio." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, + "Abilita le opzioni personalizzate dei core per impostazione predefinita all'avvio.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ENABLE, + "Visualizza il nome corrente del core all'interno del menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_DATABASE_MANAGER, + "Visualizza i database.") +MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_MANAGER, + "Visualizza le ricerche precedenti.") +MSG_HASH(MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, + "Cattura un'immagine dello schermo.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOSE_CONTENT, + "Chiude il contenuto corrente. Eventuali modifiche non salvate potrebbero essere perse." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_STATE, + "Carica un salvataggio dallo slot attualmente selezionato") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_STATE, + "Salva uno stato nello slot selezionato") +MSG_HASH(MENU_ENUM_SUBLABEL_RESUME, + "Riprendi il contenuto corrente e chiude il menu rapido..") +MSG_HASH(MENU_ENUM_SUBLABEL_RESUME_CONTENT, + "Riprende il contenuto corrente e chiude il menu rapido") +MSG_HASH(MENU_ENUM_SUBLABEL_STATE_SLOT, + "Modifica lo slot di salvataggio selezionato.") +MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, + "Se viene caricato un salvataggio, il contenuto tornerà allo stato iniziale prima del caricamento") +MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, + "Se un salvataggio è stato sovrascritto, si ritorna allo stato del salvataggio precedente.") +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Servizio Retro Achievements. Per maggiori informazioni, visitare il sito http://retroachievements.org" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, + "Gestisce gli account correntemente configurati." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_META_REWIND, + "Gestisce le impostazioni di riavvolgimento.") +MSG_HASH(MENU_ENUM_SUBLABEL_RESTART_CONTENT, + "Riavvia il contenuto dall'inizio.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Salva un file di configurazione override che si applica a tutti i contenuti caricati con questo core. Avrà la precedenza sulla configurazione principale.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Salva un file di configurazione override che si applica solo al contenuto corrente. Avrà la precedenza sulla configurazione principale.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Imposta i codici cheat.") +MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_OPTIONS, + "Imposta gli shader per aumentare visivamente l'immagine.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, + "Modifica i controlli per il contenuto attualmente in esecuzione.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_OPTIONS, + "Modifica le opzioni per il contenuto attualmente in esecuzione.") +MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, + "Mostra le impostazioni avanzate per gli utenti esperti (nascosti per impostazione predefinita).") +MSG_HASH(MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, + "Esegue le attività su un thread separato.") +MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, + "Consente all'utente di rimuovere le voci dalla collezione.") +MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, + "Imposta la directory di sistema. I core possono richiedere questa directory per caricare BIOS, configurazioni specifiche del sistema, ecc.") +MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Imposta la directory di avvio per il filebrowser.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DIR, + "Di solito impostato dagli sviluppatori,perchè raggruppa le applicazioni libretro / RetroArch dove vengono visualizzate le loro attività." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, + "Directory dove vengono memorizzati gli sfondi caricati dinamicamente dal menu a seconda del contesto.") +MSG_HASH(MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, + "Qui vengono memorizzate miniature aggiuntive (boxarts / immagini , ecc.)" + ) +MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "Imposta la directory di avvio per il browser di configurazione del menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Il numero della latenza nei fotogrammi di input per il netplay da utilizzare per nascondere la latenza di rete. Riduce il jitter e rende il netplay meno intenso di CPU, a scapito di un ritardo di input notevole.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "L'intervallo della latenza nei fotogrammi di input che può essere utilizzato per nascondere la latenza di rete. Riduce il jitter e rende il netplay meno intenso di CPU, a scapito di un imprevisto ritardo di input.") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, + "Cicli del disco corrente. Se il disco è inserito, espellerà il disco. Se il disco non è stato inserito, verrà inserito. ") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_INDEX, + "Cambia l'indice del disco.") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_OPTIONS, + "Gestione delle immagini disco.") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, + "Seleziona un'immagine disco da inserire") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, + "Assicura che i fotogrammi siano attivi all'interno del menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_THEME, + "Seleziona un tema diverso per l'icona. Le modifiche avranno effetto dopo il riavvio del programma.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, + "Abilita le ombre per tutte le icone. Questo avrà un minore rendimento") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, + "Seleziona uno sfondo differente con colore sfumato nel tema.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, + "Modifica l'opacità dello sfondo") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, + "Seleziona un colore di sfondo differente nel tema.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, + "Seleziona un effetto con sfondo animato. Può essere intenso in base alla GPU a seconda dell'effetto. Se le prestazioni sono insoddisfacenti, disattivare o tornare ad un effetto più semplice.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_FONT, + "Seleziona un altro tipo di carattere principale da utilizzare dal menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_FAVORITES, + "Mostra la colonna preferiti all'interno del menu principale.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_IMAGES, + "Mostra la colonna immagini all'interno del menu principale.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_MUSIC, + "Mostra la colonna musica all'interno del menu principale.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_VIDEO, + "Mostra la colonna video all'interno del menu principale") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_NETPLAY, + "Mostra la colonna camere netplay all'interno del menu principale") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_SETTINGS, + "Mostra la colonna impostazioni all'interno del menu principale") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_HISTORY, + "Mostra la colonna cronologia all'interno del menu principale.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_ADD, + "Mostra la colonna importa contenuto all'interno del menu principale.") +MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, + "Mostra la schermata di avvio nel menu. Questo viene automaticamente impostato su off dopo l'avvio del programma per la prima volta.") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, + "Modifica l'opacità dell'intestazione grafica.") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, + "Modifica l'opacità grafica a piè di pagina.") +MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, + "Il menu normalmente si scala dinamicamente. Se si desidera impostare una dimensione specifica, abilitare l'opzione.") +MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, + "Impostare qui la dimensione della scala personalizzata. NOTA: è necessario abilitare l'opzione 'DPI Override' per scalare a questa dimensione.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, + "Salva tutti i file scaricati in questa directory.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, + "Salva tutti i controlli remappati in questa directory.") +MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, + "Directory in cui il programma cerca contenuti / core.") +MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, + "Qui vengono memorizzati i file di informazioni dei core/applicazioni.") +MSG_HASH(MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, + "Se un joypad viene collegato, verrà automaticamente configurato se all'interno di questa directory è presente un file di configurazione corrispondente.") +MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, + "Salva tutte le collezioni in questa directory.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, + "Se non viene impostata una directory, il contenuto estratto temporaneamente (ad esempio dagli archivi) verrà estratto in questa directory." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, + "Le query salvate vengono memorizzate in questa directory.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, + "I database sono memorizzati in questa directory." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, + "Questa posizione viene interrogata per impostazione predefinita quando le interfacce di menu cercano asset caricabili, ecc." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, + "Salva tutti i file di salvataggio in questa directory. Se non è impostato, cercherà di salvare nella directory di lavoro del file di contenuto.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, + "Salva tutti gli stati di salvataggio in questa directory. Se non è impostato, cercherà di salvare nella directory di lavoro del file di contenuto.") +MSG_HASH(MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, + "Directory per scaricare screenshots su.") +MSG_HASH(MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, + "Definisce una directory in cui l'overlay viene mantenuto per un facile accesso.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, + "I file cheat sono conservati qui." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, + "Directory in cui vengono conservati i file di filtro audio DSP." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, + "Directory dove vengono conservati i file del filtro video basati su CPU." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, + "Definisce una directory in cui i file shader del video basati su GPU vengono mantenuti per un facile accesso.") +MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, + "Le registrazioni saranno scaricate in questa directory.") +MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, + "Le configurazioni di registrazione saranno conservate qui.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, + "Seleziona un altro tipo di carattere per le notifiche sullo schermo.") +MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, + "Le modifiche alla configurazione shader avranno effetto immediatamente. Utilizzare questo se hai modificato gli shader, filtri, scala FBO, ecc.") +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, + "Aumenta o diminuisce la quantità di shader pipeline. È possibile legare uno shader separato a ciascun passaggio di pipeline e configurare la sua scala e il suo filtro." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, + "Carica uno shader preimpostato. Lo shader pipeline sarà automaticamente impostato.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, + "Save the current shader settings as a new shader preset.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, + "Salva le impostazioni dello shader corrente come impostazioni predefinite per questa applicazione/core.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, + "Salva le impostazioni dello shader corrente come impostazioni predefinite per il contenuto.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, + "Consente di modificare direttamente lo shader corrente. Le modifiche non verranno salvate nel file preimpostato.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, + "Modifica le preimpostazioni dello shader attualmente utilizzato nel menu.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, + "Aumenta o diminuisce la quantità di cheat." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, + "Le modifiche sui cheat avranno effetto immediato.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, + "Carica un file cheat ." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, + "Salva i cheat correnti come file di salvataggio." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, + "Accesso rapido a tutte le impostazioni in-game") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INFORMATION, + "Visualizza le informazioni relative all'applicazione/core.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, + "Floating point value for video aspect ratio (width / height), used if the Aspect Ratio is set to 'Config'.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Altezza di visualizzazione personalizzata utilizzata se il Rapporto d'aspetto è impostato su 'Custom'.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Larghezza di visualizzazione personalizzata utilizzata se il Rapporto d'aspetto è impostato su 'Custom'.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Offset di visualizzazione personalizzata utilizzata per definire la posizione dell'asse X di visualizzazione. Queste vengono ignorate se è abilitata l'opzione 'Integer Scale' e sarà centrata automaticamente.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Offset di visualizzazione personalizzata utilizzata per definire la posizione dell'asse Y di visualizzazione. Queste vengono ignorate se è abilitata l'opzione 'Integer Scale' e sarà centrata automaticamente.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, + "Usa Relay Server") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, + "Inoltra le connessioni da netplay attraverso un server man-in-the-middle . Utile se l'host è dietro un firewall o ha problemi NAT/UPnP") +MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, + "Aggiungi al mixer") +MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, + "Aggiungi al mixer") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Filtra per core corrente") MSG_HASH( MSG_AUDIO_MIXER_VOLUME, - "Global audio mixer volume" + "Volume globale del mixer audio" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, - "Global audio mixer volume (in dB). 0 dB is normal volume, and no gain is applied." + "Volume globale del mixer audio(in dB). 0 dB è il volume normale e non viene applicato alcun guadagno." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, - "Audio Mixer Volume Level (dB)" + "Livello del Volume del mixer audio (dB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Audio Mixer Mute" + "Disattiva Mixer Audio" ) MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Mute/unmute mixer audio.") -MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, - "Show Online Updater") + "Attiva/disattiva mixer audio.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, + "Visualizza Aggiorna Online") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, - "Show/hide the 'Online Updater' option.") + "Visualizza/Nasconde l'opzione 'Aggiorna Online") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, + "Opzioni di visualizzazione") +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, + "Mostra o nascondi gli elementi nella schermata del menu." + ) MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, - "Show Core Updater") + "Visualizza Carica Core") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, - "Show/hide the ability to update cores (and core info files).") + "Mostra / nasconde la possibilità di aggiornare i core (e i file di informazioni principali).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Cancella core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Rimuove questo core dal disco.") +MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, + "Rinomina la voce del titolo.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rinomina") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Opacità Framebuffer") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modifica l'opacità del framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Preferiti") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Qui verrà visualizzato il contenuto che hai aggiunto a 'Preferiti'.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Musica") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Qui verrà visualizzata la musica che è stata eseguita in precedenza.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Immmagini") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Qui vengono inseriti le immagini precedentemente visualizzate.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Qui vengono visualizzati i video precedentemente riprodotti.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Icone del Menu") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Abilita/disabilita le icone del menu visualizzate sul lato sinistro di ogni voce.") diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index e262c30da1..3b7053e440 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -2079,6 +2079,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Cheat Filename") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Preset Filename") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "インタフェース") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -2997,3 +2999,35 @@ MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, "コンテンツをスキャンするための準備中") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index 90b7052960..a9cc790329 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -2033,6 +2033,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "치트 파일명") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "프리셋 파일명") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "인터페이스") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -2969,7 +2971,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "뷰포트의 Y축 위치를 정의하는 데 사용되는 사용자 뷰포트 오프셋. '정수 단위 화면 크기'가 활성화 된 경우 무시되고 자동으로 중앙이 됩니다.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -3004,3 +3006,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 4838976479..7069e2d7f3 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -229,6 +229,14 @@ MSG_HASH(MENU_ENUM_LABEL_DATABASE_MANAGER, "database_manager") MSG_HASH(MENU_ENUM_LABEL_DATABASE_MANAGER_LIST, "database_manager_list") +MSG_HASH(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST, + "deferred_favorites_list") +MSG_HASH(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST, + "deferred_images_list") +MSG_HASH(MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST, + "deferred_music_list") +MSG_HASH(MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST, + "deferred_video_list") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_NETPLAY, "deferred_netplay") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_MUSIC, @@ -397,6 +405,8 @@ MSG_HASH(MENU_ENUM_LABEL_FILE_BROWSER_SHADER, "file_browser_shader") MSG_HASH(MENU_ENUM_LABEL_FILE_BROWSER_SHADER_PRESET, "file_browser_shader_preset") +MSG_HASH(MENU_ENUM_LABEL_FAVORITES_TAB, + "favorites_tab") MSG_HASH(MENU_ENUM_LABEL_FPS_SHOW, "fps_show") MSG_HASH(MENU_ENUM_LABEL_FRAME_THROTTLE_ENABLE, @@ -479,6 +489,10 @@ MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_ENABLE, "input_overlay_enable") MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU, "overlay_hide_in_menu") +MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "overlay_show_physical_inputs") +MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "overlay_show_physical_inputs_port") MSG_HASH(MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE, "input_player%u_analog_dpad_mode") MSG_HASH(MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR, @@ -549,6 +563,8 @@ MSG_HASH(MENU_ENUM_LABEL_LOAD_ARCHIVE_DETECT_CORE, "load_archive_detect_core") MSG_HASH(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY, "load_recent") +MSG_HASH(MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL, + "load_special") MSG_HASH(MENU_ENUM_LABEL_LOAD_CONTENT_LIST, "load_content") MSG_HASH(MENU_ENUM_LABEL_LOAD_STATE, @@ -579,6 +595,8 @@ MSG_HASH(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, "menu_file_browser_settings") MSG_HASH(MENU_ENUM_LABEL_MENU_LINEAR_FILTER, "menu_linear_filter") +MSG_HASH(MENU_ENUM_LABEL_MENU_HORIZONTAL_ANIMATION, + "menu_horizontal_animation") MSG_HASH(MENU_ENUM_LABEL_MENU_SETTINGS, "menu_settings") MSG_HASH(MENU_ENUM_LABEL_MENU_WALLPAPER, @@ -819,6 +837,10 @@ MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE, "remap_file_save_core") MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME, "remap_file_save_game") +MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE, + "remap_file_remove_core") +MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME, + "remap_file_remove_game") MSG_HASH(MENU_ENUM_LABEL_RESTART_CONTENT, "restart_content") MSG_HASH(MENU_ENUM_LABEL_RESTART_RETROARCH, @@ -843,6 +865,8 @@ MSG_HASH(MENU_ENUM_LABEL_RGUI_CONFIG_DIRECTORY, "rgui_config_directory") MSG_HASH(MENU_ENUM_LABEL_RGUI_SHOW_START_SCREEN, "rgui_show_start_screen") +MSG_HASH(MENU_ENUM_LABEL_ADD_TO_FAVORITES, + "favorites_add") MSG_HASH(MENU_ENUM_LABEL_RUN, "collection") MSG_HASH(MENU_ENUM_LABEL_RUN_MUSIC, @@ -907,6 +931,14 @@ MSG_HASH(MENU_ENUM_LABEL_SORT_SAVEFILES_ENABLE, "sort_savefiles_enable") MSG_HASH(MENU_ENUM_LABEL_SORT_SAVESTATES_ENABLE, "sort_savestates_enable") +MSG_HASH(MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "savefiles_in_content_dir_enable") +MSG_HASH(MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "savestates_in_content_dir_enable") +MSG_HASH(MENU_ENUM_LABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "systemfiles_in_content_dir_enable") +MSG_HASH(MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "screenshots_in_content_dir_enable") MSG_HASH(MENU_ENUM_LABEL_SSH_ENABLE, "ssh_enable") MSG_HASH(MENU_ENUM_LABEL_START_CORE, @@ -1131,6 +1163,8 @@ MSG_HASH(MENU_ENUM_LABEL_XMB_SHOW_HISTORY, "xmb_show_history") MSG_HASH(MENU_ENUM_LABEL_XMB_SHOW_ADD, "xmb_show_add") +MSG_HASH(MENU_ENUM_LABEL_XMB_SHOW_FAVORITES, + "xmb_show_favorites") MSG_HASH(MENU_ENUM_LABEL_XMB_SHOW_IMAGES, "xmb_show_images") MSG_HASH(MENU_ENUM_LABEL_XMB_SHOW_MUSIC, @@ -1247,3 +1281,19 @@ MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, "menu_show_online_updater") MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_CORE_UPDATER, "menu_show_core_updater") +MSG_HASH(MENU_ENUM_LABEL_CORE_DELETE, + "core_delete") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "playlist_entry_rename") +MSG_HASH(MENU_ENUM_LABEL_MENU_FRAMEBUFFER_OPACITY, + "menu_framebuffer_opacity") +MSG_HASH(MENU_ENUM_LABEL_GOTO_FAVORITES, + "goto_favorites") +MSG_HASH(MENU_ENUM_LABEL_GOTO_MUSIC, + "goto_music") +MSG_HASH(MENU_ENUM_LABEL_GOTO_IMAGES, + "goto_images") +MSG_HASH(MENU_ENUM_LABEL_GOTO_VIDEO, + "goto_video") +MSG_HASH(MENU_ENUM_LABEL_MATERIALUI_ICONS_ENABLE, + "materialui_icons_enable") diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index 3c04639de3..939ac2016b 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -4,15 +4,15 @@ MSG_HASH( ) MSG_HASH( MSG_UNKNOWN_COMPILER, - "Unknown compiler" + "Onbekende compiler" ) MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT, - "Device disconnected from port" + "Apparaat ontkoppeld van poprt" ) MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "Unknown netplay command received" + "Onbekend netplay commando ontvangen" ) MSG_HASH( MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, @@ -56,15 +56,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "Improves performance at the cost of latency and more video stuttering. Use only if you cannot obtain full speed otherwise." + "Verbetert prestaties ten kosten van latentie en meer video stotteringen. Gebruik dit enkel als het niet mogelijk is om full speed te bereiken zonder dit te activeren." ) MSG_HASH( MSG_AUDIO_VOLUME, - "Audio volume" + "Geluidsvolume" ) MSG_HASH( MSG_AUTODETECT, - "Autodetect" + "Autodetecteren" ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FROM, @@ -76,11 +76,11 @@ MSG_HASH( ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "Connecting to netplay host" + "Verbinden met netplay host" ) MSG_HASH( MSG_CONNECTING_TO_PORT, - "Connecting to port" + "Verbinding maken met port" ) MSG_HASH( MSG_CONNECTION_SLOT, @@ -116,12 +116,12 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Achievement List" + "Achievements Lijst" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Achievement List (Hardcore)" + "Achievements Lijst (Hardcore)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, @@ -261,11 +261,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "Basic menu controls" + "Basis menu besturing" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, - "Confirm/OK" + "Bevestigen/OK" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, @@ -273,11 +273,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, - "Quit" + "Afsluiten" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Scroll Up" + "Omhoog scrollen" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, @@ -297,7 +297,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Bluetooth Enable" + "Bluetooth Activeren" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, @@ -329,11 +329,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE, - "Cheat File" + "Cheat Bestand" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Load Cheat File" + "Laad Cheat Bestand" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, @@ -365,7 +365,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - "Test Unofficial Achievements" + "Test Onofficiele Achievements" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, @@ -519,7 +519,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, "Dynamische Wallpapers") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Achievements Aciveren") + "Achievements Activeren") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, "Menu entry hover kleur") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, @@ -627,37 +627,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, "Keyboard Gamepad Mapping Enable") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, - "A button (right)") + "A knop (right)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, - "B button (down)") + "B knop (down)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, "Down D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, - "L2 button (trigger)") + "L2 knop (trigger)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, - "L3 button (thumb)") + "L3 knop (thumb)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, - "L button (shoulder)") + "L knop (shoulder)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, "Left D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, - "R2 button (trigger)") + "R2 knop (trigger)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, - "R3 button (thumb)") + "R3 knop (thumb)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, - "R button (shoulder)") + "R knop (shoulder)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, "Right D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, - "Select button") + "Select knop") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, - "Start button") + "Start knop") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, "Up D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, - "X button (top)") + "X knop (top)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, - "Y button (left)") + "Y knop (left)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, "(Key: %s)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, @@ -861,7 +861,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Menu Linear Filter") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menu") + "Appearance") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, "Achtergrond") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, @@ -1667,7 +1667,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, "Configure hotkey settings.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Gamepad button combination to toggle menu.") + "Gamepad knoppencombination to toggle menu.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, "Adjusts settings for joypads, keyboard and mouse.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, @@ -1693,7 +1693,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, "Sets the window size relative to the core viewport size. Alternatively you can set a window width and height below for a fixed window size") MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "Sets the language of the interface.") + "Stel de taal in van de gebruikersinterface.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, "Inserts a black frame inbetween frames. Useful for users of 120 Hz screens who want to play 60 Hz material with eliminated ghosting.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, @@ -1793,7 +1793,7 @@ MSG_HASH(MSG_DISK_EJECTED, MSG_HASH(MSG_DOWNLOADING, "Downloading") MSG_HASH(MSG_DOWNLOAD_FAILED, - "Download failed") + "Download mislukt") MSG_HASH(MSG_ERROR, "Error") MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, @@ -1805,17 +1805,17 @@ MSG_HASH(MSG_ERROR_PARSING_ARGUMENTS, MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, "Error saving core options file.") MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, - "Error saving remap file.") + "Fout is opgetreden tijdens het opslaan van remap bestand.") MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, - "Error saving shader preset.") + "Fout is opgetreden tijdens het opslaan van shader preset.") MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, - "External Application Dir") + "Externe Applicatie Dir") MSG_HASH(MSG_EXTRACTING, - "Extracting") + "Uitpakken") MSG_HASH(MSG_EXTRACTING_FILE, - "Extracting file") + "Uitpakken van bestand") MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, - "Failed saving config to") + "Fout is opgetrijdens tijdens het opslaan van configuratie naar ") MSG_HASH(MSG_FAILED_TO, "Failed to") MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, @@ -1920,6 +1920,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Cheat Filename") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Preset Filename") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Interface") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -1937,11 +1939,11 @@ MSG_HASH(MSG_IN_MEGABYTES, MSG_HASH(MSG_LIBRETRO_ABI_BREAK, "is compiled against a different version of libretro than this libretro implementation.") MSG_HASH(MSG_LIBRETRO_FRONTEND, - "Frontend for libretro") + "Frontend voor libretro") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, - "Loaded state from slot #%d.") + "State geladen van slot #%d.") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, - "Loaded state from slot #-1 (auto).") + "State geladen van slot #-1 (auto).") MSG_HASH(MSG_LOADING, "Laden") MSG_HASH(MSG_FIRMWARE, @@ -1953,7 +1955,7 @@ MSG_HASH(MSG_LOADING_HISTORY_FILE, MSG_HASH(MSG_LOADING_STATE, "Loading state") MSG_HASH(MSG_MEMORY, - "Memory") + "Geheugen") MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, "Movie file is not a valid BSV1 file.") MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, @@ -1975,13 +1977,13 @@ MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, "Overrides saved successfully.") MSG_HASH(MSG_PAUSED, - "Paused.") + "Gepauzeerd.") MSG_HASH(MSG_PROGRAM, "RetroArch") MSG_HASH(MSG_READING_FIRST_DATA_TRACK, "Reading first data track...") MSG_HASH(MSG_RECEIVED, - "received") + "ontvangen") MSG_HASH(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, "Recording terminated due to resize.") MSG_HASH(MSG_RECORDING_TO, @@ -2753,10 +2755,10 @@ MSG_HASH( "If set to a directory, content which is temporarily extracted (e.g. from archives) will be extracted to this directory." ) MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, - "Saved queries are stored to this directory.") + "Bewaarde queries worden in deze directory opgeslagen.") MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, - "Databases are stored to this directory." + "Databases worden in deze directory opgeslagen." ) MSG_HASH( MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, @@ -2837,22 +2839,22 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Gebruik Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, - "Add to mixer") + "Aan audio mixer toevoegen") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, - "Add to mixer") + "Aan audio mixer toevoegen") MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filter by current core") MSG_HASH( MSG_AUDIO_MIXER_VOLUME, - "Global audio mixer volume" + "Globale volume voor audio mixer" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, - "Global audio mixer volume (in dB). 0 dB is normal volume, and no gain is applied." + "Globale volume voor audio mixer (in dB uitgedrukt). 0 dB is het normale geluidsniveau." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, @@ -2865,10 +2867,44 @@ MSG_HASH( MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Mute/unmute mixer audio.") MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, - "Show Online Updater") + "Online Updater Weergeven") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, "Show/hide the 'Online Updater' option.") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 7a2b5636f7..03bf155246 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -1061,7 +1061,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Filtro Linear de Menu" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menu" + "Appearance" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, "Plano de Fundo" @@ -2725,6 +2725,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Nome de Arquivo de Predefinição" ) +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Interface" ) @@ -3852,3 +3854,35 @@ MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, ) MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, "Preparando a busca de conteúdo...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_pt_pt.h b/intl/msg_hash_pt_pt.h index 42204ab2cf..c5cd817d1c 100644 --- a/intl/msg_hash_pt_pt.h +++ b/intl/msg_hash_pt_pt.h @@ -936,7 +936,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Filtro de menu Linear") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menu") + "Appearance") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, "Fundo") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, @@ -2023,6 +2023,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Nome do Arquivo de Trapaça") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Nome de Arquivo Pré-Definido") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Interface") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -2944,7 +2946,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Personalizar o deslocamento da janela de exibição usada para definir o eixo-Y da janela de exibição. Estes serão ignorados se a 'Escala Inteira' estiver habilitada. Então ele será centralizado automaticamente.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -2979,3 +2981,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index d1f777de78..2da0888b58 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -31,9 +31,13 @@ MSG_HASH( MSG_GOT_CONNECTION_FROM_NAME, "Установленно соединение с: \"%s (%s)\"" ) +MSG_HASH( + MSG_PUBLIC_ADDRESS, + "Публичный адрес" + ) MSG_HASH( MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "Нет аргументов и встроенного меню,отображается справка..." + "Нет аргументов и встроенного меню, отображается справка..." ) MSG_HASH( MSG_NETPLAY_USERS_HAS_FLIPPED, @@ -47,9 +51,69 @@ MSG_HASH( MSG_WAITING_FOR_CLIENT, "Ожидание клиента ..." ) +MSG_HASH( + MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, + "Вы покинули игру" + ) +MSG_HASH( + MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, + "Вы присоединились под именем %d" + ) +MSG_HASH( + MSG_NETPLAY_IMPLEMENTATIONS_DIFFER, + "Реализации различаются. Убедитесь, что вы используете точные версии RetroArch и выбранного ядра." + ) +MSG_HASH( + MSG_NETPLAY_ENDIAN_DEPENDENT, + "Выбранное ядро не поддерживает архитектуру netplay между этими системами" + ) +MSG_HASH( + MSG_NETPLAY_PLATFORM_DEPENDENT, + "Выбранное ядро не поддерживает архитектуру netplay" + ) +MSG_HASH( + MSG_NETPLAY_ENTER_PASSWORD, + "Введите пароль от сервера netplay:" + ) +MSG_HASH( + MSG_NETPLAY_INCORRECT_PASSWORD, + "Неверный пароль" + ) +MSG_HASH( + MSG_NETPLAY_SERVER_NAMED_HANGUP, + "\"%s\" отключился" + ) +MSG_HASH( + MSG_NETPLAY_SERVER_HANGUP, + "Клиент netplay отключен" + ) +MSG_HASH( + MSG_NETPLAY_CLIENT_HANGUP, + "Netplay отключен" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, + "У вас недостаточно прав чтобы играть" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, + "Недостаточно свободных слотов для игры" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY, + "Невозможно переключиться в режим игры" + ) +MSG_HASH( + MSG_NETPLAY_PEER_PAUSED, + "Netplay peer \"%s\" paused" + ) +MSG_HASH( + MSG_NETPLAY_CHANGED_NICK, + "Ваше имя изменился на \"%s\"" + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Предоставьте аппаратно-рендерированным ядрам собственный контекст.Избегайте принятия изменений состояния оборудования между кадрами." + "Предоставьте аппаратно-рендерированным ядрам собственный контекст. Избегайте принятия изменений состояния оборудования между кадрами." ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, @@ -123,8 +187,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, "Список достижений" ) - - MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, "Список достижений (Hardcore)" @@ -141,6 +203,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TAB, "Импорт содержимого" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, + "Сетевая игра" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, "Спрашивать" @@ -213,6 +279,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Уровень громкости звука (dB)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_EXCLUSIVE_MODE, + "WASAPI Exclusive Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_FLOAT_FORMAT, + "WASAPI Float Format" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "WASAPI Shared Buffer Length" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, "Интервал авто-сохранений" @@ -303,7 +381,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Bluetooth Включить" + "Включить Bluetooth" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, @@ -373,6 +451,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, "Тестовые Неофициальные Достижения" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, + "Achievements Verbose Mode" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, "Разблокированные достижения:" @@ -416,8 +498,10 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, "Размер списка истории") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, + "Allow to remove entries") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "Выйти из меню") + "Внутреигровое меню") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, "Загрузки") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, @@ -427,9 +511,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, "Основной счётчик") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, - "Отобразить имя основного средства") + "Показать название ядра") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, - "Основная информация") + "Информация о ядре") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, "Авторы") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, @@ -520,6 +604,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, "Драйвер") MSG_HASH(MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, "Загрузка макета при выключении ядра") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, + "Check for Missing Firmware Before Loading") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Динамические обои") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, @@ -579,7 +665,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, "Аналого-цифровой тип") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "Все пользователи управляющие меню") + "Все пользователи управляют меню") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, "Левый аналог ось - X") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, @@ -609,7 +695,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, "Мертвая зона у стиков") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "Сменить функции кнопок") + "Сменить функции кнопок OK и Отмена") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, "Скрепить всё") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, @@ -624,8 +710,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, "Индекс устройства") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, "Тип устройства") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, + "Mouse Index") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, - "Ввод драйвера") + "Драйвер ввода") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, "Рабочий цикл") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, @@ -665,7 +753,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, "Кнопка Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, - "(Ключ: %s)") + "(Клавиша: %s)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, "Тип отображения клавиатуры для геймпада") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, @@ -685,7 +773,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, "Предыдущий диск") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, - "EВключить горячие клавиши") + "Включить горячие клавиши") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, "Ускоренная перемотка вперед") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, @@ -696,8 +784,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, "На весь экран") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Переключатель мыши") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, + "Game focus toggle") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "Состояние загрузки") + "Загрузить сохранение игры") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "Переключение меню") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, @@ -706,6 +796,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, "Отключения звука") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, "Netplay отразить пользователей") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, + "Netplay toggle play/spectate mode") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, "Переключение экранной клавиатуры") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, @@ -713,13 +805,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "Приостановить переключение") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, - "Выход из RetroArch") + "Выйти из RetroArch") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, "Сбросить игру") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, "Перемотка назад") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "Сохранить состояние") + "Сохранить игру") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, "Сделать скриншот") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, @@ -803,7 +895,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL, MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL, "Portuguese (Portugal)") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, - "Russian") + "Русский") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH, "Spanish") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, @@ -813,7 +905,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, "Ядро") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "Ядро инфо") + "Информация ядра") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, "Уровень ведения журнала") MSG_HASH(MENU_ENUM_LABEL_VALUE_LINEAR, @@ -849,7 +941,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, "Зелёный") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, - "Щит") + "NVIDIA Shield") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, "Красный") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, @@ -890,8 +982,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NEAREST, "Ближайший") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY, "Netplay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, + "Allow Slave-Mode Clients") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, "Проверка фреймов Netplay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Input Latency Frames") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Input Latency Frames Range") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CLIENT_SWAP_INPUT, "Netplay P2 использует C1") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, @@ -903,21 +1001,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, "Подключение к Netplay-хосту") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Старт хостинг") + "Запустить Netplay-хост") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Stop netplay host") + "Остановить Netplay-хост") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, "Адрес сервера") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, + "Scan local network") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, "Включить клиент Netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "Имя пользователя") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, + "Пароль сервера") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + "Публично анонсировать Netplay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, + "Disallow Non-Slave-Mode Clients") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, "Настройки Netplay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, + "Netplay режим наблюдателя") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, + "Netplay Stateless Mode") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, + "Server Spectate-Only Password") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, "Включить режим зрителя в Netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, "Порт Netplay TCP / UDP") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, + "Netplay NAT Traversal") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, "Сетевые команды") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, @@ -954,6 +1068,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, "Нет информации.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS, "Нет элементов.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, + "No netplay hosts found.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, + "No networks found.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, "Нет счетчиков производительности.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, @@ -989,11 +1107,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, "Наложение") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, - "Наложение преднастроек") + "Непрозрачность наложения") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, - "Масштаб наложения") + "Преднастройка наложения") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, - "Overlay Scale") + "Масштаб наложения") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, "Экранное наложение") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, @@ -1075,7 +1193,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, "SHA1") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, - "Запустить контент") + "Запустить игру") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, "Рейтинг TGDB") MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, @@ -1138,6 +1256,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, "Правый аналог") MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, "Запустить") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_MUSIC, + "Запустить") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, "Включить SAMBA") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, @@ -1150,6 +1270,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Автосохранение") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, "Сохранить состояние") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, + "Savestate Thumbnails") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, "Сохранить текущую конфигурацию") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, @@ -1161,7 +1283,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, "Сохранить состояние") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, - "Сохранить") + "Сохранения") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, "Сканировать каталог") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, @@ -1205,7 +1327,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, "Сохранить сортировку в папках") MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, - "Sort Savestates In Folders") + "Сортировать сохранения в папках") MSG_HASH(MENU_ENUM_LABEL_VALUE_SSH_ENABLE, "SSH включён") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, @@ -1254,6 +1376,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, "Отображать ширину (mm)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, "Поддержка DirectSound") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, + "Поддержка WASAPI") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, "Поддержка динамических библиотек") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, @@ -1282,6 +1406,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT, "Поддержка JACK") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT, "поддержка KMS/EGL") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION, + "Lakka Version") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, "Поддержка LibretroDB") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, @@ -1375,13 +1501,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, "Обновление эскизов") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, - "Boxarts") + "Артбоксы") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, "Скриншоты") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, "Экраны заголовков") MSG_HASH(MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, - "Показывать время / дата") + "Показать время/дату") MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, "Цвет заголовков в меню") MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, @@ -1423,11 +1549,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, "Обновить сленговые шейдеры") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER, - "Пользователь") + "Аккаунт") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, "Интерфейс пользователя") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, - "Language") + "Язык") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_SETTINGS, "Пользователь") MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, @@ -1438,6 +1564,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, "<Использовать этот катало>") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, "Разрешить вращение") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO, + "Config Aspect Ratio") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, "Автоотношение сторон") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, @@ -1457,9 +1585,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, "Мерцающий фильтр") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, - "Onscreen Notification включить") + "Включить экранные уведомления") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, - "Экранный шрифт уведомления") + "Шрифт экранного уведомления") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "Размер уведомлений на экране") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, @@ -1483,9 +1611,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Максимальное количество образов свопчейнов") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, - "Позиция X по уведомлению на экране") + "Позиция уведомления на экране по оси X") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, - "Позиция Y на экранном уведомлении") + "Позиция уведомления на экране по оси Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, "Индекс монитора") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, @@ -1546,6 +1674,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, "Вертикальная синхронизация (Vsync)") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, "Полноэкранный режим") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, + "Ширина окна") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, + "Высота окна") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, + "Полноэкранная ширина") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, + "Полноэкранная высота") MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, "Wi-Fi драйвер") MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, @@ -1593,21 +1729,25 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, "Вулканический красный") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, - "Шейдерный канал меню") + "Шейдерный фон меню") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, "Масштаб в меню") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, - "Тени иконок включена") + "Отображение теней у иконок") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_HISTORY, - "Показать вкладку история просмотров") + "Показать вкладку История просмотров") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_ADD, + "Показать вкладку Импорт контента") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_IMAGES, - "Показать вкладку изображение") + "Показать вкладку Изображение") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_MUSIC, - "Показать вкладку музыка") + "Показать вкладку Музыка") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_SETTINGS, - "Показать вкладку настройки") + "Показать вкладку Настройки") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_VIDEO, - "Показать вкладку видео") + "Показать вкладку Видео") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_NETPLAY, + "Показать вкладку Сетевая игра") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_THEME, "Тема значка меню") MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, @@ -1620,6 +1760,8 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, "Включение или отключение неофициальных достижений и / или бета-функций в целях тестирования.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, "Включить или отключить сохранения, читы, перемотка назад, перемотка вперед, пауза и замедленное воспроизведение для всех игр.") +MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, + "Enable or disable OSD verbosity for achievements.") MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, "Изменение драйверов для этой системы.") MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, @@ -1676,8 +1818,10 @@ MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, "Включить или отключить ведение журнала в терминале.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, "Присоединиться или создать сеанс netplay.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, + "Поиск и подключение к серверу по локальной сети.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Отображать информацию о ядре, сети и системе.") + "Показать информацию о ядре, сети и системе.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "Загрузите надстройки, компоненты и содержимое для RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, @@ -1690,6 +1834,8 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, "Включить или отключить удаленный доступ к командной строке.") MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, "Запрещается активация заставки вашей системы.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, + "Sets the window size relative to the core viewport size. Alternatively, you can set a window width and height below for a fixed window size.") MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, "Устанавливает язык интерфейса.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, @@ -1908,6 +2054,10 @@ MSG_HASH(MSG_GOT_INVALID_DISK_INDEX, "Задан неверный номер диска.") MSG_HASH(MSG_GRAB_MOUSE_STATE, "Режим перехвата мыши") +MSG_HASH(MSG_GAME_FOCUS_ON, + "Game focus on") +MSG_HASH(MSG_GAME_FOCUS_OFF, + "Game focus off") MSG_HASH(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, "Ядро использует аппаратный рендеринг. Включите запись с GPU.") MSG_HASH(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, @@ -1918,6 +2068,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Имя чита") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Имя настроек") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Переименовать заголовок") MSG_HASH(MSG_INTERFACE, "Интерфейс") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -2122,6 +2274,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_VOLUME, "Громкость звука (в дБ). 0 дБ - это нормальный уровень громкости, при этом не применяется усиление." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_EXCLUSIVE_MODE, + "Allow the WASAPI driver to take exclusive control of the audio device. If disabled, it will use shared mode instead." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_FLOAT_FORMAT, + "Use float format for the WASAPI driver, if supported by your audio device." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH, + "The intermediate buffer length (in frames) when using the WASAPI driver in shared mode." + ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, "Синхронизировать звук. Рекомендуется." @@ -2236,7 +2400,15 @@ MSG_HASH(MENU_ENUM_LABEL_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, MSG_HASH(MENU_ENUM_LABEL_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, "Database - Filter : Edge Magazine Rating") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, - "Database Info") + "Информация базы данных") +MSG_HASH(MSG_WIFI_SCAN_COMPLETE, + "Сканирование Wi-Fi успешно завершен.") +MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS, + "Scanning wireless networks...") +MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, + "Netplay scan complete.") +MSG_HASH(MSG_NETPLAY_LAN_SCANNING, + "Scanning for netplay hosts...") MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, "Ставить на паузу когда окно теряет фокус.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, @@ -2251,6 +2423,22 @@ MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, "Использовать управление в меню, такое же как в игре (для клавиатуры).") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, "Показывать сообщения на экране.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, + "User %d Remote Enable") +MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, + "Показать заряд батареи") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FILE, + "Выбрать файл") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, + "Выбрать файл с коллекции") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, + "Filter") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, + "Scale") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, + "Netplay will start when content is loaded.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, + "Couldn't find a suitable core or content file, load manually.") MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, "Просмотр URL" @@ -2266,37 +2454,37 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, "Bokeh") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Refresh Room List") + "Обновить список комнат") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, - "Nickname: %s") + "Имя: %s") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, - "Nickname (lan): %s") + "Имя (lan): %s") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, - "Compatible content found") + "Найден совместимый контент") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, - "Cuts off a few pixels around the edges of the image customarily left blank by developers which sometimes also contain garbage pixels.") + "Отрезает несколько пикселей вокруг краев экрана, обычно оставленными пустыми разработчиками, которые иногда содержат лишь мусор.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, - "Adds a slight blur to the image to take the edge off of the hard pixel edges. This option has very little impact on performance.") + "Добавляет небольшое смазывание к изображению, чтобы избавиться от острых пикселей. Эта настройка мало влияет на производительность.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, - "Apply a CPU-powered video filter. NOTE: Might come at a high performance cost. Some video filters might only work for cores that use 32bit or 16bit color.") + "Применяется CPU-powered видеофильтр. ПРИМЕЧАНИЕ: Возможна высокая нагрузка на производительность. Некоторые фильтры могут работать только на некоторых ядер, которые используют 32bit или 16bit палитру.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, - "Input the username of your Retro Achievements account.") + "Введите имя пользователя от вашего аккаунта Retro Achievements.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, - "Input the password of your Retro Achievements account.") + "Введите пароль от вашего аккаунта Retro Achievements.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, - "Input your user name here. This will be used for netplay sessions, among other things.") + "Введите ваш никнейм. Он будет использоваться в netplay сесиях и т.д.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, "Capture the image after filters (but not shaders) are applied. Your video will look as fancy as what you see on your screen.") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_LIST, - "Select which core to use.") + "Выберите, какое ядро использовать.") MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, - "Select which content to start.") + "Выберите, какой контент запустить.") MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, - "Show network interface(s) and associated IP addresses.") + "Показать сетевые интерфейсы и ассоциированные IP адреса.") MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, - "Show information specific to the device.") + "Показать информацию, относящуюся к устройству.") MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, - "Quit the program.") + "Закрыть программу.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, "Set the custom width size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, @@ -2379,15 +2567,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatically makes a savestate at the end of RetroArch's runtime. RetroArch will automatically load this savestate if 'Auto Load State' is enabled." + "Автоматически сохранять игру при выходе. RetroArch загрузит это сохранение, если включена 'Автозагрузка'." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, - "Automatically load the auto save state on startup." + "При запуске игры загружать автоматически сохраненное состояние." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, - "Show thumbnails of save states inside the menu." + "Показывать миниатюры файлов сохранений в меню." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, @@ -2475,23 +2663,23 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, - "Opacity of all UI elements of the overlay." + "Непрозрачность всех элементов пользовательского интерфейса наложения." ) MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_SCALE, - "Scale of all UI elements of the overlay." + "Масштаб всех элементов пользовательского интерфейса наложения." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, - "Enable the overlay." + "Включить наложение." ) MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_PRESET, - "Select an overlay from the file browser." + "Выберите наложение из браузера файлов." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, - "The address of the host to connect to." + "Адрес хоста для подключения." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, @@ -2499,7 +2687,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, - "The password for connecting to the netplay host. Used only in host mode." + "Пароль для подключения к Netplay-хосту. Используется только в режиме хоста." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, @@ -2551,11 +2739,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, - "Shows current date and/or time inside the menu." + "Показывать текущую дату и/или время в меню." ) MSG_HASH( MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, - "Shows current battery level inside the menu." + "Показывать текущий уровень заряда батареи в меню." ) MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, @@ -2614,9 +2802,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ENABLE, "Shows current core name inside menu.") MSG_HASH(MENU_ENUM_SUBLABEL_DATABASE_MANAGER, - "View databases.") + "Просмотр баз данных.") MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_MANAGER, - "View previous searches.") + "Просмотр предыдущих запросов.") MSG_HASH(MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, "Captures an image of the screen.") MSG_HASH( @@ -2662,7 +2850,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, MSG_HASH(MENU_ENUM_SUBLABEL_CORE_OPTIONS, "Change the options for the currently running content.") MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, - "Show advanced settings for power users (hidden by default).") + "Показывать расширенные настройки для опытных пользователей (скрыто по умолчанию).") MSG_HASH(MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, "Perform tasks on a separate thread.") MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, @@ -2670,7 +2858,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, "Sets the System directory. Cores can query for this directory to load BIOSes, system-specific configs, etc.") MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, - "Sets start directory for the filebrowser.") + "Установить начальный каталог для файлового браузера.") MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_DIR, "Usually set by developers who bundle libretro/RetroArch apps to point to assets." @@ -2814,14 +3002,14 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, "Cheat changes will take effect immediately.") MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, - "Load a cheat file." + "Загрузить чит файл." ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, "Save current cheats as a save file." ) MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, - "Quickly access all relevant in-game settings.") + "Быстрый доступ к внутреигровым настройкам (работает, когда запустится любая игра).") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INFORMATION, "View information pertaining to the application/core.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO, @@ -2835,7 +3023,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -2862,11 +3050,51 @@ MSG_HASH( ) MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Mute/unmute mixer audio.") -MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, - "Show Online Updater") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_ONLINE_UPDATER, + "Показать меню Онлайн-обновление") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, - "Show/hide the 'Online Updater' option.") + "Показать/скрыть опцию 'Онлайн-обновление'.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_VIEWS_SETTINGS, + "Элементы главного экрана") +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_VIEWS_SETTINGS, + "Показать или скрыть элементы на экране меню." + ) MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, - "Show Core Updater") + "Показать меню Обновление ядра") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, - "Show/hide the ability to update cores (and core info files).") + "Показать/скрыть возможность обновлять ядра (и информационные файлы ядер).") +MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, + "Подготовка к сканированию...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Удалить ядро") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Удаление ядра с устройства.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Переименовать название игры.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Переименовать") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Избранные") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Музыка") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Изображения") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Видео") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Иконки интерфейся") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Включить/Выключить иконки интерфейся, отображающиеся в левой части меню.") diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 45f4d19841..ed275361d8 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -25,189 +25,200 @@ #include "../configuration.h" #include "../verbosity.h" -int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) { +int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) +{ uint32_t driver_hash = 0; settings_t *settings = config_get_ptr(); + if (msg == MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM) + { + snprintf(s, len, + "TODO/FIXME - Fill in message here." + ); + return 0; + } if (msg <= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_END && - msg >= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN) { - unsigned idx = msg - MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN; + msg >= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN) + { + unsigned idx = msg - MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN; - switch (idx) { - case RARCH_FAST_FORWARD_KEY: - snprintf(s, len, - "Toggles between fast-forwarding and \n" - "normal speed." - ); - break; - case RARCH_FAST_FORWARD_HOLD_KEY: - snprintf(s, len, - "Hold for fast-forward. \n" - " \n" - "Releasing button disables fast-forward." - ); - break; - case RARCH_PAUSE_TOGGLE: - snprintf(s, len, - "Toggle between paused and non-paused state."); - break; - case RARCH_FRAMEADVANCE: - snprintf(s, len, - "Frame advance when content is paused."); - break; - case RARCH_SHADER_NEXT: - snprintf(s, len, - "Applies next shader in directory."); - break; - case RARCH_SHADER_PREV: - snprintf(s, len, - "Applies previous shader in directory."); - break; - case RARCH_CHEAT_INDEX_PLUS: - case RARCH_CHEAT_INDEX_MINUS: - case RARCH_CHEAT_TOGGLE: - snprintf(s, len, - "Cheats."); - break; - case RARCH_RESET: - snprintf(s, len, - "Reset the content."); - break; - case RARCH_SCREENSHOT: - snprintf(s, len, - "Take screenshot."); - break; - case RARCH_MUTE: - snprintf(s, len, - "Mute/unmute audio."); - break; - case RARCH_OSK: - snprintf(s, len, - "Toggles onscreen keyboard."); - break; - case RARCH_NETPLAY_FLIP: - snprintf(s, len, - "Netplay flip users."); - break; - case RARCH_NETPLAY_GAME_WATCH: - snprintf(s, len, - "Netplay toggle play/spectate mode."); - break; - case RARCH_SLOWMOTION: - snprintf(s, len, - "Hold for slowmotion."); - break; - case RARCH_ENABLE_HOTKEY: - snprintf(s, len, - "Enable other hotkeys. \n" - " \n" - "If this hotkey is bound to either\n" - "a keyboard, joybutton or joyaxis, \n" - "all other hotkeys will be enabled only \n" - "if this one is held at the same time. \n" - " \n" - "Alternatively, all hotkeys for keyboard \n" - "could be disabled by the user."); - break; - case RARCH_VOLUME_UP: - snprintf(s, len, - "Increases audio volume."); - break; - case RARCH_VOLUME_DOWN: - snprintf(s, len, - "Decreases audio volume."); - break; - case RARCH_OVERLAY_NEXT: - snprintf(s, len, - "Switches to next overlay. Wraps around."); - break; - case RARCH_DISK_EJECT_TOGGLE: - snprintf(s, len, - "Toggles eject for disks. \n" - " \n" - "Used for multiple-disk content. "); - break; - case RARCH_DISK_NEXT: - case RARCH_DISK_PREV: - snprintf(s, len, - "Cycles through disk images. Use after ejecting. \n" - " \n" - "Complete by toggling eject again."); - break; - case RARCH_GRAB_MOUSE_TOGGLE: - snprintf(s, len, - "Toggles mouse grab. \n" - " \n" - "When mouse is grabbed, RetroArch hides the \n" - "mouse, and keeps the mouse pointer inside \n" - "the window to allow relative mouse input to \n" - "work better."); - break; - case RARCH_GAME_FOCUS_TOGGLE: - snprintf(s, len, - "Toggles game focus.\n" - " \n" - "When a game has focus, RetroArch will both disable \n" - "hotkeys and keep/warp the mouse pointer inside the window."); - break; - case RARCH_MENU_TOGGLE: - snprintf(s, len, "Toggles menu."); - break; - case RARCH_LOAD_STATE_KEY: - snprintf(s, len, - "Loads state."); - break; - case RARCH_FULLSCREEN_TOGGLE_KEY: - snprintf(s, len, - "Toggles fullscreen."); - break; - case RARCH_QUIT_KEY: - snprintf(s, len, - "Key to exit RetroArch cleanly. \n" - " \n" - "Killing it in any hard way (SIGKILL, etc.) will \n" - "terminate RetroArch without saving RAM, etc." + switch (idx) + { + case RARCH_FAST_FORWARD_KEY: + snprintf(s, len, + "Toggles between fast-forwarding and \n" + "normal speed." + ); + break; + case RARCH_FAST_FORWARD_HOLD_KEY: + snprintf(s, len, + "Hold for fast-forward. \n" + " \n" + "Releasing button disables fast-forward." + ); + break; + case RARCH_PAUSE_TOGGLE: + snprintf(s, len, + "Toggle between paused and non-paused state."); + break; + case RARCH_FRAMEADVANCE: + snprintf(s, len, + "Frame advance when content is paused."); + break; + case RARCH_SHADER_NEXT: + snprintf(s, len, + "Applies next shader in directory."); + break; + case RARCH_SHADER_PREV: + snprintf(s, len, + "Applies previous shader in directory."); + break; + case RARCH_CHEAT_INDEX_PLUS: + case RARCH_CHEAT_INDEX_MINUS: + case RARCH_CHEAT_TOGGLE: + snprintf(s, len, + "Cheats."); + break; + case RARCH_RESET: + snprintf(s, len, + "Reset the content."); + break; + case RARCH_SCREENSHOT: + snprintf(s, len, + "Take screenshot."); + break; + case RARCH_MUTE: + snprintf(s, len, + "Mute/unmute audio."); + break; + case RARCH_OSK: + snprintf(s, len, + "Toggles onscreen keyboard."); + break; + case RARCH_NETPLAY_FLIP: + snprintf(s, len, + "Netplay flip users."); + break; + case RARCH_NETPLAY_GAME_WATCH: + snprintf(s, len, + "Netplay toggle play/spectate mode."); + break; + case RARCH_SLOWMOTION: + snprintf(s, len, + "Hold for slowmotion."); + break; + case RARCH_ENABLE_HOTKEY: + snprintf(s, len, + "Enable other hotkeys. \n" + " \n" + "If this hotkey is bound to either\n" + "a keyboard, joybutton or joyaxis, \n" + "all other hotkeys will be enabled only \n" + "if this one is held at the same time. \n" + " \n" + "Alternatively, all hotkeys for keyboard \n" + "could be disabled by the user."); + break; + case RARCH_VOLUME_UP: + snprintf(s, len, + "Increases audio volume."); + break; + case RARCH_VOLUME_DOWN: + snprintf(s, len, + "Decreases audio volume."); + break; + case RARCH_OVERLAY_NEXT: + snprintf(s, len, + "Switches to next overlay. Wraps around."); + break; + case RARCH_DISK_EJECT_TOGGLE: + snprintf(s, len, + "Toggles eject for disks. \n" + " \n" + "Used for multiple-disk content. "); + break; + case RARCH_DISK_NEXT: + case RARCH_DISK_PREV: + snprintf(s, len, + "Cycles through disk images. Use after ejecting. \n" + " \n" + "Complete by toggling eject again."); + break; + case RARCH_GRAB_MOUSE_TOGGLE: + snprintf(s, len, + "Toggles mouse grab. \n" + " \n" + "When mouse is grabbed, RetroArch hides the \n" + "mouse, and keeps the mouse pointer inside \n" + "the window to allow relative mouse input to \n" + "work better."); + break; + case RARCH_GAME_FOCUS_TOGGLE: + snprintf(s, len, + "Toggles game focus.\n" + " \n" + "When a game has focus, RetroArch will both disable \n" + "hotkeys and keep/warp the mouse pointer inside the window."); + break; + case RARCH_MENU_TOGGLE: + snprintf(s, len, "Toggles menu."); + break; + case RARCH_LOAD_STATE_KEY: + snprintf(s, len, + "Loads state."); + break; + case RARCH_FULLSCREEN_TOGGLE_KEY: + snprintf(s, len, + "Toggles fullscreen."); + break; + case RARCH_QUIT_KEY: + snprintf(s, len, + "Key to exit RetroArch cleanly. \n" + " \n" + "Killing it in any hard way (SIGKILL, etc.) will \n" + "terminate RetroArch without saving RAM, etc." #ifdef __unix__ - "\nOn Unix-likes, SIGINT/SIGTERM allows a clean \n" - "deinitialization." + "\nOn Unix-likes, SIGINT/SIGTERM allows a clean \n" + "deinitialization." #endif - ""); - break; - case RARCH_STATE_SLOT_PLUS: - case RARCH_STATE_SLOT_MINUS: - snprintf(s, len, - "State slots. \n" - " \n" - "With slot set to 0, save state name is \n" - "*.state (or whatever defined on commandline). \n" - " \n" - "When slot is not 0, path will be , \n" - "where is slot number."); - break; - case RARCH_SAVE_STATE_KEY: - snprintf(s, len, - "Saves state."); - break; - case RARCH_REWIND: - snprintf(s, len, - "Hold button down to rewind. \n" - " \n" - "Rewinding must be enabled."); - break; - case RARCH_MOVIE_RECORD_TOGGLE: - snprintf(s, len, - "Toggle between recording and not."); - break; - default: - if (string_is_empty(s)) - strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); - break; - } + ""); + break; + case RARCH_STATE_SLOT_PLUS: + case RARCH_STATE_SLOT_MINUS: + snprintf(s, len, + "State slots. \n" + " \n" + "With slot set to 0, save state name is \n" + "*.state (or whatever defined on commandline). \n" + " \n" + "When slot is not 0, path will be , \n" + "where is slot number."); + break; + case RARCH_SAVE_STATE_KEY: + snprintf(s, len, + "Saves state."); + break; + case RARCH_REWIND: + snprintf(s, len, + "Hold button down to rewind. \n" + " \n" + "Rewinding must be enabled."); + break; + case RARCH_MOVIE_RECORD_TOGGLE: + snprintf(s, len, + "Toggle between recording and not."); + break; + default: + if (string_is_empty(s)) + strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); + break; + } - return 0; + return 0; } - switch (msg) { + switch (msg) + { case MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS: snprintf(s, len, "Login details for your \n" "Retro Achievements account. \n" @@ -285,6 +296,9 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) { "The screenshot will be stored inside the \n" "Screenshot Directory."); break; + case MENU_ENUM_LABEL_ADD_TO_FAVORITES: + snprintf(s, len, "Add the entry to your Favorites."); + break; case MENU_ENUM_LABEL_RUN: snprintf(s, len, "Start the content."); break; @@ -572,6 +586,16 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) { "Hide the current overlay from appearing \n" "inside the menu."); break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS: + snprintf(s, len, + "Show keyboard/controller button presses on \n" + "the onscreen overlay."); + break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT: + snprintf(s, len, + "Select the port to listen for controller input \n" + "to display on the onscreen overlay."); + break; case MENU_ENUM_LABEL_OVERLAY_PRESET: snprintf(s, len, "Path to input overlay."); diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 40e9c47eca..c26b80c888 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -615,6 +615,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, "False") MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, "Maximum Run Speed") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + "Favorites") MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, "Display Framerate") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, @@ -827,6 +829,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, "Display Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, "Hide Overlay In Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Show Inputs On Overlay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Show Inputs Listen Port") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, "Poll Type Behavior") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, @@ -953,8 +959,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "Settings") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Menu Linear Filter") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Horizontal Animation") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menu") + "Appearance") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, "Background") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, @@ -1217,6 +1225,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, "Save Core Remap File") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, "Save Game Remap File") +MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, + "Delete Core Remap File") +MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, + "Delete Game Remap File") MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, "Required") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -1249,6 +1261,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, "Display Start Screen") MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, "Right Analog") +MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, + "Add to Favorites") MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, "Run") MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN_MUSIC, @@ -1323,6 +1337,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, "Sort Saves In Folders") MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, "Sort Savestates In Folders") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "Write Savestates to Content Dir") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "Write Saves to Content Dir") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "System Files are in Content Dir") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "Write Screenshots to Content Dir") MSG_HASH(MENU_ENUM_LABEL_VALUE_SSH_ENABLE, "SSH Enable") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, @@ -1526,7 +1548,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, "Update Assets") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Update Autoconfig Profiles") + "Update Joypad Profiles") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, "Update Cg Shaders") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, @@ -1733,6 +1755,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_HISTORY, "Show History Tab") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_ADD, "Show Import content Tab") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_FAVORITES, + "Show Favorites Tab") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_IMAGES, "Show Image Tab") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_MUSIC, @@ -1816,7 +1840,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, "Search for and connect to netplay hosts on the local network.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display core, network, and system information.") + "Display system information.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "Download add-ons, components, and content for RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, @@ -1851,6 +1875,8 @@ MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, "Scans for wireless networks and establishes connection.") MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, "Learn more about how the program works.") +MSG_HASH(MSG_ADDED_TO_FAVORITES, + "Added to favorites") MSG_HASH(MSG_APPENDED_DISK, "Appended disk") MSG_HASH(MSG_APPLICATION_DIR, @@ -1945,6 +1971,8 @@ MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, "Error saving core options file.") MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, "Error saving remap file.") +MSG_HASH(MSG_ERROR_REMOVING_REMAP_FILE, + "Error removing remap file.") MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, "Error saving shader preset.") MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, @@ -2063,6 +2091,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Cheat Filename") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Preset Filename") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Interface") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -2137,6 +2167,8 @@ MSG_HASH(MSG_REDIRECTING_SAVESTATE_TO, "Redirecting savestate to") MSG_HASH(MSG_REMAP_FILE_SAVED_SUCCESSFULLY, "Remap file saved successfully.") +MSG_HASH(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, + "Remap file removed successfully.") MSG_HASH(MSG_REMOVED_DISK_FROM_TRAY, "Removed disk from tray.") MSG_HASH(MSG_REMOVING_TEMPORARY_CONTENT_FILE, @@ -2494,6 +2526,10 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, "Specify the font size in points.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, "Hide the overlay while inside the menu, and show it again when exiting the menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Show keyboard/controller inputs on the onscreen overlay.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Select the port for the overlay to listen to if Show Inputs On Overlay is enabled.") MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, "Scanned content will appear here." @@ -2778,6 +2814,8 @@ MSG_HASH(MENU_ENUM_SUBLABEL_DELETE_ENTRY, "Remove this entry from the collection.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION, "View more information about the content.") +MSG_HASH(MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, + "Add the entry to your favorites.") MSG_HASH(MENU_ENUM_SUBLABEL_RUN, "Start the content.") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, @@ -2891,6 +2929,8 @@ MSG_HASH(MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, "Select an animated background effect. Can be GPU-intensive depending on the effect. If performance is unsatisfactory, either turn this off or revert to a simpler effect.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_FONT, "Select a different main font to be used by the menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_FAVORITES, + "Show the favorites tab inside the main menu.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_IMAGES, "Show the image tab inside the main menu.") MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_MUSIC, @@ -3016,7 +3056,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -3059,3 +3099,35 @@ MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") MSG_HASH(MSG_PREPARING_FOR_CONTENT_SCAN, "Preparing for content scan...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_DELETE, + "Delete core") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_DELETE, + "Remove this core from disk.") +MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/intl/msg_hash_vn.h b/intl/msg_hash_vn.h index 69fc0a05f5..a5582641b6 100644 --- a/intl/msg_hash_vn.h +++ b/intl/msg_hash_vn.h @@ -948,7 +948,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Menu Linear Filter") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menu") + "Appearance") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, "Background") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, @@ -2051,6 +2051,8 @@ MSG_HASH(MSG_INPUT_CHEAT_FILENAME, "Cheat Filename") MSG_HASH(MSG_INPUT_PRESET_FILENAME, "Preset Filename") +MSG_HASH(MSG_INPUT_RENAME_ENTRY, + "Rename Title") MSG_HASH(MSG_INTERFACE, "Interface") MSG_HASH(MSG_INTERNAL_STORAGE, @@ -3004,7 +3006,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use MITM Server") + "Use Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, @@ -3039,3 +3041,31 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Show Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "Show/hide the ability to update cores (and core info files).") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Rename the title of the entry.") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + "Rename") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + "Framebuffer Opacity") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modify the opacity of the framebuffer.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES, + "Favorites") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_FAVORITES, + "Content which you have added to 'Favorites' will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC, + "Music") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_MUSIC, + "Music which has been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES, + "Image") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_IMAGES, + "Images which have been previously viewed will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO, + "Video") +MSG_HASH(MENU_ENUM_SUBLABEL_GOTO_VIDEO, + "Videos which have been previously played will appear here.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + "Menu Icons") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE, + "Enable/disable the menu icons shown at the lefthand side of the menu entries.") diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index 8afea64b78..f9a1a226bc 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -30,6 +30,7 @@ #include #endif +#include #include #include #include @@ -46,6 +47,10 @@ #include "../../deps/stb/stb_vorbis.h" #endif +#ifdef HAVE_IBXM +#include "../../deps/ibxm/ibxm.h" +#endif + #define AUDIO_MIXER_MAX_VOICES 8 #define AUDIO_MIXER_TEMP_OGG_BUFFER 8192 @@ -70,6 +75,15 @@ struct audio_mixer_sound const void* data; } ogg; #endif + +#ifdef HAVE_IBXM + struct + { + /* mod/s3m/xm */ + unsigned size; + const void* data; + } mod; +#endif } types; }; @@ -85,14 +99,12 @@ struct audio_mixer_voice { struct { - /* wav */ unsigned position; } wav; #ifdef HAVE_STB_VORBIS struct { - /* ogg */ unsigned position; unsigned samples; unsigned buf_samples; @@ -103,6 +115,17 @@ struct audio_mixer_voice const retro_resampler_t *resampler; } ogg; #endif + +#ifdef HAVE_IBXM + struct + { + unsigned position; + unsigned samples; + unsigned buf_samples; + int* buffer; + struct replay* stream; + } mod; +#endif } types; }; @@ -319,6 +342,24 @@ audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size) #endif } +audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size) +{ +#ifdef HAVE_IBXM + audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound)); + + if (!sound) + return NULL; + + sound->type = AUDIO_MIXER_TYPE_MOD; + sound->types.mod.size = size; + sound->types.mod.data = buffer; + + return sound; +#else + return NULL; +#endif +} + void audio_mixer_destroy(audio_mixer_sound_t* sound) { void *handle = NULL; @@ -337,6 +378,13 @@ void audio_mixer_destroy(audio_mixer_sound_t* sound) handle = (void*)sound->types.ogg.data; if (handle) free(handle); +#endif + break; + case AUDIO_MIXER_TYPE_MOD: +#ifdef HAVE_IBXM + handle = (void*)sound->types.mod.data; + if (handle) + free(handle); #endif break; case AUDIO_MIXER_TYPE_NONE: @@ -413,6 +461,74 @@ error: } #endif +#ifdef HAVE_IBXM +static bool audio_mixer_play_mod( + audio_mixer_sound_t* sound, + audio_mixer_voice_t* voice, + bool repeat, float volume, + audio_mixer_stop_cb_t stop_cb) +{ + struct data data; + char message[64]; + int buf_samples = 0; + int samples = 0; + void *mod_buffer = NULL; + struct module* module = NULL; + struct replay* replay = NULL; + + data.buffer = (char*)sound->types.mod.data; + data.length = sound->types.mod.size; + module = module_load(&data, message); + + if (!module) + { + printf("audio_mixer_play_mod module_load() failed with error: %s\n", message); + goto error; + } + + replay = new_replay( module, s_rate, 1); + + if (!replay) + { + printf("audio_mixer_play_mod new_replay() failed\n"); + goto error; + } + + buf_samples = calculate_mix_buf_len(s_rate); + mod_buffer = memalign_alloc(16, ((buf_samples + 15) & ~15) * sizeof(int)); + + if (!mod_buffer) + { + printf("audio_mixer_play_mod cannot allocate mod_buffer !\n"); + goto error; + } + + samples = replay_calculate_duration(replay); + + if (!samples) + { + printf("audio_mixer_play_mod cannot retrieve duration !\n"); + goto error; + } + + voice->types.mod.buffer = (int*)mod_buffer; + voice->types.mod.buf_samples = buf_samples; + voice->types.mod.stream = replay; + voice->types.mod.position = 0; + voice->types.mod.samples = 0; /* samples; */ + + return true; + +error: + if (mod_buffer) + memalign_free(mod_buffer); + if (module) + dispose_module(module); + return false; + +} +#endif + audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb) { @@ -440,6 +556,11 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, case AUDIO_MIXER_TYPE_OGG: #ifdef HAVE_STB_VORBIS res = audio_mixer_play_ogg(sound, voice, repeat, volume, stop_cb); +#endif + break; + case AUDIO_MIXER_TYPE_MOD: +#ifdef HAVE_IBXM + res = audio_mixer_play_mod(sound, voice, repeat, volume, stop_cb); #endif break; case AUDIO_MIXER_TYPE_NONE: @@ -608,6 +729,81 @@ again: } #endif +#ifdef HAVE_IBXM +static void audio_mixer_mix_mod(float* buffer, size_t num_frames, + audio_mixer_voice_t* voice, + float volume) +{ + int i; + float samplef = 0.0f; + int samplei = 0; + unsigned temp_samples = 0; + unsigned buf_free = num_frames * 2; + int* pcm = NULL; + + if (voice->types.mod.position == voice->types.mod.samples) + { +again: + temp_samples = replay_get_audio( + voice->types.mod.stream, voice->types.mod.buffer ); + + temp_samples *= 2; /* stereo */ + + if (temp_samples == 0) + { + if (voice->repeat) + { + if (voice->stop_cb) + voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED); + + replay_seek( voice->types.mod.stream, 0); + goto again; + } + else + { + if (voice->stop_cb) + voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); + + voice->type = AUDIO_MIXER_TYPE_NONE; + return; + } + } + + voice->types.mod.position = 0; + voice->types.mod.samples = temp_samples; + } + pcm = voice->types.mod.buffer + voice->types.mod.position; + + if (voice->types.mod.samples < buf_free) + { + for (i = voice->types.mod.samples; i != 0; i--) + { + samplei = *pcm++ * volume; + samplef = (float)((int)samplei + 32768) / 65535.0f; + samplef = samplef * 2.0f - 1.0f; + *buffer++ += samplef; + } + + buf_free -= voice->types.mod.samples; + goto again; + } + else + { + int i; + for (i = buf_free; i != 0; --i ) + { + samplei = *pcm++ * volume; + samplef = (float)((int)samplei + 32768) / 65535.0f; + samplef = samplef * 2.0f - 1.0f; + *buffer++ += samplef; + } + + voice->types.mod.position += buf_free; + voice->types.mod.samples -= buf_free; + } +} +#endif + void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bool override) { unsigned i; @@ -631,6 +827,11 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo case AUDIO_MIXER_TYPE_OGG: #ifdef HAVE_STB_VORBIS audio_mixer_mix_ogg(buffer, num_frames, voice, volume); +#endif + break; + case AUDIO_MIXER_TYPE_MOD: +#ifdef HAVE_IBXM + audio_mixer_mix_mod(buffer, num_frames, voice, volume); #endif break; case AUDIO_MIXER_TYPE_NONE: diff --git a/libretro-common/audio/dsp_filters/Crystalizer.dsp b/libretro-common/audio/dsp_filters/Crystalizer.dsp new file mode 100644 index 0000000000..f8fceb5f96 --- /dev/null +++ b/libretro-common/audio/dsp_filters/Crystalizer.dsp @@ -0,0 +1,4 @@ +filters = 1 +filter0 = crystalizer +# Controls dry/wet-ness of effect. 0.0 = none, 10.0 = max. +crystalizer_intensity = 5.0 diff --git a/libretro-common/audio/dsp_filters/Makefile b/libretro-common/audio/dsp_filters/Makefile index e19930c6c1..ab0900fd9d 100644 --- a/libretro-common/audio/dsp_filters/Makefile +++ b/libretro-common/audio/dsp_filters/Makefile @@ -3,6 +3,8 @@ extra_flags := use_neon := 0 build = release DYLIB := so +PREFIX := /usr +INSTALLDIR := $(PREFIX)/lib/retroarch/filters/audio ifeq ($(platform),) platform = unix @@ -89,3 +91,10 @@ clean: strip: strip -s *.$(DYLIB) + +install: + mkdir -p $(DESTDIR)$(INSTALLDIR) + cp -t $(DESTDIR)$(INSTALLDIR) $(targets) *.dsp + +test-install: + DESTDIR=/tmp/build $(MAKE) install diff --git a/libretro-common/audio/dsp_filters/configure b/libretro-common/audio/dsp_filters/configure new file mode 100755 index 0000000000..7ce4f33995 --- /dev/null +++ b/libretro-common/audio/dsp_filters/configure @@ -0,0 +1,3 @@ +#!/bin/sh + +PACKAGE_NAME=retroarch-filters-audio diff --git a/libretro-common/audio/dsp_filters/crystalizer.c b/libretro-common/audio/dsp_filters/crystalizer.c new file mode 100644 index 0000000000..c0e253c7e3 --- /dev/null +++ b/libretro-common/audio/dsp_filters/crystalizer.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (echo.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION 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 +#include + +#include +#include + +struct delta_data +{ + float intensity; + float old[2]; +}; + +static void delta_free(void *data) +{ + free(data); +} + +static void delta_process(void *data, struct dspfilter_output *output, + const struct dspfilter_input *input) +{ + unsigned i, c; + struct delta_data *d = (struct delta_data*)data; + float *out = output->samples; + output->samples = input->samples; + output->frames = input->frames; + + for (i = 0; i < input->frames; i++) + { + for (c = 0; c < 2; c++) + { + float current = *out; + *out++ = current + (current - d->old[c]) * d->intensity; + d->old[c] = current; + } + } +} + +static void *delta_init(const struct dspfilter_info *info, + const struct dspfilter_config *config, void *userdata) +{ + struct delta_data *d = (struct delta_data*)calloc(1, sizeof(*d)); + if (!d) + return NULL; + config->get_float(userdata, "intensity", &d->intensity, 5.0f); + return d; +} + +static const struct dspfilter_implementation delta_plug = { + delta_init, + delta_process, + delta_free, + DSPFILTER_API_VERSION, + "Delta Sharpening", + "crystalizer", +}; + +#ifdef HAVE_FILTERS_BUILTIN +#define dspfilter_get_implementation delta_dspfilter_get_implementation +#endif + +const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask) +{ + (void)mask; + return &delta_plug; +} + + +#undef dspfilter_get_implementation + diff --git a/libretro-common/compat/compat_getopt.c b/libretro-common/compat/compat_getopt.c index c32c85865b..95d1bce523 100644 --- a/libretro-common/compat/compat_getopt.c +++ b/libretro-common/compat/compat_getopt.c @@ -184,7 +184,7 @@ int getopt_long(int argc, char *argv[], if (optind == 0) optind = 1; - if (argc == 1) + if (argc < 2) return -1; short_index = find_short_index(&argv[optind]); diff --git a/libretro-common/file/retro_dirent.c b/libretro-common/file/retro_dirent.c index c21b2d669c..26f3e8a897 100644 --- a/libretro-common/file/retro_dirent.c +++ b/libretro-common/file/retro_dirent.c @@ -20,8 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include #include +#include +#include #include @@ -156,45 +157,6 @@ const char *retro_dirent_get_name(struct RDIR *rdir) #endif } -static bool path_is_directory_internal(const char *path) -{ -#if defined(VITA) || defined(PSP) - SceIoStat buf; - char *tmp = strdup(path); - size_t len = strlen(tmp); - if (tmp[len-1] == '/') - tmp[len-1]='\0'; - - if (sceIoGetstat(tmp, &buf) < 0) - { - free(tmp); - return false; - } - free(tmp); - - return FIO_S_ISDIR(buf.st_mode); -#elif defined(__CELLOS_LV2__) - CellFsStat buf; - if (cellFsStat(path, &buf) < 0) - return false; - return ((buf.st_mode & S_IFMT) == S_IFDIR); -#elif defined(_WIN32) - struct _stat buf; - DWORD file_info = GetFileAttributes(path); - - _stat(path, &buf); - - if (file_info == INVALID_FILE_ATTRIBUTES) - return false; - return (file_info & FILE_ATTRIBUTE_DIRECTORY); -#else - struct stat buf; - if (stat(path, &buf) < 0) - return false; - return S_ISDIR(buf.st_mode); -#endif -} - /** * * retro_dirent_is_dir: @@ -221,17 +183,20 @@ bool retro_dirent_is_dir(struct RDIR *rdir, const char *path) #elif defined(__CELLOS_LV2__) CellFsDirent *entry = (CellFsDirent*)&rdir->entry; return (entry->d_type == CELL_FS_TYPE_DIRECTORY); -#elif defined(DT_DIR) +#else + struct stat buf; +#if defined(DT_DIR) const struct dirent *entry = (const struct dirent*)rdir->entry; if (entry->d_type == DT_DIR) return true; /* This can happen on certain file systems. */ - if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) - return path_is_directory_internal(path); - return false; -#else + if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)) + return false; +#endif /* dirent struct doesn't have d_type, do it the slow way ... */ - return path_is_directory_internal(path); + if (stat(path, &buf) < 0) + return false; + return S_ISDIR(buf.st_mode); #endif } diff --git a/libretro-common/formats/json/jsonsax.c b/libretro-common/formats/json/jsonsax.c index 1a7ac93555..fec8a7df8a 100644 --- a/libretro-common/formats/json/jsonsax.c +++ b/libretro-common/formats/json/jsonsax.c @@ -54,13 +54,13 @@ state_t; static INLINE void skip_spaces( state_t* state ) { - while ( isspace( *state->json ) ) + while ( isspace( (unsigned char)*state->json ) ) state->json++; } static INLINE void skip_digits( state_t* state ) { - while ( isdigit( *state->json ) ) + while ( isdigit( (unsigned char)*state->json ) ) state->json++; } @@ -218,7 +218,7 @@ static void jsonx_parse_number(state_t* state) if ( *state->json == '-' ) state->json++; - if ( !isdigit( *state->json ) ) + if ( !isdigit( (unsigned char)*state->json ) ) longjmp( state->env, JSONSAX_INVALID_VALUE ); skip_digits( state ); @@ -227,7 +227,7 @@ static void jsonx_parse_number(state_t* state) { state->json++; - if ( !isdigit( *state->json ) ) + if ( !isdigit( (unsigned char)*state->json ) ) longjmp( state->env, JSONSAX_INVALID_VALUE ); skip_digits( state ); @@ -240,7 +240,7 @@ static void jsonx_parse_number(state_t* state) if ( *state->json == '-' || *state->json == '+' ) state->json++; - if ( !isdigit( *state->json ) ) + if ( !isdigit( (unsigned char)*state->json ) ) longjmp( state->env, JSONSAX_INVALID_VALUE ); skip_digits( state ); diff --git a/libretro-common/formats/libchdr/bitstream.c b/libretro-common/formats/libchdr/bitstream.c new file mode 100644 index 0000000000..735b97f4b1 --- /dev/null +++ b/libretro-common/formats/libchdr/bitstream.c @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + bitstream.c + + Helper classes for reading/writing at the bit level. + +***************************************************************************/ + +#include "bitstream.h" +#include + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); } + +//------------------------------------------------- +// create_bitstream - constructor +//------------------------------------------------- + +struct bitstream* create_bitstream(const void *src, uint32_t srclength) +{ + struct bitstream* bitstream = (struct bitstream*)malloc(sizeof(struct bitstream)); + bitstream->buffer = 0; + bitstream->bits = 0; + bitstream->read = (const uint8_t*)src; + bitstream->doffset = 0; + bitstream->dlength = srclength; + return bitstream; +} + + +//----------------------------------------------------- +// bitstream_peek - fetch the requested number of bits +// but don't advance the input pointer +//----------------------------------------------------- + +uint32_t bitstream_peek(struct bitstream* bitstream, int numbits) +{ + if (numbits == 0) + return 0; + + // fetch data if we need more + if (numbits > bitstream->bits) + { + while (bitstream->bits <= 24) + { + if (bitstream->doffset < bitstream->dlength) + bitstream->buffer |= bitstream->read[bitstream->doffset] << (24 - bitstream->bits); + bitstream->doffset++; + bitstream->bits += 8; + } + } + + // return the data + return bitstream->buffer >> (32 - numbits); +} + + +//----------------------------------------------------- +// bitstream_remove - advance the input pointer by the +// specified number of bits +//----------------------------------------------------- + +void bitstream_remove(struct bitstream* bitstream, int numbits) +{ + bitstream->buffer <<= numbits; + bitstream->bits -= numbits; +} + + +//----------------------------------------------------- +// bitstream_read - fetch the requested number of bits +//----------------------------------------------------- + +uint32_t bitstream_read(struct bitstream* bitstream, int numbits) +{ + uint32_t result = bitstream_peek(bitstream, numbits); + bitstream_remove(bitstream, numbits); + return result; +} + + +//------------------------------------------------- +// read_offset - return the current read offset +//------------------------------------------------- + +uint32_t bitstream_read_offset(struct bitstream* bitstream) +{ + uint32_t result = bitstream->doffset; + int bits = bitstream->bits; + while (bits >= 8) + { + result--; + bits -= 8; + } + return result; +} + + +//------------------------------------------------- +// flush - flush to the nearest byte +//------------------------------------------------- + +uint32_t bitstream_flush(struct bitstream* bitstream) +{ + while (bitstream->bits >= 8) + { + bitstream->doffset--; + bitstream->bits -= 8; + } + bitstream->bits = bitstream->buffer = 0; + return bitstream->doffset; +} + diff --git a/libretro-common/formats/libchdr/bitstream.h b/libretro-common/formats/libchdr/bitstream.h new file mode 100644 index 0000000000..9250d3369e --- /dev/null +++ b/libretro-common/formats/libchdr/bitstream.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + bitstream.h + + Helper classes for reading/writing at the bit level. + +***************************************************************************/ + +#pragma once + +#ifndef __BITSTREAM_H__ +#define __BITSTREAM_H__ + +#include + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// helper class for reading from a bit buffer +struct bitstream +{ + uint32_t buffer; // current bit accumulator + int bits; // number of bits in the accumulator + const uint8_t * read; // read pointer + uint32_t doffset; // byte offset within the data + uint32_t dlength; // length of the data +}; + +struct bitstream* create_bitstream(const void *src, uint32_t srclength); +int bitstream_overflow(struct bitstream* bitstream); +uint32_t bitstream_read_offset(struct bitstream* bitstream); + +uint32_t bitstream_read(struct bitstream* bitstream, int numbits); +uint32_t bitstream_peek(struct bitstream* bitstream, int numbits); +void bitstream_remove(struct bitstream* bitstream, int numbits); +uint32_t bitstream_flush(struct bitstream* bitstream); + + +#endif diff --git a/libretro-common/formats/libchdr/cdrom.c b/libretro-common/formats/libchdr/cdrom.c new file mode 100644 index 0000000000..6c120cbc2a --- /dev/null +++ b/libretro-common/formats/libchdr/cdrom.c @@ -0,0 +1,417 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + cdrom.c + + Generic MAME CD-ROM utilties - build IDE and SCSI CD-ROMs on top of this + +**************************************************************************** + + IMPORTANT: + "physical" block addresses are the actual addresses on the emulated CD. + "chd" block addresses are the block addresses in the CHD file. + Because we pad each track to a 4-frame boundary, these addressing + schemes will differ after track 1! + +***************************************************************************/ + +#include +#include + +#include "cdrom.h" + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +/** @brief The verbose. */ +#define VERBOSE (0) +#if VERBOSE + +/** + * @def LOG(x) do + * + * @brief A macro that defines log. + * + * @param x The void to process. + */ + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/** + * @fn void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); + * + * @brief Logerrors the given text. + * + * @param text The text. + * + * @return A CLIB_DECL. + */ + +void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); +#else + +/** + * @def LOG(x); + * + * @brief A macro that defines log. + * + * @param x The void to process. + */ + +#define LOG(x) +#endif + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/** @brief offset within sector. */ +#define SYNC_OFFSET 0x000 +/** @brief 12 bytes. */ +#define SYNC_NUM_BYTES 12 + +/** @brief offset within sector. */ +#define MODE_OFFSET 0x00f + +/** @brief offset within sector. */ +#define ECC_P_OFFSET 0x81c +/** @brief 2 lots of 86. */ +#define ECC_P_NUM_BYTES 86 +/** @brief 24 bytes each. */ +#define ECC_P_COMP 24 + +/** @brief The ECC q offset. */ +#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES) +/** @brief 2 lots of 52. */ +#define ECC_Q_NUM_BYTES 52 +/** @brief 43 bytes each. */ +#define ECC_Q_COMP 43 + + + +/** + * @brief ------------------------------------------------- + * ECC lookup tables pre-calculated tables for ECC data calcs + * -------------------------------------------------. + */ + +static const uint8_t ecclow[256] = +{ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, + 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, + 0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03, + 0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23, + 0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43, + 0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63, + 0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83, + 0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3, + 0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3, + 0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3 +}; + +/** @brief The ecchigh[ 256]. */ +static const uint8_t ecchigh[256] = +{ + 0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05, + 0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe, + 0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee, + 0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15, + 0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce, + 0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35, + 0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25, + 0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde, + 0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e, + 0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75, + 0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65, + 0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e, + 0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45, + 0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe, + 0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae, + 0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55 +}; + +/** + * @brief ------------------------------------------------- + * poffsets - each row represents the addresses used to calculate a byte of the ECC P + * data 86 (*2) ECC P bytes, 24 values represented by each + * -------------------------------------------------. + */ + +static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] = +{ + { 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba }, + { 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb }, + { 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc }, + { 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd }, + { 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be }, + { 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf }, + { 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 }, + { 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 }, + { 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 }, + { 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 }, + { 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 }, + { 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 }, + { 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 }, + { 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 }, + { 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 }, + { 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 }, + { 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca }, + { 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb }, + { 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc }, + { 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd }, + { 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce }, + { 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf }, + { 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 }, + { 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 }, + { 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 }, + { 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 }, + { 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 }, + { 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 }, + { 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 }, + { 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 }, + { 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 }, + { 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 }, + { 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da }, + { 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db }, + { 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc }, + { 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd }, + { 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de }, + { 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df }, + { 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 }, + { 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 }, + { 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 }, + { 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 }, + { 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 }, + { 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 }, + { 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 }, + { 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 }, + { 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 }, + { 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 }, + { 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea }, + { 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb }, + { 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec }, + { 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed }, + { 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee }, + { 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef }, + { 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 }, + { 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 }, + { 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 }, + { 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 }, + { 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 }, + { 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 }, + { 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 }, + { 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 }, + { 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 }, + { 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 }, + { 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa }, + { 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb }, + { 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc }, + { 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd }, + { 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe }, + { 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff }, + { 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 }, + { 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 }, + { 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 }, + { 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 }, + { 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 }, + { 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 }, + { 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 }, + { 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 }, + { 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 }, + { 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 }, + { 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a }, + { 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b }, + { 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c }, + { 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d }, + { 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e }, + { 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f } +}; + +/** + * @brief ------------------------------------------------- + * qoffsets - each row represents the addresses used to calculate a byte of the ECC Q + * data 52 (*2) ECC Q bytes, 43 values represented by each + * -------------------------------------------------. + */ + +static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] = +{ + { 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 }, + { 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 }, + { 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a }, + { 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b }, + { 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 }, + { 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 }, + { 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 }, + { 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 }, + { 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c }, + { 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d }, + { 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 }, + { 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 }, + { 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 }, + { 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 }, + { 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e }, + { 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f }, + { 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 }, + { 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 }, + { 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba }, + { 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb }, + { 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 }, + { 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 }, + { 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa }, + { 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab }, + { 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 }, + { 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 }, + { 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 }, + { 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 }, + { 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac }, + { 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad }, + { 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 }, + { 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 }, + { 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 }, + { 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 }, + { 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae }, + { 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af }, + { 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 }, + { 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 }, + { 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a }, + { 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b }, + { 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 }, + { 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 }, + { 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 }, + { 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 }, + { 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c }, + { 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d }, + { 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 }, + { 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 }, + { 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 }, + { 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 }, + { 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e }, + { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f } +}; + + +//------------------------------------------------- +// ecc_source_byte - return data from the sector +// at the given offset, masking anything +// particular to a mode +//------------------------------------------------- + +static uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset) +{ + // in mode 2 always treat these as 0 bytes + return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset]; +} + +/** + * @fn void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2) + * + * @brief ------------------------------------------------- + * ecc_compute_bytes - calculate an ECC value (P or Q) + * -------------------------------------------------. + * + * @param sector The sector. + * @param row The row. + * @param rowlen The rowlen. + * @param [in,out] val1 The first value. + * @param [in,out] val2 The second value. + */ + +void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2) +{ + int component; + *val1 = *val2 = 0; + for (component = 0; component < rowlen; component++) + { + *val1 ^= ecc_source_byte(sector, row[component]); + *val2 ^= ecc_source_byte(sector, row[component]); + *val1 = ecclow[*val1]; + } + *val1 = ecchigh[ecclow[*val1] ^ *val2]; + *val2 ^= *val1; +} + +/** + * @fn int ecc_verify(const uint8_t *sector) + * + * @brief ------------------------------------------------- + * ecc_verify - verify the P and Q ECC codes in a sector + * -------------------------------------------------. + * + * @param sector The sector. + * + * @return true if it succeeds, false if it fails. + */ + +int ecc_verify(const uint8_t *sector) +{ + int byte; + + // first verify P bytes + for (byte = 0; byte < ECC_P_NUM_BYTES; byte++) + { + uint8_t val1, val2; + ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2); + if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2) + return 0; + } + + // then verify Q bytes + for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++) + { + uint8_t val1, val2; + ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2); + if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2) + return 0; + } + return 1; +} + +/** + * @fn void ecc_generate(uint8_t *sector) + * + * @brief ------------------------------------------------- + * ecc_generate - generate the P and Q ECC codes for a sector, overwriting any + * existing codes + * -------------------------------------------------. + * + * @param [in,out] sector If non-null, the sector. + */ + +void ecc_generate(uint8_t *sector) +{ + int byte; + // first verify P bytes + for (byte = 0; byte < ECC_P_NUM_BYTES; byte++) + ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, §or[ECC_P_OFFSET + byte], §or[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]); + + // then verify Q bytes + for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++) + ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, §or[ECC_Q_OFFSET + byte], §or[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]); +} + +/** + * @fn void ecc_clear(uint8_t *sector) + * + * @brief ------------------------------------------------- + * ecc_clear - erase the ECC P and Q cods to 0 within a sector + * -------------------------------------------------. + * + * @param [in,out] sector If non-null, the sector. + */ + +void ecc_clear(uint8_t *sector) +{ + memset(§or[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES); + memset(§or[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES); +} diff --git a/libretro-common/formats/libchdr/cdrom.h b/libretro-common/formats/libchdr/cdrom.h new file mode 100644 index 0000000000..8fc52bfa92 --- /dev/null +++ b/libretro-common/formats/libchdr/cdrom.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + cdrom.h + + Generic MAME cd-rom implementation + +***************************************************************************/ + +#pragma once + +#ifndef __CDROM_H__ +#define __CDROM_H__ + +#include + +#include + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +// tracks are padded to a multiple of this many frames +extern const uint32_t CD_TRACK_PADDING; + +#define CD_MAX_TRACKS (99) /* AFAIK the theoretical limit */ +#define CD_MAX_SECTOR_DATA (2352) +#define CD_MAX_SUBCODE_DATA (96) + +#define CD_FRAME_SIZE (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA) +#define CD_FRAMES_PER_HUNK (8) + +#define CD_METADATA_WORDS (1+(CD_MAX_TRACKS * 6)) + +enum +{ + CD_TRACK_MODE1 = 0, /* mode 1 2048 bytes/sector */ + CD_TRACK_MODE1_RAW, /* mode 1 2352 bytes/sector */ + CD_TRACK_MODE2, /* mode 2 2336 bytes/sector */ + CD_TRACK_MODE2_FORM1, /* mode 2 2048 bytes/sector */ + CD_TRACK_MODE2_FORM2, /* mode 2 2324 bytes/sector */ + CD_TRACK_MODE2_FORM_MIX, /* mode 2 2336 bytes/sector */ + CD_TRACK_MODE2_RAW, /* mode 2 2352 bytes / sector */ + CD_TRACK_AUDIO, /* redbook audio track 2352 bytes/sector (588 samples) */ + + CD_TRACK_RAW_DONTCARE /* special flag for cdrom_read_data: just return me whatever is there */ +}; + +enum +{ + CD_SUB_NORMAL = 0, /* "cooked" 96 bytes per sector */ + CD_SUB_RAW, /* raw uninterleaved 96 bytes per sector */ + CD_SUB_NONE /* no subcode data stored */ +}; + +#define CD_FLAG_GDROM 0x00000001 // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata +#define CD_FLAG_GDROMLE 0x00000002 // legacy GD-ROM, with little-endian CDDA data + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +// ECC utilities +int ecc_verify(const uint8_t *sector); +void ecc_generate(uint8_t *sector); +void ecc_clear(uint8_t *sector); + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +static INLINE uint32_t msf_to_lba(uint32_t msf) +{ + return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0); +} + +static INLINE uint32_t lba_to_msf(uint32_t lba) +{ + uint8_t m, s, f; + + m = lba / (60 * 75); + lba -= m * (60 * 75); + s = lba / 75; + f = lba % 75; + + return ((m / 10) << 20) | ((m % 10) << 16) | + ((s / 10) << 12) | ((s % 10) << 8) | + ((f / 10) << 4) | ((f % 10) << 0); +} + +// segacd needs it like this.. investigate +// Angelo also says PCE tracks often start playing at the +// wrong address.. related? +static INLINE uint32_t lba_to_msf_alt(int lba) +{ + uint32_t ret = 0; + + ret |= ((lba / (60 * 75))&0xff)<<16; + ret |= (((lba / 75) % 60)&0xff)<<8; + ret |= ((lba % 75)&0xff)<<0; + + return ret; +} + +#endif // __CDROM_H__ diff --git a/libretro-common/formats/libchdr/chd.c b/libretro-common/formats/libchdr/chd.c new file mode 100644 index 0000000000..9adecc6627 --- /dev/null +++ b/libretro-common/formats/libchdr/chd.c @@ -0,0 +1,2453 @@ +/*************************************************************************** + + chd.c + + MAME Compressed Hunks of Data file format + +**************************************************************************** + + Copyright Aaron Giles + 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 'MAME' 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 AARON GILES ''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 AARON GILES 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 DONT_SET_BYTE +typedef unsigned char Byte; + +#include "chd.h" +#include "cdrom.h" +#include "huffman.h" +#include "flac.h" + +#include "md5.h" +#include "sha1.h" +#include "LzmaEnc.h" +#include "LzmaDec.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#define TRUE 1 +#define FALSE 0 + +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +#define SHA1_DIGEST_SIZE 20 + +#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define PRINTF_MAX_HUNK (0) + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define MAP_STACK_ENTRIES 512 /* max number of entries to use on the stack */ +#define MAP_ENTRY_SIZE 16 /* V3 and later */ +#define OLD_MAP_ENTRY_SIZE 8 /* V1-V2 */ +#define METADATA_HEADER_SIZE 16 /* metadata header size */ +#define CRCMAP_HASH_SIZE 4095 /* number of CRC hashtable entries */ + +#define MAP_ENTRY_FLAG_TYPE_MASK 0x0f /* what type of hunk */ +#define MAP_ENTRY_FLAG_NO_CRC 0x10 /* no CRC is present */ + +#define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */ + +#define COOKIE_VALUE 0xbaadf00d +#define MAX_ZLIB_ALLOCS 64 + +#define END_OF_LIST_COOKIE "EndOfListCookie" + +#define NO_MATCH (~0) + +static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; + +// V3-V4 entry types +enum +{ + V34_MAP_ENTRY_TYPE_INVALID = 0, // invalid type + V34_MAP_ENTRY_TYPE_COMPRESSED = 1, // standard compression + V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, // uncompressed data + V34_MAP_ENTRY_TYPE_MINI = 3, // mini: use offset as raw data + V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, // same as another hunk in this file + V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, // same as a hunk in the parent file + V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 // compressed with secondary algorithm (usually FLAC CDDA) +}; + +// V5 compression types +enum +{ + ///< codec #0 + // these types are live when running + COMPRESSION_TYPE_0 = 0, + ///< codec #1 + COMPRESSION_TYPE_1 = 1, + ///< codec #2 + COMPRESSION_TYPE_2 = 2, + ///< codec #3 + COMPRESSION_TYPE_3 = 3, + ///< no compression; implicit length = hunkbytes + COMPRESSION_NONE = 4, + ///< same as another block in this chd + COMPRESSION_SELF = 5, + ///< same as a hunk's worth of units in the parent chd + COMPRESSION_PARENT = 6, + + ///< start of small RLE run (4-bit length) + // these additional pseudo-types are used for compressed encodings: + COMPRESSION_RLE_SMALL, + ///< start of large RLE run (8-bit length) + COMPRESSION_RLE_LARGE, + ///< same as the last COMPRESSION_SELF block + COMPRESSION_SELF_0, + ///< same as the last COMPRESSION_SELF block + 1 + COMPRESSION_SELF_1, + ///< same block in the parent + COMPRESSION_PARENT_SELF, + ///< same as the last COMPRESSION_PARENT block + COMPRESSION_PARENT_0, + ///< same as the last COMPRESSION_PARENT block + 1 + COMPRESSION_PARENT_1 +}; + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* interface to a codec */ +typedef struct _codec_interface codec_interface; +struct _codec_interface +{ + UINT32 compression; /* type of compression */ + const char *compname; /* name of the algorithm */ + UINT8 lossy; /* is this a lossy algorithm? */ + chd_error (*init)(void *codec, UINT32 hunkbytes); /* codec initialize */ + void (*free)(void *codec); /* codec free */ + chd_error (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */ + chd_error (*config)(void *codec, int param, void *config); /* configure */ +}; + + +/* a single map entry */ +typedef struct _map_entry map_entry; +struct _map_entry +{ + UINT64 offset; /* offset within the file of the data */ + UINT32 crc; /* 32-bit CRC of the data */ + UINT32 length; /* length of the data */ + UINT8 flags; /* misc flags */ +}; + + +/* simple linked-list of hunks used for our CRC map */ +typedef struct _crcmap_entry crcmap_entry; +struct _crcmap_entry +{ + UINT32 hunknum; /* hunk number */ + crcmap_entry * next; /* next entry in list */ +}; + + +/* a single metadata entry */ +typedef struct _metadata_entry metadata_entry; +struct _metadata_entry +{ + UINT64 offset; /* offset within the file of the header */ + UINT64 next; /* offset within the file of the next header */ + UINT64 prev; /* offset within the file of the previous header */ + UINT32 length; /* length of the metadata */ + UINT32 metatag; /* metadata tag */ + UINT8 flags; /* flag bits */ +}; + +/* codec-private data for the ZLIB codec */ + +typedef struct _zlib_allocator zlib_allocator; +struct _zlib_allocator +{ + UINT32 * allocptr[MAX_ZLIB_ALLOCS]; +}; + +typedef struct _zlib_codec_data zlib_codec_data; +struct _zlib_codec_data +{ + z_stream inflater; + zlib_allocator allocator; +}; + +/* codec-private data for the LZMA codec */ +#define MAX_LZMA_ALLOCS 64 + +typedef struct _lzma_allocator lzma_allocator; +struct _lzma_allocator +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ + void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */ + uint32_t* allocptr[MAX_LZMA_ALLOCS]; +}; + +typedef struct _lzma_codec_data lzma_codec_data; +struct _lzma_codec_data +{ + CLzmaDec decoder; + lzma_allocator allocator; +}; + +/* codec-private data for the CDZL codec */ +typedef struct _cdzl_codec_data cdzl_codec_data; +struct _cdzl_codec_data { + // internal state + zlib_codec_data base_decompressor; + zlib_codec_data subcode_decompressor; + uint8_t* buffer; +}; + +/* codec-private data for the CDLZ codec */ +typedef struct _cdlz_codec_data cdlz_codec_data; +struct _cdlz_codec_data { + // internal state + lzma_codec_data base_decompressor; + zlib_codec_data subcode_decompressor; + uint8_t* buffer; +}; + +/* codec-private data for the CDFL codec */ +typedef struct _cdfl_codec_data cdfl_codec_data; +struct _cdfl_codec_data { + // internal state + int swap_endian; + flac_decoder decoder; + z_stream inflater; + zlib_allocator allocator; + uint8_t* buffer; +}; + +/* internal representation of an open CHD file */ +struct _chd_file +{ + UINT32 cookie; /* cookie, should equal COOKIE_VALUE */ + + core_file * file; /* handle to the open core file */ + UINT8 owns_file; /* flag indicating if this file should be closed on chd_close() */ + chd_header header; /* header, extracted from file */ + + chd_file * parent; /* pointer to parent file, or NULL */ + + map_entry * map; /* array of map entries */ + + UINT8 * cache; /* hunk cache pointer */ + UINT32 cachehunk; /* index of currently cached hunk */ + + UINT8 * compare; /* hunk compare pointer */ + UINT32 comparehunk; /* index of current compare data */ + + UINT8 * compressed; /* pointer to buffer for compressed data */ + const codec_interface * codecintf[4]; /* interface to the codec */ + + zlib_codec_data zlib_codec_data; /* zlib codec data */ + cdzl_codec_data cdzl_codec_data; /* cdzl codec data */ + cdlz_codec_data cdlz_codec_data; /* cdlz codec data */ + cdfl_codec_data cdfl_codec_data; /* cdfl codec data */ + + crcmap_entry * crcmap; /* CRC map entries */ + crcmap_entry * crcfree; /* free list CRC entries */ + crcmap_entry ** crctable; /* table of CRC entries */ + + UINT32 maxhunk; /* maximum hunk accessed */ + + UINT8 compressing; /* are we compressing? */ + MD5_CTX compmd5; /* running MD5 during compression */ + SHA1_CTX compsha1; /* running SHA1 during compression */ + UINT32 comphunk; /* next hunk we will compress */ + + UINT8 verifying; /* are we verifying? */ + MD5_CTX vermd5; /* running MD5 during verification */ + SHA1_CTX versha1; /* running SHA1 during verification */ + UINT32 verhunk; /* next hunk we will verify */ + + UINT32 async_hunknum; /* hunk index for asynchronous operations */ + void * async_buffer; /* buffer pointer for asynchronous operations */ +}; + + +/* a single metadata hash entry */ +typedef struct _metadata_hash metadata_hash; +struct _metadata_hash +{ + UINT8 tag[4]; /* tag of the metadata in big-endian */ + UINT8 sha1[CHD_SHA1_BYTES]; /* hash */ +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 }; +static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 }; + + + +/*************************************************************************** + PROTOTYPES +***************************************************************************/ + +/* internal header operations */ +static chd_error header_validate(const chd_header *header); +static chd_error header_read(core_file *file, chd_header *header); + + +/* internal hunk read/write */ +static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum); +static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest); + +/* internal map access */ +static chd_error map_read(chd_file *chd); + +/* metadata management */ +static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry); + + +/* zlib compression codec */ +static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes); +static void zlib_codec_free(void *codec); +static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); +static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size); +static void zlib_fast_free(voidpf opaque, voidpf address); + +/* lzma compression codec */ +static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes); +static void lzma_codec_free(void *codec); +static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* cdzl compression codec */ +static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes); +static void cdzl_codec_free(void* codec); +static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* cdlz compression codec */ +static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes); +static void cdlz_codec_free(void* codec); +static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* cdfl compression codec */ +static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes); +static void cdfl_codec_free(void* codec); +static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +//************************************************************************** +// LZMA ALLOCATOR HELPER +//************************************************************************** + +void *lzma_fast_alloc(void *p, size_t size); +void lzma_fast_free(void *p, void *address); + +//------------------------------------------------- +// lzma_allocator_init +//------------------------------------------------- + +void lzma_allocator_init(void* p) +{ + lzma_allocator *codec = (lzma_allocator *)(p); + + // reset pointer list + memset(codec->allocptr, 0, sizeof(codec->allocptr)); + codec->Alloc = lzma_fast_alloc; + codec->Free = lzma_fast_free; +} + +//------------------------------------------------- +// lzma_allocator_free +//------------------------------------------------- + +void lzma_allocator_free(void* p ) +{ + int i; + lzma_allocator *codec = (lzma_allocator *)(p); + + // free our memory + for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++) + { + if (codec->allocptr[i] != NULL) + free(codec->allocptr[i]); + } +} + +//------------------------------------------------- +// lzma_fast_alloc - fast malloc for lzma, which +// allocates and frees memory frequently +//------------------------------------------------- + +void *lzma_fast_alloc(void *p, size_t size) +{ + int scan; + uint32_t *addr = NULL; + lzma_allocator *codec = (lzma_allocator *)(p); + + // compute the size, rounding to the nearest 1k + size = (size + 0x3ff) & ~0x3ff; + + // reuse a hunk if we can + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + uint32_t *ptr = codec->allocptr[scan]; + if (ptr != NULL && size == *ptr) + { + // set the low bit of the size so we don't match next time + *ptr |= 1; + return ptr + 1; + } + } + + // alloc a new one and put it into the list + addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t))); + if (addr==NULL) + return NULL; + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + if (codec->allocptr[scan] == NULL) + { + codec->allocptr[scan] = addr; + break; + } + } + + // set the low bit of the size so we don't match next time + *addr = size | 1; + return addr + 1; +} + + +//------------------------------------------------- +// lzma_fast_free - fast free for lzma, which +// allocates and frees memory frequently +//------------------------------------------------- + +void lzma_fast_free(void *p, void *address) +{ + int scan; + uint32_t *ptr; + lzma_allocator *codec; + if (address == NULL) + return; + + codec = (lzma_allocator *)(p); + + // find the hunk + ptr = (uint32_t *)(address) - 1; + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + if (ptr == codec->allocptr[scan]) + { + // clear the low bit of the size to allow matches + *ptr &= ~1; + return; + } + } +} + +//************************************************************************** +// LZMA DECOMPRESSOR +//************************************************************************** + + +//------------------------------------------------- +// lzma_codec_init - constructor +//------------------------------------------------- + +chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) +{ + CLzmaEncHandle enc; + CLzmaEncProps encoder_props; + Byte decoder_props[LZMA_PROPS_SIZE]; + SizeT props_size; + lzma_allocator* alloc; + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + + // construct the decoder + LzmaDec_Construct(&lzma_codec->decoder); + + // FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK + // This code assumes that the current version of the encoder imposes the same requirements on the + // decoder as the encoder used to produce the file. This is not necessarily true. The format + // needs to be changed so the encoder properties are written to the file. + + // configure the properties like the compressor did + LzmaEncProps_Init(&encoder_props); + encoder_props.level = 9; + encoder_props.reduceSize = hunkbytes; + LzmaEncProps_Normalize(&encoder_props); + + // convert to decoder properties + alloc = &lzma_codec->allocator; + lzma_allocator_init(alloc); + enc = LzmaEnc_Create((ISzAlloc*)alloc); + if (!enc) + return CHDERR_DECOMPRESSION_ERROR; + if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK) + { + LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc); + return CHDERR_DECOMPRESSION_ERROR; + } + props_size = sizeof(decoder_props); + if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK) + { + LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); + return CHDERR_DECOMPRESSION_ERROR; + } + LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); + + // do memory allocations + if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK) + return CHDERR_DECOMPRESSION_ERROR; + + // Okay + return CHDERR_NONE; +} + + +//------------------------------------------------- +// lzma_codec_free +//------------------------------------------------- + +void lzma_codec_free(void* codec) +{ + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + + // free memory + LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator); +} + + +//------------------------------------------------- +// decompress - decompress data using the LZMA +// codec +//------------------------------------------------- + +chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + ELzmaStatus status; + SRes res; + SizeT consumedlen, decodedlen; + // initialize + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + LzmaDec_Init(&lzma_codec->decoder); + + // decode + consumedlen = complen; + decodedlen = destlen; + res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status); + if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen) + return CHDERR_DECOMPRESSION_ERROR; + return CHDERR_NONE; +} + +// cdlz +chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) +{ + cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; + + // allocate buffer + cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + + // make sure the CHD's hunk size is an even multiple of the frame size + lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); + + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + return CHDERR_NONE; +} + +void cdlz_codec_free(void* codec) +{ + // TODO +} + +chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + uint32_t framenum; + cdlz_codec_data* cdlz = (cdlz_codec_data*)codec; + + // determine header bytes + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + // extract compressed length of base + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + // reset and decode + lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA); + zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + + // reassemble the data + for (framenum = 0; framenum < frames; framenum++) + { + uint8_t *sector; + + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + + // reconstitute the ECC data and sync header + sector = &dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } + } + return CHDERR_NONE; +} + + +// cdzl + +chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) +{ + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + + // make sure the CHD's hunk size is an even multiple of the frame size + zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); + + cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + return CHDERR_NONE; +} + +void cdzl_codec_free(void *codec) +{ + // TODO +} + +chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + uint32_t framenum; + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + + // determine header bytes + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + // extract compressed length of base + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + // reset and decode + zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA); + zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + + // reassemble the data + for (framenum = 0; framenum < frames; framenum++) + { + uint8_t *sector; + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + + // reconstitute the ECC data and sync header + sector = &dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } + } + return CHDERR_NONE; +} + +//************************************************************************** +// CD FLAC DECOMPRESSOR +//************************************************************************** + + + +//------------------------------------------------------ +// cdfl_codec_blocksize - return the optimal block size +//------------------------------------------------------ + +static uint32_t cdfl_codec_blocksize(uint32_t bytes) +{ + // determine FLAC block size, which must be 16-65535 + // clamp to 2k since that's supposed to be the sweet spot + uint32_t hunkbytes = bytes / 4; + while (hunkbytes > 2048) + hunkbytes /= 2; + return hunkbytes; +} + +chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) +{ + int zerr; + uint16_t native_endian = 0; + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + + cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + + // make sure the CHD's hunk size is an even multiple of the frame size + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + // determine whether we want native or swapped samples + *(uint8_t *)(&native_endian) = 1; + cdfl->swap_endian = (native_endian & 1); + + // init the inflater + cdfl->inflater.next_in = (Bytef *)cdfl; // bogus, but that's ok + cdfl->inflater.avail_in = 0; + //cdfl->allocator.install(cdfl->inflater); + cdfl->inflater.zalloc = zlib_fast_alloc; + cdfl->inflater.zfree = zlib_fast_free; + cdfl->inflater.opaque = &cdfl->allocator; + zerr = inflateInit2(&cdfl->inflater, -MAX_WBITS); + + // convert errors + if (zerr == Z_MEM_ERROR) + return CHDERR_OUT_OF_MEMORY; + else if (zerr != Z_OK) + return CHDERR_CODEC_ERROR; + + // init flac decoder + flac_decoder_init(&cdfl->decoder); + + return CHDERR_NONE; +} + +void cdfl_codec_free(void *codec) +{ + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + inflateEnd(&cdfl->inflater); +} + +chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + int zerr; + uint8_t *buffer; + uint32_t framenum, offset; + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + + // reset and decode + uint32_t frames = destlen / CD_FRAME_SIZE; + if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) + return CHDERR_DECOMPRESSION_ERROR; + buffer = &cdfl->buffer[0]; + if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian)) + return CHDERR_DECOMPRESSION_ERROR; + + // inflate the subcode data + offset = flac_decoder_finish(&cdfl->decoder); + cdfl->inflater.next_in = (Bytef *)(src + offset); + cdfl->inflater.avail_in = complen - offset; + cdfl->inflater.total_in = 0; + cdfl->inflater.next_out = &cdfl->buffer[frames * CD_MAX_SECTOR_DATA]; + cdfl->inflater.avail_out = frames * CD_MAX_SUBCODE_DATA; + cdfl->inflater.total_out = 0; + zerr = inflateReset(&cdfl->inflater); + if (zerr != Z_OK) + return CHDERR_DECOMPRESSION_ERROR; + + // do it + zerr = inflate(&cdfl->inflater, Z_FINISH); + if (zerr != Z_STREAM_END) + return CHDERR_DECOMPRESSION_ERROR; + if (cdfl->inflater.total_out != frames * CD_MAX_SUBCODE_DATA) + return CHDERR_DECOMPRESSION_ERROR; + + // reassemble the data + for (framenum = 0; framenum < frames; framenum++) + { + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + } + + return CHDERR_NONE; +} +/*************************************************************************** + CODEC INTERFACES +***************************************************************************/ + +#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +// general codecs with CD frontend +#define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l') +#define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z') +#define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l') + +static const codec_interface codec_interfaces[] = +{ + /* "none" or no compression */ + { + CHDCOMPRESSION_NONE, + "none", + FALSE, + NULL, + NULL, + NULL, + NULL + }, + + /* standard zlib compression */ + { + CHDCOMPRESSION_ZLIB, + "zlib", + FALSE, + zlib_codec_init, + zlib_codec_free, + zlib_codec_decompress, + NULL + }, + + /* zlib+ compression */ + { + CHDCOMPRESSION_ZLIB_PLUS, + "zlib+", + FALSE, + zlib_codec_init, + zlib_codec_free, + zlib_codec_decompress, + NULL + }, + + /* V5 CD zlib compression */ + { + CHD_CODEC_CD_ZLIB, + "cdzl (CD Deflate)", + FALSE, + cdzl_codec_init, + cdzl_codec_free, + cdzl_codec_decompress, + NULL + }, + + /* V5 CD lzma compression */ + { + CHD_CODEC_CD_LZMA, + "cdlz (CD LZMA)", + FALSE, + cdlz_codec_init, + cdlz_codec_free, + cdlz_codec_decompress, + NULL + }, + + /* V5 CD flac compression */ + { + CHD_CODEC_CD_FLAC, + "cdfl (CD FLAC)", + FALSE, + cdfl_codec_init, + cdfl_codec_free, + cdfl_codec_decompress, + NULL + }, +}; + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + get_bigendian_uint64 - fetch a UINT64 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT64 get_bigendian_uint64(const UINT8 *base) +{ + return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) | + ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7]; +} + + +/*------------------------------------------------- + put_bigendian_uint64 - write a UINT64 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value) +{ + base[0] = value >> 56; + base[1] = value >> 48; + base[2] = value >> 40; + base[3] = value >> 32; + base[4] = value >> 24; + base[5] = value >> 16; + base[6] = value >> 8; + base[7] = value; +} + +/*------------------------------------------------- + get_bigendian_uint48 - fetch a UINT48 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT64 get_bigendian_uint48(const UINT8 *base) +{ + return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) | + ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5]; +} + +/*------------------------------------------------- + put_bigendian_uint48 - write a UINT48 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint48(UINT8 *base, UINT64 value) +{ + value &= 0xffffffffffff; + base[0] = value >> 40; + base[1] = value >> 32; + base[2] = value >> 24; + base[3] = value >> 16; + base[4] = value >> 8; + base[5] = value; +} +/*------------------------------------------------- + get_bigendian_uint32 - fetch a UINT32 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT32 get_bigendian_uint32(const UINT8 *base) +{ + return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3]; +} + + +/*------------------------------------------------- + put_bigendian_uint32 - write a UINT32 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value) +{ + value &= 0xffffff; + base[0] = value >> 16; + base[1] = value >> 8; + base[2] = value; +} + + +/*------------------------------------------------- + put_bigendian_uint24 - write a UINT24 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value) +{ + value &= 0xffffff; + base[0] = value >> 16; + base[1] = value >> 8; + base[2] = value; +} + +/*------------------------------------------------- + get_bigendian_uint24 - fetch a UINT24 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT32 get_bigendian_uint24(const UINT8 *base) +{ + return (base[0] << 16) | (base[1] << 8) | base[2]; +} + +/*------------------------------------------------- + get_bigendian_uint16 - fetch a UINT16 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT16 get_bigendian_uint16(const UINT8 *base) +{ + return (base[0] << 8) | base[1]; +} + + +/*------------------------------------------------- + put_bigendian_uint16 - write a UINT16 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value) +{ + base[0] = value >> 8; + base[1] = value; +} + + +/*------------------------------------------------- + map_extract - extract a single map + entry from the datastream +-------------------------------------------------*/ + +static INLINE void map_extract(const UINT8 *base, map_entry *entry) +{ + entry->offset = get_bigendian_uint64(&base[0]); + entry->crc = get_bigendian_uint32(&base[8]); + entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16); + entry->flags = base[15]; +} + + +/*------------------------------------------------- + map_assemble - write a single map + entry to the datastream +-------------------------------------------------*/ + +static INLINE void map_assemble(UINT8 *base, map_entry *entry) +{ + put_bigendian_uint64(&base[0], entry->offset); + put_bigendian_uint32(&base[8], entry->crc); + put_bigendian_uint16(&base[12], entry->length); + base[14] = entry->length >> 16; + base[15] = entry->flags; +} + +/*------------------------------------------------- + map_size_v5 - calculate CHDv5 map size +-------------------------------------------------*/ +static INLINE int map_size_v5(chd_header* header) +{ + return header->hunkcount * header->mapentrybytes; +} + + +/*------------------------------------------------- + crc16 - calculate CRC16 (from hashing.cpp) +-------------------------------------------------*/ +uint16_t crc16(const void *data, uint32_t length) +{ + uint16_t crc = 0xffff; + + static const uint16_t s_table[256] = + { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 + }; + + const uint8_t *src = (uint8_t*)data; + + // fetch the current value into a local and rip through the source data + while (length-- != 0) + crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++]; + return crc; +} + +/*------------------------------------------------- + decompress_v5_map - decompress the v5 map +-------------------------------------------------*/ + +static chd_error decompress_v5_map(chd_file* chd, chd_header* header) +{ + int hunknum; + uint8_t lastcomp = 0; + int repcount = 0; + uint32_t last_self = 0; + uint64_t last_parent = 0; + struct bitstream* bitbuf; + uint32_t mapbytes; + uint64_t firstoffs; + uint16_t mapcrc; + uint8_t lengthbits; + uint8_t selfbits; + uint8_t parentbits; + uint8_t *compressed; + uint8_t rawbuf[16]; + struct huffman_decoder* decoder; + enum huffman_error err; + uint64_t curoffset; + + if (header->mapoffset == 0) + { + //memset(header->rawmap, 0xff,map_size_v5(header)); + return CHDERR_READ_ERROR; + } + + // read the reader + core_fseek(chd->file, header->mapoffset, SEEK_SET); + core_fread(chd->file, rawbuf, sizeof(rawbuf)); + mapbytes = get_bigendian_uint32(&rawbuf[0]); + firstoffs = get_bigendian_uint48(&rawbuf[4]); + mapcrc = get_bigendian_uint16(&rawbuf[10]); + lengthbits = rawbuf[12]; + selfbits = rawbuf[13]; + parentbits = rawbuf[14]; + + // now read the map + compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); + core_fseek(chd->file, header->mapoffset + 16, SEEK_SET); + core_fread(chd->file, compressed, mapbytes); + bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes); + header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header)); + + // first decode the compression types + decoder = create_huffman_decoder(16, 8); + err = huffman_import_tree_rle(decoder, bitbuf); + if (err != HUFFERR_NONE) + return CHDERR_DECOMPRESSION_ERROR; + for (hunknum = 0; hunknum < header->hunkcount; hunknum++) + { + uint8_t *rawmap = header->rawmap + (hunknum * 12); + if (repcount > 0) + rawmap[0] = lastcomp, repcount--; + else + { + uint8_t val = huffman_decode_one(decoder, bitbuf); + if (val == COMPRESSION_RLE_SMALL) + rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf); + else if (val == COMPRESSION_RLE_LARGE) + rawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4), repcount += huffman_decode_one(decoder, bitbuf); + else + rawmap[0] = lastcomp = val; + } + } + + // then iterate through the hunks and extract the needed data + curoffset = firstoffs; + for (hunknum = 0; hunknum < header->hunkcount; hunknum++) + { + uint8_t *rawmap = header->rawmap + (hunknum * 12); + uint64_t offset = curoffset; + uint32_t length = 0; + uint16_t crc = 0; + switch (rawmap[0]) + { + // base types + case COMPRESSION_TYPE_0: + case COMPRESSION_TYPE_1: + case COMPRESSION_TYPE_2: + case COMPRESSION_TYPE_3: + curoffset += length = bitstream_read(bitbuf, lengthbits); + crc = bitstream_read(bitbuf, 16); + break; + + case COMPRESSION_NONE: + curoffset += length = header->hunkbytes; + crc = bitstream_read(bitbuf, 16); + break; + + case COMPRESSION_SELF: + last_self = offset = bitstream_read(bitbuf, selfbits); + break; + + case COMPRESSION_PARENT: + offset = bitstream_read(bitbuf, parentbits); + last_parent = offset; + break; + + // pseudo-types; convert into base types + case COMPRESSION_SELF_1: + last_self++; + case COMPRESSION_SELF_0: + rawmap[0] = COMPRESSION_SELF; + offset = last_self; + break; + + case COMPRESSION_PARENT_SELF: + rawmap[0] = COMPRESSION_PARENT; + last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes; + break; + + case COMPRESSION_PARENT_1: + last_parent += header->hunkbytes / header->unitbytes; + case COMPRESSION_PARENT_0: + rawmap[0] = COMPRESSION_PARENT; + offset = last_parent; + break; + } + // UINT24 length + put_bigendian_uint24(&rawmap[1], length); + + // UINT48 offset + put_bigendian_uint48(&rawmap[4], offset); + + // crc16 + put_bigendian_uint16(&rawmap[10], crc); + } + + // verify the final CRC + if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc) + return CHDERR_DECOMPRESSION_ERROR; + + return CHDERR_NONE; +} + +/*------------------------------------------------- + map_extract_old - extract a single map + entry in old format from the datastream +-------------------------------------------------*/ + +static INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes) +{ + entry->offset = get_bigendian_uint64(&base[0]); + entry->crc = 0; + entry->length = entry->offset >> 44; + entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED); +#ifdef __MWERKS__ + entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL; +#else + entry->offset = (entry->offset << 20) >> 20; +#endif +} + + +/*************************************************************************** + CHD FILE MANAGEMENT +***************************************************************************/ + + +/*------------------------------------------------- + chd_open_file - open a CHD file for access +-------------------------------------------------*/ + +chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd) +{ + chd_file *newchd = NULL; + chd_error err; + int intfnum; + + /* verify parameters */ + if (file == NULL) + EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); + + /* punt if invalid parent */ + if (parent != NULL && parent->cookie != COOKIE_VALUE) + EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); + + /* allocate memory for the final result */ + newchd = (chd_file *)malloc(sizeof(chd_file)); + if (newchd == NULL) + EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); + memset(newchd, 0, sizeof(chd_file)); + newchd->cookie = COOKIE_VALUE; + newchd->parent = parent; + newchd->file = file; + + /* now attempt to read the header */ + err = header_read(newchd->file, &newchd->header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + + /* validate the header */ + err = header_validate(&newchd->header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + + /* make sure we don't open a read-only file writeable */ + if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE)) + EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE); + + /* also, never open an older version writeable */ + if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION) + EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION); + + /* if we need a parent, make sure we have one */ + if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT)) + EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + + /* make sure we have a valid parent */ + if (parent != NULL) + { + /* check MD5 if it isn't empty */ + if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 && + memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 && + memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0) + EARLY_EXIT(err = CHDERR_INVALID_PARENT); + + /* check SHA1 if it isn't empty */ + if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 && + memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 && + memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0) + EARLY_EXIT(err = CHDERR_INVALID_PARENT); + } + + /* now read the hunk map */ + if (newchd->header.version < 5) + { + err = map_read(newchd); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + } + else + { + err = decompress_v5_map(newchd, &(newchd->header)); + } + + /* allocate and init the hunk cache */ + newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes); + newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes); + if (newchd->cache == NULL || newchd->compare == NULL) + EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); + newchd->cachehunk = ~0; + newchd->comparehunk = ~0; + + /* allocate the temporary compressed buffer */ + newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes); + if (newchd->compressed == NULL) + EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); + + /* find the codec interface */ + if (newchd->header.version < 5) + { + for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++) + if (codec_interfaces[intfnum].compression == newchd->header.compression[0]) + { + newchd->codecintf[0] = &codec_interfaces[intfnum]; + break; + } + if (intfnum == ARRAY_LENGTH(codec_interfaces)) + EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT); + + /* initialize the codec */ + if (newchd->codecintf[0]->init != NULL) + err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes); + } + else + { + int decompnum; + + // verify the compression types and initialize the codecs + for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++) + { + int i; + for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++) + { + if (codec_interfaces[i].compression == newchd->header.compression[decompnum]) + { + newchd->codecintf[decompnum] = &codec_interfaces[i]; + if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0) + err = CHDERR_UNSUPPORTED_FORMAT; + + /* initialize the codec */ + if (newchd->codecintf[decompnum]->init != NULL) + { + void* codec = NULL; + switch (newchd->header.compression[decompnum]) + { + case CHD_CODEC_CD_ZLIB: + codec = &newchd->cdzl_codec_data; + break; + + case CHD_CODEC_CD_LZMA: + codec = &newchd->cdlz_codec_data; + break; + + case CHD_CODEC_CD_FLAC: + codec = &newchd->cdfl_codec_data; + break; + } + if (codec != NULL) + { + err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes); + } + } + } + } + } + } + + // HACK + //if (err != CHDERR_NONE) + // EARLY_EXIT(err); + + /* all done */ + *chd = newchd; + return CHDERR_NONE; + +cleanup: + if (newchd != NULL) + chd_close(newchd); + return err; +} + +/*------------------------------------------------- + chd_open - open a CHD file by + filename +-------------------------------------------------*/ + +chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd) +{ + chd_error err; + core_file *file = NULL; + UINT32 openflags; + + /* choose the proper mode */ + switch(mode) + { + case CHD_OPEN_READ: + break; + + default: + err = CHDERR_INVALID_PARAMETER; + goto cleanup; + } + + /* open the file */ + file = core_fopen(filename); + if (file == 0) + { + err = CHDERR_FILE_NOT_FOUND; + goto cleanup; + } + + /* now open the CHD */ + err = chd_open_file(file, mode, parent, chd); + if (err != CHDERR_NONE) + goto cleanup; + + /* we now own this file */ + (*chd)->owns_file = TRUE; + +cleanup: + if ((err != CHDERR_NONE) && (file != NULL)) + core_fclose(file); + return err; +} + + +/*------------------------------------------------- + chd_close - close a CHD file for access +-------------------------------------------------*/ + +void chd_close(chd_file *chd) +{ + /* punt if NULL or invalid */ + if (chd == NULL || chd->cookie != COOKIE_VALUE) + return; + + /* deinit the codec */ + if (chd->header.version < 5) + { + if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL) + (*chd->codecintf[0]->free)(&chd->zlib_codec_data); + } + else + { + int i; + // Free the codecs + for (i = 0 ; i < 4 ; i++) + { + void* codec = NULL; + switch (chd->codecintf[i]->compression) + { + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + + case CHD_CODEC_CD_ZLIB: + codec = &chd->cdzl_codec_data; + break; + + case CHD_CODEC_CD_FLAC: + codec = &chd->cdfl_codec_data; + break; + } + if (codec) + { + (*chd->codecintf[i]->free)(codec); + } + } + + // Free the raw map + if (chd->header.rawmap != NULL) + free(chd->header.rawmap); + } + + /* free the compressed data buffer */ + if (chd->compressed != NULL) + free(chd->compressed); + + /* free the hunk cache and compare data */ + if (chd->compare != NULL) + free(chd->compare); + if (chd->cache != NULL) + free(chd->cache); + + /* free the hunk map */ + if (chd->map != NULL) + free(chd->map); + + /* free the CRC table */ + if (chd->crctable != NULL) + free(chd->crctable); + + /* free the CRC map */ + if (chd->crcmap != NULL) + free(chd->crcmap); + + /* close the file */ + if (chd->owns_file && chd->file != NULL) + core_fclose(chd->file); + + if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks); + + /* free our memory */ + free(chd); +} + + +/*------------------------------------------------- + chd_core_file - return the associated + core_file +-------------------------------------------------*/ + +core_file *chd_core_file(chd_file *chd) +{ + return chd->file; +} + + +/*------------------------------------------------- + chd_error_string - return an error string for + the given CHD error +-------------------------------------------------*/ + +const char *chd_error_string(chd_error err) +{ + switch (err) + { + case CHDERR_NONE: return "no error"; + case CHDERR_NO_INTERFACE: return "no drive interface"; + case CHDERR_OUT_OF_MEMORY: return "out of memory"; + case CHDERR_INVALID_FILE: return "invalid file"; + case CHDERR_INVALID_PARAMETER: return "invalid parameter"; + case CHDERR_INVALID_DATA: return "invalid data"; + case CHDERR_FILE_NOT_FOUND: return "file not found"; + case CHDERR_REQUIRES_PARENT: return "requires parent"; + case CHDERR_FILE_NOT_WRITEABLE: return "file not writeable"; + case CHDERR_READ_ERROR: return "read error"; + case CHDERR_WRITE_ERROR: return "write error"; + case CHDERR_CODEC_ERROR: return "codec error"; + case CHDERR_INVALID_PARENT: return "invalid parent"; + case CHDERR_HUNK_OUT_OF_RANGE: return "hunk out of range"; + case CHDERR_DECOMPRESSION_ERROR: return "decompression error"; + case CHDERR_COMPRESSION_ERROR: return "compression error"; + case CHDERR_CANT_CREATE_FILE: return "can't create file"; + case CHDERR_CANT_VERIFY: return "can't verify file"; + case CHDERR_NOT_SUPPORTED: return "operation not supported"; + case CHDERR_METADATA_NOT_FOUND: return "can't find metadata"; + case CHDERR_INVALID_METADATA_SIZE: return "invalid metadata size"; + case CHDERR_UNSUPPORTED_VERSION: return "unsupported CHD version"; + case CHDERR_VERIFY_INCOMPLETE: return "incomplete verify"; + case CHDERR_INVALID_METADATA: return "invalid metadata"; + case CHDERR_INVALID_STATE: return "invalid state"; + case CHDERR_OPERATION_PENDING: return "operation pending"; + case CHDERR_NO_ASYNC_OPERATION: return "no async operation in progress"; + case CHDERR_UNSUPPORTED_FORMAT: return "unsupported format"; + default: return "undocumented error"; + } +} + + + +/*************************************************************************** + CHD HEADER MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + chd_get_header - return a pointer to the + extracted header data +-------------------------------------------------*/ + +const chd_header *chd_get_header(chd_file *chd) +{ + /* punt if NULL or invalid */ + if (chd == NULL || chd->cookie != COOKIE_VALUE) + return NULL; + + return &chd->header; +} + + + +/*************************************************************************** + CORE DATA READ/WRITE +***************************************************************************/ + +/*------------------------------------------------- + chd_read - read a single hunk from the CHD + file +-------------------------------------------------*/ + +chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) +{ + /* punt if NULL or invalid */ + if (chd == NULL || chd->cookie != COOKIE_VALUE) + return CHDERR_INVALID_PARAMETER; + + /* if we're past the end, fail */ + if (hunknum >= chd->header.totalhunks) + return CHDERR_HUNK_OUT_OF_RANGE; + + /* perform the read */ + return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer); +} + + + + + +/*************************************************************************** + METADATA MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + chd_get_metadata - get the indexed metadata + of the given type +-------------------------------------------------*/ + +chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags) +{ + metadata_entry metaentry; + chd_error err; + UINT32 count; + + /* if we didn't find it, just return */ + err = metadata_find_entry(chd, searchtag, searchindex, &metaentry); + if (err != CHDERR_NONE) + { + /* unless we're an old version and they are requesting hard disk metadata */ + if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0) + { + char faux_metadata[256]; + UINT32 faux_length; + + /* fill in the faux metadata */ + sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize); + faux_length = (UINT32)strlen(faux_metadata) + 1; + + /* copy the metadata itself */ + memcpy(output, faux_metadata, MIN(outputlen, faux_length)); + + /* return the length of the data and the tag */ + if (resultlen != NULL) + *resultlen = faux_length; + if (resulttag != NULL) + *resulttag = HARD_DISK_METADATA_TAG; + return CHDERR_NONE; + } + return err; + } + + /* read the metadata */ + outputlen = MIN(outputlen, metaentry.length); + core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET); + count = core_fread(chd->file, output, outputlen); + if (count != outputlen) + return CHDERR_READ_ERROR; + + /* return the length of the data and the tag */ + if (resultlen != NULL) + *resultlen = metaentry.length; + if (resulttag != NULL) + *resulttag = metaentry.metatag; + if (resultflags != NULL) + *resultflags = metaentry.flags; + return CHDERR_NONE; +} + + + +/*************************************************************************** + CODEC INTERFACES +***************************************************************************/ + +/*------------------------------------------------- + chd_codec_config - set internal codec + parameters +-------------------------------------------------*/ + +chd_error chd_codec_config(chd_file *chd, int param, void *config) +{ + + return CHDERR_INVALID_PARAMETER; +} + + +/*------------------------------------------------- + chd_get_codec_name - get the name of a + particular codec +-------------------------------------------------*/ + +const char *chd_get_codec_name(UINT32 codec) +{ + return "Unknown"; +} + + +/*************************************************************************** + INTERNAL HEADER OPERATIONS +***************************************************************************/ + +/*------------------------------------------------- + header_validate - check the validity of a + CHD header +-------------------------------------------------*/ + +static chd_error header_validate(const chd_header *header) +{ + int intfnum; + + /* require a valid version */ + if (header->version == 0 || header->version > CHD_HEADER_VERSION) + return CHDERR_UNSUPPORTED_VERSION; + + /* require a valid length */ + if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) || + (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) || + (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) || + (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) || + (header->version == 5 && header->length != CHD_V5_HEADER_SIZE)) + return CHDERR_INVALID_PARAMETER; + + /* Do not validate v5 header */ + if (header->version <= 4) + { + /* require valid flags */ + if (header->flags & CHDFLAGS_UNDEFINED) + return CHDERR_INVALID_PARAMETER; + + /* require a supported compression mechanism */ + for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++) + if (codec_interfaces[intfnum].compression == header->compression[0]) + break; + + if (intfnum == ARRAY_LENGTH(codec_interfaces)) + return CHDERR_INVALID_PARAMETER; + + /* require a valid hunksize */ + if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256) + return CHDERR_INVALID_PARAMETER; + + /* require a valid hunk count */ + if (header->totalhunks == 0) + return CHDERR_INVALID_PARAMETER; + + /* require a valid MD5 and/or SHA1 if we're using a parent */ + if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0) + return CHDERR_INVALID_PARAMETER; + + /* if we're V3 or later, the obsolete fields must be 0 */ + if (header->version >= 3 && + (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 || + header->obsolete_heads != 0 || header->obsolete_hunksize != 0)) + return CHDERR_INVALID_PARAMETER; + + /* if we're pre-V3, the obsolete fields must NOT be 0 */ + if (header->version < 3 && + (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 || + header->obsolete_heads == 0 || header->obsolete_hunksize == 0)) + return CHDERR_INVALID_PARAMETER; + } + + return CHDERR_NONE; +} + + +/*------------------------------------------------- + header_read - read a CHD header into the + internal data structure +-------------------------------------------------*/ + +static chd_error header_read(core_file *file, chd_header *header) +{ + UINT8 rawheader[CHD_MAX_HEADER_SIZE]; + UINT32 count; + + /* punt if NULL */ + if (header == NULL) + return CHDERR_INVALID_PARAMETER; + + /* punt if invalid file */ + if (file == NULL) + return CHDERR_INVALID_FILE; + + /* seek and read */ + core_fseek(file, 0, SEEK_SET); + count = core_fread(file, rawheader, sizeof(rawheader)); + if (count != sizeof(rawheader)) + return CHDERR_READ_ERROR; + + /* verify the tag */ + if (strncmp((char *)rawheader, "MComprHD", 8) != 0) + return CHDERR_INVALID_DATA; + + /* extract the direct data */ + memset(header, 0, sizeof(*header)); + header->length = get_bigendian_uint32(&rawheader[8]); + header->version = get_bigendian_uint32(&rawheader[12]); + + /* make sure it's a version we understand */ + if (header->version == 0 || header->version > CHD_HEADER_VERSION) + return CHDERR_UNSUPPORTED_VERSION; + + /* make sure the length is expected */ + if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) || + (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) || + (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) || + (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) || + (header->version == 5 && header->length != CHD_V5_HEADER_SIZE)) + + return CHDERR_INVALID_DATA; + + /* extract the common data */ + header->flags = get_bigendian_uint32(&rawheader[16]); + header->compression[0] = get_bigendian_uint32(&rawheader[20]); + + /* extract the V1/V2-specific data */ + if (header->version < 3) + { + int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]); + header->obsolete_hunksize = get_bigendian_uint32(&rawheader[24]); + header->totalhunks = get_bigendian_uint32(&rawheader[28]); + header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]); + header->obsolete_heads = get_bigendian_uint32(&rawheader[36]); + header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]); + memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES); + memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); + header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen; + header->hunkbytes = seclen * header->obsolete_hunksize; + header->metaoffset = 0; + } + + /* extract the V3-specific data */ + else if (header->version == 3) + { + header->totalhunks = get_bigendian_uint32(&rawheader[24]); + header->logicalbytes = get_bigendian_uint64(&rawheader[28]); + header->metaoffset = get_bigendian_uint64(&rawheader[36]); + memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES); + memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); + header->hunkbytes = get_bigendian_uint32(&rawheader[76]); + memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES); + memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES); + } + + /* extract the V4-specific data */ + else if (header->version == 4) + { + header->totalhunks = get_bigendian_uint32(&rawheader[24]); + header->logicalbytes = get_bigendian_uint64(&rawheader[28]); + header->metaoffset = get_bigendian_uint64(&rawheader[36]); + header->hunkbytes = get_bigendian_uint32(&rawheader[44]); + memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES); + memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES); + memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES); + } + + /* extract the V5-specific data */ + else if (header->version == 5) + { + /* TODO */ + header->compression[0] = get_bigendian_uint32(&rawheader[16]); + header->compression[1] = get_bigendian_uint32(&rawheader[20]); + header->compression[2] = get_bigendian_uint32(&rawheader[24]); + header->compression[3] = get_bigendian_uint32(&rawheader[28]); + header->logicalbytes = get_bigendian_uint64(&rawheader[32]); + header->mapoffset = get_bigendian_uint64(&rawheader[40]); + header->metaoffset = get_bigendian_uint64(&rawheader[48]); + header->hunkbytes = get_bigendian_uint32(&rawheader[56]); + header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes; + header->unitbytes = get_bigendian_uint32(&rawheader[60]); + header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; + memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES); + memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES); + memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES); + + // determine properties of map entries + header->mapentrybytes = 12; //TODO compressed() ? 12 : 4; + + // hack + header->totalhunks = header->hunkcount; + } + + /* Unknown version */ + else + { + /* TODO */ + } + + /* guess it worked */ + return CHDERR_NONE; +} + + +/*************************************************************************** + INTERNAL HUNK READ/WRITE +***************************************************************************/ + +/*------------------------------------------------- + hunk_read_into_cache - read a hunk into + the CHD's hunk cache +-------------------------------------------------*/ + +static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) +{ + chd_error err; + + /* track the max */ + if (hunknum > chd->maxhunk) + chd->maxhunk = hunknum; + + /* if we're already in the cache, we're done */ + if (chd->cachehunk == hunknum) + return CHDERR_NONE; + chd->cachehunk = ~0; + + /* otherwise, read the data */ + err = hunk_read_into_memory(chd, hunknum, chd->cache); + if (err != CHDERR_NONE) + return err; + + /* mark the hunk successfully cached in */ + chd->cachehunk = hunknum; + return CHDERR_NONE; +} + + +/*------------------------------------------------- + hunk_read_into_memory - read a hunk into + memory at the given location +-------------------------------------------------*/ + +static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest) +{ + chd_error err; + + // punt if no file + if (chd->file == NULL) + return CHDERR_INVALID_FILE; + + /* return an error if out of range */ + if (hunknum >= chd->header.totalhunks) + return CHDERR_HUNK_OUT_OF_RANGE; + + if (chd->header.version < 5) + { + map_entry *entry = &chd->map[hunknum]; + UINT32 bytes; + + /* switch off the entry type */ + switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK) + { + /* compressed data */ + case V34_MAP_ENTRY_TYPE_COMPRESSED: + { + void* codec; + /* read it into the decompression buffer */ + core_fseek(chd->file, entry->offset, SEEK_SET); + bytes = core_fread(chd->file, chd->compressed, entry->length); + if (bytes != entry->length) + return CHDERR_READ_ERROR; + + /* now decompress using the codec */ + err = CHDERR_NONE; + codec = &chd->zlib_codec_data; + if (chd->codecintf[0]->decompress != NULL) + err = (*chd->codecintf[0]->decompress)(codec, chd->compressed, entry->length, dest, chd->header.hunkbytes); + if (err != CHDERR_NONE) + return err; + } + break; + + /* uncompressed data */ + case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: + core_fseek(chd->file, entry->offset, SEEK_SET); + bytes = core_fread(chd->file, dest, chd->header.hunkbytes); + if (bytes != chd->header.hunkbytes) + return CHDERR_READ_ERROR; + break; + + /* mini-compressed data */ + case V34_MAP_ENTRY_TYPE_MINI: + put_bigendian_uint64(&dest[0], entry->offset); + for (bytes = 8; bytes < chd->header.hunkbytes; bytes++) + dest[bytes] = dest[bytes - 8]; + break; + + /* self-referenced data */ + case V34_MAP_ENTRY_TYPE_SELF_HUNK: + if (chd->cachehunk == entry->offset && dest == chd->cache) + break; + return hunk_read_into_memory(chd, entry->offset, dest); + + /* parent-referenced data */ + case V34_MAP_ENTRY_TYPE_PARENT_HUNK: + err = hunk_read_into_memory(chd->parent, entry->offset, dest); + if (err != CHDERR_NONE) + return err; + break; + } + return CHDERR_NONE; + } + else + { + + // get a pointer to the map entry + uint64_t blockoffs; + uint32_t blocklen; + uint16_t blockcrc; + void* codec = NULL; + uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum]; + + // uncompressed case + /* TODO + if (!compressed()) + { + blockoffs = uint64_t(be_read(rawmap, 4)) * uint64_t(m_hunkbytes); + if (blockoffs != 0) + file_read(blockoffs, dest, m_hunkbytes); + else if (m_parent_missing) + throw CHDERR_REQUIRES_PARENT; + else if (m_parent != nullptr) + m_parent->read_hunk(hunknum, dest); + else + memset(dest, 0, m_hunkbytes); + return CHDERR_NONE; + }*/ + + // compressed case + blocklen = get_bigendian_uint24(&rawmap[1]); + blockoffs = get_bigendian_uint48(&rawmap[4]); + blockcrc = get_bigendian_uint16(&rawmap[10]); + switch (rawmap[0]) + { + case COMPRESSION_TYPE_0: + case COMPRESSION_TYPE_1: + case COMPRESSION_TYPE_2: + case COMPRESSION_TYPE_3: + core_fseek(chd->file, blockoffs, SEEK_SET); + core_fread(chd->file, chd->compressed, blocklen); + switch (chd->codecintf[rawmap[0]]->compression) + { + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + + case CHD_CODEC_CD_ZLIB: + codec = &chd->cdzl_codec_data; + break; + + case CHD_CODEC_CD_FLAC: + codec = &chd->cdfl_codec_data; + break; + } + if (codec==NULL) + return CHDERR_DECOMPRESSION_ERROR; + chd->codecintf[rawmap[0]]->decompress(codec, chd->compressed, blocklen, dest, chd->header.hunkbytes); + if (dest != NULL && crc16(dest, chd->header.hunkbytes) != blockcrc) + return CHDERR_DECOMPRESSION_ERROR; + return CHDERR_NONE; + + case COMPRESSION_NONE: + core_fseek(chd->file, blockoffs, SEEK_SET); + core_fread(chd->file, dest, chd->header.hunkbytes); + if (crc16(dest, chd->header.hunkbytes) != blockcrc) + return CHDERR_DECOMPRESSION_ERROR; + return CHDERR_NONE; + + case COMPRESSION_SELF: + return hunk_read_into_memory(chd, blockoffs, dest); + + case COMPRESSION_PARENT: + // TODO + //if (m_parent_missing) + // return CHDERR_REQUIRES_PARENT; + //return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); + return CHDERR_DECOMPRESSION_ERROR; + } + return CHDERR_NONE; + } + + // We should not reach this code + return CHDERR_DECOMPRESSION_ERROR; +} + + +/*************************************************************************** + INTERNAL MAP ACCESS +***************************************************************************/ + +/*------------------------------------------------- + map_read - read the initial sector map +-------------------------------------------------*/ + +static chd_error map_read(chd_file *chd) +{ + UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE; + UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE]; + UINT64 fileoffset, maxoffset = 0; + UINT8 cookie[MAP_ENTRY_SIZE]; + UINT32 count; + chd_error err; + int i; + + /* first allocate memory */ + chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks); + if (!chd->map) + return CHDERR_OUT_OF_MEMORY; + + /* read the map entries in in chunks and extract to the map list */ + fileoffset = chd->header.length; + for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES) + { + /* compute how many entries this time */ + int entries = chd->header.totalhunks - i, j; + if (entries > MAP_STACK_ENTRIES) + entries = MAP_STACK_ENTRIES; + + /* read that many */ + core_fseek(chd->file, fileoffset, SEEK_SET); + count = core_fread(chd->file, raw_map_entries, entries * entrysize); + if (count != entries * entrysize) + { + err = CHDERR_READ_ERROR; + goto cleanup; + } + fileoffset += entries * entrysize; + + /* process that many */ + if (entrysize == MAP_ENTRY_SIZE) + { + for (j = 0; j < entries; j++) + map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]); + } + else + { + for (j = 0; j < entries; j++) + map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes); + } + + /* track the maximum offset */ + for (j = 0; j < entries; j++) + if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED || + (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED) + maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length); + } + + /* verify the cookie */ + core_fseek(chd->file, fileoffset, SEEK_SET); + count = core_fread(chd->file, &cookie, entrysize); + if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize)) + { + err = CHDERR_INVALID_FILE; + goto cleanup; + } + + /* verify the length */ + if (maxoffset > core_fsize(chd->file)) + { + err = CHDERR_INVALID_FILE; + goto cleanup; + } + return CHDERR_NONE; + +cleanup: + if (chd->map) + free(chd->map); + chd->map = NULL; + return err; +} + + + + +/*************************************************************************** + INTERNAL METADATA ACCESS +***************************************************************************/ + +/*------------------------------------------------- + metadata_find_entry - find a metadata entry +-------------------------------------------------*/ + +static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry) +{ + /* start at the beginning */ + metaentry->offset = chd->header.metaoffset; + metaentry->prev = 0; + + /* loop until we run out of options */ + while (metaentry->offset != 0) + { + UINT8 raw_meta_header[METADATA_HEADER_SIZE]; + UINT32 count; + + /* read the raw header */ + core_fseek(chd->file, metaentry->offset, SEEK_SET); + count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header)); + if (count != sizeof(raw_meta_header)) + break; + + /* extract the data */ + metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]); + metaentry->length = get_bigendian_uint32(&raw_meta_header[4]); + metaentry->next = get_bigendian_uint64(&raw_meta_header[8]); + + /* flags are encoded in the high byte of length */ + metaentry->flags = metaentry->length >> 24; + metaentry->length &= 0x00ffffff; + + /* if we got a match, proceed */ + if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag) + if (metaindex-- == 0) + return CHDERR_NONE; + + /* no match, fetch the next link */ + metaentry->prev = metaentry->offset; + metaentry->offset = metaentry->next; + } + + /* if we get here, we didn't find it */ + return CHDERR_METADATA_NOT_FOUND; +} + + + +/*************************************************************************** + ZLIB COMPRESSION CODEC +***************************************************************************/ + +/*------------------------------------------------- + zlib_codec_init - initialize the ZLIB codec +-------------------------------------------------*/ + +static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) +{ + zlib_codec_data *data = (zlib_codec_data*)codec; + chd_error err; + int zerr; + + /* clear the buffers */ + memset(data, 0, sizeof(zlib_codec_data)); + + /* init the inflater first */ + data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */ + data->inflater.avail_in = 0; + data->inflater.zalloc = zlib_fast_alloc; + data->inflater.zfree = zlib_fast_free; + data->inflater.opaque = &data->allocator; + zerr = inflateInit2(&data->inflater, -MAX_WBITS); + + /* convert errors */ + if (zerr == Z_MEM_ERROR) + err = CHDERR_OUT_OF_MEMORY; + else if (zerr != Z_OK) + err = CHDERR_CODEC_ERROR; + else + err = CHDERR_NONE; + + /* handle an error */ + if (err != CHDERR_NONE) + free(data); + + return err; +} + + +/*------------------------------------------------- + zlib_codec_free - free data for the ZLIB + codec +-------------------------------------------------*/ + +static void zlib_codec_free(void *codec) +{ + zlib_codec_data *data = (zlib_codec_data *)codec; + + /* deinit the streams */ + if (data != NULL) + { + int i; + zlib_allocator alloc; + + inflateEnd(&data->inflater); + + /* free our fast memory */ + alloc = data->allocator; + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (alloc.allocptr[i]) + free(alloc.allocptr[i]); + } +} + + +/*------------------------------------------------- + zlib_codec_decompress - decomrpess data using + the ZLIB codec +-------------------------------------------------*/ + +static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + zlib_codec_data *data = (zlib_codec_data *)codec; + int zerr; + + /* reset the decompressor */ + data->inflater.next_in = (Bytef *)src; + data->inflater.avail_in = complen; + data->inflater.total_in = 0; + data->inflater.next_out = (Bytef *)dest; + data->inflater.avail_out = destlen; + data->inflater.total_out = 0; + zerr = inflateReset(&data->inflater); + if (zerr != Z_OK) + return CHDERR_DECOMPRESSION_ERROR; + + /* do it */ + zerr = inflate(&data->inflater, Z_FINISH); + if (data->inflater.total_out != destlen) + return CHDERR_DECOMPRESSION_ERROR; + + return CHDERR_NONE; +} + + +/*------------------------------------------------- + zlib_fast_alloc - fast malloc for ZLIB, which + allocates and frees memory frequently +-------------------------------------------------*/ + +static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) +{ + zlib_allocator *alloc = (zlib_allocator *)opaque; + UINT32 *ptr; + int i; + + /* compute the size, rounding to the nearest 1k */ + size = (size * items + 0x3ff) & ~0x3ff; + + /* reuse a hunk if we can */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + { + ptr = alloc->allocptr[i]; + if (ptr && size == *ptr) + { + /* set the low bit of the size so we don't match next time */ + *ptr |= 1; + return ptr + 1; + } + } + + /* alloc a new one */ + ptr = (UINT32 *)malloc(size + sizeof(UINT32)); + if (!ptr) + return NULL; + + /* put it into the list */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (!alloc->allocptr[i]) + { + alloc->allocptr[i] = ptr; + break; + } + + /* set the low bit of the size so we don't match next time */ + *ptr = size | 1; + return ptr + 1; +} + + +/*------------------------------------------------- + zlib_fast_free - fast free for ZLIB, which + allocates and frees memory frequently +-------------------------------------------------*/ + +static void zlib_fast_free(voidpf opaque, voidpf address) +{ + zlib_allocator *alloc = (zlib_allocator *)opaque; + UINT32 *ptr = (UINT32 *)address - 1; + int i; + + /* find the hunk */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (ptr == alloc->allocptr[i]) + { + /* clear the low bit of the size to allow matches */ + *ptr &= ~1; + return; + } +} diff --git a/libretro-common/formats/libchdr/chd.h b/libretro-common/formats/libchdr/chd.h new file mode 100644 index 0000000000..a3a44b840a --- /dev/null +++ b/libretro-common/formats/libchdr/chd.h @@ -0,0 +1,399 @@ +/*************************************************************************** + + chd.h + + MAME Compressed Hunks of Data file format + +**************************************************************************** + + Copyright Aaron Giles + 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 'MAME' 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 AARON GILES ''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 AARON GILES 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. + +***************************************************************************/ + +#pragma once + +#ifndef __CHD_H__ +#define __CHD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "coretypes.h" + + +/*************************************************************************** + + Compressed Hunks of Data header format. All numbers are stored in + Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2) + bytes long. + + V1 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 hunksize; // 512-byte sectors per hunk + [ 28] UINT32 totalhunks; // total # of hunks represented + [ 32] UINT32 cylinders; // number of cylinders on hard disk + [ 36] UINT32 heads; // number of heads on hard disk + [ 40] UINT32 sectors; // number of sectors on hard disk + [ 44] UINT8 md5[16]; // MD5 checksum of raw data + [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file + [ 76] (V1 header length) + + V2 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 hunksize; // seclen-byte sectors per hunk + [ 28] UINT32 totalhunks; // total # of hunks represented + [ 32] UINT32 cylinders; // number of cylinders on hard disk + [ 36] UINT32 heads; // number of heads on hard disk + [ 40] UINT32 sectors; // number of sectors on hard disk + [ 44] UINT8 md5[16]; // MD5 checksum of raw data + [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file + [ 76] UINT32 seclen; // number of bytes per sector + [ 80] (V2 header length) + + V3 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 totalhunks; // total # of hunks represented + [ 28] UINT64 logicalbytes; // logical size of the data (in bytes) + [ 36] UINT64 metaoffset; // offset to the first blob of metadata + [ 44] UINT8 md5[16]; // MD5 checksum of raw data + [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file + [ 76] UINT32 hunkbytes; // number of bytes per hunk + [ 80] UINT8 sha1[20]; // SHA1 checksum of raw data + [100] UINT8 parentsha1[20];// SHA1 checksum of parent file + [120] (V3 header length) + + V4 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 totalhunks; // total # of hunks represented + [ 28] UINT64 logicalbytes; // logical size of the data (in bytes) + [ 36] UINT64 metaoffset; // offset to the first blob of metadata + [ 44] UINT32 hunkbytes; // number of bytes per hunk + [ 48] UINT8 sha1[20]; // combined raw+meta SHA1 + [ 68] UINT8 parentsha1[20];// combined raw+meta SHA1 of parent + [ 88] UINT8 rawsha1[20]; // raw data SHA1 + [108] (V4 header length) + + Flags: + 0x00000001 - set if this drive has a parent + 0x00000002 - set if this drive allows writes + + ========================================================================= + + V5 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] uint32_t length; // length of header (including tag and length fields) + [ 12] uint32_t version; // drive format version + [ 16] uint32_t compressors[4];// which custom compressors are used? + [ 32] uint64_t logicalbytes; // logical size of the data (in bytes) + [ 40] uint64_t mapoffset; // offset to the map + [ 48] uint64_t metaoffset; // offset to the first blob of metadata + [ 56] uint32_t hunkbytes; // number of bytes per hunk (512k maximum) + [ 60] uint32_t unitbytes; // number of bytes per unit within each hunk + [ 64] uint8_t rawsha1[20]; // raw data SHA1 + [ 84] uint8_t sha1[20]; // combined raw+meta SHA1 + [104] uint8_t parentsha1[20];// combined raw+meta SHA1 of parent + [124] (V5 header length) + + If parentsha1 != 0, we have a parent (no need for flags) + If compressors[0] == 0, we are uncompressed (including maps) + + V5 uncompressed map format: + + [ 0] uint32_t offset; // starting offset / hunk size + + V5 compressed map format header: + + [ 0] uint32_t length; // length of compressed map + [ 4] UINT48 datastart; // offset of first block + [ 10] uint16_t crc; // crc-16 of the map + [ 12] uint8_t lengthbits; // bits used to encode complength + [ 13] uint8_t hunkbits; // bits used to encode self-refs + [ 14] uint8_t parentunitbits; // bits used to encode parent unit refs + [ 15] uint8_t reserved; // future use + [ 16] (compressed header length) + + Each compressed map entry, once expanded, looks like: + + [ 0] uint8_t compression; // compression type + [ 1] UINT24 complength; // compressed length + [ 4] UINT48 offset; // offset + [ 10] uint16_t crc; // crc-16 of the data + +***************************************************************************/ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* header information */ +#define CHD_HEADER_VERSION 5 +#define CHD_V1_HEADER_SIZE 76 +#define CHD_V2_HEADER_SIZE 80 +#define CHD_V3_HEADER_SIZE 120 +#define CHD_V4_HEADER_SIZE 108 +#define CHD_V5_HEADER_SIZE 124 + +#define CHD_MAX_HEADER_SIZE CHD_V5_HEADER_SIZE + +/* checksumming information */ +#define CHD_MD5_BYTES 16 +#define CHD_SHA1_BYTES 20 + +/* CHD global flags */ +#define CHDFLAGS_HAS_PARENT 0x00000001 +#define CHDFLAGS_IS_WRITEABLE 0x00000002 +#define CHDFLAGS_UNDEFINED 0xfffffffc + +/* compression types */ +#define CHDCOMPRESSION_NONE 0 +#define CHDCOMPRESSION_ZLIB 1 +#define CHDCOMPRESSION_ZLIB_PLUS 2 +#define CHDCOMPRESSION_AV 3 + +/* A/V codec configuration parameters */ +#define AV_CODEC_COMPRESS_CONFIG 1 +#define AV_CODEC_DECOMPRESS_CONFIG 2 + +/* metadata parameters */ +#define CHDMETATAG_WILDCARD 0 +#define CHD_METAINDEX_APPEND ((UINT32)-1) + +/* metadata flags */ +#define CHD_MDFLAGS_CHECKSUM 0x01 /* indicates data is checksummed */ + +/* standard hard disk metadata */ +#define HARD_DISK_METADATA_TAG 0x47444444 /* 'GDDD' */ +#define HARD_DISK_METADATA_FORMAT "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d" + +/* hard disk identify information */ +#define HARD_DISK_IDENT_METADATA_TAG 0x49444e54 /* 'IDNT' */ + +/* hard disk key information */ +#define HARD_DISK_KEY_METADATA_TAG 0x4b455920 /* 'KEY ' */ + +/* pcmcia CIS information */ +#define PCMCIA_CIS_METADATA_TAG 0x43495320 /* 'CIS ' */ + +/* standard CD-ROM metadata */ +#define CDROM_OLD_METADATA_TAG 0x43484344 /* 'CHCD' */ +#define CDROM_TRACK_METADATA_TAG 0x43485452 /* 'CHTR' */ +#define CDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d" +#define CDROM_TRACK_METADATA2_TAG 0x43485432 /* 'CHT2' */ +#define CDROM_TRACK_METADATA2_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" +#define GDROM_TRACK_METADATA_TAG 0x43484744 /* 'CHTD' */ +#define GDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" + +/* standard A/V metadata */ +#define AV_METADATA_TAG 0x41564156 /* 'AVAV' */ +#define AV_METADATA_FORMAT "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d" + +/* A/V laserdisc frame metadata */ +#define AV_LD_METADATA_TAG 0x41564C44 /* 'AVLD' */ + +/* CHD open values */ +#define CHD_OPEN_READ 1 +#define CHD_OPEN_READWRITE 2 + +/* error types */ +enum _chd_error +{ + CHDERR_NONE, + CHDERR_NO_INTERFACE, + CHDERR_OUT_OF_MEMORY, + CHDERR_INVALID_FILE, + CHDERR_INVALID_PARAMETER, + CHDERR_INVALID_DATA, + CHDERR_FILE_NOT_FOUND, + CHDERR_REQUIRES_PARENT, + CHDERR_FILE_NOT_WRITEABLE, + CHDERR_READ_ERROR, + CHDERR_WRITE_ERROR, + CHDERR_CODEC_ERROR, + CHDERR_INVALID_PARENT, + CHDERR_HUNK_OUT_OF_RANGE, + CHDERR_DECOMPRESSION_ERROR, + CHDERR_COMPRESSION_ERROR, + CHDERR_CANT_CREATE_FILE, + CHDERR_CANT_VERIFY, + CHDERR_NOT_SUPPORTED, + CHDERR_METADATA_NOT_FOUND, + CHDERR_INVALID_METADATA_SIZE, + CHDERR_UNSUPPORTED_VERSION, + CHDERR_VERIFY_INCOMPLETE, + CHDERR_INVALID_METADATA, + CHDERR_INVALID_STATE, + CHDERR_OPERATION_PENDING, + CHDERR_NO_ASYNC_OPERATION, + CHDERR_UNSUPPORTED_FORMAT +}; +typedef enum _chd_error chd_error; + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* opaque types */ +typedef struct _chd_file chd_file; + + +/* extract header structure (NOT the on-disk header structure) */ +typedef struct _chd_header chd_header; +struct _chd_header +{ + UINT32 length; /* length of header data */ + UINT32 version; /* drive format version */ + UINT32 flags; /* flags field */ + UINT32 compression[4]; /* compression type */ + UINT32 hunkbytes; /* number of bytes per hunk */ + UINT32 totalhunks; /* total # of hunks represented */ + UINT64 logicalbytes; /* logical size of the data */ + UINT64 metaoffset; /* offset in file of first metadata */ + UINT64 mapoffset; /* TOOD V5 */ + UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ + UINT8 parentmd5[CHD_MD5_BYTES]; /* overall MD5 checksum of parent */ + UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ + UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ + UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */ + UINT32 unitbytes; /* TODO V5 */ + UINT64 unitcount; /* TODO V5 */ + UINT32 hunkcount; /* TODO V5 */ + + // map information + UINT32 mapentrybytes; // length of each entry in a map (V5) + UINT8* rawmap; // raw map data + + UINT32 obsolete_cylinders; /* obsolete field -- do not use! */ + UINT32 obsolete_sectors; /* obsolete field -- do not use! */ + UINT32 obsolete_heads; /* obsolete field -- do not use! */ + UINT32 obsolete_hunksize; /* obsolete field -- do not use! */ +}; + + +/* structure for returning information about a verification pass */ +typedef struct _chd_verify_result chd_verify_result; +struct _chd_verify_result +{ + UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ + UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ + UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ + UINT8 metasha1[CHD_SHA1_BYTES]; /* SHA1 checksum of metadata */ +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + + +/* ----- CHD file management ----- */ + +/* create a new CHD file fitting the given description */ +// chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); + +/* same as chd_create(), but accepts an already-opened core_file object */ +// chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); + +/* open an existing CHD file */ +chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); + + +/* close a CHD file */ +void chd_close(chd_file *chd); + +/* return the associated core_file */ +core_file *chd_core_file(chd_file *chd); + +/* return an error string for the given CHD error */ +const char *chd_error_string(chd_error err); + + + +/* ----- CHD header management ----- */ + +/* return a pointer to the extracted CHD header data */ +const chd_header *chd_get_header(chd_file *chd); + + + + +/* ----- core data read/write ----- */ + +/* read one hunk from the CHD file */ +chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer); + + + +/* ----- metadata management ----- */ + +/* get indexed metadata of a particular sort */ +chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags); + + + + +/* ----- codec interfaces ----- */ + +/* set internal codec parameters */ +chd_error chd_codec_config(chd_file *chd, int param, void *config); + +/* return a string description of a codec */ +const char *chd_get_codec_name(UINT32 codec); + +#ifdef __cplusplus +} +#endif + +#endif /* __CHD_H__ */ diff --git a/libretro-common/formats/libchdr/coretypes.h b/libretro-common/formats/libchdr/coretypes.h new file mode 100644 index 0000000000..80f161f2b6 --- /dev/null +++ b/libretro-common/formats/libchdr/coretypes.h @@ -0,0 +1,36 @@ +#ifndef __CORETYPES_H__ +#define __CORETYPES_H__ + +#include +#include + +#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0])) + +typedef uint64_t UINT64; +typedef uint32_t UINT32; +typedef uint16_t UINT16; +typedef uint8_t UINT8; + +typedef int64_t INT64; +typedef int32_t INT32; +typedef int16_t INT16; +typedef int8_t INT8; + +#define core_file FILE +#define core_fopen(file) fopen(file, "rb") +#define core_fseek fseek +#define core_fread(fc, buff, len) fread(buff, 1, len, fc) +#define core_fclose fclose +#define core_ftell ftell + +static size_t core_fsize(core_file* f) +{ + size_t rv; + size_t p = ftell(f); + fseek(f, 0, SEEK_END); + rv = ftell(f); + fseek(f, p, SEEK_SET); + return rv; +} + +#endif diff --git a/libretro-common/formats/libchdr/flac.c b/libretro-common/formats/libchdr/flac.c new file mode 100644 index 0000000000..29844b6513 --- /dev/null +++ b/libretro-common/formats/libchdr/flac.c @@ -0,0 +1,331 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + flac.c + + FLAC compression wrappers + +***************************************************************************/ + +#include +#include +#include "flac.h" + +//************************************************************************** +// FLAC DECODER +//************************************************************************** + +static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes); +static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); +static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +// getters (valid after reset) +static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; } +static uint8_t channels(flac_decoder *decoder) { return decoder->channels; } +static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; } +static uint32_t total_samples(flac_decoder *decoder) { return FLAC__stream_decoder_get_total_samples(decoder->decoder); } +static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); } +static const char *state_string(flac_decoder *decoder) { return FLAC__stream_decoder_get_resolved_state_string(decoder->decoder); } + +//------------------------------------------------- +// flac_decoder - constructor +//------------------------------------------------- + +void flac_decoder_init(flac_decoder *decoder) +{ + decoder->decoder = FLAC__stream_decoder_new(); + decoder->sample_rate = 0; + decoder->channels = 0; + decoder->bits_per_sample = 0; + decoder->compressed_offset = 0; + decoder->compressed_start = NULL; + decoder->compressed_length = 0; + decoder->compressed2_start = NULL; + decoder->compressed2_length = 0; + decoder->uncompressed_offset = 0; + decoder->uncompressed_length = 0; + decoder->uncompressed_swap = 0; +} + +//------------------------------------------------- +// flac_decoder - destructor +//------------------------------------------------- + +void flac_decoder_free(flac_decoder* decoder) +{ + if ((decoder != NULL) && (decoder->decoder != NULL)) + FLAC__stream_decoder_delete(decoder->decoder); +} + + +//------------------------------------------------- +// reset - reset state with the original +// parameters +//------------------------------------------------- + +static int flac_decoder_internal_reset(flac_decoder* decoder) +{ + decoder->compressed_offset = 0; + if (FLAC__stream_decoder_init_stream(decoder->decoder, + &flac_decoder_read_callback_static, + NULL, + &flac_decoder_tell_callback_static, + NULL, + NULL, + &flac_decoder_write_callback_static, + &flac_decoder_metadata_callback_static, + &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return 0; + return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder); +} + + + +//------------------------------------------------- +// reset - reset state with new memory parameters +// and a custom-generated header +//------------------------------------------------- + +int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length) +{ + // modify the template header with our parameters + static const uint8_t s_header_template[0x2a] = + { + 0x66, 0x4C, 0x61, 0x43, // +00: 'fLaC' stream header + 0x80, // +04: metadata block type 0 (STREAMINFO), + // flagged as last block + 0x00, 0x00, 0x22, // +05: metadata block length = 0x22 + 0x00, 0x00, // +08: minimum block size + 0x00, 0x00, // +0A: maximum block size + 0x00, 0x00, 0x00, // +0C: minimum frame size (0 == unknown) + 0x00, 0x00, 0x00, // +0F: maximum frame size (0 == unknown) + 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100), + // numchannels (2), sample bits (16), + // samples in stream (0 == unknown) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // + // +2A: start of stream data + }; + memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template)); + decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8; + decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff; + decoder->custom_header[0x12] = sample_rate >> 12; + decoder->custom_header[0x13] = sample_rate >> 4; + decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1); + + // configure the header ahead of the provided buffer + decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header); + decoder->compressed_length = sizeof(decoder->custom_header); + decoder->compressed2_start = (const FLAC__byte *)(buffer); + decoder->compressed2_length = length; + return flac_decoder_internal_reset(decoder); +} + + +//------------------------------------------------- +// decode_interleaved - decode to an interleaved +// sound stream +//------------------------------------------------- + +int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian) +{ + // configure the uncompressed buffer + memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start)); + decoder->uncompressed_start[0] = samples; + decoder->uncompressed_offset = 0; + decoder->uncompressed_length = num_samples; + decoder->uncompressed_swap = swap_endian; + + // loop until we get everything we want + while (decoder->uncompressed_offset < decoder->uncompressed_length) + if (!FLAC__stream_decoder_process_single(decoder->decoder)) + return 0; + return 1; +} + + +/* +//------------------------------------------------- +// decode - decode to an multiple independent +// data streams +//------------------------------------------------- + +bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian) +{ + // make sure we don't have too many channels + int chans = channels(); + if (chans > ARRAY_LENGTH(m_uncompressed_start)) + return false; + + // configure the uncompressed buffer + memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start)); + for (int curchan = 0; curchan < chans; curchan++) + m_uncompressed_start[curchan] = samples[curchan]; + m_uncompressed_offset = 0; + m_uncompressed_length = num_samples; + m_uncompressed_swap = swap_endian; + + // loop until we get everything we want + while (m_uncompressed_offset < m_uncompressed_length) + if (!FLAC__stream_decoder_process_single(m_decoder)) + return false; + return true; +} +*/ + +//------------------------------------------------- +// finish - finish up the decode +//------------------------------------------------- + +uint32_t flac_decoder_finish(flac_decoder* decoder) +{ + // get the final decoding position and move forward + FLAC__uint64 position = 0; + FLAC__stream_decoder_get_decode_position(decoder->decoder, &position); + FLAC__stream_decoder_finish(decoder->decoder); + + // adjust position if we provided the header + if (position == 0) + return 0; + if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header)) + position -= decoder->compressed_length; + return position; +} + + +//------------------------------------------------- +// read_callback - handle reads from the input +// stream +//------------------------------------------------- + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + return flac_decoder_read_callback(client_data, buffer, bytes); +} + +FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes) +{ + flac_decoder* decoder = (flac_decoder*)client_data; + + uint32_t expected = *bytes; + + // copy from primary buffer first + uint32_t outputpos = 0; + if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length) + { + uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset); + memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy); + outputpos += bytes_to_copy; + decoder->compressed_offset += bytes_to_copy; + } + + // once we're out of that, copy from the secondary buffer + if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length) + { + uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length)); + memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy); + outputpos += bytes_to_copy; + decoder->compressed_offset += bytes_to_copy; + } + *bytes = outputpos; + + // return based on whether we ran out of data + return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} + + +//------------------------------------------------- +// metadata_callback - handle STREAMINFO metadata +//------------------------------------------------- + +void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + flac_decoder *fldecoder; + // ignore all but STREAMINFO metadata + if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) + return; + + // parse out the data we care about + fldecoder = (flac_decoder *)(client_data); + fldecoder->sample_rate = metadata->data.stream_info.sample_rate; + fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample; + fldecoder->channels = metadata->data.stream_info.channels; +} + + +//------------------------------------------------- +// tell_callback - handle requests to find out +// where in the input stream we are +//------------------------------------------------- + +FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset; + return FLAC__STREAM_DECODER_TELL_STATUS_OK; +} + + +//------------------------------------------------- +// write_callback - handle writes to the output +// stream +//------------------------------------------------- + +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + return flac_decoder_write_callback(client_data, frame, buffer); +} + +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + int shift, blocksize; + flac_decoder * decoder = (flac_decoder *)client_data; + + assert(frame->header.channels == channels(decoder)); + + // interleaved case + shift = decoder->uncompressed_swap ? 8 : 0; + blocksize = frame->header.blocksize; + + if (decoder->uncompressed_start[1] == NULL) + { + int sampnum, chan; + int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels; + for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) + for (chan = 0; chan < frame->header.channels; chan++) + *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift)); + } + + // non-interleaved case + else + { + int sampnum, chan; + for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) + for (chan = 0; chan < frame->header.channels; chan++) + if (decoder->uncompressed_start[chan] != NULL) + decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) ); + } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +/** + * @fn void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) + * + * @brief ------------------------------------------------- + * error_callback - handle errors (ignore them) + * -------------------------------------------------. + * + * @param decoder The decoder. + * @param status The status. + * @param [in,out] client_data If non-null, information describing the client. + */ + +void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ +} diff --git a/libretro-common/formats/libchdr/flac.h b/libretro-common/formats/libchdr/flac.h new file mode 100644 index 0000000000..23e91a9ae3 --- /dev/null +++ b/libretro-common/formats/libchdr/flac.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + flac.h + + FLAC compression wrappers + +***************************************************************************/ + +#pragma once + +#ifndef __FLAC_H__ +#define __FLAC_H__ + +#include +#include "FLAC/all.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef struct _flac_decoder flac_decoder; +struct _flac_decoder { + // output state + FLAC__StreamDecoder* decoder; // actual encoder + uint32_t sample_rate; // decoded sample rate + uint8_t channels; // decoded number of channels + uint8_t bits_per_sample; // decoded bits per sample + uint32_t compressed_offset; // current offset in compressed data + const FLAC__byte * compressed_start; // start of compressed data + uint32_t compressed_length; // length of compressed data + const FLAC__byte * compressed2_start; // start of compressed data + uint32_t compressed2_length; // length of compressed data + int16_t * uncompressed_start[8]; // pointer to start of uncompressed data (up to 8 streams) + uint32_t uncompressed_offset; // current position in uncompressed data + uint32_t uncompressed_length; // length of uncompressed data + int uncompressed_swap; // swap uncompressed sample data + uint8_t custom_header[0x2a]; // custom header +}; + +// ======================> flac_decoder + +void flac_decoder_init(flac_decoder* decoder); +void flac_decoder_free(flac_decoder* decoder); +int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length); +int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian); +uint32_t flac_decoder_finish(flac_decoder* decoder); + +#endif // __FLAC_H__ diff --git a/libretro-common/formats/libchdr/huffman.c b/libretro-common/formats/libchdr/huffman.c new file mode 100644 index 0000000000..d67ec19c96 --- /dev/null +++ b/libretro-common/formats/libchdr/huffman.c @@ -0,0 +1,528 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + huffman.c + + Static Huffman compression and decompression helpers. + +**************************************************************************** + + Maximum codelength is officially (alphabetsize - 1). This would be 255 bits + (since we use 1 byte values). However, it is also dependent upon the number + of samples used, as follows: + + 2 bits -> 3..4 samples + 3 bits -> 5..7 samples + 4 bits -> 8..12 samples + 5 bits -> 13..20 samples + 6 bits -> 21..33 samples + 7 bits -> 34..54 samples + 8 bits -> 55..88 samples + 9 bits -> 89..143 samples + 10 bits -> 144..232 samples + 11 bits -> 233..376 samples + 12 bits -> 377..609 samples + 13 bits -> 610..986 samples + 14 bits -> 987..1596 samples + 15 bits -> 1597..2583 samples + 16 bits -> 2584..4180 samples -> note that a 4k data size guarantees codelength <= 16 bits + 17 bits -> 4181..6764 samples + 18 bits -> 6765..10945 samples + 19 bits -> 10946..17710 samples + 20 bits -> 17711..28656 samples + 21 bits -> 28657..46367 samples + 22 bits -> 46368..75024 samples + 23 bits -> 75025..121392 samples + 24 bits -> 121393..196417 samples + 25 bits -> 196418..317810 samples + 26 bits -> 317811..514228 samples + 27 bits -> 514229..832039 samples + 28 bits -> 832040..1346268 samples + 29 bits -> 1346269..2178308 samples + 30 bits -> 2178309..3524577 samples + 31 bits -> 3524578..5702886 samples + 32 bits -> 5702887..9227464 samples + + Looking at it differently, here is where powers of 2 fall into these buckets: + + 256 samples -> 11 bits max + 512 samples -> 12 bits max + 1k samples -> 14 bits max + 2k samples -> 15 bits max + 4k samples -> 16 bits max + 8k samples -> 18 bits max + 16k samples -> 19 bits max + 32k samples -> 21 bits max + 64k samples -> 22 bits max + 128k samples -> 24 bits max + 256k samples -> 25 bits max + 512k samples -> 27 bits max + 1M samples -> 28 bits max + 2M samples -> 29 bits max + 4M samples -> 31 bits max + 8M samples -> 32 bits max + +**************************************************************************** + + Delta-RLE encoding works as follows: + + Starting value is assumed to be 0. All data is encoded as a delta + from the previous value, such that final[i] = final[i - 1] + delta. + Long runs of 0s are RLE-encoded as follows: + + 0x100 = repeat count of 8 + 0x101 = repeat count of 9 + 0x102 = repeat count of 10 + 0x103 = repeat count of 11 + 0x104 = repeat count of 12 + 0x105 = repeat count of 13 + 0x106 = repeat count of 14 + 0x107 = repeat count of 15 + 0x108 = repeat count of 16 + 0x109 = repeat count of 32 + 0x10a = repeat count of 64 + 0x10b = repeat count of 128 + 0x10c = repeat count of 256 + 0x10d = repeat count of 512 + 0x10e = repeat count of 1024 + 0x10f = repeat count of 2048 + + Note that repeat counts are reset at the end of a row, so if a 0 run + extends to the end of a row, a large repeat count may be used. + + The reason for starting the run counts at 8 is that 0 is expected to + be the most common symbol, and is typically encoded in 1 or 2 bits. + +***************************************************************************/ + +#include +#include +#include +#include + +#include "huffman.h" + +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +//************************************************************************** +// MACROS +//************************************************************************** + +#define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f)) + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// huffman_context_base - create an encoding/ +// decoding context +//------------------------------------------------- + +struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits) +{ + struct huffman_decoder* decoder; + + /* limit to 24 bits */ + if (maxbits > 24) + return NULL; + + decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder)); + decoder->numcodes = numcodes; + decoder->maxbits = maxbits; + decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits)); + decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes); + decoder->datahisto = NULL; + decoder->prevdata = 0; + decoder->rleremaining = 0; + return decoder; +} + +//------------------------------------------------- +// decode_one - decode a single code from the +// huffman stream +//------------------------------------------------- + +uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf) +{ + /* peek ahead to get maxbits worth of data */ + uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits); + + /* look it up, then remove the actual number of bits for this code */ + lookup_value lookup = decoder->lookup[bits]; + bitstream_remove(bitbuf, lookup & 0x1f); + + /* return the value */ + return lookup >> 5; +} + +//------------------------------------------------- +// import_tree_rle - import an RLE-encoded +// huffman tree from a source data stream +//------------------------------------------------- + +enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf) +{ + enum huffman_error error; + int curnode; + // bits per entry depends on the maxbits + int numbits; + if (decoder->maxbits >= 16) + numbits = 5; + else if (decoder->maxbits >= 8) + numbits = 4; + else + numbits = 3; + + // loop until we read all the nodes + for (curnode = 0; curnode < decoder->numcodes; ) + { + // a non-one value is just raw + int nodebits = bitstream_read(bitbuf, numbits); + if (nodebits != 1) + decoder->huffnode[curnode++].numbits = nodebits; + + // a one value is an escape code + else + { + // a double 1 is just a single 1 + nodebits = bitstream_read(bitbuf, numbits); + if (nodebits == 1) + decoder->huffnode[curnode++].numbits = nodebits; + + // otherwise, we need one for value for the repeat count + else + { + int repcount = bitstream_read(bitbuf, numbits) + 3; + while (repcount--) + decoder->huffnode[curnode++].numbits = nodebits; + } + } + } + + // make sure we ended up with the right number + if (curnode != decoder->numcodes) + return HUFFERR_INVALID_DATA; + + // assign canonical codes for all nodes based on their code lengths + error = huffman_assign_canonical_codes(decoder); + if (error != HUFFERR_NONE) + return error; + + // build the lookup table + huffman_build_lookup_table(decoder); + + // determine final input length and report errors + return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; +} + + +//------------------------------------------------- +// import_tree_huffman - import a huffman-encoded +// huffman tree from a source data stream +//------------------------------------------------- + +enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf) +{ + int index; + int start; + int count = 0; + uint8_t rlefullbits = 0; + int last = 0; + int curcode; + enum huffman_error error; + uint32_t temp; + // start by parsing the lengths for the small tree + struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6); + + smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3); + start = bitstream_read(bitbuf, 3) + 1; + + for (index = 1; index < 24; index++) + { + if (index < start || count == 7) + smallhuff->huffnode[index].numbits = 0; + else + { + count = bitstream_read(bitbuf, 3); + smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count; + } + } + + // then regenerate the tree + error = huffman_assign_canonical_codes(smallhuff); + if (error != HUFFERR_NONE) + return error; + huffman_build_lookup_table(smallhuff); + + // determine the maximum length of an RLE count + temp = decoder->numcodes - 9; + while (temp != 0) + temp >>= 1, rlefullbits++; + + // now process the rest of the data + for (curcode = 0; curcode < decoder->numcodes; ) + { + int value = huffman_decode_one(smallhuff, bitbuf); + if (value != 0) + decoder->huffnode[curcode++].numbits = last = value - 1; + else + { + int count = bitstream_read(bitbuf, 3) + 2; + if (count == 7+2) + count += bitstream_read(bitbuf, rlefullbits); + for ( ; count != 0 && curcode < decoder->numcodes; count--) + decoder->huffnode[curcode++].numbits = last; + } + } + + // make sure we ended up with the right number + if (curcode != decoder->numcodes) + return HUFFERR_INVALID_DATA; + + // assign canonical codes for all nodes based on their code lengths + error = huffman_assign_canonical_codes(decoder); + if (error != HUFFERR_NONE) + return error; + + // build the lookup table + huffman_build_lookup_table(decoder); + + // determine final input length and report errors + return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; +} + + +//------------------------------------------------- +// compute_tree_from_histo - common backend for +// computing a tree based on the data histogram +//------------------------------------------------- + +enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder) +{ + int i; + uint32_t upperweight; + uint32_t lowerweight = 0; + // compute the number of data items in the histogram + uint32_t sdatacount = 0; + for (i = 0; i < decoder->numcodes; i++) + sdatacount += decoder->datahisto[i]; + + // binary search to achieve the optimum encoding + upperweight = sdatacount * 2; + while (1) + { + // build a tree using the current weight + uint32_t curweight = (upperweight + lowerweight) / 2; + int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight); + + // apply binary search here + if (curmaxbits <= decoder->maxbits) + { + lowerweight = curweight; + + // early out if it worked with the raw weights, or if we're done searching + if (curweight == sdatacount || (upperweight - lowerweight) <= 1) + break; + } + else + upperweight = curweight; + } + + // assign canonical codes for all nodes based on their code lengths + return huffman_assign_canonical_codes(decoder); +} + + + +//************************************************************************** +// INTERNAL FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// tree_node_compare - compare two tree nodes +// by weight +//------------------------------------------------- + +static int huffman_tree_node_compare(const void *item1, const void *item2) +{ + const struct node_t *node1 = *(const struct node_t **)item1; + const struct node_t *node2 = *(const struct node_t **)item2; + if (node2->weight != node1->weight) + return node2->weight - node1->weight; + if (node2->bits - node1->bits == 0) + fprintf(stderr, "identical node sort keys, should not happen!\n"); + return (int)node1->bits - (int)node2->bits; +} + + +//------------------------------------------------- +// build_tree - build a huffman tree based on the +// data distribution +//------------------------------------------------- + +int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight) +{ + int curcode; + int nextalloc; + int maxbits = 0; + // make a list of all non-zero nodes + struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2); + int listitems = 0; + memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0])); + for (curcode = 0; curcode < decoder->numcodes; curcode++) + if (decoder->datahisto[curcode] != 0) + { + list[listitems++] = &decoder->huffnode[curcode]; + decoder->huffnode[curcode].count = decoder->datahisto[curcode]; + decoder->huffnode[curcode].bits = curcode; + + // scale the weight by the current effective length, ensuring we don't go to 0 + decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata); + if (decoder->huffnode[curcode].weight == 0) + decoder->huffnode[curcode].weight = 1; + } +/* + fprintf(stderr, "Pre-sort:\n"); + for (int i = 0; i < listitems; i++) { + fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); + } +*/ + // sort the list by weight, largest weight first + qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare); +/* + fprintf(stderr, "Post-sort:\n"); + for (int i = 0; i < listitems; i++) { + fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); + } + fprintf(stderr, "===================\n"); +*/ + // now build the tree + nextalloc = decoder->numcodes; + + while (listitems > 1) + { + int curitem; + // remove lowest two items + struct node_t* node1 = &(*list[--listitems]); + struct node_t* node0 = &(*list[--listitems]); + + // create new node + struct node_t* newnode = &decoder->huffnode[nextalloc++]; + newnode->parent = NULL; + node0->parent = node1->parent = newnode; + newnode->weight = node0->weight + node1->weight; + + // insert into list at appropriate location + for (curitem = 0; curitem < listitems; curitem++) + if (newnode->weight > list[curitem]->weight) + { + memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0])); + break; + } + list[curitem] = newnode; + listitems++; + } + + // compute the number of bits in each code, and fill in another histogram + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + struct node_t* node = &decoder->huffnode[curcode]; + node->numbits = 0; + node->bits = 0; + + // if we have a non-zero weight, compute the number of bits + if (node->weight > 0) + { + struct node_t *curnode; + // determine the number of bits for this node + for (curnode = node; curnode->parent != NULL; curnode = curnode->parent) + node->numbits++; + if (node->numbits == 0) + node->numbits = 1; + + // keep track of the max + maxbits = MAX(maxbits, ((int)node->numbits)); + } + } + return maxbits; +} + + +//------------------------------------------------- +// assign_canonical_codes - assign canonical codes +// to all the nodes based on the number of bits +// in each +//------------------------------------------------- + +enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder) +{ + int curcode, codelen; + uint32_t curstart = 0; + + // build up a histogram of bit lengths + uint32_t bithisto[33] = { 0 }; + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + struct node_t* node = &decoder->huffnode[curcode]; + if (node->numbits > decoder->maxbits) + return HUFFERR_INTERNAL_INCONSISTENCY; + if (node->numbits <= 32) + bithisto[node->numbits]++; + } + + // for each code length, determine the starting code number + for (codelen = 32; codelen > 0; codelen--) + { + uint32_t nextstart = (curstart + bithisto[codelen]) >> 1; + if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen])) + return HUFFERR_INTERNAL_INCONSISTENCY; + bithisto[codelen] = curstart; + curstart = nextstart; + } + + // now assign canonical codes + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + struct node_t* node = &decoder->huffnode[curcode]; + if (node->numbits > 0) + node->bits = bithisto[node->numbits]++; + } + return HUFFERR_NONE; +} + + +//------------------------------------------------- +// build_lookup_table - build a lookup table for +// fast decoding +//------------------------------------------------- + +void huffman_build_lookup_table(struct huffman_decoder* decoder) +{ + int curcode; + // iterate over all codes + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + // process all nodes which have non-zero bits + struct node_t* node = &decoder->huffnode[curcode]; + if (node->numbits > 0) + { + int shift; + lookup_value *dest; + lookup_value *destend; + + // set up the entry + lookup_value value = MAKE_LOOKUP(curcode, node->numbits); + + // fill all matching entries + shift = decoder->maxbits - node->numbits; + dest = &decoder->lookup[node->bits << shift]; + destend = &decoder->lookup[((node->bits + 1) << shift) - 1]; + + while (dest <= destend) + *dest++ = value; + } + } +} diff --git a/libretro-common/formats/libchdr/huffman.h b/libretro-common/formats/libchdr/huffman.h new file mode 100644 index 0000000000..71de399971 --- /dev/null +++ b/libretro-common/formats/libchdr/huffman.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + huffman.h + + Static Huffman compression and decompression helpers. + +***************************************************************************/ + +#pragma once + +#ifndef __HUFFMAN_H__ +#define __HUFFMAN_H__ + +#include "bitstream.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +enum huffman_error +{ + HUFFERR_NONE = 0, + HUFFERR_TOO_MANY_BITS, + HUFFERR_INVALID_DATA, + HUFFERR_INPUT_BUFFER_TOO_SMALL, + HUFFERR_OUTPUT_BUFFER_TOO_SMALL, + HUFFERR_INTERNAL_INCONSISTENCY, + HUFFERR_TOO_MANY_CONTEXTS +}; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef uint16_t lookup_value; + +// a node in the huffman tree +struct node_t +{ + struct node_t* parent; // pointer to parent node + uint32_t count; // number of hits on this node + uint32_t weight; // assigned weight of this node + uint32_t bits; // bits used to encode the node + uint8_t numbits; // number of bits needed for this node +}; + +// ======================> huffman_context_base + +// context class for decoding +struct huffman_decoder +{ + // internal state + uint32_t numcodes; // number of total codes being processed + uint8_t maxbits; // maximum bits per code + uint8_t prevdata; // value of the previous data (for delta-RLE encoding) + int rleremaining; // number of RLE bytes remaining (for delta-RLE encoding) + lookup_value * lookup; // pointer to the lookup table + struct node_t * huffnode; // array of nodes + uint32_t * datahisto; // histogram of data values + + // array versions of the info we need + //node_t* huffnode_array; //[_NumCodes]; + //lookup_value* lookup_array; //[1 << _MaxBits]; +}; + +// ======================> huffman_decoder + +struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits); + +// single item operations +uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf); + +enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf); +enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf); + +int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight); +enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder); +enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder); + +void huffman_build_lookup_table(struct huffman_decoder* decoder); + +#endif diff --git a/libretro-common/include/audio/audio_mixer.h b/libretro-common/include/audio/audio_mixer.h index f9044bd3d6..3df9c64931 100644 --- a/libretro-common/include/audio/audio_mixer.h +++ b/libretro-common/include/audio/audio_mixer.h @@ -40,7 +40,8 @@ enum audio_mixer_type { AUDIO_MIXER_TYPE_NONE = 0, AUDIO_MIXER_TYPE_WAV, - AUDIO_MIXER_TYPE_OGG + AUDIO_MIXER_TYPE_OGG, + AUDIO_MIXER_TYPE_MOD }; typedef struct audio_mixer_sound audio_mixer_sound_t; @@ -59,6 +60,7 @@ void audio_mixer_done(void); audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size); audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size); +audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size); void audio_mixer_destroy(audio_mixer_sound_t* sound); diff --git a/libretro-common/include/encodings/win32.h b/libretro-common/include/encodings/win32.h new file mode 100644 index 0000000000..45e7c9a5c3 --- /dev/null +++ b/libretro-common/include/encodings/win32.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (utf.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION 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 _LIBRETRO_ENCODINGS_WIN32_H +#define _LIBRETRO_ENCODINGS_WIN32_H + +#ifndef _XBOX +#ifdef _WIN32 +/*#define UNICODE +#include +#include */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif +#endif + +#ifdef UNICODE +#define CHAR_TO_WCHAR_ALLOC(s, ws) \ + size_t ws##_size = (NULL != s && s[0] ? strlen(s) : 0) + 1; \ + wchar_t *ws = (wchar_t*)calloc(ws##_size, 2); \ + if (NULL != s && s[0]) \ + MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws##_size / sizeof(wchar_t)); + +#define WCHAR_TO_CHAR_ALLOC(ws, s) \ + size_t s##_size = ((NULL != ws && ws[0] ? wcslen((const wchar_t*)ws) : 0) / 2) + 1; \ + char *s = (char*)calloc(s##_size, 1); \ + if (NULL != ws && ws[0]) \ + utf16_to_char_string((const uint16_t*)ws, s, s##_size); + +#else +#define CHAR_TO_WCHAR_ALLOC(s, ws) char *ws = (NULL != s && s[0] ? strdup(s) : NULL); +#define WCHAR_TO_CHAR_ALLOC(ws, s) char *s = (NULL != ws && ws[0] ? strdup(ws) : NULL); +#endif + +#endif diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index c9e99bbf05..74820e7a3c 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -923,6 +923,18 @@ enum retro_mod * writeable (and readable). */ +#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* N/A (null) * -- + * The frontend will try to use a 'shared' hardware context (mostly applicable + * to OpenGL) when a hardware context is being set up. + * + * Returns true if the frontend supports shared hardware contexts and false + * if the frontend does not support shared hardware contexts. + * + * This will do nothing on its own until SET_HW_RENDER env callbacks are + * being used. + */ + enum retro_hw_render_interface_type { RETRO_HW_RENDER_INTERFACE_VULKAN = 0, diff --git a/libretro-common/include/net/net_socket_ssl.h b/libretro-common/include/net/net_socket_ssl.h new file mode 100644 index 0000000000..c9ca75dad0 --- /dev/null +++ b/libretro-common/include/net/net_socket_ssl.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (net_socket.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION 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 _LIBRETRO_SDK_NET_SOCKET_SSL_H +#define _LIBRETRO_SDK_NET_SOCKET_SSL_H + +#include +#include +#include + +RETRO_BEGIN_DECLS + +void* ssl_socket_init(int fd, const char *domain); + +int ssl_socket_connect(void *state_data, void *data, bool timeout_enable, bool nonblock); + +int ssl_socket_send_all_blocking(void *state_data, const void *data_, size_t size, bool no_signal); + +ssize_t ssl_socket_send_all_nonblocking(void *state_data, const void *data_, size_t size, bool no_signal); + +int ssl_socket_receive_all_blocking(void *state_data, void *data_, size_t size); + +ssize_t ssl_socket_receive_all_nonblocking(void *state_data, bool *error, void *data_, size_t size); + +void ssl_socket_close(void *state_data); + +void ssl_socket_free(void *state_data); + +RETRO_END_DECLS + +#endif diff --git a/libretro-common/include/streams/file_stream_transforms.h b/libretro-common/include/streams/file_stream_transforms.h index bf7b6a9874..8921051154 100644 --- a/libretro-common/include/streams/file_stream_transforms.h +++ b/libretro-common/include/streams/file_stream_transforms.h @@ -23,8 +23,9 @@ #ifndef __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H #define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H +#include + #include -#include #include RETRO_BEGIN_DECLS @@ -39,52 +40,21 @@ RETRO_BEGIN_DECLS #define fgets rfgets #define fwrite rfwrite -static INLINE RFILE* rfopen(const char *path, char *mode) -{ - unsigned int retro_mode = RFILE_MODE_READ_TEXT; - if (strstr(mode, "r")) - if (strstr(mode, "b")) - retro_mode = RFILE_MODE_READ; +RFILE* rfopen(const char *path, char *mode); - if (strstr(mode, "w")) - retro_mode = RFILE_MODE_WRITE; - if (strstr(mode, "+")) - retro_mode = RFILE_MODE_READ_WRITE; +int rfclose(RFILE* stream); - return filestream_open(path, retro_mode, -1); -} +long rftell(RFILE* stream); -static INLINE int rfclose(RFILE* stream) -{ - return filestream_close(stream); -} +int rfseek(RFILE* stream, long offset, int origin); -static INLINE long rftell(RFILE* stream) -{ - return filestream_tell(stream); -} +size_t rfread(void* buffer, + size_t elementSize, size_t elementCount, RFILE* stream); -static INLINE int rfseek(RFILE* stream, long offset, int origin) -{ - return filestream_seek(stream, offset, origin); -} +char *rfgets(char *buffer, int maxCount, RFILE* stream); -static INLINE size_t rfread(void* buffer, - size_t elementSize, size_t elementCount, RFILE* stream) -{ - return filestream_read(stream, buffer, elementSize*elementCount); -} - -static INLINE char *rfgets(char *buffer, int maxCount, FILE* stream) -{ - return filestream_gets(stream, buffer, maxCount); -} - -static INLINE size_t rfwrite(void const* buffer, - size_t elementSize, size_t elementCount, RFILE* stream) -{ - return filestream_write(stream, buffer, elementSize*elementCount); -} +size_t rfwrite(void const* buffer, + size_t elementSize, size_t elementCount, RFILE* stream); RETRO_END_DECLS diff --git a/libretro-common/include/string/stdstring.h b/libretro-common/include/string/stdstring.h index 845d636948..98f7aecd03 100644 --- a/libretro-common/include/string/stdstring.h +++ b/libretro-common/include/string/stdstring.h @@ -87,7 +87,7 @@ char *string_trim_whitespace_right(char *const s); /* Remove leading and trailing whitespaces */ char *string_trim_whitespace(char *const s); -char *word_wrap(char* buffer, const char *string, int line_width); +char *word_wrap(char* buffer, const char *string, int line_width, bool unicode); RETRO_END_DECLS diff --git a/libretro-common/net/net_compat.c b/libretro-common/net/net_compat.c index c82bef5d8a..eac476dbca 100644 --- a/libretro-common/net/net_compat.c +++ b/libretro-common/net/net_compat.c @@ -393,6 +393,8 @@ const char *inet_ntop_compat(int af, const void *src, char *dst, socklen_t cnt) return dst; } #endif +#else + return inet_ntop(af, src, dst, cnt); #endif return NULL; diff --git a/libretro-common/net/net_http.c b/libretro-common/net/net_http.c index 17f267eecc..d49dc38127 100644 --- a/libretro-common/net/net_http.c +++ b/libretro-common/net/net_http.c @@ -27,6 +27,9 @@ #include #include #include +#ifdef HAVE_SSL +#include +#endif #include #include @@ -47,9 +50,15 @@ enum T_CHUNK }; -struct http_t +struct http_socket_state_t { int fd; + bool ssl; + void *ssl_ctx; +}; + +struct http_t +{ int status; char part; @@ -59,7 +68,8 @@ struct http_t size_t pos; size_t len; size_t buflen; - char * data; + char *data; + struct http_socket_state_t sock_state; }; struct http_connection_t @@ -72,6 +82,7 @@ struct http_connection_t char *contenttypecopy; char *postdatacopy; int port; + struct http_socket_state_t sock_state; }; static char urlencode_lut[256]; @@ -117,37 +128,71 @@ void net_http_urlencode_full(char **dest, const char *source) (*dest)[len - 1] = '\0'; } -static int net_http_new_socket(const char *domain, int port) +static int net_http_new_socket(struct http_connection_t *conn) { int ret; struct addrinfo *addr = NULL, *next_addr = NULL; int fd = socket_init( - (void**)&addr, port, domain, SOCKET_TYPE_STREAM); + (void**)&addr, conn->port, conn->domain, SOCKET_TYPE_STREAM); +#ifdef HAVE_SSL + if (conn->sock_state.ssl) + { + if (!(conn->sock_state.ssl_ctx = ssl_socket_init(fd, conn->domain))) + return -1; + } +#endif next_addr = addr; while(fd >= 0) { - ret = socket_connect(fd, (void*)next_addr, true); - if (ret >= 0 && socket_nonblock(fd)) - break; +#ifdef HAVE_SSL + if (conn->sock_state.ssl) + { + ret = ssl_socket_connect(conn->sock_state.ssl_ctx, (void*)next_addr, true, true); + + if (ret >= 0) + break; + + ssl_socket_close(conn->sock_state.ssl_ctx); + } + else +#endif + { + ret = socket_connect(fd, (void*)next_addr, true); + + if (ret >= 0 && socket_nonblock(fd)) + break; + + socket_close(fd); + } - socket_close(fd); fd = socket_next((void**)&next_addr); } if (addr) freeaddrinfo_retro(addr); + conn->sock_state.fd = fd; + return fd; } -static void net_http_send_str(int fd, bool *error, const char *text) +static void net_http_send_str(struct http_socket_state_t *sock_state, bool *error, const char *text) { if (*error) return; - - if (!socket_send_all_blocking(fd, text, strlen(text), true)) - *error = true; +#ifdef HAVE_SSL + if (sock_state->ssl) + { + if (!ssl_socket_send_all_blocking(sock_state->ssl_ctx, text, strlen(text), true)) + *error = true; + } + else +#endif + { + if (!socket_send_all_blocking(sock_state->fd, text, strlen(text), true)) + *error = true; + } } struct http_connection_t *net_http_connection_new(const char *url, @@ -155,7 +200,8 @@ struct http_connection_t *net_http_connection_new(const char *url, { char **domain = NULL; struct http_connection_t *conn = (struct http_connection_t*)calloc(1, - sizeof(struct http_connection_t)); + sizeof(*conn)); + bool error = false; if (!conn) return NULL; @@ -174,10 +220,19 @@ struct http_connection_t *net_http_connection_new(const char *url, if (!conn->urlcopy) goto error; - if (strncmp(url, "http://", strlen("http://")) != 0) + if (!strncmp(url, "http://", strlen("http://"))) + conn->scan = conn->urlcopy + strlen("http://"); + else if (!strncmp(url, "https://", strlen("https://"))) + { + conn->scan = conn->urlcopy + strlen("https://"); + conn->sock_state.ssl = true; + } + else + error = true; + + if (error) goto error; - conn->scan = conn->urlcopy + strlen("http://"); domain = &conn->domain; *domain = conn->scan; @@ -221,7 +276,11 @@ bool net_http_connection_done(struct http_connection_t *conn) return false; *conn->scan = '\0'; - conn->port = 80; + + if (conn->sock_state.ssl) + conn->port = 443; + else + conn->port = 80; if (*conn->scan == ':') { @@ -278,7 +337,8 @@ struct http_t *net_http_new(struct http_connection_t *conn) if (!conn) goto error; - fd = net_http_new_socket(conn->domain, conn->port); + fd = net_http_new_socket(conn); + if (fd < 0) goto error; @@ -287,38 +347,38 @@ struct http_t *net_http_new(struct http_connection_t *conn) /* This is a bit lazy, but it works. */ if (conn->methodcopy) { - net_http_send_str(fd, &error, conn->methodcopy); - net_http_send_str(fd, &error, " /"); + net_http_send_str(&conn->sock_state, &error, conn->methodcopy); + net_http_send_str(&conn->sock_state, &error, " /"); } else { - net_http_send_str(fd, &error, "GET /"); + net_http_send_str(&conn->sock_state, &error, "GET /"); } - net_http_send_str(fd, &error, conn->location); - net_http_send_str(fd, &error, " HTTP/1.1\r\n"); + net_http_send_str(&conn->sock_state, &error, conn->location); + net_http_send_str(&conn->sock_state, &error, " HTTP/1.1\r\n"); - net_http_send_str(fd, &error, "Host: "); - net_http_send_str(fd, &error, conn->domain); + net_http_send_str(&conn->sock_state, &error, "Host: "); + net_http_send_str(&conn->sock_state, &error, conn->domain); - if (conn->port != 80) + if (!conn->port) { char portstr[16]; portstr[0] = '\0'; snprintf(portstr, sizeof(portstr), ":%i", conn->port); - net_http_send_str(fd, &error, portstr); + net_http_send_str(&conn->sock_state, &error, portstr); } - net_http_send_str(fd, &error, "\r\n"); + net_http_send_str(&conn->sock_state, &error, "\r\n"); /* this is not being set anywhere yet */ if (conn->contenttypecopy) { - net_http_send_str(fd, &error, "Content-Type: "); - net_http_send_str(fd, &error, conn->contenttypecopy); - net_http_send_str(fd, &error, "\r\n"); + net_http_send_str(&conn->sock_state, &error, "Content-Type: "); + net_http_send_str(&conn->sock_state, &error, conn->contenttypecopy); + net_http_send_str(&conn->sock_state, &error, "\r\n"); } if (conn->methodcopy && (string_is_equal_fast(conn->methodcopy, "POST", 4))) @@ -330,10 +390,10 @@ struct http_t *net_http_new(struct http_connection_t *conn) goto error; if (!conn->contenttypecopy) - net_http_send_str(fd, &error, + net_http_send_str(&conn->sock_state, &error, "Content-Type: application/x-www-form-urlencoded\r\n"); - net_http_send_str(fd, &error, "Content-Length: "); + net_http_send_str(&conn->sock_state, &error, "Content-Length: "); post_len = strlen(conn->postdatacopy); #ifdef _WIN32 @@ -348,24 +408,24 @@ struct http_t *net_http_new(struct http_connection_t *conn) len_str[len] = '\0'; - net_http_send_str(fd, &error, len_str); - net_http_send_str(fd, &error, "\r\n"); + net_http_send_str(&conn->sock_state, &error, len_str); + net_http_send_str(&conn->sock_state, &error, "\r\n"); free(len_str); } - net_http_send_str(fd, &error, "User-Agent: libretro\r\n"); - net_http_send_str(fd, &error, "Connection: close\r\n"); - net_http_send_str(fd, &error, "\r\n"); + net_http_send_str(&conn->sock_state, &error, "User-Agent: libretro\r\n"); + net_http_send_str(&conn->sock_state, &error, "Connection: close\r\n"); + net_http_send_str(&conn->sock_state, &error, "\r\n"); if (conn->methodcopy && (string_is_equal_fast(conn->methodcopy, "POST", 4))) - net_http_send_str(fd, &error, conn->postdatacopy); + net_http_send_str(&conn->sock_state, &error, conn->postdatacopy); if (error) goto error; state = (struct http_t*)malloc(sizeof(struct http_t)); - state->fd = fd; + state->sock_state = conn->sock_state; state->status = -1; state->data = NULL; state->part = P_HEADER_TOP; @@ -389,8 +449,17 @@ error: conn->methodcopy = NULL; conn->contenttypecopy = NULL; conn->postdatacopy = NULL; +#ifdef HAVE_SSL + if (conn->sock_state.ssl && conn->sock_state.ssl_ctx && fd >= 0) + { + ssl_socket_close(conn->sock_state.ssl_ctx); + ssl_socket_free(conn->sock_state.ssl_ctx); + conn->sock_state.ssl_ctx = NULL; + } +#else if (fd >= 0) socket_close(fd); +#endif if (state) free(state); return NULL; @@ -400,7 +469,7 @@ int net_http_fd(struct http_t *state) { if (!state) return -1; - return state->fd; + return state->sock_state.fd; } bool net_http_update(struct http_t *state, size_t* progress, size_t* total) @@ -415,9 +484,18 @@ bool net_http_update(struct http_t *state, size_t* progress, size_t* total) if (state->error) newlen = -1; else - newlen = socket_receive_all_nonblocking(state->fd, &state->error, + { +#ifdef HAVE_SSL + if (state->sock_state.ssl && state->sock_state.ssl_ctx) + newlen = ssl_socket_receive_all_nonblocking(state->sock_state.ssl_ctx, &state->error, (uint8_t*)state->data + state->pos, state->buflen - state->pos); + else +#endif + newlen = socket_receive_all_nonblocking(state->sock_state.fd, &state->error, + (uint8_t*)state->data + state->pos, + state->buflen - state->pos); + } if (newlen < 0) goto fail; @@ -487,11 +565,22 @@ bool net_http_update(struct http_t *state, size_t* progress, size_t* total) if (state->error) newlen = -1; else - newlen = socket_receive_all_nonblocking( - state->fd, + { +#ifdef HAVE_SSL + if (state->sock_state.ssl && state->sock_state.ssl_ctx) + newlen = ssl_socket_receive_all_nonblocking( + state->sock_state.ssl_ctx, &state->error, (uint8_t*)state->data + state->pos, state->buflen - state->pos); + else +#endif + newlen = socket_receive_all_nonblocking( + state->sock_state.fd, + &state->error, + (uint8_t*)state->data + state->pos, + state->buflen - state->pos); + } if (newlen < 0) { @@ -642,8 +731,17 @@ void net_http_delete(struct http_t *state) if (!state) return; - if (state->fd >= 0) - socket_close(state->fd); + if (state->sock_state.fd >= 0) + { + socket_close(state->sock_state.fd); +#ifdef HAVE_SSL + if (state->sock_state.ssl && state->sock_state.ssl_ctx) + { + ssl_socket_free(state->sock_state.ssl_ctx); + state->sock_state.ssl_ctx = NULL; + } +#endif + } free(state); } diff --git a/libretro-common/net/net_socket_ssl.c b/libretro-common/net/net_socket_ssl.c new file mode 100644 index 0000000000..4b9da1206b --- /dev/null +++ b/libretro-common/net/net_socket_ssl.c @@ -0,0 +1,260 @@ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (net_socket.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION 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 +#include +#include + +#include "../../deps/mbedtls/mbedtls/config.h" +#include "../../deps/mbedtls/mbedtls/certs.h" +#include "../../deps/mbedtls/mbedtls/debug.h" +#include "../../deps/mbedtls/mbedtls/platform.h" +#include "../../deps/mbedtls/mbedtls/net_sockets.h" +#include "../../deps/mbedtls/mbedtls/ssl.h" +#include "../../deps/mbedtls/mbedtls/ctr_drbg.h" +#include "../../deps/mbedtls/mbedtls/entropy.h" + +#include "../../deps/mbedtls/cacert.h" + +#define DEBUG_LEVEL 0 + +struct ssl_state +{ + mbedtls_net_context net_ctx; + mbedtls_ssl_context ctx; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_config conf; +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_x509_crt ca; +#endif + const char *domain; +}; + +static const char *pers = "libretro"; + +static void ssl_debug(void *ctx, int level, + const char *file, int line, + const char *str) +{ + ((void) level); + + mbedtls_fprintf((FILE*)ctx, "%s:%04d: %s", file, line, str); + fflush((FILE*)ctx); +} + +void* ssl_socket_init(int fd, const char *domain) +{ + struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state)); + + state->domain = domain; + + mbedtls_debug_set_threshold(DEBUG_LEVEL); + + mbedtls_net_init(&state->net_ctx); + mbedtls_ssl_init(&state->ctx); + mbedtls_ssl_config_init(&state->conf); +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_x509_crt_init(&state->ca); +#endif + mbedtls_ctr_drbg_init(&state->ctr_drbg); + mbedtls_entropy_init(&state->entropy); + + state->net_ctx.fd = fd; + + if (mbedtls_ctr_drbg_seed(&state->ctr_drbg, mbedtls_entropy_func, &state->entropy, (const unsigned char*)pers, strlen(pers)) != 0) + goto error; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if (mbedtls_x509_crt_parse(&state->ca, (const unsigned char*)cacert_pem, sizeof(cacert_pem) / sizeof(cacert_pem[0])) < 0) + goto error; +#endif + + return state; + +error: + if (state) + free(state); + return NULL; +} + +int ssl_socket_connect(void *state_data, void *data, bool timeout_enable, bool nonblock) +{ + struct ssl_state *state = (struct ssl_state*)state_data; + int ret, flags; + + if (socket_connect(state->net_ctx.fd, data, timeout_enable)) + return -1; + + if (mbedtls_ssl_config_defaults(&state->conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT) != 0) + return -1; + + mbedtls_ssl_conf_authmode(&state->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_ca_chain(&state->conf, &state->ca, NULL); + mbedtls_ssl_conf_rng(&state->conf, mbedtls_ctr_drbg_random, &state->ctr_drbg); + mbedtls_ssl_conf_dbg(&state->conf, ssl_debug, stderr); + + if (mbedtls_ssl_setup(&state->ctx, &state->conf) != 0) + return -1; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if (mbedtls_ssl_set_hostname(&state->ctx, state->domain) != 0) + return -1; +#endif + + mbedtls_ssl_set_bio(&state->ctx, &state->net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL); + + while ((ret = mbedtls_ssl_handshake(&state->ctx)) != 0) + { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) + return -1; + } + + if ((flags = mbedtls_ssl_get_verify_result(&state->ctx)) != 0) + { + char vrfy_buf[512]; + mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); + } + + return state->net_ctx.fd; +} + +ssize_t ssl_socket_receive_all_nonblocking(void *state_data, bool *error, void *data_, size_t size) +{ + struct ssl_state *state = (struct ssl_state*)state_data; + const uint8_t *data = (const uint8_t*)data_; + /* mbedtls_ssl_read wants non-const data but it only reads it, so this cast is safe */ + ssize_t ret; + + mbedtls_net_set_nonblock(&state->net_ctx); + + ret = mbedtls_ssl_read(&state->ctx, (unsigned char*)data, size); + + if (ret > 0) + return ret; + + if (ret == 0) + { + /* Socket closed */ + *error = true; + return -1; + } + + if (isagain((int)ret)) + return 0; + + *error = true; + return -1; +} + +int ssl_socket_receive_all_blocking(void *state_data, void *data_, size_t size) +{ + struct ssl_state *state = (struct ssl_state*)state_data; + const uint8_t *data = (const uint8_t*)data_; + + mbedtls_net_set_block(&state->net_ctx); + + while (1) + { + /* mbedtls_ssl_read wants non-const data but it only reads it, so this cast is safe */ + int ret = mbedtls_ssl_read(&state->ctx, (unsigned char*)data, size); + + if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) + continue; + + if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) + break; + + if (ret == 0) + break; /* normal EOF */ + + if (ret < 0) + return -1; + } + + return 1; +} + +int ssl_socket_send_all_blocking(void *state_data, const void *data_, size_t size, bool no_signal) +{ + struct ssl_state *state = (struct ssl_state*)state_data; + const uint8_t *data = (const uint8_t*)data_; + int ret; + + mbedtls_net_set_block(&state->net_ctx); + + while ((ret = mbedtls_ssl_write(&state->ctx, data, size)) <= 0) + { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) + return false; + } + + return true; +} + +ssize_t ssl_socket_send_all_nonblocking(void *state_data, const void *data_, size_t size, bool no_signal) +{ + struct ssl_state *state = (struct ssl_state*)state_data; + const uint8_t *data = (const uint8_t*)data_; + ssize_t sent = size; + int ret; + + mbedtls_net_set_nonblock(&state->net_ctx); + + ret = mbedtls_ssl_write(&state->ctx, data, size); + + if (ret <= 0) + return -1; + + return sent; +} + +void ssl_socket_close(void *state_data) +{ + struct ssl_state *state = (struct ssl_state*)state_data; + + mbedtls_ssl_close_notify(&state->ctx); + + socket_close(state->net_ctx.fd); +} + +void ssl_socket_free(void *state_data) +{ + struct ssl_state *state = (struct ssl_state*)state_data; + + if (!state) + return; + + mbedtls_ssl_free(&state->ctx); + mbedtls_ssl_config_free(&state->conf); + mbedtls_ctr_drbg_free(&state->ctr_drbg); + mbedtls_entropy_free(&state->entropy); +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_x509_crt_free(&state->ca); +#endif + + free(state); +} diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index c4ffce1d5c..20eddc0f9b 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -231,6 +231,8 @@ int sthread_detach(sthread_t *thread) */ void sthread_join(sthread_t *thread) { + if (!thread) + return; #ifdef USE_WIN32_THREADS WaitForSingleObject(thread->thread, INFINITE); CloseHandle(thread->thread); @@ -437,11 +439,18 @@ void scond_free(scond_t *cond) #ifdef USE_WIN32_THREADS static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds) { - static bool beginPeriod = false; - struct QueueEntry myentry; struct QueueEntry **ptr; + +#if _WIN32_WINNT >= 0x0500 + static LARGE_INTEGER performanceCounterFrequency; + LARGE_INTEGER tsBegin; + static bool first_init = true; +#else + static bool beginPeriod = false; DWORD tsBegin; +#endif + DWORD waitResult; DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head, we don't do the hot potato stuff, @@ -453,16 +462,33 @@ static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds /* since this library is meant for realtime game software * I have no problem setting this to 1 and forgetting about it. */ +#if _WIN32_WINNT >= 0x0500 + if (first_init) + { + performanceCounterFrequency.QuadPart = 0; + first_init = false; + } + + if (performanceCounterFrequency.QuadPart == 0) + { + QueryPerformanceFrequency(&performanceCounterFrequency); + } +#else if (!beginPeriod) { beginPeriod = true; timeBeginPeriod(1); } +#endif /* Now we can take a good timestamp for use in faking the timeout ourselves. */ /* But don't bother unless we need to (to save a little time) */ if (dwMilliseconds != INFINITE) +#if _WIN32_WINNT >= 0x0500 + QueryPerformanceCounter(&tsBegin); +#else tsBegin = timeGetTime(); +#endif /* add ourselves to a queue of waiting threads */ ptr = &cond->head; @@ -504,8 +530,18 @@ static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds /* Assess the remaining timeout time */ if (dwMilliseconds != INFINITE) { +#if _WIN32_WINNT >= 0x0500 + LARGE_INTEGER now; + LONGLONG elapsed; + + QueryPerformanceCounter(&now); + elapsed = now.QuadPart - tsBegin.QuadPart; + elapsed *= 1000; + elapsed /= performanceCounterFrequency.QuadPart; +#else DWORD now = timeGetTime(); DWORD elapsed = now - tsBegin; +#endif /* Try one last time with a zero timeout (keeps the code simpler) */ if (elapsed > dwMilliseconds) diff --git a/libretro-common/streams/file_stream_transforms.c b/libretro-common/streams/file_stream_transforms.c new file mode 100644 index 0000000000..f43ee7b25a --- /dev/null +++ b/libretro-common/streams/file_stream_transforms.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2010-2017 The RetroArch team +* +* --------------------------------------------------------------------------------------- +* The following license statement only applies to this file (file_stream_transforms.c). +* --------------------------------------------------------------------------------------- +* +* Permission is hereby granted, free of charge, +* to any person obtaining a copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION 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 + +RFILE* rfopen(const char *path, char *mode) +{ + unsigned int retro_mode = RFILE_MODE_READ_TEXT; + if (strstr(mode, "r")) + if (strstr(mode, "b")) + retro_mode = RFILE_MODE_READ; + + if (strstr(mode, "w")) + retro_mode = RFILE_MODE_WRITE; + if (strstr(mode, "+")) + retro_mode = RFILE_MODE_READ_WRITE; + + return filestream_open(path, retro_mode, -1); +} + +int rfclose(RFILE* stream) +{ + return filestream_close(stream); +} + +long rftell(RFILE* stream) +{ + return filestream_tell(stream); +} + +int rfseek(RFILE* stream, long offset, int origin) +{ + return filestream_seek(stream, offset, origin); +} + +size_t rfread(void* buffer, + size_t elementSize, size_t elementCount, RFILE* stream) +{ + return filestream_read(stream, buffer, elementSize*elementCount); +} + +char *rfgets(char *buffer, int maxCount, RFILE* stream) +{ + return filestream_gets(stream, buffer, maxCount); +} + +size_t rfwrite(void const* buffer, + size_t elementSize, size_t elementCount, RFILE* stream) +{ + return filestream_write(stream, buffer, elementSize*elementCount); +} diff --git a/libretro-common/string/stdstring.c b/libretro-common/string/stdstring.c index ea8d62e70f..88a436f128 100644 --- a/libretro-common/string/stdstring.c +++ b/libretro-common/string/stdstring.c @@ -24,12 +24,13 @@ #include #include +#include char *string_to_upper(char *s) { char *cs = (char *)s; for ( ; *cs != '\0'; cs++) - *cs = toupper(*cs); + *cs = toupper((unsigned char)*cs); return s; } @@ -37,7 +38,7 @@ char *string_to_lower(char *s) { char *cs = (char *)s; for ( ; *cs != '\0'; cs++) - *cs = tolower(*cs); + *cs = tolower((unsigned char)*cs); return s; } @@ -47,10 +48,10 @@ char *string_ucwords(char *s) for ( ; *cs != '\0'; cs++) { if (*cs == ' ') - *(cs+1) = toupper(*(cs+1)); + *(cs+1) = toupper((unsigned char)*(cs+1)); } - s[0] = toupper(s[0]); + s[0] = toupper((unsigned char)s[0]); return s; } @@ -107,7 +108,7 @@ char *string_trim_whitespace_left(char *const s) size_t len = strlen(s); char *cur = s; - while(*cur && isspace(*cur)) + while(*cur && isspace((unsigned char)*cur)) ++cur, --len; if(s != cur) @@ -126,10 +127,10 @@ char *string_trim_whitespace_right(char *const s) size_t len = strlen(s); char *cur = s + len - 1; - while(cur != s && isspace(*cur)) + while(cur != s && isspace((unsigned char)*cur)) --cur, --len; - cur[isspace(*cur) ? 0 : 1] = '\0'; + cur[isspace((unsigned char)*cur) ? 0 : 1] = '\0'; } return s; @@ -144,7 +145,7 @@ char *string_trim_whitespace(char *const s) return s; } -char *word_wrap(char* buffer, const char *string, int line_width) +char *word_wrap(char* buffer, const char *string, int line_width, bool unicode) { unsigned i = 0; unsigned len = (unsigned)strlen(string); @@ -156,20 +157,34 @@ char *word_wrap(char* buffer, const char *string, int line_width) /* copy string until the end of the line is reached */ for (counter = 1; counter <= (unsigned)line_width; counter++) { + const char *character; + unsigned char_len; + unsigned j = i; + + character = utf8skip(&string[i], 1); + char_len = character - &string[i]; + /* check if end of string reached */ - if (i == strlen(string)) + if (i == len) { buffer[i] = 0; return buffer; } - buffer[i] = string[i]; + if (!unicode) + counter += char_len - 1; + + do + { + buffer[i] = string[i]; + char_len--; + i++; + } while(char_len); /* check for newlines embedded in the original input * and reset the index */ - if (buffer[i] == '\n') + if (buffer[j] == '\n') counter = 1; - i++; } /* check for whitespace */ diff --git a/libretro-db/Makefile b/libretro-db/Makefile index 52db777aeb..49023b398f 100644 --- a/libretro-db/Makefile +++ b/libretro-db/Makefile @@ -24,6 +24,7 @@ C_CONVERTER_C = \ $(LIBRETRO_COMM_DIR)/hash/rhash.c \ $(LIBRETRO_COMM_DIR)/compat/compat_fnmatch.c \ $(LIBRETRO_COMM_DIR)/string/stdstring.c \ + $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \ $(LIBRETRO_COMMON_C) \ $(LIBRETRO_COMM_DIR)/compat/compat_strl.c @@ -38,6 +39,7 @@ RARCHDB_TOOL_C = \ $(LIBRETRODB_DIR)/libretrodb.c \ $(LIBRETRO_COMM_DIR)/compat/compat_fnmatch.c \ $(LIBRETRO_COMM_DIR)/string/stdstring.c \ + $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \ $(LIBRETRO_COMMON_C) \ $(LIBRETRO_COMM_DIR)/compat/compat_strl.c diff --git a/media/android/dark/res/mipmap-hdpi/ic_launcher.png b/media/android/dark/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index b3f9a06868..0000000000 Binary files a/media/android/dark/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-mdpi/ic_launcher.png b/media/android/dark/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index b10decbbe0..0000000000 Binary files a/media/android/dark/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-xhdpi/ic_launcher.png b/media/android/dark/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index a80f62fd9d..0000000000 Binary files a/media/android/dark/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-xxhdpi/ic_launcher.png b/media/android/dark/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 74cd51fc93..0000000000 Binary files a/media/android/dark/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-xxxhdpi/ic_launcher.png b/media/android/dark/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index ee5c33d461..0000000000 Binary files a/media/android/dark/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/web_hi_res_512.png b/media/android/dark/web_hi_res_512.png deleted file mode 100644 index 9f2a980250..0000000000 Binary files a/media/android/dark/web_hi_res_512.png and /dev/null differ diff --git a/media/android/light/res/mipmap-hdpi/ic_launcher.png b/media/android/light/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 26953bee42..0000000000 Binary files a/media/android/light/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-mdpi/ic_launcher.png b/media/android/light/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index e99b744135..0000000000 Binary files a/media/android/light/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-xhdpi/ic_launcher.png b/media/android/light/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index b779422b8e..0000000000 Binary files a/media/android/light/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-xxhdpi/ic_launcher.png b/media/android/light/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 21ad6ad00e..0000000000 Binary files a/media/android/light/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-xxxhdpi/ic_launcher.png b/media/android/light/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 8a28e59304..0000000000 Binary files a/media/android/light/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/web_hi_res_512.png b/media/android/light/web_hi_res_512.png deleted file mode 100644 index 4834dd25b5..0000000000 Binary files a/media/android/light/web_hi_res_512.png and /dev/null differ diff --git a/media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt b/media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt new file mode 100644 index 0000000000..8e8e537ae9 --- /dev/null +++ b/media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt @@ -0,0 +1,43 @@ +Attribution-NonCommercial 3.0 Unported + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +1. Definitions +"Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. +"Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +"Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. +"Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. +"Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +"Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. +"Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. +"Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. +3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: +to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; +to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; +to Distribute and Publicly Perform the Work including as incorporated in Collections; and, +to Distribute and Publicly Perform Adaptations. +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d). +4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: +You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. +You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. +If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. +For the avoidance of doubt: +Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; +Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, +Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c). +Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. +5. Representations, Warranties and Disclaimer +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +7. Termination +This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. +Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. +8. Miscellaneous +Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. +Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. +If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. +No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. +This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. +The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. diff --git a/media/icons/LICENSE/LICENSE.txt b/media/icons/LICENSE/LICENSE.txt new file mode 100644 index 0000000000..6be4822288 --- /dev/null +++ b/media/icons/LICENSE/LICENSE.txt @@ -0,0 +1,20 @@ +License +======= + +Icons generated with the Android Material Icon Generator are licensed under the Creative Commons Attribution-NonCommercial 3.0 License (https://creativecommons.org/licenses/by-nc/3.0/). + +For commercial usage, please submit a request under https://goo.gl/forms/zX8GZ3Jz89SRyHdJ2 or send us an email to material-icons@bitdroid.de. + + +Google Material Icons License +============================= + +This license applies to the Google Material Icons, which can be seen on the front page of the Android Material icon generator. + +(Copied from https://github.com/google/material-design-icons) +We have made these icons available for you to incorporate them into your +products under the Creative Common Attribution 4.0 International License (CC-BY +4.0, https://creativecommons.org/licenses/by/4.0/). Feel free to remix and +re-share these icons and documentation in your products. We'd love attribution +in your app's *about* screen, but it's not required. The only thing we ask is +that you not re-sell the icons themselves. \ No newline at end of file diff --git a/media/icons/icon.svg b/media/icons/icon.svg new file mode 100644 index 0000000000..549cc6f68f --- /dev/null +++ b/media/icons/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/icons/mipmap-hdpi/ic_launcher.png b/media/icons/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..d33d1953f9 Binary files /dev/null and b/media/icons/mipmap-hdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-mdpi/ic_launcher.png b/media/icons/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..a338dfb2f9 Binary files /dev/null and b/media/icons/mipmap-mdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-xhdpi/ic_launcher.png b/media/icons/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..7eb088dc92 Binary files /dev/null and b/media/icons/mipmap-xhdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-xxhdpi/ic_launcher.png b/media/icons/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..c5a7c34b79 Binary files /dev/null and b/media/icons/mipmap-xxhdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-xxxhdpi/ic_launcher.png b/media/icons/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..f6abcb638a Binary files /dev/null and b/media/icons/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/media/icons/playstore/icon.png b/media/icons/playstore/icon.png new file mode 100644 index 0000000000..73fddf683b Binary files /dev/null and b/media/icons/playstore/icon.png differ diff --git a/media/rarch.rc b/media/rarch.rc index 5bad253138..e758160872 100644 --- a/media/rarch.rc +++ b/media/rarch.rc @@ -97,7 +97,7 @@ FONT 8, "Ms Shell Dlg" // Icon resources // LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -1 ICON "icon_light.ico" +1 ICON "retroarch.ico" diff --git a/media/retroarch.ico b/media/retroarch.ico new file mode 100644 index 0000000000..6355390e3e Binary files /dev/null and b/media/retroarch.ico differ diff --git a/media/src/invader.ico b/media/src/invader.ico new file mode 100644 index 0000000000..6355390e3e Binary files /dev/null and b/media/src/invader.ico differ diff --git a/media/src/invader.png b/media/src/invader.png new file mode 100644 index 0000000000..aa9e8b6a99 Binary files /dev/null and b/media/src/invader.png differ diff --git a/media/src/invader.svg b/media/src/invader.svg new file mode 100644 index 0000000000..e9b1d5a927 --- /dev/null +++ b/media/src/invader.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/menu/cbs/menu_cbs_cancel.c b/menu/cbs/menu_cbs_cancel.c index 4891ed22cb..830cfb6e6d 100644 --- a/menu/cbs/menu_cbs_cancel.c +++ b/menu/cbs/menu_cbs_cancel.c @@ -37,10 +37,6 @@ static int action_cancel_pop_default(const char *path, menu_entries_get_last_stack(NULL, &menu_label, NULL, NULL, NULL); -#if 0 - RARCH_LOG("menu_label: %s\n", menu_label); -#endif - if (!string_is_empty(menu_label)) { if ( diff --git a/menu/cbs/menu_cbs_deferred_push.c b/menu/cbs/menu_cbs_deferred_push.c index 44c84e24df..f6f58b49fa 100644 --- a/menu/cbs/menu_cbs_deferred_push.c +++ b/menu/cbs/menu_cbs_deferred_push.c @@ -340,6 +340,11 @@ static int deferred_push_configurations_list(menu_displaylist_info_t *info) return deferred_push_dlist(info, DISPLAYLIST_CONFIGURATIONS_LIST); } +static int deferred_push_load_content_special(menu_displaylist_info_t *info) +{ + return deferred_push_dlist(info, DISPLAYLIST_LOAD_CONTENT_LIST); +} + static int deferred_push_load_content_list(menu_displaylist_info_t *info) { return deferred_push_dlist(info, DISPLAYLIST_LOAD_CONTENT_LIST); @@ -688,6 +693,24 @@ static int general_push(menu_displaylist_info_t *info, if (!string_is_empty(system->valid_extensions)) strlcpy(info->exts, system->valid_extensions, sizeof(info->exts)); } + { + union string_list_elem_attr attr; + char newstring2[PATH_MAX_LENGTH]; + struct string_list *str_list3 = string_split(info->exts, "|"); + + newstring2[0] = '\0'; + attr.i = 0; + +#ifdef HAVE_IBXM + string_list_append(str_list3, "s3m", attr); + string_list_append(str_list3, "mod", attr); + string_list_append(str_list3, "xm", attr); +#endif + string_list_join_concat(newstring2, sizeof(newstring2), + str_list3, "|"); + string_list_free(str_list3); + strlcpy(info->exts, newstring2, sizeof(info->exts)); + } break; case PUSH_ARCHIVE_OPEN_DETECT_CORE: case PUSH_DETECT_CORE_LIST: @@ -740,7 +763,24 @@ static int general_push(menu_displaylist_info_t *info, str_list2, "|"); strlcpy(info->exts, newstring, sizeof(info->exts)); + { + union string_list_elem_attr attr; + char newstring2[PATH_MAX_LENGTH]; + struct string_list *str_list3 = string_split(info->exts, "|"); + newstring2[0] = '\0'; + attr.i = 0; + +#ifdef HAVE_IBXM + string_list_append(str_list3, "s3m", attr); + string_list_append(str_list3, "mod", attr); + string_list_append(str_list3, "xm", attr); +#endif + string_list_join_concat(newstring2, sizeof(newstring2), + str_list3, "|"); + string_list_free(str_list3); + strlcpy(info->exts, newstring2, sizeof(info->exts)); + } string_list_free(str_list2); } break; @@ -781,6 +821,24 @@ static int deferred_push_detect_core_list(menu_displaylist_info_t *info) DISPLAYLIST_CORES_DETECTED); } +static int deferred_music_history_list(menu_displaylist_info_t *info) +{ + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + return general_push(info, PUSH_DEFAULT, DISPLAYLIST_MUSIC_HISTORY); +} + +static int deferred_image_history_list(menu_displaylist_info_t *info) +{ + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + return general_push(info, PUSH_DEFAULT, DISPLAYLIST_IMAGES_HISTORY); +} + +static int deferred_video_history_list(menu_displaylist_info_t *info) +{ + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + return general_push(info, PUSH_DEFAULT, DISPLAYLIST_VIDEO_HISTORY); +} + static int deferred_archive_open_detect_core(menu_displaylist_info_t *info) { return general_push(info, PUSH_ARCHIVE_OPEN_DETECT_CORE, @@ -817,6 +875,11 @@ static int deferred_push_content_collection_list(menu_displaylist_info_t *info) return deferred_push_dlist(info, DISPLAYLIST_DATABASE_PLAYLISTS); } +static int deferred_push_favorites_list(menu_displaylist_info_t *info) +{ + return general_push(info, PUSH_DEFAULT, DISPLAYLIST_FAVORITES); +} + static int deferred_push_browse_url_list(menu_displaylist_info_t *info) { return deferred_push_dlist(info, DISPLAYLIST_BROWSE_URL_LIST); @@ -901,131 +964,131 @@ static int menu_cbs_init_bind_deferred_push_compare_label( menu_file_list_cbs_t *cbs, const char *label, uint32_t label_hash) { - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_LIST))) + if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_favorites_list); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_browse_url_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_START))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_START))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_browse_url_start); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_configuration_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_saving_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_logging_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_frame_throttle_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_REWIND_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_REWIND_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_rewind_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_DISPLAY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_DISPLAY_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_onscreen_display_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_onscreen_notifications_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_onscreen_overlay_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_FILE_BROWSER_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_FILE_BROWSER_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_menu_file_browser_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_VIEWS_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_VIEWS_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_menu_views_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_menu_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_INTERFACE_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_INTERFACE_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_user_interface_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RETRO_ACHIEVEMENTS_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RETRO_ACHIEVEMENTS_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_retro_achievements_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_UPDATER_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_UPDATER_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_updater_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_NETWORK_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_NETWORK_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_network_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_WIFI_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_WIFI_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_wifi_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LAKKA_SERVICES_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LAKKA_SERVICES_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_lakka_services_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_user_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_directory_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_privacy_settings_list); return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST))) { #ifdef HAVE_NETWORKING BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_content_dirs_list); @@ -1033,19 +1096,38 @@ static int menu_cbs_init_bind_deferred_push_compare_label( return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_SUBDIR_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_SUBDIR_LIST))) { #ifdef HAVE_NETWORKING BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_content_dirs_subdir_list); #endif return 0; } - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MUSIC))) + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MUSIC))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_music_list); return 0; } - if (strstr(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RDB_ENTRY_DETAIL))) + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_music_history_list); + return 0; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_image_history_list); + return 0; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_video_history_list); + return 0; + } + else if (strstr(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RDB_ENTRY_DETAIL))) { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_rdb_entry_detail); } @@ -1059,6 +1141,110 @@ static int menu_cbs_init_bind_deferred_push_compare_label( { BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_netplay_sublist); } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_INPUT_SETTINGS_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_input_settings_list); + } +#ifdef HAVE_NETWORKING + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_updater_list); + } +#endif + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DRIVER_SETTINGS_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_driver_settings_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_SETTINGS_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_video_settings_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_audio_settings_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_CORE_INFORMATION))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_information); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_SYSTEM_INFORMATION))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_system_information); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_accounts_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_CORE_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_history_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_CORE_OPTIONS))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_options); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_NETWORK_INFORMATION))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_network_information); + } +#ifdef HAVE_NETWORKING + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_thumbnails_updater_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_content_list); + } +#endif + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_ONLINE_UPDATER))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_options); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_HELP_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_help); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_INFORMATION_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_information_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_SHADER_OPTIONS))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_shader_options); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_BINDS_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_user_binds_list); + } + else if (strstr(label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_INPUT_HOTKEY_BINDS_LIST))) + { + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_input_hotkey_binds_list); + } else { if (cbs->enum_idx != MSG_UNKNOWN) @@ -1074,9 +1260,6 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_accounts_list); break; - case MENU_ENUM_LABEL_DEFERRED_INPUT_SETTINGS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_input_settings_list); - break; case MENU_ENUM_LABEL_DEFERRED_PLAYLIST_SETTINGS_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_playlist_settings_list); break; @@ -1114,11 +1297,6 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_SUBDIR_LIST: #ifdef HAVE_NETWORKING BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_content_dirs_subdir_list); -#endif - break; - case MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST: -#ifdef HAVE_NETWORKING - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_updater_list); #endif break; case MENU_ENUM_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST: @@ -1170,6 +1348,9 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_load_content_list); break; + case MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL: + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_load_content_special); + break; case MENU_ENUM_LABEL_INFORMATION_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_information_list); break; @@ -1244,12 +1425,6 @@ static int menu_cbs_init_bind_deferred_push_compare_label( BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_cursor_manager_list_deferred_query_rdb_entry_releaseyear); break; #endif - case MENU_ENUM_LABEL_CORE_INFORMATION: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_information); - break; - case MENU_ENUM_LABEL_SYSTEM_INFORMATION: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_system_information); - break; case MENU_ENUM_LABEL_NETWORK_INFORMATION: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_network_information); break; @@ -1361,36 +1536,18 @@ static int menu_cbs_init_bind_deferred_push_compare_label( { switch (label_hash) { - case MENU_LABEL_DEFERRED_CONFIGURATIONS_LIST: + case MENU_LABEL_SETTINGS: /* TODO/FIXME */ + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_settings); + break; + case MENU_LABEL_DEFERRED_CONFIGURATIONS_LIST: /* TODO/FIXME */ BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_configurations_list); break; - case MENU_LABEL_DEFERRED_USER_BINDS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_user_binds_list); - break; - case MENU_LABEL_DEFERRED_ACCOUNTS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_accounts_list); - break; - case MENU_LABEL_DEFERRED_DRIVER_SETTINGS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_driver_settings_list); - break; - case MENU_LABEL_DEFERRED_VIDEO_SETTINGS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_video_settings_list); - break; - case MENU_LABEL_DEFERRED_AUDIO_SETTINGS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_audio_settings_list); - break; - case MENU_LABEL_DEFERRED_INPUT_SETTINGS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_input_settings_list); - break; case MENU_LABEL_DEFERRED_PLAYLIST_SETTINGS_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_playlist_settings_list); break; case MENU_LABEL_DEFERRED_RECORDING_SETTINGS_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_recording_settings_list); break; - case MENU_LABEL_DEFERRED_INPUT_HOTKEY_BINDS_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_input_hotkey_binds_list); - break; case MENU_LABEL_DEFERRED_ACCOUNTS_CHEEVOS_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_accounts_cheevos_list); break; @@ -1406,29 +1563,11 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_LABEL_DEFERRED_ARCHIVE_OPEN: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_archive_open); break; - case MENU_LABEL_DEFERRED_CORE_CONTENT_LIST: -#ifdef HAVE_NETWORKING - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_content_list); -#endif - break; - case MENU_LABEL_DEFERRED_CORE_UPDATER_LIST: -#ifdef HAVE_NETWORKING - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_updater_list); -#endif - break; - case MENU_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST: -#ifdef HAVE_NETWORKING - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_thumbnails_updater_list); -#endif - break; case MENU_LABEL_DEFERRED_LAKKA_LIST: #ifdef HAVE_NETWORKING BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_lakka_list); #endif break; - case MENU_LABEL_LOAD_CONTENT_HISTORY: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_history_list); - break; case MENU_LABEL_DATABASE_MANAGER_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_database_manager_list); break; @@ -1444,12 +1583,6 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_LABEL_RECORD_CONFIG: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_record_configfile); break; - case MENU_LABEL_SHADER_OPTIONS: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_shader_options); - break; - case MENU_LABEL_ONLINE_UPDATER: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_options); - break; case MENU_LABEL_NETPLAY: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_netplay); break; @@ -1462,15 +1595,9 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_LABEL_LOAD_CONTENT_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_load_content_list); break; - case MENU_LABEL_INFORMATION_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_information_list); - break; case MENU_LABEL_MANAGEMENT: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_management_options); break; - case MENU_LABEL_HELP_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_help); - break; case MENU_LABEL_DEFERRED_CORE_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_list_deferred); break; @@ -1536,15 +1663,6 @@ static int menu_cbs_init_bind_deferred_push_compare_label( BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_cursor_manager_list_deferred_query_rdb_entry_releaseyear); break; #endif - case MENU_LABEL_CORE_INFORMATION: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_information); - break; - case MENU_LABEL_SYSTEM_INFORMATION: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_system_information); - break; - case MENU_LABEL_NETWORK_INFORMATION: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_network_information); - break; case MENU_LABEL_ACHIEVEMENT_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_achievement_list); break; @@ -1563,21 +1681,12 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_LABEL_VIDEO_SHADER_PARAMETERS: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_video_shader_parameters); break; - case MENU_LABEL_SETTINGS: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_settings); - break; - case MENU_LABEL_CORE_OPTIONS: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_options); - break; case MENU_LABEL_CORE_CHEAT_OPTIONS: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_cheat_options); break; case MENU_LABEL_CORE_INPUT_REMAPPING_OPTIONS: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_input_remapping_options); break; - case MENU_LABEL_CORE_LIST: - BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_list); - break; case MENU_LABEL_CONTENT_COLLECTION_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_content_collection_list); break; diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c index dc99bbf803..bbf7d7651b 100644 --- a/menu/cbs/menu_cbs_get_value.c +++ b/menu/cbs/menu_cbs_get_value.c @@ -137,16 +137,13 @@ static void menu_action_setting_disp_set_label_shader_filter_pass( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) struct video_shader_pass *shader_pass = menu_shader_manager_get_pass( type - MENU_SETTINGS_SHADER_PASS_FILTER_0); -#endif *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!shader_pass) return; @@ -165,7 +162,6 @@ static void menu_action_setting_disp_set_label_shader_filter_pass( len); break; } -#endif } static void menu_action_setting_disp_set_label_filter( @@ -251,9 +247,7 @@ static void menu_action_setting_disp_set_label_shader_num_passes( *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) snprintf(s, len, "%u", menu_shader_manager_get_amount_passes()); -#endif } static void menu_action_setting_disp_set_label_shader_pass( @@ -265,23 +259,19 @@ static void menu_action_setting_disp_set_label_shader_pass( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) struct video_shader_pass *shader_pass = menu_shader_manager_get_pass( type - MENU_SETTINGS_SHADER_PASS_0); -#endif *s = '\0'; *w = 19; strlcpy(s2, path, len2); strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), len); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!shader_pass) return; if (!string_is_empty(shader_pass->source.path)) fill_pathname_base(s, shader_pass->source.path, len); -#endif } static void menu_action_setting_disp_set_label_shader_default_filter( @@ -317,15 +307,13 @@ static void menu_action_setting_disp_set_label_shader_parameter( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) video_shader_ctx_t shader_info; const struct video_shader_parameter *param = NULL; -#endif + *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) video_shader_driver_get_current_shader(&shader_info); if (!shader_info.data) @@ -339,7 +327,6 @@ static void menu_action_setting_disp_set_label_shader_parameter( snprintf(s, len, "%.2f [%.2f %.2f]", param->current, param->minimum, param->maximum); -#endif } static void menu_action_setting_disp_set_label_shader_preset_parameter( @@ -351,20 +338,17 @@ static void menu_action_setting_disp_set_label_shader_preset_parameter( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) - const struct video_shader_parameter *param = menu_shader_manager_get_parameters( - type - MENU_SETTINGS_SHADER_PRESET_PARAMETER_0); -#endif + const struct video_shader_parameter *param = + menu_shader_manager_get_parameters( + type - MENU_SETTINGS_SHADER_PRESET_PARAMETER_0); *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (param) snprintf(s, len, "%.2f [%.2f %.2f]", param->current, param->minimum, param->maximum); -#endif } static void menu_action_setting_disp_set_label_shader_scale_pass( @@ -378,10 +362,8 @@ static void menu_action_setting_disp_set_label_shader_scale_pass( { unsigned pass = 0; unsigned scale_value = 0; -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) struct video_shader_pass *shader_pass = menu_shader_manager_get_pass( type - MENU_SETTINGS_SHADER_PASS_SCALE_0); -#endif *s = '\0'; *w = 19; @@ -390,7 +372,6 @@ static void menu_action_setting_disp_set_label_shader_scale_pass( (void)pass; (void)scale_value; -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!shader_pass) return; @@ -400,7 +381,6 @@ static void menu_action_setting_disp_set_label_shader_scale_pass( strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE), len); else snprintf(s, len, "%ux", scale_value); -#endif } static void menu_action_setting_disp_set_label_menu_file_core( @@ -1844,7 +1824,6 @@ static int menu_cbs_init_bind_get_string_representation_compare_type( case MENU_SETTING_ACTION_LOADSTATE: case 7: /* Run */ case MENU_SETTING_ACTION_DELETE_ENTRY: - case 117: /* Netplay settings */ case MENU_SETTING_ACTION_CORE_DISK_OPTIONS: BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_menu_more); diff --git a/menu/cbs/menu_cbs_info.c b/menu/cbs/menu_cbs_info.c index d9ef6ef40a..ef1b16483e 100644 --- a/menu/cbs/menu_cbs_info.c +++ b/menu/cbs/menu_cbs_info.c @@ -26,6 +26,10 @@ cbs->action_info_ident = #name; #endif +#ifdef HAVE_NETWORKING +#include "../../network/netplay/netplay_discovery.h" +#endif + static int action_info_default(unsigned type, const char *label) { menu_displaylist_info_t info = {0}; @@ -60,8 +64,8 @@ static int action_info_cheevos(unsigned type, const char *label) menu_dialog_set_current_id(new_id); return generic_action_ok_help(NULL, label, new_id, 0, 0, - MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION, - MENU_DIALOG_HELP_CHEEVOS_DESCRIPTION); + MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION, + MENU_DIALOG_HELP_CHEEVOS_DESCRIPTION); } #endif @@ -72,7 +76,8 @@ int menu_cbs_init_bind_info(menu_file_list_cbs_t *cbs, return -1; #ifdef HAVE_CHEEVOS - if ((type >= MENU_SETTINGS_CHEEVOS_START)) + if ((type >= MENU_SETTINGS_CHEEVOS_START) && + (type < MENU_SETTINGS_NETPLAY_ROOMS_START)) { BIND_ACTION_INFO(cbs, action_info_cheevos); return 0; diff --git a/menu/cbs/menu_cbs_label.c b/menu/cbs/menu_cbs_label.c index 5544e21ea7..c632da71e3 100644 --- a/menu/cbs/menu_cbs_label.c +++ b/menu/cbs/menu_cbs_label.c @@ -35,55 +35,18 @@ static int action_bind_label_generic( return 0; } -static int action_bind_label_information( - file_list_t *list, - unsigned type, unsigned i, - const char *label, const char *path, - char *s, size_t len) -{ - strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INFORMATION), len); - return 0; +#define fill_label_macro(func, lbl) \ +static int (func)(file_list_t *list, unsigned type, unsigned i, const char *label, const char *path, char *s, size_t len) \ +{ \ + strlcpy(s, msg_hash_to_str(lbl), len); \ + return 0; \ } -static int action_bind_label_internal_memory( - file_list_t *list, - unsigned type, unsigned i, - const char *label, const char *path, - char *s, size_t len) -{ - strlcpy(s, msg_hash_to_str(MSG_INTERNAL_STORAGE), len); - return 0; -} - -static int action_bind_label_removable_storage( - file_list_t *list, - unsigned type, unsigned i, - const char *label, const char *path, - char *s, size_t len) -{ - strlcpy(s, msg_hash_to_str(MSG_REMOVABLE_STORAGE), len); - return 0; -} - -static int action_bind_label_external_application_dir( - file_list_t *list, - unsigned type, unsigned i, - const char *label, const char *path, - char *s, size_t len) -{ - strlcpy(s, msg_hash_to_str(MSG_EXTERNAL_APPLICATION_DIR), len); - return 0; -} - -static int action_bind_label_application_dir( - file_list_t *list, - unsigned type, unsigned i, - const char *label, const char *path, - char *s, size_t len) -{ - strlcpy(s, msg_hash_to_str(MSG_APPLICATION_DIR), len); - return 0; -} +fill_label_macro(action_bind_label_information, MENU_ENUM_LABEL_VALUE_INFORMATION) +fill_label_macro(action_bind_label_internal_memory, MSG_INTERNAL_STORAGE) +fill_label_macro(action_bind_label_removable_storage, MSG_REMOVABLE_STORAGE) +fill_label_macro(action_bind_label_external_application_dir, MSG_EXTERNAL_APPLICATION_DIR) +fill_label_macro(action_bind_label_application_dir, MSG_APPLICATION_DIR) static int action_bind_label_playlist_collection_entry( file_list_t *list, diff --git a/menu/cbs/menu_cbs_left.c b/menu/cbs/menu_cbs_left.c index 488e103e46..85da1b8e5f 100644 --- a/menu/cbs/menu_cbs_left.c +++ b/menu/cbs/menu_cbs_left.c @@ -159,8 +159,6 @@ static int action_left_mainmenu(unsigned type, const char *label, { settings_t *settings = config_get_ptr(); - menu_navigation_set_selection(0); - if ((list_info.selection != 0) || settings->bools.menu_navigation_wraparound_enable) push_list = 1; @@ -388,7 +386,6 @@ static int bind_left_generic(unsigned type, const char *label, static int menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t *cbs, const char *label, uint32_t label_hash, const char *menu_label) { - unsigned i; if (cbs->setting) { @@ -402,21 +399,25 @@ static int menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t *cbs, } } - for (i = 0; i < MAX_USERS; i++) + if (strstr(label, "input_player") && strstr(label, "_joypad_index")) { - uint32_t label_setting_hash; - char label_setting[128]; - - label_setting[0] = '\0'; + unsigned i; + for (i = 0; i < MAX_USERS; i++) + { + uint32_t label_setting_hash; + char label_setting[128]; - snprintf(label_setting, sizeof(label_setting), "input_player%d_joypad_index", i + 1); - label_setting_hash = msg_hash_calculate(label_setting); + label_setting[0] = '\0'; - if (label_hash != label_setting_hash) - continue; + snprintf(label_setting, sizeof(label_setting), "input_player%d_joypad_index", i + 1); + label_setting_hash = msg_hash_calculate(label_setting); - BIND_ACTION_LEFT(cbs, bind_left_generic); - return 0; + if (label_hash != label_setting_hash) + continue; + + BIND_ACTION_LEFT(cbs, bind_left_generic); + return 0; + } } if (string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB))) @@ -464,6 +465,7 @@ static int menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_NO_PLAYLIST_ENTRIES_AVAILABLE: if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_MUSIC_TAB)) || @@ -483,6 +485,7 @@ static int menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_TAKE_SCREENSHOT: if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) || @@ -584,6 +587,7 @@ static int menu_cbs_init_bind_left_compare_type(menu_file_list_cbs_t *cbs, case MENU_SETTING_GROUP: case MENU_SETTINGS_CORE_INFO_NONE: if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) || @@ -624,6 +628,7 @@ int menu_cbs_init_bind_left(menu_file_list_cbs_t *cbs, if (type == MENU_SETTING_NO_ITEM) { if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) || diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 9805887fee..9919155f5e 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1,6 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2015-2017 - Andrés Suárez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -158,6 +159,42 @@ int generic_action_ok_displaylist_push(const char *path, info.enum_idx = MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_START; dl_type = DISPLAYLIST_GENERIC; break; + case ACTION_OK_DL_FAVORITES_LIST: + info.type = type; + info.directory_ptr = idx; + info_path = label; + info_label = msg_hash_to_str( + MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST); + info.enum_idx = MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST; + dl_type = DISPLAYLIST_GENERIC; + break; + case ACTION_OK_DL_IMAGES_LIST: + info.type = type; + info.directory_ptr = idx; + info_path = label; + info_label = msg_hash_to_str( + MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST); + info.enum_idx = MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST; + dl_type = DISPLAYLIST_GENERIC; + break; + case ACTION_OK_DL_MUSIC_LIST: + info.type = type; + info.directory_ptr = idx; + info_path = label; + info_label = msg_hash_to_str( + MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST); + info.enum_idx = MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST; + dl_type = DISPLAYLIST_GENERIC; + break; + case ACTION_OK_DL_VIDEO_LIST: + info.type = type; + info.directory_ptr = idx; + info_path = label; + info_label = msg_hash_to_str( + MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST); + info.enum_idx = MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST; + dl_type = DISPLAYLIST_GENERIC; + break; case ACTION_OK_DL_USER_BINDS_LIST: info.type = type; info.directory_ptr = idx; @@ -262,6 +299,16 @@ int generic_action_ok_displaylist_push(const char *path, info_label = label; dl_type = DISPLAYLIST_GENERIC; break; + case ACTION_OK_DL_FILE_BROWSER_SELECT_FILE: + if (path) + strlcpy(menu->deferred_path, path, + sizeof(menu->deferred_path)); + + info.type = type; + info.directory_ptr = idx; + info_label = label; + dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE; + break; case ACTION_OK_DL_FILE_BROWSER_SELECT_DIR: if (path) strlcpy(menu->deferred_path, path, @@ -323,6 +370,7 @@ int generic_action_ok_displaylist_push(const char *path, break; case ACTION_OK_DL_DISK_IMAGE_APPEND_LIST: filebrowser_clear_type(); + filebrowser_set_type(FILEBROWSER_APPEND_IMAGE); info.type = type; info.directory_ptr = idx; info_path = settings->paths.directory_menu_content; @@ -849,7 +897,7 @@ static bool menu_content_playlist_load(menu_content_ctx_playlist_info_t *info) char *path_tolower = strdup(path); for (i = 0; i < strlen(path_tolower); ++i) - path_tolower[i] = tolower(path_tolower[i]); + path_tolower[i] = tolower((unsigned char)path_tolower[i]); if (strstr(path_tolower, file_path_str(FILE_PATH_ZIP_EXTENSION))) strstr(path_tolower, file_path_str(FILE_PATH_ZIP_EXTENSION))[4] = '\0'; @@ -904,7 +952,7 @@ static bool menu_content_find_first_core(menu_content_ctx_defer_info_t *def_info size_t default_info_length = def_info->len; if (!string_is_empty(default_info_path)) - fill_pathname_join(def_info->s, + fill_pathname_join(def_info->s, default_info_dir, default_info_path, default_info_length); @@ -925,15 +973,17 @@ static bool menu_content_find_first_core(menu_content_ctx_defer_info_t *def_info def_info->s, &info, &supported); - /* We started the menu with 'Load Content', we are + /* We started the menu with 'Load Content', we are * going to use the current core to load this. */ if (load_content_with_current_core) { core_info_get_current_core((core_info_t**)&info); if (info) { - RARCH_LOG("Use the current core (%s) to load this content...\n", +#if 0 + RARCH_LOG("[lobby] use the current core (%s) to load this content...\n", info->path); +#endif supported = 1; } } @@ -1058,7 +1108,8 @@ static int action_ok_file_load_with_detect_core(const char *path, type = 0; label = NULL; - return file_load_with_detect_core_wrapper(MSG_UNKNOWN, + return file_load_with_detect_core_wrapper( + MSG_UNKNOWN, MSG_UNKNOWN, idx, entry_idx, path, label, type, false); } @@ -1075,6 +1126,20 @@ static int action_ok_file_load_with_detect_core_collection(const char *path, path, label, type, false); } +static int set_path_generic(const char *label, const char *action_path) +{ + rarch_setting_t *setting = menu_setting_find(label); + + if (setting) + { + setting_set_with_string_representation( + setting, action_path); + return menu_setting_generic(setting, false); + } + + return 0; +} + static int generic_action_ok(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx, unsigned id, enum msg_hash_enums flush_id) @@ -1209,68 +1274,23 @@ static int generic_action_ok(const char *path, break; case ACTION_OK_SET_DIRECTORY: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(filebrowser_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(filebrowser_label, action_path); break; case ACTION_OK_SET_PATH_VIDEO_FILTER: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(filebrowser_label, action_path); break; case ACTION_OK_SET_PATH_AUDIO_FILTER: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(menu_label, action_path); break; case ACTION_OK_SET_PATH_OVERLAY: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(menu_label, action_path); break; case ACTION_OK_SET_PATH: flush_type = MENU_SETTINGS; - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(menu_label, action_path); break; default: flush_char = msg_hash_to_str(flush_id); @@ -1285,33 +1305,24 @@ error: return menu_cbs_exit(); } -static int action_ok_set_path_videofilter(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_SET_PATH_VIDEO_FILTER, MSG_UNKNOWN); +#define default_action_ok_set(funcname, _id, _flush) \ +static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \ +{ \ + return generic_action_ok(path, label, type, idx, entry_idx, _id, _flush); \ } -static int action_ok_set_path_audiofilter(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_SET_PATH_AUDIO_FILTER, MSG_UNKNOWN); -} - -static int action_ok_set_path_overlay(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_SET_PATH_OVERLAY, MSG_UNKNOWN); -} - -static int action_ok_set_path(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_SET_PATH, MSG_UNKNOWN); -} +default_action_ok_set(action_ok_set_path_audiofilter, ACTION_OK_SET_PATH_VIDEO_FILTER, MSG_UNKNOWN) +default_action_ok_set(action_ok_set_path_videofilter, ACTION_OK_SET_PATH_AUDIO_FILTER, MSG_UNKNOWN) +default_action_ok_set(action_ok_set_path_overlay, ACTION_OK_SET_PATH_OVERLAY, MSG_UNKNOWN) +default_action_ok_set(action_ok_set_path, ACTION_OK_SET_PATH, MSG_UNKNOWN) +default_action_ok_set(action_ok_load_core, ACTION_OK_LOAD_CORE, MSG_UNKNOWN) +default_action_ok_set(action_ok_config_load, ACTION_OK_LOAD_CONFIG_FILE, MSG_UNKNOWN) +default_action_ok_set(action_ok_disk_image_append, ACTION_OK_APPEND_DISK_IMAGE, MSG_UNKNOWN) +default_action_ok_set(action_ok_cheat_file_load, ACTION_OK_LOAD_CHEAT_FILE, MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS) +default_action_ok_set(action_ok_record_configfile_load, ACTION_OK_LOAD_RECORD_CONFIGFILE, MENU_ENUM_LABEL_RECORDING_SETTINGS) +default_action_ok_set(action_ok_remap_file_load, ACTION_OK_LOAD_REMAPPING_FILE, MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS ) +default_action_ok_set(action_ok_shader_preset_load, ACTION_OK_LOAD_PRESET , MENU_ENUM_LABEL_SHADER_OPTIONS) +default_action_ok_set(action_ok_shader_pass_load, ACTION_OK_LOAD_SHADER_PASS, MENU_ENUM_LABEL_SHADER_OPTIONS) static int action_ok_file_load(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) @@ -1424,11 +1435,11 @@ static int action_ok_playlist_entry_collection(const char *path, playlist_get_index(playlist, selection_ptr, &entry_path, &entry_label, &core_path, &core_name, NULL, NULL); - /* If the currently loaded core's name is equal + /* If the currently loaded core's name is equal * to the core name from the playlist entry, * then we directly load this game with the current core. */ - if (system && + if (system && string_is_equal(system->library_name, core_name)) { if (playlist_initialized) @@ -1653,7 +1664,7 @@ static int action_ok_playlist_entry_start_content(const char *path, new_core_path[0] = new_display_name[0] = '\0'; - found_associated_core = + found_associated_core = menu_content_playlist_find_associated_core( path_base, new_core_path, sizeof(new_core_path)); @@ -1758,7 +1769,7 @@ static int action_ok_audio_add_to_mixer_and_collection(const char *path, fill_pathname_join(combined_path, menu->scratch2_buf, menu->scratch_buf, sizeof(combined_path)); - playlist_push(g_defaults.music_history, + playlist_push(g_defaults.music_history, combined_path, NULL, "builtin", @@ -1801,65 +1812,6 @@ static int action_ok_menu_wallpaper_load(const char *path, ACTION_OK_LOAD_WALLPAPER, MSG_UNKNOWN); } -static int action_ok_load_core(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_LOAD_CORE, MSG_UNKNOWN); -} - -static int action_ok_config_load(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_LOAD_CONFIG_FILE, MSG_UNKNOWN); -} - -static int action_ok_disk_image_append(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_APPEND_DISK_IMAGE, MSG_UNKNOWN); -} - -static int action_ok_cheat_file_load(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_LOAD_CHEAT_FILE, - MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS); -} - -static int action_ok_record_configfile_load(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_LOAD_RECORD_CONFIGFILE, - MENU_ENUM_LABEL_RECORDING_SETTINGS); -} - -static int action_ok_remap_file_load(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_LOAD_REMAPPING_FILE, - MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS); -} - -static int action_ok_shader_preset_load(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_LOAD_PRESET, MENU_ENUM_LABEL_SHADER_OPTIONS); -} - -static int action_ok_shader_pass_load(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok(path, label, type, idx, entry_idx, - ACTION_OK_LOAD_SHADER_PASS, MENU_ENUM_LABEL_SHADER_OPTIONS); -} - int generic_action_ok_help(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx, enum msg_hash_enums id, enum menu_dialog_type id2) @@ -1910,6 +1862,37 @@ static int action_ok_cheat(const char *path, return 0; } +static void menu_input_st_string_cb_rename_entry(void *userdata, + const char *str) +{ + if (str && *str) + { + const char *label = menu_input_dialog_get_buffer(); + + if (!string_is_empty(label)) + { + playlist_t *tmp_playlist = NULL; + menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_GET, &tmp_playlist); + size_t new_selection_ptr = menu_input_dialog_get_kb_idx(); + + if (tmp_playlist) + { + playlist_update(tmp_playlist, + new_selection_ptr, + NULL, + label, + NULL, + NULL, + NULL, + NULL); + playlist_write_file(tmp_playlist); + } + } + } + + menu_input_dialog_end(); +} + static void menu_input_st_string_cb_save_preset(void *userdata, const char *str) { @@ -2080,10 +2063,12 @@ static int action_ok_cheat_file_save_as(const char *path, enum { ACTION_OK_REMAP_FILE_SAVE_CORE = 0, - ACTION_OK_REMAP_FILE_SAVE_GAME + ACTION_OK_REMAP_FILE_SAVE_GAME, + ACTION_OK_REMAP_FILE_REMOVE_CORE, + ACTION_OK_REMAP_FILE_REMOVE_GAME }; -static int generic_action_ok_remap_file_save(const char *path, +static int generic_action_ok_remap_file_operation(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx, unsigned action_type) { @@ -2108,10 +2093,12 @@ static int generic_action_ok_remap_file_save(const char *path, switch (action_type) { case ACTION_OK_REMAP_FILE_SAVE_CORE: + case ACTION_OK_REMAP_FILE_REMOVE_CORE: if (!string_is_empty(core_name)) fill_pathname_join(file, core_name, core_name, sizeof(file)); break; case ACTION_OK_REMAP_FILE_SAVE_GAME: + case ACTION_OK_REMAP_FILE_REMOVE_GAME: if (!string_is_empty(core_name)) fill_pathname_join(file, core_name, path_basename(path_get(RARCH_PATH_BASENAME)), sizeof(file)); @@ -2121,32 +2108,73 @@ static int generic_action_ok_remap_file_save(const char *path, if(!path_file_exists(directory)) path_mkdir(directory); - if(input_remapping_save_file(file)) - runloop_msg_queue_push( - msg_hash_to_str(MSG_REMAP_FILE_SAVED_SUCCESSFULLY), - 1, 100, true); - else - runloop_msg_queue_push( - msg_hash_to_str(MSG_ERROR_SAVING_REMAP_FILE), - 1, 100, true); + if (action_type < ACTION_OK_REMAP_FILE_REMOVE_CORE) + { + if(input_remapping_save_file(file)) + { + if (action_type == ACTION_OK_REMAP_FILE_SAVE_CORE) + rarch_ctl(RARCH_CTL_SET_REMAPS_CORE_ACTIVE, NULL); + else + rarch_ctl(RARCH_CTL_SET_REMAPS_GAME_ACTIVE, NULL); + runloop_msg_queue_push( + msg_hash_to_str(MSG_REMAP_FILE_SAVED_SUCCESSFULLY), + 1, 100, true); + } + else + runloop_msg_queue_push( + msg_hash_to_str(MSG_ERROR_SAVING_REMAP_FILE), + 1, 100, true); + } + else + { + if(input_remapping_remove_file(file)) + { + if (action_type == ACTION_OK_REMAP_FILE_REMOVE_CORE) + rarch_ctl(RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE, NULL); + else + rarch_ctl(RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE, NULL); + + runloop_msg_queue_push( + msg_hash_to_str(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY), + 1, 100, true); + } + else + runloop_msg_queue_push( + msg_hash_to_str(MSG_ERROR_REMOVING_REMAP_FILE), + 1, 100, true); + } return 0; } static int action_ok_remap_file_save_core(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - return generic_action_ok_remap_file_save(path, label, type, + return generic_action_ok_remap_file_operation(path, label, type, idx, entry_idx, ACTION_OK_REMAP_FILE_SAVE_CORE); } static int action_ok_remap_file_save_game(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - return generic_action_ok_remap_file_save(path, label, type, + return generic_action_ok_remap_file_operation(path, label, type, idx, entry_idx, ACTION_OK_REMAP_FILE_SAVE_GAME); } +static int action_ok_remap_file_remove_core(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + return generic_action_ok_remap_file_operation(path, label, type, + idx, entry_idx, ACTION_OK_REMAP_FILE_REMOVE_CORE); +} + +static int action_ok_remap_file_remove_game(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + return generic_action_ok_remap_file_operation(path, label, type, + idx, entry_idx, ACTION_OK_REMAP_FILE_REMOVE_GAME); +} + int action_ok_path_use_directory(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -2430,8 +2458,6 @@ static int action_ok_file_load_detect_core(const char *path, return 0; } - - static int generic_action_ok_command(enum event_command cmd) { if (!command_event(cmd, NULL)) @@ -2581,7 +2607,7 @@ static int generic_action_ok_network(const char *path, default: break; } - + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); command_event(CMD_EVENT_NETWORK_INIT, NULL); @@ -3008,12 +3034,6 @@ static int action_ok_update_autoconfig_profiles(const char *path, MENU_ENUM_LABEL_CB_UPDATE_AUTOCONFIG_PROFILES); } -static int action_ok_disk_cycle_tray_status(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_command(CMD_EVENT_DISK_EJECT_TOGGLE); -} - /* creates folder and core options stub file for subsequent runs */ static int action_ok_option_create(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) @@ -3052,60 +3072,65 @@ static int action_ok_option_create(const char *path, return 0; } - -static int action_ok_close_content(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_command(CMD_EVENT_UNLOAD_CORE); +#define default_action_ok_cmd_func(func_name, cmd) \ +int (func_name)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \ +{ \ + return generic_action_ok_command(cmd); \ } -static int action_ok_quit(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_command(CMD_EVENT_QUIT); -} +default_action_ok_cmd_func(action_ok_close_content, CMD_EVENT_UNLOAD_CORE) +default_action_ok_cmd_func(action_ok_quit, CMD_EVENT_QUIT) +default_action_ok_cmd_func(action_ok_save_new_config, CMD_EVENT_MENU_SAVE_CONFIG) +default_action_ok_cmd_func(action_ok_resume_content, CMD_EVENT_RESUME) +default_action_ok_cmd_func(action_ok_restart_content, CMD_EVENT_RESET) +default_action_ok_cmd_func(action_ok_screenshot, CMD_EVENT_TAKE_SCREENSHOT) +default_action_ok_cmd_func(action_ok_disk_cycle_tray_status, CMD_EVENT_DISK_EJECT_TOGGLE ) +default_action_ok_cmd_func(action_ok_shader_apply_changes, CMD_EVENT_SHADERS_APPLY_CHANGES ) +default_action_ok_cmd_func(action_ok_add_to_favorites, CMD_EVENT_ADD_TO_FAVORITES) -static int action_ok_save_new_config(const char *path, +static int action_ok_rename_entry(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - return generic_action_ok_command(CMD_EVENT_MENU_SAVE_CONFIG); -} + menu_input_ctx_line_t line; -static int action_ok_resume_content(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_command(CMD_EVENT_RESUME); -} + line.label = msg_hash_to_str(MSG_INPUT_RENAME_ENTRY); + line.label_setting = label; + line.type = type; + line.idx = (unsigned)entry_idx; + line.cb = menu_input_st_string_cb_rename_entry; -static int action_ok_restart_content(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_command(CMD_EVENT_RESET); -} - -static int action_ok_screenshot(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_command(CMD_EVENT_TAKE_SCREENSHOT); + if (!menu_input_dialog_start(&line)) + return -1; + return 0; } static int action_ok_delete_entry(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { size_t new_selection_ptr; - playlist_t *playlist = NULL; - char *conf_path = playlist_get_conf_path(playlist); - char *def_conf_path = playlist_get_conf_path(g_defaults.content_history); - char *def_conf_music_path= playlist_get_conf_path(g_defaults.music_history); + playlist_t *playlist = NULL; + char *conf_path = NULL; + char *def_conf_path = NULL; + char *def_conf_music_path = NULL; #ifdef HAVE_FFMPEG - char *def_conf_video_path= playlist_get_conf_path(g_defaults.video_history); + char *def_conf_video_path = NULL; #endif #ifdef HAVE_IMAGEVIEWER - char *def_conf_img_path = playlist_get_conf_path(g_defaults.image_history); + char *def_conf_img_path = NULL; #endif menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_GET, &playlist); + conf_path = playlist_get_conf_path(playlist); + def_conf_path = playlist_get_conf_path(g_defaults.content_history); + def_conf_music_path = playlist_get_conf_path(g_defaults.music_history); +#ifdef HAVE_FFMPEG + def_conf_video_path = playlist_get_conf_path(g_defaults.video_history); +#endif +#ifdef HAVE_IMAGEVIEWER + def_conf_img_path = playlist_get_conf_path(g_defaults.image_history); +#endif + if (string_is_equal(conf_path, def_conf_path)) playlist = g_defaults.content_history; else if (string_is_equal(conf_path, def_conf_music_path)) @@ -3128,12 +3153,6 @@ static int action_ok_delete_entry(const char *path, return 0; } -static int action_ok_shader_apply_changes(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_command(CMD_EVENT_SHADERS_APPLY_CHANGES); -} - static int action_ok_rdb_entry_submenu(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3205,13 +3224,73 @@ end: extern size_t hack_shader_pass; #endif -static int action_ok_browse_url_start(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_BROWSE_URL_START); +#define default_action_ok_func(func_name, lbl) \ +int (func_name)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \ +{ \ + return generic_action_ok_displaylist_push(path, NULL, label, type, idx, entry_idx, lbl); \ } +default_action_ok_func(action_ok_browse_url_start, ACTION_OK_DL_BROWSE_URL_START) +default_action_ok_func(action_ok_goto_favorites, ACTION_OK_DL_FAVORITES_LIST) +default_action_ok_func(action_ok_goto_images, ACTION_OK_DL_IMAGES_LIST) +default_action_ok_func(action_ok_goto_video, ACTION_OK_DL_VIDEO_LIST) +default_action_ok_func(action_ok_goto_music, ACTION_OK_DL_MUSIC_LIST) +default_action_ok_func(action_ok_shader_parameters, ACTION_OK_DL_SHADER_PARAMETERS) +default_action_ok_func(action_ok_parent_directory_push, ACTION_OK_DL_PARENT_DIRECTORY_PUSH) +default_action_ok_func(action_ok_directory_push, ACTION_OK_DL_DIRECTORY_PUSH) +default_action_ok_func(action_ok_configurations_list, ACTION_OK_DL_CONFIGURATIONS_LIST) +default_action_ok_func(action_ok_saving_list, ACTION_OK_DL_SAVING_SETTINGS_LIST) +default_action_ok_func(action_ok_network_list, ACTION_OK_DL_NETWORK_SETTINGS_LIST) +default_action_ok_func(action_ok_database_manager_list, ACTION_OK_DL_DATABASE_MANAGER_LIST) +default_action_ok_func(action_ok_wifi_list, ACTION_OK_DL_WIFI_SETTINGS_LIST) +default_action_ok_func(action_ok_cursor_manager_list, ACTION_OK_DL_CURSOR_MANAGER_LIST) +default_action_ok_func(action_ok_compressed_archive_push, ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH) +default_action_ok_func(action_ok_compressed_archive_push_detect_core, ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH_DETECT_CORE) +default_action_ok_func(action_ok_logging_list, ACTION_OK_DL_LOGGING_SETTINGS_LIST) +default_action_ok_func(action_ok_frame_throttle_list, ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST) +default_action_ok_func(action_ok_rewind_list, ACTION_OK_DL_REWIND_SETTINGS_LIST) +default_action_ok_func(action_ok_onscreen_display_list, ACTION_OK_DL_ONSCREEN_DISPLAY_SETTINGS_LIST) +default_action_ok_func(action_ok_onscreen_notifications_list, ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST) +default_action_ok_func(action_ok_onscreen_overlay_list, ACTION_OK_DL_ONSCREEN_OVERLAY_SETTINGS_LIST) +default_action_ok_func(action_ok_menu_list, ACTION_OK_DL_MENU_SETTINGS_LIST) +default_action_ok_func(action_ok_menu_views_list, ACTION_OK_DL_MENU_VIEWS_SETTINGS_LIST) +default_action_ok_func(action_ok_user_interface_list, ACTION_OK_DL_USER_INTERFACE_SETTINGS_LIST) +default_action_ok_func(action_ok_menu_file_browser_list, ACTION_OK_DL_MENU_FILE_BROWSER_SETTINGS_LIST) +default_action_ok_func(action_ok_retro_achievements_list, ACTION_OK_DL_RETRO_ACHIEVEMENTS_SETTINGS_LIST) +default_action_ok_func(action_ok_updater_list, ACTION_OK_DL_UPDATER_SETTINGS_LIST) +default_action_ok_func(action_ok_lakka_services, ACTION_OK_DL_LAKKA_SERVICES_LIST) +default_action_ok_func(action_ok_user_list, ACTION_OK_DL_USER_SETTINGS_LIST) +default_action_ok_func(action_ok_netplay_sublist, ACTION_OK_DL_NETPLAY) +default_action_ok_func(action_ok_directory_list, ACTION_OK_DL_DIRECTORY_SETTINGS_LIST) +default_action_ok_func(action_ok_privacy_list, ACTION_OK_DL_PRIVACY_SETTINGS_LIST) +default_action_ok_func(action_ok_rdb_entry, ACTION_OK_DL_RDB_ENTRY) +default_action_ok_func(action_ok_browse_url_list, ACTION_OK_DL_BROWSE_URL_LIST) +default_action_ok_func(action_ok_core_list, ACTION_OK_DL_CORE_LIST) +default_action_ok_func(action_ok_cheat_file, ACTION_OK_DL_CHEAT_FILE) +default_action_ok_func(action_ok_playlist_collection, ACTION_OK_DL_PLAYLIST_COLLECTION) +default_action_ok_func(action_ok_disk_image_append_list, ACTION_OK_DL_DISK_IMAGE_APPEND_LIST) +default_action_ok_func(action_ok_record_configfile, ACTION_OK_DL_RECORD_CONFIGFILE) +default_action_ok_func(action_ok_remap_file, ACTION_OK_DL_REMAP_FILE) +default_action_ok_func(action_ok_shader_preset, ACTION_OK_DL_SHADER_PRESET) +default_action_ok_func(action_ok_push_generic_list, ACTION_OK_DL_GENERIC) +default_action_ok_func(action_ok_audio_dsp_plugin, ACTION_OK_DL_AUDIO_DSP_PLUGIN) +default_action_ok_func(action_ok_rpl_entry, ACTION_OK_DL_RPL_ENTRY) +default_action_ok_func(action_ok_open_archive_detect_core, ACTION_OK_DL_OPEN_ARCHIVE_DETECT_CORE) +default_action_ok_func(action_ok_file_load_music, ACTION_OK_DL_MUSIC) +default_action_ok_func(action_ok_push_accounts_list, ACTION_OK_DL_ACCOUNTS_LIST) +default_action_ok_func(action_ok_push_driver_settings_list, ACTION_OK_DL_DRIVER_SETTINGS_LIST) +default_action_ok_func(action_ok_push_video_settings_list, ACTION_OK_DL_VIDEO_SETTINGS_LIST) +default_action_ok_func(action_ok_push_configuration_settings_list, ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST) +default_action_ok_func(action_ok_push_core_settings_list, ACTION_OK_DL_CORE_SETTINGS_LIST) +default_action_ok_func(action_ok_push_audio_settings_list, ACTION_OK_DL_AUDIO_SETTINGS_LIST) +default_action_ok_func(action_ok_push_input_settings_list, ACTION_OK_DL_INPUT_SETTINGS_LIST) +default_action_ok_func(action_ok_push_recording_settings_list, ACTION_OK_DL_RECORDING_SETTINGS_LIST) +default_action_ok_func(action_ok_push_playlist_settings_list, ACTION_OK_DL_PLAYLIST_SETTINGS_LIST) +default_action_ok_func(action_ok_push_input_hotkey_binds_list, ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST) +default_action_ok_func(action_ok_push_user_binds_list, ACTION_OK_DL_USER_BINDS_LIST) +default_action_ok_func(action_ok_push_accounts_cheevos_list, ACTION_OK_DL_ACCOUNTS_CHEEVOS_LIST) +default_action_ok_func(action_ok_open_archive, ACTION_OK_DL_OPEN_ARCHIVE) + static int action_ok_shader_pass(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3220,177 +3299,11 @@ static int action_ok_shader_pass(const char *path, entry_idx, ACTION_OK_DL_SHADER_PASS); } -static int action_ok_shader_parameters(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_SHADER_PARAMETERS); -} - -int action_ok_parent_directory_push(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_PARENT_DIRECTORY_PUSH); -} - -int action_ok_directory_push(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, - entry_idx, ACTION_OK_DL_DIRECTORY_PUSH); -} - -static int action_ok_database_manager_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, - entry_idx, ACTION_OK_DL_DATABASE_MANAGER_LIST); -} - -static int action_ok_cursor_manager_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, - entry_idx, ACTION_OK_DL_CURSOR_MANAGER_LIST); -} - -static int action_ok_compressed_archive_push(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, - entry_idx, ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH); -} - -static int action_ok_compressed_archive_push_detect_core(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, - entry_idx, ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH_DETECT_CORE); -} - -static int action_ok_configurations_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_CONFIGURATIONS_LIST); -} - -static int action_ok_saving_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_SAVING_SETTINGS_LIST); -} - -static int action_ok_logging_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_LOGGING_SETTINGS_LIST); -} - -static int action_ok_frame_throttle_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST); -} - -static int action_ok_rewind_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_REWIND_SETTINGS_LIST); -} - -static int action_ok_onscreen_display_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_ONSCREEN_DISPLAY_SETTINGS_LIST); -} - -static int action_ok_onscreen_notifications_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST); -} - -static int action_ok_onscreen_overlay_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_ONSCREEN_OVERLAY_SETTINGS_LIST); -} - -static int action_ok_menu_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_MENU_SETTINGS_LIST); -} - -static int action_ok_menu_views_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_MENU_VIEWS_SETTINGS_LIST); -} - -static int action_ok_user_interface_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_USER_INTERFACE_SETTINGS_LIST); -} - -static int action_ok_menu_file_browser_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_MENU_FILE_BROWSER_SETTINGS_LIST); -} - -static int action_ok_retro_achievements_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_RETRO_ACHIEVEMENTS_SETTINGS_LIST); -} - -static int action_ok_updater_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_UPDATER_SETTINGS_LIST); -} - -static int action_ok_wifi_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_WIFI_SETTINGS_LIST); -} - -static int action_ok_network_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_NETWORK_SETTINGS_LIST); -} - static int action_ok_netplay_connect_room(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { #ifdef HAVE_NETWORKING - char tmp_hostname[512]; + char tmp_hostname[4115]; tmp_hostname[0] = '\0'; @@ -3415,10 +3328,12 @@ static int action_ok_netplay_connect_room(const char *path, netplay_room_list[idx - 3].port); } - RARCH_LOG("Connecting to: %s with game: %s/%08x\n", +#if 0 + RARCH_LOG("[lobby] connecting to: %s with game: %s/%08x\n", tmp_hostname, netplay_room_list[idx - 3].gamename, netplay_room_list[idx - 3].gamecrc); +#endif task_push_netplay_crc_scan(netplay_room_list[idx - 3].gamecrc, netplay_room_list[idx - 3].gamename, @@ -3431,48 +3346,6 @@ static int action_ok_netplay_connect_room(const char *path, return 0; } -static int action_ok_lakka_services(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_LAKKA_SERVICES_LIST); -} - -static int action_ok_user_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_USER_SETTINGS_LIST); -} - -static int action_ok_netplay_sublist(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_NETPLAY); -} - -static int action_ok_directory_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_DIRECTORY_SETTINGS_LIST); -} - -static int action_ok_privacy_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_PRIVACY_SETTINGS_LIST); -} - -static int action_ok_rdb_entry(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_RDB_ENTRY); -} - static int action_ok_wifi(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3510,21 +3383,10 @@ static int action_ok_netplay_lan_scan(const char *path, netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL); /* Enable Netplay */ - if (!command_event(CMD_EVENT_NETPLAY_INIT_DIRECT, (void *) host)) - return -1; - - return generic_action_ok_command(CMD_EVENT_RESUME); - -#else - return -1; + if (command_event(CMD_EVENT_NETPLAY_INIT_DIRECT, (void *) host)) + return generic_action_ok_command(CMD_EVENT_RESUME); #endif -} - -static int action_ok_browse_url_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_BROWSE_URL_LIST); + return -1; } static int action_ok_content_collection_list(const char *path, @@ -3535,48 +3397,6 @@ static int action_ok_content_collection_list(const char *path, entry_idx, ACTION_OK_DL_CONTENT_COLLECTION_LIST); } -static int action_ok_core_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_CORE_LIST); -} - -static int action_ok_cheat_file(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_CHEAT_FILE); -} - -static int action_ok_playlist_collection(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_PLAYLIST_COLLECTION); -} - -static int action_ok_disk_image_append_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_DISK_IMAGE_APPEND_LIST); -} - -static int action_ok_record_configfile(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_RECORD_CONFIGFILE); -} - -static int action_ok_remap_file(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_REMAP_FILE); -} - static int action_ok_push_content_list(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3587,23 +3407,24 @@ static int action_ok_push_content_list(const char *path, entry_idx, ACTION_OK_DL_CONTENT_LIST); } - - static int action_ok_push_scan_file(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - filebrowser_clear_type(); - return action_ok_push_content_list(path, label, type, idx, entry_idx); + settings_t *settings = config_get_ptr(); + filebrowser_set_type(FILEBROWSER_SCAN_FILE); + return generic_action_ok_displaylist_push(path, + settings->paths.directory_menu_content, label, type, idx, + entry_idx, ACTION_OK_DL_CONTENT_LIST); } #ifdef HAVE_NETWORKING struct netplay_host_list *lan_hosts; int lan_room_count; + void netplay_refresh_rooms_menu(file_list_t *list) { - char s[PATH_MAX_LENGTH]; + char s[4115]; int i = 0; - int j = 0; menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, list); @@ -3649,13 +3470,20 @@ void netplay_refresh_rooms_menu(file_list_t *list) if (netplay_room_count != 0) { - RARCH_LOG ("Found %d rooms...\n", netplay_room_count); - for (i = 0; i < netplay_room_count; i++) { + char country[PATH_MAX_LENGTH] = {0}; + + if (*netplay_room_list[i].country) + { + strlcat(country, " (", sizeof(country)); + strlcat(country, netplay_room_list[i].country, sizeof(country)); + strlcat(country, ")", sizeof(country)); + } + /* Uncomment this to debug mismatched room parameters*/ #if 0 - RARCH_LOG("Room Data: %d\n" + RARCH_LOG("[lobby] room Data: %d\n" "Nickname: %s\n" "Address: %s\n" "Port: %d\n" @@ -3673,25 +3501,18 @@ void netplay_refresh_rooms_menu(file_list_t *list) netplay_room_list[i].gamecrc, netplay_room_list[i].timestamp); #endif - j+=8; - if (netplay_room_list[i].lan) - { - snprintf(s, sizeof(s), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN), - netplay_room_list[i].nickname); - } - else - { - snprintf(s, sizeof(s), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME), - netplay_room_list[i].nickname); - } + + snprintf(s, sizeof(s), "%s: %s%s", + netplay_room_list[i].lan ? "Local" : + (netplay_room_list[i].host_method == NETPLAY_HOST_METHOD_MITM ? + "Internet (relay)" : "Internet (direct)"), + netplay_room_list[i].nickname, country); menu_entries_append_enum(list, s, msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM), MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM, - MENU_ROOM, 0, 0); + MENU_SETTINGS_NETPLAY_ROOMS_START + i, 0, 0); } netplay_rooms_free(); @@ -3729,7 +3550,6 @@ static void netplay_refresh_rooms_cb(void *task_data, void *user_data, const cha if (string_is_empty(data->data)) { netplay_room_count = 0; - RARCH_LOG("Room list empty\n"); } else { @@ -3776,14 +3596,14 @@ static void netplay_refresh_rooms_cb(void *task_data, void *user_data, const cha if (address->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *) address; - inet_ntop_compat(AF_INET, &sin->sin_addr, + inet_ntop_compat(AF_INET, &sin->sin_addr, netplay_room_list[i].address, INET6_ADDRSTRLEN); } #if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY) else if (address->sa_family == AF_INET6) { struct sockaddr_in6 *sin = (struct sockaddr_in6 *) address; - inet_ntop_compat(AF_INET6, &sin->sin6_addr, + inet_ntop_compat(AF_INET6, &sin->sin6_addr, netplay_room_list[i].address, INET6_ADDRSTRLEN); } #endif @@ -3791,6 +3611,9 @@ static void netplay_refresh_rooms_cb(void *task_data, void *user_data, const cha strlcpy(netplay_room_list[i].corename, host->core, sizeof(netplay_room_list[i].corename)); + strlcpy(netplay_room_list[i].retroarch_version, + host->retroarch_version, + sizeof(netplay_room_list[i].retroarch_version)); strlcpy(netplay_room_list[i].coreversion, host->core_version, sizeof(netplay_room_list[i].coreversion)); @@ -3804,7 +3627,7 @@ static void netplay_refresh_rooms_cb(void *task_data, void *user_data, const cha netplay_room_list[i].lan = true; snprintf(s, sizeof(s), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME), netplay_room_list[i].nickname); } netplay_room_count += lan_room_count; @@ -3914,20 +3737,6 @@ static int action_ok_push_downloads_dir(const char *path, entry_idx, ACTION_OK_DL_CONTENT_LIST); } -static int action_ok_shader_preset(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_SHADER_PRESET); -} - -int action_ok_push_generic_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_GENERIC); -} - int action_ok_push_filebrowser_list_dir_select(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3937,6 +3746,15 @@ int action_ok_push_filebrowser_list_dir_select(const char *path, entry_idx, ACTION_OK_DL_FILE_BROWSER_SELECT_DIR); } +int action_ok_push_filebrowser_list_file_select(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + filebrowser_set_type(FILEBROWSER_SELECT_FILE); + strlcpy(filebrowser_label, label, sizeof(filebrowser_label)); + return generic_action_ok_displaylist_push(path, NULL, label, type, idx, + entry_idx, ACTION_OK_DL_FILE_BROWSER_SELECT_DIR); +} + static int action_ok_push_default(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3945,20 +3763,6 @@ static int action_ok_push_default(const char *path, entry_idx, ACTION_OK_DL_PUSH_DEFAULT); } -static int action_ok_audio_dsp_plugin(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_AUDIO_DSP_PLUGIN); -} - -static int action_ok_rpl_entry(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, - entry_idx, ACTION_OK_DL_RPL_ENTRY); -} - static int action_ok_start_core(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3975,125 +3779,6 @@ static int action_ok_start_core(const char *path, return 0; } -static int action_ok_open_archive_detect_core(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_OPEN_ARCHIVE_DETECT_CORE); -} - -static int action_ok_file_load_music(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_MUSIC); -} - -static int action_ok_push_accounts_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_ACCOUNTS_LIST); -} - -static int action_ok_push_driver_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_DRIVER_SETTINGS_LIST); -} - -static int action_ok_push_video_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_VIDEO_SETTINGS_LIST); -} - -static int action_ok_push_configuration_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST); -} - -static int action_ok_push_core_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_CORE_SETTINGS_LIST); -} - -static int action_ok_push_audio_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_AUDIO_SETTINGS_LIST); -} - -static int action_ok_push_input_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_INPUT_SETTINGS_LIST); -} - -static int action_ok_push_recording_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_RECORDING_SETTINGS_LIST); -} - -static int action_ok_push_playlist_settings_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_PLAYLIST_SETTINGS_LIST); -} - -static int action_ok_push_input_hotkey_binds_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST); -} - -static int action_ok_push_user_binds_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_USER_BINDS_LIST); -} - -static int action_ok_push_accounts_cheevos_list(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, label, type, idx, entry_idx, - ACTION_OK_DL_ACCOUNTS_CHEEVOS_LIST); -} - -static int action_ok_open_archive(const char *path, - const char *label, unsigned type, size_t idx, size_t entry_idx) -{ - return generic_action_ok_displaylist_push(path, NULL, - label, type, idx, entry_idx, - ACTION_OK_DL_OPEN_ARCHIVE); -} - static int action_ok_load_archive(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -4103,10 +3788,10 @@ static int action_ok_load_archive(const char *path, const char *menu_path = NULL; const char *content_path = NULL; - content_info.argc = 0; - content_info.argv = NULL; - content_info.args = NULL; - content_info.environ_get = NULL; + content_info.argc = 0; + content_info.argv = NULL; + content_info.args = NULL; + content_info.environ_get = NULL; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) return menu_cbs_exit(); @@ -4140,7 +3825,7 @@ static int action_ok_load_archive_detect_core(const char *path, const char *menu_path = NULL; const char *content_path = NULL; - new_core_path[0] = '\0'; + new_core_path[0] = '\0'; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) return menu_cbs_exit(); @@ -4184,12 +3869,10 @@ static int action_ok_load_archive_detect_core(const char *path, } return 0; case 0: - { - idx = menu_navigation_get_selection(); - return generic_action_ok_displaylist_push(path, NULL, - label, type, - idx, entry_idx, ACTION_OK_DL_DEFERRED_CORE_LIST); - } + idx = menu_navigation_get_selection(); + return generic_action_ok_displaylist_push(path, NULL, + label, type, + idx, entry_idx, ACTION_OK_DL_DEFERRED_CORE_LIST); default: break; } @@ -4260,7 +3943,7 @@ static int action_ok_video_resolution(const char *path, msg[0] = '\0'; -#ifdef __CELLOS_LV2__ +#if defined(__CELLOS_LV2__) || defined(_WIN32) command_event(CMD_EVENT_REINIT, NULL); #endif video_driver_set_video_mode(width, height, true); @@ -4301,15 +3984,10 @@ static int action_ok_netplay_enable_host(const char *path, } /* Enable Netplay itself */ - if (!command_event(CMD_EVENT_NETPLAY_INIT, NULL)) - return -1; - - return generic_action_ok_command(CMD_EVENT_RESUME); - -#else - return -1; - + if (command_event(CMD_EVENT_NETPLAY_INIT, NULL)) + return generic_action_ok_command(CMD_EVENT_RESUME); #endif + return -1; } #ifdef HAVE_NETWORKING @@ -4364,21 +4042,27 @@ static int action_ok_netplay_enable_client(const char *path, line.label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS); line.label_setting = "no_setting"; line.cb = action_ok_netplay_enable_client_hostname_cb; - if (!menu_input_dialog_start(&line)) - return -1; - return 0; - -#else - return -1; + if (menu_input_dialog_start(&line)) + return 0; #endif + return -1; } static int action_ok_netplay_disconnect(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { #ifdef HAVE_NETWORKING + settings_t *settings = config_get_ptr(); + netplay_driver_ctl(RARCH_NETPLAY_CTL_DISCONNECT, NULL); netplay_driver_ctl(RARCH_NETPLAY_CTL_DISABLE, NULL); + + /* Re-enable rewind if it was enabled + TODO: Add a setting for these tweaks */ + if (settings->bools.rewind_enable) + command_event(CMD_EVENT_REWIND_INIT, NULL); + if (settings->uints.autosave_interval != 0) + command_event(CMD_EVENT_AUTOSAVE_INIT, NULL); return generic_action_ok_command(CMD_EVENT_RESUME); #else @@ -4387,6 +4071,21 @@ static int action_ok_netplay_disconnect(const char *path, #endif } +static int action_ok_core_delete(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + char* core_path = strdup(path_get(RARCH_PATH_CORE)); + + generic_action_ok_command(CMD_EVENT_UNLOAD_CORE); + menu_entries_flush_stack(0, 0); + + remove(core_path); + + free(core_path); + + return 0; +} + static int is_rdb_entry(enum msg_hash_enums enum_idx) { switch (enum_idx) @@ -4426,25 +4125,22 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, if (cbs->enum_idx != MSG_UNKNOWN) { - unsigned i; + const char *str = msg_hash_to_str(cbs->enum_idx); - for (i = 0; i < MAX_USERS; i++) + if (str && strstr(str, "input_binds_list")) { - unsigned first_char = 0; - const char *str = msg_hash_to_str(cbs->enum_idx); + unsigned i; - if (!str) - continue; - if (!strstr(str, "input_binds_list")) - continue; + for (i = 0; i < MAX_USERS; i++) + { + unsigned first_char = atoi(&str[0]); - first_char = atoi(&str[0]); + if (first_char != ((i+1))) + continue; - if (first_char != ((i+1))) - continue; - - BIND_ACTION_OK(cbs, action_ok_push_user_binds_list); - return 0; + BIND_ACTION_OK(cbs, action_ok_push_user_binds_list); + return 0; + } } } @@ -4473,6 +4169,18 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_VIDEO_FONT_PATH: BIND_ACTION_OK(cbs, action_ok_menu_font); break; + case MENU_ENUM_LABEL_GOTO_FAVORITES: + BIND_ACTION_OK(cbs, action_ok_goto_favorites); + break; + case MENU_ENUM_LABEL_GOTO_MUSIC: + BIND_ACTION_OK(cbs, action_ok_goto_music); + break; + case MENU_ENUM_LABEL_GOTO_IMAGES: + BIND_ACTION_OK(cbs, action_ok_goto_images); + break; + case MENU_ENUM_LABEL_GOTO_VIDEO: + BIND_ACTION_OK(cbs, action_ok_goto_video); + break; case MENU_ENUM_LABEL_BROWSE_START: BIND_ACTION_OK(cbs, action_ok_browse_url_start); break; @@ -4524,12 +4232,18 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_RESUME_CONTENT: BIND_ACTION_OK(cbs, action_ok_resume_content); break; + case MENU_ENUM_LABEL_ADD_TO_FAVORITES: + BIND_ACTION_OK(cbs, action_ok_add_to_favorites); + break; case MENU_ENUM_LABEL_RESTART_CONTENT: BIND_ACTION_OK(cbs, action_ok_restart_content); break; case MENU_ENUM_LABEL_TAKE_SCREENSHOT: BIND_ACTION_OK(cbs, action_ok_screenshot); break; + case MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME: + BIND_ACTION_OK(cbs, action_ok_rename_entry); + break; case MENU_ENUM_LABEL_DELETE_ENTRY: BIND_ACTION_OK(cbs, action_ok_delete_entry); break; @@ -4659,6 +4373,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_CONTENT_SETTINGS: BIND_ACTION_OK(cbs, action_ok_push_default); break; + case MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL: + BIND_ACTION_OK(cbs, action_ok_push_filebrowser_list_file_select); + break; case MENU_ENUM_LABEL_SCAN_DIRECTORY: BIND_ACTION_OK(cbs, action_ok_scan_directory_list); break; @@ -4714,6 +4431,12 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME: BIND_ACTION_OK(cbs, action_ok_remap_file_save_game); break; + case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE: + BIND_ACTION_OK(cbs, action_ok_remap_file_remove_core); + break; + case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME: + BIND_ACTION_OK(cbs, action_ok_remap_file_remove_game); + break; case MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST: BIND_ACTION_OK(cbs, action_ok_content_collection_list); break; @@ -4831,6 +4554,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: BIND_ACTION_OK(cbs, action_ok_netplay_disconnect); break; + case MENU_ENUM_LABEL_CORE_DELETE: + BIND_ACTION_OK(cbs, action_ok_core_delete); + break; default: return -1; } @@ -4851,9 +4577,6 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_LABEL_LOAD_ARCHIVE: BIND_ACTION_OK(cbs, action_ok_load_archive); break; - case MENU_LABEL_CUSTOM_BIND_ALL: - BIND_ACTION_OK(cbs, action_ok_lookup_setting); - break; case MENU_LABEL_VIDEO_SHADER_PASS: BIND_ACTION_OK(cbs, action_ok_shader_pass); break; @@ -5024,19 +4747,23 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, BIND_ACTION_OK(cbs, action_ok_directory_push); break; case FILE_TYPE_CARCHIVE: - switch (menu_label_hash) + if (filebrowser_get_type() == FILEBROWSER_SCAN_FILE) { - case MENU_LABEL_FAVORITES: - BIND_ACTION_OK(cbs, action_ok_compressed_archive_push_detect_core); - break; - case MENU_LABEL_SCAN_FILE: #ifdef HAVE_LIBRETRODB - BIND_ACTION_OK(cbs, action_ok_scan_file); + BIND_ACTION_OK(cbs, action_ok_scan_file); #endif - break; - default: - BIND_ACTION_OK(cbs, action_ok_compressed_archive_push); - break; + } + else + { + switch (menu_label_hash) + { + case MENU_LABEL_FAVORITES: + BIND_ACTION_OK(cbs, action_ok_compressed_archive_push_detect_core); + break; + default: + BIND_ACTION_OK(cbs, action_ok_compressed_archive_push); + break; + } } break; case FILE_TYPE_CORE: @@ -5134,15 +4861,16 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, break; case FILE_TYPE_IN_CARCHIVE: case FILE_TYPE_PLAIN: - if (cbs->enum_idx != MSG_UNKNOWN) + if (filebrowser_get_type() == FILEBROWSER_SCAN_FILE) + { +#ifdef HAVE_LIBRETRODB + BIND_ACTION_OK(cbs, action_ok_scan_file); +#endif + } + else if (cbs->enum_idx != MSG_UNKNOWN) { switch (cbs->enum_idx) { -#ifdef HAVE_LIBRETRODB - case MENU_ENUM_LABEL_SCAN_FILE: - BIND_ACTION_OK(cbs, action_ok_scan_file); - break; -#endif case MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST: case MENU_ENUM_LABEL_FAVORITES: case MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN_DETECT_CORE: @@ -5153,13 +4881,15 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, } else #endif + if (filebrowser_get_type() == FILEBROWSER_APPEND_IMAGE) + { + BIND_ACTION_OK(cbs, action_ok_disk_image_append); + } + else { BIND_ACTION_OK(cbs, action_ok_file_load_with_detect_core); } break; - case MENU_ENUM_LABEL_DISK_IMAGE_APPEND: - BIND_ACTION_OK(cbs, action_ok_disk_image_append); - break; default: BIND_ACTION_OK(cbs, action_ok_file_load); break; @@ -5169,11 +4899,6 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, { switch (menu_label_hash) { -#ifdef HAVE_LIBRETRODB - case MENU_LABEL_SCAN_FILE: - BIND_ACTION_OK(cbs, action_ok_scan_file); - break; -#endif case MENU_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST: case MENU_LABEL_FAVORITES: case MENU_LABEL_DEFERRED_ARCHIVE_OPEN_DETECT_CORE: @@ -5184,13 +4909,15 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, } else #endif + if (filebrowser_get_type() == FILEBROWSER_APPEND_IMAGE) + { + BIND_ACTION_OK(cbs, action_ok_disk_image_append); + } + else { BIND_ACTION_OK(cbs, action_ok_file_load_with_detect_core); } break; - case MENU_LABEL_DISK_IMAGE_APPEND: - BIND_ACTION_OK(cbs, action_ok_disk_image_append); - break; default: BIND_ACTION_OK(cbs, action_ok_file_load); break; diff --git a/menu/cbs/menu_cbs_right.c b/menu/cbs/menu_cbs_right.c index 665d2d7aef..f982745235 100644 --- a/menu/cbs/menu_cbs_right.c +++ b/menu/cbs/menu_cbs_right.c @@ -193,8 +193,6 @@ static int action_right_mainmenu(unsigned type, const char *label, menu_driver_ctl(RARCH_MENU_CTL_LIST_GET_SIZE, &list_horiz_info); menu_driver_ctl(RARCH_MENU_CTL_LIST_GET_SIZE, &list_tabs_info); - menu_navigation_set_selection(0); - if ((list_info.selection != (list_horiz_info.size + list_tabs_info.size)) || settings->bools.menu_navigation_wraparound_enable) return action_right_goto_tab(); @@ -458,6 +456,7 @@ static int menu_cbs_init_bind_right_compare_type(menu_file_list_cbs_t *cbs, case MENU_SETTING_GROUP: case MENU_SETTINGS_CORE_INFO_NONE: if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) || @@ -488,7 +487,6 @@ static int menu_cbs_init_bind_right_compare_type(menu_file_list_cbs_t *cbs, static int menu_cbs_init_bind_right_compare_label(menu_file_list_cbs_t *cbs, const char *label, uint32_t label_hash, const char *menu_label) { - unsigned i; if (cbs->setting) { @@ -502,21 +500,25 @@ static int menu_cbs_init_bind_right_compare_label(menu_file_list_cbs_t *cbs, } } - for (i = 0; i < MAX_USERS; i++) + if (strstr(label, "input_player") && strstr(label, "_joypad_index")) { - uint32_t label_setting_hash; - char label_setting[128]; + unsigned i; + for (i = 0; i < MAX_USERS; i++) + { + uint32_t label_setting_hash; + char label_setting[128]; - label_setting[0] = '\0'; + label_setting[0] = '\0'; - snprintf(label_setting, sizeof(label_setting), "input_player%d_joypad_index", i + 1); - label_setting_hash = msg_hash_calculate(label_setting); + snprintf(label_setting, sizeof(label_setting), "input_player%d_joypad_index", i + 1); + label_setting_hash = msg_hash_calculate(label_setting); - if (label_hash != label_setting_hash) - continue; + if (label_hash != label_setting_hash) + continue; - BIND_ACTION_RIGHT(cbs, bind_right_generic); - return 0; + BIND_ACTION_RIGHT(cbs, bind_right_generic); + return 0; + } } if (string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB))) @@ -564,6 +566,7 @@ static int menu_cbs_init_bind_right_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_NO_PLAYLIST_ENTRIES_AVAILABLE: if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_MUSIC_TAB)) || @@ -582,6 +585,7 @@ static int menu_cbs_init_bind_right_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_START_VIDEO_PROCESSOR: case MENU_ENUM_LABEL_TAKE_SCREENSHOT: if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) || @@ -621,6 +625,7 @@ int menu_cbs_init_bind_right(menu_file_list_cbs_t *cbs, if (type == MENU_SETTING_NO_ITEM) { if ( string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)) || + string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)) || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) || diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 750cf41cd9..4054790c85 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -23,6 +23,9 @@ #endif #include "../../verbosity.h" +#include +#include + #ifndef BIND_ACTION_SUBLABEL #define BIND_ACTION_SUBLABEL(cbs, name) \ cbs->action_sublabel = name; \ @@ -81,6 +84,7 @@ default_sublabel_macro(action_bind_sublabel_fps_show, MENU_ default_sublabel_macro(action_bind_sublabel_netplay_settings, MENU_ENUM_SUBLABEL_NETPLAY) default_sublabel_macro(action_bind_sublabel_user_bind_settings, MENU_ENUM_SUBLABEL_INPUT_USER_BINDS) default_sublabel_macro(action_bind_sublabel_input_hotkey_settings, MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS) +default_sublabel_macro(action_bind_sublabel_materialui_icons_enable, MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE) default_sublabel_macro(action_bind_sublabel_add_content_list, MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST) default_sublabel_macro(action_bind_sublabel_video_frame_delay, MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY) default_sublabel_macro(action_bind_sublabel_video_black_frame_insertion, MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION) @@ -135,6 +139,7 @@ default_sublabel_macro(action_bind_sublabel_cheevos_password, MENU_ default_sublabel_macro(action_bind_sublabel_video_post_filter_record, MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD) default_sublabel_macro(action_bind_sublabel_core_list, MENU_ENUM_SUBLABEL_CORE_LIST) default_sublabel_macro(action_bind_sublabel_content_list, MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST) +default_sublabel_macro(action_bind_sublabel_content_special, MENU_ENUM_SUBLABEL_LOAD_CONTENT_SPECIAL) default_sublabel_macro(action_bind_sublabel_network_information, MENU_ENUM_SUBLABEL_NETWORK_INFORMATION) default_sublabel_macro(action_bind_sublabel_system_information, MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION) default_sublabel_macro(action_bind_sublabel_quit_retroarch, MENU_ENUM_SUBLABEL_QUIT_RETROARCH) @@ -221,12 +226,19 @@ default_sublabel_macro(action_bind_sublabel_sort_savefiles_enable, MENU_ default_sublabel_macro(action_bind_sublabel_sort_savestates_enable, MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE) default_sublabel_macro(action_bind_sublabel_netplay_client_swap_input, MENU_ENUM_SUBLABEL_NETPLAY_CLIENT_SWAP_INPUT) default_sublabel_macro(action_bind_sublabel_core_updater_buildbot_url, MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL) +default_sublabel_macro(action_bind_sublabel_input_overlay_show_physical_inputs, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS) +default_sublabel_macro(action_bind_sublabel_input_overlay_show_physical_inputs_port, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT) default_sublabel_macro(action_bind_sublabel_core_updater_buildbot_assets_url, MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL) default_sublabel_macro(action_bind_sublabel_core_updater_auto_extract_archive, MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE) default_sublabel_macro(action_bind_sublabel_netplay_refresh_rooms, MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS) default_sublabel_macro(action_bind_sublabel_delete_entry, MENU_ENUM_SUBLABEL_DELETE_ENTRY) default_sublabel_macro(action_bind_sublabel_information, MENU_ENUM_SUBLABEL_INFORMATION) default_sublabel_macro(action_bind_sublabel_run, MENU_ENUM_SUBLABEL_RUN) +default_sublabel_macro(action_bind_sublabel_add_to_favorites, MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES) +default_sublabel_macro(action_bind_sublabel_goto_favorites, MENU_ENUM_SUBLABEL_GOTO_FAVORITES) +default_sublabel_macro(action_bind_sublabel_goto_images, MENU_ENUM_SUBLABEL_GOTO_IMAGES) +default_sublabel_macro(action_bind_sublabel_goto_music, MENU_ENUM_SUBLABEL_GOTO_MUSIC) +default_sublabel_macro(action_bind_sublabel_goto_video, MENU_ENUM_SUBLABEL_GOTO_VIDEO) default_sublabel_macro(action_bind_sublabel_menu_filebrowser_settings, MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS) default_sublabel_macro(action_bind_sublabel_auto_remaps_enable, MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE) default_sublabel_macro(action_bind_sublabel_auto_overrides_enable, MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE) @@ -254,6 +266,7 @@ default_sublabel_macro(action_bind_sublabel_core_input_remapping_options, default_sublabel_macro(action_bind_sublabel_core_options, MENU_ENUM_SUBLABEL_CORE_OPTIONS) default_sublabel_macro(action_bind_sublabel_show_advanced_settings, MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS) default_sublabel_macro(action_bind_sublabel_threaded_data_runloop_enable, MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE) +default_sublabel_macro(action_bind_sublabel_playlist_entry_rename, MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME) default_sublabel_macro(action_bind_sublabel_playlist_entry_remove, MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE) default_sublabel_macro(action_bind_sublabel_system_directory, MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY) default_sublabel_macro(action_bind_sublabel_rgui_browser_directory, MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY) @@ -272,8 +285,10 @@ default_sublabel_macro(action_bind_sublabel_xmb_icon_theme, default_sublabel_macro(action_bind_sublabel_xmb_shadows_enable, MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE) default_sublabel_macro(action_bind_sublabel_menu_color_theme, MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME) default_sublabel_macro(action_bind_sublabel_menu_wallpaper_opacity, MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY) +default_sublabel_macro(action_bind_sublabel_menu_framebuffer_opacity, MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY) default_sublabel_macro(action_bind_sublabel_menu_ribbon_enable, MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE) default_sublabel_macro(action_bind_sublabel_menu_font, MENU_ENUM_SUBLABEL_XMB_FONT) +default_sublabel_macro(action_bind_sublabel_menu_favorites_tab, MENU_ENUM_SUBLABEL_XMB_SHOW_FAVORITES) default_sublabel_macro(action_bind_sublabel_menu_images_tab, MENU_ENUM_SUBLABEL_XMB_SHOW_IMAGES) default_sublabel_macro(action_bind_sublabel_menu_show_online_updater, MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER) default_sublabel_macro(action_bind_sublabel_menu_show_core_updater, MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER) @@ -329,6 +344,7 @@ default_sublabel_macro(action_bind_sublabel_video_viewport_custom_width, default_sublabel_macro(action_bind_sublabel_video_viewport_custom_x, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X) default_sublabel_macro(action_bind_sublabel_video_viewport_custom_y, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y) default_sublabel_macro(action_bind_sublabel_netplay_use_mitm_server, MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER) +default_sublabel_macro(action_bind_sublabel_core_delete, MENU_ENUM_SUBLABEL_CORE_DELETE) static int action_bind_sublabel_cheevos_entry( file_list_t *list, @@ -359,13 +375,10 @@ static int action_bind_sublabel_netplay_room( if (i < 1) return 0; - snprintf(s,len, "%s (%s)\n%s (%08x)\nType: %s (%s)", - netplay_room_list[i - 3].corename, netplay_room_list[i - 3].coreversion, - netplay_room_list[i - 3].gamename, netplay_room_list[i - 3].gamecrc, - netplay_room_list[i - 3].lan ? "LAN game" : - (netplay_room_list[i - 3].host_method == NETPLAY_HOST_METHOD_MITM ? - "MITM game" : "Lobby game"), netplay_room_list[i - 3].address); - + snprintf(s,len, "RetroArch: %s\nCore: %s (%s)\nGame: %s (%08x)", + string_is_empty(netplay_room_list[i - 3].retroarch_version) ? "n/a" : netplay_room_list[i - 3].retroarch_version, + netplay_room_list[i - 3].corename, netplay_room_list[i - 3].coreversion, + !string_is_equal(netplay_room_list[i - 3].gamename, "N/A") ? netplay_room_list[i - 3].gamename : "n/a", netplay_room_list[i - 3].gamecrc); #if 0 strlcpy(s, netplay_room_list[i - 3].corename, len); #endif @@ -394,6 +407,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, { switch (cbs->enum_idx) { + case MENU_ENUM_LABEL_MATERIALUI_ICONS_ENABLE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_materialui_icons_enable); + break; case MENU_ENUM_LABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_viewport_custom_height); break; @@ -538,6 +554,21 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_XMB_SHOW_SETTINGS: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_settings_tab); break; + case MENU_ENUM_LABEL_GOTO_IMAGES: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_goto_images); + break; + case MENU_ENUM_LABEL_GOTO_MUSIC: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_goto_music); + break; + case MENU_ENUM_LABEL_GOTO_VIDEO: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_goto_video); + break; + case MENU_ENUM_LABEL_GOTO_FAVORITES: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_goto_favorites); + break; + case MENU_ENUM_LABEL_XMB_SHOW_FAVORITES: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_favorites_tab); + break; case MENU_ENUM_LABEL_XMB_SHOW_IMAGES: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_images_tab); break; @@ -562,6 +593,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_XMB_RIBBON_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_ribbon_enable); break; + case MENU_ENUM_LABEL_MENU_FRAMEBUFFER_OPACITY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_framebuffer_opacity); + break; case MENU_ENUM_LABEL_MENU_WALLPAPER_OPACITY: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_wallpaper_opacity); break; @@ -606,178 +640,184 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_dynamic_wallpapers_directory); break; case MENU_ENUM_LABEL_CONTENT_DIR: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_dir); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_dir); break; case MENU_ENUM_LABEL_RGUI_BROWSER_DIRECTORY: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_rgui_browser_directory); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_rgui_browser_directory); break; case MENU_ENUM_LABEL_SYSTEM_DIRECTORY: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_system_directory); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_system_directory); + break; + case MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_entry_rename); break; case MENU_ENUM_LABEL_PLAYLIST_ENTRY_REMOVE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_entry_remove); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_entry_remove); break; case MENU_ENUM_LABEL_THREADED_DATA_RUNLOOP_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_threaded_data_runloop_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_threaded_data_runloop_enable); break; case MENU_ENUM_LABEL_SHOW_ADVANCED_SETTINGS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_show_advanced_settings); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_show_advanced_settings); break; case MENU_ENUM_LABEL_CORE_OPTIONS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_options); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_options); break; case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_input_remapping_options); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_input_remapping_options); break; case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_cheat_options); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_cheat_options); break; case MENU_ENUM_LABEL_SHADER_OPTIONS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_shader_options); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_shader_options); break; case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_save_current_config_override_game); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_save_current_config_override_game); break; case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_save_current_config_override_core); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_save_current_config_override_core); break; case MENU_ENUM_LABEL_RESTART_CONTENT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_restart_content); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_restart_content); break; case MENU_ENUM_LABEL_REWIND_SETTINGS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_rewind); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_rewind); break; case MENU_ENUM_LABEL_ACCOUNTS_LIST: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accounts_list); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accounts_list); break; case MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accounts_retro_achievements); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accounts_retro_achievements); break; case MENU_ENUM_LABEL_UNDO_SAVE_STATE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_undo_save_state); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_undo_save_state); break; case MENU_ENUM_LABEL_UNDO_LOAD_STATE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_undo_load_state); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_undo_load_state); break; case MENU_ENUM_LABEL_STATE_SLOT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_state_slot); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_state_slot); break; case MENU_ENUM_LABEL_RESUME: case MENU_ENUM_LABEL_RESUME_CONTENT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_resume_content); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_resume_content); break; case MENU_ENUM_LABEL_SAVE_STATE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_save_state); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_save_state); break; case MENU_ENUM_LABEL_LOAD_STATE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_load_state); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_load_state); break; case MENU_ENUM_LABEL_CLOSE_CONTENT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_close_content); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_close_content); break; case MENU_ENUM_LABEL_TAKE_SCREENSHOT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_take_screenshot); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_take_screenshot); break; case MENU_ENUM_LABEL_CURSOR_MANAGER: case MENU_ENUM_LABEL_CURSOR_MANAGER_LIST: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cursor_manager); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cursor_manager); break; case MENU_ENUM_LABEL_DATABASE_MANAGER: case MENU_ENUM_LABEL_DATABASE_MANAGER_LIST: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_database_manager); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_database_manager); break; case MENU_ENUM_LABEL_CORE_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_enable); break; case MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_game_specific_options); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_game_specific_options); break; case MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_auto_overrides_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_auto_overrides_enable); break; case MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_auto_remaps_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_auto_remaps_enable); break; case MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_filebrowser_settings); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_filebrowser_settings); + break; + case MENU_ENUM_LABEL_ADD_TO_FAVORITES: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_add_to_favorites); break; case MENU_ENUM_LABEL_RUN: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_run); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_run); break; case MENU_ENUM_LABEL_INFORMATION: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_information); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_information); break; case MENU_ENUM_LABEL_DELETE_ENTRY: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_delete_entry); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_delete_entry); break; case MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_refresh_rooms); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_refresh_rooms); break; case MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_auto_extract_archive); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_auto_extract_archive); break; case MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_buildbot_url); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_buildbot_url); break; case MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_buildbot_assets_url); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_buildbot_assets_url); break; case MENU_ENUM_LABEL_NETPLAY_CLIENT_SWAP_INPUT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_client_swap_input); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_client_swap_input); break; case MENU_ENUM_LABEL_SORT_SAVEFILES_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_sort_savefiles_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_sort_savefiles_enable); break; case MENU_ENUM_LABEL_SORT_SAVESTATES_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_sort_savestates_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_sort_savestates_enable); break; case MENU_ENUM_LABEL_VIDEO_SWAP_INTERVAL: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_swap_interval); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_swap_interval); break; case MENU_ENUM_LABEL_SCAN_FILE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_scan_file); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_scan_file); break; case MENU_ENUM_LABEL_SCAN_DIRECTORY: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_scan_directory); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_scan_directory); break; case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_disconnect); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_disconnect); break; case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_enable_client); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_enable_client); break; case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_enable_host); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_enable_host); break; case MENU_ENUM_LABEL_NAVIGATION_WRAPAROUND: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_navigation_wraparound); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_navigation_wraparound); break; case MENU_ENUM_LABEL_BATTERY_LEVEL_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_battery_level_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_battery_level_enable); break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_timedate_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_timedate_enable); break; case MENU_ENUM_LABEL_THUMBNAILS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_thumbnails); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_thumbnails); break; case MENU_ENUM_LABEL_MOUSE_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_mouse_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_mouse_enable); break; case MENU_ENUM_LABEL_POINTER_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_pointer_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_pointer_enable); break; case MENU_ENUM_LABEL_STDIN_CMD_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_stdin_cmd_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_stdin_cmd_enable); break; case MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_public_announce); break; case MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_nat_traversal); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_nat_traversal); break; case MENU_ENUM_LABEL_NETPLAY_CHECK_FRAMES: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_check_frames); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_check_frames); break; case MENU_ENUM_LABEL_NETPLAY_START_AS_SPECTATOR: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_start_as_spectator); @@ -789,40 +829,40 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_require_slaves); break; case MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_stateless_mode); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_stateless_mode); break; case MENU_ENUM_LABEL_NETPLAY_PASSWORD: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_password); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_password); break; case MENU_ENUM_LABEL_NETPLAY_SPECTATE_PASSWORD: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_spectate_password); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_spectate_password); break; case MENU_ENUM_LABEL_NETPLAY_TCP_UDP_PORT: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_tcp_udp_port); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_tcp_udp_port); break; case MENU_ENUM_LABEL_NETPLAY_IP_ADDRESS: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_ip_address); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_ip_address); break; case MENU_ENUM_LABEL_OVERLAY_PRESET: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_preset); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_preset); break; case MENU_ENUM_LABEL_INPUT_OVERLAY_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_enable); break; case MENU_ENUM_LABEL_OVERLAY_OPACITY: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_opacity); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_opacity); break; case MENU_ENUM_LABEL_OVERLAY_SCALE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_scale); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_overlay_scale); break; case MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_dsp_plugin); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_dsp_plugin); break; case MENU_ENUM_LABEL_AUDIO_OUTPUT_RATE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_output_rate); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_output_rate); break; case MENU_ENUM_LABEL_AUDIO_DEVICE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_device); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_device); break; case MENU_ENUM_LABEL_AUDIO_WASAPI_EXCLUSIVE_MODE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_wasapi_exclusive_mode); @@ -834,61 +874,61 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_wasapi_sh_buffer_length); break; case MENU_ENUM_LABEL_MENU_WALLPAPER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_wallpaper); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_wallpaper); break; case MENU_ENUM_LABEL_DYNAMIC_WALLPAPER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_dynamic_wallpaper); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_dynamic_wallpaper); break; case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_filter_supported_extensions); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_filter_supported_extensions); break; case MENU_ENUM_LABEL_WIFI_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_wifi_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_wifi_driver); break; case MENU_ENUM_LABEL_RECORD_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_record_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_record_driver); break; case MENU_ENUM_LABEL_MENU_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_driver); break; case MENU_ENUM_LABEL_LOCATION_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_location_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_location_driver); break; case MENU_ENUM_LABEL_CAMERA_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_camera_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_camera_driver); break; case MENU_ENUM_LABEL_AUDIO_RESAMPLER_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_resampler_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_resampler_driver); break; case MENU_ENUM_LABEL_JOYPAD_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_joypad_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_joypad_driver); break; case MENU_ENUM_LABEL_INPUT_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_driver); break; case MENU_ENUM_LABEL_AUDIO_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_driver); break; case MENU_ENUM_LABEL_VIDEO_DRIVER: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_driver); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_driver); break; case MENU_ENUM_LABEL_PAUSE_LIBRETRO: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_pause_libretro); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_pause_libretro); break; case MENU_ENUM_LABEL_MENU_INPUT_SWAP_OK_CANCEL: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_swap_ok_cancel); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_swap_ok_cancel); break; case MENU_ENUM_LABEL_INPUT_AUTODETECT_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_autodetect_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_autodetect_enable); break; case MENU_ENUM_LABEL_INPUT_REMAP_BINDS_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_remap_binds_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_remap_binds_enable); break; case MENU_ENUM_LABEL_AUTOSAVE_INTERVAL: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_autosave_interval); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_autosave_interval); break; case MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_savestate_thumbnail_enable); + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_savestate_thumbnail_enable); break; case MENU_ENUM_LABEL_SAVESTATE_AUTO_SAVE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_savestate_auto_save); @@ -947,6 +987,12 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_hide_in_menu); break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_show_physical_inputs); + break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_show_physical_inputs_port); + break; case MENU_ENUM_LABEL_VIDEO_FONT_SIZE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_font_size); break; @@ -980,6 +1026,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_list); break; + case MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_special); + break; case MENU_ENUM_LABEL_CORE_LIST: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_list); break; @@ -1286,6 +1335,8 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_NETPLAY_USE_MITM_SERVER: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_use_mitm_server); break; + case MENU_ENUM_LABEL_CORE_DELETE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_delete); default: case MSG_UNKNOWN: return -1; diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c index 438d6239a2..0930db8e2b 100644 --- a/menu/cbs/menu_cbs_title.c +++ b/menu/cbs/menu_cbs_title.c @@ -129,12 +129,17 @@ default_title_macro(action_get_audio_settings_list, MENU_ENUM_LABEL_ default_title_macro(action_get_input_settings_list, MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS) default_title_macro(action_get_core_cheat_options_list, MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS) default_title_macro(action_get_load_content_list, MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST) +default_title_macro(action_get_load_content_special, MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_SPECIAL) default_title_macro(action_get_cursor_manager_list, MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER) default_title_macro(action_get_database_manager_list, MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER) default_title_macro(action_get_system_information_list, MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION) default_title_macro(action_get_network_information_list, MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION) default_title_macro(action_get_settings_list, MENU_ENUM_LABEL_VALUE_SETTINGS) default_title_macro(action_get_title_information_list, MENU_ENUM_LABEL_VALUE_INFORMATION_LIST) +default_title_macro(action_get_title_goto_favorites, MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES) +default_title_macro(action_get_title_goto_image, MENU_ENUM_LABEL_VALUE_GOTO_IMAGES) +default_title_macro(action_get_title_goto_music, MENU_ENUM_LABEL_VALUE_GOTO_MUSIC) +default_title_macro(action_get_title_goto_video, MENU_ENUM_LABEL_VALUE_GOTO_VIDEO) default_fill_title_macro(action_get_title_disk_image_append, MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND) default_fill_title_macro(action_get_title_cheat_file_load, MENU_ENUM_LABEL_VALUE_CHEAT_FILE) @@ -246,6 +251,8 @@ static int action_get_title_group_settings(const char *path, const char *label, strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MAIN_MENU), len); else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB))) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HISTORY_TAB), len); + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB))) + strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB), len); else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_IMAGES_TAB))) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_IMAGES_TAB), len); else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MUSIC_TAB))) @@ -321,146 +328,162 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, BIND_ACTION_GET_TITLE(cbs, action_get_core_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_configuration_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_saving_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_logging_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_frame_throttle_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_REWIND_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_REWIND_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_rewind_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_DISPLAY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_DISPLAY_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_onscreen_display_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_onscreen_notifications_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_onscreen_overlay_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_VIEWS_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_VIEWS_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_menu_views_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_menu_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_INTERFACE_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_INTERFACE_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_user_interface_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_FILE_BROWSER_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_FILE_BROWSER_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_menu_file_browser_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RETRO_ACHIEVEMENTS_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RETRO_ACHIEVEMENTS_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_retro_achievements_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_WIFI_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_WIFI_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_wifi_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_UPDATER_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_UPDATER_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_updater_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_NETWORK_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_NETWORK_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_network_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_NETPLAY_LAN_SCAN_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_NETPLAY_LAN_SCAN_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_netplay_lan_scan_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LAKKA_SERVICES_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LAKKA_SERVICES_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_lakka_services_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_USER_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_user_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_directory_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_privacy_settings_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_download_core_content_list); return 0; } - - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_SUBDIR_LIST))) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_SUBDIR_LIST))) { BIND_ACTION_GET_TITLE(cbs, action_get_download_core_content_list); return 0; } - - if (cbs->enum_idx != MSG_UNKNOWN) + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_title_goto_favorites); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_title_goto_image); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_title_goto_music); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_title_goto_video); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DRIVER_SETTINGS_LIST))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_driver_settings_list); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_audio_settings_list); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SYSTEM_INFORMATION))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_system_information_list); + return 0; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETWORK_INFORMATION))) + { + BIND_ACTION_GET_TITLE(cbs, action_get_network_information_list); + return 0; + } + else if (cbs->enum_idx != MSG_UNKNOWN) { switch (cbs->enum_idx) { @@ -599,12 +622,6 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_DATABASE_MANAGER_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_database_manager_list); break; - case MENU_ENUM_LABEL_SYSTEM_INFORMATION: - BIND_ACTION_GET_TITLE(cbs, action_get_system_information_list); - break; - case MENU_ENUM_LABEL_NETWORK_INFORMATION: - BIND_ACTION_GET_TITLE(cbs, action_get_network_information_list); - break; case MENU_ENUM_LABEL_CURSOR_MANAGER_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_cursor_manager_list); break; @@ -614,6 +631,9 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_CORE_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_core_list); break; + case MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL: + BIND_ACTION_GET_TITLE(cbs, action_get_load_content_special); + break; case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_load_content_list); break; @@ -668,9 +688,6 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_DEFERRED_INPUT_HOTKEY_BINDS_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_input_hotkey_binds_settings_list); break; - case MENU_ENUM_LABEL_DEFERRED_DRIVER_SETTINGS_LIST: - BIND_ACTION_GET_TITLE(cbs, action_get_driver_settings_list); - break; case MENU_ENUM_LABEL_DEFERRED_VIDEO_SETTINGS_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_video_settings_list); break; @@ -698,9 +715,6 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_DEFERRED_CORE_SETTINGS_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_core_settings_list); break; - case MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST: - BIND_ACTION_GET_TITLE(cbs, action_get_audio_settings_list); - break; case MENU_ENUM_LABEL_DEFERRED_INPUT_SETTINGS_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_input_settings_list); break; @@ -909,12 +923,6 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_LABEL_DATABASE_MANAGER_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_database_manager_list); break; - case MENU_LABEL_SYSTEM_INFORMATION: - BIND_ACTION_GET_TITLE(cbs, action_get_system_information_list); - break; - case MENU_LABEL_NETWORK_INFORMATION: - BIND_ACTION_GET_TITLE(cbs, action_get_network_information_list); - break; case MENU_LABEL_CURSOR_MANAGER_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_cursor_manager_list); break; @@ -924,6 +932,9 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_LABEL_CORE_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_core_list); break; + case MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL: + BIND_ACTION_GET_TITLE(cbs, action_get_load_content_special); + break; case MENU_LABEL_LOAD_CONTENT_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_load_content_list); break; @@ -978,15 +989,9 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_LABEL_DEFERRED_INPUT_HOTKEY_BINDS_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_input_hotkey_binds_settings_list); break; - case MENU_LABEL_DEFERRED_DRIVER_SETTINGS_LIST: - BIND_ACTION_GET_TITLE(cbs, action_get_driver_settings_list); - break; case MENU_LABEL_DEFERRED_VIDEO_SETTINGS_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_video_settings_list); break; - case MENU_LABEL_DEFERRED_AUDIO_SETTINGS_LIST: - BIND_ACTION_GET_TITLE(cbs, action_get_audio_settings_list); - break; case MENU_LABEL_DEFERRED_INPUT_SETTINGS_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_input_settings_list); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index a0278dd770..6d20a71b29 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -57,12 +57,20 @@ #include "../../file_path_special.h" +/* This struct holds the y position and the line height for each menu entry */ typedef struct { float line_height; float y; + bool texture_switch_set; + uintptr_t texture_switch; + bool texture_switch2_set; + uintptr_t texture_switch2; + bool switch_is_on; + bool do_draw_text; } mui_node_t; +/* Textures used for the tabs and the switches */ enum { MUI_TEXTURE_POINTER = 0, @@ -74,9 +82,54 @@ enum MUI_TEXTURE_TAB_SETTINGS, MUI_TEXTURE_KEY, MUI_TEXTURE_KEY_HOVER, + MUI_TEXTURE_FOLDER, + MUI_TEXTURE_PARENT_DIRECTORY, + MUI_TEXTURE_IMAGE, + MUI_TEXTURE_ARCHIVE, + MUI_TEXTURE_VIDEO, + MUI_TEXTURE_MUSIC, + MUI_TEXTURE_QUIT, + MUI_TEXTURE_HELP, + MUI_TEXTURE_UPDATE, + MUI_TEXTURE_HISTORY, + MUI_TEXTURE_INFO, + MUI_TEXTURE_ADD, + MUI_TEXTURE_SETTINGS, + MUI_TEXTURE_FILE, + MUI_TEXTURE_PLAYLIST, + MUI_TEXTURE_UPDATER, + MUI_TEXTURE_QUICKMENU, + MUI_TEXTURE_NETPLAY, + MUI_TEXTURE_CORES, + MUI_TEXTURE_SHADERS, + MUI_TEXTURE_CONTROLS, + MUI_TEXTURE_CLOSE, + MUI_TEXTURE_CORE_OPTIONS, + MUI_TEXTURE_CORE_CHEAT_OPTIONS, + MUI_TEXTURE_RESUME, + MUI_TEXTURE_RESTART, + MUI_TEXTURE_ADD_TO_FAVORITES, + MUI_TEXTURE_RUN, + MUI_TEXTURE_RENAME, + MUI_TEXTURE_DATABASE, + MUI_TEXTURE_ADD_TO_MIXER, + MUI_TEXTURE_SCAN, + MUI_TEXTURE_REMOVE, + MUI_TEXTURE_START_CORE, + MUI_TEXTURE_LOAD_STATE, + MUI_TEXTURE_SAVE_STATE, + MUI_TEXTURE_UNDO_LOAD_STATE, + MUI_TEXTURE_UNDO_SAVE_STATE, + MUI_TEXTURE_STATE_SLOT, + MUI_TEXTURE_TAKE_SCREENSHOT, + MUI_TEXTURE_CONFIGURATIONS, + MUI_TEXTURE_LOAD_CONTENT, + MUI_TEXTURE_DISK, + MUI_TEXTURE_EJECT, MUI_TEXTURE_LAST }; +/* The menu has 3 tabs */ enum { MUI_SYSTEM_TAB_MAIN = 0, @@ -129,11 +182,17 @@ typedef struct mui_handle size_t selection_ptr; } categories; + /* One font for the menu entries, one font for the labels */ font_data_t *font; font_data_t *font2; video_font_raster_block_t raster_block; video_font_raster_block_t raster_block2; + + /* Y position of the vertical scroll */ float scroll_y; + + bool need_compute; + float content_height; } mui_handle_t; static void hex32_to_rgba_normalized(uint32_t hex, float* rgba, float alpha) @@ -166,6 +225,92 @@ static const char *mui_texture_path(unsigned id) return "key.png"; case MUI_TEXTURE_KEY_HOVER: return "key-hover.png"; + case MUI_TEXTURE_FOLDER: + return "folder.png"; + case MUI_TEXTURE_PARENT_DIRECTORY: + return "parent_directory.png"; + case MUI_TEXTURE_IMAGE: + return "image.png"; + case MUI_TEXTURE_VIDEO: + return "video.png"; + case MUI_TEXTURE_MUSIC: + return "music.png"; + case MUI_TEXTURE_ARCHIVE: + return "archive.png"; + case MUI_TEXTURE_QUIT: + return "quit.png"; + case MUI_TEXTURE_HELP: + return "help.png"; + case MUI_TEXTURE_NETPLAY: + return "netplay.png"; + case MUI_TEXTURE_CORES: + return "cores.png"; + case MUI_TEXTURE_CONTROLS: + return "controls.png"; + case MUI_TEXTURE_RESUME: + return "resume.png"; + case MUI_TEXTURE_RESTART: + return "restart.png"; + case MUI_TEXTURE_CLOSE: + return "close.png"; + case MUI_TEXTURE_CORE_OPTIONS: + return "core_options.png"; + case MUI_TEXTURE_CORE_CHEAT_OPTIONS: + return "core_cheat_options.png"; + case MUI_TEXTURE_SHADERS: + return "shaders.png"; + case MUI_TEXTURE_ADD_TO_FAVORITES: + return "add_to_favorites.png"; + case MUI_TEXTURE_RUN: + return "run.png"; + case MUI_TEXTURE_RENAME: + return "rename.png"; + case MUI_TEXTURE_DATABASE: + return "database.png"; + case MUI_TEXTURE_ADD_TO_MIXER: + return "add_to_mixer.png"; + case MUI_TEXTURE_SCAN: + return "scan.png"; + case MUI_TEXTURE_REMOVE: + return "remove.png"; + case MUI_TEXTURE_START_CORE: + return "start_core.png"; + case MUI_TEXTURE_LOAD_STATE: + return "load_state.png"; + case MUI_TEXTURE_SAVE_STATE: + return "save_state.png"; + case MUI_TEXTURE_DISK: + return "disk.png"; + case MUI_TEXTURE_EJECT: + return "eject.png"; + case MUI_TEXTURE_UNDO_LOAD_STATE: + return "undo_load_state.png"; + case MUI_TEXTURE_UNDO_SAVE_STATE: + return "undo_save_state.png"; + case MUI_TEXTURE_STATE_SLOT: + return "state_slot.png"; + case MUI_TEXTURE_TAKE_SCREENSHOT: + return "take_screenshot.png"; + case MUI_TEXTURE_CONFIGURATIONS: + return "configurations.png"; + case MUI_TEXTURE_LOAD_CONTENT: + return "load_content.png"; + case MUI_TEXTURE_UPDATER: + return "update.png"; + case MUI_TEXTURE_QUICKMENU: + return "quickmenu.png"; + case MUI_TEXTURE_HISTORY: + return "history.png"; + case MUI_TEXTURE_INFO: + return "information.png"; + case MUI_TEXTURE_ADD: + return "add.png"; + case MUI_TEXTURE_SETTINGS: + return "settings.png"; + case MUI_TEXTURE_FILE: + return "file.png"; + case MUI_TEXTURE_PLAYLIST: + return "playlist.png"; } return NULL; @@ -229,6 +374,7 @@ static void mui_draw_icon( menu_display_blend_end(); } +/* Draw a single tab */ static void mui_draw_tab(mui_handle_t *mui, unsigned i, unsigned width, unsigned height, @@ -268,6 +414,7 @@ static void mui_draw_tab(mui_handle_t *mui, &tab_color[0]); } +/* Draw the onscreen keyboard */ static void mui_render_keyboard(mui_handle_t *mui, video_frame_info_t *video_info, const char *grid[], unsigned id) @@ -357,6 +504,7 @@ static int mui_osk_ptr_at_pos(void *data, int x, int y, return -1; } +/* Draw the tabs background */ static void mui_draw_tab_begin(mui_handle_t *mui, unsigned width, unsigned height, float *tabs_bg_color, float *tabs_separator_color) @@ -378,6 +526,7 @@ static void mui_draw_tab_begin(mui_handle_t *mui, tabs_separator_color); } +/* Draw the active tab */ static void mui_draw_tab_end(mui_handle_t *mui, unsigned width, unsigned height, unsigned header_height, @@ -395,36 +544,21 @@ static void mui_draw_tab_end(mui_handle_t *mui, &active_tab_marker_color[0]); } -static float mui_content_height(void) -{ - unsigned i; - file_list_t *list = menu_entries_get_selection_buf_ptr(0); - float sum = 0; - - for (i = 0; i < menu_entries_get_end(); i++) - { - mui_node_t *node = (mui_node_t*) - menu_entries_get_userdata_at_offset(list, i); - sum += node->line_height; - } - return sum; -} - +/* Draw the scrollbar */ static void mui_draw_scrollbar(mui_handle_t *mui, unsigned width, unsigned height, float *coord_color) { unsigned header_height = menu_display_get_header_height(); - float content_height = mui_content_height(); float total_height = height - header_height - mui->tabs_height; float scrollbar_margin = mui->scrollbar_width; - float scrollbar_height = total_height / (content_height / total_height); - float y = total_height * mui->scroll_y / content_height; + float scrollbar_height = total_height / (mui->content_height / total_height); + float y = total_height * mui->scroll_y / mui->content_height; /* apply a margin on the top and bottom of the scrollbar for aestetic */ scrollbar_height -= scrollbar_margin * 2; y += scrollbar_margin; - if (content_height < total_height) + if (mui->content_height < total_height) return; /* if the scrollbar is extremely short, display it as a square */ @@ -450,6 +584,7 @@ static void mui_get_message(void *data, const char *message) strlcpy(mui->box_message, message, sizeof(mui->box_message)); } +/* Draw the modal */ static void mui_render_messagebox(mui_handle_t *mui, video_frame_info_t *video_info, const char *message, float *body_bg_color, uint32_t font_color) @@ -518,6 +653,7 @@ end: string_list_free(list); } +/* Used for the sublabels */ static unsigned mui_count_lines(const char *str) { unsigned c = 0; @@ -528,36 +664,48 @@ static unsigned mui_count_lines(const char *str) return lines; } +/* Compute the line height for each menu entries. */ static void mui_compute_entries_box(mui_handle_t* mui, int width) { + unsigned i; size_t usable_width = width - (mui->margin * 2); file_list_t *list = menu_entries_get_selection_buf_ptr(0); float sum = 0; - unsigned i = 0; + size_t entries_end = menu_entries_get_end(); + float scale_factor = menu_display_get_dpi(); + uintptr_t texture_switch2 = 0; - for (; i < menu_entries_get_end(); i++) + for (i = 0; i < entries_end; i++) { char sublabel_str[255]; - float scale_factor; unsigned lines = 0; mui_node_t *node = (mui_node_t*) menu_entries_get_userdata_at_offset(list, i); sublabel_str[0] = '\0'; + /* set texture_switch2 */ + if (node->texture_switch2_set) + texture_switch2 = node->texture_switch2; + if (menu_entry_get_sublabel(i, sublabel_str, sizeof(sublabel_str))) { - word_wrap(sublabel_str, sublabel_str, (int)(usable_width / mui->glyph_width2)); + int icon_margin = texture_switch2 ? mui->icon_size : 0; + + word_wrap(sublabel_str, sublabel_str, (int)((usable_width - icon_margin) / mui->glyph_width2), false); lines = mui_count_lines(sublabel_str); } - scale_factor = menu_display_get_dpi(); node->line_height = (scale_factor / 3) + (lines * mui->font->size); node->y = sum; sum += node->line_height; } + + mui->content_height = sum; } +/* Called on each frame. We use this callback to implement the touch scroll +with acceleration */ static void mui_render(void *data, bool is_idle) { menu_animation_ctx_delta_t delta; @@ -573,7 +721,11 @@ static void mui_render(void *data, bool is_idle) video_driver_get_size(&width, &height); - mui_compute_entries_box(mui, width); + if (mui->need_compute) + { + mui_compute_entries_box(mui, width); + mui->need_compute = false; + } menu_animation_ctl(MENU_ANIMATION_CTL_DELTA_TIME, &delta_time); @@ -588,12 +740,13 @@ static void mui_render(void *data, bool is_idle) if (settings->bools.menu_pointer_enable) { + size_t ii; int16_t pointer_y = menu_input_pointer_state(MENU_POINTER_Y_AXIS); float old_accel_val = 0.0f; float new_accel_val = 0.0f; + size_t entries_end = menu_entries_get_size(); - size_t ii = 0; - for (ii = 0; ii < menu_entries_get_size(); ii++) + for (ii = 0; ii < entries_end; ii++) { mui_node_t *node = (mui_node_t*) menu_entries_get_userdata_at_offset(list, ii); @@ -615,10 +768,11 @@ static void mui_render(void *data, bool is_idle) if (settings->bools.menu_mouse_enable) { + size_t ii; int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS); + size_t entries_end = menu_entries_get_size(); - size_t ii = 0; - for (ii = 0; ii < menu_entries_get_size(); ii++) + for (ii = 0; ii < entries_end; ii++) { mui_node_t *node = (mui_node_t*) menu_entries_get_userdata_at_offset(list, ii); @@ -633,25 +787,23 @@ static void mui_render(void *data, bool is_idle) if (mui->scroll_y < 0) mui->scroll_y = 0; - bottom = mui_content_height() - height + header_height + mui->tabs_height; + bottom = mui->content_height - height + header_height + mui->tabs_height; if (mui->scroll_y > bottom) mui->scroll_y = bottom; - if (mui_content_height() + if (mui->content_height < height - header_height - mui->tabs_height) mui->scroll_y = 0; - /*if (menu_entries_get_end() < height / mui->line_height) { } - else - i = mui->scroll_y / mui->line_height;*/ - menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &i); } +/* Display an entry value on the right of the screen. */ static void mui_render_label_value(mui_handle_t *mui, mui_node_t *node, int i, int y, unsigned width, unsigned height, uint64_t index, uint32_t color, bool selected, const char *label, - const char *value, float *label_color) + const char *value, float *label_color, + uint32_t sublabel_color) { /* This will be used instead of label_color if texture_switch is 'off' icon */ float pure_white[16]= { @@ -669,9 +821,11 @@ static void mui_render_label_value(mui_handle_t *mui, mui_node_t *node, int value_len = (int)utf8len(value); int ticker_limit = 0; uintptr_t texture_switch = 0; + uintptr_t texture_switch2 = 0; bool do_draw_text = false; size_t usable_width = width - (mui->margin * 2); - uint32_t sublabel_color = 0x888888ff; + enum msg_file_type hash_type = msg_hash_to_file_type(msg_hash_calculate(value)); + float scale_factor = menu_display_get_dpi(); label_str[0] = value_str[0] = sublabel_str[0] = '\0'; @@ -695,28 +849,15 @@ static void mui_render_label_value(mui_handle_t *mui, mui_node_t *node, menu_animation_ticker(&ticker); - if (menu_entry_get_sublabel(i, sublabel_str, sizeof(sublabel_str))) - { - word_wrap(sublabel_str, sublabel_str, (int)(usable_width / mui->glyph_width2)); - - menu_display_draw_text(mui->font2, sublabel_str, - mui->margin, - y + (menu_display_get_dpi() / 4) + mui->font->size, - width, height, sublabel_color, TEXT_ALIGN_LEFT, 1.0f, false, 0); - } - - menu_display_draw_text(mui->font, label_str, - mui->margin, - y + (menu_display_get_dpi() / 5), - width, height, color, TEXT_ALIGN_LEFT, 1.0f, false, 0); - + /* set switch_is_on */ + /* set texture_switch */ if (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) || (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))) { if (mui->textures.list[MUI_TEXTURE_SWITCH_OFF]) { - texture_switch = mui->textures.list[MUI_TEXTURE_SWITCH_OFF]; switch_is_on = false; + texture_switch = mui->textures.list[MUI_TEXTURE_SWITCH_OFF]; } else do_draw_text = true; @@ -726,18 +867,18 @@ static void mui_render_label_value(mui_handle_t *mui, mui_node_t *node, { if (mui->textures.list[MUI_TEXTURE_SWITCH_ON]) { - texture_switch = mui->textures.list[MUI_TEXTURE_SWITCH_ON]; switch_is_on = true; + texture_switch = mui->textures.list[MUI_TEXTURE_SWITCH_ON]; } else do_draw_text = true; } + /* set do_draw_text */ else { - enum msg_file_type type = msg_hash_to_file_type(msg_hash_calculate(value)); - - switch (type) + switch (hash_type) { + case FILE_TYPE_IN_CARCHIVE: case FILE_TYPE_COMPRESSED: case FILE_TYPE_MORE: case FILE_TYPE_CORE: @@ -756,18 +897,67 @@ static void mui_render_label_value(mui_handle_t *mui, mui_node_t *node, } } + /* set texture_switch2 */ + if (node->texture_switch2_set) + texture_switch2 = node->texture_switch2; + else + { + switch (hash_type) + { + case FILE_TYPE_COMPRESSED: + texture_switch2 = mui->textures.list[MUI_TEXTURE_ARCHIVE]; + break; + case FILE_TYPE_IMAGE: + texture_switch2 = mui->textures.list[MUI_TEXTURE_IMAGE]; + break; + default: + break; + } + } + + /* Sublabel */ + if (menu_entry_get_sublabel(i, sublabel_str, sizeof(sublabel_str))) + { + int icon_margin = texture_switch2 ? mui->icon_size : 0; + + word_wrap(sublabel_str, sublabel_str, (int)((usable_width - icon_margin) / mui->glyph_width2), false); + + menu_display_draw_text(mui->font2, sublabel_str, + mui->margin + (texture_switch2 ? mui->icon_size : 0), + y + (scale_factor / 4) + mui->font->size, + width, height, sublabel_color, TEXT_ALIGN_LEFT, 1.0f, false, 0); + } + + menu_display_draw_text(mui->font, label_str, + mui->margin + (texture_switch2 ? mui->icon_size : 0), + y + (scale_factor / 5), + width, height, color, TEXT_ALIGN_LEFT, 1.0f, false, 0); + if (do_draw_text) menu_display_draw_text(mui->font, value_str, width - mui->margin, - y + (menu_display_get_dpi() / 5), + y + (scale_factor / 5), width, height, color, TEXT_ALIGN_RIGHT, 1.0f, false, 0); + if (texture_switch2) + mui_draw_icon( + mui->icon_size, + (uintptr_t)texture_switch2, + 0, + y + (scale_factor / 6) - mui->icon_size/2, + width, + height, + 0, + 1, + &label_color[0] + ); + if (texture_switch) mui_draw_icon( mui->icon_size, - texture_switch, + (uintptr_t)texture_switch, width - mui->margin - mui->icon_size, - y + (menu_display_get_dpi() / 6) - mui->icon_size/2, + y + (scale_factor / 6) - mui->icon_size/2, width, height, 0, @@ -782,10 +972,12 @@ static void mui_render_menu_list( unsigned width, unsigned height, uint32_t font_normal_color, uint32_t font_hover_color, - float *menu_list_color) + float *menu_list_color, + uint32_t sublabel_color) { + size_t i; float sum = 0; - size_t i = 0; + size_t entries_end = 0; file_list_t *list = NULL; uint64_t frame_count = mui->frame_count; unsigned header_height = @@ -798,8 +990,10 @@ static void mui_render_menu_list( list = menu_entries_get_selection_buf_ptr(0); + + entries_end = menu_entries_get_end(); - for (; i < menu_entries_get_end(); i++) + for (i = 0; i < entries_end; i++) { char rich_label[255]; char entry_value[255]; @@ -811,11 +1005,21 @@ static void mui_render_menu_list( rich_label[0] = entry_value[0] = '\0'; + sum += node->line_height; + + if (y + (int)node->line_height < 0) + continue; + + if (y > (int)height) + break; + menu_entry_get_value((unsigned)i, NULL, entry_value, sizeof(entry_value)); menu_entry_get_rich_label((unsigned)i, rich_label, sizeof(rich_label)); entry_selected = selection == i; + /* Render label, value, and associated icons */ + mui_render_label_value( mui, node, @@ -828,10 +1032,9 @@ static void mui_render_menu_list( entry_selected, rich_label, entry_value, - menu_list_color + menu_list_color, + sublabel_color ); - - sum += node->line_height; } } @@ -886,6 +1089,9 @@ static int mui_get_core_title(char *s, size_t len) static void mui_draw_bg(menu_display_ctx_draw_t *draw, video_frame_info_t *video_info) { + bool add_opacity = false; + float opacity_override = video_info->menu_wallpaper_opacity; + menu_display_blend_begin(); draw->x = 0; @@ -893,94 +1099,105 @@ static void mui_draw_bg(menu_display_ctx_draw_t *draw, draw->pipeline.id = 0; draw->pipeline.active = false; - menu_display_draw_bg(draw, video_info, false); + if (video_info->libretro_running) + { + add_opacity = true; + opacity_override = video_info->menu_framebuffer_opacity; + } + + menu_display_draw_bg(draw, video_info, add_opacity, + opacity_override); menu_display_draw(draw); menu_display_blend_end(); } +/* Main function of the menu driver. Takes care of drawing the header, the tabs, +and the menu list */ static void mui_frame(void *data, video_frame_info_t *video_info) { - float black_bg[16] = { - 0, 0, 0, 0.75, - 0, 0, 0, 0.75, - 0, 0, 0, 0.75, - 0, 0, 0, 0.75, - }; - float pure_white[16]= { - 1.00, 1.00, 1.00, 1.00, - 1.00, 1.00, 1.00, 1.00, - 1.00, 1.00, 1.00, 1.00, - 1.00, 1.00, 1.00, 1.00, - }; - float white_bg[16]= { - 0.98, 0.98, 0.98, 1.00, - 0.98, 0.98, 0.98, 1.00, - 0.98, 0.98, 0.98, 1.00, - 0.98, 0.98, 0.98, 1.00, - }; - float white_transp_bg[16]= { - 0.98, 0.98, 0.98, 0.90, - 0.98, 0.98, 0.98, 0.90, - 0.98, 0.98, 0.98, 0.90, - 0.98, 0.98, 0.98, 0.90, - }; - float grey_bg[16]= { - 0.78, 0.78, 0.78, 0.90, - 0.78, 0.78, 0.78, 0.90, - 0.78, 0.78, 0.78, 0.90, - 0.78, 0.78, 0.78, 0.90, - }; - float shadow_bg[16]= { - 0.00, 0.00, 0.00, 0.00, - 0.00, 0.00, 0.00, 0.00, - 0.00, 0.00, 0.00, 0.2, - 0.00, 0.00, 0.00, 0.2, - }; - /* TODO/FIXME - convert this over to new hex format */ - float greyish_blue[16] = { - 0.22, 0.28, 0.31, 1.00, - 0.22, 0.28, 0.31, 1.00, - 0.22, 0.28, 0.31, 1.00, - 0.22, 0.28, 0.31, 1.00, - }; - float almost_black[16] = { - 0.13, 0.13, 0.13, 0.90, - 0.13, 0.13, 0.13, 0.90, - 0.13, 0.13, 0.13, 0.90, - 0.13, 0.13, 0.13, 0.90, - }; - - /* This controls the main background color */ menu_display_ctx_clearcolor_t clearcolor; + menu_animation_ctx_ticker_t ticker; menu_display_ctx_draw_t draw; char msg[255]; char title[255]; char title_buf[255]; char title_msg[255]; + float black_bg[16] = { + 0, 0, 0, 0.75, + 0, 0, 0, 0.75, + 0, 0, 0, 0.75, + 0, 0, 0, 0.75, + }; - uint32_t black_opaque_54 = 0x0000008a; - uint32_t black_opaque_87 = 0x000000de; - uint32_t white_opaque_70 = 0xffffffb3; + float pure_white[16]= { + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + }; + float white_bg[16]= { + 0.98, 0.98, 0.98, 1.00, + 0.98, 0.98, 0.98, 1.00, + 0.98, 0.98, 0.98, 1.00, + 0.98, 0.98, 0.98, 1.00, + }; + float white_transp_bg[16]= { + 0.98, 0.98, 0.98, 0.90, + 0.98, 0.98, 0.98, 0.90, + 0.98, 0.98, 0.98, 0.90, + 0.98, 0.98, 0.98, 0.90, + }; + float grey_bg[16]= { + 0.78, 0.78, 0.78, 0.90, + 0.78, 0.78, 0.78, 0.90, + 0.78, 0.78, 0.78, 0.90, + 0.78, 0.78, 0.78, 0.90, + }; + /* TODO/FIXME convert this over to new hex format */ + float greyish_blue[16] = { + 0.22, 0.28, 0.31, 1.00, + 0.22, 0.28, 0.31, 1.00, + 0.22, 0.28, 0.31, 1.00, + 0.22, 0.28, 0.31, 1.00, + }; + float almost_black[16] = { + 0.13, 0.13, 0.13, 0.90, + 0.13, 0.13, 0.13, 0.90, + 0.13, 0.13, 0.13, 0.90, + 0.13, 0.13, 0.13, 0.90, + }; - /* https://material.google.com/style/color.html#color-color-palette */ - /* Hex values converted to RGB normalized decimals, alpha set to 1 */ - float blue_500[16] = {0}; - float blue_50[16] = {0}; - float green_500[16] = {0}; - float green_50[16] = {0}; - float red_500[16] = {0}; - float red_50[16] = {0}; - float yellow_500[16] = {0}; - float blue_grey_500[16] = {0}; - float blue_grey_50[16] = {0}; - float yellow_200[16] = {0}; - float color_nv_header[16] = {0}; - float color_nv_body[16] = {0}; - float color_nv_accent[16] = {0}; - float footer_bg_color_real[16] = {0}; + float shadow_bg[16]= { + 0.00, 0.00, 0.00, 0.00, + 0.00, 0.00, 0.00, 0.00, + 0.00, 0.00, 0.00, 0.20, + 0.00, 0.00, 0.00, 0.20, + }; + + uint32_t black_opaque_54 = 0x0000008a; + uint32_t black_opaque_87 = 0x000000de; + uint32_t white_opaque_70 = 0xffffffb3; + + /* https://material.google.com/style/color.html#color-color-palette */ + /* Hex values converted to RGB normalized decimals, alpha set to 1 */ + float blue_500[16] = {0}; + float blue_50[16] = {0}; + float green_500[16] = {0}; + float green_50[16] = {0}; + float red_500[16] = {0}; + float red_50[16] = {0}; + float yellow_500[16] = {0}; + float blue_grey_500[16] = {0}; + float blue_grey_50[16] = {0}; + float yellow_200[16] = {0}; + float color_nv_header[16] = {0}; + float color_nv_body[16] = {0}; + float color_nv_accent[16] = {0}; + float footer_bg_color_real[16] = {0}; float header_bg_color_real[16] = {0}; + file_list_t *list = NULL; mui_node_t *node = NULL; unsigned width = video_info->width; @@ -995,15 +1212,16 @@ static void mui_frame(void *data, video_frame_info_t *video_info) bool libretro_running = video_info->libretro_running; /* Default is blue theme */ - float *header_bg_color = NULL; - float *highlighted_entry_color = NULL; - float *footer_bg_color = NULL; - float *body_bg_color = NULL; - float *active_tab_marker_color = NULL; + float *header_bg_color = NULL; + float *highlighted_entry_color = NULL; + float *footer_bg_color = NULL; + float *body_bg_color = NULL; + float *active_tab_marker_color = NULL; float *passive_tab_icon_color = grey_bg; + uint32_t sublabel_color = 0x888888ff; uint32_t font_normal_color = 0; - uint32_t font_hover_color = 0; + uint32_t font_hover_color = 0; uint32_t font_header_color = 0; if (!mui) @@ -1058,7 +1276,7 @@ static void mui_frame(void *data, video_frame_info_t *video_info) clearcolor.a = 0.75f; break; case MATERIALUI_THEME_GREEN: - hex32_to_rgba_normalized(0x4CAF50, green_500, 1.00); + hex32_to_rgba_normalized(0x4CAF50, green_500, 1.00); hex32_to_rgba_normalized(0x4CAF50, header_bg_color_real, 1.00); hex32_to_rgba_normalized(0xC8E6C9, green_50, 0.90); hex32_to_rgba_normalized(0xFFFFFF, footer_bg_color_real, 1.00); @@ -1145,11 +1363,12 @@ static void mui_frame(void *data, video_frame_info_t *video_info) hex32_to_rgba_normalized(0x77B900, color_nv_accent,0.90); hex32_to_rgba_normalized(0x202427, footer_bg_color_real, 1.00); + sublabel_color = 0xffffffff; header_bg_color = header_bg_color_real; body_bg_color = color_nv_body; highlighted_entry_color = color_nv_accent; footer_bg_color = footer_bg_color_real; - active_tab_marker_color = color_nv_accent; + active_tab_marker_color = white_bg; font_normal_color = 0xbbc0c4ff; font_hover_color = 0xffffffff; @@ -1262,7 +1481,8 @@ static void mui_frame(void *data, video_frame_info_t *video_info) height, font_normal_color, font_hover_color, - &active_tab_marker_color[0] + &active_tab_marker_color[0], + sublabel_color ); font_driver_flush(video_info->width, video_info->height, mui->font); @@ -1370,25 +1590,21 @@ static void mui_frame(void *data, video_frame_info_t *video_info) { const char *str = menu_input_dialog_get_buffer(); const char *label = menu_input_dialog_get_label_buffer(); - float *body_bg_color_ptr = &body_bg_color[0]; menu_display_draw_quad(0, 0, width, height, width, height, &black_bg[0]); snprintf(msg, sizeof(msg), "%s\n%s", label, str); - - if (body_bg_color_ptr) - mui_render_messagebox(mui, video_info, - msg, body_bg_color_ptr, font_hover_color); + + mui_render_messagebox(mui, video_info, + msg, &body_bg_color[0], font_hover_color); } if (!string_is_empty(mui->box_message)) { - float *body_bg_color_ptr = &body_bg_color[0]; - menu_display_draw_quad(0, 0, width, height, width, height, &black_bg[0]); - if (body_bg_color_ptr) - mui_render_messagebox(mui, video_info, - mui->box_message, body_bg_color_ptr, font_hover_color); + mui_render_messagebox(mui, video_info, + mui->box_message, &body_bg_color[0], font_hover_color); + mui->box_message[0] = '\0'; } @@ -1406,6 +1622,7 @@ static void mui_frame(void *data, video_frame_info_t *video_info) menu_display_unset_viewport(video_info->width, video_info->height); } +/* Compute the positions of the widgets */ static void mui_layout(mui_handle_t *mui, bool video_is_threaded) { float scale_factor; @@ -1420,7 +1637,7 @@ static void mui_layout(mui_handle_t *mui, bool video_is_threaded) * * On desktops, we just care about readability, with every widget * size proportional to the display width. */ - scale_factor = menu_display_get_dpi(); + scale_factor = menu_display_get_dpi(); new_header_height = scale_factor / 3; new_font_size = scale_factor / 9; @@ -1488,6 +1705,7 @@ static void *mui_init(void **userdata, bool video_is_threaded) *userdata = mui; mui->cursor.size = 64.0; + mui->need_compute = false; return menu; error: @@ -1534,6 +1752,7 @@ static void mui_context_destroy(void *data) mui_context_bg_destroy(mui); } +/* Upload textures to the gpu */ static bool mui_load_image(void *userdata, void *data, enum menu_image_type type) { mui_handle_t *mui = (mui_handle_t*)userdata; @@ -1556,6 +1775,7 @@ static bool mui_load_image(void *userdata, void *data, enum menu_image_type type return true; } +/* Compute the scroll value depending on the highlighted entry */ static float mui_get_scroll(mui_handle_t *mui) { unsigned width, height, half = 0; @@ -1575,6 +1795,8 @@ static float mui_get_scroll(mui_handle_t *mui) return ((selection + 2 - half) * mui->line_height); } +/* The navigation pointer has been updated (for example by pressing up or down +on the keyboard). We use this function to animate the scroll. */ static void mui_navigation_set(void *data, bool scroll) { menu_animation_ctx_entry_t entry; @@ -1595,11 +1817,12 @@ static void mui_navigation_set(void *data, bool scroll) menu_animation_push(&entry); } -static void mui_list_set_selection(void *data, file_list_t *list) +static void mui_list_set_selection(void *data, file_list_t *list) { mui_navigation_set(data, true); } +/* The navigation pointer is set back to zero */ static void mui_navigation_clear(void *data, bool pending_push) { size_t i = 0; @@ -1621,6 +1844,7 @@ static void mui_navigation_alphabet(void *data, size_t *unused) mui_navigation_set(data, true); } +/* A new list had been pushed. We update the scroll value */ static void mui_populate_entries( void *data, const char *path, const char *label, unsigned i) @@ -1629,9 +1853,11 @@ static void mui_populate_entries( if (!mui) return; + mui->need_compute = true; mui->scroll_y = mui_get_scroll(mui); } +/* Context reset is called on launch or when a core is launched */ static void mui_context_reset(void *data, bool is_threaded) { mui_handle_t *mui = (mui_handle_t*)data; @@ -1674,6 +1900,7 @@ static int mui_environ(enum menu_environ_cb type, void *data, void *userdata) return -1; } +/* Called before we push the new list after clicking on a tab */ static void mui_preswitch_tabs(mui_handle_t *mui, unsigned action) { size_t stack_size = 0; @@ -1712,6 +1939,8 @@ static void mui_preswitch_tabs(mui_handle_t *mui, unsigned action) } } +/* This callback is not caching anything. We use it to navigate the tabs +with the keyboard */ static void mui_list_cache(void *data, enum menu_list_type type, unsigned action) { @@ -1721,6 +1950,7 @@ static void mui_list_cache(void *data, if (!mui) return; + mui->need_compute = true; list_size = MUI_SYSTEM_TAB_END; switch (type) @@ -1759,6 +1989,8 @@ static void mui_list_cache(void *data, } } +/* A new list has been pushed. We use this callback to customize a few lists for +this menu driver */ static int mui_list_push(void *data, void *userdata, menu_displaylist_info_t *info, unsigned type) { @@ -1772,39 +2004,41 @@ static int mui_list_push(void *data, void *userdata, switch (type) { case DISPLAYLIST_LOAD_CONTENT_LIST: - menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); - - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), - msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), - MENU_ENUM_LABEL_FAVORITES, - MENU_SETTING_ACTION, 0, 0); - - core_info_get_list(&list); - if (core_info_list_num_info_files(list)) { + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), - MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), + MENU_ENUM_LABEL_FAVORITES, MENU_SETTING_ACTION, 0, 0); + + core_info_get_list(&list); + if (core_info_list_num_info_files(list)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), + MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, + MENU_SETTING_ACTION, 0, 0); + } + + if (frontend_driver_parse_drive_list(info->list, true) != 0) + menu_entries_append_enum(info->list, "/", + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, + MENU_SETTING_ACTION, 0, 0); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), + MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, + MENU_SETTING_ACTION, 0, 0); + + info->need_push = true; + info->need_refresh = true; + ret = 0; } - - if (frontend_driver_parse_drive_list(info->list, true) != 0) - menu_entries_append_enum(info->list, "/", - msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), - MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, - MENU_SETTING_ACTION, 0, 0); - - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), - MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, - MENU_SETTING_ACTION, 0, 0); - - info->need_push = true; - info->need_refresh = true; - ret = 0; break; case DISPLAYLIST_MAIN_MENU: { @@ -1824,12 +2058,6 @@ static int mui_list_push(void *data, void *userdata, menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); } - if (system->load_no_content) - { - entry.enum_idx = MENU_ENUM_LABEL_START_CORE; - menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); - } - #ifndef HAVE_DYNAMIC if (frontend_driver_has_fork()) #endif @@ -1838,6 +2066,13 @@ static int mui_list_push(void *data, void *userdata, menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); } + if (system->load_no_content) + { + entry.enum_idx = MENU_ENUM_LABEL_START_CORE; + menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); + } + + entry.enum_idx = MENU_ENUM_LABEL_LOAD_CONTENT_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); @@ -1892,6 +2127,7 @@ static int mui_list_push(void *data, void *userdata, return ret; } +/* Returns the active tab id */ static size_t mui_list_get_selection(void *data) { mui_handle_t *mui = (mui_handle_t*)data; @@ -1902,6 +2138,8 @@ static size_t mui_list_get_selection(void *data) return mui->categories.selection_ptr; } +/* The pointer or the mouse is pressed down. We use this callback to +highlight the entry that has been pressed */ static int mui_pointer_down(void *userdata, unsigned x, unsigned y, unsigned ptr, menu_file_list_cbs_t *cbs, @@ -1909,6 +2147,7 @@ static int mui_pointer_down(void *userdata, { unsigned width, height; unsigned header_height; + size_t entries_end = menu_entries_get_size(); mui_handle_t *mui = (mui_handle_t*)userdata; if (!mui) @@ -1925,11 +2164,12 @@ static int mui_pointer_down(void *userdata, { } - else if (ptr <= (menu_entries_get_size() - 1)) + else if (ptr <= (entries_end - 1)) { - size_t ii = 0; - file_list_t *list = menu_entries_get_selection_buf_ptr(0); - for (ii = 0; ii < menu_entries_get_size(); ii++) + size_t ii; + file_list_t *list = menu_entries_get_selection_buf_ptr(0); + + for (ii = 0; ii < entries_end; ii++) { mui_node_t *node = (mui_node_t*) menu_entries_get_userdata_at_offset(list, ii); @@ -1946,6 +2186,10 @@ static int mui_pointer_down(void *userdata, return 0; } +/* The pointer or the left mouse button has been released. +If we clicked on the header, we perform a cancel action. +If we clicked on the tabs, we switch to a new list. +If we clicked on a menu entry, we call the entry action callback. */ static int mui_pointer_up(void *userdata, unsigned x, unsigned y, unsigned ptr, menu_file_list_cbs_t *cbs, @@ -1953,6 +2197,7 @@ static int mui_pointer_up(void *userdata, { unsigned width, height; unsigned header_height, i; + size_t entries_end = menu_entries_get_size(); mui_handle_t *mui = (mui_handle_t*)userdata; if (!mui) @@ -1988,11 +2233,12 @@ static int mui_pointer_up(void *userdata, } } } - else if (ptr <= (menu_entries_get_size() - 1)) + else if (ptr <= (entries_end - 1)) { - size_t ii = 0; - file_list_t *list = menu_entries_get_selection_buf_ptr(0); - for (ii = 0; ii < menu_entries_get_size(); ii++) + size_t ii; + file_list_t *list = menu_entries_get_selection_buf_ptr(0); + + for (ii = 0; ii < entries_end; ii++) { mui_node_t *node = (mui_node_t*) menu_entries_get_userdata_at_offset(list, ii); @@ -2010,21 +2256,30 @@ static int mui_pointer_up(void *userdata, return 0; } +/* The menu system can insert menu entries on the fly. + * It is used in the shaders UI, the wifi UI, + * the netplay lobby, etc. + * + * This function allocates the mui_node_t + *for the new entry. */ static void mui_list_insert(void *userdata, file_list_t *list, const char *path, const char *fullpath, - const char *unused, - size_t list_size) + const char *label, + size_t list_size, + unsigned type) { float scale_factor; int i = (int)list_size; mui_node_t *node = NULL; + settings_t *settings = config_get_ptr(); mui_handle_t *mui = (mui_handle_t*)userdata; if (!mui || !list) return; + mui->need_compute = true; node = (mui_node_t*)menu_entries_get_userdata_at_offset(list, i); if (!node) @@ -2036,14 +2291,390 @@ static void mui_list_insert(void *userdata, return; } - scale_factor = menu_display_get_dpi(); + scale_factor = menu_display_get_dpi(); - node->line_height = scale_factor / 3; - node->y = 0; + node->line_height = scale_factor / 3; + node->y = 0; + node->texture_switch_set = false; + node->texture_switch2_set = false; + node->texture_switch = 0; + node->texture_switch2 = 0; + node->switch_is_on = false; + node->do_draw_text = false; + + if (settings->bools.menu_materialui_icons_enable) + { + switch (type) + { + case FILE_TYPE_DOWNLOAD_CORE: + case FILE_TYPE_CORE: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_CORES]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_DOWNLOAD_THUMBNAIL_CONTENT: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_IMAGE]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_PARENT_DIRECTORY: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_PARENT_DIRECTORY]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_PLAYLIST_COLLECTION: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_PLAYLIST]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_RDB: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_DATABASE]; + node->texture_switch2_set = true; + break; + case 32: /* TODO: Need to find out what this is */ + case FILE_TYPE_RDB_ENTRY: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_SETTINGS]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_IN_CARCHIVE: + case FILE_TYPE_PLAIN: + case FILE_TYPE_DOWNLOAD_CORE_CONTENT: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_FILE]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_MUSIC: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_MUSIC]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_MOVIE: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_VIDEO]; + node->texture_switch2_set = true; + break; + case FILE_TYPE_DIRECTORY: + case FILE_TYPE_DOWNLOAD_URL: + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_FOLDER]; + node->texture_switch2_set = true; + break; + default: + if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INFORMATION_LIST)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NO_CORE_INFORMATION_AVAILABLE)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NO_ITEMS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NO_CORE_OPTIONS_AVAILABLE)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NO_SETTINGS_FOUND)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_INFO]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_GOTO_IMAGES))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_IMAGE]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_GOTO_MUSIC))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_MUSIC]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_GOTO_VIDEO))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_VIDEO]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_SCAN]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_HISTORY]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_LIST))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_HELP]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RESTART_CONTENT))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_RESTART]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RESUME_CONTENT))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_RESUME]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CLOSE_CONTENT))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_CLOSE]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CORE_OPTIONS))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_CORE_OPTIONS]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_CORE_CHEAT_OPTIONS]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_CONTROLS]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SHADER_OPTIONS))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_SHADERS]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CORE_LIST))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_CORES]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RUN))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_RUN]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TO_FAVORITES)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_ADD_TO_FAVORITES]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_RENAME]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TO_MIXER)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TO_MIXER_AND_COLLECTION)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_ADD_TO_MIXER]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_START_CORE)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RUN_MUSIC)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_START_CORE]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_STATE)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_LOAD_STATE]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DISK_CYCLE_TRAY_STATUS)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_EJECT]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DISK_IMAGE_APPEND)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DISK_OPTIONS)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_DISK]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVE_STATE)) + || + (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE))) + || + (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME))) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_SAVE_STATE]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UNDO_LOAD_STATE))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_UNDO_LOAD_STATE]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UNDO_SAVE_STATE))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_UNDO_SAVE_STATE]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_STATE_SLOT))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_STATE_SLOT]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_TAKE_SCREENSHOT))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_TAKE_SCREENSHOT]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CONFIGURATIONS_LIST))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_CONFIGURATIONS]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_LIST))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_LOAD_CONTENT]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DELETE_ENTRY))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_REMOVE]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_NETPLAY]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_SETTINGS))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_QUICKMENU]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ONLINE_UPDATER)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_ASSETS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_CHEATS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_DATABASES)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_OVERLAYS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_CG_SHADERS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_UPDATER]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SCAN_DIRECTORY)) || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SCAN_FILE)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_ADD]; + node->texture_switch2_set = true; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_QUIT_RETROARCH))) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_QUIT]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DRIVER_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_AUDIO_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INPUT_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INPUT_HOTKEY_BINDS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CORE_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CONFIGURATION_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVING_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOGGING_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RECORDING_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_WIFI_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETWORK_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_LAN_SCAN_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LAKKA_SERVICES)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLIST_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_USER_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DIRECTORY_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PRIVACY_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MENU_VIEWS_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MENU_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ACCOUNTS_LIST)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_REWIND_SETTINGS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CORE_UPDATER_LIST)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST)) + || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_SETTINGS]; + node->texture_switch2_set = true; + } + else if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES)) || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST)) + ) + { + node->texture_switch2 = mui->textures.list[MUI_TEXTURE_FOLDER]; + node->texture_switch2_set = true; + } + break; + } + } file_list_set_userdata(list, i, node); } +/* Clearing the current menu list */ static void mui_list_clear(file_list_t *list) { size_t i; diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index fbba787ffe..5cc69ff7e4 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -77,8 +77,8 @@ static uint16_t argb32_to_rgba4444(uint32_t col) { unsigned a = ((col >> 24) & 0xff) >> 4; unsigned r = ((col >> 16) & 0xff) >> 4; - unsigned g = ((col >> 8) & 0xff) >> 4; - unsigned b = (col & 0xff) >> 4; + unsigned g = ((col >> 8) & 0xff) >> 4; + unsigned b = ((col & 0xff) ) >> 4; return (r << 12) | (g << 8) | (b << 4) | a; } #endif @@ -94,7 +94,7 @@ static void rgui_copy_glyph(uint8_t *glyph, const uint8_t *buf) { for (x = 0; x < FONT_WIDTH; x++) { - uint32_t col = + uint32_t col = ((uint32_t)buf[3 * (-y * 256 + x) + 0] << 0) | ((uint32_t)buf[3 * (-y * 256 + x) + 1] << 8) | ((uint32_t)buf[3 * (-y * 256 + x) + 2] << 16); @@ -110,11 +110,7 @@ static void rgui_copy_glyph(uint8_t *glyph, const uint8_t *buf) static uint16_t rgui_gray_filler(unsigned x, unsigned y) { - unsigned col; - - x >>= 1; - y >>= 1; - col = ((x + y) & 1) + 1; + unsigned col = (((x >> 1) + (y >> 1)) & 1) + 1; #if defined(GEKKO) || defined(PSP) return (6 << 12) | (col << 8) | (col << 4) | (col << 0); @@ -125,11 +121,7 @@ static uint16_t rgui_gray_filler(unsigned x, unsigned y) static uint16_t rgui_green_filler(unsigned x, unsigned y) { - unsigned col; - - x >>= 1; - y >>= 1; - col = ((x + y) & 1) + 1; + unsigned col = (((x >> 1) + (y >> 1)) & 1) + 1; #if defined(GEKKO) || defined(PSP) return (6 << 12) | (col << 8) | (col << 5) | (col << 0); #else @@ -137,16 +129,14 @@ static uint16_t rgui_green_filler(unsigned x, unsigned y) #endif } -static void rgui_fill_rect(size_t pitch, +static void rgui_fill_rect( + uint16_t *data, + size_t pitch, unsigned x, unsigned y, unsigned width, unsigned height, uint16_t (*col)(unsigned x, unsigned y)) { unsigned i, j; - uint16_t *data = (uint16_t*)rgui_framebuf_data; - - if (!data || !col) - return; for (j = y; j < y + height; j++) for (i = x; i < x + width; i++) @@ -154,6 +144,7 @@ static void rgui_fill_rect(size_t pitch, } static void rgui_color_rect( + uint16_t *data, size_t pitch, unsigned fb_width, unsigned fb_height, unsigned x, unsigned y, @@ -161,10 +152,6 @@ static void rgui_color_rect( uint16_t color) { unsigned i, j; - uint16_t *data = (uint16_t*)rgui_framebuf_data; - - if (!data) - return; for (j = y; j < y + height; j++) for (i = x; i < x + width; i++) @@ -175,33 +162,31 @@ static void rgui_color_rect( static void blit_line(int x, int y, const char *message, uint16_t color) { - unsigned i, j; size_t pitch = menu_display_get_framebuffer_pitch(); + const uint8_t *font_fb = menu_display_get_font_framebuffer(); - if (!rgui_framebuf_data) - return; - - while (!string_is_empty(message)) + if (font_fb) { - const uint8_t *font_fb = menu_display_get_font_framebuffer(); - uint32_t symbol = utf8_walk(&message); - - for (j = 0; j < FONT_HEIGHT; j++) + while (!string_is_empty(message)) { - for (i = 0; i < FONT_WIDTH; i++) + unsigned i, j; + char symbol = *message++; + + for (j = 0; j < FONT_HEIGHT; j++) { - uint8_t rem = 1 << ((i + j * FONT_WIDTH) & 7); - int offset = (i + j * FONT_WIDTH) >> 3; - bool col = (font_fb[FONT_OFFSET(symbol) + offset] & rem); + for (i = 0; i < FONT_WIDTH; i++) + { + uint8_t rem = 1 << ((i + j * FONT_WIDTH) & 7); + int offset = (i + j * FONT_WIDTH) >> 3; + bool col = (font_fb[FONT_OFFSET(symbol) + offset] & rem); - if (!col) - continue; - - rgui_framebuf_data[(y + j) * (pitch >> 1) + (x + i)] = color; + if (col) + rgui_framebuf_data[(y + j) * (pitch >> 1) + (x + i)] = color; + } } - } - x += FONT_WIDTH_STRIDE; + x += FONT_WIDTH_STRIDE; + } } } @@ -267,12 +252,15 @@ static void rgui_render_background(void) dst += pitch_in_pixels * 4; } - rgui_fill_rect(fb_pitch, 5, 5, fb_width - 10, 5, rgui_green_filler); - rgui_fill_rect(fb_pitch, 5, fb_height - 10, fb_width - 10, 5, rgui_green_filler); + if (rgui_framebuf_data) + { + rgui_fill_rect(rgui_framebuf_data, fb_pitch, 5, 5, fb_width - 10, 5, rgui_green_filler); + rgui_fill_rect(rgui_framebuf_data, fb_pitch, 5, fb_height - 10, fb_width - 10, 5, rgui_green_filler); - rgui_fill_rect(fb_pitch, 5, 5, 5, fb_height - 10, rgui_green_filler); - rgui_fill_rect(fb_pitch, fb_width - 10, 5, 5, fb_height - 10, - rgui_green_filler); + rgui_fill_rect(rgui_framebuf_data, fb_pitch, 5, 5, 5, fb_height - 10, rgui_green_filler); + rgui_fill_rect(rgui_framebuf_data, fb_pitch, fb_width - 10, 5, 5, fb_height - 10, + rgui_green_filler); + } } static void rgui_set_message(void *data, const char *message) @@ -337,15 +325,23 @@ static void rgui_render_messagebox(const char *message) x = (fb_width - width) / 2; y = (fb_height - height) / 2; - rgui_fill_rect(fb_pitch, x + 5, y + 5, width - 10, - height - 10, rgui_gray_filler); - rgui_fill_rect(fb_pitch, x, y, width - 5, 5, rgui_green_filler); - rgui_fill_rect(fb_pitch, x + width - 5, y, 5, - height - 5, rgui_green_filler); - rgui_fill_rect(fb_pitch, x + 5, y + height - 5, - width - 5, 5, rgui_green_filler); - rgui_fill_rect(fb_pitch, x, y + 5, 5, - height - 5, rgui_green_filler); + if (rgui_framebuf_data) + { + rgui_fill_rect(rgui_framebuf_data, + fb_pitch, x + 5, y + 5, width - 10, + height - 10, rgui_gray_filler); + rgui_fill_rect(rgui_framebuf_data, + fb_pitch, x, y, width - 5, 5, rgui_green_filler); + rgui_fill_rect(rgui_framebuf_data, + fb_pitch, x + width - 5, y, 5, + height - 5, rgui_green_filler); + rgui_fill_rect(rgui_framebuf_data, + fb_pitch, x + 5, y + height - 5, + width - 5, 5, rgui_green_filler); + rgui_fill_rect(rgui_framebuf_data, + fb_pitch, x, y + 5, 5, + height - 5, rgui_green_filler); + } color = NORMAL_COLOR(settings); @@ -355,7 +351,8 @@ static void rgui_render_messagebox(const char *message) int offset_x = (int)(FONT_WIDTH_STRIDE * (glyphs_width - utf8len(msg)) / 2); int offset_y = (int)(FONT_HEIGHT_STRIDE * i); - blit_line(x + 8 + offset_x, y + 8 + offset_y, msg, color); + if (rgui_framebuf_data) + blit_line(x + 8 + offset_x, y + 8 + offset_y, msg, color); } end: @@ -372,8 +369,11 @@ static void rgui_blit_cursor(void) menu_display_get_fb_size(&fb_width, &fb_height, &fb_pitch); - rgui_color_rect(fb_pitch, fb_width, fb_height, x, y - 5, 1, 11, 0xFFFF); - rgui_color_rect(fb_pitch, fb_width, fb_height, x - 5, y, 11, 1, 0xFFFF); + if (rgui_framebuf_data) + { + rgui_color_rect(rgui_framebuf_data, fb_pitch, fb_width, fb_height, x, y - 5, 1, 11, 0xFFFF); + rgui_color_rect(rgui_framebuf_data, fb_pitch, fb_width, fb_height, x - 5, y, 11, 1, 0xFFFF); + } } static void rgui_frame(void *data, video_frame_info_t *video_info) @@ -423,7 +423,9 @@ static void rgui_render(void *data, bool is_idle) /* if the framebuffer changed size, recache the background */ if (rgui->last_width != fb_width || rgui->last_height != fb_height) { - rgui_fill_rect(fb_pitch, 0, fb_height, fb_width, 4, rgui_gray_filler); + if (rgui_framebuf_data) + rgui_fill_rect(rgui_framebuf_data, + fb_pitch, 0, fb_height, fb_width, 4, rgui_gray_filler); rgui->last_width = fb_width; rgui->last_height = fb_height; } @@ -491,10 +493,6 @@ static void rgui_render(void *data, bool is_idle) rgui_render_background(); -#if 0 - RARCH_LOG("Dir is: %s\n", label); -#endif - menu_entries_get_title(title, sizeof(title)); ticker.s = title_buf; @@ -517,27 +515,32 @@ static void rgui_render(void *data, bool is_idle) strlcpy(back_buf, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK), sizeof(back_buf)); strlcpy(back_msg, string_to_upper(back_buf), sizeof(back_msg)); - blit_line( - RGUI_TERM_START_X(fb_width), - RGUI_TERM_START_X(fb_width), - back_msg, - TITLE_COLOR(settings)); + if (rgui_framebuf_data) + blit_line( + RGUI_TERM_START_X(fb_width), + RGUI_TERM_START_X(fb_width), + back_msg, + TITLE_COLOR(settings)); } strlcpy(title_buf, string_to_upper(title_buf), sizeof(title_buf)); - blit_line( - (int)(RGUI_TERM_START_X(fb_width) + (RGUI_TERM_WIDTH(fb_width) - - utf8len(title_buf)) * FONT_WIDTH_STRIDE / 2), - RGUI_TERM_START_X(fb_width), - title_buf, TITLE_COLOR(settings)); + if (rgui_framebuf_data) + blit_line( + (int)(RGUI_TERM_START_X(fb_width) + (RGUI_TERM_WIDTH(fb_width) + - utf8len(title_buf)) * FONT_WIDTH_STRIDE / 2), + RGUI_TERM_START_X(fb_width), + title_buf, TITLE_COLOR(settings)); if (settings->bools.menu_core_enable && menu_entries_get_core_title(title_msg, sizeof(title_msg)) == 0) - blit_line( - RGUI_TERM_START_X(fb_width), - (RGUI_TERM_HEIGHT(fb_width, fb_height) * FONT_HEIGHT_STRIDE) + - RGUI_TERM_START_Y(fb_height) + 2, title_msg, hover_color); + { + if (rgui_framebuf_data) + blit_line( + RGUI_TERM_START_X(fb_width), + (RGUI_TERM_HEIGHT(fb_width, fb_height) * FONT_HEIGHT_STRIDE) + + RGUI_TERM_START_Y(fb_height) + 2, title_msg, hover_color); + } if (settings->bools.menu_timedate_enable) { @@ -552,10 +555,11 @@ static void rgui_render(void *data, bool is_idle) menu_display_timedate(&datetime); - blit_line( - RGUI_TERM_WIDTH(fb_width) * FONT_WIDTH_STRIDE - RGUI_TERM_START_X(fb_width), - (RGUI_TERM_HEIGHT(fb_width, fb_height) * FONT_HEIGHT_STRIDE) + - RGUI_TERM_START_Y(fb_height) + 2, timedate, hover_color); + if (rgui_framebuf_data) + blit_line( + RGUI_TERM_WIDTH(fb_width) * FONT_WIDTH_STRIDE - RGUI_TERM_START_X(fb_width), + (RGUI_TERM_HEIGHT(fb_width, fb_height) * FONT_HEIGHT_STRIDE) + + RGUI_TERM_START_Y(fb_height) + 2, timedate, hover_color); } x = RGUI_TERM_START_X(fb_width); @@ -571,6 +575,7 @@ static void rgui_render(void *data, bool is_idle) char message[255]; char entry_title_buf[255]; char type_str_buf[255]; + size_t entry_title_buf_utf8len, entry_title_buf_len; unsigned entry_spacing = menu_entry_get_spacing((unsigned)i); bool entry_selected = menu_entry_is_currently_selected((unsigned)i); size_t selection = menu_navigation_get_selection(); @@ -601,16 +606,20 @@ static void rgui_render(void *data, bool is_idle) menu_animation_ticker(&ticker); + entry_title_buf_utf8len = utf8len(entry_title_buf); + entry_title_buf_len = strlen(entry_title_buf); + snprintf(message, sizeof(message), "%c %-*.*s %-*s", entry_selected ? '>' : ' ', - (int)(RGUI_TERM_WIDTH(fb_width) - (entry_spacing + 1 + 2) - utf8len(entry_title_buf) + strlen(entry_title_buf)), - (int)(RGUI_TERM_WIDTH(fb_width) - (entry_spacing + 1 + 2) - utf8len(entry_title_buf) + strlen(entry_title_buf)), + (int)(RGUI_TERM_WIDTH(fb_width) - (entry_spacing + 1 + 2) - entry_title_buf_utf8len + entry_title_buf_len), + (int)(RGUI_TERM_WIDTH(fb_width) - (entry_spacing + 1 + 2) - entry_title_buf_utf8len + entry_title_buf_len), entry_title_buf, entry_spacing, type_str_buf); - blit_line(x, y, message, - entry_selected ? hover_color : normal_color); + if (rgui_framebuf_data) + blit_line(x, y, message, + entry_selected ? hover_color : normal_color); } if (menu_input_dialog_get_display_kb()) @@ -690,8 +699,10 @@ static void *rgui_init(void **userdata, bool video_is_threaded) if (!ret) goto error; - rgui_fill_rect(fb_pitch, 0, fb_height, - fb_width, 4, rgui_gray_filler); + if (rgui_framebuf_data) + rgui_fill_rect(rgui_framebuf_data, + fb_pitch, 0, fb_height, + fb_width, 4, rgui_gray_filler); rgui->last_width = fb_width; rgui->last_height = fb_height; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c old mode 100644 new mode 100755 index 22c7a88f4e..bb8ea6dd8f --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -44,6 +44,8 @@ #include "../menu_driver.h" #include "../menu_animation.h" +#include "../../core_info.h" +#include "../../core.h" #include "../widgets/menu_entry.h" #include "../widgets/menu_list.h" #include "../widgets/menu_input_dialog.h" @@ -73,6 +75,8 @@ #define XMB_DEBUG #endif +/* NOTE: If you change this you HAVE to update + * xmb_alloc_node() and xmb_copy_node() */ typedef struct { float alpha; @@ -90,6 +94,7 @@ enum XMB_TEXTURE_MAIN_MENU = 0, XMB_TEXTURE_SETTINGS, XMB_TEXTURE_HISTORY, + XMB_TEXTURE_FAVORITES, XMB_TEXTURE_MUSICS, #ifdef HAVE_FFMPEG XMB_TEXTURE_MOVIES, @@ -97,6 +102,9 @@ enum #ifdef HAVE_NETWORKING XMB_TEXTURE_NETPLAY, XMB_TEXTURE_ROOM, +/* stub these out until we have the icons + XMB_TEXTURE_ROOM_LAN, + XMB_TEXTURE_ROOM_MITM,*/ #endif #ifdef HAVE_IMAGEVIEWER XMB_TEXTURE_IMAGES, @@ -120,9 +128,12 @@ enum XMB_TEXTURE_ACHIEVEMENT_LIST, XMB_TEXTURE_SCREENSHOT, XMB_TEXTURE_RELOAD, + XMB_TEXTURE_RENAME, XMB_TEXTURE_FILE, XMB_TEXTURE_FOLDER, XMB_TEXTURE_ZIP, + XMB_TEXTURE_FAVORITE, + XMB_TEXTURE_ADD_FAVORITE, XMB_TEXTURE_MUSIC, XMB_TEXTURE_IMAGE, XMB_TEXTURE_MOVIE, @@ -147,6 +158,7 @@ enum XMB_SYSTEM_TAB_MAIN = 0, XMB_SYSTEM_TAB_SETTINGS, XMB_SYSTEM_TAB_HISTORY, + XMB_SYSTEM_TAB_FAVORITES, XMB_SYSTEM_TAB_MUSIC, #ifdef HAVE_FFMPEG XMB_SYSTEM_TAB_VIDEO, @@ -299,6 +311,7 @@ typedef struct xmb_handle #endif xmb_node_t settings_tab_node; xmb_node_t history_tab_node; + xmb_node_t favorites_tab_node; xmb_node_t add_tab_node; xmb_node_t netplay_tab_node; @@ -404,6 +417,40 @@ const char* xmb_theme_ident(void) return "monochrome"; } +/* NOTE: This exists because calloc()ing xmb_node_t is expensive + * when you can have big lists like MAME and fba playlists */ +static xmb_node_t *xmb_alloc_node(void) +{ + xmb_node_t *node = (xmb_node_t*)malloc(sizeof(*node)); + + node->alpha = node->label_alpha = 0; + node->zoom = node->x = node->y = 0; + node->icon = node->content_icon = 0; + node->fullpath[0] = 0; + + return node; +} + +/* NOTE: This is faster than memcpy()ing xmb_node_t in most cases + * because most nodes have small (less than 200 bytes) fullpath */ +static xmb_node_t *xmb_copy_node(void *p) +{ + xmb_node_t *old_node = (xmb_node_t*)p; + xmb_node_t *new_node = (xmb_node_t*)malloc(sizeof(*new_node)); + + new_node->alpha = old_node->alpha; + new_node->label_alpha = old_node->label_alpha; + new_node->zoom = old_node->zoom; + new_node->x = old_node->x; + new_node->y = old_node->y; + new_node->icon = old_node->icon; + new_node->content_icon = old_node->content_icon; + + strlcpy(new_node->fullpath, old_node->fullpath, sizeof(old_node->fullpath)); + + return new_node; +} + static const char *xmb_thumbnails_ident(void) { settings_t *settings = config_get_ptr(); @@ -509,7 +556,7 @@ static void *xmb_list_get_entry(void *data, enum menu_list_type type, unsigned i return NULL; } -static INLINE float xmb_item_y(xmb_handle_t *xmb, int i, size_t current) +static INLINE float xmb_item_y(const xmb_handle_t *xmb, int i, size_t current) { float iy = xmb->icon.spacing.vertical; @@ -610,7 +657,7 @@ static void xmb_draw_icon( static void xmb_draw_thumbnail( menu_display_frame_info_t menu_disp_info, xmb_handle_t *xmb, float *color, - unsigned width, unsigned height, + unsigned width, unsigned height, float x, float y, float w, float h, uintptr_t texture) { @@ -826,7 +873,7 @@ static void xmb_render_messagebox_internal( { const char *msg = list->elems[i].data; int len = (int)utf8len(msg); - + if (len > longest) { longest = len; @@ -999,7 +1046,7 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) || (string_is_equal_fast(entry.label, "loadstate", 9)) || (string_is_equal_fast(entry.label, "savestate", 9)))) { - char path[PATH_MAX_LENGTH]; + char path[8204]; global_t *global = global_get_ptr(); path[0] = '\0'; @@ -1084,7 +1131,7 @@ static void xmb_selection_pointer_changed( { menu_entry_t e; unsigned i, end, height; - menu_animation_ctx_tag_t tag; + menu_animation_ctx_tag tag; size_t num = 0; int threshold = 0; menu_list_t *menu_list = NULL; @@ -1115,7 +1162,7 @@ static void xmb_selection_pointer_changed( video_driver_get_size(NULL, &height); - tag.id = (int)(uintptr_t)menu_list; + tag = (uintptr_t)selection_buf; menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &num); @@ -1187,28 +1234,24 @@ static void xmb_selection_pointer_changed( entry.target_value = ia; entry.subject = &node->alpha; entry.easing_enum = EASING_OUT_QUAD; - entry.tag = tag.id; + entry.tag = tag; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = iz; entry.subject = &node->zoom; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = iy; entry.subject = &node->y; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } } @@ -1255,23 +1298,20 @@ static void xmb_list_open_old(xmb_handle_t *xmb, entry.target_value = ia; entry.subject = &node->alpha; entry.easing_enum = EASING_OUT_QUAD; - entry.tag = -1; + entry.tag = (uintptr_t)list; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 0; entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = xmb->icon.size * dir * -2; entry.subject = &node->x; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } } @@ -1328,22 +1368,19 @@ static void xmb_list_open_new(xmb_handle_t *xmb, entry.target_value = ia; entry.subject = &node->alpha; entry.easing_enum = EASING_OUT_QUAD; - entry.tag = -1; + entry.tag = (uintptr_t)list; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 0; entry.subject = &node->x; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } @@ -1361,7 +1398,7 @@ static void xmb_list_open_new(xmb_handle_t *xmb, static xmb_node_t *xmb_node_allocate_userdata(xmb_handle_t *xmb, unsigned i) { - xmb_node_t *node = (xmb_node_t*)calloc(1, sizeof(xmb_node_t)); + xmb_node_t *node = xmb_alloc_node(); if (!node) { @@ -1391,7 +1428,7 @@ static xmb_node_t* xmb_get_userdata_from_horizontal_list( menu_entries_get_actiondata_at_offset(xmb->horizontal_list, i); } -static void xmb_push_animations(xmb_node_t *node, float ia, float ix) +static void xmb_push_animations(xmb_node_t *node, uintptr_t tag, float ia, float ix) { menu_animation_ctx_entry_t entry; @@ -1399,22 +1436,19 @@ static void xmb_push_animations(xmb_node_t *node, float ia, float ix) entry.target_value = ia; entry.subject = &node->alpha; entry.easing_enum = EASING_OUT_QUAD; - entry.tag = -1; + entry.tag = tag; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = ix; entry.subject = &node->x; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } static void xmb_list_switch_old(xmb_handle_t *xmb, @@ -1432,7 +1466,7 @@ static void xmb_list_switch_old(xmb_handle_t *xmb, if (!node) continue; - xmb_push_animations(node, ia, -xmb->icon.spacing.horizontal * dir); + xmb_push_animations(node, (uintptr_t)list, ia, -xmb->icon.spacing.horizontal * dir); } } @@ -1498,7 +1532,7 @@ static void xmb_list_switch_new(xmb_handle_t *xmb, if (i == current) ia = xmb->items.active.alpha; - xmb_push_animations(node, ia, 0); + xmb_push_animations(node, (uintptr_t)list, ia, 0); } } @@ -1550,6 +1584,8 @@ static xmb_node_t* xmb_get_node(xmb_handle_t *xmb, unsigned i) #endif case XMB_SYSTEM_TAB_HISTORY: return &xmb->history_tab_node; + case XMB_SYSTEM_TAB_FAVORITES: + return &xmb->favorites_tab_node; #ifdef HAVE_NETWORKING case XMB_SYSTEM_TAB_NETPLAY: return &xmb->netplay_tab_node; @@ -1594,14 +1630,12 @@ static void xmb_list_switch_horizontal_list(xmb_handle_t *xmb) entry.tag = -1; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = iz; entry.subject = &node->zoom; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } @@ -1612,6 +1646,7 @@ static void xmb_list_switch(xmb_handle_t *xmb) int dir = -1; file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); size_t selection = menu_navigation_get_selection(); + settings_t *settings = config_get_ptr(); if (xmb->categories.selection_ptr > xmb->categories.selection_ptr_old) dir = 1; @@ -1636,7 +1671,10 @@ static void xmb_list_switch(xmb_handle_t *xmb) xmb_list_switch_old(xmb, xmb->selection_buf_old, dir, xmb->selection_ptr_old); - xmb_list_switch_new(xmb, selection_buf, dir, selection); + + /* Check if we are to have horizontal animations. */ + if (settings->bools.menu_horizontal_animation) + xmb_list_switch_new(xmb, selection_buf, dir, selection); xmb->categories.active.idx_old = (unsigned)xmb->categories.selection_ptr; if (!string_is_equal(xmb_thumbnails_ident(), @@ -1959,28 +1997,23 @@ static void xmb_list_open(xmb_handle_t *xmb) entry.tag = -1; entry.cb = NULL; - switch (xmb->depth) { case 1: - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 0; entry.subject = &xmb->textures.arrow.alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); break; case 2: - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 1; entry.subject = &xmb->textures.arrow.alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); break; } @@ -2024,6 +2057,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_CORE_OPTIONS: case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE: return xmb->textures.list[XMB_TEXTURE_CORE_OPTIONS]; + case MENU_ENUM_LABEL_ADD_TO_FAVORITES: + return xmb->textures.list[XMB_TEXTURE_ADD_FAVORITE]; case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: return xmb->textures.list[XMB_TEXTURE_INPUT_REMAPPING_OPTIONS]; case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS: @@ -2050,6 +2085,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, return xmb->textures.list[XMB_TEXTURE_CLOSE]; case MENU_ENUM_LABEL_RESTART_CONTENT: return xmb->textures.list[XMB_TEXTURE_RELOAD]; + case MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME: + return xmb->textures.list[XMB_TEXTURE_RENAME]; case MENU_ENUM_LABEL_RESUME_CONTENT: return xmb->textures.list[XMB_TEXTURE_RESUME]; case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE: @@ -2077,6 +2114,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, switch (xmb_get_system_tab(xmb, (unsigned)xmb->categories.selection_ptr)) { + case XMB_SYSTEM_TAB_FAVORITES: + return xmb->textures.list[XMB_TEXTURE_FAVORITE]; case XMB_SYSTEM_TAB_MUSIC: return xmb->textures.list[XMB_TEXTURE_MUSIC]; #ifdef HAVE_IMAGEVIEWER @@ -2148,12 +2187,46 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, #ifdef HAVE_NETWORKING case MENU_ROOM: return xmb->textures.list[XMB_TEXTURE_ROOM]; + /* stub these out until we have the icons + case MENU_ROOM_LAN: + return xmb->textures.list[XMB_TEXTURE_ROOM_LAN]; + case MENU_ROOM_MITM: + return xmb->textures.list[XMB_TEXTURE_ROOM_MITM]; */ #endif } return xmb->textures.list[XMB_TEXTURE_SUBSETTING]; } +static void xmb_calculate_visible_range(const xmb_handle_t *xmb, unsigned height, size_t list_size, unsigned current, unsigned *first, unsigned *last) +{ + unsigned j; + float base_y = xmb->margins.screen.top; + + if (current) + { + for (j = current; j-- > 0; ) + { + float bottom = xmb_item_y(xmb, j, current) + base_y + xmb->icon.size; + + if (bottom < 0) + break; + + *first = j; + } + } + + for (j = current+1; j < list_size; j++) + { + float top = xmb_item_y(xmb, j, current) + base_y; + + if (top > height) + break; + + *last = j; + } +} + static void xmb_draw_items( video_frame_info_t *video_info, menu_display_frame_info_t menu_disp_info, @@ -2169,6 +2242,7 @@ static void xmb_draw_items( size_t end = 0; uint64_t frame_count = xmb->frame_count; const char *thumb_ident = xmb_thumbnails_ident(); + unsigned first, last; if (!list || !list->size) return; @@ -2191,11 +2265,24 @@ static void xmb_draw_items( menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); if (list == xmb->selection_buf_old) + { + xmb_node_t *node = (xmb_node_t*) + menu_entries_get_userdata_at_offset(list, current); + + if ((uint8_t)(255 * node->alpha) == 0) + return; + i = 0; + } + + first = i; + last = end - 1; + + xmb_calculate_visible_range(xmb, height, end, current, &first, &last); menu_display_blend_begin(); - for (; i < end; i++) + for (i = first; i <= last; i++) { float icon_x, icon_y, label_offset; menu_animation_ctx_ticker_t ticker; @@ -2320,7 +2407,7 @@ static void xmb_draw_items( label_offset = - xmb->margins.label.top; - word_wrap(entry_sublabel, entry.sublabel, 50); + word_wrap(entry_sublabel, entry.sublabel, 50, true); xmb_draw_text(menu_disp_info, xmb, entry_sublabel, node->x + xmb->margins.screen.left + @@ -2443,16 +2530,23 @@ static void xmb_render(void *data, bool is_idle) if (pointer_enable || mouse_enable) { - size_t selection = menu_navigation_get_selection(); + size_t selection = menu_navigation_get_selection(); + int16_t pointer_y = menu_input_pointer_state(MENU_POINTER_Y_AXIS); + int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS) + + (xmb->cursor.size/2); + unsigned first = 0, last = end; + unsigned height; - for (i = 0; i < end; i++) + video_driver_get_size(NULL, &height); + + if (height) + xmb_calculate_visible_range(xmb, height, end, selection, &first, &last); + + for (i = first; i <= last; i++) { float item_y1 = xmb->margins.screen.top + xmb_item_y(xmb, (int)i, selection); float item_y2 = item_y1 + xmb->icon.size; - int16_t pointer_y = menu_input_pointer_state(MENU_POINTER_Y_AXIS); - int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS) - + (xmb->cursor.size/2); if (pointer_enable) { @@ -2575,8 +2669,10 @@ static void xmb_draw_bg( menu_display_draw_gradient(&draw, video_info); { - bool add_opacity = false; - draw.texture = texture; + float override_opacity = video_info->menu_wallpaper_opacity; + bool add_opacity = false; + + draw.texture = texture; menu_display_set_alpha(draw.color, coord_white[3]); if (draw.texture) @@ -2585,7 +2681,7 @@ static void xmb_draw_bg( if (running || video_info->xmb_color_theme == XMB_THEME_WALLPAPER) add_opacity = true; - menu_display_draw_bg(&draw, video_info, add_opacity); + menu_display_draw_bg(&draw, video_info, add_opacity, override_opacity); } } @@ -2715,6 +2811,32 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) menu_display_rotate_z(&rotate_draw); menu_display_blend_begin(); + + if (xmb->savestate_thumbnail) + xmb_draw_thumbnail(menu_disp_info, + xmb, &coord_white[0], width, height, + xmb->margins.screen.left + xmb->icon.spacing.horizontal + + xmb->icon.spacing.horizontal*4 - xmb->icon.size / 4, + xmb->margins.screen.top + xmb->icon.size + xmb->savestate_thumbnail_height, + xmb->savestate_thumbnail_width, xmb->savestate_thumbnail_height, + xmb->savestate_thumbnail); + else if (xmb->thumbnail + && !string_is_equal(xmb_thumbnails_ident(), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) + { +#ifdef XMB_DEBUG + RARCH_LOG("[XMB thumbnail] width: %.2f, height: %.2f\n", xmb->thumbnail_width, xmb->thumbnail_height); + RARCH_LOG("[XMB thumbnail] w: %.2f, h: %.2f\n", width, height); +#endif + + xmb_draw_thumbnail(menu_disp_info, + xmb, &coord_white[0], width, height, + xmb->margins.screen.left + xmb->icon.spacing.horizontal + + xmb->icon.spacing.horizontal*4 - xmb->icon.size / 4, + xmb->margins.screen.top + xmb->icon.size + xmb->thumbnail_height, + xmb->thumbnail_width, xmb->thumbnail_height, + xmb->thumbnail); + } /* Clock image */ menu_display_set_alpha(coord_white, MIN(xmb->alpha, 1.00f)); @@ -2927,32 +3049,6 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) font_driver_flush(video_info->width, video_info->height, xmb->font2); font_driver_bind_block(xmb->font2, NULL); - if (xmb->savestate_thumbnail) - xmb_draw_thumbnail(menu_disp_info, - xmb, &coord_white[0], width, height, - xmb->margins.screen.left + xmb->icon.spacing.horizontal + - xmb->icon.spacing.horizontal*4 - xmb->icon.size / 4, - xmb->margins.screen.top + xmb->icon.size + xmb->savestate_thumbnail_height, - xmb->savestate_thumbnail_width, xmb->savestate_thumbnail_height, - xmb->savestate_thumbnail); - else if (xmb->thumbnail - && !string_is_equal(xmb_thumbnails_ident(), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) - { -#ifdef XMB_DEBUG - RARCH_LOG("[XMB thumbnail] width: %.2f, height: %.2f\n", xmb->thumbnail_width, xmb->thumbnail_height); - RARCH_LOG("[XMB thumbnail] w: %.2f, h: %.2f\n", width, height); -#endif - - xmb_draw_thumbnail(menu_disp_info, - xmb, &coord_white[0], width, height, - xmb->margins.screen.left + xmb->icon.spacing.horizontal + - xmb->icon.spacing.horizontal*4 - xmb->icon.size / 4, - xmb->margins.screen.top + xmb->icon.size + xmb->thumbnail_height, - xmb->thumbnail_width, xmb->thumbnail_height, - xmb->thumbnail); - } - if (menu_input_dialog_get_display_kb()) { const char *str = menu_input_dialog_get_buffer(); @@ -3292,6 +3388,8 @@ static void *xmb_init(void **userdata, bool video_is_threaded) xmb->tabs[xmb->system_tab_end] = XMB_SYSTEM_TAB_MAIN; if (settings->bools.menu_xmb_show_settings) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_SETTINGS; + if (settings->bools.menu_xmb_show_favorites) + xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_FAVORITES; if (settings->bools.menu_xmb_show_history) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_HISTORY; #ifdef HAVE_IMAGEVIEWER @@ -3443,6 +3541,10 @@ static const char *xmb_texture_path(unsigned id) return "settings.png"; case XMB_TEXTURE_HISTORY: return "history.png"; + case XMB_TEXTURE_FAVORITES: + return "favorites.png"; + case XMB_TEXTURE_ADD_FAVORITE: + return "add-favorite.png"; case XMB_TEXTURE_MUSICS: return "musics.png"; #ifdef HAVE_FFMPEG @@ -3499,6 +3601,8 @@ static const char *xmb_texture_path(unsigned id) return "screenshot.png"; case XMB_TEXTURE_RELOAD: return "reload.png"; + case XMB_TEXTURE_RENAME: + return "rename.png"; case XMB_TEXTURE_FILE: return "file.png"; case XMB_TEXTURE_FOLDER: @@ -3507,6 +3611,8 @@ static const char *xmb_texture_path(unsigned id) return "zip.png"; case XMB_TEXTURE_MUSIC: return "music.png"; + case XMB_TEXTURE_FAVORITE: + return "favorites-content.png"; case XMB_TEXTURE_IMAGE: return "image.png"; case XMB_TEXTURE_MOVIE: @@ -3528,6 +3634,12 @@ static const char *xmb_texture_path(unsigned id) return "netplay.png"; case XMB_TEXTURE_ROOM: return "room.png"; + /* stub these out until we have the icons + case XMB_TEXTURE_ROOM_LAN: + return "room_lan.png"; + case XMB_TEXTURE_ROOM_MITM: + return "room_mitm.png"; + */ #endif case XMB_TEXTURE_KEY: return "key.png"; @@ -3563,6 +3675,10 @@ static void xmb_context_reset_textures( xmb->history_tab_node.alpha = xmb->categories.active.alpha; xmb->history_tab_node.zoom = xmb->categories.active.zoom; + xmb->favorites_tab_node.icon = xmb->textures.list[XMB_TEXTURE_FAVORITES]; + xmb->favorites_tab_node.alpha = xmb->categories.active.alpha; + xmb->favorites_tab_node.zoom = xmb->categories.active.zoom; + xmb->music_tab_node.icon = xmb->textures.list[XMB_TEXTURE_MUSICS]; xmb->music_tab_node.alpha = xmb->categories.active.alpha; xmb->music_tab_node.zoom = xmb->categories.active.zoom; @@ -3671,7 +3787,8 @@ static void xmb_list_insert(void *userdata, const char *path, const char *fullpath, const char *unused, - size_t list_size) + size_t list_size, + unsigned entry_type) { int current = 0; int i = (int)list_size; @@ -3685,7 +3802,7 @@ static void xmb_list_insert(void *userdata, node = (xmb_node_t*)menu_entries_get_userdata_at_offset(list, i); if (!node) - node = (xmb_node_t*)calloc(1, sizeof(xmb_node_t)); + node = xmb_alloc_node(); if (!node) { @@ -3717,29 +3834,19 @@ static void xmb_list_insert(void *userdata, static void xmb_list_clear(file_list_t *list) { size_t i; - size_t size = list->size; + size_t size = list->size; + menu_animation_ctx_tag tag = (uintptr_t)list; + + menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); for (i = 0; i < size; ++i) { - menu_animation_ctx_subject_t subject; - float *subjects[5]; xmb_node_t *node = (xmb_node_t*) menu_entries_get_userdata_at_offset(list, i); if (!node) continue; - subjects[0] = &node->alpha; - subjects[1] = &node->label_alpha; - subjects[2] = &node->zoom; - subjects[3] = &node->x; - subjects[4] = &node->y; - - subject.count = 5; - subject.data = subjects; - - menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_SUBJECT, &subject); - file_list_free_userdata(list, i); } } @@ -3747,30 +3854,13 @@ static void xmb_list_clear(file_list_t *list) static void xmb_list_deep_copy(const file_list_t *src, file_list_t *dst) { size_t i; - size_t size = dst->size; + menu_animation_ctx_tag tag = (uintptr_t)dst; + size_t size = dst->size; + + menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); for (i = 0; i < size; ++i) { - xmb_node_t *node = (xmb_node_t*) - menu_entries_get_userdata_at_offset(dst, i); - - if (node) - { - menu_animation_ctx_subject_t subject; - float *subjects[5]; - - subjects[0] = &node->alpha; - subjects[1] = &node->label_alpha; - subjects[2] = &node->zoom; - subjects[3] = &node->x; - subjects[4] = &node->y; - - subject.count = 5; - subject.data = subjects; - - menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_SUBJECT, &subject); - } - file_list_free_userdata(dst, i); file_list_free_actiondata(dst, i); /* this one was allocated by us */ } @@ -3785,15 +3875,11 @@ static void xmb_list_deep_copy(const file_list_t *src, file_list_t *dst) void *src_adata = (void*)menu_entries_get_actiondata_at_offset(src, i); if (src_udata) - { - void *data = calloc(1, sizeof(xmb_node_t)); - memcpy(data, src_udata, sizeof(xmb_node_t)); - file_list_set_userdata(dst, i, data); - } + file_list_set_userdata(dst, i, xmb_copy_node(src_udata)); if (src_adata) { - void *data = calloc(1, sizeof(menu_file_list_cbs_t)); + void *data = malloc(sizeof(menu_file_list_cbs_t)); memcpy(data, src_adata, sizeof(menu_file_list_cbs_t)); file_list_set_actiondata(dst, i, data); } @@ -3807,12 +3893,18 @@ static void xmb_list_cache(void *data, enum menu_list_type type, unsigned action file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); size_t selection = menu_navigation_get_selection(); + settings_t *settings = config_get_ptr(); if (!xmb) return; - xmb_list_deep_copy(selection_buf, xmb->selection_buf_old); - xmb_list_deep_copy(menu_stack, xmb->menu_stack_old); + /* Check whether to enable the horizontal animation. */ + if (settings->bools.menu_horizontal_animation) + { + xmb_list_deep_copy(selection_buf, xmb->selection_buf_old); + xmb_list_deep_copy(menu_stack, xmb->menu_stack_old); + } + xmb->selection_ptr_old = selection; list_size = xmb_list_get_size(xmb, MENU_LIST_HORIZONTAL) @@ -3895,6 +3987,12 @@ static void xmb_list_cache(void *data, enum menu_list_type type, unsigned action menu_stack->list[stack_size - 1].type = MENU_HISTORY_TAB; break; + case XMB_SYSTEM_TAB_FAVORITES: + menu_stack->list[stack_size - 1].label = + strdup(msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)); + menu_stack->list[stack_size - 1].type = + MENU_FAVORITES_TAB; + break; #ifdef HAVE_NETWORKING case XMB_SYSTEM_TAB_NETPLAY: menu_stack->list[stack_size - 1].label = @@ -3971,8 +4069,7 @@ static void xmb_toggle(void *userdata, bool menu_on) entry.tag = -1; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); tmp = !menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL); @@ -4024,10 +4121,56 @@ static int xmb_list_push(void *data, void *userdata, { menu_displaylist_ctx_parse_entry_t entry; int ret = -1; - menu_handle_t *menu = (menu_handle_t*)data; + core_info_list_t *list = NULL; + menu_handle_t *menu = (menu_handle_t*)data; switch (type) { + case DISPLAYLIST_LOAD_CONTENT_LIST: + { + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), + MENU_ENUM_LABEL_FAVORITES, + MENU_SETTING_ACTION, 0, 0); + + core_info_get_list(&list); + if (core_info_list_num_info_files(list)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), + MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, + MENU_SETTING_ACTION, 0, 0); + } + +#ifdef HAVE_LIBRETRODB + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST), + MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST, + MENU_SETTING_ACTION, 0, 0); +#endif + + if (frontend_driver_parse_drive_list(info->list, true) != 0) + menu_entries_append_enum(info->list, "/", + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, + MENU_SETTING_ACTION, 0, 0); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), + MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, + MENU_SETTING_ACTION, 0, 0); + + info->need_push = true; + info->need_refresh = true; + ret = 0; + } + break; case DISPLAYLIST_MAIN_MENU: { rarch_system_info_t *system = runloop_get_system_info(); @@ -4066,10 +4209,6 @@ static int xmb_list_push(void *data, void *userdata, entry.enum_idx = MENU_ENUM_LABEL_ADD_CONTENT_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); #if defined(HAVE_NETWORKING) -#ifdef HAVE_LAKKA - entry.enum_idx = MENU_ENUM_LABEL_UPDATE_LAKKA; - menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); -#else { settings_t *settings = config_get_ptr(); if (settings->bools.menu_show_online_updater) @@ -4078,7 +4217,6 @@ static int xmb_list_push(void *data, void *userdata, menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); } } -#endif #endif entry.enum_idx = MENU_ENUM_LABEL_INFORMATION_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); diff --git a/menu/drivers/zarch.c b/menu/drivers/zarch.c index 11f97aaa3d..2417e35e43 100644 --- a/menu/drivers/zarch.c +++ b/menu/drivers/zarch.c @@ -976,7 +976,9 @@ static void zarch_frame(void *data, video_frame_info_t *video_info) menu_display_blend_begin(); draw.x = 0; draw.y = 0; - menu_display_draw_bg(&draw, video_info, false); + + menu_display_draw_bg(&draw, video_info, false, + video_info->menu_wallpaper_opacity); menu_display_draw(&draw); menu_display_blend_end(); diff --git a/menu/drivers_display/menu_display_vulkan.c b/menu/drivers_display/menu_display_vulkan.c index 5b7577b088..e95353ef33 100644 --- a/menu/drivers_display/menu_display_vulkan.c +++ b/menu/drivers_display/menu_display_vulkan.c @@ -254,19 +254,20 @@ static void menu_display_vk_draw(void *data) default: { - const struct vk_draw_triangles call = { - vk->display.pipelines[ - to_display_pipeline(draw->prim_type, vk->display.blend)], - texture, - texture->mipmap ? - vk->samplers.mipmap_linear : - (texture->default_smooth ? vk->samplers.linear : vk->samplers.nearest), - draw->matrix_data - ? draw->matrix_data : menu_display_vk_get_default_mvp(), - sizeof(math_matrix_4x4), - &range, - draw->coords->vertices, - }; + struct vk_draw_triangles call; + + call.pipeline = vk->display.pipelines[ + to_display_pipeline(draw->prim_type, vk->display.blend)]; + call.texture = texture; + call.sampler = texture->mipmap ? + vk->samplers.mipmap_linear : + (texture->default_smooth ? vk->samplers.linear : vk->samplers.nearest); + call.uniform = draw->matrix_data + ? draw->matrix_data : menu_display_vk_get_default_mvp(); + call.uniform_size = sizeof(math_matrix_4x4); + call.vbo = ⦥ + call.vertices = draw->coords->vertices; + vulkan_draw_triangles(vk, &call); break; } diff --git a/menu/menu_animation.c b/menu/menu_animation.c index 47acd52d29..ce6cfa17dc 100644 --- a/menu/menu_animation.c +++ b/menu/menu_animation.c @@ -36,7 +36,7 @@ struct tween float initial_value; float target_value; float *subject; - int tag; + uintptr_t tag; easing_cb easing; tween_cb cb; }; @@ -44,6 +44,7 @@ struct tween struct menu_animation { struct tween *list; + bool need_defrag; size_t capacity; size_t size; @@ -459,9 +460,38 @@ bool menu_animation_push(menu_animation_ctx_entry_t *entry) *target = t; + anim.need_defrag = true; + return true; } +static int menu_animation_defrag_cmp(const void *a, const void *b) +{ + const struct tween *ta = (const struct tween *)a; + const struct tween *tb = (const struct tween *)b; + + return tb->alive - ta->alive; +} + +/* defragments and shrinks the tween list when possible */ +static void menu_animation_defrag() +{ + size_t i; + + qsort(anim.list, anim.size, sizeof(anim.list[0]), menu_animation_defrag_cmp); + + for (i = anim.size-1; i > 0; i--) + { + if (anim.list[i].alive) + break; + + anim.size--; + } + + anim.first_dead = anim.size; + anim.need_defrag = false; +} + bool menu_animation_update(float delta_time) { unsigned i; @@ -485,9 +515,7 @@ bool menu_animation_update(float delta_time) { *tween->subject = tween->target_value; tween->alive = false; - - if (i < anim.first_dead) - anim.first_dead = i; + anim.need_defrag = true; if (tween->cb) tween->cb(); @@ -497,13 +525,18 @@ bool menu_animation_update(float delta_time) active_tweens += 1; } + if (anim.need_defrag) + menu_animation_defrag(); + if (!active_tweens) { anim.size = 0; anim.first_dead = 0; + anim.need_defrag = false; return false; } + animation_is_active = true; return true; @@ -622,14 +655,14 @@ bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data) case MENU_ANIMATION_CTL_KILL_BY_TAG: { unsigned i; - menu_animation_ctx_tag_t *tag = (menu_animation_ctx_tag_t*)data; + menu_animation_ctx_tag *tag = (menu_animation_ctx_tag*)data; - if (!tag || tag->id == -1) + if (!tag || *tag == (uintptr_t)-1) return false; for (i = 0; i < anim.size; ++i) { - if (anim.list[i].tag != tag->id) + if (anim.list[i].tag != *tag) continue; anim.list[i].alive = false; @@ -637,6 +670,8 @@ bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data) if (i < anim.first_dead) anim.first_dead = i; + + anim.need_defrag = true; } } break; @@ -647,7 +682,7 @@ bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data) (menu_animation_ctx_subject_t*)data; float **sub = (float**)subject->data; - for (i = 0; i < anim.size; ++i) + for (i = 0; i < anim.size && killed < subject->count; ++i) { if (!anim.list[i].alive) continue; @@ -664,6 +699,7 @@ bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data) anim.first_dead = i; killed++; + anim.need_defrag = true; break; } } diff --git a/menu/menu_animation.h b/menu/menu_animation.h index 49d154d305..e4a0e6e4d9 100644 --- a/menu/menu_animation.h +++ b/menu/menu_animation.h @@ -82,7 +82,9 @@ enum menu_animation_easing_type EASING_IN_BOUNCE, EASING_OUT_BOUNCE, EASING_IN_OUT_BOUNCE, - EASING_OUT_IN_BOUNCE + EASING_OUT_IN_BOUNCE, + + EASING_LAST }; typedef struct menu_animation_ctx_delta @@ -91,10 +93,7 @@ typedef struct menu_animation_ctx_delta float ideal; } menu_animation_ctx_delta_t; -typedef struct menu_animation_ctx_tag -{ - int id; -} menu_animation_ctx_tag_t; +typedef uintptr_t menu_animation_ctx_tag; typedef struct menu_animation_ctx_subject { @@ -108,7 +107,7 @@ typedef struct menu_animation_ctx_entry float target_value; float *subject; enum menu_animation_easing_type easing_enum; - int tag; + uintptr_t tag; tween_cb cb; } menu_animation_ctx_entry_t; diff --git a/menu/menu_cbs.c b/menu/menu_cbs.c index d8a833fb9a..7c7005660e 100644 --- a/menu/menu_cbs.c +++ b/menu/menu_cbs.c @@ -32,6 +32,30 @@ static void menu_cbs_init_log(const char *entry_label, const char *bind_label, c #endif } +/* This sets up all the callback functions for a menu entry. + * + * OK : When we press the 'OK' button on an entry. + * Cancel : When we press the 'Cancel' button on an entry. + * Scan : When we press the 'Scan' button on an entry. + * Start : When we press the 'Start' button on an entry. + * Select : When we press the 'Select' button on an entry. + * Info : When we press the 'Info' button on an entry. + * Content Switch : ??? (TODO/FIXME - Kivutar should document this) + * Up : when we press 'Up' on the D-pad while this entry is selected. + * Down : when we press 'Down' on the D-pad while this entry is selected. + * Left : when we press 'Left' on the D-pad while this entry is selected. + * Right : when we press 'Right' on the D-pad while this entry is selected. + * Deferred push : When pressing an entry results in spawning a new list, it waits until the next + * frame to push this onto the stack. This function callback will then be invoked. + * Refresh : What happens when the screen has to be refreshed. Does an entry have internal state + * that needs to be rebuild? + * Get value: Each entry has associated 'text', which we call the value. This function callback + * lets us render that text. + * Get title: Each entry can have a custom 'title'. + * Label: Each entry has a label name. This function callback lets us render that label text. + * Sublabel: each entry has a sublabel, which consists of one or more lines of additional information. + * This function callback lets us render that text. + */ void menu_cbs_init(void *data, menu_file_list_cbs_t *cbs, const char *path, const char *label, @@ -66,70 +90,104 @@ void menu_cbs_init(void *data, RARCH_LOG("\t\t\tenum_idx %d [%s]\n", cbs->enum_idx, msg_hash_to_str(cbs->enum_idx)); #endif + /* It will try to find a corresponding callback function inside + * menu_cbs_ok.c, then map this callback to the entry. */ menu_cbs_init_bind_ok(cbs, path, label, type, idx, label_hash, menu_label_hash); menu_cbs_init_log(repr_label, "OK", cbs->action_ok_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_cancel.c, then map this callback to the entry. */ menu_cbs_init_bind_cancel(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "CANCEL", cbs->action_cancel_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_scan.c, then map this callback to the entry. */ menu_cbs_init_bind_scan(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "SCAN", cbs->action_scan_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_start.c, then map this callback to the entry. */ menu_cbs_init_bind_start(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "START", cbs->action_start_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_select.c, then map this callback to the entry. */ menu_cbs_init_bind_select(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "SELECT", cbs->action_select_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_info.c, then map this callback to the entry. */ menu_cbs_init_bind_info(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "INFO", cbs->action_info_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_bind_content_list_switch.c, then map this callback to the entry. */ menu_cbs_init_bind_content_list_switch(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "CONTENT SWITCH", cbs->action_content_list_switch_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_up.c, then map this callback to the entry. */ menu_cbs_init_bind_up(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "UP", cbs->action_up_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_down.c, then map this callback to the entry. */ menu_cbs_init_bind_down(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "DOWN", cbs->action_down_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_left.c, then map this callback to the entry. */ menu_cbs_init_bind_left(cbs, path, label, type, idx, menu_label, label_hash); menu_cbs_init_log(repr_label, "LEFT", cbs->action_left_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_right.c, then map this callback to the entry. */ menu_cbs_init_bind_right(cbs, path, label, type, idx, menu_label, label_hash); menu_cbs_init_log(repr_label, "RIGHT", cbs->action_right_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_deferred_push.c, then map this callback to the entry. */ menu_cbs_init_bind_deferred_push(cbs, path, label, type, idx, label_hash); menu_cbs_init_log(repr_label, "DEFERRED PUSH", cbs->action_deferred_push_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_refresh.c, then map this callback to the entry. */ menu_cbs_init_bind_refresh(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "REFRESH", cbs->action_refresh_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_get_string_representation.c, then map this callback to the entry. */ menu_cbs_init_bind_get_string_representation(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "GET VALUE", cbs->action_get_value_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_title.c, then map this callback to the entry. */ menu_cbs_init_bind_title(cbs, path, label, type, idx, label_hash); menu_cbs_init_log(repr_label, "GET TITLE", cbs->action_get_title_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_label.c, then map this callback to the entry. */ menu_cbs_init_bind_label(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "LABEL", cbs->action_label_ident); + /* It will try to find a corresponding callback function inside + * menu_cbs_sublabel.c, then map this callback to the entry. */ menu_cbs_init_bind_sublabel(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "SUBLABEL", cbs->action_sublabel_ident); @@ -144,6 +202,7 @@ void menu_cbs_init(void *data, menu_driver_ctl(RARCH_MENU_CTL_BIND_INIT, &bind_info); } +/* Pretty much a stub function. TODO/FIXME - Might as well remove this. */ int menu_cbs_exit(void) { return -1; diff --git a/menu/menu_cbs.h b/menu/menu_cbs.h index 8b21bd53ae..bf83ea49de 100644 --- a/menu/menu_cbs.h +++ b/menu/menu_cbs.h @@ -41,10 +41,15 @@ enum ACTION_OK_DL_RDB_ENTRY_SUBMENU, ACTION_OK_DL_AUDIO_DSP_PLUGIN, ACTION_OK_DL_SHADER_PASS, + ACTION_OK_DL_FAVORITES_LIST, + ACTION_OK_DL_IMAGES_LIST, + ACTION_OK_DL_VIDEO_LIST, + ACTION_OK_DL_MUSIC_LIST, ACTION_OK_DL_SHADER_PARAMETERS, ACTION_OK_DL_SHADER_PRESET, ACTION_OK_DL_GENERIC, ACTION_OK_DL_PUSH_DEFAULT, + ACTION_OK_DL_FILE_BROWSER_SELECT_FILE, ACTION_OK_DL_FILE_BROWSER_SELECT_DIR, ACTION_OK_DL_INPUT_SETTINGS_LIST, ACTION_OK_DL_DRIVER_SETTINGS_LIST, @@ -221,6 +226,30 @@ int action_scan_file(const char *path, int bind_right_generic(unsigned type, const char *label, bool wraparound); +/* This sets up all the callback functions for a menu entry. + * + * OK : When we press the 'OK' button on an entry. + * Cancel : When we press the 'Cancel' button on an entry. + * Scan : When we press the 'Scan' button on an entry. + * Start : When we press the 'Start' button on an entry. + * Select : When we press the 'Select' button on an entry. + * Info : When we press the 'Info' button on an entry. + * Content Switch : ??? (TODO/FIXME - Kivutar should document this) + * Up : when we press 'Up' on the D-pad while this entry is selected. + * Down : when we press 'Down' on the D-pad while this entry is selected. + * Left : when we press 'Left' on the D-pad while this entry is selected. + * Right : when we press 'Right' on the D-pad while this entry is selected. + * Deferred push : When pressing an entry results in spawning a new list, it waits until the next + * frame to push this onto the stack. This function callback will then be invoked. + * Refresh : What happens when the screen has to be refreshed. Does an entry have internal state + * that needs to be rebuild? + * Get value: Each entry has associated 'text', which we call the value. This function callback + * lets us render that text. + * Get title: Each entry can have a custom 'title'. + * Label: Each entry has a label name. This function callback lets us render that label text. + * Sublabel: each entry has a sublabel, which consists of one or more lines of additional information. + * This function callback lets us render that text. + */ void menu_cbs_init(void *data, menu_file_list_cbs_t *cbs, const char *path, const char *label, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index abf2006c1c..9a29b03239 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -1,6 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2015-2017 - Andrés Suárez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -176,7 +177,9 @@ finish: state->path, sizeof(parent_dir)); strlcat(parent_dir, file_path_str(FILE_PATH_INDEX_DIRS_URL), sizeof(parent_dir)); - transf = (menu_file_transfer_t*)calloc(1, sizeof(*transf)); + transf = (menu_file_transfer_t*)malloc(sizeof(*transf)); + + transf->enum_idx = MSG_UNKNOWN; strlcpy(transf->path, parent_dir, sizeof(transf->path)); task_push_http_transfer(parent_dir, true, "index_dirs", cb_net_generic_subdir, transf); @@ -297,7 +300,7 @@ static void print_buf_lines(file_list_t *list, char *buf, sizeof(core_path)); if ( - path_file_exists(core_path) + path_file_exists(core_path) && core_info_get_display_name( core_path, display_name, sizeof(display_name))) menu_entries_set_alt_at_offset(list, j, display_name); @@ -397,6 +400,12 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info) msg_hash_to_str(MENU_ENUM_LABEL_NO_CORE_INFORMATION_AVAILABLE), MENU_ENUM_LABEL_NO_CORE_INFORMATION_AVAILABLE, 0, 0, 0); + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_DELETE), + msg_hash_to_str(MENU_ENUM_LABEL_CORE_DELETE), + MENU_ENUM_LABEL_CORE_DELETE, + MENU_SETTING_ACTION_CORE_DELETE, 0, 0); + return 0; } @@ -558,6 +567,12 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info) } } + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_DELETE), + msg_hash_to_str(MENU_ENUM_LABEL_CORE_DELETE), + MENU_ENUM_LABEL_CORE_DELETE, + MENU_SETTING_ACTION_CORE_DELETE, 0, 0); + return 0; } @@ -1843,7 +1858,7 @@ static int menu_displaylist_parse_database_entry(menu_displaylist_info_t *info) strlcpy(thumbnail_content, db_info_entry->name, sizeof(thumbnail_content)); if (!string_is_empty(thumbnail_content)) - menu_driver_set_thumbnail_content(thumbnail_content, sizeof(thumbnail_content)); + menu_driver_set_thumbnail_content(thumbnail_content, sizeof(thumbnail_content)); menu_driver_ctl(RARCH_MENU_CTL_UPDATE_THUMBNAIL_PATH, NULL); menu_driver_ctl(RARCH_MENU_CTL_UPDATE_THUMBNAIL_IMAGE, NULL); @@ -2688,6 +2703,19 @@ static int menu_displaylist_parse_settings_enum(void *data, ); } +static void menu_displaylist_set_new_playlist( + menu_handle_t *menu, const char *path) +{ + menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_FREE, NULL); + menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_INIT, + (void*)path); + strlcpy( + menu->db_playlist_file, + path, + sizeof(menu->db_playlist_file)); +} + + static int menu_displaylist_parse_horizontal_list( menu_displaylist_info_t *info) { @@ -2723,8 +2751,6 @@ static int menu_displaylist_parse_horizontal_list( fill_pathname_base_noext(lpl_basename, item->path, sizeof(lpl_basename)); - menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_FREE, NULL); - fill_pathname_join( path_playlist, settings->paths.directory_playlist, @@ -2733,10 +2759,8 @@ static int menu_displaylist_parse_horizontal_list( menu_driver_set_thumbnail_system(lpl_basename, sizeof(lpl_basename)); - menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_INIT, (void*)path_playlist); + menu_displaylist_set_new_playlist(menu, path_playlist); - strlcpy(menu->db_playlist_file, - path_playlist, sizeof(menu->db_playlist_file)); strlcpy(path_playlist, msg_hash_to_str(MENU_ENUM_LABEL_COLLECTION), sizeof(path_playlist)); @@ -2772,6 +2796,25 @@ static int menu_displaylist_parse_load_content_settings( #endif rarch_system_info_t *system = runloop_get_system_info(); +#if 0 + const struct retro_subsystem_info* subsystem = system ? system->subsystem.data : NULL; + + if (subsystem) + { + unsigned p; + + for (p = 0; p < system->subsystem.size; p++, subsystem++) + { + char s[PATH_MAX_LENGTH]; + snprintf(s, sizeof(s), "%s (%s)", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST), subsystem->desc); + menu_entries_append_enum(info->list, + s, + msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL), + MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL, + MENU_SETTING_ACTION, 0, 0); + } + } +#endif menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT), msg_hash_to_str(MENU_ENUM_LABEL_RESUME_CONTENT), @@ -2829,6 +2872,11 @@ static int menu_displaylist_parse_load_content_settings( MENU_ENUM_LABEL_UNDO_SAVE_STATE, MENU_SETTING_ACTION_LOADSTATE, 0, 0); + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_ADD_TO_FAVORITES), + MENU_ENUM_LABEL_ADD_TO_FAVORITES, FILE_TYPE_PLAYLIST_ENTRY, 0, 0); + menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS), msg_hash_to_str(MENU_ENUM_LABEL_CORE_OPTIONS), @@ -2859,7 +2907,7 @@ static int menu_displaylist_parse_load_content_settings( MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS, MENU_SETTING_ACTION, 0, 0); if ( (!rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) - && system && system->disk_control_cb.get_num_images) + && system->disk_control_cb.get_num_images) menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS), msg_hash_to_str(MENU_ENUM_LABEL_DISK_OPTIONS), @@ -2945,7 +2993,7 @@ static int menu_displaylist_parse_horizontal_content_actions( else { const char *ext = NULL; - + if (!string_is_empty(entry_path)) ext = path_get_extension(entry_path); @@ -2963,8 +3011,13 @@ static int menu_displaylist_parse_horizontal_content_actions( msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN), msg_hash_to_str(MENU_ENUM_LABEL_RUN), MENU_ENUM_LABEL_RUN, FILE_TYPE_PLAYLIST_ENTRY, 0, idx); - - if (settings->bools.playlist_entry_remove) + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME), + msg_hash_to_str(MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME), + MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, FILE_TYPE_PLAYLIST_ENTRY, 0, idx); + + if (settings->bools.playlist_entry_remove) menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY), msg_hash_to_str(MENU_ENUM_LABEL_DELETE_ENTRY), @@ -3146,6 +3199,23 @@ static int menu_displaylist_parse_netplay_room_list( static int menu_displaylist_parse_options( menu_displaylist_info_t *info) { +#ifdef HAVE_LAKKA + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA), + msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_LAKKA), + MENU_ENUM_LABEL_UPDATE_LAKKA, + MENU_SETTING_ACTION, 0, 0); + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST), + MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST, + MENU_SETTING_ACTION, 0, 0); + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS), + MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS, + MENU_SETTING_ACTION, 0, 0); +#else #ifdef HAVE_NETWORKING settings_t *settings = config_get_ptr(); @@ -3243,6 +3313,7 @@ static int menu_displaylist_parse_options( msg_hash_to_str(MENU_ENUM_LABEL_NO_ITEMS), MENU_ENUM_LABEL_NO_ITEMS, MENU_SETTING_NO_ITEM, 0, 0); +#endif #endif return 0; @@ -3341,6 +3412,24 @@ static int menu_displaylist_parse_options_remappings( MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME, MENU_SETTING_ACTION, 0, 0); + if (rarch_ctl(RARCH_CTL_IS_REMAPS_CORE_ACTIVE, NULL)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE), + msg_hash_to_str(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE), + MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE, + MENU_SETTING_ACTION, 0, 0); + } + + if (rarch_ctl(RARCH_CTL_IS_REMAPS_GAME_ACTIVE, NULL)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME), + msg_hash_to_str(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME), + MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME, + MENU_SETTING_ACTION, 0, 0); + } + system = runloop_get_system_info(); if (system) @@ -3408,9 +3497,9 @@ static int menu_displaylist_parse_playlists( list_size = str_list->size; -#ifdef HAVE_LIBRETRODB if (!horizontal) { +#ifdef HAVE_LIBRETRODB menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY), msg_hash_to_str(MENU_ENUM_LABEL_SCAN_DIRECTORY), @@ -3421,8 +3510,33 @@ static int menu_displaylist_parse_playlists( msg_hash_to_str(MENU_ENUM_LABEL_SCAN_FILE), MENU_ENUM_LABEL_SCAN_FILE, MENU_SETTING_ACTION, 0, 0); - } #endif + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES), + MENU_ENUM_LABEL_GOTO_FAVORITES, + MENU_SETTING_ACTION, 0, 0); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_IMAGES), + MENU_ENUM_LABEL_GOTO_IMAGES, + MENU_SETTING_ACTION, 0, 0); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_MUSIC), + MENU_ENUM_LABEL_GOTO_MUSIC, + MENU_SETTING_ACTION, 0, 0); + +#ifdef HAVE_FFMPEG + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_VIDEO), + MENU_ENUM_LABEL_GOTO_VIDEO, + MENU_SETTING_ACTION, 0, 0); +#endif + } if (list_size == 0) { @@ -3765,6 +3879,11 @@ static bool menu_displaylist_push_internal( if (menu_displaylist_ctl(DISPLAYLIST_HISTORY, info)) return true; } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB))) + { + if (menu_displaylist_ctl(DISPLAYLIST_FAVORITES, info)) + return true; + } else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SETTINGS_TAB))) { if (menu_displaylist_ctl(DISPLAYLIST_SETTINGS_ALL, info)) @@ -3937,28 +4056,22 @@ bool menu_displaylist_push(menu_displaylist_ctx_entry_t *entry) static void menu_displaylist_parse_playlist_history( menu_handle_t *menu, menu_displaylist_info_t *info, - playlist_t *playlist, const char *playlist_name, const char *playlist_path, int *ret) { char path_playlist[PATH_MAX_LENGTH]; + playlist_t *playlist = NULL; path_playlist[0] = '\0'; - if (!playlist) - command_event(CMD_EVENT_HISTORY_INIT, NULL); + menu_displaylist_set_new_playlist(menu, playlist_path); + + menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_GET, &playlist); strlcpy(path_playlist, playlist_name, sizeof(path_playlist)); *ret = menu_displaylist_parse_playlist(info, playlist, path_playlist, true); - strlcpy( - menu->db_playlist_file, - playlist_path, - sizeof(menu->db_playlist_file)); - menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_FREE, NULL); - menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_INIT, - (void*)menu->db_playlist_file); } #ifdef HAVE_NETWORKING @@ -4005,7 +4118,9 @@ static void wifi_scan_callback(void *task_data, bool menu_displaylist_process(menu_displaylist_info_t *info) { size_t idx = 0; +#if defined(HAVE_NETWORKING) settings_t *settings = config_get_ptr(); +#endif if (info->need_navigation_clear) { @@ -4022,7 +4137,7 @@ bool menu_displaylist_process(menu_displaylist_info_t *info) if (info->need_sort) file_list_sort_on_alt(info->list); -#if defined(HAVE_NETWORKING) && !defined(HAVE_LAKKA) +#if defined(HAVE_NETWORKING) if (settings->bools.menu_show_core_updater) if (info->download_core) { @@ -4033,7 +4148,7 @@ bool menu_displaylist_process(menu_displaylist_info_t *info) MENU_SETTING_ACTION, 0, 0); } #endif - + if (info->push_builtin_cores) { #if defined(HAVE_VIDEO_PROCESSOR) @@ -4290,6 +4405,12 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) return menu_displaylist_process(info); return false; } + else if (string_is_equal(info->path, file_path_str(FILE_PATH_CONTENT_FAVORITES))) + { + if (menu_displaylist_ctl(DISPLAYLIST_FAVORITES, info)) + return menu_displaylist_process(info); + return false; + } else { char path_playlist[PATH_MAX_LENGTH]; @@ -4297,7 +4418,6 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) path_playlist[0] = '\0'; - menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_FREE, NULL); fill_pathname_join( path_playlist, @@ -4305,11 +4425,8 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) info->path, sizeof(path_playlist)); - menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_INIT, - (void*)path_playlist); + menu_displaylist_set_new_playlist(menu, path_playlist); - strlcpy(menu->db_playlist_file, path_playlist, - sizeof(menu->db_playlist_file)); strlcpy(path_playlist, msg_hash_to_str(MENU_ENUM_LABEL_COLLECTION), sizeof(path_playlist)); @@ -4333,7 +4450,6 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); if (settings->bools.history_list_enable) menu_displaylist_parse_playlist_history(menu, info, - g_defaults.content_history, "history", settings->paths.path_content_history, &ret); @@ -4353,10 +4469,21 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) info->need_push = true; } break; + case DISPLAYLIST_FAVORITES: + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + menu_displaylist_parse_playlist_history(menu, info, + "favorites", + settings->paths.path_content_favorites, + &ret); + if (ret == 0) + { + info->need_refresh = true; + info->need_push = true; + } + break; case DISPLAYLIST_MUSIC_HISTORY: if (settings->bools.history_list_enable) menu_displaylist_parse_playlist_history(menu, info, - g_defaults.music_history, "music_history", settings->paths.path_content_music_history, &ret); @@ -4380,7 +4507,6 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) #ifdef HAVE_FFMPEG if (settings->bools.history_list_enable) menu_displaylist_parse_playlist_history(menu, info, - g_defaults.video_history, "video_history", settings->paths.path_content_video_history, &ret); @@ -4747,7 +4873,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) PARSE_ONLY_UINT, false); ret = menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_PLAYLIST_ENTRY_REMOVE, - PARSE_ONLY_BOOL, false); + PARSE_ONLY_BOOL, false); menu_displaylist_parse_playlist_associations(info); info->need_push = true; @@ -4849,6 +4975,18 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); info->need_refresh = true; info->need_push = true; @@ -4943,6 +5081,12 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + PARSE_ONLY_UINT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_OVERLAY_PRESET, PARSE_ONLY_PATH, false); @@ -4976,15 +5120,22 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) case DISPLAYLIST_MENU_VIEWS_SETTINGS_LIST: menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); +#if defined(HAVE_NETWORKING) && !defined(HAVE_LAKKA) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_CORE_UPDATER, PARSE_ONLY_BOOL, false); +#endif menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_XMB_SHOW_SETTINGS, PARSE_ONLY_BOOL, false); + + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_XMB_SHOW_FAVORITES, + PARSE_ONLY_BOOL, false); + #ifdef HAVE_IMAGEVIEWER menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_XMB_SHOW_IMAGES, @@ -5020,6 +5171,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_CORE_ENABLE, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_RGUI_SHOW_START_SCREEN, + PARSE_ONLY_BOOL, false); info->need_refresh = true; info->need_push = true; @@ -5037,19 +5191,13 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) MENU_ENUM_LABEL_MENU_WALLPAPER_OPACITY, PARSE_ONLY_FLOAT, false); menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_PAUSE_LIBRETRO, - PARSE_ONLY_BOOL, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_MOUSE_ENABLE, - PARSE_ONLY_BOOL, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_POINTER_ENABLE, - PARSE_ONLY_BOOL, false); + MENU_ENUM_LABEL_MENU_FRAMEBUFFER_OPACITY, + PARSE_ONLY_FLOAT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_LINEAR_FILTER, PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_NAVIGATION_WRAPAROUND, + MENU_ENUM_LABEL_MENU_HORIZONTAL_ANIMATION, PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_ENTRY_NORMAL_COLOR, @@ -5087,6 +5235,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_XMB_MENU_COLOR_THEME, PARSE_ONLY_UINT, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_MATERIALUI_ICONS_ENABLE, + PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MATERIALUI_MENU_COLOR_THEME, PARSE_ONLY_UINT, false); @@ -5096,9 +5247,6 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MATERIALUI_MENU_FOOTER_OPACITY, PARSE_ONLY_FLOAT, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_RGUI_SHOW_START_SCREEN, - PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_THUMBNAILS, PARSE_ONLY_UINT, false); @@ -5116,6 +5264,18 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SHOW_ADVANCED_SETTINGS, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_NAVIGATION_WRAPAROUND, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_PAUSE_LIBRETRO, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_MOUSE_ENABLE, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_POINTER_ENABLE, + PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_THREADED_DATA_RUNLOOP_ENABLE, PARSE_ONLY_BOOL, false); @@ -5872,7 +6032,35 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) info->need_refresh = true; break; case DISPLAYLIST_LOAD_CONTENT_LIST: + case DISPLAYLIST_LOAD_CONTENT_SPECIAL: menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES), + MENU_ENUM_LABEL_GOTO_FAVORITES, + MENU_SETTING_ACTION, 0, 0); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_IMAGES), + MENU_ENUM_LABEL_GOTO_IMAGES, + MENU_SETTING_ACTION, 0, 0); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_MUSIC), + MENU_ENUM_LABEL_GOTO_MUSIC, + MENU_SETTING_ACTION, 0, 0); + +#ifdef HAVE_FFMPEG + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_VIDEO), + MENU_ENUM_LABEL_GOTO_VIDEO, + MENU_SETTING_ACTION, 0, 0); +#endif + if (!string_is_empty(settings->paths.directory_menu_content)) menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), @@ -6052,16 +6240,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) PARSE_ACTION, false); #endif #if defined(HAVE_NETWORKING) -#ifdef HAVE_LAKKA - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_UPDATE_LAKKA, - PARSE_ACTION, false); -#else if (settings->bools.menu_show_online_updater) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_ONLINE_UPDATER, PARSE_ACTION, false); -#endif #endif menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SETTINGS, PARSE_ACTION, false); @@ -6410,7 +6592,6 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) #ifdef HAVE_IMAGEVIEWER if (settings->bools.history_list_enable) menu_displaylist_parse_playlist_history(menu, info, - g_defaults.image_history, "images_history", settings->paths.path_content_image_history, &ret); diff --git a/menu/menu_displaylist.h b/menu/menu_displaylist.h index 59fa13e046..3a6d4d0664 100644 --- a/menu/menu_displaylist.h +++ b/menu/menu_displaylist.h @@ -61,6 +61,7 @@ enum menu_displaylist_ctl_state DISPLAYLIST_HORIZONTAL, DISPLAYLIST_HORIZONTAL_CONTENT_ACTIONS, DISPLAYLIST_HISTORY, + DISPLAYLIST_FAVORITES, DISPLAYLIST_VIDEO_HISTORY, DISPLAYLIST_MUSIC_HISTORY, DISPLAYLIST_IMAGES_HISTORY, @@ -142,6 +143,7 @@ enum menu_displaylist_ctl_state DISPLAYLIST_BROWSE_URL_LIST, DISPLAYLIST_BROWSE_URL_START, DISPLAYLIST_LOAD_CONTENT_LIST, + DISPLAYLIST_LOAD_CONTENT_SPECIAL, DISPLAYLIST_INFORMATION_LIST, DISPLAYLIST_CONTENT_SETTINGS, DISPLAYLIST_OPTIONS, @@ -165,13 +167,24 @@ enum menu_displaylist_ctl_state typedef struct menu_displaylist_info { + /* should the displaylist be sorted by alphabet? */ bool need_sort; bool need_refresh; bool need_entries_refresh; bool need_push; + + /* should we clear the displaylist before we push + * entries onto it? */ bool need_clear; + bool push_builtin_cores; + + /* Should a 'download core' entry be pushed onto the list? + * This will be set to true in case there are no currently + * installed cores. */ bool download_core; + + /* does the navigation index need to be cleared to 0 (first entry) ? */ bool need_navigation_clear; file_list_t *list; file_list_t *menu_list; diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 2c20a6fd63..3c14267c81 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -60,6 +60,7 @@ #define PARTICLES_COUNT 100 +/* Menu drivers */ static const menu_ctx_driver_t *menu_ctx_drivers[] = { #if defined(HAVE_XUI) &menu_ctx_xui, @@ -83,6 +84,7 @@ static const menu_ctx_driver_t *menu_ctx_drivers[] = { NULL }; +/* Menu display drivers */ static menu_display_ctx_driver_t *menu_display_ctx_drivers[] = { #ifdef HAVE_D3D &menu_display_ctx_d3d, @@ -115,7 +117,6 @@ static menu_display_ctx_driver_t *menu_display_ctx_drivers[] = { NULL, }; - uintptr_t menu_display_white_texture; static video_coord_array_t menu_disp_ca; @@ -123,10 +124,14 @@ static video_coord_array_t menu_disp_ca; static enum menu_toggle_reason menu_display_toggle_reason = MENU_TOGGLE_REASON_NONE; +/* Width, height and pitch of the menu framebuffer */ static unsigned menu_display_framebuf_width = 0; static unsigned menu_display_framebuf_height = 0; static size_t menu_display_framebuf_pitch = 0; + +/* Height of the menu display header */ static unsigned menu_display_header_height = 0; + static bool menu_display_has_windowed = false; static bool menu_display_msg_force = false; static bool menu_display_font_alloc_framebuf = false; @@ -134,15 +139,36 @@ static bool menu_display_framebuf_dirty = false; static const uint8_t *menu_display_font_framebuf = NULL; static menu_display_ctx_driver_t *menu_disp = NULL; +/* when enabled, on next iteration the 'Quick Menu' list will + * be pushed onto the stack */ static bool menu_driver_pending_quick_menu = false; + static bool menu_driver_prevent_populate = false; + +/* Is the menu driver still running? */ static bool menu_driver_alive = false; + +/* A menu toggle has been requested; if the menu was running, + * it will be closed; if the menu was not running, it will be opened */ static bool menu_driver_toggled = false; + +/* The menu driver owns the userdata */ static bool menu_driver_data_own = false; + +/* The user has requested that the menu be shut down. This will + * be enacted upon the next menu iteration */ static bool menu_driver_pending_quit = false; + +/* The user has requested that RetroArch be shut down. This will + * be enacted upon the next menu iteration */ static bool menu_driver_pending_shutdown = false; + +/* Are we binding a button inside the menu? */ static bool menu_driver_is_binding = false; + +/* The currently active playlist that we are using inside the menu */ static playlist_t *menu_driver_playlist = NULL; + static menu_handle_t *menu_driver_data = NULL; static const menu_ctx_driver_t *menu_driver_ctx = NULL; static void *menu_userdata = NULL; @@ -164,6 +190,8 @@ void menu_display_toggle_set_reason(enum menu_toggle_reason reason) menu_display_toggle_reason = reason; } +/* Check if the current menu driver is compatible + * with your video driver. */ static bool menu_display_check_compatibility( enum menu_display_driver_type type, bool video_is_threaded) @@ -220,6 +248,9 @@ static bool menu_display_check_compatibility( return false; } +/* Display the date and time - time_mode will influence how + * the time representation will look like. + * */ void menu_display_timedate(menu_display_ctx_datetime_t *datetime) { time_t time_; @@ -254,23 +285,29 @@ void menu_display_timedate(menu_display_ctx_datetime_t *datetime) } } +/* Begin blending operation */ void menu_display_blend_begin(void) { if (menu_disp && menu_disp->blend_begin) menu_disp->blend_begin(); } +/* End blending operation */ void menu_display_blend_end(void) { if (menu_disp && menu_disp->blend_end) menu_disp->blend_end(); } +/* Teardown; deinitializes and frees all + * fonts associated to the menu driver */ void menu_display_font_free(font_data_t *font) { font_driver_free(font); } +/* Setup: Initializes the font associated + * to the menu driver */ static font_data_t *menu_display_font_main_init( menu_display_ctx_font_t *font, bool is_threaded) @@ -304,6 +341,8 @@ font_data_t *menu_display_font(enum application_special_type type, float font_si return menu_display_font_main_init(&font_info, is_threaded); } +/* Reset the menu's coordinate array vertices. + * NOTE: Not every menu driver uses this. */ void menu_display_coords_array_reset(void) { menu_disp_ca.coords.vertices = 0; @@ -337,6 +376,7 @@ static bool menu_display_libretro_running( return false; } +/* Display the libretro core's framebuffer onscreen. */ bool menu_display_libretro(bool is_idle, bool rarch_is_inited, bool rarch_is_dummy_core) { video_driver_set_texture_enable(true, false); @@ -357,6 +397,7 @@ bool menu_display_libretro(bool is_idle, bool rarch_is_inited, bool rarch_is_dum return video_driver_cached_frame(); } +/* Get the menu framebuffer's size dimensions. */ void menu_display_get_fb_size(unsigned *fb_width, unsigned *fb_height, size_t *fb_pitch) { @@ -365,11 +406,13 @@ void menu_display_get_fb_size(unsigned *fb_width, *fb_pitch = menu_display_framebuf_pitch; } +/* Set the menu framebuffer's width. */ void menu_display_set_width(unsigned width) { menu_display_framebuf_width = width; } +/* Set the menu framebuffer's height. */ void menu_display_set_height(unsigned height) { menu_display_framebuf_height = height; @@ -415,6 +458,14 @@ void menu_display_set_font_data_init(bool state) menu_display_font_alloc_framebuf = state; } +/* Returns true if an animation is still active or + * when the menu framebuffer still is dirty and + * therefore it still needs to be rendered onscreen. + * + * This function can be used for optimization purposes + * so that we don't have to render the menu graphics per-frame + * unless a change has happened. + * */ bool menu_display_get_update_pending(void) { if (menu_animation_is_active() || menu_display_framebuf_dirty) @@ -432,21 +483,29 @@ void menu_display_unset_viewport(unsigned width, unsigned height) video_driver_set_viewport(width, height, false, true); } +/* Checks if the menu framebuffer has its 'dirty flag' set. This + * means that the current contents of the framebuffer has changed + * and that it has to be rendered to the screen. */ bool menu_display_get_framebuffer_dirty_flag(void) { return menu_display_framebuf_dirty; } +/* Set the menu framebuffer's 'dirty flag'. */ void menu_display_set_framebuffer_dirty_flag(void) { menu_display_framebuf_dirty = true; } +/* Unset the menu framebufer's 'dirty flag'. */ void menu_display_unset_framebuffer_dirty_flag(void) { menu_display_framebuf_dirty = false; } +/* Get the preferred DPI at which to render the menu. + * NOTE: Only MaterialUI menu driver so far uses this, neither + * RGUI or XMB use this. */ float menu_display_get_dpi(void) { gfx_ctx_metrics_t metrics; @@ -519,7 +578,8 @@ void menu_display_draw_pipeline(menu_display_ctx_draw_t *draw) } void menu_display_draw_bg(menu_display_ctx_draw_t *draw, - video_frame_info_t *video_info, bool add_opacity_to_wallpaper) + video_frame_info_t *video_info, bool add_opacity_to_wallpaper, + float override_opacity) { static struct video_coords coords; const float *new_vertex = NULL; @@ -547,7 +607,7 @@ void menu_display_draw_bg(menu_display_ctx_draw_t *draw, add_opacity_to_wallpaper = true; if (add_opacity_to_wallpaper) - menu_display_set_alpha(draw->color, video_info->menu_wallpaper_opacity); + menu_display_set_alpha(draw->color, override_opacity); if (!draw->texture) draw->texture = menu_display_white_texture; @@ -562,7 +622,8 @@ void menu_display_draw_gradient(menu_display_ctx_draw_t *draw, draw->x = 0; draw->y = 0; - menu_display_draw_bg(draw, video_info, false); + menu_display_draw_bg(draw, video_info, false, + video_info->menu_wallpaper_opacity); menu_display_draw(draw); } @@ -988,6 +1049,9 @@ void menu_display_handle_savestate_thumbnail_upload(void *task_data, free(user_data); } +/* Function that gets called when we want to load in a + * new menu wallpaper. + */ void menu_display_handle_wallpaper_upload(void *task_data, void *user_data, const char *err) { @@ -1019,6 +1083,9 @@ void menu_display_allocate_white_texture(void) TEXTURE_FILTER_NEAREST, &menu_display_white_texture); } +/* + * Draw a hardware cursor on top of the screen for the mouse. + */ void menu_display_draw_cursor( float *color, float cursor_size, uintptr_t texture, float x, float y, unsigned width, unsigned height) @@ -1177,6 +1244,8 @@ void menu_display_snow(int width, int height) } } +/* Draw text on top of the screen. + */ void menu_display_draw_text( const font_data_t *font, const char *text, float x, float y, int width, int height, @@ -1293,6 +1362,10 @@ const char *config_get_menu_driver_options(void) } #ifdef HAVE_COMPRESSION +/* This function gets called at first startup on Android/iOS + * when we need to extract the APK contents/zip file. This + * file contains assets which then get extracted to the + * user's asset directories. */ static void bundle_decompressed(void *task_data, void *user_data, const char *err) { @@ -1376,6 +1449,11 @@ static bool menu_init(menu_handle_t *menu_data) return true; } +/* This callback gets triggered by the keyboard whenever + * we press or release a keyboard key. When a keyboard + * key is being pressed down, 'down' will be true. If it + * is being released, 'down' will be false. + */ static void menu_input_key_event(bool down, unsigned keycode, uint32_t character, uint16_t mod) { @@ -1391,6 +1469,10 @@ static void menu_input_key_event(bool down, unsigned keycode, menu_event_kb_set(down, (enum retro_key)keycode); } +/* Gets called when we want to toggle the menu. + * If the menu is already running, it will be turned off. + * If the menu is off, then the menu will be started. + */ static void menu_driver_toggle(bool on) { retro_keyboard_event_t *key_event = NULL; @@ -1516,11 +1598,15 @@ bool menu_driver_render(bool is_idle, bool rarch_is_inited, return true; } +/* Checks if the menu is still running */ bool menu_driver_is_alive(void) { return menu_driver_alive; } +/* Checks if the menu framebuffer is set. + * This would usually only return true + * for framebuffer-based menu drivers, like RGUI. */ bool menu_driver_is_texture_set(void) { if (menu_driver_ctx) @@ -1528,8 +1614,13 @@ bool menu_driver_is_texture_set(void) return false; } +/* Iterate the menu driver for one frame. */ bool menu_driver_iterate(menu_ctx_iterate_t *iterate) { + /* If the user had requested that the Quick Menu + * be spawned during the previous frame, do this now + * and exit the function to go to the next frame. + */ if (menu_driver_pending_quick_menu) { menu_driver_pending_quick_menu = false; @@ -1548,12 +1639,18 @@ bool menu_driver_iterate(menu_ctx_iterate_t *iterate) return true; } + /* If the user had requested that the menu + * be shutdown during the previous frame, do + * this now. */ if (menu_driver_pending_quit) { menu_driver_pending_quit = false; return false; } + /* if the user had requested that RetroArch + * be shutdown during the previous frame, do + * this now. */ if (menu_driver_pending_shutdown) { menu_driver_pending_shutdown = false; @@ -1572,6 +1669,7 @@ bool menu_driver_iterate(menu_ctx_iterate_t *iterate) return true; } +/* Clear all the menu lists. */ bool menu_driver_list_clear(void *data) { file_list_t *list = (file_list_t*)data; @@ -1678,6 +1776,7 @@ void menu_driver_set_thumbnail_content(char *s, size_t len) menu_driver_ctx->set_thumbnail_content(menu_userdata, s, len); } +/* Teardown function for the menu driver. */ void menu_driver_destroy(void) { menu_driver_pending_quick_menu = false; @@ -1947,7 +2046,7 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) return false; menu_driver_ctx->list_insert(menu_userdata, list->list, list->path, list->fullpath, - list->label, list->idx); + list->label, list->idx, list->entry_type); } break; case RARCH_MENU_CTL_ENVIRONMENT: diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 08a1ebdff6..3d142e8053 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -139,6 +139,7 @@ enum menu_settings_type MENU_SETTINGS, MENU_SETTINGS_TAB, MENU_HISTORY_TAB, + MENU_FAVORITES_TAB, MENU_MUSIC_TAB, MENU_VIDEO_TAB, MENU_IMAGES_TAB, @@ -161,12 +162,17 @@ enum menu_settings_type MENU_SETTING_ACTION_SCREENSHOT, MENU_SETTING_ACTION_DELETE_ENTRY, MENU_SETTING_ACTION_RESET, + MENU_SETTING_ACTION_CORE_DELETE, MENU_SETTING_STRING_OPTIONS, MENU_SETTING_GROUP, MENU_SETTING_SUBGROUP, MENU_SETTING_HORIZONTAL_MENU, MENU_WIFI, MENU_ROOM, +/* + MENU_ROOM_LAN, + MENU_ROOM_MITM, +*/ MENU_NETPLAY_LAN_SCAN, MENU_INFO_MESSAGE, MENU_SETTINGS_SHADER_PARAMETER_0, @@ -299,16 +305,26 @@ typedef struct menu_display_frame_info typedef struct menu_display_ctx_driver { + /* Draw graphics to the screen. */ void (*draw)(void *data); + /* Draw one of the menu pipeline shaders. */ void (*draw_pipeline)(void *data); void (*viewport)(void *data); + /* Start blending operation. */ void (*blend_begin)(void); + /* Finish blending operation. */ void (*blend_end)(void); + /* Set the clear color back to its default values. */ void (*restore_clear_color)(void); + /* Set the color to be used when clearing the screen */ void (*clear_color)(menu_display_ctx_clearcolor_t *clearcolor); + /* Get the default Model-View-Projection matrix */ void *(*get_default_mvp)(void); + /* Get the default vertices matrix */ const float *(*get_default_vertices)(void); + /* Get the default texture coordinates matrix */ const float *(*get_default_tex_coords)(void); + /* Initialize the first compatible font driver for this menu driver. */ bool (*font_init_first)( void **font_handle, void *video_data, const char *font_path, float font_size, @@ -320,16 +336,22 @@ typedef struct menu_display_ctx_driver typedef struct { + /* Scratchpad variables. These are used for instance + * by the filebrowser when having to store intermediary + * paths (subdirs/previous dirs/current dir/path, etc). + */ char deferred_path[PATH_MAX_LENGTH]; char scratch_buf[PATH_MAX_LENGTH]; char scratch2_buf[PATH_MAX_LENGTH]; uint64_t state; + struct { char msg[1024]; } menu_state; + /* path to the currently loaded database playlist file. */ char db_playlist_file[PATH_MAX_LENGTH]; } menu_handle_t; @@ -386,29 +408,49 @@ typedef struct menu_display_ctx_font typedef struct menu_ctx_driver { + /* Set a framebuffer texture. This is used for instance by RGUI. */ void (*set_texture)(void); + /* Render a messagebox to the screen. */ void (*render_messagebox)(void *data, const char *msg); int (*iterate)(void *data, void *userdata, enum menu_action action); void (*render)(void *data, bool is_idle); void (*frame)(void *data, video_frame_info_t *video_info); + /* Initializes the menu driver. (setup) */ void* (*init)(void**, bool); + /* Frees the menu driver. (teardown) */ void (*free)(void*); + /* This will be invoked when we are running a hardware context + * and we have just flushed the state. For instance - we have + * just toggled fullscreen, the GL driver did a teardown/setup - + * we now need to rebuild all of our textures and state for the + * menu driver. */ void (*context_reset)(void *data, bool video_is_threaded); + /* This will be invoked when we are running a hardware context + * and the context in question wants to tear itself down. All + * textures and related state on the menu driver will also + * be freed up then. */ void (*context_destroy)(void *data); void (*populate_entries)(void *data, const char *path, const char *label, unsigned k); void (*toggle)(void *userdata, bool); + /* This will clear the navigation position. */ void (*navigation_clear)(void *, bool); + /* This will decrement the navigation position by one. */ void (*navigation_decrement)(void *data); + /* This will increment the navigation position by one. */ void (*navigation_increment)(void *data); void (*navigation_set)(void *data, bool); void (*navigation_set_last)(void *data); + /* This will descend the navigation position by one alphabet letter. */ void (*navigation_descend_alphabet)(void *, size_t *); + /* This will ascend the navigation position by one alphabet letter. */ void (*navigation_ascend_alphabet)(void *, size_t *); + /* Initializes a new menu list. */ bool (*lists_init)(void*); void (*list_insert)(void *userdata, - file_list_t *list, const char *, const char *, const char *, size_t); + file_list_t *list, const char *, const char *, const char *, size_t, + unsigned); int (*list_prepend)(void *userdata, file_list_t *list, const char *, const char *, size_t); void (*list_free)(file_list_t *list, size_t, size_t); @@ -421,6 +463,7 @@ typedef struct menu_ctx_driver void (*list_set_selection)(void *data, file_list_t *list); int (*bind_init)(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx); + /* Load an image for use by the menu driver */ bool (*load_image)(void *userdata, void *data, enum menu_image_type type); const char *ident; int (*environ_cb)(enum menu_environ_cb type, void *data, void *userdata); @@ -554,6 +597,8 @@ void menu_driver_set_binding_state(bool on); void menu_driver_frame(video_frame_info_t *video_info); +/* Is a background texture set for the current menu driver? Should + * return true for RGUI, for instance. */ bool menu_driver_is_texture_set(void); bool menu_driver_is_alive(void); @@ -624,7 +669,7 @@ void menu_display_draw_pipeline(menu_display_ctx_draw_t *draw); void menu_display_draw_bg( menu_display_ctx_draw_t *draw, video_frame_info_t *video_info, - bool add_opacity); + bool add_opacity, float opacity_override); void menu_display_draw_gradient( menu_display_ctx_draw_t *draw, video_frame_info_t *video_info); diff --git a/menu/menu_entries.c b/menu/menu_entries.c index 84755f68a3..3a5896748d 100644 --- a/menu/menu_entries.c +++ b/menu/menu_entries.c @@ -383,8 +383,9 @@ void menu_entries_append(file_list_t *list, const char *path, const char *label, if (!string_is_empty(menu_path)) list_info.fullpath = strdup(menu_path); - list_info.label = label; - list_info.idx = idx; + list_info.label = label; + list_info.idx = idx; + list_info.entry_type = type; menu_driver_ctl(RARCH_MENU_CTL_LIST_INSERT, &list_info); @@ -432,6 +433,7 @@ void menu_entries_append_enum(file_list_t *list, const char *path, list_info.path = path; list_info.label = label; list_info.idx = idx; + list_info.entry_type = type; menu_driver_ctl(RARCH_MENU_CTL_LIST_INSERT, &list_info); @@ -448,7 +450,11 @@ void menu_entries_append_enum(file_list_t *list, const char *path, file_list_set_actiondata(list, idx, cbs); cbs->enum_idx = enum_idx; - cbs->setting = menu_setting_find_enum(enum_idx); + + if (enum_idx != MENU_ENUM_LABEL_PLAYLIST_ENTRY + && enum_idx != MENU_ENUM_LABEL_PLAYLIST_COLLECTION_ENTRY) { + cbs->setting = menu_setting_find_enum(enum_idx); + } menu_cbs_init(list, cbs, path, label, type, idx); } @@ -478,6 +484,7 @@ void menu_entries_prepend(file_list_t *list, const char *path, const char *label list_info.path = path; list_info.label = label; list_info.idx = idx; + list_info.entry_type = type; menu_driver_ctl(RARCH_MENU_CTL_LIST_INSERT, &list_info); diff --git a/menu/menu_event.c b/menu/menu_event.c index 7ed183833e..8c5b321bd5 100644 --- a/menu/menu_event.c +++ b/menu/menu_event.c @@ -38,6 +38,10 @@ static unsigned char menu_keyboard_key_state[RETROK_LAST] = {0}; +/* This function gets called for handling pointer events. + * + * Pointer events are touchscreen events that are spawned + * by touchpad/touchscreen. */ static int menu_event_pointer(unsigned *action) { rarch_joypad_info_t joypad_info; @@ -83,16 +87,24 @@ static int menu_event_pointer(unsigned *action) return 0; } +/* Check if a specific keyboard key has been pressed. */ unsigned char menu_event_kb_is_set(enum retro_key key) { return menu_keyboard_key_state[key]; } +/* Set a specific keyboard key latch. */ static void menu_event_kb_set_internal(unsigned idx, unsigned char key) { menu_keyboard_key_state[idx] = key; } +/* Set a specific keyboard key. + * + * 'down' sets the latch (true would + * mean the key is being pressed down, while 'false' would mean that + * the key has been released). + **/ void menu_event_kb_set(bool down, enum retro_key key) { if (key == RETROK_UNKNOWN) @@ -106,6 +118,25 @@ void menu_event_kb_set(bool down, enum retro_key key) menu_event_kb_set_internal(key, ((menu_event_kb_is_set(key) & 1) << 1) | down); } +/* + * This function gets called in order to process all input events + * for the current frame. + * + * Sends input code to menu for one frame. + * + * It uses as input the local variables' input' and 'trigger_input'. + * + * Mouse and touch input events get processed inside this function. + * + * NOTE: 'input' and 'trigger_input' is sourced from the keyboard and/or + * the gamepad. It does not contain input state derived from the mouse + * and/or touch - this gets dealt with separately within this function. + * + * TODO/FIXME - maybe needs to be overhauled so we can send multiple + * events per frame if we want to, and we shouldn't send the + * entire button state either but do a separate event per button + * state. + */ unsigned menu_event(uint64_t input, uint64_t trigger_input) { menu_animation_ctx_delta_t delta; diff --git a/menu/menu_event.h b/menu/menu_event.h index 1ae9041f63..61e9f4b0e3 100644 --- a/menu/menu_event.h +++ b/menu/menu_event.h @@ -25,17 +25,36 @@ RETRO_BEGIN_DECLS -/* Send input code to menu for one frame. +/* + * This function gets called in order to process all input events + * for the current frame. * - * TODO/FIXME - needs to be overhauled so we can send multiple + * Sends input code to menu for one frame. + * + * It uses as input the local variables' input' and 'trigger_input'. + * + * Mouse and touch input events get processed inside this function. + * + * NOTE: 'input' and 'trigger_input' is sourced from the keyboard and/or + * the gamepad. It does not contain input state derived from the mouse + * and/or touch - this gets dealt with separately within this function. + * + * TODO/FIXME - maybe needs to be overhauled so we can send multiple * events per frame if we want to, and we shouldn't send the * entire button state either but do a separate event per button * state. */ unsigned menu_event(uint64_t input, uint64_t trigger_state); +/* Set a specific keyboard key. + * + * 'down' sets the latch (true would + * mean the key is being pressed down, while 'false' would mean that + * the key has been released). + **/ void menu_event_kb_set(bool down, enum retro_key key); +/* Check if a specific keyboard key has been pressed. */ unsigned char menu_event_kb_is_set(enum retro_key key); RETRO_END_DECLS diff --git a/menu/menu_input.c b/menu/menu_input.c index 9e0fec76d0..0405248a79 100644 --- a/menu/menu_input.c +++ b/menu/menu_input.c @@ -443,7 +443,7 @@ static int menu_input_pointer_post_iterate( menu_input->pointer.counter++; - /*if (menu_input->pointer.counter == 1 && + if (menu_input->pointer.counter == 1 && !menu_input_ctl(MENU_INPUT_CTL_IS_POINTER_DRAGGED, NULL)) { menu_ctx_pointer_t point; @@ -456,7 +456,7 @@ static int menu_input_pointer_post_iterate( point.action = action; menu_driver_ctl(RARCH_MENU_CTL_POINTER_DOWN, &point); - }*/ + } if (!pointer_oldpressed[0]) { diff --git a/menu/menu_setting.c b/menu/menu_setting.c index d7a0116014..d41698c3ab 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -140,10 +140,10 @@ static void setting_get_string_representation_uint_custom_viewport_width(void *d rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; - + av_info = video_viewport_get_system_av_info(); geom = (struct retro_game_geometry*)&av_info->geometry; - + if (*setting->value.target.unsigned_integer%geom->base_width == 0) snprintf(s, len, "%u (%ux)", *setting->value.target.unsigned_integer, @@ -161,10 +161,10 @@ static void setting_get_string_representation_uint_custom_viewport_height(void * rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; - + av_info = video_viewport_get_system_av_info(); geom = (struct retro_game_geometry*)&av_info->geometry; - + if (*setting->value.target.unsigned_integer%geom->base_height == 0) snprintf(s, len, "%u (%ux)", *setting->value.target.unsigned_integer, @@ -764,7 +764,7 @@ int menu_action_handle_setting(rarch_setting_t *setting, return -1; } -static rarch_setting_t *menu_setting_find_internal(rarch_setting_t *setting, +static rarch_setting_t *menu_setting_find_internal(rarch_setting_t *setting, const char *label) { uint32_t needle = msg_hash_calculate(label); @@ -794,7 +794,7 @@ static rarch_setting_t *menu_setting_find_internal(rarch_setting_t *setting, return NULL; } -static rarch_setting_t *menu_setting_find_internal_enum(rarch_setting_t *setting, +static rarch_setting_t *menu_setting_find_internal_enum(rarch_setting_t *setting, enum msg_hash_enums enum_idx) { rarch_setting_t **list = &setting; @@ -1051,7 +1051,7 @@ static int setting_action_start_libretro_device_type(void *data) if (system) { - /* Only push RETRO_DEVICE_ANALOG as default if we use an + /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!system->ports.size) devices[types++] = RETRO_DEVICE_ANALOG; @@ -1155,7 +1155,7 @@ static int setting_action_left_libretro_device_type( if (system) { - /* Only push RETRO_DEVICE_ANALOG as default if we use an + /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!system->ports.size) devices[types++] = RETRO_DEVICE_ANALOG; @@ -1220,7 +1220,7 @@ static int setting_action_right_libretro_device_type( if (system) { - /* Only push RETRO_DEVICE_ANALOG as default if we use an + /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!system->ports.size) devices[types++] = RETRO_DEVICE_ANALOG; @@ -1391,7 +1391,7 @@ static int setting_action_ok_bind_defaults(void *data, bool wraparound) return -1; target = &input_config_binds[setting->index_offset][0]; - def_binds = (setting->index_offset) ? + def_binds = (setting->index_offset) ? retro_keybinds_rest : retro_keybinds_1; lim.min = MENU_SETTINGS_BIND_BEGIN; @@ -1506,7 +1506,7 @@ static void get_string_representation_bind_device(void * data, char *s, * Get associated label of a setting. **/ void menu_setting_get_label(void *data, char *s, - size_t len, unsigned *w, unsigned type, + size_t len, unsigned *w, unsigned type, const char *menu_label, const char *label, unsigned idx) { rarch_setting_t *setting = NULL; @@ -1636,7 +1636,7 @@ void general_write_handler(void *data) file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); info.list = menu_stack; - info.type = 0; + info.type = 0; info.directory_ptr = 0; strlcpy(info.label, msg_hash_to_str(MENU_ENUM_LABEL_HELP), sizeof(info.label)); @@ -1697,14 +1697,14 @@ void general_write_handler(void *data) settings->uints.input_joypad_map[4] = *setting->value.target.integer; break; case MENU_ENUM_LABEL_LOG_VERBOSITY: - if (setting - && setting->value.target.boolean + if (setting + && setting->value.target.boolean && *setting->value.target.boolean) verbosity_enable(); else verbosity_disable(); - if (setting + if (setting && setting->value.target.boolean && *setting->value.target.boolean) retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_VERBOSITY, NULL); @@ -1751,7 +1751,7 @@ void general_write_handler(void *data) { #if defined(__CELLOS_LV2__) && (CELL_SDK_VERSION > 0x340000) cellSysutilEnableBgmPlayback(); -#endif +#endif } else { @@ -2031,7 +2031,7 @@ static bool setting_append_list_input_player_options( (*list)[list_info->index - 1].action_right = &setting_action_right_libretro_device_type; (*list)[list_info->index - 1].action_select = &setting_action_right_libretro_device_type; (*list)[list_info->index - 1].action_start = &setting_action_start_libretro_device_type; - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_libretro_device; menu_settings_list_current_add_enum_idx(list, list_info, (enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE + user)); @@ -2052,7 +2052,7 @@ static bool setting_append_list_input_player_options( (*list)[list_info->index - 1].action_right = &setting_action_right_analog_dpad_mode; (*list)[list_info->index - 1].action_select = &setting_action_right_analog_dpad_mode; (*list)[list_info->index - 1].action_start = &setting_action_start_analog_dpad_mode; - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_analog_dpad_mode; menu_settings_list_current_add_enum_idx(list, list_info, (enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE + user)); @@ -2146,7 +2146,7 @@ static bool setting_append_list_input_player_options( ) { if (system->input_desc_btn[user][i]) - strlcat(label, + strlcat(label, system->input_desc_btn[user][i], sizeof(label)); else @@ -2343,15 +2343,6 @@ static bool setting_append_list( &subgroup_info, parent_group); -#ifdef HAVE_LAKKA - CONFIG_ACTION( - list, list_info, - MENU_ENUM_LABEL_UPDATE_LAKKA, - MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, - &group_info, - &subgroup_info, - parent_group); -#else CONFIG_ACTION( list, list_info, MENU_ENUM_LABEL_ONLINE_UPDATER, @@ -2359,8 +2350,6 @@ static bool setting_append_list( &group_info, &subgroup_info, parent_group); -#endif - #endif CONFIG_ACTION( @@ -3016,7 +3005,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 3, 1.0, true, true); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_libretro_log_level; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); @@ -3048,7 +3037,7 @@ static bool setting_append_list( case SETTINGS_LIST_SAVING: { unsigned i; - struct bool_entry bool_entries[7]; + struct bool_entry bool_entries[11]; START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS), parent_group); parent_group = msg_hash_to_str(MENU_ENUM_LABEL_SAVING_SETTINGS); @@ -3098,6 +3087,30 @@ static bool setting_append_list( bool_entries[6].default_value = savestate_thumbnail_enable; bool_entries[6].flags = SD_FLAG_ADVANCED; + bool_entries[7].target = &settings->bools.savefiles_in_content_dir; + bool_entries[7].name_enum_idx = MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[7].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[7].default_value = default_savefiles_in_content_dir; + bool_entries[7].flags = SD_FLAG_ADVANCED; + + bool_entries[8].target = &settings->bools.savestates_in_content_dir; + bool_entries[8].name_enum_idx = MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE; + bool_entries[8].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE; + bool_entries[8].default_value = default_savestates_in_content_dir; + bool_entries[8].flags = SD_FLAG_ADVANCED; + + bool_entries[9].target = &settings->bools.systemfiles_in_content_dir; + bool_entries[9].name_enum_idx = MENU_ENUM_LABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[9].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[9].default_value = default_systemfiles_in_content_dir; + bool_entries[9].flags = SD_FLAG_ADVANCED; + + bool_entries[10].target = &settings->bools.screenshots_in_content_dir; + bool_entries[10].name_enum_idx = MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE; + bool_entries[10].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE; + bool_entries[10].default_value = default_screenshots_in_content_dir; + bool_entries[10].flags = SD_FLAG_ADVANCED; + for (i = 0; i < ARRAY_SIZE(bool_entries); i++) { CONFIG_BOOL( @@ -3131,7 +3144,7 @@ static bool setting_append_list( menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_AUTOSAVE_INIT); menu_settings_list_current_add_range(list, list_info, 0, 0, 1, true, false); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_autosave_interval; #endif @@ -3187,7 +3200,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); - menu_settings_list_current_add_range(list, list_info, 1, 32768, 1, true, false); + menu_settings_list_current_add_range(list, list_info, 1, 32768, 1, true, true); END_SUB_GROUP(list, list_info, parent_group); END_GROUP(list, list_info, parent_group); @@ -3258,7 +3271,7 @@ static bool setting_append_list( general_read_handler); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_REINIT); menu_settings_list_current_add_range(list, list_info, 0, 1, 1, true, false); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_video_monitor_index; if (video_driver_has_windowed()) @@ -3356,7 +3369,7 @@ static bool setting_append_list( (*list)[list_info->index - 1].action_start = &setting_action_start_video_refresh_rate_auto; (*list)[list_info->index - 1].action_ok = &setting_action_ok_video_refresh_rate_auto; (*list)[list_info->index - 1].action_select = &setting_action_ok_video_refresh_rate_auto; - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_st_float_video_refresh_rate_auto; settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); @@ -3406,7 +3419,7 @@ static bool setting_append_list( true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_aspect_ratio_index; CONFIG_FLOAT( @@ -3635,7 +3648,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 3, 1, true, true); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_video_rotation; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); @@ -3980,7 +3993,7 @@ static bool setting_append_list( &settings->uints.audio_latency, MENU_ENUM_LABEL_AUDIO_LATENCY, MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - g_defaults.settings.out_latency ? + g_defaults.settings.out_latency ? g_defaults.settings.out_latency : out_latency, &group_info, &subgroup_info, @@ -4027,7 +4040,7 @@ static bool setting_append_list( menu_settings_list_current_add_range( list, list_info, - 0.01, + 0.0, 0.5, 0.01, true, @@ -4655,7 +4668,7 @@ static bool setting_append_list( &retro_keybinds_1[i], &group_info, &subgroup_info, parent_group); (*list)[list_info->index - 1].bind_type = i + MENU_SETTINGS_BIND_BEGIN; - menu_settings_list_current_add_enum_idx(list, list_info, + menu_settings_list_current_add_enum_idx(list, list_info, (enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN + i)); } @@ -4867,6 +4880,34 @@ static bool setting_append_list( ); (*list)[list_info->index - 1].change_handler = overlay_enable_toggle_change_handler; + CONFIG_BOOL( + list, list_info, + &settings->bools.input_overlay_show_physical_inputs, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + show_physical_inputs, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE + ); + CONFIG_UINT( + list, list_info, + &settings->uints.input_overlay_show_physical_inputs_port, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + 0, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler + ); + menu_settings_list_current_add_range(list, list_info, 0, MAX_USERS - 1, 1, true, true); CONFIG_PATH( list, list_info, settings->paths.path_overlay, @@ -4962,6 +5003,21 @@ static bool setting_append_list( general_read_handler); menu_settings_list_current_add_range(list, list_info, 0.0, 1.0, 0.010, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); + + CONFIG_FLOAT( + list, list_info, + &settings->floats.menu_framebuffer_opacity, + MENU_ENUM_LABEL_MENU_FRAMEBUFFER_OPACITY, + MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, + menu_framebuffer_opacity, + "%.3f", + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + menu_settings_list_current_add_range(list, list_info, 0.0, 1.0, 0.010, true, true); + settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); } if (string_is_equal_fast(settings->arrays.menu_driver, "xmb", 3)) @@ -5051,6 +5107,22 @@ static bool setting_append_list( SD_FLAG_ADVANCED ); + CONFIG_BOOL( + list, list_info, + &settings->bools.menu_horizontal_animation, + MENU_ENUM_LABEL_MENU_HORIZONTAL_ANIMATION, + MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + true, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_ADVANCED + ); + #ifdef RARCH_MOBILE /* We don't want mobile users being able to switch this off. */ (*list)[list_info->index - 1].action_left = NULL; @@ -5315,6 +5387,21 @@ static bool setting_append_list( SD_FLAG_NONE); settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); + CONFIG_BOOL( + list, list_info, + &settings->bools.menu_xmb_show_favorites, + MENU_ENUM_LABEL_XMB_SHOW_FAVORITES, + MENU_ENUM_LABEL_VALUE_XMB_SHOW_FAVORITES, + xmb_show_favorites, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + #ifdef HAVE_IMAGEVIEWER CONFIG_BOOL( list, list_info, @@ -5412,7 +5499,7 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); -#endif +#endif } #endif @@ -5421,6 +5508,21 @@ static bool setting_append_list( /* only MaterialUI uses these values, don't show them on other drivers */ if (string_is_equal_fast(settings->arrays.menu_driver, "glui", 4)) { + CONFIG_BOOL( + list, list_info, + &settings->bools.menu_materialui_icons_enable, + MENU_ENUM_LABEL_MATERIALUI_ICONS_ENABLE, + MENU_ENUM_LABEL_VALUE_MATERIALUI_ICONS_ENABLE, + materialui_icons_enable, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_ADVANCED); + CONFIG_UINT( list, list_info, &settings->uints.menu_materialui_color_theme, @@ -5674,8 +5776,6 @@ static bool setting_append_list( settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); #endif -#if defined(HAVE_NETWORKING) -#ifndef HAVE_LAKKA CONFIG_BOOL( list, list_info, &settings->bools.menu_show_online_updater, @@ -5705,8 +5805,6 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); -#endif -#endif if (string_is_not_equal_fast(ui_companion_driver_get_ident(), "null", 4)) { @@ -5800,7 +5898,7 @@ static bool setting_append_list( menu_settings_list_current_add_range(list, list_info, 0, 0, 1.0, true, false); END_SUB_GROUP(list, list_info, parent_group); - + START_SUB_GROUP(list, list_info, "Playlist", &group_info, &subgroup_info, parent_group); CONFIG_BOOL( @@ -5817,9 +5915,17 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); - + + CONFIG_ACTION( + list, list_info, + MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + &group_info, + &subgroup_info, + parent_group); + END_SUB_GROUP(list, list_info, parent_group); - + END_GROUP(list, list_info, parent_group); break; case SETTINGS_LIST_CHEEVOS: @@ -5912,7 +6018,7 @@ static bool setting_append_list( sizeof(settings->paths.network_buildbot_url), MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL, MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, - buildbot_server_url, + buildbot_server_url, &group_info, &subgroup_info, parent_group, @@ -5926,7 +6032,7 @@ static bool setting_append_list( sizeof(settings->paths.network_buildbot_assets_url), MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL, MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, - buildbot_assets_server_url, + buildbot_assets_server_url, &group_info, &subgroup_info, parent_group, @@ -6444,7 +6550,7 @@ static bool setting_append_list( true, true); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_MENU_REFRESH); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_user_language; #endif @@ -6509,7 +6615,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_cheevos_password; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); #endif @@ -6533,13 +6639,14 @@ static bool setting_append_list( sizeof(settings->paths.directory_system), MENU_ENUM_LABEL_SYSTEM_DIRECTORY, MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_SYSTEM], MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6547,7 +6654,7 @@ static bool setting_append_list( sizeof(settings->paths.directory_core_assets), MENU_ENUM_LABEL_CORE_ASSETS_DIRECTORY, MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, &group_info, &subgroup_info, @@ -6577,13 +6684,14 @@ static bool setting_append_list( sizeof(settings->paths.directory_dynamic_wallpapers), MENU_ENUM_LABEL_DYNAMIC_WALLPAPERS_DIRECTORY, MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_WALLPAPERS], MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6591,7 +6699,7 @@ static bool setting_append_list( sizeof(settings->paths.directory_thumbnails), MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY, MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, - g_defaults.dirs[DEFAULT_DIR_THUMBNAILS], + g_defaults.dirs[DEFAULT_DIR_THUMBNAILS], MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, &group_info, &subgroup_info, @@ -6644,6 +6752,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_CORE_INFO_INIT); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6659,6 +6768,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_CORE_INFO_INIT); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; #ifdef HAVE_LIBRETRODB CONFIG_DIR( @@ -6750,6 +6860,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; if (string_is_not_equal_fast(settings->arrays.record_driver, "null", 4)) { @@ -6797,6 +6908,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; #endif CONFIG_DIR( @@ -6835,13 +6947,14 @@ static bool setting_append_list( sizeof(settings->paths.directory_input_remapping), MENU_ENUM_LABEL_INPUT_REMAPPING_DIRECTORY, MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_REMAP], MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6864,13 +6977,14 @@ static bool setting_append_list( dir_get_size(RARCH_DIR_SAVEFILE), MENU_ENUM_LABEL_SAVEFILE_DIRECTORY, MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_SRAM], MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6878,13 +6992,14 @@ static bool setting_append_list( dir_get_size(RARCH_DIR_SAVESTATE), MENU_ENUM_LABEL_SAVESTATE_DIRECTORY, MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_SAVESTATE], MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -7001,7 +7116,7 @@ static rarch_setting_t *menu_setting_new_internal(rarch_setting_info_t *list_inf { unsigned i; rarch_setting_t* resized_list = NULL; - enum settings_list_type list_types[] = + enum settings_list_type list_types[] = { SETTINGS_LIST_MAIN_MENU, SETTINGS_LIST_DRIVERS, @@ -7082,17 +7197,19 @@ static rarch_setting_t *menu_setting_new(void) { rarch_setting_t* list = NULL; rarch_setting_info_t *list_info = (rarch_setting_info_t*) - calloc(1, sizeof(*list_info)); + malloc(sizeof(*list_info)); if (!list_info) return NULL; + list_info->index = 0; list_info->size = 32; - list = menu_setting_new_internal(list_info); + list = menu_setting_new_internal(list_info); menu_settings_info_list_free(list_info); - list_info = NULL; + + list_info = NULL; return list; } diff --git a/menu/widgets/menu_filebrowser.h b/menu/widgets/menu_filebrowser.h index cbc25daa65..93dac91e75 100644 --- a/menu/widgets/menu_filebrowser.h +++ b/menu/widgets/menu_filebrowser.h @@ -28,7 +28,9 @@ enum filebrowser_enums { FILEBROWSER_NONE = 0, FILEBROWSER_SELECT_DIR, + FILEBROWSER_APPEND_IMAGE, FILEBROWSER_SCAN_DIR, + FILEBROWSER_SCAN_FILE, FILEBROWSER_SELECT_FILE, FILEBROWSER_SELECT_IMAGE, FILEBROWSER_SELECT_FONT, diff --git a/menu/widgets/menu_list.c b/menu/widgets/menu_list.c index f135686458..5cd4d14292 100644 --- a/menu/widgets/menu_list.c +++ b/menu/widgets/menu_list.c @@ -167,11 +167,6 @@ void menu_list_flush_stack(menu_list_t *list, menu_entries_get_last(menu_list, &path, &label, &type, &entry_idx); - -#if 0 - RARCH_LOG("path: %s\n", path); - RARCH_LOG("label: %s\n", label); -#endif } } diff --git a/menu/widgets/menu_list.h b/menu/widgets/menu_list.h index 16468598c3..3776abd349 100644 --- a/menu/widgets/menu_list.h +++ b/menu/widgets/menu_list.h @@ -42,6 +42,7 @@ typedef struct menu_ctx_list char *fullpath; const char *label; size_t idx; + unsigned entry_type; enum menu_list_type type; unsigned action; size_t selection; diff --git a/msg_hash.c b/msg_hash.c index ae141c16ae..d0ccaa8b5c 100644 --- a/msg_hash.c +++ b/msg_hash.c @@ -169,6 +169,9 @@ uint32_t msg_hash_calculate(const char *s) #define MENU_VALUE_FILE_MP3 0x0b889135U #define MENU_VALUE_FILE_FLAC 0x7c96d67bU #define MENU_VALUE_FILE_OGG 0x0b8898c2U +#define MENU_VALUE_FILE_MOD 0x0b889145U +#define MENU_VALUE_FILE_S3M 0x0b88a318U +#define MENU_VALUE_FILE_XM 0x00597a2aU #define MENU_VALUE_FILE_FLV 0x0b88732dU #define MENU_VALUE_FILE_WAV 0x0b88ba13U #define MENU_VALUE_FILE_MOV 0x0b889157U @@ -347,6 +350,14 @@ enum msg_file_type msg_hash_to_file_type(uint32_t hash) case MENU_VALUE_FILE_WMA: return FILE_TYPE_WMA; #endif +#ifdef HAVE_IBXM + case MENU_VALUE_FILE_MOD: + return FILE_TYPE_MOD; + case MENU_VALUE_FILE_S3M: + return FILE_TYPE_S3M; + case MENU_VALUE_FILE_XM: + return FILE_TYPE_XM; +#endif #ifdef HAVE_IMAGEVIEWER case MENU_VALUE_FILE_JPG: case MENU_VALUE_FILE_JPG_CAPS: diff --git a/msg_hash.h b/msg_hash.h index c2a2874605..67107195cb 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -127,6 +127,10 @@ enum msg_file_type FILE_TYPE_TGA, FILE_TYPE_BMP, + FILE_TYPE_MOD, + FILE_TYPE_S3M, + FILE_TYPE_XM, + FILE_TYPE_CUE, FILE_TYPE_ISO, FILE_TYPE_LUTRO, @@ -168,6 +172,7 @@ enum msg_hash_enums MSG_NETPLAY_CANNOT_PLAY, MSG_NETPLAY_PEER_PAUSED, MSG_NETPLAY_CHANGED_NICK, + MSG_ADDED_TO_FAVORITES, MSG_AUTODETECT, MSG_AUDIO_VOLUME, MSG_AUDIO_MIXER_VOLUME, @@ -282,9 +287,12 @@ enum msg_hash_enums MSG_INPUT_CHEAT, MSG_INPUT_PRESET_FILENAME, MSG_INPUT_CHEAT_FILENAME, + MSG_INPUT_RENAME_ENTRY, MSG_REMAP_FILE_SAVED_SUCCESSFULLY, + MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, MSG_ERROR_SAVING_REMAP_FILE, + MSG_ERROR_REMOVING_REMAP_FILE, MSG_ERROR_SAVING_SHADER_PRESET, MSG_FAILED_TO_CREATE_THE_DIRECTORY, MSG_ERROR_SAVING_CORE_OPTIONS_FILE, @@ -392,11 +400,14 @@ enum msg_hash_enums MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_END = MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN + RARCH_BIND_LIST_END, MENU_LABEL(MENU_WALLPAPER_OPACITY), + MENU_LABEL(MENU_FRAMEBUFFER_OPACITY), MENU_ENUM_LABEL_VALUE_CONFIG, MENU_ENUM_LABEL_VALUE_OVERLAY, MENU_ENUM_LABEL_VALUE_AUTO, + MENU_LABEL(MATERIALUI_ICONS_ENABLE), + MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, @@ -592,6 +603,8 @@ enum msg_hash_enums MENU_LABEL(INPUT_OSK_OVERLAY_ENABLE), MENU_LABEL(INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO), MENU_LABEL(INPUT_OVERLAY_HIDE_IN_MENU), + MENU_LABEL(INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS), + MENU_LABEL(INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT), MENU_LABEL(INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE), MENU_LABEL(INPUT_SMALL_KEYBOARD_ENABLE), MENU_LABEL(INPUT_TOUCH_ENABLE), @@ -664,6 +677,7 @@ enum msg_hash_enums MENU_LABEL(MOUSE_ENABLE), MENU_LABEL(POINTER_ENABLE), MENU_LABEL(MENU_LINEAR_FILTER), + MENU_LABEL(MENU_HORIZONTAL_ANIMATION), MENU_LABEL(NAVIGATION_WRAPAROUND), MENU_LABEL(SHOW_ADVANCED_SETTINGS), MENU_LABEL(THREADED_DATA_RUNLOOP_ENABLE), @@ -676,6 +690,7 @@ enum msg_hash_enums MENU_LABEL(XMB_MENU_COLOR_THEME), MENU_LABEL(XMB_SHADOWS_ENABLE), MENU_LABEL(XMB_SHOW_SETTINGS), + MENU_LABEL(XMB_SHOW_FAVORITES), MENU_LABEL(XMB_SHOW_IMAGES), MENU_LABEL(XMB_SHOW_MUSIC), MENU_LABEL(XMB_SHOW_VIDEO), @@ -724,6 +739,12 @@ enum msg_hash_enums MENU_LABEL(HISTORY_LIST_ENABLE), MENU_LABEL(CONTENT_HISTORY_SIZE), MENU_LABEL(PLAYLIST_ENTRY_REMOVE), + MENU_LABEL(PLAYLIST_ENTRY_RENAME), + MENU_LABEL(GOTO_FAVORITES), + MENU_LABEL(GOTO_MUSIC), + MENU_LABEL(GOTO_IMAGES), + MENU_LABEL(GOTO_VIDEO), + MENU_LABEL(ADD_TO_FAVORITES), MENU_LABEL(MENU_THROTTLE_FRAMERATE), MENU_LABEL(NO_ACHIEVEMENTS_TO_DISPLAY), MENU_LABEL(NO_ENTRIES_TO_DISPLAY), @@ -811,6 +832,10 @@ enum msg_hash_enums MENU_LABEL(BROWSE_URL), MENU_LABEL(BROWSE_START), /* Deferred */ + MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST, + MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST, + MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST, + MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST, MENU_ENUM_LABEL_DEFERRED_NETPLAY, MENU_ENUM_LABEL_DEFERRED_MUSIC, MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_START, @@ -929,6 +954,7 @@ enum msg_hash_enums MENU_LABEL(NETPLAY_SETTINGS), MENU_LABEL(CONTENT_SETTINGS), MENU_LABEL(LOAD_CONTENT_LIST), + MENU_LABEL(LOAD_CONTENT_SPECIAL), MENU_LABEL(NO_SETTINGS_FOUND), MENU_LABEL(NO_NETWORKS_FOUND), MENU_LABEL(NO_PERFORMANCE_COUNTERS), @@ -1062,6 +1088,10 @@ enum msg_hash_enums MENU_LABEL(NETPLAY_NAT_TRAVERSAL), MENU_LABEL(SORT_SAVEFILES_ENABLE), MENU_LABEL(SORT_SAVESTATES_ENABLE), + MENU_LABEL(SAVEFILES_IN_CONTENT_DIR_ENABLE), + MENU_LABEL(SAVESTATES_IN_CONTENT_DIR_ENABLE), + MENU_LABEL(SYSTEMFILES_IN_CONTENT_DIR_ENABLE), + MENU_LABEL(SCREENSHOTS_IN_CONTENT_DIR_ENABLE), MENU_LABEL(NETPLAY_IP_ADDRESS), MENU_LABEL(NETPLAY_PASSWORD), MENU_LABEL(NETPLAY_SPECTATE_PASSWORD), @@ -1182,6 +1212,7 @@ enum msg_hash_enums MENU_LABEL(HORIZONTAL_MENU), MENU_LABEL(SETTINGS_TAB), MENU_LABEL(HISTORY_TAB), + MENU_LABEL(FAVORITES_TAB), MENU_LABEL(ADD_TAB), MENU_LABEL(NETPLAY_TAB), MENU_LABEL(PLAYLISTS_TAB), @@ -1265,6 +1296,7 @@ enum msg_hash_enums MENU_LABEL(ACHIEVEMENT_LIST), MENU_LABEL(ACHIEVEMENT_LIST_HARDCORE), MENU_LABEL(CORE_INFORMATION), + MENU_LABEL(CORE_DELETE), MENU_LABEL(VIDEO_SHADER_PARAMETERS), MENU_LABEL(VIDEO_SHADER_PRESET_PARAMETERS), @@ -1360,6 +1392,8 @@ enum msg_hash_enums MENU_LABEL(REMAP_FILE_SAVE_CORE), MENU_LABEL(REMAP_FILE_SAVE_GAME), + MENU_LABEL(REMAP_FILE_REMOVE_CORE), + MENU_LABEL(REMAP_FILE_REMOVE_GAME), MENU_LABEL(RESTART_CONTENT), MENU_LABEL(RESUME), MENU_LABEL(RESUME_CONTENT), diff --git a/network/netplay/netplay_discovery.c b/network/netplay/netplay_discovery.c index 8d45a86a3e..e3ad842842 100644 --- a/network/netplay/netplay_discovery.c +++ b/network/netplay/netplay_discovery.c @@ -45,6 +45,8 @@ #include "../../retroarch.h" #include "../../version.h" +#include "../../verbosity.h" + #include "netplay.h" #include "netplay_discovery.h" #include "netplay_private.h" @@ -346,14 +348,19 @@ static bool netplay_lan_ad_client(void) /* And that we know how to handle it */ if (their_addr.sa_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *) &their_addr; + struct sockaddr_in *sin = NULL; + + RARCH_WARN ("[lobby] using IPv4 for discovery\n"); + sin = (struct sockaddr_in *) &their_addr; sin->sin_port = htons(ntohl(ad_packet_buffer.port)); } #ifdef HAVE_INET6 else if (their_addr.sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &their_addr; + struct sockaddr_in6 *sin6 = NULL; + RARCH_WARN ("[lobby] using IPv6 for discovery\n"); + sin6 = (struct sockaddr_in6 *) &their_addr; sin6->sin6_port = htons(ad_packet_buffer.port); } @@ -397,6 +404,8 @@ static bool netplay_lan_ad_client(void) strlcpy(host->nick, ad_packet_buffer.nick, NETPLAY_HOST_STR_LEN); strlcpy(host->core, ad_packet_buffer.core, NETPLAY_HOST_STR_LEN); + strlcpy(host->retroarch_version, ad_packet_buffer.retroarch_version, + NETPLAY_HOST_STR_LEN); strlcpy(host->core_version, ad_packet_buffer.core_version, NETPLAY_HOST_STR_LEN); strlcpy(host->content, ad_packet_buffer.content, diff --git a/network/netplay/netplay_discovery.h b/network/netplay/netplay_discovery.h index 5148a8af9a..2260e7d6d6 100644 --- a/network/netplay/netplay_discovery.h +++ b/network/netplay/netplay_discovery.h @@ -39,6 +39,7 @@ struct netplay_host char nick[NETPLAY_HOST_STR_LEN]; char core[NETPLAY_HOST_STR_LEN]; char core_version[NETPLAY_HOST_STR_LEN]; + char retroarch_version[NETPLAY_HOST_STR_LEN]; char content[NETPLAY_HOST_LONGSTR_LEN]; int content_crc; }; @@ -57,8 +58,6 @@ enum netplay_host_method NETPLAY_HOST_METHOD_MITM }; -/* data is ordered like this on the server, I left it in this ordered - for reference */ struct netplay_room { char nickname [PATH_MAX_LENGTH]; @@ -76,6 +75,8 @@ struct netplay_room bool has_spectate_password; bool lan; bool fixed; + char retroarch_version[PATH_MAX_LENGTH]; + char country[PATH_MAX_LENGTH]; struct netplay_room *next; }; diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index ed22135418..49026cb10f 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -18,7 +18,7 @@ #include #include -#include "version.h" +#include "../../version.h" #include #include @@ -57,6 +57,8 @@ static unsigned server_port_deferred = 0; static int reannounce = 0; static bool is_mitm = false; +bool netplay_disconnect(netplay_t *netplay); + /** * netplay_is_alive: * @netplay : pointer to netplay object @@ -523,7 +525,7 @@ static int16_t netplay_input_state(netplay_t *netplay, static void netplay_announce_cb(void *task_data, void *user_data, const char *error) { - RARCH_LOG("Announcing netplay game... \n"); + RARCH_LOG("[netplay] announcing netplay game... \n"); if (task_data) { @@ -568,7 +570,7 @@ static void netplay_announce_cb(void *task_data, void *user_data, const char *er if (mitm_ip && mitm_port) { - RARCH_LOG("Joining MITM server: %s:%s\n", mitm_ip, mitm_port); + RARCH_LOG("[netplay] joining relay server: %s:%s\n", mitm_ip, mitm_port); ip_len = (unsigned)strlen(mitm_ip); port_len = (unsigned)strlen(mitm_port); @@ -633,8 +635,9 @@ static void netplay_announce(void) *settings->paths.netplay_spectate_password ? 1 : 0, settings->bools.netplay_use_mitm_server, PACKAGE_VERSION); - - RARCH_LOG("%s\n", buf); +#if 0 + RARCH_LOG("[netplay] announcement URL: %s\n", buf); +#endif task_push_http_post_transfer(url, buf, true, NULL, netplay_announce_cb, NULL); free(username); @@ -824,6 +827,13 @@ bool netplay_pre_frame(netplay_t *netplay) sync_stalled = !netplay_sync_pre_frame(netplay); + /* If we're disconnected, deinitialize */ + if (!netplay->is_server && !netplay->connections[0].active) + { + netplay_disconnect(netplay); + return true; + } + if (sync_stalled || ((!netplay->is_server || netplay->connected_players) && (netplay->stall || netplay->remote_paused))) @@ -859,6 +869,10 @@ void netplay_post_frame(netplay_t *netplay) false)) netplay_hangup(netplay, connection); } + + /* If we're disconnected, deinitialize */ + if (!netplay->is_server && !netplay->connections[0].active) + netplay_disconnect(netplay); } /** @@ -1095,7 +1109,7 @@ static void netplay_toggle_play_spectate(netplay_t *netplay) snprintf(msg, sizeof(msg)-1, msg_hash_to_str(MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N), player+1); } - RARCH_LOG("%s\n", dmsg); + RARCH_LOG("[netplay] %s\n", dmsg); runloop_msg_queue_push(dmsg, 1, 180, false); netplay_send_raw_cmd_all(netplay, NULL, NETPLAY_CMD_MODE, payload, sizeof(payload)); @@ -1203,11 +1217,11 @@ bool init_netplay(void *direct_host, const char *server, unsigned port) if (netplay_is_client) { - RARCH_LOG("%s\n", msg_hash_to_str(MSG_CONNECTING_TO_NETPLAY_HOST)); + RARCH_LOG("[netplay] %s\n", msg_hash_to_str(MSG_CONNECTING_TO_NETPLAY_HOST)); } else { - RARCH_LOG("%s\n", msg_hash_to_str(MSG_WAITING_FOR_CLIENT)); + RARCH_LOG("[netplay] %s\n", msg_hash_to_str(MSG_WAITING_FOR_CLIENT)); runloop_msg_queue_push( msg_hash_to_str(MSG_WAITING_FOR_CLIENT), 0, 180, false); diff --git a/network/netplay/netplay_room_parse.c b/network/netplay/netplay_room_parse.c index ecefc904ff..df8877f78c 100644 --- a/network/netplay/netplay_room_parse.c +++ b/network/netplay/netplay_room_parse.c @@ -47,7 +47,6 @@ typedef struct tag_Context enum parse_state state; char *cur_field; void *cur_member; - size_t cur_member_size; } Context; static struct netplay_rooms *rooms; @@ -112,7 +111,7 @@ static JSON_Parser_HandlerResult JSON_CALL StringHandler( { if (string_is_equal(pCtx->cur_field, "game_crc")) { - /* CRC comes in as a string but it is stored + /* CRC comes in as a string but it is stored * as an unsigned casted to int. */ *((int*)pCtx->cur_member) = (int)strtoul(pValue, NULL, 16); } @@ -213,25 +212,21 @@ static JSON_Parser_HandlerResult JSON_CALL ObjectMemberHandler(JSON_Parser parse { pCtx->cur_field = strdup(pValue); pCtx->cur_member = &rooms->cur->nickname; - pCtx->cur_member_size = sizeof(rooms->cur->nickname); } else if (string_is_equal_fast(pValue, "game_name", 9)) { pCtx->cur_field = strdup(pValue); pCtx->cur_member = &rooms->cur->gamename; - pCtx->cur_member_size = sizeof(rooms->cur->gamename); } else if (string_is_equal_fast(pValue, "core_name", 9)) { pCtx->cur_field = strdup(pValue); pCtx->cur_member = &rooms->cur->corename; - pCtx->cur_member_size = sizeof(rooms->cur->corename); } else if (string_is_equal_fast(pValue, "ip", 2)) { pCtx->cur_field = strdup(pValue); pCtx->cur_member = &rooms->cur->address; - pCtx->cur_member_size = sizeof(rooms->cur->address); } else if (string_is_equal_fast(pValue, "port", 4)) { @@ -247,7 +242,6 @@ static JSON_Parser_HandlerResult JSON_CALL ObjectMemberHandler(JSON_Parser parse { pCtx->cur_field = strdup(pValue); pCtx->cur_member = &rooms->cur->coreversion; - pCtx->cur_member_size = sizeof(rooms->cur->coreversion); } else if (string_is_equal_fast(pValue, "has_password", 12)) { @@ -279,6 +273,16 @@ static JSON_Parser_HandlerResult JSON_CALL ObjectMemberHandler(JSON_Parser parse pCtx->cur_field = strdup(pValue); pCtx->cur_member = &rooms->cur->host_method; } + else if (string_is_equal_fast(pValue, "retroarch_version", 17)) + { + pCtx->cur_field = strdup(pValue); + pCtx->cur_member = &rooms->cur->retroarch_version; + } + else if (string_is_equal_fast(pValue, "country", 7)) + { + pCtx->cur_field = strdup(pValue); + pCtx->cur_member = &rooms->cur->country; + } } } diff --git a/paths.c b/paths.c index c820e0027f..19aabd16c3 100644 --- a/paths.c +++ b/paths.c @@ -67,6 +67,7 @@ void path_set_redirect(void) const char *old_savefile_dir = dir_get(RARCH_DIR_SAVEFILE); const char *old_savestate_dir = dir_get(RARCH_DIR_SAVESTATE); rarch_system_info_t *info = runloop_get_system_info(); + settings_t *settings = config_get_ptr(); new_savefile_dir[0] = new_savestate_dir[0] = '\0'; @@ -93,10 +94,8 @@ void path_set_redirect(void) if (check_library_name_hash) { - settings_t *settings = config_get_ptr(); - /* per-core saves: append the library_name to the save location */ - if ( settings->bools.sort_savefiles_enable + if (settings->bools.sort_savefiles_enable && !string_is_empty(old_savefile_dir)) { fill_pathname_join( @@ -154,13 +153,21 @@ void path_set_redirect(void) } /* Set savefile directory if empty based on content directory */ - if (string_is_empty(new_savefile_dir)) + if (string_is_empty(new_savefile_dir) || settings->bools.savefiles_in_content_dir) { strlcpy(new_savefile_dir, path_main_basename, sizeof(new_savefile_dir)); path_basedir(new_savefile_dir); } + /* Set savestate directory if empty based on content directory */ + if (string_is_empty(new_savestate_dir) || settings->bools.savestates_in_content_dir) + { + strlcpy(new_savestate_dir, path_main_basename, + sizeof(new_savestate_dir)); + path_basedir(new_savestate_dir); + } + if (global) { if(path_is_directory(new_savefile_dir)) @@ -744,6 +751,13 @@ enum rarch_content_type path_is_media_type(const char *path) case FILE_TYPE_BMP: return RARCH_CONTENT_IMAGE; #endif +#ifdef HAVE_IBXM + case FILE_TYPE_MOD: + case FILE_TYPE_S3M: + case FILE_TYPE_XM: + return RARCH_CONTENT_MUSIC; +#endif + case FILE_TYPE_NONE: default: break; diff --git a/pkg/android/phoenix/AndroidManifest.xml b/pkg/android/phoenix/AndroidManifest.xml index eb5e0d5ece..0528ea7ebb 100644 --- a/pkg/android/phoenix/AndroidManifest.xml +++ b/pkg/android/phoenix/AndroidManifest.xml @@ -1,7 +1,7 @@ diff --git a/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png index 3c1e128429..d33d1953f9 100644 Binary files a/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png and b/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png index 6dbad4942f..a338dfb2f9 100644 Binary files a/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png and b/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-xhdpi/banner.png b/pkg/android/phoenix/res/drawable-xhdpi/banner.png index e04769aa8a..bcf43ef5aa 100644 Binary files a/pkg/android/phoenix/res/drawable-xhdpi/banner.png and b/pkg/android/phoenix/res/drawable-xhdpi/banner.png differ diff --git a/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png index 2949cf0822..7eb088dc92 100644 Binary files a/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png and b/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-xxhdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..c5a7c34b79 Binary files /dev/null and b/pkg/android/phoenix/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-xxxhdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..f6abcb638a Binary files /dev/null and b/pkg/android/phoenix/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable/banner.png b/pkg/android/phoenix/res/drawable/banner.png index e04769aa8a..bcf43ef5aa 100644 Binary files a/pkg/android/phoenix/res/drawable/banner.png and b/pkg/android/phoenix/res/drawable/banner.png differ diff --git a/pkg/emscripten/embed/embed.js b/pkg/emscripten/embed/embed.js index dc3a21e3ca..efbb371870 100644 --- a/pkg/emscripten/embed/embed.js +++ b/pkg/emscripten/embed/embed.js @@ -394,7 +394,7 @@ $(function() { function keyPress(k) { kp(k, "keydown"); - setInterval(function(){kp(k, "keyup")}, 1000); + setTimeout(function(){kp(k, "keyup")}, 50); } kp = function(k, event) { diff --git a/pkg/emscripten/embed/index.html b/pkg/emscripten/embed/index.html index 7d643d177b..f7f01cdabd 100644 --- a/pkg/emscripten/embed/index.html +++ b/pkg/emscripten/embed/index.html @@ -12,7 +12,7 @@ - + diff --git a/pkg/emscripten/itch/index.html b/pkg/emscripten/itch/index.html index e16e0cd527..64320efd92 100644 --- a/pkg/emscripten/itch/index.html +++ b/pkg/emscripten/itch/index.html @@ -13,7 +13,7 @@ - + diff --git a/pkg/emscripten/libretro/index.html b/pkg/emscripten/libretro/index.html index 89ecbe4eef..37cfe0cc30 100644 --- a/pkg/emscripten/libretro/index.html +++ b/pkg/emscripten/libretro/index.html @@ -12,7 +12,7 @@ - + diff --git a/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj b/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj index aa8a71ac65..2833c6ab47 100644 --- a/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj +++ b/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj @@ -62,7 +62,7 @@ /> com.RetroArch - 1.3.6 + 1.6.4 3 Cross-platform entertainment system Team Libretro diff --git a/pkg/wii/meta.xml b/pkg/wii/meta.xml index 19e4cbd45e..75c81a3cfa 100644 --- a/pkg/wii/meta.xml +++ b/pkg/wii/meta.xml @@ -2,7 +2,7 @@ RetroArch Libretro - 1.6.0 + 1.6.7 2012-2017 The cross-platform entertainment system A port of RetroArch to the GameCube/Wii. diff --git a/pkg/wiiu/meta.xml b/pkg/wiiu/meta.xml index 4a39d51ac9..66fc7271bf 100644 --- a/pkg/wiiu/meta.xml +++ b/pkg/wiiu/meta.xml @@ -2,8 +2,8 @@ Retroarch Libretro - 1.50 - 20170107153000 + 1.67 + 20170108133000 RetroArch diff --git a/playlist.c b/playlist.c index b8907f1a96..ce12074994 100644 --- a/playlist.c +++ b/playlist.c @@ -291,12 +291,8 @@ bool playlist_push(playlist_t *playlist, static char base_path[255] = {0}; fill_pathname_base_noext(base_path, core_path, sizeof(base_path)); core_name = base_path; - RARCH_LOG("core_name is now: %s\n", core_name); } - RARCH_LOG("core_name: %s.\n", string_is_empty(core_name) ? "N/A" : core_name); - RARCH_LOG("core_path: %s.\n", string_is_empty(core_path) ? "N/A" : core_path); - if (string_is_empty(core_path) || string_is_empty(core_name)) { RARCH_ERR("cannot push NULL or empty core name into the playlist.\n"); @@ -428,7 +424,7 @@ void playlist_free(playlist_t *playlist) playlist->conf_path = NULL; - for (i = 0; i < playlist->cap; i++) + for (i = 0; i < playlist->size; i++) { struct playlist_entry *entry = &playlist->entries[i]; @@ -454,7 +450,7 @@ void playlist_clear(playlist_t *playlist) if (!playlist) return; - for (i = 0; i < playlist->cap; i++) + for (i = 0; i < playlist->size; i++) { struct playlist_entry *entry = &playlist->entries[i]; diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 6f2daf2369..1031488fd8 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -35,17 +35,19 @@ fi add_define_make DYLIB_LIB "$DYLIB" [ "$OS" = 'Darwin' ] && HAVE_X11=no # X11 breaks on recent OSXes even if present. - -[ -d /opt/vc/lib ] && add_library_dirs /opt/vc/lib && add_library_dirs /opt/vc/lib/GL -check_lib VIDEOCORE -lbcm_host bcm_host_init "-lvcos -lvchiq_arm" check_lib SYSTEMD -lsystemd sd_get_machine_names +if [ "$HAVE_VIDEOCORE" != "no" ]; then + [ -d /opt/vc/lib ] && add_library_dirs /opt/vc/lib && add_library_dirs /opt/vc/lib/GL + check_lib VIDEOCORE -lbcm_host bcm_host_init "-lvcos -lvchiq_arm" +fi + if [ "$HAVE_VIDEOCORE" = 'yes' ]; then [ -d /opt/vc/include ] && add_include_dirs /opt/vc/include [ -d /opt/vc/include/interface/vcos/pthreads ] && add_include_dirs /opt/vc/include/interface/vcos/pthreads [ -d /opt/vc/include/interface/vmcs_host/linux ] && add_include_dirs /opt/vc/include/interface/vmcs_host/linux HAVE_OPENGLES='auto' - EXTRA_GL_LIBS="-lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm" + EXTRA_GL_LIBS="-lbrcmEGL -lbrcmGLESv2 -lbcm_host -lvcos -lvchiq_arm" fi if [ "$HAVE_NEON" = "yes" ]; then @@ -109,7 +111,7 @@ if [ "$HAVE_EGL" != "no" -a "$OS" != 'Win32' ]; then fi fi -if [ "HAVE_SSA" != "no" ]; then +if [ "$HAVE_SSA" != "no" ]; then check_lib SSA -lass ass_library_init fi diff --git a/qb/config.params.sh b/qb/config.params.sh index 9386d6b960..8f9913e9af 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -71,6 +71,7 @@ HAVE_FREETYPE=auto # FreeType support HAVE_STB_FONT=yes # stb_truetype font support HAVE_STB_IMAGE=yes # stb image loading support HAVE_STB_VORBIS=yes # stb vorbis support +HAVE_IBXM=yes # IBXM support HAVE_XVIDEO=auto # XVideo support HAVE_PYTHON=no # Python 3 support for shaders C89_PYTHON=no @@ -102,3 +103,4 @@ HAVE_HID=yes # Low-level HID (Human Interface Device) support HAVE_LANGEXTRA=yes # Multi-language support HAVE_OSMESA=no # Off-screen Mesa rendering HAVE_VIDEOPROCESSOR=auto # Enable video processor core +HAVE_VIDEOCORE=auto # Broadcom Videocore 4 support diff --git a/retroarch.c b/retroarch.c index 7def51cb4b..273876455f 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2,6 +2,7 @@ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2012-2015 - Michael Lelli + * Copyright (C) 2015-2017 - Andrés Suárez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -236,6 +237,8 @@ static bool runloop_shutdown_initiated = false; static bool runloop_core_shutdown_initiated = false; static bool runloop_perfcnt_enable = false; static bool runloop_overrides_active = false; +static bool runloop_remaps_core_active = false; +static bool runloop_remaps_game_active = false; static bool runloop_game_options_active = false; static bool runloop_missing_bios = false; static bool runloop_autosave = false; @@ -310,6 +313,8 @@ static void global_free(void) rarch_ups_pref = false; rarch_patch_blocked = false; runloop_overrides_active = false; + runloop_remaps_core_active = false; + runloop_remaps_game_active = false; core_unset_input_descriptors(); @@ -1587,6 +1592,22 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) break; case RARCH_CTL_IS_OVERRIDES_ACTIVE: return runloop_overrides_active; + case RARCH_CTL_SET_REMAPS_CORE_ACTIVE: + runloop_remaps_core_active = true; + break; + case RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE: + runloop_remaps_core_active = false; + break; + case RARCH_CTL_IS_REMAPS_CORE_ACTIVE: + return runloop_remaps_core_active; + case RARCH_CTL_SET_REMAPS_GAME_ACTIVE: + runloop_remaps_game_active = true; + break; + case RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE: + runloop_remaps_game_active = false; + break; + case RARCH_CTL_IS_REMAPS_GAME_ACTIVE: + return runloop_remaps_game_active; case RARCH_CTL_SET_MISSING_BIOS: runloop_missing_bios = true; break; @@ -2161,6 +2182,7 @@ bool retroarch_main_quit(void) command_event(CMD_EVENT_AUTOSAVE_STATE, NULL); command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL); command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL); + command_event(CMD_EVENT_RESTORE_REMAPS, NULL); } runloop_shutdown_initiated = true; @@ -2402,10 +2424,10 @@ static enum runloop_state runloop_check_state( current_input, RARCH_GRAB_MOUSE_TOGGLE); if (pressed && !old_pressed) -#if 1 - command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); -#else +#if HAVE_LIBUI command_event(CMD_EVENT_LIBUI_TEST, NULL); +#else + command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); #endif old_pressed = pressed; diff --git a/retroarch.h b/retroarch.h index e01d4985b6..faf8b5a1df 100644 --- a/retroarch.h +++ b/retroarch.h @@ -98,6 +98,14 @@ enum rarch_ctl_state RARCH_CTL_SET_OVERRIDES_ACTIVE, RARCH_CTL_UNSET_OVERRIDES_ACTIVE, + RARCH_CTL_IS_REMAPS_CORE_ACTIVE, + RARCH_CTL_SET_REMAPS_CORE_ACTIVE, + RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE, + + RARCH_CTL_IS_REMAPS_GAME_ACTIVE, + RARCH_CTL_SET_REMAPS_GAME_ACTIVE, + RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE, + RARCH_CTL_IS_MISSING_BIOS, RARCH_CTL_SET_MISSING_BIOS, RARCH_CTL_UNSET_MISSING_BIOS, diff --git a/tasks/task_audio_mixer.c b/tasks/task_audio_mixer.c index cbf0b4c6fa..ee5d70f0c1 100644 --- a/tasks/task_audio_mixer.c +++ b/tasks/task_audio_mixer.c @@ -99,6 +99,28 @@ static void task_audio_mixer_handle_upload_ogg(void *task_data, free(user_data); } +static void task_audio_mixer_handle_upload_mod(void *task_data, + void *user_data, const char *err) +{ + audio_mixer_stream_params_t params; + nbio_buf_t *img = (nbio_buf_t*)task_data; + + if (!img) + return; + + params.volume = 1.0f; + params.type = AUDIO_MIXER_TYPE_MOD; + params.state = AUDIO_STREAM_STATE_PLAYING; + params.buf = img->buf; + params.bufsize = img->bufsize; + params.cb = NULL; + + audio_driver_mixer_add_stream(¶ms); + + free(img); + free(user_data); +} + static void task_audio_mixer_handle_upload_wav(void *task_data, void *user_data, const char *err) { @@ -191,6 +213,14 @@ bool task_push_audio_mixer_load(const char *fullpath, retro_task_callback_t cb, nbio->type = NBIO_TYPE_OGG; t->callback = task_audio_mixer_handle_upload_ogg; } + else if ( strstr(fullpath, file_path_str(FILE_PATH_MOD_EXTENSION)) || + strstr(fullpath, file_path_str(FILE_PATH_S3M_EXTENSION)) || + strstr(fullpath, file_path_str(FILE_PATH_XM_EXTENSION))) + { + image->type = AUDIO_MIXER_TYPE_MOD; + nbio->type = NBIO_TYPE_MOD; + t->callback = task_audio_mixer_handle_upload_mod; + } nbio->data = (struct audio_mixer_handle*)image; nbio->is_finished = false; diff --git a/tasks/task_autodetect.c b/tasks/task_autodetect.c index e3da649000..b43bf8e87e 100644 --- a/tasks/task_autodetect.c +++ b/tasks/task_autodetect.c @@ -189,6 +189,8 @@ static void input_autoconfigure_joypad_add(config_file_t *conf, { if (config_get_bool(conf, "input_swap_override", &tmp)) input_autoconfigure_swap_override = tmp; + else + input_autoconfigure_swap_override = false; } if (!block_osd_spam) diff --git a/tasks/task_database.c b/tasks/task_database.c index df8d9e00f6..1a28754fb6 100644 --- a/tasks/task_database.c +++ b/tasks/task_database.c @@ -75,6 +75,8 @@ int detect_ps1_game(const char *track_path, char *game_id); int detect_psp_game(const char *track_path, char *game_id); +int detect_serial_ascii_game(const char *track_path, char *game_id); + static void database_info_set_type(database_info_handle_t *handle, enum database_type type) { if (!handle) @@ -139,10 +141,21 @@ static int iso_get_serial(database_state_handle_t *db_state, database_info_handle_t *db, const char *name, char* serial) { const char* system_name = NULL; - int rv = detect_system(name, &system_name); - if (rv < 0) - return rv; + /* Check if the system was not auto-detected. */ + if (detect_system(name, &system_name) < 0) + { + /* Attempt to read an ASCII serial, like Wii. */ + if (detect_serial_ascii_game(name, serial)) + { + /* ASCII serial (Wii) was detected. */ + RARCH_LOG("%s '%s'\n", msg_hash_to_str(MSG_FOUND_DISK_LABEL), serial); + return 0; + } + + /* Any other non-system specific detection methods? */ + return 0; + } if (string_is_equal_fast(system_name, "psp", 3)) { diff --git a/tasks/task_database_cue.c b/tasks/task_database_cue.c index 4ffb195a16..738dc30b13 100644 --- a/tasks/task_database_cue.c +++ b/tasks/task_database_cue.c @@ -153,7 +153,7 @@ static int detect_ps1_game_sub(const char *track_path, uint8_t* boot_file; int skip, frame_size, is_mode1, cd_sector; uint8_t buffer[2048 * 2]; - RFILE *fp = + RFILE *fp = filestream_open(track_path, RFILE_MODE_READ, -1); if (!fp) return 0; @@ -328,13 +328,66 @@ int detect_psp_game(const char *track_path, char *game_id) return rv; } +/** + * Check for an ASCII serial in the first few bits of the ISO (Wii). + */ +int detect_serial_ascii_game(const char *track_path, char *game_id) +{ + unsigned pos; + int numberOfAscii = 0; + bool rv = false; + RFILE *fd = filestream_open(track_path, RFILE_MODE_READ, -1); + + /* Attempt to load the file. */ + if (!fd) + { + RARCH_LOG("%s: %s\n", + msg_hash_to_str(MSG_COULD_NOT_OPEN_DATA_TRACK), + strerror(errno)); + return -errno; + } + + for (pos = 0; pos < 10000; pos++) + { + filestream_seek(fd, pos, SEEK_SET); + if (filestream_read(fd, game_id, 10000) > 0) + { + unsigned i; + game_id[15] = '\0'; + numberOfAscii = 0; + + /* Loop through until we run out of ASCII characters. */ + for (i = 0; i < 15; i++) + { + /* Is the given character ASCII? A-Z, 0-9, - */ + if (game_id[i] == 45 || (game_id[i] >= 48 && game_id[i] <= 57) || (game_id[i] >= 65 && game_id[i] <= 90)) + numberOfAscii++; + else + break; + } + + /* If the length of the text is between 3 and 9 characters, it could be a serial. */ + if (numberOfAscii > 3 && numberOfAscii < 9) + { + /* Cut the string off, and return it as a valid serial. */ + game_id[numberOfAscii] = '\0'; + rv = true; + break; + } + } + } + + filestream_close(fd); + return rv; +} + int detect_system(const char *track_path, const char **system_name) { int rv; char magic[MAGIC_LEN]; int i; RFILE *fd = filestream_open(track_path, RFILE_MODE_READ, -1); - + if (!fd) { RARCH_LOG("Could not open data track of file '%s': %s\n", @@ -390,7 +443,7 @@ int find_first_data_track(const char *cue_path, { int rv; char tmp_token[MAX_TOKEN_LEN]; - RFILE *fd = + RFILE *fd = filestream_open(cue_path, RFILE_MODE_READ, -1); if (!fd) diff --git a/tasks/task_file_transfer.c b/tasks/task_file_transfer.c index 317152e7d9..de00534f4d 100644 --- a/tasks/task_file_transfer.c +++ b/tasks/task_file_transfer.c @@ -104,6 +104,7 @@ void task_file_load_handler(retro_task_t *task) task_set_finished(task, true); break; case NBIO_TYPE_OGG: + case NBIO_TYPE_MOD: case NBIO_TYPE_WAV: if (!task_audio_mixer_load_handler(task)) task_set_finished(task, true); diff --git a/tasks/task_netplay_find_content.c b/tasks/task_netplay_find_content.c index 1dd9df061e..0adb00ed82 100644 --- a/tasks/task_netplay_find_content.c +++ b/tasks/task_netplay_find_content.c @@ -236,12 +236,14 @@ filename_matching: for (j = 0; j < playlist_size; j++) { + char entry[PATH_MAX_LENGTH]; const char *playlist_path = NULL; + const char *buf = NULL; + playlist_get_index(playlist, j, &playlist_path, NULL, NULL, NULL, NULL, NULL); - char entry[PATH_MAX_LENGTH]; - const char* buf = path_basename(playlist_path); + buf = path_basename(playlist_path); entry[0] = '\0'; strlcpy(entry, buf, sizeof(entry)); diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 990839e7f6..ac960cd049 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -211,7 +211,7 @@ static bool screenshot_dump( screenshot_path[0] = '\0'; - if (string_is_empty(screenshot_dir)) + if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) { fill_pathname_basedir(screenshot_path, name_base, sizeof(screenshot_path)); diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index bb74a2d3a3..390d9d49be 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -74,6 +74,7 @@ enum nbio_type NBIO_TYPE_TGA, NBIO_TYPE_BMP, NBIO_TYPE_OGG, + NBIO_TYPE_MOD, NBIO_TYPE_WAV }; diff --git a/tools/ps3/ps3py/pkg.py b/tools/ps3/ps3py/pkg.py index 219608bb0d..fa545d8227 100755 --- a/tools/ps3/ps3py/pkg.py +++ b/tools/ps3/ps3py/pkg.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 from __future__ import with_statement import struct, sys diff --git a/ui/drivers/ui_win32.c b/ui/drivers/ui_win32.c index e5943ec2b2..5b2a411390 100644 --- a/ui/drivers/ui_win32.c +++ b/ui/drivers/ui_win32.c @@ -101,7 +101,7 @@ typedef struct HWND label_title; HWND label_val; } trackbar; - }; + } elems; } shader_param_ctrl_t; typedef struct @@ -128,7 +128,7 @@ static bool shader_dlg_refresh_trackbar_label(int index, snprintf(val_buffer, sizeof(val_buffer), "%.2f", shader_info->data->parameters[index].current); - SendMessage(g_shader_dlg.controls[index].trackbar.label_val, + SendMessage(g_shader_dlg.controls[index].elems.trackbar.label_val, WM_SETTEXT, 0, (LPARAM)val_buffer); return true; @@ -155,7 +155,7 @@ static void shader_dlg_params_refresh(void) bool checked = shader_info.data ? (shader_info.data->parameters[i].current == shader_info.data->parameters[i].maximum) : false; - SendMessage(control->checkbox.hwnd, BM_SETCHECK, checked, 0); + SendMessage(control->elems.checkbox.hwnd, BM_SETCHECK, checked, 0); } break; case SHADER_PARAM_CTRL_TRACKBAR: @@ -167,14 +167,14 @@ static void shader_dlg_params_refresh(void) if (shader_info.data) { - SendMessage(control->trackbar.hwnd, + SendMessage(control->elems.trackbar.hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0); - SendMessage(control->trackbar.hwnd, + SendMessage(control->elems.trackbar.hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)((shader_info.data->parameters[i].maximum - shader_info.data->parameters[i].minimum) / shader_info.data->parameters[i].step)); - SendMessage(control->trackbar.hwnd, TBM_SETPOS, (WPARAM)TRUE, + SendMessage(control->elems.trackbar.hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)((shader_info.data->parameters[i].current - shader_info.data->parameters[i].minimum) / shader_info.data->parameters[i].step)); @@ -207,13 +207,13 @@ static void shader_dlg_params_clear(void) { const ui_window_t *window = ui_companion_driver_get_window_ptr(); if (window) - window->destroy(&control->checkbox); + window->destroy(&control->elems.checkbox); } break; case SHADER_PARAM_CTRL_TRACKBAR: - DestroyWindow(control->trackbar.label_title); - DestroyWindow(control->trackbar.label_val); - DestroyWindow(control->trackbar.hwnd); + DestroyWindow(control->elems.trackbar.label_title); + DestroyWindow(control->elems.trackbar.label_val); + DestroyWindow(control->elems.trackbar.hwnd); break; } @@ -260,12 +260,12 @@ void shader_dlg_params_reload(void) } control->type = SHADER_PARAM_CTRL_CHECKBOX; - control->checkbox.hwnd = CreateWindowEx(0, "BUTTON", + control->elems.checkbox.hwnd = CreateWindowEx(0, "BUTTON", shader_info.data->parameters[i].desc, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, pos_x, pos_y, SHADER_DLG_CTRL_WIDTH, SHADER_DLG_CHECKBOX_HEIGHT, g_shader_dlg.window.hwnd, (HMENU)(size_t)i, NULL, NULL); - SendMessage(control->checkbox.hwnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); + SendMessage(control->elems.checkbox.hwnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); pos_y += SHADER_DLG_CHECKBOX_HEIGHT + SHADER_DLG_CTRL_MARGIN; } else @@ -277,29 +277,29 @@ void shader_dlg_params_reload(void) pos_x += SHADER_DLG_WIDTH; } - control->type = SHADER_PARAM_CTRL_TRACKBAR; - control->trackbar.label_title = CreateWindowEx(0, "STATIC", + control->type = SHADER_PARAM_CTRL_TRACKBAR; + control->elems.trackbar.label_title = CreateWindowEx(0, "STATIC", shader_info.data->parameters[i].desc, WS_CHILD | WS_VISIBLE | SS_LEFT, pos_x, pos_y, SHADER_DLG_CTRL_WIDTH, SHADER_DLG_LABEL_HEIGHT, g_shader_dlg.window.hwnd, (HMENU)(size_t)i, NULL, NULL); - SendMessage(control->trackbar.label_title, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); + SendMessage(control->elems.trackbar.label_title, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); pos_y += SHADER_DLG_LABEL_HEIGHT; - control->trackbar.hwnd = CreateWindowEx(0, TRACKBAR_CLASS, "", + control->elems.trackbar.hwnd = CreateWindowEx(0, (LPCSTR)TRACKBAR_CLASS, "", WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_NOTICKS, pos_x + SHADER_DLG_TRACKBAR_LABEL_WIDTH, pos_y, SHADER_DLG_TRACKBAR_WIDTH, SHADER_DLG_TRACKBAR_HEIGHT, g_shader_dlg.window.hwnd, (HMENU)(size_t)i, NULL, NULL); - control->trackbar.label_val = CreateWindowEx(0, "STATIC", "", + control->elems.trackbar.label_val = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE | SS_LEFT, pos_x, pos_y, SHADER_DLG_TRACKBAR_LABEL_WIDTH, SHADER_DLG_LABEL_HEIGHT, g_shader_dlg.window.hwnd, (HMENU)(size_t)i, NULL, NULL); - SendMessage(control->trackbar.label_val, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); + SendMessage(control->elems.trackbar.label_val, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); - SendMessage(control->trackbar.hwnd, TBM_SETBUDDY, (WPARAM)TRUE, - (LPARAM)control->trackbar.label_val); + SendMessage(control->elems.trackbar.hwnd, TBM_SETBUDDY, (WPARAM)TRUE, + (LPARAM)control->elems.trackbar.label_val); pos_y += SHADER_DLG_TRACKBAR_HEIGHT + SHADER_DLG_CTRL_MARGIN; @@ -402,7 +402,7 @@ static LRESULT CALLBACK ShaderDlgWndProc(HWND hwnd, UINT message, video_shader_ctx_t shader_info; video_shader_driver_get_current_shader(&shader_info); - if (SendMessage(g_shader_dlg.controls[i].checkbox.hwnd, + if (SendMessage(g_shader_dlg.controls[i].elems.checkbox.hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) shader_info.data->parameters[i].current = shader_info.data->parameters[i].maximum; @@ -424,7 +424,7 @@ static LRESULT CALLBACK ShaderDlgWndProc(HWND hwnd, UINT message, if (g_shader_dlg.controls[i].type != SHADER_PARAM_CTRL_TRACKBAR) break; - pos = (int)SendMessage(g_shader_dlg.controls[i].trackbar.hwnd, TBM_GETPOS, 0, 0); + pos = (int)SendMessage(g_shader_dlg.controls[i].elems.trackbar.hwnd, TBM_GETPOS, 0, 0); { diff --git a/ui/drivers/win32/ui_win32_browser_window.c b/ui/drivers/win32/ui_win32_browser_window.c index 93dcaa8a55..61c05e6907 100644 --- a/ui/drivers/win32/ui_win32_browser_window.c +++ b/ui/drivers/win32/ui_win32_browser_window.c @@ -25,17 +25,33 @@ static bool ui_browser_window_win32_core(ui_browser_window_state_t *state, bool save) { - OPENFILENAME ofn = {}; + OPENFILENAME ofn; - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = (HWND)state->window; - ofn.lpstrFilter = state->filters; /* actually const */ - ofn.lpstrFile = state->path; - ofn.lpstrTitle = state->title; - ofn.lpstrInitialDir = state->startdir; - ofn.lpstrDefExt = ""; - ofn.nMaxFile = PATH_MAX; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = (HWND)state->window; + ofn.hInstance = NULL; + ofn.lpstrFilter = state->filters; /* actually const */ + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 0; + ofn.lpstrFile = state->path; + ofn.nMaxFile = PATH_MAX; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = state->startdir; + ofn.lpstrTitle = state->title; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = ""; + ofn.lCustData = 0; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; +#if (_WIN32_WINNT >= 0x0500) + ofn.pvReserved = NULL; + ofn.dwReserved = 0; + ofn.FlagsEx = 0; +#endif if (!save && !GetOpenFileName(&ofn)) return false; diff --git a/ui/drivers/win32/ui_win32_window.cpp b/ui/drivers/win32/ui_win32_window.cpp index 8a0d1e981a..8a2c4243f5 100644 --- a/ui/drivers/win32/ui_win32_window.cpp +++ b/ui/drivers/win32/ui_win32_window.cpp @@ -75,11 +75,17 @@ static void ui_window_win32_set_title(void *data, char *buf) SetWindowText(window->hwnd, buf); } +extern "C" +{ + VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); +} + void ui_window_win32_set_droppable(void *data, bool droppable) { /* Minimum supported client: Windows XP, minimum supported server: Windows 2000 Server */ ui_window_win32_t *window = (ui_window_win32_t*)data; - DragAcceptFiles(window->hwnd, droppable); + if (DragAcceptFiles_func != NULL) + DragAcceptFiles_func(window->hwnd, droppable); } static bool ui_window_win32_focused(void *data) diff --git a/version.h b/version.h index e60a30e05e..e10de54d6a 100644 --- a/version.h +++ b/version.h @@ -18,7 +18,7 @@ #define RARCH_VERSION_H__ #ifndef PACKAGE_VERSION -#define PACKAGE_VERSION "1.6.1" +#define PACKAGE_VERSION "1.6.7" #endif #endif diff --git a/wii/app_booter/Makefile b/wii/app_booter/Makefile index 4523f9045e..6a4b48fc92 100644 --- a/wii/app_booter/Makefile +++ b/wii/app_booter/Makefile @@ -14,6 +14,7 @@ else ifneq ($(findstring MINGW,$(shell uname -a)),) system_platform = win endif +EXTERNAL_LIBOGC = 0 CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) LD = $(DEVKITPPC)/bin/powerpc-eabi-ld$(EXE_EXT) OBJCOPY = $(DEVKITPPC)/bin/powerpc-eabi-objcopy$(EXE_EXT) @@ -23,8 +24,16 @@ ELF_TARGET := app_booter.elf LIBRETRO_COMM_DIR := ../../libretro-common -INCLUDE := -I. -I$(DEVKITPRO)/libogc/include -I$(LIBRETRO_COMM_DIR)/crt/include -LIBDIRS := -L$(DEVKITPRO)/libogc/lib/wii +LIBDIRS := +INCLUDE := -I. -I$(LIBRETRO_COMM_DIR)/crt/include + +ifeq ($(EXTERNAL_LIBOGC), 1) +INCLUDE += -I$(DEVKITPRO)/libogc/include +LIBDIRS += -L$(DEVKITPRO)/libogc/lib/wii +else +INCLUDE += -I../libogc/include +LIBDIRS += -Lwii/libogc/libs/wii +endif MACHDEP := -DHW_RVL -DGEKKO -mno-eabi -mno-sdata -mcpu=750 # todo: find out why -Os spits out linker errors diff --git a/wii/libogc/include/aesndlib.h b/wii/libogc/include/aesndlib.h new file mode 100644 index 0000000000..4d47d045c1 --- /dev/null +++ b/wii/libogc/include/aesndlib.h @@ -0,0 +1,61 @@ +#ifndef __AESNDLIB_H__ +#define __AESNDLIB_H__ + +#include + +#define MAX_VOICES 32 +#define SND_BUFFERSIZE 384 // output 2ms sound data at 48KHz +#define DSP_STREAMBUFFER_SIZE 1152 // input 2ms sound data at max. 144KHz + +#if defined(HW_DOL) + #define DSP_DEFAULT_FREQ 48044 +#elif defined(HW_RVL) + #define DSP_DEFAULT_FREQ 48000 +#endif + +#define VOICE_STATE_STOPPED 0 +#define VOICE_STATE_RUNNING 1 +#define VOICE_STATE_STREAM 2 + +#define VOICE_MONO8 0x00000000 +#define VOICE_STEREO8 0x00000001 +#define VOICE_MONO16 0x00000002 +#define VOICE_STEREO16 0x00000003 + +#define VOICE_FREQ32KHZ 32000 +#define VOICE_FREQ48KHZ 48000 + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct aesndpb_t AESNDPB; + +typedef void (*AESNDVoiceCallback)(AESNDPB *pb,u32 state); +typedef void (*AESNDAudioCallback)(void *audio_buffer,u32 len); + +void AESND_Init(); +void AESND_Reset(); +void AESND_Pause(bool pause); +u32 AESND_GetDSPProcessTime(); +f32 AESND_GetDSPProcessUsage(); +AESNDAudioCallback AESND_RegisterAudioCallback(AESNDAudioCallback cb); + +AESNDPB* AESND_AllocateVoice(AESNDVoiceCallback cb); +void AESND_FreeVoice(AESNDPB *pb); +void AESND_SetVoiceStop(AESNDPB *pb,bool stop); +void AESND_SetVoiceMute(AESNDPB *pb,bool mute); +void AESND_SetVoiceLoop(AESNDPB *pb,bool loop); +void AESND_SetVoiceFormat(AESNDPB *pb,u32 format); +void AESND_SetVoiceStream(AESNDPB *pb,bool stream); +void AESND_SetVoiceFrequency(AESNDPB *pb,u32 freq); +void AESND_SetVoiceVolume(AESNDPB *pb,u16 volume_l,u16 volume_r); +void AESND_SetVoiceBuffer(AESNDPB *pb,const void *buffer,u32 len); +void AESND_PlayVoice(AESNDPB *pb,u32 format,const void *buffer,u32 len,u32 freq,u32 delay,bool looped); +AESNDVoiceCallback AESND_RegisterVoiceCallback(AESNDPB *pb,AESNDVoiceCallback cb); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/asndlib.h b/wii/libogc/include/asndlib.h new file mode 100644 index 0000000000..ed62daf57a --- /dev/null +++ b/wii/libogc/include/asndlib.h @@ -0,0 +1,383 @@ +/* ASNDLIB -> accelerated sound lib using the DSP + +Copyright (c) 2008 Hermes +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. +- The names of the contributors 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. + +*/ + + +#ifndef __ASNDLIB_H__ +#define __ASNDLIB_H__ + +#define __SNDLIB_H__ + +/*! + * \file asndlib.h + * \brief ASND library + * + */ + +#define ASND_LIB 0x100 +#define SND_LIB (ASND_LIB+2) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup sndretvals SND return values + * @{ + */ +#define SND_OK 0 +#define SND_INVALID -1 +#define SND_ISNOTASONGVOICE -2 +#define SND_BUSY 1 +/*! @} */ + +/*! \addtogroup sndiavretvals SND_IsActiveVoice additional return values + * @{ + */ +#define SND_UNUSED 0 /*!< This voice is available for use. */ +#define SND_WORKING 1 /*!< This voice is currently in progress. */ +#define SND_WAITING 2 /*!< This voice is currently in progress and waiting to one SND_AddVoice() function (the voice handler is called continuously) */ +/*! @} */ + +/*! \addtogroup sndsetvoiceformats Voice format + * @{ + */ +#define VOICE_MONO_8BIT 0 +#define VOICE_MONO_16BIT 1 +#define VOICE_MONO_16BIT_BE 1 +#define VOICE_STEREO_8BIT 2 +#define VOICE_STEREO_16BIT 3 +#define VOICE_STEREO_16BIT_BE 3 +#define VOICE_MONO_8BIT_U 4 +#define VOICE_MONO_16BIT_LE 5 +#define VOICE_STEREO_8BIT_U 6 +#define VOICE_STEREO_16BIT_LE 7 +/*! @} */ + +/*! \addtogroup voicevol Voice volume + * @{ + */ +#define MIN_VOLUME 0 +#define MID_VOLUME 127 +#define MAX_VOLUME 255 +/*! @} */ + +/*! \addtogroup pitchrange Pitch Range + * @{ + */ +#define MIN_PITCH 1 /*!< 1Hz */ +#define F44100HZ_PITCH 44100 /*!< 44100Hz */ +#define MAX_PITCH 144000 /*!< 144000Hz (more process time for pitch>48000) */ +#define INIT_RATE_48000 +/*! @} */ + +/*! \addtogroup notecode Note codification + * @{ + */ +enum +{ +NOTE_DO=0, +NOTE_DOs, +NOTE_REb=NOTE_DOs, +NOTE_RE, +NOTE_REs, +NOTE_MIb=NOTE_REs, +NOTE_MI, +NOTE_FA, +NOTE_FAs, +NOTE_SOLb=NOTE_FAs, +NOTE_SOL, +NOTE_SOLs, +NOTE_LAb=NOTE_SOLs, +NOTE_LA, +NOTE_LAs, +NOTE_SIb=NOTE_LAs, +NOTE_SI +}; + +enum +{ +NOTE_C=0, +NOTE_Cs, +NOTE_Db=NOTE_Cs, +NOTE_D, +NOTE_Ds, +NOTE_Eb=NOTE_Ds, +NOTE_E, +NOTE_F, +NOTE_Fs, +NOTE_Gb=NOTE_Fs, +NOTE_G, +NOTE_Gs, +NOTE_Ab=NOTE_Gs, +NOTE_A, +NOTE_As, +NOTE_Bb=NOTE_As, +NOTE_B +}; + +#define NOTE(note,octave) (note+(octave<<3)+(octave<<2)) /*!< Final note codification. Used in Note2Freq(). */ +/*! @} */ + +/*------------------------------------------------------------------------------------------------------------------------------------------------------*/ + +/*! \addtogroup sndlibcompat SNDLIB compatibility macros + * \details These defines are for compatability with SNDLIB functions. + * @{ + */ +#define Note2Freq ANote2Freq +#define SND_Init ASND_Init +#define SND_End ASND_End +#define SND_Pause ASND_Pause +#define SND_Is_Paused ASND_Is_Paused +#define SND_GetTime ASND_GetTime +#define SND_GetSampleCounter ASND_GetSampleCounter +#define SND_GetSamplesPerTick ASND_GetSamplesPerTick +#define SND_SetTime ASND_SetTime +#define SND_SetCallback ASND_SetCallback +#define SND_GetAudioRate ASND_GetAudioRate +#define SND_SetVoice ASND_SetVoice +#define SND_AddVoice ASND_AddVoice +#define SND_StopVoice ASND_StopVoice +#define SND_PauseVoice ASND_PauseVoice +#define SND_StatusVoice ASND_StatusVoice +#define SND_GetFirstUnusedVoice ASND_GetFirstUnusedVoice +#define SND_ChangePitchVoice ASND_ChangePitchVoice +#define SND_ChangeVolumeVoice ASND_ChangeVolumeVoice +#define SND_ChangeVolumeVoice ASND_ChangeVolumeVoice +#define SND_GetTickCounterVoice ASND_GetTickCounterVoice +#define SND_GetTimerVoice ASND_GetTimerVoice +#define SND_TestPointer ASND_TestPointer +/*! @} */ + +/*------------------------------------------------------------------------------------------------------------------------------------------------------*/ + +/** \brief Callback type for ASND_SetVoice(). */ +typedef void (*ASNDVoiceCallback)(s32 voice); + +/*------------------------------------------------------------------------------------------------------------------------------------------------------*/ + +/** \brief Initializes the SND lib and fixes the hardware sample rate. + * \param[in] note \ref notecode to play. for example: NOTE(C,4) for note C and octave 4. + * \param[in] freq_base Frequency base of the sample. For example 8000Hz. + * \param[in] note_base \ref notecode of the sample. For example: NOTE(L, 3) for note L and octave 3 (LA 3). + * \return Frequency, in Hz. */ +int ANote2Freq(int note, int freq_base,int note_base); + +/*------------------------------------------------------------------------------------------------------------------------------------------------------*/ + +/*! \addtogroup General sound functions + * @{ + */ + +/*! \brief Initializes the ASND lib and fixes the hardware sample rate to 48000. + * \return None. */ +void ASND_Init(); + +/*! \brief De-initializes the ASND lib. + * \return None. */ +void ASND_End(); + +/*! \brief Used to pause (or unpause) the sound. + * \note The sound starts paused when ASND_Init() is called. + * \param[in] paused If 1, sound is paused; sound can be unpaused with 0. + * \return None. */ +void ASND_Pause(s32 paused); + +/*! \brief Returns sound paused status. + * \return 1 if paused, 0 if unpaused. */ +s32 ASND_Is_Paused(); + +/*! \brief Returns the global time. + * \details The time is updated from the IRQ. + * \return The current time, in milliseconds. */ +u32 ASND_GetTime(); + +/*! \brief Retrieves the global sample counter. + * \details This counter is updated from the IRQ in steps of ASND_GetSamplesPerTick(). + * \note You can use this to implement one timer with high precision. + * \return Current sample. */ +u32 ASND_GetSampleCounter(); + +/*! \brief Retrieves the samples sent from the IRQ in one tick. + * \return Samples per tick. */ +u32 ASND_GetSamplesPerTick(); + +/*! \brief Set the global time. + * \details This time is updated from the IRQ. + * \param[in] time Fix the current time, in milliseconds. + * \return None. */ +void ASND_SetTime(u32 time); + +/*! \brief Sets a global callback for general purposes. + * \details This callback is called from the IRQ. + * \param[in] callback Callback function to assign. + * \return None. */ +void ASND_SetCallback(void (*callback)()); + +/*! \brief Returns the current audio rate. + * \note This function is implemented for compatibility with SNDLIB. + * \return Audio rate (48000). */ +s32 ASND_GetAudioRate(); + +/*! @} */ + +/*! \addtogroup voicefuncs Voice functions + * @{ + */ + +// NOTE: I'm keeping this description around because I couldn't fully understand it; if someone else knows exactly what it's doing, they can come around +// and make sure the description is correct. +/* callback: can be NULL or one callback function is used to implement a double buffer use. When the second buffer is empty, the callback is called sending + the voice number as parameter. You can use "void callback(s32 voice)" function to call ASND_AddVoice() and add one voice to the second buffer. + NOTE: When callback is fixed the voice never stops and it turn in SND_WAITING status if success one timeout condition. +*/ + +/*! \brief Sets a PCM voice to play. + * \details This function stops one previous voice. Use ASND_StatusVoice() to test the status condition. + * \note The voices are played in 16-bit stereo, regardless of the source format.

+ * + * \note \a callback is used to implement a double buffer. When the second buffer is empty, the callback function is called with the voice number + * as an argument. You can use void callback (s32 voice) to call ASND_AddVoice() and add one voice to the second buffer. When the callback + * is non-NULL the, the voice never stops and returns SND_WAITING if successful on timeout condition. + * \param[in] voice Voice slot to use for this sound; valid values are 0 to (MAX_SND_VOICES-1). + * \param[in] format \ref sndsetvoiceformats to use for this sound. + * \param[in] pitch Frequency to use, in Hz. + * \param[in] delay Delay to wait before playing this voice; value is in milliseconds. + * \param[in] snd Buffer containing samples to play back; the buffer must be aligned and padded to 32 bytes! + * \param[in] size_snd Size of the buffer samples, in bytes. + * \param[in] volume_l \ref voicevol of the left channel; value can be 0 - 255 inclusive. + * \param[in] volume_r \ref voicevol of the right channel; value can be 0 - 255 inclusive. + * \param[in] callback Optional callback function to use; set to NULL for no callback. See the note above for details. + * \return SND_OK or SND_INVALID. */ +s32 ASND_SetVoice(s32 voice, s32 format, s32 pitch,s32 delay, void *snd, s32 size_snd, s32 volume_l, s32 volume_r, ASNDVoiceCallback callback); + +/*! \brief Sets a PCM voice to play infinitely. + * \note See ASND_SetVoice() for a detailed description, as it is largely identical. */ +s32 ASND_SetInfiniteVoice(s32 voice, s32 format, s32 pitch,s32 delay, void *snd, s32 size_snd, s32 volume_l, s32 volume_r); + +/*! \brief Adds a PCM voice to play from the second buffer. + * \note This function requires a call to ASND_SetVoice() and its subsequent return value to be a status other than SND_UNUSED prior to calling this one. + * \param[in] voice Voice slot to attach this buffer to; value must be 0 to (MAX_SND_VOICES-1). + * \param[in] snd Buffer containing the samples; it must be aligned and padded to 32 bytes AND have the same sample format as the first buffer. + * \param[in] size_snd Size of the buffer samples, in bytes. + * \return SND_OK or SND_INVALID; it may also return SND_BUSY if the second buffer is not empty and the voice cannot be added. */ +s32 ASND_AddVoice(s32 voice, void *snd, s32 size_snd); + +/*! \brief Stops the selected voice. + * \details If the voice is used in song mode, you need to assign the samples with ASND_SetSongSampleVoice() again. In this case, use ANS_PauseSongVoice() + * to stop the voice without loss of samples. + * \param[in] voice Voice to stop, from 0 to (MAX_SND_VOICES-1). + * \return SND_OK or SND_INVALID. */ +s32 ASND_StopVoice(s32 voice); + +/*! \brief Pauses the selected voice. + * \param[in] voice Voice to pause, from 0 to (MAX_SND_VOICES-1). + * \return SND_OK or SND_INVALID. */ +s32 ASND_PauseVoice(s32 voice, s32 pause); + +/*! \brief Returns the status of the selected voice. + * \param[in] voice Voice slot to get the status from, from 0 to (MAX_SND_VOICES-1). + * \return SND_INVALID if invalid, else a value from \ref sndiavretvals. */ +s32 ASND_StatusVoice(s32 voice); + +/*! \brief Returns the first unused voice. + * \note Voice 0 is the last possible voice that can be returned. The idea is that this voice is reserved for a MOD/OGG/MP3/etc. player. With this in mind, + * you can use this function to determine that the rest of the voices are working if the return value is < 1. + * \return SND_INVALID or the first free voice from 0 to (MAX_SND_VOICES-1). */ +s32 ASND_GetFirstUnusedVoice(); + +/*! \brief Changes the voice pitch in real-time. + * \details This function can be used to create audio effects such as Doppler effect emulation. + * \param[in] voice Voice to change the pitch of, from 0 to (MAX_SND_VOICES-1). + * \return SND_OK or SND_INVALID. */ +s32 ASND_ChangePitchVoice(s32 voice, s32 pitch); + +/*! \brief Changes the voice volume in real-time. + * \details This function can be used to create audio effects like distance attenuation. + * \param[in] voice Voice to change the volume of, from 0 to (MAX_SND_VOICES-1). + * \param[in] volume_l \ref voicevol to set the left channel to, from 0 to 255. + * \param[in] volume_r \ref voicevol to set the right channel to, from 0 to 255. + * \return SND_OK or SND_INVALID. */ +s32 ASND_ChangeVolumeVoice(s32 voice, s32 volume_l, s32 volume_r); + +/*! \brief Returns the voice tick counter. + * \details This value represents the number of ticks since this voice started to play, sans delay time. It uses the same resolution as the internal + * sound buffer. For example, if the lib is initialized with INIT_RATE_48000, a return value of 24000 is equal to 0.5 seconds. This value can be used, for + * example, to synchronize audio and video. + * \note This function does not return error codes. + * \param[in] voice Voice to retrieve the counter value from, from 0 to (MAX_SND_VOICES-1). + * \return Number of ticks since this voice started playing. */ +u32 ASND_GetTickCounterVoice(s32 voice); + +/*! \brief Returns the voice playback time. + * \details This value represents the time, in milliseconds, since this voice started playing, sans delay time. This value can be used, for example, to + * synchronize audio and video. + * \note This function does not return error codes. + * \param[in] voice Voice to retrieve the time value from, from 0 to (MAX_SND_VOICES-1). + * \return Amount of time since this voice has started playing. */ +u32 ASND_GetTimerVoice(s32 voice); + +/*! \brief Tests if \a pointer is in use by \a voice as a buffer. + * \param[in] voice Voice to test, from 0 to (MAX_SND_VOICES-1). + * \param[in] pointer Address to test. This must be the same pointer sent to ASND_AddVoice() or ASND_SetVoice(). + * \return SND_INVALID if invalid + * \return 0 if the pointer is unused + * \return 1 if the pointer used as a buffer. */ +s32 ASND_TestPointer(s32 voice, void *pointer); + +/*! \brief Tests to determine if the \a voice is ready to receive a new buffer sample with ASND_AddVoice(). + * \details You can use this function to block a reader when double buffering is used. It works similarly to ASND_TestPointer() without needing to pass a + * pointer. + * \param[in] voice Voice to test, from 0 to (MAX_SND_VOICES-1). + * \return SND_INVALID + * \return 0 if voice is NOT ready to receive a new voice. + * \return 1 if voice is ready to receive a new voice with ASND_AddVoice(). */ +s32 ASND_TestVoiceBufferReady(s32 voice); + +/*! @} */ + +/*! \addtogroup dspfuncs DSP functions + * @{ + */ + +/*! \brief Returns the DSP usage. + * \details The value is a percentage of DSP usage. + * \return DSP usage, in percent. */ +u32 ASND_GetDSP_PercentUse(); + +u32 ASND_GetDSP_ProcessTime(); + +/*! @} */ + +#ifdef __cplusplus + } +#endif + +#endif + diff --git a/wii/libogc/include/bte/bd_addr.h b/wii/libogc/include/bte/bd_addr.h new file mode 100644 index 0000000000..87faf92675 --- /dev/null +++ b/wii/libogc/include/bte/bd_addr.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003 EISLAB, Lulea University of Technology. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwBT Bluetooth stack. + * + * Author: Conny Ohult + * + */ + +#ifndef __BD_ADDR_H__ +#define __BD_ADDR_H__ + +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +struct bd_addr { + u8 addr[6]; +}; + +#define BD_ADDR_LEN 6 + +#define BD_ADDR_ANY (&(struct bd_addr){{0,0,0,0,0,0}}) +#define BD_ADDR_LOCAL (&(struct bd_addr){{0,0,0,0xff,0xff,0xff}}) + +#define BD_ADDR(bdaddr, a, b, c, d, e, f) do{ \ + (bdaddr)->addr[0] = a; \ + (bdaddr)->addr[1] = b; \ + (bdaddr)->addr[2] = c; \ + (bdaddr)->addr[3] = d; \ + (bdaddr)->addr[4] = e; \ + (bdaddr)->addr[5] = f; }while(0) +//TODO: USE memcmp???? +#define bd_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1]) && \ + ((addr1)->addr[2] == (addr2)->addr[2]) && \ + ((addr1)->addr[3] == (addr2)->addr[3]) && \ + ((addr1)->addr[4] == (addr2)->addr[4]) && \ + ((addr1)->addr[5] == (addr2)->addr[5])) +//TODO: USE memcpy???? +#define bd_addr_set(addr1, addr2) do { \ + (addr1)->addr[0] = (addr2)->addr[0]; \ + (addr1)->addr[1] = (addr2)->addr[1]; \ + (addr1)->addr[2] = (addr2)->addr[2]; \ + (addr1)->addr[3] = (addr2)->addr[3]; \ + (addr1)->addr[4] = (addr2)->addr[4]; \ + (addr1)->addr[5] = (addr2)->addr[5]; }while(0) + + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* __BD_ADDR_H__ */ diff --git a/wii/libogc/include/bte/bte.h b/wii/libogc/include/bte/bte.h new file mode 100644 index 0000000000..e05e9cdddb --- /dev/null +++ b/wii/libogc/include/bte/bte.h @@ -0,0 +1,154 @@ +#ifndef __BTE_H__ +#define __BTE_H__ + +#include +#include "bd_addr.h" + +#define ERR_OK 0 +#define ERR_MEM -1 +#define ERR_BUF -2 +#define ERR_ABRT -3 +#define ERR_RST -4 +#define ERR_CLSD -5 +#define ERR_CONN -6 +#define ERR_VAL -7 +#define ERR_ARG -8 +#define ERR_RTE -9 +#define ERR_USE -10 +#define ERR_IF -11 +#define ERR_PKTSIZE -17 + +#define HIDP_STATE_READY 0x00 +#define HIDP_STATE_LISTEN 0x01 +#define HIDP_STATE_CONNECTING 0x02 +#define HIDP_STATE_CONNECTED 0x04 + +#define HIDP_CONTROL_CHANNEL 0x11 +#define HIDP_DATA_CHANNEL 0x13 + +#define HIDP_HDR_TRANS_MASK 0xf0 +#define HIDP_HDR_PARAM_MASK 0x0f + +#define HIDP_TRANS_HANDSHAKE 0x00 +#define HIDP_TRANS_HIDCONTROL 0x10 +#define HIDP_TRANS_GETREPORT 0x40 +#define HIDP_TRANS_SETREPORT 0x50 +#define HIDP_TRANS_GETPROTOCOL 0x60 +#define HIDP_TRANS_SETPROTOCOL 0x70 +#define HIDP_TRANS_GETIDLE 0x80 +#define HIDP_TRANS_SETIDLE 0x90 +#define HIDP_TRANS_DATA 0xa0 +#define HIDP_TRANS_DATAC 0xb0 + +#define HIDP_HSHK_SUCCESSFULL 0x00 +#define HIDP_HSHK_NOTREADY 0x01 +#define HIDP_HSHK_INV_REPORTID 0x02 +#define HIDP_HSHK_NOTSUPPORTED 0x03 +#define HIDP_HSHK_IVALIDPARAM 0x04 +#define HIDP_HSHK_UNKNOWNERROR 0x0e +#define HIDP_HSHK_FATALERROR 0x0f + +#define HIDP_CTRL_NOP 0x00 +#define HIDP_CTRL_HARDRESET 0x01 +#define HIDP_CTRL_SOFTRESET 0x02 +#define HIDP_CTRL_SUSPEND 0x03 +#define HIDP_CTRL_RESUME 0x04 +#define HIDP_CTRL_VC_UNPLUG 0x05 + +/* HIDP data transaction headers */ +#define HIDP_DATA_RTYPE_MASK 0x03 +#define HIDP_DATA_RSRVD_MASK 0x0c +#define HIDP_DATA_RTYPE_OTHER 0x00 +#define HIDP_DATA_RTYPE_INPUT 0x01 +#define HIDP_DATA_RTYPE_OUPUT 0x02 +#define HIDP_DATA_RTYPE_FEATURE 0x03 + +#define HIDP_PROTO_BOOT 0x00 +#define HIDP_PROTO_REPORT 0x01 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +struct l2cap_pcb; +struct ctrl_req_t; + +struct inquiry_info +{ + struct bd_addr bdaddr; + u8 cod[3]; +}; + +struct inquiry_info_ex +{ + struct bd_addr bdaddr; + u8 cod[3]; + u8 psrm; + u8 psm; + u16 co; +}; + +struct linkkey_info +{ + struct bd_addr bdaddr; + u8 key[16]; +}; + +struct bte_pcb +{ + u8 err; + u32 state; + void *cbarg; + + struct ctrl_req_t *ctrl_req_head; + struct ctrl_req_t *ctrl_req_tail; + + lwpq_t cmdq; + + struct bd_addr bdaddr; + + struct l2cap_pcb *ctl_pcb; + struct l2cap_pcb *data_pcb; + + + s32 (*recv)(void *arg,void *buffer,u16 len); + s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err); + s32 (*disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err); +}; + +typedef s32 (*btecallback)(s32 result,void *userdata); + +void BTE_Init(); +void BTE_Shutdown(); +s32 BTE_InitCore(btecallback cb); +s32 BTE_ApplyPatch(btecallback cb); +s32 BTE_InitSub(btecallback cb); +s32 BTE_ReadStoredLinkKey(struct linkkey_info *keys,u8 max_cnt,btecallback cb); +s32 BTE_ReadBdAddr(struct bd_addr *bdaddr, btecallback cb); +void (*BTE_SetDisconnectCallback(void (*callback)(struct bd_addr *bdaddr,u8 reason)))(struct bd_addr *bdaddr,u8 reason); + +struct bte_pcb* bte_new(); +void bte_arg(struct bte_pcb *pcb,void *arg); +void bte_received(struct bte_pcb *pcb, s32 (*recv)(void *arg,void *buffer,u16 len)); +void bte_disconnected(struct bte_pcb *pcb,s32 (disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); + +s32 bte_registerdeviceasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); + +s32 bte_disconnect(struct bte_pcb *pcb); + +//s32 bte_listen(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm); +//s32 bte_accept(struct bte_pcb *pcb,s32 (*recv)(void *arg,void *buffer,u16 len)); +s32 bte_inquiry(struct inquiry_info *info,u8 max_cnt,u8 flush); +s32 bte_inquiry_ex(struct inquiry_info_ex *info,u8 max_cnt,u8 flush); +//s32 bte_connect(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)); +//s32 bte_connect_ex(struct bte_pcb *pcb,struct inquiry_info_ex *info,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)); +s32 bte_senddata(struct bte_pcb *pcb,void *message,u16 len); +s32 bte_sendmessage(struct bte_pcb *pcb,void *message,u16 len); +s32 bte_sendmessageasync(struct bte_pcb *pcb,void *message,u16 len,s32 (*sent)(void *arg,struct bte_pcb *pcb,u8 err)); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif + diff --git a/wii/libogc/include/debug.h b/wii/libogc/include/debug.h new file mode 100644 index 0000000000..f87f726e38 --- /dev/null +++ b/wii/libogc/include/debug.h @@ -0,0 +1,43 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include + +#define GDBSTUB_DEVICE_USB 0 /*!< device type: USBGecko */ +#define GDBSTUB_DEVICE_TCP 1 /*!< device type: BBA-TCP */ + +#define GDBSTUB_DEF_CHANNEL 0 /*!< default EXI channel. channel can be 0 or 1. Note: Used for device type USBGecko */ +#define GDBSTUB_DEF_TCPPORT 2828 /*!< default TCP port. Note: Used for device type TCP */ + +#ifdef __cplusplus + extern "C" { +#endif + +extern const char *tcp_localip; +extern const char *tcp_netmask; +extern const char *tcp_gateway; + + +/*!\fn void _break() + * \brief Stub function to insert the hardware break instruction. This function is used to enter the debug stub and to + * connect with the host. The developer is free to insert this function at any position in project's source code. + * + * \return none. + */ +void _break(); + + +/*!\fn void DEBUG_Init(s32 device_type,s32 channel_port) + * \brief Performs the initialization of the debug stub. + * \param[in] device_type type of device to use. can be either USB or TCP. + * \param[in] channel_port depending on the used device this can be either the EXI channel or the TCP port. + * + * \return none. + */ +void DEBUG_Init(s32 device_type,s32 channel_port); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/di/di.h b/wii/libogc/include/di/di.h new file mode 100644 index 0000000000..952eeeb61d --- /dev/null +++ b/wii/libogc/include/di/di.h @@ -0,0 +1,133 @@ +/*------------------------------------------------------------- + +di.h -- Drive Interface library + +Team Twiizers +Copyright (C) 2008 + +Erant +marcan + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +/* +All buffers in this document need to be 32-byte aligned! +*/ + +#ifndef __DI_H__ +#define __DI_H__ + +#include +#include +#include + +#define DVD_IDENTIFY 0x12 +#define DVD_READ_DISCID 0x70 +#define DVD_LOW_READ 0x71 +#define DVD_WAITFORCOVERCLOSE 0x79 +#define DVD_READ_PHYSICAL 0x80 +#define DVD_READ_COPYRIGHT 0x81 +#define DVD_READ_DISCKEY 0x82 +#define DVD_GETCOVER 0x88 +#define DVD_RESET 0x8A +#define DVD_OPEN_PARTITION 0x8B +#define DVD_CLOSE_PARTITION 0x8C +#define DVD_READ_UNENCRYPTED 0x8D +#define DVD_REPORTKEY 0xA4 +#define DVD_READ 0xD0 +#define DVD_READ_CONFIG 0xD1 +#define DVD_READ_BCA 0xDA +#define DVD_GET_ERROR 0xE0 +#define DVD_SET_MOTOR 0xE3 + +#define DVD_READY 0x1 +#define DVD_INIT 0x2 +#define DVD_UNKNOWN 0x4 +#define DVD_NO_DISC 0x8 +#define DVD_IOS_ERROR 0x10 +#define DVD_D0 0x20 +#define DVD_A8 0x40 + +#define DVD_COVER_DISC_INSERTED 0x02 + +#define LIBDI_MAX_RETRIES 16 + +#define DEVICE_TYPE_WII_DVD (('W'<<24)|('D'<<16)|('V'<<8)|'D') + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct{ + uint16_t rev; + uint16_t dev_code; + uint32_t rel_date; +}DI_DriveID; + +typedef int(*di_callback)(uint32_t status, uint32_t error); +typedef int(*read_func)(void*,uint32_t,uint32_t); +typedef int(*read_func_async)(void*,uint32_t,uint32_t,ipccallback); + +extern int di_fd; +extern const DISC_INTERFACE __io_wiidvd; + +int DI_Init(); +void DI_LoadDVDX(bool load); +void DI_UseCache(bool use); +void DI_SetInitCallback(di_callback cb); +void DI_Mount(); +void DI_Close(); +int DI_GetStatus(); + +int DI_Identify(DI_DriveID* id); +int DI_CheckDVDSupport(); +int DI_ReadDiscID(u64 *id); +int DI_GetError(uint32_t* error); +int DI_GetCoverRegister(uint32_t* status); +int DI_Reset(); + +int DI_StopMotor(); +int DI_Eject(); +int DI_KillDrive(); + +int DI_ReadDVD(void* buf, uint32_t len, uint32_t lba); +int DI_ReadDVDAsync(void* buf, uint32_t len, uint32_t lba, ipccallback ipc_cb); + +int DI_Read(void *buf, u32 size, u32 offset); +int DI_UnencryptedRead(void *buf, u32 size, u32 offset); + +int DI_ReadDVDConfig(uint32_t* val, uint32_t flag); +int DI_ReadDVDCopyright(uint32_t* copyright); +int DI_ReadDVDDiscKey(void *buf); +int DI_ReadDVDPhysical(void *buf); +int DI_Read_BCA(void *buf); +int DI_ReportKey(int keytype, uint32_t lba, void* buf); + +int DI_OpenPartition(u32 offset); +int DI_ClosePartition(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/wii/libogc/include/fat.h b/wii/libogc/include/fat.h new file mode 100644 index 0000000000..7d828f6e72 --- /dev/null +++ b/wii/libogc/include/fat.h @@ -0,0 +1,122 @@ +/* + fat.h + Simple functionality for startup, mounting and unmounting of FAT-based devices. + + Copyright (c) 2006 - 2012 + Michael "Chishm" Chisholm + Dave "WinterMute" Murphy + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef _LIBFAT_H +#define _LIBFAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libfatversion.h" + +// When compiling for NDS, make sure NDS is defined +#ifndef NDS + #if defined ARM9 || defined ARM7 + #define NDS + #endif +#endif + +#include + +#if defined(__gamecube__) || defined (__wii__) +# include +#else +# ifdef NDS +# include +# else +# include +# endif +#endif + +/* +Initialise any inserted block-devices. +Add the fat device driver to the devoptab, making it available for standard file functions. +cacheSize: The number of pages to allocate for each inserted block-device +setAsDefaultDevice: if true, make this the default device driver for file operations +*/ +extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice); + +/* +Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system. +*/ +extern bool fatInitDefault (void); + +/* +Mount the device pointed to by interface, and set up a devoptab entry for it as "name:". +You can then access the filesystem using "name:/". +This will mount the active partition or the first valid partition on the disc, +and will use a cache size optimized for the host system. +*/ +extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface); + +/* +Mount the device pointed to by interface, and set up a devoptab entry for it as "name:". +You can then access the filesystem using "name:/". +If startSector = 0, it will mount the active partition of the first valid partition on +the disc. Otherwise it will try to mount the partition starting at startSector. +cacheSize specifies the number of pages to allocate for the cache. +This will not startup the disc, so you need to call interface->startup(); first. +*/ +extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage); + +/* +Unmount the partition specified by name. +If there are open files, it will attempt to synchronise them to disc. +*/ +extern void fatUnmount (const char* name); + +/* +Get Volume Label +*/ +extern void fatGetVolumeLabel (const char* name, char *label); + +// File attributes +#define ATTR_ARCHIVE 0x20 // Archive +#define ATTR_DIRECTORY 0x10 // Directory +#define ATTR_VOLUME 0x08 // Volume +#define ATTR_SYSTEM 0x04 // System +#define ATTR_HIDDEN 0x02 // Hidden +#define ATTR_READONLY 0x01 // Read only + +/* +Methods to modify DOS File Attributes +*/ +int FAT_getAttr(const char *file); +int FAT_setAttr(const char *file, uint8_t attr ); + +#define LIBFAT_FEOS_MULTICWD + +#ifdef __cplusplus +} +#endif + +#endif // _LIBFAT_H diff --git a/wii/libogc/include/gccore.h b/wii/libogc/include/gccore.h new file mode 100644 index 0000000000..f45b68345a --- /dev/null +++ b/wii/libogc/include/gccore.h @@ -0,0 +1,150 @@ +/*------------------------------------------------------------- + +gccore.h -- GC core header + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __GCCORE_H__ +#define __GCCORE_H__ + +/*! \file gccore.h +\brief Core header which includes all subsequent subsystem headers + +*/ + +#include "ogc/dsp.h" +#include "ogc/aram.h" +#include "ogc/arqueue.h" +#include "ogc/arqmgr.h" +#include "ogc/audio.h" +#include "ogc/cache.h" +#include "ogc/card.h" +#include "ogc/cast.h" +#include "ogc/color.h" +#include "ogc/consol.h" +#include "ogc/dvd.h" +#include "ogc/exi.h" +#include "ogc/gu.h" +#include "ogc/gx.h" +#include "ogc/si.h" +#include "ogc/gx_struct.h" +#include "ogc/irq.h" +#include "ogc/lwp.h" +#include "ogc/mutex.h" +#include "ogc/message.h" +#include "ogc/semaphore.h" +#include "ogc/pad.h" +#include "ogc/tpl.h" +#include "ogc/system.h" +#include "ogc/video.h" +#include "ogc/usbgecko.h" +#include "ogc/video_types.h" +#include "ogc/texconv.h" + +#if defined(HW_RVL) +#include "ogc/ipc.h" +#include "ogc/es.h" +#include "ogc/stm.h" +#include "ogc/ios.h" +#include "ogc/usb.h" +#include "ogc/isfs.h" +#include "ogc/conf.h" +#include "ogc/usbstorage.h" + +#include "ogc/wiilaunch.h" + +#endif + +/* + * Error returns + */ +#define RNC_FILE_IS_NOT_RNC -1 +#define RNC_HUF_DECODE_ERROR -2 +#define RNC_FILE_SIZE_MISMATCH -3 +#define RNC_PACKED_CRC_ERROR -4 +#define RNC_UNPACKED_CRC_ERROR -5 + +#ifndef ATTRIBUTE_ALIGN +# define ATTRIBUTE_ALIGN(v) __attribute__((aligned(v))) +#endif +#ifndef ATTRIBUTE_PACKED +# define ATTRIBUTE_PACKED __attribute__((packed)) +#endif + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! + * \mainpage + * + * - \subpage intro + * - \subpage api_doc + */ + + +/*! + * \page intro Introduction + * Welcome to the libOGC reference documentation. + */ + +/*! + * \page api_doc Detailed API description + * + * - \ref aram.h "ARAM subsystem" + * - \ref arqmgr.h "ARAM queue management subsystem" + * - \ref audio.h "AUDIO subsystem" + * - \ref asndlib.h "ASND library" + * - \ref exi.h "EXI subsystem" + * - \ref irq.h "IRQ subsystem" + * - \ref dsp.h "DSP subsystem" + * - \ref dvd.h "DVD subsystem" + * - \ref gx.h "GX subsystem" + * - \ref gu.h "gu/Matrix subsystem" + * - \ref video.h "VIDEO subsystem" + * - \ref cache.h "Cache subsystem" + * - \ref card.h "Memory card subsystem" + * - \ref consol.h "Console subsystem" + * - \ref system.h "OS functions and initialization" + * - \ref lwp.h "Thread subsystem I" + * - \ref message.h "Thread subsystem II" + * - \ref mutex.h "Thread subsystem III" + * - \ref semaphore.h "Thread subsystem IV" + * - \ref cond.h "Thread subsystem V" + */ + +s32 depackrnc1_ulen(void *packed); +s32 depackrnc1(void *packed,void *unpacked); + +void depackrnc2(void *packed,void *unpacked); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/gcmodplay.h b/wii/libogc/include/gcmodplay.h new file mode 100644 index 0000000000..a59d077533 --- /dev/null +++ b/wii/libogc/include/gcmodplay.h @@ -0,0 +1,44 @@ +#ifndef __GCMODPLAY_H__ +#define __GCMODPLAY_H__ + +#include +#include "modplay/modplay.h" + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct _modsndbuf { + u32 freq; + u16 fmt; + u32 chans; + f32 samples; + void *usr_data; + void (*callback)(void *,u8 *,u32); +} MODSNDBUF; + +typedef struct _modplay { + MOD mod; + BOOL playing,paused; + BOOL bits,stereo,manual_polling; + u32 playfreq,numSFXChans; + MODSNDBUF soundBuf; +} MODPlay; + +void MODPlay_Init(MODPlay *mod); +s32 MODPlay_SetFrequency(MODPlay *mod,u32 freq); +void MODPlay_SetStereo(MODPlay *mod,BOOL stereo); +s32 MODPlay_SetMOD(MODPlay *mod,const void *mem); +void MODPlay_Unload(MODPlay *mod); +s32 MODPlay_AllocSFXChannels(MODPlay *mod,u32 sfxchans); +s32 MODPlay_Start(MODPlay *mod); +s32 MODPlay_Stop(MODPlay *mod); +s32 MODPlay_TriggerNote(MODPlay *mod,u32 chan,u8 inst,u16 freq,u8 vol); +s32 MODPlay_Pause(MODPlay *mod,BOOL); +void MODPlay_SetVolume(MODPlay * mod, s32 musicvolume, s32 sfxvolume); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/gctypes.h b/wii/libogc/include/gctypes.h new file mode 100644 index 0000000000..8d93799e4b --- /dev/null +++ b/wii/libogc/include/gctypes.h @@ -0,0 +1,110 @@ +#ifndef __GCTYPES_H__ +#define __GCTYPES_H__ + +/*! \file gctypes.h +\brief Data type definitions + +*/ + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +/*+----------------------------------------------------------------------------------------------+*/ +typedef uint8_t u8; ///< 8bit unsigned integer +typedef uint16_t u16; ///< 16bit unsigned integer +typedef uint32_t u32; ///< 32bit unsigned integer +typedef uint64_t u64; ///< 64bit unsigned integer +/*+----------------------------------------------------------------------------------------------+*/ +typedef int8_t s8; ///< 8bit signed integer +typedef int16_t s16; ///< 16bit signed integer +typedef int32_t s32; ///< 32bit signed integer +typedef int64_t s64; ///< 64bit signed integer +/*+----------------------------------------------------------------------------------------------+*/ +typedef volatile u8 vu8; ///< 8bit unsigned volatile integer +typedef volatile u16 vu16; ///< 16bit unsigned volatile integer +typedef volatile u32 vu32; ///< 32bit unsigned volatile integer +typedef volatile u64 vu64; ///< 64bit unsigned volatile integer +/*+----------------------------------------------------------------------------------------------+*/ +typedef volatile s8 vs8; ///< 8bit signed volatile integer +typedef volatile s16 vs16; ///< 16bit signed volatile integer +typedef volatile s32 vs32; ///< 32bit signed volatile integer +typedef volatile s64 vs64; ///< 64bit signed volatile integer +/*+----------------------------------------------------------------------------------------------+*/ +// fixed point math typedefs +typedef s16 sfp16; ///< signed 8:8 fixed point +typedef s32 sfp32; ///< signed 20:8 fixed point +typedef u16 ufp16; ///< unsigned 8:8 fixed point +typedef u32 ufp32; ///< unsigned 24:8 fixed point +/*+----------------------------------------------------------------------------------------------+*/ +typedef float f32; +typedef double f64; +/*+----------------------------------------------------------------------------------------------+*/ +typedef volatile float vf32; +typedef volatile double vf64; +/*+----------------------------------------------------------------------------------------------+*/ + + +typedef unsigned int BOOL; +/*+----------------------------------------------------------------------------------------------+*/ +// alias type typedefs +#define FIXED s32 ///< Alias type for sfp32 +/*+----------------------------------------------------------------------------------------------+*/ +#ifndef TRUE +#define TRUE 1 ///< True +#endif +/*+----------------------------------------------------------------------------------------------+*/ +#ifndef FALSE +#define FALSE 0 ///< False +#endif +/*+----------------------------------------------------------------------------------------------+*/ +#ifndef NULL +#define NULL 0 ///< Pointer to 0 +#endif +/*+----------------------------------------------------------------------------------------------+*/ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 3412 +#endif /* LITTLE_ENDIAN */ +/*+----------------------------------------------------------------------------------------------+*/ +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 1234 +#endif /* BIGE_ENDIAN */ +/*+----------------------------------------------------------------------------------------------+*/ +#ifndef BYTE_ORDER +#define BYTE_ORDER BIG_ENDIAN +#endif /* BYTE_ORDER */ +/*+----------------------------------------------------------------------------------------------+*/ + + +//! argv structure +/*! \struct __argv + + structure used to set up argc/argv + +*/ +struct __argv { + int argvMagic; //!< argv magic number, set to 0x5f617267 ('_arg') if valid + char *commandLine; //!< base address of command line, set of null terminated strings + int length;//!< total length of command line + int argc; + char **argv; + char **endARGV; +}; + +//! Default location for the system argv structure. +extern struct __argv *__system_argv; + +// argv struct magic number +#define ARGV_MAGIC 0x5f617267 + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* TYPES_H */ + + +/* END OF FILE */ diff --git a/wii/libogc/include/gcutil.h b/wii/libogc/include/gcutil.h new file mode 100644 index 0000000000..3458ee037d --- /dev/null +++ b/wii/libogc/include/gcutil.h @@ -0,0 +1,12 @@ +#ifndef __GCUTIL_H__ +#define __GCUTIL_H__ + +#ifndef ATTRIBUTE_ALIGN +# define ATTRIBUTE_ALIGN(v) __attribute__((aligned(v))) +#endif +#ifndef ATTRIBUTE_PACKED +# define ATTRIBUTE_PACKED __attribute__((packed)) +#endif + +#endif /* _GCUTIL_H */ + diff --git a/wii/libogc/include/ipv4/lwip/icmp.h b/wii/libogc/include/ipv4/lwip/icmp.h new file mode 100644 index 0000000000..634405b714 --- /dev/null +++ b/wii/libogc/include/ipv4/lwip/icmp.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/arch.h" + +#include "lwip/opt.h" +#include "lwip/pbuf.h" + +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ + +enum icmp_dur_type { + ICMP_DUR_NET = 0, /* net unreachable */ + ICMP_DUR_HOST = 1, /* host unreachable */ + ICMP_DUR_PROTO = 2, /* protocol unreachable */ + ICMP_DUR_PORT = 3, /* port unreachable */ + ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ + ICMP_DUR_SR = 5 /* source route failed */ +}; + +enum icmp_te_type { + ICMP_TE_TTL = 0, /* time to live exceeded in transit */ + ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ +}; + +void icmp_input(struct pbuf *p, struct netif *inp); + +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FIELD(u16_t _type_code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +PACK_STRUCT_BEGIN +struct icmp_dur_hdr { + PACK_STRUCT_FIELD(u16_t _type_code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t unused); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +PACK_STRUCT_BEGIN +struct icmp_te_hdr { + PACK_STRUCT_FIELD(u16_t _type_code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t unused); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8) +#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff) + +#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8))) +#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8))) + +#endif /* __LWIP_ICMP_H__ */ + diff --git a/wii/libogc/include/ipv4/lwip/inet.h b/wii/libogc/include/ipv4/lwip/inet.h new file mode 100644 index 0000000000..6d79aab7a4 --- /dev/null +++ b/wii/libogc/include/ipv4/lwip/inet.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/arch.h" + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +u16_t inet_chksum(void *dataptr, u16_t len); +#if 0 /* optimized routine */ +u16_t inet_chksum4(u8_t *dataptr, u16_t len); +#endif +u16_t inet_chksum_pbuf(struct pbuf *p); +u16_t inet_chksum_pseudo(struct pbuf *p, + struct ip_addr *src, struct ip_addr *dest, + u8_t proto, u16_t proto_len); + +u32_t inet_addr(const char *cp); +s8_t inet_aton(const char *cp, struct in_addr *addr); +char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#if BYTE_ORDER == BIG_ENDIAN +#define htons(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define ntohl(x) (x) +#else +#ifdef LWIP_PREFIX_BYTEORDER_FUNCS +/* workaround for naming collisions on some platforms */ +#define htons lwip_htons +#define ntohs lwip_ntohs +#define htonl lwip_htonl +#define ntohl lwip_ntohl +#endif +u16_t htons(u16_t x); +u16_t ntohs(u16_t x); +u32_t htonl(u32_t x); +u32_t ntohl(u32_t x); +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/wii/libogc/include/ipv4/lwip/ip.h b/wii/libogc/include/ipv4/lwip/ip.h new file mode 100644 index 0000000000..4c15e1a0ea --- /dev/null +++ b/wii/libogc/include/ipv4/lwip/ip.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/arch.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#include "lwip/err.h" + + +void ip_init(void); +struct netif *ip_route(struct ip_addr *dest); +err_t ip_input(struct pbuf *p, struct netif *inp); +err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto); +err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, + struct netif *netif); + +#define IP_HLEN 20 + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_UDP 17 +#define IP_PROTO_UDPLITE 170 +#define IP_PROTO_TCP 6 + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL NULL + + +/* This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB struct ip_addr local_ip; \ + struct ip_addr remote_ip; \ + /* Socket options */ \ + u16_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */ +#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */ +#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */ +#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */ +#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */ +#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */ +#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */ +#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */ +#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */ +#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */ + + + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_hdr { + /* version / header length / type of service */ + PACK_STRUCT_FIELD(u16_t _v_hl_tos); + /* total length */ + PACK_STRUCT_FIELD(u16_t _len); + /* identification */ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + /* time to live / protocol*/ + PACK_STRUCT_FIELD(u16_t _ttl_proto); + /* checksum */ + PACK_STRUCT_FIELD(u16_t _chksum); + /* source and destination IP addresses */ + PACK_STRUCT_FIELD(struct ip_addr src); + PACK_STRUCT_FIELD(struct ip_addr dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12) +#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) +#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8) +#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((ttl) << 8))) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8))) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + +#if IP_DEBUG +void ip_debug_print(struct pbuf *p); +#else +#define ip_debug_print(p) +#endif /* IP_DEBUG */ + +#endif /* __LWIP_IP_H__ */ + + diff --git a/wii/libogc/include/ipv4/lwip/ip_addr.h b/wii/libogc/include/ipv4/lwip/ip_addr.h new file mode 100644 index 0000000000..fa921961de --- /dev/null +++ b/wii/libogc/include/ipv4/lwip/ip_addr.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/arch.h" + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* For compatibility with BSD code */ +#ifndef HAVE_IN_ADDR +#define HAVE_IN_ADDR +struct in_addr { + u32_t s_addr; +}; +#endif + +struct netif; + +extern const struct ip_addr ip_addr_any; +extern const struct ip_addr ip_addr_broadcast; + +/** IP_ADDR_ can be used as a fixed IP address + * for the wildcard and the broadcast address + */ +#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any) +#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast) + +#define INADDR_NONE ((u32_t) 0xffffffff) /* 255.255.255.255 */ +#define INADDR_LOOPBACK ((u32_t) 0x7f000001) /* 127.0.0.1 */ + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ + +#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000) == 0xe0000000) +#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IN_MULTICAST(a) IN_CLASSD(a) + +#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000) == 0xf0000000) +#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 /* official! */ + + +#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = htonl(((u32_t)(a & 0xff) << 24) | ((u32_t)(b & 0xff) << 16) | \ + ((u32_t)(c & 0xff) << 8) | (u32_t)(d & 0xff)) + +#define ip_addr_set(dest, src) (dest)->addr = \ + ((src) == NULL? 0:\ + (src)->addr) +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0) + +u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *); + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000)) == ntohl(0xe0000000)) + + +#define ip_addr_debug_print(debug, ipaddr) LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \ + ipaddr?(u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff:0, \ + ipaddr?(u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff:0, \ + ipaddr?(u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff:0, \ + ipaddr?(u16_t)ntohl((ipaddr)->addr) & 0xff:0U)) + +/* cast to unsigned int, as it is used as argument to printf functions + * which expect integer arguments. CSi: use cc.h formatters (conversion chars)! */ +#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff) +#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff) +#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff) +#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff) +#endif /* __LWIP_IP_ADDR_H__ */ + + + + + + diff --git a/wii/libogc/include/ipv4/lwip/ip_frag.h b/wii/libogc/include/ipv4/lwip/ip_frag.h new file mode 100644 index 0000000000..a982c5a63f --- /dev/null +++ b/wii/libogc/include/ipv4/lwip/ip_frag.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * + */ + +#ifndef __LWIP_IP_FRAG_H__ +#define __LWIP_IP_FRAG_H__ + +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" + +void ip_reass_tmr(void); +struct pbuf * ip_reass(struct pbuf *p); +err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest); + +#endif /* __LWIP_IP_FRAG_H__ */ + + diff --git a/wii/libogc/include/iso9660.h b/wii/libogc/include/iso9660.h new file mode 100644 index 0000000000..498cf9aeda --- /dev/null +++ b/wii/libogc/include/iso9660.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * ISO9660 devoptab + * + * Copyright (C) 2008-2010 + * tipoloski, clava, shagkur, Tantric, joedj + ****************************************************************************/ + +#ifndef __ISO9660_H__ +#define __ISO9660_H__ + +#include + +#define ISO_MAXPATHLEN 128 + +#ifdef __cplusplus +extern "C" { +#endif + +bool ISO9660_Mount(const char* name, const DISC_INTERFACE* disc_interface); +bool ISO9660_Unmount(const char* name); +const char *ISO9660_GetVolumeLabel(const char *name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/include/libfatversion.h b/wii/libogc/include/libfatversion.h new file mode 100644 index 0000000000..765ac2f3f7 --- /dev/null +++ b/wii/libogc/include/libfatversion.h @@ -0,0 +1,10 @@ +#ifndef __LIBFATVERSION_H__ +#define __LIBFATVERSION_H__ + +#define _LIBFAT_MAJOR_ 1 +#define _LIBFAT_MINOR_ 1 +#define _LIBFAT_PATCH_ 1 + +#define _LIBFAT_STRING "libFAT Release 1.1.1" + +#endif // __LIBFATVERSION_H__ diff --git a/wii/libogc/include/lwip/api.h b/wii/libogc/include/lwip/api.h new file mode 100644 index 0000000000..18d5602fbd --- /dev/null +++ b/wii/libogc/include/lwip/api.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_H__ +#define __LWIP_API_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + +#include "lwip/ip.h" + +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include "lwip/err.h" + +#define NETCONN_NOCOPY 0x00 +#define NETCONN_COPY 0x01 + +enum netconn_type { + NETCONN_TCP, + NETCONN_UDP, + NETCONN_UDPLITE, + NETCONN_UDPNOCHKSUM, + NETCONN_RAW +}; + +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_ACCEPT, + NETCONN_RECV, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +enum netconn_evt { + NETCONN_EVTRCVPLUS, + NETCONN_EVTRCVMINUS, + NETCONN_EVTSENDPLUS, + NETCONN_EVTSENDMINUS +}; + +struct netbuf { + struct pbuf *p, *ptr; + struct ip_addr *fromaddr; + u16_t fromport; + err_t err; +}; + +struct netconn { + enum netconn_type type; + enum netconn_state state; + union { + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct raw_pcb *raw; + } pcb; + err_t err; + sys_sem sem; + sys_mbox mbox; + sys_mbox recvmbox; + sys_mbox acceptmbox; + u16 recvavail; + s32 socket; + void (*callback)(struct netconn *,enum netconn_evt,u32); +}; + +#endif /* __LWIP_API_H__ */ + + diff --git a/wii/libogc/include/lwip/api_msg.h b/wii/libogc/include/lwip/api_msg.h new file mode 100644 index 0000000000..cf5ba08c05 --- /dev/null +++ b/wii/libogc/include/lwip/api_msg.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_MSG_H__ +#define __LWIP_API_MSG_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + +#include "lwip/ip.h" + +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include "lwip/api.h" + +enum apimsg_type { + APIMSG_NEWCONN, + APIMSG_DELCONN, + APIMSG_BIND, + APIMSG_CONNECT, + APIMSG_DISCONNECT, + APIMSG_LISTEN, + APIMSG_ACCEPT, + APIMSG_SEND, + APIMSG_RECV, + APIMSG_WRITE, + APIMSG_CLOSE, + APIMSG_MAX +}; + +struct apimsg_msg { + struct netconn *conn; + enum netconn_type type; + union { + struct pbuf *p; + struct { + struct ip_addr *ipaddr; + u16 port; + } bc; + struct { + void *dataptr; + u32 len; + u8 copy; + } w; + sys_mbox mbox; + u16 len; + } msg; +}; + +struct api_msg { + enum apimsg_type type; + struct apimsg_msg msg; +}; + +#endif /* __LWIP_API_MSG_H__ */ + diff --git a/wii/libogc/include/lwip/arch.h b/wii/libogc/include/lwip/arch.h new file mode 100644 index 0000000000..e0d622a4b2 --- /dev/null +++ b/wii/libogc/include/lwip/arch.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ARCH_H__ +#define __LWIP_ARCH_H__ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + + + +#ifdef LWIP_PROVIDE_ERRNO + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + + +#define ENSROK 0 /* DNS server returned answer with no data */ +#define ENSRNODATA 160 /* DNS server returned answer with no data */ +#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ +#define ENSRSERVFAIL 162 /* DNS server returned general failure */ +#define ENSRNOTFOUND 163 /* Domain name not found */ +#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ +#define ENSRREFUSED 165 /* DNS server refused query */ +#define ENSRBADQUERY 166 /* Misformatted DNS query */ +#define ENSRBADNAME 167 /* Misformatted domain name */ +#define ENSRBADFAMILY 168 /* Unsupported address family */ +#define ENSRBADRESP 169 /* Misformatted DNS reply */ +#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ +#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ +#define ENSROF 172 /* End of file */ +#define ENSRFILE 173 /* Error reading file */ +#define ENSRNOMEM 174 /* Out of memory */ +#define ENSRDESTRUCTION 175 /* Application terminated lookup */ +#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ +#define ENSRCNAMELOOP 177 /* Domain name is too long */ + +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + +#endif /* __LWIP_ARCH_H__ */ diff --git a/wii/libogc/include/lwip/debug.h b/wii/libogc/include/lwip/debug.h new file mode 100644 index 0000000000..12cfd65afd --- /dev/null +++ b/wii/libogc/include/lwip/debug.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEBUG_H__ +#define __LWIP_DEBUG_H__ + +#include "arch/cc.h" + +/** lower two bits indicate debug level + * - 0 off + * - 1 warning + * - 2 serious + * - 3 severe + */ + +#define DBG_LEVEL_OFF 0 +#define DBG_LEVEL_WARNING 1 /* bad checksums, dropped packets, ... */ +#define DBG_LEVEL_SERIOUS 2 /* memory allocation failures, ... */ +#define DBG_LEVEL_SEVERE 3 /* */ +#define DBG_MASK_LEVEL 3 + +/** flag for LWIP_DEBUGF to enable that debug message */ +#define DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define DBG_OFF 0x00U + +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define DBG_HALT 0x08U + +#ifdef LWIP_DEBUG +# ifndef LWIP_NOASSERT +# define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0) +# else +# define LWIP_ASSERT(x,y) +# endif +#endif + +#ifdef LWIP_DEBUG +/** print debug message only if debug message type is enabled... + * AND is of correct type AND is at least DBG_LEVEL + */ +# define LWIP_DEBUGF(debug,x) do { if (((debug) & DBG_ON) && ((debug) & DBG_TYPES_ON) && ((int)((debug) & DBG_MASK_LEVEL) >= DBG_MIN_LEVEL)) { LWIP_PLATFORM_DIAG(x); if ((debug) & DBG_HALT) while(1); } } while(0) +# define LWIP_ERROR(x) do { LWIP_PLATFORM_DIAG(x); } while(0) +#else /* LWIP_DEBUG */ +# define LWIP_ASSERT(x,y) +# define LWIP_DEBUGF(debug,x) +# define LWIP_ERROR(x) +#endif /* LWIP_DEBUG */ + +#endif /* __LWIP_DEBUG_H__ */ + + + + + + diff --git a/wii/libogc/include/lwip/def.h b/wii/libogc/include/lwip/def.h new file mode 100644 index 0000000000..eba9b8774d --- /dev/null +++ b/wii/libogc/include/lwip/def.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEF_H__ +#define __LWIP_DEF_H__ + +/* this might define NULL already */ +#include "arch/cc.h" + +#define LWIP_MAX(x , y) (x) > (y) ? (x) : (y) +#define LWIP_MIN(x , y) (x) < (y) ? (x) : (y) + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +#endif /* __LWIP_DEF_H__ */ + diff --git a/wii/libogc/include/lwip/dhcp.h b/wii/libogc/include/lwip/dhcp.h new file mode 100644 index 0000000000..bfe753f26a --- /dev/null +++ b/wii/libogc/include/lwip/dhcp.h @@ -0,0 +1,223 @@ +/** @file + */ + +#ifndef __LWIP_DHCP_H__ +#define __LWIP_DHCP_H__ + +#include "lwip/opt.h" +#include "lwip/netif.h" +#include "lwip/udp.h" + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60 +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500 + +struct dhcp +{ + /** current DHCP state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; + /** transaction identifier of last sent request */ + u32_t xid; + /** our connection to the DHCP server */ + struct udp_pcb *pcb; + /** (first) pbuf of incoming msg */ + struct pbuf *p; + /** incoming msg */ + struct dhcp_msg *msg_in; + /** incoming msg options */ + struct dhcp_msg *options_in; + /** ingoing msg options length */ + u16_t options_in_len; + + struct pbuf *p_out; /* pbuf of outcoming msg */ + struct dhcp_msg *msg_out; /* outgoing msg */ + u16_t options_out_len; /* outgoing msg options length */ + u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */ + struct ip_addr offered_ip_addr; + struct ip_addr offered_sn_mask; + struct ip_addr offered_gw_addr; + struct ip_addr offered_bc_addr; +#define DHCP_MAX_DNS 2 + u32_t dns_count; /* actual number of DNS servers obtained */ + struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */ + + u32_t offered_t0_lease; /* lease period (in seconds) */ + u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ + u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */ +/** Patch #1308 + * TODO: See dhcp.c "TODO"s + */ +#if 0 + struct ip_addr offered_si_addr; + u8_t *boot_file_name; +#endif +}; + +/* MUST be compiled with "pack structs" or equivalent! */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ + PACK_STRUCT_FIELD(u8_t op); + PACK_STRUCT_FIELD(u8_t htype); + PACK_STRUCT_FIELD(u8_t hlen); + PACK_STRUCT_FIELD(u8_t hops); + PACK_STRUCT_FIELD(u32_t xid); + PACK_STRUCT_FIELD(u16_t secs); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FIELD(struct ip_addr ciaddr); + PACK_STRUCT_FIELD(struct ip_addr yiaddr); + PACK_STRUCT_FIELD(struct ip_addr siaddr); + PACK_STRUCT_FIELD(struct ip_addr giaddr); +#define DHCP_CHADDR_LEN 16U + PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); +#define DHCP_SNAME_LEN 64U + PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); +#define DHCP_FILE_LEN 128U + PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); + PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +# undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif + PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** start DHCP configuration */ +err_t dhcp_start(struct netif *netif); +/** enforce early lease renewal (not needed normally)*/ +err_t dhcp_renew(struct netif *netif); +/** release the DHCP lease, usually called before dhcp_stop()*/ +err_t dhcp_release(struct netif *netif); +/** stop DHCP configuration */ +void dhcp_stop(struct netif *netif); +/** inform server of our manual IP address */ +void dhcp_inform(struct netif *netif); + +/** if enabled, check whether the offered IP address is not in use, using ARP */ +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr); +#endif + +/** to be called every minute */ +void dhcp_coarse_tmr(void); +/** to be called every half second */ +void dhcp_fine_tmr(void); + +/** DHCP message item offsets and length */ +#define DHCP_MSG_OFS (UDP_DATA_OFS) + #define DHCP_OP_OFS (DHCP_MSG_OFS + 0) + #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1) + #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2) + #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3) + #define DHCP_XID_OFS (DHCP_MSG_OFS + 4) + #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8) + #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10) + #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12) + #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16) + #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20) + #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24) + #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28) + #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44) + #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108) +#define DHCP_MSG_LEN 236 + +#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN) +#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4) + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 + +/** DHCP client states */ +#define DHCP_REQUESTING 1 +#define DHCP_INIT 2 +#define DHCP_REBOOTING 3 +#define DHCP_REBINDING 4 +#define DHCP_RENEWING 5 +#define DHCP_SELECTING 6 +#define DHCP_INFORMING 7 +#define DHCP_CHECKING 8 +#define DHCP_PERMANENT 9 +#define DHCP_BOUND 10 +/** not yet implemented #define DHCP_RELEASING 11 */ +#define DHCP_BACKING_OFF 12 +#define DHCP_OFF 13 + +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE_ETH 1 + +#define DHCP_HLEN_ETH 6 + +#define DHCP_BROADCAST_FLAG 15 +#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST) + +/** BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_END 255 + +/** DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/** possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + +#endif /*__LWIP_DHCP_H__*/ diff --git a/wii/libogc/include/lwip/err.h b/wii/libogc/include/lwip/err.h new file mode 100644 index 0000000000..c92cb26d76 --- /dev/null +++ b/wii/libogc/include/lwip/err.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ERR_H__ +#define __LWIP_ERR_H__ + +#include "lwip/opt.h" + +#include "arch/cc.h" + +typedef s8_t err_t; + +/* Definitions for error constants. */ + +#define ERR_OK 0 /* No error, everything OK. */ +#define ERR_MEM -1 /* Out of memory error. */ +#define ERR_BUF -2 /* Buffer error. */ + + +#define ERR_ABRT -3 /* Connection aborted. */ +#define ERR_RST -4 /* Connection reset. */ +#define ERR_CLSD -5 /* Connection closed. */ +#define ERR_CONN -6 /* Not connected. */ + +#define ERR_VAL -7 /* Illegal value. */ + +#define ERR_ARG -8 /* Illegal argument. */ + +#define ERR_RTE -9 /* Routing problem. */ + +#define ERR_USE -10 /* Address in use. */ + +#define ERR_IF -11 /* Low-level netif error */ +#define ERR_ISCONN -12 /* Already connected. */ + + +#ifdef LWIP_DEBUG +extern char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ +#endif /* __LWIP_ERR_H__ */ diff --git a/wii/libogc/include/lwip/lwipopts.h b/wii/libogc/include/lwip/lwipopts.h new file mode 100644 index 0000000000..70dda6c0f6 --- /dev/null +++ b/wii/libogc/include/lwip/lwipopts.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +#include + +#undef BYTE_ORDER + +#define BYTE_ORDER BIG_ENDIAN +#define NO_SYS 1 +#define LWIP_CALLBACK_API 1 +#undef LWIP_EVENT_API +#define TCPIP_THREAD_PRIO 125 +#define SYS_LIGHTWEIGHT_PROT 1 + +/* ---------- Memory options ---------- */ +/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which + lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 + byte alignment -> define MEM_ALIGNMENT to 2. */ +#define MEM_ALIGNMENT 4 + +/* MEM_SIZE: the size of the heap memory. If the application will send +a lot of data that needs to be copied, this should be set high. */ +#define MEM_SIZE (192*1024) + +/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application + sends a lot of data out of ROM (or other static memory), this + should be set high. */ +#define MEMP_NUM_PBUF 128 +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#define MEMP_NUM_UDP_PCB 16 +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#define MEMP_NUM_TCP_PCB 16 +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#define MEMP_NUM_TCP_SEG 128 + +/* The following four are used only with the sequential API and can be + set to 0 if the application only will use the raw API. */ +/* MEMP_NUM_NETBUF: the number of struct netbufs. */ +#define MEMP_NUM_NETBUF 16 +/* MEMP_NUM_NETCONN: the number of struct netconns. */ +#define MEMP_NUM_NETCONN 16 +/* MEMP_NUM_APIMSG: the number of struct api_msg, used for + communication between the TCP/IP stack and the sequential + programs. */ +#define MEMP_NUM_API_MSG 128 +/* MEMP_NUM_TCPIPMSG: the number of struct tcpip_msg, which is used + for sequential API communication and incoming packets. Used in + src/api/tcpip.c. */ +#define MEMP_NUM_TCPIP_MSG 128 +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#define MEMP_NUM_SYS_TIMEOUT 0 + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#define PBUF_POOL_SIZE 128 //128 + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +#define PBUF_POOL_BUFSIZE 1600 + +/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a + link level header. */ +#define PBUF_LINK_HLEN 16 + +/* ---------- TCP options ---------- */ +#define LWIP_TCP 1 +#define TCP_TTL 255 + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#define TCP_QUEUE_OOSEQ 1 + +/* TCP Maximum segment size. */ +#define TCP_MSS 1460 + +/* TCP sender buffer space (bytes). */ +#define TCP_SND_BUF (36*TCP_MSS) + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#define TCP_SND_QUEUELEN (36*TCP_SND_BUF/TCP_MSS) + +/* TCP receive window. */ +#define TCP_WND (36*TCP_MSS) + +/* Maximum number of retransmissions of data segments. */ +#define TCP_MAXRTX 12 + +/* Maximum number of retransmissions of SYN segments. */ +#define TCP_SYNMAXRTX 4 + +/* ---------- ARP options ---------- */ +/** + * - If enabled, cache entries are generated for every kind of ARP traffic or + * broadcast IP traffic. This enhances behaviour for sending to a dynamic set + * of hosts, for example if acting as a gateway. + * - If disabled, cache entries are generated only for IP destination addresses + * in use by lwIP or applications. This enhances performance if sending to a small, + * reasonably static number of hosts. Typically for embedded devices. + */ + +/* ---------- IP options ---------- */ +/* Define IP_FORWARD to 1 if you wish to have the ability to forward + IP packets across network interfaces. If you are going to run lwIP + on a device with only one network interface, define this to 0. */ +#define IP_FORWARD 0 + +/* If defined to 1, IP options are allowed (but not parsed). If + defined to 0, all packets with IP options are dropped. */ +#define IP_OPTIONS 1 + +/* ---------- ICMP options ---------- */ +#define ICMP_TTL 255 + + +/* ---------- DHCP options ---------- */ +/* Define LWIP_DHCP to 1 if you want DHCP configuration of + interfaces. DHCP is not implemented in lwIP 0.5.1, however, so + turning this on does currently not work. */ +#define LWIP_DHCP 1 + +/* 1 if you want to do an ARP check on the offered address + (recommended). */ +#define DHCP_DOES_ARP_CHECK 1 + +/* ---------- UDP options ---------- */ +#define LWIP_UDP 1 +#define UDP_TTL 255 + +#define LWIP_STATS 0 +/* ---------- Statistics options ---------- */ +/*#define STATS*/ +#if LWIP_STATS +#define LINK_STATS 0 +#define IP_STATS 0 +#define ICMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define PBUF_STATS 0 +#define SYS_STATS 0 +#define RAW_STATS 0 +#endif + +#ifdef LWIP_DEBUG +#define DBG_TYPES_ON -1 +#define DEMO_DEBUG DBG_OFF +#define ETHARP_DEBUG DBG_OFF +#define NETIF_DEBUG DBG_OFF +#define PBUF_DEBUG DBG_OFF +#define API_LIB_DEBUG DBG_OFF +#define API_MSG_DEBUG DBG_ON +#define SOCKETS_DEBUG DBG_OFF +#define ICMP_DEBUG DBG_OFF +#define INET_DEBUG DBG_OFF +#define IP_DEBUG DBG_OFF +#define IP_REASS_DEBUG DBG_OFF +#define MEM_DEBUG DBG_OFF +#define MEMP_DEBUG DBG_OFF +#define SYS_DEBUG DBG_OFF +#define RAW_DEBUG DBG_OFF +#define TCP_DEBUG DBG_OFF +#define TCP_INPUT_DEBUG DBG_OFF +#define TCP_FR_DEBUG DBG_OFF +#define TCP_RTO_DEBUG DBG_OFF +#define TCP_REXMIT_DEBUG DBG_OFF +#define TCP_CWND_DEBUG DBG_OFF +#define TCP_WND_DEBUG DBG_OFF +#define TCP_OUTPUT_DEBUG DBG_OFF +#define TCP_RST_DEBUG DBG_OFF +#define TCP_QLEN_DEBUG DBG_OFF +#define UDP_DEBUG DBG_OFF +#define TCPIP_DEBUG DBG_OFF +#define PPP_DEBUG DBG_OFF +#define SLIP_DEBUG DBG_OFF +#define DHCP_DEBUG DBG_OFF + +#define DBG_MIN_LEVEL DBG_LEVEL_OFF +#endif + + +#endif /* __LWIPOPTS_H__ */ diff --git a/wii/libogc/include/lwip/mem.h b/wii/libogc/include/lwip/mem.h new file mode 100644 index 0000000000..ee6fea7d8c --- /dev/null +++ b/wii/libogc/include/lwip/mem.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#if MEM_SIZE > 64000l +typedef u32_t mem_size_t; +#else +typedef u16_t mem_size_t; +#endif /* MEM_SIZE > 64000 */ + + +void mem_init(void); + +void *mem_malloc(mem_size_t size); +void mem_free(void *mem); +void *mem_realloc(void *mem, mem_size_t size); +void *mem_reallocm(void *mem, mem_size_t size); + +#ifndef MEM_ALIGN_SIZE +#define MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) +#endif + +#ifndef MEM_ALIGN +#define MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#endif /* __LWIP_MEM_H__ */ + diff --git a/wii/libogc/include/lwip/memp.h b/wii/libogc/include/lwip/memp.h new file mode 100644 index 0000000000..1cd46fa3fe --- /dev/null +++ b/wii/libogc/include/lwip/memp.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_MEMP_H__ +#define __LWIP_MEMP_H__ + +#include "lwip/opt.h" + +typedef enum { + MEMP_PBUF, + MEMP_RAW_PCB, + MEMP_UDP_PCB, + MEMP_TCP_PCB, + MEMP_TCP_PCB_LISTEN, + MEMP_TCP_SEG, + + MEMP_NETBUF, + MEMP_NETCONN, + MEMP_API_MSG, + MEMP_TCPIP_MSG, + + MEMP_SYS_TIMEOUT, + + MEMP_MAX +} memp_t; + +void memp_init(void); + +void *memp_malloc(memp_t type); +void *memp_realloc(memp_t fromtype, memp_t totype, void *mem); +void memp_free(memp_t type, void *mem); + +#endif /* __LWIP_MEMP_H__ */ + diff --git a/wii/libogc/include/lwip/netif.h b/wii/libogc/include/lwip/netif.h new file mode 100644 index 0000000000..ff50c6f9c8 --- /dev/null +++ b/wii/libogc/include/lwip/netif.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_NETIF_H__ +#define __LWIP_NETIF_H__ + +#include "lwip/opt.h" + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/inet.h" +#include "lwip/pbuf.h" +#if LWIP_DHCP +# include "lwip/dhcp.h" +#endif + +/** must be the maximum of all used hardware address lengths + across all types of interfaces in use */ +#define NETIF_MAX_HWADDR_LEN 6U + +/** TODO: define the use (where, when, whom) of netif flags */ + +/** whether the network interface is 'up'. this is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + */ +#define NETIF_FLAG_UP 0x1U +/** if set, the netif has broadcast capability */ +#define NETIF_FLAG_BROADCAST 0x2U +/** if set, the netif is one end of a point-to-point connection */ +#define NETIF_FLAG_POINTTOPOINT 0x4U +/** if set, the interface is configured using DHCP */ +#define NETIF_FLAG_DHCP 0x08U +/** if set, the interface has an active link + * (set by the network interface driver) */ +#define NETIF_FLAG_LINK_UP 0x10U + +/** Generic data structure used for all lwIP network interfaces. + * The following fields should be filled in by the initialization + * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ + +struct netif { + /** pointer to next in linked list */ + struct netif *next; + + /** IP address configuration in network byte order */ + struct ip_addr ip_addr; + struct ip_addr netmask; + struct ip_addr gw; + + /** This function is called by the network device driver + * to pass a packet up the TCP/IP stack. */ + err_t (* input)(struct pbuf *p, struct netif *inp); + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. */ + err_t (* output)(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr); + /** This function is called by the ARP module when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. */ + err_t (* linkoutput)(struct netif *netif, struct pbuf *p); + /** This field can be set by the device driver and could point + * to state information for the device. */ + void *state; +#if LWIP_DHCP + /** the DHCP client state information for this netif */ + struct dhcp *dhcp; +#endif + /** number of bytes used in hwaddr */ + u8_t hwaddr_len; + /** link level hardware address of this interface */ + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + /** maximum transfer unit (in bytes) */ + u16_t mtu; + /** flags (see NETIF_FLAG_ above) */ + u8_t flags; + /** link type */ + u8_t link_type; + /** descriptive abbreviation */ + char name[2]; + /** number of this interface */ + u8_t num; +}; + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +/* netif_init() must be called first. */ +void netif_init(void); + +struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, + struct ip_addr *gw, + void *state, + err_t (* init)(struct netif *netif), + err_t (* input)(struct pbuf *p, struct netif *netif)); + +void +netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask, + struct ip_addr *gw); +void netif_remove(struct netif * netif); + +/* Returns a network interface given its name. The name is of the form + "et0", where the first two letters are the "name" field in the + netif structure, and the digit is in the num field in the same + structure. */ +struct netif *netif_find(char *name); + +void netif_set_default(struct netif *netif); + +void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr); +void netif_set_netmask(struct netif *netif, struct ip_addr *netmast); +void netif_set_gw(struct netif *netif, struct ip_addr *gw); +void netif_set_up(struct netif *netif); +void netif_set_down(struct netif *netif); +u8_t netif_is_up(struct netif *netif); + +#endif /* __LWIP_NETIF_H__ */ diff --git a/wii/libogc/include/lwip/opt.h b/wii/libogc/include/lwip/opt.h new file mode 100644 index 0000000000..8e3910d52b --- /dev/null +++ b/wii/libogc/include/lwip/opt.h @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_OPT_H__ +#define __LWIP_OPT_H__ + +/* Include user defined options first */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/* Define default values for unconfigured parameters. */ + +/* Platform specific locking */ + +/* + * enable SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT 0 +#endif + +#ifndef NO_SYS +#define NO_SYS 0 +#endif +/* ---------- Memory options ---------- */ +/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which + lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 + byte alignment -> define MEM_ALIGNMENT to 2. */ + +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 1 +#endif + +/* MEM_SIZE: the size of the heap memory. If the application will send +a lot of data that needs to be copied, this should be set high. */ +#ifndef MEM_SIZE +#define MEM_SIZE 1600 +#endif + +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK 0 +#endif + +/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application + sends a lot of data out of ROM (or other static memory), this + should be set high. */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 16 +#endif + +/* Number of raw connection PCBs */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB 4 +#endif + +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 4 +#endif +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB 5 +#endif +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#endif +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 16 +#endif +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 3 +#endif + +/* The following four are used only with the sequential API and can be + set to 0 if the application only will use the raw API. */ +/* MEMP_NUM_NETBUF: the number of struct netbufs. */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF 2 +#endif +/* MEMP_NUM_NETCONN: the number of struct netconns. */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN 4 +#endif +/* MEMP_NUM_APIMSG: the number of struct api_msg, used for + communication between the TCP/IP stack and the sequential + programs. */ +#ifndef MEMP_NUM_API_MSG +#define MEMP_NUM_API_MSG 8 +#endif +/* MEMP_NUM_TCPIPMSG: the number of struct tcpip_msg, which is used + for sequential API communication and incoming packets. Used in + src/api/tcpip.c. */ +#ifndef MEMP_NUM_TCPIP_MSG +#define MEMP_NUM_TCPIP_MSG 8 +#endif + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ + +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 16 +#endif + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ + +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE 128 +#endif + +/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a + link level header. Defaults to 14 for Ethernet. */ + +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN 14 +#endif + + + +/* ---------- ARP options ---------- */ + +/** Number of active hardware address, IP address pairs cached */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE 10 +#endif + +/** + * If enabled, outgoing packets are queued during hardware address + * resolution. + * + * This feature has not stabilized yet. Single-packet queueing is + * believed to be stable, multi-packet queueing is believed to + * clash with the TCP segment queueing. + * + * As multi-packet-queueing is currently disabled, enabling this + * _should_ work, but we need your testing feedback on lwip-users. + * + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING 1 +#endif + +/* This option is deprecated */ +#ifdef ETHARP_QUEUE_FIRST +#error ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h. +#endif + +/* This option is removed to comply with the ARP standard */ +#ifdef ETHARP_ALWAYS_INSERT +#error ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h. +#endif + +/* ---------- IP options ---------- */ +/* Define IP_FORWARD to 1 if you wish to have the ability to forward + IP packets across network interfaces. If you are going to run lwIP + on a device with only one network interface, define this to 0. */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif + +/* If defined to 1, IP options are allowed (but not parsed). If + defined to 0, all packets with IP options are dropped. */ +#ifndef IP_OPTIONS +#define IP_OPTIONS 1 +#endif + +/** IP reassembly and segmentation. Even if they both deal with IP + * fragments, note that these are orthogonal, one dealing with incoming + * packets, the other with outgoing packets + */ + +/** Reassemble incoming fragmented IP packets */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 1 +#endif + +/** Fragment outgoing IP packets if their size exceeds MTU */ +#ifndef IP_FRAG +#define IP_FRAG 1 +#endif + +/* ---------- ICMP options ---------- */ + +#ifndef ICMP_TTL +#define ICMP_TTL 255 +#endif + +/* ---------- RAW options ---------- */ + +#ifndef LWIP_RAW +#define LWIP_RAW 1 +#endif + +#ifndef RAW_TTL +#define RAW_TTL 255 +#endif + +/* ---------- DHCP options ---------- */ + +#ifndef LWIP_DHCP +#define LWIP_DHCP 0 +#endif + +/* 1 if you want to do an ARP check on the offered address + (recommended). */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK 1 +#endif + +/* ---------- UDP options ---------- */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +#ifndef UDP_TTL +#define UDP_TTL 255 +#endif + +/* ---------- TCP options ---------- */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +#ifndef TCP_TTL +#define TCP_TTL 255 +#endif + +#ifndef TCP_WND +#define TCP_WND 2048 +#endif + +#ifndef TCP_MAXRTX +#define TCP_MAXRTX 12 +#endif + +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX 6 +#endif + + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ 1 +#endif + +/* TCP Maximum segment size. */ +#ifndef TCP_MSS +#define TCP_MSS 128 /* A *very* conservative default. */ +#endif + +/* TCP sender buffer space (bytes). */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF 256 +#endif + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN 4 * TCP_SND_BUF/TCP_MSS +#endif + + +/* Maximum number of retransmissions of data segments. */ + +/* Maximum number of retransmissions of SYN segments. */ + +/* TCP writable space (bytes). This must be less than or equal + to TCP_SND_BUF. It is the amount of space which must be + available in the tcp snd_buf for select to return writable */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT TCP_SND_BUF/2 +#endif + +/* Support loop interface (127.0.0.1) */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF 1 +#endif + +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#define LWIP_EVENT_API 1 +#define LWIP_CALLBACK_API 0 +#endif + +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 1 +#endif + + +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO 1 +#endif + +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO 1 +#endif + +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO 1 +#endif + +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 1 +#endif + + +/* ---------- Socket Options ---------- */ +/* Enable SO_REUSEADDR and SO_REUSEPORT options */ +#ifndef SO_REUSE +# define SO_REUSE 0 +#endif + + +/* ---------- Statistics options ---------- */ +#ifndef LWIP_STATS +#define LWIP_STATS 1 +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + +#ifndef LINK_STATS +#define LINK_STATS 1 +#endif + +#ifndef IP_STATS +#define IP_STATS 1 +#endif + +#ifndef IPFRAG_STATS +#define IPFRAG_STATS 1 +#endif + +#ifndef ICMP_STATS +#define ICMP_STATS 1 +#endif + +#ifndef UDP_STATS +#define UDP_STATS 1 +#endif + +#ifndef TCP_STATS +#define TCP_STATS 1 +#endif + +#ifndef MEM_STATS +#define MEM_STATS 1 +#endif + +#ifndef MEMP_STATS +#define MEMP_STATS 1 +#endif + +#ifndef PBUF_STATS +#define PBUF_STATS 1 +#endif + +#ifndef SYS_STATS +#define SYS_STATS 1 +#endif + +#ifndef RAW_STATS +#define RAW_STATS 0 +#endif + +#else + +#define LINK_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define PBUF_STATS 0 +#define SYS_STATS 0 +#define RAW_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#endif /* LWIP_STATS */ + +/* ---------- PPP options ---------- */ + +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 /* Set for PPP */ +#endif + +#if PPP_SUPPORT + +#define NUM_PPP 1 /* Max PPP sessions. */ + + + +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 /* Set for PAP. */ +#endif + +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 /* Set for CHAP. */ +#endif + +#define MSCHAP_SUPPORT 0 /* Set for MSCHAP (NOT FUNCTIONAL!) */ +#define CBCP_SUPPORT 0 /* Set for CBCP (NOT FUNCTIONAL!) */ +#define CCP_SUPPORT 0 /* Set for CCP (NOT FUNCTIONAL!) */ + +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 0 /* Set for VJ header compression. */ +#endif + +#ifndef MD5_SUPPORT +#define MD5_SUPPORT 0 /* Set for MD5 (see also CHAP) */ +#endif + + +/* + * Timeouts. + */ +#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ +#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ + +#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ + +#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ +#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ + + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#if 1 +#define LCP_ECHOINTERVAL 0 +#else +#define LCP_ECHOINTERVAL 10 +#endif + +/* Number of unanswered echo requests before failure. */ +#define LCP_MAXECHOFAILS 3 + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#define PPP_MAXIDLEFLAG 100 + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + * limits. See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + * of living in lcp.h) + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#if 0 +#define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) +#else +#define PPP_MAXMTU 1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU 64 +#define PPP_MRU 1500 /* default MRU = max length of info field */ +#define PPP_MAXMRU 1500 /* Largest MRU we allow */ +#define PPP_DEFMRU 296 /* Try for this */ +#define PPP_MINMRU 128 /* No MRUs below this */ + + +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#define MAXSECRETLEN 256 /* max length of password or secret */ + +#endif /* PPP_SUPPORT */ + +/* checksum options - set to zero for hardware checksum support */ + +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 1 +#endif + +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 1 +#endif + +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 1 +#endif + +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#endif + +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#endif + +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 1 +#endif + +/* Debugging options all default to off */ + +#ifndef DBG_TYPES_ON +#define DBG_TYPES_ON 0 +#endif + +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG DBG_OFF +#endif + +#ifndef NETIF_DEBUG +#define NETIF_DEBUG DBG_OFF +#endif + +#ifndef PBUF_DEBUG +#define PBUF_DEBUG DBG_OFF +#endif + +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG DBG_OFF +#endif + +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG DBG_OFF +#endif + +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG DBG_OFF +#endif + +#ifndef ICMP_DEBUG +#define ICMP_DEBUG DBG_OFF +#endif + +#ifndef INET_DEBUG +#define INET_DEBUG DBG_OFF +#endif + +#ifndef IP_DEBUG +#define IP_DEBUG DBG_OFF +#endif + +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG DBG_OFF +#endif + +#ifndef RAW_DEBUG +#define RAW_DEBUG DBG_OFF +#endif + +#ifndef MEM_DEBUG +#define MEM_DEBUG DBG_OFF +#endif + +#ifndef MEMP_DEBUG +#define MEMP_DEBUG DBG_OFF +#endif + +#ifndef SYS_DEBUG +#define SYS_DEBUG DBG_OFF +#endif + +#ifndef TCP_DEBUG +#define TCP_DEBUG DBG_OFF +#endif + +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG DBG_OFF +#endif + +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG DBG_OFF +#endif + +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG DBG_OFF +#endif + +#ifndef TCP_REXMIT_DEBUG +#define TCP_REXMIT_DEBUG DBG_OFF +#endif + +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG DBG_OFF +#endif + +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG DBG_OFF +#endif + +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG DBG_OFF +#endif + +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG DBG_OFF +#endif + +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG DBG_OFF +#endif + +#ifndef UDP_DEBUG +#define UDP_DEBUG DBG_OFF +#endif + +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG DBG_OFF +#endif + +#ifndef PPP_DEBUG +#define PPP_DEBUG DBG_OFF +#endif + +#ifndef SLIP_DEBUG +#define SLIP_DEBUG DBG_OFF +#endif + +#ifndef DHCP_DEBUG +#define DHCP_DEBUG DBG_OFF +#endif + + +#ifndef DBG_MIN_LEVEL +#define DBG_MIN_LEVEL DBG_LEVEL_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ + + + diff --git a/wii/libogc/include/lwip/pbuf.h b/wii/libogc/include/lwip/pbuf.h new file mode 100644 index 0000000000..546aa30357 --- /dev/null +++ b/wii/libogc/include/lwip/pbuf.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_PBUF_H__ +#define __LWIP_PBUF_H__ + +#include "arch/cc.h" + + +#define PBUF_TRANSPORT_HLEN 20 +#define PBUF_IP_HLEN 20 + +typedef enum { + PBUF_TRANSPORT, + PBUF_IP, + PBUF_LINK, + PBUF_RAW +} pbuf_layer; + +typedef enum { + PBUF_RAM, + PBUF_ROM, + PBUF_REF, + PBUF_POOL +} pbuf_flag; + +/* Definitions for the pbuf flag field. These are NOT the flags that + * are passed to pbuf_alloc(). */ +#define PBUF_FLAG_RAM 0x00U /* Flags that pbuf data is stored in RAM */ +#define PBUF_FLAG_ROM 0x01U /* Flags that pbuf data is stored in ROM */ +#define PBUF_FLAG_POOL 0x02U /* Flags that the pbuf comes from the pbuf pool */ +#define PBUF_FLAG_REF 0x04U /* Flags thet the pbuf payload refers to RAM */ + +/** indicates this packet was broadcast on the link */ +#define PBUF_FLAG_LINK_BROADCAST 0x80U + +struct pbuf { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + u16_t tot_len; + + /** length of this buffer */ + u16_t len; + + /** flags telling the type of pbuf, see PBUF_FLAG_ */ + u16_t flags; + + /** + * the reference count always equals the number of pointers + * that refer to this pbuf. This can be pointers from an application, + * the stack itself, or pbuf->next pointers from a chain. + */ + u16_t ref; + +}; + +void pbuf_init(void); + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag); +void pbuf_realloc(struct pbuf *p, u16_t size); +u8_t pbuf_header(struct pbuf *p, s16_t header_size); +void pbuf_ref(struct pbuf *p); +void pbuf_ref_chain(struct pbuf *p); +u8_t pbuf_free(struct pbuf *p); +u8_t pbuf_clen(struct pbuf *p); +void pbuf_cat(struct pbuf *h, struct pbuf *t); +void pbuf_chain(struct pbuf *h, struct pbuf *t); +struct pbuf *pbuf_take(struct pbuf *f); +struct pbuf *pbuf_dechain(struct pbuf *p); +void pbuf_queue(struct pbuf *p, struct pbuf *n); +struct pbuf * pbuf_dequeue(struct pbuf *p); + +#endif /* __LWIP_PBUF_H__ */ diff --git a/wii/libogc/include/lwip/raw.h b/wii/libogc/include/lwip/raw.h new file mode 100644 index 0000000000..6f7a98717f --- /dev/null +++ b/wii/libogc/include/lwip/raw.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_RAW_H__ +#define __LWIP_RAW_H__ + +#include "lwip/arch.h" + +#include "lwip/pbuf.h" +#include "lwip/inet.h" +#include "lwip/ip.h" + +struct raw_pcb { +/* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u16_t protocol; + + u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + struct ip_addr *addr); + void *recv_arg; +}; + +/* The following functions is the application layer interface to the + RAW code. */ +struct raw_pcb * raw_new (u16_t proto); +void raw_remove (struct raw_pcb *pcb); +err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr); +err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr); + +void raw_recv (struct raw_pcb *pcb, + u8_t (* recv)(void *arg, struct raw_pcb *pcb, + struct pbuf *p, + struct ip_addr *addr), + void *recv_arg); +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr); +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +/* The following functions are the lower layer interface to RAW. */ +u8_t raw_input (struct pbuf *p, struct netif *inp); +void raw_init (void); + + +#endif /* __LWIP_RAW_H__ */ diff --git a/wii/libogc/include/lwip/sio.h b/wii/libogc/include/lwip/sio.h new file mode 100644 index 0000000000..8a37aa35ab --- /dev/null +++ b/wii/libogc/include/lwip/sio.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#include "arch/cc.h" + +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +#ifndef sio_open +sio_fd_t sio_open(u8_t); +#endif + +#ifndef sio_send +void sio_send(u8_t, sio_fd_t); +#endif + +#ifndef sio_recv +u8_t sio_recv(sio_fd_t); +#endif + +#ifndef sio_read +u32_t sio_read(sio_fd_t, u8_t *, u32_t); +#endif + +#ifndef sio_write +u32_t sio_write(sio_fd_t, u8_t *, u32_t); +#endif + +#ifndef sio_read_abort +void sio_read_abort(sio_fd_t); +#endif diff --git a/wii/libogc/include/lwip/snmp.h b/wii/libogc/include/lwip/snmp.h new file mode 100644 index 0000000000..7d160aaa44 --- /dev/null +++ b/wii/libogc/include/lwip/snmp.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2001, 2002 Leon Woestenberg + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef __LWIP_SNMP_H__ +#define __LWIP_SNMP_H__ + +#include "lwip/opt.h" + +/* SNMP support available? */ +#if defined(LWIP_SNMP) && (LWIP_SNMP > 0) + +/* network interface */ +void snmp_add_ifinoctets(unsigned long value); +void snmp_inc_ifinucastpkts(void); +void snmp_inc_ifinnucastpkts(void); +void snmp_inc_ifindiscards(void); +void snmp_add_ifoutoctets(unsigned long value); +void snmp_inc_ifoutucastpkts(void); +void snmp_inc_ifoutnucastpkts(void); +void snmp_inc_ifoutdiscards(void); + +/* IP */ +void snmp_inc_ipinreceives(void); +void snmp_inc_ipindelivers(void); +void snmp_inc_ipindiscards(void); +void snmp_inc_ipoutdiscards(void); +void snmp_inc_ipoutrequests(void); +void snmp_inc_ipunknownprotos(void); +void snmp_inc_ipnoroutes(void); +void snmp_inc_ipforwdatagrams(void); + +/* ICMP */ +void snmp_inc_icmpinmsgs(void); +void snmp_inc_icmpinerrors(void); +void snmp_inc_icmpindestunreachs(void); +void snmp_inc_icmpintimeexcds(void); +void snmp_inc_icmpinparmprobs(void); +void snmp_inc_icmpinsrcquenchs(void); +void snmp_inc_icmpinredirects(void); +void snmp_inc_icmpinechos(void); +void snmp_inc_icmpinechoreps(void); +void snmp_inc_icmpintimestamps(void); +void snmp_inc_icmpintimestampreps(void); +void snmp_inc_icmpinaddrmasks(void); +void snmp_inc_icmpinaddrmaskreps(void); +void snmp_inc_icmpoutmsgs(void); +void snmp_inc_icmpouterrors(void); +void snmp_inc_icmpoutdestunreachs(void); +void snmp_inc_icmpouttimeexcds(void); +void snmp_inc_icmpoutparmprobs(void); +void snmp_inc_icmpoutsrcquenchs(void); +void snmp_inc_icmpoutredirects(void); +void snmp_inc_icmpoutechos(void); +void snmp_inc_icmpoutechoreps(void); +void snmp_inc_icmpouttimestamps(void); +void snmp_inc_icmpouttimestampreps(void); +void snmp_inc_icmpoutaddrmasks(void); +void snmp_inc_icmpoutaddrmaskreps(void); + +/* TCP */ +void snmp_inc_tcpactiveopens(void); +void snmp_inc_tcppassiveopens(void); +void snmp_inc_tcpattemptfails(void); +void snmp_inc_tcpestabresets(void); +void snmp_inc_tcpcurrestab(void); +void snmp_inc_tcpinsegs(void); +void snmp_inc_tcpoutsegs(void); +void snmp_inc_tcpretranssegs(void); +void snmp_inc_tcpinerrs(void); +void snmp_inc_tcpoutrsts(void); + +/* UDP */ +void snmp_inc_udpindatagrams(void); +void snmp_inc_udpnoports(void); +void snmp_inc_udpinerrors(void); +void snmp_inc_udpoutdatagrams(void); + +/* LWIP_SNMP support not available */ +/* define everything to be empty */ +#else + +/* network interface */ +#define snmp_add_ifinoctets(value) +#define snmp_inc_ifinucastpkts() +#define snmp_inc_ifinnucastpkts() +#define snmp_inc_ifindiscards() +#define snmp_add_ifoutoctets(value) +#define snmp_inc_ifoutucastpkts() +#define snmp_inc_ifoutnucastpkts() +#define snmp_inc_ifoutdiscards() + +/* IP */ +#define snmp_inc_ipinreceives() +#define snmp_inc_ipindelivers() +#define snmp_inc_ipindiscards() +#define snmp_inc_ipoutdiscards() +#define snmp_inc_ipoutrequests() +#define snmp_inc_ipunknownprotos() +#define snmp_inc_ipnoroutes() +#define snmp_inc_ipforwdatagrams() + +/* ICMP */ +#define snmp_inc_icmpinmsgs() +#define snmp_inc_icmpinerrors() +#define snmp_inc_icmpindestunreachs() +#define snmp_inc_icmpintimeexcds() +#define snmp_inc_icmpinparmprobs() +#define snmp_inc_icmpinsrcquenchs() +#define snmp_inc_icmpinredirects() +#define snmp_inc_icmpinechos() +#define snmp_inc_icmpinechoreps() +#define snmp_inc_icmpintimestamps() +#define snmp_inc_icmpintimestampreps() +#define snmp_inc_icmpinaddrmasks() +#define snmp_inc_icmpinaddrmaskreps() +#define snmp_inc_icmpoutmsgs() +#define snmp_inc_icmpouterrors() +#define snmp_inc_icmpoutdestunreachs() +#define snmp_inc_icmpouttimeexcds() +#define snmp_inc_icmpoutparmprobs() +#define snmp_inc_icmpoutsrcquenchs() +#define snmp_inc_icmpoutredirects() +#define snmp_inc_icmpoutechos() +#define snmp_inc_icmpoutechoreps() +#define snmp_inc_icmpouttimestamps() +#define snmp_inc_icmpouttimestampreps() +#define snmp_inc_icmpoutaddrmasks() +#define snmp_inc_icmpoutaddrmaskreps() +/* TCP */ +#define snmp_inc_tcpactiveopens() +#define snmp_inc_tcppassiveopens() +#define snmp_inc_tcpattemptfails() +#define snmp_inc_tcpestabresets() +#define snmp_inc_tcpcurrestab() +#define snmp_inc_tcpinsegs() +#define snmp_inc_tcpoutsegs() +#define snmp_inc_tcpretranssegs() +#define snmp_inc_tcpinerrs() +#define snmp_inc_tcpoutrsts() + +/* UDP */ +#define snmp_inc_udpindatagrams() +#define snmp_inc_udpnoports() +#define snmp_inc_udpinerrors() +#define snmp_inc_udpoutdatagrams() + +#endif + +#endif /* __LWIP_SNMP_H__ */ diff --git a/wii/libogc/include/lwip/sockets.h b/wii/libogc/include/lwip/sockets.h new file mode 100644 index 0000000000..d5f8ccf74a --- /dev/null +++ b/wii/libogc/include/lwip/sockets.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +#ifndef __LWIP_SOCKETS_H__ +#define __LWIP_SOCKETS_H__ +#include "lwip/ip_addr.h" + +struct sockaddr_in { + u8_t sin_len; + u8_t sin_family; + u16_t sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +struct sockaddr { + u8_t sa_len; + u8_t sa_family; + char sa_data[14]; +}; + +#ifndef socklen_t +# define socklen_t int +#endif + + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. + */ +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ + +#define SO_DONTLINGER (int)(~SO_LINGER) + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ + + + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xfff /* options for socket level */ + + +#define AF_UNSPEC 0 +#define AF_INET 2 +#define PF_INET AF_INET +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 + +#define INADDR_ANY 0 +#define INADDR_BROADCAST 0xffffffff + +/* Flags we can use with send and recv. */ +#define MSG_DONTWAIT 0x40 /* Nonblocking i/o for this operation only */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * Definitions for IP precedence (also in ip_tos) (hopefully unused) + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000 /* no parameters */ +#define IOC_OUT 0x40000000 /* copy out parameters */ +#define IOC_IN 0x80000000 /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +#ifndef O_NONBLOCK +#define O_NONBLOCK 04000U +#endif + +#ifndef FD_SET + #undef FD_SETSIZE + #define FD_SETSIZE 16 + #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) + #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) + #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) + #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p))) + + typedef struct fd_set { + unsigned char fd_bits [(FD_SETSIZE+7)/8]; + } fd_set; + +/* + * only define this in sockets.c so it does not interfere + * with other projects namespaces where timeval is present + */ +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE + struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ + }; +#endif + +#endif + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, int len, unsigned int flags); +int lwip_read(int s, void *mem, int len); +int lwip_recvfrom(int s, void *mem, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, void *dataptr, int size, unsigned int flags); +int lwip_sendto(int s, void *dataptr, int size, unsigned int flags, + struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, void *dataptr, int size); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); + +#if LWIP_COMPAT_SOCKETS +#define accept(a,b,c) lwip_accept(a,b,c) +#define bind(a,b,c) lwip_bind(a,b,c) +#define shutdown(a,b) lwip_shutdown(a,b) +#define close(s) lwip_close(s) +#define connect(a,b,c) lwip_connect(a,b,c) +#define getsockname(a,b,c) lwip_getsockname(a,b,c) +#define getpeername(a,b,c) lwip_getpeername(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) +#define listen(a,b) lwip_listen(a,b) +#define recv(a,b,c,d) lwip_recv(a,b,c,d) +#define read(a,b,c) lwip_read(a,b,c) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) +#define send(a,b,c,d) lwip_send(a,b,c,d) +#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) +#define socket(a,b,c) lwip_socket(a,b,c) +#define write(a,b,c) lwip_write(a,b,c) +#define select(a,b,c,d,e) lwip_select(a,b,c,d,e) +#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c) +#endif /* LWIP_COMPAT_SOCKETS */ + +#endif /* __LWIP_SOCKETS_H__ */ + diff --git a/wii/libogc/include/lwip/stats.h b/wii/libogc/include/lwip/stats.h new file mode 100644 index 0000000000..71acfd068f --- /dev/null +++ b/wii/libogc/include/lwip/stats.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_STATS_H__ +#define __LWIP_STATS_H__ + +#include "lwip/opt.h" +#include "arch/cc.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#if LWIP_STATS + +struct stats_proto { + u16_t xmit; /* Transmitted packets. */ + u16_t rexmit; /* Retransmitted packets. */ + u16_t recv; /* Received packets. */ + u16_t fw; /* Forwarded packets. */ + u16_t drop; /* Dropped packets. */ + u16_t chkerr; /* Checksum error. */ + u16_t lenerr; /* Invalid length error. */ + u16_t memerr; /* Out of memory error. */ + u16_t rterr; /* Routing error. */ + u16_t proterr; /* Protocol error. */ + u16_t opterr; /* Error in options. */ + u16_t err; /* Misc error. */ + u16_t cachehit; +}; + +struct stats_mem { + mem_size_t avail; + mem_size_t used; + mem_size_t max; + mem_size_t err; +}; + +struct stats_pbuf { + u16_t avail; + u16_t used; + u16_t max; + u16_t err; + + u16_t alloc_locked; + u16_t refresh_locked; +}; + +struct stats_syselem { + u16_t used; + u16_t max; + u16_t err; +}; + +struct stats_sys { + struct stats_syselem sem; + struct stats_syselem mbox; +}; + +struct stats_ { + struct stats_proto link; + struct stats_proto ip_frag; + struct stats_proto ip; + struct stats_proto icmp; + struct stats_proto udp; + struct stats_proto tcp; + struct stats_pbuf pbuf; + struct stats_mem mem; + struct stats_mem memp[MEMP_MAX]; + struct stats_sys sys; +}; + +extern struct stats_ lwip_stats; + + +void stats_init(void); + +#define STATS_INC(x) ++lwip_stats.x +#else +#define stats_init() +#define STATS_INC(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#else +#define TCP_STATS_INC(x) +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#else +#define UDP_STATS_INC(x) +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#else +#define ICMP_STATS_INC(x) +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#else +#define IP_STATS_INC(x) +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#else +#define IPFRAG_STATS_INC(x) +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#else +#define LINK_STATS_INC(x) +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void); +#else +#define stats_display() +#endif + +#endif /* __LWIP_STATS_H__ */ + + + + diff --git a/wii/libogc/include/lwip/sys.h b/wii/libogc/include/lwip/sys.h new file mode 100644 index 0000000000..ce13484b3e --- /dev/null +++ b/wii/libogc/include/lwip/sys.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_SYS_H__ +#define __LWIP_SYS_H__ + +#include "arch/cc.h" + +#include "lwip/opt.h" + + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null + definitions of the sys_ functions. */ +#include "arch/sys_arch.h" + +struct sys_timeout {u8_t dummy;}; + +#define sys_init() +#define sys_timeout(m,h,a) +#define sys_untimeout(m,a) +#define sys_sem_new(c) c +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_sem_free(s) +#define sys_mbox_new() 0 +#define sys_mbox_fetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_free(m) + +#define sys_thread_new(t,a,p) + +#else /* NO_SYS */ + +#include "arch/sys_arch.h" + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffff + +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeout { + struct sys_timeout *next; + u32_t time; + sys_timeout_handler h; + void *arg; +}; + +struct sys_timeouts { + struct sys_timeout *next; +}; + +/* sys_init() must be called before anthing else. */ +void sys_init(void); + +/* + * sys_timeout(): + * + * Schedule a timeout a specified amount of milliseconds in the + * future. When the timeout occurs, the specified timeout handler will + * be called. The handler will be passed the "arg" argument when + * called. + * + */ +void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +void sys_untimeout(sys_timeout_handler h, void *arg); +struct sys_timeouts *sys_arch_timeouts(void); + +/* Semaphore functions. */ +sys_sem_t sys_sem_new(u8_t count); +void sys_sem_signal(sys_sem_t sem); +u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout); +void sys_sem_free(sys_sem_t sem); +void sys_sem_wait(sys_sem_t sem); +int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout); + +/* Time functions. */ +#ifndef sys_msleep +void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ +#endif +#ifndef sys_jiffies +u32_t sys_jiffies(void); /* since power up. */ +#endif + +/* Mailbox functions. */ +sys_mbox_t sys_mbox_new(void); +void sys_mbox_post(sys_mbox_t mbox, void *msg); +u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout); +void sys_mbox_free(sys_mbox_t mbox); +void sys_mbox_fetch(sys_mbox_t mbox, void **msg); + + +/* Thread functions. */ +sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio); + +/* The following functions are used only in Unix code, and + can be omitted when porting the stack. */ +/* Returns the current time in microseconds. */ +unsigned long sys_now(void); + +#endif /* NO_SYS */ + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex. This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void); +void sys_arch_unprotect(sys_prot_t pval); + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) +#define SYS_ARCH_UNPROTECT(lev) + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +#endif /* __LWIP_SYS_H__ */ diff --git a/wii/libogc/include/lwip/tcp.h b/wii/libogc/include/lwip/tcp.h new file mode 100644 index 0000000000..1cf0e856d1 --- /dev/null +++ b/wii/libogc/include/lwip/tcp.h @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCP_H__ +#define __LWIP_TCP_H__ + +#include "lwip/sys.h" +#include "lwip/mem.h" + +#include "lwip/pbuf.h" +#include "lwip/opt.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" + +#include "lwip/err.h" + +struct tcp_pcb; + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +void tcp_init (void); /* Must be called first to + initialize TCP. */ +void tcp_tmr (void); /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void); +struct tcp_pcb * tcp_alloc (u8_t prio); + +void tcp_arg (struct tcp_pcb *pcb, void *arg); +void tcp_accept (struct tcp_pcb *pcb, + err_t (* accept)(void *arg, struct tcp_pcb *newpcb, + err_t err)); +void tcp_recv (struct tcp_pcb *pcb, + err_t (* recv)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err)); +void tcp_sent (struct tcp_pcb *pcb, + err_t (* sent)(void *arg, struct tcp_pcb *tpcb, + u16_t len)); +void tcp_poll (struct tcp_pcb *pcb, + err_t (* poll)(void *arg, struct tcp_pcb *tpcb), + u8_t interval); +void tcp_err (struct tcp_pcb *pcb, + void (* err)(void *arg, err_t err)); + +#define tcp_mss(pcb) ((pcb)->mss) +#define tcp_sndbuf(pcb) ((pcb)->snd_buf) + +void tcp_recved (struct tcp_pcb *pcb, u16_t len); +err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr, + u16_t port); +err_t tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr, + u16_t port, err_t (* connected)(void *arg, + struct tcp_pcb *tpcb, + err_t err)); +struct tcp_pcb * tcp_listen (struct tcp_pcb *pcb); +void tcp_abort (struct tcp_pcb *pcb); +err_t tcp_close (struct tcp_pcb *pcb); +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t copy); + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void); +void tcp_fasttmr (void); + + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +err_t tcp_output (struct tcp_pcb *pcb); +void tcp_rexmit (struct tcp_pcb *pcb); +void tcp_rexmit_rto (struct tcp_pcb *pcb); + + + +#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in + milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in + milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in + milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6 /* x RTO */ + +#define TCP_MSL 60000 /* The maximum segment lifetime in microseconds */ + +/* + * User-settable options (used with setsockopt). + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keepalive miliseconds */ + +/* Keepalive values */ +#define TCP_KEEPDEFAULT 7200000 /* KEEPALIVE timer in miliseconds */ +#define TCP_KEEPINTVL 75000 /* Time between KEEPALIVE probes in miliseconds */ +#define TCP_KEEPCNT 9 /* Counter for KEEPALIVE probes */ +#define TCP_MAXIDLE TCP_KEEPCNT * TCP_KEEPINTVL /* Maximum KEEPALIVE probe time */ + + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); + PACK_STRUCT_FIELD(u32_t seqno); + PACK_STRUCT_FIELD(u32_t ackno); + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); + PACK_STRUCT_FIELD(u16_t wnd); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags)) +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) + +#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \ + TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0)) + +enum tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + +/* the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ + IP_PCB; +/** protocol specific PCB members */ + struct tcp_pcb *next; /* for the linked list */ + enum tcp_state state; /* TCP state */ + u8_t prio; + void *callback_arg; + + u16_t local_port; + u16_t remote_port; + + u8_t flags; +#define TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */ +#define TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */ +#define TF_INFR (u8_t)0x04U /* In fast recovery. */ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ +#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */ + + /* receiver variables */ + u32_t rcv_nxt; /* next seqno expected */ + u16_t rcv_wnd; /* receiver window */ + + /* Timers */ + u32_t tmr; + u8_t polltmr, pollinterval; + + /* Retransmission timer. */ + u16_t rtime; + + u16_t mss; /* maximum segment size */ + + /* RTT (round trip time) estimation variables */ + u32_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; /* @todo document this */ + + u16_t rto; /* retransmission time-out */ + u8_t nrtx; /* number of retransmissions */ + + /* fast retransmit/recovery */ + u32_t lastack; /* Highest acknowledged seqno. */ + u8_t dupacks; + + /* congestion avoidance/control variables */ + u16_t cwnd; + u16_t ssthresh; + + /* sender variables */ + u32_t snd_nxt, /* next seqno to be sent */ + snd_max, /* Highest seqno sent. */ + snd_wnd, /* sender window */ + snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last + window update. */ + snd_lbb; /* Sequence number of next byte to be buffered. */ + + u16_t acked; + + u16_t snd_buf; /* Available buffer space for sending (in bytes). */ + u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ + + + /* These are ordered by sequence number: */ + struct tcp_seg *unsent; /* Unsent (queued) segments. */ + struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ + struct tcp_seg *ooseq; /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + +#if LWIP_CALLBACK_API + /* Function to be called when more send buffer space is available. */ + err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space); + + /* Function to be called when (in-sequence) data has arrived. */ + err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); + + /* Function to be called when a connection has been set up. */ + err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err); + + /* Function to call when a listener has been connected. */ + err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); + + /* Function which is called periodically. */ + err_t (* poll)(void *arg, struct tcp_pcb *pcb); + + /* Function to be called whenever a fatal error occurs. */ + void (* errf)(void *arg, err_t err); +#endif /* LWIP_CALLBACK_API */ + + /* idle time before KEEPALIVE is sent */ + u32_t keepalive; + + /* KEEPALIVE counter */ + u8_t keep_cnt; +}; + +struct tcp_pcb_listen { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + struct tcp_pcb_listen *next; /* for the linked list */ + + /* Even if state is obviously LISTEN this is here for + * field compatibility with tpc_pcb to which it is cast sometimes + * Until a cleaner solution emerges this is here.FIXME + */ + enum tcp_state state; /* TCP state */ + + u8_t prio; + void *callback_arg; + + u16_t local_port; + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. */ + err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); +#endif /* LWIP_CALLBACK_API */ +}; + +#if LWIP_EVENT_API + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_POLL, NULL, 0, ERR_OK) +#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ + LWIP_EVENT_ERR, NULL, 0, (err)) +#else /* LWIP_EVENT_API */ +#define TCP_EVENT_ACCEPT(pcb,err,ret) \ + if((pcb)->accept != NULL) \ + (ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err))) +#define TCP_EVENT_SENT(pcb,space,ret) \ + if((pcb)->sent != NULL) \ + (ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space))) +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + if((pcb)->recv != NULL) \ + { ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \ + if (p) pbuf_free(p); } +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + if((pcb)->connected != NULL) \ + (ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err))) +#define TCP_EVENT_POLL(pcb,ret) \ + if((pcb)->poll != NULL) \ + (ret = (pcb)->poll((pcb)->callback_arg,(pcb))) +#define TCP_EVENT_ERR(errf,arg,err) \ + if((errf) != NULL) \ + (errf)((arg),(err)) +#endif /* LWIP_EVENT_API */ + +/* This structure represents a TCP segment on the unsent and unacked queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segements on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + void *dataptr; /* pointer to the TCP data in the pbuf */ + u16_t len; /* the TCP length of this segment */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +/* Internal functions and global variables: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); +void tcp_pcb_purge(struct tcp_pcb *pcb); +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); + +u8_t tcp_segs_free(struct tcp_seg *seg); +u8_t tcp_seg_free(struct tcp_seg *seg); +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); + +#define tcp_ack(pcb) if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + tcp_output(pcb); \ + } else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } + +#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \ + tcp_output(pcb) + +err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags); +err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len, + u8_t flags, u8_t copy, + u8_t *optdata, u8_t optlen); + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); + +void tcp_rst(u32_t seqno, u32_t ackno, + struct ip_addr *local_ip, struct ip_addr *remote_ip, + u16_t local_port, u16_t remote_port); + +u32_t tcp_next_iss(void); + +void tcp_keepalive(struct tcp_pcb *pcb); + +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr); +void tcp_debug_print_flags(u8_t flags); +void tcp_debug_print_state(enum tcp_state s); +void tcp_debug_print_pcbs(void); +s16_t tcp_pcbs_sane(void); +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ +/* +#if NO_SYS +#define tcp_timer_needed() +#else +void tcp_timer_needed(void); +#endif +*/ +void tcp_timer_needed(void); + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ + +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#if 0 +#define TCP_REG(pcbs, npcb) do {\ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \ + for(tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \ + npcb->next = *pcbs; \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \ + *(pcbs) = npcb; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \ + if(*pcbs == npcb) { \ + *pcbs = (*pcbs)->next; \ + } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \ + tcp_tmp_pcb->next = npcb->next; \ + break; \ + } \ + } \ + npcb->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \ + } while(0) + +#else /* LWIP_DEBUG */ +#define TCP_REG(pcbs, npcb) do { \ + npcb->next = *pcbs; \ + *(pcbs) = npcb; \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + if(*(pcbs) == npcb) { \ + (*(pcbs)) = (*pcbs)->next; \ + } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \ + tcp_tmp_pcb->next = npcb->next; \ + break; \ + } \ + } \ + npcb->next = NULL; \ + } while(0) +#endif /* LWIP_DEBUG */ +#endif /* __LWIP_TCP_H__ */ + + + diff --git a/wii/libogc/include/lwip/tcpip.h b/wii/libogc/include/lwip/tcpip.h new file mode 100644 index 0000000000..6945084cd9 --- /dev/null +++ b/wii/libogc/include/lwip/tcpip.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCPIP_H__ +#define __LWIP_TCPIP_H__ + +#include "lwip/api_msg.h" +#include "lwip/pbuf.h" + +enum netmsq_type { + NETMSG_API, + NETMSG_INPUT, + NETMSG_CALLBACK +}; + +struct net_msg { + enum netmsq_type type; + union { + struct api_msg *apimsg; + struct { + struct pbuf *p; + struct netif *net; + } inp; + struct { + void (*f)(void *); + void *ctx; + } cb; + } msg; +}; + +#endif /* __LWIP_TCPIP_H__ */ diff --git a/wii/libogc/include/lwip/udp.h b/wii/libogc/include/lwip/udp.h new file mode 100644 index 0000000000..ede04745f9 --- /dev/null +++ b/wii/libogc/include/lwip/udp.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_UDP_H__ +#define __LWIP_UDP_H__ + +#include "lwip/arch.h" + +#include "lwip/pbuf.h" +#include "lwip/inet.h" +#include "lwip/ip.h" + +#define UDP_HLEN 8 + +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U + +struct udp_pcb { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + + struct udp_pcb *next; + + u8_t flags; + u16_t local_port, remote_port; + + u16_t chksum_len; + + void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + struct ip_addr *addr, u16_t port); + void *recv_arg; +}; + +/* The following functions is the application layer interface to the + UDP code. */ +struct udp_pcb * udp_new (void); +void udp_remove (struct udp_pcb *pcb); +err_t udp_bind (struct udp_pcb *pcb, struct ip_addr *ipaddr, + u16_t port); +err_t udp_connect (struct udp_pcb *pcb, struct ip_addr *ipaddr, + u16_t port); +void udp_disconnect (struct udp_pcb *pcb); +void udp_recv (struct udp_pcb *pcb, + void (* recv)(void *arg, struct udp_pcb *upcb, + struct pbuf *p, + struct ip_addr *addr, + u16_t port), + void *recv_arg); +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port); +err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); + +#define udp_flags(pcb) ((pcb)->flags) +#define udp_setflags(pcb, f) ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void udp_input (struct pbuf *p, struct netif *inp); +void udp_init (void); + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr); +#else +#define udp_debug_print(udphdr) +#endif +#endif /* __LWIP_UDP_H__ */ + + diff --git a/wii/libogc/include/netif/arch/cc.h b/wii/libogc/include/netif/arch/cc.h new file mode 100644 index 0000000000..df9aef57b0 --- /dev/null +++ b/wii/libogc/include/netif/arch/cc.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __ARCH_CC_H__ +#define __ARCH_CC_H__ + +#include +#include +#include +#include "asm.h" +#include "processor.h" + +typedef u8 u8_t; +typedef s8 s8_t; +typedef u16 u16_t; +typedef s16 s16_t; +typedef u32 u32_t; +typedef s32 s32_t; +typedef u32 mem_ptr_t; + + +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +#define LWIP_PLATFORM_ASSERT(x) { printf(x); while (1); } +#define LWIP_PLATFORM_DIAG(x) printf x + +#define SYS_ARCH_DECL_PROTECT(lev) u32 lev +#define SYS_ARCH_PROTECT(lev) _CPU_ISR_Disable(lev) +#define SYS_ARCH_UNPROTECT(lev) _CPU_ISR_Restore(lev) + +/* Define (sn)printf formatters for these lwIP types */ +#define U16_F "hu" +#define S16_F "hd" +#define X16_F "hx" +#define U32_F "u" +#define S32_F "d" +#define X32_F "x" + + +#endif /* __ARCH_CC_H__ */ diff --git a/wii/libogc/include/netif/arch/cpu.h b/wii/libogc/include/netif/arch/cpu.h new file mode 100644 index 0000000000..b4cc1b19a6 --- /dev/null +++ b/wii/libogc/include/netif/arch/cpu.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __CPU_H__ +#define __CPU_H__ + +#define BYTE_ORDER BIG_ENDIAN + +#endif /* __CPU_H__ */ diff --git a/wii/libogc/include/netif/arch/init.h b/wii/libogc/include/netif/arch/init.h new file mode 100644 index 0000000000..7070029265 --- /dev/null +++ b/wii/libogc/include/netif/arch/init.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __ARCH_INIT_H__ +#define __ARCH_INIT_H__ + +#define TCPIP_INIT_DONE(arg) tcpip_init_done(arg) + +void tcpip_init_done(void *); +int wait_for_tcpip_init(void); + +#endif /* __ARCH_INIT_H__ */ + + + + diff --git a/wii/libogc/include/netif/arch/lib.h b/wii/libogc/include/netif/arch/lib.h new file mode 100644 index 0000000000..ea5e6d864e --- /dev/null +++ b/wii/libogc/include/netif/arch/lib.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LIB_H__ +#define __LIB_H__ + +#include + +#define bcopy(s, d, l) memcpy(d, s, l) +#define bzero(d, l) memset(d, 0, l) + +#endif /* __LIB_H__ */ diff --git a/wii/libogc/include/netif/arch/perf.h b/wii/libogc/include/netif/arch/perf.h new file mode 100644 index 0000000000..089facac1d --- /dev/null +++ b/wii/libogc/include/netif/arch/perf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __PERF_H__ +#define __PERF_H__ + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* __PERF_H__ */ diff --git a/wii/libogc/include/netif/arch/sys_arch.h b/wii/libogc/include/netif/arch/sys_arch.h new file mode 100644 index 0000000000..c19e57326e --- /dev/null +++ b/wii/libogc/include/netif/arch/sys_arch.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __SYS_GC_H__ +#define __SYS_GC_H__ + +#include +#include +#include +#include +#include + +#define SYS_MBOX_NULL MQ_BOX_NULL +#define SYS_SEM_NULL LWP_SEM_NULL + +typedef sem_t sys_sem; +typedef sem_t *sys_sem_t; + +typedef mqbox_t sys_mbox; +typedef mqbox_t *sys_mbox_t; + +typedef lwp_t sys_thread; +typedef lwp_t* sys_thread_t; + +#endif /* __SYS_C64_H__ */ diff --git a/wii/libogc/include/netif/etharp.h b/wii/libogc/include/netif/etharp.h new file mode 100644 index 0000000000..08437afe54 --- /dev/null +++ b/wii/libogc/include/netif/etharp.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __NETIF_ETHARP_H__ +#define __NETIF_ETHARP_H__ + +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/ip.h" + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[6]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FIELD(struct eth_addr dest); + PACK_STRUCT_FIELD(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message */ +struct etharp_hdr { + PACK_STRUCT_FIELD(struct eth_hdr ethhdr); + PACK_STRUCT_FIELD(u16_t hwtype); + PACK_STRUCT_FIELD(u16_t proto); + PACK_STRUCT_FIELD(u16_t _hwlen_protolen); + PACK_STRUCT_FIELD(u16_t opcode); + PACK_STRUCT_FIELD(struct eth_addr shwaddr); + PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); + PACK_STRUCT_FIELD(struct eth_addr dhwaddr); + PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ethip_hdr { + PACK_STRUCT_FIELD(struct eth_hdr eth); + PACK_STRUCT_FIELD(struct ip_hdr ip); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** 5 seconds period */ +#define ARP_TMR_INTERVAL 5000 + +#define ETHTYPE_ARP 0x0806 +#define ETHTYPE_IP 0x0800 + +void etharp_init(void); +void etharp_tmr(void); +void etharp_ip_input(struct netif *netif, struct pbuf *p); +void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, + struct pbuf *p); +err_t etharp_output(struct netif *netif, struct ip_addr *ipaddr, + struct pbuf *q); +err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr); + +#endif /* __NETIF_ARP_H__ */ diff --git a/wii/libogc/include/netif/gcif/gcif.h b/wii/libogc/include/netif/gcif/gcif.h new file mode 100644 index 0000000000..98e2abcb69 --- /dev/null +++ b/wii/libogc/include/netif/gcif/gcif.h @@ -0,0 +1,45 @@ +#ifndef __GCIF_H__ +#define __GCIF_H__ + +#include + +#define ERR_NODATA -12 +#define ERR_ALLREAD -13 +#define ERR_TXERROR -14 +#define ERR_RXERROR -14 +#define ERR_NODEV -16 +#define ERR_PKTSIZE -17 +#define ERR_TXPENDING -18 + +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) +static inline u16 cpu_to_le16(u16 x) { return (x<<8) | (x>>8);} +static inline u32 cpu_to_le32(u32 x) { return((x>>24) | ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));} + +#define cpu_to_le16p(addr) (cpu_to_le16(*(addr))) +#define cpu_to_le32p(addr) (cpu_to_le32(*(addr))) +#define cpu_to_be16p(addr) (cpu_to_be16(*(addr))) +#define cpu_to_be32p(addr) (cpu_to_be32(*(addr))) + +static inline void cpu_to_le16s(u16 *a) {*a = cpu_to_le16(*a);} +static inline void cpu_to_le32s(u32 *a) {*a = cpu_to_le32(*a);} +static inline void cpu_to_be16s(u16 *a) {*a = cpu_to_be16(*a);} +static inline void cpu_to_be32s(u32 *a) {*a = cpu_to_be32(*a);} + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) + +typedef void* dev_s; + +dev_s bba_create(struct netif *); +err_t bba_init(struct netif *); +void bba_process(struct pbuf *p,struct netif *dev); + +#endif diff --git a/wii/libogc/include/netif/loopif.h b/wii/libogc/include/netif/loopif.h new file mode 100644 index 0000000000..97b3c67645 --- /dev/null +++ b/wii/libogc/include/netif/loopif.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __NETIF_LOOPIF_H__ +#define __NETIF_LOOPIF_H__ + +#include "lwip/netif.h" + +err_t loopif_init(struct netif *netif); + +#endif /* __NETIF_LOOPIF_H__ */ diff --git a/wii/libogc/include/network.h b/wii/libogc/include/network.h new file mode 100644 index 0000000000..91a526d1f1 --- /dev/null +++ b/wii/libogc/include/network.h @@ -0,0 +1,287 @@ +#ifndef __NETWORK_H__ +#define __NETWORK_H__ + +#include +#include +#include + +#define INVALID_SOCKET (~0) +#define SOCKET_ERROR (-1) + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. + */ +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ + +#define SO_DONTLINGER (int)(~SO_LINGER) + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ + + + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xffff /* options for socket level */ + +#define AF_UNSPEC 0 +#define AF_INET 2 +#define PF_INET AF_INET +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 + +#define INADDR_ANY 0 +#define INADDR_BROADCAST 0xffffffff + +/* Flags we can use with send and recv. */ +#define MSG_DONTWAIT 0x40 /* Nonblocking i/o for this operation only */ + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * Definitions for IP precedence (also in ip_tos) (hopefully unused) + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000 /* no parameters */ +#define IOC_OUT 0x40000000 /* copy out parameters */ +#define IOC_IN 0x80000000 /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +#ifndef O_NONBLOCK +#define O_NONBLOCK 04000U +#endif + +#ifndef FD_SET + #undef FD_SETSIZE + #define FD_SETSIZE 16 + #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) + #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) + #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) + #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p))) + + typedef struct fd_set { + u8 fd_bits [(FD_SETSIZE+7)/8]; + } fd_set; + +#endif + +#ifndef TCP_NODELAY +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#endif +#ifndef TCP_KEEPALIVE +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keepalive miliseconds */ +#endif + +#ifndef socklen_t +#define socklen_t u32 +#endif + +#ifndef htons +#define htons(x) (x) +#endif +#ifndef ntohs +#define ntohs(x) (x) +#endif +#ifndef htonl +#define htonl(x) (x) +#endif +#ifndef ntohl +#define ntohl(x) (x) +#endif + +#ifndef h_addr +#define h_addr h_addr_list[0] +#endif + +#ifndef IP4_ADDR +#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->s_addr = htonl(((u32)(a&0xff)<<24)|((u32)(b&0xff)<<16)|((u32)(c&0xff)<<8)|(u32)(d&0xff)) +#define ip4_addr1(ipaddr) ((u32)(ntohl((ipaddr)->s_addr) >> 24) & 0xff) +#define ip4_addr2(ipaddr) ((u32)(ntohl((ipaddr)->s_addr) >> 16) & 0xff) +#define ip4_addr3(ipaddr) ((u32)(ntohl((ipaddr)->s_addr) >> 8) & 0xff) +#define ip4_addr4(ipaddr) ((u32)(ntohl((ipaddr)->s_addr)) & 0xff) +#endif + +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_IN_ADDR +#define HAVE_IN_ADDR +struct in_addr { + u32 s_addr; +}; +#endif + +struct sockaddr_in { + u8 sin_len; + u8 sin_family; + u16 sin_port; + struct in_addr sin_addr; + s8 sin_zero[8]; +}; + +struct sockaddr { + u8 sa_len; + u8 sa_family; + s8 sa_data[14]; +}; + +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + u16 h_addrtype; /* host address type */ + u16 h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +}; + +struct pollsd { + s32 socket; + u32 events; + u32 revents; +}; + +u32 inet_addr(const char *cp); +s8 inet_aton(const char *cp, struct in_addr *addr); +char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */ + +s32 if_config( char *local_ip, char *netmask, char *gateway,bool use_dhcp, int max_retries); +s32 if_configex(struct in_addr *local_ip, struct in_addr *netmask, struct in_addr *gateway, bool use_dhcp, int max_retries); + +s32 net_init(); +#ifdef HW_RVL +typedef s32 (*netcallback)(s32 result, void *usrdata); +s32 net_init_async(netcallback cb, void *usrdata); +s32 net_get_status(void); +void net_wc24cleanup(); +s32 net_get_mac_address(void *mac_buf); +#endif +void net_deinit(); + +u32 net_gethostip(); +s32 net_socket(u32 domain,u32 type,u32 protocol); +s32 net_bind(s32 s,struct sockaddr *name,socklen_t namelen); +s32 net_listen(s32 s,u32 backlog); +s32 net_accept(s32 s,struct sockaddr *addr,socklen_t *addrlen); +s32 net_connect(s32 s,struct sockaddr *,socklen_t); +s32 net_write(s32 s,const void *data,s32 size); +s32 net_send(s32 s,const void *data,s32 size,u32 flags); +s32 net_sendto(s32 s,const void *data,s32 len,u32 flags,struct sockaddr *to,socklen_t tolen); +s32 net_recv(s32 s,void *mem,s32 len,u32 flags); +s32 net_recvfrom(s32 s,void *mem,s32 len,u32 flags,struct sockaddr *from,socklen_t *fromlen); +s32 net_read(s32 s,void *mem,s32 len); +s32 net_close(s32 s); +s32 net_select(s32 maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,struct timeval *timeout); +s32 net_setsockopt(s32 s,u32 level,u32 optname,const void *optval,socklen_t optlen); +s32 net_ioctl(s32 s, u32 cmd, void *argp); +s32 net_fcntl(s32 s, u32 cmd, u32 flags); +s32 net_poll(struct pollsd *sds,s32 nsds,s32 timeout); +s32 net_shutdown(s32 s, u32 how); + +struct hostent * net_gethostbyname(const char *addrString); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/aram.h b/wii/libogc/include/ogc/aram.h new file mode 100644 index 0000000000..af382a5cca --- /dev/null +++ b/wii/libogc/include/ogc/aram.h @@ -0,0 +1,272 @@ +/*------------------------------------------------------------- + +aram.h -- ARAM subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __ARAM_H__ +#define __ARAM_H__ + +/*! + * \file aram.h + * \brief ARAM subsystem + * + */ + +#include + + +/*! + * \addtogroup dmamode ARAM DMA transfer direction + * @{ + */ + +#define AR_MRAMTOARAM 0 /*!< direction: MRAM -> ARAM (write) */ +#define AR_ARAMTOMRAM 1 /*!< direction: ARAM -> MRAM (read) */ + +/*! + * @} + */ + + + +/*! + * \addtogroup memmode ARAM memory access modes + * @{ + */ + +#define AR_ARAMINTALL 0 /*!< use all the internal ARAM memory */ +#define AR_ARAMINTUSER 1 /*!< use only the internal user space of the ARAM memory */ + +/*! + * @} + */ + + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! + * \typedef void (*ARCallback)(void) + * \brief function pointer typedef for the user's ARAM interrupt callback + * + * \param none + */ +typedef void (*ARCallback)(void); + + +/*! + * \fn ARCallback AR_RegisterCallback(ARCallback callback) + * \brief Register the given function as a DMA callback + * + * Any existing callback is replaced unconditionally + * + * \param[in] callback to be invoked upon completion of DMA transaction + * + * \return pointer to the previously registered callback and NULL respectively + */ +ARCallback AR_RegisterCallback(ARCallback callback); + + +/*! + * \fn u32 AR_GetDMAStatus() + * \brief Get current status of DMA + * + * \return zero if DMA is idle, non-zero if a DMA is in progress + */ +u32 AR_GetDMAStatus(); + + +/*! + * \fn u32 AR_Init(u32 *stack_idx_array,u32 num_entries) + * \brief Initializes ARAM subsystem. + * + * Following tasks are performed: + * + * - Disables ARAM DMA + * - Sets DMA callback to NULL + * - Initializes ARAM controller + * - Determines size of ARAM memory + * - Initializes the ARAM stack based memory allocation system
+ * + * The parameter u32 *stack_idx_array points to an array of u32 integers. The parameter u32 num_entries specifies the number of entries in this array.
+ * The user application is responsible for determining how many ARAM blocks the device driver can allocate.
+ * + * As an example, consider: + * \code + * #define MAX_NUM_BLOCKS 10 + * + * u32 aram_blocks[MAX_NUM_BLOCKS]; + * ... + * void func(void) + * { + * AR_Init(aram_blocks, MAX_NUM_BLOCKS); + * } + * \endcode + * + * Here, we are telling AR that the application will allocate, at most, 10 blocks (of arbitrary size), and that AR should store addresses for those blocks in the array aram_blocks. Note that the array is simply storage supplied by the application so that AR can track the number and size of memory blocks allocated by AR_Alloc(). + * AR_Free()also uses this array to release blocks.
+ * If you do not wish to use AR_Alloc() and AR_Free() and would rather manage ARAM usage within your application, then call AR_Init() like so:
+ * + * AR_Init(NULL, 0);
+ * + * The AR_Init() function also calculates the total size of the ARAM aggregate. Note that this procedure is destructive - i.e., any data stored in ARAM will be corrupted.
+ * AR_Init()may be invoked multiple times. This function checks the state of an initialization flag; if asserted, this function will simply exit on subsequent calls. To perform another initialization of the ARAM driver, call AR_Reset() before invoking AR_Init() again. + * + * \param[in] stack_idx_array pointer to an array of u32 integer + * \param[in] num_entries number of entries in the specified array + * + * \return base address of the "user" ARAM area. As of this writing, the operating system reserves the bottom 16 KB of ARAM. Therefore, AR_Init() returns 0x04000 to indicate the starting location of the ARAM user area. + */ +u32 AR_Init(u32 *stack_idx_array,u32 num_entries); + + +/*! + * \fn void AR_StartDMA(u32 dir,u32 memaddr,u32 aramaddr,u32 len) + * \brief Initiates a DMA between main memory and ARAM. + * + * This function: + * + * - Does not perform boundery-checking on addresses and lengths. + * - Will assert failure if a DMA is allready in progress. + * - Is provided for debugging purpose. Application programmers must use the ARQ API in order to access ARAM. + * + * \param[in] dir specifies the \ref dmamode "direction" of transfer. + * \param[in] memaddr specifies main memory address for the transfer + * \param[in] aramaddr specifies the ARAM address for the transfer. NOTE: Addresses are 27bits wide and refer to bytes + * \param[in] len specifies the length of the block to transfer. NOTE: Must be in bytes and a multiple of 32 + * + * \return none + */ +void AR_StartDMA(u32 dir,u32 memaddr,u32 aramaddr,u32 len); + + +/*! + * \fn u32 AR_Alloc(u32 len) + * \brief Allocate a block of memory from ARAM having len bytes. + * + * The len parameter must be a multiple of 32 + * + * \param[in] len length of the specified block of memory in ARAM + * + * \return address of the block if successful, otherwise NULL + */ +u32 AR_Alloc(u32 len); + + +/*! + * \fn u32 AR_Free(u32 *len) + * \brief Free a block from ARAM + * + * \param[out] len pointer to receive the length of the free'd ARAM block. This is optional and can be NULL. + * + * \return ARAM current baseaddress after free'ing the block + */ +u32 AR_Free(u32 *len); + + +/*! + * \fn void AR_Clear(u32 flag) + * \brief Clear ARAM memory + * + * \param[in] flag specifies the region of ARAM to clear + * + * \return none + */ +void AR_Clear(u32 flag); + + +/*! + * \fn BOOL AR_CheckInit() + * \brief Get the ARAM subsystem initialization flag + * + * \return TRUE if the ARAM subsystem has been initialized(via AR_Init())
+ * FALSE if the ARAM subsystem has not been initialized, or has been reset(via AR_Reset()) + */ +BOOL AR_CheckInit(); + + +/*! + * \fn void AR_Reset() + * \brief Clears the ARAM subsystem initialization flag. + * + * Calling AR_Init() after this function will cause a "real" initialization of ARAM + * + * \return none + */ +void AR_Reset(); + + +/*! + * \fn u32 AR_GetSize() + * \brief Get the total size - in bytes - of ARAM as calculated during AR_Init() + * + * \return size of the specified ARAM block + */ +u32 AR_GetSize(); + + +/*! + * \fn u32 AR_GetBaseAddress() + * \brief Get the baseaddress of ARAM memory + * + * \return ARAM memory baseaddress + */ +u32 AR_GetBaseAddress(); + + +/*! + * \fn u32 AR_GetInternalSize() + * \brief Get the size of the internal ARAM memory + * + * \return ARAM internal memory size + */ +u32 AR_GetInternalSize(); + + +/*! + * \def AR_StartDMARead(maddr,araddr,tlen) + * \brief Wraps the DMA read operation done by AR_StartDMA() + */ +#define AR_StartDMARead(maddr,araddr,tlen) \ + AR_StartDMA(AR_ARAMTOMRAM,maddr,araddr,tlen); + + +/*! + * \def AR_StartDMAWrite(maddr,araddr,tlen) + * \brief Wraps the DMA write operation done by AR_StartDMA() + */ +#define AR_StartDMAWrite(maddr,araddr,tlen) \ + AR_StartDMA(AR_MRAMTOARAM,maddr,araddr,tlen); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif //__ARAM_H__ diff --git a/wii/libogc/include/ogc/arqmgr.h b/wii/libogc/include/ogc/arqmgr.h new file mode 100644 index 0000000000..3c64628851 --- /dev/null +++ b/wii/libogc/include/ogc/arqmgr.h @@ -0,0 +1,113 @@ +/*------------------------------------------------------------- + + +arqmgr.h -- ARAM task queue management + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#ifndef __ARQMGR_H__ +#define __ARQMGR_H__ + + +/*! + * \file arqmgr.h + * \brief ARAM queue managemnt subsystem + * + */ + + +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! + * \typedef void (*ARQMCallback)() + * \brief function pointer typedef for the user's callback when ARAM operation has completed + * \param none + */ +typedef void (*ARQMCallback)(s32 result); + + +/*! + * \fn void ARQM_Init(u32 arambase,s32 len) + * \brief Initialize the ARAM queue management system + * + * \param[in] arambase ARAM startaddress to take for the queue stack + * \param[in] len maximum amount of memory to be reserved from the ARAM for the queue management + * + * \return none + */ +void ARQM_Init(u32 arambase,s32 len); + + +/*! + * \fn u32 ARQM_PushData(void *buff,s32 len) + * \brief Push the data onto the ARAM queue + * + * \param[in] buff startaddress of buffer to be pushed onto the queue. NOTE: Must be 32-bytealigned. + * \param[in] len length of data to be pushed onto the queue. + * + * \return none + */ +u32 ARQM_PushData(void *buffer,s32 len); + + +/*! + * \fn u32 ARQM_GetZeroBuffer() + * \brief Returns ARAM address of 'zero buffer' + * + * \return See description + */ +u32 ARQM_GetZeroBuffer(); + + +/*! + * \fn u32 ARQM_GetStackPointer() + * \brief Return the ARAM address of the next free stack pointer + * + * \return See description + */ +u32 ARQM_GetStackPointer(); + + +/*! + * \fn u32 ARQM_GetFreeSize() + * \brief Return Returns remaining number of bytes on stack + * + * \return See description + */ +u32 ARQM_GetFreeSize(); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/arqueue.h b/wii/libogc/include/ogc/arqueue.h new file mode 100644 index 0000000000..2aff9e1780 --- /dev/null +++ b/wii/libogc/include/ogc/arqueue.h @@ -0,0 +1,115 @@ +/*------------------------------------------------------------- + +arqueue.h -- ARAM task request queue implementation + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#ifndef __ARQUEUE_H__ +#define __ARQUEUE_H__ + +#include +#include +#include "aram.h" + +#define ARQ_MRAMTOARAM AR_MRAMTOARAM +#define ARQ_ARAMTOMRAM AR_ARAMTOMRAM + +#define ARQ_DEF_CHUNK_SIZE 4096 + +#define ARQ_PRIO_LO 0 +#define ARQ_PRIO_HI 1 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +enum { + ARQ_TASK_READY = 0, + ARQ_TASK_RUNNING, + ARQ_TASK_FINISHED +}; + +typedef struct _arq_request ARQRequest; +typedef void (*ARQCallback)(ARQRequest *); + +struct _arq_request { + lwp_node node; + u32 owner,dir,prio,state; + u32 aram_addr,mram_addr,len; + ARQCallback callback; +}; + +void ARQ_Init(); +void ARQ_Reset(); + + +/*! + * \fn void ARQ_PostRequest(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len) + * \brief Enqueue a ARAM DMA transfer request. + * + * \param[in] req structure to hold ARAM DMA request informations. + * \param[in] owner unique owner id. + * \param[in] dir direction of ARAM DMA transfer. + * \param[in] prio priority of request. + * \param[in] aram_addr startaddress of buffer to be pushed onto the queue. NOTE: Must be 32-bytealigned. + * \param[in] mram_addr length of data to be pushed onto the queue. + * \param[in] len startaddress of buffer to be pushed onto the queue. NOTE: Must be 32-bytealigned. + * \param[in] cb length of data to be pushed onto the queue. + * + * \return none + */ +void ARQ_PostRequest(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len); + + +/*! + * \fn void ARQ_PostRequestAsync(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len,ARQCallback cb) + * \brief Enqueue a ARAM DMA transfer request. + * + * \param[in] req structure to hold ARAM DMA request informations. + * \param[in] owner unique owner id. + * \param[in] dir direction of ARAM DMA transfer. + * \param[in] prio priority of request. + * \param[in] aram_addr startaddress of buffer to be pushed onto the queue. NOTE: Must be 32-bytealigned. + * \param[in] mram_addr length of data to be pushed onto the queue. + * \param[in] len startaddress of buffer to be pushed onto the queue. NOTE: Must be 32-bytealigned. + * \param[in] cb length of data to be pushed onto the queue. + * + * \return none + */ +void ARQ_PostRequestAsync(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len,ARQCallback cb); +void ARQ_RemoveRequest(ARQRequest *req); +void ARQ_SetChunkSize(u32 size); +u32 ARQ_GetChunkSize(); +void ARQ_FlushQueue(); +u32 ARQ_RemoveOwnerRequest(u32 owner); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/audio.h b/wii/libogc/include/ogc/audio.h new file mode 100644 index 0000000000..8d13f68042 --- /dev/null +++ b/wii/libogc/include/ogc/audio.h @@ -0,0 +1,319 @@ +/*------------------------------------------------------------- + +audio.h -- Audio subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + + +-------------------------------------------------------------*/ + + +#ifndef __AUDIO_H__ +#define __AUDIO_H__ + +/*! \file audio.h +\brief AUDIO subsystem + +*/ + +#include + +/*! + * \addtogroup ai_stream_mode AI streaming modes + * @{ + */ + +#define AI_STREAM_STOP 0x00000000 /*!< Stop streaming audio playback */ +#define AI_STREAM_START 0x00000001 /*!< Start streaming audio playback */ + +/*! + * @} + */ + + + +/*! + * \addtogroup ai_sample_rates AI sampling rates + * @{ + */ + +#define AI_SAMPLERATE_32KHZ 0x00000000 /*!< AI sampling rate at 32kHz */ +#define AI_SAMPLERATE_48KHZ 0x00000001 /*!< AI sampling rate at 48kHz */ + +/*! + * @} + */ + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +/*! + * \typedef void (*AIDCallback)(void) + * \brief function pointer typedef for the user's Audio DMA interrupt callback + * + * \param none + */ +typedef void (*AIDCallback)(void); + + +/*! + * \typedef void (*AISCallback)(u32 smp_cnt) + * \brief function pointer typedef for the user's Audio Streaming interrupt callback + * + * \param smp_cnt AI sample count + */ +typedef void (*AISCallback)(u32 smp_cnt); + + +/*! + * \fn AISCallback AUDIO_RegisterStreamCallback(AISCallback callback) + * \brief Register a user callback function for the AUDIO streaming interface + * + * \param[in] callback pointer to the function which to call when AIS interrupt has triggered. + * + * \return pointer to old callback function or NULL respectively. + */ +AISCallback AUDIO_RegisterStreamCallback(AISCallback callback); + + +/*! + * \fn void AUDIO_Init(u8 *stack) + * \brief Initialize the AUDIO subsystem + * + * \param[in] stack pointer to a memory area to work as stack when calling the callbacks. May be NULL + * + * \return none + */ +void AUDIO_Init(u8 *stack); + + +/*! + * \fn void AUDIO_SetStreamVolLeft(u8 vol) + * \brief Set streaming volume on the left channel. + * + * \param[in] vol level of volume 0<= vol <=255 + * + * \return none + */ +void AUDIO_SetStreamVolLeft(u8 vol); + + +/*! + * \fn u8 AUDIO_GetStreamVolLeft() + * \brief Get streaming volume of the left channel. + * + * \return level of volume. + */ +u8 AUDIO_GetStreamVolLeft(); + + +/*! + * \fn void AUDIO_SetStreamVolRight(u8 vol) + * \brief set streaming volume of the right channel. + * + * \param[in] vol level of volume 0<= vol <=255 + * + * \return none + */ +void AUDIO_SetStreamVolRight(u8 vol); + + +/*! + * \fn u8 AUDIO_GetStreamVolRight() + * \brief Get streaming volume of the right channel. + * + * \return level of volume. + */ +u8 AUDIO_GetStreamVolRight(); + + +/*! + * \fn void AUDIO_SetStreamSampleRate(u32 rate) + * \brief Set streaming sample rate + * + * \param[in] rate streaming \ref ai_sample_rates "sample rate" + * + * \return none + */ +void AUDIO_SetStreamSampleRate(u32 rate); + + +/*! + * \fn u32 AUDIO_GetStreamSampleRate() + * \brief Get streaming sample rate + * + * \return \ref ai_sample_rates "sample rate" + */ +u32 AUDIO_GetStreamSampleRate(); + + +/*! + * \fn AIDCallback AUDIO_RegisterDMACallback(AIDCallback callback) + * \brief Register a user callback function for the audio DMA interface. + * + * This callback will be called whenever the audio DMA requests new data.
+ * Internally the DMA buffers are double buffered. + * + * \param[in] callback pointer to the function which to call when AID interrupt has triggered. + * + * \return pointer to old callback function or NULL respectively. + */ +AIDCallback AUDIO_RegisterDMACallback(AIDCallback callback); + + +/*! + * \fn void AUDIO_InitDMA(u32 startaddr,u32 len) + * \brief Initialize an audio DMA transfer + * + * \param[in] startaddr start address of the memory region to load into the audio DMA. NOTE: Has to be aligned on a 32byte boundery! + * \param[in] len lenght of data to load into the audio DMA. NOTE: Should be a multiple of 32 + * + * \return none + */ +void AUDIO_InitDMA(u32 startaddr,u32 len); + + +/*! + * \fn u16 AUDIO_GetDMAEnableFlag() + * \brief Get the audio DMA flag + * + * \return state of the current DMA operation. + */ +u16 AUDIO_GetDMAEnableFlag(); + + +/*! + * \fn void AUDIO_StartDMA() + * \brief Start the audio DMA operation. + * + * Starts to transfer the data from main memory to the audio interface thru DMA.
+ * This call should follow the call to AUDIO_InitDMA() which is used to initialize DMA transfers. + * + * \return none + */ +void AUDIO_StartDMA(); + + +/*! + * \fn void AUDIO_StopDMA() + * \brief Stop the previously started audio DMA operation. + * + * \return none + */ +void AUDIO_StopDMA(); + + +/*! + * \fn u32 AUDIO_GetDMABytesLeft() + * \brief Get the count of bytes, left to play, from the audio DMA interface + * + * \return count of bytes left to play. + */ +u32 AUDIO_GetDMABytesLeft(); + + +/*! + * \fn u32 AUDIO_GetDMALength() + * \brief Get the DMA transfer length configured in the audio DMA interface. + * + * \return length of data loaded into the audio DMA interface. + */ +u32 AUDIO_GetDMALength(); + + +/*! + * \fn u32 AUDIO_GetDMAStartAddr() + * \brief Get the main memory address for the DMA operation. + * + * \return start address of mainmemory loaded into the audio DMA interface. + */ +u32 AUDIO_GetDMAStartAddr(); + + +/*! + * \fn void AUDIO_SetStreamTrigger(u32 cnt) + * \brief Set the sample count for the stream trigger + * + * \param[in] cnt count of samples when to trigger the audio stream. + * + * \return none + */ +void AUDIO_SetStreamTrigger(u32 cnt); + + +/*! + * \fn void AUDIO_ResetStreamSampleCnt() + * \brief Reset the stream sample count register. + * + * \return none + */ +void AUDIO_ResetStreamSampleCnt(); + + +/*! + * \fn void AUDIO_SetDSPSampleRate(u8 rate) + * \brief Set the sampling rate for the DSP interface + * + * \param[in] rate sampling rate to set for the DSP (AI_SAMPLERATE_32KHZ,AI_SAMPLERATE_48KHZ) + * + * \return none + */ +void AUDIO_SetDSPSampleRate(u8 rate); + + +/*! + * \fn u32 AUDIO_GetDSPSampleRate() + * \brief Get the sampling rate for the DSP interface + * + * \return DSP sampling rate (AI_SAMPLERATE_32KHZ,AI_SAMPLERATE_48KHZ) + */ +u32 AUDIO_GetDSPSampleRate(); + + +/*! + * \fn void AUDIO_SetStreamPlayState(u32 state) + * \brief Set the play state for the streaming audio interface + * + * \param[in] state playstate of the streaming audio interface (AI_STREAM_STOP,AI_STREAM_START) + * + * \return none + */ +void AUDIO_SetStreamPlayState(u32 state); + + +/*! + * \fn u32 AUDIO_GetStreamPlayState() + * \brief Get the play state from the streaming audio interface + * + * \return playstate (AI_STREAM_STOP,AI_STREAM_START) + */ +u32 AUDIO_GetStreamPlayState(); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/cache.h b/wii/libogc/include/ogc/cache.h new file mode 100644 index 0000000000..0753956a1f --- /dev/null +++ b/wii/libogc/include/ogc/cache.h @@ -0,0 +1,326 @@ +/*------------------------------------------------------------- + + +cache.h -- Cache interface + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#ifndef __CACHE_H__ +#define __CACHE_H__ + +/*! \file cache.h +\brief Cache subsystem + +*/ + +#include + +#define LC_BASEPREFIX 0xe000 +#define LC_BASE (LC_BASEPREFIX<<16) + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! + * \fn void DCEnable() + * \brief Enable L1 d-cache + * + * \return none + */ +void DCEnable(); + + +/*! + * \fn void DCDisable() + * \brief Disable L1 d-cache + * + * \return none + */ +void DCDisable(); + + +/*! + * \fn void DCFreeze() + * \brief Current contents of the L1 d-cache are locked down and will not be cast out. + * + * Hits are still serviced, but misses go straight to L2 or 60x bus. Most cache operations, such as DCFlushRange(), will still execute regardless of whether the cache is frozen.
+ * NOTE: In PowerPC architecture jargon, this feature is referred to as "locking" the data cache. We use the word "freeze" to distinguish it from the locked cache and DMA features. + * + * \return none + */ +void DCFreeze(); + + +/*! + * \fn void DCUnfreeze() + * \brief Undoes actions of DCFreeze(). + * + * Old cache blocks will now be cast out on subsequent L1 misses.
+ * NOTE: In PowerPC architecture jargon, this feature is referred to as "locking" the data cache. We use the word "freeze" to distinguish it from the locked cache and DMA features. + * + * \return none + */ +void DCUnfreeze(); + + +/*! + * \fn void DCFlashInvalidate() + * \brief Invalidate L1 d-cache. + * + * An invalidate operation is issued that marks the state of each data cache block as invalid without writing back modified cache blocks to memory.
+ * Cache access is blocked during this time.Bus accesses to the cache are signaled as a miss during invalidate-all operations. + * + * \return none + */ +void DCFlashInvalidate(); + + +/*! + * \fn void DCInvalidateRange(void *startaddress,u32 len) + * \brief Invalidates a given range of the d-cache. + * + * If any part of the range hits in the d-cache, the corresponding block will be invalidated. + * + * \param[in] startaddress pointer to the startaddress of the memory range to invalidate. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of the range to invalidate. NOTE: Should be a multiple of 32 + * + * \return none + */ +void DCInvalidateRange(void *startaddress,u32 len); + + +/*! + * \fn void DCFlushRange(void *startaddress,u32 len) + * \brief Flushes a given range. + * + * If any part of the range hits in the d-cache the corresponding block will be flushed to main memory and invalidated.
+ * NOTE: This function invokes a "sync" after flushing the range. This means the function will stall until the CPU knows that the data has been writen to main memory + * + * \param[in] startaddress pointer to the startaddress of the memory range to flush. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of range to be flushed. NOTE: Should be a multiple of 32 + * + *\return none + */ +void DCFlushRange(void *startaddress,u32 len); + +/*! + * \fn void DCStoreRange(void *startaddress,u32 len) + * \brief Ensures a range of memory is updated with any modified data in the cache. + * + * NOTE: This function invokes a "sync" after storing the range. This means the function will stall until the CPU knows that the data has been writen to main memory + * + * \param[in] startaddress pointer to the startaddress of the memory range to store. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of the range to store. NOTE: Should be a multiple of 32 + * + * \return none + */ +void DCStoreRange(void *startaddress,u32 len); + + +/*! + * \fn void DCFlushRangeNoSync(void *startaddress,u32 len) + * \brief Flushes a given range. + * + * If any part of the range hits in the d-cache the corresponding block will be flushed to main memory and invalidated.
+ * NOTE: This routine does not perform a "sync" to ensure that the range has been flushed to memory. That is, the cache blocks are sent to the bus interface unit for storage to main memory, but by the time this function returns, you are not guaranteed that the blocks have been written to memory. + * + * \param[in] startaddress pointer to the startaddress of the memory range to flush. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of range to be flushed. NOTE: Should be a multiple of 32 + * + * \return none + */ +void DCFlushRangeNoSync(void *startaddress,u32 len); + + +/*! + * \fn void DCStoreRangeNoSync(void *startaddress,u32 len) + * \brief Ensures a range of memory is updated with any modified data in the cache. + * + * NOTE: This routine does not perform a "sync" to ensure that the range has been flushed to memory. That is, the cache blocks are sent to the bus interface unit for storage to main memory, but by the time this function returns, you are not guaranteed that the blocks have been written to memory + * + * \param[in] startaddress pointer to the startaddress of the memory range to store. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of the range to store. NOTE: Should be a multiple of 32 + * + * \return none + */ +void DCStoreRangeNoSync(void *startaddress,u32 len); + + +/*! + * \fn void DCZeroRange(void *startaddress,u32 len) + * \brief Loads a range of memory into cache and zeroes all the cache lines. + * + * \param[in] startaddress pointer to the startaddress of the memory range to load/zero. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of the range to load/zero. NOTE: Should be a multiple of 32 + * + * \return none + */ +void DCZeroRange(void *startaddress,u32 len); + + +/*! + * \fn void DCTouchRange(void *startaddress,u32 len) + * \brief Loads a range of memory into cache. + * + * \param[in] startaddress pointer to the startaddress of the memory range to load. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of the range to load. NOTE: Should be a multiple of 32 + * + * \return none + */ +void DCTouchRange(void *startaddress,u32 len); + + +/*! + * \fn void ICSync() + * \brief Performs an instruction cache synchronization. + * + * This ensures that all instructions preceding this instruction have completed before this instruction completes. + * + * \return none + */ +void ICSync(); + + +/*! + * \fn void ICFlashInvalidate() + * \brief Invalidate the L1 i-cache. + * + * An invalidate operation is issued that marks the state of each instruction cache block as invalid without writing back modified cache blocks to memory.
+ * Cache access is blocked during this time. Bus accesses to the cache are signaled as a miss during invalidate-all operations. + * + * \return none + */ +void ICFlashInvalidate(); + + +/*! + * \fn void ICEnable() + * \brief Enable L1 i-cache + * + * \return none + */ +void ICEnable(); + + +/*! + * \fn void ICDisable() + * \brief Disable L1 i-cache + * + * \return none + */ +void ICDisable(); + + +/*! + * \fn void ICFreeze() + * \brief Current contents of the L1 i-cache are locked down and will not be cast out. + * + * Hits are still serviced, but misses go straight to L2 or 60x bus.
+ * NOTE: In PowerPC architecture jargon, this feature is referred to as "locking" the data cache. We use the word "freeze" to distinguish it from the locked cache and DMA features. + * + * \return none + */ +void ICFreeze(); + + +/*! + * \fn void ICUnfreeze() + * \brief Undoes actions of ICFreeze(). + * + * Old cache blocks will now be cast out on subsequent L1 misses.
+ * NOTE: In PowerPC architecture jargon, this feature is referred to as "locking" the data cache. We use the word "freeze" to distinguish it from the locked cache and DMA features. + * + * \return none + */ +void ICUnfreeze(); + + +/*! + * \fn void ICBlockInvalidate(void *startaddress) + * \brief Invalidates a block in the i-cache. + * + * If the block hits in the i-cache, the corresponding block will be invalidated. + * + * \param[in] startaddress pointer to the startaddress of the memory block to invalidate. NOTE: Has to be aligned on a 32byte boundery + * + *\return none + */ +void ICBlockInvalidate(void *startaddress); + + +/*! + * \fn void ICInvalidateRange(void *startaddress,u32 len) + * \brief Invalidate a range in the L1 i-cache. + * + * If any part of the range hits in the i-cache, the corresponding block will be invalidated. + * + * \param[in] startaddress pointer to the startaddress of the memory range to invalidate. NOTE: Has to be aligned on a 32byte boundery + * \param[in] len length of the range to invalidate. NOTE: Should be a multiple of 32 + * + * \return none + */ +void ICInvalidateRange(void *startaddress,u32 len); + +/*! + * \fn void L2Enhance() + * \brief Turn on extra L2 cache features + * + * Sets the following bits in the HID4 register which affect the L2 cache: + * - L2FM=01 (64-byte fetch mode) + * - BCO=1 (dual 64-byte castout buffers) + * - L2MUM=1 (configured as 2-deep miss-under-miss cache) + * Since these features can't be enabled safely, any HID4 writes in the HBC stub will be removed. + * + * \return none + */ +#ifdef HW_RVL +void L2Enhance(); +#endif + +void LCEnable(); +void LCDisable(); +void LCLoadBlocks(void *,void *,u32); +void LCStoreBlocks(void *,void *,u32); +u32 LCLoadData(void *,void *,u32); +u32 LCStoreData(void *,void *,u32); +u32 LCQueueLength(); +u32 LCQueueWait(u32); +void LCFlushQueue(); +void LCAlloc(void *,u32); +void LCAllocNoInvalidate(void *,u32); +void LCAllocOneTag(BOOL,void *); +void LCAllocTags(BOOL,void *,u32); + +#define LCGetBase() ((void*)LC_BASE) +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/card.h b/wii/libogc/include/ogc/card.h new file mode 100644 index 0000000000..ff7d70b56b --- /dev/null +++ b/wii/libogc/include/ogc/card.h @@ -0,0 +1,605 @@ +/*------------------------------------------------------------- + +card.h -- Memory card subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __CARD_H__ +#define __CARD_H__ + +/*! +\file card.h +\brief Memory card subsystem + +*/ + + +#include + +/*! \addtogroup cardsolts Memory card slots + * @{ + */ + +#define CARD_SLOTA 0 /*!< memory card slot A */ +#define CARD_SLOTB 1 /*!< memory card slot B */ + +/*! @} */ + + +#define CARD_WORKAREA (5*8*1024) /*!< minimum size of the workarea passed to Mount[Async]() */ +#define CARD_READSIZE 512 /*!< minimum size of block to read from memory card */ +#define CARD_FILENAMELEN 32 /*!< maximum filename length */ +#define CARD_MAXFILES 128 /*!< maximum number of files on the memory card */ + +/*! \addtogroup card_errors Memory card error codes + * @{ + */ + +#define CARD_ERROR_UNLOCKED 1 /*!< card beeing unlocked or allready unlocked. */ +#define CARD_ERROR_READY 0 /*!< card is ready. */ +#define CARD_ERROR_BUSY -1 /*!< card is busy. */ +#define CARD_ERROR_WRONGDEVICE -2 /*!< wrong device connected in slot */ +#define CARD_ERROR_NOCARD -3 /*!< no memory card in slot */ +#define CARD_ERROR_NOFILE -4 /*!< specified file not found */ +#define CARD_ERROR_IOERROR -5 /*!< internal EXI I/O error */ +#define CARD_ERROR_BROKEN -6 /*!< directory structure or file entry broken */ +#define CARD_ERROR_EXIST -7 /*!< file allready exists with the specified parameters */ +#define CARD_ERROR_NOENT -8 /*!< found no empty block to create the file */ +#define CARD_ERROR_INSSPACE -9 /*!< not enough space to write file to memory card */ +#define CARD_ERROR_NOPERM -10 /*!< not enough permissions to operate on the file */ +#define CARD_ERROR_LIMIT -11 /*!< card size limit reached */ +#define CARD_ERROR_NAMETOOLONG -12 /*!< filename too long */ +#define CARD_ERROR_ENCODING -13 /*!< font encoding PAL/SJIS mismatch*/ +#define CARD_ERROR_CANCELED -14 /*!< card operation canceled */ +#define CARD_ERROR_FATAL_ERROR -128 /*!< fatal error, non recoverable */ + +/*! @} */ + + +/* File attribute defines */ +#define CARD_ATTRIB_PUBLIC 0x04 +#define CARD_ATTRIB_NOCOPY 0x08 +#define CARD_ATTRIB_NOMOVE 0x10 + +/* Banner & Icon Attributes */ +#define CARD_BANNER_W 96 +#define CARD_BANNER_H 32 + +#define CARD_BANNER_NONE 0x00 +#define CARD_BANNER_CI 0x01 +#define CARD_BANNER_RGB 0x02 +#define CARD_BANNER_MASK 0x03 + +#define CARD_MAXICONS 8 +#define CARD_ICON_W 32 +#define CARD_ICON_H 32 + +#define CARD_ICON_NONE 0x00 +#define CARD_ICON_CI 0x01 +#define CARD_ICON_RGB 0x02 +#define CARD_ICON_MASK 0x03 + +#define CARD_ANIM_LOOP 0x00 +#define CARD_ANIM_BOUNCE 0x04 +#define CARD_ANIM_MASK 0x04 + +#define CARD_SPEED_END 0x00 +#define CARD_SPEED_FAST 0x01 +#define CARD_SPEED_MIDDLE 0x02 +#define CARD_SPEED_SLOW 0x03 +#define CARD_SPEED_MASK 0x03 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! \typedef struct _card_file card_file +\brief structure to hold the fileinformations upon open and for later use. +\param chn CARD slot. +\param filenum file index in the card directory structure. +\param offset offset into the file. +\param len length of file. +\param iblock block index on memory card. +*/ +typedef struct _card_file { + s32 chn; + s32 filenum; + s32 offset; + s32 len; + u16 iblock; +} card_file; + + +/*! \typedef struct card_dir +\brief structure to hold the information of a directory entry +\param chn CARD slot. +\param fileno file index in the card directory structure. +\param filelen length of file. +\param filename[CARD_FILENAMELEN] name of the file on card. +\param gamecode[4] string identifier <=4. +\param company[2] string identifier <=2. +\param showall boolean flag whether to showall entries or ony those identified by card_gamecode and card_company, previously set within the call to CARD_Init() +*/ +typedef struct _card_dir { + s32 chn; + u32 fileno; + u32 filelen; + u8 permissions; + u8 filename[CARD_FILENAMELEN]; + u8 gamecode[4]; + u8 company[2]; + bool showall; +} card_dir; + + +/*! \typedef struct card_stat +\brief structure to hold the additional statistical informations. +\param filename[CARD_FILENAMELEN] name of the file on card. +\param len length of file. +\param gamecode[4] string identifier <=4. +\param company[2] string identifier <=2. +\param banner_fmt format of banner. +\param icon_addr icon image address in file. +\param icon_speed speed of an animated icon. +\param comment_addr address in file of the comment block. +\param offset_banner offset in file to the banner's image data. +\param offset_banner_tlut offset in file to the banner's texture lookup table. +\param offset_icon[CARD_MAXICONS] array of offsets in file to the icon's image data banner_fmt)&CARD_BANNER_MASK) +#define CARD_SetBannerFmt(stat,fmt) ((stat)->banner_fmt = (u8)(((stat)->banner_fmt&~CARD_BANNER_MASK)|(fmt))) +#define CARD_GetIconFmt(stat,n) (((stat)->icon_fmt>>(2*(n)))&CARD_ICON_MASK) +#define CARD_SetIconFmt(stat,n,fmt) ((stat)->icon_fmt = (u16)(((stat)->icon_fmt&~(CARD_ICON_MASK<<(2*(n))))|((fmt)<<(2*(n))))) +#define CARD_GetIconSpeed(stat,n) (((stat)->icon_speed>>(2*(n)))&~CARD_SPEED_MASK); +#define CARD_SetIconSpeed(stat,n,speed) ((stat)->icon_speed = (u16)(((stat)->icon_fmt&~(CARD_SPEED_MASK<<(2*(n))))|((speed)<<(2*(n))))) +#define CARD_SetIconAddr(stat,addr) ((stat)->icon_addr = (u32)(addr)) +#define CARD_SetCommentAddr(stat,addr) ((stat)->comment_addr = (u32)(addr)) + +/*! \typedef void (*cardcallback)(s32 chan,s32 result) +\brief function pointer typedef for the user's operation callback +\param chan CARD slot +\param result result of operation upon call of callback. +*/ +typedef void (*cardcallback)(s32 chan,s32 result); + + +/*! \fn s32 CARD_Init(const char *gamecode,const char *company) +\brief Performs the initialization of the memory card subsystem +\param[in] gamecode pointer to a 4byte long string to specify the vendors game code. May be NULL +\param[in] company pointer to a 2byte long string to specify the vendors company code. May be NULL + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Init(const char *gamecode,const char *company); + + +/*! \fn s32 CARD_Probe(s32 chn) +\brief Performs a check against the desired EXI channel if a device is inserted +\param[in] chn CARD slot + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Probe(s32 chn); + + +/*! \fn s32 CARD_ProbeEx(s32 chn,s32 *mem_size,s32 *sect_size) +\brief Performs a check against the desired EXI channel if a memory card is inserted or mounted +\param[in] chn CARD slot +\param[out] mem_size pointer to a integer variable, ready to take the resulting value (this param is optional and can be NULL) +\param[out] sect_size pointer to a integer variable, ready to take the resulting value (this param is optional and can be NULL) + +\return \ref card_errors "card error codes" +*/ +s32 CARD_ProbeEx(s32 chn,s32 *mem_size,s32 *sect_size); + + +/*! \fn s32 CARD_Mount(s32 chn,void *workarea,cardcallback detach_cb) +\brief Mounts the memory card in the slot CHN. Synchronous version. +\param[in] chn CARD slot +\param[in] workarea pointer to memory area to hold the cards system area. The startaddress of the workdarea should be aligned on a 32byte boundery +\param[in] detach_cb pointer to a callback function. This callback function will be called when the card is removed from the slot. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Mount(s32 chn,void *workarea,cardcallback detach_cb); + + +/*! \fn s32 CARD_MountAsync(s32 chn,void *workarea,cardcallback detach_cb,cardcallback attach_cb) +\brief Mounts the memory card in the slot CHN. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot +\param[in] workarea pointer to memory area to hold the cards system area. The startaddress of the workdarea should be aligned on a 32byte boundery +\param[in] detach_cb pointer to a callback function. This callback function will be called when the card is removed from the slot. +\param[in] attach_cb pointer to a callback function. This callback function will be called when the mount process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_MountAsync(s32 chn,void *workarea,cardcallback detach_cb,cardcallback attach_cb); + + +/*! \fn s32 CARD_Unmount(s32 chn) +\brief Unmounts the memory card in the slot CHN and releases the EXI bus. +\param[in] chn CARD slot + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Unmount(s32 chn); + + +/*! \fn s32 CARD_Read(card_file *file,void *buffer,u32 len,u32 offset) +\brief Reads the data from the file into the buffer from the given offset with the given length. Synchronous version +\param[in] file pointer to the card_file structure. It holds the fileinformations to read from. +\param[out] buffer pointer to memory area read-in the data. The startaddress of the buffer should be aligned to a 32byte boundery. +\param[in] len length of data to read. +\param[in] offset offset into the file to read from. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Read(card_file *file,void *buffer,u32 len,u32 offset); + + +/*! \fn s32 CARD_ReadAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback) +\brief Reads the data from the file into the buffer from the given offset with the given length. This function returns immediately. Asynchronous version +\param[in] file pointer to the card_file structure. It holds the fileinformations to read from. +\param[out] buffer pointer to memory area read-in the data. The startaddress of the buffer should be aligned to a 32byte boundery. +\param[in] len length of data to read. +\param[in] offset offset into the file to read from. +\param[in] callback pointer to a callback function. This callback will be called when the read process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_ReadAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback); + + +/*! \fn s32 CARD_Open(s32 chn,const char *filename,card_file *file) +\brief Opens the file with the given filename and fills in the fileinformations. +\param[in] chn CARD slot +\param[in] filename name of the file to open. +\param[out] file pointer to the card_file structure. It receives the fileinformations for later usage. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Open(s32 chn,const char *filename,card_file *file); + + +/*! \fn s32 CARD_OpenEntry(s32 chn,card_dir *entry,card_file *file) +\brief Opens the file with the given filename and fills in the fileinformations. +\param[in] chn CARD slot +\param[in] entry pointer to the directory entry to open. +\param[out] file pointer to the card_file structure. It receives the fileinformations for later usage. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_OpenEntry(s32 chn,card_dir *entry,card_file *file); + + +/*! \fn s32 CARD_Close(card_file *file) +\brief Closes the file with the given card_file structure and releases the handle. +\param[in] file pointer to the card_file structure to close. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Close(card_file *file); + + +/*! \fn s32 CARD_Create(s32 chn,const char *filename,u32 size,card_file *file) +\brief Creates a new file with the given filename and fills in the fileinformations. Synchronous version. +\param[in] chn CARD slot +\param[in] filename name of the file to create. +\param[in] size size of the newly created file. This must be a multiple of the memory card's sector size. +\param[out] file pointer to the card_file structure. It receives the fileinformations for later usage. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Create(s32 chn,const char *filename,u32 size,card_file *file); + + +/*! \fn s32 CARD_CreateAsync(s32 chn,const char *filename,u32 size,card_file *file,cardcallback callback) +\brief Creates a new file with the given filename and fills in the fileinformations. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot +\param[in] filename name of the file to create. +\param[in] size size of the newly created file. This must be a multiple of the memory card's sector size. +\param[out] file pointer to the card_file structure. It receives the fileinformations for later usage. +\param[in] callback pointer to a callback function. This callback will be called when the create process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_CreateAsync(s32 chn,const char *filename,u32 size,card_file *file,cardcallback callback); + + +/*! \fn s32 CARD_CreateEntry(s32 chn,card_dir *entry,card_file *file) +\brief Creates a new file with the given filename and fills in the fileinformations. Synchronous version. +\param[in] chn CARD slot +\param[in] entry pointer to the directory entry to create. +\param[out] file pointer to the card_file structure. It receives the fileinformations for later usage. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_CreateEntry(s32 chn,card_dir *direntry,card_file *file); + + +/*! \fn s32 CARD_CreateEntryAsync(s32 chn,card_dir *entry,card_file *file,cardcallback callback) +\brief Creates a new file with the given filename and fills in the fileinformations. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot +\param[in] entry pointer to the directory entry to create +\param[out] file pointer to the card_file structure. It receives the fileinformations for later usage. +\param[in] callback pointer to a callback function. This callback will be called when the create process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_CreateEntryAsync(s32 chn,card_dir *direntry,card_file *file,cardcallback callback); + + +/*! \fn s32 CARD_Delete(s32 chn,const char *filename) +\brief Deletes a file with the given filename. Synchronous version. +\param[in] chn CARD slot +\param[in] filename name of the file to delete. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Delete(s32 chn,const char *filename); + + +/*! \fn s32 CARD_DeleteAsync(s32 chn,const char *filename,cardcallback callback) +\brief Deletes a file with the given filename. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot +\param[in] filename name of the file to delete. +\param[in] callback pointer to a callback function. This callback will be called when the delete process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_DeleteAsync(s32 chn,const char *filename,cardcallback callback); + + +/*! \fn s32 CARD_DeleteEntry(s32 chn,card_dir *dir_entry) +\brief Deletes a file with the given directory entry informations. +\param[in] chn CARD slot +\param[in] dir_entry pointer to the card_dir structure which holds the informations for the delete operation. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_DeleteEntry(s32 chn,card_dir *dir_entry); + + +/*! \fn s32 CARD_DeleteEntryAsync(s32 chn,card_dir *dir_entry,cardcallback callback) +\brief Deletes a file with the given directory entry informations. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot +\param[in] dir_entry pointer to the card_dir structure which holds the informations for the delete operation. +\param[in] callback pointer to a callback function. This callback will be called when the delete process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_DeleteEntryAsync(s32 chn,card_dir *dir_entry,cardcallback callback); + + +/*! \fn s32 CARD_Write(card_file *file,void *buffer,u32 len,u32 offset) +\brief Writes the data to the file from the buffer to the given offset with the given length. Synchronous version +\param[in] file pointer to the card_file structure which holds the fileinformations. +\param[in] buffer pointer to the memory area to read from. The startaddress of the buffer should be aligned on a 32byte boundery. +\param[in] len length of data to write. +\param[in] offset starting point in the file to start writing. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_Write(card_file *file,void *buffer,u32 len,u32 offset); + + +/*! \fn s32 CARD_WriteAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback) +\brief Writes the data to the file from the buffer to the given offset with the given length. This function returns immediately. Asynchronous version +\param[in] file pointer to the card_file structure which holds the fileinformations. +\param[in] buffer pointer to the memory area to read from. The startaddress of the buffer should be aligned on a 32byte boundery. +\param[in] len length of data to write. +\param[in] offset starting point in the file to start writing. +\param[in] callback pointer to a callback function. This callback will be called when the write process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_WriteAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback); + + +/*! \fn s32 CARD_GetErrorCode(s32 chn) +\brief Returns the result code from the last operation. +\param[in] chn CARD slot + +\return \ref card_errors "card error codes" of last operation +*/ +s32 CARD_GetErrorCode(s32 chn); + + +/*! \fn s32 CARD_FindFirst(s32 chn, card_dir *dir, bool showall) +\brief Start to iterate thru the memory card's directory structure and returns the first directory entry. +\param[in] chn CARD slot +\param[out] dir pointer to card_dir structure to receive the result set. +\param[in] showall Whether to show all files of the memory card or only those which are identified by the company and gamecode string. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_FindFirst(s32 chn, card_dir *dir, bool showall); + + +/*! \fn s32 CARD_FindNext(card_dir *dir) +\brief Returns the next directory entry from the memory cards directory structure. +\param[out] dir pointer to card_dir structure to receive the result set. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_FindNext(card_dir *dir); + + +/*! \fn s32 CARD_GetDirectory(s32 chn, card_dir *dir_entries, s32 *count, bool showall) +\brief Returns the directory entries. size of entries is max. 128. +\param[in] chn CARD slot +\param[out] dir_entries pointer to card_dir structure to receive the result set. +\param[out] count pointer to an integer to receive the counted entries. +\param[in] showall Whether to show all files of the memory card or only those which are identified by the company and gamecode string. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_GetDirectory(s32 chn, card_dir *dir_entries, s32 *count, bool showall); + + +/*! \fn s32 CARD_GetSectorSize(s32 chn,u32 *sector_size) +\brief Returns the next directory entry from the memory cards directory structure. +\param[in] chn CARD slot. +\param[out] sector_size pointer to receive the result. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_GetSectorSize(s32 chn,u32 *sector_size); + + +/*! \fn s32 CARD_GetBlockCount(s32 chn,u32 *block_count) +\brief Returns the next directory entry from the memory cards directory structure. +\param[in] chn CARD slot. +\param[out] sector_size pointer to receive the result. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_GetBlockCount(s32 chn,u32 *block_count); + + +/*! \fn s32 CARD_GetStatus(s32 chn,s32 fileno,card_stat *stats) +\brief Get additional file statistic informations. +\param[in] chn CARD slot. +\param[in] fileno file index. returned by a previous call to CARD_Open(). +\param[out] stats pointer to receive the result set. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_GetStatus(s32 chn,s32 fileno,card_stat *stats); + + +/*! \fn s32 CARD_SetStatus(s32 chn,s32 fileno,card_stat *stats) +\brief Set additional file statistic informations. Synchronous version. +\param[in] chn CARD slot. +\param[in] fileno file index. returned by a previous call to CARD_Open(). +\param[out] stats pointer which holds the informations to set. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_SetStatus(s32 chn,s32 fileno,card_stat *stats); + + +/*! \fn s32 CARD_SetStatusAsync(s32 chn,s32 fileno,card_stat *stats,cardcallback callback) +\brief Set additional file statistic informations. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot. +\param[in] fileno file index. returned by a previous call to CARD_Open(). +\param[out] stats pointer which holds the informations to set. +\param[in] callback pointer to a callback function. This callback will be called when the setstatus process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_SetStatusAsync(s32 chn,s32 fileno,card_stat *stats,cardcallback callback); + + +/*! \fn s32 CARD_GetAttributes(s32 chn,s32 fileno,u8 *attr) +\brief Get additional file attributes. Synchronous version. +\param[in] chn CARD slot. +\param[in] fileno file index. returned by a previous call to CARD_Open(). +\param[out] attr pointer to receive attribute value. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_GetAttributes(s32 chn,s32 fileno,u8 *attr); + + +/*! \fn s32 CARD_SetAttributes(s32 chn,s32 fileno,u8 attr) +\brief Set additional file attributes. Synchronous version. +\param[in] chn CARD slot. +\param[in] fileno file index. returned by a previous call to CARD_Open(). +\param[in] attr attribute value to set. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_SetAttributes(s32 chn,s32 fileno,u8 attr); + + +/*! \fn s32 CARD_SetAttributesAsync(s32 chn,s32 fileno,u8 attr,cardcallback callback) +\brief Set additional file attributes. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot. +\param[in] fileno file index. returned by a previous call to CARD_Open(). +\param[in] attr attribute value to set. +\param[in] callback pointer to a callback function. This callback will be called when the setattributes process has finished. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_SetAttributesAsync(s32 chn,s32 fileno,u8 attr,cardcallback callback); + +/** + * Not finished function +*/ +s32 CARD_Format(s32 chn); +/** + * Not finished function +*/ +s32 CARD_FormatAsync(s32 chn,cardcallback callback); + + +/*! \fn s32 CARD_SetCompany(const char *company) +\brief Set additional file attributes. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_SetCompany(const char *company); + + +/*! \fn s32 CARD_SetGamecode(const char *gamecode) +\brief Set additional file attributes. This function returns immediately. Asynchronous version. +\param[in] chn CARD slot. + +\return \ref card_errors "card error codes" +*/ +s32 CARD_SetGamecode(const char *gamecode); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/cast.h b/wii/libogc/include/ogc/cast.h new file mode 100644 index 0000000000..49016dc3b4 --- /dev/null +++ b/wii/libogc/include/ogc/cast.h @@ -0,0 +1,239 @@ +#ifndef __CAST_H__ +#define __CAST_H__ + +#include + +#define GQR2 914 +#define GQR3 915 +#define GQR4 916 +#define GQR5 917 +#define GQR6 918 +#define GQR7 919 + +#define GQR_TYPE_F32 0 +#define GQR_TYPE_U8 4 +#define GQR_TYPE_U16 5 +#define GQR_TYPE_S8 6 +#define GQR_TYPE_S16 7 + +#define GQR_CAST_U8 2 +#define GQR_CAST_U16 3 +#define GQR_CAST_S8 4 +#define GQR_CAST_S16 5 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef GEKKO + +#define __set_gqr(_reg,_val) asm volatile("mtspr %0,%1" : : "i"(_reg), "b"(_val)) + +// does a default init +static inline void CAST_Init() +{ + __asm__ __volatile__ ( + "li 3,0x0004\n\ + oris 3,3,0x0004\n\ + mtspr 914,3\n\ + li 3,0x0005\n\ + oris 3,3,0x0005\n\ + mtspr 915,3\n\ + li 3,0x0006\n\ + oris 3,3,0x0006\n\ + mtspr 916,3\n\ + li 3,0x0007\n\ + oris 3,3,0x0007\n\ + mtspr 917,3\n" + : : : "r3" + ); +} + +static inline void CAST_SetGQR2(u32 type,u32 scale) +{ + register u32 val = (((((scale)<<8)|(type))<<16)|(((scale)<<8)|(type))); + __set_gqr(GQR2,val); +} + +static inline void CAST_SetGQR3(u32 type,u32 scale) +{ + register u32 val = (((((scale)<<8)|(type))<<16)|(((scale)<<8)|(type))); + __set_gqr(GQR3,val); +} + +static inline void CAST_SetGQR4(u32 type,u32 scale) +{ + register u32 val = (((((scale)<<8)|(type))<<16)|(((scale)<<8)|(type))); + __set_gqr(GQR4,val); +} + +static inline void CAST_SetGQR5(u32 type,u32 scale) +{ + register u32 val = (((((scale)<<8)|(type))<<16)|(((scale)<<8)|(type))); + __set_gqr(GQR5,val); +} + +static inline void CAST_SetGQR6(u32 type,u32 scale) +{ + register u32 val = (((((scale)<<8)|(type))<<16)|(((scale)<<8)|(type))); + __set_gqr(GQR6,val); +} + +static inline void CAST_SetGQR7(u32 type,u32 scale) +{ + register u32 val = (((((scale)<<8)|(type))<<16)|(((scale)<<8)|(type))); + __set_gqr(GQR7,val); +} + + +/******************************************************************/ +/* */ +/* cast from int to float */ +/* */ +/******************************************************************/ + +static inline f32 __castu8f32(register u8 *in) +{ + register f32 rval; + __asm__ __volatile__ ( + "psq_l %[rval],0(%[in]),1,2" : [rval]"=f"(rval) : [in]"r"(in) + ); + return rval; +} + +static inline f32 __castu16f32(register u16 *in) +{ + register f32 rval; + __asm__ __volatile__ ( + "psq_l %[rval],0(%[in]),1,3" : [rval]"=f"(rval) : [in]"r"(in) + ); + return rval; +} + +static inline f32 __casts8f32(register s8 *in) +{ + register f32 rval; + __asm__ __volatile__ ( + "psq_l %[rval],0(%[in]),1,4" : [rval]"=f"(rval) : [in]"r"(in) + ); + return rval; +} + +static inline f32 __casts16f32(register s16 *in) +{ + register f32 rval; + __asm__ __volatile__ ( + "psq_l %[rval],0(%[in]),1,5" : [rval]"=f"(rval) : [in]"r"(in) + ); + return rval; +} + +static inline void castu8f32(register u8 *in,register volatile f32 *out) +{ + *out = __castu8f32(in); +} + +static inline void castu16f32(register u16 *in,register volatile f32 *out) +{ + *out = __castu16f32(in); +} + +static inline void casts8f32(register s8 *in,register volatile f32 *out) +{ + *out = __casts8f32(in); +} + +static inline void casts16f32(register s16 *in,register volatile f32 *out) +{ + *out = __casts16f32(in); +} + +/******************************************************************/ +/* */ +/* cast from float to int */ +/* */ +/******************************************************************/ + +static inline u8 __castf32u8(register f32 in) +{ + f32 a; + register u8 rval; + register f32 *ptr = &a; + + __asm__ __volatile__ ( + "psq_st %[in],0(%[ptr]),1,2\n" + "lbz %[out],0(%[ptr])\n" + : [out]"=r"(rval), [ptr]"+r"(ptr) : [in]"f"(in) + ); + return rval; +} + +static inline u16 __castf32u16(register f32 in) +{ + f32 a; + register u16 rval; + register f32 *ptr = &a; + + __asm__ __volatile__ ( + "psq_st %[in],0(%[ptr]),1,3\n" + "lhz %[out],0(%[ptr])\n" + : [out]"=r"(rval), [ptr]"+r"(ptr) : [in]"f"(in) + ); + return rval; +} + +static inline s8 __castf32s8(register f32 in) +{ + f32 a; + register s8 rval; + register f32 *ptr = &a; + + __asm__ __volatile__ ( + "psq_st %[in],0(%[ptr]),1,4\n" + "lbz %[out],0(%[ptr])\n" + : [out]"=r"(rval), [ptr]"+r"(ptr) : [in]"f"(in) + ); + return rval; +} + +static inline s16 __castf32s16(register f32 in) +{ + f32 a; + register s16 rval; + register f32 *ptr = &a; + + __asm__ __volatile__ ( + "psq_st %[in],0(%[ptr]),1,5\n" + "lha %[out],0(%[ptr])\n" + : [out]"=r"(rval), [ptr]"+r"(ptr) : [in]"f"(in) + ); + return rval; +} + +static inline void castf32u8(register f32 *in,register vu8 *out) +{ + *out = __castf32u8(*in); +} + +static inline void castf32u16(register f32 *in,register vu16 *out) +{ + *out = __castf32u16(*in); +} + +static inline void castf32s8(register f32 *in,register vs8 *out) +{ + *out = __castf32s8(*in); +} + +static inline void castf32s16(register f32 *in,register vs16 *out) +{ + *out = __castf32s16(*in); +} + +#endif //GEKKO + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/include/ogc/color.h b/wii/libogc/include/ogc/color.h new file mode 100644 index 0000000000..cb5cfef48c --- /dev/null +++ b/wii/libogc/include/ogc/color.h @@ -0,0 +1,28 @@ +#ifndef __COLOR_H__ +#define __COLOR_H__ + +// luminance is stored twice, thus one of the lum. is +// redundant, but this way we can fill the screen. + +#define COLOR_BLACK (0x00800080) +#define COLOR_MAROON (0x266A26C0) +#define COLOR_GREEN (0x4B554B4A) +#define COLOR_OLIVE (0x7140718A) +#define COLOR_NAVY (0x0EC00E75) +#define COLOR_PURPLE (0x34AA34B5) +#define COLOR_TEAL (0x59955940) +#define COLOR_GRAY (0x80808080) +#define COLOR_SILVER (0xC080C080) +#define COLOR_RED (0x4C544CFF) +#define COLOR_LIME (0x952B9515) +#define COLOR_YELLOW (0xE100E194) +#define COLOR_BLUE (0x1DFF1D6B) +#define COLOR_FUCHSIA (0x69D469EA) +#define COLOR_AQUA (0xB2ABB200) +#define COLOR_WHITE (0xFF80FF80) +#define COLOR_MONEYGREEN (0xD076D074) +#define COLOR_SKYBLUE (0xC399C36A) +#define COLOR_CREAM (0xFA79FA82) +#define COLOR_MEDGRAY (0xA082A07F) + +#endif /* COLOR_H */ diff --git a/wii/libogc/include/ogc/cond.h b/wii/libogc/include/ogc/cond.h new file mode 100644 index 0000000000..ce38e61996 --- /dev/null +++ b/wii/libogc/include/ogc/cond.h @@ -0,0 +1,115 @@ +/*------------------------------------------------------------- + +cond.h -- Thread subsystem V + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __COND_H__ +#define __COND_H__ + +/*! \file cond.h +\brief Thread subsystem V + +*/ + +#include +#include + +#define LWP_COND_NULL 0xffffffff + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \typedef u32 cond_t +\brief typedef for the condition variable handle +*/ +typedef u32 cond_t; + + +/*! \fn s32 LWP_CondInit(cond_t *cond) +\brief Initialize condition variable +\param[out] cond pointer to the cond_t handle + +\return 0 on success, <0 on error +*/ +s32 LWP_CondInit(cond_t *cond); + + +/*! \fn s32 LWP_CondWait(cond_t cond,mutex_t mutex) +\brief Wait on condition variable. +\param[in] cond handle to the cond_t structure +\param[in] mutex handle to the mutex_t structure + +\return 0 on success, <0 on error +*/ +s32 LWP_CondWait(cond_t cond,mutex_t mutex); + + +/*! \fn s32 LWP_CondSignal(cond_t cond) +\brief Signal a specific thread waiting on this condition variable to wake up. +\param[in] cond handle to the cond_t structure + +\return 0 on success, <0 on error +*/ +s32 LWP_CondSignal(cond_t cond); + + +/*! \fn s32 LWP_CondBroadcast(cond_t cond) +\brief Broadcast all threads waiting on this condition variable to wake up. +\param[in] cond handle to the cond_t structure + +\return 0 on success, <0 on error +*/ +s32 LWP_CondBroadcast(cond_t cond); + + +/*! \fn s32 LWP_CondTimedWait(cond_t cond,mutex_t mutex,const struct timespec *abstime) +\brief Timed wait on a conditionvariable. +\param[in] cond handle to the cond_t structure +\param[in] mutex handle to the mutex_t structure +\param[in] abstime pointer to a timespec structure holding the abs time for the timeout. + +\return 0 on success, <0 on error +*/ +s32 LWP_CondTimedWait(cond_t cond,mutex_t mutex,const struct timespec *abstime); + + +/*! \fn s32 LWP_CondDestroy(cond_t cond) +\brief Destroy condition variable, release all threads and handles blocked on that condition variable. +\param[in] cond handle to the cond_t structure + +\return 0 on success, <0 on error +*/ +s32 LWP_CondDestroy(cond_t cond); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/conf.h b/wii/libogc/include/ogc/conf.h new file mode 100644 index 0000000000..4cdf2962a7 --- /dev/null +++ b/wii/libogc/include/ogc/conf.h @@ -0,0 +1,183 @@ +/*------------------------------------------------------------- + +conf.h -- SYSCONF support + +Copyright (C) 2008 +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __CONF_H__ +#define __CONF_H__ + +#if defined(HW_RVL) + +#include +#include + +#define CONF_EBADFILE -0x6001 +#define CONF_ENOENT -0x6002 +#define CONF_ETOOBIG -0x6003 +#define CONF_ENOTINIT -0x6004 +#define CONF_ENOTIMPL -0x6005 +#define CONF_EBADVALUE -0x6006 +#define CONF_ENOMEM -0x6007 +#define CONF_ERR_OK 0 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +enum { + CONF_BIGARRAY = 1, + CONF_SMALLARRAY, + CONF_BYTE, + CONF_SHORT, + CONF_LONG, + CONF_BOOL = 7 +}; + +enum { + CONF_VIDEO_NTSC = 0, + CONF_VIDEO_PAL, + CONF_VIDEO_MPAL +}; + +enum { + CONF_REGION_JP = 0, + CONF_REGION_US = 1, + CONF_REGION_EU = 2, + CONF_REGION_KR = 4, + CONF_REGION_CN = 5 +}; + +enum { + CONF_AREA_JPN = 0, + CONF_AREA_USA, + CONF_AREA_EUR, + CONF_AREA_AUS, + CONF_AREA_BRA, + CONF_AREA_TWN, + CONF_AREA_ROC, + CONF_AREA_KOR, + CONF_AREA_HKG, + CONF_AREA_ASI, + CONF_AREA_LTN, + CONF_AREA_SAF, + CONF_AREA_CHN +}; + +enum { + CONF_SHUTDOWN_STANDBY = 0, + CONF_SHUTDOWN_IDLE +}; + +enum { + CONF_LED_OFF = 0, + CONF_LED_DIM, + CONF_LED_BRIGHT +}; + +enum { + CONF_SOUND_MONO = 0, + CONF_SOUND_STEREO, + CONF_SOUND_SURROUND +}; + +enum { + CONF_LANG_JAPANESE = 0, + CONF_LANG_ENGLISH, + CONF_LANG_GERMAN, + CONF_LANG_FRENCH, + CONF_LANG_SPANISH, + CONF_LANG_ITALIAN, + CONF_LANG_DUTCH, + CONF_LANG_SIMP_CHINESE, + CONF_LANG_TRAD_CHINESE, + CONF_LANG_KOREAN +}; + +enum { + CONF_ASPECT_4_3 = 0, + CONF_ASPECT_16_9 +}; + +enum { + CONF_SENSORBAR_BOTTOM = 0, + CONF_SENSORBAR_TOP +}; + +#define CONF_PAD_MAX_REGISTERED 10 +#define CONF_PAD_MAX_ACTIVE 4 + +typedef struct _conf_pad_device conf_pad_device; + +struct _conf_pad_device { + u8 bdaddr[6]; + char name[0x40]; +} ATTRIBUTE_PACKED; + +typedef struct _conf_pads conf_pads; + +struct _conf_pads { + u8 num_registered; + conf_pad_device registered[CONF_PAD_MAX_REGISTERED]; + conf_pad_device active[CONF_PAD_MAX_ACTIVE]; + conf_pad_device balance_board; + conf_pad_device unknown; +} ATTRIBUTE_PACKED; + +s32 CONF_Init(void); +s32 CONF_GetLength(const char *name); +s32 CONF_GetType(const char *name); +s32 CONF_Get(const char *name, void *buffer, u32 length); +s32 CONF_GetShutdownMode(void); +s32 CONF_GetIdleLedMode(void); +s32 CONF_GetProgressiveScan(void); +s32 CONF_GetEuRGB60(void); +s32 CONF_GetIRSensitivity(void); +s32 CONF_GetSensorBarPosition(void); +s32 CONF_GetPadSpeakerVolume(void); +s32 CONF_GetPadMotorMode(void); +s32 CONF_GetSoundMode(void); +s32 CONF_GetLanguage(void); +s32 CONF_GetCounterBias(u32 *bias); +s32 CONF_GetScreenSaverMode(void); +s32 CONF_GetDisplayOffsetH(s8 *offset); +s32 CONF_GetPadDevices(conf_pads *pads); +s32 CONF_GetNickName(u8 *nickname); +s32 CONF_GetAspectRatio(void); +s32 CONF_GetEULA(void); +s32 CONF_GetParentalPassword(s8 *password); +s32 CONF_GetParentalAnswer(s8 *answer); +s32 CONF_GetWiiConnect24(void); +s32 CONF_GetRegion(void); +s32 CONF_GetArea(void); +s32 CONF_GetVideo(void); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif + +#endif diff --git a/wii/libogc/include/ogc/consol.h b/wii/libogc/include/ogc/consol.h new file mode 100644 index 0000000000..294f7e6b11 --- /dev/null +++ b/wii/libogc/include/ogc/consol.h @@ -0,0 +1,81 @@ +#ifndef __CONSOL_H__ +#define __CONSOL_H__ + +/*! + * \file consol.h + * \brief Console subsystem + * + */ + +#include "gx_struct.h" + +/* macros to support old function names */ +#define console_init CON_Init +#define SYS_ConsoleInit CON_InitEx + +#ifdef __cplusplus + extern "C" { +#endif + +/*! + * \fn CON_Init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride) + * \brief Initializes the console subsystem with given parameters + * + * \param[in] framebuffer pointer to the framebuffer used for drawing the characters + * \param[in] xstart,ystart start position of the console output in pixel + * \param[in] xres,yres size of the console in pixel + * \param[in] stride size of one line of the framebuffer in bytes + * + * \return none + */ +void CON_Init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride); + +/*! + * \fn s32 CON_InitEx(GXRModeObj *rmode, s32 conXOrigin,s32 conYOrigin,s32 conWidth,s32 conHeight) + * \brief Initialize stdout console + * \param[in] rmode pointer to the video/render mode configuration + * \param[in] conXOrigin starting pixel in X direction of the console output on the external framebuffer + * \param[in] conYOrigin starting pixel in Y direction of the console output on the external framebuffer + * \param[in] conWidth width of the console output 'window' to be drawn + * \param[in] conHeight height of the console output 'window' to be drawn + * + * \return 0 on success, <0 on error + */ +s32 CON_InitEx(GXRModeObj *rmode, s32 conXOrigin,s32 conYOrigin,s32 conWidth,s32 conHeight); + +/*! + * \fn CON_GetMetrics(int *cols, int *rows) + * \brief retrieve the columns and rows of the current console + * + * \param[out] cols,rows number of columns and rows of the current console + * + * \return none + */ +void CON_GetMetrics(int *cols, int *rows); + +/*! + * \fn CON_GetPosition(int *col, int *row) + * \brief retrieve the current cursor position of the current console + * + * \param[out] col,row current cursor position + * + * \return none + */ +void CON_GetPosition(int *cols, int *rows); + +/*! + * \fn CON_EnableGecko(int channel, int safe) + * \brief Enable or disable the USB gecko console. + * + * \param[in] channel EXI channel, or -1 to disable the gecko console + * \param[in] safe If true, use safe mode (wait for peer) + * + * \return none + */ +void CON_EnableGecko(int channel,int safe); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/context.h b/wii/libogc/include/ogc/context.h new file mode 100644 index 0000000000..7814bb5db5 --- /dev/null +++ b/wii/libogc/include/ogc/context.h @@ -0,0 +1,51 @@ +#ifndef __EXCONTEXT_H__ +#define __EXCONTEXT_H__ + +#define NUM_EXCEPTIONS 15 + +#define EX_SYS_RESET 0 +#define EX_MACH_CHECK 1 +#define EX_DSI 2 +#define EX_ISI 3 +#define EX_INT 4 +#define EX_ALIGN 5 +#define EX_PRG 6 +#define EX_FP 7 +#define EX_DEC 8 +#define EX_SYS_CALL 9 +#define EX_TRACE 10 +#define EX_PERF 11 +#define EX_IABR 12 +#define EX_RESV 13 +#define EX_THERM 14 + +#ifndef _LANGUAGE_ASSEMBLY + +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct _excption_frame { + u32 EXCPT_Number; + u32 SRR0,SRR1; + u32 GPR[32]; + u32 GQR[8]; + u32 CR, LR, CTR, XER, MSR, DAR; + + u16 state; //used to determine whether to restore the fpu context or not + u16 mode; //unused + + f64 FPR[32]; + u64 FPSCR; + f64 PSFPR[32]; +} frame_context; + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif //!_LANGUAGE_ASSEMBLY + +#endif diff --git a/wii/libogc/include/ogc/disc_io.h b/wii/libogc/include/ogc/disc_io.h new file mode 100644 index 0000000000..0a6ef3e5a4 --- /dev/null +++ b/wii/libogc/include/ogc/disc_io.h @@ -0,0 +1,68 @@ +/* + disc_io.h + Interface template for low level disc functions. + + Copyright (c) 2006 Michael "Chishm" Chisholm + Based on code originally written by MightyMax + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OGC_DISC_IO_INCLUDE +#define OGC_DISC_IO_INCLUDE + +#include +#include + + +#define FEATURE_MEDIUM_CANREAD 0x00000001 +#define FEATURE_MEDIUM_CANWRITE 0x00000002 +#define FEATURE_GAMECUBE_SLOTA 0x00000010 +#define FEATURE_GAMECUBE_SLOTB 0x00000020 +#define FEATURE_GAMECUBE_DVD 0x00000040 +#define FEATURE_WII_SD 0x00000100 +#define FEATURE_WII_USB 0x00000200 +#define FEATURE_WII_DVD 0x00000400 + +typedef uint32_t sec_t; + +typedef bool (* FN_MEDIUM_STARTUP)(void) ; +typedef bool (* FN_MEDIUM_ISINSERTED)(void) ; +typedef bool (* FN_MEDIUM_READSECTORS)(sec_t sector, sec_t numSectors, void* buffer) ; +typedef bool (* FN_MEDIUM_WRITESECTORS)(sec_t sector, sec_t numSectors, const void* buffer) ; +typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ; +typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ; + +struct DISC_INTERFACE_STRUCT { + unsigned long ioType ; + unsigned long features ; + FN_MEDIUM_STARTUP startup ; + FN_MEDIUM_ISINSERTED isInserted ; + FN_MEDIUM_READSECTORS readSectors ; + FN_MEDIUM_WRITESECTORS writeSectors ; + FN_MEDIUM_CLEARSTATUS clearStatus ; + FN_MEDIUM_SHUTDOWN shutdown ; +} ; + +typedef struct DISC_INTERFACE_STRUCT DISC_INTERFACE ; + +#endif // define OGC_DISC_IO_INCLUDE diff --git a/wii/libogc/include/ogc/dsp.h b/wii/libogc/include/ogc/dsp.h new file mode 100644 index 0000000000..eba38aeefe --- /dev/null +++ b/wii/libogc/include/ogc/dsp.h @@ -0,0 +1,228 @@ +/*------------------------------------------------------------- + +dsp.h -- DSP subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __DSP_H__ +#define __DSP_H__ + +/*! \file dsp.h +\brief DSP subsystem + +*/ + +#include + +/*! + * \addtogroup dsp_taskstate DSP task states + * \brief DSP task state indicating DSP task's current operation + * @{ + */ + +#define DSPTASK_INIT 0 /*!< DSP task is initializing */ +#define DSPTASK_RUN 1 /*!< DSP task is running */ +#define DSPTASK_YIELD 2 /*!< DSP task has yield */ +#define DSPTASK_DONE 3 /*!< DSP task is done/ready */ + +/*! + * @} + */ + + +/*! + * \addtogroup dsp_taskflag DSP task flags + * \brief DSP task queue state flag indicating the task's current queue state. Multiple states are OR'd. + * @{ + */ + +#define DSPTASK_CLEARALL 0x00000000 /*!< DSP task emtpy/ready */ +#define DSPTASK_ATTACH 0x00000001 /*!< DSP task attached */ +#define DSPTASK_CANCEL 0x00000002 /*!< DSP task canceled */ + +/*! + * @} + */ + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! +\typedef struct _dsp_task dsptask_t +\brief forward typdef to struct _dsp_task. This struture holds certain DSP task information for execution. +*/ +typedef struct _dsp_task dsptask_t; + + +/*! \typedef void (*DSPTaskCallback)(dsptask_t *task) +\brief function pointer typedef for the user's DSP task callbacks +\param[in] task pointer to the dsp_task structure. +*/ +typedef void (*DSPTaskCallback)(dsptask_t *task); + + +/*! \typedef void (*DSPCallback)(void) +\brief function pointer typedef for the user's DSP interrupt callback +*/ +typedef void (*DSPCallback)(void); + + +/*! \typedef struct _dsp_task dsptask_t +\param state current task \ref dsp_taskstate "state" set +\param prio priority of the task +\param flags currnet task \ref dsp_taskflag "flag(s)" set. +\param init_vec initialization vector. depends on the DSP code to execute. +\param resume_vec resume vector. depends on the DSP code to execute. +\param iram_maddr main memory address of i-ram image. NOTE: Has to be aligned on a 32byte boundery! +\param iram_len size of i-ram image. NOTE: Should be a multiple of 32 +\param iram_addr DSP i-ram address to load the image to. +\param dram_maddr main memory address of d-ram image. NOTE: Has to be aligned on a 32byte boundery! +\param dram_len size of d-ram image. NOTE: Should be a multiple of 32 +\param dram_addr DSP d-ram address to load the image to. +\param init_cb pointer to the user's init callback function. Called durring task initialization. +\param res_cb pointer to the user's resume callback function. Called when the task should resume. +\param done_cb pointer to the user's done callback function. Called when the task has finished. +\param req_cb pointer to the user's request callback function. Used to retrieve data from main application durring execution. +\param next pointer to the next task in the doubly linked list. +\param prev pointer to the previous task in the doubly linked list. +*/ +struct _dsp_task { + vu32 state; + vu32 prio; + vu32 flags; + + void *iram_maddr; + u32 iram_len; + u32 iram_addr; + + void *dram_maddr; + u32 dram_len; + u32 dram_addr; + + u16 init_vec; + u16 resume_vec; + + DSPTaskCallback init_cb; + DSPTaskCallback res_cb; + DSPTaskCallback done_cb; + DSPTaskCallback req_cb; + + struct _dsp_task *next; + struct _dsp_task *prev; +}; + + +/*! \fn void DSP_Init() +\brief Initialize DSP subsystem. + +\return none +*/ +void DSP_Init(); + + +/*! \fn u32 DSP_CheckMailTo() +\brief Check if mail was sent to DSP + +\return 1: mail sent, 0: mail on route +*/ +u32 DSP_CheckMailTo(); + + +/*! \fn u32 DSP_CheckMailFrom() +\brief Check for mail from DSP + +\return 1: has mail, 0: no mail +*/ +u32 DSP_CheckMailFrom(); + + +/*! \fn u32 DSP_ReadMailFrom() +\brief Read mail from DSP + +\return mail value received +*/ +u32 DSP_ReadMailFrom(); + + +/*! \fn void DSP_AssertInt() +\brief Asserts the processor interface interrupt + +\return none +*/ +void DSP_AssertInt(); + + +/*! \fn void DSP_SendMailTo(u32 mail) +\brief Send mail to DSP +\param[in] mail value to send + +\return none +*/ +void DSP_SendMailTo(u32 mail); + + +/*! \fn u32 DSP_ReadCPUtoDSP() +\brief Read back CPU->DSP mailbox + +\return mail value received +*/ +u32 DSP_ReadCPUtoDSP(); + + +/*! \fn dsptask_t* DSP_AddTask(dsptask_t *task) +\brief Add a DSP task to the tasklist and start executing if necessary. +\param[in] task pointer to a dsptask_t structure which holds all necessary values for DSP task execution. + +\return current task +*/ +dsptask_t* DSP_AddTask(dsptask_t *task); + +dsptask_t* DSP_AssertTask(dsptask_t *task); + +void DSP_CancelTask(dsptask_t *task); + +void DSP_Reset(); + +void DSP_Halt(); + +void DSP_Unhalt(); + +/*! \fn DSPCallback DSP_RegisterCallback(DSPCallback usr_cb) +\brief Register an user's interrupt callback. This may be used to handle DSP interrupts on its own. By default a system default callback is installed on DSP_Init(). +\param[in] user_cb pointer to the user's interrupt callback function. +\ +\return pointer to old interrupt callback function. +*/ +DSPCallback DSP_RegisterCallback(DSPCallback usr_cb); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/dvd.h b/wii/libogc/include/ogc/dvd.h new file mode 100644 index 0000000000..b9e4c6369a --- /dev/null +++ b/wii/libogc/include/ogc/dvd.h @@ -0,0 +1,369 @@ +/*------------------------------------------------------------- + +dvd.h -- DVD subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __DVD_H__ +#define __DVD_H__ + +/*! + * \file dvd.h + * \brief DVD subsystem + * + */ + +#include +#include +#include + +/*! + * \addtogroup dvd_statecodes DVD state codes + * @{ + */ + +#define DVD_STATE_FATAL_ERROR -1 +#define DVD_STATE_END 0 +#define DVD_STATE_BUSY 1 +#define DVD_STATE_WAITING 2 +#define DVD_STATE_COVER_CLOSED 3 +#define DVD_STATE_NO_DISK 4 +#define DVD_STATE_COVER_OPEN 5 +#define DVD_STATE_WRONG_DISK 6 +#define DVD_STATE_MOTOR_STOPPED 7 +#define DVD_STATE_IGNORED 8 +#define DVD_STATE_CANCELED 10 +#define DVD_STATE_RETRY 11 + +#define DVD_ERROR_OK 0 +#define DVD_ERROR_FATAL -1 +#define DVD_ERROR_IGNORED -2 +#define DVD_ERROR_CANCELED -3 +#define DVD_ERROR_COVER_CLOSED -4 + +/*! + * @} + */ + + +/*! + * \addtogroup dvd_resetmode DVD reset modes + * @{ + */ + +#define DVD_RESETHARD 0 /*!< Performs a hard reset. Complete new boot of FW. */ +#define DVD_RESETSOFT 1 /*!< Performs a soft reset. FW restart and drive spinup */ +#define DVD_RESETNONE 2 /*!< Only initiate DI registers */ + +/*! + * @} + */ + + +/*! + * \addtogroup dvd_motorctrlmode DVD motor control modes + * @{ + */ + +#define DVD_SPINMOTOR_DOWN 0x00000000 /*!< Stop DVD drive */ +#define DVD_SPINMOTOR_UP 0x00000100 /*!< Start DVD drive */ +#define DVD_SPINMOTOR_ACCEPT 0x00004000 /*!< Force DVD to accept the disk */ +#define DVD_SPINMOTOR_CHECKDISK 0x00008000 /*!< Force DVD to perform a disc check */ + +/*! + * @} + */ + + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! + * \typedef struct _dvddiskid dvddiskid + * \brief forward typedef for struct _dvddiskid + */ +typedef struct _dvddiskid dvddiskid; + +/*! + * \typedef struct _dvddiskid dvddiskid + * + * This structure holds the game vendors copyright informations.
+ * Additionally it holds certain parameters for audiocontrol and
+ * multidisc support. + * + * \param gamename[4] vendors game key + * \param company[2] vendors company key + * \param disknum number of disc when multidisc support is used. + * \param gamever version of game + * \param streaming flag to control audio streaming + * \param streambufsize size of buffer used for audio streaming + * \param pad[22] padding + */ +struct _dvddiskid { + s8 gamename[4]; + s8 company[2]; + u8 disknum; + u8 gamever; + u8 streaming; + u8 streambufsize; + u8 pad[22]; +}; + +/*! + * \typedef struct _dvdcmdblk dvdcmdblk + * \brief forward typedef for struct _dvdcmdblk + */ +typedef struct _dvdcmdblk dvdcmdblk; + + +/*! + * \typedef void (*dvdcbcallback)(s32 result,dvdcmdblk *block) + * \brief function pointer typedef for the user's operations callback + */ +typedef void (*dvdcbcallback)(s32 result,dvdcmdblk *block); + + +/*! + * \typedef struct _dvdcmdblk dvdcmdblk + * + * This structure is used internally to control the requested operation. + */ +struct _dvdcmdblk { + lwp_node node; + u32 cmd; + s32 state; + s64 offset; + u32 len; + void *buf; + u32 currtxsize; + u32 txdsize; + dvddiskid *id; + dvdcbcallback cb; + void *usrdata; +}; + + +/*! + * \typedef struct _dvddrvinfo dvddrvinfo + * \brief forward typedef for struct _dvddrvinfo + */ +typedef struct _dvddrvinfo dvddrvinfo; + + +/*! + * \typedef struct _dvddrvinfo dvddrvinfo + * + * This structure structure holds the drive version infromation.
+ * Use DVD_Inquiry() to retrieve this information. + * + * \param rev_leve revision level + * \param dev_code device code + * \param rel_date release date + * \param pad[24] padding + */ +struct _dvddrvinfo { + u16 rev_level; + u16 dev_code; + u32 rel_date; + u8 pad[24]; +}; + + +/*! + * \typedef struct _dvdfileinfo dvdfileinfo + * \brief forward typedef for struct _dvdfileinfo + */ +typedef struct _dvdfileinfo dvdfileinfo; + + +/*! + * \typedef void (*dvdcallback)(s32 result,dvdfileinfo *info) + * \brief function pointer typedef for the user's DVD operation callback + * + * \param[in] result error code of last operation + * \param[in] info pointer to user's file info strucutre + */ +typedef void (*dvdcallback)(s32 result,dvdfileinfo *info); + + +/*! + * \typedef struct _dvdfileinfo dvdfileinfo + * + * This structure is used internally to control the requested file operation. + */ +struct _dvdfileinfo { + dvdcmdblk block; + u32 addr; + u32 len; + dvdcallback cb; +}; + + +/*! + * \fn void DVD_Init() + * \brief Initializes the DVD subsystem + * + * You must call this function before calling any other DVD function + * + * \return none + */ +void DVD_Init(); +void DVD_Pause(); + + +/*! + * \fn void DVD_Reset(u32 reset_mode) + * \brief Performs a reset of the drive and FW respectively. + * + * \param[in] reset_mode \ref dvd_resetmode "type" of reset + * + * \return none + */ +void DVD_Reset(u32 reset_mode); + + +/*! + * \fn s32 DVD_Mount() + * \brief Mounts the DVD drive. + * + * This is a synchronous version of DVD_MountAsync(). + * + * \return none + */ +s32 DVD_Mount(); +s32 DVD_GetDriveStatus(); + + +/*! + * \fn s32 DVD_MountAsync(dvdcmdblk *block,dvdcbcallback cb) + * \brief Mounts the DVD drive. + * + * You must call this function in order to access the DVD. + * + * Following tasks are performed: + * - Issue a hard reset to the drive. + * - Turn on drive's debug mode. + * - Patch drive's FW. + * - Enable extensions. + * - Read disc ID + * + * The patch code and procedure was taken from the gc-linux DVD device driver. + * + * \param[in] block pointer to a dvdcmdblk structure used to process the operation + * \param[in] cb callback to be invoked upon completion of operation + * + * \return none + */ +s32 DVD_MountAsync(dvdcmdblk *block,dvdcbcallback cb); + + +/*! + * \fn s32 DVD_ControlDrive(dvdcmdblk *block,u32 cmd) + * \brief Controls the drive's motor and behavior. + * + * This is a synchronous version of DVD_ControlDriveAsync(). + * + * \param[in] block pointer to a dvdcmdblk structure used to process the operation + * \param[in] cmd \ref dvd_motorctrlmode "command" to control the drive. + * + * \return none + */ +s32 DVD_ControlDrive(dvdcmdblk *block,u32 cmd); + + +/*! + * \fn s32 DVD_ControlDriveAsync(dvdcmdblk *block,u32 cmd,dvdcbcallback cb) + * \brief Controls the drive's motor and behavior. + * + * \param[in] block pointer to a dvdcmdblk structure used to process the operation + * \param[in] cmd \ref dvd_motorctrlmode "command" to control the drive. + * \param[in] cb callback to be invoked upon completion of operation. + * + * \return none + */ +s32 DVD_ControlDriveAsync(dvdcmdblk *block,u32 cmd,dvdcbcallback cb); + + +/*! + * \fn s32 DVD_SetGCMOffset(dvdcmdblk *block,u32 offset) + * \brief Sets the offset to the GCM. Used for multigame discs. + * + * This is a synchronous version of DVD_SetGCMOffsetAsync(). + * + * \param[in] block pointer to a dvdcmdblk structure used to process the operation + * \param[in] offset offset to the GCM on disc. + * + * \return \ref dvd_errorcodes "dvd error code" + */ +s32 DVD_SetGCMOffset(dvdcmdblk *block,s64 offset); + + +/*! + * \fn s32 DVD_SetGCMOffsetAsync(dvdcmdblk *block,u32 offset,dvdcbcallback cb) + * \brief Sets the offset to the GCM. Used for multigame discs. + * + * This is a synchronous version of DVD_SetGCMOffsetAsync(). + * + * \param[in] block pointer to a dvdcmdblk structure used to process the operation + * \param[in] offset offset to the GCM on disc. + * \param[in] cb callback to be invoked upon completion of operation. + * + * \return \ref dvd_errorcodes "dvd error code" + */ +s32 DVD_SetGCMOffsetAsync(dvdcmdblk *block,s64 offset,dvdcbcallback cb); + +s32 DVD_GetCmdBlockStatus(dvdcmdblk *block); +s32 DVD_SpinUpDrive(dvdcmdblk *block); +s32 DVD_SpinUpDriveAsync(dvdcmdblk *block,dvdcbcallback cb); +s32 DVD_Inquiry(dvdcmdblk *block,dvddrvinfo *info); +s32 DVD_InquiryAsync(dvdcmdblk *block,dvddrvinfo *info,dvdcbcallback cb); +s32 DVD_ReadPrio(dvdcmdblk *block,void *buf,u32 len,s64 offset,s32 prio); +s32 DVD_ReadAbsAsyncPrio(dvdcmdblk *block,void *buf,u32 len,s64 offset,dvdcbcallback cb,s32 prio); +s32 DVD_ReadAbsAsyncForBS(dvdcmdblk *block,void *buf,u32 len,s64 offset,dvdcbcallback cb); +s32 DVD_SeekPrio(dvdcmdblk *block,s64 offset,s32 prio); +s32 DVD_SeekAbsAsyncPrio(dvdcmdblk *block,s64 offset,dvdcbcallback cb,s32 prio); +s32 DVD_CancelAllAsync(dvdcbcallback cb); +s32 DVD_StopStreamAtEndAsync(dvdcmdblk *block,dvdcbcallback cb); +s32 DVD_StopStreamAtEnd(dvdcmdblk *block); +s32 DVD_ReadDiskID(dvdcmdblk *block,dvddiskid *id,dvdcbcallback cb); +u32 DVD_SetAutoInvalidation(u32 auto_inv); +dvddiskid* DVD_GetCurrentDiskID(); +dvddrvinfo* DVD_GetDriveInfo(); + +#define DVD_SetUserData(block, data) ((block)->usrdata = (data)) +#define DVD_GetUserData(block) ((block)->usrdata) + +#define DEVICE_TYPE_GAMECUBE_DVD (('G'<<24)|('D'<<16)|('V'<<8)|'D') +extern const DISC_INTERFACE __io_gcdvd; + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/es.h b/wii/libogc/include/ogc/es.h new file mode 100644 index 0000000000..c675ed800c --- /dev/null +++ b/wii/libogc/include/ogc/es.h @@ -0,0 +1,309 @@ +/*------------------------------------------------------------- + +es.h -- tik services + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) +Andre Heider (dhewg) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __ES_H__ +#define __ES_H__ + +#if defined(HW_RVL) + +#include +#include + +#define ES_EINVAL -0x1004 +#define ES_ENOMEM -0x100C +#define ES_ENOTINIT -0x1100 +#define ES_EALIGN -0x1101 + +#define ES_SIG_RSA4096 0x10000 +#define ES_SIG_RSA2048 0x10001 +#define ES_SIG_ECDSA 0x10002 + +#define ES_CERT_RSA4096 0 +#define ES_CERT_RSA2048 1 +#define ES_CERT_ECDSA 2 + +#define ES_KEY_COMMON 4 +#define ES_KEY_SDCARD 6 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef u32 sigtype; +typedef sigtype sig_header; +typedef sig_header signed_blob; + +typedef u8 sha1[20]; +typedef u8 aeskey[16]; + +typedef struct _sig_rsa2048 { + sigtype type; + u8 sig[256]; + u8 fill[60]; +} __attribute__((packed)) sig_rsa2048; + +typedef struct _sig_rsa4096 { + sigtype type; + u8 sig[512]; + u8 fill[60]; +} __attribute__((packed)) sig_rsa4096; + +typedef struct _sig_ecdsa { + sigtype type; + u8 sig[60]; + u8 fill[64]; +} __attribute__((packed)) sig_ecdsa; + +typedef char sig_issuer[0x40]; + +typedef struct _tiklimit { + u32 tag; + u32 value; +} __attribute__((packed)) tiklimit; + +typedef struct _tikview { + u32 view; + u64 ticketid; + u32 devicetype; + u64 titleid; + u16 access_mask; + u8 reserved[0x3c]; + u8 cidx_mask[0x40]; + u16 padding; + tiklimit limits[8]; +} __attribute__((packed)) tikview; + +typedef struct _tik { + sig_issuer issuer; + u8 fill[63]; //TODO: not really fill + aeskey cipher_title_key; + u8 fill2; + u64 ticketid; + u32 devicetype; + u64 titleid; + u16 access_mask; + u8 reserved[0x3c]; + u8 cidx_mask[0x40]; + u16 padding; + tiklimit limits[8]; +} __attribute__((packed)) tik; + +typedef struct _tmd_content { + u32 cid; + u16 index; + u16 type; + u64 size; + sha1 hash; +} __attribute__((packed)) tmd_content; + +typedef struct _tmd { + sig_issuer issuer; //0x140 + u8 version; //0x180 + u8 ca_crl_version; //0x181 + u8 signer_crl_version; //0x182 + u8 fill2; //0x183 + u64 sys_version; //0x184 + u64 title_id; //0x18c + u32 title_type; //0x194 + u16 group_id; //0x198 + u16 zero; //0x19a + u16 region; //0x19c + u8 ratings[16]; //0x19e + u8 reserved[12]; //0x1ae + u8 ipc_mask[12]; + u8 reserved2[18]; + u32 access_rights; + u16 title_version; + u16 num_contents; + u16 boot_index; + u16 fill3; + // content records follow + // C99 flexible array + tmd_content contents[]; +} __attribute__((packed)) tmd; + +typedef struct _tmd_view_content +{ + u32 cid; + u16 index; + u16 type; + u64 size; +} __attribute__((packed)) tmd_view_content; + +typedef struct _tmdview +{ + u8 version; // 0x0000; + u8 filler[3]; + u64 sys_version; //0x0004 + u64 title_id; // 0x00c + u32 title_type; //0x0014 + u16 group_id; //0x0018 + u8 reserved[0x3e]; //0x001a this is the same reserved 0x3e bytes from the tmd + u16 title_version; //0x0058 + u16 num_contents; //0x005a + tmd_view_content contents[]; //0x005c +}__attribute__((packed)) tmd_view; + +typedef struct _cert_header { + sig_issuer issuer; + u32 cert_type; + char cert_name[64]; + u32 cert_id; //??? +} __attribute__((packed)) cert_header; + +typedef struct _cert_rsa2048 { + sig_issuer issuer; + u32 cert_type; + char cert_name[64]; + u32 cert_id; + u8 modulus[256]; + u32 exponent; + u8 pad[0x34]; +} __attribute__((packed)) cert_rsa2048; + +typedef struct _cert_rsa4096 { + sig_issuer issuer; + u32 cert_type; + char cert_name[64]; + u32 cert_id; + u8 modulus[512]; + u32 exponent; + u8 pad[0x34]; +} __attribute__((packed)) cert_rsa4096; + +typedef struct _cert_ecdsa { + sig_issuer issuer; + u32 cert_type; + char cert_name[64]; + u32 cert_id; // ng key id + u8 r[30]; + u8 s[30]; + u8 pad[0x3c]; +} __attribute__((packed)) cert_ecdsa; + +#define TMD_SIZE(x) (((x)->num_contents)*sizeof(tmd_content) + sizeof(tmd)) +// backwards compatibility +#define TMD_CONTENTS(x) ((x)->contents) + +//TODO: add ECC stuff + +#define IS_VALID_SIGNATURE(x) ( \ + ((*(x))==ES_SIG_RSA2048) || \ + ((*(x))==ES_SIG_RSA4096) || \ + ((*(x))==ES_SIG_ECDSA)) + +#define SIGNATURE_SIZE(x) (\ + ((*(x))==ES_SIG_RSA2048) ? sizeof(sig_rsa2048) : ( \ + ((*(x))==ES_SIG_RSA4096) ? sizeof(sig_rsa4096) : ( \ + ((*(x))==ES_SIG_ECDSA) ? sizeof(sig_ecdsa) : 0 ))) + +#define SIGNATURE_SIG(x) (((u8*)x)+4) + +#define IS_VALID_CERT(x) ( \ + (((x)->cert_type)==ES_CERT_RSA2048) || \ + (((x)->cert_type)==ES_CERT_RSA4096) || \ + (((x)->cert_type)==ES_CERT_ECDSA)) + +#define CERTIFICATE_SIZE(x) (\ + (((x)->cert_type)==ES_CERT_RSA2048) ? sizeof(cert_rsa2048) : ( \ + (((x)->cert_type)==ES_CERT_RSA4096) ? sizeof(cert_rsa4096) : ( \ + (((x)->cert_type)==ES_CERT_ECDSA) ? sizeof(cert_ecdsa) : 0 ))) + +#define SIGNATURE_PAYLOAD(x) ((void *)(((u8*)(x)) + SIGNATURE_SIZE(x))) + +#define SIGNED_TMD_SIZE(x) ( TMD_SIZE((tmd*)SIGNATURE_PAYLOAD(x)) + SIGNATURE_SIZE(x)) +#define SIGNED_TIK_SIZE(x) ( sizeof(tik) + SIGNATURE_SIZE(x) ) +#define SIGNED_CERT_SIZE(x) ( CERTIFICATE_SIZE((cert_header*)SIGNATURE_PAYLOAD(x)) + SIGNATURE_SIZE(x)) + +#define STD_SIGNED_TIK_SIZE ( sizeof(tik) + sizeof(sig_rsa2048) ) + +#define MAX_NUM_TMD_CONTENTS 512 + +#define MAX_TMD_SIZE ( sizeof(tmd) + MAX_NUM_TMD_CONTENTS*sizeof(tmd_content) ) +#define MAX_SIGNED_TMD_SIZE ( MAX_TMD_SIZE + sizeof(sig_rsa2048) ) + +s32 __ES_Init(void); +s32 __ES_Close(void); +s32 __ES_Reset(void); +s32 ES_GetTitleID(u64 *titleID); +s32 ES_SetUID(u64 uid); +s32 ES_GetDataDir(u64 titleID, char *filepath); +s32 ES_GetNumTicketViews(u64 titleID, u32 *cnt); +s32 ES_GetTicketViews(u64 titleID, tikview *views, u32 cnt); +s32 ES_GetNumOwnedTitles(u32 *cnt); +s32 ES_GetOwnedTitles(u64 *titles, u32 cnt); +s32 ES_GetNumTitles(u32 *cnt); +s32 ES_GetTitles(u64 *titles, u32 cnt); +s32 ES_GetNumStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *cnt); +s32 ES_GetStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *contents, u32 cnt); +s32 ES_GetStoredTMDSize(u64 titleID, u32 *size); +s32 ES_GetStoredTMD(u64 titleID, signed_blob *stmd, u32 size); +s32 ES_GetTitleContentsCount(u64 titleID, u32 *num); +s32 ES_GetTitleContents(u64 titleID, u8 *data, u32 size); +s32 ES_GetTMDViewSize(u64 titleID, u32 *size); +s32 ES_GetTMDView(u64 titleID, u8 *data, u32 size); +s32 ES_GetNumSharedContents(u32 *cnt); +s32 ES_GetSharedContents(sha1 *contents, u32 cnt); +s32 ES_LaunchTitle(u64 titleID, const tikview *view); +s32 ES_LaunchTitleBackground(u64 titleID, const tikview *view); +s32 ES_Identify(const signed_blob *certificates, u32 certificates_size, const signed_blob *tmd, u32 tmd_size, const signed_blob *ticket, u32 ticket_size, u32 *keyid); +s32 ES_AddTicket(const signed_blob *tik, u32 tik_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size); +s32 ES_DeleteTicket(const tikview *view); +s32 ES_AddTitleTMD(const signed_blob *tmd, u32 tmd_size); +s32 ES_AddTitleStart(const signed_blob *tmd, u32 tmd_size, const signed_blob *certificatess, u32 certificatess_size, const signed_blob *crl, u32 crl_size); +s32 ES_AddContentStart(u64 titleID, u32 cid); +s32 ES_AddContentData(s32 cid, u8 *data, u32 data_size); +s32 ES_AddContentFinish(u32 cid); +s32 ES_AddTitleFinish(void); +s32 ES_AddTitleCancel(void); +s32 ES_ImportBoot(const signed_blob *tik, u32 tik_size,const signed_blob *tik_certs, u32 tik_certs_size,const signed_blob *tmd, u32 tmd_size,const signed_blob *tmd_certs, u32 tmd_certs_size,const u8 *content, u32 content_size); +s32 ES_OpenContent(u16 index); +s32 ES_OpenTitleContent(u64 titleID, tikview *views, u16 index); +s32 ES_ReadContent(s32 cfd, u8 *data, u32 data_size); +s32 ES_SeekContent(s32 cfd, s32 where, s32 whence); +s32 ES_CloseContent(s32 cfd); +s32 ES_DeleteTitle(u64 titleID); +s32 ES_DeleteTitleContent(u64 titleID); +s32 ES_Encrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest); +s32 ES_Decrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest); +s32 ES_Sign(u8 *source, u32 size, u8 *sig, u8 *certs); +s32 ES_GetDeviceCert(u8 *outbuf); +s32 ES_GetDeviceID(u32 *device_id); +s32 ES_GetBoot2Version(u32 *version); +signed_blob *ES_NextCert(const signed_blob *certs); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* defined(HW_RVL) */ + +#endif diff --git a/wii/libogc/include/ogc/exi.h b/wii/libogc/include/ogc/exi.h new file mode 100644 index 0000000000..b3f104ebd0 --- /dev/null +++ b/wii/libogc/include/ogc/exi.h @@ -0,0 +1,325 @@ +/*------------------------------------------------------------- + +exi.h -- EXI subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __EXI_H__ +#define __EXI_H__ + +/*! +\file exi.h +\brief EXI subsystem + +*/ + + +#include "gctypes.h" + +/*! + * \addtogroup exi_tx_mode EXI tranfer types + * @{ + */ + +#define EXI_READ 0 /*!< EXI transfer type read */ +#define EXI_WRITE 1 /*!< EXI transfer type write */ +#define EXI_READWRITE 2 /*!< EXI transfer type read-write */ + +/*! + * @} + */ + + +/*! + * \addtogroup exi_channels EXI channels + * @{ + */ + +#define EXI_CHANNEL_0 0 /*!< EXI channel 0 (memory card slot A) */ +#define EXI_CHANNEL_1 1 /*!< EXI channel 1 (memory card slot B) */ +#define EXI_CHANNEL_2 2 /*!< EXI channel 2 (other EXI devices connected, e.g. BBA) */ +#define EXI_CHANNEL_MAX 3 /*!< _Termination */ + +/*! + * @} + */ + + +/*! + * \addtogroup exi_devices EXI devices + * @{ + */ + +#define EXI_DEVICE_0 0 /*!< EXI device 0 */ +#define EXI_DEVICE_1 1 /*!< EXI device 1 */ +#define EXI_DEVICE_2 2 /*!< EXI device 2 */ +#define EXI_DEVICE_MAX 3 /*!< _Termination */ + +/*! + * @} + */ + + +/*! + * \addtogroup exi_speed EXI device frequencies + * @{ + */ + +#define EXI_SPEED1MHZ 0 /*!< EXI device frequency 1MHz */ +#define EXI_SPEED2MHZ 1 /*!< EXI device frequency 2MHz */ +#define EXI_SPEED4MHZ 2 /*!< EXI device frequency 4MHz */ +#define EXI_SPEED8MHZ 3 /*!< EXI device frequency 8MHz */ +#define EXI_SPEED16MHZ 4 /*!< EXI device frequency 16MHz */ +#define EXI_SPEED32MHZ 5 /*!< EXI device frequency 32MHz */ + +/*! + * @} + */ + + +/*! + * \addtogroup exi_flags EXI device operation flags + * @{ + */ + +#define EXI_FLAG_DMA 0x0001 /*!< EXI DMA mode transfer in progress */ +#define EXI_FLAG_IMM 0x0002 /*!< EXI immediate mode transfer in progress */ +#define EXI_FLAG_SELECT 0x0004 /*!< EXI channel and device selected */ +#define EXI_FLAG_ATTACH 0x0008 /*!< EXI device on selected channel and device attached */ +#define EXI_FLAG_LOCKED 0x0010 /*!< EXI channel and device locked for device operations */ + +/*! + * @} + */ + + +/*! + * \addtogroup exi_mcident EXI memory card identifier + * @{ + */ + +#define EXI_MEMCARD59 0x00000004 /*!< Nintendo memory card: 64/ 4/ 0.5 (blocks/Mbits/MB). 3rd party vendors do have the same identification */ +#define EXI_MEMCARD123 0x00000008 /*!< Nintendo memory card: 128/ 8/ 1.0 (blocks/Mbits/MB). 3rd party vendors do have the same identification */ +#define EXI_MEMCARD251 0x00000010 /*!< Nintendo memory card: 256/ 16/ 2.0 (blocks/Mbits/MB). 3rd party vendors do have the same identification */ +#define EXI_MEMCARD507 0x00000020 /*!< Nintendo memory card: 512/ 32/ 4.0 (blocks/Mbits/MB). 3rd party vendors do have the same identification */ +#define EXI_MEMCARD1019 0x00000040 /*!< Nintendo memory card: 1024/ 64/ 8.0 (blocks/Mbits/MB). 3rd party vendors do have the same identification */ +#define EXI_MEMCARD2043 0x00000080 /*!< Nintendo memory card: 2048/128/16.0 (blocks/Mbits/MB). 3rd party vendors do have the same identification */ + +/*! + * @} + */ + + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +/*! \typedef s32 (*EXICallback)(s32 chn,s32 dev) +\brief function pointer typedef for the user's EXI callback +\param chn EXI channel +\param dev EXI device +*/ +typedef s32 (*EXICallback)(s32 chn,s32 dev); + + +/*! \fn s32 EXI_ProbeEx(s32 nChn) +\brief Performs an extended probe of the EXI channel +\param[in] nChn EXI channel to probe + +\return 1 on success, <=0 on error +*/ +s32 EXI_ProbeEx(s32 nChn); + + +/*! \fn s32 EXI_Probe(s32 nChn) +\brief Probes the EXI channel +\param[in] nChn EXI channel to probe + +\return 1 on success, <=0 on error +*/ +s32 EXI_Probe(s32 nChn); + + +/*! \fn s32 EXI_Lock(s32 nChn,s32 nDev,EXICallback unlockCB) +\brief Try to lock the desired EXI channel on the given device. +\param[in] nChn EXI channel to lock +\param[in] nDev EXI device to lock +\param[in] unlockCB pointer to callback to call when EXI_Unlock() is called. Thus allowing us a small way of mutual exclusion. + +\return 1 on success, <=0 on error +*/ +s32 EXI_Lock(s32 nChn,s32 nDev,EXICallback unlockCB); + + +/*! \fn s32 EXI_Unlock(s32 nChn) +\brief Unlock the desired EXI channel. +\param[in] nChn EXI channel to unlock + +\return 1 on success, <=0 on error +*/ +s32 EXI_Unlock(s32 nChn); + + +/*! \fn s32 EXI_Select(s32 nChn,s32 nDev,s32 nFrq) +\brief Selects the spedified EXI channel on the given device with the given frequency +\param[in] nChn EXI channel to select +\param[in] nDev EXI device to select +\param[in] nFrq EXI frequency to select + +\return 1 on success, <=0 on error +*/ +s32 EXI_Select(s32 nChn,s32 nDev,s32 nFrq); + + +/*! \fn s32 EXI_SelectSD(s32 nChn,s32 nDev,s32 nFrq) +\brief Performs a special select, for SD cards or adapters respectively, on the given device with the given frequence +\param[in] nChn EXI channel to select +\param[in] nDev EXI device to select +\param[in] nFrq EXI frequency to select + +\return 1 on success, <=0 on error +*/ +s32 EXI_SelectSD(s32 nChn,s32 nDev,s32 nFrq); + + +/*! \fn s32 EXI_Deselect(s32 nChn) +\brief Deselects the EXI channel. +\param[in] nChn EXI channel to deselect + +\return 1 on success, <=0 on error +*/ +s32 EXI_Deselect(s32 nChn); + + +/*! \fn s32 EXI_Sync(s32 nChn) +\brief Synchronize or finish respectively the last EXI transfer. +\param[in] nChn EXI channel to select + +\return 1 on success, <=0 on error +*/ +s32 EXI_Sync(s32 nChn); + + +/*! \fn s32 EXI_Imm(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb) +\brief Initializes an immediate mode EXI transfer. +\param[in] nChn EXI channel to select +\param[in,out] pData pointer to a buffer to read/copy from/to data. +\param[in] nLen lenght of data to transfer <=4. +\param[in] nMode direction of transferoperation(EXI_READ,EXI_WRITE,EXI_READWRITE) +\param[in] tc_cb pointer to a callback to call when transfer has completed. May be NULL. + +\return 1 on success, <=0 on error +*/ +s32 EXI_Imm(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb); + + +/*! \fn s32 EXI_ImmEx(s32 nChn,void *pData,u32 nLen,u32 nMode) +\brief Initializes an extended immediate mode EXI transfer. +\param[in] nChn EXI channel to select +\param[in,out] pData pointer to a buffer to read/copy from/to data. +\param[in] nLen lenght of data to transfer. +\param[in] nMode direction of transferoperation(EXI_READ,EXI_WRITE,EXI_READWRITE) + +\return 1 on success, <=0 on error +*/ +s32 EXI_ImmEx(s32 nChn,void *pData,u32 nLen,u32 nMode); + + +/*! \fn s32 EXI_Dma(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb) +\brief Initializes a DMA mode EXI transfer. +\param[in] nChn EXI channel to select +\param[in,out] pData pointer to a buffer to read/copy from/to data. +\param[in] nLen lenght of data to transfer. +\param[in] nMode direction of transferoperation(EXI_READ,EXI_WRITE,EXI_READWRITE) +\param[in] tc_cb pointer to a callback to call when transfer has completed. May be NULL. + +\return 1 on success, <=0 on error +*/ +s32 EXI_Dma(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb); + + +/*! \fn s32 EXI_GetState(s32 nChn) +\brief Get the EXI state +\param[in] nChn EXI channel to select + +\return EXI channels state flag. +*/ +s32 EXI_GetState(s32 nChn); + + +/*! \fn s32 EXI_GetID(s32 nChn,s32 nDev,u32 *nId) +\brief Get the ID of the connected EXI device on the given channel +\param[in] nChn EXI channel to select +\param[in] nDev EXI device to select +\param[out] nId EXI device ID to return. + +\return 1 on success, <=0 on error +*/ +s32 EXI_GetID(s32 nChn,s32 nDev,u32 *nId); + + +/*! \fn s32 EXI_Attach(s32 nChn,EXICallback ext_cb) +\brief Attach the device on the given channel +\param[in] nChn EXI channel to select +\param[in] ext_cb pointer to callback to call when device is physically removed. + +\return 1 on success, <=0 on error +*/ +s32 EXI_Attach(s32 nChn,EXICallback ext_cb); + + +/*! \fn s32 EXI_Detach(s32 nChn) +\brief Detach the device on the given channel +\param[in] nChn EXI channel to select + +\return 1 on success, <=0 on error +*/ +s32 EXI_Detach(s32 nChn); + + +/*! \fn void EXI_ProbeReset() +\brief Resets certain internal flags and counters and performs a probe on all 3 channels. + +\return nothing +*/ +void EXI_ProbeReset(); + + +/*! \fn EXICallback EXI_RegisterEXICallback(s32 nChn,EXICallback exi_cb) +\brief Register a callback function in the EXI driver for the EXI interrupt. +\param[in] nChn EXI channel to select +\param[in] exi_cb pointer to the function which to call when EXI interrupt has triggered. + +\return old callback function pointer or NULL +*/ +EXICallback EXI_RegisterEXICallback(s32 nChn,EXICallback exi_cb); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/gu.h b/wii/libogc/include/ogc/gu.h new file mode 100644 index 0000000000..3ba8db46af --- /dev/null +++ b/wii/libogc/include/ogc/gu.h @@ -0,0 +1,499 @@ +#ifndef __GU_H__ +#define __GU_H__ + +/*! + * \file gu.h + * \brief GU/Matrix subsystem + * + * \details The GU/Matrix subsystem is used for many matrix- , vector- and quaternion-related operations. + * + * The matrix functions are coupled tightly with GX (GX will take Mtx for many of its own matrix-related functions, for example). + * This library supports 3x3, 3x4, 4x3 and 4x4 matrices. + * + * This library has functions for manipulating vectors as well; some of its functions are for transforming matrices using vectors. + * + * It also includes functions for using and converting between quaternions. Although quaternions are not used natively in libogc, + * they work well with rotation functions as they aren't susceptible to "gimbal lock". You can use the appropriate functions to + * freely convert between quaternions and matrices. + * + * \note Many of the functions come in two flavors: C and "paired single". Both perform the same exact operations, but with a key + * difference: the C versions are written in pure C and are slightly more accurate, while the PS versions are hand-written + * assembly routines utilizing the Gekko's "paired-single" extension, which is much faster for almost every operation but slightly + * less accurate. When building for the GameCube or Wii (which is probably always), the library is configured to automatically use + * the paired-single tuned versions, as the speed difference is worth the accuracy hit. If you want to use the C routine and take + * the performance hit instead, prefix the function with "c_". You are not limited to using only one or the other collection; you + * can use both in your code if you wish. + * + * \warning Some functions (notably guFrustum() and related) take a 4x4 matrix, while the rest work only on 4x3 matrices. Make sure + * you are passing the correct matrix type to each function, as passing the wrong one can create subtle bugs. + */ + +#include + +#ifdef GEKKO +#define MTX_USE_PS +#undef MTX_USE_C +#endif + +#ifndef GEKKO +#define MTX_USE_C +#undef MTX_USE_PS +#endif + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#define M_PI 3.14159265358979323846 +#define M_DTOR (3.14159265358979323846/180.0) + +#define FTOFIX32(x) (s32)((x) * (f32)0x00010000) +#define FIX32TOF(x) ((f32)(x) * (1.0f / (f32)0x00010000)) +#define FTOFRAC8(x) ((s32) MIN(((x) * (128.0f)), 127.0f) & 0xff) + +#define DegToRad(a) ( (a) * 0.01745329252f ) +#define RadToDeg(a) ( (a) * 57.29577951f ) + +/*! + * \def guMtxRowCol(mt,row,col) + * \brief Provides storage-safe access to elements of Mtx and Mtx44. + * + * \details This macro provides storage-safe access to elements of Mtx and Mtx44. Matrix storage format is transparent to the + * programmer as long as matrices are initialized and manipulated exclusively with the matrix API. Do not initialize matrices + * when they are first declared and do not set values by hand. To insulate code from changes to matrix storage format, you should + * use this macro instead of directly accessing individual matrix elements. + * + * \note When using this function, think of the matrix in row-major format. + * + * \param[in] mt Matrix to be accessed. + * \param[in] r Row index of element to access. + * \param[in] c Column index of element to access. + * + * \return none + */ +#define guMtxRowCol(mt,row,col) (mt[row][col]) + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +/*! \struct guVector + * \brief 3-element vector with x, y and z components. + * + * \details When used in 3D transformations, it is treated as a column vector with an implied fourth 'w' coordinate of 1. + * For example, to multiply a vector vOld by a matrix m: vNew = m x vOld. In code: + * + * \code guVecMultiply( m, &vOld, &vNew ); \endcode + * + * \note This is a generic structure which can be used in any situation or function that accepts an array or struct with + * three f32 values. + */ +typedef struct _vecf { + f32 x,y,z; +} guVector; + +/*! \struct guQuaternion + * \brief Quaternion type consisting of an (x,y,z) vector component and a (w) scalar component. + * + * \details This struct is used by gu library function such as guQuatMtx(), which generates a rotation matrix from a + * quaternion. + * + * \note This is a generic structure which can be used in any situation or function that accepts an array or struct with + * four f32 values. + */ +typedef struct _qrtn { + f32 x,y,z,w; +} guQuaternion; + +/*! \typedef f32 Mtx[3][4] + * \brief Standard 3x4 matrix. + * \warning Some functions take the 4x4 matrix type rather than this one, so make sure you don't mix up the two. + */ +typedef f32 Mtx[3][4]; +typedef f32 (*MtxP)[4]; + +/*! \typedef f32 ROMtx[4][3] + * \brief Column-major representation of the standard Mtx structure. + * + * \details It is not a true transpose, as it is a 4x3 matrix. These structures are only accepted by functions that explicitly + * require reordered matrices. + */ +typedef f32 ROMtx[4][3]; +typedef f32 (*ROMtxP)[3]; + +/*! \typedef f32 Mtx33[3][3] + * \brief 3x3 matrix. + */ +typedef f32 Mtx33[3][3]; +typedef f32 (*Mtx33P)[3]; + +/*! \typedef f32 Mtx44[4][4] + * \brief 4x4 matrix. + * \warning Some functions take this instead of the 3x4 matrix, so make sure you don't mix up the two. + */ +typedef f32 Mtx44[4][4]; +typedef f32 (*Mtx44P)[4]; + +/*! + * \fn void guFrustum(Mtx44 mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 f) + * \brief Sets a 4x4 perspective projection matrix from viewing volume dimensions. + * + * \details This matrix is used by the GX API to transform points to screen space. + * + * For normal perspective projection, the axis of projection is the -z axis, so \a t = positive, \a b = -\a t, \a r = + * positive, \a l = -\a r. \a n and \a f must both be given as positive distances. + * + * \note \a m negates a point's 'z' values, so pre-transformed points should have negative 'z' values in eye space in + * order to be visible after projection. + * + * \param[out] mt New projection matrix. + * \param[in] t Top edge of view volume at the near clipping plane. + * \param[in] b Bottom edge of view volume at the near clipping plane. + * \param[in] l Left edge of view volume at the near clipping plane. + * \param[in] r Right edge of view volume at the near clipping plane. + * \param[in] n Positive distance to the near clipping plane. + * \param[in] f Positive distance to the far clipping plane. + * + * \return none + */ +void guFrustum(Mtx44 mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 f); + +/*! + * \fn void guPerspective(Mtx44 mt,f32 fovy,f32 aspect,f32 n,f32 f) + * \brief Sets a 4x4 perspective projection matrix from field of view and aspect ratio parameters. + * + * \details This matrix is used by the GX API to transform points to screen space. + * + * This function generates a projection matrix equivalent to that created by guFrustum() with the axis of projection + * centered around Z. It is included to provide an alternative method of specifying view volume dimensions. + * + * The field of view (\a fovy) is the total field of view in degrees in the Y-Z plane. \a aspect is the ratio + * (width/height) of the view window in screen space. \a n and \a f must both be given as positive distances. + * + * \note \a m negates a point's 'z' values, so pre-transformed points should have negative 'z' values in eye space in order to + * be visible after projection. + * + * \param[out] mt New perspective projection matrix. + * \param[in] fovy Total field of view in the Y-Z plane measured in degrees. + * \param[in] aspect View window aspect ratio (width/height) + * \param[in] n Positive distance to near clipping plane. + * \param[in] f Positive distance to far clipping plane. + * + * \return none + */ +void guPerspective(Mtx44 mt,f32 fovy,f32 aspect,f32 n,f32 f); + +/*! + * \fn void guOrtho(Mtx44 mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 f) + * \brief Sets a 4x4 matrix for orthographic projection. + * + * \details This matrix is used by the GX API to transform points from eye space to screen space. + * + * For normal parallel projections, the axis of projection is the -z axis, so \a t = positive, \a b = -\a t, \a r = + * positive, \a l = -\a r. \a n and \a f must both be given as positive distances. + * + * \note \a m negates \a a point's 'z' values, so pre-transformed points should have negative 'z' values in eye space in order + * to be visible after projection. + * + * \param[out] mt New parallel projection matrix. + * \param[in] t Top edge of view volume. + * \param[in] b Bottom edge of view volume. + * \param[in] l Left edge of view volume. + * \param[in] r Right edge of view volume. + * \param[in] n Positive distance to the near clipping plane. + * \param[in] f Positive distance to the far clipping plane. + * + * \return none + */ +void guOrtho(Mtx44 mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 f); + + +/*! + * \fn void guLightPerspective(Mtx mt,f32 fovY,f32 aspect,f32 scaleS,f32 scaleT,f32 transS,f32 transT) + * \brief Sets a 3x4 perspective projection matrix from field of view and aspect ratio parameters, two scale values, and two + * translation values. + * + * \details This matrix is used to project points into texture space and yield texture coordinates. + * + * This function generates a projection matrix, equivalent to that created by guLightFrustum(), with the axis of projection + * centered around Z. This function is included to provide an alternative method of specifying texture projection volume + * dimensions. + * + * The field of view (\a fovy) is the total field of view in degrees in the YZ plane. \a aspect is the ratio (width / height) + * of the view window in screen space. + * + * Standard projection yields values ranging from -1.0 to 1.0 in both dimensions of the front clipping plane. Since texture + * coordinates should usually be within the range of 0.0 to 1.0, we have added a scale and translation value for both S and T. + * The most common way to use these values is to set all of them to 0.5 (so that points in the range of -1.0 to 1.0 are first + * scaled by 0.5) to be in the range of -0.5 to 0.5. Then they are translated by 0.5 to be in the range of 0.0 to 1.0. Other + * values can be used for translation and scale to yield different effects. + * + * \param[out] mt New projection matrix. + * \param[in] fovy Total field of view in the YZ plane measured in degrees. + * \param[in] aspect View window aspect ratio (width / height) + * \param[in] scaleS Scale in the S direction for projected coordinates (usually 0.5). + * \param[in] scaleT Scale in the T direction for projected coordinates (usually 0.5). + * \param[in] transS Translate in the S direction for projected coordinates (usually 0.5). + * \param[in] transT Translate in the T direction for projected coordinates (usually 0.5). + * + * \return none + */ +void guLightPerspective(Mtx mt,f32 fovY,f32 aspect,f32 scaleS,f32 scaleT,f32 transS,f32 transT); + +/*! + * \fn void guLightOrtho(Mtx mt,f32 t,f32 b,f32 l,f32 r,f32 scaleS,f32 scaleT,f32 transS,f32 transT) + * \brief Sets a 3x4 matrix for orthographic projection. + * + * \details Use this matrix to project points into texture space and yield texture coordinates. + * + * For normal parallel projections, the axis of projection is the -z axis, so \a t = positive, \a b = -\a t, \a r = positive, + * \a l = -\a r. + * + * Standard projection yields values ranging from -1.0 to 1.0 in both dimensions of the front clipping plane. Since texture + * coordinates should usually be within the range of 0.0 to 1.0, we have added a scale and translation value for both S and T. + * The most common way to use these values is to set all of them to 0.5 so that points in the range of -1.0 to 1.0 are first + * scaled by 0.5 (to be in the range of -0.5 to 0.5). Then they are translated by 0.5 to be in the range of 0.0 to 1.0. Other + * values can be used for translation and scale to yield different effects. + * + * \param[out] mt New parallel projection matrix. + * \param[in] t Top edge of view volume. + * \param[in] b Bottom edge of view volume. + * \param[in] l Left edge of view volume. + * \param[in] r Right edge of view volume. + * \param[in] scaleS Scale in the S direction for projected coordinates (usually 0.5). + * \param[in] scaleT Scale in the T direction for projected coordinates (usually 0.5). + * \param[in] transS Translate in the S direction for projected coordinates (usually 0.5). + * \param[in] transT Translate in the T direction for projected coordinates (usually 0.5). + * + * \return none + */ +void guLightOrtho(Mtx mt,f32 t,f32 b,f32 l,f32 r,f32 scaleS,f32 scaleT,f32 transS,f32 transT); + +/*! + * \fn void guLightFrustum(Mtx mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 scaleS,f32 scaleT,f32 transS,f32 transT) + * \brief Sets a 3x4 perspective projection matrix from viewing volume dimensions, two scale values, and two translation values. + * + * \details This matrix is used to project points into texture space and yield texture coordinates. + * + * For normal perspective projection, the axis of projection is the -z axis, so \a t = positive, \a b = -\a t, \a r = positive, + * \a l = -\a r. \a n must be given as a positive distance. + * + * Standard projection yields values ranging from -1.0 to 1.0 in both dimensions of the front clipping plane. Since texture + * coordinates usually should be within the range of 0.0 to 1.0, we have added a scale and translation value for both S and T. + * The most common usage of these values is to set all of them to 0.5 so that points in the range of -1.0 to 1.0 are first + * scaled by 0.5 to be in the range of -0.5 to 0.5, and are then translated by 0.5 to be in the range of 0.0 to 1.0. Other + * values can be used for translation and scale to yield different effects. + * + * \param[out] mt New projection matrix. + * \param[in] t Top edge of view volume at the near clipping plane. + * \param[in] b Bottom edge of view volume at the near clipping plane. + * \param[in] l Left edge of view volume at the near clipping plane. + * \param[in] r Right edge of view volume at the near clipping plane. + * \param[in] n Positive distance to the near clipping plane. + * \param[in] scaleS Scale in the S direction for projected coordinates (usually 0.5). + * \param[in] scaleT Scale in the T direction for projected coordinates (usually 0.5). + * \param[in] transS Translate in the S direction for projected coordinates (usually 0.5). + * \param[in] transT Translate in the T direction for projected coordinates (usually 0.5). + * + * \return none + */ +void guLightFrustum(Mtx mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 scaleS,f32 scaleT,f32 transS,f32 transT); + + +/*! + * \fn void guLookAt(Mtx mt,guVector *camPos,guVector *camUp,guVector *target) + * \brief Sets a world-space to camera-space transformation matrix. + * + * \details Create the matrix \a m by specifying a camera position (\a camPos), a camera "up" direction (\a camUp), and a target + * position (\a target). + * + * The camera's reference viewing direction is the -z axis. The camera's reference 'up' direction is the +y axis. + * + * This function is especially convenient for creating a tethered camera, aiming at an object, panning, or specifying an + * arbitrary view. + * + * \param[out] mt New viewing matrix. + * \param[in] camPos Vector giving 3D camera position in world space. + * \param[in] camUp Vector containing camera "up" vector; does not have to be a unit vector. + * \param[in] target Vector giving 3D target position in world space. + * + * \return none + */ +void guLookAt(Mtx mt,guVector *camPos,guVector *camUp,guVector *target); + + +/*! + * \fn void guVecHalfAngle(guVector *a,guVector *b,guVector *half) + * \brief Computes a vector that lies halfway between \a a and \a b. + * + * \details The halfway vector is useful in specular reflection calculations. It is interpreted as pointing from the reflecting + * surface to the general viewing direction. + * + * \a a and \a b do not have to be unit vectors. Both of these vectors are assumed to be pointing towards the surface from the + * light or viewer, respectively. Local copies of these vectors are negated, normalized and added head to tail. + * + * \a half is computed as a unit vector that points from the surface to halfway between the light and the viewing direction. + * + * \param[in] a Pointer to incident vector. Must point from the light source to the surface. + * \param[in] b Pointer to viewing vector. Must point from the viewer to the surface. + * \param[out] half Pointer to resultant half-angle unit vector; points from the surface to halfway between the light and the viewing direction. + * + * \return none + */ +void guVecHalfAngle(guVector *a,guVector *b,guVector *half); + +void c_guVecAdd(guVector *a,guVector *b,guVector *ab); +void c_guVecSub(guVector *a,guVector *b,guVector *ab); +void c_guVecScale(guVector *src,guVector *dst,f32 scale); +void c_guVecNormalize(guVector *v); +void c_guVecMultiply(Mtx mt,guVector *src,guVector *dst); +void c_guVecCross(guVector *a,guVector *b,guVector *axb); +void c_guVecMultiplySR(Mtx mt,guVector *src,guVector *dst); +f32 c_guVecDotProduct(guVector *a,guVector *b); + +#ifdef GEKKO +void ps_guVecAdd(register guVector *a,register guVector *b,register guVector *ab); +void ps_guVecSub(register guVector *a,register guVector *b,register guVector *ab); +void ps_guVecScale(register guVector *src,register guVector *dst,f32 scale); +void ps_guVecNormalize(register guVector *v); +void ps_guVecCross(register guVector *a,register guVector *b,register guVector *axb); +void ps_guVecMultiply(register Mtx mt,register guVector *src,register guVector *dst); +void ps_guVecMultiplySR(register Mtx mt,register guVector *src,register guVector *dst); +f32 ps_guVecDotProduct(register guVector *a,register guVector *b); +#endif //GEKKO + +void c_guQuatAdd(guQuaternion *a,guQuaternion *b,guQuaternion *ab); +void c_guQuatSub(guQuaternion *a,guQuaternion *b,guQuaternion *ab); +void c_guQuatMultiply(guQuaternion *a,guQuaternion *b,guQuaternion *ab); +void c_guQuatNormalize(guQuaternion *a,guQuaternion *d); +void c_guQuatInverse(guQuaternion *a,guQuaternion *d); +void c_guQuatMtx(guQuaternion *a,Mtx m); + +#ifdef GEKKO +void ps_guQuatAdd(register guQuaternion *a,register guQuaternion *b,register guQuaternion *ab); +void ps_guQuatSub(register guQuaternion *a,register guQuaternion *b,register guQuaternion *ab); +void ps_guQuatMultiply(register guQuaternion *a,register guQuaternion *b,register guQuaternion *ab); +void ps_guQuatNormalize(register guQuaternion *a,register guQuaternion *d); +void ps_guQuatInverse(register guQuaternion *a,register guQuaternion *d); +#endif + +void c_guMtxIdentity(Mtx mt); +void c_guMtxCopy(Mtx src,Mtx dst); +void c_guMtxConcat(Mtx a,Mtx b,Mtx ab); +void c_guMtxScale(Mtx mt,f32 xS,f32 yS,f32 zS); +void c_guMtxScaleApply(Mtx src,Mtx dst,f32 xS,f32 yS,f32 zS); +void c_guMtxApplyScale(Mtx src,Mtx dst,f32 xS,f32 yS,f32 zS); +void c_guMtxTrans(Mtx mt,f32 xT,f32 yT,f32 zT); +void c_guMtxTransApply(Mtx src,Mtx dst,f32 xT,f32 yT,f32 zT); +void c_guMtxApplyTrans(Mtx src,Mtx dst,f32 xT,f32 yT,f32 zT); +u32 c_guMtxInverse(Mtx src,Mtx inv); +u32 c_guMtxInvXpose(Mtx src,Mtx xPose); +void c_guMtxTranspose(Mtx src,Mtx xPose); +void c_guMtxRotRad(Mtx mt,const char axis,f32 rad); +void c_guMtxRotTrig(Mtx mt,const char axis,f32 sinA,f32 cosA); +void c_guMtxRotAxisRad(Mtx mt,guVector *axis,f32 rad); +void c_guMtxReflect(Mtx m,guVector *p,guVector *n); +void c_guMtxQuat(Mtx m,guQuaternion *a); + +#ifdef GEKKO +void ps_guMtxIdentity(register Mtx mt); +void ps_guMtxCopy(register Mtx src,register Mtx dst); +void ps_guMtxConcat(register Mtx a,register Mtx b,register Mtx ab); +void ps_guMtxTranspose(register Mtx src,register Mtx xPose); +u32 ps_guMtxInverse(register Mtx src,register Mtx inv); +u32 ps_guMtxInvXpose(register Mtx src,register Mtx xPose); +void ps_guMtxScale(register Mtx mt,register f32 xS,register f32 yS,register f32 zS); +void ps_guMtxScaleApply(register Mtx src,register Mtx dst,register f32 xS,register f32 yS,register f32 zS); +void ps_guMtxApplyScale(register Mtx src,register Mtx dst,register f32 xS,register f32 yS,register f32 zS); +void ps_guMtxTrans(register Mtx mt,register f32 xT,register f32 yT,register f32 zT); +void ps_guMtxTransApply(register Mtx src,register Mtx dst,register f32 xT,register f32 yT,register f32 zT); +void ps_guMtxApplyTrans(register Mtx src,register Mtx dst,register f32 xT,register f32 yT,register f32 zT); +void ps_guMtxRotRad(register Mtx mt,register const char axis,register f32 rad); +void ps_guMtxRotTrig(register Mtx mt,register const char axis,register f32 sinA,register f32 cosA); +void ps_guMtxRotAxisRad(register Mtx mt,register guVector *axis,register f32 tmp0); +void ps_guMtxReflect(register Mtx m,register guVector *p,register guVector *n); +#endif //GEKKO + +#ifdef MTX_USE_C + +#define guVecAdd c_guVecAdd +#define guVecSub c_guVecSub +#define guVecScale c_guVecScale +#define guVecNormalize c_guVecNormalize +#define guVecMultiply c_guVecMultiply +#define guVecCross c_guVecCross +#define guVecMultiplySR c_guVecMultiplySR +#define guVecDotProduct c_guVecDotProduct + +#define guQuatAdd c_guQuatAdd +#define guQuatSub c_guQuatSub +#define guQuatMultiply c_guQuatMultiply +#define guQuatNoramlize c_guQuatNormalize +#define guQuatInverse c_guQuatInverse +#define guQuatMtx c_guQuatMtx + +#define guMtxIdentity c_guMtxIdentity +#define guMtxCopy c_guMtxCopy +#define guMtxConcat c_guMtxConcat +#define guMtxScale c_guMtxScale +#define guMtxScaleApply c_guMtxScaleApply +#define guMtxApplyScale c_guMtxApplyScale +#define guMtxTrans c_guMtxTrans +#define guMtxTransApply c_guMtxTransApply +#define guMtxApplyTrans c_guMtxApplyTrans +#define guMtxInverse c_guMtxInverse +#define guMtxTranspose c_guMtxTranspose +#define guMtxInvXpose c_guMtxInvXpose +#define guMtxRotRad c_guMtxRotRad +#define guMtxRotTrig c_guMtxRotTrig +#define guMtxRotAxisRad c_guMtxRotAxisRad +#define guMtxReflect c_guMtxReflect +#define guMtxQuat c_guMtxQuat + +#else //MTX_USE_C + +#define guVecAdd ps_guVecAdd +#define guVecSub ps_guVecSub +#define guVecScale ps_guVecScale +#define guVecNormalize ps_guVecNormalize +#define guVecMultiply ps_guVecMultiply +#define guVecCross ps_guVecCross +#define guVecMultiplySR ps_guVecMultiplySR +#define guVecDotProduct ps_guVecDotProduct + +#define guQuatAdd ps_guQuatAdd +#define guQuatSub ps_guQuatSub +#define guQuatMultiply ps_guQuatMultiply +#define guQuatNormalize ps_guQuatNormalize +#define guQuatInverse ps_guQuatInverse + +#define guMtxIdentity ps_guMtxIdentity +#define guMtxCopy ps_guMtxCopy +#define guMtxConcat ps_guMtxConcat +#define guMtxScale ps_guMtxScale +#define guMtxScaleApply ps_guMtxScaleApply +#define guMtxApplyScale ps_guMtxApplyScale +#define guMtxTrans ps_guMtxTrans +#define guMtxTransApply ps_guMtxTransApply +#define guMtxApplyTrans ps_guMtxApplyTrans +#define guMtxInverse ps_guMtxInverse +#define guMtxTranspose ps_guMtxTranspose +#define guMtxInvXpose ps_guMtxInvXpose +#define guMtxRotRad ps_guMtxRotRad +#define guMtxRotTrig ps_guMtxRotTrig +#define guMtxRotAxisRad ps_guMtxRotAxisRad +#define guMtxReflect ps_guMtxReflect + +#endif //MTX_USE_PS + +#define guMtxRotDeg(mt,axis,deg) guMtxRotRad(mt,axis,DegToRad(deg)) +#define guMtxRotAxisDeg(mt,axis,deg) guMtxRotAxisRad(mt,axis,DegToRad(deg)) + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/gx.h b/wii/libogc/include/ogc/gx.h new file mode 100644 index 0000000000..b58d35f69c --- /dev/null +++ b/wii/libogc/include/ogc/gx.h @@ -0,0 +1,5256 @@ +#ifndef __GX_H__ +#define __GX_H__ + +/*! + * \file gx.h + * \brief GX subsystem + * + */ + +#include +#include "lwp.h" +#include "gx_struct.h" +#include "gu.h" + +#define GX_FALSE 0 +#define GX_TRUE 1 +#define GX_DISABLE 0 +#define GX_ENABLE 1 + +/*! \addtogroup clipmode Clipping mode + * @{ + */ +#define GX_CLIP_DISABLE 1 +#define GX_CLIP_ENABLE 0 +/*! @} */ + +#define GX_FIFO_MINSIZE (64*1024) /*!< Smallest usable graphics FIFO size. */ +#define GX_FIFO_HIWATERMARK (16*1024) /*!< Default hi watermark for FIFO buffer control. */ +#define GX_FIFO_OBJSIZE 128 + +#define GX_PERSPECTIVE 0 +#define GX_ORTHOGRAPHIC 1 + +#define GX_MT_NULL 0 +#define GX_MT_XF_FLUSH 1 +#define GX_MT_DL_SAVE_CTX 2 + +#define GX_XF_FLUSH_NONE 0 +#define GX_XF_FLUSH_SAFE 1 + +/*! \addtogroup channelid Color channel ID + * @{ + */ +#define GX_COLOR0 0 +#define GX_COLOR1 1 +#define GX_ALPHA0 2 +#define GX_ALPHA1 3 +#define GX_COLOR0A0 4 +#define GX_COLOR1A1 5 +#define GX_COLORZERO 6 +#define GX_ALPHA_BUMP 7 +#define GX_ALPHA_BUMPN 8 +#define GX_COLORNULL 0xff +/*! @} */ + +/*! \addtogroup mtxtype Matrix type + * @{ + */ +#define GX_MTX2x4 0 +#define GX_MTX3x4 1 +/*! @} */ + +/*! \addtogroup vtxfmt Vertex format index + * @{ + */ +#define GX_VTXFMT0 0 +#define GX_VTXFMT1 1 +#define GX_VTXFMT2 2 +#define GX_VTXFMT3 3 +#define GX_VTXFMT4 4 +#define GX_VTXFMT5 5 +#define GX_VTXFMT6 6 +#define GX_VTXFMT7 7 +#define GX_MAXVTXFMT 8 + +/*! @} */ + + +/*! \addtogroup vtxattrin Vertex data input type + * @{ + */ +#define GX_NONE 0 /*!< Input data is not used */ +#define GX_DIRECT 1 /*!< Input data is set direct */ +#define GX_INDEX8 2 /*!< Input data is set by a 8bit index */ +#define GX_INDEX16 3 /*!< Input data is set by a 16bit index */ + +/*! @} */ + + +/*! \addtogroup compsize Number of components in an attribute + * @{ + */ +#define GX_U8 0 /*!< Unsigned 8-bit integer */ +#define GX_S8 1 /*!< Signed 8-bit integer */ +#define GX_U16 2 /*!< Unsigned 16-bit integer */ +#define GX_S16 3 /*!< Signed 16-bit integer */ +#define GX_F32 4 /*!< 32-bit floating-point */ +#define GX_RGB565 0 /*!< 16-bit RGB */ +#define GX_RGB8 1 /*!< 24-bit RGB */ +#define GX_RGBX8 2 /*!< 32-bit RGBX */ +#define GX_RGBA4 3 /*!< 16-bit RGBA */ +#define GX_RGBA6 4 /*!< 24-bit RGBA */ +#define GX_RGBA8 5 /*!< 32-bit RGBA */ +/*! @} */ + +/*! \addtogroup comptype Attribute component type + * @{ + */ +#define GX_POS_XY 0 /*!< X,Y position */ +#define GX_POS_XYZ 1 /*!< X,Y,Z position */ +#define GX_NRM_XYZ 0 /*!< X,Y,Z normal */ +#define GX_NRM_NBT 1 +#define GX_NRM_NBT3 2 +#define GX_CLR_RGB 0 /*!< RGB color */ +#define GX_CLR_RGBA 1 /*!< RGBA color */ +#define GX_TEX_S 0 /*!< One texture dimension */ +#define GX_TEX_ST 1 /*!< Two texture dimensions */ +/*! @} */ + +/*! \addtogroup vtxattr Vertex attribute array type + * @{ + */ +#define GX_VA_PTNMTXIDX 0 +#define GX_VA_TEX0MTXIDX 1 +#define GX_VA_TEX1MTXIDX 2 +#define GX_VA_TEX2MTXIDX 3 +#define GX_VA_TEX3MTXIDX 4 +#define GX_VA_TEX4MTXIDX 5 +#define GX_VA_TEX5MTXIDX 6 +#define GX_VA_TEX6MTXIDX 7 +#define GX_VA_TEX7MTXIDX 8 +#define GX_VA_POS 9 +#define GX_VA_NRM 10 +#define GX_VA_CLR0 11 +#define GX_VA_CLR1 12 +#define GX_VA_TEX0 13 +#define GX_VA_TEX1 14 +#define GX_VA_TEX2 15 +#define GX_VA_TEX3 16 +#define GX_VA_TEX4 17 +#define GX_VA_TEX5 18 +#define GX_VA_TEX6 19 +#define GX_VA_TEX7 20 +#define GX_POSMTXARRAY 21 +#define GX_NRMMTXARRAY 22 +#define GX_TEXMTXARRAY 23 +#define GX_LIGHTARRAY 24 +#define GX_VA_NBT 25 +#define GX_VA_MAXATTR 26 +#define GX_VA_NULL 0xff +/*! @} */ + +/*! \addtogroup primtype Primitive type + * \brief Collection of primitive types that can be drawn by the GP. + * + * \note Which type you use depends on your needs; however, performance can increase by using triangle strips or fans instead of discrete triangles. + * @{ + */ +#define GX_POINTS 0xB8 /*!< Draws a series of points. Each vertex is a single point. */ +#define GX_LINES 0xA8 /*!< Draws a series of unconnected line segments. Each pair of vertices makes a line. */ +#define GX_LINESTRIP 0xB0 /*!< Draws a series of lines. Each vertex (besides the first) makes a line between it and the previous. */ +#define GX_TRIANGLES 0x90 /*!< Draws a series of unconnected triangles. Three vertices make a single triangle. */ +#define GX_TRIANGLESTRIP 0x98 /*!< Draws a series of triangles. Each triangle (besides the first) shares a side with the previous triangle. + * Each vertex (besides the first two) completes a triangle. */ +#define GX_TRIANGLEFAN 0xA0 /*!< Draws a single triangle fan. The first vertex is the "centerpoint". The second and third vertex complete + * the first triangle. Each subsequent vertex completes another triangle which shares a side with the previous + * triangle (except the first triangle) and has the centerpoint vertex as one of the vertices. */ +#define GX_QUADS 0x80 /*!< Draws a series of unconnected quads. Every four vertices completes a quad. Internally, each quad is + * translated into a pair of triangles. */ +/*! @} */ + +#define GX_SRC_REG 0 +#define GX_SRC_VTX 1 + +/*! \addtogroup lightid Light ID + * @{ + */ +#define GX_LIGHT0 0x001 /*!< Light 0 */ +#define GX_LIGHT1 0x002 /*!< Light 2 */ +#define GX_LIGHT2 0x004 /*!< Light 3 */ +#define GX_LIGHT3 0x008 /*!< Light 4 */ +#define GX_LIGHT4 0x010 /*!< Light 5 */ +#define GX_LIGHT5 0x020 /*!< Light 6 */ +#define GX_LIGHT6 0x040 /*!< Light 7 */ +#define GX_LIGHT7 0x080 /*!< Light 8 */ +#define GX_MAXLIGHT 0x100 /*!< All lights */ +#define GX_LIGHTNULL 0x000 /*!< No lights */ +/*! @} */ + +/*! \addtogroup difffn Diffuse function + * @{ + */ +#define GX_DF_NONE 0 +#define GX_DF_SIGNED 1 +#define GX_DF_CLAMP 2 +/*! @} */ + +/*! \addtogroup attenfunc Attenuation function + * @{ + */ +#define GX_AF_SPEC 0 /*!< Specular computation */ +#define GX_AF_SPOT 1 /*!< Spot light attenuation */ +#define GX_AF_NONE 2 /*!< No attenuation */ +/*! @} */ + +/* pos,nrm,tex,dtt matrix */ +/*! \addtogroup pnmtx Position-normal matrix index + * @{ + */ +#define GX_PNMTX0 0 +#define GX_PNMTX1 3 +#define GX_PNMTX2 6 +#define GX_PNMTX3 9 +#define GX_PNMTX4 12 +#define GX_PNMTX5 15 +#define GX_PNMTX6 18 +#define GX_PNMTX7 21 +#define GX_PNMTX8 24 +#define GX_PNMTX9 27 +/*! @} */ + +/*! \addtogroup texmtx Texture matrix index + * @{ + */ +#define GX_TEXMTX0 30 +#define GX_TEXMTX1 33 +#define GX_TEXMTX2 36 +#define GX_TEXMTX3 39 +#define GX_TEXMTX4 42 +#define GX_TEXMTX5 45 +#define GX_TEXMTX6 48 +#define GX_TEXMTX7 51 +#define GX_TEXMTX8 54 +#define GX_TEXMTX9 57 +#define GX_IDENTITY 60 +/*! @} */ + +/*! \addtogroup dttmtx Post-transform texture matrix index + * @{ + */ +#define GX_DTTMTX0 64 +#define GX_DTTMTX1 67 +#define GX_DTTMTX2 70 +#define GX_DTTMTX3 73 +#define GX_DTTMTX4 76 +#define GX_DTTMTX5 79 +#define GX_DTTMTX6 82 +#define GX_DTTMTX7 85 +#define GX_DTTMTX8 88 +#define GX_DTTMTX9 91 +#define GX_DTTMTX10 94 +#define GX_DTTMTX11 97 +#define GX_DTTMTX12 100 +#define GX_DTTMTX13 103 +#define GX_DTTMTX14 106 +#define GX_DTTMTX15 109 +#define GX_DTTMTX16 112 +#define GX_DTTMTX17 115 +#define GX_DTTMTX18 118 +#define GX_DTTMTX19 121 +#define GX_DTTIDENTITY 125 +/*! @} */ + +/* tex coord id + used by: XF: 0x1040,0x1050 + BP: 0x30 +*/ +/*! \addtogroup texcoordid texture coordinate slot + * @{ + */ +#define GX_TEXCOORD0 0x0 +#define GX_TEXCOORD1 0x1 +#define GX_TEXCOORD2 0x2 +#define GX_TEXCOORD3 0x3 +#define GX_TEXCOORD4 0x4 +#define GX_TEXCOORD5 0x5 +#define GX_TEXCOORD6 0x6 +#define GX_TEXCOORD7 0x7 +#define GX_MAXCOORD 0x8 +#define GX_TEXCOORDNULL 0xff +/*! @} */ + +/* tex format */ +#define _GX_TF_ZTF 0x10 +#define _GX_TF_CTF 0x20 + +/*! \addtogroup texfmt Texture format + * @{ + */ + +#define GX_TF_I4 0x0 +#define GX_TF_I8 0x1 +#define GX_TF_IA4 0x2 +#define GX_TF_IA8 0x3 +#define GX_TF_RGB565 0x4 +#define GX_TF_RGB5A3 0x5 +#define GX_TF_RGBA8 0x6 +#define GX_TF_CI4 0x8 +#define GX_TF_CI8 0x9 +#define GX_TF_CI14 0xa +#define GX_TF_CMPR 0xE /*!< Compressed */ + +#define GX_TL_IA8 0x00 +#define GX_TL_RGB565 0x01 +#define GX_TL_RGB5A3 0x02 + +#define GX_CTF_R4 (0x0|_GX_TF_CTF) /*!< For copying 4 bits from red */ +#define GX_CTF_RA4 (0x2|_GX_TF_CTF) /*!< For copying 4 bits from red, 4 bits from alpha */ +#define GX_CTF_RA8 (0x3|_GX_TF_CTF) /*!< For copying 8 bits from red, 8 bits from alpha */ +#define GX_CTF_YUVA8 (0x6|_GX_TF_CTF) +#define GX_CTF_A8 (0x7|_GX_TF_CTF) /*!< For copying 8 bits from alpha */ +#define GX_CTF_R8 (0x8|_GX_TF_CTF) /*!< For copying 8 bits from red */ +#define GX_CTF_G8 (0x9|_GX_TF_CTF) /*!< For copying 8 bits from green */ +#define GX_CTF_B8 (0xA|_GX_TF_CTF) /*!< For copying 8 bits from blue */ +#define GX_CTF_RG8 (0xB|_GX_TF_CTF) /*!< For copying 8 bits from red, 8 bits from green */ +#define GX_CTF_GB8 (0xC|_GX_TF_CTF) /*!< For copying 8 bits from green, 8 bits from blue */ + +/*! \addtogroup ztexfmt Z Texture format + * @{ + */ + +#define GX_TF_Z8 (0x1|_GX_TF_ZTF) /*!< For texture copy, specifies upper 8 bits of Z */ +#define GX_TF_Z16 (0x3|_GX_TF_ZTF) /*!< For texture copy, specifies upper 16 bits of Z */ +#define GX_TF_Z24X8 (0x6|_GX_TF_ZTF) /*!< For texture copy, copies 24 Z bits and 0xFF */ + +/*! @} */ + +#define GX_CTF_Z4 (0x0|_GX_TF_ZTF|_GX_TF_CTF) /*!< For copying 4 upper bits from Z */ +#define GX_CTF_Z8M (0x9|_GX_TF_ZTF|_GX_TF_CTF) /*!< For copying the middle 8 bits of Z */ +#define GX_CTF_Z8L (0xA|_GX_TF_ZTF|_GX_TF_CTF) /*!< For copying the lower 8 bits of Z */ +#define GX_CTF_Z16L (0xC|_GX_TF_ZTF|_GX_TF_CTF) /*!< For copying the lower 16 bits of Z */ + +#define GX_TF_A8 GX_CTF_A8 + +/*! @} */ + +/* gx tlut size */ +#define GX_TLUT_16 1 // number of 16 entry blocks. +#define GX_TLUT_32 2 +#define GX_TLUT_64 4 +#define GX_TLUT_128 8 +#define GX_TLUT_256 16 +#define GX_TLUT_512 32 +#define GX_TLUT_1K 64 +#define GX_TLUT_2K 128 +#define GX_TLUT_4K 256 +#define GX_TLUT_8K 512 +#define GX_TLUT_16K 1024 + +/*! \addtogroup ztexop Z Texture operator + * @{ + */ + +#define GX_ZT_DISABLE 0 +#define GX_ZT_ADD 1 /*!< Add a Z texel to reference Z */ +#define GX_ZT_REPLACE 2 /*!< Replace reference Z with Z texel */ +#define GX_MAX_ZTEXOP 3 + +/*! @} */ + + +/*! \addtogroup texgentyp Texture coordinate generation type + * @{ + */ +#define GX_TG_MTX3x4 0 /*!< 2x4 matrix multiply on the input attribute and generate S,T texture coordinates. */ +#define GX_TG_MTX2x4 1 /*!< 3x4 matrix multiply on the input attribute and generate S,T,Q coordinates; S,T are then divided + * by Q to produce the actual 2D texture coordinates. */ +#define GX_TG_BUMP0 2 /*!< Use light 0 in the bump map calculation. */ +#define GX_TG_BUMP1 3 /*!< Use light 1 in the bump map calculation. */ +#define GX_TG_BUMP2 4 /*!< Use light 2 in the bump map calculation. */ +#define GX_TG_BUMP3 5 /*!< Use light 3 in the bump map calculation. */ +#define GX_TG_BUMP4 6 /*!< Use light 4 in the bump map calculation. */ +#define GX_TG_BUMP5 7 /*!< Use light 5 in the bump map calculation. */ +#define GX_TG_BUMP6 8 /*!< Use light 6 in the bump map calculation. */ +#define GX_TG_BUMP7 9 /*!< Use light 7 in the bump map calculation. */ +#define GX_TG_SRTG 10 /*!< Coordinates generated from vertex lighting results; one of the color channel results is converted + * into texture coordinates. */ +/*! @} */ + +/*! \addtogroup texgensrc Texture coordinate source + * @{ + */ +#define GX_TG_POS 0 +#define GX_TG_NRM 1 +#define GX_TG_BINRM 2 +#define GX_TG_TANGENT 3 +#define GX_TG_TEX0 4 +#define GX_TG_TEX1 5 +#define GX_TG_TEX2 6 +#define GX_TG_TEX3 7 +#define GX_TG_TEX4 8 +#define GX_TG_TEX5 9 +#define GX_TG_TEX6 10 +#define GX_TG_TEX7 11 +#define GX_TG_TEXCOORD0 12 +#define GX_TG_TEXCOORD1 13 +#define GX_TG_TEXCOORD2 14 +#define GX_TG_TEXCOORD3 15 +#define GX_TG_TEXCOORD4 16 +#define GX_TG_TEXCOORD5 17 +#define GX_TG_TEXCOORD6 18 +#define GX_TG_COLOR0 19 +#define GX_TG_COLOR1 20 +/*! @} */ + +/*! \addtogroup compare Compare type + * @{ + */ +#define GX_NEVER 0 +#define GX_LESS 1 +#define GX_EQUAL 2 +#define GX_LEQUAL 3 +#define GX_GREATER 4 +#define GX_NEQUAL 5 +#define GX_GEQUAL 6 +#define GX_ALWAYS 7 +/*! @} */ + +/* Text Wrap Mode */ +#define GX_CLAMP 0 +#define GX_REPEAT 1 +#define GX_MIRROR 2 +#define GX_MAXTEXWRAPMODE 3 + +/*! \addtogroup blendmode Blending type + * @{ + */ +#define GX_BM_NONE 0 /*!< Write input directly to EFB */ +#define GX_BM_BLEND 1 /*!< Blend using blending equation */ +#define GX_BM_LOGIC 2 /*!< Blend using bitwise operation */ +#define GX_BM_SUBTRACT 3 /*!< Input subtracts from existing pixel */ +#define GX_MAX_BLENDMODE 4 +/*! @} */ + +/*! \addtogroup blendfactor Blending control + * \details Each pixel (source or destination) is multiplied by any of these controls. + * @{ + */ +#define GX_BL_ZERO 0 /*!< 0.0 */ +#define GX_BL_ONE 1 /*!< 1.0 */ +#define GX_BL_SRCCLR 2 /*!< source color */ +#define GX_BL_INVSRCCLR 3 /*!< 1.0 - (source color) */ +#define GX_BL_SRCALPHA 4 /*!< source alpha */ +#define GX_BL_INVSRCALPHA 5 /*!< 1.0 - (source alpha) */ +#define GX_BL_DSTALPHA 6 /*!< framebuffer alpha */ +#define GX_BL_INVDSTALPHA 7 /*!< 1.0 - (FB alpha) */ +#define GX_BL_DSTCLR GX_BL_SRCCLR +#define GX_BL_INVDSTCLR GX_BL_INVSRCCLR +/*! @} */ + +/*! \addtogroup logicop Logical operation type + * \details Destination (dst) acquires the value of one of these operations, given in C syntax. + * @{ + */ +#define GX_LO_CLEAR 0 /*!< 0 */ +#define GX_LO_AND 1 /*!< src & dst */ +#define GX_LO_REVAND 2 /*!< src & ~dst */ +#define GX_LO_COPY 3 /*!< src */ +#define GX_LO_INVAND 4 /*!< ~src & dst */ +#define GX_LO_NOOP 5 /*!< dst */ +#define GX_LO_XOR 6 /*!< src ^ dst */ +#define GX_LO_OR 7 /*!< src | dst */ +#define GX_LO_NOR 8 /*!< ~(src | dst) */ +#define GX_LO_EQUIV 9 /*!< ~(src ^ dst) */ +#define GX_LO_INV 10 /*!< ~dst */ +#define GX_LO_REVOR 11 /*!< src | ~dst */ +#define GX_LO_INVCOPY 12 /*!< ~src */ +#define GX_LO_INVOR 13 /*!< ~src | dst */ +#define GX_LO_NAND 14 /*!< ~(src & dst) */ +#define GX_LO_SET 15 /*!< 1 */ +/*! @} */ + +/*! \addtogroup texoff Texture offset value + * \brief Used for texturing points or lines. + * @{ + */ +#define GX_TO_ZERO 0 +#define GX_TO_SIXTEENTH 1 +#define GX_TO_EIGHTH 2 +#define GX_TO_FOURTH 3 +#define GX_TO_HALF 4 +#define GX_TO_ONE 5 +#define GX_MAX_TEXOFFSET 6 +/*! @} */ + +/*! \addtogroup tevdefmode TEV combiner operation + * \brief Color/Alpha combiner modes for GX_SetTevOp(). + * + * \details For these equations, Cv is the output color for the stage, Cr is the output color of previous stage, and Ct is the texture color. Av is the output + * alpha for a stage, Ar is the output alpha of previous stage, and At is the texture alpha. As a special case, rasterized color + * (GX_CC_RASC) is used as Cr and rasterized alpha (GX_CA_RASA) is used as Ar at the first TEV stage because there is no previous stage. + * + * @{ + */ + +#define GX_MODULATE 0 /*!< Cv=CrCt; Av=ArAt */ +#define GX_DECAL 1 /*!< Cv=(1-At)Cr + AtCt; Av=Ar */ +#define GX_BLEND 2 /*!< Cv=(1-Ct)Cr + Ct; Av=AtAr */ +#define GX_REPLACE 3 /*!< Cv=Ct; Ar=At */ +#define GX_PASSCLR 4 /*!< Cv=Cr; Av=Ar */ + +/*! @} */ + + +/*! \addtogroup tevcolorarg TEV color combiner input + * @{ + */ + +#define GX_CC_CPREV 0 /*!< Use the color value from previous TEV stage */ +#define GX_CC_APREV 1 /*!< Use the alpha value from previous TEV stage */ +#define GX_CC_C0 2 /*!< Use the color value from the color/output register 0 */ +#define GX_CC_A0 3 /*!< Use the alpha value from the color/output register 0 */ +#define GX_CC_C1 4 /*!< Use the color value from the color/output register 1 */ +#define GX_CC_A1 5 /*!< Use the alpha value from the color/output register 1 */ +#define GX_CC_C2 6 /*!< Use the color value from the color/output register 2 */ +#define GX_CC_A2 7 /*!< Use the alpha value from the color/output register 2 */ +#define GX_CC_TEXC 8 /*!< Use the color value from texture */ +#define GX_CC_TEXA 9 /*!< Use the alpha value from texture */ +#define GX_CC_RASC 10 /*!< Use the color value from rasterizer */ +#define GX_CC_RASA 11 /*!< Use the alpha value from rasterizer */ +#define GX_CC_ONE 12 +#define GX_CC_HALF 13 +#define GX_CC_KONST 14 +#define GX_CC_ZERO 15 /*!< Use to pass zero value */ + +/*! @} */ + + +/*! \addtogroup tevalphaarg TEV alpha combiner input + * @{ + */ + +#define GX_CA_APREV 0 /*!< Use the alpha value from previous TEV stage */ +#define GX_CA_A0 1 /*!< Use the alpha value from the color/output register 0 */ +#define GX_CA_A1 2 /*!< Use the alpha value from the color/output register 1 */ +#define GX_CA_A2 3 /*!< Use the alpha value from the color/output register 2 */ +#define GX_CA_TEXA 4 /*!< Use the alpha value from texture */ +#define GX_CA_RASA 5 /*!< Use the alpha value from rasterizer */ +#define GX_CA_KONST 6 +#define GX_CA_ZERO 7 /*!< Use to pass zero value */ + +/*! @} */ + + +/*! \addtogroup tevstage TEV stage + * \details The GameCube's Graphics Processor (GP) can use up to 16 stages to compute a texel for a particular surface. + * By default, each texture will use two stages, but it can be configured through various functions calls. + * + * \note This is different from \ref texmapid s, where textures are loaded into. + * @{ + */ + +#define GX_TEVSTAGE0 0 +#define GX_TEVSTAGE1 1 +#define GX_TEVSTAGE2 2 +#define GX_TEVSTAGE3 3 +#define GX_TEVSTAGE4 4 +#define GX_TEVSTAGE5 5 +#define GX_TEVSTAGE6 6 +#define GX_TEVSTAGE7 7 +#define GX_TEVSTAGE8 8 +#define GX_TEVSTAGE9 9 +#define GX_TEVSTAGE10 10 +#define GX_TEVSTAGE11 11 +#define GX_TEVSTAGE12 12 +#define GX_TEVSTAGE13 13 +#define GX_TEVSTAGE14 14 +#define GX_TEVSTAGE15 15 +#define GX_MAX_TEVSTAGE 16 + +/*! @} */ + + +/*! \addtogroup tevop TEV combiner operator + * @{ + */ + +#define GX_TEV_ADD 0 +#define GX_TEV_SUB 1 +#define GX_TEV_COMP_R8_GT 8 +#define GX_TEV_COMP_R8_EQ 9 +#define GX_TEV_COMP_GR16_GT 10 +#define GX_TEV_COMP_GR16_EQ 11 +#define GX_TEV_COMP_BGR24_GT 12 +#define GX_TEV_COMP_BGR24_EQ 13 +#define GX_TEV_COMP_RGB8_GT 14 +#define GX_TEV_COMP_RGB8_EQ 15 +#define GX_TEV_COMP_A8_GT GX_TEV_COMP_RGB8_GT // for alpha channel +#define GX_TEV_COMP_A8_EQ GX_TEV_COMP_RGB8_EQ // for alpha channel + +/*! @} */ + + +/*! \addtogroup tevbias TEV bias value + * @{ + */ + +#define GX_TB_ZERO 0 +#define GX_TB_ADDHALF 1 +#define GX_TB_SUBHALF 2 +#define GX_MAX_TEVBIAS 3 + +/*! @} */ + + +/*! \addtogroup tevclampmode TEV clamping mode + * \note These modes are used for a function which is not implementable on production (i.e. retail) GameCube hardware. + * @{ + */ + +#define GX_TC_LINEAR 0 +#define GX_TC_GE 1 +#define GX_TC_EQ 2 +#define GX_TC_LE 3 +#define GX_MAX_TEVCLAMPMODE 4 + +/*! @} */ + + +/*! \addtogroup tevscale TEV scale value + * @{ + */ + +#define GX_CS_SCALE_1 0 +#define GX_CS_SCALE_2 1 +#define GX_CS_SCALE_4 2 +#define GX_CS_DIVIDE_2 3 +#define GX_MAX_TEVSCALE 4 + +/*! @} */ + + +/*! \addtogroup tevcoloutreg TEV color/output register + * @{ + */ + +#define GX_TEVPREV 0 /*!< Default register for passing results from one stage to another. */ +#define GX_TEVREG0 1 +#define GX_TEVREG1 2 +#define GX_TEVREG2 3 +#define GX_MAX_TEVREG 4 + +/*! @} */ + + +/*! \addtogroup cullmode Backface culling mode + * @{ + */ +#define GX_CULL_NONE 0 /*!< Do not cull any primitives. */ +#define GX_CULL_FRONT 1 /*!< Cull front-facing primitives. */ +#define GX_CULL_BACK 2 /*!< Cull back-facing primitives. */ +#define GX_CULL_ALL 3 /*!< Cull all primitives. */ +/*! @} */ + +/*! \addtogroup texmapid texture map slot + * \brief Texture map slots to hold textures in. + * + * \details The GameCube's Graphics Processor (GP) can apply up to eight textures to a single surface. Those textures + * are assigned one of these slots. Various operations used on or with a particular texture will also take one of these + * items, including operations regarding texture coordinate generation (although not necessarily on the same slot). + * + * \note This is different from \ref tevstage s, which are the actual quanta for work with textures. + * @{ + */ +#define GX_TEXMAP0 0 /*!< Texture map slot 0 */ +#define GX_TEXMAP1 1 /*!< Texture map slot 1 */ +#define GX_TEXMAP2 2 /*!< Texture map slot 2 */ +#define GX_TEXMAP3 3 /*!< Texture map slot 3 */ +#define GX_TEXMAP4 4 /*!< Texture map slot 4 */ +#define GX_TEXMAP5 5 /*!< Texture map slot 5 */ +#define GX_TEXMAP6 6 /*!< Texture map slot 6 */ +#define GX_TEXMAP7 7 /*!< Texture map slot 7 */ +#define GX_MAX_TEXMAP 8 +#define GX_TEXMAP_NULL 0xff /*!< No texmap */ +#define GX_TEXMAP_DISABLE 0x100 /*!< Disable texmap lookup for this texmap slot (use bitwise OR with a texture map slot). */ +/*! @} */ + +/*! \addtogroup alphaop Alpha combine control + * @{ + */ +#define GX_AOP_AND 0 +#define GX_AOP_OR 1 +#define GX_AOP_XOR 2 +#define GX_AOP_XNOR 3 +#define GX_MAX_ALPHAOP 4 +/*! @} */ + +/*! \addtogroup tevkcolorid TEV constant color register + * @{ + */ +#define GX_KCOLOR0 0 /*!< Constant register 0 */ +#define GX_KCOLOR1 1 /*!< Constant register 1 */ +#define GX_KCOLOR2 2 /*!< Constant register 2 */ +#define GX_KCOLOR3 3 /*!< Constant register 3 */ +#define GX_KCOLOR_MAX 4 +/*! @} */ + +/*! \addtogroup tevkcolorsel TEV constant color selection + * @{ + */ +#define GX_TEV_KCSEL_1 0x00 /*!< constant 1.0 */ +#define GX_TEV_KCSEL_7_8 0x01 /*!< constant 7/8 */ +#define GX_TEV_KCSEL_3_4 0x02 /*!< constant 3/4 */ +#define GX_TEV_KCSEL_5_8 0x03 /*!< constant 5/8 */ +#define GX_TEV_KCSEL_1_2 0x04 /*!< constant 1/2 */ +#define GX_TEV_KCSEL_3_8 0x05 /*!< constant 3/8 */ +#define GX_TEV_KCSEL_1_4 0x06 /*!< constant 1/4 */ +#define GX_TEV_KCSEL_1_8 0x07 /*!< constant 1/8 */ +#define GX_TEV_KCSEL_K0 0x0C /*!< K0[RGB] register */ +#define GX_TEV_KCSEL_K1 0x0D /*!< K1[RGB] register */ +#define GX_TEV_KCSEL_K2 0x0E /*!< K2[RGB] register */ +#define GX_TEV_KCSEL_K3 0x0F /*!< K3[RGB] register */ +#define GX_TEV_KCSEL_K0_R 0x10 /*!< K0[RRR] register */ +#define GX_TEV_KCSEL_K1_R 0x11 /*!< K1[RRR] register */ +#define GX_TEV_KCSEL_K2_R 0x12 /*!< K2[RRR] register */ +#define GX_TEV_KCSEL_K3_R 0x13 /*!< K3[RRR] register */ +#define GX_TEV_KCSEL_K0_G 0x14 /*!< K0[GGG] register */ +#define GX_TEV_KCSEL_K1_G 0x15 /*!< K1[GGG] register */ +#define GX_TEV_KCSEL_K2_G 0x16 /*!< K2[GGG] register */ +#define GX_TEV_KCSEL_K3_G 0x17 /*!< K3[GGG] register */ +#define GX_TEV_KCSEL_K0_B 0x18 /*!< K0[BBB] register */ +#define GX_TEV_KCSEL_K1_B 0x19 /*!< K1[BBB] register */ +#define GX_TEV_KCSEL_K2_B 0x1A /*!< K2[BBB] register */ +#define GX_TEV_KCSEL_K3_B 0x1B /*!< K3[RBB] register */ +#define GX_TEV_KCSEL_K0_A 0x1C /*!< K0[AAA] register */ +#define GX_TEV_KCSEL_K1_A 0x1D /*!< K1[AAA] register */ +#define GX_TEV_KCSEL_K2_A 0x1E /*!< K2[AAA] register */ +#define GX_TEV_KCSEL_K3_A 0x1F /*!< K3[AAA] register */ +/*! @} */ + +/*! \addtogroup tevkalphasel TEV constant alpha selection + * @{ + */ +#define GX_TEV_KASEL_1 0x00 /*!< constant 1.0 */ +#define GX_TEV_KASEL_7_8 0x01 /*!< constant 7/8 */ +#define GX_TEV_KASEL_3_4 0x02 /*!< constant 3/4 */ +#define GX_TEV_KASEL_5_8 0x03 /*!< constant 5/8 */ +#define GX_TEV_KASEL_1_2 0x04 /*!< constant 1/2 */ +#define GX_TEV_KASEL_3_8 0x05 /*!< constant 3/8 */ +#define GX_TEV_KASEL_1_4 0x06 /*!< constant 1/4 */ +#define GX_TEV_KASEL_1_8 0x07 /*!< constant 1/8 */ +#define GX_TEV_KASEL_K0_R 0x10 /*!< K0[R] register */ +#define GX_TEV_KASEL_K1_R 0x11 /*!< K1[R] register */ +#define GX_TEV_KASEL_K2_R 0x12 /*!< K2[R] register */ +#define GX_TEV_KASEL_K3_R 0x13 /*!< K3[R] register */ +#define GX_TEV_KASEL_K0_G 0x14 /*!< K0[G] register */ +#define GX_TEV_KASEL_K1_G 0x15 /*!< K1[G] register */ +#define GX_TEV_KASEL_K2_G 0x16 /*!< K2[G] register */ +#define GX_TEV_KASEL_K3_G 0x17 /*!< K3[G] register */ +#define GX_TEV_KASEL_K0_B 0x18 /*!< K0[B] register */ +#define GX_TEV_KASEL_K1_B 0x19 /*!< K1[B] register */ +#define GX_TEV_KASEL_K2_B 0x1A /*!< K2[B] register */ +#define GX_TEV_KASEL_K3_B 0x1B /*!< K3[B] register */ +#define GX_TEV_KASEL_K0_A 0x1C /*!< K0[A] register */ +#define GX_TEV_KASEL_K1_A 0x1D /*!< K1[A] register */ +#define GX_TEV_KASEL_K2_A 0x1E /*!< K2[A] register */ +#define GX_TEV_KASEL_K3_A 0x1F /*!< K3[A] register */ +/*! @} */ + + +/*! \addtogroup tevswapsel TEV color swap table entry + * @{ + */ + +#define GX_TEV_SWAP0 0 +#define GX_TEV_SWAP1 1 +#define GX_TEV_SWAP2 2 +#define GX_TEV_SWAP3 3 +#define GX_MAX_TEVSWAP 4 + +/*! @} */ + + +/* tev color chan */ +#define GX_CH_RED 0 +#define GX_CH_GREEN 1 +#define GX_CH_BLUE 2 +#define GX_CH_ALPHA 3 + +/*! \addtogroup indtexstage Indirect texture stage + * @{ + */ +#define GX_INDTEXSTAGE0 0 +#define GX_INDTEXSTAGE1 1 +#define GX_INDTEXSTAGE2 2 +#define GX_INDTEXSTAGE3 3 +#define GX_MAX_INDTEXSTAGE 4 +/*! @} */ + +/*! \addtogroup indtexformat Indirect texture format + * \details Bits for the indirect offsets are extracted from the high end of each component byte. Bits for the bump alpha + * are extraced off the low end of the byte. For GX_ITF_8, the byte is duplicated for the offset and the bump alpha. + * @{ + */ +#define GX_ITF_8 0 +#define GX_ITF_5 1 +#define GX_ITF_4 2 +#define GX_ITF_3 3 +#define GX_MAX_ITFORMAT 4 +/*! @} */ + +/*! \addtogroup indtexbias Indirect texture bias select + * \brief Indicates which components of the indirect offset should receive a bias value. + * + * \details The bias is fixed at -128 for GX_ITF_8 and +1 for the other formats. The bias happens prior to the indirect matrix multiply. + * @{ + */ +#define GX_ITB_NONE 0 +#define GX_ITB_S 1 +#define GX_ITB_T 2 +#define GX_ITB_ST 3 +#define GX_ITB_U 4 +#define GX_ITB_SU 5 +#define GX_ITB_TU 6 +#define GX_ITB_STU 7 +#define GX_MAX_ITBIAS 8 +/*! @} */ + +/*! \addtogroup indtexmtx Indirect texture matrix + * @{ + */ +#define GX_ITM_OFF 0 /*!< Specifies a matrix of all zeroes. */ +#define GX_ITM_0 1 /*!< Specifies indirect matrix 0, indirect scale 0. */ +#define GX_ITM_1 2 /*!< Specifies indirect matrix 1, indirect scale 1. */ +#define GX_ITM_2 3 /*!< Specifies indirect matrix 2, indirect scale 2. */ +#define GX_ITM_S0 5 /*!< Specifies dynamic S-type matrix, indirect scale 0. */ +#define GX_ITM_S1 6 /*!< Specifies dynamic S-type matrix, indirect scale 1. */ +#define GX_ITM_S2 7 /*!< Specifies dynamic S-type matrix, indirect scale 2. */ +#define GX_ITM_T0 9 /*!< Specifies dynamic T-type matrix, indirect scale 0. */ +#define GX_ITM_T1 10 /*!< Specifies dynamic T-type matrix, indirect scale 1. */ +#define GX_ITM_T2 11 /*!< Specifies dynamic T-type matrix, indirect scale 2. */ +/*! @} */ + +/*! \addtogroup indtexwrap Indirect texture wrap value + * \brief Indicates whether the regular texture coordinate should be wrapped before being added to the offset. + * + * \details GX_ITW_OFF specifies no wrapping. GX_ITW_0 will zero out the regular texture coordinate. + * @{ + */ +#define GX_ITW_OFF 0 +#define GX_ITW_256 1 +#define GX_ITW_128 2 +#define GX_ITW_64 3 +#define GX_ITW_32 4 +#define GX_ITW_16 5 +#define GX_ITW_0 6 +#define GX_MAX_ITWRAP 7 +/*! @} */ + +/*! \addtogroup indtexalphasel Indirect texture bump alpha select + * \brief Indicates which offset component should provide the "bump" alpha output for the given TEV stage. + * + * \note Bump alpha is not available for TEV stage 0. + * @{ + */ +#define GX_ITBA_OFF 0 +#define GX_ITBA_S 1 +#define GX_ITBA_T 2 +#define GX_ITBA_U 3 +#define GX_MAX_ITBALPHA 4 +/*! @} */ + +/*! \addtogroup indtexscale Indirect texture scale + * \brief Specifies an additional scale value that may be applied to the texcoord used for an indirect initial lookup (not a TEV stage regular lookup). + * + * \details The scale value is a fraction; thus GX_ITS_32 means to divide the texture coordinate values by 32. + * @{ + */ +#define GX_ITS_1 0 +#define GX_ITS_2 1 +#define GX_ITS_4 2 +#define GX_ITS_8 3 +#define GX_ITS_16 4 +#define GX_ITS_32 5 +#define GX_ITS_64 6 +#define GX_ITS_128 7 +#define GX_ITS_256 8 +#define GX_MAX_ITSCALE 9 +/*! @} */ + +/*! \addtogroup fogtype Fog equation control + * @{ + */ +#define GX_FOG_NONE 0 + +#define GX_FOG_PERSP_LIN 2 +#define GX_FOG_PERSP_EXP 4 +#define GX_FOG_PERSP_EXP2 5 +#define GX_FOG_PERSP_REVEXP 6 +#define GX_FOG_PERSP_REVEXP2 7 + +#define GX_FOG_ORTHO_LIN 10 +#define GX_FOG_ORTHO_EXP 12 +#define GX_FOG_ORTHO_EXP2 13 +#define GX_FOG_ORTHO_REVEXP 14 +#define GX_FOG_ORTHO_REVEXP2 15 + +#define GX_FOG_LIN GX_FOG_PERSP_LIN +#define GX_FOG_EXP GX_FOG_PERSP_EXP +#define GX_FOG_EXP2 GX_FOG_PERSP_EXP2 +#define GX_FOG_REVEXP GX_FOG_PERSP_REVEXP +#define GX_FOG_REVEXP2 GX_FOG_PERSP_REVEXP2 +/*! @} */ + + +/* pixel format */ +#define GX_PF_RGB8_Z24 0 +#define GX_PF_RGBA6_Z24 1 +#define GX_PF_RGB565_Z16 2 +#define GX_PF_Z24 3 +#define GX_PF_Y8 4 +#define GX_PF_U8 5 +#define GX_PF_V8 6 +#define GX_PF_YUV420 7 + +/*! \addtogroup zfmt Compressed Z format + * @{ + */ +#define GX_ZC_LINEAR 0 +#define GX_ZC_NEAR 1 +#define GX_ZC_MID 2 +#define GX_ZC_FAR 3 +/*! @} */ + +/*! \addtogroup xfbclamp XFB clamp modes + * @{ + */ + +#define GX_CLAMP_NONE 0 +#define GX_CLAMP_TOP 1 +#define GX_CLAMP_BOTTOM 2 + +/*! @} */ + + +/*! \addtogroup gammamode Gamma values + * @{ + */ + +#define GX_GM_1_0 0 +#define GX_GM_1_7 1 +#define GX_GM_2_2 2 + +/*! @} */ + + +/*! \addtogroup copymode EFB copy mode + * \brief Controls whether all lines, only even lines, or only odd lines are copied from the EFB. + * @{ + */ +#define GX_COPY_PROGRESSIVE 0 +#define GX_COPY_INTLC_EVEN 2 +#define GX_COPY_INTLC_ODD 3 +/*! @} */ + +/*! \addtogroup alphareadmode Alpha read mode + * @{ + */ +#define GX_READ_00 0 /*!< Always read 0x00. */ +#define GX_READ_FF 1 /*!< Always read 0xFF. */ +#define GX_READ_NONE 2 /*!< Always read the real alpha value. */ +/*! @} */ + +/*! \addtogroup texcachesize Texture cache size + * \brief Size of texture cache regions. + * @{ + */ +#define GX_TEXCACHE_32K 0 +#define GX_TEXCACHE_128K 1 +#define GX_TEXCACHE_512K 2 +#define GX_TEXCACHE_NONE 3 +/*! @} */ + +/*! \addtogroup distattnfn Brightness decreasing function + * \brief Type of the brightness decreasing function by distance. + * @{ + */ +#define GX_DA_OFF 0 +#define GX_DA_GENTLE 1 +#define GX_DA_MEDIUM 2 +#define GX_DA_STEEP 3 +/*! @} */ + +/*! \addtogroup spotfn Spot illumination distribution function + * @{ + */ +#define GX_SP_OFF 0 +#define GX_SP_FLAT 1 +#define GX_SP_COS 2 +#define GX_SP_COS2 3 +#define GX_SP_SHARP 4 +#define GX_SP_RING1 5 +#define GX_SP_RING2 6 +/*! @} */ + +/*! \addtogroup texfilter Texture filter types + * @{ + */ +#define GX_NEAR 0 /*!< Point sampling, no mipmap */ +#define GX_LINEAR 1 /*!< Bilinear filtering, no mipmap */ +#define GX_NEAR_MIP_NEAR 2 /*!< Point sampling, discrete mipmap */ +#define GX_LIN_MIP_NEAR 3 /*!< Bilinear filtering, discrete mipmap */ +#define GX_NEAR_MIP_LIN 4 /*!< Point sampling, linear mipmap */ +#define GX_LIN_MIP_LIN 5 /*!< Trilinear filtering */ +/*! @} */ + +/*! \addtogroup anisotropy Maximum anisotropy filter control + * @{ + */ +#define GX_ANISO_1 0 +#define GX_ANISO_2 1 +#define GX_ANISO_4 2 +#define GX_MAX_ANISOTROPY 3 +/*! @} */ + +/*! \addtogroup vcachemetrics Vertex cache performance counter + * @{ + */ +#define GX_VC_POS 0 +#define GX_VC_NRM 1 +#define GX_VC_CLR0 2 +#define GX_VC_CLR1 3 +#define GX_VC_TEX0 4 +#define GX_VC_TEX1 5 +#define GX_VC_TEX2 6 +#define GX_VC_TEX3 7 +#define GX_VC_TEX4 8 +#define GX_VC_TEX5 9 +#define GX_VC_TEX6 10 +#define GX_VC_TEX7 11 +#define GX_VC_ALL 15 +/*! @} */ + +/*! \addtogroup perf0metrics Performance counter 0 metric + * \details Performance counter 0 is used to measure attributes dealing with geometry and primitives, such as triangle counts and clipping ratios. + * + * \note GX_PERF0_XF_* measure how many GP cycles are spent in each stage of the XF.

+ * + * \note The triangle metrics (GX_PERF0_TRIANGLES_*) allow counting triangles under specific conditions or with specific attributes.

+ * + * \note GX_PERF0_TRIANGLES_*TEX count triangles based on the number of texture coordinates supplied; GX_PERF0_TRIANGLES_*CLR count + * triangles based on the number of colors supplied.

+ * + * \note The quad metrics allow you to count the number of quads (2x2 pixels) the GP processes. The term coverage is used to indicate how many + * pixels in the quad are actually part of the triangle being rasterized. For example, a coverage of 4 means all pixels in the quad intersect the + * triangle. A coverage of 1 indicates that only 1 pixel in the quad intersected the triangle. + * @{ + */ +#define GX_PERF0_VERTICES 0 /*!< Number of vertices processed by the GP. */ +#define GX_PERF0_CLIP_VTX 1 /*!< Number of vertices that were clipped by the GP. */ +#define GX_PERF0_CLIP_CLKS 2 /*!< Number of GP clocks spent clipping. */ +#define GX_PERF0_XF_WAIT_IN 3 /*!< Number of cycles the XF is waiting on input. If the XF is waiting a large percentage + * of the total time, it may indicate that the CPU is not supplying data fast enough to + * keep the GP busy. */ +#define GX_PERF0_XF_WAIT_OUT 4 /*!< Number of cycles the XF waits to send its output to the rest of the GP pipeline. If + * the XF cannot output, it may indicate that the GP is currently fill-rate limited. */ +#define GX_PERF0_XF_XFRM_CLKS 5 /*!< Number of cycles the transform engine is busy. */ +#define GX_PERF0_XF_LIT_CLKS 6 /*!< Number of cycles the lighting engine is busy. */ +#define GX_PERF0_XF_BOT_CLKS 7 /*!< Number of cycles the bottom of the pipe (result combiner) is busy. */ +#define GX_PERF0_XF_REGLD_CLKS 8 /*!< Number of cycles are spent loading XF state registers. */ +#define GX_PERF0_XF_REGRD_CLKS 9 /*!< Number of cycles the XF reads the state registers. */ +#define GX_PERF0_CLIP_RATIO 10 +#define GX_PERF0_TRIANGLES 11 /*!< Number of triangles. */ +#define GX_PERF0_TRIANGLES_CULLED 12 /*!< Number of triangles that failed the front-face/back-face culling test. */ +#define GX_PERF0_TRIANGLES_PASSED 13 /*!< Number of triangles that passed the front-face/back-face culling test. */ +#define GX_PERF0_TRIANGLES_SCISSORED 14 /*!< Number of triangles that are scissored. */ +#define GX_PERF0_TRIANGLES_0TEX 15 +#define GX_PERF0_TRIANGLES_1TEX 16 +#define GX_PERF0_TRIANGLES_2TEX 17 +#define GX_PERF0_TRIANGLES_3TEX 18 +#define GX_PERF0_TRIANGLES_4TEX 19 +#define GX_PERF0_TRIANGLES_5TEX 20 +#define GX_PERF0_TRIANGLES_6TEX 21 +#define GX_PERF0_TRIANGLES_7TEX 22 +#define GX_PERF0_TRIANGLES_8TEX 23 +#define GX_PERF0_TRIANGLES_0CLR 24 +#define GX_PERF0_TRIANGLES_1CLR 25 +#define GX_PERF0_TRIANGLES_2CLR 26 +#define GX_PERF0_QUAD_0CVG 27 /*!< Number of quads having zero coverage. */ +#define GX_PERF0_QUAD_NON0CVG 28 /*!< Number of quads having coverage greater than zero. */ +#define GX_PERF0_QUAD_1CVG 29 /*!< Number of quads with 1 pixel coverage. */ +#define GX_PERF0_QUAD_2CVG 30 /*!< Number of quads with 2 pixel coverage. */ +#define GX_PERF0_QUAD_3CVG 31 /*!< Number of quads with 3 pixel coverage. */ +#define GX_PERF0_QUAD_4CVG 32 /*!< Number of quads with 4 pixel coverage. */ +#define GX_PERF0_AVG_QUAD_CNT 33 /*!< Average quad count; average based on what is unknown */ +#define GX_PERF0_CLOCKS 34 /*!< Number of GP clocks that have elapsed since the previous call to GX_ReadGP0Metric(). */ +#define GX_PERF0_NONE 35 /*!< Disables performance measurement for perf0 and resets the counter. */ +/*! @} */ + +/*! \addtogroup perf1metrics Performance counter 1 metric + * \details Performance counter 1 is used for measuring texturing and caching performance as well as FIFO performance. + * + * \note GX_PERF1_TC_* can be used to compute the texture cache (TC) miss rate. The TC_CHECK* parameters count how many texture cache lines are + * accessed for each pixel. In the worst case, for a mipmap, up to 8 cache lines may be accessed to produce one textured pixel. + * GX_PERF1_TC_MISS counts how many of those accesses missed the texture cache. To compute the miss rate, divide GX_PERF1_TC_MISS by the sum of all four + * GX_PERF1_TC_CHECK* values.

+ * + * \note GX_PERF1_VC_* count different vertex cache stall conditions. + * @{ + */ +#define GX_PERF1_TEXELS 0 /*!< Number of texels processed by the GP. */ +#define GX_PERF1_TX_IDLE 1 /*!< Number of clocks that the texture unit (TX) is idle. */ +#define GX_PERF1_TX_REGS 2 /*!< Number of GP clocks spent writing to state registers in the TX unit. */ +#define GX_PERF1_TX_MEMSTALL 3 /*!< Number of GP clocks the TX unit is stalled waiting for main memory. */ +#define GX_PERF1_TC_CHECK1_2 4 +#define GX_PERF1_TC_CHECK3_4 5 +#define GX_PERF1_TC_CHECK5_6 6 +#define GX_PERF1_TC_CHECK7_8 7 +#define GX_PERF1_TC_MISS 8 /*!< Number of texture cache misses in total? */ +#define GX_PERF1_VC_ELEMQ_FULL 9 +#define GX_PERF1_VC_MISSQ_FULL 10 +#define GX_PERF1_VC_MEMREQ_FULL 11 +#define GX_PERF1_VC_STATUS7 12 +#define GX_PERF1_VC_MISSREP_FULL 13 +#define GX_PERF1_VC_STREAMBUF_LOW 14 +#define GX_PERF1_VC_ALL_STALLS 15 +#define GX_PERF1_VERTICES 16 /*!< Number of vertices processed by the GP. */ +#define GX_PERF1_FIFO_REQ 17 /*!< Number of lines (32B) read from the GP FIFO. */ +#define GX_PERF1_CALL_REQ 18 /*!< Number of lines (32B) read from called display lists. */ +#define GX_PERF1_VC_MISS_REQ 19 /*!< Number vertex cache miss request. Each miss requests a 32B transfer from main memory. */ +#define GX_PERF1_CP_ALL_REQ 20 /*!< Counts all requests (32B/request) from the GP Command Processor (CP). It should be equal to + * the sum of counts returned by GX_PERF1_FIFO_REQ, GX_PERF1_CALL_REQ, and GX_PERF1_VC_MISS_REQ. */ +#define GX_PERF1_CLOCKS 21 /*!< Number of GP clocks that have elapsed since the last call to GX_ReadGP1Metric(). */ +#define GX_PERF1_NONE 22 /*!< Disables performance measurement for perf1 and resets the counter. */ +/*! @} */ + +/*! \addtogroup tlutname TLUT name + * \brief Name of Texture Look-Up Table (TLUT) in texture memory. + * + * \details Each table GX_TLUT0-GX_TLUT15 contains 256 entries,16b per entry. GX_BIGTLUT0-3 + * contains 1024 entries, 16b per entry. Used for configuring texture memory in GX_Init(). + * @{ + */ +#define GX_TLUT0 0 +#define GX_TLUT1 1 +#define GX_TLUT2 2 +#define GX_TLUT3 3 +#define GX_TLUT4 4 +#define GX_TLUT5 5 +#define GX_TLUT6 6 +#define GX_TLUT7 7 +#define GX_TLUT8 8 +#define GX_TLUT9 9 +#define GX_TLUT10 10 +#define GX_TLUT11 11 +#define GX_TLUT12 12 +#define GX_TLUT13 13 +#define GX_TLUT14 14 +#define GX_TLUT15 15 +#define GX_BIGTLUT0 16 +#define GX_BIGTLUT1 17 +#define GX_BIGTLUT2 18 +#define GX_BIGTLUT3 19 +/*! @} */ + +#define GX_MAX_VTXDESC GX_VA_MAXATTR +#define GX_MAX_VTXDESC_LISTSIZE (GX_VA_MAXATTR+1) + +#define GX_MAX_VTXATTRFMT GX_VA_MAXATTR +#define GX_MAX_VTXATTRFMT_LISTSIZE (GX_VA_MAXATTR+1) + +#define GX_MAX_Z24 0x00ffffff + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef union _wgpipe +{ + vu8 U8; + vs8 S8; + vu16 U16; + vs16 S16; + vu32 U32; + vs32 S32; + vf32 F32; +} WGPipe; + +/*! \typedef struct _gx_color GXColor + * \brief Structure used to pass colors to some GX functions. + */ +typedef struct _gx_color { + u8 r; /*!< Red color component. */ + u8 g; /*!< Green color component. */ + u8 b; /*!< Blue alpha component. */ + u8 a; /*!< Alpha component. If a function does not use the alpha value, it is safely ignored. */ +} GXColor; + +/*! \typedef struct _gx_colors10 GXColorS10 + * \brief Structure used to pass signed 10-bit colors to some GX functions. + */ +typedef struct _gx_colors10 { + s16 r; /*!< Red color component. */ + s16 g; /*!< Green color component. */ + s16 b; /*!< Blue color component. */ + s16 a; /*!< Alpha component. If a function does not use the alpha value, it is safely ignored. */ +} GXColorS10; + +/*! \typedef struct _gx_texobj GXTexObj + * \brief Object containing information about a texture. + * + * \details This structure contains precompiled register state setting commands and data. The application must use the GX_InitTexObj*() + * function to initialize or change this object. The proper size of the object is returned by + * + * \code sizeof(GXTexObj) \endcode + * + * \details but the internal data representation is not visible to the application. + */ +typedef struct _gx_texobj { + u32 val[8]; +} GXTexObj; + +/*! \typedef struct _gx_tlutobj GXTlutObj + * \brief Object containing information on a TLUT. + * + * \details This structure contains precompiled register state setting commands and data. The application must use the GX_InitTlutObj() + * function to initialize or change this object. The proper size of the object is returned by + * + * \code sizeof(GXTlutObj) \endcode + * + * \details but the internal data representation is not visible to the application. + */ +typedef struct _gx_tlutobj { + u32 val[3]; +} GXTlutObj; + +/*! \typedef struct _gx_texreg GXTexRegion + * \brief Object containing information on a texture cache region. + * + * \details This structure contains precompiled register state setting commands and data. The application must use the + * GX_InitTexCacheRegion() function to initialize or change this object. The proper size of the object is returned by + * + * \code sizeof(GXTexRegion) \endcode + * + * \details but the internal data representation is not visible to the application. + */ +typedef struct _gx_texreg { + u32 val[4]; +} GXTexRegion; + +/*! \typedef struct _gx_tlutreg GXTlutRegion + * \brief Object containing information on a TLUT cache region. + * + * \details This structure contains precompiled register state setting commands and data. The application must use the GX_InitTlutRegion() + * function to initialize or change this object. The proper size of the object is returned by + * + * \code sizeof(GXTlutRegion) \endcode + * + * \details but the internal data representation is not visible to the application. + */ +typedef struct _gx_tlutreg { + u32 val[4]; +} GXTlutRegion; + +/*! \typedef _gx_litobj GXLightObj + * \brief Object containing information on a light. + * + * \details This structure contains precompiled register state setting commands and data. The application must use the GX_InitLight*() functions + * to initialize or change this object. The proper size of the object is returned by + * + * \code sizeof(GXLightObj) \endcode + * + * \details but the internal data representation is not visible to the application. + */ +typedef struct _gx_litobj { + u32 val[16]; +} GXLightObj; + +typedef struct _vtx { + f32 x,y,z; + u16 s,t; + u32 rgba; +} Vtx; + +/*! \struct GXVtxDesc + * \brief Structure describing how a single vertex attribute will be referenced. + * + * \details An array of these structures can be used to describe all the attributes in a vertex. The attribute GX_VA_NULL should be + * used to mark the end of the array. + */ +typedef struct { + u8 attr; /*!< \ref vtxattr for this element. */ + u8 type; /*!< \ref vtxattrin for this element. */ +} GXVtxDesc; + +/*! \struct GXVtxAttrFmt + * \brief Structure describing the attribute format for one attribute. + * + * \details An array of these structures can be used to describe the format of all attributes in a vertex. The attribute GX_VA_NULL + * should be used to mark the end of the array. + */ +typedef struct { + u32 vtxattr; /*!< \ref vtxattr for this element. */ + u32 comptype; /*!< \ref comptype for this element. */ + u32 compsize; /*!< \ref compsize for this element. */ + u32 frac; /*!< Number of fractional bits for a fixed-point number. */ +} GXVtxAttrFmt; + +/*! \struct GXFifoObj + * \brief Object describing a graphics FIFO. + * + * \details This structure contains precompiled register state setting commands and data. The application must use the GX_InitFifo*() functions + * to initialize or change this object. The proper size of the object is returned by + * + * \code sizeof(GXFifoObj) \endcode + * + * but the internal data representation is not visible to the application. + */ +typedef struct { + u8 pad[GX_FIFO_OBJSIZE]; +} GXFifoObj; + +typedef struct { + u8 dummy[4]; +} GXTexReg; + +/*! \struct GXFogAdjTbl + * \brief Fog range adjustment parameter table. + */ +typedef struct { + u16 r[10]; /*!< u4.8 format range parameter. */ +} GXFogAdjTbl; + +/*! \typedef void (*GXBreakPtCallback)(void) + * \brief function pointer typedef for the GP breakpoint-token callback + */ +typedef void (*GXBreakPtCallback)(void); + +/*! \typedef void (*GXDrawDoneCallback)(void) + * \brief function pointer typedef for the GP drawdone-token callback + */ +typedef void (*GXDrawDoneCallback)(void); + +/*! \typedef void (*GXDrawSyncCallback)(u16 token) + * \brief function pointer typedef for the drawsync-token callback + * \param[out] token tokenvalue most recently encountered. + */ +typedef void (*GXDrawSyncCallback)(u16 token); + +/*! \typedef GXTexRegion* (*GXTexRegionCallback)(GXTexObj *obj,u8 mapid) + * \brief function pointer typedef for the texture region callback + * \param[out] token tokenvalue most recently encountered. + */ +typedef GXTexRegion* (*GXTexRegionCallback)(GXTexObj *obj,u8 mapid); + +/*! \typedef GXTlutRegion* (*GXTlutRegionCallback)(u32 tlut_name) + * \brief function pointer typedef for the TLUT region callback + * \param[out] token tokenvalue most recently encountered. + */ +typedef GXTlutRegion* (*GXTlutRegionCallback)(u32 tlut_name); + +extern WGPipe* const wgPipe; +/*! + * \fn GXFifoObj* GX_Init(void *base,u32 size) + * \brief Initializes the graphics processor to its initial state. + * + * \details This function sets the default state of the graphics processor and should be called before any other GX functions. + * This function sets up an immediate-mode method of communicating graphics commands from the CPU to the Graphics Processor + * (GP). This function will initialize a FIFO and attach it to both the CPU and GP. The CPU will write commands to the FIFO + * and the GP will read the commands. This function returns a pointer to the initialized FIFO. The application must allocate + * the memory for the FIFO. The parameter \a base is a pointer to the allocated main memory and must be aligned to 32B. \a size + * is the size of the FIFO in bytes and must be a multiple of 32B. Refer to additional notes in GX_InitFifoBase() concerning + * the FIFO memory. + * + * \note It is also possible to override the default immediate-mode style and instead buffer the graphics for frame n+1 + * while the GP is reading the graphics for frame n. See GX_SetCPUFifo() and GX_SetGPFifo() for further information.

+ * + * \note This function also designates the calling thread as the default GX thread; i.e., it assumes the calling thread is the + * one responsible for generating graphics data. This thread will be the thread to be suspended when the FIFO gets too full. + * The current GX thread can be changed by calling GX_SetCurrentGXThread(). + * + * \param[in] base pointer to the GX FIFO buffer base address. Must be aligned on a 32 Byte boundery. + * \param[in] size size of buffer. Must be a multiple of 32. + * + * \return pointer to the intialized GXFifoObj object. + */ +GXFifoObj* GX_Init(void *base,u32 size); + +/*! + * \fn void GX_InitFifoBase(GXFifoObj *fifo,void *base,u32 size) + * \brief Describes the area of main memory that will be used for this \a fifo. + * + * The Graphics FIFO is the mechanism used to communicate graphics commands from the CPU to the Graphics Processor (GP). The FIFO + * base pointer should be 32-byte aligned. memalign() can return 32-byte aligned pointers. The size should also be a multiple of + * 32B. + * + * The CPU's write-gather pipe is used to write data to the FIFO. Therefore, the FIFO memory area must be forced out of the CPU + * cache prior to being used. DCInvalidateRange() may be used for this purpose. Due to the mechanics of flushing the write-gather + * pipe, the FIFO memory area should be at least 32 bytes larger than the maximum expected amount of data stored. Up to 32 NOPs + * may be written at the end during flushing. + * + * \note GX_Init() also takes the arguments \a base and \a size and initializes a FIFO using these values and attaches the FIFO + * to both the CPU and GP. The application must allocate the memory for the graphics FIFO before calling GX_Init(). Therefore, it + * is not necessary to call this function unless you want to resize the default FIFO sometime after GX_Init() has been called or + * you are creating a new FIFO. The minimum size is 64kB defined by GX_FIFO_MINSIZE.

+ * + * \note This function will also set the read and write pointers for the FIFO to the base address, so ordinarily it is not + * necessary to call GX_InitFifoPtrs() when initializing the FIFO. In addition, This function sets the FIFO's high water mark to + * (size-16kB) and the low water mark to (size/2), so it is also not necessary to call GX_InitFifoLimits(). + * + * \param[in] fifo the fifo struct to use + * \param[in] base ptr to the base of allocation; must be 32-byte aligned + * \param[in] size size of the FIFO in bytes; must be multiple of 32; size must be GX_FIFO_MINSIZE or larger + * + * \return none + */ +void GX_InitFifoBase(GXFifoObj *fifo,void *base,u32 size); + +/*! + * \fn void GX_InitFifoLimits(GXFifoObj *fifo,u32 hiwatermark,u32 lowatermark) + * \brief Sets the high and low water mark for the \a fifo. + * + * \details The high and low water marks are used in immediate-mode, i.e. when the \a fifo is attached to both the CPU and + * Graphics Processor (GP) (see GX_SetCPUFifo() and GX_SetGPFifo()). + * + * The hardware keeps track of the number of bytes between the read and write pointers. This number represents how full the FIFO is, + * and when it is greater than or equal to the \a hiwatermark, the hardware issues an interrupt. The GX API will suspend sending + * graphics to the Graphics FIFO until it has emptied to a certain point. The \a lowatermark is used to set the point at which the + * FIFO is empty enough to resume sending graphics commands to the FIFO. Both \a hiwatermark and \a lowatermark should be in + * multiples of 32B. The count for \a lowatermark should be less than \a hiwatermark. Of course, \a hiwatermark and \a lowatermark + * must be less than the size of the FIFO. + * + * \note When the FIFO is only attached to the CPU or only attached to the GP, the high and low water mark interrupts are disabled. + * + * \param[in] fifo the fifo struct to use + * \param[in] hiwatermark number of bytes to be queued before libogc stops writing commands to the FIFO + * \param[in] lowatermark number of bytes to be queued before libogc resumes writing commands to the FIFO + * + * \return none + */ +void GX_InitFifoLimits(GXFifoObj *fifo,u32 hiwatermark,u32 lowatermark); + +/*! + * \fn void GX_InitFifoPtrs(GXFifoObj *fifo,void *rd_ptr,void *wt_ptr) + * \brief Sets the \a fifo read and write pointers. + * + * \note This is normally done only during initialization of the FIFO. After that, the graphics hardware manages the FIFO pointers. + * + * \param[in] fifo the fifo struct to use + * \param[in] rd_ptr the pointer to use for the FIFO read pointer; must be 32-byte aligned + * \param[in] wt_ptr the pointer to use for the FIFO write pointer; must be 32-byte aligned + * + * \return none + */ +void GX_InitFifoPtrs(GXFifoObj *fifo,void *rd_ptr,void *wt_ptr); + +/*! + * \fn void GX_GetFifoPtrs(GXFifoObj *fifo,void **rd_ptr,void **wt_ptr) + * \brief Returns the current value of the Graphics FIFO read and write pointers. + * + * \note See GX_EnableBreakPt() for an example of why you would do this. + * + * \param[in] fifo pointer to a FIFO struct + * \param[out] rd_ptr address of the FIFO read pointer + * \param[out] wt_ptr address of the FIFO write pointer + * + * \return none + */ +void GX_GetFifoPtrs(GXFifoObj *fifo,void **rd_ptr,void **wt_ptr); + +/*! + * \fn void GX_SetCPUFifo(GXFifoObj *fifo) + * \brief Attaches a FIFO to the CPU. + * + * \note If the FIFO being attached is one already attached to the GP, the FIFO can be considered to be in immediate mode. If not, + * the CPU can write commands, and the GP will execute them when the GP attaches to this FIFO (multi-buffered mode). + * + * \param[in] fifo fifo struct containing info on the FIFO to attach + * + * \return none + */ +void GX_SetCPUFifo(GXFifoObj *fifo); + +/*! + * \fn void GX_SetGPFifo(GXFifoObj *fifo) + * \brief Attaches \a fifo to the GP. + * + * \note If the FIFO is also attached to the CPU, the system is in immediate-mode, and the fifo acts like a true FIFO. In immediate-mode, + * graphics commands are fed directly from the CPU to the GP. In immediate-mode the FIFO's high and low water marks are active. The high + * and low water marks implement the flow-control mechanism between the CPU and GP. When the FIFO becomes more full than the high water + * mark, the CPU will stop writing graphics commands into the FIFO. When the FIFO empties to a point lower than the low water mark, the + * CPU will resume writing graphics commands into the FIFO. The high and low water marks are set when intializing the FIFO using + * GX_InitFifoLimits().

+ * + * \note If the FIFO is only attached to the GP, the FIFO acts like a buffer. In this case, high and low water marks are disabled, and + * the GP reads the FIFO until it is empty. Before attaching a new FIFO to the GP, you should make sure the previous FIFO is empty, using + * the \a cmdIdle status returned by GX_GetGPStatus().

+ * + * \note The break point mechanism can be used to force the FIFO to stop reading commands at a certain point; see GX_EnableBreakPt(). + * + * \param[in] fifo struct containing info on the FIFO to attach + * + * \return none + */ +void GX_SetGPFifo(GXFifoObj *fifo); + +/*! + * \fn void GX_GetCPUFifo(GXFifoObj *fifo) + * \brief Copies the information from the currently attached CPU FIFO into \a fifo. + * + * \param[out] fifo the object to copy the current CPU FIFO object data into + * + * \return none + */ +void GX_GetCPUFifo(GXFifoObj *fifo); + +/*! + * \fn void GX_GetGPFifo(GXFifoObj *fifo) + * \brief Copies the information from the currently attached GP FIFO info \a fifo. + * + * \param[out] fifo the object to copy the current GP FIFO object data into + * + * \return none + */ +void GX_GetGPFifo(GXFifoObj *fifo); + +/*! + * \fn void* GX_GetFifoBase(GXFifoObj *fifo) + * \brief Get the base address for a given \a fifo. + * + * \param[in] fifo the object to get the address from + * + * \return pointer to the base address of the FIFO in main memory. + */ +void* GX_GetFifoBase(GXFifoObj *fifo); + +/*! + * \fn u32 GX_GetFifoCount(GXFifoObj *fifo) + * \brief Returns number of cache lines in the FIFO. + * + * \note The count is incorrect if an overflow has occurred (i.e. you have written more data than the size of the fifo), as the + * hardware cannot detect an overflow in general. + * + * \param[in] fifo the FIFO to get the count from + * + * \return number of cache lines in the FIFO + */ +u32 GX_GetFifoCount(GXFifoObj *fifo); + +/*! + * \fn u32 GX_GetFifoSize(GXFifoObj *fifo) + * \brief Get the size of a given \a fifo. + * + * \param[in] fifo the object to get the size from + * + * \return size of the FIFO, in bytes + */ +u32 GX_GetFifoSize(GXFifoObj *fifo); + +/*! + * \fn u8 GX_GetFifoWrap(GXFifoObj *fifo) + * \brief Returns a non-zero value if the write pointer has passed the TOP of the FIFO. + * + * \details Returns true only if the FIFO is attached to the CPU and the FIFO write pointer has passed the top of the FIFO. Use the + * return value to detect whether or not an overflow has occured by initializing the FIFO's write pointer to the base of the FIFO + * before sending any commands to the FIFO. + * + * \note If the FIFO write pointer is not explicitly set to the base of the FIFO, you cannot rely on this function to detect overflows. + * + * \param[in] fifo the object to get the wrap status from + * + * \return wrap value + */ +u8 GX_GetFifoWrap(GXFifoObj *fifo); + +/*! + * \fn GXDrawDoneCallback GX_SetDrawDoneCallback(GXDrawDoneCallback cb) + * \brief Installs a callback that is invoked whenever a DrawDone command is encountered by the GP. + * + * \details The DrawDone command is sent by GX_SetDrawDone(). + * + * \note By the time the callback is invoked, the GP will already have resumed reading from the FIFO, if there are any commands in it. + * + * \param[in] cb callback to be invoked when DrawDone is encountered + * + * \return pointer to the previous callback + */ +GXDrawDoneCallback GX_SetDrawDoneCallback(GXDrawDoneCallback cb); + +/*! + * \fn GXBreakPtCallback GX_SetBreakPtCallback(GXBreakPtCallback cb) + * \brief Registers \a cb as a function to be invoked when a break point is encountered. + * + * \warning The callback will run with interrupts disabled, so it should terminate as quickly as possible. + * + * \param[in] cb function to be invoked when the breakpoint is encountered; NULL means no function will run + * + * \return pointer to the previous callback function + */ +GXBreakPtCallback GX_SetBreakPtCallback(GXBreakPtCallback cb); + +/*! + * \fn void GX_AbortFrame() + * \brief Aborts the current frame. + * + * \details This command will reset the entire graphics pipeline, including any commands in the graphics FIFO. + * + * \note Texture memory will not be reset, so currently loaded textures will still be valid; however, when loading texture using + * GX_PreloadEntireTexture() or TLUTs using GX_LoadTlut(), you must make sure the command completed. You can use the draw sync mechanism to + * do this; see GX_SetDrawSync() and GX_GetDrawSync(). + * + * \return none + */ +void GX_AbortFrame(); + +/*! + * \fn void GX_Flush() + * \brief Flushes all commands to the GP. + * + * \details Specifically, it flushes the write-gather FIFO in the CPU to make sure that all commands are sent to the GP. + * + * \return none + */ +void GX_Flush(); + +/*! + * \fn void GX_SetMisc(u32 token,u32 value) + * \brief Sets miscellanous settings in the GP. + * + * \param[in] token setting to change + * \param[in] value value to change the setting to + * + * \return none + */ +void GX_SetMisc(u32 token,u32 value); + +/*! + * \fn void GX_SetDrawDone() + * \brief Sends a DrawDone command to the GP. + * + * \details When all previous commands have been processed and the pipeline is empty, a DrawDone status bit will be set, + * and an interrupt will occur. You can receive notification of this event by installing a callback on the interrupt with + * GX_SetDrawDoneCallback(), or you can poll the status bit with GX_WaitDrawDone(). This function also flushes the write-gather + * FIFO in the CPU to make sure that all commands are sent to the graphics processor. + * + * \note This function is normally used in multibuffer mode (see GX_SetCPUFifo()). In immediate mode, the GX_DrawDone() command + * can be used, which both sends the command and stalls until the DrawDone status is true. + * + * \return none + */ +void GX_SetDrawDone(); + +/*! + * \fn void GX_WaitDrawDone() + * \brief Stalls until DrawDone is encountered by the GP. + * + * \details It means all graphics commands sent before this DrawDone command have executed and the last pixel has been written to + * the frame buffer. You may want to execute some non-graphics operations between executing GX_SetDrawDone() and this function, but + * if you simply want to wait and have nothing to execute, you can use GX_DrawDone(). + * + * \note This function is normally used in immediate mode (see GX_SetCPUFifo()). In multibuffer mode, sending the 'done' command is + * separated from polling the 'done' status (see GX_SetDrawDone() and GX_WaitDrawDone()). + * + * \return none + */ +void GX_WaitDrawDone(); + +/*! + * \fn u16 GX_GetDrawSync() + * \brief Returns the value of the token register, which is written using the GX_SetDrawSync() function. + * + * \return the value of the token register. + */ +u16 GX_GetDrawSync(); + +/*! + * \fn void GX_SetDrawSync(u16 token) + * \brief This function sends a token into the command stream. + * + * \details When the token register is set, an interrupt will also be received by the CPU. You can install a callback on this interrupt + * with GX_SetDrawSyncCallback(). Draw syncs can be used to notify the CPU that the graphics processor is finished using a shared + * resource (a vertex array for instance). + * + * \param[in] token 16-bit value to write to the token register. + * + * \return none + */ +void GX_SetDrawSync(u16 token); + +/*! + * \fn GXDrawSyncCallback GX_SetDrawSyncCallback(GXDrawSyncCallback cb) + * \brief Installs a callback that is invoked whenever a DrawSync token is encountered by the graphics pipeline. + * + * \details The callback's argument is the value of the token most recently encountered. Since it is possible to + * miss tokens (graphics processing does not stop while the callback is running), your code should be + * capable of deducing if any tokens have been missed. + * + * \param[in] cb callback to be invoked when the DrawSync tokens are encountered in the graphics pipeline. + * + * \return pointer to the previously set callback function. + */ +GXDrawSyncCallback GX_SetDrawSyncCallback(GXDrawSyncCallback cb); + +/*! + * \fn void GX_DisableBreakPt() + * \brief Allows reads from the FIFO currently attached to the Graphics Processor (GP) to resume. + * + * \details See GX_EnableBreakPt() for an explanation of the FIFO break point feature. + * + * \note The breakpoint applies to the FIFO currently attached to the Graphics Processor (GP) (see GX_SetGPFifo()). + * + * \return none + */ +void GX_DisableBreakPt(); + +/*! + * \fn void GX_EnableBreakPt(void *break_pt) + * \brief Sets a breakpoint that causes the GP to halt when encountered. + * + * \note The break point feature allows the application to have two frames of graphics in the FIFO at the same time, overlapping + * one frame's processing by the graphics processor with another frame's processing by the CPU. For example, suppose you finish + * writing the graphics commands for one frame and are ready to start on the next. First, execute a GX_Flush() command to make + * sure all the data in the CPU write gatherer is flushed into the FIFO. This will also align the FIFO write pointer to a 32B + * boundary. Next, read the value of the current write pointer using GX_GetFifoPtrs(). Write the value of the write pointer as + * the break point address using GX_EnableBreakPt(). When the FIFO read pointer reaches the break point address the hardware + * will disable reads from the FIFO. The status \a brkpt, returned by GX_GetGPStatus(), can be polled to detect when the break point + * is reached. The application can then decide when to disable the break point, using GX_DisableBreakPt(), which will allow the FIFO + * to resume reading graphics commands.

+ * + * \note FIFO reads will stall when the GP FIFO read pointer is equal to the break point address \a break_pt. To re-enable reads of + * the GP FIFO, use GX_DisableBreakPt().

+ * + * \note Use GX_SetBreakPtCallback() to set what function runs when the breakpoint is encountered. + * + * \param[in] break_pt address for GP to break on when read. + * + * \return none + */ +void GX_EnableBreakPt(void *break_pt); + +/*! + * \fn void GX_DrawDone() + * \brief Sends a DrawDone command to the GP and stalls until its subsequent execution. + * + * \note This function is equivalent to calling GX_SetDrawDone() then GX_WaitDrawDone(). + * + * \return none + */ +void GX_DrawDone(); + +/*! + * \fn void GX_TexModeSync() + * \brief Inserts a synchronization command into the graphics FIFO. When the Graphics Processor sees this command, it will + * allow the texture pipeline to flush before continuing. + * + * \details This command is necessary when changing the usage of regions of texture memory from preloaded or TLUT to cached areas. + * It makes sure that the texture pipeline is finished with that area of the texture memory prior to changing its usage. + * This function should be called prior to drawing any primitives that uses the texture memory region in its new mode. It is not + * necessary to call this command when changing texture memory regions from cached to preloaded (or TLUT), since the commands to + * load the regions with data will cause the necessary synchronization to happen automatically. + * + * \return none + */ +void GX_TexModeSync(); + +/*! + * \fn void GX_InvVtxCache(); + * \brief Invalidates the vertex cache. + * + * \details Specifically, this functions invalidates the vertex cache tags. This function should be used whenever you relocate or modify + * data that is read by, or may be cached by, the vertex cache. The invalidate is very fast, taking only two Graphics Processor (GP) clock + * cycles to complete. + * + * \note The vertex cache is used to cache indexed attribute data. Any attribute that is set to GX_INDEX8 or GX_INDEX16 in the current + * vertex descriptor (see GX_SetVtxDesc()) is indexed. Direct data bypasses the vertex cache. Direct data is any attribute that is set to + * GX_DIRECT in the current vertex descriptor. + * + * \return none + */ +void GX_InvVtxCache(); + +/*! + * \fn void GX_ClearVtxDesc() + * \brief Clears all vertex attributes of the current vertex descriptor to GX_NONE. + * + * \note The same functionality can be obtained using GX_SetVtxDescv(), however using GX_ClearVtxDesc() is much more efficient. + * + * \return none + */ +void GX_ClearVtxDesc(); + +/*! + * \fn void GX_LoadProjectionMtx(Mtx44 mt,u8 type) + * \brief Sets the projection matrix. + * + * \note Only two types of projection matrices are supported: GX_PERSPECTIVE or GX_ORTHOGRAPHIC. + * + * \param[in] mt matrix to use for the perspective + * \param[in] type which perspective type to use + * + * \return none + */ +void GX_LoadProjectionMtx(Mtx44 mt,u8 type); + +/*! + * \fn void GX_SetViewport(f32 xOrig,f32 yOrig,f32 wd,f32 ht,f32 nearZ,f32 farZ) + * \brief Sets the viewport rectangle in screen coordinates. + * + * \details The screen origin (\a xOrig = 0.0f, \a yOrig = 0.0f) is at the top left corner of the display. Floating point arguments allow the + * viewport to be adjusted by 1/2 line for interlaced field rendering modes; see GX_SetViewportJitter(). The viewport depth parameters are normalized coordinates + * from 0.0f - 1.0f. The GX API will convert the depth range values to proper scale values depending on the type and format of the Z-buffer. + * + * \note You should avoid using negative values for \a xOrig or \a yOrig. While this may work, it may cause problems with points and lines being clipped incorrectly. If + * you need to shift the viewport up or left, consider using GX_SetScissorBoxOffset() instead. + * + * \param[in] xOrig left-most X coordinate on the screen + * \param[in] yOrig top-most Y coordinate on the screen + * \param[in] wd width of the viewport + * \param[in] ht height of the viewport + * \param[in] nearZ value to use for near depth scale + * \param[in] farZ value to use for far depth scale + * + * \return none + */ +void GX_SetViewport(f32 xOrig,f32 yOrig,f32 wd,f32 ht,f32 nearZ,f32 farZ); + +/*! + * \fn void GX_SetViewportJitter(f32 xOrig,f32 yOrig,f32 wd,f32 ht,f32 nearZ,f32 farZ,u32 field) + * \brief Sets the viewport and adjusts the viewport's line offset for interlaced field rendering. + * + * \details Depending on whether the viewport starts on an even or odd line, and whether the next \a field to be rendered is + * even or odd, the viewport may be adjusted by half a line. This has the same effect as slightly tilting the camera down and is necessary + * for interlaced rendering. No other camera adjustment (i.e. don't change the projection matrix) is needed for interlaced field rendering. + * + * \note To set a viewport without jitter, use GX_SetViewport(). + * + * \param[in] xOrig left-most X coordinate on the screen + * \param[in] yOrig top-most Y coordinate on the screen + * \param[in] wd width of the viewport + * \param[in] ht height of the viewport + * \param[in] nearZ value to use for near depth scale + * \param[in] farZ value to use for far depth scale + * \param[in] field whether the next field is even (0) or odd (1) + * + * \return none + */ +void GX_SetViewportJitter(f32 xOrig,f32 yOrig,f32 wd,f32 ht,f32 nearZ,f32 farZ,u32 field); + +/*! + * \fn void GX_SetChanCtrl(s32 channel,u8 enable,u8 ambsrc,u8 matsrc,u8 litmask,u8 diff_fn,u8 attn_fn) + * \brief Sets the lighting controls for a particular color channel. + * + * \details The color channel can have one or more (up to 8) lights associated with it, set using \a litmask. The \a diff_fn and \a attn_fn parameters + * control the lighting equation for all lights associated with this channel; the \a ambsrc and \a matsrc can be used to select whether the input + * source colors come from register colors or vertex colors. When the channel \a enable is set to GX_FALSE, the material color source (set by \a matsrc) + * is passed through as the channel's output color. When the channel \a enable is GX_TRUE, the output color depends on the settings of the other + * controls (i.e., the lighting equation). GX_Init() sets the \a enable for all channels to GX_FALSE. This function only configures the lighting + * channel; to output the result of the channel computation, use GX_SetNumChans(). + * + * \note Even though channels GX_COLOR0 and GX_ALPHA0 are controlled separately for lighting, they are rasterized together as one RGBA color, effectively + * GX_COLOR0A0. The same is true for GX_COLOR1 and GX_ALPHA1-- effectively, they are rasterized as GX_COLOR1A1. Since there is only one rasterizer for + * color in the graphics hardware, you must choose which color to rasterize for each stage in the Texture Environment (TEV) unit. This is accomplished + * using GX_SetTevOrder().

+ * + * \note In order to use a vertex color in channel GX_COLOR1A1, two colors per vertex must be supplied, i.e. both GX_VA_CLR0 and GX_VA_CLR1 must be + * enabled in the current vertex descriptor. If only GX_VA_CLR0 or GX_VA_CLR1 is enabled in the current vertex descriptor, the vertex color is + * directed to the channel GX_VA_COLOR0A0.

+ * + * \note When \a ambsrc is set to GX_SRC_REG, the color set by GX_SetChanAmbColor() is used as the ambient color. When \a matsrc is GX_SRC_REG, the color set + * by GX_SetChanMatColor() is used as the material color. + * + * \param[in] channel color channel to use + * \param[in] enable whether or not to enable lighting for this channel + * \param[in] ambsrc source for the ambient color + * \param[in] matsrc source for the material color + * \param[in] litmask \ref lightid or IDs to associate with this channel + * \param[in] diff_fn \ref difffn to use + * \param[in] attn_fn \ref attenfunc to use + * + * \return none + */ +void GX_SetChanCtrl(s32 channel,u8 enable,u8 ambsrc,u8 matsrc,u8 litmask,u8 diff_fn,u8 attn_fn); + +/*! + * \fn void GX_SetChanAmbColor(s32 channel,GXColor color) + * \brief Sets the ambient color register for color channel \a chan. + * + * \details This color will be used by the channel as the ambient color if the ambient source, set by GX_SetChanCtrl(), is GX_SRC_REG. + * + * \param[in] channel channel to set + * \param[in] color color to set it to + * + * \return none + */ +void GX_SetChanAmbColor(s32 channel,GXColor color); + +/*! + * \fn void GX_SetChanMatColor(s32 channel,GXColor color) + * \brief Sets the material color register for color channel \a chan. + * + * \details This color will be used by the channel as the material color if the material source, set by GX_SetChanCtrl(), is GX_SRC_REG. + * + * \param[in] channel channel to set + * \param[in] color color to set it to + * + * \return none + */ +void GX_SetChanMatColor(s32 channel,GXColor color); + +/*! + * \fn void GX_SetArray(u32 attr,void *ptr,u8 stride) + * \brief Sets the array base pointer and stride for a single attribute. + * + * \details The array base and stride are used to compute the address of indexed attribute data using the equation:

+ * + *       attr_addr = \a ptr + attr_idx * \a stride + * + * When drawing a graphics primitive that has been enabled to use indexed attributes (see GX_SetVtxDesc()), attr_idx is supplied in the vertex + * data. The format and size of the data in the array must also be described using GX_SetVtxAttrFmt(). You can also index other data, such as + * matrices (see GX_LoadPosMtxIdx(), GX_LoadNrmMtxIdx3x3(), and GX_LoadTexMtxIdx()), and light objects (see GX_LoadLightObjIdx()). In the case + * of matrices and light objects, the size and format of the data to be loaded is implied by the function call. + * + * There is a base pointer, \a ptr, for each type of attribute as well as for light data and matrices. Each attribute can be stored in its own + * array for maximum data compression (i.e., removal of redundant attribute data). The \a stride is in byte units and is the distance between + * attributes in the array. + * + * \note Indexed data is loaded into a vertex cache in the graphics processor. The vertex cache fetches 32B of data for each cache miss; + * therefore, there is a small performance benefit to aligning attribute arrays to 32B, and possibly for arranging vertex data so that it + * doesn't span 32B boundaries. Conveniently enough, memalign() returns 32-byte aligned pointers. For static data arrays, you can use the + * ATTRIBUTE_ALIGN(32) attribute macro to align the \a ptr to 32B. + * + * \param[in] attr \ref vtxattr that the array is storing + * \param[in] ptr pointer to the array itself + * \param[in] stride stride (in bytes) between each element in the array + * + * \return none + */ +void GX_SetArray(u32 attr,void *ptr,u8 stride); + +/*! + * \fn void GX_SetVtxAttrFmt(u8 vtxfmt,u32 vtxattr,u32 comptype,u32 compsize,u32 frac) + * \brief Sets the attribute format (\a vtxattr) for a single attribute in the Vertex Attribute Table (VAT). + * + * \details Each attribute format describes the data type (comptype), number of elements (compsize), and fixed point format (frac), if required. The + * are eight vertex formats available in the VAT. The vertex format describes the format of all attributes in a vertex. The application can pre-program + * all eight vertex formats and then select one of them during the actual drawing of geometry (See GX_Begin()). Note that all vertices used to draw a + * particular graphics primitive will have the same format. The vertex format set using this function, along with the current vertex descriptor set + * using GX_SetVtxDesc(), completely define the vertex data format. + * + * \note The vertex format allows data to be sent to the graphics processor in its most quantized format. The graphics hardware will inverse-quantize + * the data (into floating point format) before it is used. The vertex attribute format is used to communicate the data quantization format to the hardware.

+ * + * \note GX_VA_NRM and GX_VA_NBT attributes share the same type. Also, the frac for these attributes is fixed according to the type. The component count + * (compsize) for GX_VA_NRM must be set to GX_NRM_XYZ. The component count for GX_VA_NBT must be set to GX_NRM_NBT or GX_NRM_NBT3. + * + * \param[in] vtxfmt \ref vtxfmt + * \param[in] vtxattr \ref vtxattr + * \param[in] comptype \ref comptype + * \param[in] compsize \ref compsize + * \param[in] frac number of fractional bits in a fixed-point number + * + * \return none + */ +void GX_SetVtxAttrFmt(u8 vtxfmt,u32 vtxattr,u32 comptype,u32 compsize,u32 frac); + +/*! + * \fn void GX_SetVtxAttrFmtv(u8 vtxfmt,GXVtxAttrFmt *attr_list) + * \brief Sets multiple attribute formats within a single vertex format. + * + * \details This is useful when you need to set all the attributes in a vertex format at once (e.g., during graphics initialization). + * + * \note The constant GX_MAX_VTXATTRFMT_LISTSIZE should be used to allocate the list. You can get a current vertex format using GX_GetVtxAttrFmtv(). + * + * \param[in] vtxfmt \ref vtxfmt + * \param[in] attr_list pointer to array of GXVtxAttrFmt structs to draw from + * + * \return none + */ +void GX_SetVtxAttrFmtv(u8 vtxfmt,GXVtxAttrFmt *attr_list); + +/*! + * \fn void GX_SetVtxDesc(u8 attr,u8 type) + * \brief Sets the \a type of a single attribute (\a attr) in the current vertex descriptor. + * + * \details The current vertex descriptor defines which attributes are present in a vertex and how each attribute is referenced. The current + * vertex descriptor is used by the Graphics Processor (GP) to interpret the graphics command stream produced by the GX API. In particular, + * the current vertex descriptor is used to parse the vertex data that is present in the command stream. + * + * \param[in] attr \ref vtxattr + * \param[in] type \ref vtxattrin + * + * \return none + */ +void GX_SetVtxDesc(u8 attr,u8 type); + +/*! + * \fn void GX_SetVtxDescv(GXVtxDesc *attr_list) + * \brief Sets the type of multiple attributes. + * + * \details This function is used when more than one attribute needs to be set (e.g., during initialization of geometry). + * + * \note The constant GX_MAX_VTXATTRFMT_LISTSIZE can be used to allocate memory for \a attr_list + * + * \param[in] attr_list array of pointers to GXVtxDesc structs; last element of the array should be GX_VA_NULL + * + * \return none + */ +void GX_SetVtxDescv(GXVtxDesc *attr_list); + +/*! + * \fn void GX_GetVtxDescv(GXVtxDesc *attr_list) + * \brief Gets the type of multiple attributes. + * + * \details This function saves the attributes that are current set. This is usually used in conjunction with GX_SetVtxDescv + * + * \note The constant GX_MAX_VTXATTRFMT_LISTSIZE must be used to allocate memory for \a attr_list + * + * \param[in] attr_list array of pointers to GXVtxDesc structs + * + * \return none + */ +void GX_GetVtxDescv(GXVtxDesc *attr_list); + +/*! + * \fn u32 GX_EndDispList() + * \brief Ends a display list and resumes writing graphics commands to the CPU FIFO. + * + * \details This function returns the size of the display list written to the display list buffer since GX_BeginDispList() was called. If + * the display list size exceeds the size of the buffer allocated, a zero length size will be returned. The display list size is a + * multiple of 32B and any unsed commands in the last 32B will be padded with GX_NOP. The size returned should be passed to + * GX_CallDispList() when the display list needs to be executed. + * + * \note Due to the mechanics of flushing the write-gather pipe (which is used to create the display list), the display buffer should be + * at least 32 bytes larger than the maximum expected amount of data stored. This function calls GX_Flush(), and thus it is not necessary + * to call GX_Flush() explicitly after creating the display list.

+ * + * \note A display list cannot be nested; i.e., no display list functions (GX_BeginDispList(), GX_EndDispList() and GX_CallDispList()) can + * be called between a GX_BeginDispList() and GX_EndDispList() pair.

+ * + * \note To execute a display list, use GX_CallDispList(). + * + * \return 0 if display list size exceeds buffer, otherwise gives list size in bytes + * + * \bug Specifying a display list buffer size for GX_BeginDispList() the exact size that the display list will be (after padding) will cause + * this function to return a very large (and very incorrect) value. + */ +u32 GX_EndDispList(); + +/*! + * \fn void GX_Begin(u8 primitve,u8 vtxfmt,u16 vtxcnt) + * \brief Begins drawing of a graphics primitive. + * + * \details To draw a graphics primitive, a stream of vertex data matching the description of both GX_SetVtxDesc() and GX_SetVtxAttrFmt() is + * enclosed between GX_Begin()/GX_End() pairs. The number of vertices between GX_Begin() and GX_End() must match that specified by the \a vtxcnt + * parameter. The type of the primitive will determine the minimum number of vertices required. For example, a GX_TRIANGLES primitive must + * have at least 3 vertices. + * + * \note Primitives in which the vertex order is clockwise to the viewer are considered front-facing (for culling purposes). + * + * \param[in] primitve \ref primtype to draw + * \param[in] vtxfmt \ref vtxfmt to use + * \param[in] vtxcnt number of vertices being drawn; maximum is 65536 + */ +void GX_Begin(u8 primitve,u8 vtxfmt,u16 vtxcnt); + +/*! + * \fn void GX_BeginDispList(void *list,u32 size) + * \brief Begins a display list and disables writes to the FIFO currently attached to the CPU. + * + * \details After this function is called, GX API functions that normally send command or data into the CPU FIFO will send them to the + * display list buffer instead of the FIFO until GX_EndDispList() is called. Writes to the CPU FIFO will be re-enabled when the function + * GX_EndDispList() executes. + * + * Basically you can put most of GX API commands into a display list. However, since the use of display list can bypass all state + * coherences controlled by GX API in run-time, sometimes it brings some state collisions or incoherences that may lead to unexpected + * behavior or even graphics pipeline hang. The most recommended safe way is putting only primitives (regions enclosed by GX_Begin() and + * GX_End()) that don't cause any state collisions. + * + * \note The application is expected to allocate the memory for the display list buffer. If the display list exceeds the maximum size + * of the buffer, GX_EndDispList() will return 0. The address of the buffer must be 32-byte aligned; memalign() can return 32-byte-aligned + * pointers. You can use the macro ATTRIBUTE_ALIGN(32) to align statically allocated buffers.

+ * + * \note The CPU's write-gather pipe is used to write graphics commands to the display list. Therefore, the display list buffer must be + * forced out of the CPU cache prior to being filled. DCInvalidateRange() may be used for this purpose. In addition, due to the mechanics + * of flushing the write-gather pipe, the display list buffer should be at least 63 bytes larger than the maximum expected amount of data + * stored.

+ * + * \note A display list cannot be nested; i.e., no display list functions (GX_BeginDispList(), GX_EndDispList() and GX_CallDispList()) can + * be called between a GX_BeginDispList() and GX_EndDispList() pair.

+ * + * \note To execute a display list, use GX_CallDispList(). + * + * \param[in] list 32-byte aligned buffer to hold the list + * \param[in] size size of the buffer, multiple of 32 + * + * \return none + */ +void GX_BeginDispList(void *list,u32 size); + +/*! + * \fn void GX_CallDispList(void *list,u32 nbytes) + * \brief Causes the GP to execute graphics commands from the display \a list instead of from the GP FIFO. + * + * \details When the number of bytes specified by \a nbytes have been read, the graphics processor will resume executing + * commands from the graphics FIFO. Graphics commands from a display list are prefetched into a separate 4KB FIFO. This prevents + * any data prefetched for the main graphics command stream from being lost during the display list call. + * + * \note A display list cannot call another display list.

+ * + * \note The display list must be padded to a length of 32B. All the data in the display list is interpreted by the graphics + * processor, so any unused memory at the end of a display list should be set to GX_NOP. If you create the display list using + * GX_BeginDispList()/GX_EndDispList(), this padding will be inserted automatically. + * + * \param[in] list 32-byte aligned pointer to the display list buffer + * \param[in] nbytes number of bytes in the display list. Use the return value of GX_EndDispList() here. + * + * \return none + */ +void GX_CallDispList(void *list,u32 nbytes); + +/*! + * \fn static inline void GX_End() + * \brief Used to end the drawing of a graphics primitive. This does nothing in libogc. + * + * \return none + */ +static inline void GX_End() +{ +} + +static inline void GX_Position3f32(f32 x,f32 y,f32 z) +{ + wgPipe->F32 = x; + wgPipe->F32 = y; + wgPipe->F32 = z; +} + +static inline void GX_Position3u16(u16 x,u16 y,u16 z) +{ + wgPipe->U16 = x; + wgPipe->U16 = y; + wgPipe->U16 = z; +} + +static inline void GX_Position3s16(s16 x,s16 y,s16 z) +{ + wgPipe->S16 = x; + wgPipe->S16 = y; + wgPipe->S16 = z; +} + +static inline void GX_Position3u8(u8 x,u8 y,u8 z) +{ + wgPipe->U8 = x; + wgPipe->U8 = y; + wgPipe->U8 = z; +} + +static inline void GX_Position3s8(s8 x,s8 y,s8 z) +{ + wgPipe->S8 = x; + wgPipe->S8 = y; + wgPipe->S8 = z; +} + +static inline void GX_Position2f32(f32 x,f32 y) +{ + wgPipe->F32 = x; + wgPipe->F32 = y; +} + +static inline void GX_Position2u16(u16 x,u16 y) +{ + wgPipe->U16 = x; + wgPipe->U16 = y; +} + +static inline void GX_Position2s16(s16 x,s16 y) +{ + wgPipe->S16 = x; + wgPipe->S16 = y; +} + +static inline void GX_Position2u8(u8 x,u8 y) +{ + wgPipe->U8 = x; + wgPipe->U8 = y; +} + +static inline void GX_Position2s8(s8 x,s8 y) +{ + wgPipe->S8 = x; + wgPipe->S8 = y; +} + +static inline void GX_Position1x8(u8 index) +{ + wgPipe->U8 = index; +} + +static inline void GX_Position1x16(u16 index) +{ + wgPipe->U16 = index; +} + +static inline void GX_Normal3f32(f32 nx,f32 ny,f32 nz) +{ + wgPipe->F32 = nx; + wgPipe->F32 = ny; + wgPipe->F32 = nz; +} + +static inline void GX_Normal3s16(s16 nx,s16 ny,s16 nz) +{ + wgPipe->S16 = nx; + wgPipe->S16 = ny; + wgPipe->S16 = nz; +} + +static inline void GX_Normal3s8(s8 nx,s8 ny,s8 nz) +{ + wgPipe->S8 = nx; + wgPipe->S8 = ny; + wgPipe->S8 = nz; +} + +static inline void GX_Normal1x8(u8 index) +{ + wgPipe->U8 = index; +} + +static inline void GX_Normal1x16(u16 index) +{ + wgPipe->U16 = index; +} + +static inline void GX_Color4u8(u8 r,u8 g,u8 b,u8 a) +{ + wgPipe->U8 = r; + wgPipe->U8 = g; + wgPipe->U8 = b; + wgPipe->U8 = a; +} + +static inline void GX_Color3u8(u8 r,u8 g,u8 b) +{ + wgPipe->U8 = r; + wgPipe->U8 = g; + wgPipe->U8 = b; +} + +static inline void GX_Color3f32(f32 r, f32 g, f32 b) +{ + wgPipe->U8 = (u8)(r * 255.0); + wgPipe->U8 = (u8)(g * 255.0); + wgPipe->U8 = (u8)(b * 255.0); +} + +static inline void GX_Color1u32(u32 clr) +{ + wgPipe->U32 = clr; +} + +static inline void GX_Color1u16(u16 clr) +{ + wgPipe->U16 = clr; +} + +static inline void GX_Color1x8(u8 index) +{ + wgPipe->U8 = index; +} + +static inline void GX_Color1x16(u16 index) +{ + wgPipe->U16 = index; +} + +static inline void GX_TexCoord2f32(f32 s,f32 t) +{ + wgPipe->F32 = s; + wgPipe->F32 = t; +} + +static inline void GX_TexCoord2u16(u16 s,u16 t) +{ + wgPipe->U16 = s; + wgPipe->U16 = t; +} + +static inline void GX_TexCoord2s16(s16 s,s16 t) +{ + wgPipe->S16 = s; + wgPipe->S16 = t; +} + +static inline void GX_TexCoord2u8(u8 s,u8 t) +{ + wgPipe->U8 = s; + wgPipe->U8 = t; +} + +static inline void GX_TexCoord2s8(s8 s,s8 t) +{ + wgPipe->S8 = s; + wgPipe->S8 = t; +} + +static inline void GX_TexCoord1f32(f32 s) +{ + wgPipe->F32 = s; +} + +static inline void GX_TexCoord1u16(u16 s) +{ + wgPipe->U16 = s; +} + +static inline void GX_TexCoord1s16(s16 s) +{ + wgPipe->S16 = s; +} + +static inline void GX_TexCoord1u8(u8 s) +{ + wgPipe->U8 = s; +} + +static inline void GX_TexCoord1s8(s8 s) +{ + wgPipe->S8 = s; +} + +static inline void GX_TexCoord1x8(u8 index) +{ + wgPipe->U8 = index; +} + +static inline void GX_TexCoord1x16(u16 index) +{ + wgPipe->U16 = index; +} + +static inline void GX_MatrixIndex1x8(u8 index) +{ + wgPipe->U8 = index; +} + +/*! + * \fn void GX_AdjustForOverscan(GXRModeObj *rmin,GXRModeObj *rmout,u16 hor,u16 ver) + * \brief Takes a given render mode and returns a version that is reduced in size to account for overscan. + * + * \details The number of pixels specified by \a hor is subtracted from each side of the screen, and the number of pixels specified + * by \a ver is subtracted from both the top and the bottom of the screen. The active screen area is centered within what the render + * mode specified before the adjustment. + * + * \note Due to the wide possibilities of how a render mode may be configured, this function may not work in all cases. For instance, + * if you use Y-scaling to create a size difference between the EFB and XFB, this function may not do the right thing. In such cases, + * you should configure the desired render mode manually (or else call this function and then fix up the results). + * + * \param[in] rmin rmode that is being copied + * \param[in] rmout rmode to hold the adjusted version. Needs to be allocated but can be uninitialized. + * \param[in] hor pixels to trim from each side of the screen + * \param[in] ver pixels to tim from top and bottom of the screen + * + * \returns none + */ +void GX_AdjustForOverscan(GXRModeObj *rmin,GXRModeObj *rmout,u16 hor,u16 ver); + +/*! + * \fn void GX_LoadPosMtxImm(Mtx mt,u32 pnidx) + * \brief Used to load a 3x4 modelview matrix \a mt into matrix memory at location \a pnidx. + * + * \details This matrix can be used to transform positions in model space to view space, either by making the matrix the current one (see + * GX_SetCurrentMtx()), or by setting a matrix \a pnidx for each vertex. The parameter \a mt is a pointer to a 3x4 (row x column) matrix. The + * parameter \a pnidx is used to refer to the matrix location (see \ref pnmtx) in matrix memory. + * + * You can also load a normal matrix (GX_LoadNrmMtxImm() or GX_LoadNrmMtxIdx3x3()) to the same \a pnidx. Generally, the normal matrix + * will be the inverse transpose of the position matrix. The normal matrix is used during vertex lighting. In cases where the modelview + * and inverse transpose of the modelview (excluding translation) are the same, you can load the same matrix for both position and normal + * transforms. + * + * \note The matrix data is copied from DRAM through the CPU cache into the Graphics FIFO, so matrices loaded using this function are always + * coherent with the CPU cache. + * + * \param[in] mt the matrix to load + * \param[in] pnidx \ref pnmtx to load into + * + * \return none + */ +void GX_LoadPosMtxImm(Mtx mt,u32 pnidx); + +/*! + * \fn void GX_LoadPosMtxIdx(u16 mtxidx,u32 pnidx) + * \brief Loads a 3x4 modelview matrix at index \a mtxidx from the array in main memory. + * + * \details The array is set by GX_SetArray(), and the matrix is loaded into matrix memory at index \a pnidx (see \ref pnmtx). This + * modelview matrix is used to transform positions in model space to view space, either by making the matrix the current one (see + * GX_SetCurrentMtx()) or by setting a matrix \a pnidx for each vertex (see GX_SetVtxDesc()). The matrix will be loaded through the vertex cache. + * + * You can also load a normal matrix (GX_LoadNrmMtxImm() or GX_LoadNrmMtxIdx3x3()) to the same \a pnidx. Generally, the normal matrix + * will be the inverse transpose of the position matrix. The normal matrix is used during vertex lighting. In cases where the modelview + * and inverse transpose of the modelview (excluding translation) are the same, you can load the same matrix for both position and normal + * transforms. Since indexed matrix loads are through the vertex cache, you will only incur the main memory bandwidth load of one matrix load. + * + * \note The matrix is loaded directly from main memory into the matrix memory thrugh the vertex cache, so it is incoherent with the CPU's cache. + * It is the application's responsibility to flush any matrix data from the CPU cache (see DCStoreRange()) before calling this function. + * + * \param[in] mtxidx index to the matrix array to load + * \param[in] pnidx \ref pnmtx to load into + * + * \return none + */ +void GX_LoadPosMtxIdx(u16 mtxidx,u32 pnidx); + +/*! + * \fn void GX_LoadNrmMtxImm(Mtx mt,u32 pnidx) + * \brief Used to load a normal transform matrix into matrix memory at location \a pnidx from the 4x3 matrix \a mt. + * + * \details This matrix is used to transform normals in model space to view space, either by making it the current matrix (see GX_SetCurrentMtx()), + * or by setting a matrix pnidx for each vertex. The parameter \a mt is a pointer to a 3x4 (row x column) matrix. The translation terms + * in the 3x4 matrix are not needed for normal rotation and are ignored during the load. The parameter \a pnidx is used to refer to the + * matrix location (see \ref pnmtx) in matrix memory. + * + * \note You can also load a position matrix (GX_LoadPosMtxImm()) to the same \a pnidx. Normally, the normal matrix will be the inverse transpose of + * the position (modelview) matrix and is used during vertex lighting. In cases where the modelview and the inverse transpose of the modelview + * matrix (excluding translation) are the same, the same matrix can be loaded for both normal and position matrices.

+ * + * \note The matrix data is copied from main memory or the CPU cache into the Graphics FIFO, so matrices loaded by this function are always coherent + * with the CPU cache.

+ * + * \param[in] mt the matrix to load + * \param[in] pnidx \ref pnmtx to load into + * + * \return none + */ +void GX_LoadNrmMtxImm(Mtx mt,u32 pnidx); + +/*! + * \fn void GX_LoadNrmMtxIdx3x3(u16 mtxidx,u32 pnidx) + * \brief Loads a 3x3 normal matrix into matrix memory at location \a pnidx from a 3x3 matrix located at index \a mtxidx + * from the array in main memory. + * + * \details The array is set by set by GX_SetArray(), and the matrix is loaded into matrix memory at index \a pnidx. This matrix can be used to + * transform normals in model space to view space, either by making the matrix the current one (see GX_SetCurrentMtx()), or by setting a + * matrix \a pnidx for each vertex (see GX_SetVtxDesc()). The matrix will be loaded through the vertex cache. You can also load a position + * matrix (GX_LoadPosMtxImm() or GX_LoadPosMtxIdx()) to the same \a pnidx. + * + * \note You cannot use an indexed load to load a 3x3 matrix from an indexed 3x4 matrix in main memory; you must use GX_LoadNrmMtxImm() for + * this case.

+ * + * \note The matrix is loaded directly from main memory into the matrix memory through the vertex cache, therefore it is incoherent with the + * CPU's cache. It is the application's responsibility to flush any matrix data from the CPU cache (see DCStoreRange()) before calling this + * function. + * + * \param[in] mtxidx index to the matrix array to load + * \param[in] pnidx \ref pnmtx to load into + * + * \return none + */ +void GX_LoadNrmMtxIdx3x3(u16 mtxidx,u32 pnidx); + +/*! + * \fn void GX_LoadTexMtxImm(Mtx mt,u32 texidx,u8 type) + * \brief Loads a texture matrix \a mt into the matrix memory at location \a texidx. + * + * \details The matrix loaded can be either a 2x4 or 3x4 matrix as indicated by \a type. You can use the loaded matrix to + * transform texture coordinates, or to generate texture coordinates from position or normal vectors. Such generated texture + * coordinates are used for projected textures, reflection mapping, etc. See GX_SetTexCoordGen() for more details. + * + * Texture matrices can be either 2x4 or 3x4. GX_MTX_2x4 matrices can be used for simple translations and/or rotations of texture + * coordinates. GX_MTX_3x4 matrices are used when projection is required. + * + * \note The default matrix memory configuration allows for ten (3x4 or 2x4) texture matrices, and a 3x4 identity matrix. The GX_IDENTITY + * matrix is preloaded by GX_Init().

+ * + * \note This function allows one to load post-transform texture matrices as well. Specifying a texidx in the range of \ref dttmtx will load a + * post-transform texture matrix instead of a regular, first-pass texture matrix. Note that post-transform matrices are always 3x4. Refer to + * GX_SetTexCoordGen2() for information about how to use post-transform texture matrices. + * + * \param[in] mt the matrix to load + * \param[in] texidx \ref texmtx + * \param[in] type \ref mtxtype + * + * \return none + */ +void GX_LoadTexMtxImm(Mtx mt,u32 texidx,u8 type); + +/*! + * \fn void GX_LoadTexMtxIdx(u16 mtxidx,u32 texidx,u8 type) + * \brief Loads a texture matrix at index \a mtxidx from the array in main memory + * + * \details The array is set by GX_SetArray(), and the matrix is loaded into matrix memory at location \a texid. The loaded matrix can be + * either 2x4 or 3x4 as indicated by \a type. This matrix can be used to generate texture coordinates from positions, normals, and input + * texture coordinates (see GX_SetTexCoordGen()). The matrix is loaded through the vertex cache. The size of the matrix to load is indicated by its + * \a type. Texture matrices can be either 2x4 or 3x4. GX_MTX_2x4 matrices can be used for simple translations and/or rotations of texture + * coordinates; GX_MTX_3x4 matrices are used when projection is required. + * + * \note The matrix is loaded directly from main memory into the matrix memory through the vertex cache, so it is incoherent with the CPU's + * cache. It is the application's responsibility to flush any matrix data from the CPU cache (see DCStoreRange()) before calling this function.

+ * + * \note This function allows one to load post-transform texture matrices as well. Specifying a \a texidx in the range of \ref dttmtx will load a + * post-transform texture matrix instead of a regular, first-pass texture matrix. Note that post-transform matrices are always 3x4. Refer to + * GX_SetTexCoordGen2() for information about how to use post-transform texture matrices. + * + * \param[in] mtxidx index to the matrix array to load + * \param[in] texidx \ref texmtx + * \param[in] type \ref mtxtype + * + * \return none + */ +void GX_LoadTexMtxIdx(u16 mtxidx,u32 texidx,u8 type); + +/*! + * \fn void GX_SetCurrentMtx(u32 mtx) + * \brief Selects a specific matrix to use for transformations. + * + * \details The matrix \a mtx specified will be used to select the current modelview transform matrix and normal transform matrix, + * as long as a matrix index is not present in the vertex data (see GX_SetVtxDesc()). If the current vertex descriptor enables GX_VA_PTNMTXIDX, + * the matrix \a mtx specified by this function will be overwritten when the vertices are drawn. + * + * \param[in] mtx \ref pnmtx + * + * \return none + */ +void GX_SetCurrentMtx(u32 mtx); + +/*! + * \fn void GX_SetTevOp(u8 tevstage,u8 mode) + * \brief Simplified function to set various TEV parameters for this \a tevstage based on a predefined combiner \a mode. + * + * \details This is a convenience function designed to make initial programming of the Texture Environment unit (TEV) easier. This function calls + * GX_SetTevColorIn(), GX_SetTevColorOp(), GX_SetTevAlphaIn() and GX_SetTevAlphaOp() with predefined arguments to implement familiar texture + * combining functions. + * + * \note To enable a consecutive set of TEV stages, you must call GX_SetNumTevStages(). + * + * \param[in] tevstage \ref tevstage. + * \param[in] mode \ref tevdefmode + * + * \return none + */ +void GX_SetTevOp(u8 tevstage,u8 mode); + +/*! + * \fn void GX_SetTevColor(u8 tev_regid,GXColor color) + * \brief Used to set one of the primary color registers in the TEV unit. + * + * \details These registers are available to all TEV stages. At least one of these registers is used to pass the output of one TEV stage to + * the next in a multi-texture configuration. The application is responsible for allocating these registers so that no collisions in usage occur. + * + * \note This function can only set unsigned 8-bit colors. To set signed, 10-bit colors use GX_SetTevColorS10(). + * + * \param[in] tev_regid \ref tevcoloutreg. + * \param[in] color Constant color value. + * + * \return none + */ +void GX_SetTevColor(u8 tev_regid,GXColor color); + +/*! + * \fn void GX_SetTevColorS10(u8 tev_regid,GXColorS10 color) + * \brief Used to set one of the constant color registers in the TEV unit. + * + * \details These registers are available to all TEV stages. At least one of these registers is used to pass the output of one TEV stage to the + * next in a multi-texture configuration. The application is responsible for allocating these registers so that no collisions in usage occur. + * + * \note This function enables the color components to be signed 10-bit numbers. To set 8-bit unsigned colors (the common case), use GX_SetTevColor(). + * + * \param[in] tev_regid \ref tevcoloutreg. + * \param[in] color Constant color value in S10 format. + * + * \return none + */ +void GX_SetTevColorS10(u8 tev_regid,GXColorS10 color); + +/*! + * \fn void GX_SetTevColorIn(u8 tevstage,u8 a,u8 b,u8 c,u8 d) + * \brief Sets the color input sources for one \a tevstage of the Texture Environment (TEV) color combiner. + * + * \details This includes constant (register) colors and alphas, texture color/alpha, rasterized color/alpha (the result of per-vertex lighting), + * and a few useful constants. + * + * \note The input controls are independent for each TEV stage. + * + * \param[in] tevstage \ref tevstage + * \param[in] a \ref tevcolorarg + * \param[in] b \ref tevcolorarg + * \param[in] c \ref tevcolorarg + * \param[in] d \ref tevcolorarg + * + * \return none + */ +void GX_SetTevColorIn(u8 tevstage,u8 a,u8 b,u8 c,u8 d); + +/*! + * \fn void GX_SetTevAlphaIn(u8 tevstage,u8 a,u8 b,u8 c,u8 d) + * \brief Sets the alpha input sources for one \a tevstage of the Texture Environment (TEV) alpha combiner. + * + * \details There are fewer alpha inputs than color inputs, and there are no color channels available in the alpha combiner. + * + * \note The input controls are independent for each TEV stage. + * + * \param[in] tevstage \ref tevstage + * \param[in] a \ref tevalphaarg + * \param[in] b \ref tevalphaarg + * \param[in] c \ref tevalphaarg + * \param[in] d \ref tevalphaarg + * + * \return none + */ +void GX_SetTevAlphaIn(u8 tevstage,u8 a,u8 b,u8 c,u8 d); + +/*! + * \fn void GX_SetTevColorOp(u8 tevstage,u8 tevop,u8 tevbias,u8 tevscale,u8 clamp,u8 tevregid) + * \brief Sets the \a tevop, \a tevbias, \a tevscale and \a clamp-mode operation for the color combiner + * for this \a tevstage of the TEV unit. + * + * \details This function also specifies the register, \a tevregid, that will contain the result of the color combiner function. The color + * combiner function is:

+ * + *       \a tevregid = (d (\a tevop) ((1.0 - c)*a + c*b) + \a tevbias) * \a tevscale;

+ * + * + * The input sources a,b,c and d are set using GX_SetTevColorIn(). + * + * \param[in] tevstage \ref tevstage. + * \param[in] tevop \ref tevop + * \param[in] tevbias \ref tevbias. + * \param[in] tevscale \ref tevscale. + * \param[in] clamp Clamp results when GX_TRUE. + * \param[in] tevregid \ref tevcoloutreg + * + * \return none + */ +void GX_SetTevColorOp(u8 tevstage,u8 tevop,u8 tevbias,u8 tevscale,u8 clamp,u8 tevregid); + + +/*! + * \fn void GX_SetTevAlphaOp(u8 tevstage,u8 tevop,u8 tevbias,u8 tevscale,u8 clamp,u8 tevregid) + * \brief Sets the \a tevop, \a tevbias, \a tevscale and \a clamp-mode operation for the alpha combiner + * for this \a tevstage of the TEV unit. + * + * \details This function also specifies the register, \a tevregid, that will contain the result of the alpha combiner function. The alpha + * combiner function is:

+ * + *       \a tevregid = (d (\a tevop) ((1.0 - c)*a + c*b) + \a tevbias) * \a tevscale;

+ * + * The input sources a,b,c and d are set using GX_SetTevAlphaIn(). + * + * \param[in] tevstage \ref tevstage. + * \param[in] tevop \ref tevop + * \param[in] tevbias \ref tevbias. + * \param[in] tevscale \ref tevscale. + * \param[in] clamp Clamp results when GX_TRUE. + * \param[in] tevregid \ref tevcoloutreg + * + * \return none + */ +void GX_SetTevAlphaOp(u8 tevstage,u8 tevop,u8 tevbias,u8 tevscale,u8 clamp,u8 tevregid); + +/*! + * \fn void GX_SetNumTexGens(u32 nr) + * \brief Sets the number of texture coordinates that are generated and available for use in the Texture Environment TEV stages. + * + * \details Texture coordinates are generated from input data as described by GX_SetTexCoordGen(). The generated texture coordinates are linked to + * specific textures and specific TEV stages using GX_SetTevOrder(). + * + * \note A consecutive number of texture coordinates may be generated, starting at GX_TEXCOORD0. A maximum of 8 texture coordinates may be generated. + * If \a nr is set to 0, no texture coordinates will be generated. In this case, at least one color channel must be output (see GX_SetNumChans()). + * + * \param[in] nr number of tex coords to generate, between 0 and 8 inclusive + * + * \return none + */ +void GX_SetNumTexGens(u32 nr); + +/*! + * \fn void GX_SetTexCoordGen(u16 texcoord,u32 tgen_typ,u32 tgen_src,u32 mtxsrc) + * \brief Specifies how texture coordinates are generated. + * + * \details Output texture coordinates are usually the result of some transform of an input attribute; either position, normal, or texture coordinate. + * You can also generate texture coordinates from the output color channel of the per-vertex lighting calculations. In C-language syntax the texture + * coordinate generation function would look like this:

+ * + *       \a texcoord = \a tgen_typ(\a tgen_src, \a mtxsrc);

+ * + * The current vertex descriptor as set by GX_SetVtxDesc() only describes the data input to the graphics processor. Using this function, you can create + * new output texture coordinates from the input data. The texcoord parameter is used to give the output texture coordinate a name. This texture + * coordinate can be bound to a texture using GX_SetTevOrder(). GX_SetNumTexGens() specifies a consecutive number of texture coordinates, starting at + * GX_TEXCOORD0, that are available to GX_SetTevOrder(). + * + * \ref texmtx defines a default set of texture matrix names that can be supplied as mtxsrc. The matrix names are actually row addresses (4 floats per + * row) in the matrix memory that indicate the first row of a loaded matrix. The user may define another memory map of matrix memory to suit their + * needs. Keep in mind, however, that modelview matrices (see GX_LoadPosMtxImm() and \ref pnmtx) and texture matrices share matrix memory. + * + * \note Input texture coordinates must always go through the texture coordinate generation hardware. GX_Init() initializes the hardware (by calling + * this function) so that all texture coordinates are transformed by the GX_IDENTITY matrix in order to appear as if input coordinates are passed + * unchanged through to the texture hardware. + * + * There are 8 output texture coordinates that can be referenced in any of the 16 TEV stages. There are a maximum of 8 input texture coordinates. + * + * \param[in] texcoord \ref texcoordid + * \param[in] tgen_typ \ref texgentyp + * \param[in] tgen_src \ref texgensrc + * \param[in] mtxsrc \ref texmtx + * + * \return none + */ +void GX_SetTexCoordGen(u16 texcoord,u32 tgen_typ,u32 tgen_src,u32 mtxsrc); + +/*! + * \fn void GX_SetTexCoordGen2(u16 texcoord,u32 tgen_typ,u32 tgen_src,u32 mtxsrc,u32 normalize,u32 postmtx) + * \brief An extension of GX_SetTexCoordGen(). It allows one to specify additional texgen options. + * + * \details The first four arguments are identical to those for GX_SetTexCoordGen() and function in the same way. All requirements for the first + * four arguments are the same as they are for that function as well. The new options only apply for "ordinary" texgens, where the texgen type is + * GX_TG_MTX2x4 or GX_TG_MTX3x4. They do not work for light-based texgens or emboss texgens. + * + * The \a normalize argument allows the computed texcoord to be normalized after the multiplication by \a mtxsrc (the first-pass transformation). + * After the optional normalization step, the texcoord is then multiplied by the 3x4 matrix \a postmtx. This matrix is refered to as the + * post-transform matrix. + * + * The result of this step is the texture coordinate that is used to look up the texture. + * + * \note The post-transform matrices are separate from the first pass matrices. They are stored in a separate memory area in the same format as the + * first pass matrices, except that all matrices have three rows.

+ * + * \note When a vertex contains only position and one texture coordinate and the texgen type is GX_TG_MTX2x4, there are certain limitations. In + * this special performance case, normalization is not performed (even if specified). + * + * \param[in] texcoord \ref texcoordid + * \param[in] tgen_typ \ref texgentyp + * \param[in] tgen_src \ref texgensrc + * \param[in] mtxsrc \ref texmtx + * \param[in] normalize if GX_TRUE, normalize tex coord after first-pass transform. Only used with GX_TG_MTX*. + * \param[in] postmtx \ref dttmtx + * + * \return none + */ +void GX_SetTexCoordGen2(u16 texcoord,u32 tgen_typ,u32 tgen_src,u32 mtxsrc,u32 normalize,u32 postmtx); + +/*! + * \fn void GX_SetZTexture(u8 op,u8 fmt,u32 bias) + * \brief Controls Z texture operations. + * + * \details Z textures can be used to implement image-based rendering algorithms. A composite image consisting of color and depth image planes can + * be merged into the Embedded Frame Buffer (EFB). + * + * Normally, the Z for a quad (2x2) of pixels is computed as a reference Z and two slopes. Once Z texturing is enabled, the Z is computed by adding + * a Z texel to the reference Z (\a op = GX_ZT_ADD) or by replacing the reference Z with the Z texel value (\a op = GX_ZT_REPLACE). + * + * Z textures are always the output from the last active Texture Environment (TEV) stage (see GX_SetNumTevStages()) when enabled. When Z texturing is + * enabled, the texture color of the last TEV stage is not available, but all other color inputs and operations are available. The pixel color is + * always output from the last active TEV stage. You cannot use the TEV to operate on the Z texture, it is fed directly into the Z texture logic. + * + * Z texel formats can be unsigned 8-bit (GX_TF_Z8), 16-bit (GX_TF_Z16), or 24-bit (GX_TF_Z24X8 (32-bit texture)) are used. The Graphics Processor + * converts the Z-textures to 24-bit values by placing the texel value in the least-significant bits and inserting zero's in the remaining + * most-significant bits. The 24-bit constant \a bias is added to the Z texture. If the pixel format is GX_PF_RGB565_Z16 the 24-bit result is converted + * to the current 16-bit Z format before comparing with the EFB's Z. + * + * \note The Z-texture calculation is done before the fog range calculation.

+ * + * \note GX_Init() disables Z texturing. + * + * \param[in] op \ref ztexop to perform + * \param[in] fmt \ref ztexfmt to use + * \param[in] bias Bias value. Format is 24bit unsigned. + * + * \return none + */ +void GX_SetZTexture(u8 op,u8 fmt,u32 bias); + +/*! + * \fn void GX_SetZMode(u8 enable,u8 func,u8 update_enable) + * \brief Sets the Z-buffer compare mode. + * + * \details The result of the Z compare is used to conditionally write color values to the Embedded Frame Buffer (EFB). + * + * When \a enable is set to GX_DISABLE, Z buffering is disabled and the Z buffer is not updated. + * + * The \a func parameter determines the comparison that is performed. In the comparison function, the newly rasterized Z value is on the left + * while the Z value from the Z buffer is on the right. If the result of the comparison is false, the newly rasterized pixel is discarded. + * + * The parameter \a update_enable determines whether or not the Z buffer is updated with the new Z value after a comparison is performed. This + * parameter also affects whether the Z buffer is cleared during copy operations (see GX_CopyDisp() and GX_CopyTex()). + * + * \param[in] enable Enables comparisons with source and destination Z values if GX_TRUE; disables compares otherwise. + * \param[in] func \ref compare + * \param[in] update_enable Enables Z-buffer updates when GX_TRUE; otherwise, Z-buffer updates are disabled, but compares may still be enabled. + * + * \return none + */ +void GX_SetZMode(u8 enable,u8 func,u8 update_enable); + +/*! + * \fn void GX_SetZCompLoc(u8 before_tex) + * \brief Sets whether Z buffering happens before or after texturing. + * + * \details Normally, Z buffering should happen before texturing, as this enables better performance by not texturing pixels that are not + * visible; however, when alpha compare is used, Z buffering must be done after texturing (see GX_SetAlphaCompare()). + * + * \param[in] before_tex Enables Z-buffering before texturing when set to GX_TRUE; otherwise, Z-buffering takes place after texturing. + * + * \return none + */ +void GX_SetZCompLoc(u8 before_tex); + +/*! + * \fn void GX_SetLineWidth(u8 width,u8 fmt) + * \brief Sets the width of line primitives. + * + * The parameter \a fmt is added to the texture coordinate to obtain texture coordinates at the other corners of a wide line. The \a fmt + * values are added after the texture coordinate generation operation; see GX_SetTexCoordGen(). + * + * \param[in] width width of the line in 1/16th pixel increments; maximum width is 42.5 px + * \param[in] fmt \ref texoff + * + * \return none + */ +void GX_SetLineWidth(u8 width,u8 fmt); + +/*! + * \fn void GX_SetPointSize(u8 width,u8 fmt) + * \brief Sets the size of point primitives. + * + * \details The parameter \a fmt is added to the texture coordinate(s), if any, to obtain texture coordinates at the other corners of a point. The + * \a fmts are added after the texture coordinate generation operation; see GX_SetTexCoordGen(). + * + * \param[in] width width of the point in 1/16th pixel increments; maximum width is 42.5 px + * \param[in] fmt \ref texoff + * + * \return none + */ +void GX_SetPointSize(u8 width,u8 fmt); + +/*! + * \fn void GX_SetBlendMode(u8 type,u8 src_fact,u8 dst_fact,u8 op) + * \brief Determines how the source image, generated by the graphics processor, is blended with the Embedded Frame Buffer (EFB). + * + * \details When \a type is set to GX_BM_NONE, the source data is written directly to the EFB. When \a type is set to GX_BM_BLEND, the source color and EFB + * pixels are blended using the following equation: + * + *       dst_pix_clr = src_pix_clr * \a src_fact + dst_pix_clr * \a dst_fact + * + * The GX_BL_DSTALPHA / GX_BL_INVDSTALPHA can be used only when the EFB has GX_PF_RGBA6_Z24 as the pixel format (see GX_SetPixelFmt()). If the pixel + * format is GX_PF_RGBA6_Z24 then the \a src_fact and \a dst_fact are also applied to the alpha channel. To write the alpha channel to the EFB you must + * call GX_SetAlphaUpdate(). + * + * When type is set to GX_BM_LOGIC, the source and EFB pixels are blended using logical bitwise operations. When type is set to GX_BM_SUBTRACT, the destination + * pixel is computed as follows: + * + *       dst_pix_clr = dst_pix_clr - src_pix_clr [clamped to zero] + * + * Note that \a src_fact and \a dst_fact are not part of this equation. + * + * \note Color updates should be enabled by calling GX_SetColorUpdate(). + * + * \param[in] type \ref blendmode + * \param[in] src_fact \ref blendfactor + * \param[in] dst_fact \ref blendfactor + * \param[in] op \ref logicop + * + * \return none + */ +void GX_SetBlendMode(u8 type,u8 src_fact,u8 dst_fact,u8 op); + +/*! + * \fn void GX_SetCullMode(u8 mode) + * \brief Enables or disables culling of geometry based on its orientation to the viewer. + * + * \details Primitives in which the vertex order is clockwise to the viewer are considered front-facing. + * + * \note GX_Init() sets this to GX_CULL_BACK. + * + * \param[in] mode \ref cullmode + * + * \return none + */ +void GX_SetCullMode(u8 mode); + +/*! + * \fn void GX_SetCoPlanar(u8 enable) + * \brief Enables or disables coplanar triangle processing. + * + * \details While coplanar mode is enabled, all subsequent triangles (called decal triangles) will have the same Z coefficients as the reference + * plane. Coplanar mode should be enabled immediately after a reference triangle is drawn. + * + * \note The reference triangle can be culled using GX_SetCullMode(GX_CULL_ALL) to create an invisible reference plane; however, the reference + * triangle must not be completely out of view, i.e. trivially rejected by clipping.

+ * + * \note GX_Init() disables coplanar mode. + * + * \param[in] enable when GX_ENABLE, coplanar mode is enabled; GX_DISABLE disables this mode + * + * \return none + */ +void GX_SetCoPlanar(u8 enable); + +/*! + * \fn void GX_EnableTexOffsets(u8 coord,u8 line_enable,u8 point_enable) + * \brief Enables a special texture offset feature for points and lines. + * + * \details When a point's size is defined using GX_SetPointSize() or a line's width is described using GX_SetLineWidth(), you can also specify a second + * parameter. The parameter \a fmt is added to the texture coordinate(s), if any, to obtain texture coordinates at the other corners of a + * point or line. The \a fmts are added after the texture coordinate generation operation; see GX_SetTexCoordGen(). This function enables this + * operation for a particular texture coordinate. Offset operations for points and lines are enabled separately. If the enables are false, the same + * texture coordinate is used for every vertex of the line or point. + * + * \param[in] coord \ref texcoordid + * \param[in] line_enable enable or disable tex offset calculation for lines + * \param[in] point_enable enable or disable tex offset calculation for points + * + * \return none + */ +void GX_EnableTexOffsets(u8 coord,u8 line_enable,u8 point_enable); + +/*! + * \fn void GX_SetClipMode(u8 mode) + * \brief Enables or disables clipping of geometry. + * + * \details This may help performance issues that occur when objects are far-clipped; however, any near-clipped objects will be rendered incorrectly. + * + * \note GX_Init() sets this to GX_CLIP_ENABLE. + * + * \param[in] mode \ref clipmode + * + * \return none + */ +void GX_SetClipMode(u8 mode); + +/*! + * \fn void GX_SetScissor(u32 xOrigin,u32 yOrigin,u32 wd,u32 ht) + * \brief Sets the scissor rectangle. + * + * \details The scissor rectangle specifies an area of the screen outside of which all primitives are culled. This function sets the scissor rectangle in + * screen coordinates. The screen origin (\a xOrigin=0, \a yOrigin=0) is at the top left corner of the display. + * + * The values may be within the range of 0 - 2047 inclusive. Using values that extend beyond the EFB size is allowable since the scissor box may be + * repositioned within the EFB using GX_SetScissorBoxOffset(). + * + * \note By default, the scissor rectangle is set to match the viewport rectangle. GX_Init() initializes the scissor rectangle to match the viewport + * given the current render mode. + * + * \param[in] xOrigin left-most coord in screen coordinates + * \param[in] yOrigin top-most coord in screen coordinates + * \param[in] wd width of the scissorbox in screen coordinates + * \param[in] ht height of the scissorbox in screen coordinates + * + * \return none + */ +void GX_SetScissor(u32 xOrigin,u32 yOrigin,u32 wd,u32 ht); + +/*! + * \fn void GX_SetScissorBoxOffset(s32 xoffset,s32 yoffset) + * \brief Repositions the scissorbox rectangle within the Embedded Frame Buffer (EFB) memory space. + * + * \details The offsets are subtracted from the screen coordinates to determine the actual EFB coordinates where the pixels are stored. Thus with + * positive offsets, the scissor box may be shifted left and/or up; and with negative offsets, the scissor box may be shifted right and/or down. + * + * The intended use for this command is to make it easy to do two-pass antialiased rendering. To draw the top half of the screen, the scissor box is set to + * the top and the offset set to zero. To draw the bottom half, the scissor box is set to the bottom, and the offset is set to shift the scissor box back up + * to the top. + * + * Another use for the offset is to displace how an image is rendered with respect to the dither matrix. Since the dither matrix is 4x4, a \a yoffset of -2 + * shifts the image down by 2 lines with respect to the matrix. This can be useful for field-rendering mode. + * + * \note Achieving an offset of an odd number of lines is possible, but more difficult than just changing the scissor box: one must render and copy 2 + * additional lines, then skip one by adjusting the argument of VIDEO_SetNextFrameBuffer().

+ * + * \note GX_Init() initializes the scissor box offset to zero. Since the GP works on 2x2 regions of pixels, only even offsets are allowed. + * + * \param[in] xoffset number of pixels to shift the scissorbox left, between -342 - 382 inclusive; must be even + * \param[in] yoffset number of pixels to shift the scissorbox up, between -342 - 494 inclusive; must be even + * + * \return none + */ +void GX_SetScissorBoxOffset(s32 xoffset,s32 yoffset); + +/*! + * \fn void GX_SetNumChans(u8 num) + * \brief Sets the number of color channels that are output to the TEV stages. + * + * \details Color channels are the mechanism used to compute per-vertex lighting effects. Color channels are controlled using GX_SetChanCtrl(). + * Color channels are linked to specific TEV stages using GX_SetTevOrder(). + * + * This function basically defines the number of per-vertex colors that get rasterized. If \a num is set to 0, then at least one texture coordinate + * must be generated (see GX_SetNumTexGens()). If \a num is set to 1, then channel GX_COLOR0A0 will be rasterized. If \a num is set to 2 (the maximum + * value), then GX_COLOR0A0 and GX_COLOR1A1 will be rasterized. + * + * \param[in] num number of color channels to rasterize; number must be 0, 1 or 2 + * + * \return none + */ +void GX_SetNumChans(u8 num); + +/*! + * \fn void GX_SetTevOrder(u8 tevstage,u8 texcoord,u32 texmap,u8 color) + * \brief Specifies the texture and rasterized color that will be available as inputs to this TEV \a tevstage. + * + * The texture coordinate \a texcoord is generated from input attributes using the GX_SetTexCoordGen() function and is used to look up the + * texture map, previously loaded by GX_LoadTexObj(). The \a color to rasterize for this \a tevstage is also specified. The color + * is the result of per-vertex lighting which is controlled by GX_SetChanCtrl(). + * + * This function will scale the normalized texture coordinates produced by GX_SetTexCoordGen() according to the size of the texture map in the + * function call. For this reason, texture coordinates can only be broadcast to multiple texture maps if and only if the maps are the same size. In + * some cases, you may want to generate a texture coordinate having a certain scale, but disable the texture lookup (this comes up when generating + * texture coordinates for indirect bump mapping). To accomplish this, use the GX_TEXMAP_DISABLE flag: + * + * \code GX_SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD0, GX_TEXMAP3 | GX_TEXMAP_DISABLE, GX_COLORNULL); \endcode + * + * \details This will scale GX_TEXCOORD0 using GX_TEXMAP3 but disable the lookup of GX_TEXMAP3. + * + * \note This function does not enable the TEV stage. To enable a consecutive number of TEV stages, starting at stage GX_TEVSTAGE0, use GX_SetNumTevStages().

+ * + * \note The operation of each TEV stage is independent. The color operations are controlled by GX_SetTevColorIn() and GX_SetTevColorOp(). The alpha + * operations are controlled by GX_SetTevAlphaIn() and GX_SetTevAlphaOp().

+ * + * \note The number of texture coordinates available for all the active TEV stages is set using GX_SetNumTexGens(). The number of color channels + * available for all the active TEV stages is set using GX_SetNumChans(). Active TEV stages should not reference more texture coordinates or colors + * than are being generated.

+ * + * \note There are some special settings for the \a color argument. If you specify GX_COLOR_ZERO, you always get zero as rasterized color. If you specify + * GX_ALPHA_BUMP or GX_ALPHA_BUMPN, you can use "Bump alpha" component from indirect texture unit as rasterized color input (see GX_SetTevIndirect() + * for details about how to configure bump alpha). Since bump alpha contains only 5-bit data, GX_ALPHA_BUMP shifts them to higher bits, which makes the + * value range 0-248. Meanwhile GX_ALPHA_BUMPN performs normalization and you can get the value range 0-255. + * + * \param[in] tevstage \ref tevstage + * \param[in] texcoord \ref texcoordid + * \param[in] texmap \ref texmapid + * \param[in] color \ref channelid + * + * \return none + */ +void GX_SetTevOrder(u8 tevstage,u8 texcoord,u32 texmap,u8 color); + +/*! + * \fn void GX_SetNumTevStages(u8 num) + * \brief Enables a consecutive number of TEV stages. + * + * \details The output pixel color (before fogging and blending) is the result from the last stage. The last TEV stage must write to register GX_TEVPREV; + * see GX_SetTevColorOp() and GX_SetTevAlphaOp(). At least one TEV stage must be enabled. If a Z-texture is enabled, the Z texture must be looked up on + * the last stage; see GX_SetZTexture(). + * + * \note The association of lighting colors, texture coordinates, and texture maps with a TEV stage is set using GX)SetTevOrder(). The number of texture + * coordinates available is set using GX_SetNumTexGens(). The number of color channels available is set using GX_SetNumChans().

+ * + * \note GX_Init() will set \a num to 1. + * + * \param[in] num number of active TEV stages, between 1 and 16 inclusive + * + * \return none + */ +void GX_SetNumTevStages(u8 num); + +/*! + * \fn void GX_SetAlphaCompare(u8 comp0,u8 ref0,u8 aop,u8 comp1,u8 ref1) + * \brief Sets the parameters for the alpha compare function which uses the alpha output from the last active TEV stage. + * + * \details The alpha compare operation is:

+ * + *       alpha_pass = (alpha_src (\a comp0) \a ref0) (\a op) (alpha_src (\a comp1) \a ref1)

+ * + * where alpha_src is the alpha from the last active TEV stage. As an example, you can implement these equations:

+ * + *       alpha_pass = (alpha_src \> \a ref0) AND (alpha_src \< \a ref1) + * + * or + * + *       alpha_pass = (alpha_src \> \a ref0) OR (alpha_src \< \a ref1) + * + * \note The output alpha can be used in the blending equation (see GX_SetBlendMode()) to control how source and destination (frame buffer) + * pixels are combined.

+ * + * \note The Z compare can occur either before or after texturing (see GX_SetZCompLoc()). In the case where Z compare occurs before texturing, the Z is + * written based only on the Z test. The color is written if both the Z test and alpha test pass. When Z compare occurs after texturing, the color + * and Z are written if both the Z test and alpha test pass. When using texture to make cutout shapes (like billboard trees) that need to be correctly Z + * buffered, you should configure the pipeline to Z buffer after texturing.

+ * + * \note The number of active TEV stages is specified using GX_SetNumTevStages(). + * + * \param[in] comp0 \ref compare subfunction 0 + * \param[in] ref0 reference val for subfunction 0 + * \param[in] aop \ref alphaop for combining subfunctions 0 and 1; must not be GX_MAX_ALPHAOP + * \param[in] comp1 \ref compare subfunction 1 + * \param[in] ref1 reference val for subfunction 1 + * + * \return none + */ +void GX_SetAlphaCompare(u8 comp0,u8 ref0,u8 aop,u8 comp1,u8 ref1); + +/*! + * \fn void GX_SetTevKColor(u8 sel, GXColor col) + * \brief Sets one of the "konstant" color registers in the TEV unit. + * + * \details These registers are available to all TEV stages. They are constant in the sense that they cannot be written to be the TEV itself. + * + * \param[in] sel \ref tevkcolorid + * \param[in] col constant color value + * + * \return none + */ +void GX_SetTevKColor(u8 sel, GXColor col); + +/*! + * \fn void GX_SetTevKColorSel(u8 tevstage,u8 sel) + * \brief Selects a "konstant" color input to be used in a given TEV stage. + * + * The constant color input is used only if GX_CC_KONST is selected for an input for that TEV stage. Only one constant color selection is + * available for a given TEV stage, though it may be used for more than one input. + * + * \param[in] tevstage \ref tevstage + * \param[in] sel \ref tevkcolorsel + * + * \return none + */ +void GX_SetTevKColorSel(u8 tevstage,u8 sel); + +/*! + * \fn void GX_SetTevKAlphaSel(u8 tevstage,u8 sel) + * \brief Selects a "konstant" alpha input to be used in a given TEV stage. + * + * \details The constant alpha input is used only if GX_CA_KONST is selected for an input for that TEV stage. Only one constant alpha selection is + * available for a given TEV stage, though it may be used for more than one input. + * + * \param[in] tevstage \ref tevstage + * \param[in] sel \ref tevkalphasel + * + * \return none + */ +void GX_SetTevKAlphaSel(u8 tevstage,u8 sel); + +/*! + * \fn void GX_SetTevKColorS10(u8 sel, GXColorS10 col) + * \brief Used to set one of the constant color registers in the Texture Environment (TEV) unit. + * + * \details These registers are available to all TEV stages. At least one of these registers is used to pass the output of one TEV stage to the next + * in a multi-texture configuration. + * + * \note The application is responsible for allocating these registers so that no collisions in usage occur.

+ * + * \note This function takes 10-bit signed values as color values; use GX_SetTevColor() to give 8-bit values. + * + * \param[in] sel \ref tevcoloutreg + * \param[in] col constant color value + * + * \return none + */ +void GX_SetTevKColorS10(u8 sel, GXColorS10 col); + +/*! + * \fn void GX_SetTevSwapMode(u8 tevstage,u8 ras_sel,u8 tex_sel) + * \brief Selects a set of swap modes for the rasterized color and texture color for a given TEV stage. + * + * \details This allows the color components of these inputs to be rearranged or duplicated. + * + * \note There are four different swap mode table entries, and each entry in the table specifies how the RGBA inputs map to the RGBA outputs. + * + * \param[in] tevstage \ref tevstage + * \param[in] ras_sel selects a swap mode for the rasterized color input. + * \param[in] tex_sel selects a swap mode for the texture color input. + * + * \return none + */ +void GX_SetTevSwapMode(u8 tevstage,u8 ras_sel,u8 tex_sel); + +/*! + * \fn void GX_SetTevSwapModeTable(u8 swapid,u8 r,u8 g,u8 b,u8 a) + * \brief Sets up the TEV color swap table. + * + * \details The swap table allows the rasterized color and texture color to be swapped component-wise. An entry in the table specifies how the + * input color components map to the output color components. + * + * \param[in] swapid \ref tevswapsel + * \param[in] r input color component that should be mapped to the red output component. + * \param[in] g input color component that should be mapped to the green output component. + * \param[in] b input color component that should be mapped to the blue output component. + * \param[in] a input color component that should be mapped to the alpha output component. + * + * \return none + */ +void GX_SetTevSwapModeTable(u8 swapid,u8 r,u8 g,u8 b,u8 a); + +/*! + * \fn void GX_SetTevIndirect(u8 tevstage,u8 indtexid,u8 format,u8 bias,u8 mtxid,u8 wrap_s,u8 wrap_t,u8 addprev,u8 utclod,u8 a) + * \brief Controls how the results from an indirect lookup will be used to modify a given regular TEV stage lookup. + * + * \param[in] tevstage \ref tevstage being affected + * \param[in] indtexid \ref indtexstage results to use with this TEV stage + * \param[in] format \ref indtexformat, i.e. how many bits to extract from the indirect result color to use in indirect offsets and the indirect "bump" alpha + * \param[in] bias \ref indtexbias to be applied to each component of the indirect offset + * \param[in] mtxid which \ref indtexmtx and scale value to multiply the offsets with + * \param[in] wrap_s \ref indtexwrap to use with the S component of the regular texture coordinate + * \param[in] wrap_t \ref indtexwrap to use with the T component of the regular texture coordinate + * \param[in] addprev whether the tex coords results from the previous TEV stage should be added in + * \param[in] utclod whether to the unmodified (GX_TRUE) or modified (GX_FALSE) tex coords for mipmap LOD computation + * \param[in] a which offset component will supply the \ref indtexalphasel, if any + * + * \return none + */ +void GX_SetTevIndirect(u8 tevstage,u8 indtexid,u8 format,u8 bias,u8 mtxid,u8 wrap_s,u8 wrap_t,u8 addprev,u8 utclod,u8 a); + +/*! + * \fn void GX_SetTevDirect(u8 tevstage) + * \brief Used to turn off all indirect texture processing for the specified regular TEV stage. + * + * \param[in] tevstage the \ref tevstage to change + * + * \return none + */ +void GX_SetTevDirect(u8 tevstage); + +/*! + * \fn void GX_SetNumIndStages(u8 nstages) + * \brief Used to set how many indirect lookups will take place. + * + * \details The results from these indirect lookups may then be used to alter the lookups for any number of regular TEV stages. + * + * \param[in] nstages number of indirect lookup stages + * + * \return none + */ +void GX_SetNumIndStages(u8 nstages); + +/*! + * \fn void GX_SetIndTexOrder(u8 indtexstage,u8 texcoord,u8 texmap) + * \brief Used to specify the \a texcoord and \a texmap to used with a given indirect lookup. + * + * \param[in] indtexstage \ref indtexstage being affected + * \param[in] texcoord \ref texcoordid to be used for this stage + * \param[in] texmap \ref texmapid to be used for this stage + * + * \return none + */ +void GX_SetIndTexOrder(u8 indtexstage,u8 texcoord,u8 texmap); + +/*! + * \fn void GX_SetIndTexCoordScale(u8 indtexid,u8 scale_s,u8 scale_t) + * \brief Allows the sharing of a texcoord between an indirect stage and a regular TEV stage. + * + * It allows the texture coordinates to be scaled down for use with an indirect map that is smaller than the corresponding regular map. + * + * \param[in] indtexid \ref indtexstage being affected + * \param[in] scale_s \ref indtexscale factor for the S coord + * \param[in] scale_t \ref indtexscale factor for the T coord + * + * \return none + */ +void GX_SetIndTexCoordScale(u8 indtexid,u8 scale_s,u8 scale_t); + +/*! + * \fn void GX_SetFog(u8 type,f32 startz,f32 endz,f32 nearz,f32 farz,GXColor col) + * \brief Enables fog. + * + * \details Using \a type, the programmer may select one of several functions to control the fog density as a function of range to a quad (2x2 pixels). + * Range is cosine corrected Z in the x-z plane (eye coordinates), but is not corrected in the y direction (see GX_SetFogRangeAdj()). The parameters \a startz and + * \a endz allow further control over the fog behavior. The parameters \a nearz and \a farz should be set consistent with the projection matrix parameters. Note that these + * parameters are defined in eye-space. The fog color, in RGBX format (i.e. the alpha component is ignored), is set using the \a col parameter. This will be the + * color of the pixel when fully fogged. + * + * \note GX_Init() turns fog off by default. + * + * \param[in] type \ref fogtype to use + * \param[in] startz minimum Z value at which the fog function is active + * \param[in] endz maximum Z value at which the fog function is active + * \param[in] nearz near plane (which should match the projection matrix parameters) + * \param[in] farz far plane (which should match the projection matrix parameters) + * \param[in] col fog color; alpha component is ignored + * + * \return none + */ +void GX_SetFog(u8 type,f32 startz,f32 endz,f32 nearz,f32 farz,GXColor col); + +/*! + * \fn void GX_SetFogRangeAdj(u8 enable,u16 center,GXFogAdjTbl *table) + * \brief Enables or disables horizontal fog-range adjustment. + * + * \details This adjustment is a factor that is multiplied by the eye-space Z used for fog computation; it is based upon the X position of the pixels being + * rendered. The Y direction is not compensated. This effectively increases the fog density at the edges of the screen, making for a more realistic fog + * effect. The adjustment is computed per quad (2x2 pixels), not per-pixel. The center of the viewport is specified using \a center. The range adjustment + * table is specified using \a table. The range adjust function is mirrored horizontally about the \a center. + * + * \note GX_Init() disables range adjustment. + * + * \sa GX_InitFogAdjTable() + * + * \param[in] enable enables adjustment when GX_ENABLE is passed; disabled with GX_DISABLE + * \param[in] center centers the range adjust function; normally corresponds with the center of the viewport + * \param[in] table range adjustment parameter table + * + * \return none + */ +void GX_SetFogRangeAdj(u8 enable,u16 center,GXFogAdjTbl *table); + +/*! + * \fn GX_SetFogColor(GXColor color) + * \brief Sets the fog color. + * + * \details \a color is the color that a pixel will be if fully fogged. Alpha channel is ignored. + * + * \param[in] color color to set fog to + */ +void GX_SetFogColor(GXColor color); + +/*! + * \fn void GX_InitFogAdjTable(GXFogAdjTbl *table,u16 width,f32 projmtx[4][4]) + * \brief Generates the standard range adjustment table and puts the results into \a table. + * + * \details This table can be used by GX_SetFogRangeAdj() to adjust the eye-space Z used for fog based upon the X position of the pixels being rendered. + * The Y direction is not compensated. This effectively increases the fog density at the edges of the screen, making for a more realistic fog effect. The + * width of the viewport is specified using \a width. The \a projmtx parameter is the projection matrix that is used to render into the viewport. It must + * be specified so that the function can compute the X extent of the viewing frustum in eye space. + * + * \note You must allocate \a table yourself. + * + * \param[in] table range adjustment parameter table + * \param[in] width width of the viewport + * \param[in] projmtx projection matrix used to render into the viewport + */ +void GX_InitFogAdjTable(GXFogAdjTbl *table,u16 width,f32 projmtx[4][4]); + +/*! + * \fn void GX_SetIndTexMatrix(u8 indtexmtx,f32 offset_mtx[2][3],s8 scale_exp) + * \brief Sets one of the three static indirect matrices and the associated scale factor. + * + * \details The indirect matrix and scale is used to process the results of an indirect lookup in order to produce offsets to use during a regular lookup. + * The matrix is multiplied by the [S T U] offsets that have been extracted (and optionally biased) from the indirect lookup color. In this matrix-vector + * multiply, the matrix is on the left and the [S T U] column vector is on the right. + * + * \note The matrix values are stored in the hardware as a sign and 10 fractional bits (two's complement); thus the smallest number that can be stored is + * -1 and the largest is (1 - 1/1024) or approximately 0.999. Since +1 cannot be stored, you may consider dividing all the matrix values by 2 (thus +1 + * becomes +0.5) and adding one to the scale value in order to compensate. + * + * \param[in] indtexmtx \ref indtexmtx that is being affected + * \param[in] offset_mtx values to assign to the indirect matrix + * \param[in] scale_exp exponent to use for the associated scale factor + * + * \return none + */ +void GX_SetIndTexMatrix(u8 indtexmtx,f32 offset_mtx[2][3],s8 scale_exp); + +/*! + * \fn void GX_SetTevIndBumpST(u8 tevstage,u8 indstage,u8 mtx_sel) + * \brief Sets up an environment-mapped bump-mapped indirect lookup. + * + * \details The indirect map specifies offsets in (S,T) space. This kind of lookup requires 3 TEV stages to compute. As a result of all this work, a simple + * 2D bump map is properly oriented to the surface to which it is applied. It is used to alter a normal-based texgen which then looks up an environment map. + * The environment map may be a simple light map, or else it may be a reflection map of the surrounding scenery. + * + * \note When using this function, texture lookup should be disabled for the first two TEV stages. The third stage is where the texture lookup is actually performed. + * The associated geometry must supply normal/binormal/tangent coordinates at each vertex. Appropriate texgens must supply each of these to the proper stages + * (binormal to the first, tangent to the second, and normal to the third). Although a static indirect matrix is not used, one must choose a matrix slot and set up + * the associated scale value to be used with this lookup. + * + * \param[in] tevstage \ref tevstage that is being affected + * \param[in] indstage \ref indtexstage results to use with this TEV stage + * \param[in] mtx_sel which \ref indtexmtx to multiply the offsets with + * + * \return none + */ +void GX_SetTevIndBumpST(u8 tevstage,u8 indstage,u8 mtx_sel); + +/*! + * \fn void GX_SetTevIndBumpXYZ(u8 tevstage,u8 indstage,u8 mtx_sel) + * \brief Sets up an environment-mapped bump-mapped indirect lookup. + * + * \details The indirect map specifies offsets in object (X, Y, Z) space. This kind of lookup requires only one TEV stage to compute; however, the bump map (indirect + * map) used is geometry-specific. Thus there is a space/computation tradeoff between using this function and using GX_SetTevIndBumpST(). + * + * \note The indirect matrix must be loaded with a transformation for normals from object space to texture space (similar to eye space, but possibly with an inverted + * Y axis). The surface geometry need only provide regular normals at each vertex. A normal-based texgen must be set up for the regular texture coordinate. + * + * \param[in] tevstage \ref tevstage that is being affected + * \param[in] indstage \ref indtexstage results to use with this TEV stage + * \param[in] mtx_sel which \ref indtexmtx to multiply the offsets with + * + * \return none + */ +void GX_SetTevIndBumpXYZ(u8 tevstage,u8 indstage,u8 mtx_sel); + +/*! + * \fn void GX_SetTevIndTile(u8 tevstage,u8 indtexid,u16 tilesize_x,u16 tilesize_y,u16 tilespacing_x,u16 tilespacing_y,u8 indtexfmt,u8 indtexmtx,u8 bias_sel,u8 alpha_sel) + * \brief Used to implement tiled texturing using indirect textures. + * + * \details It will set up the correct values in the given indirect matrix; you only need to specify which matrix slot to use. + * + * \note The regular texture map contains only the tile definitions. The actual texture size to be applied to the polygon being drawn is the product of the base tile + * size and the size of the indirect map. In order to set the proper texture coordinate scale, one must call GX_SetTexCoordScaleManually(). One can also use + * GX_SetIndTexCoordScale() in order to use the same texcoord for the indirect stage as the regular TEV stage. + * + * \param[in] tevstage \ref tevstage that is being affected + * \param[in] indtexid \ref indtexstage results to use with this TEV stage + * \param[in] tilesize_x size of the tile in the X dimension + * \param[in] tilesize_y size of the tile in the Y dimension + * \param[in] tilespacing_x spacing of the tiles (in the tile-definition map) in the X dimension + * \param[in] tilespacing_y spacing of the tiles (in the tile-definition map) in the Y dimension + * \param[in] indtexfmt \ref indtexformat to use + * \param[in] indtexmtx \ref indtexmtx to multiply the offsets with + * \param[in] bias_sel \ref indtexbias to indicate tile stacking direction for pseudo-3D textures + * \param[in] alpha_sel which \ref indtexalphasel will supply the indirect "bump" alpha, if any (for pseudo-3D textures). + * + * \return none + */ +void GX_SetTevIndTile(u8 tevstage,u8 indtexid,u16 tilesize_x,u16 tilesize_y,u16 tilespacing_x,u16 tilespacing_y,u8 indtexfmt,u8 indtexmtx,u8 bias_sel,u8 alpha_sel); + +/*! + * \fn void GX_SetTevIndRepeat(u8 tevstage) + * \brief Set a given TEV stage to use the same texture coordinates as were computed in the previous stage. + * + * \note This is only useful when the previous stage texture coordinates took more than one stage to compute, as is the case for GX_SetTevIndBumpST(). + * + * \param[in] tevstage \ref tevstage to modify + * + * \return none + */ +void GX_SetTevIndRepeat(u8 tevstage); + +/*! + * \fn void GX_SetColorUpdate(u8 enable) + * \brief Enables or disables color-buffer updates when rendering into the Embedded Frame Buffer (EFB). + * + * \note This function also affects whether the color buffer is cleared during copies; see GX_CopyDisp() and GX_CopyTex(). + * + * \param[in] enable enables color-buffer updates with GX_TRUE + * + * \return none + */ +void GX_SetColorUpdate(u8 enable); + +/*! + * \fn void GX_SetAlphaUpdate(u8 enable) + * \brief Enables or disables alpha-buffer updates of the Embedded Frame Buffer (EFB). + * + * \note This function also affects whether the alpha buffer is cleared during copy operations; see GX_CopyDisp() and GX_CopyTex().

+ * + * \note The only EFB pixel format supporting an alpha buffer is GX_PF_RGBA6_Z24; see GX_SetPixelFmt(). The alpha \a enable is ignored for non-alpha + * pixel formats. + * + * \param[in] enable enables alpha-buffer updates with GX_TRUE + * + * \return none + */ +void GX_SetAlphaUpdate(u8 enable); + +/*! + * \fn void GX_SetPixelFmt(u8 pix_fmt,u8 z_fmt) + * \brief Sets the format of pixels in the Embedded Frame Buffer (EFB). + * + * \details There are two non-antialiased \a pix_fmts: GX_PF_RGB8_Z24 and GX_PF_RGBA6_Z24. The stride of the EFB is fixed at 640 pixels. The + * non-antialiased EFB has 528 lines available. + * + * When \a pix_fmt is set to GX_PF_RGB565_Z16, multi-sample antialiasing is enabled. In order to get proper results, one must also call GX_SetCopyFilter(). + * The position of the subsamples and the antialiasing filter coefficients are set using GX_SetCopyFilter(). When antialiasing, three 16b color/Z + * samples are computed for each pixel, and the total available number of pixels in the EFB is reduced by half (640 pixels x 264 lines). This function also sets the + * compression type for 16-bit Z formats, which allows trading off Z precision for range. The following guidelines apply:

+ * + *       a) far/near ratio <= 2^16, use GX_ZC_LINEAR
+ *       b) far/near ratio <= 2^18, use GX_ZC_NEAR
+ *       c) far/near ratio <= 2^20, use GX_ZC_MID
+ *       d) far/near ratio <= 2^24, use GX_ZC_FAR

+ * + * It is always best to use as little compression as possible (choice "a" is least compressed, choice "d" is most compressed). You get less precision with higher compression. + * The "far" in the above list does not necessarily refer to the far clipping plane. You should think of it as the farthest object you want correct occlusion for. + * + * \note This function also controls antialiasing (AA) mode.

+ * + * \note Since changing pixel format requires the pixel pipeline to be synchronized, the use of this function causes stall of the graphics processor as a result. Therefore, + * you should avoid redundant calls of this function. + * + * \param[in] pix_fmt GX_PF_RGB8_Z24 or GX_PF_RGBA6_Z24 for non-AA, GX_PF_RGB565_Z16 for AA + * \param[in] z_fmt \ref zfmt to use + * + * \return none + */ +void GX_SetPixelFmt(u8 pix_fmt,u8 z_fmt); + +/*! + * \fn void GX_SetDither(u8 dither) + * \brief Enables or disables dithering. + * + * \details A 4x4 Bayer matrix is used for dithering. + * + * \note Only valid when the pixel format (see GX_SetPixelFmt()) is either GX_PF_RGBA6_Z24 or GX_PF_RGB565_Z16.

+ * + * \note Dithering should probably be turned off if you are planning on using the result of rendering for comparisons (e.g. outline rendering + * algorithm that writes IDs to the alpha channel, copies the alpha channel to a texture, and later compares the texture in the TEV). + * + * \param[in] dither enables dithering if GX_TRUE is given and pixel format is one of the two above, otherwise disabled + * + * \return none + */ +void GX_SetDither(u8 dither); + +/*! + * \fn void GX_SetDstAlpha(u8 enable,u8 a) + * \brief Sets a constant alpha value for writing to the Embedded Frame Buffer (EFB). + * + * \note To be effective, the EFB pixel type must have an alpha channel (see GX_SetPixelFmt()). The alpha compare operation (see + * GX_SetAlphaCompare()) and blending operations (see GX_SetBlendMode()) still use source alpha (output from the last TEV stage) but when + * writing the pixel color, the constant alpha will replace the pixel alpha in the EFB. + * + * \param[in] enable \a a will be written to the framebuffer if GX_ENABLE is here and frame buffer pixel format supports destination alpha + * \param[in] a constant alpha value + * + * \return none + */ +void GX_SetDstAlpha(u8 enable,u8 a); + +/*! + * \fn void GX_SetFieldMask(u8 even_mask,u8 odd_mask) + * \brief selectively enables and disables interlacing of the frame buffer image. + * + * \details This function is used when rendering fields to an interlaced Embedded Frame Buffer (EFB). + * + * \note When the mask is GX_FALSE, that field will not be written to the EFB, but the other field will be computed. In other words, you pay the + * fill rate price of a frame to produce a field. + * + * \param[in] even_mask whether to write pixels with even Y coordinate + * \param[in] odd_mask whether to write pixels with odd Y coordinate + * + * \return none + */ +void GX_SetFieldMask(u8 even_mask,u8 odd_mask); + +/*! + * \fn void GX_SetFieldMode(u8 field_mode,u8 half_aspect_ratio) + * \brief Controls various rasterization and texturing parameters that relate to field-mode and double-strike rendering. + * + * \details In field-mode rendering, one must adjust the vertical part of the texture LOD computation to account for the fact that pixels cover only half of + * the space from one rendered scan line to the next (with the other half of the space filled by a pixel from the other field). In both field-mode and + * double-strike rendering, one must adjust the aspect ratio for points and lines to account for the fact that pixels will be double-height when displayed + * (the pixel aspect ratio is 1/2). + * + * \note The values set here usually come directly from the render mode. The \a field_rendering flags goes straight into \a field_mode. The \a half_aspect_ratio + * parameter is true if the \a xfbHeight is half of the \a viHeight, false otherwise.

+ * + * \note GX_Init() sets both fields according to the default render mode.

+ * + * \note On production hardware (i.e. a retail GameCube), only line aspect-ratio adjustment is implemented. Points are not adjusted. + * + * \param[in] field_mode adjusts texture LOD computation as described above if true, otherwise does not + * \param[in] half_aspect_ratio adjusts line aspect ratio accordingly, otherwise does not + * + * \return none + */ +void GX_SetFieldMode(u8 field_mode,u8 half_aspect_ratio); + +/*! + * \fn f32 GX_GetYScaleFactor(u16 efbHeight,u16 xfbHeight) + * \brief Calculates an appropriate Y scale factor value for GX_SetDispCopyYScale() based on the height of the EFB and + * the height of the XFB. + * + * \param[in] efbHeight Height of embedded framebuffer. Range from 2 to 528. Should be a multiple of 2. + * \param[in] xfbHeight Height of external framebuffer. Range from 2 to 1024. Should be equal or greater than \a efbHeight. + * + * \return Y scale factor which can be used as argument of GX_SetDispCopyYScale(). + */ +f32 GX_GetYScaleFactor(u16 efbHeight,u16 xfbHeight); + +/*! + * \fn u32 GX_SetDispCopyYScale(f32 yscale) + * \brief Sets the vertical scale factor for the EFB to XFB copy operation. + * + * \details The number of actual lines copied is returned, based on the current EFB height. You can use this number to allocate the proper XFB size. You + * have to call GX_SetDispCopySrc() prior to this function call if you want to get the number of lines by using this function. + * + * \param[in] yscale Vertical scale value. Range from 1.0 to 256.0. + * + * \return Number of lines that will be copied. + */ +u32 GX_SetDispCopyYScale(f32 yscale); + +/*! + * \fn void GX_SetDispCopySrc(u16 left,u16 top,u16 wd,u16 ht) + * \brief Sets the source parameters for the EFB to XFB copy operation. + * + * \param[in] left left most source pixel to copy. Must be a multiple of 2 pixels. + * \param[in] top top most source line to copy. Must be a multiple of 2 lines. + * \param[in] wd width in pixels to copy. Must be a multiple of 2 pixels. + * \param[in] ht height in lines to copy. Must be a multiple of 2 lines. + * + * \return none + */ +void GX_SetDispCopySrc(u16 left,u16 top,u16 wd,u16 ht); + +/*! + * \fn void GX_SetDispCopyDst(u16 wd,u16 ht) + * \brief Sets the witdth and height of the display buffer in pixels. + * + * \details The application typical renders an image into the EFB(source) and then copies it into the XFB(destination) in main memory. \a wd + * specifies the number of pixels between adjacent lines in the destination buffer and can be different than the width of the EFB. + * + * \param[in] wd Distance between successive lines in the XFB, in pixels. Must be a multiple of 16. + * \param[in] ht Height of the XFB in lines. + * + * \return none + */ +void GX_SetDispCopyDst(u16 wd,u16 ht); + +/*! + * \fn void GX_SetCopyClamp(u8 clamp) + * \brief Sets the vertical clamping mode to use during the EFB to XFB or texture copy. + * + * \param[in] clamp bit-wise OR of desired \ref xfbclamp. Use GX_CLAMP_NONE for no clamping. + * + * \return none + */ +void GX_SetCopyClamp(u8 clamp); + +/*! + * \fn void GX_SetDispCopyGamma(u8 gamma) + * \brief Sets the gamma correction applied to pixels during EFB to XFB copy operation. + * + * \param[in] gamma \ref gammamode + * + * \return none + */ +void GX_SetDispCopyGamma(u8 gamma); + +/*! + * \fn void GX_SetCopyFilter(u8 aa,u8 sample_pattern[12][2],u8 vf,u8 vfilter[7]) + * \brief Sets the subpixel sample patterns and vertical filter coefficients used to filter subpixels into pixels. + * + * \details This function normally uses the \a aa, \a sample_pattern and \a vfilter provided by the render mode struct:

+ * + * \code GXRModeObj* rmode = VIDEO_GetPreferredMode(NULL); + * GX_SetCopyFilter(rmode->aa,rmode->sample_pattern,GX_TRUE,rmode->vfilter); \endcode + * + * \note In order to make use of the \a sample_pattern, antialiasing must be enabled by setting the Embedded Frame Buffer (EFB) format to + * GX_PF_RGB565_Z16; see GX_SetPixelFmt(). + * + * \param[in] aa utilizes \a sample_pattern if GX_TRUE, otherwise all sample points are centered + * \param[in] sample_pattern array of coordinates for sample points; valid range is 1 - 11 inclusive + * \param[in] vf use \a vfilter if GX_TRUE, otherwise use default 1-line filter + * \param[in] vfilter vertical filter coefficients; valid coefficient range is 0 - 63 inclusive; sum should equal 64 + * + * \return none + */ +void GX_SetCopyFilter(u8 aa,u8 sample_pattern[12][2],u8 vf,u8 vfilter[7]); + +/*! + * \fn void GX_SetDispCopyFrame2Field(u8 mode) + * \brief Determines which lines are read from the Embedded Frame Buffer (EFB) when using GX_CopyDisp(). + * + * \details Specifically, it determines whether all lines, only even lines, or only odd lines are read. + * + * \note The opposite function, which determines whether all lines, only even lines or only odd lines are written to the EFB, is GX_SetFieldMask().

+ * + * \note Only applies to display copies, GX_CopyTex() always uses the GX_COPY_PROGRESSIVE mode. + * + * \param[in] mode \ref copymode to determine which field to copy (or both) + * + * \return none + */ +void GX_SetDispCopyFrame2Field(u8 mode); + +/*! + * \fn void GX_SetCopyClear(GXColor color,u32 zvalue) + * \brief Sets color and Z value to clear the EFB to during copy operations. + * + * \details These values are used during both display copies and texture copies. + * + * \param[in] color RGBA color (8-bit/component) to use during clear operation. + * \param[in] zvalue 24-bit Z value to use during clear operation. Use the constant GX_MAX_Z24 to specify the maximum depth value. + * + * \return none + */ +void GX_SetCopyClear(GXColor color,u32 zvalue); + +/*! + * \fn void GX_CopyDisp(void *dest,u8 clear) + * \brief Copies the embedded framebuffer (EFB) to the external framebuffer(XFB) in main memory. + * + * \note The stride of the XFB is set using GX_SetDispCopyDst(). The source image in the EFB is described using GX_SetDispCopySrc().

+ * + * \note The graphics processor will stall all graphics commands util the copy is complete.

+ * + * \note If the \a clear flag is true, the color and Z buffers will be cleared during the copy. They will be cleared to the constant + * values set using GX_SetCopyClear(). + * + * \param[in] dest pointer to the external framebuffer. \a dest should be 32B aligned. + * \param[in] clear flag that indicates framebuffer should be cleared if GX_TRUE. + * + * \return none + */ +void GX_CopyDisp(void *dest,u8 clear); + +/*! + * \fn void GX_SetTexCopySrc(u16 left,u16 top,u16 wd,u16 ht) + * \brief Sets the source parameters for the Embedded Frame Buffer (EFB) to texture image copy. + * + * \details The GP will copy textures into the tiled texture format specified in GX_CopyTex(). The GP always copies tiles (32B) so image widths and + * heights that are not a multiple of the tile width will be padded with undefined data in the copied image + * + * \param[in] left left-most source pixel to copy, multiple of two + * \param[in] top top-most source line to copy, multiple of two + * \param[in] wd width to copy in pixels, multiple of two + * \param[in] ht height to copy in pixels, multiple of two + * + * \return none + */ +void GX_SetTexCopySrc(u16 left,u16 top,u16 wd,u16 ht); + +/*! + * \fn void GX_SetTexCopyDst(u16 wd,u16 ht,u32 fmt,u8 mipmap) + * \brief This function sets the width and height of the destination texture buffer in texels. + * + * \details This function sets the width (\a wd) and height (\a ht) of the destination texture buffer in texels. The application may render an image into + * the EFB and then copy it into a texture buffer in main memory. \a wd specifies the number of texels between adjacent lines in the texture buffer and can + * be different than the width of the source image. This function also sets the texture format (\a fmt) to be created during the copy operation. An + * optional box filter can be enabled using \a mipmap. This flag will scale the source image by 1/2. + * + * Normally, the width of the EFB and destination \a wd are the same. When rendering smaller images that get copied and composited into a larger texture + * buffer, however, the EFB width and texture buffer \a wd are not necessarily the same. + * + * The Z buffer can be copied to a Z texture format by setting \a fmt to GX_TF_Z24X8. This operation is only valid when the EFB format is + * GX_PF_RGB8_Z24 or GX_PF_RGBA6_Z24. + * + * The alpha channel can be copied from an EFB with format GX_PF_RGBA6_Z24 by setting \a fmt to GX_TF_A8. + * + * \param[in] wd distance between successive lines in the texture buffer, in texels; must be a multiple of the texture tile width, which depends on \a fmt. + * \param[in] ht height of the texture buffer + * \param[in] fmt \ref texfmt + * \param[in] mipmap flag that indicates framebuffer should be cleared if GX_TRUE. + * + * \return none + */ +void GX_SetTexCopyDst(u16 wd,u16 ht,u32 fmt,u8 mipmap); + +/*! + * \fn void GX_CopyTex(void *dest,u8 clear) + * \brief Copies the embedded framebuffer (EFB) to the texture image buffer \a dest in main memory. + * + * \details This is useful when creating textures using the Graphics Processor (GP). If the \a clear flag is set to GX_TRUE, the EFB will be cleared + * to the current color(see GX_SetCopyClear()) during the copy operation. + * + * \param[in] dest pointer to the image buffer in main memory. \a dest should be 32B aligned. + * \param[in] clear flag that indicates framebuffer should be cleared if GX_TRUE. + * + * \return none + */ +void GX_CopyTex(void *dest,u8 clear); + +/*! + * \fn void GX_PixModeSync() + * \brief Causes the GPU to wait for the pipe to flush. + * + * \details This function inserts a synchronization command into the graphics FIFO. When the GPU sees this command it will allow the rest of the pipe to + * flush before continuing. This command is useful in certain situation such as after using GX_CopyTex() and before a primitive that uses the copied texture. + * + * \note The command is actually implemented by writing the control register that determines the format of the embedded frame buffer (EFB). As a result, care + * should be used if this command is placed within a display list. + * + * \return none + */ +void GX_PixModeSync(); + +/*! + * \fn void GX_ClearBoundingBox() + * \brief Clears the bounding box values before a new image is drawn. + * + * \details The graphics hardware keeps track of a bounding box of pixel coordinates that are drawn in the Embedded Frame Buffer (EFB). + * + * \return none + */ +void GX_ClearBoundingBox(); + +/*! + * \fn GX_PokeAlphaMode(u8 func,u8 threshold) + * \brief Sets a threshold which is compared to the alpha of pixels written to the Embedded Frame Buffer (EFB) using the GX_Poke*() functions. + * + * \details The compare function order is:

+ * + *       src_alpha \a func \a threshold + * + * \note The alpha compare function can be used to conditionally write pixels to the EFB using the source alpha channel as a template. If the compare function is + * true, the source color will be written to the EFB based on the result of the Z compare (see GX_PokeZMode()). If the alpha compare function is false, the source + * color is not written to the EFB.

+ * + * \note The alpha compare test happens before the Z compare and before blending (see GX_PokeBlendMode()). + * + * \param[in] func \ref compare to use + * \param[in] threshold to which the source alpha will be compared to + * + * \return none + */ +void GX_PokeAlphaMode(u8 func,u8 threshold); + +/*! + * \fn void GX_PokeAlphaUpdate(u8 update_enable) + * \brief Enables or disables alpha-buffer updates for GX_Poke*() functions. + * + * \details The normal rendering state (set by GX_SetAlphaUpdate()) is not affected. + * + * \param[in] update_enable enables alpha-buffer updates with GX_TRUE, otherwise does not + * + * \return none + */ +void GX_PokeAlphaUpdate(u8 update_enable); + +/*! + * \fn void GX_PokeColorUpdate(u8 update_enable) + * \brief Enables or disables color-buffer updates when writing the Embedded Frame Buffer (EFB) using the GX_Poke*() functions. + * + * \param[in] update_enable enables color-buffer updates with GX_TRUE, otherwise does not + * + * \return none + */ +void GX_PokeColorUpdate(u8 update_enable); + +/*! + * \fn void GX_PokeDither(u8 dither) + * \brief Enables dithering when writing the Embedded Frame Buffer (EFB) using GX_Poke*() functions. + * + * \note The \a dither enable is only valid when the pixel format (see GX_SetPixelFmt()) is either GX_PF_RGBA6_Z24 or GX_PF_RGB565_Z16.

+ * + * \note A 4x4 Bayer matrix is used for dithering. + * + * \param[in] dither if set to GX_TRUE and pixel format is one of the above, dithering is enabled; otherwise disabled + * + * \return none + */ +void GX_PokeDither(u8 dither); + +/*! + * \fn void GX_PokeBlendMode(u8 type,u8 src_fact,u8 dst_fact,u8 op) + * \brief Determines how the source image, is blended with the current Embedded Frame Buffer (EFB). + * + * \details When type is set to GX_BM_NONE, no color data is written to the EFB. When type is set to GX_BM_BLEND, the source and EFB pixels + * are blended using the following equation:

+ * + *       dst_pix_clr = src_pix_clr * \a src_fact + dst_pix_clr * \a dst_fact

+ * + * When type is set to GX_BM_SUBTRACT, the destination pixel is computed as follows:

+ * + *       dst_pix_clr = dst_pix_clr - src_pix_clr [clamped to zero]

+ * + * Note that \a src_fact and \a dst_fact are not part of the equation. + * + * \note \a dst_fact can be used only when the frame buffer has GX_PF_RGBA6_Z24 as the pixel format (see GX_SetPixelFmt()).

+ * + * \note When type is set to GX_BM_LOGIC, the source and EFB pixels are blended using logical bitwise operations.

+ * + * \note This function does not effect the normal rendering state; see GX_SetBlendMode(). + * + * \param[in] type \ref blendmode + * \param[in] src_fact source \ref blendfactor; the pixel color produced by the graphics processor is multiplied by this factor + * \param[in] dst_fact destination \ref blendfactor; the current frame buffer pixel color is multiplied by this factor + * \param[in] op \ref logicop to use + */ +void GX_PokeBlendMode(u8 type,u8 src_fact,u8 dst_fact,u8 op); + +/*! + * \fn void GX_PokeAlphaRead(u8 mode) + * \brief Determines what value of alpha will be read from the Embedded Frame Buffer (EFB). + * + * \details The mode only applies to GX_Peek*() functions. + * + * \note This feature works no matter what pixel type (see GX_SetPixelFmt()) you are using. If you are using the EFB with alpha plane, it is + * recommended that you use GX_READ_NONE so that you can read correct alpha value from the EFB. If you are using the EFB with no alpha, you should + * set either of GX_READ_00 or GX_READ_FF in order to get a certain value.

+ * + * \param[in] mode \ref alphareadmode that determines value of alpha read from a frame buffer with no alpha channel. + * + * \return none + */ +void GX_PokeAlphaRead(u8 mode); + +/*! + * \fn void GX_PokeDstAlpha(u8 enable,u8 a) + * \brief Sets a constant alpha value for writing to the Embedded Frame Buffer (EFB). + * + * \details The EFB pixel type must have an alpha channel for this function to be effective (see GX_SetPixelFmt()). The blending operations (see + * GX_PokeBlendMode()) still use source alpha but when writing the pixel color, the constant \a a will replace the pixel alpha in the EFB. + * + * \param[in] enable if set to GX_ENABLE and pixel format supports dest alpha, \a a will be written to the framebuffer + * \param[in] a constant alpha value + * + * \return none + */ +void GX_PokeDstAlpha(u8 enable,u8 a); + +/*! + * \fn void GX_PokeARGB(u16 x,u16 y,GXColor color) + * \brief Allows the CPU to write \a color directly to the Embedded Frame Buffer (EFB) at position \a x,\a y. + * + * \details The alpha value in \a color can be compared with the current alpha threshold (see GX_PokeAlphaMode()). The color will be blended + * into the EFB using the blend mode set by GX_PokeBlendMode(). + * + * \note For an antialiased frame buffer, all 3 subsamples of a pixel are affected by the poke. + * + * \param[in] x coordinate, in pixels; must be 0 - 639 inclusive + * \param[in] y coordinate, in lines; must be 0 - 527 inclusive + * \param[in] color color to write at the location + * + * \return none + */ +void GX_PokeARGB(u16 x,u16 y,GXColor color); + +/*! + * \fn void GX_PeekARGB(u16 x,u16 y,GXColor *color) + * \brief Allows the CPU to read a color value directly from the Embedded Frame Buffer (EFB) at position \a x,\a y. + * + * \note For an antialiased frame buffer, only subsample 0 of a pixel is read. + * + * \param[in] x coordinate, in pixels; must be 0 - 639 inclusive + * \param[in] y coordinate, in lines; must be 0 - 527 inclusive + * \param[out] color struct to store color in + * + * \return none + */ +void GX_PeekARGB(u16 x,u16 y,GXColor *color); + +/*! + * \fn void GX_PokeZ(u16 x,u16 y,u32 z) + * \brief Allows the CPU to write a z value directly to the Embedded Frame Buffer (EFB) at position \a x,\a y. + * + * \details The \a z value can be compared with the current contents of the EFB. The Z compare fuction is set using GX_PokeZMode(). + * + * \note The \a z value should be in the range of 0x00000000 <= \a z < 0x00FFFFFF in the case of non-antialiased frame buffer. For an antialiased + * frame buffer, the \a z value should be in the compressed 16-bit format (0x00000000 <= \a z <= 0x0000FFFF), and the poke will affect all 3 + * subsamples of a pixel. + * + * \param[in] x coordinate, in pixels; must be 0 - 639 inclusive + * \param[in] y coordinate, in lines; must be 0 - 527 inclusive + * \param[in] z value to write at position \a x,\a y in the EFB + * + * \return none + */ +void GX_PokeZ(u16 x,u16 y,u32 z); + +/*! + * \fn void GX_PeekZ(u16 x,u16 y,u32 *z) + * \brief Allows the CPU to read a z value directly from the Embedded Frame Buffer (EFB) at position x,y. + * + * \details The z value is raw integer value from the Z buffer. + * + * \note The value range is 24-bit when reading from non-antialiased frame buffer. When reading from an antialiased frame buffer, subsample + * 0 is read and returned. The value will be compressed 16-bit form in this case. + * + * \param[in] x coordinate, in pixels; must be 0 - 639 inclusive + * \param[in] y coordinate, in lines; must be 0 - 527 inclusive + * \param[out] z pointer to a returned Z value + * + * \return none + */ +void GX_PeekZ(u16 x,u16 y,u32 *z); + +/*! + * \fn void GX_PokeZMode(u8 comp_enable,u8 func,u8 update_enable) + * \brief Sets the Z-buffer compare mode when writing the Embedded Frame Buffer (EFB). + * + * \details The result of the Z compare is used to conditionally write color values to the EFB. The Z value will be updated according to the + * result of the compare if Z update is enabled. + * + * When \a comp_enable is set to GX_DISABLE, poke Z buffering is disabled and the Z buffer is not updated. The \a func parameter determines the + * comparison that is performed. In the comparison function, the poked Z value is on the left while the Z value from the Z buffer is on the + * right. If the result of the comparison is false, the poked Z value is discarded. The parameter \a update_enable determines whether or not the + * Z buffer is updated with the new Z value after a comparison is performed. + * + * \note The normal rendering Z mode (set by GX_SetZMode()) is not affected by this function.

+ * + * \note Even if update_enable is GX_FALSE, compares may still be enabled. + * + * \param[in] comp_enable enables comparisons with source and destination Z values if GX_TRUE + * \param[in] func \ref compare function to use + * \param[in] update_enable enables Z-buffer updates when GX_TRUE + * + * \return none + */ +void GX_PokeZMode(u8 comp_enable,u8 func,u8 update_enable); + +/*! + * \fn u32 GX_GetTexObjFmt(GXTexObj *obj) + * \brief Returns the texture format described by texture object \a obj. + * + * \note Use GX_InitTexObj() or GX_InitTexObjCI() to initialize the texture format. + * + * \param[in] obj ptr to a texture object + * + * \return texture format of the given texture object + */ +u32 GX_GetTexObjFmt(GXTexObj *obj); + +/*! + * \fn u32 GX_GetTexObjMipMap(GXTexObj *obj) + * \brief Returns the texture mipmap enable described by texture object \a obj. + * + * \note Use GX_InitTexObj() or GX_InitTexObjCI() to initialize the texture mipmap enable. + * + * \param[in] obj ptr to a texture object + * + * \return mipmap enable flag + */ +u32 GX_GetTexObjMipMap(GXTexObj *obj); + +/*! + * \fn void* GX_GetTexObjUserData(GXTexObj *obj) + * \brief Used to get a pointer to user data from the \ref GXTexObj structure. + * + * \details You can use this function to retrieve private data structures from the texture object. This pointer is set using GX_InitTexObjUserData(). + * + * \param[in] obj ptr to object to read data from + * + * \return Pointer to user data. + */ +void* GX_GetTexObjUserData(GXTexObj *obj); + +/*! + * \fn void* GX_GetTexObjData(GXTexObj *obj) + * \brief Used to get a pointer to texture data from the \ref GXTexObj structure. + * + * \note The returned pointer is a physical address. + * + * \param[in] obj ptr to a texture object + * + * \return Physical pointer to texture data. + */ +void* GX_GetTexObjData(GXTexObj *obj); + +/*! + * \fn u8 GX_GetTexObjWrapS(GXTexObj* obj) + * \brief Returns the texture wrap s mode described by texture object \a obj. + * + * \note Use GX_InitTexObj() or GX_InitTexObjCI() to initialize the texture wrap s mode. + * + * \param[in] obj ptr to a texture object + * + * \return wrap s mode + */ +u8 GX_GetTexObjWrapS(GXTexObj* obj); + +/*! + * \fn u8 GX_GetTexObjWrapT(GXTexObj* obj) + * \brief Returns the texture wrap t mode described by texture object \a obj. + * + * \note Use GX_InitTexObj() or GX_InitTexObjCI() to initialize the texture wrap t mode. + * + * \param[in] obj ptr to a texture object + * + * \return wrap t mode + */ +u8 GX_GetTexObjWrapT(GXTexObj* obj); + +/*! + * \fn u16 GX_GetTexObjHeight(GXTexObj* obj) + * \brief Returns the texture height described by texture object \a obj. + * + * \note Use GX_InitTexObj() or GX_InitTexObjCI() to initialize the texture height. + * + * \param[in] obj ptr to a texture object + * + * \return texture height + */ +u16 GX_GetTexObjHeight(GXTexObj* obj); + +/*! + * \fn u16 GX_GetTexObjWidth(GXTexObj* obj) + * \brief Returns the texture width described by texture object \a obj. + * + * \note Use GX_InitTexObj() or GX_InitTexObjCI() to initialize the texture width. + * + * \param[in] obj ptr to a texture object + * + * \return texture width + */ +u16 GX_GetTexObjWidth(GXTexObj* obj); + +/*! + * \fn void GX_GetTexObjAll(GXTexObj* obj, void** image_ptr, u16* width, u16* height, u8* format, u8* wrap_s, u8* wrap_t, u8* mipmap); + * \brief Returns the parameters described by a texture object. Texture objects are used to describe all the parameters associated with a texture, including size, format, wrap modes, filter modes, etc. Texture objects are initialized using either GX_InitTexObj() or, for color index format textures, GX_InitTexObjCI(). + * + * \param[in] obj ptr to a texture object + * \param[out] image_ptr Returns a physical pointer to the image data for a texture. + * \param[out] width Returns the width of the texture or LOD 0 for mipmaps + * \param[out] height Returns the height of the texture or LOD 0 for mipmaps + * \param[out] format Returns the texel format + * \param[out] mipmap Returns the mipmap enable flag. + * + * \return none + */ +void GX_GetTexObjAll(GXTexObj* obj, void** image_ptr, u16* width, u16* height, u8* format, u8* wrap_s, u8* wrap_t, u8* mipmap); + +/*! + * \fn u32 GX_GetTexBufferSize(u16 wd,u16 ht,u32 fmt,u8 mipmap,u8 maxlod) + * \brief Returns the amount of memory in bytes needed to store a texture of the given size and \a fmt. + * + * \details If the \a mipmap flag is GX_TRUE, then the size of buffer needed for the mipmap pyramid up to \a maxlod will be returned. + * \a maxlod will be clamped to the number of LODs possible given the map \a wd and \a ht. For mipmaps, \a wd and \a ht must be a power of two. + * + * \note This function takes into account the tiling and padding requirements of the GameCube's native texture format. The resulting size can be used + * along with memalign() to allocate texture buffers (see GX_CopyTex()). + * + * \param[in] wd width of the texture in texels + * \param[in] ht height of the texture in texels + * \param[in] fmt format of the texture; use GX_TexFmt() or GX_CITexFmt() to get it + * \param[in] mipmap flag indicating whether or not the texture is a mipmap + * \param[in] maxlod if \a mipmap is \a GX_TRUE, texture size will include mipmap pyramid up to this value + * + * \return number of bytes needed for the texture, including tile padding + */ +u32 GX_GetTexBufferSize(u16 wd,u16 ht,u32 fmt,u8 mipmap,u8 maxlod); + +/*! + * \fn void GX_InvalidateTexAll() + * \brief Invalidates the current caches of the Texture Memory (TMEM). + * + * \details It takes about 512 GP clocks to invalidate all the texture caches. + * + * \note Preloaded textures (see GX_PreloadEntireTexture()) are not affected. + * + * \return none + */ +void GX_InvalidateTexAll(); + +/*! + * \fn void GX_InvalidateTexRegion(GXTexRegion *region) + * \brief Invalidates the texture cache in Texture Memory (TMEM) described by \a region. + * + * \details This function should be called when the CPU is used to modify a texture in main memory, or a new texture is loaded into main memory that + * is possibly cached in the texture region. + * + * \note In reality, this function invalidates the cache tags, forcing the texture cache to load new data. Preloaded textures (see + * GX_PreloadEntireTexture()) do not use the tags.

+ * + * \note The texture hardware can invalidate 4 tags each GP clock. Each tag represents a superline or 512B of TMEM. Therefore, it takes 16 + * GP clocks to invalidate a 32KB texture region. + * + * \param[in] region ptr to GXTexRegion object + * + * \return none + */ +void GX_InvalidateTexRegion(GXTexRegion *region); + +/*! + * \fn void GX_InitTexCacheRegion(GXTexRegion *region,u8 is32bmipmap,u32 tmem_even,u8 size_even,u32 tmem_odd,u8 size_odd) + * \brief Initializes a texture memory (TMEM) region object for cache. + * + * \details The region is allocated by the application and can be used as a cache. An application can create many region objects and some of them can + * overlap; however, no two overlapping regions can be active at the same time. + * + * The possible sizes of a TMEM cache region are 32K, 128K or 512K. + * + * \note For pre-loaded textures, the region must be defined by using GX_InitTexPreloadRegion().

+ * + * \note GX_Init() creates default texture regions, so it is not necessary for the application to use this function unless a different Texture Memory + * configuration is desired. In that case, the application should also define a region allocator using GX_SetTexRegionCallback().

+ * + * \note The function GX_InvalidateTexRegion() can be used to force the texture in main memory associated with this region to be reloaded. This will be + * necessary whenever the texture data in main memory changes. You may invalidate all cached regions at once using GX_InvalidateTexAll(). + * + * \param[in] region ptr to a GXTexRegion struct + * \param[in] is32bmipmap should be set to GX_TRUE to interpret parameters according to the 32b mipmap meaning. + * \param[in] tmem_even base ptr in TMEM for even LODs; must be multiple of 2KB + * \param[in] size_even even \ref texcachesize other than GX_TEXCACHE_NONE + * \param[in] tmem_odd base ptr in TMEM for odd LODs; must be multiple of 2KB + * \param[in] size_odd odd \ref texcachesize other than GX_TEXCACHE_NONE + * + * \return none + */ +void GX_InitTexCacheRegion(GXTexRegion *region,u8 is32bmipmap,u32 tmem_even,u8 size_even,u32 tmem_odd,u8 size_odd); + +/*! + * \fn void GX_InitTexPreloadRegion(GXTexRegion *region,u32 tmem_even,u32 size_even,u32 tmem_odd,u32 size_odd) + * \brief Initializes a Texture Memory (TMEM) region object for preloading. + * + * \details The region is allocated in TMEM by the application and can be used only as a pre-loaded buffer. Cache regions must be allocated + * by using GX_InitTexCacheRegion(). For pre-loaded textures, the size of the region must match the size of the texture. An application can + * create many region objects and some of them can overlap; however, no two overlapping regions can be active at the same time. + * + * \note The maximum size of a region is 512K. + * + * \warning GX_Init() creates no region for preloading, so the application should allocate appropriate regions if preloading is necessary. It + * is also required to create cache regions and its allocator by using GX_InitTexCacheRegion() and GX_SetTexRegionCallback(), otherwise new + * cache regions may overwrite the preloaded areas. (Alternatively, if you do not use any color-index textures, you may preload textures into + * the portion of texture memory normally allocated to color-index usage by the default allocator.) + * + * \param[in] region ptr to a GXTexRegion struct + * \param[in] tmem_even base ptr in TMEM for even LODs; must be 32B aligned + * \param[in] size_even size of the even cache, in bytes; should be multiple of 32B + * \param[in] tmem_odd base ptr in TMEM for odd LODs; must be 32B aligned + * \param[in] size_odd size of the odd cache, in bytes; should be multiple of 32B + * + * \return none + */ +void GX_InitTexPreloadRegion(GXTexRegion *region,u32 tmem_even,u32 size_even,u32 tmem_odd,u32 size_odd); + +/*! + * \fn void GX_InitTexObj(GXTexObj *obj,void *img_ptr,u16 wd,u16 ht,u8 fmt,u8 wrap_s,u8 wrap_t,u8 mipmap) + * \brief Used to initialize or change a texture object for non-color index textures. + * + * \details Texture objects are used to describe all the parameters associated with a texture, including size, format, wrap modes, filter modes, + * etc. It is the application's responsibility to provide memory for a texture object. Once initialized, a texture object can be associated with + * one of eight active texture IDs using GX_LoadTexObj(). + * + * \note To initialize a texture object for color index format textures, use GX_InitTexObjCI().

+ * + * \note If the mipmap flag is GX_TRUE, then the texture is a mipmap and the texture will be trilerped. If the mipmap flag is GX_FALSE, the texture + * is not a mipmap and the texture will be bilerped. To override the filter modes and other mipmap controls, see GX_InitTexObjLOD(). + * + * \param[out] obj ptr to a texture object + * \param[in] img_ptr ptr to the image data for a texture, aligned to 32B + * \param[in] wd width of the texture, or LOD level 0 for mipmaps; max value is 1024; mipmaps must be a power of two + * \param[in] ht height of the texture, or LOD level 0 for mipmaps; max value is 1024; mipmaps must be a power of two + * \param[in] fmt \ref texfmt + * \param[in] wrap_s texture coordinate wrapping strategy in the S direction; use GX_CLAMP, GX_REPEAT or GX_MIRROR + * \param[in] wrap_t texture coordinate wrapping strategy in the T direction; use GX_CLAMP, GX_REPEAT or GX_MIRROR + * \param[in] mipmap trilinear filtering will be used if GX_TRUE, otherwise bilinear is used + * + * \return none + */ +void GX_InitTexObj(GXTexObj *obj,void *img_ptr,u16 wd,u16 ht,u8 fmt,u8 wrap_s,u8 wrap_t,u8 mipmap); + +/*! + * \fn void GX_InitTexObjCI(GXTexObj *obj,void *img_ptr,u16 wd,u16 ht,u8 fmt,u8 wrap_s,u8 wrap_t,u8 mipmap,u32 tlut_name) + * \brief Used to initialize or change a texture object when the texture is color index format. + * + * \details Texture objects are used to describe all the parameters associated with a texture, including size, format, wrap modes, filter modes, + * etc. It is the application's responsibility to provide memory for a texture object. Once initialized, a texture object can be associated with + * one of eight active texture IDs using GX_LoadTexObj(). + * + * \note If the \a mipmap flag is GX_TRUE, then the texture is a mipmap and the texture will be filtered using the GX_LIN_MIP_NEAR filter mode + * (color index mipmaps cannot use the GX_LIN_MIP_LIN or GX_NEAR_MIP_LIN mode). If the \a mipmap flag is GX_FALSE, the texture is not a mipmap + * and the texture will be bilerped. To override the filter modes and other mipmap controls, use GX_InitTexObjLOD(). Mipmap textures should + * set the width and height to a power of two, but mipmaps do not need to be square.

+ * + * \note Non-mipmap (planar) textures do not have to be a power of two. However, to use the GX_REPEAT or GX_MIRROR modes for \a wrap_s and \a wrap_t + * the width and height, respectively, must be a power of two.

+ * + * \note The \a tlut_name is used to indicate which texture lookup table (TLUT) to use for the index to color conversion. To load the TLUT into + * texture memory, use GX_LoadTlut(). + * + * \param[in] obj ptr to a texture object + * \param[in] img_ptr ptr to the image data for a texture, aligned to 32B + * \param[in] wd width of the texture, or LOD level 0 for mipmaps; max value is 1024; mipmaps must be a power of two + * \param[in] ht height of the texture, or LOD level 0 for mipmaps; max value is 1024; mipmaps must be a power of two + * \param[in] fmt \ref texfmt + * \param[in] wrap_s texture coordinate wrapping strategy in the S direction; use GX_CLAMP, GX_REPEAT or GX_MIRROR + * \param[in] wrap_t texture coordinate wrapping strategy in the T direction; use GX_CLAMP, GX_REPEAT or GX_MIRROR + * \param[in] mipmap if GX_TRUE, it is a mipmap texture, else it is a planar texture + * \param[in] tlut_name TLUT name to use for this texture; default texture configuration recognizes \ref tlutname + * + * \return none + */ +void GX_InitTexObjCI(GXTexObj *obj,void *img_ptr,u16 wd,u16 ht,u8 fmt,u8 wrap_s,u8 wrap_t,u8 mipmap,u32 tlut_name); + +/*! + * \fn void GX_InitTexObjTlut(GXTexObj *obj,u32 tlut_name) + * \brief Allows one to modify the TLUT that is associated with an existing texture object. + * + * \param[in] obj ptr to a texture object + * \param[in] tlut_name TLUT name to use for this texture; default texture configuration recognizes \ref tlutname + * + * \return none + */ +void GX_InitTexObjTlut(GXTexObj *obj,u32 tlut_name); + +/*! + * \fn void GX_InitTexObjData(GXTexObj *obj,void *img_ptr) + * \brief Allows one to modify the image data pointer for an existing texture object. + * + * \note The image format and size for the new data must agree with what they were when the texture object was first initialized using + * GX_InitTexObj() or GX_InitTexObjCI(). + * + * \param[in] obj ptr to a texture object + * \param[in] img_ptr ptr to the texture data in main memory + * + * \return none + */ +void GX_InitTexObjData(GXTexObj *obj,void *img_ptr); + +/*! + * \fn void GX_InitTexObjWrapMode(GXTexObj *obj,u8 wrap_s,u8 wrap_t) + * \brief Allows one to modify the texture coordinate wrap modes for an existing texture object. + * + * \param[in] obj ptr to a texture object + * \param[in] wrap_s texture coordinate wrapping strategy in the S direction; use GX_CLAMP, GX_REPEAT or GX_MIRROR + * \param[in] wrap_t texture coordinate wrapping strategy in the T direction; use GX_CLAMP, GX_REPEAT or GX_MIRROR + * + * \return none + */ +void GX_InitTexObjWrapMode(GXTexObj *obj,u8 wrap_s,u8 wrap_t); + +/*! + * \fn void GX_InitTexObjFilterMode(GXTexObj *obj,u8 minfilt,u8 magfilt) + * \brief Sets the filter mode for a texture. + * + * \details When the ratio of texels for this texture to pixels is not 1:1, the filter type for \a minfilt or \a magfilt is used. + * + * \param[in] obj texture object to set the filters for + * \param[in] minfilt filter mode to use when the texel/pixel ratio is >= 1.0; needs to be one of \ref texfilter. + * \param[in] magfilt filter mode to use when the texel/pixel ratio is < 1.0; needs to be \a GX_NEAR or \a GX_LINEAR + */ +void GX_InitTexObjFilterMode(GXTexObj *obj,u8 minfilt,u8 magfilt); + +/*! + * \fn void GX_InitTexObjMinLOD(GXTexObj *obj,f32 minlod) + * \brief Sets the minimum LOD for a given texture. + * + * \param[in] obj texture to set the minimum LOD for + * \param[in] minlod minimum LOD value; the hardware will use MAX(min_lod, lod); range is 0.0 to 10.0. + */ +void GX_InitTexObjMinLOD(GXTexObj *obj,f32 minlod); + +/*! + * void GX_InitTexObjMaxLOD(GXTexObj *obj,f32 maxlod) + * \brief Sets the maximum LOD for a given texture. + * + * \param[in] obj texture to set the maximum LOD for + * \param[in] maxlod maximum LOD value; the hardware will use MIN(max_lod, lod); range is 0.0 to 10.0. + */ +void GX_InitTexObjMaxLOD(GXTexObj *obj,f32 maxlod); + +/*! + * \fn void GX_InitTexObjLODBias(GXTexObj *obj,f32 lodbias) + * \brief Sets the LOD bias for a given texture. + * + * \details The LOD computed by the graphics hardware can be biased using this function. The \a lodbias is added to the computed lod and the + * result is clamped between the values given to GX_InitTexObjMinLOD() and GX_InitTexObjMaxLOD(). If \a GX_ENABLE is given to + * GX_InitTexObjBiasClamp(), the effect of \a lodbias will diminish as the polygon becomes more perpendicular to the view direction. + * + * \param[in] obj texture to set the LOD bias for + * \param[in] lodbias bias to add to computed LOD value + */ +void GX_InitTexObjLODBias(GXTexObj *obj,f32 lodbias); + +/*! + * \fn void GX_InitTexObjBiasClamp(GXTexObj *obj,u8 biasclamp) + * \brief Enables bias clamping for texture LOD. + * + * \details If \a biasclamp is \a GX_ENABLE, the sum of LOD and \a lodbias (given in GX_InitTexObjLODBias()) is clamped so that it is never + * less than the minimum extent of the pixel projected in texture space. This prevents over-biasing the LOD when the polygon is perpendicular + * to the view direction. + * + * \param[in] obj texture to set the bias clamp value for + * \param[in] biasclamp whether or not to enable the bias clamp + */ +void GX_InitTexObjBiasClamp(GXTexObj *obj,u8 biasclamp); + +/*! + * \fn void GX_InitTexObjEdgeLOD(GXTexObj *obj,u8 edgelod) + * \brief Changes LOD computing mode. + * + * \details When set to \a GX_ENABLE, the LOD is computed using adjacent texels; when \a GX_DISABLE, diagonal texels are used instead. This + * should be set to \a GX_ENABLE if you use bias clamping (see GX_InitTexObjBiasClamp()) or anisotropic filtering (GX_ANISO_2 or GX_ANISO_4 + * for GX_InitTexObjMaxAniso() argument). + * + * \param[in] obj texture to set the edge LOD for + * \param[in] edgelod mode to set LOD computation to + */ +void GX_InitTexObjEdgeLOD(GXTexObj *obj,u8 edgelod); + +/*! + * \fn void GX_InitTexObjMaxAniso(GXTexObj *obj,u8 maxaniso) + * \brief Sets the maximum anisotropic filter to use for a texture. + * + * \details Anisotropic filtering is accomplished by iterating the square filter along the direction of anisotropy to better approximate the + * quadralateral. This type of filtering results in sharper textures at the expense of multiple cycles per quad. The hardware will only use + * multiple cycles when necessary, and the maximum number of cycles is clamped by the \a maxaniso parameter, so setting \a maxaniso to + * \a GX_ANISO_2 will use at most 2 filter cycles per texture. + * + * \note These filter cycles are internal to the texture filter hardware and do not affect the available number of TEV stages. When setting + * \a maxaniso to \a GX_ANISO_2 or \a GX_ANISO_4, the \a minfilt parameter given to GX_InitTexObjFilterMode() should be set to + * \a GX_LIN_MIP_LIN. + * + * \param[in] obj texture to set the max anisotropy value to + * \param[in] maxaniso the maximum anistropic filter to use; must be one of \ref anisotropy + */ +void GX_InitTexObjMaxAniso(GXTexObj *obj,u8 maxaniso); + +/*! + * \fn GX_InitTexObjUserData(GXTexObj *obj,void *userdata) + * \brief Used to set a pointer to user data in the \ref GXTexObj structure. + * + * \details You can use this function to attach private data structures to the texture object. This pointer can be retrieved using GX_GetTexObjUserData(). + * + * \param[in] obj ptr to a texture object + * \param[in] userdata pointer to your data to attach to this texture + */ +void GX_InitTexObjUserData(GXTexObj *obj,void *userdata); + +/*! + * \fn void GX_LoadTexObj(GXTexObj *obj,u8 mapid) + * \brief Loads the state describing a texture into one of eight hardware register sets. + * + * \details Before this happens, the texture object \a obj should be initialized using GX_InitTexObj() or GX_InitTexObjCI(). The \a id parameter refers to + * the texture state register set. Once loaded, the texture can be used in any Texture Environment (TEV) stage using GX_SetTevOrder(). + * + * \note This function will call the functions set by GX_SetTexRegionCallback() (and GX_SetTlutRegionCallback() if the texture is color-index + * format) to obtain the texture regions associated with this texture object. These callbacks are set to default functions by GX_Init(). + * + * \warning If the texture is a color-index texture, you must load the associated TLUT (using GX_LoadTlut()) before calling GX_LoadTexObj(). + * + * \param[in] obj ptr to a texture object + * \param[in] mapid \ref texmapid, GX_TEXMAP0 to GX_TEXMAP7 only + * + * \return none + */ +void GX_LoadTexObj(GXTexObj *obj,u8 mapid); + +/*! + * \fn void GX_LoadTlut(GXTlutObj *obj,u32 tlut_name) + * \brief Copies a Texture Look-Up Table (TLUT) from main memory to Texture Memory (TMEM). + * + * \details The \a tlut_name parameter is the name of a pre-allocated area of TMEM. The callback function set by GX_SetTlutRegionCallback() converts + * the \a tlut_name into a \ref GXTlutRegion pointer. The TLUT is loaded in the TMEM region described by this pointer. The TLUT object \a obj describes the + * location of the TLUT in main memory, the TLUT format, and the TLUT size. \a obj should have been previously initialized using GX_InitTlutObj(). + * + * \note GX_Init() sets a default callback to convert \a tlut_names from \ref tlutname to \ref GXTlutRegion pointers. The default configuration of + * TMEM has 20 TLUTs, 16 each 256 entries by 16 bits, and 4 each 1k entries by 16 bits. This configuration can be overriden by calling + * GX_InitTlutRegion() and GX_InitTexCacheRegion() to allocate TMEM. Then you can define your own region allocation scheme using GX_SetTlutRegionCallback() + * and GX_SetTexRegionCallback(). + * + * \param[in] obj ptr to a TLUT object; application must allocate this + * \param[in] tlut_name \ref tlutname + * + * \return none + */ +void GX_LoadTlut(GXTlutObj *obj,u32 tlut_name); + +/*! + * \fn void GX_LoadTexObjPreloaded(GXTexObj *obj,GXTexRegion *region,u8 mapid) + * \brief Loads the state describing a preloaded texture into one of eight hardware register sets. + * + * \details Before this happens, the texture object \a obj should be initialized using GX_InitTexObj() or GX_InitTexObjCI(). The \a mapid parameter refers to + * the texture state register set. The texture should be loaded beforehand using GX_PreloadEntireTexture(). Once loaded, the texture can be used in any Texture Environment + * (TEV) stage using GX_SetTevOrder(). + * + * \note GX_Init() initially calls GX_SetTevOrder() to make a simple texture pipeline that associates GX_TEXMAP0 with GX_TEVSTAGE0, + * GX_TEXMAP1 with GX_TEVSTAGE1, etc.

+ * + * \note GX_LoadTexObjPreloaded() will not call the functions set by GX_SetTexRegionCallback() (and GX_SetTlutRegionCallback() if the texture is color + * index format) because the region is set explicitly; however, these callback functions must be aware of all regions that are preloaded. The default + * callbacks set by GX_Init() assume there are no preloaded regions. + * + * \param[in] obj ptr to a texture object + * \param[in] region ptr to a region object that describes an area of texture memory + * \param[in] mapid \ref texmapid for reference in a TEV stage + * + * \return none + */ +void GX_LoadTexObjPreloaded(GXTexObj *obj,GXTexRegion *region,u8 mapid); + +/*! + * \fn void GX_PreloadEntireTexture(GXTexObj *obj,GXTexRegion *region) + * \brief Loads a given texture from DRAM into the texture memory. + * + * \details Accesses to this texture will bypass the texture cache tag look-up and instead read the texels directly from texture memory. The + * texture region must be the same size as the texture (see GX_InitTexPreloadRegion()). + * + * \note This function loads the texture into texture memory, but to use it as a source for the Texture Environment (TEV) unit, you must first + * call GX_LoadTexObjPreloaded(). The default configuration (as set by GX_Init()) of texture memory has no preloaded regions, so you must install + * your own region allocator callbacks using GX_SetTexRegionCallback() and GX_SetTlutRegionCallback(). + * + * \param[in] obj ptr to object describing the texture to laod + * \param[in] region TMEM texture region to load the texture into + * + * \return none + */ +void GX_PreloadEntireTexture(GXTexObj *obj,GXTexRegion *region); + +/*! + * \fn void GX_InitTlutObj(GXTlutObj *obj,void *lut,u8 fmt,u16 entries) + * \brief Initializes a Texture Look-Up Table (TLUT) object. + * + * \details The TLUT object describes the location of the TLUT in main memory, its format and the number of entries. The TLUT in main + * memory described by this object can be loaded into a TLUT allocated in the texture memory using the GX_LoadTlut() function. + * + * \param[in] obj ptr to a TLUT object + * \param[in] lut ptr to look-up table data; must be 32B aligned + * \param[in] fmt format of the entries in the TLUt; GX_TL_IA8, GX_TL_RGB565 or GX_TL_RGB5A3 + * \param[in] entries number of entries in this table; maximum is 16,384 + * + * \return none + */ +void GX_InitTlutObj(GXTlutObj *obj,void *lut,u8 fmt,u16 entries); + +/*! + * \fn void GX_InitTlutRegion(GXTlutRegion *region,u32 tmem_addr,u8 tlut_sz) + * \brief Initializes a Texture Look-Up Table (TLUT) region object. + * + * \note GX_Init() creates default TLUT regions, so the application does not need to call this function unless a new configuration + * of Texture Memory is desired. In that case, the application should also set a new TLUT region allocator using GX_SetTlutRegionCallback(). + * + * \param[in] region obj ptr to a TLUT region struct; application must allocate this + * \param[in] tmem_addr location of the TLU in TMEM; ptr must be aligned to table size + * \param[in] tlut_sz size of the table + * + * \return none + */ +void GX_InitTlutRegion(GXTlutRegion *region,u32 tmem_addr,u8 tlut_sz); + +/*! + * \fn void GX_InitTexObjLOD(GXTexObj *obj,u8 minfilt,u8 magfilt,f32 minlod,f32 maxlod,f32 lodbias,u8 biasclamp,u8 edgelod,u8 maxaniso) + * \brief Sets texture Level Of Detail (LOD) controls explicitly for a texture object. + * + * \details It is the application's responsibility to provide memory for a texture object. When initializing a texture object using GX_InitTexObj() + * or GX_InitTexObjCI(), this information is set to default values based on the mipmap flag. This function allows the programmer to override those + * defaults. + * + * \note This function should be called after GX_InitTexObj() or GX_InitTexObjCI() for a particular texture object.

+ * + * \note Setting \a biasclamp prevents over-biasing the LOD when the polygon is perpendicular to the view direction.

+ * + * \note \a edgelod should be set if \a biasclamp is set or \a maxaniso is set to GX_ANISO_2 or GX_ANISO_4.

+ * + * \note Theoretically, there is no performance difference amongst various magnification/minification filter settings except GX_LIN_MIP_LIN filter with + * GX_TF_RGBA8 texture format which takes twice as much as other formats. However, this argument is assuming an environment where texture cache always + * hits. On real environments, you will see some performance differences by changing filter modes (especially minification filter) because cache-hit ratio + * changes according to which filter mode is being used. + * + * \param[in] obj ptr to a texture object + * \param[in] minfilt \ref texfilter to use when the texel/pixel ratio is >= 1.0 + * \param[in] magfilt \ref texfilter to use when the texel/pixel ratio is < 1.0; use only GX_NEAR or GX_LINEAR + * \param[in] minlod minimum LOD value from 0.0 - 10.0 inclusive + * \param[in] maxlod maximum LOD value from 0.0 - 10.0 inclusive + * \param[in] lodbias bias to add to computed LOD value + * \param[in] biasclamp if GX_ENABLE, clamp (LOD+lodbias) so that it is never less than the minimum extent of the pixel projected in texture space + * \param[in] edgelod if GX_ENABLE, compute LOD using adjacent texels + * \param[in] maxaniso \ref anisotropy to use + * + * \return none + */ +void GX_InitTexObjLOD(GXTexObj *obj,u8 minfilt,u8 magfilt,f32 minlod,f32 maxlod,f32 lodbias,u8 biasclamp,u8 edgelod,u8 maxaniso); + +/*! + * \fn void GX_SetTexCoordScaleManually(u8 texcoord,u8 enable,u16 ss,u16 ts) + * \brief Overrides the automatic texture coordinate scaling (based upon the associated map size) and lets one manually assign the scale values that + * are used for a given \a texcoord. + * + * \details Setting the \a enable parameter to GX_TRUE gives this behavior. The given \a texcoord retains these manual scale values until this function is + * called again. This function is also used to return a given texture coordinate back to normal, automatic scaling (by setting \a enable to GX_FALSE). + * + * \note A texture coordinate is scaled after being computed by the relevant texgen and before the actual texture lookup Normally, the scale value is set + * according to the texture map that is associated with the texcoord by GX_SetTevOrder(). However, there are certain cases where a different scale value is + * desirable. One such case is when using indirect tiled textures (see GX_SetTevIndTile()). + * + * \param[in] texcoord the \ref texcoordid being changed + * \param[in] enable if GX_TRUE, scale will be set manually, otherwise set automatically and \a ss and \a ts ignored + * \param[in] ss manual scale value for the S component of the coordinate + * \param[in] ts manual scale value for the T component of the coordinate + * + * \return none + */ +void GX_SetTexCoordScaleManually(u8 texcoord,u8 enable,u16 ss,u16 ts); + +/*! + * \fn void GX_SetTexCoordBias(u8 texcoord,u8 s_enable,u8 t_enable) + * \brief Sets the texture coordinate bias of a particular texture. + * + * \details Range bias is used with texture coordinates applied in GX_REPEAT wrap mode in order to increase the precision of texture coordinates + * that spread out over a large range. The texture coordinate values for a primitive are biased (by an equal integer) towards zero early in the + * graphics pipeline, thus preserving bits for calculation later in the pipe. Since the coordinates are repeated, this bias by an integer should + * have no effect upon the actual appearance of the texture. + * + * \note Texture coordinate range bias is something that is normally set automatically by the GX API (during GX_Begin()); however, when a texture + * coordinate is being scaled manually (by using GX_SetTexCoordScaleManually()), the associated bias is no longer modified by GX. Thus, + * GX_SetTexCoordBias() allows the bias to be changed while a texture coordinate is being manually controlled. + * + * \param[in] texcoord \ref texcoordid being changed + * \param[in] s_enable enable or disable range bias in the S direction with GX_ENABLE/GX_DISABLE + * \param[in] t_enable enable or disable range bias in the T direction with GX_ENABLE/GX_DISABLE + * + * \return none + */ +void GX_SetTexCoordBias(u8 texcoord,u8 s_enable,u8 t_enable); + +/*! + * \fn GXTexRegionCallback GX_SetTexRegionCallback(GXTexRegionCallback cb) + * \brief Sets the callback function called by GX_LoadTexObj() to obtain an available texture region. + * + * \details GX_Init() calls this function to set a default region-assignment policy. A programmer can override this default region assignment + * by implementing his own callback function. A pointer to the texture object and the texture map ID that are passed + * to GX_LoadTexObj() are provided to the callback function. + * + * \param[in] cb ptr to a function that takes a pointer to a GXTexObj and a \ref texmapid as a parameter and returns a pointer to a \ref GXTexRegion. + * + * \return pointer to the previously set callback + */ +GXTexRegionCallback GX_SetTexRegionCallback(GXTexRegionCallback cb); + +/*! + * \fn GXTlutRegionCallback GX_SetTlutRegionCallback(GXTlutRegionCallback cb) + * \brief Sets the callback function called by GX_LoadTlut() to find the region into which to load the TLUT. + * + * \details GX_LoadTexObj() will also call \a cb to obtain the Texture Look-up Table (TLUT) region when the texture forma + * is color-index. + * + * GX_Init() calls GX_SetTlutRegionCallback() to set a default TLUT index-to-region mapping. The name for the TLUT from the texture + * object is provided as an argument to the callback. The callback should return a pointer to the \ref GXTlutRegion for this TLUT index. + * + * \note For a given \a tlut_name (in the \ref GXTlutRegionCallback struct), \a cb must always return the same \ref GXTlutRegion; this is because + * GX_LoadTlut() will initialize data into the \ref GXTlutRegion which GX_LoadTexObj() will subsequently use. + * + * \param[in] cb ptr to a function that takes a u32 TLUT name as a parameter and returns a pointer to a \ref GXTlutRegion. + * + * \return pointer to the previously set callback + */ +GXTlutRegionCallback GX_SetTlutRegionCallback(GXTlutRegionCallback cb); + +/*! + * \fn void GX_InitLightPos(GXLightObj *lit_obj,f32 x,f32 y,f32 z) + * \brief Sets the position of the light in the light object. + * + * \details The GameCube graphics hardware supports local diffuse lights. The position of the light should be in the same space as a transformed + * vertex position (i.e., view space). + * + * \note Although the hardware doesn't support parallel directional diffuse lights, it is possible to get "almost parallel" lights by setting + * sufficient large values to position parameters (x, y and z) which makes the light position very far away from objects to be lit and all rays + * considered almost parallel.

+ * + * \note The memory for the light object must be allocated by the application; this function does not load any hardware registers directly. To + * load a light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to the light object + * \param[in] x X coordinate to place the light at + * \param[in] y Y coordinate to place the light at + * \param[in] z Z coordinate to place the light at + * + * \return none + */ +void GX_InitLightPos(GXLightObj *lit_obj,f32 x,f32 y,f32 z); + +/*! + * \fn void GX_InitLightColor(GXLightObj *lit_obj,GXColor col) + * \brief Sets the color of the light in the light object. + * + * \note The memory for the light object should be allocated by the application; this function does not load any hardware register directly. To + * load a light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to the light object + * \param[in] col color to set the light to + * + * \return none + */ +void GX_InitLightColor(GXLightObj *lit_obj,GXColor col); + +/*! + * \fn void GX_InitLightDir(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz) + * \brief Sets the direction of a light in the light object. + * + * \details This direction is used when the light object is used as spotlight or a specular light (see the attn_fn parameter of GX_SetChanCtrl()). + * + * \note The coordinate space of the light normal should be consistent with a vertex normal transformed by a normal matrix; i.e., it should be + * transformed to view space.

+ * + * \note This function does not set the direction of parallel directional diffuse lights. If you want parallel diffuse lights, you may put the light + * position very far from every objects to be lit. (See GX_InitLightPos() and GX_SetChanCtrl())

+ * + * \note The memory for the light object must be allocated by the application; this function does not load any hardware registers. To load a light + * object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to the light object + * \param[in] nx X coordinate of the light normal + * \param[in] ny Y coordinate of the light normal + * \param[in] nz Z coordinate of the light normal + * + * \return none + */ +void GX_InitLightDir(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz); + +/*! + * \fn void GX_LoadLightObj(GXLightObj *lit_obj,u8 lit_id) + * \brief Loads a light object into a set of hardware registers associated with a \ref lightid. + * + * \details This function copies the light object data into the graphics FIFO through the CPU write-gather buffer mechanism. This guarantees that + * the light object is coherent with the CPU cache. + * + * \note The light object must have been initialized first using the necessary GX_InitLight*() functions.

+ * + * \note Another way to load a light object is with GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to the light object to load + * \param[in] lit_id \ref lightid to load this light into + * + * \return none + */ +void GX_LoadLightObj(GXLightObj *lit_obj,u8 lit_id); + +/*! + * \fn void GX_LoadLightObjIdx(u32 litobjidx,u8 litid) + * \brief Instructs the GP to fetch the light object at \a ltobjindx from an array. + * + * \details The light object is retrieved from the array to which GX_SetArray(GX_VA_LIGHTARRAY, ...) points. Then it loads the object into + * the hardware register associated with \ref lightid. + * + * \note Data flows directly from the array in DRAM to the GP; therefore, the light object data may not be coherent with the CPU's cache. The + * application is responsible for storing the light object data from the CPU cache (using DCStoreRange()) before calling GX_LoadLightObjIdx(). + * + * \param[in] litobjidx index to a light object + * \param[in] litid \ref lightid to load this light into + * + * \return none + */ +void GX_LoadLightObjIdx(u32 litobjidx,u8 litid); + +/*! + * \fn void GX_InitLightDistAttn(GXLightObj *lit_obj,f32 ref_dist,f32 ref_brite,u8 dist_fn) + * \brief Sets coefficients for distance attenuation in a light object. + * + * \details This function uses three easy-to-control parameters instead of k0, k1, and k2 in GX_InitLightAttn(). + * + * In this function, you can specify the brightness on an assumed reference point. The parameter \a ref_distance is distance between the light + * and the reference point. The parameter \a ref_brite specifies ratio of the brightness on the reference point. The value for \a ref_dist should + * be greater than 0 and that for \a ref_brite should be within 0 < \a ref_brite < 1, otherwise distance attenuation feature is turned off. The + * parameter \a dist_fn defines type of the brightness decreasing curve by distance; GX_DA_OFF turns distance attenuation feature off. + * + * \note If you want more flexible control, it is better to use GX_InitLightAttn() and calculate appropriate coefficients.

+ * + * \note This function sets parameters only for distance attenuation. Parameters for angular attenuation should be set by using + * GX_InitLightSpot() or GX_InitLightAttnA().

+ * + * \note This function does not load any hardware registers directly. To load a light object into a hardware light, use GX_LoadLightObj() or + * GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to a light object + * \param[in] ref_dist distance between the light and reference point + * \param[in] ref_brite brightness of the reference point + * \param[in] dist_fn \ref distattnfn to use + * + * \return none + */ +void GX_InitLightDistAttn(GXLightObj *lit_obj,f32 ref_dist,f32 ref_brite,u8 dist_fn); + +/*! + * \fn void GX_InitLightAttn(GXLightObj *lit_obj,f32 a0,f32 a1,f32 a2,f32 k0,f32 k1,f32 k2) + * \brief Sts coefficients used in the lighting attenuation calculation in a given light object. + * + * \details The parameters \a a0, \a a1, and \a a2 are used for angular (spotlight) attenuation. The coefficients \a k0, \a k1, and \a k2 are used for + * distance attenuation. The attenuation function is: + * + *       atten = clamp0(\a a2^2 * aattn^2 + \a a1 * aattn + \a a0) / (\a k2 * d^2 + \a k1 * d + \a k0) + * + * where aattn is the cosine of the angle between the light direction and the vector from the light position to the vertex, and d is + * the distance from the light position to the vertex when the channel attenuation function is GX_AF_SPOT. The light color will be + * multiplied by the atten factor when the attenuation function for the color channel referencing this light is set to GX_AF_SPOT + * (see GX_SetChanCtrl()). + * + * \note The convenience function GX_InitLightSpot() can be used to set the angle attenuation coefficents based on several spot light + * types. The convenience function GX_InitLightDistAttn() can be used to set the distance attenuation coefficients using one of several + * common attenuation functions.

+ * + * \note The convenience macro GX_InitLightShininess() can be used to set the attenuation parameters for specular lights.

+ * + * \note When the channel attenuation function is set to GX_AF_SPEC, the aattn and d parameter are equal to the dot product of the + * eye-space vertex normal and the half-angle vector set by GX_InitSpecularDir().

+ * + * \note This function does not load any hardware registers directly. To load a light object into a hardware light, use GX_LoadLightObj() + * or GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to a light object + * \param[in] a0 angle attenuation coefficient + * \param[in] a1 angle attenuation coefficient + * \param[in] a2 angle attenuation coefficient + * \param[in] k0 distance attenuation coefficient + * \param[in] k1 distance attenuation coefficient + * \param[in] k2 distance attenuation coefficient + * + * \return none + */ +void GX_InitLightAttn(GXLightObj *lit_obj,f32 a0,f32 a1,f32 a2,f32 k0,f32 k1,f32 k2); + +/*! + * \fn void GX_InitLightAttnA(GXLightObj *lit_obj,f32 a0,f32 a1,f32 a2) + * \brief Sets coefficients used in the lighting angle attenuation calculation in a given light object. + * + * \details The parameters \a a0, \a a1, and \a a2 are used for angular (spotlight) attenuation. The attenuation + * function is: + * + *       atten = clamp0(\a a2^2 * cos(theta)^2 + \a a1 * cos(theta) + \a a0) / (\a k2 * d^2 + \a k1 * d + \a k0) + * + * where cos(theta) is the cosine of the angle between the light normal and the vector from the light position to the vertex, and d is the distance + * from the light position to the vertex. The \a k0-\a 2 coefficients can be set using GX_InitLightAttnK(). You can set both the \a a0-\a 2 and \a k0-\a 2 coefficients + * can be set using GX_InitLightAttn(). The light color will be multiplied by the atten factor when the attenuation function for the color channel + * referencing this light is set to GX_AF_SPOT (see GX_SetChanCtrl()). + * + * \note The convenience function GX_InitLightSpot() can be used to set the angle attenuation coefficents based on several spot light types. The + * convenience function GX_InitLightDistAttn() can be used to set the distance attenuation coefficients using one of several common attenuation functions.

+ * + * \note This function does not load any hardware registers directly. To load a light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to a light object + * \param[in] a0 angle attenuation coefficient + * \param[in] a1 angle attenuation coefficient + * \param[in] a2 angle attenuation coefficient + * + * \return none + */ +void GX_InitLightAttnA(GXLightObj *lit_obj,f32 a0,f32 a1,f32 a2); + +/*! + * \fn void GX_InitLightAttnK(GXLightObj *lit_obj,f32 k0,f32 k1,f32 k2) + * \brief Sets coefficients used in the lighting distance attenuation calculation in a given light object. + * + * \details The coefficients \a k0, \a k1, and \a k2 are used for distance attenuation. The attenuation function is: + * + *       atten = clamp0(\a a2^2 * cos(theta)^2 + \a a1 * cos(theta) + \a a0) / (\a k2 * d^2 + \a k1 * d + \a k0) + * + * where cos(theta) is the cosine of the angle between the light normal and the vector from the light position to the vertex, and d is the distance + * from the light position to the vertex. The \a a0-\a 2 coefficients can be set using GX_InitLightAttnA(). You can set both the \a a0-\a 2 and \a k0-\a 2 coefficients + * can be set using GX_InitLightAttn(). The light color will be multiplied by the atten factor when the attenuation function for the color channel + * referencing this light is set to GX_AF_SPOT (see GX_SetChanCtrl()). + * + * \note The convenience function GX_InitLightSpot() can be used to set the angle attenuation coefficents based on several spot light types. The convenience + * function GX_InitLightDistAttn() can be used to set the distance attenuation coefficients using one of several common attenuation functions.

+ * + * \note Note that this function does not load any hardware registers directly. To load a light object into a hardware light, use GX_LoadLightObj() or + * GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to a light object + * \param[in] k0 distance attenuation coefficient + * \param[in] k1 distance attenuation coefficient + * \param[in] k2 distance attenuation coefficient + * + * \return none + */ +void GX_InitLightAttnK(GXLightObj *lit_obj,f32 k0,f32 k1,f32 k2); + +/*! + * \fn void GX_InitSpecularDirHA(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz,f32 hx,f32 hy,f32 hz) + * \brief Sets the direction and half-angle vector of a specular light in the light object. + * + * \details These vectors are used when the light object is used only as specular light. In contrast to GX_InitSpecularDir(), + * which caclulates half-angle vector automatically by assuming the view vector as (0, 0, 1), this function allows users to + * specify half-angle vector directly as input arguments. It is useful to do detailed control for orientation of highlights. + * + * \note This function does not load any hardware registers. To load a light object into a hardware light, use GX_LoadLightObj() + * or GX_LoadLightObjIdx().

+ * + * \note Other notes are similar to those described in GX_InitSpecularDir(). + * + * \param[in] lit_obj ptr to a light object + * \param[in] nx X coordinate of the light normal + * \param[in] ny Y coordinate of the light normal + * \param[in] nz Z coordinate of the light normal + * \param[in] hx X coordinate of half-angle + * \param[in] hy Y coordinate of half-angle + * \param[in] hz Z coordinate of half-angle + * + * \return none + */ +void GX_InitSpecularDirHA(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz,f32 hx,f32 hy,f32 hz); + +/*! + * \fn void GX_InitSpecularDir(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz) + * \brief Sets the direction of a specular light in the light object. + * + * \details This direction is used when the light object is used only as specular light. The coordinate space of the light normal + * should be consistent with a vertex normal transformed by a normal matrix; i.e., it should be transformed to view space. + * + * \note This function should be used if and only if the light object is used as specular light. One specifies a specular light in + * GX_SetChanCtrl() by setting the \ref attenfunc to GX_AF_SPEC. Furthermore, one must not use GX_InitLightDir() or + * GX_InitLightPos() to set up a light object which will be used as a specular light since these functions will destroy the information + * set by GX_InitSpecularDir(). In contrast to diffuse lights (including spotlights) that are considered local lights, a specular light + * is a parallel light (i.e. the specular light is infinitely far away such that all the rays of the light are parallel), and thus one + * can only specify directional information. + * + * \note This function does not load any hardware registers. To load a light object into a hardware light, use GX_LoadLightObj() + * or GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to a light object + * \param[in] nx X coordinate of the light normal + * \param[in] ny Y coordinate of the light normal + * \param[in] nz Z coordinate of the light normal + * + * \return none + */ +void GX_InitSpecularDir(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz); + +/*! + * \fn void GX_InitLightSpot(GXLightObj *lit_obj,f32 cut_off,u8 spotfn) + * \brief Sets coefficients for angular (spotlight) attenuation in light object. + * + * \details This function uses two easy-to-control parameters instead of \a a0, \a a1, and \a a2 on GX_InitLightAttn(). + * + * \details The parameter \a cut_off specifies cutoff angle of the spotlight by degree. The spotlight works while the angle between the ray for a vertex and + * the light direction given by GX_InitLightDir() is smaller than this cutoff angle. The value for \a cut_off should be within 0 < \a cut_off <= 90.0, otherwise + * given light object doesn't become a spotlight. + * + * The parameter \a spotfn defines type of the illumination distribution within cutoff angle. The value GX_SP_OFF turns spotlight feature off even if + * color channel setting is using GX_AF_SPOT (see GX_SetChanCtrl()). + * + * \note This function can generate only some kind of simple spotlights. If you want more flexible control, it is better to use GX_InitLightAttn() and calculate + * appropriate coefficients.

+ * + * \note This function sets parameters only for angular attenuation. Parameters for distance attenuation should be set by using GX_InitLightDistAttn() or + * GX_InitLightAttnK().

+ * + * \note This function does not load any hardware registers directly. To load a light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx(). + * + * \param[in] lit_obj ptr to a light object + * \param[in] cut_off cutoff angle of the spotlight, in degrees + * \param[in] spotfn \ref spotfn to use for this light + * + * \return none + */ +void GX_InitLightSpot(GXLightObj *lit_obj,f32 cut_off,u8 spotfn); + +u32 GX_ReadClksPerVtx(); +u32 GX_GetOverflowCount(); +u32 GX_ResetOverflowCount(); + +/*! + * \fn lwp_t GX_GetCurrentGXThread() + * \brief Returns the current GX thread. + * + * \details The current GX thread should be the thread that is currently responsible for generating graphics data. By default, + * the GX thread is the thread that invoked GX_Init(); however, it may be changed by calling GX_SetCurrentGXThread(). + * + * \note When graphics data is being generated in immediate mode (that is, the CPU FIFO = GP FIFO, and the GP is actively consuming + * data), the high watermark may be triggered. When this happens, the high watermark interrupt handler will suspend the GX thread, thus + * preventing any further graphics data from being generated. The low watermark interrupt handler will resume the thread. + * + * \return the current GX thread + */ +lwp_t GX_GetCurrentGXThread(); + +/*! + * \fn lwp_t GX_SetCurrentGXThread() + * \brief Sets the current GX thread to the calling thread. + * + * \details The new thread should be the thread that will be responsible for generating graphics data. By default, the GX thread is + * the thread that invoked GX_Init(); however, it may be changed by calling this function. + * + * \note It is a programming error to change GX thread while the current GX thread is suspended by a high water mark interrupt. This + * indicates that you have two threads about to generate GX data.

+ * + * \note When graphics data is being generated in immediate mode (that is, the CPU FIFO = GP FIFO, and the GP is actively consuming + * data), the high watermark may be triggered. When this happens, the high watermark interrupt handler will suspend the GX thread, thus + * preventing any further graphics data from being generated. The low watermark interrupt handler will resume the thread. + * + * \return the previous GX thread ID + */ +lwp_t GX_SetCurrentGXThread(); + +/*! + * \fn void GX_RestoreWriteGatherPipe() + * \brief Restores the write-gather pipe. + * + * \details The CPU fifo that was attached at the time GX_RedirectWriteGatherPipe() was called will be re-attached. If there is data pending + * in the write gather pipe (e.g. if the amount of data written was not a multiple of 32 bytes), the data will be padded with zeroes and + * flushed out. + * + * \warning This function must be called between successive calls to GX_RedirectWriteGatherPipe(). + * + * \return none + */ +void GX_RestoreWriteGatherPipe(); + +/*! + * \fn void GX_SetGPMetric(u32 perf0,u32 perf1) + * \brief Sets two performance metrics to measure in the GP. + * + * \details perf0 and perf1 are set to measure. The initial metrics measured are GX_PERF0_NONE and GX_PERF1_NONE, which return counts of zero + * for the first call to GX_ReadGPMetric(). + * + * Each performance counter has a unique set of events or ratios that it can count. In some cases the same metric can be counted using both + * counters, for example GX_PERF0_VERTICES and GX_PERF1_VERTICES. Ratios (the metric name ends in _RATIO) are multiplied by + * 1000 (1000 = all misses/clips, etc., 0 = no misses/clips, etc.). + * + * \note GX_ReadGPMetric() and GX_ClearGPMetric() can be used in the callback associated with the draw sync interrupt (see GX_SetDrawSyncCallback()). + * This function should not be used in the draw sync callback because it will insert tokens in the GP command stream at random times. + * + * \warning This function reads results from CPU-accessible registers in the GP, therefore, this command must not be used in a display list. In + * addition, the performance counters in some cases are triggered by sending tokens through the Graphics FIFO to the GP. This implies that + * the function should only be used in immediate mode (when the Graphics FIFO is connected to the CPU and the GP at the same time). It may + * also be necessary to send a draw sync token using GX_SetDrawSync() or call GX_SetDrawDone() after GX_ReadGPMetric() to ensure that the + * state has actually been processed by the GP. + * + * \param[in] perf0 \ref perf0metrics to measure + * \param[in] perf1 \ref perf1metrics to measure + * + * \returns none + */ +void GX_SetGPMetric(u32 perf0,u32 perf1); + +/*! + * \fn void GX_ClearGPMetric() + * \brief Clears the two virtual GP performance counters to zero. + * + * \note The counter's function is set using GX_SetGPMetric(); the counter's value is read using GX_ReadGPMetric(). Consult these for more details. + * + * \warning This function resets CPU accessible counters, so it should not be used in a display list. + * + * \return none + */ +void GX_ClearGPMetric(); + +/*! + * \fn void GX_InitXfRasMetric() + * \brief Initialize the transformation unit (XF) rasterizer unit (RAS) to take performance measurements. + * + * \warning This function should be avoided; use the GP performance metric functions instead. + * + * \return none + */ +void GX_InitXfRasMetric(); + +/*! + * \fn void GX_ReadXfRasMetric(u32 *xfwaitin,u32 *xfwaitout,u32 *rasbusy,u32 *clks) + * \brief Read performance metric values from the XF and RAS units. + * + * \warning This function should be avoided; use the GP performance metric functions instead.

+ * + * \warning The parameters for this function are a best guess based on names and existing code. + * + * \param[out] xfwaitin Number of clocks the XF has waited for data to arrive? + * \param[out] xfwaitout Number of clocks the XF has waited to push finished data down? + * \param[out] rasbusy Number of clocks the RAS has spent being busy? + * \param[out] clks Clocks that have passed since last count reset? + * + * \return none + */ +void GX_ReadXfRasMetric(u32 *xfwaitin,u32 *xfwaitout,u32 *rasbusy,u32 *clks); + +/*! + * \fn void GX_ClearVCacheMetric() + * \brief Clears the Vertex Cache performance counter. + * + * \details This function clears the performance counter by sending a special clear token via the Graphics FIFO. + * + * \note To set the metric for the counter, call GX_SetVCacheMetric(); to read the counter value, call GX_ReadVCacheMetric(). + * + * \return none + */ +void GX_ClearVCacheMetric(); + +/*! + * \fn void GX_ReadVCacheMetric(u32 *check,u32 *miss,u32 *stall) + * \brief Returns Vertex Cache performance counters. + * + * \details Each call to this function resets the counter to zero. GX_SetVCacheMetric() sets the metric to be measured by + * the Vertex Cache performance counter. + * + * \warning This function reads CPU-accessible registers in the GP and so should not be called in a display list. + * + * \param[out] check total number of accesses to the vertex cache + * \param[out] miss total number of cache misses to the vertex cache + * \param[out] stall number of GP clocks that the vertex cache was stalled + * + * \return none + */ +void GX_ReadVCacheMetric(u32 *check,u32 *miss,u32 *stall); + +/*! + * \fn void GX_SetVCacheMetric(u32 attr) + * \brief Sets the metric the Vertex Cache performance counter will measure. + * + * \details It is possible to monitor a particular attribute or all attributes using \a attr. + * + * \note To clear the counter, call GX_ClearVCacheMetric(); to read the counter value, call GX_ReadVCacheMetric(). + * + * \param[in] attr \ref vcachemetrics to measure + * + * \return none + */ +void GX_SetVCacheMetric(u32 attr); + +/*! + * \fn void GX_GetGPStatus(u8 *overhi,u8 *underlow,u8 *readIdle,u8 *cmdIdle,u8 *brkpt) + * \brief Reads the current status of the GP. + * + * \details \a overhi and \a underlow will indicate whether or not the watermarks have been reached. If the CPU and GP FIFOs + * are the same, then \a overhi will indicate whether or not the current GX thread is suspended. The value of \a brkpt can be + * used to determine if a breakpoint is in progress (i.e. GP reads are suspended; they are resumed by a call to + * GX_DisableBreakPt()). A callback can also be used to notify your application that the break point has been reached. (see + * GX_SetBreakPtCallback()) + * + * \param[out] overhi GX_TRUE if high watermark has been passed + * \param[out] underlow GX_TRUE if low watermark has been passed + * \param[out] readIdle GX_TRUE if the GP read unit is idle + * \param[out] cmdIdle GX_TRUE if all commands have been flushed to XF + * \param[out] brkpt GX_TRUE if FIFO has reached a breakpoint and GP reads have been stopped + * + * \return none + */ +void GX_GetGPStatus(u8 *overhi,u8 *underlow,u8 *readIdle,u8 *cmdIdle,u8 *brkpt); + +/*! + * \fn void GX_ReadGPMetric(u32 *cnt0,u32 *cnt1) + * \brief Returns the count of the previously set performance metrics. + * + * \note The performance metrics can be set using GX_SetGPMetric(); the counters can be cleared using GX_ClearGPMetric().

+ * + * \note GX_ReadGPMetric() and GX_ClearGPMetric() can be used in the callback associated with the draw sync interrupt (see GX_SetDrawSyncCallback()). + * The function GX_SetGPMetric() should not be used in the draw sync callback because it will insert tokens in the GP command stream at random times.

+ * + * \warning This function reads results from CPU-accessible registers in the GP, therefore, this command must not be used in a display list. It + * may also be necessary to send a draw sync token using GX_SetDrawSync() or GX_SetDrawDone() before GX_ReadGPMetric() is called to ensure that the + * state has actually been processed by the GP. + * + * \param[out] cnt0 current value of GP counter 0 + * \param[out] cnt1 current value of GP counter 1 + * + * \return none + */ +void GX_ReadGPMetric(u32 *cnt0,u32 *cnt1); + +/*! + * \fn void GX_ReadBoundingBox(u16 *top,u16 *bottom,u16 *left,u16 *right) + * \brief Returns the bounding box of pixel coordinates that are drawn in the Embedded Framebuffer (EFB). + * + * \details This function reads the bounding box values. GX_ClearBoundingBox() can be used reset the values of the bounding box. + * + * \note Since the hardware can only test the bounding box in quads (2x2 pixel blocks), the result of this function may contain error + * of plus or minus 1 pixel. Also because of this, left and top are always even-numbered and right and bottom + * are always odd-numbered. + * + * \param[out] top uppermost line in the bounding box + * \param[out] bottom lowest line in the bounding box + * \param[out] left leftmost pixel in the bounding box + * \param[out] right rightmost pixel in the bounding box + * + * \return none + */ +void GX_ReadBoundingBox(u16 *top,u16 *bottom,u16 *left,u16 *right); + +/*! + * \fn volatile void* GX_RedirectWriteGatherPipe(void *ptr) + * \brief Temporarily points the CPU's write-gather pipe at a new location. + * + * \details After calling this function, subsequent writes to the address returned by this function (or the WGPipe union) + * will be gathered and sent to a destination buffer. The write pointer is automatically incremented by the GP. The write + * gather pipe can be restored by calling GX_RestoreWriteGatherPipe(). This function cannot be called between a + * GX_Begin()/GX_End() pair. + * + * \note The destination buffer, referred to by \a ptr, must be 32 byte aligned. The amount of data written should + * also be 32-byte aligned. If it is not, zeroes will be added to pad the destination buffer to 32 bytes. No part of the + * destination buffer should be modified inside the CPU caches - this may introduce cache incoherency problems.

+ * + * \note The write gather pipe is one of the fastest ways to move data out of the CPU (the other being the locked cache DMA). + * In general, you are compute-bound when sending data from the CPU.

+ * + * \note This function is cheaper than trying to create a fake CPU fifo around a destination buffer, which requires calls to + * GX_SetCPUFifo(), GX_InitFifoBase(), etc. This function performs very light weight state saves by assuming that the CPU and + * GP FIFOs never change. + * + * \warning No GX commands can be called until the write gather pipe is restored. You MUST call + * GX_RestoreWriteGatherPipe() before calling this function again, or else the final call to restore the pipe will fail. + * + * \param[in] ptr to destination buffer, 32-byte aligned + * + * \return real address of the write-gather "port". All writes to this address will be gathered by the CPU write gather pipe. + * You may also use the WGPipe union. If you do not use the WGPipe union, ensure that your local variable is volatile. + */ +volatile void* GX_RedirectWriteGatherPipe(void *ptr); + +/*! + * \def GX_InitLightPosv(lo,vec) + * \brief Sets the position of the light in the light object using a vector structure. + * + * \note The GameCube graphics hardware supports local diffuse lights. The position of the light should be in the same space as a + * transformed vertex position (i.e. view space).

+ * + * \note The memory for the light object must be allocated by the application; this function does not load any hardware registers directly. To + * load a light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx(). + * + * \param[in] lo ptr to the light object + * \param[in] vec struct or array of three values for the position + * + * \return none + */ +#define GX_InitLightPosv(lo,vec) \ + (GX_InitLightPos((lo), *(f32*)(vec), *((f32*)(vec)+1), *((f32*)(vec)+2))) + +/*! + * \def GX_InitLightDirv(lo,vec) + * \brief Sets the direction of a light in the light object using a vector structure. + * + * \details This direction is used when the light object is used as a spotlight or a specular light, see the \a attn_fn parameter of + * GX_SetChanCtrl(). + * + * \note The memory for the light object must be allocated by the application; this function does not load any hardware registers. To load a + * light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx().

+ * + * \note The coordinate space of the light normal should be consistent with a vertex normal transformed by a normal matrix; i.e., it should be + * transformed to view space.

+ * + * \note This function does not set the direction of parallel lights. + * + * \param[in] lo ptr to the light object + * \param[in] vec struct or array of three values for the direction + * + * \return none + */ +#define GX_InitLightDirv(lo,vec) \ + (GX_InitLightDir((lo), *(f32*)(vec), *((f32*)(vec)+1), *((f32*)(vec)+2))) + +/*! + * \def GX_InitSpecularDirv(lo,vec) + * \brief Sets the direction of a specular light in the light object using a vector. + * + * \details This direction is used when the light object is used only as specular light. + * + * \note The memory for the light object must be allocated by the application; this function does not load any hardware registers. To load a + * light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx().

+ * + * \note The coordinate space of the light normal should be consistent with a vertex normal transformed by a normal matrix; i.e., it should + * be transformed to view space. + * + * \warning This function should be used if and only if the light object is used as specular light. One specifies a specular light in + * GX_SetChanCtrl() by setting \a attn_fn to GX_AF_SPEC. Furthermore, one must not use GX_InitLightDir() or GX_InitLightPos() to + * set up a light object which will be used as a specular light since these functions will destroy the information set by GX_InitSpecularDir(). + * In contrast to diffuse lights (including spotlights) that are considered local lights, a specular light is a parallel light (i.e. the + * specular light is infinitely far away such that all the rays of the light are parallel), and thus one can only specify directional + * information. + * + * \param[in] lo ptr to the light object + * \param[in] vec struct or array of three values for the direction + * + * \return none + */ +#define GX_InitSpecularDirv(lo,vec) \ + (GX_InitSpecularDir((lo), *(f32*)(vec), *((f32*)(vec)+1), *((f32*)(vec)+2))) + +/*! + * \def GX_InitSpecularDirHAv(lo,vec0,vec1) + * \brief Sets the direction and half-angle vector of a specular light in the light object using a vector. + * + * \details These vectors are used when the light object is used only as specular light. + * + * \note The memory for the light object must be allocated by the application; this function does not load any hardware registers. To load a + * light object into a hardware light, use GX_LoadLightObj() or GX_LoadLightObjIdx().

+ * + * \note In contrast to GX_InitSpecularDirv(), which caclulates half-angle vector automatically by assuming the view vector as (0,0,1), this + * function allows users to specify half-angle vector directly as input arguments. It is useful to do detailed control for orientation of + * highlights.

+ * + * \note Other notes are similar to that described in GX_InitSpecularDirv(). + * + * \param[in] lo ptr to the light object + * \param[in] vec0 struct or array of three values for the direction + * \param[in] vec1 struct or array of three values for the half-angle + * + * \return none + */ +#define GX_InitSpecularDirHAv(lo,vec0,vec1) \ + (GX_InitSpecularDirHA((lo), \ + *(f32*)(vec0), *((f32*)(vec0)+1), *((f32*)(vec0)+2), \ + *(f32*)(vec1), *((f32*)(vec1)+1), *((f32*)(vec1)+2))) + +/*! + * \def GX_InitLightShininess(lobj, shininess) + * \brief Sets \a shininess of a per-vertex specular light. + * + * \details In reality, shininess is a property of the material being lit, not the light. However, in the Graphics Processor, the specular + * calculation is implemented by reusing the diffuse angle/distance attenuation function, so shininess is determined by the light attenuation + * parameters (see GX_InitLightAttn()). Note that the equation is attempting to approximate the function (N*H)^shininess. Since the attenuation + * equation is only a ratio of quadratics, a true exponential function is not possible. To enable the specular calculation, you must set the + * attenuation parameter of the lighting channel to GX_AF_SPEC using GX_SetChanCtrl(). + * + * \param[in] lobj ptr to the light object + * \param[in] shininess shininess parameter + * + * \return none + */ +#define GX_InitLightShininess(lobj, shininess) \ + (GX_InitLightAttn(lobj, 0.0F, 0.0F, 1.0F, \ + (shininess)/2.0F, 0.0F, \ + 1.0F-(shininess)/2.0F )) + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/gx_struct.h b/wii/libogc/include/ogc/gx_struct.h new file mode 100644 index 0000000000..107e7a7b72 --- /dev/null +++ b/wii/libogc/include/ogc/gx_struct.h @@ -0,0 +1,78 @@ +/*------------------------------------------------------------- + +gx_struct.h -- support header + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __GX_STRUCT_H__ +#define __GX_STRUCT_H__ + +/*! +\file gx_struct.h +\brief support header +*/ + +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! +\typedef struct _gx_rmodeobj GXRModeObj +\brief structure to hold the selected video and render settings +\param viTVMode mode and type of TV +\param fbWidth width of external framebuffer +\param efbHeight height of embedded framebuffer +\param xfbHeight height of external framebuffer +\param viXOrigin x starting point of first pixel to draw on VI +\param viYOrigin y starting point of first pixel to draw on VI +\param viWidth width of configured VI +\param viHeight height of configured VI +*/ +typedef struct _gx_rmodeobj { + u32 viTVMode; + u16 fbWidth; + u16 efbHeight; + u16 xfbHeight; + u16 viXOrigin; + u16 viYOrigin; + u16 viWidth; + u16 viHeight; + u32 xfbMode; + u8 field_rendering; + u8 aa; + u8 sample_pattern[12][2]; + u8 vfilter[7]; +} GXRModeObj; + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/ios.h b/wii/libogc/include/ogc/ios.h new file mode 100644 index 0000000000..c308d02345 --- /dev/null +++ b/wii/libogc/include/ogc/ios.h @@ -0,0 +1,65 @@ +/*------------------------------------------------------------- + +ios.h -- IOS control + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __IOS_H__ +#define __IOS_H__ + +#if defined(HW_RVL) + +#include +#include + +#define IOS_EINVAL -0x3004 +#define IOS_EBADVERSION -0x3100 +#define IOS_ETOOMANYVIEWS -0x3101 +#define IOS_EMISMATCH -0x3102 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +s32 __IOS_InitializeSubsystems(void); +s32 __IOS_ShutdownSubsystems(void); +s32 __IOS_LoadStartupIOS(void); +s32 __IOS_LaunchNewIOS(int version); +s32 IOS_GetPreferredVersion(void); +s32 IOS_ReloadIOS(int version); +s32 IOS_GetVersion(); +s32 IOS_GetRevision(); +s32 IOS_GetRevisionMajor(); +s32 IOS_GetRevisionMinor(); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif + +#endif diff --git a/wii/libogc/include/ogc/ipc.h b/wii/libogc/include/ogc/ipc.h new file mode 100644 index 0000000000..c65c44be19 --- /dev/null +++ b/wii/libogc/include/ogc/ipc.h @@ -0,0 +1,103 @@ +/*------------------------------------------------------------- + +ipc.h -- Interprocess Communication with Starlet + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __IPC_H__ +#define __IPC_H__ + +#include + +#define IPC_HEAP -1 + +#define IPC_OPEN_NONE 0 +#define IPC_OPEN_READ 1 +#define IPC_OPEN_WRITE 2 +#define IPC_OPEN_RW (IPC_OPEN_READ|IPC_OPEN_WRITE) + +#define IPC_MAXPATH_LEN 64 + +#define IPC_OK 0 +#define IPC_EINVAL -4 +#define IPC_ENOHEAP -5 +#define IPC_ENOENT -6 +#define IPC_EQUEUEFULL -8 +#define IPC_ENOMEM -22 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct _ioctlv +{ + void *data; + u32 len; +} ioctlv; + +void __IPC_Reinitialize(void); + +typedef s32 (*ipccallback)(s32 result,void *usrdata); + +s32 iosCreateHeap(s32 size); +void* iosAlloc(s32 hid,s32 size); +void iosFree(s32 hid,void *ptr); + +void* IPC_GetBufferLo(); +void* IPC_GetBufferHi(); +void IPC_SetBufferLo(void *bufferlo); +void IPC_SetBufferHi(void *bufferhi); + +s32 IOS_Open(const char *filepath,u32 mode); +s32 IOS_OpenAsync(const char *filepath,u32 mode,ipccallback ipc_cb,void *usrdata); + +s32 IOS_Close(s32 fd); +s32 IOS_CloseAsync(s32 fd,ipccallback ipc_cb,void *usrdata); + +s32 IOS_Seek(s32 fd,s32 where,s32 whence); +s32 IOS_SeekAsync(s32 fd,s32 where,s32 whence,ipccallback ipc_cb,void *usrdata); +s32 IOS_Read(s32 fd,void *buf,s32 len); +s32 IOS_ReadAsync(s32 fd,void *buf,s32 len,ipccallback ipc_cb,void *usrdata); +s32 IOS_Write(s32 fd,const void *buf,s32 len); +s32 IOS_WriteAsync(s32 fd,const void *buf,s32 len,ipccallback ipc_cb,void *usrdata); + +s32 IOS_Ioctl(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io); +s32 IOS_IoctlAsync(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io,ipccallback ipc_cb,void *usrdata); +s32 IOS_Ioctlv(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv); +s32 IOS_IoctlvAsync(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv,ipccallback ipc_cb,void *usrdata); + +s32 IOS_IoctlvFormat(s32 hId,s32 fd,s32 ioctl,const char *format,...); +s32 IOS_IoctlvFormatAsync(s32 hId,s32 fd,s32 ioctl,ipccallback usr_cb,void *usr_data,const char *format,...); + +s32 IOS_IoctlvReboot(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv); +s32 IOS_IoctlvRebootBackground(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/irq.h b/wii/libogc/include/ogc/irq.h new file mode 100644 index 0000000000..2dae7bdc90 --- /dev/null +++ b/wii/libogc/include/ogc/irq.h @@ -0,0 +1,189 @@ +/*------------------------------------------------------------- + +irq.h -- Interrupt subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#ifndef __IRQ_H__ +#define __IRQ_H__ + +/*! \file irq.h +\brief Interrupt subsystem + +*/ + +#include +#include "context.h" + +#define IM_NONE (0xffffffff) +#define IRQ_MEM0 0 +#define IRQ_MEM1 1 +#define IRQ_MEM2 2 +#define IRQ_MEM3 3 +#define IRQ_MEMADDRESS 4 +#define IRQ_DSP_AI 5 +#define IRQ_DSP_ARAM 6 +#define IRQ_DSP_DSP 7 +#define IRQ_AI 8 +#define IRQ_EXI0_EXI 9 +#define IRQ_EXI0_TC 10 +#define IRQ_EXI0_EXT 11 +#define IRQ_EXI1_EXI 12 +#define IRQ_EXI1_TC 13 +#define IRQ_EXI1_EXT 14 +#define IRQ_EXI2_EXI 15 +#define IRQ_EXI2_TC 16 +#define IRQ_PI_CP 17 +#define IRQ_PI_PETOKEN 18 +#define IRQ_PI_PEFINISH 19 +#define IRQ_PI_SI 20 +#define IRQ_PI_DI 21 +#define IRQ_PI_RSW 22 +#define IRQ_PI_ERROR 23 +#define IRQ_PI_VI 24 +#define IRQ_PI_DEBUG 25 +#define IRQ_PI_HSP 26 +#if defined(HW_RVL) +#define IRQ_PI_ACR 27 +#endif +#define IRQ_MAX 32 + +#define IRQMASK(irq) (0x80000000u>>irq) + +#define IM_MEM0 IRQMASK(IRQ_MEM0) +#define IM_MEM1 IRQMASK(IRQ_MEM1) +#define IM_MEM2 IRQMASK(IRQ_MEM2) +#define IM_MEM3 IRQMASK(IRQ_MEM3) +#define IM_MEMADDRESS IRQMASK(IRQ_MEMADDRESS) +#define IM_MEM (IM_MEM0|IM_MEM1|IM_MEM2|IM_MEM3|IM_MEMADDRESS) + +#define IM_DSP_AI IRQMASK(IRQ_DSP_AI) +#define IM_DSP_ARAM IRQMASK(IRQ_DSP_ARAM) +#define IM_DSP_DSP IRQMASK(IRQ_DSP_DSP) +#define IM_DSP (IM_DSP_AI|IM_DSP_ARAM|IM_DSP_DSP) + +#define IM_AI IRQMASK(IRQ_AI) + +#define IM_EXI0_EXI IRQMASK(IRQ_EXI0_EXI) +#define IM_EXI0_TC IRQMASK(IRQ_EXI0_TC) +#define IM_EXI0_EXT IRQMASK(IRQ_EXI0_EXT) +#define IM_EXI0 (IM_EXI0_EXI|IM_EXI0_TC|IM_EXI0_EXT) + +#define IM_EXI1_EXI IRQMASK(IRQ_EXI1_EXI) +#define IM_EXI1_TC IRQMASK(IRQ_EXI1_TC) +#define IM_EXI1_EXT IRQMASK(IRQ_EXI1_EXT) +#define IM_EXI1 (IM_EXI1_EXI|IM_EXI1_TC|IM_EXI1_EXT) + +#define IM_EXI2_EXI IRQMASK(IRQ_EXI2_EXI) +#define IM_EXI2_TC IRQMASK(IRQ_EXI2_TC) +#define IM_EXI2 (IM_EXI2_EXI|IM_EXI2_TC) +#define IM_EXI (IM_EXI0|IM_EXI1|IM_EXI2) + +#define IM_PI_CP IRQMASK(IRQ_PI_CP) +#define IM_PI_PETOKEN IRQMASK(IRQ_PI_PETOKEN) +#define IM_PI_PEFINISH IRQMASK(IRQ_PI_PEFINISH) +#define IM_PI_SI IRQMASK(IRQ_PI_SI) +#define IM_PI_DI IRQMASK(IRQ_PI_DI) +#define IM_PI_RSW IRQMASK(IRQ_PI_RSW) +#define IM_PI_ERROR IRQMASK(IRQ_PI_ERROR) +#define IM_PI_VI IRQMASK(IRQ_PI_VI) +#define IM_PI_DEBUG IRQMASK(IRQ_PI_DEBUG) +#define IM_PI_HSP IRQMASK(IRQ_PI_HSP) +#if defined(HW_DOL) +#define IM_PI (IM_PI_CP|IM_PI_PETOKEN|IM_PI_PEFINISH|IM_PI_SI|IM_PI_DI|IM_PI_RSW|IM_PI_ERROR|IM_PI_VI|IM_PI_DEBUG|IM_PI_HSP) +#elif defined(HW_RVL) +#define IM_PI_ACR IRQMASK(IRQ_PI_ACR) +#define IM_PI (IM_PI_CP|IM_PI_PETOKEN|IM_PI_PEFINISH|IM_PI_SI|IM_PI_DI|IM_PI_RSW|IM_PI_ERROR|IM_PI_VI|IM_PI_DEBUG|IM_PI_HSP|IM_PI_ACR) +#endif + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! \typedef void (*raw_irq_handler_t)(u32 irq,void *ctx) +\brief function pointer typedef for the interrupt handler callback +\param[in] irq interrupt number of triggered interrupt. +\param[in] ctx pointer to the user data. +*/ +typedef void (*raw_irq_handler_t)(u32 irq,void *ctx); + + +/*! \fn raw_irq_handler_t IRQ_Request(u32 nIrq,raw_irq_handler_t pHndl,void *pCtx) +\brief Register an interrupt handler. +\param[in] nIrq interrupt number to which to register the handler +\param[in] pHndl pointer to the handler callback function which to call when interrupt has triggered +\param[in] pCtx pointer to user data to pass with, when handler is called + +\return Old interrupt handler, else NULL +*/ +raw_irq_handler_t IRQ_Request(u32 nIrq,raw_irq_handler_t pHndl,void *pCtx); + + +/*! \fn raw_irq_handler_t IRQ_Free(u32 nIrq) +\brief Free an interrupt handler. +\param[in] nIrq interrupt number for which to free the handler + +\return Old interrupt handler, else NULL +*/ +raw_irq_handler_t IRQ_Free(u32 nIrq); + + +/*! \fn raw_irq_handler_t IRQ_GetHandler(u32 nIrq) +\brief Get the handler from interrupt number +\param[in] nIrq interrupt number for which to retrieve the handler + +\return interrupt handler, else NULL +*/ +raw_irq_handler_t IRQ_GetHandler(u32 nIrq); + + +/*! \fn u32 IRQ_Disable() +\brief Disable the complete IRQ subsystem. No interrupts will be served. Multithreading kernel fully disabled. + +\return Old state of the IRQ subsystem +*/ +u32 IRQ_Disable(void); + + +/*! \fn u32 IRQ_Restore(u32 level) +\brief Restore the IRQ subsystem with the given level. This is function should be used together with IRQ_Disable() +\param[in] level IRQ level to restore to. + +\return none +*/ +void IRQ_Restore(u32 level); + +void __MaskIrq(u32 nMask); +void __UnmaskIrq(u32 nMask); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/isfs.h b/wii/libogc/include/ogc/isfs.h new file mode 100644 index 0000000000..584848c57d --- /dev/null +++ b/wii/libogc/include/ogc/isfs.h @@ -0,0 +1,70 @@ +#ifndef __ISFS_H__ +#define __ISFS_H__ + +#if defined(HW_RVL) + +#include + +#define ISFS_MAXPATH IPC_MAXPATH_LEN + +#define ISFS_OPEN_READ 0x01 +#define ISFS_OPEN_WRITE 0x02 +#define ISFS_OPEN_RW (ISFS_OPEN_READ | ISFS_OPEN_WRITE) + +#define ISFS_OK 0 +#define ISFS_ENOMEM -22 +#define ISFS_EINVAL -101 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct _fstats +{ + u32 file_length; + u32 file_pos; +} fstats; + +typedef s32 (*isfscallback)(s32 result,void *usrdata); + +s32 ISFS_Initialize(); +s32 ISFS_Deinitialize(); + +s32 ISFS_Open(const char *filepath,u8 mode); +s32 ISFS_OpenAsync(const char *filepath,u8 mode,isfscallback cb,void *usrdata); +s32 ISFS_Close(s32 fd); +s32 ISFS_CloseAsync(s32 fd,isfscallback cb,void *usrdata); +s32 ISFS_Delete(const char *filepath); +s32 ISFS_DeleteAsync(const char *filepath,isfscallback cb,void *usrdata); +s32 ISFS_ReadDir(const char *filepath,char *name_list,u32 *num); +s32 ISFS_ReadDirAsync(const char *filepath,char *name_list,u32 *num,isfscallback cb,void *usrdata); +s32 ISFS_CreateFile(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm); +s32 ISFS_CreateFileAsync(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm,isfscallback cb,void *usrdata); +s32 ISFS_Write(s32 fd,const void *buffer,u32 length); +s32 ISFS_WriteAsync(s32 fd,const void *buffer,u32 length,isfscallback cb,void *usrdata); +s32 ISFS_Read(s32 fd,void *buffer,u32 length); +s32 ISFS_ReadAsync(s32 fd,void *buffer,u32 length,isfscallback cb,void *usrdata); +s32 ISFS_Seek(s32 fd,s32 where,s32 whence); +s32 ISFS_SeekAsync(s32 fd,s32 where,s32 whence,isfscallback cb,void *usrdata); +s32 ISFS_CreateDir(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm); +s32 ISFS_CreateDirAsync(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm,isfscallback cb,void *usrdata); +s32 ISFS_GetStats(void *stats); +s32 ISFS_GetStatsAsync(void *stats,isfscallback cb,void *usrdata); +s32 ISFS_GetFileStats(s32 fd,fstats *status); +s32 ISFS_GetFileStatsAsync(s32 fd,fstats *status,isfscallback cb,void *usrdata); +s32 ISFS_GetAttr(const char *filepath,u32 *ownerID,u16 *groupID,u8 *attributes,u8 *ownerperm,u8 *groupperm,u8 *otherperm); +s32 ISFS_GetAttrAsync(const char *filepath,u32 *ownerID,u16 *groupID,u8 *attributes,u8 *ownerperm,u8 *groupperm,u8 *otherperm,isfscallback cb,void *usrdata); +s32 ISFS_Rename(const char *filepathOld,const char *filepathNew); +s32 ISFS_RenameAsync(const char *filepathOld,const char *filepathNew,isfscallback cb,void *usrdata); +s32 ISFS_SetAttr(const char *filepath,u32 ownerID,u16 groupID,u8 attributes,u8 ownerperm,u8 groupperm,u8 otherperm); +s32 ISFS_SetAttrAsync(const char *filepath,u32 ownerID,u16 groupID,u8 attributes,u8 ownerperm,u8 groupperm,u8 otherperm,isfscallback cb,void *usrdata); +s32 ISFS_GetUsage(const char* filepath, u32* usage1, u32* usage2); +s32 ISFS_GetUsageAsync(const char* filepath, u32* usage1, u32* usage2,isfscallback cb,void *usrdata); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* defined(HW_RVL) */ + +#endif diff --git a/wii/libogc/include/ogc/libversion.h b/wii/libogc/include/ogc/libversion.h new file mode 100644 index 0000000000..88d910daff --- /dev/null +++ b/wii/libogc/include/ogc/libversion.h @@ -0,0 +1,13 @@ +#ifndef __LIBVERSION_H__ +#define __LIBVERSION_H__ + +#define _V_MAJOR_ 1 +#define _V_MINOR_ 8 +#define _V_PATCH_ 17 + +#define _V_DATE_ __DATE__ +#define _V_TIME_ __TIME__ + +#define _V_STRING "libOGC Release 1.8.17" + +#endif // __LIBVERSION_H__ diff --git a/wii/libogc/include/ogc/lwp.h b/wii/libogc/include/ogc/lwp.h new file mode 100644 index 0000000000..b68bf065f2 --- /dev/null +++ b/wii/libogc/include/ogc/lwp.h @@ -0,0 +1,204 @@ +/*------------------------------------------------------------- + +lwp.h -- Thread subsystem I + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + + +-------------------------------------------------------------*/ + + +#ifndef __LWP_H__ +#define __LWP_H__ + +/*! \file lwp.h +\brief Thread subsystem I + +*/ + +#include + +#define LWP_CLOSED -1 +#define LWP_SUCCESSFUL 0 +#define LWP_ALREADY_SUSPENDED 1 +#define LWP_NOT_SUSPENDED 2 + +#define LWP_PRIO_IDLE 0 +#define LWP_PRIO_HIGHEST 127 + +#define LWP_THREAD_NULL 0xffffffff +#define LWP_TQUEUE_NULL 0xffffffff + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \typedef u32 lwp_t +\brief typedef for the thread context handle +*/ +typedef u32 lwp_t; + + +/*! \typedef u32 lwpq_t +\brief typedef for the thread queue's context handle +*/ +typedef u32 lwpq_t; + +/*! \fn s32 LWP_CreateThread(lwp_t *thethread,void* (*entry)(void *),void *arg,void *stackbase,u32 stack_size,u8 prio) +\brief Spawn a new thread with the given parameters +\param[out] thethread pointer to a lwp_t handle +\param[in] entry pointer to the thread's entry function. +\param[in] arg pointer to an argument for the thread's entry function. +\param[in] stackbase pointer to the threads stackbase address. If NULL, the stack is allocated by the thread system. +\param[in] stack_size size of the provided stack. If 0, the default STACKSIZE of 8Kb is taken. +\param[in] prio priority on which the newly created thread runs. + +\return 0 on success, <0 on error +*/ +s32 LWP_CreateThread(lwp_t *thethread,void* (*entry)(void *),void *arg,void *stackbase,u32 stack_size,u8 prio); + + +/*! \fn s32 LWP_SuspendThread(lwp_t thethread) +\brief Suspend the given thread. +\param[in] thethread handle to the thread context which should be suspended. + +\return 0 on success, <0 on error +*/ +s32 LWP_SuspendThread(lwp_t thethread); + + +/*! \fn s32 LWP_ResumeThread(lwp_t thethread) +\brief Resume the given thread. +\param[in] thethread handle to the thread context which should be resumed. + +\return 0 on success, <0 on error +*/ +s32 LWP_ResumeThread(lwp_t thethread); + + +/*! \fn BOOL LWP_ThreadIsSuspended(lwp_t thethread) +\brief Test whether the given thread is suspended or not +\param[in] thethread handle to the thread context which should be tested. + +\return TRUE or FALSE +*/ +BOOL LWP_ThreadIsSuspended(lwp_t thethread); + + +/*! \fn lwp_t LWP_GetSelf() +\brief Return the handle to the current thread. + +\return thread context handle +*/ +lwp_t LWP_GetSelf(); + + +/*! \fn void LWP_SetThreadPriority(lwp_t thethread,u32 prio) +\brief Set the priority of the given thread. +\param[in] thethread handle to the thread context whos priority should be changed. If NULL, the current thread will be taken. +\param[in] prio new priority to set + +\return none +*/ +void LWP_SetThreadPriority(lwp_t thethread,u32 prio); + + +/*! \fn void LWP_YieldThread() +\brief Yield the current thread to another one with higher priority or if not running at the same priority which state is runnable. + +\return none +*/ +void LWP_YieldThread(); + + +/*! \fn void LWP_Reschedule(u32 prio) +\brief Reschedule all threads running at the given priority +\param[in] prio priority level to reschedule + +\return none +*/ +void LWP_Reschedule(u32 prio); + + +/*! \fn s32 LWP_JoinThread(lwp_t thethread,void **value_ptr) +\brief Join the given thread. +\param[in] thethread handle to the thread's context which should be joined to wait on termination. +\param[in] value_ptr pointer-pointer to a variable to receive the return code of the terminated thread. + +\return 0 on success, <0 on error +*/ +s32 LWP_JoinThread(lwp_t thethread,void **value_ptr); + + +/*! \fn void LWP_InitQueue(lwpq_t *thequeue) +\brief Initialize the thread synchronization queue +\param[in] thequeue pointer to a lwpq_t handle. + +\return 0 on success, <0 on error +*/ +s32 LWP_InitQueue(lwpq_t *thequeue); + + +/*! \fn void LWP_CloseQueue(lwpq_t thequeue) +\brief Close the thread synchronization queue and releas the handle +\param[in] thequeue handle to the thread's synchronization queue + +\return none +*/ +void LWP_CloseQueue(lwpq_t thequeue); + + +/*! \fn s32 LWP_ThreadSleep(lwpq_t thequeue) +\brief Pushes the current thread onto the given thread synchronization queue and sets the thread state to blocked. +\param[in] thequeue handle to the thread's synchronization queue to push the thread on + +\return none +*/ +s32 LWP_ThreadSleep(lwpq_t thequeue); + + +/*! \fn void LWP_ThreadSignal(lwpq_t thequeue) +\brief Signals one thread to be revmoved from the thread synchronization queue and sets it back to running state. +\param[in] thequeue handle to the thread's synchronization queue to pop the blocked thread off + +\return none +*/ +void LWP_ThreadSignal(lwpq_t thequeue); + + +/*! \fn void LWP_ThreadBroadcast(lwpq_t thequeue) +\brief Removes all blocked threads from the thread synchronization queue and sets them back to running state. +\param[in] thequeue handle to the thread's synchronization queue to pop the blocked threads off + +\return none +*/ +void LWP_ThreadBroadcast(lwpq_t thequeue); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_config.h b/wii/libogc/include/ogc/lwp_config.h new file mode 100644 index 0000000000..beda421e54 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_config.h @@ -0,0 +1,19 @@ +#ifndef __LWP_CONFIG_H__ +#define __LWP_CONFIG_H__ + + +#define LWP_MAX_MQUEUES 64 + +#define LWP_MAX_MUTEXES 64 + +#define LWP_MAX_THREADS 16 + +#define LWP_MAX_SEMAS 64 + +#define LWP_MAX_CONDVARS 64 + +#define LWP_MAX_TQUEUES 64 + +#define LWP_MAX_WATCHDOGS 64 + +#endif diff --git a/wii/libogc/include/ogc/lwp_heap.h b/wii/libogc/include/ogc/lwp_heap.h new file mode 100644 index 0000000000..3c9ac48502 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_heap.h @@ -0,0 +1,59 @@ +#ifndef __LWP_HEAP_H__ +#define __LWP_HEAP_H__ + +#include +#include "machine/asm.h" + +#define HEAP_BLOCK_USED 1 +#define HEAP_BLOCK_FREE 0 + +#define HEAP_DUMMY_FLAG (0+HEAP_BLOCK_USED) + +#define HEAP_OVERHEAD (sizeof(u32)*2) +#define HEAP_BLOCK_USED_OVERHEAD (sizeof(void*)*2) +#define HEAP_MIN_SIZE (HEAP_OVERHEAD+sizeof(heap_block)) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _heap_block_st heap_block; +struct _heap_block_st { + u32 back_flag; + u32 front_flag; + heap_block *next; + heap_block *prev; +}; + +typedef struct _heap_iblock_st { + u32 free_blocks; + u32 free_size; + u32 used_blocks; + u32 used_size; +} heap_iblock; + +typedef struct _heap_cntrl_st { + heap_block *start; + heap_block *final; + + heap_block *first; + heap_block *perm_null; + heap_block *last; + u32 pg_size; + u32 reserved; +} heap_cntrl; + +u32 __lwp_heap_init(heap_cntrl *theheap,void *start_addr,u32 size,u32 pg_size); +void* __lwp_heap_allocate(heap_cntrl *theheap,u32 size); +BOOL __lwp_heap_free(heap_cntrl *theheap,void *ptr); +u32 __lwp_heap_getinfo(heap_cntrl *theheap,heap_iblock *theinfo); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_messages.h b/wii/libogc/include/ogc/lwp_messages.h new file mode 100644 index 0000000000..2529b6331d --- /dev/null +++ b/wii/libogc/include/ogc/lwp_messages.h @@ -0,0 +1,79 @@ +#ifndef __LWP_MESSAGES_H__ +#define __LWP_MESSAGES_H__ + +#include +#include +#include +#include + +//#define _LWPMQ_DEBUG + +#define LWP_MQ_FIFO 0 +#define LWP_MQ_PRIORITY 1 + +#define LWP_MQ_STATUS_SUCCESSFUL 0 +#define LWP_MQ_STATUS_INVALID_SIZE 1 +#define LWP_MQ_STATUS_TOO_MANY 2 +#define LWP_MQ_STATUS_UNSATISFIED 3 +#define LWP_MQ_STATUS_UNSATISFIED_NOWAIT 4 +#define LWP_MQ_STATUS_DELETED 5 +#define LWP_MQ_STATUS_TIMEOUT 6 +#define LWP_MQ_STATUS_UNSATISFIED_WAIT 7 + +#define LWP_MQ_SEND_REQUEST INT_MAX +#define LWP_MQ_SEND_URGENT INT_MIN + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*mq_notifyhandler)(void *); + +typedef struct _mqbuffer { + u32 size; + u32 buffer[1]; +} mq_buffer; + +typedef struct _mqbuffercntrl { + lwp_node node; + u32 prio; + mq_buffer contents; +} mq_buffercntrl; + +//the following struct is extensible +typedef struct _mqattr { + u32 mode; +} mq_attr; + +typedef struct _mqcntrl { + lwp_thrqueue wait_queue; + mq_attr attr; + u32 max_pendingmsgs; + u32 num_pendingmsgs; + u32 max_msgsize; + lwp_queue pending_msgs; + mq_buffer *msq_buffers; + mq_notifyhandler notify_handler; + void *notify_arg; + lwp_queue inactive_msgs; +} mq_cntrl; + +u32 __lwpmq_initialize(mq_cntrl *mqueue,mq_attr *attrs,u32 max_pendingmsgs,u32 max_msgsize); +void __lwpmq_close(mq_cntrl *mqueue,u32 status); +u32 __lwpmq_seize(mq_cntrl *mqueue,u32 id,void *buffer,u32 *size,u32 wait,u64 timeout); +u32 __lwpmq_submit(mq_cntrl *mqueue,u32 id,void *buffer,u32 size,u32 type,u32 wait,u64 timeout); +u32 __lwpmq_broadcast(mq_cntrl *mqueue,void *buffer,u32 size,u32 id,u32 *count); +void __lwpmq_msg_insert(mq_cntrl *mqueue,mq_buffercntrl *msg,u32 type); +u32 __lwpmq_flush(mq_cntrl *mqueue); +u32 __lwpmq_flush_support(mq_cntrl *mqueue); +void __lwpmq_flush_waitthreads(mq_cntrl *mqueue); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_mutex.h b/wii/libogc/include/ogc/lwp_mutex.h new file mode 100644 index 0000000000..fb8c495eaa --- /dev/null +++ b/wii/libogc/include/ogc/lwp_mutex.h @@ -0,0 +1,76 @@ +#ifndef __LWP_MUTEX_H__ +#define __LWP_MUTEX_H__ + +#include +#include + +#define LWP_MUTEX_LOCKED 0 +#define LWP_MUTEX_UNLOCKED 1 + +#define LWP_MUTEX_NEST_ACQUIRE 0 +#define LWP_MUTEX_NEST_ERROR 1 +#define LWP_MUTEX_NEST_BLOCK 2 + +#define LWP_MUTEX_FIFO 0 +#define LWP_MUTEX_PRIORITY 1 +#define LWP_MUTEX_INHERITPRIO 2 +#define LWP_MUTEX_PRIORITYCEIL 3 + +#define LWP_MUTEX_SUCCESSFUL 0 +#define LWP_MUTEX_UNSATISFIED_NOWAIT 1 +#define LWP_MUTEX_NEST_NOTALLOWED 2 +#define LWP_MUTEX_NOTOWNER 3 +#define LWP_MUTEX_DELETED 4 +#define LWP_MUTEX_TIMEOUT 5 +#define LWP_MUTEX_CEILINGVIOL 6 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _lwpmutexattr { + u32 mode; + u32 nest_behavior; + u8 prioceil,onlyownerrelease; +} lwp_mutex_attr; + +typedef struct _lwpmutex { + lwp_thrqueue wait_queue; + lwp_mutex_attr atrrs; + u32 lock,nest_cnt,blocked_cnt; + lwp_cntrl *holder; +} lwp_mutex; + +void __lwp_mutex_initialize(lwp_mutex *mutex,lwp_mutex_attr *attrs,u32 init_lock); +u32 __lwp_mutex_surrender(lwp_mutex *mutex); +void __lwp_mutex_seize_irq_blocking(lwp_mutex *mutex,u64 timeout); +void __lwp_mutex_flush(lwp_mutex *mutex,u32 status); + +static __inline__ u32 __lwp_mutex_seize_irq_trylock(lwp_mutex *mutex,u32 *isr_level); + +#define __lwp_mutex_seize(_mutex_t,_id,_wait,_timeout,_level) \ + do { \ + if(__lwp_mutex_seize_irq_trylock(_mutex_t,&_level)) { \ + if(!_wait) { \ + _CPU_ISR_Restore(_level); \ + _thr_executing->wait.ret_code = LWP_MUTEX_UNSATISFIED_NOWAIT; \ + } else { \ + __lwp_threadqueue_csenter(&(_mutex_t)->wait_queue); \ + _thr_executing->wait.queue = &(_mutex_t)->wait_queue; \ + _thr_executing->wait.id = _id; \ + __lwp_thread_dispatchdisable(); \ + _CPU_ISR_Restore(_level); \ + __lwp_mutex_seize_irq_blocking(_mutex_t,(u64)_timeout); \ + } \ + } \ + } while(0) + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_objmgr.h b/wii/libogc/include/ogc/lwp_objmgr.h new file mode 100644 index 0000000000..00c6e788fb --- /dev/null +++ b/wii/libogc/include/ogc/lwp_objmgr.h @@ -0,0 +1,49 @@ +#ifndef __LWP_OBJMGR_H__ +#define __LWP_OBJMGR_H__ + +#include +#include "lwp_queue.h" + +#define LWP_OBJMASKTYPE(type) ((type)<<16) +#define LWP_OBJMASKID(id) ((id)&0xffff) +#define LWP_OBJTYPE(id) ((id)>>16) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _lwp_objinfo lwp_objinfo; + +typedef struct _lwp_obj { + lwp_node node; + s32 id; + lwp_objinfo *information; +} lwp_obj; + +struct _lwp_objinfo { + u32 min_id; + u32 max_id; + u32 max_nodes; + u32 node_size; + lwp_obj **local_table; + void *obj_blocks; + lwp_queue inactives; + u32 inactives_cnt; +}; + +void __lwp_objmgr_initinfo(lwp_objinfo *info,u32 max_nodes,u32 node_size); +void __lwp_objmgr_free(lwp_objinfo *info,lwp_obj *object); +lwp_obj* __lwp_objmgr_allocate(lwp_objinfo *info); +lwp_obj* __lwp_objmgr_get(lwp_objinfo *info,u32 id); +lwp_obj* __lwp_objmgr_getisrdisable(lwp_objinfo *info,u32 id,u32 *p_level); +lwp_obj* __lwp_objmgr_getnoprotection(lwp_objinfo *info,u32 id); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_priority.h b/wii/libogc/include/ogc/lwp_priority.h new file mode 100644 index 0000000000..3a55f3ac98 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_priority.h @@ -0,0 +1,33 @@ +#ifndef __LWP_PRIORITY_H__ +#define __LWP_PRIORITY_H__ + +#include +#include "machine/processor.h" + +#define LWP_PRIO_MIN 0 +#define LWP_PRIO_MAX 255 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _priocntrl { + u32 *minor; + u32 ready_minor,ready_major; + u32 block_minor,block_major; +} prio_cntrl; + +extern vu32 _prio_major_bitmap; +extern u32 _prio_bitmap[]; + +void __lwp_priority_init(); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_queue.h b/wii/libogc/include/ogc/lwp_queue.h new file mode 100644 index 0000000000..4f6993c2f6 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_queue.h @@ -0,0 +1,41 @@ +#ifndef __LWP_QUEUE_H__ +#define __LWP_QUEUE_H__ + +#include + +//#define _LWPQ_DEBUG + +#ifdef _LWPQ_DEBUG +extern int printk(const char *fmt,...); +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _lwpnode { + struct _lwpnode *next; + struct _lwpnode *prev; +} lwp_node; + +typedef struct _lwpqueue { + lwp_node *first; + lwp_node *perm_null; + lwp_node *last; +} lwp_queue; + +void __lwp_queue_initialize(lwp_queue *,void *,u32,u32); +lwp_node* __lwp_queue_get(lwp_queue *); +void __lwp_queue_append(lwp_queue *,lwp_node *); +void __lwp_queue_extract(lwp_node *); +void __lwp_queue_insert(lwp_node *,lwp_node *); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_sema.h b/wii/libogc/include/ogc/lwp_sema.h new file mode 100644 index 0000000000..f4c5816ad3 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_sema.h @@ -0,0 +1,44 @@ +#ifndef __LWP_SEMA_H__ +#define __LWP_SEMA_H__ + +#include +#include + +#define LWP_SEMA_MODEFIFO 0 +#define LWP_SEMA_MODEPRIORITY 1 + +#define LWP_SEMA_SUCCESSFUL 0 +#define LWP_SEMA_UNSATISFIED_NOWAIT 1 +#define LWP_SEMA_DELETED 2 +#define LWP_SEMA_TIMEOUT 3 +#define LWP_SEMA_MAXCNT_EXCEEDED 4 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _lwpsemattr { + u32 max_cnt; + u32 mode; +} lwp_semattr; + +typedef struct _lwpsema { + lwp_thrqueue wait_queue; + lwp_semattr attrs; + u32 count; +} lwp_sema; + +void __lwp_sema_initialize(lwp_sema *sema,lwp_semattr *attrs,u32 init_count); +u32 __lwp_sema_surrender(lwp_sema *sema,u32 id); +u32 __lwp_sema_seize(lwp_sema *sema,u32 id,u32 wait,u64 timeout); +void __lwp_sema_flush(lwp_sema *sema,u32 status); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_stack.h b/wii/libogc/include/ogc/lwp_stack.h new file mode 100644 index 0000000000..b047b700c3 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_stack.h @@ -0,0 +1,27 @@ +#ifndef __LWP_STACK_H__ +#define __LWP_STACK_H__ + +#include +#include + +#define CPU_STACK_ALIGNMENT 8 +#define CPU_MINIMUM_STACK_SIZE 1024*8 +#define CPU_MINIMUM_STACK_FRAME_SIZE 16 +#define CPU_MODES_INTERRUPT_MASK 0x00000001 /* interrupt level in mode */ + +#ifdef __cplusplus +extern "C" { +#endif + +u32 __lwp_stack_allocate(lwp_cntrl *,u32); +void __lwp_stack_free(lwp_cntrl *); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_states.h b/wii/libogc/include/ogc/lwp_states.h new file mode 100644 index 0000000000..6fc1236e04 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_states.h @@ -0,0 +1,48 @@ +#ifndef ___LWP_STATES_H__ +#define ___LWP_STATES_H__ + +#include + +#define LWP_STATES_READY 0x00000000 +#define LWP_STATES_DORMANT 0x00000001 +#define LWP_STATES_SUSPENDED 0x00000002 +#define LWP_STATES_TRANSIENT 0x00000004 +#define LWP_STATES_DELAYING 0x00000008 +#define LWP_STATES_WAITING_FOR_TIME 0x00000010 +#define LWP_STATES_WAITING_FOR_BUFFER 0x00000020 +#define LWP_STATES_WAITING_FOR_SEGMENT 0x00000040 +#define LWP_STATES_WAITING_FOR_MESSAGE 0x00000080 +#define LWP_STATES_WAITING_FOR_EVENT 0x00000100 +#define LWP_STATES_WAITING_FOR_MUTEX 0x00000200 +#define LWP_STATES_WAITING_FOR_SEMAPHORE 0x00000400 +#define LWP_STATES_WAITING_FOR_CONDVAR 0x00000800 +#define LWP_STATES_WAITING_FOR_JOINATEXIT 0x00001000 +#define LWP_STATES_WAITING_FOR_RPCREPLAY 0x00002000 +#define LWP_STATES_WAITING_FOR_PERIOD 0x00004000 +#define LWP_STATES_WAITING_FOR_SIGNAL 0x00008000 +#define LWP_STATES_INTERRUPTIBLE_BY_SIGNAL 0x00010000 + +#define LWP_STATES_LOCALLY_BLOCKED (LWP_STATES_WAITING_FOR_BUFFER | LWP_STATES_WAITING_FOR_SEGMENT | \ + LWP_STATES_WAITING_FOR_MESSAGE | LWP_STATES_WAITING_FOR_SEMAPHORE | \ + LWP_STATES_WAITING_FOR_MUTEX | LWP_STATES_WAITING_FOR_CONDVAR | \ + LWP_STATES_WAITING_FOR_JOINATEXIT | LWP_STATES_WAITING_FOR_SIGNAL) + +#define LWP_STATES_WAITING_ON_THREADQ (LWP_STATES_LOCALLY_BLOCKED | LWP_STATES_WAITING_FOR_RPCREPLAY) + +#define LWP_STATES_BLOCKED (LWP_STATES_DELAYING | LWP_STATES_WAITING_FOR_TIME | \ + LWP_STATES_WAITING_FOR_PERIOD | LWP_STATES_WAITING_FOR_EVENT | \ + LWP_STATES_WAITING_ON_THREADQ | LWP_STATES_INTERRUPTIBLE_BY_SIGNAL) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_threadq.h b/wii/libogc/include/ogc/lwp_threadq.h new file mode 100644 index 0000000000..ed9c6bbd4b --- /dev/null +++ b/wii/libogc/include/ogc/lwp_threadq.h @@ -0,0 +1,39 @@ +#ifndef __LWP_THREADQ_H__ +#define __LWP_THREADQ_H__ + +#include +#include +#include +#include + +#define LWP_THREADQ_NOTIMEOUT LWP_WD_NOTIMEOUT + +#ifdef __cplusplus +extern "C" { +#endif + +lwp_cntrl* __lwp_threadqueue_firstfifo(lwp_thrqueue *queue); +lwp_cntrl* __lwp_threadqueue_firstpriority(lwp_thrqueue *queue); +void __lwp_threadqueue_enqueuefifo(lwp_thrqueue *queue,lwp_cntrl *thethread,u64 timeout); +lwp_cntrl* __lwp_threadqueue_dequeuefifo(lwp_thrqueue *queue); +void __lwp_threadqueue_enqueuepriority(lwp_thrqueue *queue,lwp_cntrl *thethread,u64 timeout); +lwp_cntrl* __lwp_threadqueue_dequeuepriority(lwp_thrqueue *queue); +void __lwp_threadqueue_init(lwp_thrqueue *queue,u32 mode,u32 state,u32 timeout_state); +lwp_cntrl* __lwp_threadqueue_first(lwp_thrqueue *queue); +void __lwp_threadqueue_enqueue(lwp_thrqueue *queue,u64 timeout); +lwp_cntrl* __lwp_threadqueue_dequeue(lwp_thrqueue *queue); +void __lwp_threadqueue_flush(lwp_thrqueue *queue,u32 status); +void __lwp_threadqueue_extract(lwp_thrqueue *queue,lwp_cntrl *thethread); +void __lwp_threadqueue_extractfifo(lwp_thrqueue *queue,lwp_cntrl *thethread); +void __lwp_threadqueue_extractpriority(lwp_thrqueue *queue,lwp_cntrl *thethread); +u32 __lwp_threadqueue_extractproxy(lwp_cntrl *thethread); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_threads.h b/wii/libogc/include/ogc/lwp_threads.h new file mode 100644 index 0000000000..5b504aef2a --- /dev/null +++ b/wii/libogc/include/ogc/lwp_threads.h @@ -0,0 +1,107 @@ +#ifndef __LWP_THREADS_H__ +#define __LWP_THREADS_H__ + +#include +#include +#include "lwp_states.h" +#include "lwp_tqdata.h" +#include "lwp_watchdog.h" +#include "lwp_objmgr.h" +#include "context.h" + +//#define _LWPTHREADS_DEBUG +#define LWP_TIMESLICE_TIMER_ID 0x00070040 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + LWP_CPU_BUDGET_ALGO_NONE = 0, + LWP_CPU_BUDGET_ALGO_TIMESLICE +} lwp_cpu_budget_algorithms; + +typedef struct _lwpwaitinfo { + u32 id; + u32 cnt; + void *ret_arg; + void *ret_arg_1; + u32 option; + u32 ret_code; + lwp_queue block2n; + lwp_thrqueue *queue; +} lwp_waitinfo; + +typedef struct _lwpcntrl { + lwp_obj object; + u8 cur_prio,real_prio; + u32 suspendcnt,res_cnt; + u32 isr_level; + u32 cur_state; + u32 cpu_time_budget; + lwp_cpu_budget_algorithms budget_algo; + bool is_preemptible; + lwp_waitinfo wait; + prio_cntrl priomap; + wd_cntrl timer; + + void* (*entry)(void *); + void *arg; + void *stack; + u32 stack_size; + u8 stack_allocated; + lwp_queue *ready; + lwp_thrqueue join_list; + frame_context context; //16 + void *libc_reent; +} lwp_cntrl, *lwp_cntrl_t; + +extern lwp_cntrl *_thr_main; +extern lwp_cntrl *_thr_idle; +extern lwp_cntrl *_thr_executing; +extern lwp_cntrl *_thr_heir; +extern lwp_cntrl *_thr_allocated_fp; +extern vu32 _context_switch_want; +extern vu32 _thread_dispatch_disable_level; + +extern wd_cntrl _lwp_wd_timeslice; +extern void **__lwp_thr_libc_reent; +extern lwp_queue _lwp_thr_ready[]; + +void __thread_dispatch(); +void __lwp_thread_yield(); +void __lwp_thread_closeall(); +void __lwp_thread_setstate(lwp_cntrl *,u32); +void __lwp_thread_clearstate(lwp_cntrl *,u32); +void __lwp_thread_changepriority(lwp_cntrl *,u32,u32); +void __lwp_thread_setpriority(lwp_cntrl *,u32); +void __lwp_thread_settransient(lwp_cntrl *); +void __lwp_thread_suspend(lwp_cntrl *); +void __lwp_thread_resume(lwp_cntrl *,u32); +void __lwp_thread_loadenv(lwp_cntrl *); +void __lwp_thread_ready(lwp_cntrl *); +u32 __lwp_thread_init(lwp_cntrl *,void *,u32,u32,u32,bool); +u32 __lwp_thread_start(lwp_cntrl *,void* (*)(void*),void *); +void __lwp_thread_exit(void *); +void __lwp_thread_close(lwp_cntrl *); +void __lwp_thread_startmultitasking(); +void __lwp_thread_stopmultitasking(void (*exitfunc)()); +lwp_obj* __lwp_thread_getobject(lwp_cntrl *); +u32 __lwp_evaluatemode(); + +u32 __lwp_isr_in_progress(); +void __lwp_thread_resettimeslice(); +void __lwp_rotate_readyqueue(u32); +void __lwp_thread_delayended(void *); +void __lwp_thread_tickle_timeslice(void *); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_tqdata.h b/wii/libogc/include/ogc/lwp_tqdata.h new file mode 100644 index 0000000000..0ebaffd2d3 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_tqdata.h @@ -0,0 +1,38 @@ +#ifndef __LWP_TQDATA_H__ +#define __LWP_TQDATA_H__ + +#define LWP_THREADQ_NUM_PRIOHEADERS 4 +#define LWP_THREADQ_PRIOPERHEADER 64 +#define LWP_THREADQ_REVERSESEARCHMASK 0x20 + +#define LWP_THREADQ_SYNCHRONIZED 0 +#define LWP_THREADQ_NOTHINGHAPPEND 1 +#define LWP_THREADQ_TIMEOUT 2 +#define LWP_THREADQ_SATISFIED 3 + +#define LWP_THREADQ_MODEFIFO 0 +#define LWP_THREADQ_MODEPRIORITY 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwp_queue.h" +#include "lwp_priority.h" + +typedef struct _lwpthrqueue { + union { + lwp_queue fifo; + lwp_queue priority[LWP_THREADQ_NUM_PRIOHEADERS]; + } queues; + u32 sync_state; + u32 mode; + u32 state; + u32 timeout_state; +} lwp_thrqueue; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_watchdog.h b/wii/libogc/include/ogc/lwp_watchdog.h new file mode 100644 index 0000000000..421373cd25 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_watchdog.h @@ -0,0 +1,107 @@ +#ifndef __LWP_WATCHDOG_H__ +#define __LWP_WATCHDOG_H__ + +#include +#include "lwp_queue.h" +#include + +#if defined(HW_RVL) + #define TB_BUS_CLOCK 243000000u + #define TB_CORE_CLOCK 729000000u +#elif defined(HW_DOL) + #define TB_BUS_CLOCK 162000000u + #define TB_CORE_CLOCK 486000000u +#endif +#define TB_TIMER_CLOCK (TB_BUS_CLOCK/4000) //4th of the bus frequency + +#define TB_SECSPERMIN 60 +#define TB_MINSPERHR 60 +#define TB_MONSPERYR 12 +#define TB_DAYSPERYR 365 +#define TB_HRSPERDAY 24 +#define TB_SECSPERDAY (TB_SECSPERMIN*TB_MINSPERHR*TB_HRSPERDAY) +#define TB_SECSPERNYR (365*TB_SECSPERDAY) + +#define TB_MSPERSEC 1000 +#define TB_USPERSEC 1000000 +#define TB_NSPERSEC 1000000000 +#define TB_NSPERMS 1000000 +#define TB_NSPERUS 1000 +#define TB_USPERTICK 10000 + +#define ticks_to_cycles(ticks) ((((u64)(ticks)*(u64)((TB_CORE_CLOCK*2)/TB_TIMER_CLOCK))/2)) +#define ticks_to_secs(ticks) (((u64)(ticks)/(u64)(TB_TIMER_CLOCK*1000))) +#define ticks_to_millisecs(ticks) (((u64)(ticks)/(u64)(TB_TIMER_CLOCK))) +#define ticks_to_microsecs(ticks) ((((u64)(ticks)*8)/(u64)(TB_TIMER_CLOCK/125))) +#define ticks_to_nanosecs(ticks) ((((u64)(ticks)*8000)/(u64)(TB_TIMER_CLOCK/125))) + +#define tick_microsecs(ticks) ((((u64)(ticks)*8)%(u64)(TB_TIMER_CLOCK/125))) +#define tick_nanosecs(ticks) ((((u64)(ticks)*8000)%(u64)(TB_TIMER_CLOCK/125))) + + +#define secs_to_ticks(sec) ((u64)(sec)*(TB_TIMER_CLOCK*1000)) +#define millisecs_to_ticks(msec) ((u64)(msec)*(TB_TIMER_CLOCK)) +#define microsecs_to_ticks(usec) (((u64)(usec)*(TB_TIMER_CLOCK/125))/8) +#define nanosecs_to_ticks(nsec) (((u64)(nsec)*(TB_TIMER_CLOCK/125))/8000) + +#define diff_ticks(tick0,tick1) (((u64)(tick1)<(u64)(tick0))?((u64)-1-(u64)(tick0)+(u64)(tick1)):((u64)(tick1)-(u64)(tick0))) + +#define LWP_WD_INACTIVE 0 +#define LWP_WD_INSERTED 1 +#define LWP_WD_ACTIVE 2 +#define LWP_WD_REMOVE 3 + +#define LWP_WD_FORWARD 0 +#define LWP_WD_BACKWARD 1 + +#define LWP_WD_NOTIMEOUT 0 + +#define LWP_WD_ABS(x) ((s64)(x)>0?(s64)(x):-((s64)(x))) + +#ifdef __cplusplus +extern "C" { +#endif + +extern vu32 _wd_sync_level; +extern vu32 _wd_sync_count; +extern u32 _wd_ticks_since_boot; + +extern lwp_queue _wd_ticks_queue; + +extern u32 gettick(); +extern u64 gettime(); +extern void settime(u64); + +u32 diff_sec(u64 start,u64 end); +u32 diff_msec(u64 start,u64 end); +u32 diff_usec(u64 start,u64 end); +u32 diff_nsec(u64 start,u64 end); + +typedef void (*wd_service_routine)(void *); + +typedef struct _wdcntrl { + lwp_node node; + u64 start; + u32 id; + u32 state; + u64 fire; + wd_service_routine routine; + void *usr_data; +} wd_cntrl; + +void __lwp_watchdog_init(); +void __lwp_watchdog_settimer(wd_cntrl *wd); +void __lwp_wd_insert(lwp_queue *header,wd_cntrl *wd); +u32 __lwp_wd_remove(lwp_queue *header,wd_cntrl *wd); +void __lwp_wd_tickle(lwp_queue *queue); +void __lwp_wd_adjust(lwp_queue *queue,u32 dir,s64 interval); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/lwp_wkspace.h b/wii/libogc/include/ogc/lwp_wkspace.h new file mode 100644 index 0000000000..c5dd500a23 --- /dev/null +++ b/wii/libogc/include/ogc/lwp_wkspace.h @@ -0,0 +1,23 @@ +#ifndef __LWP_WKSPACE_H__ +#define __LWP_WKSPACE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern heap_cntrl __wkspace_heap; + +void __lwp_wkspace_init(u32 size); + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/machine/asm.h b/wii/libogc/include/ogc/machine/asm.h new file mode 100644 index 0000000000..2feed006f4 --- /dev/null +++ b/wii/libogc/include/ogc/machine/asm.h @@ -0,0 +1,338 @@ +#ifndef __ASM_H__ +#define __ASM_H__ + +#ifdef _LANGUAGE_ASSEMBLY +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + + +/* General Purpose Registers (GPRs) */ + +#define r0 0 +#define r1 1 +#define sp 1 +#define r2 2 +#define toc 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + + +/* Floating Point Registers (FPRs) */ + +#define fr0 0 +#define fr1 1 +#define fr2 2 +#define fr3 3 +#define fr4 4 +#define fr5 5 +#define fr6 6 +#define fr7 7 +#define fr8 8 +#define fr9 9 +#define fr10 10 +#define fr11 11 +#define fr12 12 +#define fr13 13 +#define fr14 14 +#define fr15 15 +#define fr16 16 +#define fr17 17 +#define fr18 18 +#define fr19 19 +#define fr20 20 +#define fr21 21 +#define fr22 22 +#define fr23 23 +#define fr24 24 +#define fr25 25 +#define fr26 26 +#define fr27 27 +#define fr28 28 +#define fr29 29 +#define fr30 30 +#define fr31 31 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 + +#endif //_LANGUAGE_ASSEMBLY + +#define SPRG0 272 +#define SPRG1 273 +#define SPRG2 274 +#define SPRG3 275 + +#define PMC1 953 +#define PMC2 954 +#define PMC3 957 +#define PMC4 958 + +#define MMCR0 952 +#define MMCR1 956 + + +#define LINK_REGISTER_CALLEE_UPDATE_ROOM 4 +#define EXCEPTION_NUMBER 8 +#define SRR0_OFFSET 12 +#define SRR1_OFFSET 16 +#define GPR0_OFFSET 20 +#define GPR1_OFFSET 24 +#define GPR2_OFFSET 28 +#define GPR3_OFFSET 32 +#define GPR4_OFFSET 36 +#define GPR5_OFFSET 40 +#define GPR6_OFFSET 44 +#define GPR7_OFFSET 48 +#define GPR8_OFFSET 52 +#define GPR9_OFFSET 56 +#define GPR10_OFFSET 60 +#define GPR11_OFFSET 64 +#define GPR12_OFFSET 68 +#define GPR13_OFFSET 72 +#define GPR14_OFFSET 76 +#define GPR15_OFFSET 80 +#define GPR16_OFFSET 84 +#define GPR17_OFFSET 88 +#define GPR18_OFFSET 92 +#define GPR19_OFFSET 96 +#define GPR20_OFFSET 100 +#define GPR21_OFFSET 104 +#define GPR22_OFFSET 108 +#define GPR23_OFFSET 112 +#define GPR24_OFFSET 116 +#define GPR25_OFFSET 120 +#define GPR26_OFFSET 124 +#define GPR27_OFFSET 128 +#define GPR28_OFFSET 132 +#define GPR29_OFFSET 136 +#define GPR30_OFFSET 140 +#define GPR31_OFFSET 144 + +#define GQR0_OFFSET 148 +#define GQR1_OFFSET 152 +#define GQR2_OFFSET 156 +#define GQR3_OFFSET 160 +#define GQR4_OFFSET 164 +#define GQR5_OFFSET 168 +#define GQR6_OFFSET 172 +#define GQR7_OFFSET 176 + +#define CR_OFFSET 180 +#define LR_OFFSET 184 +#define CTR_OFFSET 188 +#define XER_OFFSET 192 +#define MSR_OFFSET 196 +#define DAR_OFFSET 200 + +#define STATE_OFFSET 204 +#define MODE_OFFSET 206 + +#define FPR0_OFFSET 208 +#define FPR1_OFFSET 216 +#define FPR2_OFFSET 224 +#define FPR3_OFFSET 232 +#define FPR4_OFFSET 240 +#define FPR5_OFFSET 248 +#define FPR6_OFFSET 256 +#define FPR7_OFFSET 264 +#define FPR8_OFFSET 272 +#define FPR9_OFFSET 280 +#define FPR10_OFFSET 288 +#define FPR11_OFFSET 296 +#define FPR12_OFFSET 304 +#define FPR13_OFFSET 312 +#define FPR14_OFFSET 320 +#define FPR15_OFFSET 328 +#define FPR16_OFFSET 336 +#define FPR17_OFFSET 344 +#define FPR18_OFFSET 352 +#define FPR19_OFFSET 360 +#define FPR20_OFFSET 368 +#define FPR21_OFFSET 376 +#define FPR22_OFFSET 384 +#define FPR23_OFFSET 392 +#define FPR24_OFFSET 400 +#define FPR25_OFFSET 408 +#define FPR26_OFFSET 416 +#define FPR27_OFFSET 424 +#define FPR28_OFFSET 432 +#define FPR29_OFFSET 440 +#define FPR30_OFFSET 448 +#define FPR31_OFFSET 456 + +#define FPSCR_OFFSET 464 + +#define PSR0_OFFSET 472 +#define PSR1_OFFSET 480 +#define PSR2_OFFSET 488 +#define PSR3_OFFSET 496 +#define PSR4_OFFSET 504 +#define PSR5_OFFSET 512 +#define PSR6_OFFSET 520 +#define PSR7_OFFSET 528 +#define PSR8_OFFSET 536 +#define PSR9_OFFSET 544 +#define PSR10_OFFSET 552 +#define PSR11_OFFSET 560 +#define PSR12_OFFSET 568 +#define PSR13_OFFSET 576 +#define PSR14_OFFSET 584 +#define PSR15_OFFSET 592 +#define PSR16_OFFSET 600 +#define PSR17_OFFSET 608 +#define PSR18_OFFSET 616 +#define PSR19_OFFSET 624 +#define PSR20_OFFSET 632 +#define PSR21_OFFSET 640 +#define PSR22_OFFSET 648 +#define PSR23_OFFSET 656 +#define PSR24_OFFSET 664 +#define PSR25_OFFSET 672 +#define PSR26_OFFSET 680 +#define PSR27_OFFSET 688 +#define PSR28_OFFSET 696 +#define PSR29_OFFSET 704 +#define PSR30_OFFSET 712 +#define PSR31_OFFSET 720 +/* + * maintain the EABI requested 8 bytes aligment + * As SVR4 ABI requires 16, make it 16 (as some + * exception may need more registers to be processed...) + */ +#define EXCEPTION_FRAME_END 728 + +#define IBAT0U 528 +#define IBAT0L 529 +#define IBAT1U 530 +#define IBAT1L 531 +#define IBAT2U 532 +#define IBAT2L 533 +#define IBAT3U 534 +#define IBAT3L 535 +#define IBAT4U 560 +#define IBAT4L 561 +#define IBAT5U 562 +#define IBAT5L 563 +#define IBAT6U 564 +#define IBAT6L 565 +#define IBAT7U 566 +#define IBAT7L 567 + +#define DBAT0U 536 +#define DBAT0L 537 +#define DBAT1U 538 +#define DBAT1L 539 +#define DBAT2U 540 +#define DBAT2L 541 +#define DBAT3U 542 +#define DBAT3L 543 +#define DBAT4U 568 +#define DBAT4L 569 +#define DBAT5U 570 +#define DBAT5L 571 +#define DBAT6U 572 +#define DBAT6L 573 +#define DBAT7U 574 +#define DBAT7L 575 + +#define HID0 1008 +#define HID1 1009 +#define HID2 920 +#define HID4 1011 + +#define GQR0 912 +#define GQR1 913 +#define GQR2 914 +#define GQR3 915 +#define GQR4 916 +#define GQR5 917 +#define GQR6 918 +#define GQR7 919 + +#define L2CR 1017 + +#define WPAR 921 + +#define DMAU 922 +#define DMAL 923 + +#define MSR_RI 0x00000002 +#define MSR_DR 0x00000010 +#define MSR_IR 0x00000020 +#define MSR_IP 0x00000040 +#define MSR_SE 0x00000400 +#define MSR_ME 0x00001000 +#define MSR_FP 0x00002000 +#define MSR_POW 0x00004000 +#define MSR_EE 0x00008000 + +#define PPC_ALIGNMENT 8 + +#define PPC_CACHE_ALIGNMENT 32 + +#endif //__ASM_H__ diff --git a/wii/libogc/include/ogc/machine/processor.h b/wii/libogc/include/ogc/machine/processor.h new file mode 100644 index 0000000000..f8693927ac --- /dev/null +++ b/wii/libogc/include/ogc/machine/processor.h @@ -0,0 +1,251 @@ +#ifndef __PROCESSOR_H__ +#define __PROCESSOR_H__ + +#include +#include "asm.h" + +#define __stringify(rn) #rn +#define ATTRIBUTE_ALIGN(v) __attribute__((aligned(v))) +// courtesy of Marcan +#define STACK_ALIGN(type, name, cnt, alignment) u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + (((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - ((sizeof(type)*(cnt))%(alignment))) : 0))]; \ + type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (((u32)(_al__##name))&((alignment)-1)))) + +#define _sync() asm volatile("sync") +#define _nop() asm volatile("nop") +#define ppcsync() asm volatile("sc") +#define ppchalt() ({ \ + asm volatile("sync"); \ + while(1) { \ + asm volatile("nop"); \ + asm volatile("li 3,0"); \ + asm volatile("nop"); \ + } \ +}) + +#define mfpvr() ({register u32 _rval; \ + asm volatile("mfpvr %0" : "=r"(_rval)); _rval;}) + +#define mfdcr(_rn) ({register u32 _rval; \ + asm volatile("mfdcr %0," __stringify(_rn) \ + : "=r" (_rval)); _rval;}) +#define mtdcr(rn, val) asm volatile("mtdcr " __stringify(rn) ",%0" : : "r" (val)) + +#define mfmsr() ({register u32 _rval; \ + asm volatile("mfmsr %0" : "=r" (_rval)); _rval;}) +#define mtmsr(val) asm volatile("mtmsr %0" : : "r" (val)) + +#define mfdec() ({register u32 _rval; \ + asm volatile("mfdec %0" : "=r" (_rval)); _rval;}) +#define mtdec(_val) asm volatile("mtdec %0" : : "r" (_val)) + +#define mfspr(_rn) \ +({ register u32 _rval = 0; \ + asm volatile("mfspr %0," __stringify(_rn) \ + : "=r" (_rval));\ + _rval; \ +}) + +#define mtspr(_rn, _val) asm volatile("mtspr " __stringify(_rn) ",%0" : : "r" (_val)) + +#define mfwpar() mfspr(WPAR) +#define mtwpar(_val) mtspr(WPAR,_val) + +#define mfmmcr0() mfspr(MMCR0) +#define mtmmcr0(_val) mtspr(MMCR0,_val) +#define mfmmcr1() mfspr(MMCR1) +#define mtmmcr1(_val) mtspr(MMCR1,_val) + +#define mfpmc1() mfspr(PMC1) +#define mtpmc1(_val) mtspr(PMC1,_val) +#define mfpmc2() mfspr(PMC2) +#define mtpmc2(_val) mtspr(PMC2,_val) +#define mfpmc3() mfspr(PMC3) +#define mtpmc3(_val) mtspr(PMC3,_val) +#define mfpmc4() mfspr(PMC4) +#define mtpmc4(_val) mtspr(PMC4,_val) + +#define mfhid0() mfspr(HID0) +#define mthid0(_val) mtspr(HID0,_val) +#define mfhid1() mfspr(HID1) +#define mthid1(_val) mtspr(HID1,_val) +#define mfhid2() mfspr(HID2) +#define mthid2(_val) mtspr(HID2,_val) +#define mfhid4() mfspr(HID4) +#define mthid4(_val) mtspr(HID4,_val) + +#define __lhbrx(base,index) \ +({ register u16 res; \ + __asm__ volatile ("lhbrx %0,%1,%2" : "=r"(res) : "b%"(index), "r"(base) : "memory"); \ + res; }) + +#define __lwbrx(base,index) \ +({ register u32 res; \ + __asm__ volatile ("lwbrx %0,%1,%2" : "=r"(res) : "b%"(index), "r"(base) : "memory"); \ + res; }) + +#define __sthbrx(base,index,value) \ + __asm__ volatile ("sthbrx %0,%1,%2" : : "r"(value), "b%"(index), "r"(base) : "memory") + +#define __stwbrx(base,index,value) \ + __asm__ volatile ("stwbrx %0,%1,%2" : : "r"(value), "b%"(index), "r"(base) : "memory") + +#define cntlzw(_val) ({register u32 _rval; \ + asm volatile("cntlzw %0, %1" : "=r"((_rval)) : "r"((_val))); _rval;}) + +#define _CPU_MSR_GET( _msr_value ) \ + do { \ + _msr_value = 0; \ + asm volatile ("mfmsr %0" : "=&r" ((_msr_value)) : "0" ((_msr_value))); \ + } while (0) + +#define _CPU_MSR_SET( _msr_value ) \ +{ asm volatile ("mtmsr %0" : "=&r" ((_msr_value)) : "0" ((_msr_value))); } + +#define _CPU_ISR_Enable() \ + { register u32 _val = 0; \ + __asm__ __volatile__ ( \ + "mfmsr %0\n" \ + "ori %0,%0,0x8000\n" \ + "mtmsr %0" \ + : "=&r" ((_val)) : "0" ((_val)) \ + ); \ + } + +#define _CPU_ISR_Disable( _isr_cookie ) \ + { register u32 _disable_mask = 0; \ + _isr_cookie = 0; \ + __asm__ __volatile__ ( \ + "mfmsr %0\n" \ + "rlwinm %1,%0,0,17,15\n" \ + "mtmsr %1\n" \ + "extrwi %0,%0,1,16" \ + : "=&r" ((_isr_cookie)), "=&r" ((_disable_mask)) \ + : "0" ((_isr_cookie)), "1" ((_disable_mask)) \ + ); \ + } + +#define _CPU_ISR_Restore( _isr_cookie ) \ + { register u32 _enable_mask = 0; \ + __asm__ __volatile__ ( \ + " cmpwi %0,0\n" \ + " beq 1f\n" \ + " mfmsr %1\n" \ + " ori %1,%1,0x8000\n" \ + " mtmsr %1\n" \ + "1:" \ + : "=r"((_isr_cookie)),"=&r" ((_enable_mask)) \ + : "0"((_isr_cookie)),"1" ((_enable_mask)) \ + ); \ + } + +#define _CPU_ISR_Flash( _isr_cookie ) \ + { register u32 _flash_mask = 0; \ + __asm__ __volatile__ ( \ + " cmpwi %0,0\n" \ + " beq 1f\n" \ + " mfmsr %1\n" \ + " ori %1,%1,0x8000\n" \ + " mtmsr %1\n" \ + " rlwinm %1,%1,0,17,15\n" \ + " mtmsr %1\n" \ + "1:" \ + : "=r" ((_isr_cookie)), "=&r" ((_flash_mask)) \ + : "0" ((_isr_cookie)), "1" ((_flash_mask)) \ + ); \ + } + +#define _CPU_FPR_Enable() \ +{ register u32 _val = 0; \ + asm volatile ("mfmsr %0; ori %0,%0,0x2000; mtmsr %0" : \ + "=&r" (_val) : "0" (_val));\ +} + +#define _CPU_FPR_Disable() \ +{ register u32 _val = 0; \ + asm volatile ("mfmsr %0; rlwinm %0,%0,0,19,17; mtmsr %0" : \ + "=&r" (_val) : "0" (_val));\ +} + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +static inline u16 bswap16(u16 val) +{ + u16 tmp = val; + return __lhbrx(&tmp,0); +} + +static inline u32 bswap32(u32 val) +{ + u32 tmp = val; + return __lwbrx(&tmp,0); +} + +static inline u64 bswap64(u64 val) +{ + union ullc { + u64 ull; + u32 ul[2]; + } outv; + u64 tmp = val; + + outv.ul[0] = __lwbrx(&tmp,4); + outv.ul[1] = __lwbrx(&tmp,0); + + return outv.ull; +} + +// Basic I/O + +static inline u32 read32(u32 addr) +{ + u32 x; + asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr)); + return x; +} + +static inline void write32(u32 addr, u32 x) +{ + asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr)); +} + +static inline void mask32(u32 addr, u32 clear, u32 set) +{ + write32(addr, (read32(addr)&(~clear)) | set); +} + +static inline u16 read16(u32 addr) +{ + u16 x; + asm volatile("lhz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr)); + return x; +} + +static inline void write16(u32 addr, u16 x) +{ + asm("sth %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr)); +} + +static inline u8 read8(u32 addr) +{ + u8 x; + asm volatile("lbz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr)); + return x; +} + +static inline void write8(u32 addr, u8 x) +{ + asm("stb %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr)); +} + +static inline void writef32(u32 addr, f32 x) +{ + asm("stfs %0,0(%1) ; eieio" : : "f"(x), "b"(0xc0000000 | addr)); +} + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/machine/spinlock.h b/wii/libogc/include/ogc/machine/spinlock.h new file mode 100644 index 0000000000..1d6022a2fb --- /dev/null +++ b/wii/libogc/include/ogc/machine/spinlock.h @@ -0,0 +1,191 @@ +#ifndef __SPINLOCK_H__ +#define __SPINLOCK_H__ + +#include +#include + +typedef struct { + vu32 lock; +} spinlock_t; + +#define SPIN_LOCK_UNLOCKED (spinlock_t){0} + +#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; }while(0) + +static __inline__ u32 _test_and_set(u32 *atomic) +{ + register u32 ret; + + __asm__ __volatile__ ("1: lwarx %0,0,%1\n" + " cmpwi 0,%0,0\n" + " bne- 2f\n" + " stwcx. %2,0,%1\n" + " bne- 1b\n" + " isync\n" + "2:" : "=&r"(ret) + : "r"(atomic), "r"(1) + : "cr0", "memory"); + + return ret; +} + +static __inline__ u32 atomic_inc(u32 *pint) +{ + register u32 ret; + __asm__ __volatile__( + "1: lwarx %0,0,%1\n\ + addi %0,%0,1\n\ + stwcx. %0,0,%1\n\ + bne- 1b\n\ + isync\n" + : "=&r"(ret) : "r"(pint) + : "cr0", "memory"); + return ret; +} + +static __inline__ u32 atomic_dec(u32 *pint) +{ + register u32 ret; + __asm__ __volatile__( + "1: lwarx %0,0,%1\n\ + addi %0,%0,-1\n\ + stwcx. %0,0,%1\n\ + bne- 1b\n\ + isync\n" + : "=&r"(ret) : "r"(pint) + : "cr0", "memory"); + return ret; +} + +static __inline__ void spin_lock(spinlock_t *lock) +{ + register u32 tmp; + + __asm__ __volatile__( + "b 1f # spin_lock\n\ +2: lwzx %0,0,%1\n\ + cmpwi 0,%0,0\n\ + bne+ 2b\n\ +1: lwarx %0,0,%1\n\ + cmpwi 0,%0,0\n\ + bne- 2b\n\ + stwcx. %2,0,%1\n\ + bne- 2b\n\ + isync" + : "=&r"(tmp) + : "r"(lock), "r"(1) + : "cr0", "memory"); +} + +static __inline__ void spin_lock_irqsave(spinlock_t *lock,register u32 *p_isr_level) +{ + register u32 level; + register u32 tmp; + + _CPU_ISR_Disable(level); + + __asm__ __volatile__( + " b 1f # spin_lock\n\ + 2: lwzx %0,0,%1\n\ + cmpwi 0,%0,0\n\ + bne+ 2b\n\ + 1: lwarx %0,0,%1\n\ + cmpwi 0,%0,0\n\ + bne- 2b\n\ + stwcx. %2,0,%1\n\ + bne- 2b\n\ + isync" + : "=&r"(tmp) + : "r"(lock), "r"(1) + : "cr0", "memory"); + + *p_isr_level = level; +} + +static __inline__ void spin_unlock(spinlock_t *lock) +{ + __asm__ __volatile__("eieio # spin_unlock": : :"memory"); + lock->lock = 0; +} + +static __inline__ void spin_unlock_irqrestore(spinlock_t *lock,register u32 isr_level) +{ + __asm__ __volatile__( + "eieio # spin_unlock" + : : :"memory"); + lock->lock = 0; + + _CPU_ISR_Restore(isr_level); +} + +typedef struct { + vu32 lock; +} rwlock_t; + +#define RW_LOCK_UNLOCKED (rwlock_t){0} + +#define read_lock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; }while(0) + +static __inline__ void read_lock(rwlock_t *rw) +{ + register u32 tmp; + + __asm__ __volatile__( + "b 2f # read_lock\n\ +1: lwzx %0,0,%1\n\ + cmpwi 0,%0,0\n\ + blt+ 1b\n\ +2: lwarx %0,0,%1\n\ + addic. %0,%0,1\n\ + ble- 1b\n\ + stwcx. %0,0,%1\n\ + bne- 2b\n\ + isync" + : "=&r"(tmp) + : "r"(&rw->lock) + : "cr0", "memory"); +} + +static __inline__ void read_unlock(rwlock_t *rw) +{ + register u32 tmp; + + __asm__ __volatile__( + "eieio # read_unlock\n\ +1: lwarx %0,0,%1\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%1\n\ + bne- 1b" + : "=&r"(tmp) + : "r"(&rw->lock) + : "cr0", "memory"); +} + +static __inline__ void write_lock(rwlock_t *rw) +{ + register u32 tmp; + + __asm__ __volatile__( + "b 2f # write_lock\n\ +1: lwzx %0,0,%1\n\ + cmpwi 0,%0,0\n\ + bne+ 1b\n\ +2: lwarx %0,0,%1\n\ + cmpwi 0,%0,0\n\ + bne- 1b\n\ + stwcx. %2,0,%1\n\ + bne- 2b\n\ + isync" + : "=&r"(tmp) + : "r"(&rw->lock), "r"(-1) + : "cr0", "memory"); +} + +static __inline__ void write_unlock(rwlock_t *rw) +{ + __asm__ __volatile__("eieio # write_unlock": : :"memory"); + rw->lock = 0; +} + + +#endif diff --git a/wii/libogc/include/ogc/message.h b/wii/libogc/include/ogc/message.h new file mode 100644 index 0000000000..445b1bc4d6 --- /dev/null +++ b/wii/libogc/include/ogc/message.h @@ -0,0 +1,123 @@ +/*------------------------------------------------------------- + +message.h -- Thread subsystem II + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __MESSAGE_H__ +#define __MESSAGE_H__ + +/*! \file message.h +\brief Thread subsystem II + +*/ + +#include + +#define MQ_BOX_NULL 0xffffffff + +#define MQ_ERROR_SUCCESSFUL 0 +#define MQ_ERROR_TOOMANY -5 + +#define MQ_MSG_BLOCK 0 +#define MQ_MSG_NOBLOCK 1 + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \typedef u32 mqbox_t +\brief typedef for the message queue handle +*/ +typedef u32 mqbox_t; + + +/*! \typedef void* mqmsg_t +\brief typedef for the message pointer +*/ +typedef void* mqmsg_t; + + + +/*! \fn u32 MQ_Init(mqbox_t *mqbox,u32 count) +\brief Initializes a message queue +\param[out] mqbox pointer to the mqbox_t handle. +\param[in] count maximum number of messages the queue can hold + +\return 0 on success, <0 on error +*/ +s32 MQ_Init(mqbox_t *mqbox,u32 count); + + +/*! \fn void MQ_Close(mqbox_t mqbox) +\brief Closes the message queue and releases all memory. +\param[in] mqbox handle to the mqbox_t structure. + +\return none +*/ +void MQ_Close(mqbox_t mqbox); + + +/*! \fn BOOL MQ_Send(mqbox_t mqbox,mqmsg_t msg,u32 flags) +\brief Sends a message to the given message queue. +\param[in] mqbox mqbox_t handle to the message queue +\param[in] msg message to send +\param[in] flags message flags (MQ_MSG_BLOCK, MQ_MSG_NOBLOCK) + +\return bool result +*/ +BOOL MQ_Send(mqbox_t mqbox,mqmsg_t msg,u32 flags); + + +/*! \fn BOOL MQ_Jam(mqbox_t mqbox,mqmsg_t msg,u32 flags) +\brief Sends a message to the given message queue and jams it in front of the queue. +\param[in] mqbox mqbox_t handle to the message queue +\param[in] msg message to send +\param[in] flags message flags (MQ_MSG_BLOCK, MQ_MSG_NOBLOCK) + +\return bool result +*/ +BOOL MQ_Jam(mqbox_t mqbox,mqmsg_t msg,u32 flags); + + +/*! \fn BOOL MQ_Receive(mqbox_t mqbox,mqmsg_t *msg,u32 flags) +\brief Sends a message to the given message queue. +\param[in] mqbox mqbox_t handle to the message queue +\param[in] msg pointer to a mqmsg_t_t-type message to receive. +\param[in] flags message flags (MQ_MSG_BLOCK, MQ_MSG_NOBLOCK) + +\return bool result +*/ +BOOL MQ_Receive(mqbox_t mqbox,mqmsg_t *msg,u32 flags); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/mutex.h b/wii/libogc/include/ogc/mutex.h new file mode 100644 index 0000000000..4faaf23926 --- /dev/null +++ b/wii/libogc/include/ogc/mutex.h @@ -0,0 +1,103 @@ +/*------------------------------------------------------------- + +mutex.h -- Thread subsystem III + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __MUTEX_H__ +#define __MUTEX_H__ + +/*! \file mutex.h +\brief Thread subsystem III + +*/ + +#include + +#define LWP_MUTEX_NULL 0xffffffff + +#ifdef __cplusplus + extern "C" { +#endif + + +/*! \typedef u32 mutex_t +\brief typedef for the mutex handle +*/ +typedef u32 mutex_t; + + +/*! \fn s32 LWP_MutexInit(mutex_t *mutex,bool use_recursive) +\brief Initializes a mutex lock. +\param[out] mutex pointer to a mutex_t handle. +\param[in] use_recursive whether to allow the thread, whithin the same context, to enter multiple times the lock or not. + +\return 0 on success, <0 on error +*/ +s32 LWP_MutexInit(mutex_t *mutex,bool use_recursive); + + +/*! \fn s32 LWP_MutexDestroy(mutex_t mutex) +\brief Close mutex lock, release all threads and handles locked on this mutex. +\param[in] mutex handle to the mutex_t structure. + +\return 0 on success, <0 on error +*/ +s32 LWP_MutexDestroy(mutex_t mutex); + + +/*! \fn s32 LWP_MutexLock(mutex_t mutex) +\brief Enter the mutex lock. +\param[in] mutex handle to the mutext_t structure. + +\return 0 on success, <0 on error +*/ +s32 LWP_MutexLock(mutex_t mutex); + + +/*! \fn s32 LWP_MutexTryLock(mutex_t mutex) +\brief Try to enter the mutex lock. +\param[in] mutex handle to the mutex_t structure. + +\return 0: on first aquire, 1: would lock +*/ +s32 LWP_MutexTryLock(mutex_t mutex); + + +/*! \fn s32 LWP_MutexUnlock(mutex_t mutex) +\brief Release the mutex lock and let other threads process further on this mutex. +\param[in] mutex handle to the mutex_t structure. + +\return 0 on success, <0 on error +*/ +s32 LWP_MutexUnlock(mutex_t mutex); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/pad.h b/wii/libogc/include/ogc/pad.h new file mode 100644 index 0000000000..3488c5c5b4 --- /dev/null +++ b/wii/libogc/include/ogc/pad.h @@ -0,0 +1,97 @@ +#ifndef __PAD_H__ +#define __PAD_H__ + +#include + +#define PAD_CHAN0 0 +#define PAD_CHAN1 1 +#define PAD_CHAN2 2 +#define PAD_CHAN3 3 +#define PAD_CHANMAX 4 + +#define PAD_MOTOR_STOP 0 +#define PAD_MOTOR_RUMBLE 1 +#define PAD_MOTOR_STOP_HARD 2 + +#define PAD_ERR_NONE 0 +#define PAD_ERR_NO_CONTROLLER -1 +#define PAD_ERR_NOT_READY -2 +#define PAD_ERR_TRANSFER -3 + +#define PAD_BUTTON_LEFT 0x0001 +#define PAD_BUTTON_RIGHT 0x0002 +#define PAD_BUTTON_DOWN 0x0004 +#define PAD_BUTTON_UP 0x0008 +#define PAD_TRIGGER_Z 0x0010 +#define PAD_TRIGGER_R 0x0020 +#define PAD_TRIGGER_L 0x0040 +#define PAD_BUTTON_A 0x0100 +#define PAD_BUTTON_B 0x0200 +#define PAD_BUTTON_X 0x0400 +#define PAD_BUTTON_Y 0x0800 +#define PAD_BUTTON_MENU 0x1000 +#define PAD_BUTTON_START 0x1000 + +#define PAD_CHAN0_BIT 0x80000000 +#define PAD_CHAN1_BIT 0x40000000 +#define PAD_CHAN2_BIT 0x20000000 +#define PAD_CHAN3_BIT 0x10000000 +/*+----------------------------------------------------------------------------------------------+*/ +/*+----------------------------------------------------------------------------------------------+*/ +/*+----------------------------------------------------------------------------------------------+*/ +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ +/*+----------------------------------------------------------------------------------------------+*/ +typedef struct _padstatus { + u16 button; + s8 stickX; + s8 stickY; + s8 substickX; + s8 substickY; + u8 triggerL; + u8 triggerR; + u8 analogA; + u8 analogB; + s8 err; +} PADStatus; + +typedef void (*sampling_callback)(void); +/*+----------------------------------------------------------------------------------------------+*/ +/*+----------------------------------------------------------------------------------------------+*/ +/*+----------------------------------------------------------------------------------------------+*/ + +u32 PAD_Init(); +u32 PAD_Sync(); +u32 PAD_Read(PADStatus *status); +u32 PAD_Reset(u32 mask); +u32 PAD_Recalibrate(u32 mask); +void PAD_Clamp(PADStatus *status); +void PAD_ControlMotor(s32 chan,u32 cmd); +void PAD_SetSpec(u32 spec); + +u32 PAD_ScanPads(); + +u16 PAD_ButtonsUp(int pad); +u16 PAD_ButtonsDown(int pad); +u16 PAD_ButtonsHeld(int pad); + +s8 PAD_SubStickX(int pad); +s8 PAD_SubStickY(int pad); + +s8 PAD_StickX(int pad); +s8 PAD_StickY(int pad); + +u8 PAD_TriggerL(int pad); +u8 PAD_TriggerR(int pad); + + +sampling_callback PAD_SetSamplingCallback(sampling_callback cb); + +/*+----------------------------------------------------------------------------------------------+*/ + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/semaphore.h b/wii/libogc/include/ogc/semaphore.h new file mode 100644 index 0000000000..c7ba6c6d0e --- /dev/null +++ b/wii/libogc/include/ogc/semaphore.h @@ -0,0 +1,96 @@ +/*------------------------------------------------------------- + +semaphore.h -- Thread subsystem IV + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __SEMAPHORE_H__ +#define __SEMAPHORE_H__ + +/*! \file semaphore.h +\brief Thread subsystem IV + +*/ + + +#include + +#define LWP_SEM_NULL 0xffffffff + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \typedef u32 sem_t +\brief typedef for the semaphore handle +*/ +typedef u32 sem_t; + + +/*! \fn s32 LWP_SemInit(sem_t *sem,u32 start,u32 max) +\brief Initializes a semaphore. +\param[out] sem pointer to a sem_t handle. +\param[in] start start count of the semaphore +\param[in] max maximum count of the semaphore + +\return 0 on success, <0 on error +*/ +s32 LWP_SemInit(sem_t *sem,u32 start,u32 max); + + +/*! \fn s32 LWP_SemDestroy(sem_t sem) +\brief Close and destroy a semaphore, release all threads and handles locked on this semaphore. +\param[in] sem handle to the sem_t structure. + +\return 0 on success, <0 on error +*/ +s32 LWP_SemDestroy(sem_t sem); + + +/*! \fn s32 LWP_SemWait(sem_t sem) +\brief Count down semaphore counter and enter lock if counter <=0 +\param[in] sem handle to the sem_t structure. + +\return 0 on success, <0 on error +*/ +s32 LWP_SemWait(sem_t sem); + + +/*! \fn s32 LWP_SemPost(sem_t sem) +\brief Count up semaphore counter and release lock if counter >0 +\param[in] sem handle to the sem_t structure. + +\return 0 on success, <0 on error +*/ +s32 LWP_SemPost(sem_t sem); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/si.h b/wii/libogc/include/ogc/si.h new file mode 100644 index 0000000000..df40c81709 --- /dev/null +++ b/wii/libogc/include/ogc/si.h @@ -0,0 +1,95 @@ +#ifndef __SI_H__ +#define __SI_H__ + +#include + +#define SI_CHAN0 0 +#define SI_CHAN1 1 +#define SI_CHAN2 2 +#define SI_CHAN3 3 +#define SI_MAX_CHAN 4 + +#define SI_CHAN0_BIT 0x80000000 +#define SI_CHAN1_BIT 0x40000000 +#define SI_CHAN2_BIT 0x20000000 +#define SI_CHAN3_BIT 0x10000000 +#define SI_CHAN_BIT(chn) (SI_CHAN0_BIT>>(chn)) + +#define SI_ERROR_UNDER_RUN 0x0001 +#define SI_ERROR_OVER_RUN 0x0002 +#define SI_ERROR_COLLISION 0x0004 +#define SI_ERROR_NO_RESPONSE 0x0008 +#define SI_ERROR_WRST 0x0010 +#define SI_ERROR_RDST 0x0020 +#define SI_ERR_UNKNOWN 0x0040 +#define SI_ERR_BUSY 0x0080 + +// +// CMD_TYPE_AND_STATUS response data +// +#define SI_TYPE_MASK 0x18000000u +#define SI_TYPE_N64 0x00000000u +#define SI_TYPE_DOLPHIN 0x08000000u +#define SI_TYPE_GC SI_TYPE_DOLPHIN + +// GameCube specific +#define SI_GC_WIRELESS 0x80000000u +#define SI_GC_NOMOTOR 0x20000000u // no rumble motor +#define SI_GC_STANDARD 0x01000000u // dolphin standard controller + +// WaveBird specific +#define SI_WIRELESS_RECEIVED 0x40000000u // 0: no wireless unit +#define SI_WIRELESS_IR 0x04000000u // 0: IR 1: RF +#define SI_WIRELESS_STATE 0x02000000u // 0: variable 1: fixed +#define SI_WIRELESS_ORIGIN 0x00200000u // 0: invalid 1: valid +#define SI_WIRELESS_FIX_ID 0x00100000u // 0: not fixed 1: fixed +#define SI_WIRELESS_TYPE 0x000f0000u +#define SI_WIRELESS_LITE_MASK 0x000c0000u // 0: normal 1: lite controller +#define SI_WIRELESS_LITE 0x00040000u // 0: normal 1: lite controller +#define SI_WIRELESS_CONT_MASK 0x00080000u // 0: non-controller 1: non-controller +#define SI_WIRELESS_CONT 0x00000000u +#define SI_WIRELESS_ID 0x00c0ff00u +#define SI_WIRELESS_TYPE_ID (SI_WIRELESS_TYPE | SI_WIRELESS_ID) + +#define SI_N64_CONTROLLER (SI_TYPE_N64 | 0x05000000) +#define SI_N64_MIC (SI_TYPE_N64 | 0x00010000) +#define SI_N64_KEYBOARD (SI_TYPE_N64 | 0x00020000) +#define SI_N64_MOUSE (SI_TYPE_N64 | 0x02000000) +#define SI_GBA (SI_TYPE_N64 | 0x00040000) +#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD) +#define SI_GC_RECEIVER (SI_TYPE_GC | SI_GC_WIRELESS) +#define SI_GC_WAVEBIRD (SI_TYPE_GC | SI_GC_WIRELESS | SI_GC_STANDARD | SI_WIRELESS_STATE | SI_WIRELESS_FIX_ID) +#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000) +#define SI_GC_STEERING (SI_TYPE_GC | 0x00000000) + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef void (*SICallback)(s32,u32); +typedef void (*RDSTHandler)(u32,void*); + +u32 SI_Sync(); +u32 SI_Busy(); +u32 SI_IsChanBusy(s32 chan); +void SI_EnablePolling(u32 poll); +void SI_DisablePolling(u32 poll); +void SI_SetCommand(s32 chan,u32 cmd); +u32 SI_GetStatus(s32 chan); +u32 SI_GetResponse(s32 chan,void *buf); +u32 SI_GetResponseRaw(s32 chan); +void SI_RefreshSamplingRate(); +u32 SI_Transfer(s32 chan,void *out,u32 out_len,void *in,u32 in_len,SICallback cb,u32 us_delay); +u32 SI_GetTypeAsync(s32 chan,SICallback cb); +u32 SI_GetType(s32 chan); +u32 SI_GetCommand(s32 chan); +void SI_TransferCommands(); +u32 SI_RegisterPollingHandler(RDSTHandler handler); +u32 SI_UnregisterPollingHandler(RDSTHandler handler); +u32 SI_EnablePollingInterrupt(s32 enable); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/stm.h b/wii/libogc/include/ogc/stm.h new file mode 100644 index 0000000000..5d2307f4c5 --- /dev/null +++ b/wii/libogc/include/ogc/stm.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------- + +stm.h - System and miscellaneous hardware control functions + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __STM_H__ +#define __STM_H__ + +#if defined(HW_RVL) + +#include +#include + +#define STM_EVENT_RESET 0x00020000 +#define STM_EVENT_POWER 0x00000800 + +#define STM_EINVAL -0x2004 +#define STM_ENOTINIT -0x2100 +#define STM_ENOHANDLER -0x2101 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef void (*stmcallback)(u32 event); + +s32 __STM_Init(); +s32 __STM_Close(); +s32 STM_ShutdownToStandby(); +s32 STM_ShutdownToIdle(); +s32 STM_SetLedMode(u32 mode); +s32 STM_RebootSystem(); +stmcallback STM_RegisterEventHandler(stmcallback newhandler); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* defined(HW_RVL) */ + +#endif diff --git a/wii/libogc/include/ogc/sys_state.h b/wii/libogc/include/ogc/sys_state.h new file mode 100644 index 0000000000..b48837b2e2 --- /dev/null +++ b/wii/libogc/include/ogc/sys_state.h @@ -0,0 +1,27 @@ +#ifndef __SYS_STATE_H__ +#define __SYS_STATE_H__ + +#define SYS_STATE_BEFORE_INIT 0 +#define SYS_STATE_BEFORE_MT 1 +#define SYS_STATE_BEGIN_MT 2 +#define SYS_STATE_UP 3 +#define SYS_STATE_SHUTDOWN 4 +#define SYS_STATE_FAILED 5 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern u32 _sys_state_curr; + +#ifdef LIBOGC_INTERNAL +#include +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/ogc/system.h b/wii/libogc/include/ogc/system.h new file mode 100644 index 0000000000..b82e251438 --- /dev/null +++ b/wii/libogc/include/ogc/system.h @@ -0,0 +1,350 @@ +/*------------------------------------------------------------- + +system.h -- OS functions and initialization + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ + + +/*! \file system.h +\brief OS functions and initialization + +*/ + +#include +#include +#include +#include +#include "gx_struct.h" + +#define SYS_BASE_CACHED (0x80000000) +#define SYS_BASE_UNCACHED (0xC0000000) + +#define SYS_WD_NULL 0xffffffff + +/*! + * \addtogroup sys_resettypes OS reset types + * @{ + */ + +#define SYS_RESTART 0 /*!< Reboot the gamecube, force, if necessary, to boot the IPL menu. Cold reset is issued */ +#define SYS_HOTRESET 1 /*!< Restart the application. Kind of softreset */ +#define SYS_SHUTDOWN 2 /*!< Shutdown the thread system, card management system etc. Leave current thread running and return to caller */ + +#define SYS_RETURNTOMENU 3 /*!< Directly load the Wii Channels menu, without actually cold-resetting the system */ +#define SYS_POWEROFF 4 /*!< Powers off the Wii, automatically choosing Standby or Idle mode depending on the user's configuration */ +#define SYS_POWEROFF_STANDBY 5 /*!< Powers off the Wii to standby (red LED, WC24 off) mode. */ +#define SYS_POWEROFF_IDLE 6 /*!< Powers off the Wii to idle (yellow LED, WC24 on) mode. */ + +/*! + *@} + */ + + +/*! + * \addtogroup sys_mprotchans OS memory protection channels + * @{ + */ + +#define SYS_PROTECTCHAN0 0 /*!< OS memory protection channel 0 */ +#define SYS_PROTECTCHAN1 1 /*!< OS memory protection channel 1 */ +#define SYS_PROTECTCHAN2 2 /*!< OS memory protection channel 2 */ +#define SYS_PROTECTCHAN3 3 /*!< OS memory protection channel 2 */ +#define SYS_PROTECTCHANMAX 4 /*!< _Termination */ + +/*! + *@} + */ + + +/*! + * \addtogroup sys_mprotmodes OS memory protection modes + * @{ + */ + +#define SYS_PROTECTNONE 0x00000000 /*!< Read and write operations on protected region is granted */ +#define SYS_PROTECTREAD 0x00000001 /*!< Read from protected region is permitted */ +#define SYS_PROTECTWRITE 0x00000002 /*!< Write to protected region is permitted */ +#define SYS_PROTECTRDWR (SYS_PROTECTREAD|SYS_PROTECTWRITE) /*!< Read and write operations on protected region is permitted */ + +/*! + *@} + */ + +#define SYS_FONTSIZE_ANSI (288 + 131072) +#define SYS_FONTSIZE_SJIS (3840 + 1179648) + + + +/*! + * \addtogroup sys_mcastmacros OS memory casting macros + * @{ + */ + +#define MEM_VIRTUAL_TO_PHYSICAL(x) (((u32)(x)) & ~SYS_BASE_UNCACHED) /*!< Cast virtual address to physical address, e.g. 0x8xxxxxxx -> 0x0xxxxxxx */ +#define MEM_PHYSICAL_TO_K0(x) (void*)((u32)(x) + SYS_BASE_CACHED) /*!< Cast physical address to cached virtual address, e.g. 0x0xxxxxxx -> 0x8xxxxxxx */ +#define MEM_PHYSICAL_TO_K1(x) (void*)((u32)(x) + SYS_BASE_UNCACHED) /*!< Cast physical address to uncached virtual address, e.g. 0x0xxxxxxx -> 0xCxxxxxxx */ +#define MEM_K0_TO_PHYSICAL(x) (void*)((u32)(x) - SYS_BASE_CACHED) /*!< Cast physical address to cached virtual address, e.g. 0x0xxxxxxx -> 0x8xxxxxxx */ +#define MEM_K1_TO_PHYSICAL(x) (void*)((u32)(x) - SYS_BASE_UNCACHED) /*!< Cast physical address to uncached virtual address, e.g. 0x0xxxxxxx -> 0xCxxxxxxx */ +#define MEM_K0_TO_K1(x) (void*)((u32)(x) + (SYS_BASE_UNCACHED - SYS_BASE_CACHED)) /*!< Cast cached virtual address to uncached virtual address, e.g. 0x8xxxxxxx -> 0xCxxxxxxx */ +#define MEM_K1_TO_K0(x) (void*)((u32)(x) - (SYS_BASE_UNCACHED - SYS_BASE_CACHED)) /*!< Cast uncached virtual address to cached virtual address, e.g. 0xCxxxxxxx -> 0x8xxxxxxx */ + +/*! + *@} + */ + +#define SYS_GetArenaLo SYS_GetArena1Lo +#define SYS_SetArenaLo SYS_SetArena1Lo +#define SYS_GetArenaHi SYS_GetArena1Hi +#define SYS_SetArenaHi SYS_SetArena1Hi +#define SYS_GetArenaSize SYS_GetArena1Size + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! + * \typedef u32 syswd_t + * \brief handle typedef for the alarm context + */ +typedef u32 syswd_t; + + + /*! + * \typedef struct _syssram syssram + * \brief holds the stored configuration value from the system SRAM area + * \param checksum holds the block checksum. + * \param checksum_in holds the inverse block checksum + * \param ead0 unknown attribute + * \param ead1 unknown attribute + * \param counter_bias bias value for the realtime clock + * \param display_offsetH pixel offset for the VI + * \param ntd unknown attribute + * \param lang language of system + * \param flags device and operations flag + */ +typedef struct _syssram syssram; + +struct _syssram { + u16 checksum; + u16 checksum_inv; + u32 ead0; + u32 ead1; + u32 counter_bias; + s8 display_offsetH; + u8 ntd; + u8 lang; + u8 flags; +} ATTRIBUTE_PACKED; + + +/*! + * \typedef struct _syssramex syssramex + * \brief holds the stored configuration value from the extended SRAM area + * \param flash_id[2][12] 96bit memorycard unlock flash ID + * \param wirelessKbd_id Device ID of last connected wireless keyboard + * \param wirelessPad_id[4] 16bit device ID of last connected pad. + * \param dvderr_code last non-recoverable error from DVD interface + * \param __padding0 padding + * \param flashID_chksum[2] 16bit checksum of unlock flash ID + * \param __padding1[4] padding + */ +typedef struct _syssramex syssramex; + +struct _syssramex { + u8 flash_id[2][12]; + u32 wirelessKbd_id; + u16 wirelessPad_id[4]; + u8 dvderr_code; + u8 __padding0; + u16 flashID_chksum[2]; + u8 __padding1[4]; +} ATTRIBUTE_PACKED; + +typedef void (*alarmcallback)(syswd_t alarm,void *cb_arg); + +typedef struct _sys_fontheader sys_fontheader; + +struct _sys_fontheader { + u16 font_type; + u16 first_char; + u16 last_char; + u16 inval_char; + u16 asc; + u16 desc; + u16 width; + u16 leading; + u16 cell_width; + u16 cell_height; + u32 sheet_size; + u16 sheet_format; + u16 sheet_column; + u16 sheet_row; + u16 sheet_width; + u16 sheet_height; + u16 width_table; + u32 sheet_image; + u32 sheet_fullsize; + u8 c0; + u8 c1; + u8 c2; + u8 c3; +} ATTRIBUTE_PACKED; + +typedef void (*resetcallback)(void); +typedef void (*powercallback)(void); +typedef s32 (*resetfunction)(s32 final); +typedef struct _sys_resetinfo sys_resetinfo; + +struct _sys_resetinfo { + lwp_node node; + resetfunction func; + u32 prio; +}; + +/*! \fn void SYS_Init() +\deprecated Performs basic system initialization such as EXI init etc. This function is called from within the crt0 startup code. + +\return none +*/ +void SYS_Init(); + + +/*! + * \fn void* SYS_AllocateFramebuffer(GXRModeObj *rmode) + * \brief Allocate cacheline aligned memory for the external framebuffer based on the rendermode object. + * \param[in] rmode pointer to the video/render mode configuration + * + * \return pointer to the framebuffer's startaddress. NOTE: Address returned is aligned to a 32byte boundery! + */ +void* SYS_AllocateFramebuffer(GXRModeObj *rmode); + + +void SYS_ProtectRange(u32 chan,void *addr,u32 bytes,u32 cntrl); +void SYS_StartPMC(u32 mcr0val,u32 mcr1val); +void SYS_DumpPMC(); +void SYS_StopPMC(); + + +/*! \fn s32 SYS_CreateAlarm(syswd_t *thealarm) +\brief Create/initialize sysalarm structure +\param[in] thealarm pointer to the handle to store the created alarm context identifier + +\return 0 on succuess, non-zero on error +*/ +s32 SYS_CreateAlarm(syswd_t *thealarm); + + +/*! \fn s32 SYS_SetAlarm(syswd_t thealarm,const struct timespec *tp,alarmcallback cb) +\brief Set the alarm parameters for a one-shot alarm, add to the list of alarms and start. +\param[in] thealarm identifier to the alarm context to be initialize for a one-shot alarm +\param[in] tp pointer to timespec structure holding the time to fire the alarm +\param[in] cb pointer to callback which is called when the alarm fires. + +\return 0 on succuess, non-zero on error +*/ +s32 SYS_SetAlarm(syswd_t thealarm,const struct timespec *tp,alarmcallback cb,void *cbarg); + + +/*! \fn s32 SYS_SetPeriodicAlarm(syswd_t thealarm,const struct timespec *tp_start,const struct timespec *tp_period,alarmcallback cb) +\brief Set the alarm parameters for a periodioc alarm, add to the list of alarms and start. The alarm and interval persists as long as SYS_CancelAlarm() isn't called. +\param[in] thealarm identifier to the alarm context to be initialized for a periodic alarm +\param[in] tp_start pointer to timespec structure holding the time to fire first time the alarm +\param[in] tp_period pointer to timespec structure holding the interval for all following alarm triggers. +\param[in] cb pointer to callback which is called when the alarm fires. + +\return 0 on succuess, non-zero on error +*/ +s32 SYS_SetPeriodicAlarm(syswd_t thealarm,const struct timespec *tp_start,const struct timespec *tp_period,alarmcallback cb,void *cbarg); + + +/*! \fn s32 SYS_RemoveAlarm(syswd_t thealarm) +\brief Remove the given alarm context from the list of contexts and destroy it +\param[in] thealarm identifier to the alarm context to be removed and destroyed + +\return 0 on succuess, non-zero on error +*/ +s32 SYS_RemoveAlarm(syswd_t thealarm); + + +/*! \fn s32 SYS_CancelAlarm(syswd_t thealarm) +\brief Cancel the alarm, but do not remove from the list of contexts. +\param[in] thealarm identifier to the alram context to be canceled + +\return 0 on succuess, non-zero on error +*/ +s32 SYS_CancelAlarm(syswd_t thealarm); + + +void SYS_SetWirelessID(u32 chan,u32 id); +u32 SYS_GetWirelessID(u32 chan); +u32 SYS_GetFontEncoding(); +u32 SYS_InitFont(sys_fontheader *font_data); +void SYS_GetFontTexture(s32 c,void **image,s32 *xpos,s32 *ypos,s32 *width); +void SYS_GetFontTexel(s32 c,void *image,s32 pos,s32 stride,s32 *width); +void SYS_ResetSystem(s32 reset,u32 reset_code,s32 force_menu); +void SYS_RegisterResetFunc(sys_resetinfo *info); +void SYS_UnregisterResetFunc(sys_resetinfo *info); +void SYS_SwitchFiber(u32 arg0,u32 arg1,u32 arg2,u32 arg3,u32 pc,u32 newsp); + +void* SYS_GetArena1Lo(); +void SYS_SetArena1Lo(void *newLo); +void* SYS_GetArena1Hi(); +void SYS_SetArena1Hi(void *newHi); +u32 SYS_GetArena1Size(); + +resetcallback SYS_SetResetCallback(resetcallback cb); + +u32 SYS_ResetButtonDown(); + +#if defined(HW_RVL) +u32 SYS_GetHollywoodRevision(); +void* SYS_GetArena2Lo(); +void SYS_SetArena2Lo(void *newLo); +void* SYS_GetArena2Hi(); +void SYS_SetArena2Hi(void *newHi); +u32 SYS_GetArena2Size(); +powercallback SYS_SetPowerCallback(powercallback cb); +#endif + +/* \fn u64 SYS_Time() +\brief Returns the current time in ticks since 2000 (proper Dolphin/Wii time) +\return ticks since 2000 +*/ +u64 SYS_Time(); + +void kprintf(const char *str, ...); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/texconv.h b/wii/libogc/include/ogc/texconv.h new file mode 100644 index 0000000000..3a07ee0ca7 --- /dev/null +++ b/wii/libogc/include/ogc/texconv.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------- + +texconv.h -- GX texture helper functions + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __TEXCONV_H__ +#define __TEXTCONV_H__ + +/*! +\file texconv.h +\brief GX texture helper functions +*/ + +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +void MakeTexture565(const void *src,void *dst,s32 width,s32 height); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/tpl.h b/wii/libogc/include/ogc/tpl.h new file mode 100644 index 0000000000..740b7613ae --- /dev/null +++ b/wii/libogc/include/ogc/tpl.h @@ -0,0 +1,31 @@ +#ifndef __TPL_H__ +#define __TPL_H__ + +#include "gx.h" + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef void* FHANDLE; + +// tdf file +typedef struct _tplfile { + int type; + int ntextures; + void *texdesc; + FHANDLE tpl_file; +} TPLFile; + +s32 TPL_OpenTPLFromFile(TPLFile* tdf, const char* file_name); +s32 TPL_OpenTPLFromMemory(TPLFile* tdf, void *memory,u32 len); +s32 TPL_GetTexture(TPLFile *tdf,s32 id,GXTexObj *texObj); +s32 TPL_GetTextureCI(TPLFile *tdf,s32 id,GXTexObj *texObj,GXTlutObj *tlutObj,u8 tluts); +s32 TPL_GetTextureInfo(TPLFile *tdf,s32 id,u32 *fmt,u16 *width,u16 *height); +void TPL_CloseTPLFile(TPLFile *tdf); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/usb.h b/wii/libogc/include/ogc/usb.h new file mode 100644 index 0000000000..706b81139f --- /dev/null +++ b/wii/libogc/include/ogc/usb.h @@ -0,0 +1,239 @@ +#ifndef __USB_H__ +#define __USB_H__ + +#if defined(HW_RVL) + +#include +#include + +#define USB_MAXPATH IPC_MAXPATH_LEN + +#define USB_OK 0 +#define USB_FAILED 1 + +#define USB_CLASS_HID 0x03 +#define USB_SUBCLASS_BOOT 0x01 +#define USB_PROTOCOL_KEYBOARD 0x01 +#define USB_PROTOCOL_MOUSE 0x02 + +#define USB_REPTYPE_INPUT 0x01 +#define USB_REPTYPE_OUTPUT 0x02 +#define USB_REPTYPE_FEATURE 0x03 + +/* Descriptor types */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 +#define USB_DT_OTG 0x09 +#define USB_DT_DEBUG 0x10 +#define USB_DT_INTERFACE_ASSOCIATION 0x11 +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL 0x23 +#define USB_DT_CLASS_SPECIFIC_INTERFACE 0x24 +#define USB_DT_CLASS_SPECIFIC_ENDPOINT 0x25 +#define USB_DT_HUB 0x29 + +/* Standard requests */ +#define USB_REQ_GETSTATUS 0x00 +#define USB_REQ_CLEARFEATURE 0x01 +#define USB_REQ_SETFEATURE 0x03 +#define USB_REQ_SETADDRESS 0x05 +#define USB_REQ_GETDESCRIPTOR 0x06 +#define USB_REQ_SETDESCRIPTOR 0x07 +#define USB_REQ_GETCONFIG 0x08 +#define USB_REQ_SETCONFIG 0x09 +#define USB_REQ_GETINTERFACE 0x0A +#define USB_REQ_SETINTERFACE 0x0B +#define USB_REQ_SYNCFRAME 0x0C + +#define USB_REQ_GETREPORT 0x01 +#define USB_REQ_GETIDLE 0x02 +#define USB_REQ_GETPROTOCOL 0x03 +#define USB_REQ_SETREPORT 0x09 +#define USB_REQ_SETIDLE 0x0A +#define USB_REQ_SETPROTOCOL 0x0B + +/* Descriptor sizes per descriptor type */ +#define USB_DT_DEVICE_SIZE 18 +#define USB_DT_CONFIG_SIZE 9 +#define USB_DT_INTERFACE_SIZE 9 +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ +#define USB_DT_HID_SIZE 9 +#define USB_DT_HUB_NONVAR_SIZE 7 + +/* control message request type bitmask */ +#define USB_CTRLTYPE_DIR_HOST2DEVICE (0<<7) +#define USB_CTRLTYPE_DIR_DEVICE2HOST (1<<7) +#define USB_CTRLTYPE_TYPE_STANDARD (0<<5) +#define USB_CTRLTYPE_TYPE_CLASS (1<<5) +#define USB_CTRLTYPE_TYPE_VENDOR (2<<5) +#define USB_CTRLTYPE_TYPE_RESERVED (3<<5) +#define USB_CTRLTYPE_REC_DEVICE 0 +#define USB_CTRLTYPE_REC_INTERFACE 1 +#define USB_CTRLTYPE_REC_ENDPOINT 2 +#define USB_CTRLTYPE_REC_OTHER 3 + +#define USB_REQTYPE_INTERFACE_GET (USB_CTRLTYPE_DIR_DEVICE2HOST|USB_CTRLTYPE_TYPE_CLASS|USB_CTRLTYPE_REC_INTERFACE) +#define USB_REQTYPE_INTERFACE_SET (USB_CTRLTYPE_DIR_HOST2DEVICE|USB_CTRLTYPE_TYPE_CLASS|USB_CTRLTYPE_REC_INTERFACE) +#define USB_REQTYPE_ENDPOINT_GET (USB_CTRLTYPE_DIR_DEVICE2HOST|USB_CTRLTYPE_TYPE_CLASS|USB_CTRLTYPE_REC_ENDPOINT) +#define USB_REQTYPE_ENDPOINT_SET (USB_CTRLTYPE_DIR_HOST2DEVICE|USB_CTRLTYPE_TYPE_CLASS|USB_CTRLTYPE_REC_ENDPOINT) + +#define USB_FEATURE_ENDPOINT_HALT 0 + +#define USB_ENDPOINT_INTERRUPT 0x03 +#define USB_ENDPOINT_IN 0x80 +#define USB_ENDPOINT_OUT 0x00 + +#define USB_OH0_DEVICE_ID 0x00000000 // for completion +#define USB_OH1_DEVICE_ID 0x00200000 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct _usbendpointdesc +{ + u8 bLength; + u8 bDescriptorType; + u8 bEndpointAddress; + u8 bmAttributes; + u16 wMaxPacketSize; + u8 bInterval; +} ATTRIBUTE_PACKED usb_endpointdesc; + +typedef struct _usbinterfacedesc +{ + u8 bLength; + u8 bDescriptorType; + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; + u8 *extra; + u16 extra_size; + struct _usbendpointdesc *endpoints; +} ATTRIBUTE_PACKED usb_interfacedesc; + +typedef struct _usbconfdesc +{ + u8 bLength; + u8 bDescriptorType; + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; + u8 iConfiguration; + u8 bmAttributes; + u8 bMaxPower; + struct _usbinterfacedesc *interfaces; +} ATTRIBUTE_PACKED usb_configurationdesc; + +typedef struct _usbdevdesc +{ + u8 bLength; + u8 bDescriptorType; + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize0; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; + struct _usbconfdesc *configurations; +} ATTRIBUTE_PACKED usb_devdesc; + +typedef struct _usbhiddesc +{ + u8 bLength; + u8 bDescriptorType; + u16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + struct { + u8 bDescriptorType; + u16 wDescriptorLength; + } ATTRIBUTE_PACKED descr[1]; +} ATTRIBUTE_PACKED usb_hiddesc; + +typedef struct _usb_device_entry { + s32 device_id; + u16 vid; + u16 pid; + u32 token; +} usb_device_entry; + +typedef s32 (*usbcallback)(s32 result,void *usrdata); + +s32 USB_Initialize(); +s32 USB_Deinitialize(); + +s32 USB_OpenDevice(s32 device_id,u16 vid,u16 pid,s32 *fd); +s32 USB_CloseDevice(s32 *fd); +s32 USB_CloseDeviceAsync(s32 *fd,usbcallback cb,void *usrdata); + +s32 USB_GetDescriptors(s32 fd, usb_devdesc *udd); +void USB_FreeDescriptors(usb_devdesc *udd); + +s32 USB_GetGenericDescriptor(s32 fd,u8 type,u8 index,u8 interface,void *data,u32 size); +s32 USB_GetHIDDescriptor(s32 fd,u8 interface,usb_hiddesc *uhd,u32 size); + +s32 USB_GetDeviceDescription(s32 fd,usb_devdesc *devdesc); +s32 USB_DeviceRemovalNotifyAsync(s32 fd,usbcallback cb,void *userdata); +s32 USB_DeviceChangeNotifyAsync(u8 interface_class,usbcallback cb,void *userdata); + +s32 USB_SuspendDevice(s32 fd); +s32 USB_ResumeDevice(s32 fd); + +s32 USB_ReadIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData); +s32 USB_ReadIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata); + +s32 USB_ReadIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData); +s32 USB_ReadIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *usrdata); + +s32 USB_ReadBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData); +s32 USB_ReadBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *usrdata); + +s32 USB_ReadCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData); +s32 USB_ReadCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *usrdata); + +s32 USB_WriteIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData); +s32 USB_WriteIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata); + +s32 USB_WriteIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData); +s32 USB_WriteIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *usrdata); + +s32 USB_WriteBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData); +s32 USB_WriteBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *usrdata); + +s32 USB_WriteCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData); +s32 USB_WriteCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *usrdata); + +s32 USB_GetConfiguration(s32 fd, u8 *configuration); +s32 USB_SetConfiguration(s32 fd, u8 configuration); +s32 USB_SetAlternativeInterface(s32 fd, u8 interface, u8 alternateSetting); +s32 USB_ClearHalt(s32 fd, u8 endpointAddress); +s32 USB_GetDeviceList(usb_device_entry *descr_buffer,u8 num_descr,u8 interface_class,u8 *cnt_descr); + +s32 USB_GetAsciiString(s32 fd,u8 bIndex,u16 wLangID,u16 wLength,void *rpData); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* defined(HW_RVL) */ + +#endif diff --git a/wii/libogc/include/ogc/usbgecko.h b/wii/libogc/include/ogc/usbgecko.h new file mode 100644 index 0000000000..dbbbbe928c --- /dev/null +++ b/wii/libogc/include/ogc/usbgecko.h @@ -0,0 +1,28 @@ +#ifndef __USBGECKO_H___ +#define __USBGECKO_H___ + +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +void usb_flush(s32 chn); +int usb_isgeckoalive(s32 chn); +int usb_recvbuffer(s32 chn,void *buffer,int size); +int usb_sendbuffer(s32 chn,const void *buffer,int size); +int usb_recvbuffer_safe(s32 chn,void *buffer,int size); +int usb_sendbuffer_safe(s32 chn,const void *buffer,int size); +int usb_recvbuffer_ex(s32 chn,void *buffer,int size, int retries); +int usb_sendbuffer_ex(s32 chn,const void *buffer,int size, int retries); +int usb_recvbuffer_safe_ex(s32 chn,void *buffer,int size, int retries); +int usb_sendbuffer_safe_ex(s32 chn,const void *buffer,int size, int retries); +int usb_flashread(s32 chn, u32 offset, void *buffer, size_t length); +int usb_flashwrite(s32 chn, u32 offset, const void *buffer, size_t length); +int usb_flashverify(s32 chn); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/usbmouse.h b/wii/libogc/include/ogc/usbmouse.h new file mode 100644 index 0000000000..28b8581120 --- /dev/null +++ b/wii/libogc/include/ogc/usbmouse.h @@ -0,0 +1,30 @@ +#ifndef __USBMOUSE_H__ +#define __USBMOUSE_H__ + +#if defined(HW_RVL) + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct { + u8 button; + int rx; + int ry; + int rz; +} mouse_event; + +s32 MOUSE_Init(void); +s32 MOUSE_Deinit(void); + +s32 MOUSE_GetEvent(mouse_event *event); +s32 MOUSE_FlushEvents(void); +bool MOUSE_IsConnected(void); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif + +#endif diff --git a/wii/libogc/include/ogc/usbstorage.h b/wii/libogc/include/ogc/usbstorage.h new file mode 100644 index 0000000000..04efa5fbed --- /dev/null +++ b/wii/libogc/include/ogc/usbstorage.h @@ -0,0 +1,92 @@ +#ifndef __USBSTORAGE_H__ +#define __USBSTORAGE_H__ + +#if defined(HW_RVL) + +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +#define USBSTORAGE_OK 0 +#define USBSTORAGE_ENOINTERFACE -10000 +#define USBSTORAGE_ESENSE -10001 +#define USBSTORAGE_ESHORTWRITE -10002 +#define USBSTORAGE_ESHORTREAD -10003 +#define USBSTORAGE_ESIGNATURE -10004 +#define USBSTORAGE_ETAG -10005 +#define USBSTORAGE_ESTATUS -10006 +#define USBSTORAGE_EDATARESIDUE -10007 +#define USBSTORAGE_ETIMEDOUT -10008 +#define USBSTORAGE_EINIT -10009 +#define USBSTORAGE_PROCESSING -10010 + +typedef struct +{ + u8 configuration; + u32 interface; + u32 altInterface; + u8 bInterfaceSubClass; + + u8 ep_in; + u8 ep_out; + + u8 max_lun; + u32 *sector_size; + + s32 usb_fd; + + mutex_t lock; + syswd_t alarm; + s32 retval; + + u32 tag; + u8 suspended; + + u8 *buffer; +} usbstorage_handle; + +#define B_RAW_DEVICE_DATA_IN 0x01 +#define B_RAW_DEVICE_COMMAND 0 + +typedef struct { + uint8_t command[16]; + uint8_t command_length; + uint8_t flags; + uint8_t scsi_status; + void* data; + size_t data_length; +} raw_device_command; + +s32 USBStorage_Initialize(); + +s32 USBStorage_Open(usbstorage_handle *dev, s32 device_id, u16 vid, u16 pid); +s32 USBStorage_Close(usbstorage_handle *dev); +s32 USBStorage_Reset(usbstorage_handle *dev); + +s32 USBStorage_GetMaxLUN(usbstorage_handle *dev); +s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun); +s32 USBStorage_Suspend(usbstorage_handle *dev); +s32 USBStorage_IsDVD(); +s32 USBStorage_ioctl(int request, ...); + +s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors); +s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer); +s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer); +s32 USBStorage_StartStop(usbstorage_handle *dev, u8 lun, u8 lo_ej, u8 start, u8 imm); + +#define DEVICE_TYPE_WII_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B') + +extern DISC_INTERFACE __io_usbstorage; + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* HW_RVL */ + +#endif /* __USBSTORAGE_H__ */ diff --git a/wii/libogc/include/ogc/video.h b/wii/libogc/include/ogc/video.h new file mode 100644 index 0000000000..4e01bdc2f8 --- /dev/null +++ b/wii/libogc/include/ogc/video.h @@ -0,0 +1,206 @@ +/*------------------------------------------------------------- + +video.h -- VIDEO subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __VIDEO_H__ +#define __VIDEO_H__ + +/*! + * \file video.h + * \brief VIDEO subsystem + * + */ + +#include +#include "gx_struct.h" +#include "video_types.h" + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + +/*! + * \typedef void (*VIRetraceCallback)(u32 retraceCnt) + * \brief function pointer typedef for the user's retrace callback + * \param[in] retraceCnt current retrace count + */ +typedef void (*VIRetraceCallback)(u32 retraceCnt); + +typedef void (*VIPositionCallback)(u32 posX,u32 posY); + +void* VIDEO_GetNextFramebuffer(); +void* VIDEO_GetCurrentFramebuffer(); + + +/*! + * \fn void VIDEO_Init() + * \brief Initializes the VIDEO subsystem. This call should be done in the early stages of your main() + * + * \return none + */ +void VIDEO_Init(); + + +/*! + * \fn void VIDEO_Flush() + * \brief Flush the shadow registers to the drivers video registers. + * + * \return none + */ +void VIDEO_Flush(); + + +/*! + * \fn void VIDEO_SetBlack(bool black) + * \brief Blackout the VIDEO interface. + * + * \param[in] black Boolean flag to determine whether to blackout the VI or not. + * + * \return none + */ +void VIDEO_SetBlack(bool black); + + +/*! + * \fn u32 VIDEO_GetNextField() + * \brief Get the next field in DS mode. + * + * \return \ref vi_fielddef "field" + */ +u32 VIDEO_GetNextField(); + + +/*! + * \fn u32 VIDEO_GetCurrentLine() + * \brief Get current video line + * + * \return linenumber + */ +u32 VIDEO_GetCurrentLine(); + + +/*! + * \fn u32 VIDEO_GetCurrentTvMode() + * \brief Get current configured TV mode + * + * \return \ref vi_standardtypedef "tvmode" + */ +u32 VIDEO_GetCurrentTvMode(); + + +/*! + * \fn void VIDEO_Configure(GXRModeObj *rmode) + * \brief Configure the VI with the given render mode object + * + * \param[in] rmode pointer to the video/render mode \ref gxrmode_obj "configuration". + * + * \return none + */ +void VIDEO_Configure(GXRModeObj *rmode); + +u32 VIDEO_GetFrameBufferSize(GXRModeObj *rmode); + +/*! + * \fn void VIDEO_ClearFrameBuffer(GXRModeObj *rmode,void *fb,u32 color) + * \brief Clear the given framebuffer. + * + * \param[in] rmode pointer to a GXRModeObj, specifying the mode. + * \param[in] fb pointer to the startaddress of the framebuffer to clear. + * \param[in] color YUYUV value to use for clearing. + * + * \return none + */ +void VIDEO_ClearFrameBuffer(GXRModeObj *rmode,void *fb,u32 color); + + +/*! + * \fn void VIDEO_WaitVSync(void) + * \brief Wait on the next vertical retrace + * + * \return none + */ +void VIDEO_WaitVSync(void); + + +/*! + * \fn void VIDEO_SetNextFramebuffer(void *fb) + * \brief Set the framebuffer for the next VI register update. + * + * \return none + */ +void VIDEO_SetNextFramebuffer(void *fb); + + +/*! + * \fn void VIDEO_SetNextRightFramebuffer(void *fb) + * \brief Set the right framebuffer for the next VI register update. This is used for 3D Gloves for instance. + * + * \return none + */ +void VIDEO_SetNextRightFramebuffer(void *fb); + + +/*! + * \fn VIRetraceCallback VIDEO_SetPreRetraceCallback(VIRetraceCallback callback) + * \brief Set the Pre-Retrace callback function. This function is called within the video interrupt handler before the VI registers will be updated. + * + * \param[in] callback pointer to the callback function which is called at pre-retrace. + * + * \return Old pre-retrace callback or NULL + */ +VIRetraceCallback VIDEO_SetPreRetraceCallback(VIRetraceCallback callback); + + +/*! + * \fn VIRetraceCallback VIDEO_SetPostRetraceCallback(VIRetraceCallback callback) + * \brief Set the Post-Retrace callback function. This function is called within the video interrupt handler after the VI registers are updated. + * + * \param[in] callback pointer to the callback function which is called at post-retrace. + * + * \return Old post-retrace callback or NULL + */ +VIRetraceCallback VIDEO_SetPostRetraceCallback(VIRetraceCallback callback); + + +/*! + * \fn u32 VIDEO_HaveComponentCable(void) + * \brief Check for a component cable. This function returns 1 when a Component (YPbPr) cable is connected. + * + * \return 1 if a component cable is connected, 0 otherwise + */ +u32 VIDEO_HaveComponentCable(void); + +GXRModeObj * VIDEO_GetPreferredMode(GXRModeObj *mode); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/ogc/video_types.h b/wii/libogc/include/ogc/video_types.h new file mode 100644 index 0000000000..9a03873d82 --- /dev/null +++ b/wii/libogc/include/ogc/video_types.h @@ -0,0 +1,195 @@ +/*------------------------------------------------------------- + +video_types.h -- support header + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#ifndef __VIDEO_TYPES_H__ +#define __VIDEO_TYPES_H__ + +/*! +\file video_types.h +\brief support header +*/ + +#include + +/*! + * \addtogroup vi_defines List of defines used for the VIDEO subsystem + * @{ + */ + + +#define VI_DISPLAY_PIX_SZ 2 /*!< multiplier to get real pixel size in bytes */ + +/*! + * \addtogroup vi_modetypedef VIDEO mode types + * @{ + */ + +#define VI_INTERLACE 0 /*!< Video mode INTERLACED. */ +#define VI_NON_INTERLACE 1 /*!< Video mode NON INTERLACED */ +#define VI_PROGRESSIVE 2 /*!< Video mode PROGRESSIVE. Special mode for higher quality */ + +/*! + * @} + */ + + +/*! + * \addtogroup vi_standardtypedef VIDEO standard types + * @{ + */ + +#define VI_NTSC 0 /*!< Video standard used in North America and Japan */ +#define VI_PAL 1 /*!< Video standard used in Europe */ +#define VI_MPAL 2 /*!< Video standard, similar to NTSC, used in Brazil */ +#define VI_DEBUG 3 /*!< Video standard, for debugging purpose, used in North America and Japan. Special decoder needed */ +#define VI_DEBUG_PAL 4 /*!< Video standard, for debugging purpose, used in Europe. Special decoder needed */ +#define VI_EURGB60 5 /*!< RGB 60Hz, 480 lines mode (same timing and aspect ratio as NTSC) used in Europe */ + +/*! + * @} + */ + + +#define VI_XFBMODE_SF 0 +#define VI_XFBMODE_DF 1 + + +/*! + * \addtogroup vi_fielddef VIDEO field types + * @{ + */ + +#define VI_FIELD_ABOVE 1 /*!< Upper field in DS mode */ +#define VI_FIELD_BELOW 0 /*!< Lower field in DS mode */ + +/*! + * @} + */ + + +// Maximum screen space +#define VI_MAX_WIDTH_NTSC 720 +#define VI_MAX_HEIGHT_NTSC 480 + +#define VI_MAX_WIDTH_PAL 720 +#define VI_MAX_HEIGHT_PAL 576 + +#define VI_MAX_WIDTH_MPAL 720 +#define VI_MAX_HEIGHT_MPAL 480 + +#define VI_MAX_WIDTH_EURGB60 VI_MAX_WIDTH_NTSC +#define VI_MAX_HEIGHT_EURGB60 VI_MAX_HEIGHT_NTSC + +#define VIDEO_PadFramebufferWidth(width) ((u16)(((u16)(width) + 15) & ~15)) /*!< macro to pad the width to a multiple of 16 */ + +/*! + * @} + */ + + +#define VI_TVMODE(fmt, mode) ( ((fmt) << 2) + (mode) ) + +#define VI_TVMODE_NTSC_INT VI_TVMODE(VI_NTSC, VI_INTERLACE) +#define VI_TVMODE_NTSC_DS VI_TVMODE(VI_NTSC, VI_NON_INTERLACE) +#define VI_TVMODE_NTSC_PROG VI_TVMODE(VI_NTSC, VI_PROGRESSIVE) + +#define VI_TVMODE_PAL_INT VI_TVMODE(VI_PAL, VI_INTERLACE) +#define VI_TVMODE_PAL_DS VI_TVMODE(VI_PAL, VI_NON_INTERLACE) +#define VI_TVMODE_PAL_PROG VI_TVMODE(VI_PAL, VI_PROGRESSIVE) + +#define VI_TVMODE_EURGB60_INT VI_TVMODE(VI_EURGB60, VI_INTERLACE) +#define VI_TVMODE_EURGB60_DS VI_TVMODE(VI_EURGB60, VI_NON_INTERLACE) +#define VI_TVMODE_EURGB60_PROG VI_TVMODE(VI_EURGB60, VI_PROGRESSIVE) + +#define VI_TVMODE_MPAL_INT VI_TVMODE(VI_MPAL, VI_INTERLACE) +#define VI_TVMODE_MPAL_DS VI_TVMODE(VI_MPAL, VI_NON_INTERLACE) +#define VI_TVMODE_MPAL_PROG VI_TVMODE(VI_MPAL, VI_PROGRESSIVE) + +#define VI_TVMODE_DEBUG_INT VI_TVMODE(VI_DEBUG, VI_INTERLACE) + +#define VI_TVMODE_DEBUG_PAL_INT VI_TVMODE(VI_DEBUG_PAL, VI_INTERLACE) +#define VI_TVMODE_DEBUG_PAL_DS VI_TVMODE(VI_DEBUG_PAL, VI_NON_INTERLACE) + + +/*! + * \addtogroup vi_defines List of defines used for the VIDEO subsystem + * @{ + */ + + +/*! + * \addtogroup gxrmode_obj VIDEO render modes + * @{ + */ + +extern GXRModeObj TVNtsc240Ds; /*!< Video and render mode configuration for 240 lines,singlefield NTSC mode */ +extern GXRModeObj TVNtsc240DsAa; /*!< Video and render mode configuration for 240 lines,singlefield,antialiased NTSC mode */ +extern GXRModeObj TVNtsc240Int; /*!< Video and render mode configuration for 240 lines,interlaced NTSC mode */ +extern GXRModeObj TVNtsc240IntAa; /*!< Video and render mode configuration for 240 lines,interlaced,antialiased NTSC mode */ +extern GXRModeObj TVNtsc480Int; /*!< Video and render mode configuration for 480 lines,interlaced NTSC mode */ +extern GXRModeObj TVNtsc480IntDf; /*!< Video and render mode configuration for 480 lines,interlaced,doublefield NTSC mode */ +extern GXRModeObj TVNtsc480IntAa; /*!< Video and render mode configuration for 480 lines,interlaced,doublefield,antialiased NTSC mode */ +extern GXRModeObj TVNtsc480Prog; /*!< Video and render mode configuration for 480 lines,progressive,singlefield NTSC mode */ +extern GXRModeObj TVNtsc480ProgSoft; +extern GXRModeObj TVNtsc480ProgAa; +extern GXRModeObj TVMpal240Ds; +extern GXRModeObj TVMpal240DsAa; +extern GXRModeObj TVMpal480IntDf; /*!< Video and render mode configuration for 480 lines,interlaced,doublefield,antialiased MPAL mode */ +extern GXRModeObj TVMpal480IntAa; +extern GXRModeObj TVMpal480Prog; +extern GXRModeObj TVPal264Ds; /*!< Video and render mode configuration for 264 lines,singlefield PAL mode */ +extern GXRModeObj TVPal264DsAa; /*!< Video and render mode configuration for 264 lines,singlefield,antialiased PAL mode */ +extern GXRModeObj TVPal264Int; /*!< Video and render mode configuration for 264 lines,interlaced PAL mode */ +extern GXRModeObj TVPal264IntAa; /*!< Video and render mode configuration for 264 lines,interlaced,antialiased PAL mode */ +extern GXRModeObj TVPal524IntAa; /*!< Video and render mode configuration for 524 lines,interlaced,antialiased PAL mode */ +extern GXRModeObj TVPal528Int; /*!< Video and render mode configuration for 528 lines,interlaced,antialiased PAL mode */ +extern GXRModeObj TVPal528IntDf; /*!< Video and render mode configuration for 264 lines,interlaced,doublefield antialiased PAL mode */ +extern GXRModeObj TVPal576IntDfScale; +extern GXRModeObj TVPal576ProgScale; +extern GXRModeObj TVEurgb60Hz240Ds; +extern GXRModeObj TVEurgb60Hz240DsAa; +extern GXRModeObj TVEurgb60Hz240Int; +extern GXRModeObj TVEurgb60Hz240IntAa; +extern GXRModeObj TVEurgb60Hz480Int; +extern GXRModeObj TVEurgb60Hz480IntDf; +extern GXRModeObj TVEurgb60Hz480IntAa; +extern GXRModeObj TVEurgb60Hz480Prog; +extern GXRModeObj TVEurgb60Hz480ProgSoft; +extern GXRModeObj TVEurgb60Hz480ProgAa; + +/*! + * @} + */ + +/*! + * @} + */ + +#endif diff --git a/wii/libogc/include/ogc/wiilaunch.h b/wii/libogc/include/ogc/wiilaunch.h new file mode 100644 index 0000000000..18475465c0 --- /dev/null +++ b/wii/libogc/include/ogc/wiilaunch.h @@ -0,0 +1,79 @@ +/*------------------------------------------------------------- + +wiilaunch.h -- Wii NAND title launching and argument passing + +Copyright (C) 2008 +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#ifndef __WIILAUNCH_H__ +#define __WIILAUNCH_H__ + +#include +#include + +// not initialized +#define WII_ENOTINIT -0x9001 +// internal error +#define WII_EINTERNAL -0x9002 +// checksum error +#define WII_ECHECKSUM -0x9003 +// required title not installed +#define WII_EINSTALL -0x9004 +// argument list too big +#define WII_E2BIG -0x9005 + +// you probably shouldn't use anything not in this list, since those may change +// these are guaranteed to exist because Nintendo hardcodes them +// any category not on this list will cause a hang when the settings menu tries to do the animation +// however, settings items contained in one of the following categories will work +// nonexistent items will cause a 404 +#define SETTINGS_CALENDAR "Calendar/Calendar_index.html" +#define SETTINGS_DISPLAY "Display/Display_index.html" +#define SETTINGS_SOUND "Sound/Sound_index.html" +#define SETTINGS_PARENTAL "Parental_Control/Parental_Control_index.html" +#define SETTINGS_INTERNET "Internet/Internet_index.html" +#define SETTINGS_WC24 "WiiConnect24/Wiiconnect24_index.html" +#define SETTINGS_UPDATE "Update/Update_index.html" + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +s32 WII_Initialize(void); +s32 WII_ReturnToMenu(void); +s32 WII_ReturnToSettings(void); +s32 WII_ReturnToSettingsPage(const char *page); +s32 WII_LaunchTitle(u64 titleID); +s32 WII_LaunchTitleWithArgs(u64 titleID, int launchcode, ...); +s32 WII_OpenURL(const char *url); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif + +#endif diff --git a/wii/libogc/include/ogcsys.h b/wii/libogc/include/ogcsys.h new file mode 100644 index 0000000000..3c52eccd90 --- /dev/null +++ b/wii/libogc/include/ogcsys.h @@ -0,0 +1,41 @@ +#ifndef __OGCSYS_H__ +#define __OGCSYS_H__ + +#include +#include + +#if defined(HW_RVL) + #define TB_BUS_CLOCK 243000000u + #define TB_CORE_CLOCK 729000000u +#elif defined(HW_DOL) + #define TB_BUS_CLOCK 162000000u + #define TB_CORE_CLOCK 486000000u +#endif +#define TB_TIMER_CLOCK (TB_BUS_CLOCK/4000) //4th of the bus frequency + +#define TB_MSPERSEC 1000 +#define TB_USPERSEC 1000000 +#define TB_NSPERSEC 1000000000 +#define TB_NSPERMS 1000000 +#define TB_NSPERUS 1000 +#define TB_USPERTICK 10000 + +#define TB_SECSPERMIN 60 +#define TB_MINSPERHR 60 +#define TB_MONSPERYR 12 +#define TB_DAYSPERYR 365 +#define TB_HRSPERDAY 24 +#define TB_SECSPERDAY (TB_SECSPERMIN*TB_MINSPERHR*TB_HRSPERDAY) +#define TB_SECSPERNYR (365*TB_SECSPERDAY) + +#ifdef __cplusplus + extern "C" { +#endif + +int nanosleep(struct timespec *tb); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/samplerate.h b/wii/libogc/include/samplerate.h new file mode 100644 index 0000000000..9232dc29da --- /dev/null +++ b/wii/libogc/include/samplerate.h @@ -0,0 +1,196 @@ +/* +** Copyright (C) 2002-2004 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** API documentation is available here: +** http://www.mega-nerd.com/SRC/api.html +*/ + +#ifndef SAMPLERATE_H +#define SAMPLERATE_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Opaque data type SRC_STATE. */ +typedef struct SRC_STATE_tag SRC_STATE ; + +/* SRC_DATA is used to pass data to src_simple() and src_process(). */ +typedef struct +{ float *data_in, *data_out ; + + long input_frames, output_frames ; + long input_frames_used, output_frames_gen ; + + int end_of_input ; + + double src_ratio ; +} SRC_DATA ; + +/* SRC_CB_DATA is used with callback based API. */ +typedef struct +{ long frames ; + float *data_in ; +} SRC_CB_DATA ; + +/* +** User supplied callback function type for use with src_callback_new() +** and src_callback_read(). First parameter is the same pointer that was +** passed into src_callback_new(). Second parameter is pointer to a +** pointer. The user supplied callback function must modify *data to +** point to the start of the user supplied float array. The user supplied +** function must return the number of frames that **data points to. +*/ + +typedef long (*src_callback_t) (void *cb_data, float **data) ; + +/* +** Standard initialisation function : return an anonymous pointer to the +** internal state of the converter. Choose a converter from the enums below. +** Error returned in *error. +*/ + +SRC_STATE* src_new (int converter_type, int channels, int *error) ; + +/* +** Initilisation for callback based API : return an anonymous pointer to the +** internal state of the converter. Choose a converter from the enums below. +** The cb_data pointer can point to any data or be set to NULL. Whatever the +** value, when processing, user supplied function "func" gets called with +** cb_data as first parameter. +*/ + +SRC_STATE* src_callback_new (src_callback_t func, int converter_type, int channels, + int *error, void* cb_data) ; + +/* +** Cleanup all internal allocations. +** Always returns NULL. +*/ + +SRC_STATE* src_delete (SRC_STATE *state) ; + +/* +** Standard processing function. +** Returns non zero on error. +*/ + +int src_process (SRC_STATE *state, SRC_DATA *data) ; + +/* +** Callback based processing function. Read up to frames worth of data from +** the converter int *data and return frames read or -1 on error. +*/ +long src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data) ; + +/* +** Simple interface for performing a single conversion from input buffer to +** output buffer at a fixed conversion ratio. +** Simple interface does not require initialisation as it can only operate on +** a single buffer worth of audio. +*/ + +int src_simple (SRC_DATA *data, int converter_type, int channels) ; + +/* +** This library contains a number of different sample rate converters, +** numbered 0 through N. +** +** Return a string giving either a name or a more full description of each +** sample rate converter or NULL if no sample rate converter exists for +** the given value. The converters are sequentially numbered from 0 to N. +*/ + +const char *src_get_name (int converter_type) ; +const char *src_get_description (int converter_type) ; +const char *src_get_version (void) ; + +/* +** Set a new SRC ratio. This allows step responses +** in the conversion ratio. +** Returns non zero on error. +*/ + +int src_set_ratio (SRC_STATE *state, double new_ratio) ; + +/* +** Reset the internal SRC state. +** Does not modify the quality settings. +** Does not free any memory allocations. +** Returns non zero on error. +*/ + +int src_reset (SRC_STATE *state) ; + +/* +** Return TRUE if ratio is a valid conversion ratio, FALSE +** otherwise. +*/ + +int src_is_valid_ratio (double ratio) ; + +/* +** Return an error number. +*/ + +int src_error (SRC_STATE *state) ; + +/* +** Convert the error number into a string. +*/ +const char* src_strerror (int error) ; + +/* +** The following enums can be used to set the interpolator type +** using the function src_set_converter(). +*/ + +enum +{ + SRC_SINC_BEST_QUALITY = 0, + SRC_SINC_MEDIUM_QUALITY = 1, + SRC_SINC_FASTEST = 2, + SRC_ZERO_ORDER_HOLD = 3, + SRC_LINEAR = 4 +} ; + +/* +** Extra helper functions for converting from short to float and +** back again. +*/ + +void src_short_to_float_array (const short *in, float *out, int len) ; +void src_float_to_short_array (const float *in, short *out, int len) ; + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* SAMPLERATE_H */ + +/* +** Do not edit or modify anything in this comment block. +** The arch-tag line is a file identity tag for the GNU Arch +** revision control system. +** +** arch-tag: 5421ef3e-c898-4ec3-8671-ea03d943ee00 +*/ + diff --git a/wii/libogc/include/sdcard/card_buf.h b/wii/libogc/include/sdcard/card_buf.h new file mode 100644 index 0000000000..376358231f --- /dev/null +++ b/wii/libogc/include/sdcard/card_buf.h @@ -0,0 +1,18 @@ +#ifndef __CARD_BUF_H__ +#define __CARD_BUF_H__ + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +void sdgecko_initBufferPool(); +u8* sdgecko_allocBuffer(); +void sdgecko_freeBuffer(u8 *buf); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/sdcard/card_cmn.h b/wii/libogc/include/sdcard/card_cmn.h new file mode 100644 index 0000000000..bc189ee041 --- /dev/null +++ b/wii/libogc/include/sdcard/card_cmn.h @@ -0,0 +1,65 @@ +#ifndef __CARD_CMN_H__ +#define __CARD_CMN_H__ + +#include + +#define CARDIO_ERROR_READY 0 +#define CARDIO_ERROR_BUSY -1 +#define CARDIO_ERROR_WRONGDEVICE -2 +#define CARDIO_ERROR_NOCARD -3 +#define CARDIO_ERROR_IDLE -4 +#define CARDIO_ERROR_IOERROR -5 +#define CARDIO_ERROR_IOTIMEOUT -6 + +#define CARDIO_ERROR_NOTPERMITTED -107 +#define CARDIO_ERROR_ROOTENTRY -108 +#define CARDIO_ERROR_OUTOFROOTENTRY -109 +#define CARDIO_ERROR_FILEEXIST -110 +#define CARDIO_ERROR_NOEMPTYCLUSTER -111 +#define CARDIO_ERROR_EOF -112 +#define CARDIO_ERROR_SYSTEMPARAM -113 +#define CARDIO_ERROR_FILEOPENED -114 +#define CARDIO_ERROR_FILENOTOPENED -115 +#define CARDIO_ERROR_FILENAMETOOLONG -116 +#define CARDIO_ERROR_INVALIDNAME -117 +#define CARDIO_ERROR_NOLONGNAME -118 +#define CARDIO_ERROR_INCORRECTFAT -119 +#define CARDIO_ERROR_NOTFOUND -120 +#define CARDIO_ERROR_OUTOFMEMORY -121 +#define CARDIO_ERROR_INVALIDFAT -122 +#define CARDIO_ERROR_INVALIDMBR -123 +#define CARDIO_ERROR_INVALIDPBR -124 +#define CARDIO_ERROR_NOEMPTYBLOCK -125 +#define CARDIO_ERROR_INTERNAL -126 +#define CARDIO_ERROR_INVALIDPARAM -127 +#define CARDIO_ERROR_FATALERROR -128 + +#define MAX_DRIVE 2 +#define SECTOR_SIZE 512 + +#define NOT_INITIALIZED 0 +#define INITIALIZING 1 +#define INITIALIZED 2 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct _dev_info { + u32 CpV; + u32 HpC; + u32 SpH; + u32 allS; + u32 szS; + u32 PBpV; + u32 LBpV; + u32 SpB; + u32 PpB; + u32 szP; +} DEV_INFO; + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/sdcard/card_io.h b/wii/libogc/include/sdcard/card_io.h new file mode 100644 index 0000000000..265947b55f --- /dev/null +++ b/wii/libogc/include/sdcard/card_io.h @@ -0,0 +1,51 @@ +#ifndef __CARD_IO_H__ +#define __CARD_IO_H__ + +#include + +#define MAX_MI_NUM 1 +#define MAX_DI_NUM 5 + +#define PAGE_SIZE256 256 +#define PAGE_SIZE512 512 + +/* CID Register */ +#define MANUFACTURER_ID(drv_no) ((u8)(g_CID[drv_no][0])) + +/* CSD Register */ +#define READ_BL_LEN(drv_no) ((u8)(g_CSD[drv_no][5]&0x0f)) +#define WRITE_BL_LEN(drv_no) ((u8)((g_CSD[drv_no][12]&0x03)<<2)|((g_CSD[drv_no][13]>>6)&0x03)) +#define C_SIZE(drv_no) ((u16)(((g_CSD[drv_no][6]&0x03)<<10)|(g_CSD[drv_no][7]<<2)|((g_CSD[drv_no][8]>>6)&0x03))) +#define C_SIZE_MULT(drv_no) ((u8)((g_CSD[drv_no][9]&0x03)<<1)|((g_CSD[drv_no][10]>>7)&0x01)) + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +extern u8 g_CSD[MAX_DRIVE][16]; +extern u8 g_CID[MAX_DRIVE][16]; +extern u8 g_mCode[MAX_MI_NUM]; +extern u16 g_dCode[MAX_MI_NUM][MAX_DI_NUM]; + + +void sdgecko_initIODefault(); +s32 sdgecko_initIO(s32 drv_no); +s32 sdgecko_preIO(s32 drv_no); +s32 sdgecko_readCID(s32 drv_no); +s32 sdgecko_readCSD(s32 drv_no); +s32 sdgecko_readStatus(s32 drv_no); +s32 sdgecko_readSectors(s32 drv_no,u32 sector_no,u32 num_sectors,void *buf); +s32 sdgecko_writeSector(s32 drv_no,u32 sector_no,const void *buf,u32 len); +s32 sdgecko_writeSectors(s32 drv_no,u32 sector_no,u32 num_sectors,const void *buf); + +s32 sdgecko_doUnmount(s32 drv_no); + +void sdgecko_insertedCB(s32 drv_no); +void sdgecko_ejectedCB(s32 drv_no); + + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/include/sdcard/gcsd.h b/wii/libogc/include/sdcard/gcsd.h new file mode 100644 index 0000000000..c27a7316f3 --- /dev/null +++ b/wii/libogc/include/sdcard/gcsd.h @@ -0,0 +1,45 @@ +/* + + gcsd.h + + Hardware routines for reading and writing to SD geckos connected + to the memory card ports. + + These functions are just wrappers around libsdcard's functions. + + Copyright (c) 2008 Sven "svpe" Peter + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __GCSD_H__ +#define __GCSD_H__ + +#include +#include + +#define DEVICE_TYPE_GC_SD (('G'<<24)|('C'<<16)|('S'<<8)|'D') + +extern const DISC_INTERFACE __io_gcsda; +extern const DISC_INTERFACE __io_gcsdb; + +#endif diff --git a/wii/libogc/include/sdcard/wiisd_io.h b/wii/libogc/include/sdcard/wiisd_io.h new file mode 100644 index 0000000000..3f414d91ab --- /dev/null +++ b/wii/libogc/include/sdcard/wiisd_io.h @@ -0,0 +1,44 @@ +/* + + wii_sd.h + + Hardware interface for libfat Wii internal SD + + Copyright (c) 2008 + Michael Wiedenbauer (shagkur) + Dave Murphy (WinterMute) + + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __WIISD_IO_H__ +#define __WIISD_IO_H__ + +#include +#include + +#define DEVICE_TYPE_WII_SD (('W'<<24)|('I'<<16)|('S'<<8)|'D') + +extern const DISC_INTERFACE __io_wiisd; + +#endif diff --git a/wii/libogc/include/smb.h b/wii/libogc/include/smb.h new file mode 100644 index 0000000000..579f1979c4 --- /dev/null +++ b/wii/libogc/include/smb.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * TinySMB + * Nintendo Wii/GameCube SMB implementation + * + * Copyright softdev + * Modified by Tantric to utilize NTLM authentication + * PathInfo added by rodries + * SMB devoptab by scip, rodries + * + * You will find WireShark (http://www.wireshark.org/) + * invaluable for debugging SAMBA implementations. + * + * Recommended Reading + * Implementing CIFS - Christopher R Hertel + * http://www.ubiqx.org/cifs/SMB.html + * + * License: + * + * This library 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.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ****************************************************************************/ + +#ifndef __NBTSMB_H__ +#define __NBTSMB_H__ + +#include +#include + +#define SMB_MAXPATH 4096 + +/** +* SMB Error codes +*/ +#define SMB_SUCCESS 0 +#define SMB_ERROR -1 +#define SMB_BAD_PROTOCOL -2 +#define SMB_BAD_COMMAND -3 +#define SMB_PROTO_FAIL -4 +#define SMB_NOT_USER -5 +#define SMB_BAD_KEYLEN -6 +#define SMB_BAD_DATALEN -7 +#define SMB_BAD_LOGINDATA -8 + +/** +* SMB File Open Function +*/ +#define SMB_OF_OPEN 1 +#define SMB_OF_TRUNCATE 2 +#define SMB_OF_CREATE 16 + +/** +* FileSearch +*/ +#define SMB_SRCH_READONLY 1 +#define SMB_SRCH_HIDDEN 2 +#define SMB_SRCH_SYSTEM 4 +#define SMB_SRCH_VOLUME 8 +#define SMB_SRCH_DIRECTORY 16 +#define SMB_SRCH_ARCHIVE 32 + +/** +* SMB File Access Modes +*/ +#define SMB_OPEN_READING 0 +#define SMB_OPEN_WRITING 1 +#define SMB_OPEN_READWRITE 2 +#define SMB_OPEN_COMPATIBLE 0 +#define SMB_DENY_READWRITE 0x10 +#define SMB_DENY_WRITE 0x20 +#define SMB_DENY_READ 0x30 +#define SMB_DENY_NONE 0x40 + + +#ifdef __cplusplus +extern "C" { +#endif + +/*** + * SMB Connection Handle + */ +typedef u32 SMBCONN; + +/*** + * SMB File Handle + */ +typedef void* SMBFILE; + +/*** SMB_FILEENTRY + SMB Long Filename Directory Entry + ***/ + typedef struct +{ + u64 size; + u64 ctime; + u64 atime; + u64 mtime; + u32 attributes; + u16 sid; + char name[768]; //unicode +} SMBDIRENTRY; + +/** + * Prototypes + */ + +/*** Functions to be used with stdio API ***/ +bool smbInitDevice(const char* name, const char *user, const char *password, const char *share, const char *ip); +bool smbInit(const char *user, const char *password, const char *share, const char *ip); +void smbClose(const char* name); +bool smbCheckConnection(const char* name); +void smbSetSearchFlags(unsigned short flags); + +/*** Session ***/ +s32 SMB_Connect(SMBCONN *smbhndl, const char *user, const char *password, const char *share, const char *IP); +void SMB_Close(SMBCONN smbhndl); +s32 SMB_Reconnect(SMBCONN *_smbhndl, bool test_conn); + +/*** File Find ***/ +s32 SMB_PathInfo(const char *filename, SMBDIRENTRY *sdir, SMBCONN smbhndl); +s32 SMB_FindFirst(const char *filename, unsigned short flags, SMBDIRENTRY *sdir, SMBCONN smbhndl); +s32 SMB_FindNext(SMBDIRENTRY *sdir,SMBCONN smbhndl); +s32 SMB_FindClose(SMBDIRENTRY *sdir,SMBCONN smbhndl); + +/*** File I/O ***/ +SMBFILE SMB_OpenFile(const char *filename, unsigned short access, unsigned short creation,SMBCONN smbhndl); +void SMB_CloseFile(SMBFILE sfid); +s32 SMB_ReadFile(char *buffer, size_t size, off_t offset, SMBFILE sfid); +s32 SMB_WriteFile(const char *buffer, size_t size, off_t offset, SMBFILE sfid); +s32 SMB_CreateDirectory(const char *dirname, SMBCONN smbhndl); +s32 SMB_DeleteDirectory(const char *dirname, SMBCONN smbhndl); +s32 SMB_DeleteFile(const char *filename, SMBCONN smbhndl); +s32 SMB_Rename(const char *filename, const char * newname, SMBCONN smbhndl); +s32 SMB_DiskInformation(struct statvfs *buf, SMBCONN smbhndl); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/wii/libogc/include/wiikeyboard/keyboard.h b/wii/libogc/include/wiikeyboard/keyboard.h new file mode 100644 index 0000000000..150086f291 --- /dev/null +++ b/wii/libogc/include/wiikeyboard/keyboard.h @@ -0,0 +1,92 @@ +/*------------------------------------------------------------- + +keyboard.h -- keyboard event system + +Copyright (C) 2008, 2009 +DAVY Guillaume davyg2@gmail.com +Brian Johnson brijohn@gmail.com +dhewg + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __KEYBOARD_H__ +#define __KEYBOARD_H__ + +#include "wsksymdef.h" + +#define MOD_SHIFT_L (1 << 0) +#define MOD_SHIFT_R (1 << 1) +#define MOD_SHIFTLOCK (1 << 2) +#define MOD_CAPSLOCK (1 << 3) +#define MOD_CONTROL_L (1 << 4) +#define MOD_CONTROL_R (1 << 5) +#define MOD_META_L (1 << 6) +#define MOD_META_R (1 << 7) +#define MOD_MODESHIFT (1 << 8) +#define MOD_NUMLOCK (1 << 9) +#define MOD_COMPOSE (1 << 10) +#define MOD_HOLDSCREEN (1 << 11) +#define MOD_COMMAND (1 << 12) +#define MOD_COMMAND1 (1 << 13) +#define MOD_COMMAND2 (1 << 14) +#define MOD_MODELOCK (1 << 15) + +#define MOD_ANYSHIFT (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK) +#define MOD_ANYCONTROL (MOD_CONTROL_L | MOD_CONTROL_R) +#define MOD_ANYMETA (MOD_META_L | MOD_META_R) + +#define MOD_ONESET(val, mask) (((val) & (mask)) != 0) +#define MOD_ALLSET(val, mask) (((val) & (mask)) == (mask)) + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef enum { + KEYBOARD_CONNECTED, + KEYBOARD_DISCONNECTED, + KEYBOARD_PRESSED, + KEYBOARD_RELEASED +} keyboard_event_type; + +typedef struct { + keyboard_event_type type; + u16 modifiers; + u8 keycode; + u16 symbol; +} keyboard_event; + +typedef void (*keyPressCallback)(char symbol); + +s32 KEYBOARD_Init(keyPressCallback keypress_cb); +s32 KEYBOARD_Deinit(void); + +s32 KEYBOARD_GetEvent(keyboard_event *event); +s32 KEYBOARD_FlushEvents(void); + + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* __KEYBOARD_H__ */ + diff --git a/wii/libogc/include/wiikeyboard/usbkeyboard.h b/wii/libogc/include/wiikeyboard/usbkeyboard.h new file mode 100644 index 0000000000..a5da919a18 --- /dev/null +++ b/wii/libogc/include/wiikeyboard/usbkeyboard.h @@ -0,0 +1,76 @@ +/*------------------------------------------------------------- + +usbkeyboard.h -- Usb keyboard support(boot protocol) + +Copyright (C) 2008, 2009 +DAVY Guillaume davyg2@gmail.com +dhewg + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __USBKEYBOARD_H__ +#define __USBKEYBOARD_H__ + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef enum +{ + USBKEYBOARD_PRESSED = 0, + USBKEYBOARD_RELEASED, + USBKEYBOARD_DISCONNECTED +} USBKeyboard_eventType; + +typedef enum +{ + USBKEYBOARD_LEDNUM = 0, + USBKEYBOARD_LEDCAPS, + USBKEYBOARD_LEDSCROLL +} USBKeyboard_led; + +typedef struct +{ + USBKeyboard_eventType type; + u8 keyCode; +} USBKeyboard_event; + +typedef void (*eventcallback) (USBKeyboard_event event); + +s32 USBKeyboard_Initialize(void); +s32 USBKeyboard_Deinitialize(void); + +s32 USBKeyboard_Open(const eventcallback cb); +void USBKeyboard_Close(void); + +bool USBKeyboard_IsConnected(void); +s32 USBKeyboard_Scan(void); + +s32 USBKeyboard_SetLed(const USBKeyboard_led led, bool on); +s32 USBKeyboard_ToggleLed(const USBKeyboard_led led); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* __USBKEYBOARD_H__ */ + diff --git a/wii/libogc/include/wiikeyboard/wsksymdef.h b/wii/libogc/include/wiikeyboard/wsksymdef.h new file mode 100644 index 0000000000..552544675c --- /dev/null +++ b/wii/libogc/include/wiikeyboard/wsksymdef.h @@ -0,0 +1,776 @@ +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 _DEV_WSCONS_WSKSYMDEF_H_ +#define _DEV_WSCONS_WSKSYMDEF_H_ + +/* + * Keysymbols encoded as 16-bit Unicode. Special symbols + * are encoded in the private area (0xe000 - 0xf8ff). + * Currently only ISO Latin-1 subset is supported. + * + * This file is parsed from userland. Encode keysyms as: + * + * #define KS_[^ \t]* 0x[0-9a-f]* + * + * and don't modify the border comments. + */ + +/*BEGINKEYSYMDECL*/ + +/* + * Group Ascii (ISO Latin1) character in low byte + */ + +#define KS_BackSpace 0x08 +#define KS_Tab 0x09 +#define KS_Linefeed 0x0a +#define KS_Clear 0x0b +#define KS_Return 0x0d +#define KS_Escape 0x1b +#define KS_space 0x20 +#define KS_exclam 0x21 +#define KS_quotedbl 0x22 +#define KS_numbersign 0x23 +#define KS_dollar 0x24 +#define KS_percent 0x25 +#define KS_ampersand 0x26 +#define KS_apostrophe 0x27 +#define KS_parenleft 0x28 +#define KS_parenright 0x29 +#define KS_asterisk 0x2a +#define KS_plus 0x2b +#define KS_comma 0x2c +#define KS_minus 0x2d +#define KS_period 0x2e +#define KS_slash 0x2f +#define KS_0 0x30 +#define KS_1 0x31 +#define KS_2 0x32 +#define KS_3 0x33 +#define KS_4 0x34 +#define KS_5 0x35 +#define KS_6 0x36 +#define KS_7 0x37 +#define KS_8 0x38 +#define KS_9 0x39 +#define KS_colon 0x3a +#define KS_semicolon 0x3b +#define KS_less 0x3c +#define KS_equal 0x3d +#define KS_greater 0x3e +#define KS_question 0x3f +#define KS_at 0x40 +#define KS_A 0x41 +#define KS_B 0x42 +#define KS_C 0x43 +#define KS_D 0x44 +#define KS_E 0x45 +#define KS_F 0x46 +#define KS_G 0x47 +#define KS_H 0x48 +#define KS_I 0x49 +#define KS_J 0x4a +#define KS_K 0x4b +#define KS_L 0x4c +#define KS_M 0x4d +#define KS_N 0x4e +#define KS_O 0x4f +#define KS_P 0x50 +#define KS_Q 0x51 +#define KS_R 0x52 +#define KS_S 0x53 +#define KS_T 0x54 +#define KS_U 0x55 +#define KS_V 0x56 +#define KS_W 0x57 +#define KS_X 0x58 +#define KS_Y 0x59 +#define KS_Z 0x5a +#define KS_bracketleft 0x5b +#define KS_backslash 0x5c +#define KS_bracketright 0x5d +#define KS_asciicircum 0x5e +#define KS_underscore 0x5f +#define KS_grave 0x60 +#define KS_a 0x61 +#define KS_b 0x62 +#define KS_c 0x63 +#define KS_d 0x64 +#define KS_e 0x65 +#define KS_f 0x66 +#define KS_g 0x67 +#define KS_h 0x68 +#define KS_i 0x69 +#define KS_j 0x6a +#define KS_k 0x6b +#define KS_l 0x6c +#define KS_m 0x6d +#define KS_n 0x6e +#define KS_o 0x6f +#define KS_p 0x70 +#define KS_q 0x71 +#define KS_r 0x72 +#define KS_s 0x73 +#define KS_t 0x74 +#define KS_u 0x75 +#define KS_v 0x76 +#define KS_w 0x77 +#define KS_x 0x78 +#define KS_y 0x79 +#define KS_z 0x7a +#define KS_braceleft 0x7b +#define KS_bar 0x7c +#define KS_braceright 0x7d +#define KS_asciitilde 0x7e +#define KS_Delete 0x7f + +#define KS_nobreakspace 0xa0 +#define KS_exclamdown 0xa1 +#define KS_cent 0xa2 +#define KS_sterling 0xa3 +#define KS_currency 0xa4 +#define KS_yen 0xa5 +#define KS_brokenbar 0xa6 +#define KS_section 0xa7 +#define KS_diaeresis 0xa8 +#define KS_copyright 0xa9 +#define KS_ordfeminine 0xaa +#define KS_guillemotleft 0xab +#define KS_notsign 0xac +#define KS_hyphen 0xad +#define KS_registered 0xae +#define KS_macron 0xaf +#define KS_degree 0xb0 +#define KS_plusminus 0xb1 +#define KS_twosuperior 0xb2 +#define KS_threesuperior 0xb3 +#define KS_acute 0xb4 +#define KS_mu 0xb5 +#define KS_paragraph 0xb6 +#define KS_periodcentered 0xb7 +#define KS_cedilla 0xb8 +#define KS_onesuperior 0xb9 +#define KS_masculine 0xba +#define KS_guillemotright 0xbb +#define KS_onequarter 0xbc +#define KS_onehalf 0xbd +#define KS_threequarters 0xbe +#define KS_questiondown 0xbf +#define KS_Agrave 0xc0 +#define KS_Aacute 0xc1 +#define KS_Acircumflex 0xc2 +#define KS_Atilde 0xc3 +#define KS_Adiaeresis 0xc4 +#define KS_Aring 0xc5 +#define KS_AE 0xc6 +#define KS_Ccedilla 0xc7 +#define KS_Egrave 0xc8 +#define KS_Eacute 0xc9 +#define KS_Ecircumflex 0xca +#define KS_Ediaeresis 0xcb +#define KS_Igrave 0xcc +#define KS_Iacute 0xcd +#define KS_Icircumflex 0xce +#define KS_Idiaeresis 0xcf +#define KS_ETH 0xd0 +#define KS_Ntilde 0xd1 +#define KS_Ograve 0xd2 +#define KS_Oacute 0xd3 +#define KS_Ocircumflex 0xd4 +#define KS_Otilde 0xd5 +#define KS_Odiaeresis 0xd6 +#define KS_multiply 0xd7 +#define KS_Ooblique 0xd8 +#define KS_Ugrave 0xd9 +#define KS_Uacute 0xda +#define KS_Ucircumflex 0xdb +#define KS_Udiaeresis 0xdc +#define KS_Yacute 0xdd +#define KS_THORN 0xde +#define KS_ssharp 0xdf +#define KS_agrave 0xe0 +#define KS_aacute 0xe1 +#define KS_acircumflex 0xe2 +#define KS_atilde 0xe3 +#define KS_adiaeresis 0xe4 +#define KS_aring 0xe5 +#define KS_ae 0xe6 +#define KS_ccedilla 0xe7 +#define KS_egrave 0xe8 +#define KS_eacute 0xe9 +#define KS_ecircumflex 0xea +#define KS_ediaeresis 0xeb +#define KS_igrave 0xec +#define KS_iacute 0xed +#define KS_icircumflex 0xee +#define KS_idiaeresis 0xef +#define KS_eth 0xf0 +#define KS_ntilde 0xf1 +#define KS_ograve 0xf2 +#define KS_oacute 0xf3 +#define KS_ocircumflex 0xf4 +#define KS_otilde 0xf5 +#define KS_odiaeresis 0xf6 +#define KS_division 0xf7 +#define KS_oslash 0xf8 +#define KS_ugrave 0xf9 +#define KS_uacute 0xfa +#define KS_ucircumflex 0xfb +#define KS_udiaeresis 0xfc +#define KS_yacute 0xfd +#define KS_thorn 0xfe +#define KS_ydiaeresis 0xff + +#define KS_Odoubleacute 0x150 +#define KS_odoubleacute 0x151 +#define KS_Udoubleacute 0x170 +#define KS_udoubleacute 0x171 + +/* + * Group Dead (dead accents) + */ + +#define KS_dead_grave 0x0300 +#define KS_dead_acute 0x0301 +#define KS_dead_circumflex 0x0302 +#define KS_dead_tilde 0x0303 +#define KS_dead_diaeresis 0x0308 +#define KS_dead_abovering 0x030a +#define KS_dead_cedilla 0x0327 + +/* + * Group Cyrillic (koi8-r) + */ + +#define KS_Cyrillic_A 0xe1 +#define KS_Cyrillic_BE 0xe2 +#define KS_Cyrillic_VE 0xf7 +#define KS_Cyrillic_GE 0xe7 +#define KS_Cyrillic_DE 0xe4 +#define KS_Cyrillic_IE 0xe5 +#define KS_Cyrillic_YO 0xb3 +#define KS_Cyrillic_ZHE 0xf6 +#define KS_Cyrillic_ZE 0xfa +#define KS_Cyrillic_I 0xe9 +#define KS_Cyrillic_ISHORT 0xea +#define KS_Cyrillic_IUKR 0xb6 +#define KS_Cyrillic_YI 0xb7 +#define KS_Cyrillic_KA 0xeb +#define KS_Cyrillic_EL 0xec +#define KS_Cyrillic_EM 0xed +#define KS_Cyrillic_EN 0xee +#define KS_Cyrillic_O 0xef +#define KS_Cyrillic_PE 0xf0 +#define KS_Cyrillic_ER 0xf2 +#define KS_Cyrillic_ES 0xf3 +#define KS_Cyrillic_TE 0xf4 +#define KS_Cyrillic_U 0xf5 +#define KS_Cyrillic_EF 0xe6 +#define KS_Cyrillic_HA 0xe8 +#define KS_Cyrillic_TSE 0xe3 +#define KS_Cyrillic_CHE 0xfe +#define KS_Cyrillic_SHA 0xfb +#define KS_Cyrillic_SCHA 0xfd +#define KS_Cyrillic_HSIGHN 0xff +#define KS_Cyrillic_YERU 0xf9 +#define KS_Cyrillic_SSIGHN 0xf8 +#define KS_Cyrillic_E 0xfc +#define KS_Cyrillic_YU 0xe0 +#define KS_Cyrillic_YA 0xf1 +#define KS_Cyrillic_a 0xc1 +#define KS_Cyrillic_be 0xc2 +#define KS_Cyrillic_ve 0xd7 +#define KS_Cyrillic_ge 0xc7 +#define KS_Cyrillic_de 0xc4 +#define KS_Cyrillic_ie 0xc5 +#define KS_Cyrillic_yo 0xa3 +#define KS_Cyrillic_zhe 0xd6 +#define KS_Cyrillic_ze 0xda +#define KS_Cyrillic_i 0xc9 +#define KS_Cyrillic_ishort 0xca +#define KS_Cyrillic_iukr 0xa6 +#define KS_Cyrillic_yi 0xa7 +#define KS_Cyrillic_ka 0xcb +#define KS_Cyrillic_el 0xcc +#define KS_Cyrillic_em 0xcd +#define KS_Cyrillic_en 0xce +#define KS_Cyrillic_o 0xcf +#define KS_Cyrillic_pe 0xd0 +#define KS_Cyrillic_er 0xd2 +#define KS_Cyrillic_es 0xd3 +#define KS_Cyrillic_te 0xd4 +#define KS_Cyrillic_u 0xd5 +#define KS_Cyrillic_ef 0xc6 +#define KS_Cyrillic_ha 0xc8 +#define KS_Cyrillic_tse 0xc3 +#define KS_Cyrillic_che 0xde +#define KS_Cyrillic_sha 0xdb +#define KS_Cyrillic_scha 0xdd +#define KS_Cyrillic_hsighn 0xdf +#define KS_Cyrillic_yeru 0xd9 +#define KS_Cyrillic_ssighn 0xd8 +#define KS_Cyrillic_e 0xdc +#define KS_Cyrillic_yu 0xc0 +#define KS_Cyrillic_ya 0xd1 +#define KS_Cyrillic_gheukr 0xad +#define KS_Cyrillic_GHEUKR 0xbd +#define KS_Cyrillic_yeukr 0xa4 +#define KS_Cyrillic_YEUKR 0xb4 + +/* + * Group Latin-2 (iso8859-2) + */ + +#define KS_L2_Aogonek 0xa1 +#define KS_L2_breve 0xa2 +#define KS_L2_Lstroke 0xa3 +#define KS_L2_Lcaron 0xa5 +#define KS_L2_Sacute 0xa6 +#define KS_L2_Scaron 0xa9 +#define KS_L2_Scedilla 0xaa +#define KS_L2_Tcaron 0xab +#define KS_L2_Zacute 0xac +#define KS_L2_Zcaron 0xae +#define KS_L2_Zdotabove 0xaf +#define KS_L2_aogonek 0xb1 +#define KS_L2_ogonek 0xb2 +#define KS_L2_lstroke 0xb3 +#define KS_L2_lcaron 0xb5 +#define KS_L2_sacute 0xb6 +#define KS_L2_caron 0xb7 +#define KS_L2_scaron 0xb9 +#define KS_L2_scedilla 0xba +#define KS_L2_tcaron 0xbb +#define KS_L2_zacute 0xbc +#define KS_L2_dblacute 0xbd +#define KS_L2_zcaron 0xbe +#define KS_L2_zdotabove 0xbf +#define KS_L2_Racute 0xc0 +#define KS_L2_Abreve 0xc3 +#define KS_L2_Lacute 0xc5 +#define KS_L2_Cacute 0xc6 +#define KS_L2_Ccaron 0xc8 +#define KS_L2_Eogonek 0xca +#define KS_L2_Ecaron 0xcc +#define KS_L2_Dcaron 0xcf +#define KS_L2_Dstroke 0xd0 +#define KS_L2_Nacute 0xd1 +#define KS_L2_Ncaron 0xd2 +#define KS_L2_Odoubleacute 0xd5 +#define KS_L2_Rcaron 0xd8 +#define KS_L2_Uring 0xd9 +#define KS_L2_Udoubleacute 0xdb +#define KS_L2_Tcedilla 0xde +#define KS_L2_racute 0xe0 +#define KS_L2_abreve 0xe3 +#define KS_L2_lacute 0xe5 +#define KS_L2_cacute 0xe6 +#define KS_L2_ccaron 0xe8 +#define KS_L2_eogonek 0xea +#define KS_L2_ecaron 0xec +#define KS_L2_dcaron 0xef +#define KS_L2_dstroke 0xf0 +#define KS_L2_nacute 0xf1 +#define KS_L2_odoubleacute 0xf5 +#define KS_L2_rcaron 0xf8 +#define KS_L2_uring 0xf9 +#define KS_L2_udoubleacute 0xfb +#define KS_L2_tcedilla 0xfe +#define KS_L2_dotabove 0xff + +/* + * Group Latin-5 (iso8859-9) + */ + +#define KS_L5_Gbreve 0xd0 +#define KS_L5_Idotabove 0xdd +#define KS_L5_Scedilla 0xde +#define KS_L5_gbreve 0xf0 +#define KS_L5_idotless 0xfd +#define KS_L5_scedilla 0xfe + + /* + * Group Latin-7 (iso8859-13) + */ + +#define KS_L7_rightdblquot 0xa1 +#define KS_L7_dbllow9quot 0xa5 +#define KS_L7_Ostroke 0xa8 +#define KS_L7_Rcedilla 0xaa +#define KS_L7_AE 0xaf +#define KS_L7_leftdblquot 0xb4 +#define KS_L7_ostroke 0xb8 +#define KS_L7_rcedilla 0xba +#define KS_L7_ae 0xbf +#define KS_L7_Aogonek 0xc0 +#define KS_L7_Iogonek 0xc1 +#define KS_L7_Amacron 0xc2 +#define KS_L7_Cacute 0xc3 +#define KS_L7_Eogonek 0xc6 +#define KS_L7_Emacron 0xc7 +#define KS_L7_Ccaron 0xc8 +#define KS_L7_Zacute 0xca +#define KS_L7_Edot 0xcb +#define KS_L7_Gcedilla 0xcc +#define KS_L7_Kcedilla 0xcd +#define KS_L7_Imacron 0xce +#define KS_L7_Lcedilla 0xcf +#define KS_L7_Scaron 0xd0 +#define KS_L7_Nacute 0xd1 +#define KS_L7_Ncedilla 0xd2 +#define KS_L7_Omacron 0xd4 +#define KS_L7_Uogonek 0xd8 +#define KS_L7_Lstroke 0xd9 +#define KS_L7_Sacute 0xda +#define KS_L7_Umacron 0xdb +#define KS_L7_Zdot 0xdd +#define KS_L7_Zcaron 0xde +#define KS_L7_aogonek 0xe0 +#define KS_L7_iogonek 0xe1 +#define KS_L7_amacron 0xe2 +#define KS_L7_cacute 0xe3 +#define KS_L7_eogonek 0xe6 +#define KS_L7_emacron 0xe7 +#define KS_L7_ccaron 0xe8 +#define KS_L7_zacute 0xea +#define KS_L7_edot 0xeb +#define KS_L7_gcedilla 0xec +#define KS_L7_kcedilla 0xed +#define KS_L7_imacron 0xee +#define KS_L7_lcedilla 0xef +#define KS_L7_scaron 0xf0 +#define KS_L7_nacute 0xf1 +#define KS_L7_ncedilla 0xf2 +#define KS_L7_omacron 0xf4 +#define KS_L7_uogonek 0xf8 +#define KS_L7_lstroke 0xf9 +#define KS_L7_sacute 0xfa +#define KS_L7_umacron 0xfb +#define KS_L7_zdot 0xfd +#define KS_L7_zcaron 0xfe +#define KS_L7_rightsnglquot 0xff + +/* + * Group 1 (modifiers) + */ + +#define KS_Shift_L 0xf101 +#define KS_Shift_R 0xf102 +#define KS_Control_L 0xf103 +#define KS_Control_R 0xf104 +#define KS_Caps_Lock 0xf105 +#define KS_Shift_Lock 0xf106 +#define KS_Alt_L 0xf107 +#define KS_Alt_R 0xf108 +#define KS_Multi_key 0xf109 +#define KS_Mode_switch 0xf10a +#define KS_Num_Lock 0xf10b +#define KS_Hold_Screen 0xf10c +#define KS_Cmd 0xf10d +#define KS_Cmd1 0xf10e +#define KS_Cmd2 0xf10f +#define KS_Meta_L 0xf110 +#define KS_Meta_R 0xf111 +#define KS_Zenkaku_Hankaku 0xf112 /* Zenkaku/Hankaku toggle */ +#define KS_Hiragana_Katakana 0xf113 /* Hiragana/Katakana toggle */ +#define KS_Henkan_Mode 0xf114 /* Start/Stop Conversion */ +#define KS_Henkan 0xf115 /* Alias for Henkan_Mode */ +#define KS_Muhenkan 0xf116 /* Cancel Conversion */ +#define KS_Mode_Lock 0xf117 + +/* + * Group 2 (keypad) character in low byte + */ + +#define KS_KP_F1 0xf291 +#define KS_KP_F2 0xf292 +#define KS_KP_F3 0xf293 +#define KS_KP_F4 0xf294 +#define KS_KP_Home 0xf295 +#define KS_KP_Left 0xf296 +#define KS_KP_Up 0xf297 +#define KS_KP_Right 0xf298 +#define KS_KP_Down 0xf299 +#define KS_KP_Prior 0xf29a +#define KS_KP_Next 0xf29b +#define KS_KP_End 0xf29c +#define KS_KP_Begin 0xf29d +#define KS_KP_Insert 0xf29e +#define KS_KP_Delete 0xf29f + +#define KS_KP_Space 0xf220 +#define KS_KP_Tab 0xf209 +#define KS_KP_Enter 0xf20d +#define KS_KP_Equal 0xf23d +#define KS_KP_Numbersign 0xf223 +#define KS_KP_Multiply 0xf22a +#define KS_KP_Add 0xf22b +#define KS_KP_Separator 0xf22c +#define KS_KP_Subtract 0xf22d +#define KS_KP_Decimal 0xf22e +#define KS_KP_Divide 0xf22f +#define KS_KP_0 0xf230 +#define KS_KP_1 0xf231 +#define KS_KP_2 0xf232 +#define KS_KP_3 0xf233 +#define KS_KP_4 0xf234 +#define KS_KP_5 0xf235 +#define KS_KP_6 0xf236 +#define KS_KP_7 0xf237 +#define KS_KP_8 0xf238 +#define KS_KP_9 0xf239 + +/* + * Group 3 (function) + */ + +#define KS_f1 0xf300 +#define KS_f2 0xf301 +#define KS_f3 0xf302 +#define KS_f4 0xf303 +#define KS_f5 0xf304 +#define KS_f6 0xf305 +#define KS_f7 0xf306 +#define KS_f8 0xf307 +#define KS_f9 0xf308 +#define KS_f10 0xf309 +#define KS_f11 0xf30a +#define KS_f12 0xf30b +#define KS_f13 0xf30c +#define KS_f14 0xf30d +#define KS_f15 0xf30e +#define KS_f16 0xf30f +#define KS_f17 0xf310 +#define KS_f18 0xf311 +#define KS_f19 0xf312 +#define KS_f20 0xf313 + +#define KS_F1 0xf340 +#define KS_F2 0xf341 +#define KS_F3 0xf342 +#define KS_F4 0xf343 +#define KS_F5 0xf344 +#define KS_F6 0xf345 +#define KS_F7 0xf346 +#define KS_F8 0xf347 +#define KS_F9 0xf348 +#define KS_F10 0xf349 +#define KS_F11 0xf34a +#define KS_F12 0xf34b +#define KS_F13 0xf34c +#define KS_F14 0xf34d +#define KS_F15 0xf34e +#define KS_F16 0xf34f +#define KS_F17 0xf350 +#define KS_F18 0xf351 +#define KS_F19 0xf352 +#define KS_F20 0xf353 + +#define KS_Home 0xf381 +#define KS_Prior 0xf382 +#define KS_Next 0xf383 +#define KS_Up 0xf384 +#define KS_Down 0xf385 +#define KS_Left 0xf386 +#define KS_Right 0xf387 +#define KS_End 0xf388 +#define KS_Insert 0xf389 +#define KS_Help 0xf38a +#define KS_Execute 0xf38b +#define KS_Find 0xf38c +#define KS_Select 0xf38d +#define KS_Again 0xf38e +#define KS_Props 0xf38f +#define KS_Undo 0xf390 +#define KS_Front 0xf391 +#define KS_Copy 0xf392 +#define KS_Open 0xf393 +#define KS_Paste 0xf394 +#define KS_Cut 0xf395 + +#define KS_Menu 0xf3c0 +#define KS_Pause 0xf3c1 +#define KS_Print_Screen 0xf3c2 + +#define KS_AudioMute 0xf3d1 +#define KS_AudioLower 0xf3d2 +#define KS_AudioRaise 0xf3d3 + +/* + * Group 4 (command) + */ + +#define KS_Cmd_Screen0 0xf400 +#define KS_Cmd_Screen1 0xf401 +#define KS_Cmd_Screen2 0xf402 +#define KS_Cmd_Screen3 0xf403 +#define KS_Cmd_Screen4 0xf404 +#define KS_Cmd_Screen5 0xf405 +#define KS_Cmd_Screen6 0xf406 +#define KS_Cmd_Screen7 0xf407 +#define KS_Cmd_Screen8 0xf408 +#define KS_Cmd_Screen9 0xf409 +#define KS_Cmd_Screen10 0xf40a +#define KS_Cmd_Screen11 0xf40b +#define KS_Cmd_Debugger 0xf420 +#define KS_Cmd_ResetEmul 0xf421 +#define KS_Cmd_ResetClose 0xf422 +#define KS_Cmd_BacklightOn 0xf423 +#define KS_Cmd_BacklightOff 0xf424 +#define KS_Cmd_BacklightToggle 0xf425 +#define KS_Cmd_BrightnessUp 0xf426 +#define KS_Cmd_BrightnessDown 0xf427 +#define KS_Cmd_BrightnessRotate 0xf428 +#define KS_Cmd_ContrastUp 0xf429 +#define KS_Cmd_ContrastDown 0xf42a +#define KS_Cmd_ContrastRotate 0xf42b +#define KS_Cmd_ScrollBack 0xf42c +#define KS_Cmd_ScrollFwd 0xf42d +#define KS_Cmd_KbdReset 0xf42e + +/* + * Group 5 (internal) + */ + +#define KS_voidSymbol 0xf500 + +/*ENDKEYSYMDECL*/ + +/* + * keysym groups + */ + +#define KS_GROUP_Mod 0xf100 +#define KS_GROUP_Keypad 0xf200 +#define KS_GROUP_Function 0xf300 +#define KS_GROUP_Command 0xf400 +#define KS_GROUP_Internal 0xf500 +#define KS_GROUP_Dead 0xf801 /* not encoded in keysym */ +#define KS_GROUP_Ascii 0xf802 /* not encoded in keysym */ +#define KS_GROUP_Keycode 0xf803 /* not encoded in keysym */ + +#define KS_NUMKEYCODES 0x1000 +#define KS_KEYCODE(v) ((v) | 0xe000) + +#define KS_GROUP(k) ((k) >= 0x0300 && (k) < 0x0370 ? KS_GROUP_Dead : \ + (((k) & 0xf000) == 0xe000 ? KS_GROUP_Keycode : \ + (((k) & 0xf800) == 0xf000 ? ((k) & 0xff00) : \ + KS_GROUP_Ascii))) + +#define KS_VALUE(k) (((k) & 0xf000) == 0xe000 ? ((k) & 0x0fff) : \ + (((k) & 0xf800) == 0xf000 ? ((k) & 0x00ff) : (k))) + +/* + * Keyboard types: 8bit encoding, 24bit variant + */ + +#define KB_ENCODING(e) ((e) & 0x0000ff00) +#define KB_VARIANT(e) ((e) & 0xffff00ff) + +#define KB_NONE 0x0000 +#define KB_USER 0x0100 +#define KB_US 0x0200 +#define KB_DE 0x0300 +#define KB_DK 0x0400 +#define KB_IT 0x0500 +#define KB_FR 0x0600 +#define KB_UK 0x0700 +#define KB_JP 0x0800 +#define KB_SV 0x0900 +#define KB_NO 0x0a00 +#define KB_ES 0x0b00 +#define KB_HU 0x0c00 +#define KB_BE 0x0d00 +#define KB_RU 0x0e00 +#define KB_SG 0x0f00 +#define KB_SF 0x1000 +#define KB_PT 0x1100 +#define KB_UA 0x1200 +#define KB_LT 0x1300 +#define KB_LA 0x1400 +#define KB_BR 0x1500 +#define KB_NL 0x1600 +#define KB_TR 0x1700 +#define KB_PL 0x1800 +#define KB_SI 0x1900 +#define KB_CF 0x1a00 +#define KB_LV 0x1b00 + +#define KB_NODEAD 0x000001 /* disable dead accents */ +#define KB_DECLK 0x000002 /* DEC LKnnn layout */ +#define KB_LK401 0x000004 /* DEC LK401 instead LK201 */ +#define KB_SWAPCTRLCAPS 0x000008 /* swap Left-Control and Caps-Lock */ +#define KB_DVORAK 0x000010 /* Dvorak layout */ +#define KB_METAESC 0x000020 /* generate ESC prefix on ALT-key */ +#define KB_IOPENER 0x000040 /* f1-f12 -> ESC,f1-f11 */ +#define KB_MACHDEP 0x000080 /* machine dependent */ +#define KB_APPLE 0x010000 /* Apple specific layout */ + +#define KB_ENCTAB \ + { KB_USER, "user" }, \ + { KB_US, "us" }, \ + { KB_DE, "de" }, \ + { KB_DK, "dk" }, \ + { KB_IT, "it" }, \ + { KB_FR, "fr" }, \ + { KB_UK, "uk" }, \ + { KB_JP, "jp" }, \ + { KB_SV, "sv" }, \ + { KB_NO, "no" }, \ + { KB_ES, "es" }, \ + { KB_HU, "hu" }, \ + { KB_BE, "be" }, \ + { KB_RU, "ru" }, \ + { KB_UA, "ua" }, \ + { KB_SG, "sg" }, \ + { KB_SF, "sf" }, \ + { KB_PT, "pt" }, \ + { KB_LT, "lt" }, \ + { KB_LA, "la" }, \ + { KB_BR, "br" }, \ + { KB_NL, "nl" }, \ + { KB_TR, "tr" }, \ + { KB_PL, "pl" }, \ + { KB_SI, "si" }, \ + { KB_CF, "cf" }, \ + { KB_LV, "lv" } + +#define KB_VARTAB \ + { KB_NODEAD, "nodead" }, \ + { KB_DECLK, "declk" }, \ + { KB_LK401, "lk401" }, \ + { KB_SWAPCTRLCAPS, "swapctrlcaps" }, \ + { KB_DVORAK, "dvorak" }, \ + { KB_METAESC, "metaesc" }, \ + { KB_IOPENER, "iopener" }, \ + { KB_MACHDEP, "machdep" }, \ + { KB_APPLE, "apple" } + +#endif /* !_DEV_WSCONS_WSKSYMDEF_H_ */ diff --git a/wii/libogc/include/wiiuse/wiiuse.h b/wii/libogc/include/wiiuse/wiiuse.h new file mode 100644 index 0000000000..7be2a7d9e9 --- /dev/null +++ b/wii/libogc/include/wiiuse/wiiuse.h @@ -0,0 +1,748 @@ +#ifndef __WIIUSE_H__ +#define __WIIUSE_H__ + +#if defined(_WIN32) + /* windows */ + #include +#elif defined(GEKKO) + /* wii */ + #include +#elif defined(__linux__) + /* nix */ + #include +#endif + +#ifdef WIIUSE_INTERNAL_H_INCLUDED + #define WCONST +#else + #define WCONST const +#endif + +/* led bit masks */ +#define WIIMOTE_LED_NONE 0x00 +#define WIIMOTE_LED_1 0x10 +#define WIIMOTE_LED_2 0x20 +#define WIIMOTE_LED_3 0x40 +#define WIIMOTE_LED_4 0x80 + +/* button codes */ +#define WIIMOTE_BUTTON_TWO 0x0001 +#define WIIMOTE_BUTTON_ONE 0x0002 +#define WIIMOTE_BUTTON_B 0x0004 +#define WIIMOTE_BUTTON_A 0x0008 +#define WIIMOTE_BUTTON_MINUS 0x0010 +#define WIIMOTE_BUTTON_ZACCEL_BIT6 0x0020 +#define WIIMOTE_BUTTON_ZACCEL_BIT7 0x0040 +#define WIIMOTE_BUTTON_HOME 0x0080 +#define WIIMOTE_BUTTON_LEFT 0x0100 +#define WIIMOTE_BUTTON_RIGHT 0x0200 +#define WIIMOTE_BUTTON_DOWN 0x0400 +#define WIIMOTE_BUTTON_UP 0x0800 +#define WIIMOTE_BUTTON_PLUS 0x1000 +#define WIIMOTE_BUTTON_ZACCEL_BIT4 0x2000 +#define WIIMOTE_BUTTON_ZACCEL_BIT5 0x4000 +#define WIIMOTE_BUTTON_UNKNOWN 0x8000 +#define WIIMOTE_BUTTON_ALL 0x1F9F + +/* nunchul button codes */ +#define NUNCHUK_BUTTON_Z 0x01 +#define NUNCHUK_BUTTON_C 0x02 +#define NUNCHUK_BUTTON_ALL 0x03 + +/* classic controller button codes */ +#define CLASSIC_CTRL_BUTTON_UP 0x0001 +#define CLASSIC_CTRL_BUTTON_LEFT 0x0002 +#define CLASSIC_CTRL_BUTTON_ZR 0x0004 +#define CLASSIC_CTRL_BUTTON_X 0x0008 +#define CLASSIC_CTRL_BUTTON_A 0x0010 +#define CLASSIC_CTRL_BUTTON_Y 0x0020 +#define CLASSIC_CTRL_BUTTON_B 0x0040 +#define CLASSIC_CTRL_BUTTON_ZL 0x0080 +#define CLASSIC_CTRL_BUTTON_FULL_R 0x0200 +#define CLASSIC_CTRL_BUTTON_PLUS 0x0400 +#define CLASSIC_CTRL_BUTTON_HOME 0x0800 +#define CLASSIC_CTRL_BUTTON_MINUS 0x1000 +#define CLASSIC_CTRL_BUTTON_FULL_L 0x2000 +#define CLASSIC_CTRL_BUTTON_DOWN 0x4000 +#define CLASSIC_CTRL_BUTTON_RIGHT 0x8000 +#define CLASSIC_CTRL_BUTTON_ALL 0xFEFF + +/* guitar hero 3 button codes */ +#define GUITAR_HERO_3_BUTTON_STRUM_UP 0x0001 +#define GUITAR_HERO_3_BUTTON_YELLOW 0x0008 +#define GUITAR_HERO_3_BUTTON_GREEN 0x0010 +#define GUITAR_HERO_3_BUTTON_BLUE 0x0020 +#define GUITAR_HERO_3_BUTTON_RED 0x0040 +#define GUITAR_HERO_3_BUTTON_ORANGE 0x0080 +#define GUITAR_HERO_3_BUTTON_PLUS 0x0400 +#define GUITAR_HERO_3_BUTTON_MINUS 0x1000 +#define GUITAR_HERO_3_BUTTON_STRUM_DOWN 0x4000 +#define GUITAR_HERO_3_BUTTON_ALL 0xFEFF + +/* guitar hero world tour touch bar codes */ +#define GUITAR_HERO_3_TOUCH_AVAILABLE 0x1000 +#define GUITAR_HERO_3_TOUCH_GREEN 0x1001 +#define GUITAR_HERO_3_TOUCH_RED 0x1002 +#define GUITAR_HERO_3_TOUCH_YELLOW 0x1004 +#define GUITAR_HERO_3_TOUCH_BLUE 0x1008 +#define GUITAR_HERO_3_TOUCH_ORANGE 0x1010 + +/* wiimote option flags */ +#define WIIUSE_SMOOTHING 0x01 +#define WIIUSE_CONTINUOUS 0x02 +#define WIIUSE_ACCEL_THRESH 0x04 +#define WIIUSE_IR_THRESH 0x08 +#define WIIUSE_JS_THRESH 0x10 +#define WIIUSE_INIT_FLAGS WIIUSE_SMOOTHING + +#define WIIUSE_ORIENT_PRECISION 100.0f + +/* expansion codes */ +#define EXP_NONE 0 +#define EXP_NUNCHUK 1 +#define EXP_CLASSIC 2 +#define EXP_GUITAR_HERO_3 3 +#define EXP_WII_BOARD 4 +#define EXP_MOTION_PLUS 5 + +/* IR correction types */ +typedef enum ir_position_t { + WIIUSE_IR_ABOVE, + WIIUSE_IR_BELOW +} ir_position_t; + +/** + * @brief Check if a button is pressed. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is pressed, 0 if not. + */ +#define IS_PRESSED(dev, button) ((dev->btns & button) == button) + +/** + * @brief Check if a button is being held. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is held, 0 if not. + */ +#define IS_HELD(dev, button) ((dev->btns_held & button) == button) + +/** + * @brief Check if a button is released on this event. \n\n + * This does not mean the button is not pressed, it means \n + * this button was just now released. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is released, 0 if not. + * + */ +#define IS_RELEASED(dev, button) ((dev->btns_released & button) == button) + +/** + * @brief Check if a button has just been pressed this event. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is pressed, 0 if not. + */ +#define IS_JUST_PRESSED(dev, button) (IS_PRESSED(dev, button) && !IS_HELD(dev, button)) + +/** + * @brief Return the IR sensitivity level. + * @param wm Pointer to a wiimote_t structure. + * @param lvl [out] Pointer to an int that will hold the level setting. + * If no level is set 'lvl' will be set to 0. + */ +#define WIIUSE_GET_IR_SENSITIVITY(dev, lvl) \ + do { \ + if ((wm->state & 0x01000) == 0x01000) *lvl = 1; \ + else if ((wm->state & 0x02000) == 0x02000) *lvl = 2; \ + else if ((wm->state & 0x04000) == 0x04000) *lvl = 3; \ + else if ((wm->state & 0x08000) == 0x08000) *lvl = 4; \ + else if ((wm->state & 0x10000) == 0x10000) *lvl = 5; \ + else *lvl = 0; \ + } while (0) + +#define WIIUSE_USING_ACC(wm) ((wm->state & 0x00100) == 0x00100) +#define WIIUSE_USING_EXP(wm) ((wm->state & 0x00200) == 0x00200) +#define WIIUSE_USING_IR(wm) ((wm->state & 0x00400) == 0x00400) +#define WIIUSE_USING_SPEAKER(wm) ((wm->state & 0x00800) == 0x00800) + +#define WIIUSE_IS_LED_SET(wm, num) ((wm->leds & WIIMOTE_LED_##num) == WIIMOTE_LED_##num) + +/* + * Largest known payload is 21 bytes. + * Add 2 for the prefix and round up to a power of 2. + */ +#define MAX_PAYLOAD 32 + +/* + * This is left over from an old hack, but it may actually + * be a useful feature to keep so it wasn't removed. + */ +#ifdef WIN32 + #define WIIMOTE_DEFAULT_TIMEOUT 100 + #define WIIMOTE_EXP_TIMEOUT 100 +#endif + +typedef unsigned char ubyte; +typedef char sbyte; +typedef unsigned short uword; +typedef short sword; +typedef unsigned int uint; +typedef char sint; + + +struct wiimote_t; +struct vec3b_t; +struct orient_t; +struct gforce_t; + +#ifdef GEKKO + typedef void (*wii_event_cb)(struct wiimote_t*, s32 event); +#endif + +/** + * @brief Callback that handles a read event. + * + * @param wm Pointer to a wiimote_t structure. + * @param data Pointer to the filled data block. + * @param len Length in bytes of the data block. + * + * @see wiiuse_init() + * + * A registered function of this type is called automatically by the wiiuse + * library when the wiimote has returned the full data requested by a previous + * call to wiiuse_read_data(). + */ +typedef void (*wiiuse_data_cb)(struct wiimote_t* wm, ubyte* data, unsigned short len); + +typedef enum data_req_s +{ + REQ_READY = 0, + REQ_SENT, + REQ_DONE +} data_req_s; + +/** + * @struct data_req_t + * @brief Data read request structure. + */ +struct data_req_t { + lwp_node node; + ubyte data[48]; /**< buffer where read data is written */ + unsigned int len; + data_req_s state; /**< set to 1 if not using callback and needs to be cleaned up */ + wiiuse_data_cb cb; /**< read data callback */ + struct data_req_t *next; +}; + +typedef void (*cmd_blk_cb)(struct wiimote_t *wm,ubyte *data,uword len); + +typedef enum cmd_blk_s +{ + CMD_READY = 0, + CMD_SENT, + CMD_DONE +} cmd_blk_s; + +struct cmd_blk_t +{ + lwp_node node; + + ubyte data[48]; + uint len; + + cmd_blk_s state; + cmd_blk_cb cb; + + struct cmd_blk_t *next; +}; + + +/** + * @struct vec2b_t + * @brief Unsigned x,y byte vector. + */ +typedef struct vec2b_t { + ubyte x, y; +} vec2b_t; + + +/** +* @struct vec3b_t +* @brief Unsigned x,y,z byte vector. +*/ +typedef struct vec3b_t { + ubyte x, y, z; +} vec3b_t; + +/** +* @struct vec3b_t +* @brief Unsigned x,y,z byte vector. +*/ +typedef struct vec3w_t { + uword x, y, z; +} vec3w_t; + + +/** + * @struct vec3f_t + * @brief Signed x,y,z float struct. + */ +typedef struct vec3f_t { + float x, y, z; +} vec3f_t; + + +/** + * @struct orient_t + * @brief Orientation struct. + * + * Yaw, pitch, and roll range from -180 to 180 degrees. + */ +typedef struct orient_t { + float roll; /**< roll, this may be smoothed if enabled */ + float pitch; /**< pitch, this may be smoothed if enabled */ + float yaw; + + float a_roll; /**< absolute roll, unsmoothed */ + float a_pitch; /**< absolute pitch, unsmoothed */ +} orient_t; + + +/** + * @struct gforce_t + * @brief Gravity force struct. + */ +typedef struct gforce_t { + float x, y, z; +} gforce_t; + + +/** + * @struct accel_t + * @brief Accelerometer struct. For any device with an accelerometer. + */ +typedef struct accel_t { + struct vec3w_t cal_zero; /**< zero calibration */ + struct vec3w_t cal_g; /**< 1g difference around 0cal */ + + float st_roll; /**< last smoothed roll value */ + float st_pitch; /**< last smoothed roll pitch */ + float st_alpha; /**< alpha value for smoothing [0-1] */ +} accel_t; + + +/** + * @struct ir_dot_t + * @brief A single IR source. + */ +typedef struct ir_dot_t { + ubyte visible; /**< if the IR source is visible */ + + short rx; /**< raw X coordinate (0-1023) */ + short ry; /**< raw Y coordinate (0-767) */ + + ubyte size; /**< size of the IR dot (0-15) */ +} ir_dot_t; + + +typedef struct fdot_t { + float x,y; +} fdot_t; + +typedef struct sb_t { + fdot_t dots[2]; + fdot_t acc_dots[2]; + fdot_t rot_dots[2]; + float angle; + float off_angle; + float score; +} sb_t; + +/** + * @enum aspect_t + * @brief Screen aspect ratio. + */ +typedef enum aspect_t { + WIIUSE_ASPECT_4_3, + WIIUSE_ASPECT_16_9 +} aspect_t; + + +/** + * @struct ir_t + * @brief IR struct. Hold all data related to the IR tracking. + */ +typedef struct ir_t { + struct ir_dot_t dot[4]; /**< IR dots */ + ubyte num_dots; /**< number of dots at this time */ + + int state; /**< keeps track of the IR state */ + + int raw_valid; /**< is the raw position valid? */ + sb_t sensorbar; /**< sensor bar, detected or guessed */ + float ax; /**< raw X coordinate */ + float ay; /**< raw Y coordinate */ + float distance; /**< pixel width of the sensor bar */ + float z; /**< calculated distance in meters */ + float angle; /**< angle of the wiimote to the sensor bar*/ + + int smooth_valid; /**< is the smoothed position valid? */ + float sx; /**< smoothed X coordinate */ + float sy; /**< smoothed Y coordinate */ + float error_cnt; /**< error count, for smoothing algorithm*/ + float glitch_cnt; /**< glitch count, same */ + + int valid; /**< is the bounded position valid? */ + float x; /**< bounded X coordinate */ + float y; /**< bounded Y coordinate */ + enum aspect_t aspect; /**< aspect ratio of the screen */ + enum ir_position_t pos; /**< IR sensor bar position */ + unsigned int vres[2]; /**< IR virtual screen resolution */ + int offset[2]; /**< IR XY correction offset */ + +} ir_t; + + +/** + * @struct joystick_t + * @brief Joystick calibration structure. + * + * The angle \a ang is relative to the positive y-axis into quadrant I + * and ranges from 0 to 360 degrees. So if the joystick is held straight + * upwards then angle is 0 degrees. If it is held to the right it is 90, + * down is 180, and left is 270. + * + * The magnitude \a mag is the distance from the center to where the + * joystick is being held. The magnitude ranges from 0 to 1. + * If the joystick is only slightly tilted from the center the magnitude + * will be low, but if it is closer to the outter edge the value will + * be higher. + */ +typedef struct joystick_t { + struct vec2b_t max; /**< maximum joystick values */ + struct vec2b_t min; /**< minimum joystick values */ + struct vec2b_t center; /**< center joystick values */ + struct vec2b_t pos; /**< raw position values */ + + float ang; /**< angle the joystick is being held */ + float mag; /**< magnitude of the joystick (range 0-1) */ +} joystick_t; + + +/** + * @struct nunchuk_t + * @brief Nunchuk expansion device. + */ +typedef struct nunchuk_t { + struct accel_t accel_calib; /**< nunchuk accelerometer calibration */ + struct joystick_t js; /**< joystick calibration */ + + int* flags; /**< options flag (points to wiimote_t.flags) */ + + ubyte btns; /**< what buttons have just been pressed */ + ubyte btns_last; /**< what buttons have just been pressed */ + ubyte btns_held; /**< what buttons are being held down */ + ubyte btns_released; /**< what buttons were just released this */ + + struct vec3w_t accel; /**< current raw acceleration data */ + struct orient_t orient; /**< current orientation on each axis */ + struct gforce_t gforce; /**< current gravity forces on each axis */ +} nunchuk_t; + + +/** + * @struct classic_ctrl_t + * @brief Classic controller expansion device. + */ +typedef struct classic_ctrl_t { + short btns; /**< what buttons have just been pressed */ + short btns_last; /**< what buttons have just been pressed */ + short btns_held; /**< what buttons are being held down */ + short btns_released; /**< what buttons were just released this */ + + ubyte rs_raw; + ubyte ls_raw; + + float r_shoulder; /**< right shoulder button (range 0-1) */ + float l_shoulder; /**< left shoulder button (range 0-1) */ + + struct joystick_t ljs; /**< left joystick calibration */ + struct joystick_t rjs; /**< right joystick calibration */ + ubyte type; /**< original, pro, wiiu pro */ +} classic_ctrl_t; + + +/** + * @struct guitar_hero_3_t + * @brief Guitar Hero 3 expansion device. + */ +typedef struct guitar_hero_3_t { + short btns; /**< what buttons have just been pressed */ + short btns_last; /**< what buttons have just been pressed */ + short btns_held; /**< what buttons are being held down */ + short btns_released; /**< what buttons were just released this */ + + ubyte wb_raw; + float whammy_bar; /**< whammy bar (range 0-1) */ + + ubyte tb_raw; + int touch_bar; /**< touch bar */ + + struct joystick_t js; /**< joystick calibration */ +} guitar_hero_3_t; + +/** + * @struct wii_board_t + * @brief Wii Balance Board expansion device. + */ +typedef struct wii_board_t { + float tl; /* Interpolated */ + float tr; + float bl; + float br; /* End interp */ + short rtl; /* RAW */ + short rtr; + short rbl; + short rbr; /* /RAW */ + short ctl[3]; /* Calibration */ + short ctr[3]; + short cbl[3]; + short cbr[3]; /* /Calibration */ + float x; + float y; +} wii_board_t; + +typedef struct motion_plus_t +{ + short rx, ry, rz; + ubyte status; + ubyte ext; +} motion_plus_t; + +/** + * @struct expansion_t + * @brief Generic expansion device plugged into wiimote. + */ +typedef struct expansion_t { + int type; /**< type of expansion attached */ + + union { + struct nunchuk_t nunchuk; + struct classic_ctrl_t classic; + struct guitar_hero_3_t gh3; + struct wii_board_t wb; + struct motion_plus_t mp; + }; +} expansion_t; + + +/** + * @enum win32_bt_stack_t + * @brief Available bluetooth stacks for Windows. + */ +typedef enum win_bt_stack_t { + WIIUSE_STACK_UNKNOWN, + WIIUSE_STACK_MS, + WIIUSE_STACK_BLUESOLEIL +} win_bt_stack_t; + + +/** + * @struct wiimote_state_t + * @brief Significant data from the previous event. + */ +typedef struct wiimote_state_t { + unsigned short btns; + + struct ir_t ir; + struct vec3w_t accel; + struct expansion_t exp; +} wiimote_state_t; + + +/** + * @enum WIIUSE_EVENT_TYPE + * @brief Events that wiiuse can generate from a poll. + */ +typedef enum WIIUSE_EVENT_TYPE { + WIIUSE_NONE = 0, + WIIUSE_EVENT, + WIIUSE_STATUS, + WIIUSE_CONNECT, + WIIUSE_DISCONNECT, + WIIUSE_UNEXPECTED_DISCONNECT, + WIIUSE_READ_DATA, + WIIUSE_ACK, + WIIUSE_NUNCHUK_INSERTED, + WIIUSE_NUNCHUK_REMOVED, + WIIUSE_CLASSIC_CTRL_INSERTED, + WIIUSE_CLASSIC_CTRL_REMOVED, + WIIUSE_GUITAR_HERO_3_CTRL_INSERTED, + WIIUSE_GUITAR_HERO_3_CTRL_REMOVED, + WIIUSE_WII_BOARD_INSERTED, + WIIUSE_WII_BOARD_REMOVED, + WIIUSE_MOTION_PLUS_ACTIVATED, + WIIUSE_MOTION_PLUS_REMOVED +} WIIUSE_EVENT_TYPE; + +/** + * @struct wiimote_t + * @brief Wiimote structure. + */ +typedef struct wiimote_t { + WCONST int unid; /**< user specified id */ + + #if defined(_WIN32) + WCONST HANDLE dev_handle; /**< HID handle */ + WCONST OVERLAPPED hid_overlap; /**< overlap handle */ + WCONST enum win_bt_stack_t stack; /**< type of bluetooth stack to use */ + WCONST int timeout; /**< read timeout */ + WCONST ubyte normal_timeout; /**< normal timeout */ + WCONST ubyte exp_timeout; /**< timeout for expansion handshake */ + #elif defined(GEKKO) + WCONST lwp_queue cmdq; + WCONST struct bd_addr bdaddr; /**< bt address */ + WCONST char bdaddr_str[18]; /**< readable bt address */ + WCONST struct bte_pcb *sock; /**< output socket */ + WCONST wii_event_cb event_cb; /**< event callback */ + #elif defined(unix) + WCONST bdaddr_t bdaddr; /**< bt address */ + WCONST char bdaddr_str[18]; /**< readable bt address */ + WCONST int out_sock; /**< output socket */ + WCONST int in_sock; /**< input socket */ + #endif + + WCONST int state; /**< various state flags */ + WCONST ubyte leds; /**< currently lit leds */ +#ifdef GEKKO + WCONST ubyte battery_level; /**< battery level */ +#else + WCONST float battery_level; /**< battery level */ +#endif + + WCONST int flags; /**< options flag */ + + WCONST ubyte handshake_state; /**< the state of the connection handshake */ + WCONST ubyte expansion_state; /**< the state of the expansion handshake */ + + WCONST struct data_req_t* data_req; /**< list of data read requests */ + + WCONST struct cmd_blk_t *cmd_head; + WCONST struct cmd_blk_t *cmd_tail; + + WCONST struct accel_t accel_calib; /**< wiimote accelerometer calibration */ + WCONST struct expansion_t exp; /**< wiimote expansion device */ + + WCONST struct vec3w_t accel; /**< current raw acceleration data */ + WCONST struct orient_t orient; /**< current orientation on each axis */ + WCONST struct gforce_t gforce; /**< current gravity forces on each axis */ + + WCONST struct ir_t ir; /**< IR data */ + + WCONST unsigned short btns; /**< what buttons are down */ + WCONST unsigned short btns_last; /**< what buttons were down before */ + WCONST unsigned short btns_held; /**< what buttons are and were held down */ + WCONST unsigned short btns_released; /**< what buttons were just released */ + + WCONST struct wiimote_state_t lstate; /**< last saved state */ + + WCONST WIIUSE_EVENT_TYPE event; /**< type of event that occured */ + WCONST ubyte event_buf[MAX_PAYLOAD]; /**< event buffer */ + + WCONST ubyte motion_plus_id[6]; +} wiimote; + +#if defined(GEKKO) +/** + * @struct wiimote_listen_t + * @brief Wiimote listen structure. + */ +typedef struct wiimote_listen_t { + WCONST struct bd_addr bdaddr; + WCONST struct bte_pcb *sock; + WCONST struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr); + WCONST struct wiimote_t *wm; +} wiimote_listen; +#endif + +/***************************************** + * + * Include API specific stuff + * + *****************************************/ + +#ifdef _WIN32 + #define WIIUSE_EXPORT_DECL __declspec(dllexport) + #define WIIUSE_IMPORT_DECL __declspec(dllimport) +#else + #define WIIUSE_EXPORT_DECL + #define WIIUSE_IMPORT_DECL +#endif + +#ifdef WIIUSE_COMPILE_LIB + #define WIIUSE_EXPORT WIIUSE_EXPORT_DECL +#else + #define WIIUSE_EXPORT WIIUSE_IMPORT_DECL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* wiiuse.c */ +WIIUSE_EXPORT extern const char* wiiuse_version(); + +#ifndef GEKKO +WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes); +#else +WIIUSE_EXPORT extern int wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr)); +WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes, wii_event_cb event_cb); +WIIUSE_EXPORT extern void wiiuse_sensorbar_enable(int enable); +#endif + +WIIUSE_EXPORT extern void wiiuse_disconnected(struct wiimote_t* wm); +WIIUSE_EXPORT extern void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes); +WIIUSE_EXPORT extern void wiiuse_rumble(struct wiimote_t* wm, int status); +WIIUSE_EXPORT extern void wiiuse_toggle_rumble(struct wiimote_t* wm); +WIIUSE_EXPORT extern void wiiuse_set_leds(struct wiimote_t* wm, int leds,cmd_blk_cb cb); +WIIUSE_EXPORT extern void wiiuse_motion_sensing(struct wiimote_t* wm, int status); +WIIUSE_EXPORT extern int wiiuse_read_data(struct wiimote_t* wm, ubyte* buffer, unsigned int offset, unsigned short len, cmd_blk_cb cb); +WIIUSE_EXPORT extern int wiiuse_write_data(struct wiimote_t *wm,unsigned int addr,ubyte *data,ubyte len,cmd_blk_cb cb); +WIIUSE_EXPORT extern void wiiuse_status(struct wiimote_t *wm,cmd_blk_cb cb); +WIIUSE_EXPORT extern struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid); +WIIUSE_EXPORT extern int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable); +WIIUSE_EXPORT extern float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha); +WIIUSE_EXPORT extern void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt_stack_t type); +WIIUSE_EXPORT extern void wiiuse_resync(struct wiimote_t* wm); +WIIUSE_EXPORT extern void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, ubyte normal_timeout, ubyte exp_timeout); +WIIUSE_EXPORT extern int wiiuse_write_streamdata(struct wiimote_t *wm,ubyte *data,ubyte len,cmd_blk_cb cb); + +/* connect.c */ +WIIUSE_EXPORT extern int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout); +WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_t** wm, int wiimotes); +WIIUSE_EXPORT extern void wiiuse_disconnect(struct wiimote_t* wm); + +/* events.c */ +WIIUSE_EXPORT extern int wiiuse_poll(struct wiimote_t** wm, int wiimotes); + +/* ir.c */ +WIIUSE_EXPORT extern void wiiuse_set_ir_mode(struct wiimote_t *wm); +WIIUSE_EXPORT extern void wiiuse_set_ir(struct wiimote_t* wm, int status); +WIIUSE_EXPORT extern void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y); +WIIUSE_EXPORT extern void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos); +WIIUSE_EXPORT extern void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect); +WIIUSE_EXPORT extern void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level); + +/* motion_plus.c */ +WIIUSE_EXPORT extern void wiiuse_set_motion_plus(struct wiimote_t *wm, int status); + +/* speaker.c */ +WIIUSE_EXPORT extern void wiiuse_set_speaker(struct wiimote_t *wm, int status); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/include/wiiuse/wpad.h b/wii/libogc/include/wiiuse/wpad.h new file mode 100644 index 0000000000..3f7f5c496e --- /dev/null +++ b/wii/libogc/include/wiiuse/wpad.h @@ -0,0 +1,208 @@ +/*------------------------------------------------------------- + +wpad.h -- Wiimote Application Programmers Interface + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef __WPAD_H__ +#define __WPAD_H__ + +#include +#include + +#define WPAD_MAX_IR_DOTS 4 + +enum { + WPAD_CHAN_ALL = -1, + WPAD_CHAN_0, + WPAD_CHAN_1, + WPAD_CHAN_2, + WPAD_CHAN_3, + WPAD_BALANCE_BOARD, + WPAD_MAX_WIIMOTES, +}; + +#define WPAD_BUTTON_2 0x0001 +#define WPAD_BUTTON_1 0x0002 +#define WPAD_BUTTON_B 0x0004 +#define WPAD_BUTTON_A 0x0008 +#define WPAD_BUTTON_MINUS 0x0010 +#define WPAD_BUTTON_HOME 0x0080 +#define WPAD_BUTTON_LEFT 0x0100 +#define WPAD_BUTTON_RIGHT 0x0200 +#define WPAD_BUTTON_DOWN 0x0400 +#define WPAD_BUTTON_UP 0x0800 +#define WPAD_BUTTON_PLUS 0x1000 + +#define WPAD_NUNCHUK_BUTTON_Z (0x0001<<16) +#define WPAD_NUNCHUK_BUTTON_C (0x0002<<16) + +#define WPAD_CLASSIC_BUTTON_UP (0x0001<<16) +#define WPAD_CLASSIC_BUTTON_LEFT (0x0002<<16) +#define WPAD_CLASSIC_BUTTON_ZR (0x0004<<16) +#define WPAD_CLASSIC_BUTTON_X (0x0008<<16) +#define WPAD_CLASSIC_BUTTON_A (0x0010<<16) +#define WPAD_CLASSIC_BUTTON_Y (0x0020<<16) +#define WPAD_CLASSIC_BUTTON_B (0x0040<<16) +#define WPAD_CLASSIC_BUTTON_ZL (0x0080<<16) +#define WPAD_CLASSIC_BUTTON_FULL_R (0x0200<<16) +#define WPAD_CLASSIC_BUTTON_PLUS (0x0400<<16) +#define WPAD_CLASSIC_BUTTON_HOME (0x0800<<16) +#define WPAD_CLASSIC_BUTTON_MINUS (0x1000<<16) +#define WPAD_CLASSIC_BUTTON_FULL_L (0x2000<<16) +#define WPAD_CLASSIC_BUTTON_DOWN (0x4000<<16) +#define WPAD_CLASSIC_BUTTON_RIGHT (0x8000<<16) + +#define WPAD_GUITAR_HERO_3_BUTTON_STRUM_UP (0x0001<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_YELLOW (0x0008<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_GREEN (0x0010<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_BLUE (0x0020<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_RED (0x0040<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_ORANGE (0x0080<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_PLUS (0x0400<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_MINUS (0x1000<<16) +#define WPAD_GUITAR_HERO_3_BUTTON_STRUM_DOWN (0x4000<<16) + +enum { + WPAD_EXP_NONE = 0, + WPAD_EXP_NUNCHUK, + WPAD_EXP_CLASSIC, + WPAD_EXP_GUITARHERO3, + WPAD_EXP_WIIBOARD, + WPAD_EXP_UNKNOWN = 255 +}; + +enum { + WPAD_FMT_BTNS = 0, + WPAD_FMT_BTNS_ACC, + WPAD_FMT_BTNS_ACC_IR +}; + +enum { + WPAD_STATE_DISABLED, + WPAD_STATE_ENABLING, + WPAD_STATE_ENABLED +}; + +#define WPAD_ERR_NONE 0 +#define WPAD_ERR_NO_CONTROLLER -1 +#define WPAD_ERR_NOT_READY -2 +#define WPAD_ERR_TRANSFER -3 +#define WPAD_ERR_NONEREGISTERED -4 +#define WPAD_ERR_UNKNOWN -5 +#define WPAD_ERR_BAD_CHANNEL -6 +#define WPAD_ERR_QUEUE_EMPTY -7 +#define WPAD_ERR_BADVALUE -8 +#define WPAD_ERR_BADCONF -9 + +#define WPAD_DATA_BUTTONS 0x01 +#define WPAD_DATA_ACCEL 0x02 +#define WPAD_DATA_EXPANSION 0x04 +#define WPAD_DATA_IR 0x08 + +#define WPAD_ENC_FIRST 0x00 +#define WPAD_ENC_CONT 0x01 + +#define WPAD_THRESH_IGNORE -1 +#define WPAD_THRESH_ANY 0 +#define WPAD_THRESH_DEFAULT_BUTTONS 0 +#define WPAD_THRESH_DEFAULT_IR WPAD_THRESH_IGNORE +#define WPAD_THRESH_DEFAULT_ACCEL 20 +#define WPAD_THRESH_DEFAULT_JOYSTICK 2 +#define WPAD_THRESH_DEFAULT_BALANCEBOARD 60 +#define WPAD_THRESH_DEFAULT_MOTION_PLUS 100 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +typedef struct _wpad_data +{ + s16 err; + + u32 data_present; + u8 battery_level; + + u32 btns_h; + u32 btns_l; + u32 btns_d; + u32 btns_u; + + struct ir_t ir; + struct vec3w_t accel; + struct orient_t orient; + struct gforce_t gforce; + struct expansion_t exp; +} WPADData; + +typedef struct _wpad_encstatus +{ + u8 data[32]; +}WPADEncStatus; + +typedef void (*WPADDataCallback)(s32 chan, const WPADData *data); +typedef void (*WPADShutdownCallback)(s32 chan); + +s32 WPAD_Init(); +s32 WPAD_ControlSpeaker(s32 chan,s32 enable); +s32 WPAD_ReadEvent(s32 chan, WPADData *data); +s32 WPAD_DroppedEvents(s32 chan); +s32 WPAD_Flush(s32 chan); +s32 WPAD_ReadPending(s32 chan, WPADDataCallback datacb); +s32 WPAD_SetDataFormat(s32 chan, s32 fmt); +s32 WPAD_SetMotionPlus(s32 chan, u8 enable); +s32 WPAD_SetVRes(s32 chan,u32 xres,u32 yres); +s32 WPAD_GetStatus(); +s32 WPAD_Probe(s32 chan,u32 *type); +s32 WPAD_SetEventBufs(s32 chan, WPADData *bufs, u32 cnt); +s32 WPAD_Disconnect(s32 chan); +s32 WPAD_IsSpeakerEnabled(s32 chan); +s32 WPAD_SendStreamData(s32 chan,void *buf,u32 len); +void WPAD_Shutdown(); +void WPAD_SetIdleTimeout(u32 seconds); +void WPAD_SetPowerButtonCallback(WPADShutdownCallback cb); +void WPAD_SetBatteryDeadCallback(WPADShutdownCallback cb); +s32 WPAD_ScanPads(); +s32 WPAD_Rumble(s32 chan, int status); +s32 WPAD_SetIdleThresholds(s32 chan, s32 btns, s32 ir, s32 accel, s32 js, s32 wb, s32 mp); +void WPAD_EncodeData(WPADEncStatus *info,u32 flag,const s16 *pcmSamples,s32 numSamples,u8 *encData); +WPADData *WPAD_Data(int chan); +u8 WPAD_BatteryLevel(int chan); +u32 WPAD_ButtonsUp(int chan); +u32 WPAD_ButtonsDown(int chan); +u32 WPAD_ButtonsHeld(int chan); +void WPAD_IR(int chan, struct ir_t *ir); +void WPAD_Orientation(int chan, struct orient_t *orient); +void WPAD_GForce(int chan, struct gforce_t *gforce); +void WPAD_Accel(int chan, struct vec3w_t *accel); +void WPAD_Expansion(int chan, struct expansion_t *exp); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif diff --git a/wii/libogc/libdb/debug.c b/wii/libogc/libdb/debug.c new file mode 100644 index 0000000000..f9dce171de --- /dev/null +++ b/wii/libogc/libdb/debug.c @@ -0,0 +1,653 @@ +#include +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "spinlock.h" +#include "lwp.h" +#include "lwp_threads.h" +#include "sys_state.h" +#include "context.h" +#include "cache.h" +#include "video.h" +#include "ogcsys.h" + +#include "lwp_config.h" + +#include "tcpip.h" +#include "geckousb.h" +#include "debug_if.h" +#include "debug_supp.h" + +#define GEKKO_MAX_BP 256 + +#define SP_REGNUM 1 //register no. for stackpointer +#define PC_REGNUM 64 //register no. for programcounter (srr0) + +#define BUFMAX 2048 //we take the same as in ppc-stub.c + +#define BPCODE 0x7d821008 + +#define highhex(x) hexchars [((x)>>4)&0xf] +#define lowhex(x) hexchars [(x)&0xf] + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +static s32 dbg_active = 0; +static s32 dbg_instep = 0; +static s32 dbg_initialized = 0; + +static struct dbginterface *current_device = NULL; + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +const char hexchars[]="0123456789abcdef"; + +static struct hard_trap_info { + u32 tt; + u8 signo; +} hard_trap_info[] = { + {EX_MACH_CHECK,SIGSEGV},/* Machine Check */ + {EX_DSI,SIGSEGV}, /* Adress Error(store) DSI */ + {EX_ISI,SIGBUS}, /* Instruction Bus Error ISI */ + {EX_INT,SIGINT}, /* Interrupt */ + {EX_ALIGN,SIGBUS}, /* Alignment */ + {EX_PRG,SIGTRAP}, /* Breakpoint Trap */ + {EX_FP,SIGFPE}, /* FPU unavail */ + {EX_DEC,SIGALRM}, /* Decrementer */ + {EX_SYS_CALL,SIGSYS}, /* System Call */ + {EX_TRACE,SIGTRAP}, /* Singel-Step/Watch */ + {0xB,SIGILL}, /* Reserved */ + {EX_IABR,SIGTRAP}, /* Instruction Address Breakpoint (GEKKO) */ + {0xD,SIGFPE}, /* FP assist */ + {0,0} /* MUST be the last */ +}; + +static struct bp_entry { + u32 *address; + u32 instr; + struct bp_entry *next; +} bp_entries[GEKKO_MAX_BP]; + +static struct bp_entry *p_bpentries = NULL; +static frame_context current_thread_registers; + +void __breakinst(); +void c_debug_handler(frame_context *ctx); + +extern void dbg_exceptionhandler(); +extern void __exception_sethandler(u32 nExcept, void (*pHndl)(frame_context*)); + +extern void __clr_iabr(); +extern void __enable_iabr(); +extern void __disable_iabr(); +extern void __set_iabr(void *); + +extern const char *tcp_localip; +extern const char *tcp_netmask; +extern const char *tcp_gateway; +extern u8 __text_start[],__data_start[],__bss_start[]; +extern u8 __text_fstart[],__data_fstart[],__bss_fstart[]; + +static __inline__ void bp_init() +{ + s32 i; + + for(i=0;i= 'a' && ch <= 'f') + return ch-'a'+10; + if (ch >= '0' && ch <= '9') + return ch-'0'; + if (ch >= 'A' && ch <= 'F') + return ch-'A'+10; + return -1; +} + +static s32 hexToInt(char **ptr, s32 *ival) +{ + s32 cnt; + s32 val,nibble; + + val = 0; + cnt = 0; + while(**ptr) { + nibble = hex(**ptr); + if(nibble<0) break; + + val = (val<<4)|nibble; + cnt++; + + (*ptr)++; + } + *ival = val; + return cnt; +} + +static s32 computeSignal(s32 excpt) +{ + struct hard_trap_info *ht; + for(ht = hard_trap_info;ht->tt && ht->signo;ht++) { + if(ht->tt==excpt) return ht->signo; + } + return SIGHUP; +} + +static u32 insert_bp(void *mem) +{ + u32 i; + struct bp_entry *p; + + for(i=0;inext = p_bpentries; + p->address = mem; + p_bpentries = p; + + p->instr = *(p->address); + *(p->address) = BPCODE; + + DCStoreRangeNoSync((void*)((u32)mem&~0x1f),32); + ICInvalidateRange((void*)((u32)mem&~0x1f),32); + _sync(); + + return 1; +} + +static u32 remove_bp(void *mem) +{ + struct bp_entry *e = p_bpentries; + struct bp_entry *f = NULL; + + if(!e) return 0; + if(e->address==mem) { + p_bpentries = e->next; + f = e; + } else { + for(;e->next;e=e->next) { + if(e->next->address==mem) { + f = e->next; + e->next = f->next; + break; + } + } + } + if(!f) return 0; + + *(f->address) = f->instr; + f->instr = 0xffffffff; + f->address = NULL; + + DCStoreRangeNoSync((void*)((u32)mem&~0x1f),32); + ICInvalidateRange((void*)((u32)mem&~0x1f),32); + _sync(); + + return 1; +} + +static char getdbgchar() +{ + char ch = 0; + s32 len = 0; + + len = current_device->read(current_device,&ch,1); + + return (len>0)?ch:0; +} + +static void putdbgchar(char ch) +{ + current_device->write(current_device,&ch,1); +} + +static void putdbgstr(const char *str) +{ + current_device->write(current_device,str,strlen(str)); +} + +static void putpacket(const char *buffer) +{ + u8 recv; + u8 chksum,ch; + char *ptr; + const char *inp; + static char outbuf[2048]; + + do { + inp = buffer; + ptr = outbuf; + + *ptr++ = '$'; + + chksum = 0; + while((ch=*inp++)!='\0') { + *ptr++ = ch; + chksum += ch; + } + + *ptr++ = '#'; + *ptr++ = hexchars[chksum>>4]; + *ptr++ = hexchars[chksum&0x0f]; + *ptr = '\0'; + + putdbgstr(outbuf); + + recv = getdbgchar(); + } while((recv&0x7f)!='+'); +} + +static void getpacket(char *buffer) +{ + char ch; + u8 chksum,xmitsum; + s32 i,cnt; + + do { + while((ch=(getdbgchar()&0x7f))!='$'); + + cnt = 0; + chksum = 0; + xmitsum = -1; + + while(cnt=BUFMAX) continue; + + buffer[cnt] = 0; + if(ch=='#') { + xmitsum = hex(getdbgchar()&0x7f)<<4; + xmitsum |= hex(getdbgchar()&0x7f); + + if(chksum!=xmitsum) putdbgchar('-'); + else { + putdbgchar('+'); + if(buffer[2]==':') { + putdbgchar(buffer[0]); + putdbgchar(buffer[1]); + + cnt = strlen((const char*)buffer); + for(i=3;i<=cnt;i++) buffer[i-3] = buffer[i]; + } + } + } + } while(chksum!=xmitsum); +} + +static void process_query(const char *inp,char *outp,s32 thread) +{ + char *optr; + + switch(inp[1]) { + case 'C': + optr = outp; + *optr++ = 'Q'; + *optr++ = 'C'; + optr = thread2vhstr(optr,thread); + *optr++ = 0; + break; + case 'P': + { + s32 ret,rthread,mask; + struct gdbstub_threadinfo info; + + ret = parseqp(inp,&mask,&rthread); + if(!ret || mask&~0x1f) { + strcpy(outp,"E01"); + break; + } + + ret = gdbstub_getthreadinfo(rthread,&info); + if(!ret) { + strcpy(outp,"E02"); + break; + } + packqq(outp,mask,rthread,&info); + } + break; + case 'L': + { + s32 ret,athread,first,max_cnt,i,done,rthread; + + ret = parseql(inp,&first,&max_cnt,&athread); + if(!ret) { + strcpy(outp,"E02"); + break; + } + if(max_cnt==0) { + strcpy(outp,"E02"); + break; + } + if(max_cnt>QM_MAXTHREADS) max_cnt = QM_MAXTHREADS; + + optr = reserve_qmheader(outp); + if(first) rthread = 0; + else rthread = athread; + + done = 0; + for(i=0;iGPR,th->context.GPR,(32*4)); + memcpy(frame->FPR,th->context.FPR,(32*8)); + frame->SRR0 = th->context.LR; + frame->SRR1 = th->context.MSR; + frame->CR = th->context.CR; + frame->LR = th->context.LR; + frame->CTR = th->context.CTR; + frame->XER = th->context.XER; + frame->FPSCR = th->context.FPSCR; + return 1; + } + return 0; +} + +static void gdbstub_report_exception(frame_context *frame,s32 thread) +{ + s32 sigval; + char *ptr; + + ptr = remcomOutBuffer; + sigval = computeSignal(frame->EXCPT_Number); + *ptr++ = 'T'; + *ptr++ = highhex(sigval); + *ptr++ = lowhex(sigval); + *ptr++ = highhex(SP_REGNUM); + *ptr++ = lowhex(SP_REGNUM); + *ptr++ = ':'; + ptr = mem2hstr(ptr,(char*)&frame->GPR[1],4); + *ptr++ = ';'; + *ptr++ = highhex(PC_REGNUM); + *ptr++ = lowhex(PC_REGNUM); + *ptr++ = ':'; + ptr = mem2hstr(ptr,(char*)&frame->SRR0,4); + *ptr++ = ';'; + + *ptr++ = 't'; + *ptr++ = 'h'; + *ptr++ = 'r'; + *ptr++ = 'e'; + *ptr++ = 'a'; + *ptr++ = 'd'; + *ptr++ = ':'; + ptr = thread2vhstr(ptr,thread); + *ptr++ = ';'; + + *ptr++ = '\0'; + +} + + +void c_debug_handler(frame_context *frame) +{ + char *ptr; + s32 addr,len; + s32 thread,current_thread; + s32 host_has_detached; + frame_context *regptr; + + thread = gdbstub_getcurrentthread(); + current_thread = thread; + + if(current_device->open(current_device)<0) return; + + if(dbg_active) { + gdbstub_report_exception(frame,thread); + putpacket(remcomOutBuffer); + } + + if(frame->SRR0==(u32)__breakinst) frame->SRR0 += 4; + + host_has_detached = 0; + while(!host_has_detached) { + remcomOutBuffer[0]= 0; + getpacket(remcomInBuffer); + switch(remcomInBuffer[0]) { + case '?': + gdbstub_report_exception(frame,thread); + break; + case 'D': + dbg_instep = 0; + dbg_active = 0; + frame->SRR1 &= ~MSR_SE; + strcpy(remcomOutBuffer,"OK"); + host_has_detached = 1; + break; + case 'k': + dbg_instep = 0; + dbg_active = 0; + frame->SRR1 &= ~MSR_SE; + frame->SRR0 = 0x80001800; + host_has_detached = 1; + goto exit; + case 'g': + regptr = frame; + ptr = remcomOutBuffer; + if(current_thread!=thread) regptr = ¤t_thread_registers; + + ptr = mem2hstr(ptr,(char*)regptr->GPR,32*4); + ptr = mem2hstr(ptr,(char*)regptr->FPR,32*8); + ptr = mem2hstr(ptr,(char*)®ptr->SRR0,4); + ptr = mem2hstr(ptr,(char*)®ptr->SRR1,4); + ptr = mem2hstr(ptr,(char*)®ptr->CR,4); + ptr = mem2hstr(ptr,(char*)®ptr->LR,4); + ptr = mem2hstr(ptr,(char*)®ptr->CTR,4); + ptr = mem2hstr(ptr,(char*)®ptr->XER,4); + ptr = mem2hstr(ptr,(char*)®ptr->FPSCR,4); + break; + case 'm': + ptr = &remcomInBuffer[1]; + if(hexToInt(&ptr,&addr) && ((addr&0xC0000000)==0xC0000000 || (addr&0xC0000000)==0x80000000) + && *ptr++==',' + && hexToInt(&ptr,&len) && len<=((BUFMAX - 4)/2)) + mem2hstr(remcomOutBuffer,(void*)addr,len); + else + strcpy(remcomOutBuffer,"E00"); + break; + case 'q': + process_query(remcomInBuffer,remcomOutBuffer,thread); + break; + case 'c': + dbg_instep = 0; + dbg_active = 1; + frame->SRR1 &= ~MSR_SE; + current_device->wait(current_device); + goto exit; + case 's': + dbg_instep = 1; + dbg_active = 1; + frame->SRR1 |= MSR_SE; + current_device->wait(current_device); + goto exit; + case 'z': + { + s32 ret,type; + u32 len; + char *addr; + + ret = parsezbreak(remcomInBuffer,&type,&addr,&len); + if(!ret) { + strcpy(remcomOutBuffer,"E01"); + break; + } + if(type!=0) break; + + if(len<4) { + strcpy(remcomOutBuffer,"E02"); + break; + } + + ret = remove_bp(addr); + if(!ret) { + strcpy(remcomOutBuffer,"E03"); + break; + } + strcpy(remcomOutBuffer,"OK"); + } + break; + case 'H': + if(remcomInBuffer[1]=='g') + { + s32 tmp,ret; + + if(vhstr2thread(&remcomInBuffer[2],&tmp)==NULL) { + strcpy(remcomOutBuffer,"E01"); + break; + } + if(!tmp) tmp = thread; + if(tmp==current_thread) { + strcpy(remcomOutBuffer,"OK"); + break; + } + + if(current_thread!=thread) ret = gdbstub_setthreadregs(current_thread,¤t_thread_registers); + if(tmp!=thread) { + ret = gdbstub_getthreadregs(tmp,¤t_thread_registers); + if(!ret) { + strcpy(remcomOutBuffer,"E02"); + break; + } + } + current_thread= tmp; + } + strcpy(remcomOutBuffer,"OK"); + break; + case 'T': + { + s32 tmp; + + if(vhstr2thread(&remcomInBuffer[1],&tmp)==NULL) { + strcpy(remcomOutBuffer,"E01"); + break; + } + if(gdbstub_indextoid(tmp)==NULL) strcpy(remcomOutBuffer,"E02"); + else strcpy(remcomOutBuffer,"OK"); + } + break; + case 'Z': + { + s32 ret,type; + u32 len; + char *addr; + + ret = parsezbreak(remcomInBuffer,&type,&addr,&len); + if(!ret) { + strcpy(remcomOutBuffer,"E01"); + break; + } + if(type!=0) { + strcpy(remcomOutBuffer,"E02"); + break; + } + if(len<4) { + strcpy(remcomOutBuffer,"E03"); + break; + } + + ret = insert_bp(addr); + if(!ret) { + strcpy(remcomOutBuffer,"E04"); + break; + } + strcpy(remcomOutBuffer,"OK"); + } + break; + } + putpacket(remcomOutBuffer); + } + current_device->close(current_device); +exit: + return; +} + +void _break(void) +{ + if(!dbg_initialized) return; + __asm__ __volatile__ (".globl __breakinst\n\ + __breakinst: .long 0x7d821008"); +} + +void DEBUG_Init(s32 device_type,s32 channel_port) +{ + u32 level; + struct uip_ip_addr localip,netmask,gateway; + + UIP_LOG("DEBUG_Init()\n"); + + __lwp_thread_dispatchdisable(); + + bp_init(); + + if(device_type==GDBSTUB_DEVICE_USB) { + current_device = usb_init(channel_port); + } else { + localip.addr = uip_ipaddr((const u8_t*)tcp_localip); + netmask.addr = uip_ipaddr((const u8_t*)tcp_netmask); + gateway.addr = uip_ipaddr((const u8_t*)tcp_gateway); + + current_device = tcpip_init(&localip,&netmask,&gateway,(u16)channel_port); + } + + if(current_device!=NULL) { + _CPU_ISR_Disable(level); + __exception_sethandler(EX_DSI,dbg_exceptionhandler); + __exception_sethandler(EX_PRG,dbg_exceptionhandler); + __exception_sethandler(EX_TRACE,dbg_exceptionhandler); + __exception_sethandler(EX_IABR,dbg_exceptionhandler); + _CPU_ISR_Restore(level); + + dbg_initialized = 1; + + } + __lwp_thread_dispatchenable(); +} + diff --git a/wii/libogc/libdb/debug_handler.S b/wii/libogc/libdb/debug_handler.S new file mode 100644 index 0000000000..7a311a3c13 --- /dev/null +++ b/wii/libogc/libdb/debug_handler.S @@ -0,0 +1,169 @@ +#include + +#define EXCEPTION_PROLOG \ + mfspr r0,912; \ + stw r0,GQR0_OFFSET(sp); \ + mfspr r0,913; \ + stw r0,GQR1_OFFSET(sp); \ + mfspr r0,914; \ + stw r0,GQR2_OFFSET(sp); \ + mfspr r0,915; \ + stw r0,GQR3_OFFSET(sp); \ + mfspr r0,916; \ + stw r0,GQR4_OFFSET(sp); \ + mfspr r0,917; \ + stw r0,GQR5_OFFSET(sp); \ + mfspr r0,918; \ + stw r0,GQR6_OFFSET(sp); \ + mfspr r0,919; \ + stw r0,GQR7_OFFSET(sp); \ + stmw r6,GPR6_OFFSET(sp) + +#define EXCEPTION_EPILOG \ + lwz r4,GQR0_OFFSET(sp); \ + mtspr 912,r4; \ + lwz r4,GQR1_OFFSET(sp); \ + mtspr 913,r4; \ + lwz r4,GQR2_OFFSET(sp); \ + mtspr 914,r4; \ + lwz r4,GQR3_OFFSET(sp); \ + mtspr 915,r4; \ + lwz r4,GQR4_OFFSET(sp); \ + mtspr 916,r4; \ + lwz r4,GQR5_OFFSET(sp); \ + mtspr 917,r4; \ + lwz r4,GQR6_OFFSET(sp); \ + mtspr 918,r4; \ + lwz r4,GQR7_OFFSET(sp); \ + mtspr 919,r4; \ + lmw r5,GPR5_OFFSET(sp) + + .extern c_debug_handler + .extern _cpu_context_save_fp + .globl dbg_exceptionhandler +dbg_exceptionhandler: + stwu sp,-EXCEPTION_FRAME_END(sp) //now we're able to adjust the stackpointer with it's cached address + + EXCEPTION_PROLOG + + mfmsr r4 + ori r4,r4,MSR_FP + mtmsr r4 + isync + + addi r14,sp,0 + + lis r15,__debug_nestlevel@ha + lwz r6,__debug_nestlevel@l(r15) + cmpwi r6,0 + bne nested + + lis sp,__debugstack@h + ori sp,sp,__debugstack@l + lis r0,0 + stwu r0,-16(sp) + +nested: + addi r6,r6,1 + stw r6,__debug_nestlevel@l(r15) + + addi r3,r14,0x08 + bl _cpu_context_save_fp + bl c_debug_handler + + lwz r6,__debug_nestlevel@l(r15) + addi r6,r6,-1 + stw r6,__debug_nestlevel@l(r15) + + addi sp,r14,0 + +exit: + lwz r4,CR_OFFSET(sp) + mtcr r4 + lwz r4,LR_OFFSET(sp) + mtlr r4 + lwz r4,CTR_OFFSET(sp) + mtctr r4 + lwz r4,XER_OFFSET(sp) + mtxer r4 + + EXCEPTION_EPILOG + + mfmsr r4 + rlwinm r4,r4,0,19,17 + mtmsr r4 + isync + + lwz toc,GPR2_OFFSET(sp) + lwz r0,GPR0_OFFSET(sp) + + lwz r4,SRR0_OFFSET(sp) + mtsrr0 r4 + lwz r4,SRR1_OFFSET(sp) + mtsrr1 r4 + + lwz r4,GPR4_OFFSET(sp) + lwz r3,GPR3_OFFSET(sp) + addi sp,sp,EXCEPTION_FRAME_END + rfi + + .globl __set_iabr +__set_iabr: + mfmsr r4 + rlwinm r5,r4,0,18,16 + mtmsr r5 + clrrwi r3,r3,2 + mtspr 1010,r3 + isync + sync + mtmsr r4 + blr + + .globl __enable_iabr +__enable_iabr: + mfmsr r4 + rlwinm r5,r4,0,18,16 + mtmsr r5 + mfspr r3,1010 + ori r3,r3,0x0003 + mtspr 1010,r3 + isync + sync + mtmsr r4 + blr + + .globl __disable_iabr +__disable_iabr: + mfmsr r4 + rlwinm r5,r4,0,18,16 + mtmsr r5 + mfspr r3,1010 + clrrwi r3,r3,2 + mtspr 1010,r3 + isync + sync + mtmsr r4 + blr + + .globl __clr_iabr +__clr_iabr: + mfmsr r4 + rlwinm r5,r4,0,18,16 + mtmsr r5 + mtspr 1010,0 + isync + sync + mtmsr r4 + blr + + .section .bss + + .balign 4 +__debug_nestlevel: + .long 0 + + .balign 8 + .globl __debugstack_end,__debugstack +__debugstack_end: + .space 0x4000 +__debugstack: diff --git a/wii/libogc/libdb/debug_if.h b/wii/libogc/libdb/debug_if.h new file mode 100644 index 0000000000..d739a7cde8 --- /dev/null +++ b/wii/libogc/libdb/debug_if.h @@ -0,0 +1,20 @@ +#ifndef __DEBUG_IF_H__ +#define __DEBUG_IF_H__ + +#include + +#define GDBSTUB_DEVICE_USB 0 +#define GDBSTUB_DEVICE_TCP 1 + +struct dbginterface +{ + s32 fhndl; + + int (*open)(struct dbginterface *device); + int (*close)(struct dbginterface *device); + int (*wait)(struct dbginterface *device); + int (*read)(struct dbginterface *device,void *buffer,int size); + int (*write)(struct dbginterface *devicec,const void *buffer,int size); +}; + +#endif diff --git a/wii/libogc/libdb/debug_supp.c b/wii/libogc/libdb/debug_supp.c new file mode 100644 index 0000000000..dbbc7d0c5f --- /dev/null +++ b/wii/libogc/libdb/debug_supp.c @@ -0,0 +1,477 @@ +#include +#include +#include +#include + +#include "lwp_threads.h" +#include "debug_supp.h" + +extern lwp_objinfo _lwp_cond_objects; +extern lwp_objinfo _lwp_thr_objects; +extern lwp_objinfo _lwp_tqueue_objects; +extern lwp_objinfo _lwp_mqbox_objects; +extern lwp_objinfo _lwp_mutex_objects; +extern lwp_objinfo _lwp_sema_objects; + +extern const u8 hexchars[]; + +extern u8 __text_start[],__data_start[],__bss_start[]; +extern u8 __text_fstart[],__data_fstart[],__bss_fstart[]; + +s32 hstr2nibble(const char *buf,s32 *nibble) +{ + s32 ch; + + ch = *buf; + if(ch>='0' && ch<='9') { + *nibble = ch - '0'; + return 1; + } + if(ch>='a' && ch<='f') { + *nibble = ch - 'a' + 10; + return 1; + } + if(ch>='A' && ch<='F') { + *nibble = ch - 'A' + 10; + return 1; + } + return 0; +} + +s32 hstr2byte(const char *buf,s32 *bval) +{ + s32 hnib,lnib; + + if(!hstr2nibble(buf,&hnib) || !hstr2nibble(buf+1,&lnib)) return 0; + + *bval = (hnib<<4)|lnib; + return 1; +} + +const char* vhstr2int(const char *buf,s32 *ival) +{ + s32 i,val,nibble; + s32 found0,lim; + + found0 = 0; + for(i=0;i<8;i++,buf++) { + if(*buf!='0') break; + + found0 = 1; + } + + val = 0; + lim = 8 - i; + for(i=0;i>shift)&0x0f; + *buf = hexchars[nibble]; + } + return buf; +} + +char* int2vhstr(char *buf,s32 val) +{ + s32 i,nibble,shift; + + for(i=0,shift=28;i<8;i++,shift-=4) { + nibble = (val>>shift)&0x0f; + if(nibble) break; + } + if(i==8) { + *buf++ = '0'; + return buf; + } + + *buf++ = hexchars[nibble]; + for(i++,shift-=4;i<8;i++,shift-=4,buf++) { + nibble = (val>>shift)&0x0f; + *buf = hexchars[nibble]; + } + return buf; +} + +char* mem2hstr(char *buf,const char *mem,s32 count) +{ + s32 i; + char ch; + + for(i=0;i>4]; + *buf++ = hexchars[ch&0x0f]; + } + *buf = 0; + return buf; +} +char* thread2fhstr(char *buf,s32 thread) +{ + s32 i,nibble,shift; + + for(i=0;i<8;i++,buf++) *buf = '0'; + for(i=0,shift=28;i<8;i++,shift-=4,buf++) { + nibble = (thread>>shift)&0x0f; + *buf = hexchars[nibble]; + } + return buf; +} + +char* thread2vhstr(char *buf,s32 thread) +{ + s32 i,nibble,shift; + + for(i=0,shift=28;i<8;i++,shift-=4) { + nibble = (thread>>shift)&0x0f; + if(nibble) break; + } + if(i==8) { + *buf++ = '0'; + return buf; + } + + *buf++ = hexchars[nibble]; + for(i++,shift-=4;i<8;i++,shift-=4,buf++) { + nibble = (thread>>shift)&0x0f; + *buf = hexchars[nibble]; + } + return buf; +} + +const char* fhstr2thread(const char *buf,s32 *thread) +{ + s32 i,nibble,val; + + for(i=0;i<8;i++,buf++) + if(*buf!='0') return NULL; + + val = 0; + for(i=0;i<8;i++,buf++) { + if(!hstr2nibble(buf,&nibble)) return NULL; + + val = (val<<4)|nibble; + } + + *thread = val; + return buf; +} + +const char* vhstr2thread(const char *buf,s32 *thread) +{ + s32 i,val,nibble; + s32 found0,lim; + + found0 = 0; + for(i=0;i<16;i++,buf++) { + if(*buf!='0') break; + + found0 = 1; + } + + val = 0; + lim = 16 - i; + for(i=0;i=min_id && objidobject.id); +} + +s32 gdbstub_getnextthread(s32 athread) +{ + s32 id,start; + s32 first_id,min_id,max_id,lim; + + if(athread<1) return 1; + + first_id = 1; + min_id = _lwp_thr_objects.min_id; + max_id = _lwp_thr_objects.max_id; + lim = first_id + max_id - min_id; + if(athreaddisplay,"idle thread"); + strcpy(info->name,"IDLE"); + info->more_display[0] = 0; + return 1; + } + + first_id = 1; + min_id = _lwp_thr_objects.min_id; + max_id = _lwp_thr_objects.max_id; + if(thread<=(first_id + (max_id - min_id))){ + th = (lwp_cntrl*)_lwp_thr_objects.local_table[thread - first_id]; + if(th==NULL) return 0; + + strcpy(info->display,"libogc task: control at: 0x"); + tmp_buf[0] = hexchars[(((int)th)>>28)&0x0f]; + tmp_buf[1] = hexchars[(((int)th)>>24)&0x0f]; + tmp_buf[2] = hexchars[(((int)th)>>20)&0x0f]; + tmp_buf[3] = hexchars[(((int)th)>>16)&0x0f]; + tmp_buf[4] = hexchars[(((int)th)>>12)&0x0f]; + tmp_buf[5] = hexchars[(((int)th)>>8)&0x0f]; + tmp_buf[6] = hexchars[(((int)th)>>4)&0x0f]; + tmp_buf[7] = hexchars[((int)th)&0x0f]; + tmp_buf[8] = 0; + strcat(info->display,tmp_buf); + + info->name[0] = 0; + info->name[1] = 0; + info->name[2] = 0; + info->name[3] = 0; + info->name[4] = 0; + + info->more_display[0] = 0; + return 1; + } + return 0; +} + +s32 parsezbreak(const char *in,s32 *type,char **addr,u32 *len) +{ + s32 ttmp,atmp,ltmp; + + in++; + if(!hstr2nibble(in,&ttmp) || *(in+1)!=',') return 0; + + in += 2; + in = vhstr2int(in,&atmp); + if(in==NULL || *in!=',') return 0; + + in++; + in = vhstr2int(in,<mp); + if(in==NULL || ltmp<1) return 0; + + *type = ttmp; + *addr = (char*)atmp; + *len = ltmp; + + return 1; +} + +s32 parseqp(const char *in,s32 *mask,s32 *thread) +{ + const char *ptr; + + ptr = fhstr2int(in+2,mask); + if(ptr==NULL) return 0; + + ptr = fhstr2thread(ptr,thread); + if(ptr==NULL) return 0; + + return 1; +} + +void packqq(char *out,s32 mask,s32 thread,struct gdbstub_threadinfo *info) +{ + s32 len; + + *out++ = 'q'; + *out++ = 'Q'; + out = int2fhstr(out,mask); + out = thread2fhstr(out,thread); + + if(mask&0x01) { + memcpy(out,"00000001",8); + out += 8; + *out++ = '1'; + *out++ = '0'; + out = thread2fhstr(out,thread); + } + if(mask&0x02) { + memcpy(out,"00000002",8); + out += 8; + *out++ = '0'; + *out++ = '1'; + *out++ = '1'; + } + if(mask&0x04) { + memcpy(out,"00000004",8); + out += 8; + + info->display[sizeof(info->display)-1] = 0; //for god sake + len = strlen(info->display); + + *out++ = hexchars[(len>>4)&0x0f]; + *out++ = hexchars[len&0x0f]; + + memcpy(out,info->display,len); + out += len; + } + if(mask&0x08) { + memcpy(out,"00000008",8); + out += 8; + + info->display[sizeof(info->name)-1] = 0; //for god sake + len = strlen(info->name); + + *out++ = hexchars[(len>>4)&0x0f]; + *out++ = hexchars[len&0x0f]; + + memcpy(out,info->name,len); + out += len; + } + if(mask&0x10) { + memcpy(out,"00000010",8); + out += 8; + + info->display[sizeof(info->more_display)-1] = 0; //for god sake + len = strlen(info->more_display); + + *out++ = hexchars[(len>>4)&0x0f]; + *out++ = hexchars[len&0x0f]; + + memcpy(out,info->more_display,len); + out += len; + } + *out = 0; +} + +s32 parseql(const char *in,s32 *first,s32 *max_cnt,s32 *athread) +{ + const char *ptr; + + ptr = in+2; + if(!hstr2nibble(ptr,first)) return 0; + + ptr++; + if(!hstr2byte(ptr,max_cnt)) return 0; + + ptr += 2; + ptr = fhstr2thread(ptr,athread); + if(ptr==NULL) return 0; + + return 1; +} + +char* reserve_qmheader(char *out) +{ + return (out+21); +} + +char* packqmthread(char *out,s32 thread) +{ + return thread2fhstr(out,thread); +} + +void packqmheader(char *out,s32 count,s32 done,s32 athread) +{ + *out++ = 'q'; + *out++ = 'M'; + *out++ = hexchars[(count>>4)&0x0f]; + *out++ = hexchars[count&0x0f]; + + if(done) *out++ = '1'; + else *out++ = '0'; + + thread2fhstr(out,athread); +} diff --git a/wii/libogc/libdb/debug_supp.h b/wii/libogc/libdb/debug_supp.h new file mode 100644 index 0000000000..a12e38663c --- /dev/null +++ b/wii/libogc/libdb/debug_supp.h @@ -0,0 +1,32 @@ +#ifndef __DEBUG_SUPP_H__ +#define __DEBUG_SUPP_H__ + +#include + +#define QM_MAXTHREADS (20) + +struct gdbstub_threadinfo { + char display[256]; + char more_display[256]; + char name[256]; +}; + +s32 gdbstub_getcurrentthread(); +s32 hstr2nibble(const char *buf,s32 *nibble); +char* int2vhstr(char *buf,s32 val); +char* mem2hstr(char *buf,const char *mem,s32 count); +char* thread2vhstr(char *buf,s32 thread); +const char* vhstr2thread(const char *buf,s32 *thread); +lwp_cntrl* gdbstub_indextoid(s32 thread); +s32 gdbstub_getoffsets(char **textaddr,char **dataaddr,char **bssaddr); +s32 parsezbreak(const char *in,s32 *type,char **addr,u32 *len); +s32 gdbstub_getthreadinfo(s32 thread,struct gdbstub_threadinfo *info); +s32 parseqp(const char *in,s32 *mask,s32 *thread); +void packqq(char *out,s32 mask,s32 thread,struct gdbstub_threadinfo *info); +char* reserve_qmheader(char *out); +s32 parseql(const char *in,s32 *first,s32 *max_cnt,s32 *athread); +s32 gdbstub_getnextthread(s32 athread); +char* packqmthread(char *out,s32 thread); +void packqmheader(char *out,s32 count,s32 done,s32 athread); + +#endif diff --git a/wii/libogc/libdb/geckousb.c b/wii/libogc/libdb/geckousb.c new file mode 100644 index 0000000000..2e92e2dd79 --- /dev/null +++ b/wii/libogc/libdb/geckousb.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include + +#include "geckousb.h" + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +static struct dbginterface usb_device; + +static __inline__ int __send_command(s32 chn,u16 *cmd) +{ + s32 ret; + + ret = 0; + if(!EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED32MHZ)) ret |= 0x01; + if(!EXI_Imm(chn,cmd,sizeof(u16),EXI_READWRITE,NULL)) ret |= 0x02; + if(!EXI_Sync(chn)) ret |= 0x04; + if(!EXI_Deselect(chn)) ret |= 0x08; + + if(ret) return 0; + return 1; +} + +static int __usb_sendbyte(s32 chn,char ch) +{ + s32 ret; + u16 val; + + val = (0xB000|_SHIFTL(ch,4,8)); + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0400)) ret = 0; + + return ret; +} + +static int __usb_recvbyte(s32 chn,char *ch) +{ + s32 ret; + u16 val; + + *ch = 0; + val = 0xA000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0800)) ret = 0; + else if(ret==1) *ch = (val&0xff); + + return ret; +} + +static int __usb_checksend(s32 chn) +{ + s32 ret; + u16 val; + + val = 0xC000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0400)) ret = 0; + + return ret; +} + +static int __usb_checkrecv(s32 chn) +{ + s32 ret; + u16 val; + + val = 0xD000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0400)) ret = 0; + + return ret; +} + +static void __usb_flush(s32 chn) +{ + char tmp; + + if(!EXI_Lock(chn,EXI_DEVICE_0,NULL)) return; + + while(__usb_recvbyte(chn,&tmp)); + + EXI_Unlock(chn); +} + + +static int __usb_isgeckoalive(s32 chn) +{ + s32 ret; + u16 val; + + if(!EXI_Lock(chn,EXI_DEVICE_0,NULL)) return 0; + + val = 0x9000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0470)) ret = 0; + + EXI_Unlock(chn); + return ret; +} + +static int __usb_recvbuffer(s32 chn,void *buffer,int size) +{ + s32 ret; + s32 left = size; + char *ptr = (char*)buffer; + + if(!EXI_Lock(chn,EXI_DEVICE_0,NULL)) return 0; + + while(left>0) { + if(__usb_checkrecv(chn)) { + ret = __usb_recvbyte(chn,ptr); + if(ret==0) break; + + ptr++; + left--; + } + } + + EXI_Unlock(chn); + return (size - left); +} + +static int __usb_sendbuffer(s32 chn,const void *buffer,int size) +{ + s32 ret; + s32 left = size; + char *ptr = (char*)buffer; + + if(!EXI_Lock(chn,EXI_DEVICE_0,NULL)) return 0; + + while(left>0) { + if(__usb_checksend(chn)) { + ret = __usb_sendbyte(chn,*ptr); + if(ret==0) break; + + ptr++; + left--; + } + } + + EXI_Unlock(chn); + return (size - left); +} + +static int usbopen(struct dbginterface *device) +{ + if(!__usb_isgeckoalive(device->fhndl)) { + return -1; + } + + return 0; +} + +static int usbclose(struct dbginterface *device) +{ + return 0; +} + +static int usbwait(struct dbginterface *device) +{ + return 0; +} + +static int usbread(struct dbginterface *device,void *buffer,int size) +{ + int ret; + ret = __usb_recvbuffer(device->fhndl,buffer,size); + return ret; +} + +static int usbwrite(struct dbginterface *device,const void *buffer,int size) +{ + int ret; + ret = __usb_sendbuffer(device->fhndl,buffer,size); + return ret; +} + +struct dbginterface* usb_init(s32 channel) +{ + usb_device.fhndl = channel; + if(__usb_isgeckoalive(channel)) + __usb_flush(channel); + + usb_device.open = usbopen; + usb_device.close = usbclose; + usb_device.wait = usbwait; + usb_device.read = usbread; + usb_device.write = usbwrite; + + return &usb_device; +} diff --git a/wii/libogc/libdb/geckousb.h b/wii/libogc/libdb/geckousb.h new file mode 100644 index 0000000000..7e14a42d90 --- /dev/null +++ b/wii/libogc/libdb/geckousb.h @@ -0,0 +1,8 @@ +#ifndef __GECKOUSB_H___ +#define __GECKOUSB_H___ + +#include "debug_if.h" + +struct dbginterface* usb_init(s32 channel); + +#endif diff --git a/wii/libogc/libdb/tcpip.c b/wii/libogc/libdb/tcpip.c new file mode 100644 index 0000000000..66a4889553 --- /dev/null +++ b/wii/libogc/libdb/tcpip.c @@ -0,0 +1,466 @@ +#include +#include +#include + +#include "asm.h" +#include "processor.h" + +#include "uIP/bba.h" +#include "uIP/memr.h" +#include "uIP/memb.h" +#include "uIP/uip_ip.h" +#include "uIP/uip_arp.h" +#include "uIP/uip_tcp.h" +#include "uIP/uip_pbuf.h" +#include "uIP/uip_netif.h" + +#include "tcpip.h" +#include "debug_if.h" + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +const char *tcp_localip __attribute__ ((weak)) = ""; +const char *tcp_netmask __attribute__ ((weak)) = ""; +const char *tcp_gateway __attribute__ ((weak)) = ""; + +struct tcpip_sock { + struct tcpip_sock *next; + struct uip_tcp_pcb *pcb; + struct uip_pbuf *lastdata; + s32 lastoffset,recvevt,sendevt,flags; + s32 err,socket; +} tcpip_socks[UIP_TCPIP_SOCKS]; + +static s64 tcpip_time = 0; +static s32 listensock = -1; +static struct uip_netif netif; +static struct dbginterface netif_device; +static struct tcpip_sock *tcpip_accepted_sockets = NULL; + +extern s64 gettime(); +extern u32 diff_msec(s64 start,s64 end); + +static s32_t tcpip_allocsocket(struct uip_tcp_pcb *pcb) +{ + s32_t i; + + for(i=0;i=UIP_TCPIP_SOCKS) return NULL; + + sock = &tcpip_socks[s]; + if(!sock->pcb) return NULL; + + return sock; +} + +//device callbacks +static int opentcpip(struct dbginterface *device) +{ + if(listensock>=0 && (device->fhndl<0 )) + device->fhndl = tcpip_accept(listensock); + + if(device->fhndl<0) + return -1; + else + tcpip_starttimer(device->fhndl); + + return 0; +} + +static int closetcpip(struct dbginterface *device) +{ + tcpip_stoptimer(device->fhndl); + tcpip_close(device->fhndl); + device->fhndl = -1; + return 0; +} + +static int waittcpip(struct dbginterface *device) +{ + tcpip_stoptimer(device->fhndl); + return 0; +} + +static int readtcpip(struct dbginterface *device,void *buffer,int size) +{ + if(device->fhndl>=0) + return tcpip_read(device->fhndl,buffer,size); + + return 0; +} + +static int writetcpip(struct dbginterface *device,const void *buffer,int size) +{ + if(device->fhndl>=0) + return tcpip_write(device->fhndl,buffer,size); + + return 0; +} + +static void tcpip_err(void *arg,s8_t err) +{ +// printf("tcpip_err: err_code(%d)\n",err); +} + +static s8_t tcpip_poll(void *arg,struct uip_tcp_pcb *pcb) +{ + UIP_LOG("tcpip_poll()"); + return UIP_ERR_OK; +} + +static s8_t tcpip_sent(void *arg,struct uip_tcp_pcb *pcb,u16_t space) +{ +// printf("tcpip_sent(%d)\n",space); + return UIP_ERR_OK; +} + +//static u32 qcnt = 0; + +static s8_t tcpip_recved(void *arg,struct uip_tcp_pcb *pcb,struct uip_pbuf *p,s8_t err) +{ + u16_t len; + struct tcpip_sock *sock = (struct tcpip_sock*)arg; + + //printf("tcpip_recved(%s (%d/%d))\n",(u8_t*)p->payload,p->len,p->tot_len); + if(!sock) { + uip_pbuf_free(p); + return UIP_ERR_VAL; + } + + if(p) { + len = p->tot_len; + if(sock->lastdata==NULL) { + sock->lastdata = p; + } else { +/* + qcnt++; + printf("tcpip_recved(queuing %d)\n",qcnt); +*/ + uip_pbuf_queue(sock->lastdata,p); + } + } else + len = 1; + + uip_tcp_recved(pcb,len); + return UIP_ERR_OK; +} + + +static s8_t tcpip_accept_func(void *arg,struct uip_tcp_pcb *newpcb,s8_t err) +{ + s32_t s; + struct tcpip_sock *ptr,*newsock = NULL; + struct tcpip_sock *sock = (struct tcpip_sock*)arg; + + UIP_LOG("tcpip_accept_func()"); + if(!sock) return UIP_ERR_ABRT; + + s = tcpip_allocsocket(newpcb); + if(s<0) { + uip_tcp_close(newpcb); + return UIP_ERR_ABRT; + } + + newsock = tcpip_getsocket(s); + newsock->pcb->flags |= UIP_TF_NODELAY; + + ptr = tcpip_accepted_sockets; + while(ptr && ptr->next) ptr = ptr->next; + if(!ptr) tcpip_accepted_sockets = newsock; + else ptr->next = newsock; + + uip_tcp_arg(newpcb,newsock); + uip_tcp_recv(newpcb,tcpip_recved); + uip_tcp_sent(newpcb,tcpip_sent); + uip_tcp_err(newpcb,tcpip_err); + uip_tcp_poll(newpcb,tcpip_poll,4); + + return UIP_ERR_OK; +} + +static void __tcpip_poll() +{ + u32 diff; + s64 now; + + if(uip_netif_default==NULL) return; + + uip_bba_poll(uip_netif_default); + + if(tcpip_time && (uip_tcp_active_pcbs || uip_tcp_tw_pcbs)) { + now = gettime(); + diff = diff_msec(tcpip_time,now); + if(diff>=UIP_TCP_TMR_INTERVAL) { + uip_tcp_tmr(); + tcpip_time = gettime(); + } + } else + tcpip_time = 0; +} + +void tcpip_tmr_needed() +{ + if(!tcpip_time && (uip_tcp_active_pcbs || uip_tcp_tw_pcbs)) { + tcpip_time = gettime(); + } +} + +struct dbginterface* tcpip_init(struct uip_ip_addr *localip,struct uip_ip_addr *netmask,struct uip_ip_addr *gateway,u16 port) +{ + uipdev_s hbba; + struct uip_netif *pnet ; + struct sockaddr_in name; + socklen_t namelen = sizeof(struct sockaddr); + + memr_init(); + uip_ipinit(); + uip_pbuf_init(); + uip_netif_init(); + uip_tcp_init(); + + UIP_MEMSET(tcpip_socks,0,(UIP_TCPIP_SOCKS*sizeof(struct tcpip_sock))); + + hbba = uip_bba_create(&netif); + pnet = uip_netif_add(&netif,localip,netmask,gateway,hbba,uip_bba_init,uip_ipinput); + if(pnet) { + uip_netif_setdefault(pnet); + + listensock = tcpip_socket(); + if(listensock<0) return NULL; + + name.sin_addr.s_addr = INADDR_ANY; + name.sin_port = htons(port); + name.sin_family = AF_INET; + + if(tcpip_bind(listensock,(struct sockaddr*)&name,&namelen)<0){ + tcpip_close(listensock); + listensock = -1; + return NULL; + } + if(tcpip_listen(listensock,1)<0) { + tcpip_close(listensock); + listensock = -1; + return NULL; + } + + netif_device.fhndl = -1; + netif_device.wait = waittcpip; + netif_device.open = opentcpip; + netif_device.close = closetcpip; + netif_device.read = readtcpip; + netif_device.write = writetcpip; + + return &netif_device; + } + return NULL; +} + +s32_t tcpip_socket() +{ + s32_t s; + struct tcpip_sock *sock; + struct uip_tcp_pcb *pcb; + + pcb = uip_tcp_new(); + if(!pcb) return -1; + + s = tcpip_allocsocket(pcb); + if(s<0) { + uip_tcp_close(pcb); + return -1; + } + + sock = tcpip_getsocket(s); + uip_tcp_arg(pcb,sock); + + return s; +} + +s32_t tcpip_bind(s32_t s,struct sockaddr *name,socklen_t *namelen) +{ + struct tcpip_sock *sock; + struct uip_ip_addr local_ip; + u16_t local_port; + s8_t err; + + sock = tcpip_getsocket(s); + if(!sock) return -1; + + local_ip.addr = ((struct sockaddr_in*)name)->sin_addr.s_addr; + local_port = ((struct sockaddr_in*)name)->sin_port; + + err = uip_tcp_bind(sock->pcb,&local_ip,local_port); + + return (s32_t)err; +} + +s32_t tcpip_listen(s32_t s,u32_t backlog) +{ + struct tcpip_sock *sock; + + sock = tcpip_getsocket(s); + if(!sock) return -1; + + sock->pcb = uip_tcp_listen(sock->pcb); + if(sock->pcb==NULL) return -1; + + uip_tcp_accept(sock->pcb,tcpip_accept_func); + + return 0; +} + +s32_t tcpip_accept(s32_t s) +{ + s32_t newsock = -1; + struct tcpip_sock *sock; + + sock = tcpip_getsocket(s); + if(sock==NULL) return -1; + + do { + __tcpip_poll(); + } while(!tcpip_accepted_sockets); + + newsock = tcpip_accepted_sockets->socket; + tcpip_accepted_sockets = tcpip_accepted_sockets->next; + + return newsock; +} + +s32_t tcpip_read(s32_t s,void *buffer,u32_t len) +{ + u32_t off,copy; + u8_t *ptr; + struct uip_pbuf *p; + struct tcpip_sock *sock; + + sock = tcpip_getsocket(s); + if(!sock) return -1; + + do { + __tcpip_poll(); + } while(sock->lastdata==NULL); + + if(sock->lastdata) { + off = 0; + ptr = buffer; + while(len>0 && sock->lastdata) { + p = sock->lastdata; + + if(len>p->len-sock->lastoffset) copy = (p->len-sock->lastoffset); + else copy = len; + + UIP_MEMCPY(ptr+off,(u8_t*)p->payload+sock->lastoffset,copy); + + off += copy; + len -= copy; + sock->lastoffset += copy; + + if(sock->lastoffset>=p->len) { + sock->lastoffset = 0; + sock->lastdata = uip_pbuf_dequeue(p); + uip_pbuf_free(p); +/* + if(qcnt>0) { + printf("tcpip_read(dequeuing %d)\n",--qcnt); + } +*/ + } + } + return off; + } + return -1; +} + +s32_t tcpip_write(s32_t s,const void *buffer,u32_t len) +{ + s8_t err; + u16_t snd_buf,copy; + struct tcpip_sock *sock; + + sock = tcpip_getsocket(s); + if(!sock) return -1; + +// printf("tcpip_write()\n"); + while(len>0) { + do { + __tcpip_poll(); + } while((snd_buf=uip_tcp_sndbuf(sock->pcb))==0); + + if(len>snd_buf) copy = snd_buf; + else copy = len; + + err = uip_tcp_write(sock->pcb,buffer,copy,1); + if(err==UIP_ERR_OK && (!sock->pcb->unacked || sock->pcb->flags&UIP_TF_NODELAY || sock->pcb->snd_queuelen>1)) + uip_tcpoutput(sock->pcb); + + buffer = buffer+copy; + len -= copy; + } + return UIP_ERR_OK; +} + +void tcpip_close(s32_t s) +{ + struct tcpip_sock *sock; + + sock = tcpip_getsocket(s); + if(sock==NULL) return; + + uip_tcp_close(sock->pcb); + sock->pcb = NULL; +} + +// does basically only stop the tcpip timer +void tcpip_stoptimer(s32_t s) +{ + struct tcpip_sock *sock; + + sock = tcpip_getsocket(s); + if(!sock) return; + + if(tcpip_time && sock->pcb && (uip_tcp_active_pcbs || uip_tcp_tw_pcbs)) tcpip_time = 0; +} + +// does basically only restart the tcpip timer +void tcpip_starttimer(s32_t s) +{ + struct tcpip_sock *sock; + + sock = tcpip_getsocket(s); + if(!sock) return; + + if(tcpip_time==0 && sock->pcb && (uip_tcp_active_pcbs || uip_tcp_tw_pcbs)) tcpip_time = gettime(); +} + diff --git a/wii/libogc/libdb/tcpip.h b/wii/libogc/libdb/tcpip.h new file mode 100644 index 0000000000..99f9db73e2 --- /dev/null +++ b/wii/libogc/libdb/tcpip.h @@ -0,0 +1,53 @@ +#ifndef __TCPIP_H__ +#define __TCPIP_H__ + +#include "uIP/uip.h" +#include +#include + +#define AF_UNSPEC 0 +#define AF_INET 2 +#define PF_INET AF_INET +#define PF_UNSPEC AF_UNSPEC + +#define INADDR_ANY 0 +#define INADDR_BROADCAST 0xffffffff + +#ifndef socklen_t +#define socklen_t u32_t +#endif + +#ifndef HAVE_IN_ADDR +#define HAVE_IN_ADDR +struct in_addr { + u32 s_addr; +}; +#endif + +struct sockaddr_in { + u8 sin_len; + u8 sin_family; + u16 sin_port; + struct in_addr sin_addr; + s8 sin_zero[8]; +}; + +struct sockaddr { + u8 sa_len; + u8 sa_family; + s8 sa_data[14]; +}; + +struct dbginterface* tcpip_init(struct uip_ip_addr *localip,struct uip_ip_addr *netmask,struct uip_ip_addr *gateway,u16 port); + +void tcpip_close(s32_t s); +void tcpip_starttimer(s32_t s); +void tcpip_stoptimer(s32_t s); +s32_t tcpip_socket(); +s32_t tcpip_listen(s32_t s,u32_t backlog); +s32_t tcpip_bind(s32_t s,struct sockaddr *name,socklen_t *namelen); +s32_t tcpip_accept(s32_t s); +s32_t tcpip_read(s32_t s,void *buffer,u32_t len); +s32_t tcpip_write(s32_t s,const void *buffer,u32_t len); + +#endif diff --git a/wii/libogc/libdb/uIP/bba.c b/wii/libogc/libdb/uIP/bba.c new file mode 100644 index 0000000000..0e6075ecf8 --- /dev/null +++ b/wii/libogc/libdb/uIP/bba.c @@ -0,0 +1,835 @@ +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "exi.h" +#include "cache.h" +#include "bba.h" +#include "uip_pbuf.h" +#include "uip_netif.h" +#include "uip_arp.h" + +#define IFNAME0 'e' +#define IFNAME1 't' + +#define BBA_MINPKTSIZE 60 + +#define BBA_CID 0x04020200 + +#define BBA_CMD_IRMASKALL 0x00 +#define BBA_CMD_IRMASKNONE 0xF8 + +#define BBA_NCRA 0x00 /* Network Control Register A, RW */ +#define BBA_NCRA_RESET (1<<0) /* RESET */ +#define BBA_NCRA_ST0 (1<<1) /* ST0, Start transmit command/status */ +#define BBA_NCRA_ST1 (1<<2) /* ST1, " */ +#define BBA_NCRA_SR (1<<3) /* SR, Start Receive */ + +#define BBA_NCRB 0x01 /* Network Control Register B, RW */ +#define BBA_NCRB_PR (1<<0) /* PR, Promiscuous Mode */ +#define BBA_NCRB_CA (1<<1) /* CA, Capture Effect Mode */ +#define BBA_NCRB_PM (1<<2) /* PM, Pass Multicast */ +#define BBA_NCRB_PB (1<<3) /* PB, Pass Bad Frame */ +#define BBA_NCRB_AB (1<<4) /* AB, Accept Broadcast */ +#define BBA_NCRB_HBD (1<<5) /* HBD, reserved */ +#define BBA_NCRB_RXINTC0 (1<<6) /* RXINTC, Receive Interrupt Counter */ +#define BBA_NCRB_RXINTC1 (1<<7) /* " */ +#define BBA_NCRB_1_PACKET_PER_INT (0<<6) /* 0 0 */ +#define BBA_NCRB_2_PACKETS_PER_INT (1<<6) /* 0 1 */ +#define BBA_NCRB_4_PACKETS_PER_INT (2<<6) /* 1 0 */ +#define BBA_NCRB_8_PACKETS_PER_INT (3<<6) /* 1 1 */ + +#define BBA_LTPS 0x04 /* Last Transmitted Packet Status, RO */ +#define BBA_LRPS 0x05 /* Last Received Packet Status, RO */ + +#define BBA_IMR 0x08 /* Interrupt Mask Register, RW, 00h */ +#define BBA_IMR_FRAGIM (1<<0) /* FRAGIM, Fragment Counter Int Mask */ +#define BBA_IMR_RIM (1<<1) /* RIM, Receive Interrupt Mask */ +#define BBA_IMR_TIM (1<<2) /* TIM, Transmit Interrupt Mask */ +#define BBA_IMR_REIM (1<<3) /* REIM, Receive Error Interrupt Mask */ +#define BBA_IMR_TEIM (1<<4) /* TEIM, Transmit Error Interrupt Mask */ +#define BBA_IMR_FIFOEIM (1<<5) /* FIFOEIM, FIFO Error Interrupt Mask */ +#define BBA_IMR_BUSEIM (1<<6) /* BUSEIM, BUS Error Interrupt Mask */ +#define BBA_IMR_RBFIM (1<<7) /* RBFIM, RX Buffer Full Interrupt Mask */ + +#define BBA_IR 0x09 /* Interrupt Register, RW, 00h */ +#define BBA_IR_FRAGI (1<<0) /* FRAGI, Fragment Counter Interrupt */ +#define BBA_IR_RI (1<<1) /* RI, Receive Interrupt */ +#define BBA_IR_TI (1<<2) /* TI, Transmit Interrupt */ +#define BBA_IR_REI (1<<3) /* REI, Receive Error Interrupt */ +#define BBA_IR_TEI (1<<4) /* TEI, Transmit Error Interrupt */ +#define BBA_IR_FIFOEI (1<<5) /* FIFOEI, FIFO Error Interrupt */ +#define BBA_IR_BUSEI (1<<6) /* BUSEI, BUS Error Interrupt */ +#define BBA_IR_RBFI (1<<7) /* RBFI, RX Buffer Full Interrupt */ + +#define BBA_BP 0x0a/*+0x0b*/ /* Boundary Page Pointer Register */ +#define BBA_TLBP 0x0c/*+0x0d*/ /* TX Low Boundary Page Pointer Register */ +#define BBA_TWP 0x0e/*+0x0f*/ /* Transmit Buffer Write Page Pointer Register */ +#define BBA_TRP 0x12/*+0x13*/ /* Transmit Buffer Read Page Pointer Register */ +#define BBA_RWP 0x16/*+0x17*/ /* Receive Buffer Write Page Pointer Register */ +#define BBA_RRP 0x18/*+0x19*/ /* Receive Buffer Read Page Pointer Register */ +#define BBA_RHBP 0x1a/*+0x1b*/ /* Receive High Boundary Page Pointer Register */ + +#define BBA_RXINTT 0x14/*+0x15*/ /* Receive Interrupt Timer Register */ + +#define BBA_NAFR_PAR0 0x20 /* Physical Address Register Byte 0 */ +#define BBA_NAFR_PAR1 0x21 /* Physical Address Register Byte 1 */ +#define BBA_NAFR_PAR2 0x22 /* Physical Address Register Byte 2 */ +#define BBA_NAFR_PAR3 0x23 /* Physical Address Register Byte 3 */ +#define BBA_NAFR_PAR4 0x24 /* Physical Address Register Byte 4 */ +#define BBA_NAFR_PAR5 0x25 /* Physical Address Register Byte 5 */ + +#define BBA_NWAYC 0x30 /* NWAY Configuration Register, RW, 84h */ +#define BBA_NWAYC_FD (1<<0) /* FD, Full Duplex Mode */ +#define BBA_NWAYC_PS100 (1<<1) /* PS100/10, Port Select 100/10 */ +#define BBA_NWAYC_ANE (1<<2) /* ANE, Autonegotiation Enable */ +#define BBA_NWAYC_ANS_RA (1<<3) /* ANS, Restart Autonegotiation */ +#define BBA_NWAYC_LTE (1<<7) /* LTE, Link Test Enable */ + +#define BBA_NWAYS 0x31 +#define BBA_NWAYS_LS10 (1<<0) +#define BBA_NWAYS_LS100 (1<<1) +#define BBA_NWAYS_LPNWAY (1<<2) +#define BBA_NWAYS_ANCLPT (1<<3) +#define BBA_NWAYS_100TXF (1<<4) +#define BBA_NWAYS_100TXH (1<<5) +#define BBA_NWAYS_10TXF (1<<6) +#define BBA_NWAYS_10TXH (1<<7) + +#define BBA_GCA 0x32 /* GMAC Configuration A Register, RW, 00h */ +#define BBA_GCA_ARXERRB (1<<3) /* ARXERRB, Accept RX packet with error */ + +#define BBA_MISC 0x3d /* MISC Control Register 1, RW, 3ch */ +#define BBA_MISC_BURSTDMA (1<<0) +#define BBA_MISC_DISLDMA (1<<1) + +#define BBA_TXFIFOCNT 0x3e/*0x3f*/ /* Transmit FIFO Counter Register */ +#define BBA_WRTXFIFOD 0x48/*-0x4b*/ /* Write TX FIFO Data Port Register */ + +#define BBA_MISC2 0x50 /* MISC Control Register 2, RW, 00h */ +#define BBA_MISC2_HBRLEN0 (1<<0) /* HBRLEN, Host Burst Read Length */ +#define BBA_MISC2_HBRLEN1 (1<<1) /* " */ +#define BBA_MISC2_RUNTSIZE (1<<2) /* " */ +#define BBA_MISC2_DREQBCTRL (1<<3) /* " */ +#define BBA_MISC2_RINTSEL (1<<4) /* " */ +#define BBA_MISC2_ITPSEL (3<<5) /* " */ +#define BBA_MISC2_AUTORCVR (1<<7) /* Auto RX Full Recovery */ + +#define BBA_RX_STATUS_BF (1<<0) +#define BBA_RX_STATUS_CRC (1<<1) +#define BBA_RX_STATUS_FAE (1<<2) +#define BBA_RX_STATUS_FO (1<<3) +#define BBA_RX_STATUS_RW (1<<4) +#define BBA_RX_STATUS_MF (1<<5) +#define BBA_RX_STATUS_RF (1<<6) +#define BBA_RX_STATUS_RERR (1<<7) + +#define BBA_TX_STATUS_CC0 (1<<0) +#define BBA_TX_STATUS_CC1 (1<<1) +#define BBA_TX_STATUS_CC2 (1<<2) +#define BBA_TX_STATUS_CC3 (1<<3) +#define BBA_TX_STATUS_CCMASK (0x0f) +#define BBA_TX_STATUS_CRSLOST (1<<4) +#define BBA_TX_STATUS_UF (1<<5) +#define BBA_TX_STATUS_OWC (1<<6) +#define BBA_TX_STATUS_OWN (1<<7) +#define BBA_TX_STATUS_TERR (1<<7) + +#define BBA_TX_MAX_PACKET_SIZE 1518 /* 14+1500+4 */ +#define BBA_RX_MAX_PACKET_SIZE 1536 /* 6 pages * 256 bytes */ + +#define BBA_INIT_TLBP 0x00 +#define BBA_INIT_BP 0x01 +#define BBA_INIT_RHBP 0x0f +#define BBA_INIT_RWP BBA_INIT_BP +#define BBA_INIT_RRP BBA_INIT_BP + +#define BBA_NAPI_WEIGHT 16 + +#define RX_BUFFERS 16 + +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) +static inline u16 cpu_to_le16(u16 x) { return (x<<8) | (x>>8);} +static inline u32 cpu_to_le32(u32 x) { return((x>>24) | ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));} + +#define cpu_to_le16p(addr) (cpu_to_le16(*(addr))) +#define cpu_to_le32p(addr) (cpu_to_le32(*(addr))) +#define cpu_to_be16p(addr) (cpu_to_be16(*(addr))) +#define cpu_to_be32p(addr) (cpu_to_be32(*(addr))) + +static inline void cpu_to_le16s(u16 *a) {*a = cpu_to_le16(*a);} +static inline void cpu_to_le32s(u32 *a) {*a = cpu_to_le32(*a);} +static inline void cpu_to_be16s(u16 *a) {*a = cpu_to_be16(*a);} +static inline void cpu_to_be32s(u32 *a) {*a = cpu_to_be32(*a);} + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) + +struct bba_priv { + u8 revid; + u16 devid; + u8 acstart; + s8_t state; + struct uip_eth_addr *ethaddr; +}; + +#define X(a,b) b,a +struct bba_descr { + u32 X(X(next_packet_ptr:12, packet_len:12), status:8); +} __attribute((packed)); + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +/* new functions */ +#define bba_select() EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_2,EXI_SPEED32MHZ) +#define bba_deselect() EXI_Deselect(EXI_CHANNEL_0) + +#define bba_in12(reg) ((bba_in8(reg)&0xff)|((bba_in8((reg)+1)&0x0f)<<8)) +#define bba_out12(reg,val) do { \ + bba_out8((reg),(val)&0xff); \ + bba_out8((reg)+1,((val)&0x0f00)>>8); \ + } while(0) + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +static s64 bba_arp_tmr = 0; + +static struct uip_pbuf *bba_recv_pbufs = NULL; +static struct uip_netif *bba_netif = NULL; +static struct bba_priv bba_device; +static struct bba_descr cur_descr; + +static void bba_cmd_ins(u32 reg,void *val,u32 len); +static void bba_cmd_outs(u32 reg,void *val,u32 len); +static void bba_ins(u32 reg,void *val,u32 len); +static void bba_outs(u32 reg,void *val,u32 len); + +static void bba_devpoll(u16 *pstatus); + +extern void udelay(int us); +extern u32 diff_msec(long long start,long long end); +extern u32 diff_usec(long long start,long long end); +extern long long gettime(); + +static __inline__ void bba_cmd_insnosel(u32 reg,void *val,u32 len) +{ + u16 req; + req = reg<<8; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_READ); +} + +static void bba_cmd_ins(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_cmd_insnosel(reg,val,len); + bba_deselect(); +} + +static __inline__ void bba_cmd_outsnosel(u32 reg,void *val,u32 len) +{ + u16 req; + req = (reg<<8)|0x4000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_WRITE); +} + +static void bba_cmd_outs(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_cmd_outsnosel(reg,val,len); + bba_deselect(); +} + +static inline u8 bba_cmd_in8(u32 reg) +{ + u8 val; + bba_cmd_ins(reg,&val,sizeof(val)); + return val; +} + +static inline u8 bba_cmd_in8_slow(u32 reg) +{ + u8 val; + bba_select(); + bba_cmd_insnosel(reg,&val,sizeof(val)); + udelay(200); //usleep doesn't work on this amount, decrementer is based on 10ms, wait is 200us + bba_deselect(); + return val; +} + +static inline void bba_cmd_out8(u32 reg,u8 val) +{ + bba_cmd_outs(reg,&val,sizeof(val)); +} + +static inline u8 bba_in8(u32 reg) +{ + u8 val; + bba_ins(reg,&val,sizeof(val)); + return val; +} + +static inline void bba_out8(u32 reg,u8 val) +{ + bba_outs(reg,&val,sizeof(val)); +} + +static inline void bba_insnosel(u32 reg,void *val,u32 len) +{ + u32 req; + req = (reg<<8)|0x80000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_READ); +} + +static void bba_ins(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_insnosel(reg,val,len); + bba_deselect(); +} + +static inline void bba_outsnoselect(u32 reg,void *val,u32 len) +{ + u32 req; + req = (reg<<8)|0xC0000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_WRITE); +} + +static void bba_outs(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_outsnoselect(reg,val,len); + bba_deselect(); +} + +static inline void bba_insregister(u32 reg) +{ + u32 req; + req = (reg<<8)|0x80000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); +} + +static inline void bba_insdata(void *val,u32 len) +{ + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_READ); +} + + +static inline void bba_outsregister(u32 reg) +{ + u32 req; + req = (reg<<8)|0xC0000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); +} + +static inline void bba_outsdata(void *val,u32 len) +{ + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_WRITE); +} + +static __inline__ u32 __linkstate() +{ + u8 nways = 0; + + nways = bba_in8(BBA_NWAYS); + if(nways&BBA_NWAYS_LS10 || nways&BBA_NWAYS_LS100) return 1; + return 0; +} + +static u32 __bba_getlink_state_async() +{ + u32 ret; + + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_2,NULL)==0) return 0; + ret = __linkstate(); + EXI_Unlock(EXI_CHANNEL_0); + return ret; +} + + +static u32 __bba_read_cid() +{ + u16 cmd = 0; + u32 cid = 0; + + bba_select(); + EXI_Imm(EXI_CHANNEL_0,&cmd,2,EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_Imm(EXI_CHANNEL_0,&cid,4,EXI_READ,NULL); + EXI_Sync(EXI_CHANNEL_0); + bba_deselect(); + + return cid; +} +static void __bba_reset() +{ + bba_out8(0x60,0x00); + udelay(10000); + bba_cmd_in8_slow(0x0F); + udelay(10000); + bba_out8(BBA_NCRA,BBA_NCRA_RESET); + bba_out8(BBA_NCRA,0x00); +} + +static void __bba_recv_init() +{ + bba_out8(BBA_NCRB,(BBA_NCRB_CA|BBA_NCRB_AB)); + bba_out8(BBA_MISC2,(BBA_MISC2_AUTORCVR)); + + bba_out12(BBA_TLBP, BBA_INIT_TLBP); + bba_out12(BBA_BP,BBA_INIT_BP); + bba_out12(BBA_RWP,BBA_INIT_RWP); + bba_out12(BBA_RRP,BBA_INIT_RRP); + bba_out12(BBA_RHBP,BBA_INIT_RHBP); + + bba_out8(BBA_GCA,BBA_GCA_ARXERRB); + bba_out8(BBA_NCRA,BBA_NCRA_SR); +} + +static void bba_process(struct uip_pbuf *p,struct uip_netif *dev) +{ + struct uip_eth_hdr *ethhdr = NULL; + struct bba_priv *priv = (struct bba_priv*)dev->state; + const s32 ethhlen = sizeof(struct uip_eth_hdr); + + if(p) { + ethhdr = p->payload; + switch(htons(ethhdr->type)) { + case UIP_ETHTYPE_IP: + uip_arp_ipin(dev,p); + uip_pbuf_header(p,-(ethhlen)); + dev->input(p,dev); + break; + case UIP_ETHTYPE_ARP: + uip_arp_arpin(dev,priv->ethaddr,p); + break; + default: + uip_pbuf_free(p); + break; + } + } +} + +static s8_t bba_start_rx(struct uip_netif *dev,u32 budget) +{ + s32 size; + u16 top,pos,rwp,rrp; + u32 pkt_status,recvd; + struct uip_pbuf *p,*q; + + UIP_LOG("bba_start_rx()\n"); + + recvd = 0; + rwp = bba_in12(BBA_RWP); + rrp = bba_in12(BBA_RRP); + while(recvd(BBA_RX_MAX_PACKET_SIZE+4)) { + UIP_LOG("bba_start_rx: packet dropped due to big buffer.\n"); + continue; + } + + if(pkt_status&(BBA_RX_STATUS_RERR|BBA_RX_STATUS_FAE)) { + UIP_LOG("bba_start_rx: packet dropped due to receive errors.\n"); + rwp = bba_in12(BBA_RWP); + rrp = bba_in12(BBA_RRP); + continue; + } + + pos = (rrp<<8)+4; + top = (BBA_INIT_RHBP+1)<<8; + + p = uip_pbuf_alloc(UIP_PBUF_RAW,size,UIP_PBUF_POOL); + if(p) { + for(q=p;q!=NULL;q=q->next) { + bba_select(); + bba_insregister(pos); + if((pos+size)payload,size); + } else { + s32 chunk = top-pos; + + size -= chunk; + pos = BBA_INIT_RRP<<8; + bba_insdata(q->payload,chunk); + bba_deselect(); + + bba_select(); + bba_insregister(pos); + bba_insdata(q->payload+chunk,size); + } + bba_deselect(); + pos += size; + } + + EXI_Unlock(EXI_CHANNEL_0); + bba_process(p,dev); + EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_2,NULL); + } else + break; + + recvd++; + + bba_out12(BBA_RRP,(rrp=cur_descr.next_packet_ptr)); + rwp = bba_in12(BBA_RWP); + } + return UIP_ERR_OK; +} + +static inline void bba_interrupt(u16 *pstatus) +{ + u8 ir,imr,status; + + ir = bba_in8(BBA_IR); + imr = bba_in8(BBA_IMR); + status = ir&imr; + + if(status&BBA_IR_FRAGI) { + bba_out8(BBA_IR,BBA_IR_FRAGI); + } + if(status&BBA_IR_RI) { + bba_start_rx(bba_netif,0x10); + bba_out8(BBA_IR,BBA_IR_RI); + } + if(status&BBA_IR_REI) { + bba_out8(BBA_IR,BBA_IR_REI); + } + if(status&BBA_IR_TI) { + bba_out8(BBA_IR,BBA_IR_TI); + } + if(status&BBA_IR_TEI) { + bba_out8(BBA_IR,BBA_IR_TEI); + } + if(status&BBA_IR_FIFOEI) { + bba_out8(BBA_IR,BBA_IR_FIFOEI); + } + if(status&BBA_IR_BUSEI) { + bba_out8(BBA_IR,BBA_IR_BUSEI); + } + if(status&BBA_IR_RBFI) { + bba_start_rx(bba_netif,0x10); + bba_out8(BBA_IR,BBA_IR_RBFI); + } + *pstatus |= status; +} + +static s8_t bba_dochallengeresponse() +{ + u16 status; + s32 cnt; + + UIP_LOG("bba_dochallengeresponse()\n"); + /* as we do not have interrupts we've to poll the irqs */ + cnt = 0; + do { + cnt++; + bba_devpoll(&status); + if(status==0x1000) cnt = 0; + } while(cnt<100 && !(status&0x0800)); + + if(cnt>=1000) return UIP_ERR_IF; + return UIP_ERR_OK; +} + +static s8_t __bba_init(struct uip_netif *dev) +{ + struct bba_priv *priv = (struct bba_priv*)dev->state; + if(!priv) return UIP_ERR_IF; + + __bba_reset(); + + priv->revid = bba_cmd_in8(0x01); + + bba_cmd_outs(0x04,&priv->devid,2); + bba_cmd_out8(0x05,priv->acstart); + + bba_out8(0x5b, (bba_in8(0x5b)&~0x80)); + bba_out8(0x5e, 0x01); + bba_out8(0x5c, (bba_in8(0x5c)|0x04)); + + __bba_recv_init(); + + bba_ins(BBA_NAFR_PAR0,priv->ethaddr->addr, 6); + + bba_out8(BBA_IR,0xFF); + bba_out8(BBA_IMR,0xFF&~BBA_IMR_FIFOEIM); + + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + + return UIP_ERR_OK; +} + +static s8_t bba_init_one(struct uip_netif *dev) +{ + s32 ret; + struct bba_priv *priv = (struct bba_priv*)dev->state; + + if(!priv) return UIP_ERR_IF; + + priv->revid = 0x00; + priv->devid = 0xD107; + priv->acstart = 0x4E; + + ret = __bba_init(dev); + + return ret; +} + +static s8_t bba_probe(struct uip_netif *dev) +{ + s32 ret; + u32 cid; + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_2,NULL)==0) return -1; + + cid = __bba_read_cid(); + if(cid!=BBA_CID) { + EXI_Unlock(EXI_CHANNEL_0); + return -1; + } + + ret = bba_init_one(dev); + + EXI_Unlock(EXI_CHANNEL_0); + return ret; +} + +static u32 bba_calc_response(struct uip_netif *dev,u32 val) +{ + u8 revid_0, revid_eth_0, revid_eth_1; + struct bba_priv *priv = (struct bba_priv*)dev->state; + + UIP_LOG("bba_calc_response()\n"); + + revid_0 = priv->revid; + revid_eth_0 = _SHIFTR(priv->devid,8,8); + revid_eth_1 = priv->devid&0xff; + + u8 i0, i1, i2, i3; + i0 = (val & 0xff000000) >> 24; + i1 = (val & 0x00ff0000) >> 16; + i2 = (val & 0x0000ff00) >> 8; + i3 = (val & 0x000000ff); + + u8 c0, c1, c2, c3; + c0 = ((i0 + i1 * 0xc1 + 0x18 + revid_0) ^ (i3 * i2 + 0x90) + ) & 0xff; + c1 = ((i1 + i2 + 0x90) ^ (c0 + i0 - 0xc1) + ) & 0xff; + c2 = ((i2 + 0xc8) ^ (c0 + ((revid_eth_0 + revid_0 * 0x23) ^ 0x19)) + ) & 0xff; + c3 = ((i0 + 0xc1) ^ (i3 + ((revid_eth_1 + 0xc8) ^ 0x90)) + ) & 0xff; + + return ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); +} + +static void bba_devpoll(u16 *pstatus) +{ + u8 status; + s64 now; + + UIP_LOG("bba_devpoll()\n"); + + now = gettime(); + if(diff_msec(bba_arp_tmr,now)>=UIP_ARP_TMRINTERVAL) { + uip_arp_timer(); + bba_arp_tmr = gettime(); + } + + status = 0; + *pstatus = 0; + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_2,NULL)==1) { + status = bba_cmd_in8(0x03); + if(status) { + bba_cmd_out8(0x02,BBA_CMD_IRMASKALL); + if(status&0x80) { + *pstatus |= (status<<8); + bba_interrupt(pstatus); + bba_cmd_out8(0x03,0x80); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return; + } + if(status&0x40) { + *pstatus |= (status<<8); + __bba_init(bba_netif); + bba_cmd_out8(0x03, 0x40); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return; + } + if(status&0x20) { + *pstatus |= (status<<8); + bba_cmd_out8(0x03, 0x20); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return; + } + if(status&0x10) { + u32 response,challange; + + *pstatus |= (status<<8); + bba_cmd_out8(0x05,bba_device.acstart); + bba_cmd_ins(0x08,&challange,sizeof(challange)); + response = bba_calc_response(bba_netif,challange); + bba_cmd_outs(0x09,&response,sizeof(response)); + bba_cmd_out8(0x03, 0x10); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return; + } + if(status&0x08) { + *pstatus |= (status<<8); + bba_cmd_out8(0x03, 0x08); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return; + } + + *pstatus |= (status<<8); + bba_interrupt(pstatus); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + } + EXI_Unlock(EXI_CHANNEL_0); + } +} + +static s8_t __bba_start_tx(struct uip_netif *dev,struct uip_pbuf *p,struct uip_ip_addr *ipaddr) +{ + return uip_arp_out(dev,ipaddr,p); +} + +static s8_t __bba_link_tx(struct uip_netif *dev,struct uip_pbuf *p) +{ + u8 pad[60]; + u32 len; + struct uip_pbuf *tmp; + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_2,NULL)==0) return UIP_ERR_IF; + + if(p->tot_len>BBA_TX_MAX_PACKET_SIZE) { + UIP_LOG("__bba_link_tx: packet dropped due to big buffer.\n"); + EXI_Unlock(EXI_CHANNEL_0); + return UIP_ERR_PKTSIZE; + } + + if(!__linkstate()) { + EXI_Unlock(EXI_CHANNEL_0); + return UIP_ERR_ABRT; + } + + while((bba_in8(BBA_NCRA)&(BBA_NCRA_ST0|BBA_NCRA_ST1))); + + len = p->tot_len; + bba_out12(BBA_TXFIFOCNT,len); + + bba_select(); + bba_outsregister(BBA_WRTXFIFOD); + for(tmp=p;tmp!=NULL;tmp=tmp->next) { + bba_outsdata(tmp->payload,tmp->len); + } + if(lenflags |= UIP_NETIF_FLAG_LINK_UP; + uip_netif_setup(dev); + uip_arp_init(); + + bba_recv_pbufs = NULL; + bba_arp_tmr = gettime(); + + return UIP_ERR_OK; +} + +uipdev_s uip_bba_create(struct uip_netif *dev) +{ + dev->name[0] = IFNAME0; + dev->name[1] = IFNAME1; + + dev->output = __bba_start_tx; + dev->linkoutput = __bba_link_tx; + dev->mtu = 1500; + dev->flags = UIP_NETIF_FLAG_BROADCAST; + dev->hwaddr_len = 6; + + bba_device.ethaddr = (struct uip_eth_addr*)dev->hwaddr; + bba_device.state = UIP_ERR_OK; + + bba_netif = dev; + return &bba_device; +} + +void uip_bba_poll(struct uip_netif *dev) +{ + u16 status; + + UIP_LOG("uip_bba_poll()\n"); + + bba_devpoll(&status); + +} diff --git a/wii/libogc/libdb/uIP/bba.h b/wii/libogc/libdb/uIP/bba.h new file mode 100644 index 0000000000..4fa92f60e4 --- /dev/null +++ b/wii/libogc/libdb/uIP/bba.h @@ -0,0 +1,14 @@ +#ifndef __BBA_DBG_H__ +#define __BBA_DBG_H__ + +#include "uip.h" + +struct uip_netif; + +typedef void* uipdev_s; + +uipdev_s uip_bba_create(struct uip_netif *dev); +s8_t uip_bba_init(struct uip_netif *dev); +void uip_bba_poll(struct uip_netif *dev); + +#endif diff --git a/wii/libogc/libdb/uIP/memb.c b/wii/libogc/libdb/uIP/memb.c new file mode 100644 index 0000000000..5787a6db4c --- /dev/null +++ b/wii/libogc/libdb/uIP/memb.c @@ -0,0 +1,48 @@ +#include +#include + +#include "uip.h" +#include "memb.h" + +void memb_init(struct memb_blks *blk) +{ + UIP_MEMSET(blk->mem,0,(MEM_ALIGN_SIZE(blk->size)+sizeof(u32))*blk->num); +} + +void* memb_alloc(struct memb_blks *blk) +{ + s32 i; + u32 *ptr; + + ptr = (u32*)blk->mem; + for(i=0;inum;i++) { + if(*ptr==0) { + ++(*ptr); + return (void*)(ptr+1); + } + ptr = (u32*)(u8*)ptr+(MEM_ALIGN_SIZE(blk->size)+sizeof(u32)); + } + return NULL; +} + +u8 memb_free(struct memb_blks *blk,void *ptr) +{ + s32 i; + u32 *ptr2,*ptr1; + + ptr1 = ptr; + ptr2 = (u32*)blk->mem; + for(i=0;inum;i++) { + if(ptr2==(ptr1 - 1)) { + return --(*ptr2); + } + ptr2 = (u32*)(u8*)ptr2+(MEM_ALIGN_SIZE(blk->size)+sizeof(u32)); + } + return -1; +} + +u8 memb_ref(struct memb_blks *blk,void *ptr) +{ + u32 *pref = ptr-sizeof(u32); + return ++(*pref); +} diff --git a/wii/libogc/libdb/uIP/memb.h b/wii/libogc/libdb/uIP/memb.h new file mode 100644 index 0000000000..8da054ed7a --- /dev/null +++ b/wii/libogc/libdb/uIP/memb.h @@ -0,0 +1,21 @@ +#ifndef __MEMB_H__ +#define __MEMB_H__ + +#include + +#define MEMB(name,size,num) \ + static u8 memb_mem_##name[(MEM_ALIGN_SIZE(size)+sizeof(u32))*num]; \ + static struct memb_blks name = {size,num,memb_mem_##name} + +struct memb_blks { + u16 size; + u16 num; + u8 *mem; +}; + +void memb_init(struct memb_blks *blk); +void* memb_alloc(struct memb_blks *blk); +u8 memb_free(struct memb_blks *blk,void *ptr); +u8 memb_ref(struct memb_blks *blk,void *ptr); + +#endif diff --git a/wii/libogc/libdb/uIP/memr.c b/wii/libogc/libdb/uIP/memr.c new file mode 100644 index 0000000000..c4df89cafa --- /dev/null +++ b/wii/libogc/libdb/uIP/memr.c @@ -0,0 +1,155 @@ +#include +#include + +#include "uip.h" +#include "memr.h" + +#if UIP_ERRORING == 1 +#include +#define UIP_ERROR(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_ERROR(m) +#endif /* UIP_ERRORING == 1 */ + +#define MIN_SIZE 12 +#define SIZEOF_STRUCT_MEM (sizeof(struct mem)+(((sizeof(struct mem)%MEM_ALIGNMENT)==0)?0:(4-(sizeof(struct mem)%MEM_ALIGNMENT)))) + +struct mem { + u32 next,prev; + u32 used; +}; + +static struct mem *ram_free; +static struct mem *ram_end; +static u8 ram_block[sizeof(struct mem)+UIP_MEM_SIZE+MEM_ALIGNMENT]; + +static void plug_holes(struct mem *rmem) +{ + struct mem *nmem; + struct mem *pmem; + + nmem = (struct mem*)&ram_block[rmem->next]; + if(rmem!=nmem && nmem->used==0 && (u8_t*)nmem!=(u8_t*)ram_end) { + if(ram_free==nmem) ram_free = rmem; + + rmem->next = nmem->next; + ((struct mem*)&ram_block[nmem->next])->prev = (u8_t*)rmem - ram_block; + } + + pmem = (struct mem*)&ram_block[rmem->prev]; + if(pmem!=rmem && pmem->used==0) { + if(ram_free==rmem) ram_free = pmem; + pmem->next = rmem->next; + ((struct mem*)&ram_block[rmem->next])->prev = (u8_t*)pmem - ram_block; + } +} + +void memr_init() +{ + struct mem *rmem; + + UIP_MEMSET(ram_block,0,UIP_MEM_SIZE); + rmem = (struct mem*)ram_block; + rmem->next = UIP_MEM_SIZE; + rmem->prev = 0; + rmem->used = 0; + + ram_end = (struct mem*)&ram_block[UIP_MEM_SIZE]; + ram_end->used = 1; + ram_end->prev = UIP_MEM_SIZE; + ram_end->next = UIP_MEM_SIZE; + + ram_free = (struct mem*)ram_block; +} + +void* memr_malloc(u32 size) +{ + u32 ptr,ptr2; + struct mem *rmem,*rmem2; + + if(size==0) return NULL; + + if(size%MEM_ALIGNMENT) size += MEM_ALIGNMENT - ((size+SIZEOF_STRUCT_MEM)%SIZEOF_STRUCT_MEM); + if(size>UIP_MEM_SIZE) return NULL; + + for(ptr = (u8_t*)ram_free - ram_block;ptrnext) { + rmem = (struct mem*)&ram_block[ptr]; + if(!rmem->used && rmem->next - (ptr + SIZEOF_STRUCT_MEM)>=size + SIZEOF_STRUCT_MEM) { + ptr2 = ptr + SIZEOF_STRUCT_MEM + size; + rmem2 = (struct mem*)&ram_block[ptr2]; + + rmem2->prev = ptr; + rmem2->next = rmem->next; + rmem->next = ptr2; + if(rmem->next!=UIP_MEM_SIZE) ((struct mem*)&ram_block[rmem2->next])->prev = ptr2; + + rmem2->used = 0; + rmem->used = 1; + + if(rmem==ram_free) { + while(ram_free->used && ram_free!=ram_end) ram_free = (struct mem*)&ram_block[ram_free->next]; + } + + return (u8_t*)rmem+SIZEOF_STRUCT_MEM; + } + } + return NULL; +} + +void memr_free(void *ptr) +{ + struct mem *rmem; + + if(ptr==NULL) return; + if((u8_t*)ptr<(u8_t*)ram_block || (u8_t*)ptr>=(u8_t*)ram_end) return; + + rmem = (struct mem*)((u8_t*)ptr - SIZEOF_STRUCT_MEM); + rmem->used = 0; + + if(rmemUIP_MEM_SIZE) return NULL; + if((u8_t*)ptr<(u8_t*)ram_block || (u8_t*)ptr>=(u8_t*)ram_end) { + UIP_ERROR("memr_realloc: illegal memory.\n"); + return ptr; + } + rmem = (struct mem*)((u8_t*)ptr - SIZEOF_STRUCT_MEM); + ptr1 = (u8_t*)rmem - ram_block; + size = rmem->next - ptr1 - SIZEOF_STRUCT_MEM; + + if(newsize+SIZEOF_STRUCT_MEM+MIN_SIZEused = 0; + rmem2->next = rmem->next; + rmem2->prev = ptr1; + rmem->next = ptr2; + if(rmem2->next!=UIP_MEM_SIZE) ((struct mem*)&ram_block[rmem2->next])->prev = ptr2; + + plug_holes(rmem2); + } + + return ptr; +} + +void* memr_reallocm(void *ptr,u32 newsize) +{ + void *nmem; + + nmem = memr_malloc(newsize); + if(nmem==NULL) return memr_realloc(ptr,newsize); + + UIP_MEMCPY(nmem,ptr,newsize); + memr_free(ptr); + + return nmem; +} diff --git a/wii/libogc/libdb/uIP/memr.h b/wii/libogc/libdb/uIP/memr.h new file mode 100644 index 0000000000..a2455d6cc4 --- /dev/null +++ b/wii/libogc/libdb/uIP/memr.h @@ -0,0 +1,12 @@ +#ifndef __MEMR_H__ +#define __MEMR_H__ + +#include + +void memr_init(); +void* memr_malloc(u32 size); +void memr_free(void *ptr); +void* memr_realloc(void *ptr,u32 newsize); +void* memr_reallocm(void *ptr,u32 newsize); + +#endif diff --git a/wii/libogc/libdb/uIP/uip.h b/wii/libogc/libdb/uIP/uip.h new file mode 100644 index 0000000000..2bc5713d17 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip.h @@ -0,0 +1,176 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * Header file for the uIP TCP/IP stack. + * \author Adam Dunkels + * + * The uIP TCP/IP stack header file contains definitions for a number + * of C macros that are used by uIP programs as well as internal uIP + * structures, TCP/IP header structures and function declarations. + * + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + +#ifndef __UIP_H__ +#define __UIP_H__ + +#include "uipopt.h" +#include "uip_arch.h" +#include "uip_ip.h" + +#define UIP_ERR_OK 0 +#define UIP_ERR_MEM -1 +#define UIP_ERR_BUF -2 +#define UIP_ERR_ABRT -3 +#define UIP_ERR_RST -4 +#define UIP_ERR_CLSD -5 +#define UIP_ERR_CONN -6 +#define UIP_ERR_VAL -7 +#define UIP_ERR_ARG -8 +#define UIP_ERR_RTE -9 +#define UIP_ERR_USE -10 +#define UIP_ERR_IF -11 +#define UIP_ERR_PKTSIZE -17 + +#define UIP_PROTO_ICMP 1 +#define UIP_PROTO_TCP 6 +#define UIP_PROTO_UDP 17 + +/* Header sizes. */ +#define UIP_IP_HLEN 20 /* Size of IP header */ +#define UIP_TRANSPORT_HLEN 20 + +#define UIP_UDP_HLEN 8 /* Size of UDP header */ +#define UIP_TCP_HLEN 20 /* Size of TCP header */ +#define UIP_IPUDP_HLEN 28 /* Size of IP + UDP header */ +#define UIP_IPTCP_HLEN 40 /* Size of IP + TCP header */ + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This macro is primarily used for converting constants from host + * byte order to network byte order. For converting variables to + * network byte order, use the htons() function instead. + * + * \hideinitializer + */ +#ifndef HTONS +# if BYTE_ORDER == BIG_ENDIAN +# define HTONS(n) (n) +# else /* BYTE_ORDER == BIG_ENDIAN */ +# define HTONS(n) ((((u16_t)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8)) +# endif /* BYTE_ORDER == BIG_ENDIAN */ +#endif /* HTONS */ + +/** + * The structure holding the TCP/IP statistics that are gathered if + * UIP_STATISTICS is set to 1. + * + */ +struct uip_stats { + struct { + uip_stats_t drop; /**< Number of dropped packets at the IP + layer. */ + uip_stats_t recv; /**< Number of received packets at the IP + layer. */ + uip_stats_t sent; /**< Number of sent packets at the IP + layer. */ + uip_stats_t vhlerr; /**< Number of packets dropped due to wrong + IP version or header length. */ + uip_stats_t hblenerr; /**< Number of packets dropped due to wrong + IP length, high byte. */ + uip_stats_t lblenerr; /**< Number of packets dropped due to wrong + IP length, low byte. */ + uip_stats_t fragerr; /**< Number of packets dropped since they + were IP fragments. */ + uip_stats_t chkerr; /**< Number of packets dropped due to IP + checksum errors. */ + uip_stats_t protoerr; /**< Number of packets dropped since they + were neither ICMP, UDP nor TCP. */ + } ip; /**< IP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped ICMP packets. */ + uip_stats_t recv; /**< Number of received ICMP packets. */ + uip_stats_t sent; /**< Number of sent ICMP packets. */ + uip_stats_t typeerr; /**< Number of ICMP packets with a wrong + type. */ + } icmp; /**< ICMP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped TCP segments. */ + uip_stats_t recv; /**< Number of recived TCP segments. */ + uip_stats_t sent; /**< Number of sent TCP segments. */ + uip_stats_t chkerr; /**< Number of TCP segments with a bad + checksum. */ + uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK + number. */ + uip_stats_t rst; /**< Number of recevied TCP RST (reset) segments. */ + uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */ + uip_stats_t syndrop; /**< Number of dropped SYNs due to too few + connections was avaliable. */ + uip_stats_t synrst; /**< Number of SYNs for closed ports, + triggering a RST. */ + } tcp; /**< TCP statistics. */ +}; + +/** + * The uIP TCP/IP statistics. + * + * This is the variable in which the uIP TCP/IP statistics are gathered. + */ +extern struct uip_stats uip_stat; + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This function is primarily used for converting variables from host + * byte order to network byte order. For converting constants to + * network byte order, use the HTONS() macro instead. + */ +#ifndef htons +u16_t htons(u16_t val); +#endif /* htons */ + +/** @} */ + +#endif /* __UIP_H__ */ + + +/** @} */ + diff --git a/wii/libogc/libdb/uIP/uip_arch.c b/wii/libogc/libdb/uIP/uip_arch.c new file mode 100644 index 0000000000..5a973caf81 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_arch.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + +#include +#include +#include + +#include "uip.h" +#include "uip_arch.h" +#include "uip_ip.h" +#include "uip_tcp.h" +#include "uip_pbuf.h" + + +/*-----------------------------------------------------------------------------------*/ +u16_t uip_chksum(u16_t *sdata, u32_t len) +{ + u32_t acc; + + for(acc = 0;len > 1;len -= 2) { + acc += *sdata++; + } + + /* add up any odd byte */ + if(len==1) { + acc += htons((u16_t)((((u8_t *)sdata)[0]&0xff)<<8)); + } + while(acc>>16) acc = (acc&0xffffUL)+(acc>>16); + + return (u16_t)acc; +} + +/*-----------------------------------------------------------------------------------*/ +u16_t uip_chksum_pseudo(struct uip_pbuf *p,struct uip_ip_addr *src,struct uip_ip_addr *dst,u8_t proto,u16_t proto_len) +{ + u32_t acc,len,rem; + struct uip_pbuf *q; + + acc = 0; + + rem = proto_len; + for(q=p;q!=NULL && rem>0;q=q->next) { + len = (rem>q->len)?q->len:rem; + acc += uip_chksum(q->payload,len); + rem -= len; + } + + acc += (src->addr&0xffffUL); + acc += ((src->addr>>16)&0xffffUL); + acc += (dst->addr&0xffffUL); + acc += ((dst->addr>>16)&0xffffUL); + acc += (u32_t)htons(proto); + acc += (u32_t)htons(proto_len); + + while(acc>>16) acc = (acc&0xffffUL)+(acc>>16); + + return (u16_t)~(acc&0xffffUL); +} +/*-----------------------------------------------------------------------------------*/ +u16_t +uip_ipchksum(void *dataptr,u16_t len) +{ + return ~(uip_chksum(dataptr,len)); +} + +u16_t uip_ipchksum_pbuf(struct uip_pbuf *p) +{ + u32_t acc; + struct uip_pbuf *q; + + acc = 0; + for(q = p; q != NULL; q = q->next) { + acc += uip_chksum(q->payload,q->len); + } + while(acc>>16) acc = (acc&0xffffUL)+(acc>>16); + + return (u16_t)~(acc & 0xffffUL); +} + +void uip_log(const char *filename,int line_nb,char *msg) +{ + printf("%s(%d):\n%s\n",filename,line_nb,msg); +} + +/*-----------------------------------------------------------------------------------*/ diff --git a/wii/libogc/libdb/uIP/uip_arch.h b/wii/libogc/libdb/uIP/uip_arch.h new file mode 100644 index 0000000000..2a0e26a8b9 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_arch.h @@ -0,0 +1,170 @@ +/** + * \defgroup uiparch Architecture specific uIP functions + * @{ + * + * The functions in the architecture specific module implement the IP + * check sum and 32-bit additions. + * + * The IP checksum calculation is the most computationally expensive + * operation in the TCP/IP stack and it therefore pays off to + * implement this in efficient assembler. The purpose of the uip-arch + * module is to let the checksum functions to be implemented in + * architecture specific assembler. + * + */ + +/** + * \file + * Declarations of architecture specific functions. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + +#ifndef __UIP_ARCH_H__ +#define __UIP_ARCH_H__ + +#include "uip.h" + +#define UIP_MIN(x,y) (x)<(y)?(x):(y) + +#define MEM_ALIGNMENT 4 +#define MEM_ALIGN(mem) ((void*)(((u32_t)(mem)+MEM_ALIGNMENT-1)&~(u32_t)(MEM_ALIGNMENT-1))) +#define MEM_ALIGN_SIZE(size) (((size)+MEM_ALIGNMENT-1)&~(u32_t)(MEM_ALIGNMENT-1)) + +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +#ifndef htons +#define htons(x) (x) +#endif +#ifndef ntohs +#define ntohs(x) (x) +#endif +#ifndef htonl +#define htonl(x) (x) +#endif +#ifndef ntohl +#define ntohl(x) (x) +#endif + +struct uip_pbuf; +struct uip_ip_addr; + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \note This function is not called in the current version of uIP, + * but future versions might make use of it. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u32_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void *dataptr,u16_t len); + +u16_t uip_ipchksum_pbuf(struct uip_pbuf *p); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \note The uip_appdata pointer that points to the packet data may + * point anywhere in memory, so it is not possible to simply calculate + * the Internet checksum of the contents of the uip_buf buffer. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_chksum_pseudo(struct uip_pbuf *p,struct uip_ip_addr *src,struct uip_ip_addr *dst,u8_t proto,u16_t proto_len); + + + +extern void tcpip_tmr_needed(); +#define tcp_tmr_needed tcpip_tmr_needed + +#if UIP_LIBC_MEMFUNCREPLACE +static __inline__ void uip_memcpy(void *dest,const void *src,s32_t len) +{ + u8_t *dest0 = (u8_t*)dest; + u8_t *src0 = (u8_t*)src; + + while(len--) { + *dest0++ = *src0++; + } +} + +static __inline__ void uip_memset(void *dest,s32_t c,s32_t len) +{ + u8_t *dest0 = (u8_t*)dest; + + while(len--) { + *dest0++ = (s8_t)c; + } +} + +#define UIP_MEMCPY uip_memcpy +#define UIP_MEMSET uip_memset +#else +#define UIP_MEMCPY memcpy +#define UIP_MEMSET memset +#endif + +/** @} */ + +#endif /* __UIP_ARCH_H__ */ diff --git a/wii/libogc/libdb/uIP/uip_arp.c b/wii/libogc/libdb/uIP/uip_arp.c new file mode 100644 index 0000000000..44cb1f5300 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_arp.c @@ -0,0 +1,464 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uiparp uIP Address Resolution Protocol + * @{ + * + * The Address Resolution Protocol ARP is used for mapping between IP + * addresses and link level addresses such as the Ethernet MAC + * addresses. ARP uses broadcast queries to ask for the link level + * address of a known IP address and the host which is configured with + * the IP address for which the query was meant, will respond with its + * link level address. + * + * \note This ARP implementation only supports Ethernet. + */ + +/** + * \file + * Implementation of the ARP Address Resolution Protocol. + * \author Adam Dunkels + * + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + + +#include "uip_pbuf.h" +#include "uip_netif.h" +#include "uip_arp.h" + +#include + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + + +#define ARP_TRY_HARD 0x01 + +#define ARP_MAXAGE 240 +#define ARP_MAXPENDING 2 + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define ARP_HWTYPE_ETH 1 + +#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8) +#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff) + +#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8)) +#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8)) + +enum arp_state { + ARP_STATE_EMPTY, + ARP_STATE_PENDING, + ARP_STATE_STABLE, + ARP_STATE_EXPIRED +}; + +struct arp_entry { + struct uip_ip_addr ipaddr; + struct uip_eth_addr ethaddr; + enum arp_state state; + u8_t time; +}; + +static const struct uip_eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; +/*-----------------------------------------------------------------------------------*/ +/** + * Initialize the ARP module. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_init(void) +{ + s32_t i; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + arp_table[i].state = ARP_STATE_EMPTY; + arp_table[i].time = 0; + } +} +/*-----------------------------------------------------------------------------------*/ +/** + * Periodic ARP processing function. + * + * This function performs periodic timer processing in the ARP module + * and should be called at regular intervals. The recommended interval + * is 10 seconds between the calls. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_timer(void) +{ + u8_t i; + + for(i=0;i=ARP_MAXAGE) { + arp_table[i].state = ARP_STATE_EXPIRED; + } else if(arp_table[i].state==ARP_STATE_PENDING) { + if(arp_table[i].time>=ARP_MAXPENDING) arp_table[i].state = ARP_STATE_EXPIRED; + } + + if(arp_table[i].state==ARP_STATE_EXPIRED) arp_table[i].state = ARP_STATE_EMPTY; + } +} + +static s8_t uip_arp_findentry(struct uip_ip_addr *ipaddr,u8_t flags) +{ + s8_t old_pending = UIP_ARPTAB_SIZE, old_stable = UIP_ARPTAB_SIZE; + s8_t empty = UIP_ARPTAB_SIZE; + u8_t i = 0,age_pending = 0,age_stable = 0; + + /* Walk through the ARP mapping table and try to find an entry to + update. If none is found, the IP -> MAC address mapping is + inserted in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + if(empty==UIP_ARPTAB_SIZE && arp_table[i].state==ARP_STATE_EMPTY) { + empty = i; + } else if(arp_table[i].state==ARP_STATE_PENDING) { + if(ipaddr && ip_addr_cmp(ipaddr,&arp_table[i].ipaddr)) return i; + else if(arp_table[i].time>=age_pending) { + old_pending = i; + age_pending = arp_table[i].time; + } + } else if(arp_table[i].state==ARP_STATE_STABLE) { + if(ipaddr && ip_addr_cmp(ipaddr,&arp_table[i].ipaddr)) return i; + else if(arp_table[i].time>=age_stable) { + old_stable = i; + age_stable = arp_table[i].time; + } + } + } + if(empty==UIP_ARPTAB_SIZE && !(flags&ARP_TRY_HARD)) return UIP_ERR_MEM; + + if(emptyhwaddr_len;k++) arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; + + return UIP_ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming IP packets + * + * This function should be called by the device driver when an IP + * packet has been received. The function will check if the address is + * in the ARP cache, and if so the ARP cache entry will be + * refreshed. If no ARP cache entry was found, a new one is created. + * + * This function expects an IP packet with a prepended Ethernet header + * in the uip_buf[] buffer, and the length of the packet in the global + * variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_ipin(struct uip_netif *netif,struct uip_pbuf *p) +{ + struct uip_ethip_hdr *hdr; + + hdr = p->payload; + if(!ip_addr_netcmp(&hdr->ip.src,&netif->ip_addr,&netif->netmask)) return; + + uip_arp_update(netif,&hdr->ip.src,&hdr->ethhdr.src,0); + } + +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming ARP packets. + * + * This function should be called by the device driver when an ARP + * packet has been received. The function will act differently + * depending on the ARP packet type: if it is a reply for a request + * that we previously sent out, the ARP cache will be filled in with + * the values from the ARP reply. If the incoming ARP packet is an ARP + * request for our IP address, an ARP reply packet is created and put + * into the uip_buf[] buffer. + * + * When the function returns, the value of the global variable uip_len + * indicates whether the device driver should send out a packet or + * not. If uip_len is zero, no packet should be sent. If uip_len is + * non-zero, it contains the length of the outbound packet that is + * present in the uip_buf[] buffer. + * + * This function expects an ARP packet with a prepended Ethernet + * header in the uip_buf[] buffer, and the length of the packet in the + * global variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_arpin(struct uip_netif *netif,struct uip_eth_addr *ethaddr,struct uip_pbuf *p) +{ + u8_t i,for_us; + struct uip_ip_addr sipaddr,dipaddr; + struct uip_arp_hdr *hdr; + + if(p->tot_lenpayload; + + *(struct uip_ip_addr2*)((void*)&sipaddr) = hdr->sipaddr; + *(struct uip_ip_addr2*)((void*)&dipaddr) = hdr->dipaddr; + + if(netif->ip_addr.addr==0) for_us = 0; + else for_us = ip_addr_cmp(&dipaddr,&netif->ip_addr); + + if(for_us) uip_arp_update(netif,&sipaddr,&hdr->shwaddr,ARP_TRY_HARD); + else uip_arp_update(netif,&sipaddr,&hdr->shwaddr,0); + + switch(htons(hdr->opcode)) { + case ARP_REQUEST: + if(for_us) { + hdr->opcode = htons(ARP_REPLY); + hdr->dipaddr = hdr->sipaddr; + hdr->sipaddr = *(struct uip_ip_addr2*)((void*)&netif->ip_addr); + + for(i=0;ihwaddr_len;i++) { + hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; + hdr->shwaddr.addr[i] = ethaddr->addr[i]; + hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i]; + hdr->ethhdr.src.addr[i] = ethaddr->addr[i]; + } + + hdr->hwtype = htons(ARP_HWTYPE_ETH); + ARPH_HWLEN_SET(hdr,netif->hwaddr_len); + + hdr->protocol = htons(UIP_ETHTYPE_IP); + ARPH_PROTOLEN_SET(hdr,sizeof(struct uip_ip_addr)); + + netif->linkoutput(netif,p); + } else { + UIP_LOG("uip_arp_arpin: ip packet not for us.\n"); + } + break; + case ARP_REPLY: + break; + default: + UIP_LOG("uip_arp_arpin: ARP unknown opcode type.\n"); + break; + } + uip_pbuf_free(p); +} +/*-----------------------------------------------------------------------------------*/ +/** + * Prepend Ethernet header to an outbound IP packet and see if we need + * to send out an ARP request. + * + * This function should be called before sending out an IP packet. The + * function checks the destination IP address of the IP packet to see + * what Ethernet MAC address that should be used as a destination MAC + * address on the Ethernet. + * + * If the destination IP address is in the local network (determined + * by logical ANDing of netmask and our IP address), the function + * checks the ARP cache to see if an entry for the destination IP + * address is found. If so, an Ethernet header is prepended and the + * function returns. If no ARP cache entry is found for the + * destination IP address, the packet in the uip_buf[] is replaced by + * an ARP request packet for the IP address. The IP packet is dropped + * and it is assumed that they higher level protocols (e.g., TCP) + * eventually will retransmit the dropped packet. + * + * If the destination IP address is not on the local network, the IP + * address of the default router is used instead. + * + * When the function returns, a packet is present in the uip_buf[] + * buffer, and the length of the packet is in the global variable + * uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +s8_t uip_arp_out(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_pbuf *q) +{ + u8_t i; + struct uip_eth_addr *dest,*srcaddr,mcastaddr; + struct uip_eth_hdr *ethhdr; + + if(uip_pbuf_header(q,sizeof(struct uip_eth_hdr))!=0) { + UIP_LOG("uip_arp_out: could not allocate room for header.\n"); + return UIP_ERR_BUF; + } + + dest = NULL; + if(ip_addr_isbroadcast(ipaddr,netif)) { + dest = (struct uip_eth_addr*)ðbroadcast; + } else if(ip_addr_ismulticast(ipaddr)) { + /* Hash IP multicast address to MAC address.*/ + mcastaddr.addr[0] = 0x01; + mcastaddr.addr[1] = 0x00; + mcastaddr.addr[2] = 0x5e; + mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; + mcastaddr.addr[4] = ip4_addr3(ipaddr); + mcastaddr.addr[5] = ip4_addr4(ipaddr); + /* destination Ethernet address is multicast */ + dest = &mcastaddr; + } else { + if(!ip_addr_netcmp(ipaddr,&netif->ip_addr,&netif->netmask)) { + if(netif->gw.addr!=0) ipaddr = &netif->gw; + else return UIP_ERR_RTE; + } + return uip_arp_arpquery(netif,ipaddr,q); + } + + srcaddr = (struct uip_eth_addr*)netif->hwaddr; + ethhdr = q->payload; + for(i=0;ihwaddr_len;i++) { + ethhdr->dest.addr[i] = dest->addr[i]; + ethhdr->src.addr[i] = srcaddr->addr[i]; + } + + ethhdr->type = htons(UIP_ETHTYPE_IP); + return netif->linkoutput(netif,q); +} +/*-----------------------------------------------------------------------------------*/ + +s8_t uip_arp_arpquery(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_pbuf *q) +{ + s8_t i,k; + s8_t err = UIP_ERR_MEM; + struct uip_eth_addr *srcaddr = (struct uip_eth_addr*)netif->hwaddr; + + if(ip_addr_isbroadcast(ipaddr,netif) || + ip_addr_ismulticast(ipaddr) || + ip_addr_isany(ipaddr)) return UIP_ERR_ARG; + + i = uip_arp_findentry(ipaddr,ARP_TRY_HARD); + if(i<0) return i; + + if(arp_table[i].state==ARP_STATE_EMPTY) arp_table[i].state = ARP_STATE_PENDING; + if(arp_table[i].state==ARP_STATE_PENDING || q==NULL) err = uip_arp_arprequest(netif,ipaddr); + + if(q!=NULL) { + if(arp_table[i].state==ARP_STATE_STABLE) { + + struct uip_eth_hdr *hdr = q->payload; + for(k=0;khwaddr_len;k++) { + hdr->dest.addr[k] = arp_table[i].ethaddr.addr[k]; + hdr->src.addr[k] = srcaddr->addr[k]; + } + + hdr->type = htons(UIP_ETHTYPE_IP); + err = netif->linkoutput(netif,q); + } else if(arp_table[i].state==ARP_STATE_PENDING) { + UIP_LOG("uip_arp_query: Ethernet destination address unknown, queueing disabled, packet dropped.\n"); + } + } + return err; +} + +s8_t uip_arp_arprequest(struct uip_netif *netif,struct uip_ip_addr *ipaddr) +{ + s8_t k; + s8_t err = UIP_ERR_MEM; + struct uip_arp_hdr *hdr; + struct uip_pbuf *p; + struct uip_eth_addr *srcaddr = (struct uip_eth_addr*)netif->hwaddr; + + p = uip_pbuf_alloc(UIP_PBUF_LINK,sizeof(struct uip_arp_hdr),UIP_PBUF_RAM); + if(p==NULL) return err; + + hdr = p->payload; + hdr->opcode = htons(ARP_REQUEST); + + for(k=0;khwaddr_len;k++) { + hdr->shwaddr.addr[k] = srcaddr->addr[k]; + hdr->dhwaddr.addr[k] = 0; + } + + hdr->dipaddr = *(struct uip_ip_addr2*)((void*)ipaddr); + hdr->sipaddr = *(struct uip_ip_addr2*)((void*)&netif->ip_addr); + + hdr->hwtype = htons(ARP_HWTYPE_ETH); + ARPH_HWLEN_SET(hdr,netif->hwaddr_len); + + hdr->protocol = htons(UIP_ETHTYPE_IP); + ARPH_PROTOLEN_SET(hdr,sizeof(struct uip_ip_addr)); + for(k=0;khwaddr_len;k++) { + hdr->ethhdr.dest.addr[k] = 0xff; + hdr->ethhdr.src.addr[k] = srcaddr->addr[k]; + } + hdr->ethhdr.type = htons(UIP_ETHTYPE_ARP); + + err = netif->linkoutput(netif,p); + uip_pbuf_free(p); + + return err; +} + +/** @} */ +/** @} */ diff --git a/wii/libogc/libdb/uIP/uip_arp.h b/wii/libogc/libdb/uIP/uip_arp.h new file mode 100644 index 0000000000..16569cf43a --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_arp.h @@ -0,0 +1,150 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \addtogroup uiparp + * @{ + */ + +/** + * \file + * Macros and definitions for the ARP module. + * \author Adam Dunkels + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + +#ifndef __UIP_ARP_H__ +#define __UIP_ARP_H__ + +#include "uip.h" +#include "uip_arch.h" + +#define UIP_ARP_TMRINTERVAL 5000 + +#define UIP_ETHTYPE_ARP 0x0806 +#define UIP_ETHTYPE_IP 0x0800 +#define UIP_ETHTYPE_IP6 0x86dd +/** + * Representation of a 48-bit Ethernet address. + */ +PACK_STRUCT_BEGIN +struct uip_eth_addr { + PACK_STRUCT_FIELD(u8_t addr[6]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +/** + * The Ethernet header. + */ +PACK_STRUCT_BEGIN +struct uip_eth_hdr { + PACK_STRUCT_FIELD(struct uip_eth_addr dest); + PACK_STRUCT_FIELD(struct uip_eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +PACK_STRUCT_BEGIN +struct uip_arp_hdr { + PACK_STRUCT_FIELD(struct uip_eth_hdr ethhdr); + PACK_STRUCT_FIELD(u16_t hwtype); + PACK_STRUCT_FIELD(u16_t protocol); + PACK_STRUCT_FIELD(u16_t _hwlen_protolen); + PACK_STRUCT_FIELD(u16_t opcode); + PACK_STRUCT_FIELD(struct uip_eth_addr shwaddr); + PACK_STRUCT_FIELD(struct uip_ip_addr2 sipaddr); + PACK_STRUCT_FIELD(struct uip_eth_addr dhwaddr); + PACK_STRUCT_FIELD(struct uip_ip_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +PACK_STRUCT_BEGIN +struct uip_ethip_hdr { + PACK_STRUCT_FIELD(struct uip_eth_hdr ethhdr); + PACK_STRUCT_FIELD(struct uip_ip_hdr ip); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + + +extern struct uip_eth_addr uip_ethaddr; + +struct uip_pbuf; +struct uip_netif; + +/* The uip_arp_init() function must be called before any of the other + ARP functions. */ +void uip_arp_init(void); + +/* The uip_arp_ipin() function should be called whenever an IP packet + arrives from the Ethernet. This function refreshes the ARP table or + inserts a new mapping if none exists. The function assumes that an + IP packet with an Ethernet header is present in the uip_buf buffer + and that the length of the packet is in the uip_len variable. */ +void uip_arp_ipin(struct uip_netif *netif,struct uip_pbuf *p); + +/* The uip_arp_arpin() should be called when an ARP packet is received + by the Ethernet driver. This function also assumes that the + Ethernet frame is present in the uip_buf buffer. When the + uip_arp_arpin() function returns, the contents of the uip_buf + buffer should be sent out on the Ethernet if the uip_len variable + is > 0. */ +void uip_arp_arpin(struct uip_netif *netif,struct uip_eth_addr *ethaddr,struct uip_pbuf *p); + +/* The uip_arp_out() function should be called when an IP packet + should be sent out on the Ethernet. This function creates an + Ethernet header before the IP header in the uip_buf buffer. The + Ethernet header will have the correct Ethernet MAC destination + address filled in if an ARP table entry for the destination IP + address (or the IP address of the default router) is present. If no + such table entry is found, the IP packet is overwritten with an ARP + request and we rely on TCP to retransmit the packet that was + overwritten. In any case, the uip_len variable holds the length of + the Ethernet frame that should be transmitted. */ +s8_t uip_arp_out(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_pbuf *q); + +/* The uip_arp_timer() function should be called every ten seconds. It + is responsible for flushing old entries in the ARP table. */ +void uip_arp_timer(void); + +s8_t uip_arp_arpquery(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_pbuf *q); + +s8_t uip_arp_arprequest(struct uip_netif *netif,struct uip_ip_addr *ipaddr); + +#endif /* __UIP_ARP_H__ */ + + diff --git a/wii/libogc/libdb/uIP/uip_icmp.c b/wii/libogc/libdb/uIP/uip_icmp.c new file mode 100644 index 0000000000..5c96e65355 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_icmp.c @@ -0,0 +1,101 @@ +#include +#include + +#include "uip_ip.h" +#include "uip_pbuf.h" +#include "uip_netif.h" +#include "uip_icmp.h" + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +void uip_icmpinput(struct uip_pbuf *p,struct uip_netif *inp) +{ + u8_t type; + u16_t hlen; + struct uip_ip_addr tmpaddr; + struct uip_ip_hdr *iphdr; + struct uip_icmp_echo_hdr *iecho; + + iphdr = p->payload; + hlen = UIP_IPH_HL(iphdr)*4; + if(uip_pbuf_header(p,-((s16_t)hlen)) || p->tot_lenpayload); + //code = *((u8_t*)p->payload+1); + switch(type) { + case UIP_ICMP_ECHO: + if(ip_addr_isbroadcast(&iphdr->dst,inp) || ip_addr_ismulticast(&iphdr->dst)) { + UIP_LOG("uip_icmpinput: Not echoing to broadcast pings.\n"); + uip_pbuf_free(p); + return; + } + + if(p->tot_lenpayload; + if(uip_ipchksum_pbuf(p)!=0) { + UIP_LOG("uip_icmpinput: checksum failed for received ICMP echo.\n"); + uip_pbuf_free(p); + return; + } + + tmpaddr.addr = iphdr->src.addr; + iphdr->src.addr = iphdr->dst.addr; + iphdr->dst.addr = tmpaddr.addr; + UIP_ICMPH_TYPE_SET(iecho,UIP_ICMP_ER); + + if(iecho->chksum>=htons(0xffff-(UIP_ICMP_ECHO<<8))) iecho->chksum += htons(UIP_ICMP_ECHO<<8)+1; + else iecho->chksum += htons(UIP_ICMP_ECHO<<8); + + uip_pbuf_header(p,hlen); + uip_ipoutput_if(p,&iphdr->src,NULL,UIP_IPH_TTL(iphdr),0,UIP_PROTO_ICMP,inp); + break; + default: + UIP_LOG("uip_icmpinput: ICMP type/code not supported.\n"); + break; + } + uip_pbuf_free(p); +} + +void uip_icmp_destunreach(struct uip_pbuf *p,enum uip_icmp_dur_type t) +{ + struct uip_pbuf *q; + struct uip_ip_hdr *iphdr; + struct uip_icmp_dur_hdr *idur; + + q = uip_pbuf_alloc(UIP_PBUF_IP,sizeof(struct uip_icmp_dur_hdr)+UIP_IP_HLEN+8,UIP_PBUF_RAM); + + iphdr = p->payload; + idur = q->payload; + + UIP_ICMPH_TYPE_SET(idur,UIP_ICMP_DUR); + UIP_ICMPH_CODE_SET(idur,t); + + UIP_MEMCPY((u8_t*)q->payload+sizeof(struct uip_icmp_dur_hdr),p->payload,UIP_IP_HLEN+8); + + idur->chksum = 0; + idur->chksum = uip_ipchksum(idur,q->len); + + uip_ipoutput(q,NULL,&iphdr->src,UIP_ICMP_TTL,0,UIP_PROTO_ICMP); + uip_pbuf_free(q); +} diff --git a/wii/libogc/libdb/uIP/uip_icmp.h b/wii/libogc/libdb/uIP/uip_icmp.h new file mode 100644 index 0000000000..42928a0fab --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_icmp.h @@ -0,0 +1,60 @@ +#ifndef __UIP_ICMP_H__ +#define __UIP_ICMP_H__ + +#include "uip.h" +#include "uip_arch.h" + +#define UIP_ICMP_TTL 255 + +#define UIP_ICMP_ER 0 /* echo reply */ +#define UIP_ICMP_DUR 3 /* destination unreachable */ +#define UIP_ICMP_SQ 4 /* source quench */ +#define UIP_ICMP_RD 5 /* redirect */ +#define UIP_ICMP_ECHO 8 /* echo */ +#define UIP_ICMP_TE 11 /* time exceeded */ +#define UIP_ICMP_PP 12 /* parameter problem */ +#define UIP_ICMP_TS 13 /* timestamp */ +#define UIP_ICMP_TSR 14 /* timestamp reply */ +#define UIP_ICMP_IRQ 15 /* information request */ +#define UIP_ICMP_IR 16 /* information reply */ + +#define UIP_ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8) +#define UIP_ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff) + +#define UIP_ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(UIP_ICMPH_CODE(hdr) | ((type) << 8))) +#define UIP_ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (UIP_ICMPH_TYPE(hdr) << 8))) + +enum uip_icmp_dur_type { + UIP_ICMP_DUR_NET = 0, /* net unreachable */ + UIP_ICMP_DUR_HOST = 1, /* host unreachable */ + UIP_ICMP_DUR_PROTO = 2, /* protocol unreachable */ + UIP_ICMP_DUR_PORT = 3, /* port unreachable */ + UIP_ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ + UIP_ICMP_DUR_SR = 5 /* source route failed */ +}; + +PACK_STRUCT_BEGIN +struct uip_icmp_echo_hdr { + PACK_STRUCT_FIELD(u16_t _type_code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +PACK_STRUCT_BEGIN +struct uip_icmp_dur_hdr { + PACK_STRUCT_FIELD(u16_t _type_code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t unused); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +struct uip_pbuf; +struct uip_netif; + + +void uip_icmpinput(struct uip_pbuf *p,struct uip_netif *inp); +void uip_icmp_destunreach(struct uip_pbuf *p,enum uip_icmp_dur_type t); + +#endif diff --git a/wii/libogc/libdb/uIP/uip_ip.c b/wii/libogc/libdb/uIP/uip_ip.c new file mode 100644 index 0000000000..baac2014b9 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_ip.c @@ -0,0 +1,490 @@ +#include +#include +#include + +#include "uip_ip.h" +#include "uip_tcp.h" +#include "uip_icmp.h" +#include "uip_netif.h" +#include "uip_pbuf.h" + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_ERRORING == 1 +#include +#define UIP_ERROR(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_ERROR(m) +#endif /* UIP_ERRORING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +const struct uip_ip_addr ipaddr_any = { 0x0000000UL }; +const struct uip_ip_addr ipaddr_broadcast = { 0xffffffffUL }; + +#if UIP_IP_REASSEMBLY + +#define UIP_REASS_FLAG_LASTFRAG 0x01 +#define UIP_REASS_BUFSIZE 5760 + +static u8_t uip_reassbuf[UIP_IP_HLEN+UIP_REASS_BUFSIZE]; +static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)]; +static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; +static u16_t uip_reasslen; +static u8_t uip_reassflags; +static u8_t uip_reasstmr; +static s64 uip_reasstime = 0; + +extern s64 gettime(); + +static struct uip_pbuf* uip_copyfrom_pbuf(struct uip_pbuf *p,u16_t *offset,u8_t *buffer,u16_t len) +{ + u16_t l; + + p->payload = (u8_t*)p->payload+(*offset); + p->len -= (*offset); + while(len) { + l = lenlen?len:p->len; + UIP_MEMCPY(buffer,p->payload,l); + buffer += l; + len -= l; + if(len) p = p->next; + else *offset = l; + } + return p; +} + +static struct uip_pbuf* uip_ipreass(struct uip_pbuf *p) +{ + u16_t offset, len; + u16_t i; + struct uip_pbuf *q; + struct uip_ip_hdr *iphdr,*fraghdr; + + /* If ip_reasstmr is zero, no packet is present in the buffer, so we + write the IP header of the fragment into the reassembly + buffer. The timer is updated with the maximum age. */ + iphdr = (struct uip_ip_hdr*)uip_reassbuf; + fraghdr = (struct uip_ip_hdr*)p->payload; + if(uip_reasstmr == 0) { + UIP_MEMCPY(iphdr, fraghdr, UIP_IP_HLEN); + uip_reasstmr = UIP_REASS_MAXAGE; + uip_reassflags = 0; + uip_reasstime = gettime(); + /* Clear the bitmap. */ + UIP_MEMSET(uip_reassbitmap, 0,sizeof(uip_reassbitmap)); + } + + /* Check if the incoming fragment matches the one currently present + in the reasembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if(ip_addr_cmp(&iphdr->src,&fraghdr->src) + && ip_addr_cmp(&iphdr->dst,&fraghdr->dst) + && UIP_IPH_ID(iphdr) == UIP_IPH_ID(fraghdr)) { + + len = ntohs(UIP_IPH_LEN(fraghdr)) - UIP_IPH_HL(fraghdr)*4; + offset = (ntohs(UIP_IPH_OFFSET(fraghdr))&UIP_IP_OFFMASK)*8; + + /* If the offset or the offset + fragment length overflows the + reassembly buffer, we discard the entire packet. */ + if(offset > UIP_REASS_BUFSIZE || + offset + len > UIP_REASS_BUFSIZE) { + uip_reasstmr = 0; + uip_reasstime = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + i = UIP_IPH_HL(fraghdr)*4; + uip_copyfrom_pbuf(p,&i,&uip_reassbuf[UIP_IP_HLEN+offset],len); + + /* Update the bitmap. */ + if(offset / (8 * 8) == (offset + len) / (8 * 8)) { + /* If the two endpoints are in the same byte, we only update + that byte. */ + + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7] & + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } else { + /* If the two endpoints are in different bytes, we update the + bytes in the endpoints and fill the stuff inbetween with + 0xff. */ + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7]; + for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { + uip_reassbitmap[i] = 0xff; + } + uip_reassbitmap[(offset + len) / (8 * 8)] |= + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } + + /* If this fragment has the More Fragments flag set to zero, we + know that this is the last fragment, so we can calculate the + size of the entire packet. We also set the + IP_REASS_FLAG_LASTFRAG flag to indicate that we have received + the final fragment. */ + + if((ntohs(UIP_IPH_OFFSET(fraghdr))&UIP_IP_MF)==0) { + uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; + uip_reasslen = offset + len; + } + + /* Finally, we check if we have a full packet in the buffer. We do + this by checking if we have the last fragment and if all bits + in the bitmap are set. */ + if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { + /* Check all bytes up to and including all but the last byte in + the bitmap. */ + for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { + if(uip_reassbitmap[i] != 0xff) { + goto nullreturn; + } + } + /* Check the last byte in the bitmap. It should contain just the + right amount of bits. */ + if(uip_reassbitmap[uip_reasslen / (8 * 8)] != + (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) { + goto nullreturn; + } + + uip_reasslen += UIP_IP_HLEN; + + /* Pretend to be a "normal" (i.e., not fragmented) IP packet + from now on. */ + UIP_IPH_LEN_SET(iphdr,htons(uip_reasslen)); + UIP_IPH_OFFSET_SET(iphdr,0); + UIP_IPH_CHKSUM_SET(iphdr,0); + UIP_IPH_CHKSUM_SET(iphdr,uip_ipchksum(iphdr,UIP_IP_HLEN)); + + /* If we have come this far, we have a full packet in the + buffer, so we allocate a pbuf and copy the packet into it. We + also reset the timer. */ + uip_reasstmr = 0; + uip_reasstime = 0; + uip_pbuf_free(p); + p = uip_pbuf_alloc(UIP_PBUF_LINK,uip_reasslen,UIP_PBUF_POOL); + if(p==NULL) return NULL; + + i = 0; + for(q=p;q!=NULL;q=q->next) { + UIP_MEMCPY(q->payload,&uip_reassbuf[i],((q->len>(uip_reasslen-i))?(uip_reasslen-i):q->len)); + i += q->len; + } + return p; + } + } + + nullreturn: + uip_pbuf_free(p); + return NULL; +} +#endif /* UIP_IP_REASSEMBLY */ + +#if UIP_IP_FRAG +#define MAX_MTU 1500 +static u8_t buf[MEM_ALIGN_SIZE(MAX_MTU)]; + +s8_t uip_ipfrag(struct uip_pbuf *p,struct uip_netif *netif,struct uip_ip_addr *ipaddr) +{ + struct uip_pbuf *rambuf; + struct uip_pbuf *header; + struct uip_ip_hdr *iphdr; + u16_t left,cop,ofo,omf,last,tmp; + u16_t mtu = netif->mtu; + u16_t poff = UIP_IP_HLEN; + u16_t nfb = 0; + + rambuf = uip_pbuf_alloc(UIP_PBUF_LINK,0,UIP_PBUF_REF); + rambuf->tot_len = rambuf->len = mtu; + rambuf->payload = MEM_ALIGN(buf); + + iphdr = rambuf->payload; + UIP_MEMCPY(iphdr,p->payload,UIP_IP_HLEN); + + tmp = ntohs(UIP_IPH_OFFSET(iphdr)); + ofo = tmp&UIP_IP_OFFMASK; + omf = tmp&UIP_IP_MF; + + left = p->tot_len - UIP_IP_HLEN; + while(left) { + last = (left<=(mtu-UIP_IP_HLEN)); + + ofo += nfb; + tmp = omf|(UIP_IP_OFFMASK&ofo); + + if(!last) tmp |= UIP_IP_MF; + UIP_IPH_OFFSET_SET(iphdr,htons(tmp)); + + nfb = (mtu - UIP_IP_HLEN)/8; + cop = last?left:nfb*8; + + p = uip_copyfrom_pbuf(p,&poff,(u8_t*)iphdr+UIP_IP_HLEN,cop); + + UIP_IPH_LEN_SET(iphdr,htons(cop+UIP_IP_HLEN)); + UIP_IPH_CHKSUM_SET(iphdr,0); + UIP_IPH_CHKSUM_SET(iphdr,uip_ipchksum(iphdr,UIP_IP_HLEN)); + + if(last) uip_pbuf_realloc(rambuf,left+UIP_IP_HLEN); + + header = uip_pbuf_alloc(UIP_PBUF_LINK,0,UIP_PBUF_RAM); + uip_pbuf_chain(header,rambuf); + netif->output(netif,header,ipaddr); + uip_pbuf_free(header); + + left -= cop; + } + uip_pbuf_free(rambuf); + return UIP_ERR_OK; +} +#endif /* UIP_IP_FRAG */ + +struct uip_netif* uip_iproute(struct uip_ip_addr *dst) +{ + struct uip_netif *netif; + + for(netif=uip_netif_list;netif!=NULL;netif=netif->next) { + if(ip_addr_netcmp(dst,&netif->ip_addr,&netif->netmask)) return netif; + } + + return uip_netif_default; +} + +u8_t uip_ipaddr_isbroadcast(struct uip_ip_addr *addr,struct uip_netif *netif) +{ + if(addr->addr==ipaddr_broadcast.addr + || addr->addr==ipaddr_any.addr) + return 1; + else if(!(netif->flags&UIP_NETIF_FLAG_BROADCAST)) + return 0; + else if(addr->addr==netif->ip_addr.addr) + return 0; + else if(ip_addr_netcmp(addr,&netif->ip_addr,&netif->netmask) + && ((addr->addr&~netif->netmask.addr)==(ipaddr_broadcast.addr&~netif->netmask.addr))) + return 1; + else + return 0; +} + +s8_t uip_ipinput(struct uip_pbuf *p,struct uip_netif *inp) +{ + u16_t iphdr_len; + struct uip_ip_hdr *iphdr; + struct uip_netif *netif; + + iphdr = p->payload; + if(UIP_IPH_V(iphdr)!=4) { + UIP_ERROR("uip_ipinput: ip packet dropped due to bad version number.\n"); + uip_pbuf_free(p); + return 0; + } + + iphdr_len = UIP_IPH_HL(iphdr); + iphdr_len *= 4; + + if(iphdr_len>p->len) { + UIP_ERROR("uip_ipinput: ip packet dropped due to too small packet size.\n"); + uip_pbuf_free(p); + return 0; + } + + if(uip_ipchksum(iphdr,iphdr_len)!=0) { + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.chkerr); + UIP_ERROR("uip_ipinput: bad checksum.\n"); + uip_pbuf_free(p); + return 0; + } + + uip_pbuf_realloc(p,ntohs(UIP_IPH_LEN(iphdr))); + + for(netif=uip_netif_list;netif!=NULL;netif=netif->next) { + if(uip_netif_isup(netif) && !ip_addr_isany(&netif->ip_addr)) { + if(ip_addr_cmp(&iphdr->dst,&netif->ip_addr) || + ip_addr_isbroadcast(&iphdr->dst,netif)) break; + } + } + + if(!netif) { + UIP_ERROR("uip_ipinput: no route found.\n"); + uip_pbuf_free(p); + return 0; + } + + if((UIP_IPH_OFFSET(iphdr)&htons(UIP_IP_OFFMASK|UIP_IP_MF))!=0) { +#if UIP_IP_REASSEMBLY + p = uip_ipreass(p); + if(p==NULL) return UIP_ERR_OK; + + iphdr = (struct uip_ip_hdr*)p->payload; +#else + uip_pbuf_free(p); + UIP_STAT(++uip_stat.ip.drop); + UIP_ERROR("ip: fragment dropped.\n"); + return 0; +#endif + } + + switch(UIP_IPH_PROTO(iphdr)) { + case UIP_PROTO_TCP: + uip_tcpinput(p,inp); + break; + case UIP_PROTO_ICMP: + uip_icmpinput(p,inp); + break; + default: + UIP_LOG("uip_ipinput: Unsupported protocol.\n"); + if(!ip_addr_isbroadcast(&(iphdr->dst),inp) + && !ip_addr_ismulticast(&(iphdr->dst))) { + p->payload = iphdr; + uip_icmp_destunreach(p,UIP_ICMP_DUR_PROTO); + } + uip_pbuf_free(p); + break; + } + return 0; +} + +s8_t uip_ipoutput_if(struct uip_pbuf *p,struct uip_ip_addr *src,struct uip_ip_addr *dst,u8_t ttl,u8_t tos,u8_t proto,struct uip_netif *netif) +{ + struct uip_ip_hdr *iphdr = NULL; + u16_t ip_id = 0; + + if(dst!=NULL) { + if(uip_pbuf_header(p,UIP_IP_HLEN)) { + UIP_ERROR("uip_ipoutput_if: not enough room for IP header in pbuf.\n"); + return UIP_ERR_BUF; + } + + iphdr = p->payload; + + UIP_IPH_TTL_SET(iphdr,ttl); + UIP_IPH_PROTO_SET(iphdr,proto); + + ip_addr_set(&iphdr->dst,dst); + + UIP_IPH_VHLTOS_SET(iphdr,4,(UIP_IP_HLEN/4),tos); + UIP_IPH_LEN_SET(iphdr,htons(p->tot_len)); + UIP_IPH_OFFSET_SET(iphdr,htons(UIP_IP_DF)); + UIP_IPH_ID_SET(iphdr,htons(ip_id)); + ++ip_id; + + if(ip_addr_isany(src)) ip_addr_set(&iphdr->src,&netif->ip_addr); + else ip_addr_set(&iphdr->src,src); + + UIP_IPH_CHKSUM_SET(iphdr,0); + UIP_IPH_CHKSUM_SET(iphdr,uip_ipchksum(iphdr,UIP_IP_HLEN)); + } else { + iphdr = p->payload; + dst = &iphdr->dst; + } +#if UIP_IP_FRAG + if(netif->mtu && p->tot_len>netif->mtu) + return uip_ipfrag(p,netif,dst); +#endif + return netif->output(netif,p,dst); +} + +s8_t uip_ipoutput(struct uip_pbuf *p,struct uip_ip_addr *src,struct uip_ip_addr *dst,u8_t ttl,u8_t tos,u8_t proto) +{ + struct uip_netif *netif; + + if((netif=uip_iproute(dst))==NULL) { + UIP_ERROR("uip_ipoutput: No route found.\n"); + return UIP_ERR_RTE; + } + return uip_ipoutput_if(p,src,dst,ttl,tos,proto,netif); +} + +void uip_ipinit() +{ + +} + +s32_t uip_ipaton(const u8_t *cp,struct in_addr *addr) +{ + u32_t val; + u8_t c; + u32_t parts[4]; + u32_t *pp = parts; + int base,n; + + c = *cp; + for(;;) { + if(!isdigit(c)) return 0; + + val = 0; base = 10; + if(c=='0') { + c = *++cp; + if(c=='x' || c=='X') + base = 16, c = *++cp; + else + base = 8; + } + for(;;) { + if(isdigit(c)) { + val = (val*base)+(int)(c-'0'); + c = *++cp; + } else if(base==16 && isxdigit(c)) { + val = (val<<4)|(int)(c+10-(islower(c)?'a':'A')); + c = *++cp; + } else + break; + } + if(c=='.') { + if(pp>=parts+3) return 0; + *pp++ = val; + c = *++cp; + } else + break; + } + + if(c!='\0' && (!isascii(c) || isspace(c))) return 0; + + n = pp-parts+1; + switch(n) { + case 0: + return 0; + case 1: + break; + case 2: + if(val>0x00ffffff) return 0; + + val |= (parts[0]<<24); + break; + case 3: + if(val>0x0000ffff) return 0; + + val |= (parts[0]<<24)|(parts[1]<<16); + break; + case 4: + if(val>0x000000ff) return 0; + + val |= (parts[0]<<24)|(parts[1]<<16)|(parts[2]<<8); + break; + } + if(addr) + addr->s_addr = htonl(val); + + return 1; +} + +u32_t uip_ipaddr(const u8_t *cp) +{ + struct in_addr val; + + if(uip_ipaton(cp,&val)) return (val.s_addr); + + return (UIP_INADDR_NONE); +} diff --git a/wii/libogc/libdb/uIP/uip_ip.h b/wii/libogc/libdb/uIP/uip_ip.h new file mode 100644 index 0000000000..366829efee --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_ip.h @@ -0,0 +1,135 @@ +#ifndef __UIP_IP_H__ +#define __UIP_IP_H__ + +#include "uip.h" + +#define UIP_INADDR_NONE ((u32_t) 0xffffffff) /* 255.255.255.255 */ +#define UIP_INADDR_LOOPBACK ((u32_t) 0x7f000001) /* 127.0.0.1 */ + +#define UIP_IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12) +#define UIP_IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) +#define UIP_IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#define UIP_IPH_LEN(hdr) ((hdr)->_len) +#define UIP_IPH_ID(hdr) ((hdr)->_id) +#define UIP_IPH_OFFSET(hdr) ((hdr)->_offset) +#define UIP_IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8) +#define UIP_IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff) +#define UIP_IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define UIP_IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#define UIP_IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define UIP_IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define UIP_IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define UIP_IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(UIP_IPH_PROTO(hdr) | ((ttl) << 8))) +#define UIP_IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (UIP_IPH_TTL(hdr) << 8))) +#define UIP_IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +#define UIP_SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */ +#define UIP_SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */ +#define UIP_SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */ +#define UIP_SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */ +#define UIP_SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */ +#define UIP_SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */ +#define UIP_SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */ +#define UIP_SOF_LINGER (u16_t)0x0080U /* linger on close if data present */ +#define UIP_SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */ +#define UIP_SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */ + +#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = htonl(((u32_t)(a & 0xff) << 24) | ((u32_t)(b & 0xff) << 16) | \ + ((u32_t)(c & 0xff) << 8) | (u32_t)(d & 0xff)) + +#define ip_addr_set(dest, src) (dest)->addr = \ + ((src) == NULL? 0:\ + (src)->addr) + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0) + +#define ip_addr_isbroadcast uip_ipaddr_isbroadcast + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000)) == ntohl(0xe0000000)) + +#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff) +#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff) +#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff) +#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff) + +#ifndef HAVE_IN_ADDR +#define HAVE_IN_ADDR +struct in_addr { + u32 s_addr; +}; +#endif + +/* The IP Address */ +PACK_STRUCT_BEGIN +struct uip_ip_addr { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +PACK_STRUCT_BEGIN +struct uip_ip_addr2 { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +/* The IP Header */ +PACK_STRUCT_BEGIN +struct uip_ip_hdr { +#define UIP_IP_RF 0x8000 +#define UIP_IP_DF 0x4000 +#define UIP_IP_MF 0x2000 +#define UIP_IP_OFFMASK 0x1fff + PACK_STRUCT_FIELD(u16_t _v_hl_tos); + PACK_STRUCT_FIELD(u16_t _len); + PACK_STRUCT_FIELD(u16_t _id); + PACK_STRUCT_FIELD(u16_t _offset); + PACK_STRUCT_FIELD(u16_t _ttl_proto); + PACK_STRUCT_FIELD(u16_t _chksum); + + PACK_STRUCT_FIELD(struct uip_ip_addr src); + PACK_STRUCT_FIELD(struct uip_ip_addr dst); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#define UIP_IP_PCB \ + struct uip_ip_addr local_ip; \ + struct uip_ip_addr remote_ip; \ + u16_t so_options; \ + u8_t tos; \ + u8_t ttl + +struct uip_pbuf; +struct uip_netif; +struct ip_addr; + + +void uip_ipinit(); + +u32_t uip_ipaddr(const u8_t *cp); +s32_t uip_ipaton(const u8_t *cp,struct in_addr *addr); +s8_t uip_ipinput(struct uip_pbuf *p,struct uip_netif *inp); +s8_t uip_ipoutput(struct uip_pbuf *p,struct uip_ip_addr *src,struct uip_ip_addr *dst,u8_t ttl,u8_t tos,u8_t proto); +s8_t uip_ipoutput_if(struct uip_pbuf *p,struct uip_ip_addr *src,struct uip_ip_addr *dst,u8_t ttl,u8_t tos,u8_t proto,struct uip_netif *netif); +struct uip_netif* uip_iproute(struct uip_ip_addr *dst); +u8_t uip_ipaddr_isbroadcast(struct uip_ip_addr *addr,struct uip_netif *netif); + + +#endif diff --git a/wii/libogc/libdb/uIP/uip_netif.c b/wii/libogc/libdb/uIP/uip_netif.c new file mode 100644 index 0000000000..5c7e1b77ff --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_netif.c @@ -0,0 +1,133 @@ +#include +#include + +#include "uip_ip.h" +#include "uip_tcp.h" +#include "uip_pbuf.h" +#include "uip_netif.h" + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_ERRORING == 1 +#include +#define UIP_ERROR(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_ERROR(m) +#endif /* UIP_ERRORING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + + +struct uip_netif *uip_netif_list; +struct uip_netif *uip_netif_default; + +void uip_netif_init() +{ + uip_netif_list = uip_netif_default = NULL; +} + +void uip_netif_setup(struct uip_netif *netif) +{ + netif->flags |= UIP_NETIF_FLAG_UP; +} + +u8_t uip_netif_isup(struct uip_netif *netif) +{ + return (netif->flags&UIP_NETIF_FLAG_UP); +} + +struct uip_netif* uip_netif_add(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_ip_addr *netmask,struct uip_ip_addr *gw,void *state,s8_t (*init)(struct uip_netif *netif),s8_t (*input)(struct uip_pbuf *p,struct uip_netif *netif)) +{ + static int netif_num = 0; + + netif->state = state; + netif->num = netif_num++; + netif->input = input; + + uip_netif_setaddr(netif,ipaddr,netmask,gw); + + if(init(netif)!=0) return NULL; + + UIP_LOG("uip_netif_add: netif is up.\n"); + + netif->next = uip_netif_list; + uip_netif_list = netif; + + return netif; +} + +void uip_netif_setaddr(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_ip_addr *netmask,struct uip_ip_addr *gw) +{ + uip_netif_setipaddr(netif,ipaddr); + uip_netif_setnetmask(netif,netmask); + uip_netif_setgw(netif,gw); +} + +void uip_netif_setipaddr(struct uip_netif *netif,struct uip_ip_addr *ipaddr) +{ +#if UIP_TCP + struct uip_tcp_pcb *pcb; + struct uip_tcp_pcb_listen *lpcb; + + if((ip_addr_cmp(ipaddr,&netif->ip_addr))==0) { + pcb = uip_tcp_active_pcbs; + while(pcb!=NULL) { + if(ip_addr_cmp(&pcb->local_ip,&netif->ip_addr)) { + struct uip_tcp_pcb *next = pcb->next; + pcb = next; + } else { + pcb = pcb->next; + } + } + for(lpcb=uip_tcp_listen_pcbs.listen_pcbs;lpcb!=NULL;lpcb=lpcb->next) { + if(ip_addr_cmp(&lpcb->local_ip,&netif->ip_addr)) { + ip_addr_set(&lpcb->local_ip,ipaddr); + } + } + } +#endif + ip_addr_set(&netif->ip_addr,ipaddr); +} + +void uip_netif_setnetmask(struct uip_netif *netif,struct uip_ip_addr *netmask) +{ + ip_addr_set(&netif->netmask,netmask); +} + +void uip_netif_setgw(struct uip_netif *netif,struct uip_ip_addr *gw) +{ + ip_addr_set(&netif->gw,gw); +} + +void uip_netif_setdefault(struct uip_netif *netif) +{ + uip_netif_default = netif; +} + +struct uip_netif* uip_netif_find(const char *name) +{ + u8_t num; + struct uip_netif *netif; + + if(name==NULL) return NULL; + + num = name[2] - '0'; + + for(netif=uip_netif_list;netif!=NULL;netif=netif->next) { + if(netif->num==num && + netif->name[0]==name[0] && + netif->name[1]==name[1]) return netif; + } + + return NULL; +} diff --git a/wii/libogc/libdb/uIP/uip_netif.h b/wii/libogc/libdb/uIP/uip_netif.h new file mode 100644 index 0000000000..364d825c88 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_netif.h @@ -0,0 +1,65 @@ +#ifndef __UIP_NETIF_H__ +#define __UIP_NETIF_H__ + +#include "uip.h" + +#define UIP_NETIF_MAX_HWADDR_LEN 6U + +/** TODO: define the use (where, when, whom) of netif flags */ + +/** whether the network interface is 'up'. this is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + */ +#define UIP_NETIF_FLAG_UP 0x1U +/** if set, the netif has broadcast capability */ +#define UIP_NETIF_FLAG_BROADCAST 0x2U +/** if set, the netif is one end of a point-to-point connection */ +#define UIP_NETIF_FLAG_POINTTOPOINT 0x4U +/** if set, the interface is configured using DHCP */ +#define UIP_NETIF_FLAG_DHCP 0x08U +/** if set, the interface has an active link + * (set by the network interface driver) */ +#define UIP_NETIF_FLAG_LINK_UP 0x10U + +struct uip_netif; +struct uip_pbuf; +struct uip_ip_addr; + +struct uip_netif { + struct uip_netif *next; + + struct uip_ip_addr ip_addr; + struct uip_ip_addr netmask; + struct uip_ip_addr gw; + + s8_t (*input)(struct uip_pbuf *p,struct uip_netif *inp); + s8_t (*output)(struct uip_netif *netif,struct uip_pbuf *p,struct uip_ip_addr *ipaddr); + s8_t (*linkoutput)(struct uip_netif *netif,struct uip_pbuf *p); + + void *state; + + u8_t hwaddr_len; + u8_t hwaddr[UIP_NETIF_MAX_HWADDR_LEN]; + + u16_t mtu; + u8_t flags; + + s8_t name[2]; + u8_t num; +}; + +extern struct uip_netif *uip_netif_list; +extern struct uip_netif *uip_netif_default; + +void uip_netif_init(); +void uip_netif_setup(struct uip_netif *netif); +void uip_netif_setaddr(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_ip_addr *netmask,struct uip_ip_addr *gw); +void uip_netif_setipaddr(struct uip_netif *netif,struct uip_ip_addr *ipaddr); +void uip_netif_setnetmask(struct uip_netif *netif,struct uip_ip_addr *netmask); +void uip_netif_setgw(struct uip_netif *netif,struct uip_ip_addr *gw); +void uip_netif_setdefault(struct uip_netif *netif); +u8_t uip_netif_isup(struct uip_netif *netif); +struct uip_netif* uip_netif_add(struct uip_netif *netif,struct uip_ip_addr *ipaddr,struct uip_ip_addr *netmask,struct uip_ip_addr *gw,void *state,s8_t (*init)(struct uip_netif *netif),s8_t (*input)(struct uip_pbuf *p,struct uip_netif *netif)); + +#endif diff --git a/wii/libogc/libdb/uIP/uip_pbuf.c b/wii/libogc/libdb/uIP/uip_pbuf.c new file mode 100644 index 0000000000..bb7612488a --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_pbuf.c @@ -0,0 +1,287 @@ +#include +#include + +#include "memb.h" +#include "memr.h" +#include "uip_pbuf.h" + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_ERRORING == 1 +#include +#define UIP_ERROR(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_ERROR(m) +#endif /* UIP_ERRORING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +MEMB(uip_pool_pbufs,sizeof(struct uip_pbuf)+UIP_PBUF_POOL_BUFSIZE,UIP_PBUF_POOL_NUM); +MEMB(uip_rom_pbufs,sizeof(struct uip_pbuf),UIP_PBUF_ROM_NUM); + +void uip_pbuf_init() +{ + memb_init(&uip_pool_pbufs); + memb_init(&uip_rom_pbufs); +} + +struct uip_pbuf* uip_pbuf_alloc(uip_pbuf_layer layer,u16_t len,uip_pbuf_flag flag) +{ + u16_t offset; + s32_t rem_len; + struct uip_pbuf *p,*q,*r; + + offset = 0; + switch(layer) { + case UIP_PBUF_TRANSPORT: + offset += UIP_TRANSPORT_HLEN; + case UIP_PBUF_IP: + offset += UIP_IP_HLEN; + case UIP_PBUF_LINK: + offset += UIP_LL_HLEN; + break; + case UIP_PBUF_RAW: + break; + default: + UIP_ERROR("uip_pbuf_alloc: bad pbuf layer.\n"); + return NULL; + } + + switch(flag) { + case UIP_PBUF_POOL: + p = memb_alloc(&uip_pool_pbufs); + if(p==NULL) { + UIP_ERROR("uip_pbuf_alloc: couldn't allocate pbuf(p) from pool\n"); + return NULL; + } + + p->next = NULL; + p->payload = MEM_ALIGN((void*)((u8_t*)p+(sizeof(struct uip_pbuf)+offset))); + p->tot_len = len; + p->len = (len>(UIP_PBUF_POOL_BUFSIZE-offset)?(UIP_PBUF_POOL_BUFSIZE-offset):len); + p->flags = UIP_PBUF_FLAG_POOL; + p->ref = 1; + + r = p; + rem_len = len - p->len; + while(rem_len>0) { + q = memb_alloc(&uip_pool_pbufs); + if(q==NULL) { + UIP_ERROR("uip_pbuf_alloc: couldn't allocate pbuf(q) from pool\n"); + uip_pbuf_free(p); + return NULL; + } + + q->next = NULL; + r->next = q; + q->tot_len = rem_len; + q->len = (rem_len>UIP_PBUF_POOL_BUFSIZE?UIP_PBUF_POOL_BUFSIZE:rem_len); + q->payload = (void*)((u8_t*)q+sizeof(struct uip_pbuf)); + q->flags = UIP_PBUF_FLAG_POOL; + q->ref = 1; + + rem_len -= q->len; + r = q; + } + break; + case UIP_PBUF_RAM: + p = memr_malloc(MEM_ALIGN_SIZE(sizeof(struct uip_pbuf)+offset)+MEM_ALIGN_SIZE(len)); + if(p==NULL) { + UIP_ERROR("uip_pbuf_alloc: couldn't allocate pbuf from ram\n"); + return NULL; + } + p->payload = MEM_ALIGN((u8_t*)p+sizeof(struct uip_pbuf)+offset); + p->len = p->tot_len = len; + p->next = NULL; + p->flags = UIP_PBUF_FLAG_RAM; + break; + case UIP_PBUF_ROM: + case UIP_PBUF_REF: + p = memb_alloc(&uip_rom_pbufs); + if(p==NULL) { + UIP_ERROR("uip_pbuf_alloc: couldn't allocate pbuf from rom/ref\n"); + return NULL; + } + p->payload = NULL; + p->next = NULL; + p->len = p->tot_len = len; + p->flags = (flag==UIP_PBUF_ROM?UIP_PBUF_FLAG_ROM:UIP_PBUF_FLAG_REF); + break; + default: + UIP_ERROR("uip_pbuf_alloc: bad flag value.\n"); + return NULL; + } + + p->ref = 1; + return p; +} + +u8_t uip_pbuf_free(struct uip_pbuf *p) +{ + u8_t cnt; + struct uip_pbuf *q; + + if(p==NULL) return 0; + + cnt = 0; + while(p!=NULL) { + p->ref--; + if(p->ref==0) { + q = p->next; + if(p->flags==UIP_PBUF_FLAG_POOL) { + memb_free(&uip_pool_pbufs,p); + } else if(p->flags==UIP_PBUF_FLAG_ROM || p->flags==UIP_PBUF_FLAG_REF) { + memb_free(&uip_rom_pbufs,p); + } else { + memr_free(p); + } + cnt++; + p = q; + } else + p = NULL; + } + return cnt; +} + +void uip_pbuf_realloc(struct uip_pbuf *p,u16_t new_len) +{ + u16_t rem_len; + s16_t grow; + struct uip_pbuf *q; + + if(new_len>=p->tot_len) return; + + grow = new_len - p->tot_len; + rem_len = new_len; + q = p; + while(rem_len>q->len) { + rem_len -= q->len; + q->tot_len += grow; + q = q->next; + } + + if(q->flags==UIP_PBUF_FLAG_RAM && rem_len!=q->len) + memr_realloc(q,(u8_t*)q->payload-(u8_t*)q+rem_len); + + q->len = rem_len; + q->tot_len = q->len; + + if(q->next!=NULL) uip_pbuf_free(q->next); + q->next = NULL; +} + +u8_t uip_pbuf_header(struct uip_pbuf *p,s16_t hdr_size_inc) +{ + void *payload; + + if(hdr_size_inc==0 || p==NULL) return 0; + + + payload = p->payload; + if(p->flags==UIP_PBUF_FLAG_POOL || p->flags==UIP_PBUF_FLAG_RAM) { + p->payload = (u8_t*)p->payload-hdr_size_inc; + if((u8_t*)p->payload<(u8_t*)p+sizeof(struct uip_pbuf)) { + p->payload = payload; + return 1; + } + } else if(p->flags==UIP_PBUF_FLAG_ROM || p->flags==UIP_PBUF_FLAG_REF) { + if(hdr_size_inc<0 && hdr_size_inc-p->len<=0) p->payload = (u8_t*)p->payload-hdr_size_inc; + else return 1; + } + p->tot_len += hdr_size_inc; + p->len += hdr_size_inc; + + return 0; +} + +u8_t uip_pbuf_clen(struct uip_pbuf *p) +{ + u8_t len; + + len = 0; + while(p!=NULL) { + len++; + p = p->next; + } + return len; +} + +void uip_pbuf_ref(struct uip_pbuf *p) +{ + if(p!=NULL) { + ++(p->ref); + } +} + +void uip_pbuf_cat(struct uip_pbuf *h,struct uip_pbuf *t) +{ + struct uip_pbuf *p; + + if(h==NULL || t==NULL) return; + + for(p=h;p->next!=NULL;p=p->next) { + p->tot_len += t->tot_len; + } + p->tot_len += t->tot_len; + p->next = t; +} + +void uip_pbuf_queue(struct uip_pbuf *p,struct uip_pbuf *n) +{ + if(p==NULL || n==NULL || p==n) return; + + while(p->next!=NULL) p = p->next; + + p->next = n; + uip_pbuf_ref(n); +} + +struct uip_pbuf* uip_pbuf_dequeue(struct uip_pbuf *p) +{ + struct uip_pbuf *q; + u8_t tail_gone = 1; + + if(p==NULL) return NULL; + + while(p->tot_len!=p->len) p = p->next; + + q = p->next; + if(q!=NULL) { + p->next = NULL; + tail_gone = uip_pbuf_free(q); + } + return (tail_gone>0?NULL:q); +} + +void uip_pbuf_chain(struct uip_pbuf *h,struct uip_pbuf *t) +{ + uip_pbuf_cat(h,t); + uip_pbuf_ref(t); +} + +struct uip_pbuf* uip_pbuf_dechain(struct uip_pbuf *p) +{ + struct uip_pbuf *q; + u8_t tail_gone = 1; + + q = p->next; + if(q!=NULL) { + q->tot_len = p->tot_len - p->len; + p->next = NULL; + p->tot_len = p->len; + + tail_gone = uip_pbuf_free(q); + } + + return (tail_gone>0?NULL:q); +} diff --git a/wii/libogc/libdb/uIP/uip_pbuf.h b/wii/libogc/libdb/uIP/uip_pbuf.h new file mode 100644 index 0000000000..c3e55af3cf --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_pbuf.h @@ -0,0 +1,49 @@ +#ifndef __UIP_PBUF_H__ +#define __UIP_PBUF_H__ + +#include "uip.h" + +/* Definitions for the pbuf flag field. These are NOT the flags that + * are passed to pbuf_alloc(). */ +#define UIP_PBUF_FLAG_RAM 0x00U /* Flags that pbuf data is stored in RAM */ +#define UIP_PBUF_FLAG_ROM 0x01U /* Flags that pbuf data is stored in ROM */ +#define UIP_PBUF_FLAG_POOL 0x02U /* Flags that the pbuf comes from the pbuf pool */ +#define UIP_PBUF_FLAG_REF 0x04U /* Flags thet the pbuf payload refers to RAM */ + +typedef enum { + UIP_PBUF_TRANSPORT, + UIP_PBUF_IP, + UIP_PBUF_LINK, + UIP_PBUF_RAW +} uip_pbuf_layer; + +typedef enum { + UIP_PBUF_POOL, + UIP_PBUF_RAM, + UIP_PBUF_ROM, + UIP_PBUF_REF +} uip_pbuf_flag; + +struct uip_pbuf { + struct uip_pbuf *next; + void *payload; + u16_t tot_len; + u16_t len; + u16_t flags; + u16_t ref; +}; + +void uip_pbuf_init(); +struct uip_pbuf* uip_pbuf_alloc(uip_pbuf_layer layer,u16_t len,uip_pbuf_flag flag); +u8_t uip_pbuf_free(struct uip_pbuf *p); +void uip_pbuf_realloc(struct uip_pbuf *p,u16_t new_len); +u8_t uip_pbuf_header(struct uip_pbuf *p,s16_t hdr_size_inc); +void uip_pbuf_cat(struct uip_pbuf *h,struct uip_pbuf *t); +u8_t uip_pbuf_clen(struct uip_pbuf *p); +void uip_pbuf_queue(struct uip_pbuf *p,struct uip_pbuf *n); +void uip_pbuf_ref(struct uip_pbuf *p); +void uip_pbuf_chain(struct uip_pbuf *h,struct uip_pbuf *t); +struct uip_pbuf* uip_pbuf_dequeue(struct uip_pbuf *p); +struct uip_pbuf* uip_pbuf_dechain(struct uip_pbuf *p); + +#endif diff --git a/wii/libogc/libdb/uIP/uip_tcp.c b/wii/libogc/libdb/uIP/uip_tcp.c new file mode 100644 index 0000000000..004e2af978 --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_tcp.c @@ -0,0 +1,1478 @@ +#include +#include + +#include "memb.h" +#include "uip.h" +#include "uip_arch.h" +#include "uip_ip.h" +#include "uip_tcp.h" +#include "uip_pbuf.h" +#include "uip_netif.h" + +#if UIP_LOGGING == 1 +#include +#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_ERRORING == 1 +#include +#define UIP_ERROR(m) uip_log(__FILE__,__LINE__,m) +#else +#define UIP_ERROR(m) +#endif /* UIP_ERRORING == 1 */ + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +static u8_t uip_tcp_timer; +static u8_t uip_flags,uip_recv_flags; +static u16_t uip_tcplen; +static u32_t uip_seqno,uip_ackno; + +static struct uip_tcpseg uip_inseg; + +static struct uip_pbuf *uip_recv_data = NULL; +static struct uip_ip_hdr *uip_iphdr = NULL; +static struct uip_tcp_hdr *uip_tcphdr = NULL; + +u32_t uip_tcp_ticks; +struct uip_tcp_pcb *uip_tcp_tmp_pcb = NULL; +struct uip_tcp_pcb *uip_tcp_input_pcb = NULL; +struct uip_tcp_pcb *uip_tcp_active_pcbs = NULL; +struct uip_tcp_pcb *uip_tcp_tw_pcbs = NULL; + +union uip_tcp_listen_pcbs_t uip_tcp_listen_pcbs; + +const u8_t uip_tcp_backoff[13] = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; + +MEMB(uip_listen_tcp_pcbs,sizeof(struct uip_tcp_pcb_listen),UIP_LISTEN_TCP_PCBS); +MEMB(uip_tcp_pcbs,sizeof(struct uip_tcp_pcb),UIP_TCP_PCBS); +MEMB(uip_tcp_segs,sizeof(struct uip_tcpseg),UIP_TCP_SEGS); + +static s8_t uip_tcp_nullaccept(void *arg,struct uip_tcp_pcb *pcb,s8_t err); +static s8_t uip_tcp_nullrecv(void *arg,struct uip_tcp_pcb *pcb,struct uip_pbuf *p,s8_t err); + +static void uip_tcp_parseopt(struct uip_tcp_pcb *pcb); +static void uip_tcpoutput_segments(struct uip_tcpseg *seg,struct uip_tcp_pcb *pcb); +static s8_t uip_tcpinput_listen(struct uip_tcp_pcb_listen *pcb); +static s8_t uip_tcpinput_timewait(struct uip_tcp_pcb *pcb); +static s8_t uip_tcpprocess(struct uip_tcp_pcb *pcb); +static void uip_tcpreceive(struct uip_tcp_pcb *pcb); +static u16_t uip_tcp_newport(); + +s8_t uip_tcp_sendctrl(struct uip_tcp_pcb *pcb,u8_t flags) +{ + return uip_tcpenqueue(pcb,NULL,0,flags,1,NULL,0); +} + +s8_t uip_tcp_write(struct uip_tcp_pcb *pcb,const void *arg,u16_t len,u8_t copy) +{ + if(pcb->state==UIP_ESTABLISHED || pcb->state==UIP_CLOSE_WAIT || + pcb->state==UIP_SYN_SENT || pcb->state==UIP_SYN_RCVD) { + if(len>0) { + return uip_tcpenqueue(pcb,(void*)arg,len,0,copy,NULL,0); + } + return UIP_ERR_OK; + } + return UIP_ERR_CONN; +} + +s8_t uip_tcpenqueue(struct uip_tcp_pcb *pcb,void *arg,u16_t len,u8_t flags,u8_t copy,u8_t *optdata,u8_t optlen) +{ + struct uip_pbuf *p; + struct uip_tcpseg *seg,*useg,*queue = NULL; + u32_t left,seqno; + u16_t seglen; + void *ptr; + u8_t queue_len; + + if(len>pcb->snd_buf) { + UIP_ERROR("uip_tcpenqueue: too much data (len>pcb->snd_buf).\n"); + return UIP_ERR_MEM; + } + + left = len; + ptr = arg; + + seqno = pcb->snd_lbb; + queue_len = pcb->snd_queuelen; + + if(queue_len>=UIP_TCP_SND_QUEUELEN) { + UIP_ERROR("uip_tcpenqueue: too long queue."); + goto memerr; + } + useg = seg = queue = NULL; + seglen = 0; + while(queue==NULL || left>0) { + seglen = left>pcb->mss?pcb->mss:len; + seg = memb_alloc(&uip_tcp_segs); + if(seg==NULL) { + UIP_ERROR("uip_tcpenqueue: could not allocate memory for tcp_seg."); + goto memerr; + } + + seg->next = NULL; + seg->p = NULL; + + if(queue==NULL) queue = seg; + else useg->next = seg; + + useg = seg; + + if(optdata!=NULL) { + if((seg->p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,optlen,UIP_PBUF_RAM))==NULL) { + UIP_ERROR("uip_tcpenqueue: could not allocate memory for pbuf opdata."); + goto memerr; + } + ++queue_len; + seg->dataptr = seg->p->payload; + } else if(copy) { + if((seg->p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,seglen,UIP_PBUF_RAM))==NULL) { + UIP_ERROR("uip_tcpenqueue: could not allocate memory for pbuf copy size."); + goto memerr; + } + + ++queue_len; + if(ptr!=NULL) UIP_MEMCPY(seg->p->payload,ptr,seglen); + + seg->dataptr = seg->p->payload; + } else { + if((p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,seglen,UIP_PBUF_ROM))==NULL) { + UIP_ERROR("uip_tcpenqueue: could not allocate memory for zero-copy pbuf."); + goto memerr; + } + + ++queue_len; + p->payload = ptr; + seg->dataptr = ptr; + if((seg->p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,0,UIP_PBUF_RAM))==NULL) { + UIP_LOG("uip_tcpenqueue: could not allocate memory for header pbuf."); + uip_pbuf_free(p); + goto memerr; + } + + ++queue_len; + uip_pbuf_cat(seg->p,p); + p = NULL; + } + + if(queue_len>UIP_TCP_SND_QUEUELEN) { + UIP_ERROR("uip_tcpenqueue: queue too long."); + goto memerr; + } + + seg->len = seglen; + if(uip_pbuf_header(seg->p,UIP_TCP_HLEN)) { + UIP_ERROR("uip_tcpenqueue: no room for TCP header in pbuf."); + goto memerr; + } + + seg->tcphdr = seg->p->payload; + seg->tcphdr->src = htons(pcb->local_port); + seg->tcphdr->dst = htons(pcb->remote_port); + seg->tcphdr->seqno = htonl(seqno); + seg->tcphdr->urgp = 0; + UIP_TCPH_FLAGS_SET(seg->tcphdr,flags); + if(optdata==NULL) UIP_TCPH_HDRLEN_SET(seg->tcphdr,5); + else { + UIP_TCPH_HDRLEN_SET(seg->tcphdr,(5+(optlen/4))); + UIP_MEMCPY(seg->dataptr,optdata,optlen); + } + left -= seglen; + seqno += seglen; + ptr = (void*)((u8_t*)ptr+seglen); + } + + if(pcb->unsent==NULL) useg = NULL; + else { + for(useg=pcb->unsent;useg->next!=NULL;useg=useg->next); + } + + if(useg!=NULL && + UIP_TCP_TCPLEN(useg)!=0 && + !(UIP_TCPH_FLAGS(useg->tcphdr)&(UIP_TCP_SYN|UIP_TCP_FIN)) && + !(flags&(UIP_TCP_SYN|UIP_TCP_FIN)) && + useg->len+queue->len<=pcb->mss) { + + uip_pbuf_header(queue->p,-UIP_TCP_HLEN); + uip_pbuf_cat(useg->p,queue->p); + + useg->len += queue->len; + useg->next = queue->next; + if(seg==queue) seg = NULL; + + memb_free(&uip_tcp_segs,queue); + } else { + if(useg==NULL) pcb->unsent = queue; + else useg->next = queue; + } + + if(flags&UIP_TCP_SYN || flags&UIP_TCP_FIN) len++; + + pcb->snd_lbb += len; + pcb->snd_buf -= len; + pcb->snd_queuelen = queue_len; + + if(seg!=NULL && seglen>0 && seg->tcphdr!=NULL) UIP_TCPH_SET_FLAG(seg->tcphdr,UIP_TCP_PSH); + + return UIP_ERR_OK; +memerr: + if(queue!=NULL) uip_tcpsegs_free(queue); + return UIP_ERR_MEM; +} + +void uip_tcpinput(struct uip_pbuf *p,struct uip_netif *inp) +{ + s8_t err; + u8_t hdr_len; + struct uip_tcp_pcb *pcb,*prev; + struct uip_tcp_pcb_listen *lpcb; + + uip_iphdr = p->payload; + uip_tcphdr = (struct uip_tcp_hdr*)((u8_t*)p->payload+UIP_IPH_HL(uip_iphdr)*4); + + if(uip_pbuf_header(p,-((s16_t)(UIP_IPH_HL(uip_iphdr)*4))) || p->tot_lendst,inp) || + ip_addr_ismulticast(&uip_iphdr->dst)) { + uip_pbuf_free(p); + return; + } + + if(uip_chksum_pseudo(p,&uip_iphdr->src,&uip_iphdr->dst,UIP_PROTO_TCP,p->tot_len)!=0) { + UIP_LOG("uip_tcpinput: packet discarded due to failing checksum."); + uip_pbuf_free(p); + return; + } + + hdr_len = UIP_TCPH_HDRLEN(uip_tcphdr); + uip_pbuf_header(p,-(hdr_len*4)); + + uip_tcphdr->src = ntohs(uip_tcphdr->src); + uip_tcphdr->dst = ntohs(uip_tcphdr->dst); + uip_seqno = uip_tcphdr->seqno = ntohl(uip_tcphdr->seqno); + uip_ackno = uip_tcphdr->ackno = ntohl(uip_tcphdr->ackno); + uip_tcphdr->wnd = ntohs(uip_tcphdr->wnd); + + uip_flags = UIP_TCPH_FLAGS(uip_tcphdr)&UIP_TCP_FLAGS; + uip_tcplen = p->tot_len+((uip_flags&UIP_TCP_FIN||uip_flags&UIP_TCP_SYN)?1:0); + + prev = NULL; + for(pcb=uip_tcp_active_pcbs;pcb!=NULL;pcb=pcb->next) { + if(pcb->state!=UIP_CLOSED && pcb->state!=UIP_TIME_WAIT && pcb->state!=UIP_LISTEN) { + if(pcb->remote_port==uip_tcphdr->src && + pcb->local_port==uip_tcphdr->dst && + ip_addr_cmp(&pcb->remote_ip,&uip_iphdr->src) && + ip_addr_cmp(&pcb->local_ip,&uip_iphdr->dst)) { + if(prev!=NULL) { + prev->next = pcb->next; + pcb->next = uip_tcp_active_pcbs; + uip_tcp_active_pcbs = pcb; + } + break; + } + prev = pcb; + } + } + + if(pcb==NULL) { + for(pcb=uip_tcp_tw_pcbs;pcb!=NULL;pcb=pcb->next) { + if(pcb->state==UIP_TIME_WAIT && + pcb->remote_port==uip_tcphdr->src && + pcb->local_port==uip_tcphdr->dst && + ip_addr_cmp(&pcb->remote_ip,&uip_iphdr->src) && + ip_addr_cmp(&pcb->local_ip,&uip_iphdr->dst)) { + uip_tcpinput_timewait(pcb); + return; + } + } + + prev = NULL; + for(lpcb=uip_tcp_listen_pcbs.listen_pcbs;lpcb!=NULL;lpcb=lpcb->next) { + if((ip_addr_isany(&lpcb->local_ip) || ip_addr_cmp(&lpcb->local_ip,&uip_iphdr->dst)) && + lpcb->local_port==uip_tcphdr->dst) { + if(prev!=NULL) { + ((struct uip_tcp_pcb_listen*)prev)->next = lpcb->next; + lpcb->next = uip_tcp_listen_pcbs.listen_pcbs; + uip_tcp_listen_pcbs.listen_pcbs = lpcb; + } + uip_tcpinput_listen(lpcb); + return; + } + prev = (struct uip_tcp_pcb*)lpcb; + } + } + + if(pcb!=NULL) { + uip_inseg.next = NULL; + uip_inseg.len = p->tot_len; + uip_inseg.dataptr = p->payload; + uip_inseg.p = p; + uip_inseg.tcphdr = uip_tcphdr; + + uip_recv_data = NULL; + uip_recv_flags = 0; + + uip_tcp_input_pcb = pcb; + err = uip_tcpprocess(pcb); + uip_tcp_input_pcb = NULL; + + if(err!=UIP_ERR_ABRT) { + if(uip_recv_flags&UIP_TF_RESET) { + if(pcb->errf) pcb->errf(pcb->cb_arg,UIP_ERR_RST); + uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb); + memb_free(&uip_tcp_pcbs,pcb); + } else if(uip_recv_flags&UIP_TF_CLOSED) { + uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb); + memb_free(&uip_tcp_pcbs,pcb); + } else { + err = UIP_ERR_OK; + + if(pcb->acked>0) { + if(pcb->sent) err = pcb->sent(pcb->cb_arg,pcb,pcb->acked); + } + + if(uip_recv_data!=NULL) { + if(pcb->recv) err = pcb->recv(pcb->cb_arg,pcb,uip_recv_data,UIP_ERR_OK); + } + + if(err==UIP_ERR_OK) uip_tcpoutput(pcb); + } + } + if(uip_inseg.p!=NULL) uip_pbuf_free(uip_inseg.p); + } else { + if(!(UIP_TCPH_FLAGS(uip_tcphdr)&UIP_TCP_RST)) + uip_tcp_rst(uip_ackno,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src); + + uip_pbuf_free(p); + } +} + +s8_t uip_tcpoutput(struct uip_tcp_pcb *pcb) +{ + u32_t wnd; + struct uip_pbuf *p; + struct uip_tcp_hdr *tcphdr; + struct uip_tcpseg *seg,*useg; + + if(uip_tcp_input_pcb==pcb) return 0; + + wnd = UIP_MIN(pcb->snd_wnd,pcb->cwnd); + seg = pcb->unsent; + useg = pcb->unacked; + if(useg!=NULL) { + for(;useg->next!=NULL;useg=useg->next); + } + + if(pcb->flags&UIP_TF_ACK_NOW && + (seg==NULL || ntohl(seg->tcphdr->seqno)-pcb->lastack+seg->len>wnd)) { + //printf("uip_tcpout: ACK - seqno = %u, ackno = %u\n",pcb->snd_nxt,pcb->rcv_nxt); + p = uip_pbuf_alloc(UIP_PBUF_IP,UIP_TCP_HLEN,UIP_PBUF_RAM); + if(p==NULL) { + UIP_ERROR("uip_tcpoutput: (ACK) could not allocate pbuf."); + return UIP_ERR_BUF; + } + pcb->flags &= ~(UIP_TF_ACK_DELAY|UIP_TF_ACK_NOW); + + tcphdr = p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dst = htons(pcb->remote_port); + tcphdr->seqno = htonl(pcb->snd_nxt); + tcphdr->ackno = htonl(pcb->rcv_nxt); + UIP_TCPH_FLAGS_SET(tcphdr,UIP_TCP_ACK); + tcphdr->wnd = htons(pcb->rcv_wnd); + tcphdr->urgp = 0; + UIP_TCPH_HDRLEN_SET(tcphdr,5); + + tcphdr->chksum = 0; + tcphdr->chksum = uip_chksum_pseudo(p,&pcb->local_ip,&pcb->remote_ip,UIP_PROTO_TCP,p->tot_len); + + uip_ipoutput(p,&pcb->local_ip,&pcb->remote_ip,pcb->ttl,pcb->tos,UIP_PROTO_TCP); + uip_pbuf_free(p); + + return UIP_ERR_OK; + } + + while(seg!=NULL && ntohl(seg->tcphdr->seqno)-pcb->lastack+seg->len<=wnd) { + pcb->unsent = seg->next; + if(pcb->state!=UIP_SYN_SENT) { + UIP_TCPH_SET_FLAG(seg->tcphdr,UIP_TCP_ACK); + pcb->flags &= ~(UIP_TF_ACK_DELAY|UIP_TF_ACK_NOW); + } + + uip_tcpoutput_segments(seg,pcb); + + pcb->snd_nxt = ntohl(seg->tcphdr->seqno)+UIP_TCP_TCPLEN(seg); + if(UIP_TCP_SEQ_LT(pcb->snd_max,pcb->snd_nxt)) pcb->snd_max = pcb->snd_nxt; + + if(UIP_TCP_TCPLEN(seg)>0) { + seg->next = NULL; + if(pcb->unacked==NULL) { + pcb->unacked = seg; + useg = seg; + } else { + if(UIP_TCP_SEQ_LT(ntohl(seg->tcphdr->seqno),ntohl(useg->tcphdr->seqno))) { + seg->next = pcb->unacked; + pcb->unacked = seg; + } else { + useg->next = seg; + useg = useg->next; + } + } + } else + uip_tcpseg_free(seg); + + seg = pcb->unsent; + } + return UIP_ERR_OK; +} + +void uip_tcp_tmr() +{ + uip_tcp_fasttmr(); + + if(++uip_tcp_timer&1) uip_tcp_slowtmr(); +} + +void uip_tcp_init() +{ + memb_init(&uip_tcp_pcbs); + memb_init(&uip_listen_tcp_pcbs); + memb_init(&uip_tcp_segs); + + uip_tcp_listen_pcbs.listen_pcbs = NULL; + uip_tcp_active_pcbs = NULL; + uip_tcp_tw_pcbs = NULL; + + uip_tcp_ticks = 0; + uip_tcp_timer = 0; +} + +void uip_tcp_accept(struct uip_tcp_pcb *pcb,s8_t (*accept)(void *,struct uip_tcp_pcb *,s8_t)) +{ + ((struct uip_tcp_pcb_listen*)pcb)->accept = accept; +} + +void uip_tcp_err(struct uip_tcp_pcb *pcb,void (*errf)(void *,s8_t)) +{ + pcb->errf = errf; +} + +void uip_tcp_recv(struct uip_tcp_pcb *pcb,s8_t (*recv)(void *,struct uip_tcp_pcb *,struct uip_pbuf *,s8_t)) +{ + pcb->recv = recv; +} + +void uip_tcp_sent(struct uip_tcp_pcb *pcb,s8_t (*sent)(void *,struct uip_tcp_pcb *,u16_t)) +{ + pcb->sent = sent; +} + +void uip_tcp_poll(struct uip_tcp_pcb *pcb,s8_t (*poll)(void *,struct uip_tcp_pcb *),u8_t interval) +{ + pcb->poll = poll; + pcb->pollinterval = interval; +} + +void uip_tcp_arg(struct uip_tcp_pcb *pcb,void *arg) +{ + pcb->cb_arg = arg; +} + +struct uip_tcp_pcb* uip_tcp_pcballoc(u8_t prio) +{ + u32_t iss; + struct uip_tcp_pcb *pcb = NULL; + + pcb = memb_alloc(&uip_tcp_pcbs); + if(pcb!=NULL) { + UIP_MEMSET(pcb,0,sizeof(struct uip_tcp_pcb)); + pcb->prio = UIP_TCP_PRIO_NORMAL; + pcb->snd_buf = UIP_TCP_SND_BUF; + pcb->snd_queuelen = 0; + pcb->rcv_wnd = UIP_TCP_WND; + pcb->tos = 0; + pcb->ttl = UIP_TCP_TTL; + pcb->mss = UIP_TCP_MSS; + pcb->rto = 3000/UIP_TCP_SLOW_INTERVAL; + pcb->sa = 0; + pcb->sv = 3000/UIP_TCP_SLOW_INTERVAL; + pcb->rtime = 0; + pcb->cwnd = 1; + iss = uip_tcpiss_next(); + pcb->snd_wl2 = iss; + pcb->snd_nxt = iss; + pcb->snd_max = iss; + pcb->lastack = iss; + pcb->snd_lbb = iss; + pcb->tmr = uip_tcp_ticks; + pcb->polltmr = 0; + + pcb->recv = uip_tcp_nullrecv; + + pcb->keepalive = UIP_TCP_KEEPDEFAULT; + pcb->keepcnt = 0; + } + return pcb; +} + +void uip_tcp_pcbremove(struct uip_tcp_pcb **pcblist,struct uip_tcp_pcb *pcb) +{ + UIP_TCP_RMV(pcblist,pcb); + + uip_tcp_pcbpurge(pcb); + if(pcb->state!=UIP_TIME_WAIT && + pcb->state!=UIP_LISTEN && + pcb->flags&UIP_TF_ACK_DELAY) { + pcb->flags |= UIP_TF_ACK_NOW; + uip_tcpoutput(pcb); + } + pcb->state = UIP_CLOSED; +} + +void uip_tcp_pcbpurge(struct uip_tcp_pcb *pcb) +{ + if(pcb->state!=UIP_CLOSED && + pcb->state!=UIP_TIME_WAIT && + pcb->state!=UIP_LISTEN) { + uip_tcpsegs_free(pcb->ooseq); + uip_tcpsegs_free(pcb->unsent); + uip_tcpsegs_free(pcb->unacked); + pcb->unsent = pcb->unacked = pcb->ooseq = NULL; + } +} + +struct uip_tcp_pcb* uip_tcp_new() +{ + return uip_tcp_pcballoc(UIP_TCP_PRIO_NORMAL); +} + +s8_t uip_tcp_bind(struct uip_tcp_pcb *pcb,struct uip_ip_addr *ipaddr,u16_t port) +{ + struct uip_tcp_pcb *cpcb; + + if(port==0) port = uip_tcp_newport(); + + for(cpcb=(struct uip_tcp_pcb*)uip_tcp_listen_pcbs.pcbs;cpcb!=NULL;cpcb=cpcb->next) { + if(cpcb->local_port==port) { + if(ip_addr_isany(&cpcb->local_ip) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&cpcb->local_ip,ipaddr)) return UIP_ERR_USE; + } + } + + for(cpcb=uip_tcp_active_pcbs;cpcb!=NULL;cpcb=cpcb->next) { + if(cpcb->local_port==port) { + if(ip_addr_isany(&cpcb->local_ip) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&cpcb->local_ip,ipaddr)) return UIP_ERR_USE; + } + } + + if(!ip_addr_isany(ipaddr)) pcb->local_ip = *ipaddr; + pcb->local_port = port; + + return UIP_ERR_OK; +} + +struct uip_tcp_pcb* uip_tcp_listen(struct uip_tcp_pcb *pcb) +{ + struct uip_tcp_pcb_listen *lpcb; + + if(pcb->state==UIP_LISTEN) return pcb; + + lpcb = memb_alloc(&uip_listen_tcp_pcbs); + if(lpcb==NULL) return NULL; + + lpcb->cb_arg = pcb->cb_arg; + lpcb->local_port = pcb->local_port; + lpcb->state = UIP_LISTEN; + lpcb->so_options = pcb->so_options; + lpcb->so_options |= UIP_SOF_ACCEPTCONN; + lpcb->ttl = pcb->ttl; + lpcb->tos = pcb->tos; + ip_addr_set(&lpcb->local_ip,&pcb->local_ip); + + memb_free(&uip_tcp_pcbs,pcb); + + lpcb->accept = uip_tcp_nullaccept; + + UIP_TCP_REG(&uip_tcp_listen_pcbs.listen_pcbs,lpcb); + return (struct uip_tcp_pcb*)lpcb; +} + +void uip_tcp_recved(struct uip_tcp_pcb *pcb,u16_t len) +{ + if((u32_t)pcb->rcv_wnd+len>UIP_TCP_WND) pcb->rcv_wnd = UIP_TCP_WND; + else pcb->rcv_wnd += len; + + if(!(pcb->flags&UIP_TF_ACK_DELAY) && !(pcb->flags&UIP_TF_ACK_NOW)) { + uip_tcp_ack(pcb); + } else if(pcb->flags&UIP_TF_ACK_DELAY && pcb->rcv_wnd>=UIP_TCP_WND/2) { + uip_tcp_acknow(pcb); + } +} + +s8_t uip_tcp_close(struct uip_tcp_pcb *pcb) +{ + s8_t err; + + switch(pcb->state) { + case UIP_CLOSED: + err = UIP_ERR_OK; + memb_free(&uip_tcp_pcbs,pcb); + pcb = NULL; + break; + case UIP_LISTEN: + err = UIP_ERR_OK; + uip_tcp_pcbremove((struct uip_tcp_pcb**)&uip_tcp_listen_pcbs.pcbs,pcb); + memb_free(&uip_listen_tcp_pcbs,pcb); + pcb = NULL; + break; + case UIP_SYN_SENT: + err = UIP_ERR_OK; + uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb); + memb_free(&uip_tcp_pcbs,pcb); + pcb = NULL; + break; + case UIP_SYN_RCVD: + case UIP_ESTABLISHED: + err = uip_tcp_sendctrl(pcb,UIP_TCP_FIN); + if(err==UIP_ERR_OK) pcb->state = UIP_FIN_WAIT_1; + break; + case UIP_CLOSE_WAIT: + err = uip_tcp_sendctrl(pcb,UIP_TCP_FIN); + if(err==UIP_ERR_OK) pcb->state = UIP_LAST_ACK; + break; + default: + err = UIP_ERR_OK; + pcb = NULL; + break; + } + if(pcb!=NULL && err==UIP_ERR_OK) uip_tcpoutput(pcb); + + return err; +} + +void uip_tcp_rst(u32_t seqno,u32_t ackno,struct uip_ip_addr *lipaddr,struct uip_ip_addr *ripaddr,u16_t lport,u16_t rport) +{ + struct uip_pbuf *p; + struct uip_tcp_hdr *tcphdr; + + p = uip_pbuf_alloc(UIP_PBUF_IP,UIP_TCP_HLEN,UIP_PBUF_RAM); + if(p==NULL) { + UIP_LOG("uip_tcp_rst: could not allocate memory for pbuf.\n"); + return; + } + + tcphdr = p->payload; + tcphdr->src = htons(lport); + tcphdr->dst = htons(rport); + tcphdr->seqno = htonl(seqno); + tcphdr->ackno = htonl(ackno); + UIP_TCPH_FLAGS_SET(tcphdr,UIP_TCP_RST|UIP_TCP_ACK); + tcphdr->wnd = htons(UIP_TCP_WND); + tcphdr->urgp = 0; + UIP_TCPH_HDRLEN_SET(tcphdr,5); + + tcphdr->chksum = 0; + tcphdr->chksum = uip_chksum_pseudo(p,lipaddr,ripaddr,UIP_PROTO_TCP,p->tot_len); + + uip_ipoutput(p,lipaddr,ripaddr,UIP_TCP_TTL,0,UIP_PROTO_TCP); + uip_pbuf_free(p); +} + +void uip_tcp_abort(struct uip_tcp_pcb *pcb) +{ + u32_t seqno,ackno; + u16_t remote_port,local_port; + struct uip_ip_addr remote_ip,local_ip; + void (*errf)(void *arg,s8_t err); + void *errf_arg; + + if(pcb->state==UIP_TIME_WAIT) { + memb_free(&uip_tcp_pcbs,pcb); + } else { + seqno = pcb->snd_nxt; + ackno = pcb->rcv_nxt; + + ip_addr_set(&local_ip,&pcb->local_ip); + ip_addr_set(&remote_ip,&pcb->remote_ip); + local_port = pcb->local_port; + remote_port = pcb->remote_port; + + errf = pcb->errf; + errf_arg = pcb->cb_arg; + + uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb); + + if(pcb->unacked!=NULL) + uip_tcpsegs_free(pcb->unacked); + if(pcb->unsent!=NULL) + uip_tcpsegs_free(pcb->unsent); + if(pcb->ooseq!=NULL) + uip_tcpsegs_free(pcb->ooseq); + + memb_free(&uip_tcp_pcbs,pcb); + if(errf) errf(errf_arg,UIP_ERR_ABRT); + + uip_tcp_rst(seqno,ackno,&local_ip,&remote_ip,local_port,remote_port); + } +} + +void uip_tcp_keepalive(struct uip_tcp_pcb *pcb) +{ + struct uip_pbuf *p; + struct uip_tcp_hdr *tcphdr; + + p = uip_pbuf_alloc(UIP_PBUF_IP,UIP_TCP_HLEN,UIP_PBUF_RAM); + if(p==NULL) return; + + tcphdr = p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dst = htons(pcb->remote_port); + tcphdr->seqno = htonl(pcb->snd_nxt-1); + tcphdr->ackno = htonl(pcb->rcv_nxt); + tcphdr->wnd = htons(pcb->rcv_wnd); + tcphdr->urgp = 0; + UIP_TCPH_HDRLEN_SET(tcphdr,5); + + tcphdr->chksum = 0; + tcphdr->chksum = uip_chksum_pseudo(p,&pcb->local_ip,&pcb->remote_ip,UIP_PROTO_TCP,p->tot_len); + + uip_ipoutput(p,&pcb->local_ip,&pcb->remote_ip,pcb->ttl,0,UIP_PROTO_TCP); + uip_pbuf_free(p); +} + +void uip_tcp_rexmit(struct uip_tcp_pcb *pcb) +{ + struct uip_tcpseg *seg; + + if(pcb->unacked==NULL) return; + + seg = pcb->unacked->next; + pcb->unacked->next = pcb->unsent; + pcb->unsent = pcb->unacked; + pcb->unacked = seg; + + pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); + pcb->nrtx++; + pcb->rttest = 0; + + uip_tcpoutput(pcb); +} + +void uip_tcp_rexmit_rto(struct uip_tcp_pcb *pcb) +{ + struct uip_tcpseg *seg; + + if(pcb->unacked==NULL) return; + + for(seg=pcb->unacked;seg->next!=NULL;seg=seg->next); + + seg->next = pcb->unsent; + pcb->unsent = pcb->unacked; + pcb->unacked = NULL; + + pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); + pcb->nrtx++; + + uip_tcpoutput(pcb); +} + +void uip_tcp_fasttmr() +{ + struct uip_tcp_pcb *pcb; + + for(pcb=uip_tcp_active_pcbs;pcb!=NULL;pcb=pcb->next) { + if(pcb->flags&UIP_TF_ACK_DELAY) { + uip_tcp_acknow(pcb); + pcb->flags &= ~(UIP_TF_ACK_DELAY|UIP_TF_ACK_NOW); + } + } +} + +void uip_tcp_slowtmr() +{ + struct uip_tcp_pcb *prev,*pcb,*pcb2; + u32 eff_wnd; + u8_t pcb_remove; + s8_t err; + + err = UIP_ERR_OK; + + uip_tcp_ticks++; + + prev = NULL; + pcb = uip_tcp_active_pcbs; + while(pcb!=NULL) { + pcb_remove = 0; + + if(pcb->state==UIP_SYN_SENT && pcb->nrtx==UIP_MAXSYNRTX) pcb_remove++; + else if(pcb->nrtx==UIP_MAXRTX) pcb_remove++; + else { + pcb->rtime++; + if(pcb->unacked!=NULL && pcb->rtime>=pcb->rto) { + if(pcb->state==UIP_SYN_SENT) pcb->rto = ((pcb->sa>>3)+pcb->sv)<nrtx]; + + eff_wnd = UIP_MIN(pcb->cwnd,pcb->snd_wnd); + pcb->ssthresh = eff_wnd>>1; + + if(pcb->ssthreshmss) pcb->ssthresh = pcb->mss*2; + pcb->cwnd = pcb->mss; + + uip_tcp_rexmit_rto(pcb); + } + } + + if(pcb->state==UIP_FIN_WAIT_2) { + if((u32_t)(uip_tcp_ticks-pcb->tmr)>UIP_TCP_FIN_WAIT_TIMEOUT/UIP_TCP_SLOW_INTERVAL) pcb_remove++; + } + + if(pcb->so_options&UIP_SOF_KEEPALIVE && + (pcb->state==UIP_ESTABLISHED || pcb->state==UIP_CLOSE_WAIT)) { + if((u32_t)(uip_tcp_ticks-pcb->tmr)>(pcb->keepalive+UIP_TCP_MAXIDLE)/UIP_TCP_SLOW_INTERVAL) uip_tcp_abort(pcb); + else if((u32_t)(uip_tcp_ticks-pcb->tmr)>(pcb->keepalive+pcb->keepcnt*UIP_TCP_KEEPINTVL)/UIP_TCP_SLOW_INTERVAL) { + uip_tcp_keepalive(pcb); + pcb->keepcnt++; + } + } + + if(pcb->ooseq!=NULL && (u32_t)uip_tcp_ticks-pcb->tmr>=pcb->rto*UIP_TCP_OOSEQ_TIMEOUT) { + uip_tcpsegs_free(pcb->ooseq); + pcb->ooseq = NULL; + } + if(pcb->state==UIP_SYN_RCVD) { + if((u32_t)(uip_tcp_ticks-pcb->tmr)>UIP_TCP_SYN_RCVD_TIMEOUT/UIP_TCP_SLOW_INTERVAL) pcb_remove++; + } + + if(pcb_remove) { + uip_tcp_pcbpurge(pcb); + + if(prev!=NULL) prev->next = pcb->next; + else uip_tcp_active_pcbs = pcb->next; + + if(pcb->errf) pcb->errf(pcb->cb_arg,UIP_ERR_ABRT); + + pcb2 = pcb->next; + memb_free(&uip_tcp_pcbs,pcb); + pcb = pcb2; + } else { + pcb->polltmr++; + if(pcb->polltmr>=pcb->pollinterval) { + pcb->polltmr = 0; + if(pcb->poll) err = pcb->poll(pcb->cb_arg,pcb); + + if(err==UIP_ERR_OK) uip_tcpoutput(pcb); + } + + prev = pcb; + pcb = pcb->next; + } + } + + prev = NULL; + pcb = uip_tcp_tw_pcbs; + while(pcb!=NULL) { + pcb_remove = 0; + + if((u32_t)(uip_tcp_ticks-pcb->tmr)>2*UIP_TCP_MSL/UIP_TCP_SLOW_INTERVAL) pcb_remove++; + + if(pcb_remove) { + uip_tcp_pcbpurge(pcb); + + if(prev!=NULL) prev->next = pcb->next; + else uip_tcp_tw_pcbs = pcb->next; + + pcb2 = pcb->next; + memb_free(&uip_tcp_pcbs,pcb); + pcb = pcb2; + } else { + prev = pcb; + pcb = pcb->next; + } + } +} + +u32_t uip_tcpiss_next() +{ + static u32_t iss = 6510; + iss += uip_tcp_ticks; + return iss; +} + +struct uip_tcpseg* uip_tcpseg_copy(struct uip_tcpseg *seg) +{ + struct uip_tcpseg *cseg; + + cseg = memb_alloc(&uip_tcp_segs); + if(cseg==NULL) return NULL; + + UIP_MEMCPY(cseg,seg,sizeof(struct uip_tcpseg)); + uip_pbuf_ref(cseg->p); + + return cseg; +} + +u8_t uip_tcpsegs_free(struct uip_tcpseg *seg) +{ + u8_t cnt = 0; + struct uip_tcpseg *next; + + while(seg!=NULL) { + next = seg->next; + cnt += uip_tcpseg_free(seg); + seg = next; + } + + return cnt; +} + +u8_t uip_tcpseg_free(struct uip_tcpseg *seg) +{ + u8_t cnt = 0; + + if(seg!=NULL) { + if(seg->p!=NULL) { + cnt = uip_pbuf_free(seg->p); + } + memb_free(&uip_tcp_segs,seg); + } + return cnt; +} + +#ifndef TCP_LOCAL_PORT_RANGE_START +#define TCP_LOCAL_PORT_RANGE_START 4096 +#define TCP_LOCAL_PORT_RANGE_END 0x7fff +#endif + +static u16_t uip_tcp_newport() +{ + struct uip_tcp_pcb *pcb; + static u16_t port = TCP_LOCAL_PORT_RANGE_START; + +again: + if(++port>=TCP_LOCAL_PORT_RANGE_END) port = TCP_LOCAL_PORT_RANGE_START; + + for(pcb=uip_tcp_active_pcbs;pcb!=NULL;pcb=pcb->next) { + if(pcb->local_port==port) goto again; + } + for(pcb=uip_tcp_tw_pcbs;pcb!=NULL;pcb=pcb->next) { + if(pcb->local_port==port) goto again; + } + for(pcb=(struct uip_tcp_pcb*)uip_tcp_listen_pcbs.pcbs;pcb!=NULL;pcb=pcb->next) { + if(pcb->local_port==port) goto again; + } + return port; +} + +static void uip_tcp_parseopt(struct uip_tcp_pcb *pcb) +{ + u8_t c; + u8_t *opts,opt; + u16_t mss; + + opts = (u8_t*)uip_tcphdr+UIP_TCP_HLEN; + if(UIP_TCPH_HDRLEN(uip_tcphdr)>0x05) { + for(c=0;c<((UIP_TCPH_HDRLEN(uip_tcphdr)-5)<<2);) { + opt = opts[c]; + if(opt==0x00) break; + else if(opt==0x01) c++; + else if(opt==0x02 && opts[c+1]==0x04) { + mss = (opts[c+2]<<8|opts[c+3]); + pcb->mss = mss>UIP_TCP_MSS?UIP_TCP_MSS:mss; + break; + } else { + if(opts[c+1]==0) break; + c += opts[c+1]; + } + } + } +} + +static void uip_tcpoutput_segments(struct uip_tcpseg *seg,struct uip_tcp_pcb *pcb) +{ + u16_t len; + struct uip_netif *netif; + + seg->tcphdr->ackno = htonl(pcb->rcv_nxt); + if(pcb->rcv_wndmss) seg->tcphdr->wnd = 0; + else seg->tcphdr->wnd = htons(pcb->rcv_wnd); + + if(ip_addr_isany(&pcb->local_ip)) { + netif = uip_iproute(&pcb->remote_ip); + if(netif==NULL) { + UIP_ERROR("uip_tcpoutput_segments: no route found."); + return; + } + ip_addr_set(&pcb->local_ip,&netif->ip_addr); + } + + pcb->rtime = 0; + if(pcb->rttest==0) { + pcb->rttest = uip_tcp_ticks; + pcb->rtseq = ntohl(seg->tcphdr->seqno); + } + + len = (u16_t)((u8_t*)seg->tcphdr-(u8_t*)seg->p->payload); + seg->p->len -= len; + seg->p->tot_len -= len; + seg->p->payload = seg->tcphdr; + + seg->tcphdr->chksum = 0; + seg->tcphdr->chksum = uip_chksum_pseudo(seg->p,&pcb->local_ip,&pcb->remote_ip,UIP_PROTO_TCP,seg->p->tot_len); + + uip_ipoutput(seg->p,&pcb->local_ip,&pcb->remote_ip,pcb->ttl,pcb->tos,UIP_PROTO_TCP); +} + +static s8_t uip_tcpinput_listen(struct uip_tcp_pcb_listen *pcb) +{ + u32_t optdata; + struct uip_tcp_pcb *npcb; + + if(uip_flags&UIP_TCP_ACK) { + UIP_LOG("uip_tcp_listen_input: ACK in LISTEN, sending reset.\n"); + uip_tcp_rst(uip_ackno+1,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src); + } else if(uip_flags&UIP_TCP_SYN) { + npcb = uip_tcp_pcballoc(pcb->prio); + if(!npcb) return UIP_ERR_MEM; + + ip_addr_set(&npcb->local_ip,&uip_iphdr->dst); + npcb->local_port = pcb->local_port; + ip_addr_set(&npcb->remote_ip,&uip_iphdr->src); + npcb->remote_port = uip_tcphdr->src; + npcb->state = UIP_SYN_RCVD; + npcb->rcv_nxt = uip_seqno+1; + npcb->snd_wnd = uip_tcphdr->wnd; + npcb->ssthresh = npcb->snd_wnd; + npcb->snd_wl1 = uip_seqno-1; + npcb->cb_arg = pcb->cb_arg; + npcb->accept = pcb->accept; + + npcb->so_options = pcb->so_options&(UIP_SOF_DEBUG|UIP_SOF_DONTROUTE|UIP_SOF_KEEPALIVE|UIP_SOF_OOBINLINE|UIP_SOF_LINGER); + + UIP_TCP_REG(&uip_tcp_active_pcbs,npcb); + + uip_tcp_parseopt(npcb); + + optdata = htonl((((u32_t)2<<24)|((u32_t)4<<16)|(((u32_t)npcb->mss/256)<<8)|((u32_t)npcb->mss&255))); + + uip_tcpenqueue(npcb,NULL,0,UIP_TCP_SYN|UIP_TCP_ACK,0,(u8_t*)&optdata,4); + return uip_tcpoutput(npcb); + } + return UIP_ERR_OK; +} + +static s8_t uip_tcpinput_timewait(struct uip_tcp_pcb *pcb) +{ + if(UIP_TCP_SEQ_GT(uip_seqno+uip_tcplen,pcb->rcv_nxt)) pcb->rcv_nxt = uip_seqno+uip_tcplen; + if(uip_tcplen>0) { + uip_tcp_acknow(pcb); + } + + return uip_tcpoutput(pcb); +} + +static s8_t uip_tcpprocess(struct uip_tcp_pcb *pcb) +{ + struct uip_tcpseg *rseg; + u8_t acceptable = 0; + s8_t err; + + err = 0; + if(uip_flags&UIP_TCP_RST) { + if(pcb->state==UIP_SYN_SENT) { + if(uip_ackno==pcb->snd_nxt) acceptable = 1; + } else { + if(UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd)) acceptable = 1; + } + if(acceptable) { + uip_recv_flags = UIP_TF_RESET; + pcb->flags &= ~UIP_TF_ACK_DELAY; + return UIP_ERR_RST; + } else + return UIP_ERR_OK; + } + + pcb->tmr = uip_tcp_ticks; + pcb->keepcnt = 0; + + switch(pcb->state) { + case UIP_SYN_SENT: + if(uip_flags&UIP_TCP_ACK && uip_flags&UIP_TCP_SYN && + uip_ackno==ntohl(pcb->unacked->tcphdr->seqno)+1) { + pcb->snd_buf++; + pcb->rcv_nxt = uip_seqno+1; + pcb->lastack = uip_ackno; + pcb->snd_wnd = uip_tcphdr->wnd; + pcb->snd_wl1 = uip_seqno-1; + pcb->state = UIP_ESTABLISHED; + pcb->cwnd = pcb->mss; + pcb->snd_queuelen--; + + rseg = pcb->unacked; + pcb->unacked = rseg->next; + uip_tcpseg_free(rseg); + + uip_tcp_parseopt(pcb); + + if(pcb->connected!=NULL) err = pcb->connected(pcb->cb_arg,pcb,UIP_ERR_OK); + + uip_tcp_ack(pcb); + } else if(uip_flags&UIP_TCP_ACK) { + uip_tcp_rst(uip_ackno,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src); + } + break; + case UIP_SYN_RCVD: + if(uip_flags&UIP_TCP_ACK && !(uip_flags&UIP_TCP_RST)) { + if(UIP_TCP_SEQ_BETWEEN(uip_ackno,pcb->lastack+1,pcb->snd_nxt)) { + pcb->state = UIP_ESTABLISHED; + + if(pcb->accept!=NULL) err = pcb->accept(pcb->cb_arg,pcb,UIP_ERR_OK); + if(err!=UIP_ERR_OK) { + uip_tcp_abort(pcb); + return UIP_ERR_ABRT; + } + uip_tcpreceive(pcb); + pcb->cwnd = pcb->mss; + } else { + uip_tcp_rst(uip_ackno,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src); + } + } + break; + case UIP_CLOSE_WAIT: + case UIP_ESTABLISHED: + uip_tcpreceive(pcb); + if(uip_flags&UIP_TCP_FIN) { + uip_tcp_acknow(pcb); + pcb->state = UIP_CLOSE_WAIT; + } + break; + case UIP_FIN_WAIT_1: + uip_tcpreceive(pcb); + if(uip_flags&UIP_TCP_FIN) { + if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) { + uip_tcp_acknow(pcb); + uip_tcp_pcbpurge(pcb); + UIP_TCP_RMV(&uip_tcp_active_pcbs,pcb); + pcb->state = UIP_TIME_WAIT; + UIP_TCP_REG(&uip_tcp_tw_pcbs,pcb); + } else { + uip_tcp_acknow(pcb); + pcb->state = UIP_CLOSING; + } + } else if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) { + pcb->state = UIP_FIN_WAIT_2; + } + break; + case UIP_FIN_WAIT_2: + uip_tcpreceive(pcb); + if(uip_flags&UIP_TCP_FIN) { + uip_tcp_acknow(pcb); + uip_tcp_pcbpurge(pcb); + UIP_TCP_RMV(&uip_tcp_active_pcbs,pcb); + pcb->state = UIP_TIME_WAIT; + UIP_TCP_REG(&uip_tcp_tw_pcbs,pcb); + } + break; + case UIP_CLOSING: + uip_tcpreceive(pcb); + if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) { + uip_tcp_acknow(pcb); + uip_tcp_pcbpurge(pcb); + UIP_TCP_RMV(&uip_tcp_active_pcbs,pcb); + pcb->state = UIP_TIME_WAIT; + UIP_TCP_REG(&uip_tcp_tw_pcbs,pcb); + } + break; + case UIP_LAST_ACK: + uip_tcpreceive(pcb); + if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) { + pcb->state = UIP_CLOSED; + uip_recv_flags = UIP_TF_CLOSED; + } + break; + default: + break; + + } + return UIP_ERR_OK; +} + +static void uip_tcpreceive(struct uip_tcp_pcb *pcb) +{ + struct uip_tcpseg *next,*prev; + struct uip_tcpseg *cseg; + struct uip_pbuf *p; + s32_t off,m; + u32_t right_wnd_edge; + u16_t new_tot_len; + + if(uip_flags&UIP_TCP_ACK) { + right_wnd_edge = pcb->snd_wnd+pcb->snd_wl1; + if(UIP_TCP_SEQ_LT(pcb->snd_wl1,uip_seqno) || + (pcb->snd_wl1==uip_seqno && UIP_TCP_SEQ_LT(pcb->snd_wl2,uip_ackno)) || + (pcb->snd_wl2==uip_ackno && uip_tcphdr->wnd>pcb->snd_wnd)) { + pcb->snd_wnd = uip_tcphdr->wnd; + pcb->snd_wl1 = uip_seqno; + pcb->snd_wl2 = uip_ackno; + } + + if(pcb->lastack==uip_ackno) { + pcb->acked = 0; + if(pcb->snd_wl1+pcb->snd_wnd==right_wnd_edge) { + pcb->dupacks++; + if(pcb->dupacks>=3 && pcb->unacked!=NULL) { + if(!(uip_flags&UIP_TF_INFR)) { + UIP_LOG("uip_tcpreceive: dupacks, fast retransmit."); + uip_tcp_rexmit(pcb) ; + + if(pcb->cwnd>pcb->snd_wnd) pcb->ssthresh = pcb->snd_wnd/2; + else pcb->ssthresh = pcb->cwnd/2; + + pcb->cwnd = pcb->ssthresh+3*pcb->mss; + pcb->flags |= UIP_TF_INFR; + } else { + if((u16_t)(pcb->cwnd+pcb->mss)>pcb->cwnd) pcb->cwnd += pcb->mss; + } + } + } + } else if(UIP_TCP_SEQ_BETWEEN(uip_ackno,pcb->lastack+1,pcb->snd_max)) { + if(pcb->flags&UIP_TF_INFR) { + pcb->flags &= ~UIP_TF_INFR; + pcb->cwnd = pcb->ssthresh; + } + + pcb->nrtx = 0; + pcb->rto = (pcb->sa>>3)+pcb->sv; + pcb->acked = uip_ackno-pcb->lastack; + pcb->snd_buf += pcb->acked; + pcb->dupacks = 0; + pcb->lastack = uip_ackno; + + if(pcb->state>=UIP_ESTABLISHED) { + if(pcb->cwndssthresh) { + if((u16_t)(pcb->cwnd+pcb->mss)>pcb->cwnd) pcb->cwnd += pcb->mss; + + } else { + u16_t new_cwnd = (pcb->cwnd+pcb->mss*pcb->mss/pcb->cwnd); + if(new_cwnd>pcb->cwnd) pcb->cwnd = new_cwnd; + } + } + + while(pcb->unacked!=NULL && + UIP_TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno)+UIP_TCP_TCPLEN(pcb->unacked),uip_ackno)) { + + next = pcb->unacked; + pcb->unacked = pcb->unacked->next; + pcb->snd_queuelen -= uip_pbuf_clen(next->p); + + uip_tcpseg_free(next); + } + pcb->polltmr = 0; + } + + while(pcb->unsent!=NULL && + UIP_TCP_SEQ_BETWEEN(uip_ackno,ntohl(pcb->unsent->tcphdr->seqno)+UIP_TCP_TCPLEN(pcb->unsent),pcb->snd_max)) { + + next = pcb->unsent; + pcb->unsent = pcb->unsent->next; + pcb->snd_queuelen -= uip_pbuf_clen(next->p); + + uip_tcpseg_free(next); + + if(pcb->unsent!=NULL) pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno); + } + + if(pcb->rttest && UIP_TCP_SEQ_LT(pcb->rtseq,uip_ackno)) { + m = uip_tcp_ticks - pcb->rttest; + m = m - (pcb->sa>>3); + pcb->sa += m; + + if(m<0) m -= m; + + m = m - (pcb->sv>>2); + pcb->sv += m; + pcb->rto = (pcb->sa>>3)+pcb->sv; + + pcb->rttest = 0; + } + } + + if(uip_tcplen>0) { + if(UIP_TCP_SEQ_BETWEEN(pcb->rcv_nxt,uip_seqno+1,uip_seqno+uip_tcplen-1)) { + off = pcb->rcv_nxt - uip_seqno; + p = uip_inseg.p; + if(uip_inseg.p->lentot_len - off; + while(p->lenlen; + p->tot_len = new_tot_len; + p->len = 0; + p = p->next; + } + uip_pbuf_header(p,-off); + } else { + uip_pbuf_header(uip_inseg.p,-off); + } + + uip_inseg.dataptr = p->payload; + uip_inseg.len -= pcb->rcv_nxt - uip_seqno; + uip_inseg.tcphdr->seqno = uip_seqno = pcb->rcv_nxt; + } else { + if(UIP_TCP_SEQ_LT(uip_seqno,pcb->rcv_nxt)) { + UIP_LOG("uip_tcpreceive: duplicate seqno."); + uip_tcp_acknow(pcb); + } + } + + if(UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd-1)) { + //printf("uip_tcpreceive: seqno = %u, rcv_nxt = %u, wnd = %u\n",uip_seqno,pcb->rcv_nxt,(pcb->rcv_nxt+pcb->rcv_wnd-1)); + if(pcb->rcv_nxt==uip_seqno) { + if(pcb->ooseq!=NULL && UIP_TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno,uip_seqno+uip_inseg.len)) { + uip_inseg.len = pcb->ooseq->tcphdr->seqno - uip_seqno; + uip_pbuf_realloc(uip_inseg.p,uip_inseg.len); + } + + uip_tcplen = UIP_TCP_TCPLEN(&uip_inseg); + if(pcb->state!=UIP_CLOSE_WAIT) pcb->rcv_nxt += uip_tcplen; + //printf("uip_tcpreceive: uip_tcplen = %u, rcv_nxt = %u\n",uip_tcplen,pcb->rcv_nxt); + + if(pcb->rcv_wndrcv_wnd = 0; + else pcb->rcv_wnd -= uip_tcplen; + + if(uip_inseg.p->tot_len>0) { + uip_recv_data = uip_inseg.p; + uip_inseg.p = NULL; + } + + if(UIP_TCPH_FLAGS(uip_inseg.tcphdr)&UIP_TCP_FIN) { + UIP_LOG("uip_tcpreceive: received FIN.\n"); + uip_recv_flags = UIP_TF_GOT_FIN; + } + + while(pcb->ooseq!=NULL && pcb->ooseq->tcphdr->seqno==pcb->rcv_nxt) { + cseg = pcb->ooseq; + uip_seqno = pcb->ooseq->tcphdr->seqno; + + pcb->rcv_nxt += UIP_TCP_TCPLEN(cseg); + if(pcb->rcv_wndrcv_wnd = 0; + else pcb->rcv_wnd -= UIP_TCP_TCPLEN(cseg); + + if(cseg->p->tot_len>0) { + if(uip_recv_data) uip_pbuf_cat(uip_recv_data,cseg->p); + else uip_recv_data = cseg->p; + + cseg->p = NULL; + } + + if(UIP_TCPH_FLAGS(cseg->tcphdr)&UIP_TCP_FIN) { + UIP_LOG("uip_tcpreceive: dequeued FIN.\n"); + uip_recv_flags = UIP_TF_GOT_FIN; + } + + pcb->ooseq = cseg->next; + uip_tcpseg_free(cseg); + } + //printf("uip_tcpreceive: pcb->flags = %02x\n",pcb->flags); + uip_tcp_ack(pcb); + //printf("uip_tcpreceive: pcb->flags = %02x\n",pcb->flags); + } else { + UIP_LOG("uip_tcpreceive: packet out-of-sequence."); + uip_tcp_acknow(pcb); + if(pcb->ooseq==NULL) + uip_tcpseg_copy(&uip_inseg); + else { + prev = NULL; + for(next=pcb->ooseq;next!=NULL;next=next->next) { + if(uip_seqno==next->tcphdr->seqno) { + if(uip_inseg.len>next->len) { + cseg = uip_tcpseg_copy(&uip_inseg); + if(cseg!=NULL) { + cseg->next = next->next; + if(prev!=NULL) prev->next = cseg; + else pcb->ooseq = cseg; + } + break; + } else + break; + } else { + if(prev==NULL) { + if(UIP_TCP_SEQ_LT(uip_seqno,next->tcphdr->seqno)) { + if(UIP_TCP_SEQ_GT(uip_seqno+uip_inseg.len,next->tcphdr->seqno)) { + uip_inseg.len = next->tcphdr->seqno - uip_seqno; + uip_pbuf_realloc(uip_inseg.p,uip_inseg.len); + } + + cseg = uip_tcpseg_copy(&uip_inseg); + if(cseg!=NULL) { + cseg->next = next; + pcb->ooseq = cseg; + } + break; + } + } else if(UIP_TCP_SEQ_BETWEEN(uip_seqno,prev->tcphdr->seqno+1,next->tcphdr->seqno-1)) { + if(UIP_TCP_SEQ_GT(uip_seqno+uip_inseg.len,next->tcphdr->seqno)) { + uip_inseg.len = next->tcphdr->seqno - uip_seqno; + uip_pbuf_realloc(uip_inseg.p,uip_inseg.len); + } + + cseg = uip_tcpseg_copy(&uip_inseg); + if(cseg!=NULL) { + cseg->next = next; + prev->next = cseg; + if(UIP_TCP_SEQ_GT(prev->tcphdr->seqno+prev->len,uip_seqno)) { + prev->len = uip_seqno - prev->tcphdr->seqno; + uip_pbuf_realloc(prev->p,prev->len); + } + } + break; + } + + if(next->next==NULL && UIP_TCP_SEQ_GT(uip_seqno,next->tcphdr->seqno)) { + next->next = uip_tcpseg_copy(&uip_inseg); + if(next->next!=NULL) { + if(UIP_TCP_SEQ_GT(next->tcphdr->seqno+next->len,uip_seqno)) { + next->len = uip_seqno - next->tcphdr->seqno; + uip_pbuf_realloc(next->p,next->len); + } + } + } + } + prev = next; + } + } + } + } else { + if(!UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd-1)) { + uip_tcp_acknow(pcb); + } + } + } else { + if(!UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd-1)) { + uip_tcp_acknow(pcb); + } + } +} + +static s8_t uip_tcp_nullaccept(void *arg,struct uip_tcp_pcb *pcb,s8_t err) +{ + return UIP_ERR_ABRT; +} + +static s8_t uip_tcp_nullrecv(void *arg,struct uip_tcp_pcb *pcb,struct uip_pbuf *p,s8_t err) +{ + if(p!=NULL) uip_pbuf_free(p); + else if(err==UIP_ERR_OK) return uip_tcp_close(pcb); + + return UIP_ERR_OK; +} diff --git a/wii/libogc/libdb/uIP/uip_tcp.h b/wii/libogc/libdb/uIP/uip_tcp.h new file mode 100644 index 0000000000..9c058c9e1e --- /dev/null +++ b/wii/libogc/libdb/uIP/uip_tcp.h @@ -0,0 +1,256 @@ +#ifndef __UIP_TCP_H__ +#define __UIP_TCP_H__ + +#include "uip.h" +#include "uip_ip.h" +#include "uip_pbuf.h" + +#define UIP_TCP_PRIO_MIN 1 +#define UIP_TCP_PRIO_NORMAL 64 +#define UIP_TCP_PRIO_MAX 127 + +/* Keepalive values */ +#define UIP_TCP_KEEPDEFAULT 7200000 /* KEEPALIVE timer in miliseconds */ +#define UIP_TCP_KEEPINTVL 75000 /* Time between KEEPALIVE probes in miliseconds */ +#define UIP_TCP_KEEPCNT 9 /* Counter for KEEPALIVE probes */ +#define UIP_TCP_MAXIDLE (UIP_TCP_KEEPCNT*UIP_TCP_KEEPINTVL) /* Maximum KEEPALIVE probe time */ + +#define UIP_TCP_TMR_INTERVAL 250 +#define UIP_TCP_SLOW_INTERVAL (2*UIP_TCP_TMR_INTERVAL) + +#define UIP_TCP_OOSEQ_TIMEOUT 6 /* x RTO */ + +#define UIP_TCP_MSL 60000 /* The maximum segment lifetime in microseconds */ + +#define UIP_TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) +#define UIP_TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) +#define UIP_TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) +#define UIP_TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) + +#define UIP_TCP_SEQ_BETWEEN(a,b,c) (UIP_TCP_SEQ_GEQ(a,b) && UIP_TCP_SEQ_LEQ(a,c)) +#define UIP_TCP_FIN 0x01U +#define UIP_TCP_SYN 0x02U +#define UIP_TCP_RST 0x04U +#define UIP_TCP_PSH 0x08U +#define UIP_TCP_ACK 0x10U +#define UIP_TCP_URG 0x20U +#define UIP_TCP_ECE 0x40U +#define UIP_TCP_CWR 0x80U + +#define UIP_TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define UIP_TCP_HLEN 20 + +#define UIP_TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define UIP_TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define UIP_TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define UIP_TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define UIP_TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & UIP_TCP_FLAGS) + +#define UIP_TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8)|UIP_TCPH_FLAGS(phdr)) +#define UIP_TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len)<<12)|UIP_TCPH_FLAGS(phdr)) +#define UIP_TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags)&~UIP_TCP_FLAGS)|(flags)) +#define UIP_TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags)|(flags)) +#define UIP_TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags)|(UIP_TCPH_FLAGS(phdr)&~(flags)) ) + +#define UIP_TCP_TCPLEN(seg) ((seg)->len+((UIP_TCPH_FLAGS((seg)->tcphdr)&UIP_TCP_FIN || UIP_TCPH_FLAGS((seg)->tcphdr)&UIP_TCP_SYN)?1:0)) + +#define UIP_TCP_REG(pcbs,npcb) \ + do { \ + npcb->next = *pcbs; \ + *(pcbs) = npcb; \ + tcp_tmr_needed(); \ + } while(0) + +#define UIP_TCP_RMV(pcbs,npcb) \ + do { \ + if(*(pcbs)==npcb) { \ + *(pcbs) = (*pcbs)->next; \ + } else { \ + for(uip_tcp_tmp_pcb=*pcbs;uip_tcp_tmp_pcb!=NULL;uip_tcp_tmp_pcb=uip_tcp_tmp_pcb->next) { \ + if(uip_tcp_tmp_pcb->next!=NULL && uip_tcp_tmp_pcb->next==npcb) { \ + uip_tcp_tmp_pcb->next = npcb->next; \ + break; \ + } \ + } \ + } \ + } while(0) + +#define uip_tcp_sndbuf(pcb) (pcb)->snd_buf + +#define uip_tcp_acknow(pcb) \ + (pcb)->flags |= UIP_TF_ACK_NOW; \ + uip_tcpoutput((pcb)) + +#define uip_tcp_ack(pcb) \ + if((pcb)->flags&UIP_TF_ACK_DELAY) { \ + (pcb)->flags &= ~UIP_TF_ACK_DELAY; \ + (pcb)->flags |= UIP_TF_ACK_NOW; \ + uip_tcpoutput((pcb)); \ + } else { \ + (pcb)->flags |= UIP_TF_ACK_DELAY; \ + } + +/* The TCP Header */ +PACK_STRUCT_BEGIN +struct uip_tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dst); + PACK_STRUCT_FIELD(u32_t seqno); + PACK_STRUCT_FIELD(u32_t ackno); + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); + PACK_STRUCT_FIELD(u16_t wnd); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +enum uip_tcp_state { + UIP_CLOSED = 0, + UIP_LISTEN = 1, + UIP_SYN_SENT = 2, + UIP_SYN_RCVD = 3, + UIP_ESTABLISHED = 4, + UIP_FIN_WAIT_1 = 5, + UIP_FIN_WAIT_2 = 6, + UIP_CLOSE_WAIT = 7, + UIP_CLOSING = 8, + UIP_LAST_ACK = 9, + UIP_TIME_WAIT = 10 +}; + +struct uip_tcpseg { + struct uip_tcpseg *next; + struct uip_pbuf *p; + u8_t *dataptr; + u16_t len; + struct uip_tcp_hdr *tcphdr; +}; + +struct uip_tcp_pcb { + UIP_IP_PCB; + + struct uip_tcp_pcb *next; + enum uip_tcp_state state; + + u8_t prio; + void *cb_arg; + + u16_t local_port; + u16_t remote_port; + + u8_t flags; +#define UIP_TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */ +#define UIP_TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */ +#define UIP_TF_INFR (u8_t)0x04U /* In fast recovery. */ +#define UIP_TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define UIP_TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ +#define UIP_TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ +#define UIP_TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */ + + u32_t rcv_nxt; + u16_t rcv_wnd; + + u32_t tmr; + u8_t polltmr,pollinterval; + + u16_t rtime; + u16_t mss; + + u32_t rttest; + u32_t rtseq; + s16_t sa,sv; + + u16_t rto; + u8_t nrtx; + + u32_t lastack; + u8_t dupacks; + + u16_t cwnd; + u16_t ssthresh; + + u32_t snd_nxt,snd_max,snd_wnd,snd_wl1,snd_wl2,snd_lbb; + + u16_t acked; + u16_t snd_buf; + u8_t snd_queuelen; + + struct uip_tcpseg *unsent; + struct uip_tcpseg *unacked; + struct uip_tcpseg *ooseq; + + s8_t (*accept)(void *arg,struct uip_tcp_pcb *newpcb,s8_t err); + s8_t (*connected)(void *arg,struct uip_tcp_pcb *newpcb,s8_t err); + s8_t (*poll)(void *arg,struct uip_tcp_pcb *pcb); + + s8_t (*sent)(void *arg,struct uip_tcp_pcb *pcb,u16_t space); + s8_t (*recv)(void *arg,struct uip_tcp_pcb *pcb,struct uip_pbuf *p,s8_t err); + + void (*errf)(void *arg,s8_t err); + + u32_t keepalive; + u8_t keepcnt; +}; + +struct uip_tcp_pcb_listen { + UIP_IP_PCB; + + struct uip_tcp_pcb_listen *next; + enum uip_tcp_state state; + + u8_t prio; + void *cb_arg; + + u16_t local_port; + + s8_t (*accept)(void *arg,struct uip_tcp_pcb *newpcb,s8_t err); +}; + +union uip_tcp_listen_pcbs_t { + struct uip_tcp_pcb_listen *listen_pcbs; + struct uip_tcp_pcb *pcbs; +}; + +extern struct uip_tcp_pcb *uip_tcp_tmp_pcb; +extern struct uip_tcp_pcb *uip_tcp_active_pcbs; +extern struct uip_tcp_pcb *uip_tcp_tw_pcbs; +extern union uip_tcp_listen_pcbs_t uip_tcp_listen_pcbs; + +void uip_tcp_tmr(); +void uip_tcp_slowtmr(); +void uip_tcp_fasttmr(); +void uip_tcp_init(); +void uip_tcp_rst(u32_t seqno,u32_t ackno,struct uip_ip_addr *lipaddr,struct uip_ip_addr *ripaddr,u16_t lport,u16_t rport); +void uip_tcp_abort(struct uip_tcp_pcb *pcb); +void uip_tcp_pcbremove(struct uip_tcp_pcb **pcblist,struct uip_tcp_pcb *pcb); +void uip_tcp_pcbpurge(struct uip_tcp_pcb *pcb); +void uip_tcp_rexmit(struct uip_tcp_pcb *pcb); +void uip_tcp_rexmit_rto(struct uip_tcp_pcb *pcb); +void uip_tcp_accept(struct uip_tcp_pcb *pcb,s8_t (*accept)(void *,struct uip_tcp_pcb *,s8_t)); +void uip_tcp_recved(struct uip_tcp_pcb *pcb,u16_t len); +void uip_tcp_err(struct uip_tcp_pcb *pcb,void (*errf)(void *,s8_t)); +void uip_tcp_keepalive(struct uip_tcp_pcb *pcb); +void uip_tcp_arg(struct uip_tcp_pcb *pcb,void *arg); +void uip_tcp_recv(struct uip_tcp_pcb *pcb,s8_t (*recv)(void *,struct uip_tcp_pcb *,struct uip_pbuf *,s8_t)); +void uip_tcp_sent(struct uip_tcp_pcb *pcb,s8_t (*sent)(void *,struct uip_tcp_pcb *,u16_t)); +void uip_tcp_poll(struct uip_tcp_pcb *pcb,s8_t (*poll)(void *,struct uip_tcp_pcb *),u8_t interval); +s8_t uip_tcp_close(struct uip_tcp_pcb *pcb); +s8_t uip_tcp_bind(struct uip_tcp_pcb *pcb,struct uip_ip_addr *ipaddr,u16_t port); +s8_t uip_tcp_write(struct uip_tcp_pcb *pcb,const void *arg,u16_t len,u8_t copy); +struct uip_tcp_pcb* uip_tcp_listen(struct uip_tcp_pcb *pcb); +struct uip_tcp_pcb* uip_tcp_new(); +struct uip_tcp_pcb* uip_tcp_pcballoc(u8_t prio); + +s8_t uip_tcp_sendctrl(struct uip_tcp_pcb *pcb,u8_t flags); +s8_t uip_tcpoutput(struct uip_tcp_pcb *pcb); +s8_t uip_tcpenqueue(struct uip_tcp_pcb *pcb,void *arg,u16_t len,u8_t flags,u8_t copy,u8_t *optdata,u8_t optlen); +u8_t uip_tcpseg_free(struct uip_tcpseg *seg); +u8_t uip_tcpsegs_free(struct uip_tcpseg *seg); +u32_t uip_tcpiss_next(); +void uip_tcpinput(struct uip_pbuf *p,struct uip_netif *inp); +struct uip_tcpseg* uip_tcpseg_copy(struct uip_tcpseg *seg); + +#endif diff --git a/wii/libogc/libdb/uIP/uipopt.h b/wii/libogc/libdb/uIP/uipopt.h new file mode 100644 index 0000000000..e21f967639 --- /dev/null +++ b/wii/libogc/libdb/uIP/uipopt.h @@ -0,0 +1,500 @@ +/** + * \defgroup uipopt Configuration options for uIP + * @{ + * + * uIP is configured using the per-project configuration file + * "uipopt.h". This file contains all compile-time options for uIP and + * should be tweaked to match each specific project. The uIP + * distribution contains a documented example "uipopt.h" that can be + * copied and modified for each project. + */ + +/** + * \file + * Configuration options for uIP. + * \author Adam Dunkels + * + * This file is used for tweaking various configuration options for + * uIP. You should make a copy of this file into one of your project's + * directories instead of editing this example "uipopt.h" file that + * comes with the uIP distribution. + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + +#ifndef __UIPOPT_H__ +#define __UIPOPT_H__ + +#include +#include +#include + +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipopttypedef uIP type definitions + * @{ + */ + +/** + * The 8-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * char" works for most compilers. + */ +typedef u8 u8_t; + +/** + * The 8-bit signed data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * char" works for most compilers. + */ +typedef s8 s8_t; + +/** + * The 16-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef u16 u16_t; + +/** + * The 16-bit signed data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef s16 s16_t; + +/** + * The 32-bit signed data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef s32 s32_t; + +/** + * The 32-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef u32 u32_t; + +/** + * The statistics data type. + * + * This datatype determines how high the statistics counters are able + * to count. + */ +typedef u16 uip_stats_t; + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptip IP configuration options + * @{ + * + */ +/** + * The IP TTL (time to live) of IP packets sent by uIP. + * + * This should normally not be changed. + */ +#define UIP_TCP_TTL 255 + +#define UIP_TCP 1 + +/** + * Turn on support for IP packet reassembly. + * + * uIP supports reassembly of fragmented IP packets. This features + * requires an additonal amount of RAM to hold the reassembly buffer + * and the reassembly code size is approximately 700 bytes. The + * reassembly buffer is of the same size as the uip_buf buffer + * (configured by UIP_BUFSIZE). + * + * \note IP packet reassembly is not heavily tested. + * + * \hideinitializer + */ +#define UIP_IP_REASSEMBLY 0 + +#define UIP_IP_FRAG 0 + +/** + * The maximum time an IP fragment should wait in the reassembly + * buffer before it is dropped. + * + */ +#define UIP_REASS_MAXAGE 30 + +/** @} */ + +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptudp UDP configuration options + * @{ + * + * \note The UDP support in uIP is still not entirely complete; there + * is no support for sending or receiving broadcast or multicast + * packets, but it works well enough to support a number of vital + * applications such as DNS queries, though + */ + +/** + * Toggles wether UDP support should be compiled in or not. + * + * \hideinitializer + */ +#define UIP_UDP 0 + +/** + * Toggles if UDP checksums should be used or not. + * + * \note Support for UDP checksums is currently not included in uIP, + * so this option has no function. + * + * \hideinitializer + */ +#define UIP_UDP_CHECKSUMS 0 + +/** + * The maximum amount of concurrent UDP connections. + * + * \hideinitializer + */ +#define UIP_UDP_CONNS 10 + +/** + * The name of the function that should be called when UDP datagrams arrive. + * + * \hideinitializer + */ +//#define UIP_UDP_APPCALL ((void*0) + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipopttcp TCP configuration options + * @{ + */ + +/** + * Determines if support for opening connections from uIP should be + * compiled in. + * + * If the applications that are running on top of uIP for this project + * do not need to open outgoing TCP connections, this configration + * option can be turned off to reduce the code size of uIP. + * + * \hideinitializer + */ +#define UIP_ACTIVE_OPEN 1 + +/** + * The maximum number of simultaneously open TCP connections. + * + * Since the TCP connections are statically allocated, turning this + * configuration knob down results in less RAM used. Each TCP + * connection requires approximatly 30 bytes of memory. + * + * \hideinitializer + */ +#define UIP_TCP_PCBS 4 + +/** + * The maximum number of simultaneously listening TCP ports. + * + * Each listening TCP port requires 2 bytes of memory. + * + * \hideinitializer + */ +#define UIP_LISTEN_TCP_PCBS 2 + +/** + * The size of the advertised receiver's window. + * + * Should be set low (i.e., to the size of the uip_buf buffer) is the + * application is slow to process incoming data, or high (32768 bytes) + * if the application processes data quickly. + * + * \hideinitializer + */ +#define UIP_TCPIP_SOCKS 32 + +#define UIP_TCP_SEGS 32 + + +/** + * Determines if support for TCP urgent data notification should be + * compiled in. + * + * Urgent data (out-of-band data) is a rarely used TCP feature that + * very seldom would be required. + * + * \hideinitializer + */ +#define UIP_URGDATA 1 + +/** + * The initial retransmission timeout counted in timer pulses. + * + * This should not be changed. + */ +#define UIP_RTO 3 + +/** + * The maximum number of times a segment should be retransmitted + * before the connection should be aborted. + * + * This should not be changed. + */ +#define UIP_MAXRTX 12 + +/** + * The maximum number of times a SYN segment should be retransmitted + * before a connection request should be deemed to have been + * unsuccessful. + * + * This should not need to be changed. + */ +#define UIP_MAXSYNRTX 4 + +/** + * The TCP maximum segment size. + * + * This is should not be to set to more than UIP_BUFSIZE - UIP_LLH_LEN - 40. + */ +#define UIP_TCP_MSS (1460) + + +#define UIP_TCP_SND_BUF (4*UIP_TCP_MSS) + +#define UIP_TCP_SND_QUEUELEN (4*UIP_TCP_SND_BUF/UIP_TCP_MSS) + +#define UIP_TCP_WND (4*UIP_TCP_MSS) + +/** + * How long a connection should stay in the TIME_WAIT state. + * + * This configiration option has no real implication, and it should be + * left untouched. + */ +#define UIP_TIME_WAIT_TIMEOUT 120 + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptarp ARP configuration options + * @{ + */ + +/** + * The size of the ARP table. + * + * This option should be set to a larger value if this uIP node will + * have many connections from the local network. + * + * \hideinitializer + */ +#define UIP_ARPTAB_SIZE 8 + +/** + * The maxium age of ARP table entries measured in 10ths of seconds. + * + * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD + * default). + */ +#define UIP_ARP_MAXAGE 120 + +/** @} */ + +/*------------------------------------------------------------------------------*/ + +/** + * \defgroup uipoptgeneral General configuration options + * @{ + */ + +/** + * The size of the uIP packet buffer. + * + * The uIP packet buffer should not be smaller than 60 bytes, and does + * not need to be larger than 1500 bytes. Lower size results in lower + * TCP throughput, larger size results in higher TCP throughput. + * + * \hideinitializer + */ +#define UIP_MEM_SIZE (28*1024) + +#define UIP_PBUF_POOL_NUM 16 +#define UIP_PBUF_POOL_BUFSIZE 1600 + +#define UIP_PBUF_ROM_NUM 128 + + +/** + * Determines if statistics support should be compiled in. + * + * The statistics is useful for debugging and to show the user. + * + * \hideinitializer + */ +#define UIP_STATISTICS 0 + +/** + * Determines if logging of certain events should be compiled in. + * + * This is useful mostly for debugging. The function uip_log() + * must be implemented to suit the architecture of the project, if + * logging is turned on. + * + * \hideinitializer + */ +#define UIP_LOGGING 0 +#define UIP_ERRORING 0 + +/** + * Print out a uIP log message. + * + * This function must be implemented by the module that uses uIP, and + * is called by uIP whenever a log message is generated. + */ +void uip_log(const char *filename,int line_nb,char *msg); + +/** + * The link level header length. + * + * This is the offset into the uip_buf where the IP header can be + * found. For Ethernet, this should be set to 14. For SLIP, this + * should be set to 0. + * + * \hideinitializer + */ +#define UIP_LL_HLEN 16 + +#define UIP_TCPIP_HLEN 40 +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptcpu CPU architecture configuration + * @{ + * + * The CPU architecture configuration is where the endianess of the + * CPU on which uIP is to be run is specified. Most CPUs today are + * little endian, and the most notable exception are the Motorolas + * which are big endian. The BYTE_ORDER macro should be changed to + * reflect the CPU architecture on which uIP is to be run. + */ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 3412 +#endif /* LITTLE_ENDIAN */ +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 1234 +#endif /* BIGE_ENDIAN */ + +/** + * The byte order of the CPU architecture on which uIP is to be run. + * + * This option can be either BIG_ENDIAN (Motorola byte order) or + * LITTLE_ENDIAN (Intel byte order). + * + * \hideinitializer + */ +#ifndef BYTE_ORDER +#define BYTE_ORDER BIG_ENDIAN +#endif /* BYTE_ORDER */ + +/** @} */ +/*------------------------------------------------------------------------------*/ + +/** + * \defgroup uipoptapp Appication specific configurations + * @{ + * + * An uIP application is implemented using a single application + * function that is called by uIP whenever a TCP/IP event occurs. The + * name of this function must be registered with uIP at compile time + * using the UIP_APPCALL definition. + * + * uIP applications can store the application state within the + * uip_conn structure by specifying the size of the application + * structure with the UIP_APPSTATE_SIZE macro. + * + * The file containing the definitions must be included in the + * uipopt.h file. + * + * The following example illustrates how this can look. + \code + +void httpd_appcall(void); +#define UIP_APPCALL httpd_appcall + +struct httpd_state { + u8_t state; + u16_t count; + char *dataptr; + char *script; +}; +#define UIP_APPSTATE_SIZE (sizeof(struct httpd_state)) + \endcode + */ + +/** + * \var #define UIP_APPCALL + * + * The name of the application function that uIP should call in + * response to TCP/IP events. + * + */ + +/** + * \var #define UIP_APPSTATE_SIZE + * + * The size of the application state that is to be stored in the + * uip_conn structure. + */ +/** @} */ + +/* Include the header file for the application program that should be + used. If you don't use the example web server, you should change + this. */ + +#define UIP_LIBC_MEMFUNCREPLACE 1 + +#endif /* __UIPOPT_H__ */ diff --git a/wii/libogc/libfat/bit_ops.h b/wii/libogc/libfat/bit_ops.h new file mode 100644 index 0000000000..762be0b340 --- /dev/null +++ b/wii/libogc/libfat/bit_ops.h @@ -0,0 +1,57 @@ +/* + bit_ops.h + Functions for dealing with conversion of data between types + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BIT_OPS_H +#define _BIT_OPS_H + +#include + +/*----------------------------------------------------------------- +Functions to deal with little endian values stored in uint8_t arrays +-----------------------------------------------------------------*/ +static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) { + return ( item[offset] | (item[offset + 1] << 8)); +} + +static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) { + return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24)); +} + +static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) { + item[offset] = (uint8_t) value; + item[offset + 1] = (uint8_t)(value >> 8); +} + +static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) { + item[offset] = (uint8_t) value; + item[offset + 1] = (uint8_t)(value >> 8); + item[offset + 2] = (uint8_t)(value >> 16); + item[offset + 3] = (uint8_t)(value >> 24); +} + +#endif // _BIT_OPS_H diff --git a/wii/libogc/libfat/cache.c b/wii/libogc/libfat/cache.c new file mode 100644 index 0000000000..07576b9cbf --- /dev/null +++ b/wii/libogc/libfat/cache.c @@ -0,0 +1,323 @@ +/* + cache.c + The cache is not visible to the user. It should be flushed + when any file is closed or changes are made to the filesystem. + + This cache implements a least-used-page replacement policy. This will + distribute sectors evenly over the pages, so if less than the maximum + pages are used at once, they should all eventually remain in the cache. + This also has the benefit of throwing out old sectors, so as not to keep + too many stale pages around. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "common.h" +#include "cache.h" +#include "disc.h" + +#include "mem_allocate.h" +#include "bit_ops.h" +#include "file_allocation_table.h" + +#define CACHE_FREE UINT_MAX + +CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, unsigned int bytesPerSector) { + CACHE* cache; + unsigned int i; + CACHE_ENTRY* cacheEntries; + + if (numberOfPages < 2) { + numberOfPages = 2; + } + + if (sectorsPerPage < 8) { + sectorsPerPage = 8; + } + + cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE)); + if (cache == NULL) { + return NULL; + } + + cache->disc = discInterface; + cache->endOfPartition = endOfPartition; + cache->numberOfPages = numberOfPages; + cache->sectorsPerPage = sectorsPerPage; + cache->bytesPerSector = bytesPerSector; + + + cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages); + if (cacheEntries == NULL) { + _FAT_mem_free (cache); + return NULL; + } + + for (i = 0; i < numberOfPages; i++) { + cacheEntries[i].sector = CACHE_FREE; + cacheEntries[i].count = 0; + cacheEntries[i].last_access = 0; + cacheEntries[i].dirty = false; + cacheEntries[i].cache = (uint8_t*) _FAT_mem_align ( sectorsPerPage * bytesPerSector ); + } + + cache->cacheEntries = cacheEntries; + + return cache; +} + +void _FAT_cache_destructor (CACHE* cache) { + unsigned int i; + // Clear out cache before destroying it + _FAT_cache_flush(cache); + + // Free memory in reverse allocation order + for (i = 0; i < cache->numberOfPages; i++) { + _FAT_mem_free (cache->cacheEntries[i].cache); + } + _FAT_mem_free (cache->cacheEntries); + _FAT_mem_free (cache); +} + + +static u32 accessCounter = 0; + +static u32 accessTime(){ + accessCounter++; + return accessCounter; +} + + +static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector) +{ + unsigned int i; + CACHE_ENTRY* cacheEntries = cache->cacheEntries; + unsigned int numberOfPages = cache->numberOfPages; + unsigned int sectorsPerPage = cache->sectorsPerPage; + + bool foundFree = false; + unsigned int oldUsed = 0; + unsigned int oldAccess = UINT_MAX; + + for(i=0;i=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) { + cacheEntries[i].last_access = accessTime(); + return &(cacheEntries[i]); + } + + if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_accessdisc,cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL; + cacheEntries[oldUsed].dirty = false; + } + + sector = (sector/sectorsPerPage)*sectorsPerPage; // align base sector to page size + sec_t next_page = sector + sectorsPerPage; + if(next_page > cache->endOfPartition) next_page = cache->endOfPartition; + + if(!_FAT_disc_readSectors(cache->disc,sector,next_page-sector,cacheEntries[oldUsed].cache)) return NULL; + + cacheEntries[oldUsed].sector = sector; + cacheEntries[oldUsed].count = next_page-sector; + cacheEntries[oldUsed].last_access = accessTime(); + + return &(cacheEntries[oldUsed]); +} + +bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buffer) +{ + sec_t sec; + sec_t secs_to_read; + CACHE_ENTRY *entry; + uint8_t *dest = (uint8_t *)buffer; + + while(numSectors>0) { + entry = _FAT_cache_getPage(cache,sector); + if(entry==NULL) return false; + + sec = sector - entry->sector; + secs_to_read = entry->count - sec; + if(secs_to_read>numSectors) secs_to_read = numSectors; + + memcpy(dest,entry->cache + (sec*cache->bytesPerSector),(secs_to_read*cache->bytesPerSector)); + + dest += (secs_to_read*cache->bytesPerSector); + sector += secs_to_read; + numSectors -= secs_to_read; + } + + return true; +} + +/* +Reads some data from a cache page, determined by the sector number +*/ +bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size) +{ + sec_t sec; + CACHE_ENTRY *entry; + + if (offset + size > cache->bytesPerSector) return false; + + entry = _FAT_cache_getPage(cache,sector); + if(entry==NULL) return false; + + sec = sector - entry->sector; + memcpy(buffer,entry->cache + ((sec*cache->bytesPerSector) + offset),size); + + return true; +} + +bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) { + uint8_t buf[4]; + if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false; + + switch(num_bytes) { + case 1: *value = buf[0]; break; + case 2: *value = u8array_to_u16(buf,0); break; + case 4: *value = u8array_to_u32(buf,0); break; + default: return false; + } + return true; +} + +/* +Writes some data to a cache page, making sure it is loaded into memory first. +*/ +bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) +{ + sec_t sec; + CACHE_ENTRY *entry; + + if (offset + size > cache->bytesPerSector) return false; + + entry = _FAT_cache_getPage(cache,sector); + if(entry==NULL) return false; + + sec = sector - entry->sector; + memcpy(entry->cache + ((sec*cache->bytesPerSector) + offset),buffer,size); + + entry->dirty = true; + return true; +} + +bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) { + uint8_t buf[4] = {0, 0, 0, 0}; + + switch(size) { + case 1: buf[0] = value; break; + case 2: u16_to_u8array(buf, 0, value); break; + case 4: u32_to_u8array(buf, 0, value); break; + default: return false; + } + + return _FAT_cache_writePartialSector(cache, buf, sector, offset, size); +} + +/* +Writes some data to a cache page, zeroing out the page first +*/ +bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) +{ + sec_t sec; + CACHE_ENTRY *entry; + + if (offset + size > cache->bytesPerSector) return false; + + entry = _FAT_cache_getPage(cache,sector); + if(entry==NULL) return false; + + sec = sector - entry->sector; + memset(entry->cache + (sec*cache->bytesPerSector),0,cache->bytesPerSector); + memcpy(entry->cache + ((sec*cache->bytesPerSector) + offset),buffer,size); + + entry->dirty = true; + return true; +} + + +bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer) +{ + sec_t sec; + sec_t secs_to_write; + CACHE_ENTRY* entry; + const uint8_t *src = (const uint8_t *)buffer; + + while(numSectors>0) + { + entry = _FAT_cache_getPage(cache,sector); + if(entry==NULL) return false; + + sec = sector - entry->sector; + secs_to_write = entry->count - sec; + if(secs_to_write>numSectors) secs_to_write = numSectors; + + memcpy(entry->cache + (sec*cache->bytesPerSector),src,(secs_to_write*cache->bytesPerSector)); + + src += (secs_to_write*cache->bytesPerSector); + sector += secs_to_write; + numSectors -= secs_to_write; + + entry->dirty = true; + } + return true; +} + +/* +Flushes all dirty pages to disc, clearing the dirty flag. +*/ +bool _FAT_cache_flush (CACHE* cache) { + unsigned int i; + + for (i = 0; i < cache->numberOfPages; i++) { + if (cache->cacheEntries[i].dirty) { + if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) { + return false; + } + } + cache->cacheEntries[i].dirty = false; + } + + return true; +} + +void _FAT_cache_invalidate (CACHE* cache) { + unsigned int i; + _FAT_cache_flush(cache); + for (i = 0; i < cache->numberOfPages; i++) { + cache->cacheEntries[i].sector = CACHE_FREE; + cache->cacheEntries[i].last_access = 0; + cache->cacheEntries[i].count = 0; + cache->cacheEntries[i].dirty = false; + } +} diff --git a/wii/libogc/libfat/cache.h b/wii/libogc/libfat/cache.h new file mode 100644 index 0000000000..07bb14c23e --- /dev/null +++ b/wii/libogc/libfat/cache.h @@ -0,0 +1,128 @@ +/* + cache.h + The cache is not visible to the user. It should be flushed + when any file is closed or changes are made to the filesystem. + + This cache implements a least-used-page replacement policy. This will + distribute sectors evenly over the pages, so if less than the maximum + pages are used at once, they should all eventually remain in the cache. + This also has the benefit of throwing out old sectors, so as not to keep + too many stale pages around. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _CACHE_H +#define _CACHE_H + +#include "common.h" +#include "disc.h" + +typedef struct { + sec_t sector; + unsigned int count; + unsigned int last_access; + bool dirty; + uint8_t* cache; +} CACHE_ENTRY; + +typedef struct { + const DISC_INTERFACE* disc; + sec_t endOfPartition; + unsigned int numberOfPages; + unsigned int sectorsPerPage; + unsigned int bytesPerSector; + CACHE_ENTRY* cacheEntries; +} CACHE; + +/* +Read data from a sector in the cache +If the sector is not in the cache, it will be swapped in +offset is the position to start reading from +size is the amount of data to read +Precondition: offset + size <= BYTES_PER_READ +*/ +bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size); + +bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes); + +/* +Write data to a sector in the cache +If the sector is not in the cache, it will be swapped in. +When the sector is swapped out, the data will be written to the disc +offset is the position to start writing to +size is the amount of data to write +Precondition: offset + size <= BYTES_PER_READ +*/ +bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size); + +bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes); + +/* +Write data to a sector in the cache, zeroing the sector first +If the sector is not in the cache, it will be swapped in. +When the sector is swapped out, the data will be written to the disc +offset is the position to start writing to +size is the amount of data to write +Precondition: offset + size <= BYTES_PER_READ +*/ +bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size); + +/* +Read several sectors from the cache +*/ +bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer); + +/* +Read a full sector from the cache +*/ +static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) { + return _FAT_cache_readPartialSector (cache, buffer, sector, 0, cache->bytesPerSector); +} + +/* +Write a full sector to the cache +*/ +static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) { + return _FAT_cache_writePartialSector (cache, buffer, sector, 0, cache->bytesPerSector); +} + +bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer); + +/* +Write any dirty sectors back to disc and clear out the contents of the cache +*/ +bool _FAT_cache_flush (CACHE* cache); + +/* +Clear out the contents of the cache without writing any dirty sectors first +*/ +void _FAT_cache_invalidate (CACHE* cache); + +CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, unsigned int bytesPerSector); + +void _FAT_cache_destructor (CACHE* cache); + +#endif // _CACHE_H + diff --git a/wii/libogc/libfat/common.h b/wii/libogc/libfat/common.h new file mode 100644 index 0000000000..c5c5632555 --- /dev/null +++ b/wii/libogc/libfat/common.h @@ -0,0 +1,78 @@ +/* + common.h + Common definitions and included files for the FATlib + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _COMMON_H +#define _COMMON_H + +#include +#include +#include + +// When compiling for NDS, make sure NDS is defined +#ifndef NDS + #if defined ARM9 || defined ARM7 + #define NDS + #endif +#endif + +// Platform specific includes +#if defined(__gamecube__) || defined (__wii__) + #include + #include + #include +#elif defined(NDS) + #include + #include + #include +#elif defined(GBA) + #include + #include +#endif + +// Platform specific options +#if defined (__wii__) + #define DEFAULT_CACHE_PAGES 4 + #define DEFAULT_SECTORS_PAGE 64 + #define USE_LWP_LOCK + #define USE_RTC_TIME +#elif defined (__gamecube__) + #define DEFAULT_CACHE_PAGES 4 + #define DEFAULT_SECTORS_PAGE 64 + #define USE_LWP_LOCK + #define USE_RTC_TIME +#elif defined (NDS) + #define DEFAULT_CACHE_PAGES 16 + #define DEFAULT_SECTORS_PAGE 8 + #define USE_RTC_TIME +#elif defined (GBA) + #define DEFAULT_CACHE_PAGES 2 + #define DEFAULT_SECTORS_PAGE 8 + #define LIMIT_SECTORS 128 +#endif + +#endif // _COMMON_H diff --git a/wii/libogc/libfat/directory.c b/wii/libogc/libfat/directory.c new file mode 100644 index 0000000000..65906d844b --- /dev/null +++ b/wii/libogc/libfat/directory.c @@ -0,0 +1,1129 @@ +/* + directory.c + Reading, writing and manipulation of the directory structure on + a FAT partition + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include + +#include "directory.h" +#include "common.h" +#include "partition.h" +#include "file_allocation_table.h" +#include "bit_ops.h" +#include "filetime.h" + +// Directory entry codes +#define DIR_ENTRY_LAST 0x00 +#define DIR_ENTRY_FREE 0xE5 + +typedef unsigned short ucs2_t; + +// Long file name directory entry +enum LFN_offset { + LFN_offset_ordinal = 0x00, // Position within LFN + LFN_offset_char0 = 0x01, + LFN_offset_char1 = 0x03, + LFN_offset_char2 = 0x05, + LFN_offset_char3 = 0x07, + LFN_offset_char4 = 0x09, + LFN_offset_flag = 0x0B, // Should be equal to ATTRIB_LFN + LFN_offset_reserved1 = 0x0C, // Always 0x00 + LFN_offset_checkSum = 0x0D, // Checksum of short file name (alias) + LFN_offset_char5 = 0x0E, + LFN_offset_char6 = 0x10, + LFN_offset_char7 = 0x12, + LFN_offset_char8 = 0x14, + LFN_offset_char9 = 0x16, + LFN_offset_char10 = 0x18, + LFN_offset_reserved2 = 0x1A, // Always 0x0000 + LFN_offset_char11 = 0x1C, + LFN_offset_char12 = 0x1E +}; +static const int LFN_offset_table[13]={0x01,0x03,0x05,0x07,0x09,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E}; + +#define LFN_END 0x40 +#define LFN_DEL 0x80 + +static const char ILLEGAL_ALIAS_CHARACTERS[] = "\\/:;*?\"<>|&+,=[] "; +static const char ILLEGAL_LFN_CHARACTERS[] = "\\/:*?\"<>|"; + +/* +Returns number of UCS-2 characters needed to encode an LFN +Returns -1 if it is an invalid LFN +*/ +#define ABOVE_UCS_RANGE 0xF0 +static int _FAT_directory_lfnLength (const char* name) { + unsigned int i; + size_t nameLength; + int ucsLength; + const char* tempName = name; + + nameLength = strnlen(name, NAME_MAX); + // Make sure the name is short enough to be valid + if ( nameLength >= NAME_MAX) { + return -1; + } + // Make sure it doesn't contain any invalid characters + if (strpbrk (name, ILLEGAL_LFN_CHARACTERS) != NULL) { + return -1; + } + // Make sure the name doesn't contain any control codes or codes not representable in UCS-2 + for (i = 0; i < nameLength; i++) { + unsigned char ch = (unsigned char) name[i]; + if (ch < 0x20 || ch >= ABOVE_UCS_RANGE) { + return -1; + } + } + // Convert to UCS-2 and get the resulting length + ucsLength = mbsrtowcs(NULL, &tempName, MAX_LFN_LENGTH, NULL); + if (ucsLength < 0 || ucsLength >= MAX_LFN_LENGTH) { + return -1; + } + + // Otherwise it is valid + return ucsLength; +} + +/* +Convert a multibyte encoded string into a NUL-terminated UCS-2 string, storing at most len characters +return number of characters stored +*/ +static size_t _FAT_directory_mbstoucs2 (ucs2_t* dst, const char* src, size_t len) { + mbstate_t ps = {0}; + wchar_t tempChar; + int bytes; + size_t count = 0; + + while (count < len-1 && *src != '\0') { + bytes = mbrtowc (&tempChar, src, MB_CUR_MAX, &ps); + if (bytes > 0) { + *dst = (ucs2_t)tempChar; + src += bytes; + dst++; + count++; + } else if (bytes == 0) { + break; + } else { + return -1; + } + } + *dst = '\0'; + + return count; +} + +/* +Convert a UCS-2 string into a NUL-terminated multibyte string, storing at most len chars +return number of chars stored, or (size_t)-1 on error +*/ +static size_t _FAT_directory_ucs2tombs (char* dst, const ucs2_t* src, size_t len) { + mbstate_t ps = {0}; + size_t count = 0; + int bytes; + char buff[MB_CUR_MAX]; + int i; + + while (count < len - 1 && *src != '\0') { + bytes = wcrtomb (buff, *src, &ps); + if (bytes < 0) { + return -1; + } + if (count + bytes < len && bytes > 0) { + for (i = 0; i < bytes; i++) { + *dst++ = buff[i]; + } + src++; + count += bytes; + } else { + break; + } + } + *dst = L'\0'; + + return count; +} + +/* +Case-independent comparison of two multibyte encoded strings +*/ +static int _FAT_directory_mbsncasecmp (const char* s1, const char* s2, size_t len1) { + wchar_t wc1, wc2; + mbstate_t ps1 = {0}; + mbstate_t ps2 = {0}; + size_t b1 = 0; + size_t b2 = 0; + + if (len1 == 0) { + return 0; + } + + do { + s1 += b1; + s2 += b2; + b1 = mbrtowc(&wc1, s1, MB_CUR_MAX, &ps1); + b2 = mbrtowc(&wc2, s2, MB_CUR_MAX, &ps2); + if ((int)b1 < 0 || (int)b2 < 0) { + break; + } + len1 -= b1; + } while (len1 > 0 && towlower(wc1) == towlower(wc2) && wc1 != 0); + + return towlower(wc1) - towlower(wc2); +} + + +static bool _FAT_directory_entryGetAlias (const u8* entryData, char* destName) { + char c; + bool caseInfo; + int i = 0; + int j = 0; + + destName[0] = '\0'; + if (entryData[0] != DIR_ENTRY_FREE) { + if (entryData[0] == '.') { + destName[0] = '.'; + if (entryData[1] == '.') { + destName[1] = '.'; + destName[2] = '\0'; + } else { + destName[1] = '\0'; + } + } else { + // Copy the filename from the dirEntry to the string + caseInfo = entryData[DIR_ENTRY_caseInfo] & CASE_LOWER_BASE; + for (i = 0; (i < 8) && (entryData[DIR_ENTRY_name + i] != ' '); i++) { + c = entryData[DIR_ENTRY_name + i]; + destName[i] = (caseInfo ? tolower((unsigned char)c) : c); + } + // Copy the extension from the dirEntry to the string + if (entryData[DIR_ENTRY_extension] != ' ') { + destName[i++] = '.'; + caseInfo = entryData[DIR_ENTRY_caseInfo] & CASE_LOWER_EXT; + for ( j = 0; (j < 3) && (entryData[DIR_ENTRY_extension + j] != ' '); j++) { + c = entryData[DIR_ENTRY_extension + j]; + destName[i++] = (caseInfo ? tolower((unsigned char)c) : c); + } + } + destName[i] = '\0'; + } + } + + return (destName[0] != '\0'); +} + +uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData) { + if (partition->filesysType == FS_FAT32) { + // Only use high 16 bits of start cluster when we are certain they are correctly defined + return u8array_to_u16(entryData,DIR_ENTRY_cluster) | (u8array_to_u16(entryData, DIR_ENTRY_clusterHigh) << 16); + } else { + return u8array_to_u16(entryData,DIR_ENTRY_cluster); + } +} + +static bool _FAT_directory_incrementDirEntryPosition (PARTITION* partition, DIR_ENTRY_POSITION* entryPosition, bool extendDirectory) { + DIR_ENTRY_POSITION position = *entryPosition; + uint32_t tempCluster; + + // Increment offset, wrapping at the end of a sector + ++ position.offset; + if (position.offset == partition->bytesPerSector / DIR_ENTRY_DATA_SIZE) { + position.offset = 0; + // Increment sector when wrapping + ++ position.sector; + // But wrap at the end of a cluster + if ((position.sector == partition->sectorsPerCluster) && (position.cluster != FAT16_ROOT_DIR_CLUSTER)) { + position.sector = 0; + // Move onto the next cluster, making sure there is another cluster to go to + tempCluster = _FAT_fat_nextCluster(partition, position.cluster); + if (tempCluster == CLUSTER_EOF) { + if (extendDirectory) { + tempCluster = _FAT_fat_linkFreeClusterCleared (partition, position.cluster); + if (!_FAT_fat_isValidCluster(partition, tempCluster)) { + return false; // This will only happen if the disc is full + } + } else { + return false; // Got to the end of the directory, not extending it + } + } + position.cluster = tempCluster; + } else if ((position.cluster == FAT16_ROOT_DIR_CLUSTER) && (position.sector == (partition->dataStart - partition->rootDirStart))) { + return false; // Got to end of root directory, can't extend it + } + } + *entryPosition = position; + return true; +} + +bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry) { + DIR_ENTRY_POSITION entryStart; + DIR_ENTRY_POSITION entryEnd; + uint8_t entryData[0x20]; + ucs2_t lfn[MAX_LFN_LENGTH]; + bool notFound, found; + int lfnPos; + uint8_t lfnChkSum, chkSum; + bool lfnExists; + int i; + + lfnChkSum = 0; + + entryStart = entry->dataEnd; + + // Make sure we are using the correct root directory, in case of FAT32 + if (entryStart.cluster == FAT16_ROOT_DIR_CLUSTER) { + entryStart.cluster = partition->rootDirCluster; + } + + entryEnd = entryStart; + + lfnExists = false; + + found = false; + notFound = false; + + while (!found && !notFound) { + if (_FAT_directory_incrementDirEntryPosition (partition, &entryEnd, false) == false) { + notFound = true; + break; + } + + _FAT_cache_readPartialSector (partition->cache, entryData, + _FAT_fat_clusterToSector(partition, entryEnd.cluster) + entryEnd.sector, + entryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + + if (entryData[DIR_ENTRY_attributes] == ATTRIB_LFN) { + // It's an LFN + if (entryData[LFN_offset_ordinal] & LFN_DEL) { + lfnExists = false; + } else if (entryData[LFN_offset_ordinal] & LFN_END) { + // Last part of LFN, make sure it isn't deleted using previous if(Thanks MoonLight) + entryStart = entryEnd; // This is the start of a directory entry + lfnExists = true; + lfnPos = (entryData[LFN_offset_ordinal] & ~LFN_END) * 13; + if (lfnPos > MAX_LFN_LENGTH - 1) { + lfnPos = MAX_LFN_LENGTH - 1; + } + lfn[lfnPos] = '\0'; // Set end of lfn to null character + lfnChkSum = entryData[LFN_offset_checkSum]; + } + if (lfnChkSum != entryData[LFN_offset_checkSum]) { + lfnExists = false; + } + if (lfnExists) { + lfnPos = ((entryData[LFN_offset_ordinal] & ~LFN_END) - 1) * 13; + for (i = 0; i < 13; i++) { + if (lfnPos + i < MAX_LFN_LENGTH - 1) { + lfn[lfnPos + i] = entryData[LFN_offset_table[i]] | (entryData[LFN_offset_table[i]+1] << 8); + } + } + } + } else if (entryData[DIR_ENTRY_attributes] & ATTRIB_VOL) { + // This is a volume name, don't bother with it + } else if (entryData[0] == DIR_ENTRY_LAST) { + notFound = true; + } else if ((entryData[0] != DIR_ENTRY_FREE) && (entryData[0] > 0x20) && !(entryData[DIR_ENTRY_attributes] & ATTRIB_VOL)) { + if (lfnExists) { + // Calculate file checksum + chkSum = 0; + for (i=0; i < 11; i++) { + // NOTE: The operation is an unsigned char rotate right + chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + entryData[i]; + } + if (chkSum != lfnChkSum) { + lfnExists = false; + entry->filename[0] = '\0'; + } + } + + if (lfnExists) { + if (_FAT_directory_ucs2tombs (entry->filename, lfn, NAME_MAX) == (size_t)-1) { + // Failed to convert the file name to UTF-8. Maybe the wrong locale is set? + return false; + } + } else { + entryStart = entryEnd; + _FAT_directory_entryGetAlias (entryData, entry->filename); + } + found = true; + } + } + + // If no file is found, return false + if (notFound) { + return false; + } else { + // Fill in the directory entry struct + entry->dataStart = entryStart; + entry->dataEnd = entryEnd; + memcpy (entry->entryData, entryData, DIR_ENTRY_DATA_SIZE); + return true; + } +} + +bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster) { + entry->dataStart.cluster = dirCluster; + entry->dataStart.sector = 0; + entry->dataStart.offset = -1; // Start before the beginning of the directory + + entry->dataEnd = entry->dataStart; + + return _FAT_directory_getNextEntry (partition, entry); +} + +bool _FAT_directory_getRootEntry (PARTITION* partition, DIR_ENTRY* entry) { + entry->dataStart.cluster = 0; + entry->dataStart.sector = 0; + entry->dataStart.offset = 0; + + entry->dataEnd = entry->dataStart; + + memset (entry->filename, '\0', NAME_MAX); + entry->filename[0] = '.'; + + memset (entry->entryData, 0, DIR_ENTRY_DATA_SIZE); + memset (entry->entryData, ' ', 11); + entry->entryData[0] = '.'; + + entry->entryData[DIR_ENTRY_attributes] = ATTRIB_DIR; + + u16_to_u8array (entry->entryData, DIR_ENTRY_cluster, partition->rootDirCluster); + u16_to_u8array (entry->entryData, DIR_ENTRY_clusterHigh, partition->rootDirCluster >> 16); + + return true; +} + +bool _FAT_directory_getVolumeLabel (PARTITION* partition, char *label) { + DIR_ENTRY entry; + DIR_ENTRY_POSITION entryEnd; + uint8_t entryData[DIR_ENTRY_DATA_SIZE]; + int i; + bool end; + + _FAT_directory_getRootEntry(partition, &entry); + + entryEnd = entry.dataEnd; + + // Make sure we are using the correct root directory, in case of FAT32 + if (entryEnd.cluster == FAT16_ROOT_DIR_CLUSTER) { + entryEnd.cluster = partition->rootDirCluster; + } + + label[0]='\0'; + label[11]='\0'; + end = false; + //this entry should be among the first 3 entries in the root directory table, if not, then system can have trouble displaying the right volume label + while(!end) { + if(!_FAT_cache_readPartialSector (partition->cache, entryData, + _FAT_fat_clusterToSector(partition, entryEnd.cluster) + entryEnd.sector, + entryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE)) + { //error reading + return false; + } + + if (entryData[DIR_ENTRY_attributes] == ATTRIB_VOL && entryData[0] != DIR_ENTRY_FREE) { + for (i = 0; i < 11; i++) { + label[i] = entryData[DIR_ENTRY_name + i]; + } + return true; + } else if (entryData[0] == DIR_ENTRY_LAST) { + end = true; + } + + if (_FAT_directory_incrementDirEntryPosition (partition, &entryEnd, false) == false) { + end = true; + } + } + return false; +} + +bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry) { + DIR_ENTRY_POSITION entryStart = entry->dataStart; + DIR_ENTRY_POSITION entryEnd = entry->dataEnd; + bool entryStillValid; + bool finished; + ucs2_t lfn[MAX_LFN_LENGTH]; + int i; + int lfnPos; + uint8_t entryData[DIR_ENTRY_DATA_SIZE]; + + memset (entry->filename, '\0', NAME_MAX); + + // Create an empty directory entry to overwrite the old ones with + for ( entryStillValid = true, finished = false; + entryStillValid && !finished; + entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &entryStart, false)) + { + _FAT_cache_readPartialSector (partition->cache, entryData, + _FAT_fat_clusterToSector(partition, entryStart.cluster) + entryStart.sector, + entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + + if ((entryStart.cluster == entryEnd.cluster) + && (entryStart.sector == entryEnd.sector) + && (entryStart.offset == entryEnd.offset)) { + // Copy the entry data and stop, since this is the last section of the directory entry + memcpy (entry->entryData, entryData, DIR_ENTRY_DATA_SIZE); + finished = true; + } else { + // Copy the long file name data + lfnPos = ((entryData[LFN_offset_ordinal] & ~LFN_END) - 1) * 13; + for (i = 0; i < 13; i++) { + if (lfnPos + i < MAX_LFN_LENGTH - 1) { + lfn[lfnPos + i] = entryData[LFN_offset_table[i]] | (entryData[LFN_offset_table[i]+1] << 8); + } + } + } + } + + if (!entryStillValid) { + return false; + } + + entryStart = entry->dataStart; + if ((entryStart.cluster == entryEnd.cluster) + && (entryStart.sector == entryEnd.sector) + && (entryStart.offset == entryEnd.offset)) { + // Since the entry doesn't have a long file name, extract the short filename + if (!_FAT_directory_entryGetAlias (entry->entryData, entry->filename)) { + return false; + } + } else { + // Encode the long file name into a multibyte string + if (_FAT_directory_ucs2tombs (entry->filename, lfn, NAME_MAX) == (size_t)-1) { + return false; + } + } + + return true; +} + + + +bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd) { + size_t dirnameLength; + const char* pathPosition; + const char* nextPathPosition; + uint32_t dirCluster; + bool foundFile; + char alias[MAX_ALIAS_LENGTH]; + bool found, notFound; + + pathPosition = path; + + found = false; + notFound = false; + + if (pathEnd == NULL) { + // Set pathEnd to the end of the path string + pathEnd = strchr (path, '\0'); + } + + if (pathPosition[0] == DIR_SEPARATOR) { + // Start at root directory + dirCluster = partition->rootDirCluster; + // Consume separator(s) + while (pathPosition[0] == DIR_SEPARATOR) { + pathPosition++; + } + // If the path is only specifying a directory in the form of "/" return it + if (pathPosition >= pathEnd) { + _FAT_directory_getRootEntry (partition, entry); + found = true; + } + } else { + // Start in current working directory + dirCluster = partition->cwdCluster; + } + + while (!found && !notFound) { + // Get the name of the next required subdirectory within the path + nextPathPosition = strchr (pathPosition, DIR_SEPARATOR); + if (nextPathPosition != NULL) { + dirnameLength = nextPathPosition - pathPosition; + } else { + dirnameLength = strlen(pathPosition); + } + + if (dirnameLength > NAME_MAX) { + // The path is too long to bother with + return false; + } + + // Check for "." or ".." when the dirCluster is root cluster + // These entries do not exist, so we must fake it + if ((dirCluster == partition->rootDirCluster) + && ((strncmp(".", pathPosition, dirnameLength) == 0) + || (strncmp("..", pathPosition, dirnameLength) == 0))) { + foundFile = true; + _FAT_directory_getRootEntry(partition, entry); + } else { + // Look for the directory within the path + foundFile = _FAT_directory_getFirstEntry (partition, entry, dirCluster); + + while (foundFile && !found && !notFound) { // It hasn't already found the file + // Check if the filename matches + if ((dirnameLength == strnlen(entry->filename, NAME_MAX)) + && (_FAT_directory_mbsncasecmp(pathPosition, entry->filename, dirnameLength) == 0)) { + found = true; + } + + // Check if the alias matches + _FAT_directory_entryGetAlias (entry->entryData, alias); + if ((dirnameLength == strnlen(alias, MAX_ALIAS_LENGTH)) + && (strncasecmp(pathPosition, alias, dirnameLength) == 0)) { + found = true; + } + + if (found && !(entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) && (nextPathPosition != NULL)) { + // Make sure that we aren't trying to follow a file instead of a directory in the path + found = false; + } + + if (!found) { + foundFile = _FAT_directory_getNextEntry (partition, entry); + } + } + } + + if (!foundFile) { + // Check that the search didn't get to the end of the directory + notFound = true; + found = false; + } else if ((nextPathPosition == NULL) || (nextPathPosition >= pathEnd)) { + // Check that we reached the end of the path + found = true; + } else if (entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) { + dirCluster = _FAT_directory_entryGetCluster (partition, entry->entryData); + if (dirCluster == CLUSTER_ROOT) + dirCluster = partition->rootDirCluster; + pathPosition = nextPathPosition; + // Consume separator(s) + while (pathPosition[0] == DIR_SEPARATOR) { + pathPosition++; + } + // The requested directory was found + if (pathPosition >= pathEnd) { + found = true; + } else { + found = false; + } + } + } + + if (found && !notFound) { + if (partition->filesysType == FS_FAT32 && (entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) && + _FAT_directory_entryGetCluster (partition, entry->entryData) == CLUSTER_ROOT) + { + // On FAT32 it should specify an actual cluster for the root entry, + // not cluster 0 as on FAT16 + _FAT_directory_getRootEntry (partition, entry); + } + return true; + } else { + return false; + } +} + +bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry) { + DIR_ENTRY_POSITION entryStart = entry->dataStart; + DIR_ENTRY_POSITION entryEnd = entry->dataEnd; + bool entryStillValid; + bool finished; + uint8_t entryData[DIR_ENTRY_DATA_SIZE]; + + // Create an empty directory entry to overwrite the old ones with + for ( entryStillValid = true, finished = false; + entryStillValid && !finished; + entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &entryStart, false)) + { + _FAT_cache_readPartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, entryStart.cluster) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + entryData[0] = DIR_ENTRY_FREE; + _FAT_cache_writePartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, entryStart.cluster) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + if ((entryStart.cluster == entryEnd.cluster) && (entryStart.sector == entryEnd.sector) && (entryStart.offset == entryEnd.offset)) { + finished = true; + } + } + + if (!entryStillValid) { + return false; + } + + return true; +} + +static bool _FAT_directory_findEntryGap (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster, size_t size) { + DIR_ENTRY_POSITION gapStart; + DIR_ENTRY_POSITION gapEnd; + uint8_t entryData[DIR_ENTRY_DATA_SIZE]; + size_t dirEntryRemain; + bool endOfDirectory, entryStillValid; + + // Scan Dir for free entry + gapEnd.offset = 0; + gapEnd.sector = 0; + gapEnd.cluster = dirCluster; + + gapStart = gapEnd; + + entryStillValid = true; + dirEntryRemain = size; + endOfDirectory = false; + + while (entryStillValid && !endOfDirectory && (dirEntryRemain > 0)) { + _FAT_cache_readPartialSector (partition->cache, entryData, + _FAT_fat_clusterToSector(partition, gapEnd.cluster) + gapEnd.sector, + gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + if (entryData[0] == DIR_ENTRY_LAST) { + if (dirEntryRemain == size) { + gapStart = gapEnd; + } + -- dirEntryRemain; + endOfDirectory = true; + } else if (entryData[0] == DIR_ENTRY_FREE) { + if (dirEntryRemain == size) { + gapStart = gapEnd; + } + -- dirEntryRemain; + } else { + dirEntryRemain = size; + } + + if (!endOfDirectory && (dirEntryRemain > 0)) { + entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &gapEnd, true); + } + } + + // Make sure the scanning didn't fail + if (!entryStillValid) { + return false; + } + + // Save the start entry, since we know it is valid + entry->dataStart = gapStart; + + if (endOfDirectory) { + memset (entryData, DIR_ENTRY_LAST, DIR_ENTRY_DATA_SIZE); + dirEntryRemain += 1; // Increase by one to take account of End Of Directory Marker + while ((dirEntryRemain > 0) && entryStillValid) { + // Get the gapEnd before incrementing it, so the second to last one is saved + entry->dataEnd = gapEnd; + // Increment gapEnd, moving onto the next entry + entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &gapEnd, true); + -- dirEntryRemain; + // Fill the entry with blanks + _FAT_cache_writePartialSector (partition->cache, entryData, + _FAT_fat_clusterToSector(partition, gapEnd.cluster) + gapEnd.sector, + gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + } + if (!entryStillValid) { + return false; + } + } else { + entry->dataEnd = gapEnd; + } + + return true; +} + +static bool _FAT_directory_entryExists (PARTITION* partition, const char* name, uint32_t dirCluster) { + DIR_ENTRY tempEntry; + bool foundFile; + char alias[MAX_ALIAS_LENGTH]; + size_t dirnameLength; + + dirnameLength = strnlen(name, NAME_MAX); + + if (dirnameLength >= NAME_MAX) { + return false; + } + + // Make sure the entry doesn't already exist + foundFile = _FAT_directory_getFirstEntry (partition, &tempEntry, dirCluster); + + while (foundFile) { // It hasn't already found the file + // Check if the filename matches + if ((dirnameLength == strnlen(tempEntry.filename, NAME_MAX)) + && (_FAT_directory_mbsncasecmp(name, tempEntry.filename, dirnameLength) == 0)) { + return true; + } + + // Check if the alias matches + _FAT_directory_entryGetAlias (tempEntry.entryData, alias); + if ((strncasecmp(name, alias, MAX_ALIAS_LENGTH) == 0)) { + return true; + } + foundFile = _FAT_directory_getNextEntry (partition, &tempEntry); + } + return false; +} + +/* +Creates an alias for a long file name. If the alias is not an exact match for the +filename, it returns the number of characters in the alias. If the two names match, +it returns 0. If there was an error, it returns -1. +*/ +static int _FAT_directory_createAlias (char* alias, const char* lfn) { + bool lossyConversion = false; // Set when the alias had to be modified to be valid + int lfnPos = 0; + int aliasPos = 0; + wchar_t lfnChar; + int oemChar; + mbstate_t ps = {0}; + int bytesUsed = 0; + const char* lfnExt; + int aliasExtLen; + + // Strip leading periods + while (lfn[lfnPos] == '.') { + lfnPos ++; + lossyConversion = true; + } + + // Primary portion of alias + while (aliasPos < 8 && lfn[lfnPos] != '.' && lfn[lfnPos] != '\0') { + bytesUsed = mbrtowc(&lfnChar, lfn + lfnPos, NAME_MAX - lfnPos, &ps); + if (bytesUsed < 0) { + return -1; + } + oemChar = wctob(towupper((wint_t)lfnChar)); + if (wctob((wint_t)lfnChar) != oemChar) { + // Case of letter was changed + lossyConversion = true; + } + if (oemChar == ' ') { + // Skip spaces in filename + lossyConversion = true; + lfnPos += bytesUsed; + continue; + } + if (oemChar == EOF) { + oemChar = '_'; // Replace unconvertable characters with underscores + lossyConversion = true; + } + if (strchr (ILLEGAL_ALIAS_CHARACTERS, oemChar) != NULL) { + // Invalid Alias character + oemChar = '_'; // Replace illegal characters with underscores + lossyConversion = true; + } + + alias[aliasPos] = (char)oemChar; + aliasPos++; + lfnPos += bytesUsed; + } + + if (lfn[lfnPos] != '.' && lfn[lfnPos] != '\0') { + // Name was more than 8 characters long + lossyConversion = true; + } + + // Alias extension + lfnExt = strrchr (lfn, '.'); + if (lfnExt != NULL && lfnExt != strchr (lfn, '.')) { + // More than one period in name + lossyConversion = true; + } + if (lfnExt != NULL && lfnExt[1] != '\0') { + lfnExt++; + alias[aliasPos] = '.'; + aliasPos++; + memset (&ps, 0, sizeof(ps)); + for (aliasExtLen = 0; aliasExtLen < MAX_ALIAS_EXT_LENGTH && *lfnExt != '\0'; aliasExtLen++) { + bytesUsed = mbrtowc(&lfnChar, lfnExt, NAME_MAX - lfnPos, &ps); + if (bytesUsed < 0) { + return -1; + } + oemChar = wctob(towupper((wint_t)lfnChar)); + if (wctob((wint_t)lfnChar) != oemChar) { + // Case of letter was changed + lossyConversion = true; + } + if (oemChar == ' ') { + // Skip spaces in alias + lossyConversion = true; + lfnExt += bytesUsed; + continue; + } + if (oemChar == EOF) { + oemChar = '_'; // Replace unconvertable characters with underscores + lossyConversion = true; + } + if (strchr (ILLEGAL_ALIAS_CHARACTERS, oemChar) != NULL) { + // Invalid Alias character + oemChar = '_'; // Replace illegal characters with underscores + lossyConversion = true; + } + + alias[aliasPos] = (char)oemChar; + aliasPos++; + lfnExt += bytesUsed; + } + if (*lfnExt != '\0') { + // Extension was more than 3 characters long + lossyConversion = true; + } + } + + alias[aliasPos] = '\0'; + if (lossyConversion) { + return aliasPos; + } else { + return 0; + } +} + +bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster) { + size_t entrySize; + uint8_t lfnEntry[DIR_ENTRY_DATA_SIZE]; + int i,j; // Must be signed for use when decrementing in for loop + char *tmpCharPtr; + DIR_ENTRY_POSITION curEntryPos; + bool entryStillValid; + uint8_t aliasCheckSum = 0; + char alias [MAX_ALIAS_LENGTH]; + int aliasLen; + int lfnLen; + + // Remove trailing spaces + for (i = strlen (entry->filename) - 1; (i >= 0) && (entry->filename[i] == ' '); --i) { + entry->filename[i] = '\0'; + } +#if 0 + // Remove leading spaces + for (i = 0; entry->filename[i] == ' '; ++i) ; + if (i > 0) { + memmove (entry->filename, entry->filename + i, strlen (entry->filename + i)); + } +#endif + + // Make sure the filename is not 0 length + if (strnlen (entry->filename, NAME_MAX) < 1) { + return false; + } + + // Make sure the filename is at least a valid LFN + lfnLen = _FAT_directory_lfnLength (entry->filename); + if (lfnLen < 0) { + return false; + } + + // Remove junk in filename + i = strlen (entry->filename); + memset (entry->filename + i, '\0', NAME_MAX - i); + + // Make sure the entry doesn't already exist + if (_FAT_directory_entryExists (partition, entry->filename, dirCluster)) { + return false; + } + + // Clear out alias, so we can generate a new one + memset (entry->entryData, ' ', 11); + + if ( strncmp(entry->filename, ".", NAME_MAX) == 0) { + // "." entry + entry->entryData[0] = '.'; + entrySize = 1; + } else if ( strncmp(entry->filename, "..", NAME_MAX) == 0) { + // ".." entry + entry->entryData[0] = '.'; + entry->entryData[1] = '.'; + entrySize = 1; + } else { + // Normal file name + aliasLen = _FAT_directory_createAlias (alias, entry->filename); + if (aliasLen < 0) { + return false; + } else if (aliasLen == 0) { + // It's a normal short filename + entrySize = 1; + } else { + // It's a long filename with an alias + entrySize = ((lfnLen + LFN_ENTRY_LENGTH - 1) / LFN_ENTRY_LENGTH) + 1; + + // Generate full alias for all cases except when the alias is simply an upper case version of the LFN + // and there isn't already a file with that name + if (strncasecmp (alias, entry->filename, MAX_ALIAS_LENGTH) != 0 || + _FAT_directory_entryExists (partition, alias, dirCluster)) + { + // expand primary part to 8 characters long by padding the end with underscores + i = 0; + j = MAX_ALIAS_PRI_LENGTH; + // Move extension to last 3 characters + while (alias[i] != '.' && alias[i] != '\0') i++; + if (i < j) { + memmove (alias + j, alias + i, aliasLen - i + 1); + // Pad primary component + memset (alias + i, '_', j - i); + } + // Generate numeric tail + for (i = 1; i <= MAX_NUMERIC_TAIL; i++) { + j = i; + tmpCharPtr = alias + MAX_ALIAS_PRI_LENGTH - 1; + while (j > 0) { + *tmpCharPtr = '0' + (j % 10); // ASCII numeric value + tmpCharPtr--; + j /= 10; + } + *tmpCharPtr = '~'; + if (!_FAT_directory_entryExists (partition, alias, dirCluster)) { + break; + } + } + if (i > MAX_NUMERIC_TAIL) { + // Couldn't get a valid alias + return false; + } + } + } + + // Copy alias or short file name into directory entry data + for (i = 0, j = 0; (j < 8) && (alias[i] != '.') && (alias[i] != '\0'); i++, j++) { + entry->entryData[j] = alias[i]; + } + while (j < 8) { + entry->entryData[j] = ' '; + ++ j; + } + if (alias[i] == '.') { + // Copy extension + ++ i; + while ((alias[i] != '\0') && (j < 11)) { + entry->entryData[j] = alias[i]; + ++ i; + ++ j; + } + } + while (j < 11) { + entry->entryData[j] = ' '; + ++ j; + } + + // Generate alias checksum + for (i=0; i < ALIAS_ENTRY_LENGTH; i++) { + // NOTE: The operation is an unsigned char rotate right + aliasCheckSum = ((aliasCheckSum & 1) ? 0x80 : 0) + (aliasCheckSum >> 1) + entry->entryData[i]; + } + } + + // Find or create space for the entry + if (_FAT_directory_findEntryGap (partition, entry, dirCluster, entrySize) == false) { + return false; + } + + // Write out directory entry + curEntryPos = entry->dataStart; + + { + // lfn is only pushed onto the stack here, reducing overall stack usage + ucs2_t lfn[MAX_LFN_LENGTH] = {0}; + _FAT_directory_mbstoucs2 (lfn, entry->filename, MAX_LFN_LENGTH); + + for (entryStillValid = true, i = entrySize; entryStillValid && i > 0; + entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &curEntryPos, false), -- i ) + { + if (i > 1) { + // Long filename entry + lfnEntry[LFN_offset_ordinal] = (i - 1) | ((size_t)i == entrySize ? LFN_END : 0); + for (j = 0; j < 13; j++) { + if (lfn [(i - 2) * 13 + j] == '\0') { + if ((j > 1) && (lfn [(i - 2) * 13 + (j-1)] == '\0')) { + u16_to_u8array (lfnEntry, LFN_offset_table[j], 0xffff); // Padding + } else { + u16_to_u8array (lfnEntry, LFN_offset_table[j], 0x0000); // Terminating null character + } + } else { + u16_to_u8array (lfnEntry, LFN_offset_table[j], lfn [(i - 2) * 13 + j]); + } + } + + lfnEntry[LFN_offset_checkSum] = aliasCheckSum; + lfnEntry[LFN_offset_flag] = ATTRIB_LFN; + lfnEntry[LFN_offset_reserved1] = 0; + u16_to_u8array (lfnEntry, LFN_offset_reserved2, 0); + _FAT_cache_writePartialSector (partition->cache, lfnEntry, _FAT_fat_clusterToSector(partition, curEntryPos.cluster) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + } else { + // Alias & file data + _FAT_cache_writePartialSector (partition->cache, entry->entryData, _FAT_fat_clusterToSector(partition, curEntryPos.cluster) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + } + } + } + + return true; +} + +bool _FAT_directory_chdir (PARTITION* partition, const char* path) { + DIR_ENTRY entry; + + if (!_FAT_directory_entryFromPath (partition, &entry, path, NULL)) { + return false; + } + + if (!(entry.entryData[DIR_ENTRY_attributes] & ATTRIB_DIR)) { + return false; + } + + partition->cwdCluster = _FAT_directory_entryGetCluster (partition, entry.entryData); + + return true; +} + +void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st) { + // Fill in the stat struct + // Some of the values are faked for the sake of compatibility + st->st_dev = _FAT_disc_hostType(partition->disc); // The device is the 32bit ioType value + st->st_ino = (ino_t)(_FAT_directory_entryGetCluster(partition, entry->entryData)); // The file serial number is the start cluster + st->st_mode = (_FAT_directory_isDirectory(entry) ? S_IFDIR : S_IFREG) | + (S_IRUSR | S_IRGRP | S_IROTH) | + (_FAT_directory_isWritable (entry) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0); // Mode bits based on dirEntry ATTRIB byte + st->st_nlink = 1; // Always one hard link on a FAT file + st->st_uid = 1; // Faked for FAT + st->st_gid = 2; // Faked for FAT + st->st_rdev = st->st_dev; + st->st_size = u8array_to_u32 (entry->entryData, DIR_ENTRY_fileSize); // File size + st->st_atime = _FAT_filetime_to_time_t ( + 0, + u8array_to_u16 (entry->entryData, DIR_ENTRY_aDate) + ); + st->st_spare1 = 0; + st->st_mtime = _FAT_filetime_to_time_t ( + u8array_to_u16 (entry->entryData, DIR_ENTRY_mTime), + u8array_to_u16 (entry->entryData, DIR_ENTRY_mDate) + ); + st->st_spare2 = 0; + st->st_ctime = _FAT_filetime_to_time_t ( + u8array_to_u16 (entry->entryData, DIR_ENTRY_cTime), + u8array_to_u16 (entry->entryData, DIR_ENTRY_cDate) + ); + st->st_spare3 = 0; + st->st_blksize = partition->bytesPerSector; // Prefered file I/O block size + st->st_blocks = (st->st_size + partition->bytesPerSector - 1) / partition->bytesPerSector; // File size in blocks + st->st_spare4[0] = 0; + st->st_spare4[1] = 0; +} diff --git a/wii/libogc/libfat/directory.h b/wii/libogc/libfat/directory.h new file mode 100644 index 0000000000..9f7af8ed35 --- /dev/null +++ b/wii/libogc/libfat/directory.h @@ -0,0 +1,181 @@ +/* + directory.h + Reading, writing and manipulation of the directory structure on + a FAT partition + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _DIRECTORY_H +#define _DIRECTORY_H + +#include +#include + +#include "common.h" +#include "partition.h" + +#define DIR_ENTRY_DATA_SIZE 0x20 +#define MAX_LFN_LENGTH 256 +#define MAX_ALIAS_LENGTH 13 +#define LFN_ENTRY_LENGTH 13 +#define ALIAS_ENTRY_LENGTH 11 +#define MAX_ALIAS_EXT_LENGTH 3 +#define MAX_ALIAS_PRI_LENGTH 8 +#define MAX_NUMERIC_TAIL 999999 +#define FAT16_ROOT_DIR_CLUSTER 0 + +#define DIR_SEPARATOR '/' + +// File attributes +#define ATTRIB_ARCH 0x20 // Archive +#define ATTRIB_DIR 0x10 // Directory +#define ATTRIB_LFN 0x0F // Long file name +#define ATTRIB_VOL 0x08 // Volume +#define ATTRIB_SYS 0x04 // System +#define ATTRIB_HID 0x02 // Hidden +#define ATTRIB_RO 0x01 // Read only + +#define CASE_LOWER_EXT 0x10 // WinNT lowercase extension +#define CASE_LOWER_BASE 0x08 // WinNT lowercase basename + +typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE; + +typedef struct { + uint32_t cluster; + sec_t sector; + int32_t offset; +} DIR_ENTRY_POSITION; + +typedef struct { + uint8_t entryData[DIR_ENTRY_DATA_SIZE]; + DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN + DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry + char filename[NAME_MAX]; +} DIR_ENTRY; + +// Directory entry offsets +enum DIR_ENTRY_offset { + DIR_ENTRY_name = 0x00, + DIR_ENTRY_extension = 0x08, + DIR_ENTRY_attributes = 0x0B, + DIR_ENTRY_caseInfo = 0x0C, + DIR_ENTRY_cTime_ms = 0x0D, + DIR_ENTRY_cTime = 0x0E, + DIR_ENTRY_cDate = 0x10, + DIR_ENTRY_aDate = 0x12, + DIR_ENTRY_clusterHigh = 0x14, + DIR_ENTRY_mTime = 0x16, + DIR_ENTRY_mDate = 0x18, + DIR_ENTRY_cluster = 0x1A, + DIR_ENTRY_fileSize = 0x1C +}; + +/* +Returns true if the file specified by entry is a directory +*/ +static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) { + return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) != 0); +} + +static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) { + return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO) == 0); +} + +static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) { + return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') || + ((entry->filename[1] == '.') && entry->filename[2] == '\0'))); +} + +/* +Reads the first directory entry from the directory starting at dirCluster +Places result in entry +entry will be destroyed even if no directory entry is found +Returns true on success, false on failure +*/ +bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster); + +/* +Reads the next directory entry after the one already pointed to by entry +Places result in entry +entry will be destroyed even if no directory entry is found +Returns true on success, false on failure +*/ +bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry); + +/* +Gets the directory entry corrsponding to the supplied path +entry will be destroyed even if no directory entry is found +pathEnd specifies the end of the path string, for cutting strings short if needed + specify NULL to use the full length of path + pathEnd is only a suggestion, and the path string will be searched up until the next PATH_SEPARATOR + after pathEND. +Returns true on success, false on failure +*/ +bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd); + +/* +Changes the current directory to the one specified by path +Returns true on success, false on failure +*/ +bool _FAT_directory_chdir (PARTITION* partition, const char* path); + +/* +Removes the directory entry specified by entry +Assumes that entry is valid +Returns true on success, false on failure +*/ +bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry); + +/* +Add a directory entry to the directory specified by dirCluster +The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are +updated with the new directory entry position and alias. +Returns true on success, false on failure +*/ +bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster); + +/* +Get the start cluster of a file from it's entry data +*/ +uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData); + +/* +Fill in the file name and entry data of DIR_ENTRY* entry. +Assumes that the entry's dataStart and dataEnd are correct +Returns true on success, false on failure +*/ +bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry); + +/* +Fill in a stat struct based on a file entry +*/ +void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st); + +/* +Get volume label +*/ +bool _FAT_directory_getVolumeLabel (PARTITION* partition, char *label); + +#endif // _DIRECTORY_H diff --git a/wii/libogc/libfat/disc.c b/wii/libogc/libfat/disc.c new file mode 100644 index 0000000000..d27da2a099 --- /dev/null +++ b/wii/libogc/libfat/disc.c @@ -0,0 +1,112 @@ +/* + disc.c + Interface to the low level disc functions. Used by the higher level + file system code. + + Copyright (c) 2008 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "disc.h" + +/* +The list of interfaces consists of a series of name/interface pairs. +The interface is returned via a simple function. This allows for +platforms where the interface has to be "assembled" before it can +be used, like DLDI on the NDS. For cases where a simple struct +is available, wrapper functions are used. +The list is terminated by a NULL/NULL entry. +*/ + +/* ====================== Wii ====================== */ +#if defined (__wii__) +#include +#include +#include + +static const DISC_INTERFACE* get_io_wiisd (void) { + return &__io_wiisd; +} +static const DISC_INTERFACE* get_io_usbstorage (void) { + return &__io_usbstorage; +} + +static const DISC_INTERFACE* get_io_gcsda (void) { + return &__io_gcsda; +} + +static const DISC_INTERFACE* get_io_gcsdb (void) { + return &__io_gcsdb; +} + +const INTERFACE_ID _FAT_disc_interfaces[] = { + {"sd", get_io_wiisd}, + {"usb", get_io_usbstorage}, + {"carda", get_io_gcsda}, + {"cardb", get_io_gcsdb}, + {NULL, NULL} +}; + +/* ==================== Gamecube ==================== */ +#elif defined (__gamecube__) +#include + +static const DISC_INTERFACE* get_io_gcsda (void) { + return &__io_gcsda; +} +static const DISC_INTERFACE* get_io_gcsdb (void) { + return &__io_gcsdb; +} + +const INTERFACE_ID _FAT_disc_interfaces[] = { + {"carda", get_io_gcsda}, + {"cardb", get_io_gcsdb}, + {NULL, NULL} +}; + +/* ====================== NDS ====================== */ +#elif defined (NDS) +#include +#include + +static const DISC_INTERFACE* get_io_dsisd (void) { + return isDSiMode() ? &__io_dsisd : NULL; +} + +const INTERFACE_ID _FAT_disc_interfaces[] = { + {"sd", get_io_dsisd}, + {"fat", dldiGetInternal}, + {NULL, NULL} +}; + +/* ====================== GBA ====================== */ +#elif defined (GBA) +#include + +const INTERFACE_ID _FAT_disc_interfaces[] = { + {"fat", discGetInterface}, + {NULL, NULL} +}; + +#endif + diff --git a/wii/libogc/libfat/disc.h b/wii/libogc/libfat/disc.h new file mode 100644 index 0000000000..5c955f90ae --- /dev/null +++ b/wii/libogc/libfat/disc.h @@ -0,0 +1,110 @@ +/* + disc.h + Interface to the low level disc functions. Used by the higher level + file system code. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _DISC_H +#define _DISC_H + +#include "common.h" + +/* +A list of all default devices to try at startup, +terminated by a {NULL,NULL} entry. +*/ +typedef struct { + const char* name; + const DISC_INTERFACE* (*getInterface)(void); +} INTERFACE_ID; +extern const INTERFACE_ID _FAT_disc_interfaces[]; + +/* +Check if a disc is inserted +Return true if a disc is inserted and ready, false otherwise +*/ +static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) { + return disc->isInserted(); +} + +/* +Read numSectors sectors from a disc, starting at sector. +numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined, +else it is at least 1 +sector is 0 or greater +buffer is a pointer to the memory to fill +*/ +static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) { + return disc->readSectors (sector, numSectors, buffer); +} + +/* +Write numSectors sectors to a disc, starting at sector. +numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined, +else it is at least 1 +sector is 0 or greater +buffer is a pointer to the memory to read from +*/ +static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) { + return disc->writeSectors (sector, numSectors, buffer); +} + +/* +Reset the card back to a ready state +*/ +static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) { + return disc->clearStatus(); +} + +/* +Initialise the disc to a state ready for data reading or writing +*/ +static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) { + return disc->startup(); +} + +/* +Put the disc in a state ready for power down. +Complete any pending writes and disable the disc if necessary +*/ +static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) { + return disc->shutdown(); +} + +/* +Return a 32 bit value unique to each type of interface +*/ +static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) { + return disc->ioType; +} + +/* +Return a 32 bit value that specifies the capabilities of the disc +*/ +static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) { + return disc->features; +} + +#endif // _DISC_H diff --git a/wii/libogc/libfat/fatdir.c b/wii/libogc/libfat/fatdir.c new file mode 100644 index 0000000000..1ef5aec6d5 --- /dev/null +++ b/wii/libogc/libfat/fatdir.c @@ -0,0 +1,615 @@ +/* + fatdir.c + + Functions used by the newlib disc stubs to interface with + this library + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +#include "fatdir.h" + +#include "cache.h" +#include "file_allocation_table.h" +#include "partition.h" +#include "directory.h" +#include "bit_ops.h" +#include "filetime.h" +#include "lock.h" + + +int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) { + PARTITION* partition = NULL; + DIR_ENTRY dirEntry; + + // Get the partition this file is on + partition = _FAT_partition_getPartitionFromPath (path); + if (partition == NULL) { + r->_errno = ENODEV; + return -1; + } + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + r->_errno = EINVAL; + return -1; + } + + _FAT_lock(&partition->lock); + + // Search for the file on the disc + if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOENT; + return -1; + } + + // Fill in the stat struct + _FAT_directory_entryStat (partition, &dirEntry, st); + + _FAT_unlock(&partition->lock); + return 0; +} + +int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink) { + r->_errno = ENOTSUP; + return -1; +} + +int _FAT_unlink_r (struct _reent *r, const char *path) { + PARTITION* partition = NULL; + DIR_ENTRY dirEntry; + DIR_ENTRY dirContents; + uint32_t cluster; + bool nextEntry; + bool errorOccured = false; + + // Get the partition this directory is on + partition = _FAT_partition_getPartitionFromPath (path); + if (partition == NULL) { + r->_errno = ENODEV; + return -1; + } + + // Make sure we aren't trying to write to a read-only disc + if (partition->readOnly) { + r->_errno = EROFS; + return -1; + } + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + r->_errno = EINVAL; + return -1; + } + + _FAT_lock(&partition->lock); + + // Search for the file on the disc + if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOENT; + return -1; + } + + cluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData); + + + // If this is a directory, make sure it is empty + if (_FAT_directory_isDirectory (&dirEntry)) { + nextEntry = _FAT_directory_getFirstEntry (partition, &dirContents, cluster); + + while (nextEntry) { + if (!_FAT_directory_isDot (&dirContents)) { + // The directory had something in it that isn't a reference to itself or it's parent + _FAT_unlock(&partition->lock); + r->_errno = ENOTEMPTY; + return -1; + } + nextEntry = _FAT_directory_getNextEntry (partition, &dirContents); + } + } + + if (_FAT_fat_isValidCluster(partition, cluster)) { + // Remove the cluster chain for this file + if (!_FAT_fat_clearLinks (partition, cluster)) { + r->_errno = EIO; + errorOccured = true; + } + } + + // Remove the directory entry for this file + if (!_FAT_directory_removeEntry (partition, &dirEntry)) { + r->_errno = EIO; + errorOccured = true; + } + + // Flush any sectors in the disc cache + if (!_FAT_cache_flush(partition->cache)) { + r->_errno = EIO; + errorOccured = true; + } + + _FAT_unlock(&partition->lock); + if (errorOccured) { + return -1; + } else { + return 0; + } +} + +int _FAT_chdir_r (struct _reent *r, const char *path) { + PARTITION* partition = NULL; + + // Get the partition this directory is on + partition = _FAT_partition_getPartitionFromPath (path); + if (partition == NULL) { + r->_errno = ENODEV; + return -1; + } + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + r->_errno = EINVAL; + return -1; + } + + _FAT_lock(&partition->lock); + + // Try changing directory + if (_FAT_directory_chdir (partition, path)) { + // Successful + _FAT_unlock(&partition->lock); + return 0; + } else { + // Failed + _FAT_unlock(&partition->lock); + r->_errno = ENOTDIR; + return -1; + } +} + +int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) { + PARTITION* partition = NULL; + DIR_ENTRY oldDirEntry; + DIR_ENTRY newDirEntry; + const char *pathEnd; + uint32_t dirCluster; + + // Get the partition this directory is on + partition = _FAT_partition_getPartitionFromPath (oldName); + if (partition == NULL) { + r->_errno = ENODEV; + return -1; + } + + _FAT_lock(&partition->lock); + + // Make sure the same partition is used for the old and new names + if (partition != _FAT_partition_getPartitionFromPath (newName)) { + _FAT_unlock(&partition->lock); + r->_errno = EXDEV; + return -1; + } + + // Make sure we aren't trying to write to a read-only disc + if (partition->readOnly) { + _FAT_unlock(&partition->lock); + r->_errno = EROFS; + return -1; + } + + // Move the path pointer to the start of the actual path + if (strchr (oldName, ':') != NULL) { + oldName = strchr (oldName, ':') + 1; + } + if (strchr (oldName, ':') != NULL) { + _FAT_unlock(&partition->lock); + r->_errno = EINVAL; + return -1; + } + if (strchr (newName, ':') != NULL) { + newName = strchr (newName, ':') + 1; + } + if (strchr (newName, ':') != NULL) { + _FAT_unlock(&partition->lock); + r->_errno = EINVAL; + return -1; + } + + // Search for the file on the disc + if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOENT; + return -1; + } + + // Make sure there is no existing file / directory with the new name + if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL)) { + _FAT_unlock(&partition->lock); + r->_errno = EEXIST; + return -1; + } + + // Create the new file entry + // Get the directory it has to go in + pathEnd = strrchr (newName, DIR_SEPARATOR); + if (pathEnd == NULL) { + // No path was specified + dirCluster = partition->cwdCluster; + pathEnd = newName; + } else { + // Path was specified -- get the right dirCluster + // Recycling newDirEntry, since it needs to be recreated anyway + if (!_FAT_directory_entryFromPath (partition, &newDirEntry, newName, pathEnd) || + !_FAT_directory_isDirectory(&newDirEntry)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOTDIR; + return -1; + } + dirCluster = _FAT_directory_entryGetCluster (partition, newDirEntry.entryData); + // Move the pathEnd past the last DIR_SEPARATOR + pathEnd += 1; + } + + // Copy the entry data + memcpy (&newDirEntry, &oldDirEntry, sizeof(DIR_ENTRY)); + + // Set the new name + strncpy (newDirEntry.filename, pathEnd, NAME_MAX - 1); + + // Write the new entry + if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOSPC; + return -1; + } + + // Remove the old entry + if (!_FAT_directory_removeEntry (partition, &oldDirEntry)) { + _FAT_unlock(&partition->lock); + r->_errno = EIO; + return -1; + } + + // Flush any sectors in the disc cache + if (!_FAT_cache_flush (partition->cache)) { + _FAT_unlock(&partition->lock); + r->_errno = EIO; + return -1; + } + + _FAT_unlock(&partition->lock); + return 0; +} + +int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { + PARTITION* partition = NULL; + bool fileExists; + DIR_ENTRY dirEntry; + const char* pathEnd; + uint32_t parentCluster, dirCluster; + uint8_t newEntryData[DIR_ENTRY_DATA_SIZE]; + + partition = _FAT_partition_getPartitionFromPath (path); + if (partition == NULL) { + r->_errno = ENODEV; + return -1; + } + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + r->_errno = EINVAL; + return -1; + } + + _FAT_lock(&partition->lock); + + // Search for the file/directory on the disc + fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL); + + // Make sure it doesn't exist + if (fileExists) { + _FAT_unlock(&partition->lock); + r->_errno = EEXIST; + return -1; + } + + if (partition->readOnly) { + // We can't write to a read-only partition + _FAT_unlock(&partition->lock); + r->_errno = EROFS; + return -1; + } + + // Get the directory it has to go in + pathEnd = strrchr (path, DIR_SEPARATOR); + if (pathEnd == NULL) { + // No path was specified + parentCluster = partition->cwdCluster; + pathEnd = path; + } else { + // Path was specified -- get the right parentCluster + // Recycling dirEntry, since it needs to be recreated anyway + if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) || + !_FAT_directory_isDirectory(&dirEntry)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOTDIR; + return -1; + } + parentCluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData); + // Move the pathEnd past the last DIR_SEPARATOR + pathEnd += 1; + } + // Create the entry data + strncpy (dirEntry.filename, pathEnd, NAME_MAX - 1); + memset (dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE); + + // Set the creation time and date + dirEntry.entryData[DIR_ENTRY_cTime_ms] = 0; + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cTime, _FAT_filetime_getTimeFromRTC()); + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC()); + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mTime, _FAT_filetime_getTimeFromRTC()); + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mDate, _FAT_filetime_getDateFromRTC()); + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_aDate, _FAT_filetime_getDateFromRTC()); + + // Set the directory attribute + dirEntry.entryData[DIR_ENTRY_attributes] = ATTRIB_DIR; + + // Get a cluster for the new directory + dirCluster = _FAT_fat_linkFreeClusterCleared (partition, CLUSTER_FREE); + if (!_FAT_fat_isValidCluster(partition, dirCluster)) { + // No space left on disc for the cluster + _FAT_unlock(&partition->lock); + r->_errno = ENOSPC; + return -1; + } + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cluster, dirCluster); + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16); + + // Write the new directory's entry to it's parent + if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOSPC; + return -1; + } + + // Create the dot entry within the directory + memset (newEntryData, 0, DIR_ENTRY_DATA_SIZE); + memset (newEntryData, ' ', 11); + newEntryData[DIR_ENTRY_name] = '.'; + newEntryData[DIR_ENTRY_attributes] = ATTRIB_DIR; + u16_to_u8array (newEntryData, DIR_ENTRY_cluster, dirCluster); + u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16); + + // Write it to the directory, erasing that sector in the process + _FAT_cache_eraseWritePartialSector ( partition->cache, newEntryData, + _FAT_fat_clusterToSector (partition, dirCluster), 0, DIR_ENTRY_DATA_SIZE); + + + // Create the double dot entry within the directory + + // if ParentDir == Rootdir then ".."" always link to Cluster 0 + if(parentCluster == partition->rootDirCluster) + parentCluster = FAT16_ROOT_DIR_CLUSTER; + + newEntryData[DIR_ENTRY_name + 1] = '.'; + u16_to_u8array (newEntryData, DIR_ENTRY_cluster, parentCluster); + u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16); + + // Write it to the directory + _FAT_cache_writePartialSector ( partition->cache, newEntryData, + _FAT_fat_clusterToSector (partition, dirCluster), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + + // Flush any sectors in the disc cache + if (!_FAT_cache_flush(partition->cache)) { + _FAT_unlock(&partition->lock); + r->_errno = EIO; + return -1; + } + + _FAT_unlock(&partition->lock); + return 0; +} + +int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) +{ + PARTITION* partition = NULL; + unsigned int freeClusterCount; + + // Get the partition of the requested path + partition = _FAT_partition_getPartitionFromPath (path); + if (partition == NULL) { + r->_errno = ENODEV; + return -1; + } + + _FAT_lock(&partition->lock); + + if(partition->filesysType == FS_FAT32) { + // Sync FSinfo block + _FAT_partition_readFSinfo(partition); + freeClusterCount = partition->fat.numberFreeCluster; + } else { + freeClusterCount = _FAT_fat_freeClusterCount (partition); + } + + // FAT clusters = POSIX blocks + buf->f_bsize = partition->bytesPerCluster; // File system block size. + buf->f_frsize = partition->bytesPerCluster; // Fundamental file system block size. + + buf->f_blocks = partition->fat.lastCluster - CLUSTER_FIRST + 1; // Total number of blocks on file system in units of f_frsize. + buf->f_bfree = freeClusterCount; // Total number of free blocks. + buf->f_bavail = freeClusterCount; // Number of free blocks available to non-privileged process. + + // Treat requests for info on inodes as clusters + buf->f_files = partition->fat.lastCluster - CLUSTER_FIRST + 1; // Total number of file serial numbers. + buf->f_ffree = freeClusterCount; // Total number of free file serial numbers. + buf->f_favail = freeClusterCount; // Number of file serial numbers available to non-privileged process. + + // File system ID. 32bit ioType value + buf->f_fsid = _FAT_disc_hostType(partition->disc); + + // Bit mask of f_flag values. + buf->f_flag = ST_NOSUID /* No support for ST_ISUID and ST_ISGID file mode bits */ + | (partition->readOnly ? ST_RDONLY /* Read only file system */ : 0 ) ; + // Maximum filename length. + buf->f_namemax = NAME_MAX; + + _FAT_unlock(&partition->lock); + return 0; +} + +DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) { + DIR_ENTRY dirEntry; + DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); + bool fileExists; + + state->partition = _FAT_partition_getPartitionFromPath (path); + if (state->partition == NULL) { + r->_errno = ENODEV; + return NULL; + } + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + r->_errno = EINVAL; + return NULL; + } + + _FAT_lock(&state->partition->lock); + + // Get the start cluster of the directory + fileExists = _FAT_directory_entryFromPath (state->partition, &dirEntry, path, NULL); + + if (!fileExists) { + _FAT_unlock(&state->partition->lock); + r->_errno = ENOENT; + return NULL; + } + + // Make sure it is a directory + if (! _FAT_directory_isDirectory (&dirEntry)) { + _FAT_unlock(&state->partition->lock); + r->_errno = ENOTDIR; + return NULL; + } + + // Save the start cluster for use when resetting the directory data + state->startCluster = _FAT_directory_entryGetCluster (state->partition, dirEntry.entryData); + + // Get the first entry for use with a call to dirnext + state->validEntry = + _FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster); + + // We are now using this entry + state->inUse = true; + _FAT_unlock(&state->partition->lock); + return (DIR_ITER*) state; +} + +int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) { + DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); + + _FAT_lock(&state->partition->lock); + + // Make sure we are still using this entry + if (!state->inUse) { + _FAT_unlock(&state->partition->lock); + r->_errno = EBADF; + return -1; + } + + // Get the first entry for use with a call to dirnext + state->validEntry = + _FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster); + + _FAT_unlock(&state->partition->lock); + return 0; +} + +int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) { + DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); + + _FAT_lock(&state->partition->lock); + + // Make sure we are still using this entry + if (!state->inUse) { + _FAT_unlock(&state->partition->lock); + r->_errno = EBADF; + return -1; + } + + // Make sure there is another file to report on + if (! state->validEntry) { + _FAT_unlock(&state->partition->lock); + return -1; + } + + // Get the filename + strncpy (filename, state->currentEntry.filename, NAME_MAX); + // Get the stats, if requested + if (filestat != NULL) { + _FAT_directory_entryStat (state->partition, &(state->currentEntry), filestat); + } + + // Look for the next entry for use next time + state->validEntry = + _FAT_directory_getNextEntry (state->partition, &(state->currentEntry)); + + _FAT_unlock(&state->partition->lock); + return 0; +} + +int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState) { + DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); + + // We are no longer using this entry + _FAT_lock(&state->partition->lock); + state->inUse = false; + _FAT_unlock(&state->partition->lock); + + return 0; +} diff --git a/wii/libogc/libfat/fatdir.h b/wii/libogc/libfat/fatdir.h new file mode 100644 index 0000000000..426dd30bcd --- /dev/null +++ b/wii/libogc/libfat/fatdir.h @@ -0,0 +1,73 @@ +/* + fatdir.h + + Functions used by the newlib disc stubs to interface with + this library + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef _FATDIR_H +#define _FATDIR_H + +#include +#include +#include +#include +#include "common.h" +#include "directory.h" + +typedef struct { + PARTITION* partition; + DIR_ENTRY currentEntry; + uint32_t startCluster; + bool inUse; + bool validEntry; +} DIR_STATE_STRUCT; + +extern int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st); + +extern int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink); + +extern int _FAT_unlink_r (struct _reent *r, const char *name); + +extern int _FAT_chdir_r (struct _reent *r, const char *name); + +extern int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName); + +extern int _FAT_mkdir_r (struct _reent *r, const char *path, int mode); + +extern int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf); + +/* +Directory iterator functions +*/ +extern DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path); +extern int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState); +extern int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat); +extern int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState); + + +#endif // _FATDIR_H diff --git a/wii/libogc/libfat/fatfile.c b/wii/libogc/libfat/fatfile.c new file mode 100644 index 0000000000..06c2ca7c1e --- /dev/null +++ b/wii/libogc/libfat/fatfile.c @@ -0,0 +1,1213 @@ +/* + fatfile.c + + Functions used by the newlib disc stubs to interface with + this library + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + 2009-10-23 oggzee: fixes for cluster aligned file size (write, truncate, seek) +*/ + + +#include "fatfile.h" + +#include +#include +#include +#include +#include + +#include "cache.h" +#include "file_allocation_table.h" +#include "bit_ops.h" +#include "filetime.h" +#include "lock.h" + +bool _FAT_findEntry(const char *path, DIR_ENTRY *dirEntry) { + PARTITION *partition = _FAT_partition_getPartitionFromPath(path); + + // Check Partition + if( !partition ) + return false; + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + return false; + } + + // Search for the file on the disc + return _FAT_directory_entryFromPath (partition, dirEntry, path, NULL); + +} + +int FAT_getAttr(const char *file) { + DIR_ENTRY dirEntry; + if (!_FAT_findEntry(file,&dirEntry)) return -1; + + return dirEntry.entryData[DIR_ENTRY_attributes]; +} + +int FAT_setAttr(const char *file, uint8_t attr) { + + // Defines... + DIR_ENTRY_POSITION entryEnd; + PARTITION *partition = NULL; + DIR_ENTRY dirEntry; + + // Get Partition + partition = _FAT_partition_getPartitionFromPath( file ); + + // Check Partition + if( !partition ) + return -1; + + // Move the path pointer to the start of the actual path + if (strchr (file, ':') != NULL) + file = strchr (file, ':') + 1; + if (strchr (file, ':') != NULL) + return -1; + + // Get DIR_ENTRY + if( !_FAT_directory_entryFromPath (partition, &dirEntry, file, NULL) ) + return -1; + + // Get Entry-End + entryEnd = dirEntry.dataEnd; + + // Lock Partition + _FAT_lock(&partition->lock); + + + // Write Data + _FAT_cache_writePartialSector ( + partition->cache // Cache to write + , &attr // Value to be written + , _FAT_fat_clusterToSector( partition , entryEnd.cluster ) + entryEnd.sector // cluster + , entryEnd.offset * DIR_ENTRY_DATA_SIZE + DIR_ENTRY_attributes // offset + , 1 // Size in bytes + ); + + // Flush any sectors in the disc cache + if ( !_FAT_cache_flush( partition->cache ) ) { + _FAT_unlock(&partition->lock); // Unlock Partition + return -1; + } + + // Unlock Partition + _FAT_unlock(&partition->lock); + + return 0; +} + + +int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { + PARTITION* partition = NULL; + bool fileExists; + DIR_ENTRY dirEntry; + const char* pathEnd; + uint32_t dirCluster; + FILE_STRUCT* file = (FILE_STRUCT*) fileStruct; + partition = _FAT_partition_getPartitionFromPath (path); + + if (partition == NULL) { + r->_errno = ENODEV; + return -1; + } + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + r->_errno = EINVAL; + return -1; + } + + // Determine which mode the file is openned for + if ((flags & 0x03) == O_RDONLY) { + // Open the file for read-only access + file->read = true; + file->write = false; + file->append = false; + } else if ((flags & 0x03) == O_WRONLY) { + // Open file for write only access + file->read = false; + file->write = true; + file->append = false; + } else if ((flags & 0x03) == O_RDWR) { + // Open file for read/write access + file->read = true; + file->write = true; + file->append = false; + } else { + r->_errno = EACCES; + return -1; + } + + // Make sure we aren't trying to write to a read-only disc + if (file->write && partition->readOnly) { + r->_errno = EROFS; + return -1; + } + + // Search for the file on the disc + _FAT_lock(&partition->lock); + fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL); + + // The file shouldn't exist if we are trying to create it + if ((flags & O_CREAT) && (flags & O_EXCL) && fileExists) { + _FAT_unlock(&partition->lock); + r->_errno = EEXIST; + return -1; + } + + // It should not be a directory if we're openning a file, + if (fileExists && _FAT_directory_isDirectory(&dirEntry)) { + _FAT_unlock(&partition->lock); + r->_errno = EISDIR; + return -1; + } + + // We haven't modified the file yet + file->modified = false; + + // If the file doesn't exist, create it if we're allowed to + if (!fileExists) { + if (flags & O_CREAT) { + if (partition->readOnly) { + // We can't write to a read-only partition + _FAT_unlock(&partition->lock); + r->_errno = EROFS; + return -1; + } + // Create the file + // Get the directory it has to go in + pathEnd = strrchr (path, DIR_SEPARATOR); + if (pathEnd == NULL) { + // No path was specified + dirCluster = partition->cwdCluster; + pathEnd = path; + } else { + // Path was specified -- get the right dirCluster + // Recycling dirEntry, since it needs to be recreated anyway + if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) || + !_FAT_directory_isDirectory(&dirEntry)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOTDIR; + return -1; + } + dirCluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData); + // Move the pathEnd past the last DIR_SEPARATOR + pathEnd += 1; + } + // Create the entry data + strncpy (dirEntry.filename, pathEnd, NAME_MAX - 1); + memset (dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE); + + // Set the creation time and date + dirEntry.entryData[DIR_ENTRY_cTime_ms] = 0; + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cTime, _FAT_filetime_getTimeFromRTC()); + u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC()); + + if (!_FAT_directory_addEntry (partition, &dirEntry, dirCluster)) { + _FAT_unlock(&partition->lock); + r->_errno = ENOSPC; + return -1; + } + + // File entry is modified + file->modified = true; + } else { + // file doesn't exist, and we aren't creating it + _FAT_unlock(&partition->lock); + r->_errno = ENOENT; + return -1; + } + } + + file->filesize = u8array_to_u32 (dirEntry.entryData, DIR_ENTRY_fileSize); + + /* Allow LARGEFILEs with undefined results + // Make sure that the file size can fit in the available space + if (!(flags & O_LARGEFILE) && (file->filesize >= (1<<31))) { + r->_errno = EFBIG; + return -1; + } + */ + + // Make sure we aren't trying to write to a read-only file + if (file->write && !_FAT_directory_isWritable(&dirEntry)) { + _FAT_unlock(&partition->lock); + r->_errno = EROFS; + return -1; + } + + // Associate this file with a particular partition + file->partition = partition; + + file->startCluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData); + + // Truncate the file if requested + if ((flags & O_TRUNC) && file->write && (file->startCluster != 0)) { + _FAT_fat_clearLinks (partition, file->startCluster); + file->startCluster = CLUSTER_FREE; + file->filesize = 0; + // File is modified since we just cut it all off + file->modified = true; + } + + // Remember the position of this file's directory entry + file->dirEntryStart = dirEntry.dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN + file->dirEntryEnd = dirEntry.dataEnd; + + // Reset read/write pointer + file->currentPosition = 0; + file->rwPosition.cluster = file->startCluster; + file->rwPosition.sector = 0; + file->rwPosition.byte = 0; + + if (flags & O_APPEND) { + file->append = true; + + // Set append pointer to the end of the file + file->appendPosition.cluster = _FAT_fat_lastCluster (partition, file->startCluster); + file->appendPosition.sector = (file->filesize % partition->bytesPerCluster) / partition->bytesPerSector; + file->appendPosition.byte = file->filesize % partition->bytesPerSector; + + // Check if the end of the file is on the end of a cluster + if ( (file->filesize > 0) && ((file->filesize % partition->bytesPerCluster)==0) ){ + // Set flag to allocate a new cluster + file->appendPosition.sector = partition->sectorsPerCluster; + file->appendPosition.byte = 0; + } + } else { + file->append = false; + // Use something sane for the append pointer, so the whole file struct contains known values + file->appendPosition = file->rwPosition; + } + + file->inUse = true; + + // Insert this file into the double-linked list of open files + partition->openFileCount += 1; + if (partition->firstOpenFile) { + file->nextOpenFile = partition->firstOpenFile; + partition->firstOpenFile->prevOpenFile = file; + } else { + file->nextOpenFile = NULL; + } + file->prevOpenFile = NULL; + partition->firstOpenFile = file; + + _FAT_unlock(&partition->lock); + + return (int) file; +} + +/* +Synchronizes the file data to disc. +Does no locking of its own -- lock the partition before calling. +Returns 0 on success, an error code on failure. +*/ +int _FAT_syncToDisc (FILE_STRUCT* file) { + uint8_t dirEntryData[DIR_ENTRY_DATA_SIZE]; + + if (!file || !file->inUse) { + return EBADF; + } + + if (file->write && file->modified) { + // Load the old entry + _FAT_cache_readPartialSector (file->partition->cache, dirEntryData, + _FAT_fat_clusterToSector(file->partition, file->dirEntryEnd.cluster) + file->dirEntryEnd.sector, + file->dirEntryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + + // Write new data to the directory entry + // File size + u32_to_u8array (dirEntryData, DIR_ENTRY_fileSize, file->filesize); + + // Start cluster + u16_to_u8array (dirEntryData, DIR_ENTRY_cluster, file->startCluster); + u16_to_u8array (dirEntryData, DIR_ENTRY_clusterHigh, file->startCluster >> 16); + + // Modification time and date + u16_to_u8array (dirEntryData, DIR_ENTRY_mTime, _FAT_filetime_getTimeFromRTC()); + u16_to_u8array (dirEntryData, DIR_ENTRY_mDate, _FAT_filetime_getDateFromRTC()); + + // Access date + u16_to_u8array (dirEntryData, DIR_ENTRY_aDate, _FAT_filetime_getDateFromRTC()); + + // Set archive attribute + dirEntryData[DIR_ENTRY_attributes] |= ATTRIB_ARCH; + + // Write the new entry + _FAT_cache_writePartialSector (file->partition->cache, dirEntryData, + _FAT_fat_clusterToSector(file->partition, file->dirEntryEnd.cluster) + file->dirEntryEnd.sector, + file->dirEntryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE); + + // Flush any sectors in the disc cache + if (!_FAT_cache_flush(file->partition->cache)) { + return EIO; + } + } + + file->modified = false; + + return 0; +} + + +int _FAT_close_r (struct _reent *r, void *fd) { + FILE_STRUCT* file = (FILE_STRUCT*) fd; + int ret = 0; + + if (!file->inUse) { + r->_errno = EBADF; + return -1; + } + + _FAT_lock(&file->partition->lock); + + if (file->write) { + ret = _FAT_syncToDisc (file); + if (ret != 0) { + r->_errno = ret; + ret = -1; + } + } + + file->inUse = false; + + // Remove this file from the double-linked list of open files + file->partition->openFileCount -= 1; + if (file->nextOpenFile) { + file->nextOpenFile->prevOpenFile = file->prevOpenFile; + } + if (file->prevOpenFile) { + file->prevOpenFile->nextOpenFile = file->nextOpenFile; + } else { + file->partition->firstOpenFile = file->nextOpenFile; + } + + _FAT_unlock(&file->partition->lock); + + return ret; +} + +ssize_t _FAT_read_r (struct _reent *r, void *fd, char *ptr, size_t len) { + FILE_STRUCT* file = (FILE_STRUCT*) fd; + PARTITION* partition; + CACHE* cache; + FILE_POSITION position; + uint32_t tempNextCluster; + unsigned int tempVar; + size_t remain; + bool flagNoError = true; + + // Short circuit cases where len is 0 (or less) + if (len <= 0) { + return 0; + } + + // Make sure we can actually read from the file + if ((file == NULL) || !file->inUse || !file->read) { + r->_errno = EBADF; + return -1; + } + + partition = file->partition; + _FAT_lock(&partition->lock); + + // Don't try to read if the read pointer is past the end of file + if (file->currentPosition >= file->filesize || file->startCluster == CLUSTER_FREE) { + r->_errno = EOVERFLOW; + _FAT_unlock(&partition->lock); + return 0; + } + + // Don't read past end of file + if (len + file->currentPosition > file->filesize) { + r->_errno = EOVERFLOW; + len = file->filesize - file->currentPosition; + } + + remain = len; + position = file->rwPosition; + cache = file->partition->cache; + + // Align to sector + tempVar = partition->bytesPerSector - position.byte; + if (tempVar > remain) { + tempVar = remain; + } + + if ((tempVar < partition->bytesPerSector) && flagNoError) + { + _FAT_cache_readPartialSector ( cache, ptr, _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, + position.byte, tempVar); + + remain -= tempVar; + ptr += tempVar; + + position.byte += tempVar; + if (position.byte >= partition->bytesPerSector) { + position.byte = 0; + position.sector++; + } + } + + // align to cluster + // tempVar is number of sectors to read + if (remain > (partition->sectorsPerCluster - position.sector) * partition->bytesPerSector) { + tempVar = partition->sectorsPerCluster - position.sector; + } else { + tempVar = remain / partition->bytesPerSector; + } + + if ((tempVar > 0) && flagNoError) { + if (! _FAT_cache_readSectors (cache, _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, + tempVar, ptr)) + { + flagNoError = false; + r->_errno = EIO; + } else { + ptr += tempVar * partition->bytesPerSector; + remain -= tempVar * partition->bytesPerSector; + position.sector += tempVar; + } + } + + // Move onto next cluster + // It should get to here without reading anything if a cluster is due to be allocated + if ((position.sector >= partition->sectorsPerCluster) && flagNoError) { + tempNextCluster = _FAT_fat_nextCluster(partition, position.cluster); + if ((remain == 0) && (tempNextCluster == CLUSTER_EOF)) { + position.sector = partition->sectorsPerCluster; + } else if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) { + r->_errno = EIO; + flagNoError = false; + } else { + position.sector = 0; + position.cluster = tempNextCluster; + } + } + + // Read in whole clusters, contiguous blocks at a time + while ((remain >= partition->bytesPerCluster) && flagNoError) { + uint32_t chunkEnd; + uint32_t nextChunkStart = position.cluster; + size_t chunkSize = 0; + + do { + chunkEnd = nextChunkStart; + nextChunkStart = _FAT_fat_nextCluster (partition, chunkEnd); + chunkSize += partition->bytesPerCluster; + } while ((nextChunkStart == chunkEnd + 1) && +#ifdef LIMIT_SECTORS + (chunkSize + partition->bytesPerCluster <= LIMIT_SECTORS * partition->bytesPerSector) && +#endif + (chunkSize + partition->bytesPerCluster <= remain)); + + if (!_FAT_cache_readSectors (cache, _FAT_fat_clusterToSector (partition, position.cluster), + chunkSize / partition->bytesPerSector, ptr)) + { + flagNoError = false; + r->_errno = EIO; + break; + } + ptr += chunkSize; + remain -= chunkSize; + + // Advance to next cluster + if ((remain == 0) && (nextChunkStart == CLUSTER_EOF)) { + position.sector = partition->sectorsPerCluster; + position.cluster = chunkEnd; + } else if (!_FAT_fat_isValidCluster(partition, nextChunkStart)) { + r->_errno = EIO; + flagNoError = false; + } else { + position.sector = 0; + position.cluster = nextChunkStart; + } + } + + // Read remaining sectors + tempVar = remain / partition->bytesPerSector; // Number of sectors left + if ((tempVar > 0) && flagNoError) { + if (!_FAT_cache_readSectors (cache, _FAT_fat_clusterToSector (partition, position.cluster), + tempVar, ptr)) + { + flagNoError = false; + r->_errno = EIO; + } else { + ptr += tempVar * partition->bytesPerSector; + remain -= tempVar * partition->bytesPerSector; + position.sector += tempVar; + } + } + + // Last remaining sector + // Check if anything is left + if ((remain > 0) && flagNoError) { + _FAT_cache_readPartialSector ( cache, ptr, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, 0, remain); + position.byte += remain; + remain = 0; + } + + // Length read is the wanted length minus the stuff not read + len = len - remain; + + // Update file information + file->rwPosition = position; + file->currentPosition += len; + + _FAT_unlock(&partition->lock); + return len; +} + +// if current position is on the cluster border and more data has to be written +// then get next cluster or allocate next cluster +// this solves the over-allocation problems when file size is aligned to cluster size +// return true on succes, false on error +static bool _FAT_check_position_for_next_cluster(struct _reent *r, + FILE_POSITION *position, PARTITION* partition, size_t remain, bool *flagNoError) +{ + uint32_t tempNextCluster; + // do nothing if no more data to write + if (remain == 0) return true; + if (flagNoError && *flagNoError == false) return false; + if (position->sector > partition->sectorsPerCluster) { + // invalid arguments - internal error + r->_errno = EINVAL; + goto err; + } + if (position->sector == partition->sectorsPerCluster) { + // need to advance to next cluster + tempNextCluster = _FAT_fat_nextCluster(partition, position->cluster); + if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE)) { + // Ran out of clusters so get a new one + tempNextCluster = _FAT_fat_linkFreeCluster(partition, position->cluster); + } + if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) { + // Couldn't get a cluster, so abort + r->_errno = ENOSPC; + goto err; + } + position->sector = 0; + position->cluster = tempNextCluster; + } + return true; +err: + if (flagNoError) *flagNoError = false; + return false; +} + +/* +Extend a file so that the size is the same as the rwPosition +*/ +static bool _FAT_file_extend_r (struct _reent *r, FILE_STRUCT* file) { + PARTITION* partition = file->partition; + CACHE* cache = file->partition->cache; + FILE_POSITION position; + uint8_t zeroBuffer [partition->bytesPerSector]; + memset(zeroBuffer, 0, partition->bytesPerSector); + uint32_t remain; + uint32_t tempNextCluster; + unsigned int sector; + + position.byte = file->filesize % partition->bytesPerSector; + position.sector = (file->filesize % partition->bytesPerCluster) / partition->bytesPerSector; + // It is assumed that there is always a startCluster + // This will be true when _FAT_file_extend_r is called from _FAT_write_r + position.cluster = _FAT_fat_lastCluster (partition, file->startCluster); + + remain = file->currentPosition - file->filesize; + + if ((remain > 0) && (file->filesize > 0) && (position.sector == 0) && (position.byte == 0)) { + // Get a new cluster on the edge of a cluster boundary + tempNextCluster = _FAT_fat_linkFreeCluster(partition, position.cluster); + if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) { + // Couldn't get a cluster, so abort + r->_errno = ENOSPC; + return false; + } + position.cluster = tempNextCluster; + position.sector = 0; + } + + if (remain + position.byte < partition->bytesPerSector) { + // Only need to clear to the end of the sector + _FAT_cache_writePartialSector (cache, zeroBuffer, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, position.byte, remain); + position.byte += remain; + } else { + if (position.byte > 0) { + _FAT_cache_writePartialSector (cache, zeroBuffer, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, position.byte, + partition->bytesPerSector - position.byte); + remain -= (partition->bytesPerSector - position.byte); + position.byte = 0; + position.sector ++; + } + + while (remain >= partition->bytesPerSector) { + if (position.sector >= partition->sectorsPerCluster) { + position.sector = 0; + // Ran out of clusters so get a new one + tempNextCluster = _FAT_fat_linkFreeCluster(partition, position.cluster); + if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) { + // Couldn't get a cluster, so abort + r->_errno = ENOSPC; + return false; + } + position.cluster = tempNextCluster; + } + + sector = _FAT_fat_clusterToSector (partition, position.cluster) + position.sector; + _FAT_cache_writeSectors (cache, sector, 1, zeroBuffer); + + remain -= partition->bytesPerSector; + position.sector ++; + } + + if (!_FAT_check_position_for_next_cluster(r, &position, partition, remain, NULL)) { + // error already marked + return false; + } + + if (remain > 0) { + _FAT_cache_writePartialSector (cache, zeroBuffer, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, 0, remain); + position.byte = remain; + } + } + + file->rwPosition = position; + file->filesize = file->currentPosition; + return true; +} + +ssize_t _FAT_write_r (struct _reent *r, void *fd, const char *ptr, size_t len) { + FILE_STRUCT* file = (FILE_STRUCT*) fd; + PARTITION* partition; + CACHE* cache; + FILE_POSITION position; + uint32_t tempNextCluster; + unsigned int tempVar; + size_t remain; + bool flagNoError = true; + bool flagAppending = false; + + // Make sure we can actually write to the file + if ((file == NULL) || !file->inUse || !file->write) { + r->_errno = EBADF; + return -1; + } + + partition = file->partition; + cache = file->partition->cache; + _FAT_lock(&partition->lock); + + // Only write up to the maximum file size, taking into account wrap-around of ints + if (len + file->filesize > FILE_MAX_SIZE || len + file->filesize < file->filesize) { + len = FILE_MAX_SIZE - file->filesize; + } + + // Short circuit cases where len is 0 (or less) + if (len <= 0) { + _FAT_unlock(&partition->lock); + return 0; + } + + remain = len; + + // Get a new cluster for the start of the file if required + if (file->startCluster == CLUSTER_FREE) { + tempNextCluster = _FAT_fat_linkFreeCluster (partition, CLUSTER_FREE); + if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) { + // Couldn't get a cluster, so abort immediately + _FAT_unlock(&partition->lock); + r->_errno = ENOSPC; + return -1; + } + file->startCluster = tempNextCluster; + + // Appending starts at the begining for a 0 byte file + file->appendPosition.cluster = file->startCluster; + file->appendPosition.sector = 0; + file->appendPosition.byte = 0; + + file->rwPosition.cluster = file->startCluster; + file->rwPosition.sector = 0; + file->rwPosition.byte = 0; + } + + if (file->append) { + position = file->appendPosition; + flagAppending = true; + } else { + // If the write pointer is past the end of the file, extend the file to that size + if (file->currentPosition > file->filesize) { + if (!_FAT_file_extend_r (r, file)) { + _FAT_unlock(&partition->lock); + return -1; + } + } + + // Write at current read pointer + position = file->rwPosition; + + // If it is writing past the current end of file, set appending flag + if (len + file->currentPosition > file->filesize) { + flagAppending = true; + } + } + + // Move onto next cluster if needed + _FAT_check_position_for_next_cluster(r, &position, partition, remain, &flagNoError); + + // Align to sector + tempVar = partition->bytesPerSector - position.byte; + if (tempVar > remain) { + tempVar = remain; + } + + if ((tempVar < partition->bytesPerSector) && flagNoError) { + // Write partial sector to disk + _FAT_cache_writePartialSector (cache, ptr, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, position.byte, tempVar); + + remain -= tempVar; + ptr += tempVar; + position.byte += tempVar; + + + // Move onto next sector + if (position.byte >= partition->bytesPerSector) { + position.byte = 0; + position.sector ++; + } + } + + // Align to cluster + // tempVar is number of sectors to write + if (remain > (partition->sectorsPerCluster - position.sector) * partition->bytesPerSector) { + tempVar = partition->sectorsPerCluster - position.sector; + } else { + tempVar = remain / partition->bytesPerSector; + } + + if ((tempVar > 0 && tempVar < partition->sectorsPerCluster) && flagNoError) { + if (!_FAT_cache_writeSectors (cache, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, tempVar, ptr)) + { + flagNoError = false; + r->_errno = EIO; + } else { + ptr += tempVar * partition->bytesPerSector; + remain -= tempVar * partition->bytesPerSector; + position.sector += tempVar; + } + } + + // Write whole clusters + while ((remain >= partition->bytesPerCluster) && flagNoError) { + // allocate next cluster + _FAT_check_position_for_next_cluster(r, &position, partition, remain, &flagNoError); + if (!flagNoError) break; + // set indexes to the current position + uint32_t chunkEnd = position.cluster; + uint32_t nextChunkStart = position.cluster; + size_t chunkSize = partition->bytesPerCluster; + FILE_POSITION next_position = position; + + // group consecutive clusters + while (flagNoError && +#ifdef LIMIT_SECTORS + (chunkSize + partition->bytesPerCluster <= LIMIT_SECTORS * partition->bytesPerSector) && +#endif + (chunkSize + partition->bytesPerCluster < remain)) + { + // pretend to use up all sectors in next_position + next_position.sector = partition->sectorsPerCluster; + // get or allocate next cluster + _FAT_check_position_for_next_cluster(r, &next_position, partition, + remain - chunkSize, &flagNoError); + if (!flagNoError) break; // exit loop on error + nextChunkStart = next_position.cluster; + if (nextChunkStart != chunkEnd + 1) break; // exit loop if not consecutive + chunkEnd = nextChunkStart; + chunkSize += partition->bytesPerCluster; + } + + if ( !_FAT_cache_writeSectors (cache, + _FAT_fat_clusterToSector(partition, position.cluster), chunkSize / partition->bytesPerSector, ptr)) + { + flagNoError = false; + r->_errno = EIO; + break; + } + ptr += chunkSize; + remain -= chunkSize; + + if ((chunkEnd != nextChunkStart) && _FAT_fat_isValidCluster(partition, nextChunkStart)) { + // new cluster is already allocated (because it was not consecutive) + position.cluster = nextChunkStart; + position.sector = 0; + } else { + // Allocate a new cluster when next writing the file + position.cluster = chunkEnd; + position.sector = partition->sectorsPerCluster; + } + } + + // allocate next cluster if needed + _FAT_check_position_for_next_cluster(r, &position, partition, remain, &flagNoError); + + // Write remaining sectors + tempVar = remain / partition->bytesPerSector; // Number of sectors left + if ((tempVar > 0) && flagNoError) { + if (!_FAT_cache_writeSectors (cache, _FAT_fat_clusterToSector (partition, position.cluster), tempVar, ptr)) + { + flagNoError = false; + r->_errno = EIO; + } else { + ptr += tempVar * partition->bytesPerSector; + remain -= tempVar * partition->bytesPerSector; + position.sector += tempVar; + } + } + + // Last remaining sector + if ((remain > 0) && flagNoError) { + if (flagAppending) { + _FAT_cache_eraseWritePartialSector ( cache, ptr, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, 0, remain); + } else { + _FAT_cache_writePartialSector ( cache, ptr, + _FAT_fat_clusterToSector (partition, position.cluster) + position.sector, 0, remain); + } + position.byte += remain; + remain = 0; + } + + + // Amount written is the originally requested amount minus stuff remaining + len = len - remain; + + // Update file information + file->modified = true; + if (file->append) { + // Appending doesn't affect the read pointer + file->appendPosition = position; + file->filesize += len; + } else { + // Writing also shifts the read pointer + file->rwPosition = position; + file->currentPosition += len; + if (file->filesize < file->currentPosition) { + file->filesize = file->currentPosition; + } + } + _FAT_unlock(&partition->lock); + + return len; +} + + +off_t _FAT_seek_r (struct _reent *r, void *fd, off_t pos, int dir) { + FILE_STRUCT* file = (FILE_STRUCT*) fd; + PARTITION* partition; + uint32_t cluster, nextCluster; + int clusCount; + off_t newPosition; + uint32_t position; + + if ((file == NULL) || (file->inUse == false)) { + // invalid file + r->_errno = EBADF; + return -1; + } + + partition = file->partition; + _FAT_lock(&partition->lock); + + switch (dir) { + case SEEK_SET: + newPosition = pos; + break; + case SEEK_CUR: + newPosition = (off_t)file->currentPosition + pos; + break; + case SEEK_END: + newPosition = (off_t)file->filesize + pos; + break; + default: + _FAT_unlock(&partition->lock); + r->_errno = EINVAL; + return -1; + } + + if ((pos > 0) && (newPosition < 0)) { + _FAT_unlock(&partition->lock); + r->_errno = EOVERFLOW; + return -1; + } + + // newPosition can only be larger than the FILE_MAX_SIZE on platforms where + // off_t is larger than 32 bits. + if (newPosition < 0 || ((sizeof(newPosition) > 4) && newPosition > (off_t)FILE_MAX_SIZE)) { + _FAT_unlock(&partition->lock); + r->_errno = EINVAL; + return -1; + } + + position = (uint32_t)newPosition; + + // Only change the read/write position if it is within the bounds of the current filesize, + // or at the very edge of the file + if (position <= file->filesize && file->startCluster != CLUSTER_FREE) { + // Calculate where the correct cluster is + // how many clusters from start of file + clusCount = position / partition->bytesPerCluster; + cluster = file->startCluster; + if (position >= file->currentPosition) { + // start from current cluster + int currentCount = file->currentPosition / partition->bytesPerCluster; + if (file->rwPosition.sector == partition->sectorsPerCluster) { + currentCount--; + } + clusCount -= currentCount; + cluster = file->rwPosition.cluster; + } + // Calculate the sector and byte of the current position, + // and store them + file->rwPosition.sector = (position % partition->bytesPerCluster) / partition->bytesPerSector; + file->rwPosition.byte = position % partition->bytesPerSector; + + nextCluster = _FAT_fat_nextCluster (partition, cluster); + while ((clusCount > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) { + clusCount--; + cluster = nextCluster; + nextCluster = _FAT_fat_nextCluster (partition, cluster); + } + + // Check if ran out of clusters and it needs to allocate a new one + if (clusCount > 0) { + if ((clusCount == 1) && (file->filesize == position) && (file->rwPosition.sector == 0)) { + // Set flag to allocate a new cluster + file->rwPosition.sector = partition->sectorsPerCluster; + file->rwPosition.byte = 0; + } else { + _FAT_unlock(&partition->lock); + r->_errno = EINVAL; + return -1; + } + } + + file->rwPosition.cluster = cluster; + } + + // Save position + file->currentPosition = position; + + _FAT_unlock(&partition->lock); + return position; +} + + + +int _FAT_fstat_r (struct _reent *r, void *fd, struct stat *st) { + FILE_STRUCT* file = (FILE_STRUCT*) fd; + PARTITION* partition; + DIR_ENTRY fileEntry; + + if ((file == NULL) || (file->inUse == false)) { + // invalid file + r->_errno = EBADF; + return -1; + } + + partition = file->partition; + _FAT_lock(&partition->lock); + + // Get the file's entry data + fileEntry.dataStart = file->dirEntryStart; + fileEntry.dataEnd = file->dirEntryEnd; + + if (!_FAT_directory_entryFromPosition (partition, &fileEntry)) { + _FAT_unlock(&partition->lock); + r->_errno = EIO; + return -1; + } + + // Fill in the stat struct + _FAT_directory_entryStat (partition, &fileEntry, st); + + // Fix stats that have changed since the file was openned + st->st_ino = (ino_t)(file->startCluster); // The file serial number is the start cluster + st->st_size = file->filesize; // File size + + _FAT_unlock(&partition->lock); + return 0; +} + +int _FAT_ftruncate_r (struct _reent *r, void *fd, off_t len) { + FILE_STRUCT* file = (FILE_STRUCT*) fd; + PARTITION* partition; + int ret=0; + uint32_t newSize = (uint32_t)len; + + if (len < 0) { + // Trying to truncate to a negative size + r->_errno = EINVAL; + return -1; + } + + if ((sizeof(len) > 4) && len > (off_t)FILE_MAX_SIZE) { + // Trying to extend the file beyond what FAT supports + r->_errno = EFBIG; + return -1; + } + + if (!file || !file->inUse) { + // invalid file + r->_errno = EBADF; + return -1; + } + + if (!file->write) { + // Read-only file + r->_errno = EINVAL; + return -1; + } + + partition = file->partition; + _FAT_lock(&partition->lock); + + if (newSize > file->filesize) { + // Expanding the file + FILE_POSITION savedPosition; + uint32_t savedOffset; + // Get a new cluster for the start of the file if required + if (file->startCluster == CLUSTER_FREE) { + uint32_t tempNextCluster = _FAT_fat_linkFreeCluster (partition, CLUSTER_FREE); + if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) { + // Couldn't get a cluster, so abort immediately + _FAT_unlock(&partition->lock); + r->_errno = ENOSPC; + return -1; + } + file->startCluster = tempNextCluster; + + file->rwPosition.cluster = file->startCluster; + file->rwPosition.sector = 0; + file->rwPosition.byte = 0; + } + // Save the read/write pointer + savedPosition = file->rwPosition; + savedOffset = file->currentPosition; + // Set the position to the new size + file->currentPosition = newSize; + // Extend the file to the new position + if (!_FAT_file_extend_r (r, file)) { + ret = -1; + } + // Set the append position to the new rwPointer + if (file->append) { + file->appendPosition = file->rwPosition; + } + // Restore the old rwPointer; + file->rwPosition = savedPosition; + file->currentPosition = savedOffset; + } else if (newSize < file->filesize){ + // Shrinking the file + if (len == 0) { + // Cutting the file down to nothing, clear all clusters used + _FAT_fat_clearLinks (partition, file->startCluster); + file->startCluster = CLUSTER_FREE; + + file->appendPosition.cluster = CLUSTER_FREE; + file->appendPosition.sector = 0; + file->appendPosition.byte = 0; + } else { + // Trimming the file down to the required size + unsigned int chainLength; + uint32_t lastCluster; + + // Drop the unneeded end of the cluster chain. + // If the end falls on a cluster boundary, drop that cluster too, + // then set a flag to allocate a cluster as needed + chainLength = ((newSize-1) / partition->bytesPerCluster) + 1; + lastCluster = _FAT_fat_trimChain (partition, file->startCluster, chainLength); + + if (file->append) { + file->appendPosition.byte = newSize % partition->bytesPerSector; + // Does the end of the file fall on the edge of a cluster? + if (newSize % partition->bytesPerCluster == 0) { + // Set a flag to allocate a new cluster + file->appendPosition.sector = partition->sectorsPerCluster; + } else { + file->appendPosition.sector = (newSize % partition->bytesPerCluster) / partition->bytesPerSector; + } + file->appendPosition.cluster = lastCluster; + } + } + } else { + // Truncating to same length, so don't do anything + } + + file->filesize = newSize; + file->modified = true; + + _FAT_unlock(&partition->lock); + return ret; +} + +int _FAT_fsync_r (struct _reent *r, void *fd) { + FILE_STRUCT* file = (FILE_STRUCT*) fd; + int ret = 0; + + if (!file->inUse) { + r->_errno = EBADF; + return -1; + } + + _FAT_lock(&file->partition->lock); + + ret = _FAT_syncToDisc (file); + if (ret != 0) { + r->_errno = ret; + ret = -1; + } + + _FAT_unlock(&file->partition->lock); + + return ret; +} diff --git a/wii/libogc/libfat/fatfile.h b/wii/libogc/libfat/fatfile.h new file mode 100644 index 0000000000..3d9836c061 --- /dev/null +++ b/wii/libogc/libfat/fatfile.h @@ -0,0 +1,105 @@ +/* + fatfile.h + + Functions used by the newlib disc stubs to interface with + this library + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef _FATFILE_H +#define _FATFILE_H + +#include +#include + +#include "common.h" +#include "partition.h" +#include "directory.h" + +#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B + +typedef struct { + u32 cluster; + sec_t sector; + s32 byte; +} FILE_POSITION; + +struct _FILE_STRUCT; + +struct _FILE_STRUCT { + uint32_t filesize; + uint32_t startCluster; + uint32_t currentPosition; + FILE_POSITION rwPosition; + FILE_POSITION appendPosition; + DIR_ENTRY_POSITION dirEntryStart; // Points to the start of the LFN entries of a file, or the alias for no LFN + DIR_ENTRY_POSITION dirEntryEnd; // Always points to the file's alias entry + PARTITION* partition; + struct _FILE_STRUCT* prevOpenFile; // The previous entry in a double-linked list of open files + struct _FILE_STRUCT* nextOpenFile; // The next entry in a double-linked list of open files + bool read; + bool write; + bool append; + bool inUse; + bool modified; +}; + +typedef struct _FILE_STRUCT FILE_STRUCT; + +int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode); + +int _FAT_close_r (struct _reent *r, void *fd); + +ssize_t _FAT_write_r (struct _reent *r,void *fd, const char *ptr, size_t len); + +ssize_t _FAT_read_r (struct _reent *r, void *fd, char *ptr, size_t len); + +off_t _FAT_seek_r (struct _reent *r, void *fd, off_t pos, int dir); + +int _FAT_fstat_r (struct _reent *r, void *fd, struct stat *st); + +int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st); + +int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink); + +int _FAT_unlink_r (struct _reent *r, const char *name); + +int _FAT_chdir_r (struct _reent *r, const char *name); + +int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName); + +int _FAT_ftruncate_r (struct _reent *r, void *fd, off_t len); + +int _FAT_fsync_r (struct _reent *r, void *fd); + +/* +Synchronizes the file data to disc. +Does no locking of its own -- lock the partition before calling. +Returns 0 on success, an error code on failure. +*/ +extern int _FAT_syncToDisc (FILE_STRUCT* file); + +#endif // _FATFILE_H diff --git a/wii/libogc/libfat/file_allocation_table.c b/wii/libogc/libfat/file_allocation_table.c new file mode 100644 index 0000000000..72f8aa74aa --- /dev/null +++ b/wii/libogc/libfat/file_allocation_table.c @@ -0,0 +1,393 @@ +/* + file_allocation_table.c + Reading, writing and manipulation of the FAT structure on + a FAT partition + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "file_allocation_table.h" +#include "partition.h" +#include "mem_allocate.h" +#include + +/* +Gets the cluster linked from input cluster +*/ +uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster) +{ + uint32_t nextCluster = CLUSTER_FREE; + sec_t sector; + int offset; + + if (cluster == CLUSTER_FREE) { + return CLUSTER_FREE; + } + + switch (partition->filesysType) + { + case FS_UNKNOWN: + return CLUSTER_ERROR; + break; + + case FS_FAT12: + { + u32 nextCluster_h; + sector = partition->fat.fatStart + (((cluster * 3) / 2) / partition->bytesPerSector); + offset = ((cluster * 3) / 2) % partition->bytesPerSector; + + + _FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u8)); + + offset++; + + if (offset >= partition->bytesPerSector) { + offset = 0; + sector++; + } + nextCluster_h = 0; + + _FAT_cache_readLittleEndianValue (partition->cache, &nextCluster_h, sector, offset, sizeof(u8)); + nextCluster |= (nextCluster_h << 8); + + if (cluster & 0x01) { + nextCluster = nextCluster >> 4; + } else { + nextCluster &= 0x0FFF; + } + + if (nextCluster >= 0x0FF7) + { + nextCluster = CLUSTER_EOF; + } + + break; + } + case FS_FAT16: + sector = partition->fat.fatStart + ((cluster << 1) / partition->bytesPerSector); + offset = (cluster % (partition->bytesPerSector >> 1)) << 1; + + _FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u16)); + + if (nextCluster >= 0xFFF7) { + nextCluster = CLUSTER_EOF; + } + break; + + case FS_FAT32: + sector = partition->fat.fatStart + ((cluster << 2) / partition->bytesPerSector); + offset = (cluster % (partition->bytesPerSector >> 2)) << 2; + + _FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u32)); + + if (nextCluster >= 0x0FFFFFF7) { + nextCluster = CLUSTER_EOF; + } + break; + + default: + return CLUSTER_ERROR; + break; + } + + return nextCluster; +} + +/* +writes value into the correct offset within a partition's FAT, based +on the cluster number. +*/ +static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value) { + sec_t sector; + int offset; + uint32_t oldValue; + + if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */)) + { + return false; + } + + switch (partition->filesysType) + { + case FS_UNKNOWN: + return false; + break; + + case FS_FAT12: + sector = partition->fat.fatStart + (((cluster * 3) / 2) / partition->bytesPerSector); + offset = ((cluster * 3) / 2) % partition->bytesPerSector; + + if (cluster & 0x01) { + + _FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8)); + + value = (value << 4) | (oldValue & 0x0F); + + _FAT_cache_writeLittleEndianValue (partition->cache, value & 0xFF, sector, offset, sizeof(u8)); + + offset++; + if (offset >= partition->bytesPerSector) { + offset = 0; + sector++; + } + + _FAT_cache_writeLittleEndianValue (partition->cache, (value >> 8) & 0xFF, sector, offset, sizeof(u8)); + + } else { + + _FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8)); + + offset++; + if (offset >= partition->bytesPerSector) { + offset = 0; + sector++; + } + + _FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8)); + + value = ((value >> 8) & 0x0F) | (oldValue & 0xF0); + + _FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8)); + } + + break; + + case FS_FAT16: + sector = partition->fat.fatStart + ((cluster << 1) / partition->bytesPerSector); + offset = (cluster % (partition->bytesPerSector >> 1)) << 1; + + _FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u16)); + + break; + + case FS_FAT32: + sector = partition->fat.fatStart + ((cluster << 2) / partition->bytesPerSector); + offset = (cluster % (partition->bytesPerSector >> 2)) << 2; + + _FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u32)); + + break; + + default: + return false; + break; + } + + return true; +} + +/*----------------------------------------------------------------- +gets the first available free cluster, sets it +to end of file, links the input cluster to it then returns the +cluster number +If an error occurs, return CLUSTER_ERROR +-----------------------------------------------------------------*/ +uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) { + uint32_t firstFree; + uint32_t curLink; + uint32_t lastCluster; + bool loopedAroundFAT = false; + + lastCluster = partition->fat.lastCluster; + + if (cluster > lastCluster) { + return CLUSTER_ERROR; + } + + // Check if the cluster already has a link, and return it if so + curLink = _FAT_fat_nextCluster(partition, cluster); + if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster)) { + return curLink; // Return the current link - don't allocate a new one + } + + // Get a free cluster + firstFree = partition->fat.firstFree; + // Start at first valid cluster + if (firstFree < CLUSTER_FIRST) { + firstFree = CLUSTER_FIRST; + } + + // Search until a free cluster is found + while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) { + firstFree++; + if (firstFree > lastCluster) { + if (loopedAroundFAT) { + // If couldn't get a free cluster then return an error + partition->fat.firstFree = firstFree; + return CLUSTER_ERROR; + } else { + // Try looping back to the beginning of the FAT + // This was suggested by loopy + firstFree = CLUSTER_FIRST; + loopedAroundFAT = true; + } + } + } + partition->fat.firstFree = firstFree; + if(partition->fat.numberFreeCluster) + partition->fat.numberFreeCluster--; + partition->fat.numberLastAllocCluster = firstFree; + + if ((cluster >= CLUSTER_FIRST) && (cluster <= lastCluster)) + { + // Update the linked from FAT entry + _FAT_fat_writeFatEntry (partition, cluster, firstFree); + } + // Create the linked to FAT entry + _FAT_fat_writeFatEntry (partition, firstFree, CLUSTER_EOF); + + return firstFree; +} + +/*----------------------------------------------------------------- +gets the first available free cluster, sets it +to end of file, links the input cluster to it, clears the new +cluster to 0 valued bytes, then returns the cluster number +If an error occurs, return CLUSTER_ERROR +-----------------------------------------------------------------*/ +uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster) { + uint32_t newCluster; + uint32_t i; + uint8_t *emptySector; + + // Link the cluster + newCluster = _FAT_fat_linkFreeCluster(partition, cluster); + + if (newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR) { + return CLUSTER_ERROR; + } + + emptySector = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector); + + // Clear all the sectors within the cluster + memset (emptySector, 0, partition->bytesPerSector); + for (i = 0; i < partition->sectorsPerCluster; i++) { + _FAT_cache_writeSectors (partition->cache, + _FAT_fat_clusterToSector (partition, newCluster) + i, + 1, emptySector); + } + + _FAT_mem_free(emptySector); + + return newCluster; +} + + +/*----------------------------------------------------------------- +_FAT_fat_clearLinks +frees any cluster used by a file +-----------------------------------------------------------------*/ +bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster) { + uint32_t nextCluster; + + if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */)) + return false; + + // If this clears up more space in the FAT before the current free pointer, move it backwards + if (cluster < partition->fat.firstFree) { + partition->fat.firstFree = cluster; + } + + while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR)) { + // Store next cluster before erasing the link + nextCluster = _FAT_fat_nextCluster (partition, cluster); + + // Erase the link + _FAT_fat_writeFatEntry (partition, cluster, CLUSTER_FREE); + + if(partition->fat.numberFreeCluster < (partition->numberOfSectors/partition->sectorsPerCluster)) + partition->fat.numberFreeCluster++; + // Move onto next cluster + cluster = nextCluster; + } + + return true; +} + +/*----------------------------------------------------------------- +_FAT_fat_trimChain +Drop all clusters past the chainLength. +If chainLength is 0, all clusters are dropped. +If chainLength is 1, the first cluster is kept and the rest are +dropped, and so on. +Return the last cluster left in the chain. +-----------------------------------------------------------------*/ +uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength) { + uint32_t nextCluster; + + if (chainLength == 0) { + // Drop the entire chain + _FAT_fat_clearLinks (partition, startCluster); + return CLUSTER_FREE; + } else { + // Find the last cluster in the chain, and the one after it + chainLength--; + nextCluster = _FAT_fat_nextCluster (partition, startCluster); + while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) { + chainLength--; + startCluster = nextCluster; + nextCluster = _FAT_fat_nextCluster (partition, startCluster); + } + + // Drop all clusters after the last in the chain + if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF) { + _FAT_fat_clearLinks (partition, nextCluster); + } + + // Mark the last cluster in the chain as the end of the file + _FAT_fat_writeFatEntry (partition, startCluster, CLUSTER_EOF); + + return startCluster; + } +} + +/*----------------------------------------------------------------- +_FAT_fat_lastCluster +Trace the cluster links until the last one is found +-----------------------------------------------------------------*/ +uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) { + while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF)) { + cluster = _FAT_fat_nextCluster(partition, cluster); + } + return cluster; +} + +/*----------------------------------------------------------------- +_FAT_fat_freeClusterCount +Return the number of free clusters available +-----------------------------------------------------------------*/ +unsigned int _FAT_fat_freeClusterCount (PARTITION* partition) { + unsigned int count = 0; + uint32_t curCluster; + + for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++) { + if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE) { + count++; + } + } + + return count; +} + diff --git a/wii/libogc/libfat/file_allocation_table.h b/wii/libogc/libfat/file_allocation_table.h new file mode 100644 index 0000000000..d9c43614dd --- /dev/null +++ b/wii/libogc/libfat/file_allocation_table.h @@ -0,0 +1,70 @@ +/* + file_allocation_table.h + Reading, writing and manipulation of the FAT structure on + a FAT partition + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _FAT_H +#define _FAT_H + +#include "common.h" +#include "partition.h" + +#define CLUSTER_EOF_16 0xFFFF +#define CLUSTER_EOF 0x0FFFFFFF +#define CLUSTER_FREE 0x00000000 +#define CLUSTER_ROOT 0x00000000 +#define CLUSTER_FIRST 0x00000002 +#define CLUSTER_ERROR 0xFFFFFFFF + +#define CLUSTERS_PER_FAT12 4085 +#define CLUSTERS_PER_FAT16 65525 + + +uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster); + +uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster); +uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster); + +bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster); + +uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength); + +uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster); + +unsigned int _FAT_fat_freeClusterCount (PARTITION* partition); + +static inline sec_t _FAT_fat_clusterToSector (PARTITION* partition, uint32_t cluster) { + return (cluster >= CLUSTER_FIRST) ? + ((cluster - CLUSTER_FIRST) * (sec_t)partition->sectorsPerCluster) + partition->dataStart : + partition->rootDirStart; +} + +static inline bool _FAT_fat_isValidCluster (PARTITION* partition, uint32_t cluster) { + return (cluster >= CLUSTER_FIRST) && (cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */); +} + +#endif // _FAT_H diff --git a/wii/libogc/libfat/filetime.c b/wii/libogc/libfat/filetime.c new file mode 100644 index 0000000000..d297bf6400 --- /dev/null +++ b/wii/libogc/libfat/filetime.c @@ -0,0 +1,107 @@ +/* + filetime.c + Conversion of file time and date values to various other types + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include "filetime.h" +#include "common.h" + +#define MAX_HOUR 23 +#define MAX_MINUTE 59 +#define MAX_SECOND 59 + +#define MAX_MONTH 11 +#define MIN_MONTH 0 +#define MAX_DAY 31 +#define MIN_DAY 1 + +uint16_t _FAT_filetime_getTimeFromRTC (void) { +#ifdef USE_RTC_TIME + struct tm timeParts; + time_t epochTime; + + if (time(&epochTime) == (time_t)-1) { + return 0; + } + localtime_r(&epochTime, &timeParts); + + // Check that the values are all in range. + // If they are not, return 0 (no timestamp) + if ((timeParts.tm_hour < 0) || (timeParts.tm_hour > MAX_HOUR)) return 0; + if ((timeParts.tm_min < 0) || (timeParts.tm_min > MAX_MINUTE)) return 0; + if ((timeParts.tm_sec < 0) || (timeParts.tm_sec > MAX_SECOND)) return 0; + + return ( + ((timeParts.tm_hour & 0x1F) << 11) | + ((timeParts.tm_min & 0x3F) << 5) | + ((timeParts.tm_sec >> 1) & 0x1F) + ); +#else + return 0; +#endif +} + + +uint16_t _FAT_filetime_getDateFromRTC (void) { +#ifdef USE_RTC_TIME + struct tm timeParts; + time_t epochTime; + + if (time(&epochTime) == (time_t)-1) { + return 0; + } + localtime_r(&epochTime, &timeParts); + + if ((timeParts.tm_mon < MIN_MONTH) || (timeParts.tm_mon > MAX_MONTH)) return 0; + if ((timeParts.tm_mday < MIN_DAY) || (timeParts.tm_mday > MAX_DAY)) return 0; + + return ( + (((timeParts.tm_year - 80) & 0x7F) <<9) | // Adjust for MS-FAT base year (1980 vs 1900 for tm_year) + (((timeParts.tm_mon + 1) & 0xF) << 5) | + (timeParts.tm_mday & 0x1F) + ); +#else + return 0; +#endif +} + +time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d) { + struct tm timeParts; + + timeParts.tm_hour = t >> 11; + timeParts.tm_min = (t >> 5) & 0x3F; + timeParts.tm_sec = (t & 0x1F) << 1; + + timeParts.tm_mday = d & 0x1F; + timeParts.tm_mon = ((d >> 5) & 0x0F) - 1; + timeParts.tm_year = (d >> 9) + 80; + + timeParts.tm_isdst = 0; + + return mktime(&timeParts); +} diff --git a/wii/libogc/libfat/filetime.h b/wii/libogc/libfat/filetime.h new file mode 100644 index 0000000000..3bfd8ed8af --- /dev/null +++ b/wii/libogc/libfat/filetime.h @@ -0,0 +1,41 @@ +/* + filetime.h + Conversion of file time and date values to various other types + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _FILETIME_H +#define _FILETIME_H + +#include "common.h" +#include + +uint16_t _FAT_filetime_getTimeFromRTC (void); +uint16_t _FAT_filetime_getDateFromRTC (void); + +time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d); + + +#endif // _FILETIME_H diff --git a/wii/libogc/libfat/libfat.c b/wii/libogc/libfat/libfat.c new file mode 100644 index 0000000000..4d323cae1a --- /dev/null +++ b/wii/libogc/libfat/libfat.c @@ -0,0 +1,255 @@ +/* + libfat.c + Simple functionality for startup, mounting and unmounting of FAT-based devices. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "partition.h" +#include "fatfile.h" +#include "fatdir.h" +#include "lock.h" +#include "mem_allocate.h" +#include "disc.h" + +static const devoptab_t dotab_fat = { + "fat", + sizeof (FILE_STRUCT), + _FAT_open_r, + _FAT_close_r, + _FAT_write_r, + _FAT_read_r, + _FAT_seek_r, + _FAT_fstat_r, + _FAT_stat_r, + _FAT_link_r, + _FAT_unlink_r, + _FAT_chdir_r, + _FAT_rename_r, + _FAT_mkdir_r, + sizeof (DIR_STATE_STRUCT), + _FAT_diropen_r, + _FAT_dirreset_r, + _FAT_dirnext_r, + _FAT_dirclose_r, + _FAT_statvfs_r, + _FAT_ftruncate_r, + _FAT_fsync_r, + NULL, /* Device data */ + NULL, // chmod_r + NULL, // fchmod_r + NULL // rmdir_r +}; + +bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) { + PARTITION* partition; + devoptab_t* devops; + char* nameCopy; + + if(!name || strlen(name) > 8 || !interface) + return false; + + if(!interface->startup()) + return false; + + if(!interface->isInserted()) + return false; + + char devname[10]; + strcpy(devname, name); + strcat(devname, ":"); + if(FindDevice(devname) >= 0) + return true; + + devops = _FAT_mem_allocate (sizeof(devoptab_t) + strlen(name) + 1); + if (!devops) { + return false; + } + // Use the space allocated at the end of the devoptab struct for storing the name + nameCopy = (char*)(devops+1); + + // Initialize the file system + partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector); + if (!partition) { + _FAT_mem_free (devops); + return false; + } + + // Add an entry for this device to the devoptab table + memcpy (devops, &dotab_fat, sizeof(dotab_fat)); + strcpy (nameCopy, name); + devops->name = nameCopy; + devops->deviceData = partition; + + AddDevice (devops); + + return true; +} + +bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) { + return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE); +} + +void fatUnmount (const char* name) { + devoptab_t *devops; + PARTITION* partition; + + if(!name) + return; + + devops = (devoptab_t*)GetDeviceOpTab (name); + if (!devops) { + return; + } + + // Perform a quick check to make sure we're dealing with a libfat controlled device + if (devops->open_r != dotab_fat.open_r) { + return; + } + + if (RemoveDevice (name) == -1) { + return; + } + + partition = (PARTITION*)devops->deviceData; + _FAT_partition_destructor (partition); + _FAT_mem_free (devops); +} + +bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) { + int i; + int defaultDevice = -1; + const DISC_INTERFACE *disc; + + for (i = 0; + _FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL; + i++) + { + disc = _FAT_disc_interfaces[i].getInterface(); + if (!disc) { + continue; + } + if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) { + // The first device to successfully mount is set as the default + if (defaultDevice < 0) { + defaultDevice = i; + } + } + } + + if (defaultDevice < 0) { + // None of our devices mounted + return false; + } + + if (setAsDefaultDevice) { + char filePath[PATH_MAX]; + strcpy (filePath, _FAT_disc_interfaces[defaultDevice].name); + strcat (filePath, ":/"); +#ifdef ARGV_MAGIC + if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL ) { + // Check the app's path against each of our mounted devices, to see + // if we can support it. If so, change to that path. + for (i = 0; + _FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL; + i++) + { + if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name, + strlen(_FAT_disc_interfaces[i].name))) + { + char *lastSlash; + strcpy(filePath, __system_argv->argv[0]); + lastSlash = strrchr( filePath, '/' ); + + if ( NULL != lastSlash) { + if ( *(lastSlash - 1) == ':') lastSlash++; + *lastSlash = 0; + } + } + } + } +#endif + chdir (filePath); + } + + return true; +} + +bool fatInitDefault (void) { + return fatInit (DEFAULT_CACHE_PAGES, true); +} + +void fatGetVolumeLabel (const char* name, char *label) { + devoptab_t *devops; + PARTITION* partition; + char *buf; + int namelen,i; + + if(!name || !label) + return; + + namelen = strlen(name); + buf=(char*)_FAT_mem_allocate(sizeof(char)*namelen+2); + strcpy(buf,name); + + if (name[namelen-1] == '/') { + buf[namelen-1]='\0'; + namelen--; + } + + if (name[namelen-1] != ':') { + buf[namelen]=':'; + buf[namelen+1]='\0'; + } + + devops = (devoptab_t*)GetDeviceOpTab(buf); + + for(i=0;buf[i]!='\0' && buf[i]!=':';i++); + if (!devops || strncasecmp(buf,devops->name,i)) { + _FAT_mem_free(buf); + return; + } + + _FAT_mem_free(buf); + + // Perform a quick check to make sure we're dealing with a libfat controlled device + if (devops->open_r != dotab_fat.open_r) { + return; + } + + partition = (PARTITION*)devops->deviceData; + + if(!_FAT_directory_getVolumeLabel(partition, label)) { + strncpy(label,partition->label,11); + label[11]='\0'; + } + if(!strncmp(label, "NO NAME", 7)) label[0]='\0'; +} diff --git a/wii/libogc/libfat/lock.c b/wii/libogc/libfat/lock.c new file mode 100644 index 0000000000..59c3444c51 --- /dev/null +++ b/wii/libogc/libfat/lock.c @@ -0,0 +1,29 @@ +#include "common.h" + +#ifndef USE_LWP_LOCK + +#ifndef mutex_t +typedef int mutex_t; +#endif + +void __attribute__ ((weak)) _FAT_lock_init(mutex_t *mutex) +{ + return; +} + +void __attribute__ ((weak)) _FAT_lock_deinit(mutex_t *mutex) +{ + return; +} + +void __attribute__ ((weak)) _FAT_lock(mutex_t *mutex) +{ + return; +} + +void __attribute__ ((weak)) _FAT_unlock(mutex_t *mutex) +{ + return; +} + +#endif // USE_LWP_LOCK diff --git a/wii/libogc/libfat/lock.h b/wii/libogc/libfat/lock.h new file mode 100644 index 0000000000..de5723a9cb --- /dev/null +++ b/wii/libogc/libfat/lock.h @@ -0,0 +1,72 @@ +/* + lock.h + + Copyright (c) 2008 Sven Peter + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _LOCK_H +#define _LOCK_H + +#include "common.h" + +#ifdef USE_LWP_LOCK + +static inline void _FAT_lock_init(mutex_t *mutex) +{ + LWP_MutexInit(mutex, false); +} + +static inline void _FAT_lock_deinit(mutex_t *mutex) +{ + LWP_MutexDestroy(*mutex); +} + +static inline void _FAT_lock(mutex_t *mutex) +{ + LWP_MutexLock(*mutex); +} + +static inline void _FAT_unlock(mutex_t *mutex) +{ + LWP_MutexUnlock(*mutex); +} + +#else + +// We still need a blank lock type +#ifndef mutex_t +typedef int mutex_t; +#endif + +void _FAT_lock_init(mutex_t *mutex); +void _FAT_lock_deinit(mutex_t *mutex); +void _FAT_lock(mutex_t *mutex); +void _FAT_unlock(mutex_t *mutex); + +#endif // USE_LWP_LOCK + + +#endif // _LOCK_H + diff --git a/wii/libogc/libfat/mem_allocate.h b/wii/libogc/libfat/mem_allocate.h new file mode 100644 index 0000000000..3308807ad0 --- /dev/null +++ b/wii/libogc/libfat/mem_allocate.h @@ -0,0 +1,52 @@ +/* + mem_allocate.h + Memory allocation and destruction calls + Replace these calls with custom allocators if + malloc is unavailable + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _MEM_ALLOCATE_H +#define _MEM_ALLOCATE_H + +#include + +static inline void* _FAT_mem_allocate (size_t size) { + return malloc (size); +} + +static inline void* _FAT_mem_align (size_t size) { +#ifdef __wii__ + return memalign (32, size); +#else + return malloc (size); +#endif +} + +static inline void _FAT_mem_free (void* mem) { + free (mem); +} + +#endif // _MEM_ALLOCATE_H diff --git a/wii/libogc/libfat/partition.c b/wii/libogc/libfat/partition.c new file mode 100644 index 0000000000..1584e0ed59 --- /dev/null +++ b/wii/libogc/libfat/partition.c @@ -0,0 +1,448 @@ +/* + partition.c + Functions for mounting and dismounting partitions + on various block devices. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "partition.h" +#include "bit_ops.h" +#include "file_allocation_table.h" +#include "directory.h" +#include "mem_allocate.h" +#include "fatfile.h" + +#include +#include +#include + +/* +Data offsets +*/ + +// BIOS Parameter Block offsets +enum BPB { + BPB_jmpBoot = 0x00, + BPB_OEMName = 0x03, + // BIOS Parameter Block + BPB_bytesPerSector = 0x0B, + BPB_sectorsPerCluster = 0x0D, + BPB_reservedSectors = 0x0E, + BPB_numFATs = 0x10, + BPB_rootEntries = 0x11, + BPB_numSectorsSmall = 0x13, + BPB_mediaDesc = 0x15, + BPB_sectorsPerFAT = 0x16, + BPB_sectorsPerTrk = 0x18, + BPB_numHeads = 0x1A, + BPB_numHiddenSectors = 0x1C, + BPB_numSectors = 0x20, + // Ext BIOS Parameter Block for FAT16 + BPB_FAT16_driveNumber = 0x24, + BPB_FAT16_reserved1 = 0x25, + BPB_FAT16_extBootSig = 0x26, + BPB_FAT16_volumeID = 0x27, + BPB_FAT16_volumeLabel = 0x2B, + BPB_FAT16_fileSysType = 0x36, + // Bootcode + BPB_FAT16_bootCode = 0x3E, + // FAT32 extended block + BPB_FAT32_sectorsPerFAT32 = 0x24, + BPB_FAT32_extFlags = 0x28, + BPB_FAT32_fsVer = 0x2A, + BPB_FAT32_rootClus = 0x2C, + BPB_FAT32_fsInfo = 0x30, + BPB_FAT32_bkBootSec = 0x32, + // Ext BIOS Parameter Block for FAT32 + BPB_FAT32_driveNumber = 0x40, + BPB_FAT32_reserved1 = 0x41, + BPB_FAT32_extBootSig = 0x42, + BPB_FAT32_volumeID = 0x43, + BPB_FAT32_volumeLabel = 0x47, + BPB_FAT32_fileSysType = 0x52, + // Bootcode + BPB_FAT32_bootCode = 0x5A, + BPB_bootSig_55 = 0x1FE, + BPB_bootSig_AA = 0x1FF +}; + +// File system information block offsets +enum FSIB +{ + FSIB_SIG1 = 0x00, + FSIB_SIG2 = 0x1e4, + FSIB_numberOfFreeCluster = 0x1e8, + FSIB_numberLastAllocCluster = 0x1ec, + FSIB_bootSig_55 = 0x1FE, + FSIB_bootSig_AA = 0x1FF +}; + +static const char FAT_SIG[3] = {'F', 'A', 'T'}; +static const char FS_INFO_SIG1[4] = {'R', 'R', 'a', 'A'}; +static const char FS_INFO_SIG2[4] = {'r', 'r', 'A', 'a'}; + +sec_t FindFirstValidPartition_buf(const DISC_INTERFACE* disc, uint8_t *sectorBuffer) +{ + uint8_t part_table[16*4]; + uint8_t *ptr; + int i; + + // Read first sector of disc + if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) { + return 0; + } + + memcpy(part_table,sectorBuffer+0x1BE,16*4); + ptr = part_table; + + for(i=0;i<4;i++,ptr+=16) { + sec_t part_lba = u8array_to_u32(ptr, 0x8); + + if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || + !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { + return part_lba; + } + + if(ptr[4]==0) continue; + + if(ptr[4]==0x0F) { + sec_t part_lba2=part_lba; + sec_t next_lba2=0; + int n; + + for(n=0;n<8;n++) // max 8 logic partitions + { + if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer)) return 0; + + part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6) ; + next_lba2 = u8array_to_u32(sectorBuffer, 0x1D6); + + if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer)) return 0; + + if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || + !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) + { + return part_lba2; + } + + if(next_lba2==0) break; + } + } else { + if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer)) return 0; + if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || + !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { + return part_lba; + } + } + } + return 0; +} + +sec_t FindFirstValidPartition(const DISC_INTERFACE* disc) +{ + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE); + if (!sectorBuffer) return 0; + sec_t ret = FindFirstValidPartition_buf(disc, sectorBuffer); + _FAT_mem_free(sectorBuffer); + return ret; +} + + +PARTITION* _FAT_partition_constructor_buf (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector, uint8_t *sectorBuffer) +{ + PARTITION* partition; + + // Read first sector of disc + if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { + return NULL; + } + + // Make sure it is a valid MBR or boot sector + if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) { + return NULL; + } + + if (startSector != 0) { + // We're told where to start the partition, so just accept it + } else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { + // Check if there is a FAT string, which indicates this is a boot sector + startSector = 0; + } else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { + // Check for FAT32 + startSector = 0; + } else { + startSector = FindFirstValidPartition_buf(disc, sectorBuffer); + if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { + return NULL; + } + } + + // Now verify that this is indeed a FAT partition + if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) && + memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) + { + return NULL; + } + + partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION)); + if (partition == NULL) { + return NULL; + } + + // Init the partition lock + _FAT_lock_init(&partition->lock); + + if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) + strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT16_volumeLabel), 11); + else + strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT32_volumeLabel), 11); + partition->label[11] = '\0'; + + // Set partition's disc interface + partition->disc = disc; + + // Store required information about the file system + partition->fat.sectorsPerFat = u8array_to_u16(sectorBuffer, BPB_sectorsPerFAT); + if (partition->fat.sectorsPerFat == 0) { + partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32); + } + + partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall); + if (partition->numberOfSectors == 0) { + partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors); + } + + partition->bytesPerSector = u8array_to_u16(sectorBuffer, BPB_bytesPerSector); + if(partition->bytesPerSector < MIN_SECTOR_SIZE || partition->bytesPerSector > MAX_SECTOR_SIZE) { + // Unsupported sector size + _FAT_mem_free(partition); + return NULL; + } + + partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster]; + partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster; + partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors); + + partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat); + partition->dataStart = partition->rootDirStart + + (( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector); + + partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector; + + //FS info sector + partition->fsInfoSector = startSector + (u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) ? u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) : 1); + + // Store info about FAT + uint32_t clusterCount = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster; + partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1; + partition->fat.firstFree = CLUSTER_FIRST; + partition->fat.numberFreeCluster = 0; + partition->fat.numberLastAllocCluster = 0; + + if (clusterCount < CLUSTERS_PER_FAT12) { + partition->filesysType = FS_FAT12; // FAT12 volume + } else if (clusterCount < CLUSTERS_PER_FAT16) { + partition->filesysType = FS_FAT16; // FAT16 volume + } else { + partition->filesysType = FS_FAT32; // FAT32 volume + } + + if (partition->filesysType != FS_FAT32) { + partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER; + } else { + // Set up for the FAT32 way + partition->rootDirCluster = u8array_to_u32(sectorBuffer, BPB_FAT32_rootClus); + // Check if FAT mirroring is enabled + if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) { + // Use the active FAT + partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * (sectorBuffer[BPB_FAT32_extFlags] & 0x0F)); + } + } + + // Create a cache to use + partition->cache = _FAT_cache_constructor (cacheSize, sectorsPerPage, partition->disc, startSector+partition->numberOfSectors, partition->bytesPerSector); + + // Set current directory to the root + partition->cwdCluster = partition->rootDirCluster; + + // Check if this disc is writable, and set the readOnly property appropriately + partition->readOnly = !(_FAT_disc_features(disc) & FEATURE_MEDIUM_CANWRITE); + + // There are currently no open files on this partition + partition->openFileCount = 0; + partition->firstOpenFile = NULL; + + _FAT_partition_readFSinfo(partition); + + return partition; +} + +PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) +{ + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE); + if (!sectorBuffer) return NULL; + PARTITION *ret = _FAT_partition_constructor_buf(disc, cacheSize, + sectorsPerPage, startSector, sectorBuffer); + _FAT_mem_free(sectorBuffer); + return ret; +} + + +void _FAT_partition_destructor (PARTITION* partition) { + FILE_STRUCT* nextFile; + + _FAT_lock(&partition->lock); + + // Synchronize open files + nextFile = partition->firstOpenFile; + while (nextFile) { + _FAT_syncToDisc (nextFile); + nextFile = nextFile->nextOpenFile; + } + + // Write out the fs info sector + _FAT_partition_writeFSinfo(partition); + + // Free memory used by the cache, writing it to disc at the same time + _FAT_cache_destructor (partition->cache); + + // Unlock the partition and destroy the lock + _FAT_unlock(&partition->lock); + _FAT_lock_deinit(&partition->lock); + + // Free memory used by the partition + _FAT_mem_free (partition); +} + +PARTITION* _FAT_partition_getPartitionFromPath (const char* path) { + const devoptab_t *devops; + + devops = GetDeviceOpTab (path); + + if (!devops) { + return NULL; + } + + return (PARTITION*)devops->deviceData; +} + +static void _FAT_updateFS_INFO(PARTITION * partition, uint8_t *sectorBuffer) { + partition->fat.numberFreeCluster = _FAT_fat_freeClusterCount(partition); + u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster); + u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster); + _FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer); +} + +void _FAT_partition_createFSinfo(PARTITION * partition) +{ + if(partition->readOnly || partition->filesysType != FS_FAT32) + return; + + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector); + if (!sectorBuffer) return; + memset(sectorBuffer, 0, partition->bytesPerSector); + + int i; + for(i = 0; i < 4; ++i) + { + sectorBuffer[FSIB_SIG1+i] = FS_INFO_SIG1[i]; + sectorBuffer[FSIB_SIG2+i] = FS_INFO_SIG2[i]; + } + + sectorBuffer[FSIB_bootSig_55] = 0x55; + sectorBuffer[FSIB_bootSig_AA] = 0xAA; + + _FAT_updateFS_INFO(partition,sectorBuffer); + + _FAT_mem_free(sectorBuffer); +} + +void _FAT_partition_readFSinfo(PARTITION * partition) +{ + if(partition->filesysType != FS_FAT32) + return; + + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector); + if (!sectorBuffer) return; + memset(sectorBuffer, 0, partition->bytesPerSector); + // Read first sector of disc + if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer)) { + _FAT_mem_free(sectorBuffer); + return; + } + + if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) != 0 || + memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4) != 0 || + u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster) == 0) + { + //sector does not yet exist, create one! + _FAT_partition_createFSinfo(partition); + } else { + partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster); + if(partition->fat.numberFreeCluster == 0xffffffff) { + _FAT_updateFS_INFO(partition,sectorBuffer); + partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster); + } + partition->fat.numberLastAllocCluster = u8array_to_u32(sectorBuffer, FSIB_numberLastAllocCluster); + } + _FAT_mem_free(sectorBuffer); +} + +void _FAT_partition_writeFSinfo(PARTITION * partition) +{ + if(partition->filesysType != FS_FAT32) + return; + + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector); + if (!sectorBuffer) return; + memset(sectorBuffer, 0, partition->bytesPerSector); + // Read first sector of disc + if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer)) { + _FAT_mem_free(sectorBuffer); + return; + } + + if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) || memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4)) { + _FAT_mem_free(sectorBuffer); + return; + } + + u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster); + u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster); + + // Write first sector of disc + _FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer); + _FAT_mem_free(sectorBuffer); +} + +uint32_t* _FAT_getCwdClusterPtr(const char* name) { + PARTITION *partition = _FAT_partition_getPartitionFromPath(name); + + if (!partition) { + return NULL; + } + + return &partition->cwdCluster; +} diff --git a/wii/libogc/libfat/partition.h b/wii/libogc/libfat/partition.h new file mode 100644 index 0000000000..ec27a0ebed --- /dev/null +++ b/wii/libogc/libfat/partition.h @@ -0,0 +1,107 @@ +/* + partition.h + Functions for mounting and dismounting partitions + on various block devices. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _PARTITION_H +#define _PARTITION_H + +#include "common.h" +#include "cache.h" +#include "lock.h" + +#define MIN_SECTOR_SIZE 512 +#define MAX_SECTOR_SIZE 4096 + +// Filesystem type +typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE; + +typedef struct { + sec_t fatStart; + uint32_t sectorsPerFat; + uint32_t lastCluster; + uint32_t firstFree; + uint32_t numberFreeCluster; + uint32_t numberLastAllocCluster; +} FAT; + +typedef struct { + const DISC_INTERFACE* disc; + CACHE* cache; + // Info about the partition + FS_TYPE filesysType; + uint64_t totalSize; + sec_t rootDirStart; + uint32_t rootDirCluster; + uint32_t numberOfSectors; + sec_t dataStart; + uint32_t bytesPerSector; + uint32_t sectorsPerCluster; + uint32_t bytesPerCluster; + uint32_t fsInfoSector; + FAT fat; + // Values that may change after construction + uint32_t cwdCluster; // Current working directory cluster + int openFileCount; + struct _FILE_STRUCT* firstOpenFile; // The start of a linked list of files + mutex_t lock; // A lock for partition operations + bool readOnly; // If this is set, then do not try writing to the disc + char label[12]; // Volume label +} PARTITION; + +/* +Mount the supplied device and return a pointer to the struct necessary to use it +*/ +PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector); + +/* +Dismount the device and free all structures used. +Will also attempt to synchronise all open files to disc. +*/ +void _FAT_partition_destructor (PARTITION* partition); + +/* +Return the partition specified in a path, as taken from the devoptab. +*/ +PARTITION* _FAT_partition_getPartitionFromPath (const char* path); + +/* +Create the fs info sector. +*/ +void _FAT_partition_createFSinfo(PARTITION * partition); + +/* +Read the fs info sector data. +*/ +void _FAT_partition_readFSinfo(PARTITION * partition); + +/* +Write the fs info sector data. +*/ +void _FAT_partition_writeFSinfo(PARTITION * partition); + +#endif // _PARTITION_H diff --git a/wii/libogc/libogc/aram.c b/wii/libogc/libogc/aram.c new file mode 100644 index 0000000000..a306c4564b --- /dev/null +++ b/wii/libogc/libogc/aram.c @@ -0,0 +1,378 @@ +/*------------------------------------------------------------- + +aram.c -- ARAM subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "aram.h" +#include "irq.h" +#include "cache.h" + +// DSPCR bits +#define DSPCR_DSPRESET 0x0800 // Reset DSP +#define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set +#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) +#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) +#define DSPCR_ARINTMSK 0x0040 +#define DSPCR_ARINT 0x0020 +#define DSPCR_AIINTMSK 0x0010 +#define DSPCR_AIINT 0x0008 +#define DSPCR_HALT 0x0004 // halt DSP +#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt +#define DSPCR_RES 0x0001 // reset DSP + +#define AR_ARAMEXPANSION 2 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +static vu16* const _dspReg = (u16*)0xCC005000; + +static ARCallback __ARDmaCallback = NULL; +static u32 __ARInit_Flag = 0; +static u32 __ARStackPointer = 0; +static u32 __ARFreeBlocks = 0; +static u32 *__ARBlockLen = NULL; + +static u32 __ARInternalSize = 0; +static u32 __ARExpansionSize = 0; +static u32 __ARSize = 0; + +static void __ARHandler(u32 irq,void *ctx); +static void __ARCheckSize(void); +static void __ARClearArea(u32 aramaddr,u32 len); + +ARCallback AR_RegisterCallback(ARCallback callback) +{ + u32 level; + ARCallback old; + + _CPU_ISR_Disable(level); + old = __ARDmaCallback; + __ARDmaCallback = callback; + _CPU_ISR_Restore(level); + return old; +} + +u32 AR_GetDMAStatus() +{ + u32 level,ret; + _CPU_ISR_Disable(level); + ret = ((_dspReg[5]&DSPCR_DSPDMA)==DSPCR_DSPDMA); + _CPU_ISR_Restore(level); + return ret; +} + +u32 AR_Init(u32 *stack_idx_array,u32 num_entries) +{ + u32 level; + u32 aram_base = 0x4000; + + if(__ARInit_Flag) return aram_base; + + _CPU_ISR_Disable(level); + + __ARDmaCallback = NULL; + + IRQ_Request(IRQ_DSP_ARAM,__ARHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_DSP_ARAM)); + + __ARStackPointer = aram_base; + __ARFreeBlocks = num_entries; + __ARBlockLen = stack_idx_array; + _dspReg[13] = (_dspReg[13]&~0xff)|(_dspReg[13]&0xff); + + __ARCheckSize(); + __ARInit_Flag = 1; + + _CPU_ISR_Restore(level); + return __ARStackPointer; +} + +void AR_StartDMA(u32 dir,u32 memaddr,u32 aramaddr,u32 len) +{ + u32 level; + + _CPU_ISR_Disable(level); + + // set main memory address + _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16); + _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16); + + // set aram address + _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16); + _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16); + + // set cntrl bits + _dspReg[20] = (_dspReg[20]&~0x8000)|_SHIFTL(dir,15,1); + _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16); + _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16); + + _CPU_ISR_Restore(level); +} + +u32 AR_Alloc(u32 len) +{ + u32 level; + u32 curraddr; + + _CPU_ISR_Disable(level); + curraddr = __ARStackPointer; + __ARStackPointer += len; + *__ARBlockLen++ = len; + __ARFreeBlocks--; + _CPU_ISR_Restore(level); + + return curraddr; +} + +u32 AR_Free(u32 *len) +{ + u32 level; + + _CPU_ISR_Disable(level); + __ARBlockLen--; + if(len) *len = *__ARBlockLen; + __ARStackPointer -= *__ARBlockLen; + __ARFreeBlocks++; + _CPU_ISR_Restore(level); + + return __ARStackPointer; +} + +void AR_Clear(u32 flag) +{ + switch(flag) { + case AR_ARAMINTALL: + if(__ARInternalSize) + __ARClearArea(0,__ARInternalSize); + break; + case AR_ARAMINTUSER: + if(__ARInternalSize) + __ARClearArea(0x4000,__ARInternalSize-0x4000); + break; + case AR_ARAMEXPANSION: + if(__ARInternalSize && __ARExpansionSize) + __ARClearArea(__ARInternalSize,__ARExpansionSize); + break; + default: + break; + } +} + +BOOL AR_CheckInit() +{ + return __ARInit_Flag; +} + +void AR_Reset() +{ + __ARInit_Flag = 0; +} + +u32 AR_GetSize() +{ + return __ARSize; +} + +u32 AR_GetBaseAddress() +{ + return 0x4000; +} + +u32 AR_GetInternalSize() +{ + return __ARInternalSize; +} + +static __inline__ void __ARClearInterrupt() +{ + u16 cause; + + cause = _dspReg[5]&~(DSPCR_DSPINT|DSPCR_AIINT); + _dspReg[5] = (cause|DSPCR_ARINT); +} + +static __inline__ void __ARWaitDma() +{ + while(_dspReg[5]&DSPCR_DSPDMA); +} + +static void __ARReadDMA(u32 memaddr,u32 aramaddr,u32 len) +{ + // set main memory address + _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16); + _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16); + + // set aram address + _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16); + _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16); + + // set cntrl bits + _dspReg[20] = (_dspReg[20]&~0x8000)|0x8000; + _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16); + _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16); + + __ARWaitDma(); + __ARClearInterrupt(); + +} + +static void __ARWriteDMA(u32 memaddr,u32 aramaddr,u32 len) +{ + // set main memory address + _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16); + _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16); + + // set aram address + _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16); + _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16); + + // set cntrl bits + _dspReg[20] = (_dspReg[20]&~0x8000); + _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16); + _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16); + + __ARWaitDma(); + __ARClearInterrupt(); +} + +static void __ARClearArea(u32 aramaddr,u32 len) +{ + u32 currlen,curraddr,endaddr; + static u8 zero_buffer[2048] ATTRIBUTE_ALIGN(32); + + while(!(_dspReg[11]&0x0001)); + + memset(zero_buffer,0,2048); + DCFlushRange(zero_buffer,2048); + + curraddr = aramaddr; + endaddr = aramaddr+len; + + currlen = 2048; + while(curraddr + +extern u8 __Arena1Lo[]; +extern char *__argvArena1Lo; +void build_argv (struct __argv* argstruct ); + +void __CheckARGV() { + + if ( __system_argv->argvMagic != ARGV_MAGIC ) { + __system_argv->argc = 0; + __system_argv->argv = NULL; + return; + } + + u8 *dest = (u8 *)( ((int)__Arena1Lo + 3) & ~3); + + memmove(dest, __system_argv->commandLine, __system_argv->length); + __system_argv->commandLine = (char *)dest; + build_argv(__system_argv); + + __argvArena1Lo = (char *)__system_argv->endARGV; + +} diff --git a/wii/libogc/libogc/arqmgr.c b/wii/libogc/libogc/arqmgr.c new file mode 100644 index 0000000000..ed3a99936b --- /dev/null +++ b/wii/libogc/libogc/arqmgr.c @@ -0,0 +1,155 @@ +/*------------------------------------------------------------- + +arqmgr.c -- ARAM task request queue management + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include + +#include "asm.h" +#include "processor.h" +#include "arqueue.h" +#include "arqmgr.h" + +#define ARQM_STACKENTRIES 16 +#define ARQM_ZEROBYTES 256 +#define ROUNDUP32(x) (((u32)(x)+0x1f)&~0x1f) + +typedef struct _arqm_info { + ARQRequest arqhandle; + ARQMCallback callback; + void *buffer; + u32 file_len; + u32 read_len; + u32 aram_start; + u32 curr_read_offset; + u32 curr_aram_offset; + volatile BOOL polled; +} ARQM_Info; + +static u32 __ARQMStackLocation; +static u32 __ARQMFreeBytes; +static u32 __ARQMStackPointer[ARQM_STACKENTRIES]; +static ARQM_Info __ARQMInfo[ARQM_STACKENTRIES]; +static u8 __ARQMZeroBuffer[ARQM_ZEROBYTES] ATTRIBUTE_ALIGN(32); + +static void __ARQMPollCallback(ARQRequest *req) +{ + u32 i; + ARQM_Info *ptr = NULL; + + for(i=0;iarqhandle) break; + } + if(i>=ARQM_STACKENTRIES) return; + + ptr->callback = NULL; + ptr->polled = TRUE; +} + +void ARQM_Init(u32 arambase,s32 len) +{ + u32 i; + + if(len<=0) return; + + __ARQMStackLocation = 0; + __ARQMStackPointer[0] = arambase; + __ARQMFreeBytes = len; + + for(i=0;i=rlen && __ARQMStackLocation<(ARQM_STACKENTRIES-1)) { + ptr = &__ARQMInfo[__ARQMStackLocation]; + + _CPU_ISR_Disable(level); + ptr->polled = FALSE; + ptr->aram_start = __ARQMStackPointer[__ARQMStackLocation++]; + __ARQMStackPointer[__ARQMStackLocation] = ptr->aram_start+rlen; + __ARQMFreeBytes -= rlen; + + ARQ_PostRequestAsync(&ptr->arqhandle,__ARQMStackLocation-1,ARQ_MRAMTOARAM,ARQ_PRIO_HI,ptr->aram_start,(u32)buffer,rlen,__ARQMPollCallback); + _CPU_ISR_Restore(level); + + while(ptr->polled==FALSE); + return (ptr->aram_start); + } + return 0; +} + +void ARQM_Pop() +{ + u32 level; + + _CPU_ISR_Disable(level); + + if(__ARQMStackLocation>1) { + __ARQMFreeBytes += (__ARQMStackPointer[__ARQMStackLocation]-__ARQMStackPointer[__ARQMStackLocation-1]); + __ARQMStackLocation--; + } + _CPU_ISR_Restore(level); +} + +u32 ARQM_GetZeroBuffer() +{ + return __ARQMStackPointer[0]; +} + +u32 ARQM_GetStackPointer() +{ + u32 level,tmp; + + _CPU_ISR_Disable(level) + tmp = __ARQMStackPointer[__ARQMStackLocation]; + _CPU_ISR_Restore(level); + + return tmp; +} + +u32 ARQM_GetFreeSize() +{ + u32 level,tmp; + + _CPU_ISR_Disable(level) + tmp = __ARQMFreeBytes; + _CPU_ISR_Restore(level); + + return tmp; +} diff --git a/wii/libogc/libogc/arqueue.c b/wii/libogc/libogc/arqueue.c new file mode 100644 index 0000000000..15b55e0644 --- /dev/null +++ b/wii/libogc/libogc/arqueue.c @@ -0,0 +1,257 @@ +/*------------------------------------------------------------- + +arqueue.c -- ARAM task request queue implementation + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include + +#include "asm.h" +#include "processor.h" +#include "arqueue.h" + +static u32 __ARQChunkSize; +static u32 __ARQInitFlag = 0; +static lwpq_t __ARQSyncQueue; + +static lwp_queue __ARQReqQueueLo; +static lwp_queue __ARQReqQueueHi; +static ARQRequest *__ARQReqPendingLo; +static ARQRequest *__ARQReqPendingHi; +static ARQCallback __ARQCallbackLo = NULL; +static ARQCallback __ARQCallbackHi = NULL; + +static __inline__ void __ARQPopTaskQueueHi() +{ + ARQRequest *req; + + req = (ARQRequest*)__lwp_queue_getI(&__ARQReqQueueHi); + if(!req) return; + + req->state = ARQ_TASK_RUNNING; + AR_StartDMA(req->dir,req->mram_addr,req->aram_addr,req->len); + __ARQCallbackHi = req->callback; + __ARQReqPendingHi = req; +} + +static void __ARQCallbackDummy(ARQRequest *req) +{ +} + +static void __ARQCallbackSync(ARQRequest *req) +{ + LWP_ThreadBroadcast(__ARQSyncQueue); +} + +static void __ARQServiceQueueLo() +{ + ARQRequest *req; + + if(!__ARQReqPendingLo) { + req = (ARQRequest*)__lwp_queue_getI(&__ARQReqQueueLo); + __ARQReqPendingLo = req; + } + + req = __ARQReqPendingLo; + if(req) { + req->state = ARQ_TASK_RUNNING; + if(req->len<=__ARQChunkSize) { + AR_StartDMA(req->dir,req->mram_addr,req->aram_addr,req->len); + __ARQCallbackLo = __ARQReqPendingLo->callback; + } else { + AR_StartDMA(req->dir,req->mram_addr,req->aram_addr,__ARQChunkSize); + __ARQReqPendingLo->len -= __ARQChunkSize; + __ARQReqPendingLo->aram_addr += __ARQChunkSize; + __ARQReqPendingLo->mram_addr += __ARQChunkSize; + } + } +} + +static void __ARInterruptServiceRoutine() +{ + if(__ARQCallbackHi) { + __ARQReqPendingHi->state = ARQ_TASK_FINISHED; + __ARQCallbackHi(__ARQReqPendingHi); + __ARQReqPendingHi = NULL; + __ARQCallbackHi = NULL; + } else if(__ARQCallbackLo) { + __ARQReqPendingLo->state = ARQ_TASK_FINISHED; + __ARQCallbackLo(__ARQReqPendingLo); + __ARQReqPendingLo = NULL; + __ARQCallbackLo = NULL; + } + __ARQPopTaskQueueHi(); + if(!__ARQReqPendingHi) __ARQServiceQueueLo(); +} + +void ARQ_Init() +{ + u32 level; + if(__ARQInitFlag) return; + + _CPU_ISR_Disable(level); + + __ARQReqPendingLo = NULL; + __ARQReqPendingHi = NULL; + __ARQCallbackLo = NULL; + __ARQCallbackHi = NULL; + + __ARQChunkSize = ARQ_DEF_CHUNK_SIZE; + + LWP_InitQueue(&__ARQSyncQueue); + + __lwp_queue_init_empty(&__ARQReqQueueLo); + __lwp_queue_init_empty(&__ARQReqQueueHi); + + AR_RegisterCallback(__ARInterruptServiceRoutine); + + __ARQInitFlag = 1; + _CPU_ISR_Restore(level); +} + +void ARQ_Reset() +{ + u32 level; + _CPU_ISR_Disable(level); + __ARQInitFlag = 0; + _CPU_ISR_Restore(level); +} + +void ARQ_SetChunkSize(u32 size) +{ + u32 level; + _CPU_ISR_Disable(level); + __ARQChunkSize = (size+31)&~31; + _CPU_ISR_Restore(level); +} + +u32 ARQ_GetChunkSize() +{ + return __ARQChunkSize; +} + +void ARQ_FlushQueue() +{ + u32 level; + + _CPU_ISR_Disable(level); + + __lwp_queue_init_empty(&__ARQReqQueueLo); + __lwp_queue_init_empty(&__ARQReqQueueHi); + if(!__ARQCallbackLo) __ARQReqPendingLo = NULL; + + _CPU_ISR_Restore(level); +} + +void ARQ_PostRequestAsync(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len,ARQCallback cb) +{ + u32 level; + ARQRequest *p; + + req->state = ARQ_TASK_READY; + req->dir = dir; + req->owner = owner; + req->aram_addr = aram_addr; + req->mram_addr = mram_addr; + req->len = len; + req->prio = prio; + req->callback = (cb==NULL) ? __ARQCallbackDummy : cb; + + _CPU_ISR_Disable(level); + + if(prio==ARQ_PRIO_LO) __lwp_queue_appendI(&__ARQReqQueueLo,&req->node); + else __lwp_queue_appendI(&__ARQReqQueueHi,&req->node); + + if(!__ARQReqPendingLo && !__ARQReqPendingHi) { + p = (ARQRequest*)__lwp_queue_getI(&__ARQReqQueueHi); + if(p) { + p->state = ARQ_TASK_RUNNING; + AR_StartDMA(p->dir,p->mram_addr,p->aram_addr,p->len); + __ARQCallbackHi = p->callback; + __ARQReqPendingHi = p; + } + if(!__ARQReqPendingHi) __ARQServiceQueueLo(); + } + _CPU_ISR_Restore(level); +} + +void ARQ_PostRequest(ARQRequest *req,u32 owner,u32 dir,u32 prio,u32 aram_addr,u32 mram_addr,u32 len) +{ + u32 level; + + ARQ_PostRequestAsync(req,owner,dir,prio,aram_addr,mram_addr,len,__ARQCallbackSync); + + _CPU_ISR_Disable(level); + while(req->state!=ARQ_TASK_FINISHED) { + LWP_ThreadSleep(__ARQSyncQueue); + } + _CPU_ISR_Restore(level); +} + +void ARQ_RemoveRequest(ARQRequest *req) +{ + u32 level; + + _CPU_ISR_Disable(level); + __lwp_queue_extractI(&req->node); + if(__ARQReqPendingLo && __ARQReqPendingLo==req && __ARQCallbackLo==NULL) __ARQReqPendingLo = NULL; + _CPU_ISR_Restore(level); +} + +u32 ARQ_RemoveOwnerRequest(u32 owner) +{ + u32 level,cnt; + ARQRequest *req; + + _CPU_ISR_Disable(level); + + cnt = 0; + req = (ARQRequest*)__ARQReqQueueHi.first; + while(req!=(ARQRequest*)__lwp_queue_tail(&__ARQReqQueueHi)) { + if(req->owner==owner) { + __lwp_queue_extractI(&req->node); + cnt++; + } + req = (ARQRequest*)req->node.next; + } + + req = (ARQRequest*)__ARQReqQueueLo.first; + while(req!=(ARQRequest*)__lwp_queue_tail(&__ARQReqQueueLo)) { + if(req->owner==owner) { + __lwp_queue_extractI(&req->node); + cnt++; + } + req = (ARQRequest*)req->node.next; + } + if(__ARQReqPendingLo && __ARQReqPendingLo==req && __ARQCallbackLo==NULL) __ARQReqPendingLo = NULL; + _CPU_ISR_Restore(level); + + return cnt; +} + diff --git a/wii/libogc/libogc/audio.c b/wii/libogc/libogc/audio.c new file mode 100644 index 0000000000..037688660a --- /dev/null +++ b/wii/libogc/libogc/audio.c @@ -0,0 +1,386 @@ +/*------------------------------------------------------------- + +audio.c -- Audio subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include +#include "asm.h" +#include "processor.h" +#include "irq.h" +#include "audio.h" +#include "lwp_watchdog.h" + +#define STACKSIZE 16384 + +// DSPCR bits +#define DSPCR_DSPRESET 0x0800 // Reset DSP +#define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set +#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) +#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) +#define DSPCR_ARINTMSK 0x0040 +#define DSPCR_ARINT 0x0020 +#define DSPCR_AIINTMSK 0x0010 +#define DSPCR_AIINT 0x0008 +#define DSPCR_HALT 0x0004 // halt DSP +#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt +#define DSPCR_RES 0x0001 // reset DSP + +// Audio Interface Registers +#define AI_CONTROL 0 +#define AI_STREAM_VOL 1 +#define AI_SAMPLE_COUNT 2 +#define AI_INT_TIMING 3 + +#define AI_PSTAT 0x01 +#define AI_AISFR 0x02 +#define AI_AIINTMSK 0x04 +#define AI_AIINT 0x08 +#define AI_AIINTVLD 0x10 +#define AI_SCRESET 0x20 +#define AI_DMAFR 0x40 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +#if defined(HW_DOL) + static vu32* const _aiReg = (u32*)0xCC006C00; +#elif defined(HW_RVL) + static vu32* const _aiReg = (u32*)0xCD006C00; +#else + #error HW model not supported. +#endif + +static vu16* const _dspReg = (u16*)0xCC005000; + +static u32 __AIInitFlag = 0; +static u32 __AIActive = 0; +static u8 *__CallbackStack __attribute__((used)) = NULL; +static u8 *__OldStack __attribute__((used)) = NULL; + +static u64 bound_32KHz,bound_48KHz,min_wait,max_wait,buffer; + +#if defined(HW_DOL) +static AISCallback __AIS_Callback; +#endif +static AIDCallback __AID_Callback; + +static void __AICallbackStackSwitch(AIDCallback handler) +{ + __asm__ __volatile__("mflr %r0\n\t\ + stw %r0,4(%r1)\n\t\ + stwu %r1,-24(%r1)\n\t\ + stw %r31,20(%r1)\n\t\ + mr %r31,%r3\n\t\ + lis %r5,__OldStack@ha\n\t\ + addi %r5,%r5,__OldStack@l\n\t\ + stw %r1,0(%r5)\n\t\ + lis %r5,__CallbackStack@ha\n\t\ + addi %r5,%r5,__CallbackStack@l\n\t\ + lwz %r1,0(%r5)\n\t\ + subi %r1,%r1,8\n\t\ + mtlr %r31\n\t\ + blrl\n\t\ + lis %r5,__OldStack@ha\n\t\ + addi %r5,%r5,__OldStack@l\n\t\ + lwz %r1,0(%r5)\n\t\ + lwz %r0,28(%r1)\n\t\ + lwz %r31,20(%r1)\n\t\ + addi %r1,%r1,24\n\t\ + mtlr %r0\n" + ); +} + +#if defined(HW_DOL) +static void __AISHandler(u32 nIrq,void *pCtx) +{ + if(__AIS_Callback) + __AIS_Callback(_aiReg[AI_SAMPLE_COUNT]); + _aiReg[AI_CONTROL] |= AI_AIINT; +} +#endif + +static void __AIDHandler(u32 nIrq,void *pCtx) +{ + _dspReg[5] = (_dspReg[5]&~(DSPCR_DSPINT|DSPCR_ARINT))|DSPCR_AIINT; + if(__AID_Callback) { + if(!__AIActive) { + __AIActive = 1; + if(__CallbackStack) + __AICallbackStackSwitch(__AID_Callback); + else + __AID_Callback(); + __AIActive = 0; + } + } +} + +static void __AISRCINIT() +{ + int done = 0; + u32 sample_counter; + u64 time1, time2, tdiff; + u64 wait = 0; + + while (!done) { + _aiReg[AI_CONTROL] |= AI_SCRESET; + _aiReg[AI_CONTROL] &= ~AI_AISFR; + _aiReg[AI_CONTROL] |= AI_PSTAT; + +#ifdef HW_DOL + sample_counter = _aiReg[AI_SAMPLE_COUNT]; + while (sample_counter == _aiReg[AI_SAMPLE_COUNT]) {} +#else + sample_counter = _aiReg[AI_SAMPLE_COUNT] & 0x7fffffff; + while (sample_counter == (_aiReg[AI_SAMPLE_COUNT] & 0x7fffffff)) {} +#endif + + time1 = gettime(); + + _aiReg[AI_CONTROL] |= AI_AISFR; + _aiReg[AI_CONTROL] |= AI_PSTAT; + +#ifdef HW_DOL + sample_counter = _aiReg[AI_SAMPLE_COUNT]; + while (sample_counter == _aiReg[AI_SAMPLE_COUNT]) {} +#else + sample_counter = _aiReg[AI_SAMPLE_COUNT] & 0x7fffffff; + while (sample_counter == (_aiReg[AI_SAMPLE_COUNT] & 0x7fffffff)) {} +#endif + + time2 = gettime(); + tdiff = time2 - time1; + + _aiReg[AI_CONTROL] &= ~AI_AISFR; + _aiReg[AI_CONTROL] &= ~AI_PSTAT; + + if ((tdiff > (bound_32KHz - buffer)) && + (tdiff < (bound_32KHz + buffer))) { + if (tdiff < (bound_48KHz - buffer)) { + wait = max_wait; + done = 1; + } + } else { + wait = min_wait; + done = 1; + } + } + + while (diff_ticks(time2, gettime()) < wait) {} +} + +void AUDIO_Init(u8 *stack) +{ + u32 rate,level; + + if(!__AIInitFlag) { + bound_32KHz = nanosecs_to_ticks(31524); + bound_48KHz = nanosecs_to_ticks(42024); + min_wait = nanosecs_to_ticks(42000); + max_wait = nanosecs_to_ticks(63000); + buffer = nanosecs_to_ticks(3000); + + _aiReg[AI_CONTROL] &= ~(AI_AIINTVLD|AI_AIINTMSK|AI_PSTAT); + _aiReg[1] = 0; + _aiReg[3] = 0; + + _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET; + + rate = (_SHIFTR(_aiReg[AI_CONTROL],6,1))^1; + if(rate==AI_SAMPLERATE_48KHZ) { + _aiReg[AI_CONTROL] &= ~AI_DMAFR; + _CPU_ISR_Disable(level); + __AISRCINIT(); + _aiReg[AI_CONTROL] |= AI_DMAFR; + _CPU_ISR_Restore(level); + } + + __AID_Callback = NULL; + + __OldStack = NULL; // davem - use it or lose it + // looks like 3.4 isn't picking up the use from the asm below + __CallbackStack = stack; + + IRQ_Request(IRQ_DSP_AI,__AIDHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_DSP_AI)); +#if defined(HW_DOL) + __AIS_Callback = NULL; + + IRQ_Request(IRQ_AI,__AISHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_AI)); +#endif + __AIInitFlag = 1; + } +} + +#if defined(HW_DOL) +void AUDIO_SetStreamVolLeft(u8 vol) +{ + _aiReg[1] = (_aiReg[1]&~0x000000ff)|(vol&0xff); +} + +u8 AUDIO_GetStreamVolLeft() +{ + return (u8)(_aiReg[1]&0xff); +} + +void AUDIO_SetStreamVolRight(u8 vol) +{ + _aiReg[1] = (_aiReg[1]&~0x0000ff00)|(_SHIFTL(vol,8,8)); +} + +u8 AUDIO_GetStreamVolRight() +{ + return (u8)(_SHIFTR(_aiReg[1],8,8)); +} + +void AUDIO_SetStreamSampleRate(u32 rate) +{ + _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_AISFR)|(_SHIFTL(rate,1,1)); +} + +u32 AUDIO_GetStreamSampleRate() +{ + return _SHIFTR(_aiReg[AI_CONTROL],1,1); +} + +void AUDIO_SetStreamTrigger(u32 cnt) +{ + _aiReg[3] = cnt; +} + +void AUDIO_ResetStreamSampleCnt() +{ + _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET; +} + +void AUDIO_SetStreamPlayState(u32 state) +{ + u32 playstate,streamrate; + u32 volright,volleft,level; + + playstate = AUDIO_GetStreamPlayState(); + streamrate = AUDIO_GetStreamSampleRate(); + if(playstate!=state && state==AI_STREAM_START && streamrate==AI_SAMPLERATE_32KHZ ) { + volright = AUDIO_GetStreamVolRight(); + AUDIO_SetStreamVolRight(0); + volleft = AUDIO_GetStreamVolLeft(); + AUDIO_SetStreamVolLeft(0); + + _CPU_ISR_Disable(level); + __AISRCINIT(); + _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET; + _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~0x01)|0x01; + _CPU_ISR_Restore(level); + AUDIO_SetStreamVolRight(volright); + AUDIO_SetStreamVolLeft(volleft); + } else { + _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_PSTAT)|(state&AI_PSTAT); + } +} + +u32 AUDIO_GetStreamPlayState() +{ + return (_aiReg[AI_CONTROL]&AI_PSTAT); +} +#endif + +AIDCallback AUDIO_RegisterDMACallback(AIDCallback callback) +{ + u32 level; + AIDCallback old; + + _CPU_ISR_Disable(level); + old = __AID_Callback; + __AID_Callback = callback; + _CPU_ISR_Restore(level); + return old; +} + +void AUDIO_InitDMA(u32 startaddr,u32 len) +{ + u32 level; + + _CPU_ISR_Disable(level); + _dspReg[24] = (_dspReg[24]&~0x1fff)|(_SHIFTR(startaddr,16,13)); + _dspReg[25] = (_dspReg[25]&~0xffe0)|(startaddr&0xffff); + _dspReg[27] = (_dspReg[27]&~0x7fff)|(_SHIFTR(len,5,15)); + _CPU_ISR_Restore(level); +} + +u16 AUDIO_GetDMAEnableFlag() +{ + return (_SHIFTR(_dspReg[27],15,1)); +} + +void AUDIO_StartDMA() +{ + _dspReg[27] = (_dspReg[27]&~0x8000)|0x8000; +} + +void AUDIO_StopDMA() +{ + _dspReg[27] = (_dspReg[27]&~0x8000); +} + +u32 AUDIO_GetDMABytesLeft() +{ + return (_SHIFTL(_dspReg[29],5,15)); +} + +u32 AUDIO_GetDMAStartAddr() +{ + return (_SHIFTL((_dspReg[24]&0x1fff),16,13)|(_dspReg[25]&0xffe0)); +} + +u32 AUDIO_GetDMALength() +{ + return ((_dspReg[27]&0x7fff)<<5); +} + +void AUDIO_SetDSPSampleRate(u8 rate) +{ + u32 level; + + if(AUDIO_GetDSPSampleRate()!=rate) { + _aiReg[AI_CONTROL] &= ~AI_DMAFR; + if(rate==AI_SAMPLERATE_32KHZ) { + _CPU_ISR_Disable(level); + __AISRCINIT(); + _aiReg[AI_CONTROL] |= AI_DMAFR; + _CPU_ISR_Restore(level); + } + } +} + +u32 AUDIO_GetDSPSampleRate() +{ + return (_SHIFTR(_aiReg[AI_CONTROL],6,1))^1; //0^1(1) = 48Khz, 1^1(0) = 32Khz +} diff --git a/wii/libogc/libogc/cache.c b/wii/libogc/libogc/cache.c new file mode 100644 index 0000000000..e9b35ade13 --- /dev/null +++ b/wii/libogc/libogc/cache.c @@ -0,0 +1,177 @@ +/*------------------------------------------------------------- + +cache.c -- Cache interface + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include "cache.h" + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +extern void __LCEnable(); +extern void L2GlobalInvalidate(); +extern void L2Enable(); + +void LCEnable() +{ + u32 level; + + _CPU_ISR_Disable(level); + __LCEnable(); + _CPU_ISR_Restore(level); +} + +u32 LCLoadData(void *dstAddr,void *srcAddr,u32 nCount) +{ + u32 cnt,blocks; + + if((s32)nCount<=0) return 0; + + cnt = (nCount+31)>>5; + blocks = (cnt+127)>>7; + while(cnt) { + if(cnt<0x80) { + LCLoadBlocks(dstAddr,srcAddr,cnt); + cnt = 0; + break; + } + LCLoadBlocks(dstAddr,srcAddr,0); + cnt -= 128; + dstAddr += 4096; + srcAddr += 4096; + } + return blocks; +} + +u32 LCStoreData(void *dstAddr,void *srcAddr,u32 nCount) +{ + u32 cnt,blocks; + + if((s32)nCount<=0) return 0; + + cnt = (nCount+31)>>5; + blocks = (cnt+127)>>7; + while(cnt) { + if(cnt<0x80) { + LCStoreBlocks(dstAddr,srcAddr,cnt); + cnt = 0; + break; + } + LCStoreBlocks(dstAddr,srcAddr,0); + cnt -= 128; + dstAddr += 4096; + srcAddr += 4096; + } + return blocks; +} + +u32 LCQueueLength() +{ + u32 hid2 = mfspr(920); + return _SHIFTR(hid2,4,4); +} + +u32 LCQueueWait(u32 len) +{ + len++; + while(_SHIFTR(mfspr(920),4,4)>=len); + return len; +} + +void LCFlushQueue() +{ + mtspr(922,0); + mtspr(923,1); + ppcsync(); +} + +void LCAlloc(void *addr,u32 bytes) +{ + u32 level; + u32 cnt = bytes>>5; + u32 hid2 = mfspr(920); + if(!(hid2&0x10000000)) { + _CPU_ISR_Disable(level); + __LCEnable(); + _CPU_ISR_Restore(level); + } + LCAllocTags(TRUE,addr,cnt); +} + +void LCAllocNoInvalidate(void *addr,u32 bytes) +{ + u32 level; + u32 cnt = bytes>>5; + u32 hid2 = mfspr(920); + if(!(hid2&0x10000000)) { + _CPU_ISR_Disable(level); + __LCEnable(); + _CPU_ISR_Restore(level); + } + LCAllocTags(FALSE,addr,cnt); +} +#ifdef HW_RVL +void L2Enhance() +{ + u32 level, hid4; + u32 *stub = (u32*)0x80001800; + _CPU_ISR_Disable(level); + hid4 = mfspr(HID4); + // make sure H4A is set before doing anything + if (hid4 & 0x80000000) { + // There's no easy way to flush only L2, so just flush everything + // L2GlobalInvalidate will take care of syncing + DCFlushRangeNoSync((void*)0x80000000, 0x01800000); + DCFlushRangeNoSync((void*)0x90000000, 0x04000000); + + // Invalidate L2 (this will disable it first) + L2GlobalInvalidate(); + // set bits: L2FM=01, BCO=1, L2MUM=1 + hid4 |= 0x24200000; + mtspr(HID4, hid4); + // Re-enable L2 + L2Enable(); + + // look for HBC stub (STUBHAXX) + if (stub[1]==0x53545542 && stub[2]==0x48415858) { + // look for a HID4 write + for (stub += 3; (u32)stub < 0x80003000; stub++) { + if ((stub[0] & 0xFC1FFFFF)==0x7C13FBA6) { + write32((u32)stub, 0x60000000); + break; + } + } + } + } + _CPU_ISR_Restore(level); +} +#endif diff --git a/wii/libogc/libogc/cache_asm.S b/wii/libogc/libogc/cache_asm.S new file mode 100644 index 0000000000..a6e39de916 --- /dev/null +++ b/wii/libogc/libogc/cache_asm.S @@ -0,0 +1,471 @@ +/*------------------------------------------------------------- + +cache_asm.S -- Cache interface + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include + + .globl DCFlashInvalidate +DCFlashInvalidate: + mfspr r3,HID0 + ori r3,r3,0x0400 + mtspr HID0,r3 + isync + blr + + .globl DCEnable +DCEnable: + mfspr r3,HID0 + ori r3,r3,0x4000 + mtspr HID0,r3 + isync + blr + + .globl DCDisable +DCDisable: + mfspr r3,HID0 + rlwinm r3,r3,0,18,16 + mtspr HID0,r3 + isync + blr + + .globl DCFreeze +DCFreeze: + mfspr r3,HID0 + ori r3,r3,0x1000 + mtspr HID0,r3 + isync + blr + + .globl DCUnfreeze +DCUnfreeze: + mfspr r3,HID0 + rlwinm r3,r3,0,20,18 + mtspr HID0,r3 + isync + blr + + .globl DCTouchLoad +DCTouchLoad: + dcbt r0,r3 + blr + + .globl DCBlockZero +DCBlockZero: + dcbz r0,r3 + blr + + .globl DCBlockStore +DCBlockStore: + dcbst r0,r3 + blr + + .globl DCBlockFlush +DCBlockFlush: + dcbf r0,r3 + blr + + .globl DCBlockInvalidate +DCBlockInvalidate: + dcbi r0,r3 + blr + + .globl DCInvalidateRange +DCInvalidateRange: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + dcbi r0, r3 + addi r3, r3, 0x20 + bdnz 2b + blr + + .globl DCFlushRange +DCFlushRange: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + dcbf r0, r3 + addi r3, r3, 0x20 + bdnz 2b + sc + blr + + .globl DCStoreRange +DCStoreRange: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + dcbst r0, r3 + addi r3, r3, 0x20 + bdnz 2b + sc + blr + + .globl DCFlushRangeNoSync +DCFlushRangeNoSync: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + dcbf r0, r3 + addi r3, r3, 0x20 + bdnz 2b + blr + + .globl DCStoreRangeNoSync +DCStoreRangeNoSync: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + dcbst r0, r3 + addi r3, r3, 0x20 + bdnz 2b + blr + + .globl DCZeroRange +DCZeroRange: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + dcbz r0, r3 + addi r3, r3, 0x20 + bdnz 2b + blr + + .globl DCTouchRange +DCTouchRange: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + dcbt r0, r3 + addi r3, r3, 0x20 + bdnz 2b + blr + + .globl ICInvalidateRange +ICInvalidateRange: + cmplwi r4, 0 # zero or negative size? + blelr + clrlwi. r5, r3, 27 # check for lower bits set in address + beq 1f + addi r4, r4, 0x20 +1: + addi r4, r4, 0x1f + srwi r4, r4, 5 + mtctr r4 +2: + icbi r0, r3 + addi r3, r3, 0x20 + bdnz 2b + sync + isync + blr + + .globl ICFlashInvalidate +ICFlashInvalidate: + mfspr r3,HID0 + ori r3,r3,0x0800 + mtspr HID0,r3 + isync + blr + + .globl ICEnable +ICEnable: + mfspr r3,HID0 + ori r3,r3,0x8000 + mtspr HID0,r3 + isync + blr + + .globl ICDisable +ICDisable: + mfspr r3,HID0 + rlwinm r3,r3,0,17,15 + mtspr HID0,r3 + isync + blr + + .globl ICFreeze +ICFreeze: + mfspr r3,HID0 + ori r3,r3,0x2000 + mtspr HID0,r3 + isync + blr + + .globl ICUnfreeze +ICUnfreeze: + mfspr r3,HID0 + rlwinm r3,r3,0,19,17 + mtspr HID0,r3 + isync + blr + + .globl ICBlockInvalidate +ICBlockInvalidate: + icbi r0,r3 + blr + + .globl ICSync +ICSync: + isync + blr + + .globl L2Init +L2Init: + mflr r0 + stw r0,4(sp) + stwu sp,-16(sp) + stw r31,12(sp) + mfmsr r3 + mr r31,r3 + sync + li r3,48 + mtmsr r3 + sync + bl L2Disable + bl L2GlobalInvalidate + mr r3,r31 + mtmsr r3 + lwz r0,20(sp) + lwz r31,12(sp) + mtlr r0 + blr + + .globl L2Enable +L2Enable: + sync + mfspr r3,L2CR; + oris r0,r3,0x8000 + rlwinm r3,r0,0,11,9 + mtspr L2CR,r3 + sync + blr + + .globl L2Disable +L2Disable: + sync + mfspr r3,L2CR + clrlwi r3,r3,1 + mtspr L2CR,r3 + sync + blr + + .globl L2GlobalInvalidate +L2GlobalInvalidate: + mflr r0 + stw r0,4(sp) + stwu sp,-8(sp) + bl L2Disable + mfspr r3,L2CR + oris r3,r3,0x0020 + mtspr L2CR,r3 +1: mfspr r3,L2CR + clrlwi r0,r3,31 + cmplwi r0,0x0000 + bne 1b + mfspr r3,L2CR + rlwinm r3,r3,0,11,9 + mtspr L2CR,r3 +2: mfspr r3,L2CR + clrlwi r0,r3,31 + cmplwi r0,0x0000 + bne 2b + lwz r0,12(sp) + addi sp,sp,8 + mtlr r0 + blr + + .globl __LCEnable +__LCEnable: + mfmsr r5 + ori r5,r5,0x1000 + mtmsr r5 + lis r3,0x8000 + li r4,1024 + mtctr r4 +1: dcbt r0,r3 + dcbst r0,r3 + addi r3,r3,32 + bdnz 1b + mfspr r4,HID2 + oris r4,r4,0x100f + mtspr HID2,r4 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + lis r3,0xe000 + ori r3,r3,0x0002 + mtspr DBAT3L,r3 + ori r3,r3,0x01fe + mtspr DBAT3U,r3 + isync + lis r3,0xe000 + li r6,512 + mtctr r6 + li r6,0 +2: dcbz_l r6,r3 + addi r3,r3,32 + bdnz 2b + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + blr + + .globl LCDisable +LCDisable: + lis r3,0xe000 + li r4,512 + mtctr r4 +1: dcbi r0,r3 + addi r3,r3,32 + bdnz 1b + mfspr r4,HID2 + rlwinm r4,r4,0,4,2 + mtspr HID2,r4 + blr + + .globl LCAllocOneTag +LCAllocOneTag: + cmpwi r3,0 + beq 1f + dcbi r0,r4 +1: dcbz_l r0,r4 + blr + + .globl LCAllocTags +LCAllocTags: + mflr r6 + cmplwi r5,0 + ble 2f + mtctr r5 + cmpwi r3,0 + beq 3f +1: dcbi r0,r4 + dcbz_l r0,r4 + addi r4,r4,32 + bdnz 1b + b 2f +3: dcbz_l r0,r4 + addi r4,r4,32 + bdnz 3b +2: mtlr r6 + blr + + .globl LCLoadBlocks +LCLoadBlocks: + extrwi r6,r5,5,25 + clrlwi r4,r4,4 + or r6,r6,r4 + mtspr DMAU,r6 + clrlslwi r6,r5,30,2 + or r6,r6,r3 + ori r6,r6,0x0012 + mtspr DMAL,r6 + blr + + .globl LCStoreBlocks +LCStoreBlocks: + extrwi r6,r5,5,25 + clrlwi r4,r4,4 + or r6,r6,r3 + mtspr DMAU,r6 + clrlslwi r6,r5,30,2 + or r6,r6,r4 + ori r6,r6,0x0002 + mtspr DMAL,r6 + blr + diff --git a/wii/libogc/libogc/card.c b/wii/libogc/libogc/card.c new file mode 100644 index 0000000000..6afaa6e2d7 --- /dev/null +++ b/wii/libogc/libogc/card.c @@ -0,0 +1,2977 @@ +/*------------------------------------------------------------- + +card.c -- Memory card subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "system.h" +#include "ogcsys.h" +#include "cache.h" +#include "dsp.h" +#include "lwp.h" +#include "exi.h" +#include "card.h" + +#define CARD_SYSAREA 5 +#define CARD_SYSDIR 0x2000 +#define CARD_SYSDIR_BACK 0x4000 +#define CARD_SYSBAT 0x6000 +#define CARD_SYSBAT_BACK 0x8000 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) +#define _ROTL(v,s) \ + (((u32)v<>(0x20-s))) + +#define CARD_STATUS_UNLOCKED 0x40 + +struct card_header { + u32 serial[0x08]; + u16 device_id; + u16 size; + u16 encoding; + u8 padding[0x1d6]; + u16 chksum1; + u16 chksum2; +} ATTRIBUTE_PACKED; + +struct card_direntry { + u8 gamecode[4]; + u8 company[2]; + u8 pad_00; + u8 bannerfmt; + u8 filename[CARD_FILENAMELEN]; + u32 lastmodified; + u32 iconaddr; + u16 iconfmt; + u16 iconspeed; + u8 permission; + u8 copytimes; + u16 block; + u16 length; + u16 pad_01; + u32 commentaddr; +} ATTRIBUTE_PACKED; + +struct card_dat { // dir allocation table + struct card_direntry entries[CARD_MAXFILES]; +}; + +struct card_dircntrl { + u8 pad[58]; + u16 updated; + u16 chksum1; + u16 chksum2; +} ATTRIBUTE_PACKED; + +struct card_bat { + u16 chksum1; + u16 chksum2; + u16 updated; + u16 freeblocks; + u16 lastalloc; + u16 fat[0xffc]; +} ATTRIBUTE_PACKED; + +typedef struct _card_block { + u8 cmd[9]; + u32 cmd_len; + u32 cmd_mode; + u32 cmd_blck_cnt; + u32 cmd_sector_addr; + u32 cmd_retries; + u32 attached; + s32 result; + u32 cid; + u16 card_size; + u32 mount_step; + u32 format_step; + u32 sector_size; + u16 blocks; + u32 latency; + u32 cipher; + u32 key[3]; + u32 transfer_cnt; + u16 curr_fileblock; + card_file *curr_file; + struct card_dat *curr_dir; + struct card_bat *curr_fat; + void *workarea; + void *cmd_usr_buf; + lwpq_t wait_sync_queue; + syswd_t timeout_svc; + dsptask_t dsp_task; + + cardcallback card_ext_cb; + cardcallback card_tx_cb; + cardcallback card_exi_cb; + cardcallback card_api_cb; + cardcallback card_xfer_cb; + cardcallback card_erase_cb; + cardcallback card_unlock_cb; +} card_block; + +#if defined(HW_RVL) + +static u32 _cardunlockdata[0x160] ATTRIBUTE_ALIGN(32) = +{ + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000021,0x02ff0021, + 0x13061203,0x12041305,0x009200ff,0x0088ffff, + 0x0089ffff,0x008affff,0x008bffff,0x8f0002bf, + 0x008816fc,0xdcd116fd,0x000016fb,0x000102bf, + 0x008e25ff,0x0380ff00,0x02940027,0x02bf008e, + 0x1fdf24ff,0x02403fff,0x00980400,0x009a0010, + 0x00990000,0x8e0002bf,0x009402bf,0x864402bf, + 0x008816fc,0xdcd116fd,0x000316fb,0x00018f00, + 0x02bf008e,0x0380cdd1,0x02940048,0x27ff0380, + 0x00010295,0x005a0380,0x00020295,0x8000029f, + 0x00480021,0x8e0002bf,0x008e25ff,0x02bf008e, + 0x25ff02bf,0x008e25ff,0x02bf008e,0x00c5ffff, + 0x03403fff,0x1c9f02bf,0x008e00c7,0xffff02bf, + 0x008e00c6,0xffff02bf,0x008e00c0,0xffff02bf, + 0x008e20ff,0x03403fff,0x1f5f02bf,0x008e21ff, + 0x02bf008e,0x23ff1205,0x1206029f,0x80b50021, + 0x27fc03c0,0x8000029d,0x008802df,0x27fe03c0, + 0x8000029c,0x008e02df,0x2ece2ccf,0x00f8ffcd, + 0x00f9ffc9,0x00faffcb,0x26c902c0,0x0004029d, + 0x009c02df,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000 +}; + +#elif defined(HW_DOL) + +static u32 _cardunlockdata[0x160] ATTRIBUTE_ALIGN(32) = +{ + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000021,0x02ff0021, + 0x13061203,0x12041305,0x009200ff,0x0088ffff, + 0x0089ffff,0x008affff,0x008bffff,0x8f0002bf, + 0x008816fc,0xdcd116fd,0x000016fb,0x000102bf, + 0x008e25ff,0x0380ff00,0x02940027,0x02bf008e, + 0x1fdf24ff,0x02400fff,0x00980400,0x009a0010, + 0x00990000,0x8e0002bf,0x009402bf,0x864402bf, + 0x008816fc,0xdcd116fd,0x000316fb,0x00018f00, + 0x02bf008e,0x0380cdd1,0x02940048,0x27ff0380, + 0x00010295,0x005a0380,0x00020295,0x8000029f, + 0x00480021,0x8e0002bf,0x008e25ff,0x02bf008e, + 0x25ff02bf,0x008e25ff,0x02bf008e,0x00c5ffff, + 0x03400fff,0x1c9f02bf,0x008e00c7,0xffff02bf, + 0x008e00c6,0xffff02bf,0x008e00c0,0xffff02bf, + 0x008e20ff,0x03400fff,0x1f5f02bf,0x008e21ff, + 0x02bf008e,0x23ff1205,0x1206029f,0x80b50021, + 0x27fc03c0,0x8000029d,0x008802df,0x27fe03c0, + 0x8000029c,0x008e02df,0x2ece2ccf,0x00f8ffcd, + 0x00f9ffc9,0x00faffcb,0x26c902c0,0x0004029d, + 0x009c02df,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000 +}; +#endif + +static u32 card_sector_size[] = +{ + 0x0002000, + 0x0004000, + 0x0008000, + 0x0010000, + 0x0020000, + 0x0040000, + 0x0000000, + 0x0000000 +}; + +static u32 card_latency[] = +{ + 0x00000004, + 0x00000008, + 0x00000010, + 0x00000020, + 0x00000030, + 0x00000080, + 0x00000100, + 0x00000200 +}; + +static u32 card_inited = 0; +static u32 crand_next = 1; + +static u8 card_gamecode[4] = {0xff,0xff,0xff,0xff}; +static u8 card_company[2] = {0xff,0xff}; +static card_block cardmap[2]; + +static void __card_mountcallback(s32 chn,s32 result); +static void __erase_callback(s32 chn,s32 result); +static s32 __dounlock(s32 chn,u32 *key); +static s32 __card_readsegment(s32 chn,cardcallback callback); +static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback); +static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback); +static s32 __card_updatedir(s32 chn,cardcallback callback); +static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback); +static s32 __card_writepage(s32 chn,cardcallback callback); +static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback); +static s32 __card_onreset(s32 final); + +static sys_resetinfo card_resetinfo = { + {}, + __card_onreset, + 127 +}; + +extern unsigned long gettick(); +extern long long gettime(); +extern syssram* __SYS_LockSram(); +extern syssramex* __SYS_LockSramEx(); +extern u32 __SYS_UnlockSram(u32 write); +extern u32 __SYS_UnlockSramEx(u32 write); + +static vu16* const _viReg = (u16*)0xCC002000; + +/* new api */ +static s32 __card_onreset(s32 final) +{ + if(final==FALSE) { + if(CARD_Unmount(CARD_SLOTA)==-1) return 0; + if(CARD_Unmount(CARD_SLOTB)==-1) return 0; + } + return 1; +} + +static void __card_checksum(u16 *buff,u32 len,u16 *cs1,u16 *cs2) +{ + u32 i; + *cs1 = 0; + *cs2 = 0; + len /= 2; + for (i = 0; i < len; ++i) { + *cs1 += buff[i]; + *cs2 += (buff[i] ^ 0xffff); + } + if (*cs1 == 0xffff) *cs1 = 0; + if (*cs2 == 0xffff) *cs2 = 0; +} + +static s32 __card_putcntrlblock(card_block *card,s32 result) +{ + u32 level; + + _CPU_ISR_Disable(level); + if(card->attached) card->result = result; + else if(card->result==CARD_ERROR_BUSY) card->result = result; + _CPU_ISR_Restore(level); + return result; +} + +static s32 __card_getcntrlblock(s32 chn,card_block **card) +{ + s32 ret; + u32 level; + card_block *rcard = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + + _CPU_ISR_Disable(level); + rcard = &cardmap[chn]; + if(!rcard->attached) { + _CPU_ISR_Restore(level); + return CARD_ERROR_NOCARD; + } + + ret = CARD_ERROR_BUSY; + if(rcard->result!=CARD_ERROR_BUSY) { + rcard->result = CARD_ERROR_BUSY; + rcard->card_api_cb = NULL; + *card = rcard; + ret = CARD_ERROR_READY; + } + _CPU_ISR_Restore(level); + return ret; +} + +static __inline__ struct card_dat* __card_getdirblock(card_block *card) +{ + return card->curr_dir; +} + +static __inline__ struct card_bat* __card_getbatblock(card_block *card) +{ + return card->curr_fat; +} + +static s32 __card_sync(s32 chn) +{ + s32 ret; + u32 level; + card_block *card = &cardmap[chn]; + + _CPU_ISR_Disable(level); + while((ret=CARD_GetErrorCode(chn))==CARD_ERROR_BUSY) { + LWP_ThreadSleep(card->wait_sync_queue); + } + _CPU_ISR_Restore(level); + return ret; +} + +static void __card_synccallback(s32 chn,s32 result) +{ + u32 level; + card_block *card = &cardmap[chn]; + _CPU_ISR_Disable(level); + LWP_ThreadBroadcast(card->wait_sync_queue); + _CPU_ISR_Restore(level); +} + +static void __card_updateiconoffsets(struct card_direntry *entry,card_stat *stats) +{ + s32 i; + u8 bnrfmt,nicons; + u32 iconaddr,iconbase; + + iconaddr = entry->iconaddr; + if(iconaddr==-1) { + stats->banner_fmt = 0; + stats->icon_fmt = 0; + stats->icon_speed = 0; + iconaddr = 0; + } + + if(entry->bannerfmt&CARD_BANNER_MASK) { + if(!(entry->bannerfmt&0x10)) { + bnrfmt = (entry->bannerfmt&CARD_BANNER_MASK); + if(bnrfmt==CARD_BANNER_CI) { + stats->banner_fmt = bnrfmt; + stats->offset_banner = iconaddr; + stats->offset_banner_tlut = iconaddr+3072; + iconaddr += (3072+512); + } else if(bnrfmt==CARD_BANNER_RGB) { + stats->banner_fmt = bnrfmt; + stats->offset_banner = iconaddr; + stats->offset_banner_tlut = -1; + iconaddr += 6144; + } + } else { + stats->offset_banner = -1; + stats->offset_banner_tlut = -1; + } + } + + nicons = 0; + for(i=0;iiconfmt[i] = ((entry->iconfmt>>(i<<1))&CARD_ICON_MASK); + stats->iconspeed[i] = ((entry->iconspeed>>(i<<1))&CARD_SPEED_MASK); + if(stats->iconspeed[i]==0) stats->iconfmt[i] = 0; + if(stats->iconfmt[i]) nicons++; + } + + iconbase = iconaddr; + for(i=0;iiconfmt[i]) { + case 1: //CARD_ICON_CI with shared palette + stats->offset_icon[i] = iconaddr; + stats->offset_icon_tlut[i] = iconbase + (nicons*1024); + iconaddr += 1024; + break; + case 2: //CARD_ICON_RGB + stats->offset_icon[i] = iconaddr; + stats->offset_icon_tlut[i] = -1; + iconaddr += 3072; + break; + case 3: //CARD_ICON_CI with own palette + stats->offset_icon[i] = iconaddr; + stats->offset_icon_tlut[i] = iconaddr + 1024; + iconaddr += 1536; + break; + default: //CARD_ICON_NONE + stats->offset_icon[i] = -1; + stats->offset_icon_tlut[i] = -1; + break; + + + } + } +// stats->offset_data = iconaddr; +} + +static s32 __card_getstatusex(s32 chn,s32 fileno,struct card_direntry *entry) +{ + s32 ret; + card_block *card = NULL; + struct card_dat *dirblock = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + ret = CARD_ERROR_BROKEN; + dirblock = __card_getdirblock(card); + if(dirblock) { + ret = CARD_ERROR_READY; + memcpy(entry,&dirblock->entries[fileno],sizeof(struct card_direntry)); + } + return __card_putcntrlblock(card,ret); +} + +static s32 __card_setstatusexasync(s32 chn,s32 fileno,struct card_direntry *entry,cardcallback callback) +{ + s32 ret,i,bend; + card_block *card = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entries = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR; + if(entry->filename[0]==0xff || entry->filename[0]==0) return CARD_ERROR_FATAL_ERROR; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + ret = CARD_ERROR_BROKEN; + dirblock = __card_getdirblock(card); + if(dirblock) { + i = 0; bend = 0; + ret = CARD_ERROR_READY; + entries = dirblock->entries; + while(ifilename[i]==0) { + entry->filename[i] = 0; + bend = 1; + } + i++; + } + + if(memcmp(entries[fileno].filename,entry->filename,CARD_FILENAMELEN) + || memcmp(entries[fileno].gamecode,entry->gamecode,4) + || memcmp(entries[fileno].company,entry->company,2)) { + i = 0; + while(igamecode,4)==0 + && memcmp(entries[i].company,entry->company,2)==0 + && memcmp(entries[i].filename,entry->filename,CARD_FILENAMELEN)==0) { + return __card_putcntrlblock(card,CARD_ERROR_EXIST); + } + i++; + } + memcpy(entries[fileno].filename,entry->filename,CARD_FILENAMELEN); + memcpy(entries[fileno].gamecode,entry->gamecode,4); + memcpy(entries[fileno].company,entry->company,2); + } + + entries[fileno].lastmodified = entry->lastmodified; + entries[fileno].bannerfmt = entry->bannerfmt; + entries[fileno].iconaddr = entry->iconaddr; + entries[fileno].iconfmt = entry->iconfmt; + entries[fileno].iconspeed = entry->iconspeed; + entries[fileno].commentaddr = entry->commentaddr; + entries[fileno].permission = entry->permission; + entries[fileno].copytimes = entry->copytimes; + + if((ret=__card_updatedir(chn,callback))>=0) return ret; + } + return __card_putcntrlblock(card,ret); +} + +static s32 __card_getfilenum(card_block *card,const char *filename,const char *gamecode,const char *company,s32 *fileno) +{ + u32 i = 0; + struct card_direntry *entries = NULL; + struct card_dat *dirblock = NULL; + if(!card->attached) return CARD_ERROR_NOCARD; + dirblock = __card_getdirblock(card); + + entries = dirblock->entries; + for(i=0;i=CARD_MAXFILES) return CARD_ERROR_NOFILE; + return CARD_ERROR_READY; +} + +static s32 __card_seek(card_file *file,s32 len,s32 offset,card_block **rcard) +{ + s32 ret; + s32 i,entry_len; + card_block *card = NULL; + struct card_direntry *entry = NULL; + struct card_dat *dirblock = NULL; + struct card_bat *fatblock = NULL; + if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR; + if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret; + if(file->iblockiblock>=card->blocks) { + __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR); + return CARD_ERROR_FATAL_ERROR; + } + + dirblock = __card_getdirblock(card); + entry = &dirblock->entries[file->filenum]; + if(entry->gamecode[0]!=0xff) { + entry_len = entry->length*card->sector_size; + if(entry_lencurr_file = file; + file->len = len; + + if(offsetoffset) { + file->offset = 0; + file->iblock = entry->block; + if(file->iblockiblock>=card->blocks) { + __card_putcntrlblock(card,CARD_ERROR_BROKEN); + return CARD_ERROR_BROKEN; + } + } + + fatblock = __card_getbatblock(card); + for(i=file->iblock;iblocks && file->offset<(offset&~(card->sector_size-1));i=file->iblock) { + file->offset += card->sector_size; + file->iblock = fatblock->fat[i-CARD_SYSAREA]; + if(file->iblockiblock>=card->blocks) { + __card_putcntrlblock(card,CARD_ERROR_BROKEN); + return CARD_ERROR_BROKEN; + } + } + file->offset = offset; + *rcard = card; + } + return CARD_ERROR_READY; +} + +static u32 __card_checkdir(card_block *card,u32 *currdir) +{ + u32 dir,bad,bad_dir; + u16 chksum0,chksum1; + struct card_dircntrl *dircntrl[2]; + struct card_dat *dirblock[2]; + dir = 0; + bad = 0; + bad_dir = 0; + while(dir<2) { + dirblock[dir] = card->workarea+((dir+1)<<13); + dircntrl[dir] = (card->workarea+((dir+1)<<13))+8128; + __card_checksum((u16*)dirblock[dir],0x1ffc,&chksum0,&chksum1); + if(chksum0!=dircntrl[dir]->chksum1 || chksum1!=dircntrl[dir]->chksum2) { + card->curr_dir = NULL; + bad_dir = dir; + bad++; + } + dir++; + } + + dir = bad_dir; + if(!bad) { + if(dircntrl[0]->updatedupdated) dir = 0; + else dir = 1; + } + if(card->curr_dir==NULL) { + card->curr_dir = dirblock[dir]; + memcpy(dirblock[dir],dirblock[dir^1],8192); + } + else if(card->curr_dir==dirblock[0]) dir = 0; + else dir = 1; + + if(currdir) *currdir = dir; + return bad; +} + +static u32 __card_checkfat(card_block *card,u32 *currfat) +{ + u32 fat,bad,bad_fat; + u16 chksum0,chksum1; + struct card_bat *fatblock[2]; + fat = 0; + bad = 0; + bad_fat = 0; + while(fat<2) { + fatblock[fat] = card->workarea+((fat+3)<<13); + __card_checksum((u16*)(((u32)fatblock[fat])+4),0x1ffc,&chksum0,&chksum1); + if(chksum0!=fatblock[fat]->chksum1 || chksum1!=fatblock[fat]->chksum2) { + card->curr_fat = NULL; + bad_fat = fat; + bad++; + } else { + u16 curblock = CARD_SYSAREA; + u16 freeblocks = 0; + while(curblockblocks) { + if(!fatblock[fat]->fat[curblock-CARD_SYSAREA]) freeblocks++; + curblock++; + } + if(freeblocks!=fatblock[fat]->freeblocks) { + card->curr_fat = NULL; + bad_fat = fat; + bad++; + } + } + fat++; + } + + fat = bad_fat; + if(!bad) { + if(fatblock[0]->updatedupdated) fat = 0; + else fat = 1; + } + if(card->curr_fat==NULL) { + card->curr_fat = fatblock[fat]; + memcpy(fatblock[fat],fatblock[fat^1],8192); + } + else if(card->curr_fat==fatblock[0]) fat = 0; + else fat = 1; + + if(currfat) *currfat = fat; + return bad; +} + +static s32 __card_verify(card_block *card) +{ + u32 ret = 0; + + ret += __card_checkdir(card,NULL); + ret += __card_checkfat(card,NULL); + if(ret<=2) { + if(card->curr_dir && card->curr_fat) return CARD_ERROR_READY; + } + return CARD_ERROR_BROKEN; +} + +static u32 __card_iscard(u32 id) +{ + u32 ret; + u32 idx,tmp,secsize; + + if(id&~0xffff) return 0; + if(id&0x03) return 0; + + ret = 0; + tmp = id&0xfc; + if(tmp==EXI_MEMCARD59 || tmp==EXI_MEMCARD123 + || tmp==EXI_MEMCARD251 || tmp==EXI_MEMCARD507 + || tmp==EXI_MEMCARD1019 || tmp==EXI_MEMCARD2043) { + idx = _ROTL(id,23)&0x1c; + if((secsize=card_sector_size[idx>>2])==0) return 0; + tmp = ((tmp<<20)&0x1FFE0000)/secsize; + if(tmp>8) ret = 1; + } + return ret; +} + +static s32 __card_allocblock(s32 chn,u32 blocksneed,cardcallback callback) +{ + s32 ret; + u16 block,currblock = 0,prevblock = 0; + u32 i,count; + card_block *card = NULL; + struct card_bat *fatblock = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + card = &cardmap[chn]; + + if(!card->attached) return CARD_ERROR_NOCARD; + fatblock = __card_getbatblock(card); + + if(fatblock->freeblockslastalloc; + i = blocksneed; + while(1) { + if(i==0) { + // Done allocating blocks + fatblock->freeblocks -= blocksneed; + fatblock->lastalloc = currblock; + card->curr_fileblock = block; + ret = __card_updatefat(chn,fatblock,callback); + break; + } + + /* + Since testing free space has already been done, if all the blocks + the file takes up cannot be entered into the FAT, something is + wrong. + */ + count++; + if(count>=(card->blocks-CARD_SYSAREA)) return CARD_ERROR_BROKEN; + + currblock++; + if(currblock=card->blocks) currblock = CARD_SYSAREA; + if(fatblock->fat[currblock-CARD_SYSAREA]==0) { + if(block!=0xffff) + fatblock->fat[prevblock-CARD_SYSAREA] = currblock; + else + block = currblock; + + fatblock->fat[currblock-CARD_SYSAREA] = 0xffff; + prevblock = currblock; + i--; + } + } + return ret; +} + +static s32 __card_freeblock(s32 chn,u16 block,cardcallback callback) +{ + u16 next = 0xffff,prev = 0xffff; + card_block *card = NULL; + struct card_bat *fatblock = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + + if(!card->attached) return CARD_ERROR_NOCARD; + + fatblock = __card_getbatblock(card); + next = fatblock->fat[block-CARD_SYSAREA]; + while(1) { + if(next==0xffff) break; + if(next=card->blocks) return CARD_ERROR_BROKEN; + + // Get the file's next block and clear the previous one from the fat + prev = next; + next = fatblock->fat[prev-CARD_SYSAREA]; + fatblock->fat[prev-CARD_SYSAREA] = 0; + fatblock->freeblocks++; + } + return __card_updatefat(chn,fatblock,callback); +} + +static s32 __card_unlockedhandler(s32 chn,s32 dev) +{ + s32 ret; + cardcallback cb = NULL; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + + ret = CARD_ERROR_READY; + cb = card->card_unlock_cb; + if(cb) { + card->card_unlock_cb = NULL; + if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD; + cb(chn,ret); + } + return CARD_ERROR_UNLOCKED; +} + +static s32 __card_readstatus(s32 chn,u8 *pstatus) +{ + u8 val[2]; + u32 err; + s32 ret; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD; + + err = 0; + val[0] = 0x83; val[1] = 0x00; + if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01; + if(EXI_Sync(chn)==0) err |= 0x02; + if(EXI_Imm(chn,pstatus,1,EXI_READ,NULL)==0) err |= 0x04; + if(EXI_Sync(chn)==0) err |= 0x08; + if(EXI_Deselect(chn)==0) err |= 0x10; + + if(err) ret = CARD_ERROR_NOCARD; + else ret = CARD_ERROR_READY; + return ret; +} + +static s32 __card_clearstatus(s32 chn) +{ + u8 val; + u32 err; + s32 ret; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD; + + err = 0; + val = 0x89; + if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01; + if(EXI_Sync(chn)==0) err |= 0x02; + if(EXI_Deselect(chn)==0) err |= 0x04; + + if(err) ret = CARD_ERROR_NOCARD; + else ret = CARD_ERROR_READY; + + return ret; +} + +static s32 __card_enableinterrupt(s32 chn,u32 enable) +{ + u8 val[2]; + u32 err; + s32 ret; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD; + + err = 0; + val[0] = 0x81; + if(enable) val[1] = 0x01; + else val[1] = 0x00; + if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01; + if(EXI_Sync(chn)==0) err |= 0x02; + if(EXI_Deselect(chn)==0) err |= 0x04; + + if(err) ret = CARD_ERROR_BUSY; + else ret = CARD_ERROR_READY; + + return ret; +} + +static s32 __card_txhandler(s32 chn,s32 dev) +{ + u32 err; + s32 ret = CARD_ERROR_READY; + cardcallback cb = NULL; + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return 0; + card = &cardmap[chn]; + + err = 0; + if(EXI_Deselect(chn)==0) ret |= err; + if(EXI_Unlock(chn)==0) ret |= err; + + cb = card->card_tx_cb; + if(cb) { + card->card_tx_cb = NULL; + if(!err) { + if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD; + } else ret = CARD_ERROR_NOCARD; + cb(chn,ret); + } + return 1; +} + +static void __timeouthandler(syswd_t alarm,void *cbarg) +{ + u32 chn; + s32 ret = CARD_ERROR_READY; + cardcallback cb; + card_block *card = NULL; + chn = 0; + while(chntimeout_svc==alarm) break; + chn++; + } + if(chn=EXI_CHANNEL_2) return; + + + if(card->attached) { + EXI_RegisterEXICallback(chn,NULL); + cb = card->card_exi_cb; + if(cb) { + card->card_exi_cb = NULL; + ret = CARD_ERROR_IOERROR; + cb(chn,ret); + } + } +} + +static void __setuptimeout(card_block *card) +{ + struct timespec tb; + SYS_CancelAlarm(card->timeout_svc); + + if(card->cmd[0]==0xf1 || card->cmd[0]==0xf4) { + tb.tv_sec = 1*(card->sector_size/8192); + tb.tv_nsec = 0; + SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler,NULL); + } else if(card->cmd[0]==0xf2) { + tb.tv_sec = 0; + tb.tv_nsec = 100*TB_NSPERMS; + SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler,NULL); + } +} + +static s32 __retry(s32 chn) +{ + u32 len; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) { + EXI_Unlock(chn); + return CARD_ERROR_NOCARD; + } + + __setuptimeout(card); + + if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) { + EXI_Deselect(chn); + EXI_Unlock(chn); + return CARD_ERROR_NOCARD; + } + + if(card->cmd[0]==0x52) { + if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) { + EXI_Deselect(chn); + EXI_Unlock(chn); + return CARD_ERROR_NOCARD; + } + } + + if(card->cmd_mode==-1) { + EXI_Deselect(chn); + EXI_Unlock(chn); + return CARD_ERROR_READY; + } + + len = 128; + if(card->cmd[0]==0x52) len = CARD_READSIZE; + if(EXI_Dma(chn,card->cmd_usr_buf,len,card->cmd_mode,__card_txhandler)==0) { + EXI_Deselect(chn); + EXI_Unlock(chn); + return CARD_ERROR_NOCARD; + } + return CARD_ERROR_READY; +} + +static void __card_defaultapicallback(s32 chn,s32 result) +{ + return; +} + +static s32 __card_exihandler(s32 chn,s32 dev) +{ + u8 status; + s32 ret = CARD_ERROR_READY; + card_block *card = NULL; + cardcallback cb; + if(chn=EXI_CHANNEL_2) return 1; + card = &cardmap[chn]; + + SYS_CancelAlarm(card->timeout_svc); + if(card->attached) { + if(EXI_Lock(chn,EXI_DEVICE_0,NULL)==1) { + if((ret=__card_readstatus(chn,&status))>=0 + && (ret=__card_clearstatus(chn))>=0) { + if(status&0x18) ret = CARD_ERROR_IOERROR; + else ret = CARD_ERROR_READY; + + if(ret==CARD_ERROR_IOERROR) { + if((--card->cmd_retries)>0) { + ret = __retry(chn); + if(ret<0) goto exit; + return 1; + } + } + } + EXI_Unlock(chn); + } else ret = CARD_ERROR_FATAL_ERROR; +exit: + cb = card->card_exi_cb; + if(cb) { + card->card_exi_cb = NULL; + cb(chn,ret); + } + } + return 1; +} + +static s32 __card_exthandler(s32 chn,s32 dev) +{ + cardcallback cb; + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return 0; + card = &cardmap[chn]; + + if(card->attached) { + if(card->card_tx_cb) { + printf("error: card->card_tx_cb!=NULL\n"); + } + card->attached = 0; + EXI_RegisterEXICallback(chn,NULL); + SYS_CancelAlarm(card->timeout_svc); + + cb = card->card_exi_cb; + if(cb) { + card->card_exi_cb = NULL; + cb(chn,CARD_ERROR_NOCARD); + } + + cb = card->card_ext_cb; + if(cb) { + card->card_ext_cb = NULL; + cb(chn,CARD_ERROR_NOCARD); + } + + } + return 1; +} + +static void __write_callback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + card_file *file = NULL; + struct card_bat *fatblock = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entry = NULL; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + file = card->curr_file; + if(file->len>=0) { + file->len = (card->sector_size-file->len); + if(file->len<=0) { + dirblock = __card_getdirblock(card); + entry = &dirblock->entries[file->filenum]; + entry->lastmodified = time(NULL); + cb = card->card_api_cb; + card->card_api_cb = NULL; + if((ret=__card_updatedir(chn,cb))>=0) return; + } else { + fatblock = __card_getbatblock(card); + file->offset += card->sector_size; + file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA]; + if(file->iblockiblock>=card->blocks) { + ret = CARD_ERROR_BROKEN; + goto exit; + } + if((ret=__card_sectorerase(chn,(file->iblock*card->sector_size),__erase_callback))>=0) return; + } + } else + ret = CARD_ERROR_CANCELED; + } + +exit: + cb = card->card_api_cb; + card->card_api_cb = NULL; + __card_putcntrlblock(card,ret); + if(cb) cb(chn,ret); +} + +static void __erase_callback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + card_file *file = NULL; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + file = card->curr_file; + if((ret=__card_write(chn,(file->iblock*card->sector_size),card->sector_size,card->cmd_usr_buf,__write_callback))>=0) return; + } + + cb = card->card_api_cb; + card->card_api_cb = NULL; + __card_putcntrlblock(card,ret); + if(cb) cb(chn,ret); +} + +static void __read_callback(s32 chn,s32 result) +{ + s32 ret; + s32 len; + cardcallback cb = NULL; + card_file *file = NULL; + card_block *card = 0; + struct card_bat *fatblock = NULL; + if(chn=EXI_CHANNEL_2) return; + card = &cardmap[chn]; + + ret = result; + file = card->curr_file; + if(ret>=0) { + if(file->len>=0) { + file->len = file->len-(((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset); + if(file->len>0) { + fatblock = __card_getbatblock(card); + file->offset += (((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset); + file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA]; + if(file->iblockiblock>=card->blocks) { + ret = CARD_ERROR_BROKEN; + goto exit; + } + len = file->lensector_size?card->sector_size:file->len; + if(__card_read(chn,(file->iblock*card->sector_size),len,card->cmd_usr_buf,__read_callback)>=0) return; + + } + } else + ret = CARD_ERROR_CANCELED; + } + +exit: + cb = card->card_api_cb; + card->card_api_cb = NULL; + __card_putcntrlblock(card,ret); + if(cb) cb(chn,ret); +} + +static void __delete_callback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + card_block *card = &cardmap[chn]; + cb = card->card_api_cb; + card->card_api_cb = NULL; + + ret = result; + if(ret>=0 && (ret=__card_freeblock(chn,card->curr_fileblock,cb))>=0) return; + + __card_putcntrlblock(card,ret); + if(cb) cb(chn,ret); +} + +static void __format_callback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + card_block *card = &cardmap[chn]; + + ret = result; + if(ret>=0) { + if((++card->format_step)format_step*card->sector_size),__format_callback))>=0) return; + goto exit; + } + if(card->format_step<10) { + if((ret=__card_write(chn,((card->format_step-CARD_SYSAREA)*card->sector_size),8192,card->workarea+((card->format_step-CARD_SYSAREA)<<13),__format_callback))>=0) return; + goto exit; + } + + card->curr_dir = card->workarea+CARD_SYSDIR; + memcpy(card->curr_dir,card->workarea+CARD_SYSDIR_BACK,8192); + + card->curr_fat = card->workarea+CARD_SYSBAT; + memcpy(card->curr_fat,card->workarea+CARD_SYSBAT_BACK,8192); + } +exit: + cb = card->card_api_cb; + card->card_api_cb = NULL; + __card_putcntrlblock(card,ret); + if(cb) cb(chn,ret); +} + +static void __blockwritecallback(s32 chn,s32 result) +{ + s32 ret = CARD_ERROR_READY; + cardcallback cb = NULL; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + card->transfer_cnt += 128; + card->cmd_sector_addr += 128; + card->cmd_usr_buf += 128; + if((--card->cmd_blck_cnt)>0) { + if((ret=__card_writepage(chn,__blockwritecallback))>=CARD_ERROR_READY) return; + } + } + + if(!card->card_api_cb) __card_putcntrlblock(card,ret); + + cb = card->card_xfer_cb; + if(cb) { + card->card_xfer_cb = NULL; + cb(chn,ret); + } +} + +static void __blockreadcallback(s32 chn,s32 result) +{ + s32 ret = CARD_ERROR_READY; + cardcallback cb = NULL; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + card->transfer_cnt += CARD_READSIZE; + card->cmd_sector_addr += CARD_READSIZE; + card->cmd_usr_buf += CARD_READSIZE; + if((--card->cmd_blck_cnt)>0) { + if((ret=__card_readsegment(chn,__blockreadcallback))>=CARD_ERROR_READY) return; + } + } + + if(!card->card_api_cb) __card_putcntrlblock(card,ret); + cb = card->card_xfer_cb; + if(cb) { + card->card_xfer_cb = NULL; + cb(chn,ret); + } +} + +static void __unlocked_callback(s32 chn,s32 result) +{ + s32 ret; + card_block *card; + cardcallback cb; + if(chn=EXI_CHANNEL_2) return; + card = &cardmap[chn]; + + ret = result; + if(ret>=0) { + card->card_unlock_cb = __unlocked_callback; + if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==1) { + card->card_unlock_cb = NULL; + ret = __retry(chn); + } else + ret = 0; + } + if(ret<0) { + if(card->cmd[0]==0xf3 || card->cmd[0]>=0xf5) return; + else if(card->cmd[0]==0x52) { + cb = card->card_tx_cb; + if(cb) { + card->card_tx_cb = NULL; + cb(chn,ret); + } + } else if(card->cmd[0]>=0xf1) { + cb = card->card_exi_cb; + if(cb) { + card->card_exi_cb = NULL; + cb(chn,ret); + } + } + } +} + +static s32 __card_start(s32 chn,cardcallback tx_cb,cardcallback exi_cb) +{ + u32 level; + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + + _CPU_ISR_Disable(level); + if(tx_cb) card->card_tx_cb = tx_cb; + if(exi_cb) card->card_exi_cb = exi_cb; + + card->card_unlock_cb = __unlocked_callback; + if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) { + _CPU_ISR_Restore(level); + return CARD_ERROR_BUSY; + } + card->card_unlock_cb = NULL; + + if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) { + EXI_Unlock(chn); + _CPU_ISR_Restore(level); + return CARD_ERROR_NOCARD; + } + + __setuptimeout(card); + _CPU_ISR_Restore(level); + + return CARD_ERROR_READY; +} + +static s32 __card_writepage(s32 chn,cardcallback callback) +{ + s32 ret; + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + + card->cmd[0] = 0xf2; + card->cmd[1] = (card->cmd_sector_addr>>17)&0x3f; + card->cmd[2] = (card->cmd_sector_addr>>9)&0xff; + card->cmd[3] = (card->cmd_sector_addr>>7)&3; + card->cmd[4] = card->cmd_sector_addr&0x7f; + card->cmd_len = 5; + card->cmd_mode = EXI_WRITE; + card->cmd_retries = 3; + + ret = __card_start(chn,NULL,callback); + if(ret<0) return ret; + + if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==1 + && EXI_Dma(chn,card->cmd_usr_buf,128,card->cmd_mode,__card_txhandler)==1) return CARD_ERROR_READY; + + card->card_exi_cb = NULL; + EXI_Deselect(chn); + EXI_Unlock(chn); + return CARD_ERROR_NOCARD; +} + +static s32 __card_readsegment(s32 chn,cardcallback callback) +{ + u32 err; + s32 ret; + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + + card->cmd[0] = 0x52; + card->cmd[1] = (card->cmd_sector_addr&0xFE0000)>>17; + card->cmd[2] = (card->cmd_sector_addr&0x01FE00)>>9; + card->cmd[3] = (card->cmd_sector_addr&0x000180)>>7; + card->cmd[4] = (card->cmd_sector_addr&0x00007F); + card->cmd_len = 5; + card->cmd_mode = EXI_READ; + card->cmd_retries = 0; + + ret = __card_start(chn,callback,NULL); + if(ret<0) return ret; + + err = 0; + if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) err |= 0x01; + if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02; + if(EXI_Dma(chn,card->cmd_usr_buf,CARD_READSIZE,card->cmd_mode,__card_txhandler)==0) err |= 0x04; + + if(err) { + card->card_tx_cb = NULL; + EXI_Deselect(chn); + EXI_Unlock(chn); + return CARD_ERROR_NOCARD; + } + return CARD_ERROR_READY; +} + +static void __card_fatwritecallback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + struct card_bat *fat1,*fat2; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + fat1 = (card->workarea+0x6000); + fat2 = (card->workarea+0x8000); + if(card->curr_fat==fat1) { + card->curr_fat = fat2; + memcpy(fat2,fat1,8192); + } else { + card->curr_fat = fat1; + memcpy(fat1,fat2,8192); + } + } + if(!card->card_api_cb) __card_putcntrlblock(card,ret); + cb = card->card_erase_cb; + if(cb) { + card->card_erase_cb = NULL; + cb(chn,ret); + } +} + +static void __card_dirwritecallback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + struct card_dat *dir1,*dir2; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + dir1 = (card->workarea+0x2000); + dir2 = (card->workarea+0x4000); + if(card->curr_dir==dir1) { + card->curr_dir = dir2; + memcpy(dir2,dir1,8192); + } else { + card->curr_dir = dir1; + memcpy(dir1,dir2,8192); + } + } + if(!card->card_api_cb) __card_putcntrlblock(card,ret); + cb = card->card_erase_cb; + if(cb) { + card->card_erase_cb = NULL; + cb(chn,ret); + } +} + +static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback) +{ + s32 ret; + card_block *card = NULL; + if(chn= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + card = &cardmap[chn]; + + if(!card->attached) return CARD_ERROR_NOCARD; + + card->cmd_blck_cnt = block_len>>7; + card->cmd_sector_addr = address; + card->cmd_usr_buf = buffer; + card->card_xfer_cb = callback; + ret = __card_writepage(chn,__blockwritecallback); + + return ret; +} + +static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback) +{ + s32 ret; + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + + card->cmd_sector_addr = address; + card->cmd_blck_cnt = block_len>>9; + card->cmd_usr_buf = buffer; + card->card_xfer_cb = callback; + ret = __card_readsegment(chn,__blockreadcallback); + + return ret; +} + +static s32 __card_formatregion(s32 chn,u32 encode,cardcallback callback) +{ + s32 ret; + u16 tmp; + u32 cnt; + u64 time; + u64 rnd_val; + void *workarea,*memblock; + cardcallback cb = NULL; + card_block *card = NULL; + struct card_header *header; + struct card_bat *fatblock = NULL; + struct card_dircntrl *dircntrl = NULL; + syssram *sram; + syssramex *sramex; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + header = workarea = card->workarea; + memset(header,0xff,8192); + + tmp = _viReg[55]; + header->encoding = encode; + + sram = __SYS_LockSram(); + header->serial[5] = sram->counter_bias; + header->serial[6] = sram->lang; + __SYS_UnlockSram(0); + + cnt = 0; + rnd_val = time = gettime(); + sramex = __SYS_LockSramEx(); + while(cnt<12) { + rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16); + ((u8*)header->serial)[cnt] = (sramex->flash_id[chn][cnt]+(u32)rnd_val); + + rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16); + rnd_val &= (u64)0x0000000000007fff; + + cnt++; + } + __SYS_UnlockSramEx(0); + + *(u64*)&(header->serial[3]) = time; + header->serial[7] = tmp; + header->device_id = 0; + header->size = card->card_size; + __card_checksum((u16*)header,508,&header->chksum1,&header->chksum2); + + cnt = 0; + while(cnt<2) { + memblock = workarea+((cnt+1)<<13); + dircntrl = memblock+8128; + memset(memblock,0xff,8192); + __card_checksum(memblock,8188,&dircntrl->chksum1,&dircntrl->chksum2); + cnt++; + } + + cnt = 0; + while(cnt<2) { + memblock = workarea+((cnt+3)<<13); + fatblock = memblock; + memset(memblock,0,8192); + fatblock->updated = cnt; + fatblock->freeblocks = card->blocks-CARD_SYSAREA; + fatblock->lastalloc = 4; + __card_checksum(memblock+4,8188,&fatblock->chksum1,&fatblock->chksum2); + cnt++; + } + + cb = callback; + if(!cb) cb = __card_defaultapicallback; + card->card_api_cb = cb; + + DCStoreRange(card->workarea,0xA000); + + card->format_step = 0; + if((ret=__card_sectorerase(chn,(card->sector_size*card->format_step),__format_callback))>=0) return ret; + + __card_putcntrlblock(card,ret); + return ret; +} + +static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback) +{ + s32 ret; + card_block *card = NULL; + if(chn= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + card = &cardmap[chn]; + + if(sector%card->sector_size) return CARD_ERROR_FATAL_ERROR; + + card->cmd[0] = 0xf1; + card->cmd[1] = (sector>>17)&0x7f; + card->cmd[2] = (sector>>9)&0xff; + card->cmd_len = 3; + card->cmd_mode = -1; + card->cmd_retries = 3; + + ret = __card_start(chn,NULL,callback); + if(ret<0) return ret; + + if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) { + card->card_exi_cb = NULL; + return CARD_ERROR_NOCARD; + } + + EXI_Deselect(chn); + EXI_Unlock(chn); + return ret; +} + +static void __card_faterasecallback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + struct card_bat *fatblock = NULL; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + fatblock = __card_getbatblock(card); + if((ret=__card_write(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,8192,fatblock,__card_fatwritecallback))>=0) return; + } + if(!card->card_api_cb) __card_putcntrlblock(card,ret); + + cb = card->card_erase_cb; + if(cb) { + card->card_erase_cb = NULL; + cb(chn,ret); + } +} + +static void __card_direrasecallback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + struct card_dat *dirblock = NULL; + card_block *card = &cardmap[chn]; + ret = result; + if(ret>=0) { + dirblock = __card_getdirblock(card); + if((ret=__card_write(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,8192,dirblock,__card_dirwritecallback))>=0) return; + } + if(!card->card_api_cb) __card_putcntrlblock(card,ret); + + cb = card->card_erase_cb; + if(cb) { + card->card_erase_cb = NULL; + cb(chn,ret); + } +} + +static void __card_createfatcallback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb = NULL; + card_file *file = NULL; + struct card_direntry *entry = NULL; + struct card_dat *dirblock = NULL; + card_block *card = &cardmap[chn]; + cb = card->card_api_cb; + card->card_api_cb = NULL; + + dirblock = __card_getdirblock(card); + + file = card->curr_file; + entry = &dirblock->entries[file->filenum]; + + memset(entry->gamecode,0,4); + memset(entry->company,0,2); + if(card_gamecode[0]!=0xff) memcpy(entry->gamecode,card_gamecode,4); + if(card_gamecode[0]!=0xff) memcpy(entry->company,card_company,2); + entry->block = card->curr_fileblock; + entry->permission = CARD_ATTRIB_PUBLIC; + entry->pad_00 = 0xff; + entry->copytimes = 0; + entry->iconaddr = -1; + entry->iconfmt = 0; + entry->iconspeed = 0; + entry->pad_01 = 0xffff; + entry->iconspeed = (entry->iconspeed&~CARD_SPEED_MASK)|CARD_SPEED_FAST; + entry->lastmodified = time(NULL); + + file->offset = 0; + file->iblock = card->curr_fileblock; + + if((ret=__card_updatedir(chn,cb))<0) { + __card_putcntrlblock(card,ret); + if(cb) cb(chn,ret); + } +} + +static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback) +{ + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + card = &cardmap[chn]; + + if(!card->attached) return CARD_ERROR_NOCARD; + + ++fatblock->updated; + __card_checksum((u16*)(((u32)fatblock)+4),0x1ffc,&fatblock->chksum1,&fatblock->chksum2); + DCStoreRange(fatblock,8192); + card->card_erase_cb = callback; + + return __card_sectorerase(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,__card_faterasecallback); +} + +static s32 __card_updatedir(s32 chn,cardcallback callback) +{ + card_block *card = NULL; + void *dirblock = NULL; + struct card_dircntrl *dircntrl = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + card = &cardmap[chn]; + + if(!card->attached) return CARD_ERROR_NOCARD; + + dirblock = __card_getdirblock(card); + dircntrl = dirblock+8128; + ++dircntrl->updated; + __card_checksum((u16*)dirblock,0x1ffc,&dircntrl->chksum1,&dircntrl->chksum2); + DCStoreRange(dirblock,0x2000); + card->card_erase_cb = callback; + + return __card_sectorerase(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,__card_direrasecallback); +} + +static void __card_dounmount(s32 chn,s32 result) +{ + u32 level; + card_block *card; + + if(chn=EXI_CHANNEL_2) return; + card = &cardmap[chn]; + + _CPU_ISR_Disable(level); + if(card->attached) { + card->attached = 0; + card->mount_step = 0; + card->result = result; + EXI_RegisterEXICallback(chn,NULL); + EXI_Detach(chn); + SYS_CancelAlarm(card->timeout_svc); + } + _CPU_ISR_Restore(level); +} + +static s32 __card_domount(s32 chn) +{ + u8 status,kval; + s32 ret = CARD_ERROR_READY; + u32 sum; + u32 id,idx,cnt; + card_block *card; + syssramex *sramex; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + if(card->mount_step==0) { + ret = 0; + id = 0; + if(EXI_GetID(chn,EXI_DEVICE_0,&id)==0) ret = CARD_ERROR_NOCARD; + else if(!__card_iscard(id)) ret = CARD_ERROR_WRONGDEVICE; + + if(ret<0) goto exit; + card->cid = id; + card->card_size = (id&0xfc); + if(card->card_size) { + idx = _ROTL(id,23)&0x1c; + card->sector_size = card_sector_size[idx>>2]; + card->blocks = ((card->card_size<<20)>>3)/card->sector_size; + + if(card->blocks>0x0008) { + idx = _ROTL(id,26)&0x1c; + card->latency = card_latency[idx>>2]; + + if((ret=__card_clearstatus(chn))<0) goto exit; + if((ret=__card_readstatus(chn,&status))<0) goto exit; + + if(EXI_Probe(chn)==0) { + ret = CARD_ERROR_NOCARD; + goto exit; + } + if(!(status&CARD_STATUS_UNLOCKED)) { + if((ret=__dounlock(chn,card->key))<0) goto exit; + + cnt = 0; + sum = 0; + sramex = __SYS_LockSramEx(); + while(cnt<12) { + kval = ((u8*)card->key)[cnt]; + sramex->flash_id[chn][cnt] = kval; + sum += kval; + cnt++; + } + sum = (sum^-1)&0xff; + sramex->flashID_chksum[chn] = (sum<<8)|sum; + __SYS_UnlockSramEx(1); + return ret; + } + card->mount_step = 1; + + cnt = 0; + sum = 0; + sramex = __SYS_LockSramEx(); + while(cnt<12) { + sum += sramex->flash_id[chn][cnt]; + cnt++; + } + cnt = sramex->flashID_chksum[chn]; + __SYS_UnlockSramEx(0); + + sum = (sum^-1)&0xff; + sum |= (sum<<8); + if(cnt!=sum) { + ret = CARD_ERROR_IOERROR; + goto exit; + } + } + } + } + if(card->mount_step==1) { + card->mount_step = 2; + if((ret=__card_enableinterrupt(chn,1))<0) goto exit; + EXI_RegisterEXICallback(chn,__card_exihandler); + EXI_Unlock(chn); + + DCInvalidateRange(card->workarea,0xA000); + } + + if((ret=__card_read(chn,(card->sector_size*(card->mount_step-2)),card->sector_size,card->workarea+((card->mount_step-2)<<13),__card_mountcallback))<0) goto exit; + return ret; + +exit: + EXI_Unlock(chn); + __card_dounmount(chn,ret); + + return ret; +} + +static void __card_mountcallback(s32 chn,s32 result) +{ + s32 ret; + cardcallback cb; + card_block *card = &cardmap[chn]; + + ret = result; + if(ret==CARD_ERROR_NOCARD || ret==CARD_ERROR_IOERROR) { + __card_dounmount(chn,ret); + __card_putcntrlblock(card,ret); + }else if(ret==CARD_ERROR_UNLOCKED) { + if((ret=__card_domount(chn))>=0) return; + } else { + if((++card->mount_step)<7) { + if((ret=__card_domount(chn))>=0) return; + } else { + ret = __card_verify(card); + __card_putcntrlblock(card,ret); + } + } + + cb = card->card_api_cb; + card->card_api_cb = NULL; + if(cb) cb(chn,ret); +} + +static __inline__ void __card_srand(u32 val) +{ + crand_next = val; +} + +static __inline__ u32 __card_rand() +{ + crand_next = (crand_next*0x41C64E6D)+12345; + return _SHIFTR(crand_next,16,15); +} + +static u32 __card_initval() +{ + u32 ticks = gettick(); + + __card_srand(ticks); + return ((0x7FEC8000|__card_rand())&~0x00000fff); +} + +static u32 __card_dummylen() +{ + u32 ticks = gettick(); + u32 val = 0,cnt = 0,shift = 1; + + __card_srand(ticks); + val = (__card_rand()&0x1f)+1; + + do { + ticks = gettick(); + val = ticks<16) shift = 1; + __card_srand(val); + val = (__card_rand()&0x1f)+1; + cnt++; + }while(val<4 && cnt<10); + if(val<4) val = 4; + + return val; + +} + +static u32 exnor_1st(u32 a,u32 b) +{ + u32 c,d,e,f,r1,r2,r3,r4; + + c = 0; + while(c>23); + e = (a>>15); + f = (a>>7); + r1 = (a^f); + r2 = (e^r1); + r3 = ~(d^r2); //eqv(d,r2) + e = (a>>1); + r4 = ((r3<<30)&0x40000000); + a = (e|r4); + c++; + }; + return a; +} + +static u32 exnor(u32 a,u32 b) +{ + u32 c,d,e,f,r1,r2,r3,r4; + + c = 0; + while(c>30)&0x02); + a = (e|r4); + c++; + }; + return a; +} + +static u32 bitrev(u32 val) +{ + u32 cnt,val1,ret,shift,shift1; + + cnt = 0; + ret = 0; + shift = 1; + shift1 = 0; + while(cnt<32) { + if(cnt<=15) { + val1 = val&(1<>31; + ret |= val1; + } else { + val1 = 1; + val1 = val&(1<>= shift; + ret |= val1; + shift += 2; + } + cnt++; + } + return ret; +} + +static s32 __card_readarrayunlock(s32 chn,u32 address,void *buffer,u32 len,u32 flag) +{ + s32 ret; + u32 err; + u8 regbuf[5]; + card_block *card = &cardmap[chn]; + if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD; + + address &= 0xFFFFF000; + memset(regbuf,0,5); + + regbuf[0] = 0x52; + if(!flag) { + regbuf[1] = ((address&0x60000000)>>29)&0xff; + regbuf[2] = ((address&0x1FE00000)>>21)&0xff; + regbuf[3] = ((address&0x00180000)>>19)&0xff; + regbuf[4] = ((address&0x0007F000)>>12)&0xff; + } else { + regbuf[1] = (address>>24)&0xff; + regbuf[2] = ((address&0x00FF0000)>>16)&0xff; + } + + err = 0; + if(EXI_ImmEx(chn,regbuf,5,EXI_WRITE)==0) err |= 0x01; + if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02; + if(EXI_ImmEx(chn,buffer,len,EXI_READ)==0) err |= 0x04; + if(EXI_Deselect(chn)==0) err |= 0x08; + + if(err) ret = CARD_ERROR_NOCARD; + else ret = CARD_ERROR_READY; + + return ret; +} + +static void __dsp_initcallback(dsptask_t *task) +{ + u32 chn; + card_block *card = NULL; + chn = 0; + while(chndsp_task==task) break; + chn++; + } + if(chn>=EXI_CHANNEL_2) return; + + DSP_SendMailTo(0xFF000000); + while(DSP_CheckMailTo()); + DSP_SendMailTo((u32)card->workarea); + while(DSP_CheckMailTo()); +} + +static u8 tmp_buffer[64] ATTRIBUTE_ALIGN(32); +static void __dsp_donecallback(dsptask_t *task) +{ + + u8 status; + s32 ret; + u32 chn,len,key; + u32 workarea,val; + card_block *card = NULL; + chn = 0; + while(chndsp_task==task) break; + chn++; + } + if(chn>=EXI_CHANNEL_2) return; + + workarea = (u32)card->workarea; + workarea = ((workarea+47)&~0x1f); + key = ((u32*)workarea)[8]; + + val = (key^card->cipher)&~0xffff; + len = __card_dummylen(); + if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) { + EXI_Unlock(chn); + __card_mountcallback(chn,CARD_ERROR_NOCARD); + return; + } + + val = exnor(card->cipher,((len+card->latency+4)<<3)+1); + { + u32 a,b,c,r1,r2,r3; + a = (val<<23); + b = (val<<15); + c = (val<<7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3>>31)); + card->cipher = r1; + } + + val = ((key<<16)^card->cipher)&~0xffff; + len = __card_dummylen(); + if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) { + EXI_Unlock(chn); + __card_mountcallback(chn,CARD_ERROR_NOCARD); + return; + } + + ret = __card_readstatus(chn,&status); + if(EXI_Probe(chn)==0) { + EXI_Unlock(chn); + __card_mountcallback(chn,CARD_ERROR_NOCARD); + return; + } + if(!ret && !(status&CARD_STATUS_UNLOCKED)) { + EXI_Unlock(chn); + ret = CARD_ERROR_IOERROR; + } + __card_mountcallback(chn,ret); +} + +static s32 __dounlock(s32 chn,u32 *key) +{ + u32 array_addr,len,val; + u32 a,b,c,d,e; + card_block *card = &cardmap[chn]; + u32 *workarea = card->workarea; + u32 *cipher1 = (u32*)(((u32)card->workarea+47)&~31); + u32 *cipher2 = &cipher1[8]; + array_addr = __card_initval(); + len = __card_dummylen(); + + if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len,0)<0) return CARD_ERROR_NOCARD; + + + val = exnor_1st(array_addr,(len<<3)+1); + { + u32 a,b,c,r1,r2,r3; + a = (val>>23); + b = (val>>15); + c = (val>>7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3<<31)); + card->cipher = r1; + } + card->cipher = bitrev(card->cipher); + + array_addr = 0; + len = __card_dummylen(); + if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len+20,1)<0) return CARD_ERROR_NOCARD; + + a = ((u32*)tmp_buffer)[0]; + b = ((u32*)tmp_buffer)[1]; + c = ((u32*)tmp_buffer)[2]; + d = ((u32*)tmp_buffer)[3]; + e = ((u32*)tmp_buffer)[4]; + + a = a^card->cipher; + val = exnor(card->cipher,32); + { + u32 a,b,c,r1,r2,r3; + a = (val<<23); + b = (val<<15); + c = (val<<7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3>>31)); + card->cipher = r1; + } + + b = b^card->cipher; + val = exnor(card->cipher,32); + { + u32 a,b,c,r1,r2,r3; + a = (val<<23); + b = (val<<15); + c = (val<<7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3>>31)); + card->cipher = r1; + } + + c = c^card->cipher; + val = exnor(card->cipher,32); + { + u32 a,b,c,r1,r2,r3; + a = (val<<23); + b = (val<<15); + c = (val<<7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3>>31)); + card->cipher = r1; + } + + d = d^card->cipher; + val = exnor(card->cipher,32); + { + u32 a,b,c,r1,r2,r3; + a = (val<<23); + b = (val<<15); + c = (val<<7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3>>31)); + card->cipher = r1; + } + + e = e^card->cipher; + val = exnor(card->cipher,(len<<3)); + { + u32 a,b,c,r1,r2,r3; + a = (val<<23); + b = (val<<15); + c = (val<<7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3>>31)); + card->cipher = r1; + } + + val = exnor(card->cipher,33); + { + u32 a,b,c,r1,r2,r3; + a = (val<<23); + b = (val<<15); + c = (val<<7); + r1 = (val^c); + r2 = (b^r1); + r3 = ~(a^r2); //eqv(a,r2) + r1 = (val|(r3>>31)); + card->cipher = r1; + } + + cipher1[0] = d; + cipher1[1] = e; + workarea[0] = (u32)cipher1; + workarea[1] = 8; +#ifdef HW_RVL + workarea[2] = 0x10000000; // use MEM2 base +#else + workarea[2] = 0; // use ARAM base +#endif + workarea[3] = (u32)cipher2; + DCFlushRange(cipher1,8); + DCInvalidateRange(cipher2,4); + DCFlushRange(workarea,16); + + card->dsp_task.prio = 255; + card->dsp_task.iram_maddr = (u16*)MEM_VIRTUAL_TO_PHYSICAL(_cardunlockdata); + card->dsp_task.iram_len = 352; + card->dsp_task.iram_addr = 0x0000; + card->dsp_task.init_vec = 16; + card->dsp_task.res_cb = NULL; + card->dsp_task.req_cb = NULL; + card->dsp_task.init_cb = __dsp_initcallback; + card->dsp_task.done_cb = __dsp_donecallback; + DSP_AddTask(&card->dsp_task); + + key[0] = a; + key[1] = b; + key[2] = c; + + return CARD_ERROR_READY; +} + +s32 CARD_Init(const char *gamecode,const char *company) +{ + u32 i,level; + + if(card_inited) return CARD_ERROR_READY; + if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4); + if(company && strlen(company)<=2) memcpy(card_company,company,2); + + _CPU_ISR_Disable(level); + DSP_Init(); + + memset(cardmap,0,sizeof(card_block)*2); + for(i=0;i<2;i++) { + cardmap[i].result = CARD_ERROR_NOCARD; + LWP_InitQueue(&cardmap[i].wait_sync_queue); + SYS_CreateAlarm(&cardmap[i].timeout_svc); + } + SYS_RegisterResetFunc(&card_resetinfo); + card_inited = 1; + _CPU_ISR_Restore(level); + return CARD_ERROR_READY; +} + +s32 CARD_Probe(s32 chn) +{ + return EXI_Probe(chn); +} + +s32 CARD_ProbeEx(s32 chn,s32 *mem_size,s32 *sect_size) +{ + s32 ret; + u32 level,card_id; + card_block *card = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + card = &cardmap[chn]; + + _CPU_ISR_Disable(level); + ret = EXI_ProbeEx(chn); + if(ret<=0) { + if(!ret) ret = CARD_ERROR_BUSY; + else ret = CARD_ERROR_NOCARD; + _CPU_ISR_Restore(level); + return ret; + } + + if(card->attached) { + if(card->mount_step<1) { + _CPU_ISR_Restore(level); + return CARD_ERROR_BUSY; + } + if(mem_size) *mem_size = card->card_size; + if(sect_size) *sect_size = card->sector_size; + + _CPU_ISR_Restore(level); + return CARD_ERROR_READY; + } + + if(EXI_GetState(chn)&EXI_FLAG_ATTACH) ret = CARD_ERROR_WRONGDEVICE; + else { + ret = CARD_ERROR_BUSY; + if(EXI_GetID(chn,EXI_DEVICE_0,&card_id)) { + if(!__card_iscard(card_id)) ret = CARD_ERROR_WRONGDEVICE; + else { + if(mem_size) *mem_size = card_id&0xFC; + if(sect_size) { + u32 idx = _ROTL(card_id,23)&0x1c; + *sect_size = card_sector_size[idx>>2]; + } + ret = CARD_ERROR_READY; + } + } + } + + _CPU_ISR_Restore(level); + return ret; +} + +s32 CARD_MountAsync(s32 chn,void *workarea,cardcallback detach_cb,cardcallback attach_cb) +{ + s32 ret = CARD_ERROR_READY; + u32 level; + cardcallback attachcb = NULL; + card_block *card = NULL; + if(!workarea) return CARD_ERROR_NOCARD; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + card = &cardmap[chn]; + + _CPU_ISR_Disable(level); + if(card->result==CARD_ERROR_BUSY) { + _CPU_ISR_Restore(level); + return CARD_ERROR_BUSY; + } + if(card->attached || !(EXI_GetState(chn)&EXI_FLAG_ATTACH)) { + card->result = CARD_ERROR_BUSY; + card->workarea = workarea; + card->card_ext_cb = detach_cb; + + attachcb = attach_cb; + if(!attachcb) attachcb = __card_defaultapicallback; + card->card_api_cb = attachcb; + card->card_exi_cb = NULL; + + if(!card->attached) { + if(EXI_Attach(chn,__card_exthandler)==0) { + card->result = CARD_ERROR_NOCARD; + _CPU_ISR_Restore(level); + return CARD_ERROR_NOCARD; + } + } + card->mount_step = 0; + card->attached = 1; + EXI_RegisterEXICallback(chn,NULL); + SYS_CancelAlarm(card->timeout_svc); + card->curr_dir = NULL; + card->curr_fat = NULL; + _CPU_ISR_Restore(level); + + card->card_unlock_cb = __card_mountcallback; + if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) return 0; + + card->card_unlock_cb = NULL; + __card_domount(chn); + return 1; + } + + ret = CARD_ERROR_WRONGDEVICE; + _CPU_ISR_Restore(level); + return ret; +} + +s32 CARD_Mount(s32 chn,void *workarea,cardcallback detach_cb) +{ + s32 ret; + if((ret=CARD_MountAsync(chn,workarea,detach_cb,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_Unmount(s32 chn) +{ + s32 ret; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + + if((ret=__card_getcntrlblock(chn,&card))<0) ret = CARD_ERROR_NOCARD; + + __card_dounmount(chn,ret); + return CARD_ERROR_READY; +} + +s32 CARD_ReadAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback) +{ + s32 ret; + cardcallback cb = NULL; + card_block *card = NULL; + + if(len<=0 || (len&0x1ff) || (offset>0 && (offset&0x1ff))) return CARD_ERROR_FATAL_ERROR; + if((ret=__card_seek(file,len,offset,&card))<0) return ret; + + DCInvalidateRange(buffer,len); + + cb = callback; + if(!cb) cb = __card_defaultapicallback; + card->card_api_cb = cb; + + if(len>=(card->sector_size-(file->offset&(card->sector_size-1)))) len = (card->sector_size-(file->offset&(card->sector_size-1))); + + if((ret=__card_read(file->chn,(file->iblock*card->sector_size),len,buffer,__read_callback))<0) { + __card_putcntrlblock(card,ret); + return ret; + } + return 0; +} + +s32 CARD_Read(card_file *file,void *buffer,u32 len,u32 offset) +{ + s32 ret; + + if((ret=CARD_ReadAsync(file,buffer,len,offset,__card_synccallback))>=0) { + ret = __card_sync(file->chn); + } + return ret; +} + +s32 CARD_WriteAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback) +{ + s32 ret; + cardcallback cb = NULL; + card_block *card = NULL; + + if((ret=__card_seek(file,len,offset,&card))<0) return ret; + if(len<0 || (len&(card->sector_size-1)) || (offset>0 && offset&(card->sector_size-1))) { + __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR); + return CARD_ERROR_FATAL_ERROR; + } + + DCStoreRange(buffer,len); + cb = callback; + if(!cb) cb = __card_defaultapicallback; + card->card_api_cb = cb; + + card->cmd_usr_buf = buffer; + if((ret=__card_sectorerase(file->chn,(file->iblock*card->sector_size),__erase_callback))>=0) return ret; + __card_putcntrlblock(card,ret); + return ret; +} + +s32 CARD_Write(card_file *file,void *buffer,u32 len,u32 offset) +{ + s32 ret; + + if((ret=CARD_WriteAsync(file,buffer,len,offset,__card_synccallback))>=0) { + ret = __card_sync(file->chn); + } + return ret; +} + +s32 CARD_CreateAsync(s32 chn,const char *filename,u32 size,card_file *file,cardcallback callback) +{ + u32 i,len; + s32 ret,filenum; + cardcallback cb = NULL; + card_block *card = NULL; + struct card_bat *fatblock = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entry = NULL; + len = strlen(filename); + if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG; + + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + if(size<=0 || size%card->sector_size) return CARD_ERROR_FATAL_ERROR; + + dirblock = __card_getdirblock(card); + + filenum = -1; + entry = dirblock->entries; + for(i=0;ifreeblocks*card->sector_size)card_api_cb = cb; + + entry[filenum].length = size/card->sector_size; + memset(entry[filenum].filename,0,CARD_FILENAMELEN); + memcpy(entry[filenum].filename,filename,len+1); + + card->curr_file = file; + file->chn = chn; + file->filenum = filenum; + if((ret=__card_allocblock(chn,(size/card->sector_size),__card_createfatcallback))<0) { + __card_putcntrlblock(card,ret); + return ret; + } + + return 0; +} + +s32 CARD_Create(s32 chn,const char *filename,u32 size,card_file *file) +{ + s32 ret; + + if((ret=CARD_CreateAsync(chn,filename,size,file,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_CreateEntryAsync(s32 chn,card_dir *direntry,card_file *file,cardcallback callback) +{ + u32 i,len; + s32 ret,filenum; + cardcallback cb = NULL; + card_block *card = NULL; + struct card_bat *fatblock = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entry = NULL; + len = strlen((const char*)direntry->filename); + if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG; + + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + if(direntry->filelen<=0 || direntry->filelen%card->sector_size) return CARD_ERROR_FATAL_ERROR; + + dirblock = __card_getdirblock(card); + + filenum = -1; + entry = dirblock->entries; + for(i=0;ifilename,len)==0) { + if((entry->gamecode[0]==0xff || entry->company[0]==0xff) + || ((entry->gamecode[0]!=0xff && memcmp(entry[i].gamecode,entry->gamecode,4)==0) + && (entry->company[0]!=0xff && memcmp(entry[i].company,entry->company,2)==0))) { + __card_putcntrlblock(card,CARD_ERROR_EXIST); + return CARD_ERROR_EXIST; + } + } + } + if(filenum==-1) { + __card_putcntrlblock(card,CARD_ERROR_NOENT); + return CARD_ERROR_NOENT; + } + + fatblock = __card_getbatblock(card); + if((fatblock->freeblocks*card->sector_size)filelen) { + __card_putcntrlblock(card,CARD_ERROR_INSSPACE); + return CARD_ERROR_INSSPACE; + } + + cb = callback; + if(!cb) cb = __card_defaultapicallback; + card->card_api_cb = cb; + + entry[filenum].length = direntry->filelen/card->sector_size; + memset(entry[filenum].filename,0,CARD_FILENAMELEN); + memcpy(entry[filenum].filename,direntry->filename,len+1); + + card->curr_file = file; + file->chn = chn; + file->filenum = filenum; + if((ret=__card_allocblock(chn,(direntry->filelen/card->sector_size),__card_createfatcallback))<0) { + __card_putcntrlblock(card,ret); + return ret; + } + + return 0; +} + +s32 CARD_CreateEntry(s32 chn,card_dir *direntry,card_file *file) +{ + s32 ret; + + if((ret=CARD_CreateEntryAsync(chn,direntry,file,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_Open(s32 chn,const char *filename,card_file *file) +{ + s32 ret,fileno; + struct card_dat *dirblock = NULL; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + + file->filenum = -1; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) { + __card_putcntrlblock(card,ret); + return ret; + } + dirblock = __card_getdirblock(card); + if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) { + __card_putcntrlblock(card,CARD_ERROR_BROKEN); + return CARD_ERROR_BROKEN; + } + file->chn = chn; + file->filenum = fileno; + file->offset = 0; + file->len = dirblock->entries[fileno].length*card->sector_size; + file->iblock = dirblock->entries[fileno].block; + + __card_putcntrlblock(card,CARD_ERROR_READY); + return CARD_ERROR_READY; +} + +s32 CARD_OpenEntry(s32 chn,card_dir *entry,card_file *file) +{ + s32 ret,fileno; + struct card_dat *dirblock = NULL; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + + file->filenum = -1; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + if((ret=__card_getfilenum(card,(const char*)entry->filename,(const char*)entry->gamecode,(const char*)entry->company,&fileno))<0) { + __card_putcntrlblock(card,ret); + return ret; + } + + dirblock = __card_getdirblock(card); + if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) { + __card_putcntrlblock(card,CARD_ERROR_BROKEN); + return CARD_ERROR_BROKEN; + } + + file->chn = chn; + file->filenum = entry->fileno; + file->offset = 0; + file->len = dirblock->entries[fileno].length*card->sector_size; + file->iblock = dirblock->entries[fileno].block; + + __card_putcntrlblock(card,CARD_ERROR_READY); + return CARD_ERROR_READY; +} + +s32 CARD_Close(card_file *file) +{ + s32 ret; + card_block *card = NULL; + + if(file->chnchn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_NOFILE; + if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret; + + file->chn = -1; + __card_putcntrlblock(card,CARD_ERROR_READY); + return CARD_ERROR_READY; +} + +s32 CARD_DeleteAsync(s32 chn,const char *filename,cardcallback callback) +{ + s32 ret,fileno; + cardcallback cb = NULL; + card_block *card = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entry = NULL; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) { + __card_putcntrlblock(card,ret); + return ret; + } + + dirblock = __card_getdirblock(card); + entry = &dirblock->entries[fileno]; + + card->curr_fileblock = entry->block; + memset(entry,-1,sizeof(struct card_direntry)); + + cb = callback; + if(!cb) cb = __card_defaultapicallback; + card->card_api_cb = cb; + + if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret; + + __card_putcntrlblock(card,ret); + return ret; +} + +s32 CARD_Delete(s32 chn,const char *filename) +{ + s32 ret; + if((ret=CARD_DeleteAsync(chn,filename,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_DeleteEntryAsync(s32 chn,card_dir *dir_entry,cardcallback callback) +{ + s32 ret; + cardcallback cb = NULL; + card_block *card = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entry = NULL; + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + dirblock = __card_getdirblock(card); + entry = &dirblock->entries[dir_entry->fileno]; + + card->curr_fileblock = entry->block; + memset(entry,-1,sizeof(struct card_direntry)); + + cb = callback; + if(!cb) cb = __card_defaultapicallback; + card->card_api_cb = cb; + + if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret; + + __card_putcntrlblock(card,ret); + return ret; +} + +s32 CARD_DeleteEntry(s32 chn,card_dir *dir_entry) +{ + s32 ret; + if((ret=CARD_DeleteEntryAsync(chn,dir_entry,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_FormatAsync(s32 chn,cardcallback callback) +{ + u32 enc; + + enc = SYS_GetFontEncoding(); + return __card_formatregion(chn,enc,callback); +} + +s32 CARD_Format(s32 chn) +{ + s32 ret; + u32 enc; + + enc = SYS_GetFontEncoding(); + if((ret=__card_formatregion(chn,enc,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_GetErrorCode(s32 chn) +{ + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + card = &cardmap[chn]; + return card->result; +} + +s32 __card_findnext(card_dir *dir) +{ + s32 ret; + struct card_dat *dirblock = NULL; + struct card_direntry *entries = NULL; + card_block *card = NULL; + + if(dir->chnchn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(dir->fileno>=CARD_MAXFILES) return CARD_ERROR_NOFILE; + if((ret=__card_getcntrlblock(dir->chn,&card))<0) return ret; + + if(!card->attached) return CARD_ERROR_NOCARD; + dirblock = __card_getdirblock(card); + + entries = dirblock->entries; + do { + //printf("%s\n", entries[dir->fileno].filename); + if(entries[dir->fileno].gamecode[0]!=0xff) { + if ((dir->showall || memcmp(entries[dir->fileno].gamecode,card_gamecode,4)==0) + && (dir->showall || memcmp(entries[dir->fileno].company,card_company,2)==0)) { + dir->filelen = entries[dir->fileno].length*card->sector_size; + memcpy(dir->filename, entries[dir->fileno].filename, CARD_FILENAMELEN); + memcpy(dir->gamecode, entries[dir->fileno].gamecode, 4); + memcpy(dir->company, entries[dir->fileno].company, 2); + + __card_putcntrlblock(card,CARD_ERROR_READY); + return CARD_ERROR_READY; + } + } + dir->fileno++; + } while (dir->fileno < CARD_MAXFILES); + __card_putcntrlblock(card,CARD_ERROR_NOFILE); + return CARD_ERROR_NOFILE; +} + +s32 CARD_FindFirst(s32 chn, card_dir *dir, bool showall) +{ + // initialise structure + dir->chn = chn; + dir->fileno = 0; + dir->filelen = 0; + dir->filename[0] = 0; + dir->gamecode[0] = 0; + dir->company[0] = 0; + dir->showall = showall; + return __card_findnext(dir); +} + +s32 CARD_FindNext(card_dir *dir) +{ + dir->fileno++; + + return __card_findnext(dir); +} + +s32 CARD_GetDirectory(s32 chn,card_dir *dir_entries,s32 *count,bool showall) +{ + s32 i,cnt; + s32 ret = CARD_ERROR_READY; + struct card_dat *dirblock = NULL; + struct card_direntry *entries = NULL; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + if(!card->attached) return CARD_ERROR_NOCARD; + dirblock = __card_getdirblock(card); + + entries = dirblock->entries; + for(i=0,cnt=0;isector_size; + memcpy(dir_entries[cnt].gamecode,entries[i].gamecode,4); + memcpy(dir_entries[cnt].company,entries[i].company,2); + memcpy(dir_entries[cnt].filename,entries[i].filename,CARD_FILENAMELEN); + cnt++; + } + } + } + if(count) *count = cnt; + if(cnt==0) ret = CARD_ERROR_NOFILE; + __card_putcntrlblock(card,ret); + return ret; +} + +s32 CARD_GetSectorSize(s32 chn,u32 *sector_size) +{ + s32 ret; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + *sector_size = card->sector_size; + ret = __card_putcntrlblock(card,CARD_ERROR_READY); + + return ret; +} + +s32 CARD_GetBlockCount(s32 chn,u32 *block_count) +{ + s32 ret; + card_block *card = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + *block_count = card->blocks; + ret = __card_putcntrlblock(card,CARD_ERROR_READY); + + return ret; +} + +s32 CARD_GetStatus(s32 chn,s32 fileno,card_stat *stats) +{ + s32 ret; + card_block *card = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entry = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR; + + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + dirblock = __card_getdirblock(card); + if(dirblock) { + entry = &dirblock->entries[fileno]; + memcpy(stats->gamecode,entry->gamecode,4); + memcpy(stats->company,entry->company,2); + memcpy(stats->filename,entry->filename,CARD_FILENAMELEN); + stats->len = entry->length*card->sector_size; + stats->time = entry->lastmodified; + stats->banner_fmt = entry->bannerfmt; + stats->icon_addr = entry->iconaddr; + stats->icon_fmt = entry->iconfmt; + stats->icon_speed = entry->iconspeed; + stats->comment_addr = entry->commentaddr; + __card_updateiconoffsets(entry,stats); + } + + return __card_putcntrlblock(card,CARD_ERROR_READY); +} + +s32 CARD_SetStatusAsync(s32 chn,s32 fileno,card_stat *stats,cardcallback callback) +{ + s32 ret; + card_block *card = NULL; + struct card_dat *dirblock = NULL; + struct card_direntry *entry = NULL; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_NOCARD; + if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR; + if(stats->icon_addr!=-1 && stats->icon_addr>CARD_READSIZE) return CARD_ERROR_FATAL_ERROR; + if(stats->comment_addr!=-1 && stats->comment_addr>8128) return CARD_ERROR_FATAL_ERROR; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + ret = CARD_ERROR_BROKEN; + dirblock = __card_getdirblock(card); + if(dirblock) { + entry = &dirblock->entries[fileno]; + entry->bannerfmt = stats->banner_fmt; + entry->iconaddr = stats->icon_addr; + entry->iconfmt = stats->icon_fmt; + entry->iconspeed = stats->icon_speed; + entry->commentaddr = stats->comment_addr; + __card_updateiconoffsets(entry,stats); + + if(entry->iconaddr==-1) entry->iconfmt = ((entry->iconfmt&~CARD_ICON_MASK)|CARD_ICON_CI); + + entry->lastmodified = time(NULL); + if((ret=__card_updatedir(chn,callback))>=0) return ret; + } + + return __card_putcntrlblock(card,ret); +} + +s32 CARD_SetStatus(s32 chn,s32 fileno,card_stat *stats) +{ + s32 ret; + + if((ret=CARD_SetStatusAsync(chn,fileno,stats,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_GetAttributes(s32 chn,s32 fileno,u8 *attr) +{ + s32 ret; + struct card_direntry entry; + + if((ret=__card_getstatusex(chn,fileno,&entry))==CARD_ERROR_READY) { + *attr = entry.permission; + } + return ret; +} + +s32 CARD_SetAttributesAsync(s32 chn,s32 fileno,u8 attr,cardcallback callback) +{ + s32 ret; + struct card_direntry entry; + + if((ret=__card_getstatusex(chn,fileno,&entry))>=0) { + entry.permission = attr; + ret = __card_setstatusexasync(chn,fileno,&entry,callback); + } + return ret; +} + +s32 CARD_SetAttributes(s32 chn,s32 fileno,u8 attr) +{ + s32 ret; + + if((ret=CARD_SetAttributesAsync(chn,fileno,attr,__card_synccallback))>=0) { + ret = __card_sync(chn); + } + return ret; +} + +s32 CARD_SetCompany(const char *company) +{ + u32 level,i; + + _CPU_ISR_Disable(level); + for(i=0;i<2;i++) card_company[i] = 0xff; + if(company && strlen(company)<=2) memcpy(card_company,company,2) ; + _CPU_ISR_Restore(level); + + return CARD_ERROR_READY; +} + +s32 CARD_SetGamecode(const char *gamecode) +{ + u32 level,i; + + _CPU_ISR_Disable(level); + for(i=0;i<4;i++) card_gamecode[i] = 0xff; + if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4) ; + _CPU_ISR_Restore(level); + + return CARD_ERROR_READY; +} diff --git a/wii/libogc/libogc/cond.c b/wii/libogc/libogc/cond.c new file mode 100644 index 0000000000..9b893a83f8 --- /dev/null +++ b/wii/libogc/libogc/cond.c @@ -0,0 +1,199 @@ +/*------------------------------------------------------------- + +cond.c -- Thread subsystem V + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include "asm.h" +#include "mutex.h" +#include "lwp_threadq.h" +#include "lwp_objmgr.h" +#include "lwp_config.h" +#include "cond.h" + +#define LWP_OBJTYPE_COND 5 + +#define LWP_CHECK_COND(hndl) \ +{ \ + if(((hndl)==LWP_COND_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_COND)) \ + return NULL; \ +} + +typedef struct _cond_st { + lwp_obj object; + mutex_t lock; + lwp_thrqueue wait_queue; +} cond_st; + +lwp_objinfo _lwp_cond_objects; + +extern int clock_gettime(struct timespec *tp); +extern void timespec_subtract(const struct timespec *tp_start,const struct timespec *tp_end,struct timespec *result); + +void __lwp_cond_init() +{ + __lwp_objmgr_initinfo(&_lwp_cond_objects,LWP_MAX_CONDVARS,sizeof(cond_st)); +} + +static __inline__ cond_st* __lwp_cond_open(cond_t cond) +{ + LWP_CHECK_COND(cond); + return (cond_st*)__lwp_objmgr_get(&_lwp_cond_objects,LWP_OBJMASKID(cond)); +} + +static __inline__ void __lwp_cond_free(cond_st *cond) +{ + __lwp_objmgr_close(&_lwp_cond_objects,&cond->object); + __lwp_objmgr_free(&_lwp_cond_objects,&cond->object); +} + +static cond_st* __lwp_cond_allocate() +{ + cond_st *cond; + + __lwp_thread_dispatchdisable(); + cond = (cond_st*)__lwp_objmgr_allocate(&_lwp_cond_objects); + if(cond) { + __lwp_objmgr_open(&_lwp_cond_objects,&cond->object); + return cond; + } + __lwp_thread_dispatchenable(); + return NULL; +} + +static s32 __lwp_cond_waitsupp(cond_t cond,mutex_t mutex,u64 timeout,u8 timedout) +{ + u32 status,mstatus,level; + cond_st *thecond = __lwp_cond_open(cond); + + if(!thecond) return -1; + + if(thecond->lock!=LWP_MUTEX_NULL && thecond->lock!=mutex) { + __lwp_thread_dispatchenable(); + return EINVAL; + } + + + LWP_MutexUnlock(mutex); + if(!timedout) { + thecond->lock = mutex; + _CPU_ISR_Disable(level); + __lwp_threadqueue_csenter(&thecond->wait_queue); + _thr_executing->wait.ret_code = 0; + _thr_executing->wait.queue = &thecond->wait_queue; + _thr_executing->wait.id = cond; + _CPU_ISR_Restore(level); + __lwp_threadqueue_enqueue(&thecond->wait_queue,timeout); + __lwp_thread_dispatchenable(); + + status = _thr_executing->wait.ret_code; + if(status && status!=ETIMEDOUT) + return status; + } else { + __lwp_thread_dispatchenable(); + status = ETIMEDOUT; + } + + mstatus = LWP_MutexLock(mutex); + if(mstatus) + return EINVAL; + + return status; +} + +static s32 __lwp_cond_signalsupp(cond_t cond,u8 isbroadcast) +{ + lwp_cntrl *thethread; + cond_st *thecond = __lwp_cond_open(cond); + if(!thecond) return -1; + + do { + thethread = __lwp_threadqueue_dequeue(&thecond->wait_queue); + if(!thethread) thecond->lock = LWP_MUTEX_NULL; + } while(isbroadcast && thethread); + __lwp_thread_dispatchenable(); + return 0; +} + +s32 LWP_CondInit(cond_t *cond) +{ + cond_st *ret; + + if(!cond) return -1; + + ret = __lwp_cond_allocate(); + if(!ret) return ENOMEM; + + ret->lock = LWP_MUTEX_NULL; + __lwp_threadqueue_init(&ret->wait_queue,LWP_THREADQ_MODEFIFO,LWP_STATES_WAITING_FOR_CONDVAR,ETIMEDOUT); + + *cond = (cond_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_COND)|LWP_OBJMASKID(ret->object.id)); + __lwp_thread_dispatchenable(); + + return 0; +} + +s32 LWP_CondWait(cond_t cond,mutex_t mutex) +{ + return __lwp_cond_waitsupp(cond,mutex,LWP_THREADQ_NOTIMEOUT,FALSE); +} + +s32 LWP_CondSignal(cond_t cond) +{ + return __lwp_cond_signalsupp(cond,FALSE); +} + +s32 LWP_CondBroadcast(cond_t cond) +{ + return __lwp_cond_signalsupp(cond,TRUE); +} + +s32 LWP_CondTimedWait(cond_t cond,mutex_t mutex,const struct timespec *abstime) +{ + u64 timeout = LWP_THREADQ_NOTIMEOUT; + bool timedout = FALSE; + + if(abstime) timeout = __lwp_wd_calc_ticks(abstime); + return __lwp_cond_waitsupp(cond,mutex,timeout,timedout); +} + +s32 LWP_CondDestroy(cond_t cond) +{ + cond_st *ptr = __lwp_cond_open(cond); + if(!ptr) return -1; + + if(__lwp_threadqueue_first(&ptr->wait_queue)) { + __lwp_thread_dispatchenable(); + return EBUSY; + } + __lwp_thread_dispatchenable(); + + __lwp_cond_free(ptr); + return 0; +} diff --git a/wii/libogc/libogc/conf.c b/wii/libogc/libogc/conf.c new file mode 100644 index 0000000000..2492e45c8a --- /dev/null +++ b/wii/libogc/libogc/conf.c @@ -0,0 +1,479 @@ +/*------------------------------------------------------------- + +conf.c -- SYSCONF support + +Copyright (C) 2008 +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include +#include +#include "ipc.h" +#include "asm.h" +#include "processor.h" +#include "conf.h" + + +static int __conf_inited = 0; +static u8 __conf_buffer[0x4000] ATTRIBUTE_ALIGN(32); +static char __conf_txt_buffer[0x101] ATTRIBUTE_ALIGN(32); + +static const char __conf_file[] ATTRIBUTE_ALIGN(32) = "/shared2/sys/SYSCONF"; +static const char __conf_txt_file[] ATTRIBUTE_ALIGN(32) = "/title/00000001/00000002/data/setting.txt"; + +void __CONF_DecryptTextBuffer(void) +{ + u32 key = 0x73B5DBFA; + int i; + + for(i=0; i<0x100; i++) { + __conf_txt_buffer[i] ^= key & 0xff; + key = (key<<1) | (key>>31); + } +} + +s32 CONF_Init(void) +{ + int fd; + int ret; + + if(__conf_inited) return 0; + + fd = IOS_Open(__conf_file,1); + if(fd < 0) return fd; + + memset(__conf_buffer,0,0x4000); + memset(__conf_txt_buffer,0,0x101); + + ret = IOS_Read(fd, __conf_buffer, 0x4000); + IOS_Close(fd); + if(ret != 0x4000) return CONF_EBADFILE; + + fd = IOS_Open(__conf_txt_file,1); + if(fd < 0) return fd; + + ret = IOS_Read(fd, __conf_txt_buffer, 0x100); + IOS_Close(fd); + if(ret != 0x100) return CONF_EBADFILE; + + if(memcmp(__conf_buffer, "SCv0", 4)) return CONF_EBADFILE; + + __CONF_DecryptTextBuffer(); + + __conf_inited = 1; + return 0; +} + +int __CONF_GetTxt(const char *name, char *buf, int length) +{ + char *line = __conf_txt_buffer; + char *delim, *end; + int slen; + int nlen = strlen(name); + + if(!__conf_inited) return CONF_ENOTINIT; + + while(line < (__conf_txt_buffer+0x100) ) { + delim = strchr(line, '='); + if(delim && ((delim - line) == nlen) && !memcmp(name, line, nlen)) { + delim++; + end = strchr(line, '\r'); + if (!end) end = strchr(line, '\n'); + if(end) { + slen = end - delim; + if(slen < length) { + memcpy(buf, delim, slen); + buf[slen] = 0; + return slen; + } else { + return CONF_ETOOBIG; + } + } + } + + // skip to line end + while(line < (__conf_txt_buffer+0x100) && *line++ != '\n'); + } + return CONF_ENOENT; +} + +u8 *__CONF_Find(const char *name) +{ + u16 count; + u16 *offset; + int nlen = strlen(name); + count = *((u16*)(&__conf_buffer[4])); + offset = (u16*)&__conf_buffer[6]; + + while(count--) { + if((nlen == ((__conf_buffer[*offset]&0x0F)+1)) && !memcmp(name, &__conf_buffer[*offset+1], nlen)) + return &__conf_buffer[*offset]; + offset++; + } + return NULL; +} + +s32 CONF_GetLength(const char *name) +{ + u8 *entry; + + if(!__conf_inited) return CONF_ENOTINIT; + + entry = __CONF_Find(name); + if(!entry) return CONF_ENOENT; + + switch(*entry>>5) { + case 1: + return *((u16*)&entry[strlen(name)+1]) + 1; + case 2: + return entry[strlen(name)+1] + 1; + case 3: + return 1; + case 4: + return 2; + case 5: + return 4; + case 7: + return 1; + default: + return CONF_ENOTIMPL; + } +} + +s32 CONF_GetType(const char *name) +{ + u8 *entry; + if(!__conf_inited) return CONF_ENOTINIT; + + entry = __CONF_Find(name); + if(!entry) return CONF_ENOENT; + + return *entry>>5; +} + +s32 CONF_Get(const char *name, void *buffer, u32 length) +{ + u8 *entry; + s32 len; + if(!__conf_inited) return CONF_ENOTINIT; + + entry = __CONF_Find(name); + if(!entry) return CONF_ENOENT; + + len = CONF_GetLength(name); + if(len<0) return len; + if(len>length) return CONF_ETOOBIG; + + switch(*entry>>5) { + case CONF_BIGARRAY: + memcpy(buffer, &entry[strlen(name)+3], len); + break; + case CONF_SMALLARRAY: + memcpy(buffer, &entry[strlen(name)+2], len); + break; + case CONF_BYTE: + case CONF_SHORT: + case CONF_LONG: + case CONF_BOOL: + memset(buffer, 0, length); + memcpy(buffer, &entry[strlen(name)+1], len); + break; + default: + return CONF_ENOTIMPL; + } + return len; +} + +s32 CONF_GetShutdownMode(void) +{ + u8 idleconf[2] = {0,0}; + int res; + + res = CONF_Get("IPL.IDL", idleconf, 2); + if(res<0) return res; + if(res!=2) return CONF_EBADVALUE; + return idleconf[0]; +} + +s32 CONF_GetIdleLedMode(void) +{ + int res; + u8 idleconf[2] = {0,0}; + res = CONF_Get("IPL.IDL", idleconf, 2); + if(res<0) return res; + if(res!=2) return CONF_EBADVALUE; + return idleconf[1]; +} + +s32 CONF_GetProgressiveScan(void) +{ + int res; + u8 val = 0; + res = CONF_Get("IPL.PGS", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetEuRGB60(void) +{ + int res; + u8 val = 0; + res = CONF_Get("IPL.E60", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetIRSensitivity(void) +{ + int res; + u32 val = 0; + res = CONF_Get("BT.SENS", &val, 4); + if(res<0) return res; + if(res!=4) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetSensorBarPosition(void) +{ + int res; + u8 val = 0; + res = CONF_Get("BT.BAR", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetPadSpeakerVolume(void) +{ + int res; + u8 val = 0; + res = CONF_Get("BT.SPKV", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetPadMotorMode(void) +{ + int res; + u8 val = 0; + res = CONF_Get("BT.MOT", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetSoundMode(void) +{ + int res; + u8 val = 0; + res = CONF_Get("IPL.SND", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetLanguage(void) +{ + int res; + u8 val = 0; + res = CONF_Get("IPL.LNG", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetCounterBias(u32 *bias) +{ + int res; + res = CONF_Get("IPL.CB", bias, 4); + if(res<0) return res; + if(res!=4) return CONF_EBADVALUE; + return CONF_ERR_OK; +} + +s32 CONF_GetScreenSaverMode(void) +{ + int res; + u8 val = 0; + res = CONF_Get("IPL.SSV", &val, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetDisplayOffsetH(s8 *offset) +{ + int res; + res = CONF_Get("IPL.DH", offset, 1); + if(res<0) return res; + if(res!=1) return CONF_EBADVALUE; + return 0; +} + +s32 CONF_GetPadDevices(conf_pads *pads) +{ + int res; + + res = CONF_Get("BT.DINF", pads, sizeof(conf_pads)); + if(res < 0) return res; + if(res < sizeof(conf_pads)) return CONF_EBADVALUE; + return 0; +} + +s32 CONF_GetNickName(u8 *nickname) +{ + int i, res; + u16 buf[11]; + + res = CONF_Get("IPL.NIK", buf, 0x16); + if(res < 0) return res; + if((res != 0x16) || (!buf[0])) return CONF_EBADVALUE; + + for(i=0; i<10; i++) + nickname[i] = buf[i]; + nickname[10] = 0; + + return res; +} + +s32 CONF_GetAspectRatio(void) +{ + int res; + u8 val = 0; + + res = CONF_Get("IPL.AR", &val, 1); + if(res < 0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetEULA(void) +{ + int res; + u8 val = 0; + + res = CONF_Get("IPL.EULA", &val, 1); + if(res < 0) return res; + if(res!=1) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetParentalPassword(s8 *password) +{ + int res; + u8 buf[0x4A]; + + res = CONF_Get("IPL.PC", buf, 0x4A); + if(res < 0) return res; + if(res!=1) return CONF_EBADVALUE; + + memcpy(password, buf+3, 4); + password[4] = 0; + + return res; +} + +s32 CONF_GetParentalAnswer(s8 *answer) +{ + int res; + u8 buf[0x4A]; + + res = CONF_Get("IPL.PC", buf, 0x4A); + if(res < 0) return res; + if(res!=1) return CONF_EBADVALUE; + + memcpy(answer, buf+8, 32); + answer[32] = 0; + + return res; +} + +s32 CONF_GetWiiConnect24(void) +{ + int res; + u32 val = 0; + + res = CONF_Get("NET.WCFG", &val, 4); + if(res < 0) return res; + if(res!=4) return CONF_EBADVALUE; + return val; +} + +s32 CONF_GetRegion(void) +{ + int res; + char buf[3]; + + res = __CONF_GetTxt("GAME", buf, 3); + if(res < 0) return res; + if(!strcmp(buf, "JP")) return CONF_REGION_JP; + if(!strcmp(buf, "US")) return CONF_REGION_US; + if(!strcmp(buf, "EU")) return CONF_REGION_EU; + if(!strcmp(buf, "KR")) return CONF_REGION_KR; + if(!strcmp(buf, "CN")) return CONF_REGION_CN; + return CONF_EBADVALUE; +} + +s32 CONF_GetArea(void) +{ + int res; + char buf[4]; + + res = __CONF_GetTxt("AREA", buf, 4); + if(res < 0) return res; + if(!strcmp(buf, "JPN")) return CONF_AREA_JPN; + if(!strcmp(buf, "USA")) return CONF_AREA_USA; + if(!strcmp(buf, "EUR")) return CONF_AREA_EUR; + if(!strcmp(buf, "AUS")) return CONF_AREA_AUS; + if(!strcmp(buf, "BRA")) return CONF_AREA_BRA; + if(!strcmp(buf, "TWN")) return CONF_AREA_TWN; + if(!strcmp(buf, "ROC")) return CONF_AREA_ROC; + if(!strcmp(buf, "KOR")) return CONF_AREA_KOR; + if(!strcmp(buf, "HKG")) return CONF_AREA_HKG; + if(!strcmp(buf, "ASI")) return CONF_AREA_ASI; + if(!strcmp(buf, "LTN")) return CONF_AREA_LTN; + if(!strcmp(buf, "SAF")) return CONF_AREA_SAF; + if(!strcmp(buf, "CHN")) return CONF_AREA_CHN; + return CONF_EBADVALUE; +} + +s32 CONF_GetVideo(void) +{ + int res; + char buf[5]; + + res = __CONF_GetTxt("VIDEO", buf, 5); + if(res < 0) return res; + if(!strcmp(buf, "NTSC")) return CONF_VIDEO_NTSC; + if(!strcmp(buf, "PAL")) return CONF_VIDEO_PAL; + if(!strcmp(buf, "MPAL")) return CONF_VIDEO_MPAL; + return CONF_EBADVALUE; +} + +#endif diff --git a/wii/libogc/libogc/console.c b/wii/libogc/libogc/console.c new file mode 100644 index 0000000000..be43822a2e --- /dev/null +++ b/wii/libogc/libogc/console.c @@ -0,0 +1,644 @@ +#include +#include +#include +#include + +#include "asm.h" +#include "processor.h" +#include "color.h" +#include "cache.h" +#include "video.h" +#include "system.h" + +#include "console.h" +#include "consol.h" +#include "usbgecko.h" + +#include +#include + +//--------------------------------------------------------------------------------- +const devoptab_t dotab_stdout = { +//--------------------------------------------------------------------------------- + "stdout", // device name + 0, // size of file structure + NULL, // device open + NULL, // device close + __console_write, // device write + NULL, // device read + NULL, // device seek + NULL, // device fstat + NULL, // device stat + NULL, // device link + NULL, // device unlink + NULL, // device chdir + NULL, // device rename + NULL, // device mkdir + 0, // dirStateSize + NULL, // device diropen_r + NULL, // device dirreset_r + NULL, // device dirnext_r + NULL, // device dirclose_r + NULL, // device statvfs_r + NULL, // device ftrunctate_r + NULL, // device fsync_r + NULL, // deviceData; +}; + +//color table +static const unsigned int color_table[] = +{ + 0x00800080, // 30 normal black + 0x246A24BE, // 31 normal red + 0x4856484B, // 32 normal green + 0x6D416D8A, // 33 normal yellow + 0x0DBE0D75, // 34 normal blue + 0x32A932B4, // 35 normal magenta + 0x56955641, // 36 normal cyan + 0xC580C580, // 37 normal white + 0x7B807B80, // 30 bright black + 0x4C544CFF, // 31 bright red + 0x95299512, // 32 bright green + 0xE200E294, // 33 bright yellow + 0x1CFF1C6B, // 34 bright blue + 0x69D669ED, // 35 bright magenta + 0xB2ABB200, // 36 bright cyan + 0xFF80FF80, // 37 bright white +}; + +static u32 do_xfb_copy = FALSE; +static struct _console_data_s stdcon; +static struct _console_data_s *curr_con = NULL; +static void *_console_buffer = NULL; + +static s32 __gecko_status = -1; +static u32 __gecko_safe = 0; + +extern u8 console_font_8x16[]; + +void __console_vipostcb(u32 retraceCnt) +{ + u32 ycnt,xcnt, fb_stride; + u32 *fb,*ptr; + + do_xfb_copy = TRUE; + + ptr = curr_con->destbuffer; + fb = VIDEO_GetCurrentFramebuffer()+(curr_con->target_y*curr_con->tgt_stride) + curr_con->target_x*VI_DISPLAY_PIX_SZ; + fb_stride = curr_con->tgt_stride/4 - (curr_con->con_xres/VI_DISPLAY_PIX_SZ); + + for(ycnt=curr_con->con_yres;ycnt>0;ycnt--) + { + for(xcnt=curr_con->con_xres;xcnt>0;xcnt-=VI_DISPLAY_PIX_SZ) + { + *fb++ = *ptr++; + } + fb += fb_stride; + } + + do_xfb_copy = FALSE; +} + + +static void __console_drawc(int c) +{ + console_data_s *con; + int ay; + unsigned int *ptr; + unsigned char *pbits; + unsigned char bits; + unsigned int color; + unsigned int fgcolor, bgcolor; + unsigned int nextline; + + if(do_xfb_copy==TRUE) return; + if(!curr_con) return; + con = curr_con; + + ptr = (unsigned int*)(con->destbuffer + ( con->con_stride * con->cursor_row * FONT_YSIZE ) + ((con->cursor_col * FONT_XSIZE / 2) * 4)); + pbits = &con->font[c * FONT_YSIZE]; + nextline = con->con_stride/4 - 4; + fgcolor = con->foreground; + bgcolor = con->background; + + for (ay = 0; ay < FONT_YSIZE; ay++) + { + /* hard coded loop unrolling ! */ + /* this depends on FONT_XSIZE = 8*/ +#if FONT_XSIZE == 8 + bits = *pbits++; + + /* bits 1 & 2 */ + if ( bits & 0x80) + color = fgcolor & 0xFFFF00FF; + else + color = bgcolor & 0xFFFF00FF; + if (bits & 0x40) + color |= fgcolor & 0x0000FF00; + else + color |= bgcolor & 0x0000FF00; + *ptr++ = color; + + /* bits 3 & 4 */ + if ( bits & 0x20) + color = fgcolor & 0xFFFF00FF; + else + color = bgcolor & 0xFFFF00FF; + if (bits & 0x10) + color |= fgcolor & 0x0000FF00; + else + color |= bgcolor & 0x0000FF00; + *ptr++ = color; + + /* bits 5 & 6 */ + if ( bits & 0x08) + color = fgcolor & 0xFFFF00FF; + else + color = bgcolor & 0xFFFF00FF; + if (bits & 0x04) + color |= fgcolor & 0x0000FF00; + else + color |= bgcolor & 0x0000FF00; + *ptr++ = color; + + /* bits 7 & 8 */ + if ( bits & 0x02) + color = fgcolor & 0xFFFF00FF; + else + color = bgcolor & 0xFFFF00FF; + if (bits & 0x01) + color |= fgcolor & 0x0000FF00; + else + color |= bgcolor & 0x0000FF00; + *ptr++ = color; + + /* next line */ + ptr += nextline; +#endif + } +} +static void __console_clear_line( int line, int from, int to ) { + console_data_s *con; + unsigned int c; + unsigned int *p; + unsigned int x_pixels; + unsigned int px_per_col = FONT_XSIZE/2; + unsigned int line_height = FONT_YSIZE; + unsigned int line_width; + + if( !(con = curr_con) ) return; + // For some reason there are xres/2 pixels per screen width + x_pixels = con->con_xres / 2; + + line_width = (to - from)*px_per_col; + p = (unsigned int*)con->destbuffer; + + // Move pointer to the current line and column offset + p += line*(FONT_YSIZE*x_pixels) + from*px_per_col; + + // Clears 1 line of pixels at a time, line_height times + while( line_height-- ) { + c = line_width; + while( c-- ) + *p++ = con->background; + p -= line_width; + p += x_pixels; + } +} +static void __console_clear(void) +{ + console_data_s *con; + unsigned int c; + unsigned int *p; + + if( !(con = curr_con) ) return; + + c = (con->con_xres*con->con_yres)/2; + p = (unsigned int*)con->destbuffer; + + while(c--) + *p++ = con->background; + + con->cursor_row = 0; + con->cursor_col = 0; + con->saved_row = 0; + con->saved_col = 0; +} +static void __console_clear_from_cursor() { + console_data_s *con; + int cur_row; + + if( !(con = curr_con) ) return; + cur_row = con->cursor_row; + + __console_clear_line( cur_row, con->cursor_col, con->con_cols ); + + while( cur_row++ < con->con_rows ) + __console_clear_line( cur_row, 0, con->con_cols ); + +} +static void __console_clear_to_cursor() { + console_data_s *con; + int cur_row; + + if( !(con = curr_con) ) return; + cur_row = con->cursor_row; + + __console_clear_line( cur_row, 0, con->cursor_col ); + + while( cur_row-- ) + __console_clear_line( cur_row, 0, con->con_cols ); +} + +void __console_init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride) +{ + unsigned int level; + console_data_s *con = &stdcon; + + _CPU_ISR_Disable(level); + + con->destbuffer = framebuffer; + con->con_xres = xres; + con->con_yres = yres; + con->con_cols = xres / FONT_XSIZE; + con->con_rows = yres / FONT_YSIZE; + con->con_stride = con->tgt_stride = stride; + con->target_x = xstart; + con->target_y = ystart; + + con->font = console_font_8x16; + + con->foreground = COLOR_WHITE; + con->background = COLOR_BLACK; + + curr_con = con; + + __console_clear(); + + devoptab_list[STD_OUT] = &dotab_stdout; + devoptab_list[STD_ERR] = &dotab_stdout; + _CPU_ISR_Restore(level); + + setvbuf(stdout, NULL , _IONBF, 0); + setvbuf(stderr, NULL , _IONBF, 0); +} + +void __console_init_ex(void *conbuffer,int tgt_xstart,int tgt_ystart,int tgt_stride,int con_xres,int con_yres,int con_stride) +{ + unsigned int level; + console_data_s *con = &stdcon; + + _CPU_ISR_Disable(level); + + con->destbuffer = conbuffer; + con->target_x = tgt_xstart; + con->target_y = tgt_ystart; + con->con_xres = con_xres; + con->con_yres = con_yres; + con->tgt_stride = tgt_stride; + con->con_stride = con_stride; + con->con_cols = con_xres / FONT_XSIZE; + con->con_rows = con_yres / FONT_YSIZE; + con->cursor_row = 0; + con->cursor_col = 0; + con->saved_row = 0; + con->saved_col = 0; + + con->font = console_font_8x16; + + con->foreground = COLOR_WHITE; + con->background = COLOR_BLACK; + + curr_con = con; + + __console_clear(); + + devoptab_list[STD_OUT] = &dotab_stdout; + devoptab_list[STD_ERR] = &dotab_stdout; + + VIDEO_SetPostRetraceCallback(__console_vipostcb); + + _CPU_ISR_Restore(level); + + setvbuf(stdout, NULL , _IONBF, 0); + setvbuf(stderr, NULL , _IONBF, 0); +} + +static int __console_parse_escsequence(char *pchr) +{ + char chr; + console_data_s *con; + int i; + int parameters[3]; + int para; + + if(!curr_con) return -1; + con = curr_con; + + /* set default value */ + para = 0; + parameters[0] = 0; + parameters[1] = 0; + parameters[2] = 0; + + /* scan parameters */ + i = 0; + chr = *pchr; + while( (para < 3) && (chr >= '0') && (chr <= '9') ) + { + while( (chr >= '0') && (chr <= '9') ) + { + /* parse parameter */ + parameters[para] *= 10; + parameters[para] += chr - '0'; + pchr++; + i++; + chr = *pchr; + } + para++; + + if( *pchr == ';' ) + { + /* skip parameter delimiter */ + pchr++; + i++; + } + chr = *pchr; + } + + /* get final character */ + chr = *pchr++; + i++; + switch(chr) + { + ///////////////////////////////////////// + // Cursor directional movement + ///////////////////////////////////////// + case 'A': + { + curr_con->cursor_row -= parameters[0]; + if(curr_con->cursor_row < 0) curr_con->cursor_row = 0; + break; + } + case 'B': + { + curr_con->cursor_row += parameters[0]; + if(curr_con->cursor_row >= curr_con->con_rows) curr_con->cursor_row = curr_con->con_rows - 1; + break; + } + case 'C': + { + curr_con->cursor_col += parameters[0]; + if(curr_con->cursor_col >= curr_con->con_cols) curr_con->cursor_col = curr_con->con_cols - 1; + break; + } + case 'D': + { + curr_con->cursor_col -= parameters[0]; + if(curr_con->cursor_col < 0) curr_con->cursor_col = 0; + break; + } + ///////////////////////////////////////// + // Cursor position movement + ///////////////////////////////////////// + case 'H': + case 'f': + { + curr_con->cursor_col = parameters[1]; + curr_con->cursor_row = parameters[0]; + if(curr_con->cursor_row >= curr_con->con_rows) curr_con->cursor_row = curr_con->con_rows - 1; + if(curr_con->cursor_col >= curr_con->con_cols) curr_con->cursor_col = curr_con->con_cols - 1; + break; + } + ///////////////////////////////////////// + // Screen clear + ///////////////////////////////////////// + case 'J': + { + if( parameters[0] == 0 ) + __console_clear_from_cursor(); + if( parameters[0] == 1 ) + __console_clear_to_cursor(); + if( parameters[0] == 2 ) + __console_clear(); + + break; + } + ///////////////////////////////////////// + // Line clear + ///////////////////////////////////////// + case 'K': + { + if( parameters[0] == 0 ) + __console_clear_line( curr_con->cursor_row, curr_con->cursor_col, curr_con->con_cols ); + if( parameters[0] == 1 ) + __console_clear_line( curr_con->cursor_row, 0, curr_con->cursor_col ); + if( parameters[0] == 2 ) + __console_clear_line( curr_con->cursor_row, 0, curr_con->con_cols); + + break; + } + ///////////////////////////////////////// + // Save cursor position + ///////////////////////////////////////// + case 's': + { + con->saved_col = con->cursor_col; + con->saved_row = con->cursor_row; + break; + } + ///////////////////////////////////////// + // Load cursor position + ///////////////////////////////////////// + case 'u': + con->cursor_col = con->saved_col; + con->cursor_row = con->saved_row; + break; + ///////////////////////////////////////// + // SGR Select Graphic Rendition + ///////////////////////////////////////// + case 'm': + { + // handle 30-37,39 for foreground color changes + if( (parameters[0] >= 30) && (parameters[0] <= 39) ) + { + parameters[0] -= 30; + + //39 is the reset code + if(parameters[0] == 9){ + parameters[0] = 15; + } + else if(parameters[0] > 7){ + parameters[0] = 7; + } + + if(parameters[1] == 1) + { + // Intensity: Bold makes color bright + parameters[0] += 8; + } + con->foreground = color_table[parameters[0]]; + } + // handle 40-47 for background color changes + else if( (parameters[0] >= 40) && (parameters[0] <= 47) ) + { + parameters[0] -= 40; + + if(parameters[1] == 1) + { + // Intensity: Bold makes color bright + parameters[0] += 8; + } + con->background = color_table[parameters[0]]; + } + break; + } + } + + return(i); +} + +int __console_write(struct _reent *r,void *fd,const char *ptr,size_t len) +{ + size_t i = 0; + char *tmp = (char*)ptr; + console_data_s *con; + char chr; + + if(__gecko_status>=0) { + if(__gecko_safe) + usb_sendbuffer_safe(__gecko_status,ptr,len); + else + usb_sendbuffer(__gecko_status,ptr,len); + } + + if(!curr_con) return -1; + con = curr_con; + if(!tmp || len<=0) return -1; + + i = 0; + while(*tmp!='\0' && icursor_row++; + con->cursor_col = 0; + break; + case '\r': + con->cursor_col = 0; + break; + case '\b': + con->cursor_col--; + if(con->cursor_col < 0) + { + con->cursor_col = 0; + } + break; + case '\f': + con->cursor_row++; + break; + case '\t': + if(con->cursor_col%TAB_SIZE) con->cursor_col += (con->cursor_col%TAB_SIZE); + else con->cursor_col += TAB_SIZE; + break; + default: + __console_drawc(chr); + con->cursor_col++; + + if( con->cursor_col >= con->con_cols) + { + /* if right border reached wrap around */ + con->cursor_row++; + con->cursor_col = 0; + } + } + } + + if( con->cursor_row >= con->con_rows) + { + /* if bottom border reached scroll */ + memcpy(con->destbuffer, + con->destbuffer+con->con_stride*(FONT_YSIZE*FONT_YFACTOR+FONT_YGAP), + con->con_stride*con->con_yres-FONT_YSIZE); + + unsigned int cnt = (con->con_stride * (FONT_YSIZE * FONT_YFACTOR + FONT_YGAP))/4; + unsigned int *ptr = (unsigned int*)(con->destbuffer + con->con_stride * (con->con_yres - FONT_YSIZE)); + while(cnt--) + *ptr++ = con->background; + con->cursor_row--; + } + } + + return i; +} + +void CON_Init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride) +{ + __console_init(framebuffer,xstart,ystart,xres,yres,stride); +} + +s32 CON_InitEx(GXRModeObj *rmode, s32 conXOrigin,s32 conYOrigin,s32 conWidth,s32 conHeight) +{ + VIDEO_SetPostRetraceCallback(NULL); + if(_console_buffer) + free(_console_buffer); + + _console_buffer = malloc(conWidth*conHeight*VI_DISPLAY_PIX_SZ); + if(!_console_buffer) return -1; + + __console_init_ex(_console_buffer,conXOrigin,conYOrigin,rmode->fbWidth*VI_DISPLAY_PIX_SZ,conWidth,conHeight,conWidth*VI_DISPLAY_PIX_SZ); + + return 0; +} + +void CON_GetMetrics(int *cols, int *rows) +{ + if(curr_con) { + *cols = curr_con->con_cols; + *rows = curr_con->con_rows; + } +} + +void CON_GetPosition(int *col, int *row) +{ + if(curr_con) { + *col = curr_con->cursor_col; + *row = curr_con->cursor_row; + } +} + +void CON_EnableGecko(int channel,int safe) +{ + if(channel && (channel>1 || !usb_isgeckoalive(channel))) channel = -1; + + __gecko_status = channel; + __gecko_safe = safe; + + if(__gecko_status!=-1) { + devoptab_list[STD_OUT] = &dotab_stdout; + devoptab_list[STD_ERR] = &dotab_stdout; + + // line buffered output for threaded apps when only using the usbgecko + if(!curr_con) { + setvbuf(stdout, NULL, _IOLBF, 0); + setvbuf(stderr, NULL, _IOLBF, 0); + } + } +} + diff --git a/wii/libogc/libogc/console.h b/wii/libogc/libogc/console.h new file mode 100644 index 0000000000..df05b1e798 --- /dev/null +++ b/wii/libogc/libogc/console.h @@ -0,0 +1,30 @@ +#ifndef __CONSOLE_H__ +#define __CONSOLE_H__ + + +#define FONT_XSIZE 8 +#define FONT_YSIZE 16 +#define FONT_XFACTOR 1 +#define FONT_YFACTOR 1 +#define FONT_XGAP 0 +#define FONT_YGAP 0 +#define TAB_SIZE 4 + +typedef struct _console_data_s { + void *destbuffer; + unsigned char *font; + int con_xres,con_yres,con_stride; + int target_x,target_y, tgt_stride; + int cursor_row,cursor_col; + int saved_row,saved_col; + int con_rows, con_cols; + + unsigned int foreground,background; +} console_data_s; + +extern int __console_write(struct _reent *r,void *fd,const char *ptr,size_t len); +extern void __console_init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride); + +//extern const devoptab_t dotab_stdout; + +#endif diff --git a/wii/libogc/libogc/console_font_8x16.c b/wii/libogc/libogc/console_font_8x16.c new file mode 100644 index 0000000000..21ef8da057 --- /dev/null +++ b/wii/libogc/libogc/console_font_8x16.c @@ -0,0 +1,4613 @@ +unsigned char console_font_8x16[] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x1a, /* 00011010 */ + 0x32, /* 00110010 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe7, /* 11100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0xf0, /* 11110000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0e, /* 00001110 */ + 0x1e, /* 00011110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x86, /* 10000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xdc, /* 11011100 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xde, /* 11011110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0x70, /* 01110000 */ + 0x38, /* 00111000 */ + 0x1c, /* 00011100 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x36, /* 00110110 */ + 0x32, /* 00110010 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e '' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x6e, /* 01101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a '' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c '' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xe6, /* 11100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e '' */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xf8, /* 11111000 */ + 0xc4, /* 11000100 */ + 0xcc, /* 11001100 */ + 0xde, /* 11011110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f '' */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xdc, /* 11011100 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xce, /* 11001110 */ + 0x9a, /* 10011010 */ + 0x3f, /* 00111111 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '' */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + + /* 177 0xb1 '' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '' */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + + /* 179 0xb3 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 ' ' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb ' ' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd ' ' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde ' ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf ' ' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xf3, /* 11110011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 ' ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 ' ' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb ' ' */ + 0x00, /* 00000000 */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc '' */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd '' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + + diff --git a/wii/libogc/libogc/decrementer.c b/wii/libogc/libogc/decrementer.c new file mode 100644 index 0000000000..eb1c962c33 --- /dev/null +++ b/wii/libogc/libogc/decrementer.c @@ -0,0 +1,47 @@ +/*------------------------------------------------------------- + +decrementer.c -- PPC decrementer exception support + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include +#include +#include "asm.h" +#include "processor.h" +#include "lwp_threads.h" +#include "lwp_watchdog.h" +#include "context.h" + +void __decrementer_init() +{ +} + +void c_decrementer_handler(frame_context *ctx) +{ + __lwp_wd_tickle_ticks(); +} diff --git a/wii/libogc/libogc/decrementer_handler.S b/wii/libogc/libogc/decrementer_handler.S new file mode 100644 index 0000000000..6e824d94be --- /dev/null +++ b/wii/libogc/libogc/decrementer_handler.S @@ -0,0 +1,167 @@ +/*------------------------------------------------------------- + +decrementer_handler.S -- PPC decrementer exception support + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include + +#define EXCEPTION_PROLOG \ + mfspr r0,912; \ + stw r0,GQR0_OFFSET(sp); \ + mfspr r0,913; \ + stw r0,GQR1_OFFSET(sp); \ + mfspr r0,914; \ + stw r0,GQR2_OFFSET(sp); \ + mfspr r0,915; \ + stw r0,GQR3_OFFSET(sp); \ + mfspr r0,916; \ + stw r0,GQR4_OFFSET(sp); \ + mfspr r0,917; \ + stw r0,GQR5_OFFSET(sp); \ + mfspr r0,918; \ + stw r0,GQR6_OFFSET(sp); \ + mfspr r0,919; \ + stw r0,GQR7_OFFSET(sp); \ + stw r6,GPR6_OFFSET(sp); \ + stw r7,GPR7_OFFSET(sp); \ + stw r8,GPR8_OFFSET(sp); \ + stw r9,GPR9_OFFSET(sp); \ + stw r10,GPR10_OFFSET(sp); \ + stw r11,GPR11_OFFSET(sp); \ + stw r12,GPR12_OFFSET(sp); \ + stw r13,GPR13_OFFSET(sp); \ + stw r14,GPR14_OFFSET(sp); \ + stw r15,GPR15_OFFSET(sp) + +#define EXCEPTION_EPILOG \ + lwz r4,GQR0_OFFSET(sp); \ + mtspr 912,r4; \ + lwz r4,GQR1_OFFSET(sp); \ + mtspr 913,r4; \ + lwz r4,GQR2_OFFSET(sp); \ + mtspr 914,r4; \ + lwz r4,GQR3_OFFSET(sp); \ + mtspr 915,r4; \ + lwz r4,GQR4_OFFSET(sp); \ + mtspr 916,r4; \ + lwz r4,GQR5_OFFSET(sp); \ + mtspr 917,r4; \ + lwz r4,GQR6_OFFSET(sp); \ + mtspr 918,r4; \ + lwz r4,GQR7_OFFSET(sp); \ + mtspr 919,r4; \ + lwz r15,GPR15_OFFSET(sp); \ + lwz r14,GPR14_OFFSET(sp); \ + lwz r13,GPR13_OFFSET(sp); \ + lwz r12,GPR12_OFFSET(sp); \ + lwz r11,GPR11_OFFSET(sp); \ + lwz r10,GPR10_OFFSET(sp); \ + lwz r9,GPR9_OFFSET(sp); \ + lwz r8,GPR8_OFFSET(sp); \ + lwz r7,GPR7_OFFSET(sp); \ + lwz r6,GPR6_OFFSET(sp); \ + lwz r5,GPR5_OFFSET(sp) + + .extern c_decrementer_handler + .globl dec_exceptionhandler +dec_exceptionhandler: + stwu sp,-EXCEPTION_FRAME_END(sp) //now we're able to adjust the stackpointer with it's cached address + + EXCEPTION_PROLOG + + mfmsr r3 + ori r3,r3,MSR_RI + mtmsr r3 + isync + + addi r14,sp,0 + lis r15,_thread_dispatch_disable_level@ha + + mfspr r3,SPRG0 + cmpwi r3,0 + bne nested + mfspr sp,SPRG1 + +nested: + addi r3,r3,1 + lwz r6,_thread_dispatch_disable_level@l(r15) + mtspr SPRG0,r3 + addi r6,r6,1 + stw r6,_thread_dispatch_disable_level@l(r15) + + addi r3,r14,0x08 + bl c_decrementer_handler + + mfspr r4,SPRG0 + lwz r3,_thread_dispatch_disable_level@l(r15) + addi r4,r4,-1 + addic. r3,r3,-1 + mtspr SPRG0,r4 + stw r3,_thread_dispatch_disable_level@l(r15) + addi sp,r14,0 + bne easy_exit + + lis r4,_context_switch_want@ha + lwz r5,_context_switch_want@l(r4) + cmpwi r5,0 + beq easy_exit + +switch: + bl __thread_dispatch + +easy_exit: + lwz r4,CR_OFFSET(sp) + mtcr r4 + lwz r4,LR_OFFSET(sp) + mtlr r4 + lwz r4,CTR_OFFSET(sp) + mtctr r4 + lwz r4,XER_OFFSET(sp) + mtxer r4 + + EXCEPTION_EPILOG + + mfmsr r4 + rlwinm r4,r4,0,31,29 + mtmsr r4 + isync + + lwz r0,GPR0_OFFSET(sp) + lwz toc,GPR2_OFFSET(sp) + + lwz r4,SRR0_OFFSET(sp) + mtsrr0 r4 + lwz r4,SRR1_OFFSET(sp) + rlwinm r4, r4, 0, 19, 17 + mtsrr1 r4 + + lwz r4,GPR4_OFFSET(sp) + lwz r3,GPR3_OFFSET(sp) + addi sp,sp,EXCEPTION_FRAME_END + rfi diff --git a/wii/libogc/libogc/depackrnc.S b/wii/libogc/libogc/depackrnc.S new file mode 100644 index 0000000000..18b70e3b65 --- /dev/null +++ b/wii/libogc/libogc/depackrnc.S @@ -0,0 +1,279 @@ +#include + +/**********************************/ +/* register map */ +/* */ +/* r0 = tmp */ +/* r3 = in = r2 */ +/* r4 = out = r4 */ +/* r5 = A = r5 */ +/* r6 = X = r6 */ +/* r7 = Y = r7 */ +/* r8 = carry flag = r3 */ +/* r10 = tmp = r8 */ +/* r11 = store data = r9 */ +/* r29 = copy in(r3) = r0 */ +/* r30 = copy out(r4) = r1 */ +/* */ +/**********************************/ + +#define LOAD \ + lbzu r5,1(r29); \ + slwi r5,r5,1; \ + insrwi r5,r8,1,31; \ + extrwi r8,r5,1,23; \ + clrlwi. r5,r5,24 + +#define GETBIT \ + slwi r5,r5,1; \ + extrwi r8,r5,1,23; \ + clrlwi. r5,r5,24 + +#define COPYRAW \ + lbzu r11,1(r29); \ + stbu r11,1(r30) + + //r3 is input, r4 is output + .globl depackrnc2 +depackrnc2: + mflr r0 + stw r0,4(sp) + stwu sp,-64(sp) + stw r3,8(sp) + stw r4,12(sp) + stw r29,48(sp) + mr r29,r3 + stw r30,52(sp) + mr r30,r4 + + li r8,1 + addi r30,r30,-1 + addi r29,r29,17 + + LOAD + GETBIT + b _xloop + +_fetch3: + LOAD + b _back3 +_fetch4: + LOAD + b _back4 +_fetch5: + LOAD + b _back5 +_fetch6: + LOAD + b _back6 +_fetch7: + LOAD + b _back7 + +_raw: + li r7,4 +_x4bits: + GETBIT + beq _fetch7 +_back7: + slwi r6,r6,1 //ROL(X) + insrwi r6,r8,1,31 + extrwi r8,r6,1,23 + clrlwi r6,r6,24 + + subic. r7,r7,1 + bne _x4bits + addi r7,r6,3 + + slwi r7,r7,1 //ROL(Y) + insrwi r7,r8,1,31 + extrwi r8,r7,1,23 + clrlwi r7,r7,24 +_rawlpb: + COPYRAW + COPYRAW + + subic. r7,r7,1 + bne _rawlpb + b _xloop + +_fetch0: + LOAD + rlwinm. r0,r8,0,31,31 + bne _smalls +_getlen: + GETBIT + beq _fetch3 +_back3: + slwi r7,r7,1 //ROL(Y) + insrwi r7,r8,1,31 + extrwi r8,r7,1,23 + clrlwi r7,r7,24 + + GETBIT + beq _fetch4 +_back4: + rlwinm. r0,r8,0,31,31 + beq _copy + + GETBIT + beq _fetch5 +_back5: + subic r7,r7,1 + slwi r7,r7,1 //ROL(Y) + insrwi r7,r8,1,31 + extrwi r8,r7,1,23 + clrlwi r7,r7,24 + + cmpwi r7,9 + beq _raw + +_copy: + GETBIT + beq _fetch6 +_back6: + rlwinm. r0,r8,0,31,31 + beq _bytedisp + + GETBIT + bne _skip0 + + LOAD +_skip0: + slwi r6,r6,1 //ROL(X) + insrwi r6,r8,1,31 + extrwi r8,r6,1,23 + clrlwi r6,r6,24 + + slwi r5,r5,1 //ROL(A) + insrwi r5,r8,1,31 + extrwi r8,r5,1,23 + clrlwi. r5,r5,24 + bne _skip1 + + LOAD +_skip1: + rlwinm. r0,r8,0,31,31 + bne _bigdisp + cmpwi r6,0 + bne _bytedisp + addic r6,r6,1 + +_another: + GETBIT + bne _dispx + + LOAD +_dispx: + slwi r6,r6,1 //ROL(X) + insrwi r6,r8,1,31 + extrwi r8,r6,1,23 + clrlwi r6,r6,24 + +_bytedisp: + lbzu r8,1(r29) + andi. r10,r30,0xff + sub r8,r10,r8 + srwi r10,r30,8 + sub r10,r10,r6 + slwi r10,r10,8 + add r8,r8,r10 + subic r8,r8,1 +_bytelp: + lbzu r11,1(r8) + stbu r11,1(r30) + + subic. r7,r7,1 + bne _bytelp + b _xloop + +_getbits: + LOAD + rlwinm. r0,r8,0,31,31 + bne _string +_xbyte: + COPYRAW +_xloop: + GETBIT + rlwinm. r0,r8,0,31,31 + bne _chkz + + COPYRAW + + GETBIT + rlwinm. r0,r8,0,31,31 + beq _xbyte + + li r8,1 +_chkz: + rlwinm. r0,r5,0,24,31 + beq _getbits + +_string: + li r6,0 + li r7,2 + GETBIT + beq _fetch0 + rlwinm. r0,r8,0,31,31 + beq _getlen +_smalls: + GETBIT + beq _fetch1 +_back1: + rlwinm. r0,r8,0,31,31 + beq _bytedisp + + addic r7,r7,1 + + GETBIT + beq _fetch2 +_back2: + rlwinm. r0,r8,0,31,31 + beq _copy + lbzu r7,1(r29) + cmpwi r7,0 + beq _overnout + addic r7,r7,8 + b _copy + +_bigdisp: + GETBIT + bne _skip2 + LOAD +_skip2: + slwi r6,r6,1 //ROL(X) + insrwi r6,r8,1,31 + extrwi r8,r6,1,23 + clrlwi r6,r6,24 + ori r6,r6,4 + + GETBIT + bne _skip3 + LOAD +_skip3: + rlwinm. r0,r8,0,31,31 + bne _bytedisp + b _another + +_fetch1: + LOAD + b _back1 +_fetch2: + LOAD + b _back2 +_overnout: + GETBIT + bne _check4end + LOAD +_check4end: + rlwinm. r0,r8,0,31,31 + bne _xloop + + lwz r29,48(sp) + lwz r30,52(sp) + lwz r4,12(sp) + lwz r3,8(sp) + lwz r0,68(sp) + addi sp,sp,64 + mtlr r0 + blr diff --git a/wii/libogc/libogc/depackrnc1.c b/wii/libogc/libogc/depackrnc1.c new file mode 100644 index 0000000000..e9bb782e5e --- /dev/null +++ b/wii/libogc/libogc/depackrnc1.c @@ -0,0 +1,309 @@ +#include + +#define RNC_SIGNATURE 0x524E4301 /* "RNC\001" */ + +typedef struct { + unsigned long bitbuf; /* holds between 16 and 32 bits */ + int bitcount; /* how many bits does bitbuf hold? */ +} bit_stream; + +typedef struct { + int num; /* number of nodes in the tree */ + struct { + unsigned long code; + int codelen; + int value; + } table[32]; +} huf_table; + +static long rnc_crc (void *data, long len); +static void read_huftable (huf_table *h, bit_stream *bs, unsigned char **p); +static unsigned long huf_read (huf_table *h, bit_stream *bs,unsigned char **p); + +static void bitread_init (bit_stream *bs, unsigned char **p); +static void bitread_fix (bit_stream *bs, unsigned char **p); +static unsigned long bit_peek (bit_stream *bs, unsigned long mask); +static void bit_advance (bit_stream *bs, int n, unsigned char **p); +static unsigned long bit_read (bit_stream *bs, unsigned long mask,int n, unsigned char **p); + +static unsigned long blong (unsigned char *p); +static unsigned long bword (unsigned char *p); +static unsigned long lword (unsigned char *p); + +static unsigned long mirror (unsigned long x, int n); + +s32 depackrnc1_ulen(void *packed) +{ + unsigned char *p = packed; + if (blong (p) != RNC_SIGNATURE) + return RNC_FILE_IS_NOT_RNC; + return blong (p+4); +} + +s32 depackrnc1(void *packed,void *unpacked) +{ + unsigned char *input = packed; + unsigned char *output = unpacked; + unsigned char *inputend, *outputend; + bit_stream bs; + huf_table raw, dist, len; + unsigned long ch_count; + unsigned long ret_len; + unsigned out_crc; + + if (blong(input) != RNC_SIGNATURE) + return RNC_FILE_IS_NOT_RNC; + ret_len = blong (input+4); + outputend = output + ret_len; + inputend = input + 18 + blong(input+8); + + input += 18; /* skip header */ + + /* + * Check the packed-data CRC. Also save the unpacked-data CRC + * for later. + */ + if (rnc_crc(input, inputend-input) != bword(input-4)) + return RNC_PACKED_CRC_ERROR; + out_crc = bword(input-6); + + bitread_init (&bs, &input); + bit_advance (&bs, 2, &input); /* discard first two bits */ + + /* + * Process chunks. + */ + while (output < outputend) { + read_huftable (&raw, &bs, &input); + read_huftable (&dist, &bs, &input); + read_huftable (&len, &bs, &input); + ch_count = bit_read (&bs, 0xFFFF, 16, &input); + + while (1) { + long length, posn; + + length = huf_read (&raw, &bs, &input); + if (length == -1) + return RNC_HUF_DECODE_ERROR; + if (length) { + while (length--) + *output++ = *input++; + bitread_fix (&bs, &input); + } + if (--ch_count <= 0) + break; + + posn = huf_read (&dist, &bs, &input); + if (posn == -1) + return RNC_HUF_DECODE_ERROR; + length = huf_read (&len, &bs, &input); + if (length == -1) + return RNC_HUF_DECODE_ERROR; + posn += 1; + length += 2; + while (length--) { + *output = output[-posn]; + output++; + } + } + } + if (outputend != output) + return RNC_FILE_SIZE_MISMATCH; + + if (rnc_crc(outputend-ret_len, ret_len) != out_crc) + return RNC_UNPACKED_CRC_ERROR; + + return ret_len; +} + +/* + * Read a Huffman table out of the bit stream and data stream given. + */ +static void read_huftable (huf_table *h, bit_stream *bs, unsigned char **p) { + int i, j, k, num; + int leaflen[32]; + int leafmax; + unsigned long codeb; /* big-endian form of code */ + + num = bit_read (bs, 0x1F, 5, p); + if (!num) + return; + + leafmax = 1; + for (i=0; itable[k].code = mirror (codeb, i); + h->table[k].codelen = i; + h->table[k].value = j; + codeb++; + k++; + } + codeb <<= 1; + } + + h->num = k; +} + +/* + * Read a value out of the bit stream using the given Huffman table. + */ +static unsigned long huf_read (huf_table *h, bit_stream *bs, + unsigned char **p) { + int i; + unsigned long val; + + for (i=0; inum; i++) { + unsigned long mask = (1 << h->table[i].codelen) - 1; + if (bit_peek(bs, mask) == h->table[i].code) + break; + } + if (i == h->num) + return -1; + bit_advance (bs, h->table[i].codelen, p); + + val = h->table[i].value; + + if (val >= 2) { + val = 1 << (val-1); + val |= bit_read (bs, val-1, h->table[i].value - 1, p); + } + return val; +} + +/* + * Initialises a bit stream with the first two bytes of the packed + * data. + */ +static void bitread_init (bit_stream *bs, unsigned char **p) { + bs->bitbuf = lword (*p); + bs->bitcount = 16; +} + +/* + * Fixes up a bit stream after literals have been read out of the + * data stream. + */ +static void bitread_fix (bit_stream *bs, unsigned char **p) { + bs->bitcount -= 16; + bs->bitbuf &= (1<bitcount)-1; /* remove the top 16 bits */ + bs->bitbuf |= (lword(*p)<bitcount);/* replace with what's at *p */ + bs->bitcount += 16; +} + +/* + * Returns some bits. + */ +static unsigned long bit_peek (bit_stream *bs, unsigned long mask) { + return bs->bitbuf & mask; +} + +/* + * Advances the bit stream. + */ +static void bit_advance (bit_stream *bs, int n, unsigned char **p) { + bs->bitbuf >>= n; + bs->bitcount -= n; + if (bs->bitcount < 16) { + (*p) += 2; + bs->bitbuf |= (lword(*p)<bitcount); + bs->bitcount += 16; + } +} + +/* + * Reads some bits in one go (ie the above two routines combined). + */ +static unsigned long bit_read (bit_stream *bs, unsigned long mask, + int n, unsigned char **p) { + unsigned long result = bit_peek (bs, mask); + bit_advance (bs, n, p); + return result; +} + +/* + * Return the big-endian longword at p. + */ +static unsigned long blong (unsigned char *p) { + unsigned long n; + n = p[0]; + n = (n << 8) + p[1]; + n = (n << 8) + p[2]; + n = (n << 8) + p[3]; + return n; +} + +/* + * Return the big-endian word at p. + */ +static unsigned long bword (unsigned char *p) { + unsigned long n; + n = p[0]; + n = (n << 8) + p[1]; + return n; +} + +/* + * Return the little-endian word at p. + */ +static unsigned long lword (unsigned char *p) { + unsigned long n; + n = p[1]; + n = (n << 8) + p[0]; + return n; +} + +/* + * Mirror the bottom n bits of x. + */ +static unsigned long mirror (unsigned long x, int n) { + unsigned long top = 1 << (n-1), bottom = 1; + while (top > bottom) { + unsigned long mask = top | bottom; + unsigned long masked = x & mask; + if (masked != 0 && masked != mask) + x ^= mask; + top >>= 1; + bottom <<= 1; + } + return x; +} + +/* + * Calculate a CRC, the RNC way. It re-computes its CRC table every + * time it's run, but who cares? ;-) + */ +static long rnc_crc (void *data, long len) { + unsigned short crctab[256]; + unsigned short val; + int i, j; + unsigned char *p = data; + + for (i=0; i<256; i++) { + val = i; + + for (j=0; j<8; j++) { + if (val & 1) + val = (val >> 1) ^ 0xA001; + else + val = (val >> 1); + } + crctab[i] = val; + } + + val = 0; + while (len--) { + val ^= *p++; + val = (val >> 8) ^ crctab[val & 0xFF]; + } + + return val; +} diff --git a/wii/libogc/libogc/dsp.c b/wii/libogc/libogc/dsp.c new file mode 100644 index 0000000000..01b16f8013 --- /dev/null +++ b/wii/libogc/libogc/dsp.c @@ -0,0 +1,459 @@ +/*------------------------------------------------------------- + +dsp.c -- DSP subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include +#include +#include "asm.h" +#include "processor.h" +#include "irq.h" +#include "dsp.h" + +// DSPCR bits +#define DSPCR_DSPRESET 0x0800 // Reset DSP +#define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set +#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) +#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) +#define DSPCR_ARINTMSK 0x0040 +#define DSPCR_ARINT 0x0020 +#define DSPCR_AIINTMSK 0x0010 +#define DSPCR_AIINT 0x0008 +#define DSPCR_HALT 0x0004 // halt DSP +#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt +#define DSPCR_RES 0x0001 // reset DSP + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +static u32 __dsp_inited = FALSE; +static u32 __dsp_rudetask_pend = FALSE; +static DSPCallback __dsp_intcb = NULL; +static dsptask_t *__dsp_currtask,*__dsp_lasttask,*__dsp_firsttask,*__dsp_rudetask,*tmp_task; + +static vu16* const _dspReg = (u16*)0xCC005000; + +static void __dsp_inserttask(dsptask_t *task) +{ + dsptask_t *t; + + if(!__dsp_firsttask) { + __dsp_currtask = task; + __dsp_lasttask = task; + __dsp_firsttask = task; + task->next = NULL; + task->prev = NULL; + return; + } + + t = __dsp_firsttask; + while(t) { + if(task->prioprio) { + task->prev = t->prev; + t->prev = task; + task->next = t; + if(!task->prev) { + __dsp_firsttask = task; + break; + } else { + task->prev->next = task; + break; + } + } + t = t->next; + } + if(t) return; + + __dsp_lasttask->next = task; + task->next = NULL; + task->prev = __dsp_lasttask; + __dsp_lasttask = task; +} + +static void __dsp_removetask(dsptask_t *task) +{ + task->flags = DSPTASK_CLEARALL; + task->state = DSPTASK_DONE; + if(__dsp_firsttask==task) { + if(task->next) { + __dsp_firsttask = task->next; + __dsp_firsttask->prev = NULL; + return; + } + __dsp_currtask = NULL; + __dsp_lasttask = NULL; + __dsp_firsttask = NULL; + return; + } + if(__dsp_lasttask==task) { + __dsp_lasttask = task->prev; + __dsp_lasttask->next = NULL; + __dsp_currtask = __dsp_firsttask; + return; + } + __dsp_currtask = __dsp_currtask->next; +} + +static void __dsp_boottask(dsptask_t *task) +{ + u32 mail; + while(!DSP_CheckMailFrom()); + mail = DSP_ReadMailFrom(); + DSP_SendMailTo(0x80F3A001); + while(DSP_CheckMailTo()); + DSP_SendMailTo((u32)task->iram_maddr); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0x80F3C002); + while(DSP_CheckMailTo()); + DSP_SendMailTo((task->iram_addr&0xffff)); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0x80F3A002); + while(DSP_CheckMailTo()); + DSP_SendMailTo(task->iram_len); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0x80F3B002); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0x80F3D001); + while(DSP_CheckMailTo()); + DSP_SendMailTo(task->init_vec); + while(DSP_CheckMailTo()); +} + +static void __dsp_exectask(dsptask_t *exec,dsptask_t *hire) +{ + if(!exec) { + DSP_SendMailTo(0); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0); + while(DSP_CheckMailTo()); + } else { + DSP_SendMailTo((u32)exec->dram_maddr); + while(DSP_CheckMailTo()); + DSP_SendMailTo(exec->dram_len); + while(DSP_CheckMailTo()); + DSP_SendMailTo(exec->dram_addr); + while(DSP_CheckMailTo()); + } + + DSP_SendMailTo((u32)hire->iram_maddr); + while(DSP_CheckMailTo()); + DSP_SendMailTo(hire->iram_len); + while(DSP_CheckMailTo()); + DSP_SendMailTo(hire->iram_addr); + while(DSP_CheckMailTo()); + if(hire->state==DSPTASK_INIT) { + DSP_SendMailTo(hire->init_vec); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0); + while(DSP_CheckMailTo()); + DSP_SendMailTo(0); + while(DSP_CheckMailTo()); + return; + } + + DSP_SendMailTo(hire->resume_vec); + while(DSP_CheckMailTo()); + + DSP_SendMailTo((u32)hire->dram_maddr); + while(DSP_CheckMailTo()); + DSP_SendMailTo(hire->dram_len); + while(DSP_CheckMailTo()); + DSP_SendMailTo(hire->dram_addr); + while(DSP_CheckMailTo()); +} + +static void __dsp_def_taskcb() +{ + u32 mail; + while(!DSP_CheckMailFrom()); + + mail = DSP_ReadMailFrom(); + if(__dsp_currtask->flags&DSPTASK_CANCEL) { + if(mail==0xDCD10002) mail = 0xDCD10003; + } + + switch(mail) { + case 0xDCD10000: + __dsp_currtask->state = DSPTASK_RUN; + if(__dsp_currtask->init_cb) __dsp_currtask->init_cb(__dsp_currtask); + break; + case 0xDCD10001: + __dsp_currtask->state = DSPTASK_RUN; + if(__dsp_currtask->res_cb) __dsp_currtask->res_cb(__dsp_currtask); + break; + case 0xDCD10002: + if(__dsp_rudetask_pend==TRUE) { + if(__dsp_rudetask==__dsp_currtask) { + DSP_SendMailTo(0xCDD10003); + while(DSP_CheckMailTo()); + + __dsp_rudetask = NULL; + __dsp_rudetask_pend = FALSE; + if(__dsp_currtask->res_cb) __dsp_currtask->res_cb(__dsp_currtask); + } else { + DSP_SendMailTo(0xCDD10001); + while(DSP_CheckMailTo()); + + __dsp_exectask(__dsp_currtask,__dsp_rudetask); + __dsp_currtask->flags = DSPTASK_YIELD; + __dsp_currtask = __dsp_rudetask; + __dsp_rudetask = NULL; + __dsp_rudetask_pend = FALSE; + } + } else if(__dsp_currtask->next==NULL) { + if(__dsp_firsttask==__dsp_currtask) { + DSP_SendMailTo(0xCDD10003); + while(DSP_CheckMailTo()); + + if(__dsp_currtask->res_cb) __dsp_currtask->res_cb(__dsp_currtask); + } else { + DSP_SendMailTo(0xCDD10001); + while(DSP_CheckMailTo()); + + __dsp_exectask(__dsp_currtask,__dsp_firsttask); + __dsp_currtask->state = DSPTASK_YIELD; + __dsp_currtask = __dsp_firsttask; + } + } else { + DSP_SendMailTo(0xCDD10001); + while(DSP_CheckMailTo()); + + __dsp_exectask(__dsp_currtask,__dsp_currtask->next); + __dsp_currtask->state = DSPTASK_YIELD; + __dsp_currtask = __dsp_currtask->next; + } + break; + case 0xDCD10003: + if(__dsp_rudetask_pend==TRUE) { + if(__dsp_currtask->done_cb) __dsp_currtask->done_cb(__dsp_currtask); + DSP_SendMailTo(0xCDD10001); + while(DSP_CheckMailTo()); + + __dsp_exectask(NULL,__dsp_rudetask); + __dsp_removetask(__dsp_currtask); + + __dsp_currtask = __dsp_rudetask; + __dsp_rudetask_pend = FALSE; + __dsp_rudetask = NULL; + } else if(__dsp_currtask->next==NULL) { + if(__dsp_firsttask==__dsp_currtask) { + if(__dsp_currtask->done_cb) __dsp_currtask->done_cb(__dsp_currtask); + DSP_SendMailTo(0xCDD10002); + while(DSP_CheckMailTo()); + + __dsp_currtask->state = DSPTASK_DONE; + __dsp_removetask(__dsp_currtask); + } + } else { + if(__dsp_currtask->done_cb) __dsp_currtask->done_cb(__dsp_currtask); + + DSP_SendMailTo(0xCDD10001); + while(DSP_CheckMailTo()); + + __dsp_currtask->state = DSPTASK_DONE; + __dsp_exectask(NULL,__dsp_firsttask); + __dsp_currtask = __dsp_firsttask; + __dsp_removetask(__dsp_lasttask); + } + break; + case 0xDCD10004: + if(__dsp_currtask->req_cb) __dsp_currtask->req_cb(__dsp_currtask); + break; + } + +} + +static void __dsp_inthandler(u32 nIrq,void *pCtx) +{ + _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT))|DSPCR_DSPINT; + if(__dsp_intcb) __dsp_intcb(); +} + +void DSP_Init() +{ + u32 level; + _CPU_ISR_Disable(level); + if(__dsp_inited==FALSE) { + __dsp_intcb= __dsp_def_taskcb; + + IRQ_Request(IRQ_DSP_DSP,__dsp_inthandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_DSP_DSP)); + + _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|DSPCR_DSPRESET; + _dspReg[5] = (_dspReg[5]&~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)); + + __dsp_currtask = NULL; + __dsp_firsttask = NULL; + __dsp_lasttask = NULL; + tmp_task = NULL; + __dsp_inited = TRUE; + } + _CPU_ISR_Restore(level); +} + +DSPCallback DSP_RegisterCallback(DSPCallback usr_cb) +{ + u32 level; + DSPCallback ret; + _CPU_ISR_Disable(level); + ret = __dsp_intcb; + if(usr_cb) + __dsp_intcb = usr_cb; + else + __dsp_intcb = __dsp_def_taskcb; + _CPU_ISR_Restore(level); + + return ret; +} + +u32 DSP_CheckMailTo() +{ + return _SHIFTR(_dspReg[0],15,1); +} + +u32 DSP_CheckMailFrom() +{ + return _SHIFTR(_dspReg[2],15,1); +} + +u32 DSP_ReadMailFrom() +{ + return (_SHIFTL(_dspReg[2],16,16)|(_dspReg[3]&0xffff)); +} + +void DSP_SendMailTo(u32 mail) +{ + _dspReg[0] = _SHIFTR(mail,16,16); + _dspReg[1] = (mail&0xffff); +} + +u32 DSP_ReadCPUtoDSP() +{ + u32 cpu_dsp; + cpu_dsp = (_SHIFTL(_dspReg[0],16,16)|(_dspReg[1]&0xffff)); + return cpu_dsp; +} + +void DSP_AssertInt() +{ + u32 level; + _CPU_ISR_Disable(level); + _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|DSPCR_PIINT; + _CPU_ISR_Restore(level); +} + +void DSP_Reset() +{ + u16 old; + u32 level; + + _CPU_ISR_Disable(level); + old = _dspReg[5]; + _dspReg[5] = (old&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|(DSPCR_DSPRESET|DSPCR_RES); + _CPU_ISR_Restore(level); +} + +void DSP_Halt() +{ + u32 level,old; + + _CPU_ISR_Disable(level); + old = _dspReg[5]; + _dspReg[5] = (old&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|DSPCR_HALT; + _CPU_ISR_Restore(level); +} + +void DSP_Unhalt() +{ + u32 level; + + _CPU_ISR_Disable(level); + _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT|DSPCR_HALT)); + _CPU_ISR_Restore(level); +} + +u32 DSP_GetDMAStatus() +{ + return _dspReg[5]&DSPCR_DSPDMA; +} + +dsptask_t* DSP_AddTask(dsptask_t *task) +{ + u32 level; + _CPU_ISR_Disable(level); + __dsp_inserttask(task); + task->state = DSPTASK_INIT; + task->flags = DSPTASK_ATTACH; + _CPU_ISR_Restore(level); + + if(__dsp_firsttask==task) __dsp_boottask(task); + return task; +} + +void DSP_CancelTask(dsptask_t *task) +{ + u32 level; + + _CPU_ISR_Disable(level); + task->flags |= DSPTASK_CANCEL; + _CPU_ISR_Restore(level); +} + +dsptask_t* DSP_AssertTask(dsptask_t *task) +{ + u32 level; + dsptask_t *ret = NULL; + + _CPU_ISR_Disable(level); + if(task==__dsp_currtask) { + __dsp_rudetask = task; + __dsp_rudetask_pend = TRUE; + ret = task; + } else { + if(task->prio<__dsp_currtask->prio) { + __dsp_rudetask = task; + __dsp_rudetask_pend = TRUE; + if(__dsp_currtask->state==DSPTASK_RUN) + _dspReg[5] = ((_dspReg[5]&~(DSPCR_DSPINT|DSPCR_ARINT|DSPCR_AIINT))|DSPCR_PIINT); + + ret = task; + } + } + _CPU_ISR_Restore(level); + + return ret; +} diff --git a/wii/libogc/libogc/dvd.c b/wii/libogc/libogc/dvd.c new file mode 100644 index 0000000000..3156954609 --- /dev/null +++ b/wii/libogc/libogc/dvd.c @@ -0,0 +1,2432 @@ +/*------------------------------------------------------------- + +dvd.h -- DVD subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +Additionally following copyrights apply for the patching system: + * Copyright (C) 2005 The GameCube Linux Team + * Copyright (C) 2005 Albert Herranz + +Thanks alot guys for that incredible patch!! + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "cache.h" +#include "lwp.h" +#include "irq.h" +#include "ogcsys.h" +#include "system.h" +#include "dvd.h" + +#define DVD_BRK (1<<0) +#define DVD_DE_MSK (1<<1) +#define DVD_DE_INT (1<<2) +#define DVD_TC_MSK (1<<3) +#define DVD_TC_INT (1<<4) +#define DVD_BRK_MSK (1<<5) +#define DVD_BRK_INT (1<<6) + +#define DVD_CVR_INT (1<<2) +#define DVD_CVR_MSK (1<<1) +#define DVD_CVR_STATE (1<<0) + +#define DVD_DI_MODE (1<<2) +#define DVD_DI_DMA (1<<1) +#define DVD_DI_START (1<<0) + +#define DVD_DISKIDSIZE 0x20 +#define DVD_DRVINFSIZE 0x20 +#define DVD_MAXCOMMANDS 0x12 + +#define DVD_DVDINQUIRY 0x12000000 +#define DVD_FWSETOFFSET 0x32000000 +#define DVD_FWENABLEEXT 0x55000000 +#define DVD_READSECTOR 0xA8000000 +#define DVD_READDISKID 0xA8000040 +#define DVD_SEEKSECTOR 0xAB000000 +#define DVD_REQUESTERROR 0xE0000000 +#define DVD_AUDIOSTREAM 0xE1000000 +#define DVD_AUDIOSTATUS 0xE2000000 +#define DVD_STOPMOTOR 0xE3000000 +#define DVD_AUDIOCONFIG 0xE4000000 +#define DVD_FWSETSTATUS 0xEE000000 +#define DVD_FWWRITEMEM 0xFE010100 +#define DVD_FWREADMEM 0xFE010000 +#define DVD_FWCTRLMOTOR 0xFE110000 +#define DVD_FWFUNCCALL 0xFE120000 + +#define DVD_MODEL04 0x20020402 +#define DVD_MODEL06 0x20010608 +#define DVD_MODEL08 0x20020823 +#define DVD_MODEL08Q 0x20010831 + +#define DVD_FWIRQVECTOR 0x00804c + +#define DVD_DRIVERESET 0x00000001 +#define DVD_CHIPPRESENT 0x00000002 +#define DVD_INTEROPER 0x00000004 + +/* drive status, status */ +#define DVD_STATUS(s) ((u8)((s)>>24)) + +#define DVD_STATUS_READY 0x00 +#define DVD_STATUS_COVER_OPENED 0x01 +#define DVD_STATUS_DISK_CHANGE 0x02 +#define DVD_STATUS_NO_DISK 0x03 +#define DVD_STATUS_MOTOR_STOP 0x04 +#define DVD_STATUS_DISK_ID_NOT_READ 0x05 + +/* drive status, error */ +#define DVD_ERROR(s) ((u32)((s)&0x00ffffff)) + +#define DVD_ERROR_NO_ERROR 0x000000 +#define DVD_ERROR_MOTOR_STOPPED 0x020400 +#define DVD_ERROR_DISK_ID_NOT_READ 0x020401 +#define DVD_ERROR_MEDIUM_NOT_PRESENT 0x023a00 +#define DVD_ERROR_SEEK_INCOMPLETE 0x030200 +#define DVD_ERROR_UNRECOVERABLE_READ 0x031100 +#define DVD_ERROR_TRANSFER_PROTOCOL 0x040800 +#define DVD_ERROR_INVALID_COMMAND 0x052000 +#define DVD_ERROR_AUDIOBUFFER_NOTSET 0x052001 +#define DVD_ERROR_BLOCK_OUT_OF_RANGE 0x052100 +#define DVD_ERROR_INVALID_FIELD 0x052400 +#define DVD_ERROR_INVALID_AUDIO_CMD 0x052401 +#define DVD_ERROR_INVALID_CONF_PERIOD 0x052402 +#define DVD_ERROR_END_OF_USER_AREA 0x056300 +#define DVD_ERROR_MEDIUM_CHANGED 0x062800 +#define DVD_ERROR_MEDIUM_CHANGE_REQ 0x0B5A01 + +#define DVD_SPINMOTOR_MASK 0x0000ff00 + +#define cpu_to_le32(x) (((x>>24)&0x000000ff) | ((x>>8)&0x0000ff00) | ((x<<8)&0x00ff0000) | ((x<<24)&0xff000000)) +#define dvd_may_retry(s) (DVD_STATUS(s) == DVD_STATUS_READY || DVD_STATUS(s) == DVD_STATUS_DISK_ID_NOT_READ) + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +typedef void (*dvdcallbacklow)(s32); +typedef void (*dvdstatecb)(dvdcmdblk *); + +typedef struct _dvdcmdl { + s32 cmd; + void *buf; + u32 len; + s64 offset; + dvdcallbacklow cb; +} dvdcmdl; + +typedef struct _dvdcmds { + void *buf; + u32 len; + s64 offset; +} dvdcmds; + +static u32 __dvd_initflag = 0; +static u32 __dvd_stopnextint = 0; +static vu32 __dvd_resetoccured = 0; +static u32 __dvd_waitcoverclose = 0; +static u32 __dvd_breaking = 0; +static vu32 __dvd_resetrequired = 0; +static u32 __dvd_canceling = 0; +static u32 __dvd_pauseflag = 0; +static u32 __dvd_pausingflag = 0; +static u64 __dvd_lastresetend = 0; +static u32 __dvd_ready = 0; +static u32 __dvd_resumefromhere = 0; +static u32 __dvd_fatalerror = 0; +static u32 __dvd_lasterror = 0; +static u32 __dvd_internalretries = 0; +static u32 __dvd_autofinishing = 0; +static u32 __dvd_autoinvalidation = 1; +static u32 __dvd_cancellasterror = 0; +static u32 __dvd_drivechecked = 0; +static u32 __dvd_drivestate = 0; +static u32 __dvd_extensionsenabled = TRUE; +static u32 __dvd_lastlen; +static u32 __dvd_nextcmdnum; +static u32 __dvd_workaround; +static u32 __dvd_workaroundseek; +static u32 __dvd_lastcmdwasread; +static u32 __dvd_currcmd; +static u32 __dvd_motorcntrl; +static lwpq_t __dvd_wait_queue; +static syswd_t __dvd_timeoutalarm; +static dvdcmdblk __dvd_block$15; +static dvdcmdblk __dvd_dummycmdblk; +static dvddiskid __dvd_tmpid0 ATTRIBUTE_ALIGN(32); +static dvddrvinfo __dvd_driveinfo ATTRIBUTE_ALIGN(32); +static dvdcallbacklow __dvd_callback = NULL; +static dvdcallbacklow __dvd_resetcovercb = NULL; +static dvdcallbacklow __dvd_finalunlockcb = NULL; +static dvdcallbacklow __dvd_finalreadmemcb = NULL; +static dvdcallbacklow __dvd_finalsudcb = NULL; +static dvdcallbacklow __dvd_finalstatuscb = NULL; +static dvdcallbacklow __dvd_finaladdoncb = NULL; +static dvdcallbacklow __dvd_finalpatchcb = NULL; +static dvdcallbacklow __dvd_finaloffsetcb = NULL; +static dvdcbcallback __dvd_cancelcallback = NULL; +static dvdcbcallback __dvd_mountusrcb = NULL; +static dvdstatecb __dvd_laststate = NULL; +static dvdcmdblk *__dvd_executing = NULL; +static void *__dvd_usrdata = NULL; +static dvddiskid *__dvd_diskID = (dvddiskid*)0x80000000; + +static lwp_queue __dvd_waitingqueue[4]; +static dvdcmdl __dvd_cmdlist[4]; +static dvdcmds __dvd_cmd_curr,__dvd_cmd_prev; + +static u32 __dvdpatchcode_size = 0; +static const u8 *__dvdpatchcode = NULL; + +static const u32 __dvd_patchcode04_size = 448; +static const u8 __dvd_patchcode04[] = +{ + 0xf7,0x10,0xff,0xf7,0xf4,0x74,0x25,0xd0,0x40,0xf7,0x20,0x4c,0x80,0xf4,0x74,0xd6, + 0x9c,0x08,0xf7,0x20,0xd6,0xfc,0xf4,0x74,0x28,0xae,0x08,0xf7,0x20,0xd2,0xfc,0x80, + 0x0c,0xc4,0xda,0xfc,0xfe,0xc8,0xda,0xfc,0xf5,0x00,0x01,0xe8,0x03,0xfc,0xc1,0x00, + 0xa0,0xf4,0x74,0x09,0xec,0x40,0x10,0xc8,0xda,0xfc,0xf5,0x00,0x02,0xe8,0x03,0xfc, + 0xbc,0x00,0xf4,0x74,0xf9,0xec,0x40,0x80,0x02,0xf0,0x20,0xc8,0x84,0x80,0xc0,0x9c, + 0x81,0xdc,0xb4,0x80,0xf5,0x30,0x00,0xf4,0x44,0xa1,0xd1,0x40,0xf8,0xaa,0x00,0x10, + 0xf4,0xd0,0x9c,0xd1,0x40,0xf0,0x01,0xdc,0xb4,0x80,0xf5,0x30,0x00,0xf7,0x48,0xaa, + 0x00,0xe9,0x07,0xf4,0xc4,0xa1,0xd1,0x40,0x10,0xfe,0xd8,0x32,0xe8,0x1d,0xf7,0x48, + 0xa8,0x00,0xe8,0x28,0xf7,0x48,0xab,0x00,0xe8,0x22,0xf7,0x48,0xe1,0x00,0xe8,0x1c, + 0xf7,0x48,0xee,0x00,0xe8,0x3d,0xd8,0x55,0xe8,0x31,0xfe,0x71,0x04,0xfd,0x22,0x00, + 0xf4,0x51,0xb0,0xd1,0x40,0xa0,0x40,0x04,0x40,0x06,0xea,0x33,0xf2,0xf9,0xf4,0xd2, + 0xb0,0xd1,0x40,0x71,0x04,0xfd,0x0a,0x00,0xf2,0x49,0xfd,0x05,0x00,0x51,0x04,0xf2, + 0x36,0xfe,0xf7,0x21,0xbc,0xff,0xf7,0x31,0xbc,0xff,0xfe,0xf5,0x30,0x01,0xfd,0x7e, + 0x00,0xea,0x0c,0xf5,0x30,0x01,0xc4,0xb0,0x81,0xf5,0x30,0x02,0xc4,0x94,0x81,0xdc, + 0xb4,0x80,0xf8,0xe0,0x00,0x10,0xa0,0xf5,0x10,0x01,0xf5,0x10,0x02,0xf5,0x10,0x03, + 0xfe,0xc8,0xda,0xfc,0xf7,0x00,0xfe,0xff,0xf7,0x31,0xd2,0xfc,0xea,0x0b,0xc8,0xda, + 0xfc,0xf7,0x00,0xfd,0xff,0xf7,0x31,0xd6,0xfc,0xc4,0xda,0xfc,0xcc,0x44,0xfc,0xf7, + 0x00,0xfe,0xff,0xc4,0x44,0xfc,0xf4,0x7d,0x28,0xae,0x08,0xe9,0x07,0xf4,0x75,0x60, + 0xd1,0x40,0xea,0x0c,0xf4,0x7d,0xd6,0x9c,0x08,0xe9,0x05,0xf4,0x75,0x94,0xd1,0x40, + 0xf2,0x7c,0xd0,0x04,0xcc,0x5b,0x80,0xd8,0x01,0xe9,0x02,0x7c,0x04,0x51,0x20,0x71, + 0x34,0xf4,0x7d,0xc1,0x85,0x08,0xe8,0x05,0xfe,0x80,0x01,0xea,0x02,0x80,0x00,0xa5, + 0xd8,0x00,0xe8,0x02,0x85,0x0c,0xc5,0xda,0xfc,0xf4,0x75,0xa0,0xd1,0x40,0x14,0xfe, + 0xf7,0x10,0xff,0xf7,0xf4,0xc9,0xa0,0xd1,0x40,0xd9,0x00,0xe8,0x22,0x21,0xf7,0x49, + 0x08,0x06,0xe9,0x05,0x85,0x02,0xf5,0x10,0x01,0xf4,0x79,0x00,0xf0,0x00,0xe9,0x05, + 0x80,0x00,0xf5,0x10,0x09,0xd9,0x06,0xe9,0x06,0x61,0x06,0xd5,0x06,0x41,0x06,0xf4, + 0xe0,0x9f,0xdc,0xc7,0xf4,0xe0,0xb5,0xcb,0xc7,0x00,0x00,0x00,0x74,0x0a,0x08,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static const u32 __dvd_patchcode06_size = 448; +static const u8 __dvd_patchcode06[] = +{ + 0xf7,0x10,0xff,0xf7,0xf4,0x74,0x25,0xd0,0x40,0xf7,0x20,0x4c,0x80,0xf4,0x74,0x42, + 0x9d,0x08,0xf7,0x20,0xd6,0xfc,0xf4,0x74,0x45,0xb1,0x08,0xf7,0x20,0xd2,0xfc,0x80, + 0x0c,0xc4,0xda,0xfc,0xfe,0xc8,0xda,0xfc,0xf5,0x00,0x01,0xe8,0x03,0xfc,0xc1,0x00, + 0xa0,0xf4,0x74,0x09,0xec,0x40,0x10,0xc8,0xda,0xfc,0xf5,0x00,0x02,0xe8,0x03,0xfc, + 0xbc,0x00,0xf4,0x74,0x02,0xed,0x40,0x80,0x02,0xf0,0x20,0xc8,0x78,0x80,0xc0,0x90, + 0x81,0xdc,0xa8,0x80,0xf5,0x30,0x00,0xf4,0x44,0xa1,0xd1,0x40,0xf8,0xaa,0x00,0x10, + 0xf4,0xd0,0x9c,0xd1,0x40,0xf0,0x01,0xdc,0xa8,0x80,0xf5,0x30,0x00,0xf7,0x48,0xaa, + 0x00,0xe9,0x07,0xf4,0xc4,0xa1,0xd1,0x40,0x10,0xfe,0xd8,0x32,0xe8,0x1d,0xf7,0x48, + 0xa8,0x00,0xe8,0x28,0xf7,0x48,0xab,0x00,0xe8,0x22,0xf7,0x48,0xe1,0x00,0xe8,0x1c, + 0xf7,0x48,0xee,0x00,0xe8,0x3d,0xd8,0x55,0xe8,0x31,0xfe,0x71,0x04,0xfd,0x22,0x00, + 0xf4,0x51,0xb0,0xd1,0x40,0xa0,0x40,0x04,0x40,0x06,0xea,0x33,0xf2,0xf9,0xf4,0xd2, + 0xb0,0xd1,0x40,0x71,0x04,0xfd,0x0a,0x00,0xf2,0x49,0xfd,0x05,0x00,0x51,0x04,0xf2, + 0x36,0xfe,0xf7,0x21,0xbc,0xff,0xf7,0x31,0xbc,0xff,0xfe,0xf5,0x30,0x01,0xfd,0x7e, + 0x00,0xea,0x0c,0xf5,0x30,0x01,0xc4,0xa4,0x81,0xf5,0x30,0x02,0xc4,0x88,0x81,0xdc, + 0xa8,0x80,0xf8,0xe0,0x00,0x10,0xa0,0xf5,0x10,0x01,0xf5,0x10,0x02,0xf5,0x10,0x03, + 0xfe,0xc8,0xda,0xfc,0xf7,0x00,0xfe,0xff,0xf7,0x31,0xd2,0xfc,0xea,0x0b,0xc8,0xda, + 0xfc,0xf7,0x00,0xfd,0xff,0xf7,0x31,0xd6,0xfc,0xc4,0xda,0xfc,0xcc,0x44,0xfc,0xf7, + 0x00,0xfe,0xff,0xc4,0x44,0xfc,0xf4,0x7d,0x45,0xb1,0x08,0xe9,0x07,0xf4,0x75,0x60, + 0xd1,0x40,0xea,0x0c,0xf4,0x7d,0x42,0x9d,0x08,0xe9,0x05,0xf4,0x75,0x94,0xd1,0x40, + 0xf2,0x7c,0xd0,0x04,0xcc,0x5b,0x80,0xd8,0x01,0xe9,0x02,0x7c,0x04,0x51,0x20,0x71, + 0x34,0xf4,0x7d,0xb9,0x85,0x08,0xe8,0x05,0xfe,0x80,0x01,0xea,0x02,0x80,0x00,0xa5, + 0xd8,0x00,0xe8,0x02,0x85,0x0c,0xc5,0xda,0xfc,0xf4,0x75,0xa0,0xd1,0x40,0x14,0xfe, + 0xf7,0x10,0xff,0xf7,0xf4,0xc9,0xa0,0xd1,0x40,0xd9,0x00,0xe8,0x22,0x21,0xf7,0x49, + 0x08,0x06,0xe9,0x05,0x85,0x02,0xf5,0x10,0x01,0xf4,0x79,0x00,0xf0,0x00,0xe9,0x05, + 0x80,0x00,0xf5,0x10,0x09,0xd9,0x06,0xe9,0x06,0x61,0x06,0xd5,0x06,0x41,0x06,0xf4, + 0xe0,0xbc,0xdf,0xc7,0xf4,0xe0,0x37,0xcc,0xc7,0x00,0x00,0x00,0x74,0x0a,0x08,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static const u32 __dvd_patchcode08_size = 448; +static const u8 __dvd_patchcode08[] = +{ + 0xf7,0x10,0xff,0xf7,0xf4,0x74,0x25,0xd0,0x40,0xf7,0x20,0x4c,0x80,0xf4,0x74,0x32, + 0x9d,0x08,0xf7,0x20,0xd6,0xfc,0xf4,0x74,0x75,0xae,0x08,0xf7,0x20,0xd2,0xfc,0x80, + 0x0c,0xc4,0xda,0xfc,0xfe,0xc8,0xda,0xfc,0xf5,0x00,0x01,0xe8,0x03,0xfc,0xc1,0x00, + 0xa0,0xf4,0x74,0x09,0xec,0x40,0x10,0xc8,0xda,0xfc,0xf5,0x00,0x02,0xe8,0x03,0xfc, + 0xbc,0x00,0xf4,0x74,0xf5,0xec,0x40,0x80,0x02,0xf0,0x20,0xc8,0x80,0x80,0xc0,0x98, + 0x81,0xdc,0xb0,0x80,0xf5,0x30,0x00,0xf4,0x44,0xa1,0xd1,0x40,0xf8,0xaa,0x00,0x10, + 0xf4,0xd0,0x9c,0xd1,0x40,0xf0,0x01,0xdc,0xb0,0x80,0xf5,0x30,0x00,0xf7,0x48,0xaa, + 0x00,0xe9,0x07,0xf4,0xc4,0xa1,0xd1,0x40,0x10,0xfe,0xd8,0x32,0xe8,0x1d,0xf7,0x48, + 0xa8,0x00,0xe8,0x28,0xf7,0x48,0xab,0x00,0xe8,0x22,0xf7,0x48,0xe1,0x00,0xe8,0x1c, + 0xf7,0x48,0xee,0x00,0xe8,0x3d,0xd8,0x55,0xe8,0x31,0xfe,0x71,0x04,0xfd,0x22,0x00, + 0xf4,0x51,0xb0,0xd1,0x40,0xa0,0x40,0x04,0x40,0x06,0xea,0x33,0xf2,0xf9,0xf4,0xd2, + 0xb0,0xd1,0x40,0x71,0x04,0xfd,0x0a,0x00,0xf2,0x49,0xfd,0x05,0x00,0x51,0x04,0xf2, + 0x36,0xfe,0xf7,0x21,0xbc,0xff,0xf7,0x31,0xbc,0xff,0xfe,0xf5,0x30,0x01,0xfd,0x7e, + 0x00,0xea,0x0c,0xf5,0x30,0x01,0xc4,0xac,0x81,0xf5,0x30,0x02,0xc4,0x90,0x81,0xdc, + 0xb0,0x80,0xf8,0xe0,0x00,0x10,0xa0,0xf5,0x10,0x01,0xf5,0x10,0x02,0xf5,0x10,0x03, + 0xfe,0xc8,0xda,0xfc,0xf7,0x00,0xfe,0xff,0xf7,0x31,0xd2,0xfc,0xea,0x0b,0xc8,0xda, + 0xfc,0xf7,0x00,0xfd,0xff,0xf7,0x31,0xd6,0xfc,0xc4,0xda,0xfc,0xcc,0x44,0xfc,0xf7, + 0x00,0xfe,0xff,0xc4,0x44,0xfc,0xf4,0x7d,0x75,0xae,0x08,0xe9,0x07,0xf4,0x75,0x60, + 0xd1,0x40,0xea,0x0c,0xf4,0x7d,0x32,0x9d,0x08,0xe9,0x05,0xf4,0x75,0x94,0xd1,0x40, + 0xf2,0x7c,0xd0,0x04,0xcc,0x5b,0x80,0xd8,0x01,0xe9,0x02,0x7c,0x04,0x51,0x20,0x71, + 0x34,0xf4,0x7d,0xc1,0x85,0x08,0xe8,0x05,0xfe,0x80,0x01,0xea,0x02,0x80,0x00,0xa5, + 0xd8,0x00,0xe8,0x02,0x85,0x0c,0xc5,0xda,0xfc,0xf4,0x75,0xa0,0xd1,0x40,0x14,0xfe, + 0xf7,0x10,0xff,0xf7,0xf4,0xc9,0xa0,0xd1,0x40,0xd9,0x00,0xe8,0x22,0x21,0xf7,0x49, + 0x08,0x06,0xe9,0x05,0x85,0x02,0xf5,0x10,0x01,0xf4,0x79,0x00,0xf0,0x00,0xe9,0x05, + 0x80,0x00,0xf5,0x10,0x09,0xd9,0x06,0xe9,0x06,0x61,0x06,0xd5,0x06,0x41,0x06,0xf4, + 0xe0,0xec,0xdc,0xc7,0xf4,0xe0,0x0e,0xcc,0xc7,0x00,0x00,0x00,0x74,0x0a,0x08,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static const u32 __dvd_patchcodeQ08_size = 448; +static const u8 __dvd_patchcodeQ08[] = +{ + 0xf7,0x10,0xff,0xf7,0xf4,0x74,0x25,0xd0,0x40,0xf7,0x20,0x4c,0x80,0xf4,0x74,0x39, + 0x9e,0x08,0xf7,0x20,0xd6,0xfc,0xf4,0x74,0x02,0xb3,0x08,0xf7,0x20,0xd2,0xfc,0x80, + 0x0c,0xc4,0xda,0xfc,0xfe,0xc8,0xda,0xfc,0xf5,0x00,0x01,0xe8,0x03,0xfc,0xc1,0x00, + 0xa0,0xf4,0x74,0x09,0xec,0x40,0x10,0xc8,0xda,0xfc,0xf5,0x00,0x02,0xe8,0x03,0xfc, + 0xbc,0x00,0xf4,0x74,0x02,0xed,0x40,0x80,0x02,0xf0,0x20,0xc8,0x78,0x80,0xc0,0x92, + 0x81,0xdc,0xaa,0x80,0xf5,0x30,0x00,0xf4,0x44,0xa1,0xd1,0x40,0xf8,0xaa,0x00,0x10, + 0xf4,0xd0,0x9c,0xd1,0x40,0xf0,0x01,0xdc,0xaa,0x80,0xf5,0x30,0x00,0xf7,0x48,0xaa, + 0x00,0xe9,0x07,0xf4,0xc4,0xa1,0xd1,0x40,0x10,0xfe,0xd8,0x32,0xe8,0x1d,0xf7,0x48, + 0xa8,0x00,0xe8,0x28,0xf7,0x48,0xab,0x00,0xe8,0x22,0xf7,0x48,0xe1,0x00,0xe8,0x1c, + 0xf7,0x48,0xee,0x00,0xe8,0x3d,0xd8,0x55,0xe8,0x31,0xfe,0x71,0x04,0xfd,0x22,0x00, + 0xf4,0x51,0xb0,0xd1,0x40,0xa0,0x40,0x04,0x40,0x06,0xea,0x33,0xf2,0xf9,0xf4,0xd2, + 0xb0,0xd1,0x40,0x71,0x04,0xfd,0x0a,0x00,0xf2,0x49,0xfd,0x05,0x00,0x51,0x04,0xf2, + 0x36,0xfe,0xf7,0x21,0xbc,0xff,0xf7,0x31,0xbc,0xff,0xfe,0xf5,0x30,0x01,0xfd,0x7e, + 0x00,0xea,0x0c,0xf5,0x30,0x01,0xc4,0xa6,0x81,0xf5,0x30,0x02,0xc4,0x8a,0x81,0xdc, + 0xaa,0x80,0xf8,0xe0,0x00,0x10,0xa0,0xf5,0x10,0x01,0xf5,0x10,0x02,0xf5,0x10,0x03, + 0xfe,0xc8,0xda,0xfc,0xf7,0x00,0xfe,0xff,0xf7,0x31,0xd2,0xfc,0xea,0x0b,0xc8,0xda, + 0xfc,0xf7,0x00,0xfd,0xff,0xf7,0x31,0xd6,0xfc,0xc4,0xda,0xfc,0xcc,0x44,0xfc,0xf7, + 0x00,0xfe,0xff,0xc4,0x44,0xfc,0xf4,0x7d,0x02,0xb3,0x08,0xe9,0x07,0xf4,0x75,0x60, + 0xd1,0x40,0xea,0x0c,0xf4,0x7d,0x39,0x9e,0x08,0xe9,0x05,0xf4,0x75,0x94,0xd1,0x40, + 0xf2,0x7c,0xd0,0x04,0xcc,0x5b,0x80,0xd8,0x01,0xe9,0x02,0x7c,0x04,0x51,0x20,0x71, + 0x34,0xf4,0x7d,0x7f,0x86,0x08,0xe8,0x05,0xfe,0x80,0x01,0xea,0x02,0x80,0x00,0xa5, + 0xd8,0x00,0xe8,0x02,0x85,0x0c,0xc5,0xda,0xfc,0xf4,0x75,0xa0,0xd1,0x40,0x14,0xfe, + 0xf7,0x10,0xff,0xf7,0xf4,0xc9,0xa0,0xd1,0x40,0xd9,0x00,0xe8,0x22,0x21,0xf7,0x49, + 0x08,0x06,0xe9,0x05,0x85,0x02,0xf5,0x10,0x01,0xf4,0x79,0x00,0xf0,0x00,0xe9,0x05, + 0x80,0x00,0xf5,0x10,0x09,0xd9,0x06,0xe9,0x06,0x61,0x06,0xd5,0x06,0x41,0x06,0xf4, + 0xe0,0x79,0xe1,0xc7,0xf4,0xe0,0xeb,0xcd,0xc7,0x00,0x00,0x00,0xa4,0x0a,0x08,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static vu32* const _piReg = (u32*)0xCC003000; + +#if defined(HW_RVL) + static vu32* const _diReg = (u32*)0xCD006000; +#elif defined(HW_DOL) + static vu32* const _diReg = (u32*)0xCC006000; +#endif + +static u8 __dvd_unlockcmd$221[12] = {0xff,0x01,'M','A','T','S','H','I','T','A',0x02,0x00}; +static u8 __dvd_unlockcmd$222[12] = {0xff,0x00,'D','V','D','-','G','A','M','E',0x03,0x00}; +static u32 __dvd_errortable[] = { + 0x00000000, 0x00023a00, 0x00062800, 0x00030200, + 0x00031100, 0x00052000, 0x00052001, 0x00052100, + 0x00052400, 0x00052401, 0x00052402, 0x000B5A01, + 0x00056300, 0x00020401, 0x00020400, 0x00040800, + 0x00100007, 0x00000000 +}; + +void __dvd_statecheckid(void); +void __dvd_stategettingerror(void); +void __dvd_statecoverclosed(void); +void __dvd_stateready(void); +void __dvd_statemotorstopped(void); +void __dvd_statetimeout(void); +void __dvd_stategotoretry(void); +void __dvd_stateerror(s32 result); +void __dvd_statecoverclosed_cmd(dvdcmdblk *block); +void __dvd_statebusy(dvdcmdblk *block); +void DVD_LowReset(u32 reset_mode); +s32 DVD_LowSeek(s64 offset,dvdcallbacklow cb); +s32 DVD_LowRead(void *buf,u32 len,s64 offset,dvdcallbacklow cb); +s32 DVD_LowReadId(dvddiskid *diskID,dvdcallbacklow cb); +s32 DVD_LowRequestError(dvdcallbacklow cb); +s32 DVD_LowStopMotor(dvdcallbacklow cb); +s32 DVD_LowInquiry(dvddrvinfo *info,dvdcallbacklow cb); +s32 DVD_LowWaitCoverClose(dvdcallbacklow cb); +s32 DVD_LowAudioStream(u32 subcmd,u32 len,s64 offset,dvdcallbacklow cb); +s32 DVD_LowAudioBufferConfig(s32 enable,u32 size,dvdcallbacklow cb); +s32 DVD_LowRequestAudioStatus(u32 subcmd,dvdcallbacklow cb); +s32 DVD_LowEnableExtensions(u8 enable,dvdcallbacklow cb); +s32 DVD_LowSpinMotor(u32 mode,dvdcallbacklow cb); +s32 DVD_LowSetStatus(u32 status,dvdcallbacklow cb); +s32 DVD_LowUnlockDrive(dvdcallbacklow cb); +s32 DVD_LowPatchDriveCode(dvdcallbacklow cb); +s32 DVD_LowSpinUpDrive(dvdcallbacklow cb); +s32 DVD_LowControlMotor(u32 mode,dvdcallbacklow cb); +s32 DVD_LowFuncCall(u32 address,dvdcallbacklow cb); +s32 DVD_LowReadmem(u32 address,void *buffer,dvdcallbacklow cb); +s32 DVD_LowSetGCMOffset(s64 offset,dvdcallbacklow cb); +s32 DVD_LowSetOffset(s64 offset,dvdcallbacklow cb); +s32 DVD_ReadAbsAsyncPrio(dvdcmdblk *block,void *buf,u32 len,s64 offset,dvdcbcallback cb,s32 prio); +s32 DVD_ReadDiskID(dvdcmdblk *block,dvddiskid *id,dvdcbcallback cb); +s32 __issuecommand(s32 prio,dvdcmdblk *block); + +extern void udelay(int us); +extern u32 diff_msec(unsigned long long start,unsigned long long end); +extern long long gettime(void); +extern void __MaskIrq(u32); +extern void __UnmaskIrq(u32); +extern syssramex* __SYS_LockSramEx(void); +extern u32 __SYS_UnlockSramEx(u32 write); + +static u8 err2num(u32 errorcode) +{ + u32 i; + + i=0; + while(i<18) { + if(errorcode==__dvd_errortable[i]) return i; + i++; + } + if(errorcode<0x00100000 || errorcode>0x00100008) return 29; + + return 17; +} + +static u8 convert(u32 errorcode) +{ + u8 err,err_num; + + if((errorcode-0x01230000)==0x4567) return 255; + else if((errorcode-0x01230000)==0x4568) return 254; + + err = _SHIFTR(errorcode,24,8); + err_num = err2num((errorcode&0x00ffffff)); + if(err>0x06) err = 0x06; + + return err_num+(err*30); +} + +static void __dvd_clearwaitingqueue() +{ + u32 i; + + for(i=0;i<4;i++) + __lwp_queue_init_empty(&__dvd_waitingqueue[i]); +} + +static s32 __dvd_checkwaitingqueue() +{ + u32 i; + u32 level; + + _CPU_ISR_Disable(level); + for(i=0;i<4;i++) { + if(!__lwp_queue_isempty(&__dvd_waitingqueue[i])) break; + } + _CPU_ISR_Restore(level); + return (i<4); +} + +static s32 __dvd_pushwaitingqueue(s32 prio,dvdcmdblk *block) +{ + u32 level; + _CPU_ISR_Disable(level); + __lwp_queue_appendI(&__dvd_waitingqueue[prio],&block->node); + _CPU_ISR_Restore(level); + return 1; +} + +static dvdcmdblk* __dvd_popwaitingqueueprio(s32 prio) +{ + u32 level; + dvdcmdblk *ret = NULL; + _CPU_ISR_Disable(level); + ret = (dvdcmdblk*)__lwp_queue_firstnodeI(&__dvd_waitingqueue[prio]); + _CPU_ISR_Restore(level); + return ret; +} + +static dvdcmdblk* __dvd_popwaitingqueue() +{ + u32 i,level; + dvdcmdblk *ret = NULL; + _CPU_ISR_Disable(level); + for(i=0;i<4;i++) { + if(!__lwp_queue_isempty(&__dvd_waitingqueue[i])) { + _CPU_ISR_Restore(level); + ret = __dvd_popwaitingqueueprio(i); + return ret; + } + } + _CPU_ISR_Restore(level); + return NULL; +} + +static void __dvd_timeouthandler(syswd_t alarm,void *cbarg) +{ + dvdcallbacklow cb; + + __MaskIrq(IRQMASK(IRQ_PI_DI)); + cb = __dvd_callback; + if(cb) cb(0x10); +} + +static void __dvd_storeerror(u32 errorcode) +{ + u8 err; + syssramex *ptr; + + err = convert(errorcode); + ptr = __SYS_LockSramEx(); + ptr->dvderr_code = err; + __SYS_UnlockSramEx(1); +} + +static u32 __dvd_categorizeerror(u32 errorcode) +{ + if((errorcode-0x20000)==0x0400) { + __dvd_lasterror = errorcode; + return 1; + } + + if(DVD_ERROR(errorcode)==DVD_ERROR_MEDIUM_CHANGED + || DVD_ERROR(errorcode)==DVD_ERROR_MEDIUM_NOT_PRESENT + || DVD_ERROR(errorcode)==DVD_ERROR_MEDIUM_CHANGE_REQ + || (DVD_ERROR(errorcode)-0x40000)==0x3100) return 0; + + __dvd_internalretries++; + if(__dvd_internalretries==2) { + if(__dvd_lasterror==DVD_ERROR(errorcode)) { + __dvd_lasterror = DVD_ERROR(errorcode); + return 1; + } + __dvd_lasterror = DVD_ERROR(errorcode); + return 2; + } + + __dvd_lasterror = DVD_ERROR(errorcode); + if(DVD_ERROR(errorcode)!=DVD_ERROR_UNRECOVERABLE_READ) { + if(__dvd_executing->cmd!=0x0005) return 3; + } + return 2; +} + +static void __SetupTimeoutAlarm(const struct timespec *tp) +{ + SYS_SetAlarm(__dvd_timeoutalarm,tp,__dvd_timeouthandler,NULL); +} + +static void __Read(void *buffer,u32 len,s64 offset,dvdcallbacklow cb) +{ + u32 val; + struct timespec tb; + __dvd_callback = cb; + __dvd_stopnextint = 0; + __dvd_lastcmdwasread = 1; + + _diReg[2] = DVD_READSECTOR; + _diReg[3] = (u32)(offset>>2); + _diReg[4] = len; + _diReg[5] = (u32)buffer; + _diReg[6] = len; + + __dvd_lastlen = len; + + _diReg[7] = (DVD_DI_DMA|DVD_DI_START); + val = _diReg[7]; + if(val>0x00a00000) { + tb.tv_sec = 20; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + } else { + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + } +} + +static void __DoRead(void *buffer,u32 len,s64 offset,dvdcallbacklow cb) +{ + __dvd_nextcmdnum = 0; + __dvd_cmdlist[0].cmd = -1; + __Read(buffer,len,offset,cb); +} + +static u32 __ProcessNextCmd() +{ + u32 cmd_num = __dvd_nextcmdnum; + if(__dvd_cmdlist[cmd_num].cmd==0x0001) { + __dvd_nextcmdnum++; + __Read(__dvd_cmdlist[cmd_num].buf,__dvd_cmdlist[cmd_num].len,__dvd_cmdlist[cmd_num].offset,__dvd_cmdlist[cmd_num].cb); + return 1; + } + + if(__dvd_cmdlist[cmd_num].cmd==0x0002) { + __dvd_nextcmdnum++; + DVD_LowSeek(__dvd_cmdlist[cmd_num].offset,__dvd_cmdlist[cmd_num].cb); + return 1; + } + return 0; +} + +static void __DVDLowWATypeSet(u32 workaround,u32 workaroundseek) +{ + u32 level; + + _CPU_ISR_Disable(level); + __dvd_workaround = workaround; + __dvd_workaroundseek = workaroundseek; + _CPU_ISR_Restore(level); +} + +static void __DVDInitWA() +{ + __dvd_nextcmdnum = 0; + __DVDLowWATypeSet(0,0); +} + +static s32 __dvd_checkcancel(u32 cancelpt) +{ + dvdcmdblk *block; + + if(__dvd_canceling) { + __dvd_resumefromhere = cancelpt; + __dvd_canceling = 0; + + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + + block->state = 10; + if(block->cb) block->cb(-3,block); + if(__dvd_cancelcallback) __dvd_cancelcallback(0,block); + + __dvd_stateready(); + return 1; + } + return 0; +} + +static void __dvd_stateretrycb(s32 result) +{ + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + + if(result&0x0002) __dvd_stateerror(0x01234567); + if(result==0x0001) { + __dvd_statebusy(__dvd_executing); + return; + } +} + +static void __dvd_unrecoverederrorretrycb(s32 result) +{ + u32 val; + + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + + __dvd_executing->state = -1; + if(result&0x0002) __dvd_stateerror(0x01234567); + else { + val = _diReg[8]; + __dvd_stateerror(val); + } +} + +static void __dvd_unrecoverederrorcb(s32 result) +{ + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + if(result&0x0001) { + __dvd_stategotoretry(); + return; + } + if(!(result==0x0002)) DVD_LowRequestError(__dvd_unrecoverederrorretrycb); +} + +static void __dvd_stateerrorcb(s32 result) +{ + dvdcmdblk *block; + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + + __dvd_fatalerror = 1; + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + if(block->cb) block->cb(-1,block); + if(__dvd_canceling) { + __dvd_canceling = 0; + if(__dvd_cancelcallback) __dvd_cancelcallback(0,block); + } + __dvd_stateready(); +} + +static void __dvd_stategettingerrorcb(s32 result) +{ + s32 ret; + u32 val,cnclpt; + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + if(result&0x0002) { + __dvd_executing->state = -1; + __dvd_stateerror(0x01234567); + return; + } + if(result==0x0001) { + val = _diReg[8]; + ret = __dvd_categorizeerror(val); + if(ret==1) { + __dvd_executing->state = -1; + __dvd_stateerror(val); + return; + } else if(ret==2 || ret==3) cnclpt = 0; + else { + if(DVD_STATUS(val)==DVD_STATUS_COVER_OPENED) cnclpt = 4; + else if(DVD_STATUS(val)==DVD_STATUS_DISK_CHANGE) cnclpt = 6; + else if(DVD_STATUS(val)==DVD_STATUS_NO_DISK) cnclpt = 3; + else cnclpt = 5; + } + if(__dvd_checkcancel(cnclpt)) return; + + if(ret==2) { + if(dvd_may_retry(val)) { + // disable the extensions iff they're enabled and we were trying to read the disc ID + if(__dvd_executing->cmd==0x05) { + __dvd_lasterror = 0; + __dvd_extensionsenabled = FALSE; + DVD_LowSpinUpDrive(__dvd_stateretrycb); + return; + } + __dvd_statebusy(__dvd_executing); + } else { + __dvd_storeerror(val); + __dvd_stategotoretry(); + } + return; + } else if(ret==3) { + if(DVD_ERROR(val)==DVD_ERROR_UNRECOVERABLE_READ) { + DVD_LowSeek(__dvd_executing->offset,__dvd_unrecoverederrorcb); + return; + } else { + __dvd_laststate(__dvd_executing); + return; + } + } else if(DVD_STATUS(val)==DVD_STATUS_COVER_OPENED) { + __dvd_executing->state = 5; + __dvd_statemotorstopped(); + return; + } else if(DVD_STATUS(val)==DVD_STATUS_DISK_CHANGE) { + __dvd_executing->state = 3; + __dvd_statecoverclosed(); + return; + } else if(DVD_STATUS(val)==DVD_STATUS_NO_DISK) { + __dvd_executing->state = 4; + __dvd_statemotorstopped(); + return; + } + __dvd_executing->state = -1; + __dvd_stateerror(0x01234567); + return; + } +} + +static void __dvd_statebusycb(s32 result) +{ + u32 val; + dvdcmdblk *block; + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + if(__dvd_currcmd==0x0003 || __dvd_currcmd==0x000f) { + if(result&0x0002) { + __dvd_executing->state = -1; + __dvd_stateerror(0x01234567); + return; + } + if(result==0x0001) { + __dvd_internalretries = 0; + if(__dvd_currcmd==0x000f) __dvd_resetrequired = 1; + if(__dvd_checkcancel(7)) return; + + __dvd_executing->state = 7; + __dvd_statemotorstopped(); + return; + } + } + if(result&0x0004) { + + } + if(__dvd_currcmd==0x0001 || __dvd_currcmd==0x0004 + || __dvd_currcmd==0x0005 || __dvd_currcmd==0x000e) { + __dvd_executing->txdsize += (__dvd_executing->currtxsize-_diReg[6]); + } + if(result&0x0008) { + __dvd_canceling = 0; + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + __dvd_executing->state = 10; + if(block->cb) block->cb(-3,block); + if(__dvd_cancelcallback) __dvd_cancelcallback(0,block); + __dvd_stateready(); + return; + } + if(result&0x0001) { + __dvd_internalretries = 0; + if(__dvd_checkcancel(0)) return; + + if(__dvd_currcmd==0x0001 || __dvd_currcmd==0x0004 + || __dvd_currcmd==0x0005 || __dvd_currcmd==0x000e) { + if(__dvd_executing->txdsize!=__dvd_executing->len) { + __dvd_statebusy(__dvd_executing); + return; + } + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + block->state = 0; + if(block->cb) block->cb(block->txdsize,block); + __dvd_stateready(); + return; + } + if(__dvd_currcmd==0x0009 || __dvd_currcmd==0x000a + || __dvd_currcmd==0x000b || __dvd_currcmd==0x000c) { + + val = _diReg[8]; + if(__dvd_currcmd==0x000a || __dvd_currcmd==0x000b) val <<= 2; + + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + block->state = 0; + if(block->cb) block->cb(val,block); + __dvd_stateready(); + return; + } + if(__dvd_currcmd==0x0006) { + if(!__dvd_executing->currtxsize) { + if(_diReg[8]&0x0001) { + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + block->state = 9; + if(block->cb) block->cb(-2,block); + __dvd_stateready(); + return; + } + __dvd_autofinishing = 0; + __dvd_executing->currtxsize = 1; + DVD_LowAudioStream(0,__dvd_executing->len,__dvd_executing->offset,__dvd_statebusycb); + return; + } + + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + block->state = 0; + if(block->cb) block->cb(0,block); + __dvd_stateready(); + return; + } + if(__dvd_currcmd==0x0010) { + if(__dvd_drivestate&DVD_CHIPPRESENT) { + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + block->state = 0; + if(block->cb) block->cb(DVD_DISKIDSIZE,block); + __dvd_stateready(); + return; + } + } + + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + block->state = 0; + if(block->cb) block->cb(0,block); + __dvd_stateready(); + return; + } + if(result==0x0002) { + if(__dvd_currcmd==0x000e) { + __dvd_executing->state = -1; + __dvd_stateerror(0x01234567); + return; + } + if((__dvd_currcmd==0x0001 || __dvd_currcmd==0x0004 + || __dvd_currcmd==0x0005 || __dvd_currcmd==0x000e) + && __dvd_executing->txdsize==__dvd_executing->len) { + if(__dvd_checkcancel(0)) return; + + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + block->state = 0; + if(block->cb) block->cb(block->txdsize,block); + __dvd_stateready(); + return; + } + } + __dvd_stategettingerror(); +} + +static void __dvd_mountsynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_inquirysynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_readsynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_streamatendsynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_seeksynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_spinupdrivesynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_motorcntrlsynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_setgcmsynccb(s32 result,dvdcmdblk *block) +{ + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_statemotorstoppedcb(s32 result) +{ + _diReg[1] = 0; + __dvd_executing->state = 3; + __dvd_statecoverclosed(); +} + +static void __dvd_statecoverclosedcb(s32 result) +{ + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + + if(!(result&0x0006)) { + __dvd_internalretries = 0; + __dvd_statecheckid(); + return; + } + + if(result==0x0002) __dvd_stategettingerror(); +} + +static void __dvd_statecheckid1cb(s32 result) +{ + __dvd_ready = 1; + if(memcmp(__dvd_diskID,&__dvd_tmpid0,DVD_DISKIDSIZE)) memcpy(__dvd_diskID,&__dvd_tmpid0,DVD_DISKIDSIZE); + LWP_ThreadBroadcast(__dvd_wait_queue); +} + +static void __dvd_stategotoretrycb(s32 result) +{ + if(result==0x0010) { + __dvd_executing->state = -1; + __dvd_statetimeout(); + return; + } + if(result&0x0002) { + __dvd_executing->state = -1; + __dvd_stateerror(0x01234567); + return; + } + if(result==0x0001) { + __dvd_internalretries = 0; + if(__dvd_currcmd==0x0004 || __dvd_currcmd==0x0005 + || __dvd_currcmd==0x000d || __dvd_currcmd==0x000f) { + __dvd_resetrequired = 1; + if(__dvd_checkcancel(2)) return; + + __dvd_executing->state = 11; + __dvd_statemotorstopped(); + } + } +} + +static void __dvd_getstatuscb(s32 result) +{ + u32 val,*pn_data; + dvdcallbacklow cb; + if(result==0x0010) { + __dvd_statetimeout(); + return; + } + if(result==0x0001) { + val = _diReg[8]; + + pn_data = __dvd_usrdata; + __dvd_usrdata = NULL; + if(pn_data) pn_data[0] = val; + + cb = __dvd_finalstatuscb; + __dvd_finalstatuscb = NULL; + if(cb) cb(result); + return; + } + __dvd_stategettingerror(); +} + +static void __dvd_readmemcb(s32 result) +{ + u32 val,*pn_data; + dvdcallbacklow cb; + if(result==0x0010) { + __dvd_statetimeout(); + return; + } + if(result==0x0001) { + val = _diReg[8]; + + pn_data = __dvd_usrdata; + __dvd_usrdata = NULL; + if(pn_data) pn_data[0] = val; + + cb = __dvd_finalreadmemcb; + __dvd_finalreadmemcb = NULL; + if(cb) cb(result); + return; + } + __dvd_stategettingerror(); +} + +static void __dvd_cntrldrivecb(s32 result) +{ + if(result==0x0010) { + __dvd_statetimeout(); + return; + } + if(result==0x0001) { + DVD_LowSpinMotor(__dvd_motorcntrl,__dvd_finalsudcb); + return; + } + __dvd_stategettingerror(); +} + +static void __dvd_setgcmoffsetcb(s32 result) +{ + s64 *pn_data,offset; + if(result==0x0010) { + __dvd_statetimeout(); + return; + } + if(result==0x0001) { + pn_data = (s64*)__dvd_usrdata; + __dvd_usrdata = NULL; + + offset = 0; + if(pn_data) offset = *pn_data; + DVD_LowSetOffset(offset,__dvd_finaloffsetcb); + return; + } + __dvd_stategettingerror(); +} + +static void __dvd_handlespinupcb(s32 result) +{ + static u32 step = 0; + if(result==0x0010) { + __dvd_statetimeout(); + return; + } + if(result==0x0001) { + if(step==0x0000) { + step++; + _diReg[1] = _diReg[1]; + DVD_LowEnableExtensions(__dvd_extensionsenabled,__dvd_handlespinupcb); + return; + } + if(step==0x0001) { + step++; + _diReg[1] = _diReg[1]; + DVD_LowSpinMotor((DVD_SPINMOTOR_ACCEPT|DVD_SPINMOTOR_UP),__dvd_handlespinupcb); + return; + } + if(step==0x0002) { + step = 0; + if(!__dvd_lasterror) { + _diReg[1] = _diReg[1]; + DVD_LowSetStatus((_SHIFTL((DVD_STATUS_DISK_ID_NOT_READ+1),16,8)|0x00000300),__dvd_finalsudcb); + return; + } + __dvd_finalsudcb(result); + return; + } + } + + step = 0; + __dvd_stategettingerror(); +} + +static void __dvd_fwpatchcb(s32 result) +{ + static u32 step = 0; + if(result==0x0010) { + __dvd_statetimeout(); + return; + } + if(result==0x0001) { + if(step==0x0000) { + step++; + _diReg[1] = _diReg[1]; + DVD_LowUnlockDrive(__dvd_fwpatchcb); + return; + } + if(step==0x0001) { + step = 0; + DVD_LowPatchDriveCode(__dvd_finalpatchcb); + return; + } + } + + step = 0; + __dvd_stategettingerror(); +} + +static void __dvd_checkaddonscb(s32 result) +{ + u32 txdsize; + dvdcallbacklow cb; + __dvd_drivechecked = 1; + txdsize = (DVD_DISKIDSIZE-_diReg[6]); + if(result&0x0001) { + // if the read was successful but was interrupted by a break we issue the read again. + if(txdsize!=DVD_DISKIDSIZE) { + _diReg[1] = _diReg[1]; + DCInvalidateRange(&__dvd_tmpid0,DVD_DISKIDSIZE); + DVD_LowReadId(&__dvd_tmpid0,__dvd_checkaddonscb); + return; + } + __dvd_drivestate |= DVD_CHIPPRESENT; + } + + cb = __dvd_finaladdoncb; + __dvd_finaladdoncb = NULL; + if(cb) cb(0x01); +} + +static void __dvd_checkaddons(dvdcallbacklow cb) +{ + __dvd_finaladdoncb = cb; + + // try to read disc ID. + _diReg[1] = _diReg[1]; + DCInvalidateRange(&__dvd_tmpid0,DVD_DISKIDSIZE); + DVD_LowReadId(&__dvd_tmpid0,__dvd_checkaddonscb); + return; +} + +static void __dvd_fwpatchmem(dvdcallbacklow cb) +{ + __dvd_finalpatchcb = cb; + + _diReg[1] = _diReg[1]; + DCInvalidateRange(&__dvd_driveinfo,DVD_DRVINFSIZE); + DVD_LowInquiry(&__dvd_driveinfo,__dvd_fwpatchcb); + return; +} + +static void __dvd_handlespinup() +{ + _diReg[1] = _diReg[1]; + DVD_LowUnlockDrive(__dvd_handlespinupcb); + return; +} + +static void __dvd_spinupdrivecb(s32 result) +{ + if(result==0x0010) { + __dvd_statetimeout(); + return; + } + if(result==0x0001) { + if(!__dvd_drivechecked) { + __dvd_checkaddons(__dvd_spinupdrivecb); + return; + } + if(!(__dvd_drivestate&DVD_CHIPPRESENT)) { + if(!(__dvd_drivestate&DVD_INTEROPER)) { + if(!(__dvd_drivestate&DVD_DRIVERESET)) { + DVD_Reset(DVD_RESETHARD); + udelay(1150*1000); + } + __dvd_fwpatchmem(__dvd_spinupdrivecb); + return; + } + __dvd_handlespinup(); + return; + } + + __dvd_finalsudcb(result); + return; + } + __dvd_stategettingerror(); +} + +static void __dvd_statecoverclosed_spinupcb(s32 result) +{ + DCInvalidateRange(&__dvd_tmpid0,DVD_DISKIDSIZE); + __dvd_laststate = __dvd_statecoverclosed_cmd; + __dvd_statecoverclosed_cmd(__dvd_executing); +} + +static void __DVDInterruptHandler(u32 nIrq,void *pCtx) +{ + s64 now; + u32 status,ir,irm,irmm,diff; + dvdcallbacklow cb; + + SYS_CancelAlarm(__dvd_timeoutalarm); + + irmm = 0; + if(__dvd_lastcmdwasread) { + __dvd_cmd_prev.buf = __dvd_cmd_curr.buf; + __dvd_cmd_prev.len = __dvd_cmd_curr.len; + __dvd_cmd_prev.offset = __dvd_cmd_curr.offset; + if(__dvd_stopnextint) irmm |= 0x0008; + } + __dvd_lastcmdwasread = 0; + __dvd_stopnextint = 0; + + status = _diReg[0]; + irm = (status&(DVD_DE_MSK|DVD_TC_MSK|DVD_BRK_MSK)); + ir = ((status&(DVD_DE_INT|DVD_TC_INT|DVD_BRK_INT))&(irm<<1)); + if(ir&DVD_BRK_INT) irmm |= 0x0008; + if(ir&DVD_TC_INT) irmm |= 0x0001; + if(ir&DVD_DE_INT) irmm |= 0x0002; + + if(irmm) __dvd_resetoccured = 0; + + _diReg[0] = (ir|irm); + + now = gettime(); + diff = diff_msec(__dvd_lastresetend,now); + if(__dvd_resetoccured && diff>200) { + status = _diReg[1]; + irm = status&DVD_CVR_MSK; + ir = (status&DVD_CVR_INT)&(irm<<1); + if(ir&0x0004) { + cb = __dvd_resetcovercb; + __dvd_resetcovercb = NULL; + if(cb) { + cb(0x0004); + } + } + _diReg[1] = _diReg[1]; + } else { + if(__dvd_waitcoverclose) { + status = _diReg[1]; + irm = status&DVD_CVR_MSK; + ir = (status&DVD_CVR_INT)&(irm<<1); + if(ir&DVD_CVR_INT) irmm |= 0x0004; + _diReg[1] = (ir|irm); + __dvd_waitcoverclose = 0; + } else + _diReg[1] = 0; + } + + if(irmm&0x0008) { + if(!__dvd_breaking) irmm &= ~0x0008; + } + + if(irmm&0x0001) { + if(__ProcessNextCmd()) return; + } else { + __dvd_cmdlist[0].cmd = -1; + __dvd_nextcmdnum = 0; + } + + cb = __dvd_callback; + __dvd_callback = NULL; + if(cb) cb(irmm); + + __dvd_breaking = 0; +} + +static void __dvd_patchdrivecb(s32 result) +{ + u32 cnt = 0; + static u32 cmd_buf[3]; + static u32 stage = 0; + static u32 nPos = 0; + static u32 drv_address = 0x0040d000; + const u32 chunk_size = 3*sizeof(u32); + + if(__dvdpatchcode==NULL || __dvdpatchcode_size<=0) return; + + while(stage!=0x0003) { + __dvd_callback = __dvd_patchdrivecb; + if(stage==0x0000) { + for(cnt=0;cnt=__dvdpatchcode_size) stage = 0x0002; + else stage = 0x0001; + + _diReg[1] = _diReg[1]; + _diReg[2] = DVD_FWWRITEMEM; + _diReg[3] = drv_address; + _diReg[4] = _SHIFTL(cnt,16,16); + _diReg[7] = (DVD_DI_DMA|DVD_DI_START); + + drv_address += cnt; + return; + } + + if(stage>=0x0001) { + if(stage>0x0001) stage = 0x0003; + else stage = 0; + + _diReg[1] = _diReg[1]; + _diReg[2] = cmd_buf[0]; + _diReg[3] = cmd_buf[1]; + _diReg[4] = cmd_buf[2]; + _diReg[7] = DVD_DI_START; + return; + } + } + __dvd_callback = NULL; + __dvdpatchcode = NULL; + __dvd_drivestate |= DVD_INTEROPER; + DVD_LowFuncCall(0x0040d000,__dvd_finalpatchcb); +} + + +static void __dvd_unlockdrivecb(s32 result) +{ + u32 i; + __dvd_callback = __dvd_finalunlockcb; + _diReg[1] = _diReg[1]; + for(i=0;i<3;i++) _diReg[2+i] = ((u32*)__dvd_unlockcmd$222)[i]; + _diReg[7] = DVD_DI_START; +} + +void __dvd_resetasync(dvdcbcallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + __dvd_clearwaitingqueue(); + if(__dvd_canceling) __dvd_cancelcallback = cb; + else { + if(__dvd_executing) __dvd_executing->cb = NULL; + DVD_CancelAllAsync(cb); + } + _CPU_ISR_Restore(level); +} + +void __dvd_statebusy(dvdcmdblk *block) +{ + u32 len; + __dvd_laststate = __dvd_statebusy; + if(block->cmd>DVD_MAXCOMMANDS) return; + + switch(block->cmd) { + case 1: //Read(Sector) + case 4: + _diReg[1] = _diReg[1]; + len = block->len-block->txdsize; + if(len<0x80000) block->currtxsize = len; + else block->currtxsize = 0x80000; + DVD_LowRead(block->buf+block->txdsize,block->currtxsize,(block->offset+block->txdsize),__dvd_statebusycb); + return; + case 2: //Seek(Sector) + _diReg[1] = _diReg[1]; + DVD_LowSeek(block->offset,__dvd_statebusycb); + return; + case 3: + case 15: + DVD_LowStopMotor(__dvd_statebusycb); + return; + case 5: //ReadDiskID + _diReg[1] = _diReg[1]; + block->currtxsize = DVD_DISKIDSIZE; + DVD_LowReadId(block->buf,__dvd_statebusycb); + return; + case 6: + _diReg[1] = _diReg[1]; + if(__dvd_autofinishing) { + __dvd_executing->currtxsize = 0; + DVD_LowRequestAudioStatus(0,__dvd_statebusycb); + } else { + __dvd_executing->currtxsize = 1; + DVD_LowAudioStream(0,__dvd_executing->len,__dvd_executing->offset,__dvd_statebusycb); + } + return; + case 7: + _diReg[1] = _diReg[1]; + DVD_LowAudioStream(0x00010000,0,0,__dvd_statebusycb); + return; + case 8: + _diReg[1] = _diReg[1]; + __dvd_autofinishing = 1; + DVD_LowAudioStream(0,0,0,__dvd_statebusycb); + return; + case 9: + _diReg[1] = _diReg[1]; + DVD_LowRequestAudioStatus(0,__dvd_statebusycb); + return; + case 10: + _diReg[1] = _diReg[1]; + DVD_LowRequestAudioStatus(0x00010000,__dvd_statebusycb); + return; + case 11: + _diReg[1] = _diReg[1]; + DVD_LowRequestAudioStatus(0x00020000,__dvd_statebusycb); + return; + case 12: + _diReg[1] = _diReg[1]; + DVD_LowRequestAudioStatus(0x00030000,__dvd_statebusycb); + return; + case 13: + _diReg[1] = _diReg[1]; + DVD_LowAudioBufferConfig(__dvd_executing->offset,__dvd_executing->len,__dvd_statebusycb); + return; + case 14: //Inquiry + _diReg[1] = _diReg[1]; + block->currtxsize = 0x20; + DVD_LowInquiry(block->buf,__dvd_statebusycb); + return; + case 16: + __dvd_lasterror = 0; + __dvd_extensionsenabled = TRUE; + DVD_LowSpinUpDrive(__dvd_statebusycb); + return; + case 17: + _diReg[1] = _diReg[1]; + DVD_LowControlMotor(block->offset,__dvd_statebusycb); + return; + case 18: + _diReg[1] = _diReg[1]; + DVD_LowSetGCMOffset(block->offset,__dvd_statebusycb); + return; + default: + return; + } +} + +void __dvd_stateready() +{ + dvdcmdblk *block; + if(!__dvd_checkwaitingqueue()) { + __dvd_executing = NULL; + return; + } + + __dvd_executing = __dvd_popwaitingqueue(); + + if(__dvd_fatalerror) { + __dvd_executing->state = -1; + block = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + if(block->cb) block->cb(-1,block); + __dvd_stateready(); + return; + } + + __dvd_currcmd = __dvd_executing->cmd; + + if(__dvd_resumefromhere) { + if(__dvd_resumefromhere<=7) { + switch(__dvd_resumefromhere) { + case 1: + __dvd_executing->state = 6; + __dvd_statemotorstopped(); + break; + case 2: + __dvd_executing->state = 11; + __dvd_statemotorstopped(); + break; + case 3: + __dvd_executing->state = 4; + __dvd_statemotorstopped(); + break; + case 4: + __dvd_executing->state = 5; + __dvd_statemotorstopped(); + break; + case 5: + __dvd_executing->state = -1; + __dvd_stateerror(__dvd_cancellasterror); + break; + case 6: + __dvd_executing->state = 3; + __dvd_statecoverclosed(); + break; + case 7: + __dvd_executing->state = 7; + __dvd_statemotorstopped(); + break; + default: + break; + + } + } + __dvd_resumefromhere = 0; + return; + } + __dvd_executing->state = 1; + __dvd_statebusy(__dvd_executing); +} + +void __dvd_statecoverclosed() +{ + dvdcmdblk *blk; + if(__dvd_currcmd==0x0004 || __dvd_currcmd==0x0005 + || __dvd_currcmd==0x000d || __dvd_currcmd==0x000f + || __dvd_currcmd==0x0010) { + __dvd_clearwaitingqueue(); + blk = __dvd_executing; + __dvd_executing = &__dvd_dummycmdblk; + if(blk->cb) blk->cb(-4,blk); + __dvd_stateready(); + } else { + __dvd_extensionsenabled = TRUE; + DVD_LowSpinUpDrive(__dvd_statecoverclosed_spinupcb); + } +} + +void __dvd_statecoverclosed_cmd(dvdcmdblk *block) +{ + DVD_LowReadId(&__dvd_tmpid0,__dvd_statecoverclosedcb); +} + +void __dvd_statemotorstopped() +{ + DVD_LowWaitCoverClose(__dvd_statemotorstoppedcb); +} + +void __dvd_stateerror(s32 result) +{ + __dvd_storeerror(result); + DVD_LowStopMotor(__dvd_stateerrorcb); +} + +void __dvd_stategettingerror() +{ + DVD_LowRequestError(__dvd_stategettingerrorcb); +} + +void __dvd_statecheckid2(dvdcmdblk *block) +{ + +} + +void __dvd_statecheckid() +{ + dvdcmdblk *blk; + if(__dvd_currcmd==0x0003) { + if(memcmp(&__dvd_dummycmdblk,&__dvd_executing,sizeof(dvdcmdblk))) { + DVD_LowStopMotor(__dvd_statecheckid1cb); + return; + } + memcpy(__dvd_diskID,&__dvd_tmpid0,DVD_DISKIDSIZE); + + __dvd_executing->state = 1; + DCInvalidateRange(&__dvd_tmpid0,DVD_DISKIDSIZE); + __dvd_laststate = __dvd_statecheckid2; + __dvd_statecheckid2(__dvd_executing); + return; + } + if(__dvd_currcmd==0x0010) { + blk = __dvd_executing; + blk->state = 0; + __dvd_executing = &__dvd_dummycmdblk; + if(blk->cb) blk->cb(0,blk); + __dvd_stateready(); + return; + } + if(__dvd_currcmd!=0x0005 && memcmp(__dvd_diskID,&__dvd_tmpid0,DVD_DISKIDSIZE)) { + blk = __dvd_executing; + blk->state = -1; + __dvd_executing = &__dvd_dummycmdblk; + if(blk->cb) blk->cb(-1,blk); //terminate current operation + if(__dvd_mountusrcb) __dvd_mountusrcb(DVD_DISKIDSIZE,blk); //if we came across here, notify user callback of successful remount + __dvd_stateready(); + return; + } + __dvd_statebusy(__dvd_executing); +} + +void __dvd_statetimeout() +{ + __dvd_storeerror(0x01234568); + DVD_Reset(DVD_RESETSOFT); + __dvd_stateerrorcb(0); +} + +void __dvd_stategotoretry() +{ + DVD_LowStopMotor(__dvd_stategotoretrycb); +} + +s32 __issuecommand(s32 prio,dvdcmdblk *block) +{ + s32 ret; + u32 level; + if(__dvd_autoinvalidation && + (block->cmd==0x0001 || block->cmd==0x00004 + || block->cmd==0x0005 || block->cmd==0x000e)) DCInvalidateRange(block->buf,block->len); + + _CPU_ISR_Disable(level); + block->state = 0x0002; + ret = __dvd_pushwaitingqueue(prio,block); + if(!__dvd_executing) __dvd_stateready(); + _CPU_ISR_Restore(level); + return ret; +} + +s32 DVD_LowUnlockDrive(dvdcallbacklow cb) +{ + u32 i; + + __dvd_callback = __dvd_unlockdrivecb; + __dvd_finalunlockcb = cb; + __dvd_stopnextint = 0; + + for(i=0;i<3;i++) _diReg[2+i] = ((u32*)__dvd_unlockcmd$221)[i]; + _diReg[7] = DVD_DI_START; + + return 1; +} + +s32 DVD_LowPatchDriveCode(dvdcallbacklow cb) +{ + __dvd_finalpatchcb = cb; + __dvd_stopnextint = 0; + + if(__dvd_driveinfo.rel_date==DVD_MODEL04) { + __dvdpatchcode = __dvd_patchcode04; + __dvdpatchcode_size = __dvd_patchcode04_size; + } else if((__dvd_driveinfo.rel_date&0x0000ff00)==0x00000500) { // for wii: since i don't know the real date i have to mask & compare. + } else if(__dvd_driveinfo.rel_date==DVD_MODEL06) { + __dvdpatchcode = __dvd_patchcode06; + __dvdpatchcode_size = __dvd_patchcode06_size; + } else if(__dvd_driveinfo.rel_date==DVD_MODEL08) { + __dvdpatchcode = __dvd_patchcode08; + __dvdpatchcode_size = __dvd_patchcode08_size; + } else if(__dvd_driveinfo.rel_date==DVD_MODEL08Q) { + __dvdpatchcode = __dvd_patchcodeQ08; + __dvdpatchcode_size = __dvd_patchcodeQ08_size; + } else if((__dvd_driveinfo.rel_date&0x0000ff00)==0x00000900) { // for wii: since i don't know the real date i have to mask & compare. + } else { + __dvdpatchcode = NULL; + __dvdpatchcode_size = 0; + } + + __dvd_patchdrivecb(0); + return 1; +} + +s32 DVD_LowSetOffset(s64 offset,dvdcallbacklow cb) +{ + __dvd_stopnextint = 0; + __dvd_callback = cb; + + _diReg[2] = DVD_FWSETOFFSET; + _diReg[3] = (u32)(offset>>2); + _diReg[4] = 0; + _diReg[7] = DVD_DI_START; + + return 1; +} + +s32 DVD_LowSetGCMOffset(s64 offset,dvdcallbacklow cb) +{ + static s64 loc_offset = 0; + loc_offset = offset; + + __dvd_finaloffsetcb = cb; + __dvd_stopnextint = 0; + __dvd_usrdata = &loc_offset; + + DVD_LowUnlockDrive(__dvd_setgcmoffsetcb); + return 1; +} + +s32 DVD_LowReadmem(u32 address,void *buffer,dvdcallbacklow cb) +{ + __dvd_finalreadmemcb = cb; + __dvd_usrdata = buffer; + __dvd_callback = __dvd_readmemcb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_FWREADMEM; + _diReg[3] = address; + _diReg[4] = 0x00010000; + _diReg[7] = DVD_DI_START; + + return 1; +} + +s32 DVD_LowFuncCall(u32 address,dvdcallbacklow cb) +{ + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_FWFUNCCALL; + _diReg[3] = address; + _diReg[4] = 0x66756E63; + _diReg[7] = DVD_DI_START; + + return 1; +} + +s32 DVD_LowSpinMotor(u32 mode,dvdcallbacklow cb) +{ + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_FWCTRLMOTOR|(mode&0x0000ff00); + _diReg[3] = 0; + _diReg[4] = 0; + _diReg[7] = DVD_DI_START; + + return 1; +} + +s32 DVD_LowEnableExtensions(u8 enable,dvdcallbacklow cb) +{ + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = (DVD_FWENABLEEXT|_SHIFTL(enable,16,8)); + _diReg[3] = 0; + _diReg[4] = 0; + _diReg[7] = DVD_DI_START; + + return 1; +} + +s32 DVD_LowSetStatus(u32 status,dvdcallbacklow cb) +{ + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = (DVD_FWSETSTATUS|(status&0x00ffffff)); + _diReg[3] = 0; + _diReg[4] = 0; + _diReg[7] = DVD_DI_START; + + return 1; +} + +s32 DVD_LowGetStatus(u32 *status,dvdcallbacklow cb) +{ + __dvd_finalstatuscb = cb; + __dvd_usrdata = status; + + DVD_LowRequestError(__dvd_getstatuscb); + return 1; +} + +s32 DVD_LowControlMotor(u32 mode,dvdcallbacklow cb) +{ + __dvd_stopnextint = 0; + __dvd_motorcntrl = mode; + __dvd_finalsudcb = cb; + DVD_LowUnlockDrive(__dvd_cntrldrivecb); + + return 1; + +} + +s32 DVD_LowSpinUpDrive(dvdcallbacklow cb) +{ + __dvd_finalsudcb = cb; + __dvd_spinupdrivecb(1); + + return 1; +} + +s32 DVD_LowRead(void *buf,u32 len,s64 offset,dvdcallbacklow cb) +{ + _diReg[6] = len; + + __dvd_cmd_curr.buf = buf; + __dvd_cmd_curr.len = len; + __dvd_cmd_curr.offset = offset; + __DoRead(buf,len,offset,cb); + return 1; +} + +s32 DVD_LowSeek(s64 offset,dvdcallbacklow cb) +{ + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_SEEKSECTOR; + _diReg[3] = (u32)(offset>>2); + _diReg[7] = DVD_DI_START; + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +s32 DVD_LowReadId(dvddiskid *diskID,dvdcallbacklow cb) +{ + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_READDISKID; + _diReg[3] = 0; + _diReg[4] = DVD_DISKIDSIZE; + _diReg[5] = (u32)diskID; + _diReg[6] = DVD_DISKIDSIZE; + _diReg[7] = (DVD_DI_DMA|DVD_DI_START); + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +s32 DVD_LowRequestError(dvdcallbacklow cb) +{ + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_REQUESTERROR; + _diReg[7] = DVD_DI_START; + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +s32 DVD_LowStopMotor(dvdcallbacklow cb) +{ + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_STOPMOTOR; + _diReg[7] = DVD_DI_START; + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +s32 DVD_LowInquiry(dvddrvinfo *info,dvdcallbacklow cb) +{ + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_DVDINQUIRY; + _diReg[4] = 0x20; + _diReg[5] = (u32)info; + _diReg[6] = 0x20; + _diReg[7] = (DVD_DI_DMA|DVD_DI_START); + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +s32 DVD_LowWaitCoverClose(dvdcallbacklow cb) +{ + __dvd_callback = cb; + __dvd_waitcoverclose = 1; + __dvd_stopnextint = 0; + _diReg[1] = DVD_CVR_MSK; + return 1; +} + +void DVD_LowReset(u32 reset_mode) +{ + u32 val; + + _diReg[1] = DVD_CVR_MSK; + val = _piReg[9]; + _piReg[9] = ((val&~0x0004)|0x0001); + + udelay(12); + + if(reset_mode==DVD_RESETHARD) val |= 0x0004; + val |= 0x0001; + _piReg[9] = val; + + __dvd_resetoccured = 1; + __dvd_lastresetend = gettime(); + __dvd_drivestate |= DVD_DRIVERESET; +} + +s32 DVD_LowAudioStream(u32 subcmd,u32 len,s64 offset,dvdcallbacklow cb) +{ + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_AUDIOSTREAM|subcmd; + _diReg[3] = (u32)(offset>>2); + _diReg[4] = len; + _diReg[7] = DVD_DI_START; + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +s32 DVD_LowAudioBufferConfig(s32 enable,u32 size,dvdcallbacklow cb) +{ + u32 val; + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + val = 0; + if(enable) { + val |= 0x00010000; + if(!size) val |= 0x0000000a; + } + + _diReg[2] = DVD_AUDIOCONFIG|val; + _diReg[7] = DVD_DI_START; + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +s32 DVD_LowRequestAudioStatus(u32 subcmd,dvdcallbacklow cb) +{ + struct timespec tb; + + __dvd_callback = cb; + __dvd_stopnextint = 0; + + _diReg[2] = DVD_AUDIOSTATUS|subcmd; + _diReg[7] = DVD_DI_START; + + tb.tv_sec = 10; + tb.tv_nsec = 0; + __SetupTimeoutAlarm(&tb); + + return 1; +} + +//special, only used in bios replacement. therefor only there extern'd +s32 __DVDAudioBufferConfig(dvdcmdblk *block,u32 enable,u32 size,dvdcbcallback cb) +{ + if(!block) return 0; + + block->cmd = 0x000d; + block->offset = enable; + block->len = size; + block->cb = cb; + + return __issuecommand(2,block); +} + +s32 DVD_ReadDiskID(dvdcmdblk *block,dvddiskid *id,dvdcbcallback cb) +{ + if(!block || !id) return 0; + + block->cmd = 0x0005; + block->buf = id; + block->len = DVD_DISKIDSIZE; + block->offset = 0; + block->txdsize = 0; + block->cb = cb; + + return __issuecommand(2,block); +} + +s32 DVD_ReadAbsAsyncPrio(dvdcmdblk *block,void *buf,u32 len,s64 offset,dvdcbcallback cb,s32 prio) +{ + block->cmd = 0x0001; + block->buf = buf; + block->len = len; + block->offset = offset; + block->txdsize = 0; + block->cb = cb; + + return __issuecommand(prio,block); +} + +s32 DVD_ReadAbsAsyncForBS(dvdcmdblk *block,void *buf,u32 len,s64 offset,dvdcbcallback cb) +{ + block->cmd = 0x0004; + block->buf = buf; + block->len = len; + block->offset = offset; + block->txdsize = 0; + block->cb = cb; + + return __issuecommand(2,block); +} + +s32 DVD_SeekAbsAsyncPrio(dvdcmdblk *block,s64 offset,dvdcbcallback cb,s32 prio) +{ + block->cmd = 0x0002; + block->offset = offset; + block->cb = cb; + + return __issuecommand(prio,block); +} + +s32 DVD_InquiryAsync(dvdcmdblk *block,dvddrvinfo *info,dvdcbcallback cb) +{ + block->cmd = 0x000e; + block->buf = info; + block->len = 0x20; + block->txdsize = 0; + block->cb = cb; + return __issuecommand(2,block); +} + +s32 DVD_Inquiry(dvdcmdblk *block,dvddrvinfo *info) +{ + u32 level; + s32 state,ret; + ret = DVD_InquiryAsync(block,info,__dvd_inquirysynccb); + if(!ret) return -1; + + _CPU_ISR_Disable(level); + do { + state = block->state; + if(state==0) ret = block->txdsize; + else if(state==-1) ret = -1; + else if(state==10) ret = -3; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + _CPU_ISR_Restore(level); + return ret; +} + +s32 DVD_ReadPrio(dvdcmdblk *block,void *buf,u32 len,s64 offset,s32 prio) +{ + u32 level; + s32 state,ret; + if(offset>=0 && offset<8511160320LL) { + ret = DVD_ReadAbsAsyncPrio(block,buf,len,offset,__dvd_readsynccb,prio); + if(!ret) return -1; + + _CPU_ISR_Disable(level); + do { + state = block->state; + if(state==0) ret = block->txdsize; + else if(state==-1) ret = -1; + else if(state==10) ret = -3; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + _CPU_ISR_Restore(level); + return ret; + } + return -1; +} + +s32 DVD_SeekPrio(dvdcmdblk *block,s64 offset,s32 prio) +{ + u32 level; + s32 state,ret; + if(offset>0 && offset<8511160320LL) { + ret = DVD_SeekAbsAsyncPrio(block,offset,__dvd_seeksynccb,prio); + if(!ret) return -1; + + _CPU_ISR_Disable(level); + do { + state = block->state; + if(state==0) ret = 0; + else if(state==-1) ret = -1; + else if(state==10) ret = -3; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + _CPU_ISR_Restore(level); + + return ret; + } + return -1; +} + +s32 DVD_CancelAllAsync(dvdcbcallback cb) +{ + u32 level; + _CPU_ISR_Disable(level); + DVD_Pause(); + _CPU_ISR_Restore(level); + return 1; +} + +s32 DVD_StopStreamAtEndAsync(dvdcmdblk *block,dvdcbcallback cb) +{ + block->cmd = 0x08; + block->cb = cb; + return __issuecommand(1,block); +} + +s32 DVD_StopStreamAtEnd(dvdcmdblk *block) +{ + s32 ret,state; + u32 level; + ret = DVD_StopStreamAtEndAsync(block,__dvd_streamatendsynccb); + if(!ret) return -1; + + _CPU_ISR_Disable(level); + do { + state = block->state; + if(state==0 || state==-1) ret = -1; + else if(state==10) ret = block->txdsize; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + _CPU_ISR_Restore(level); + + return ret; +} + +s32 DVD_SpinUpDriveAsync(dvdcmdblk *block,dvdcbcallback cb) +{ + DVD_Reset(DVD_RESETNONE); + + block->cmd = 0x10; + block->cb = cb; + return __issuecommand(1,block); +} + +s32 DVD_SpinUpDrive(dvdcmdblk *block) +{ + s32 ret,state; + u32 level; + ret = DVD_SpinUpDriveAsync(block,__dvd_spinupdrivesynccb); + if(!ret) return -1; + + _CPU_ISR_Disable(level); + do { + state = block->state; + if(state==0 || state==-1) ret = -1; + else if(state==10) ret = block->txdsize; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + _CPU_ISR_Restore(level); + + return ret; +} + +s32 DVD_ControlDriveAsync(dvdcmdblk *block,u32 cmd,dvdcbcallback cb) +{ + block->cmd = 0x11; + block->cb = cb; + block->offset = cmd; + return __issuecommand(1,block); +} + +s32 DVD_ControlDrive(dvdcmdblk *block,u32 cmd) +{ + s32 ret,state; + u32 level; + ret = DVD_ControlDriveAsync(block,cmd,__dvd_motorcntrlsynccb); + + _CPU_ISR_Disable(level); + do { + state = block->state; + if(state==0 || state==-1) ret = -1; + else if(state==10) ret = block->txdsize; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + _CPU_ISR_Restore(level); + + return ret; +} + +s32 DVD_SetGCMOffsetAsync(dvdcmdblk *block,s64 offset,dvdcbcallback cb) +{ + block->cmd = 0x12; + block->cb = cb; + block->offset = offset; + return __issuecommand(1,block); +} + +s32 DVD_SetGCMOffset(dvdcmdblk *block,s64 offset) +{ + s32 ret,state; + u32 level; + ret = DVD_SetGCMOffsetAsync(block,offset,__dvd_setgcmsynccb); + + _CPU_ISR_Disable(level); + do { + state = block->state; + if(state==0 || state==-1) ret = -1; + else if(state==10) ret = block->txdsize; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + _CPU_ISR_Restore(level); + + return ret; +} + +s32 DVD_GetCmdBlockStatus(dvdcmdblk *block) +{ + u32 level; + s32 ret = -1; + + _CPU_ISR_Disable(level); + if(block) { + if((ret=block->state)==0x0003) ret = 1; + } + _CPU_ISR_Restore(level); + return ret; +} + +s32 DVD_GetDriveStatus() +{ + s32 ret; + u32 level; + + _CPU_ISR_Disable(level); + if(__dvd_fatalerror) ret = -1; + else { + if(__dvd_pausingflag) ret = 8; + else { + if(!__dvd_executing || __dvd_executing==&__dvd_dummycmdblk) ret = 0; + else ret = DVD_GetCmdBlockStatus(__dvd_executing); + } + } + _CPU_ISR_Restore(level); + return ret; +} + +void DVD_Pause() +{ + u32 level; + + _CPU_ISR_Disable(level); + __dvd_pauseflag = 1; + if(__dvd_executing==NULL) __dvd_pausingflag = 1; + _CPU_ISR_Restore(level); +} + +void DVD_Reset(u32 reset_mode) +{ + __dvd_drivestate &= ~(DVD_INTEROPER|DVD_CHIPPRESENT|DVD_DRIVERESET); + + if(reset_mode!=DVD_RESETNONE) + DVD_LowReset(reset_mode); + + _diReg[0] = (DVD_DE_MSK|DVD_TC_MSK|DVD_BRK_MSK); + _diReg[1] = _diReg[1]; + + __dvd_resetrequired = 0; + __dvd_internalretries = 0; +} + +void callback(s32 result,dvdcmdblk *block) +{ + if(result==0x00) { + DVD_ReadDiskID(block,&__dvd_tmpid0,callback); + return; + } + else if(result>=DVD_DISKIDSIZE) { + memcpy(__dvd_diskID,&__dvd_tmpid0,DVD_DISKIDSIZE); + } else if(result==-4) { + DVD_SpinUpDriveAsync(block,callback); + return; + } + if(__dvd_mountusrcb) __dvd_mountusrcb(result,block); +} + +s32 DVD_MountAsync(dvdcmdblk *block,dvdcbcallback cb) +{ + __dvd_mountusrcb = cb; + DVD_Reset(DVD_RESETHARD); + udelay(1150*1000); + return DVD_SpinUpDriveAsync(block,callback); +} + +s32 DVD_Mount() +{ + s32 ret = 0; + s32 state; + u32 level; + + ret = DVD_MountAsync(&__dvd_block$15,__dvd_mountsynccb); + if(!ret) return -1; + + _CPU_ISR_Disable(level); + do { + state = __dvd_block$15.state; + if(state==0) ret = 0; + else if(state==-1) ret = -1; + else if(state==10) ret = -3; + else LWP_ThreadSleep(__dvd_wait_queue); + } while(state!=0 && state!=-1 && state!=10); + __dvd_mountusrcb = NULL; //set to zero coz this is only used to sync for this function. + _CPU_ISR_Restore(level); + + return ret; +} + +dvddiskid* DVD_GetCurrentDiskID() +{ + return __dvd_diskID; +} + +dvddrvinfo* DVD_GetDriveInfo() +{ + return &__dvd_driveinfo; +} + +void DVD_Init() +{ + if(!__dvd_initflag) { + __dvd_initflag = 1; + __dvd_clearwaitingqueue(); + __DVDInitWA(); + + IRQ_Request(IRQ_PI_DI,__DVDInterruptHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_PI_DI)); + + SYS_CreateAlarm(&__dvd_timeoutalarm); + LWP_InitQueue(&__dvd_wait_queue); + } +} + +u32 DVD_SetAutoInvalidation(u32 auto_inv) +{ + u32 ret = __dvd_autoinvalidation; + __dvd_autoinvalidation= auto_inv; + return ret; +} + +static bool dvdio_Startup() +{ + DVD_Init(); + + if (mfpvr() == 0x00083214) // GameCube + { + DVD_Mount(); + } + else + { + DVD_Reset(DVD_RESETHARD); + DVD_ReadDiskID(&__dvd_block$15, &__dvd_tmpid0, callback); + } + return true; +} + +static bool dvdio_IsInserted() +{ + u32 status = 0; + DVD_LowGetStatus(&status, NULL); + + if(DVD_STATUS(status) == DVD_STATUS_READY) + return true; + + return false; +} + +static bool dvdio_ReadSectors(sec_t sector,sec_t numSectors,void *buffer) +{ + dvdcmdblk blk; + + if(DVD_ReadPrio(&blk, buffer, numSectors<<11, sector << 11, 2) <= 0) + return false; + + return true; +} + +static bool dvdio_WriteSectors(sec_t sector,sec_t numSectors,const void *buffer) +{ + return true; +} + +static bool dvdio_ClearStatus() +{ + return true; +} + +static bool dvdio_Shutdown() +{ + return true; +} + +const DISC_INTERFACE __io_gcdvd = { + DEVICE_TYPE_GAMECUBE_DVD, + FEATURE_MEDIUM_CANREAD | FEATURE_GAMECUBE_DVD, + (FN_MEDIUM_STARTUP)&dvdio_Startup, + (FN_MEDIUM_ISINSERTED)&dvdio_IsInserted, + (FN_MEDIUM_READSECTORS)&dvdio_ReadSectors, + (FN_MEDIUM_WRITESECTORS)&dvdio_WriteSectors, + (FN_MEDIUM_CLEARSTATUS)&dvdio_ClearStatus, + (FN_MEDIUM_SHUTDOWN)&dvdio_Shutdown +}; diff --git a/wii/libogc/libogc/es.c b/wii/libogc/libogc/es.c new file mode 100644 index 0000000000..2a9f1330ee --- /dev/null +++ b/wii/libogc/libogc/es.c @@ -0,0 +1,1091 @@ +/*------------------------------------------------------------- + +es.c -- ETicket services + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) +Andre Heider (dhewg) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include +#include +#include +#include +#include +#include +#include "ipc.h" +#include "asm.h" +#include "processor.h" +#include "mutex.h" +#include "es.h" + +#define IOCTL_ES_ADDTICKET 0x01 +#define IOCTL_ES_ADDTITLESTART 0x02 +#define IOCTL_ES_ADDCONTENTSTART 0x03 +#define IOCTL_ES_ADDCONTENTDATA 0x04 +#define IOCTL_ES_ADDCONTENTFINISH 0x05 +#define IOCTL_ES_ADDTITLEFINISH 0x06 +#define IOCTL_ES_GETDEVICEID 0x07 +#define IOCTL_ES_LAUNCH 0x08 +#define IOCTL_ES_OPENCONTENT 0x09 +#define IOCTL_ES_READCONTENT 0x0A +#define IOCTL_ES_CLOSECONTENT 0x0B +#define IOCTL_ES_GETOWNEDTITLECNT 0x0C +#define IOCTL_ES_GETOWNEDTITLES 0x0D +#define IOCTL_ES_GETTITLECNT 0x0E +#define IOCTL_ES_GETTITLES 0x0F +#define IOCTL_ES_GETTITLECONTENTSCNT 0x10 +#define IOCTL_ES_GETTITLECONTENTS 0x11 +#define IOCTL_ES_GETVIEWCNT 0x12 +#define IOCTL_ES_GETVIEWS 0x13 +#define IOCTL_ES_GETTMDVIEWCNT 0x14 +#define IOCTL_ES_GETTMDVIEWS 0x15 +//#define IOCTL_ES_GETCONSUMPTION 0x16 +#define IOCTL_ES_DELETETITLE 0x17 +#define IOCTL_ES_DELETETICKET 0x18 +//#define IOCTL_ES_DIGETTMDVIEWSIZE 0x19 +//#define IOCTL_ES_DIGETTMDVIEW 0x1A +//#define IOCTL_ES_DIGETTICKETVIEW 0x1B +#define IOCTL_ES_DIVERIFY 0x1C +#define IOCTL_ES_GETTITLEDIR 0x1D +#define IOCTL_ES_GETDEVICECERT 0x1E +#define IOCTL_ES_IMPORTBOOT 0x1F +#define IOCTL_ES_GETTITLEID 0x20 +#define IOCTL_ES_SETUID 0x21 +#define IOCTL_ES_DELETETITLECONTENT 0x22 +#define IOCTL_ES_SEEKCONTENT 0x23 +#define IOCTL_ES_OPENTITLECONTENT 0x24 +//#define IOCTL_ES_LAUNCHBC 0x25 +//#define IOCTL_ES_EXPORTTITLEINIT 0x26 +//#define IOCTL_ES_EXPORTCONTENTBEGIN 0x27 +//#define IOCTL_ES_EXPORTCONTENTDATA 0x28 +//#define IOCTL_ES_EXPORTCONTENTEND 0x29 +//#define IOCTL_ES_EXPORTTITLEDONE 0x2A +#define IOCTL_ES_ADDTMD 0x2B +#define IOCTL_ES_ENCRYPT 0x2C +#define IOCTL_ES_DECRYPT 0x2D +#define IOCTL_ES_GETBOOT2VERSION 0x2E +#define IOCTL_ES_ADDTITLECANCEL 0x2F +#define IOCTL_ES_SIGN 0x30 +//#define IOCTL_ES_VERIFYSIGN 0x31 +#define IOCTL_ES_GETSTOREDCONTENTCNT 0x32 +#define IOCTL_ES_GETSTOREDCONTENTS 0x33 +#define IOCTL_ES_GETSTOREDTMDSIZE 0x34 +#define IOCTL_ES_GETSTOREDTMD 0x35 +#define IOCTL_ES_GETSHAREDCONTENTCNT 0x36 +#define IOCTL_ES_GETSHAREDCONTENTS 0x37 + + +#define ES_HEAP_SIZE 0x800 + +#define ISALIGNED(x) ((((u32)x)&0x1F)==0) + +static char __es_fs[] ATTRIBUTE_ALIGN(32) = "/dev/es"; + +static s32 __es_fd = -1; +static s32 __es_hid = -1; + +static void __ES_InitFS(void); +static void __ES_DeinitFS(void); + +s32 __ES_Init(void) +{ + s32 ret = 0; + + if(__es_hid < 0 ) { + __es_hid = iosCreateHeap(ES_HEAP_SIZE); + if(__es_hid < 0) + return __es_hid; + } + + if (__es_fd < 0) { + ret = IOS_Open(__es_fs,0); + if(ret<0) + return ret; + __es_fd = ret; + } + + + __ES_InitFS(); + + return 0; +} + +s32 __ES_Close(void) +{ + s32 ret; + + if(__es_fd < 0) return 0; + + __ES_DeinitFS(); + + ret = IOS_Close(__es_fd); + + __es_fd = -1; + + if(ret<0) + return ret; + + return 0; +} + +// Used by ios.c after reloading IOS +s32 __ES_Reset(void) +{ + __es_fd = -1; + return 0; +} + +s32 ES_GetTitleID(u64 *titleID) +{ + s32 ret; + u64 title; + + if(__es_fd<0) return ES_ENOTINIT; + if(!titleID) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLEID,":q",&title); + if(ret<0) return ret; + + *titleID = title; + return ret; +} + +s32 ES_SetUID(u64 uid) +{ + if(__es_fd<0) return ES_ENOTINIT; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_SETUID,"q:",uid); +} + +s32 ES_GetDataDir(u64 titleID,char *filepath) +{ + s32 ret; + + if(__es_fd<0) return ES_ENOTINIT; + if(!filepath) return ES_EINVAL; + if(!ISALIGNED(filepath)) return ES_EALIGN; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLEDIR,"q:d",titleID,filepath,30); + + return ret; +} + +s32 ES_LaunchTitle(u64 titleID, const tikview *view) +{ + + s32 res; + STACK_ALIGN(u64,title,1,32); + STACK_ALIGN(ioctlv,vectors,2,32); + + if(__es_fd<0) return ES_ENOTINIT; + if(!view) return ES_EINVAL; + if(!ISALIGNED(view)) return ES_EALIGN; + + *title = titleID; + vectors[0].data = (void*)title; + vectors[0].len = sizeof(u64); + vectors[1].data = (void*)view; + vectors[1].len = sizeof(tikview); + res = IOS_IoctlvReboot(__es_fd,IOCTL_ES_LAUNCH,2,0,vectors); + + return res; +} + +s32 ES_LaunchTitleBackground(u64 titleID, const tikview *view) +{ + + s32 res; + STACK_ALIGN(u64,title,1,32); + STACK_ALIGN(ioctlv,vectors,2,32); + + if(__es_fd<0) return ES_ENOTINIT; + if(!view) return ES_EINVAL; + if(!ISALIGNED(view)) return ES_EALIGN; + + *title = titleID; + vectors[0].data = (void*)title; + vectors[0].len = sizeof(u64); + vectors[1].data = (void*)view; + vectors[1].len = sizeof(tikview); + res = IOS_IoctlvRebootBackground(__es_fd,IOCTL_ES_LAUNCH,2,0,vectors); + + return res; +} + +s32 ES_GetNumTicketViews(u64 titleID, u32 *cnt) +{ + s32 ret; + u32 cntviews; + + if(__es_fd<0) return ES_ENOTINIT; + if(!cnt) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETVIEWCNT,"q:i",titleID,&cntviews); + + if(ret<0) return ret; + *cnt = cntviews; + return ret; +} + +s32 ES_GetTicketViews(u64 titleID, tikview *views, u32 cnt) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cnt <= 0) return ES_EINVAL; + if(!views) return ES_EINVAL; + if(!ISALIGNED(views)) return ES_EALIGN; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETVIEWS,"qi:d",titleID,cnt,views,sizeof(tikview)*cnt); +} + +s32 ES_GetNumOwnedTitles(u32 *cnt) +{ + s32 ret; + u32 cnttitles; + + if(__es_fd<0) return ES_ENOTINIT; + if(cnt == NULL) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETOWNEDTITLECNT,":i",&cnttitles); + + if(ret<0) return ret; + *cnt = cnttitles; + return ret; +} + +s32 ES_GetOwnedTitles(u64 *titles, u32 cnt) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cnt <= 0) return ES_EINVAL; + if(!titles) return ES_EINVAL; + if(!ISALIGNED(titles)) return ES_EALIGN; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETOWNEDTITLES,"i:d",cnt,titles,sizeof(u64)*cnt); +} + +s32 ES_GetNumTitles(u32 *cnt) +{ + s32 ret; + u32 cnttitles; + + if(__es_fd<0) return ES_ENOTINIT; + if(cnt == NULL) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLECNT,":i",&cnttitles); + + if(ret<0) return ret; + *cnt = cnttitles; + return ret; +} + +s32 ES_GetTitles(u64 *titles, u32 cnt) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cnt <= 0) return ES_EINVAL; + if(!titles) return ES_EINVAL; + if(!ISALIGNED(titles)) return ES_EALIGN; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLES,"i:d",cnt,titles,sizeof(u64)*cnt); +} + +s32 ES_GetNumStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *cnt) +{ + s32 ret; + u32 cntct; + + if(__es_fd<0) return ES_ENOTINIT; + if(!cnt) return ES_EINVAL; + if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL; + if(!ISALIGNED(stmd)) return ES_EALIGN; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDCONTENTCNT,"d:i",stmd,tmd_size,&cntct); + + if(ret<0) return ret; + *cnt = cntct; + return ret; +} + +s32 ES_GetStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *contents, u32 cnt) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cnt <= 0) return ES_EINVAL; + if(!contents) return ES_EINVAL; + if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL; + if(!ISALIGNED(stmd)) return ES_EALIGN; + if(!ISALIGNED(contents)) return ES_EALIGN; + if(tmd_size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDCONTENTS,"di:d",stmd,tmd_size,cnt,contents,sizeof(u32)*cnt); +} + +s32 ES_GetTitleContentsCount(u64 titleID, u32 *num) +{ + s32 ret; + u32 _num; + + if(__es_fd<0) return ES_ENOTINIT; + if(!num) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLECONTENTSCNT,"q:i",titleID,&_num); + + if(ret<0) return ret; + *num = _num; + return ret; +} + +s32 ES_GetTitleContents(u64 titleID, u8 *data, u32 size) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(size <= 0) return ES_EINVAL; + if(!data) return ES_EINVAL; + if(!ISALIGNED(data)) return ES_EALIGN; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMD,"qi:d",titleID,size,data,size); +} + +s32 ES_GetTMDViewSize(u64 titleID, u32 *size) +{ + s32 ret; + u32 tmdsize; + + if(__es_fd<0) return ES_ENOTINIT; + if(!size) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWCNT,"q:i",titleID,&tmdsize); + + if(ret<0) return ret; + *size = tmdsize; + return ret; +} + +s32 ES_GetTMDView(u64 titleID, u8 *data, u32 size) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(size <= 0) return ES_EINVAL; + if(!data) return ES_EINVAL; + if(!ISALIGNED(data)) return ES_EALIGN; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWS,"qi:d",titleID,size,data,size); +} + +s32 ES_GetStoredTMDSize(u64 titleID, u32 *size) +{ + s32 ret; + u32 tmdsize; + + if(__es_fd<0) return ES_ENOTINIT; + if(!size) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMDSIZE,"q:i",titleID,&tmdsize); + + if(ret<0) return ret; + *size = tmdsize; + return ret; +} + +s32 ES_GetStoredTMD(u64 titleID, signed_blob *stmd, u32 size) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(size <= 0) return ES_EINVAL; + if(!stmd) return ES_EINVAL; + if(!ISALIGNED(stmd)) return ES_EALIGN; + if(size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMD,"qi:d",titleID,size,stmd,size); +} + +s32 ES_GetNumSharedContents(u32 *cnt) +{ + s32 ret; + u32 cntct; + + if(__es_fd<0) return ES_ENOTINIT; + if(!cnt) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSHAREDCONTENTCNT,":i",&cntct); + + if(ret<0) return ret; + *cnt = cntct; + return ret; +} + +s32 ES_GetSharedContents(sha1 *contents, u32 cnt) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cnt <= 0) return ES_EINVAL; + if(!contents) return ES_EINVAL; + if(!ISALIGNED(contents)) return ES_EALIGN; + + return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSHAREDCONTENTS,"i:d",cnt,contents,sizeof(sha1)*cnt); +} + +signed_blob *ES_NextCert(const signed_blob *certs) +{ + cert_header *cert; + if(!SIGNATURE_SIZE(certs)) return NULL; + cert = SIGNATURE_PAYLOAD(certs); + if(!CERTIFICATE_SIZE(cert)) return NULL; + return (signed_blob*)(((u8*)cert) + CERTIFICATE_SIZE(cert)); +} + +s32 __ES_sanity_check_certlist(const signed_blob *certs, u32 certsize) +{ + int count = 0; + signed_blob *end; + + if(!certs || !certsize) return 0; + + end = (signed_blob*)(((u8*)certs) + certsize); + while(certs != end) { + certs = ES_NextCert(certs); + if(!certs) return 0; + count++; + } + return count; +} + +s32 ES_Identify(const signed_blob *certificates, u32 certificates_size, const signed_blob *stmd, u32 tmd_size, const signed_blob *sticket, u32 ticket_size, u32 *keyid) +{ + + tmd *p_tmd; + u8 *hashes; + s32 ret; + u32 *keyid_buf; + + if(__es_fd<0) return ES_ENOTINIT; + + if(ticket_size != STD_SIGNED_TIK_SIZE) return ES_EINVAL; + if(!stmd || !tmd_size || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL; + if(!sticket || !IS_VALID_SIGNATURE(sticket)) return ES_EINVAL; + if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL; + if(!ISALIGNED(certificates)) return ES_EALIGN; + if(!ISALIGNED(stmd)) return ES_EALIGN; + if(!ISALIGNED(sticket)) return ES_EALIGN; + if(tmd_size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL; + + p_tmd = SIGNATURE_PAYLOAD(stmd); + + if(!(keyid_buf = iosAlloc(__es_hid, 4))) return ES_ENOMEM; + if(!(hashes = iosAlloc(__es_hid, p_tmd->num_contents*20))) { + iosFree(__es_hid, keyid_buf); + return ES_ENOMEM; + } + + ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DIVERIFY, "dddd:id", certificates, certificates_size, 0, 0, sticket, ticket_size, stmd, tmd_size, keyid_buf, hashes, p_tmd->num_contents*20); + if(ret >= 0 && keyid) *keyid = *keyid_buf; + + iosFree(__es_hid, keyid_buf); + iosFree(__es_hid, hashes); + + if(ret >= 0) { + __ES_Close(); + __ES_Init(); + } + + return ret; +} + +s32 ES_AddTicket(const signed_blob *stik, u32 stik_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size) +{ + s32 ret; + + if(__es_fd<0) return ES_ENOTINIT; + if(stik_size != STD_SIGNED_TIK_SIZE) return ES_EINVAL; + if(!stik || !IS_VALID_SIGNATURE(stik)) return ES_EINVAL; + if(crl_size && (!crl || !IS_VALID_SIGNATURE(crl))) return ES_EINVAL; + if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL; + if(!certificates || !ISALIGNED(certificates)) return ES_EALIGN; + if(!ISALIGNED(stik)) return ES_EALIGN; + if(!ISALIGNED(certificates)) return ES_EALIGN; + if(!ISALIGNED(crl)) return ES_EALIGN; + + if(!crl_size) crl=NULL; + + ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTICKET, "ddd:", stik, stik_size, certificates, certificates_size, crl, crl_size); + return ret; + +} + +s32 ES_DeleteTicket(const tikview *view) +{ + s32 ret; + + if(__es_fd<0) return ES_ENOTINIT; + if(!view) return ES_EINVAL; + if(!ISALIGNED(view)) return ES_EALIGN; + ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETICKET, "d:", view, sizeof(tikview)); + return ret; +} + +s32 ES_AddTitleTMD(const signed_blob *stmd, u32 stmd_size) +{ + s32 ret; + + if(__es_fd<0) return ES_ENOTINIT; + if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL; + if(stmd_size != SIGNED_TMD_SIZE(stmd)) return ES_EINVAL; + if(!ISALIGNED(stmd)) return ES_EALIGN; + + ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTMD, "d:", stmd, stmd_size); + return ret; + +} + +s32 ES_AddTitleStart(const signed_blob *stmd, u32 tmd_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size) +{ + s32 ret; + + if(__es_fd<0) return ES_ENOTINIT; + if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL; + if(tmd_size != SIGNED_TMD_SIZE(stmd)) return ES_EINVAL; + if(crl_size && (!crl || !IS_VALID_SIGNATURE(crl))) return ES_EINVAL; + if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL; + if(!certificates || !ISALIGNED(certificates)) return ES_EALIGN; + if(!ISALIGNED(stmd)) return ES_EALIGN; + if(!ISALIGNED(certificates)) return ES_EALIGN; + if(!ISALIGNED(crl)) return ES_EALIGN; + + if(!crl_size) crl=NULL; + + ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLESTART, "dddi:", stmd, tmd_size, certificates, certificates_size, crl, crl_size, 1); + return ret; +} + +s32 ES_AddContentStart(u64 titleID, u32 cid) +{ + if(__es_fd<0) return ES_ENOTINIT; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTSTART, "qi:", titleID, cid); +} + +s32 ES_AddContentData(s32 cfd, u8 *data, u32 data_size) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cfd<0) return ES_EINVAL; + if(!data || !data_size) return ES_EINVAL; + if(!ISALIGNED(data)) return ES_EALIGN; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTDATA, "id:", cfd, data, data_size); +} + +s32 ES_AddContentFinish(u32 cid) +{ + if(__es_fd<0) return ES_ENOTINIT; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTFINISH, "i:", cid); +} + +s32 ES_AddTitleFinish(void) +{ + if(__es_fd<0) return ES_ENOTINIT; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLEFINISH, ""); +} + +s32 ES_AddTitleCancel(void) +{ + if(__es_fd<0) return ES_ENOTINIT; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLECANCEL, ""); +} + +s32 ES_ImportBoot(const signed_blob *tik, u32 tik_size,const signed_blob *tik_certs,u32 tik_certs_size,const signed_blob *tmd,u32 tmd_size,const signed_blob *tmd_certs,u32 tmd_certs_size,const u8 *content,u32 content_size) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(!tik || !tik_size) return ES_EINVAL; + if(!tik_certs || !tik_certs_size) return ES_EINVAL; + if(!tmd || !tmd_size) return ES_EINVAL; + if(!tmd_certs || !tmd_certs_size) return ES_EINVAL; + if(!content || !content_size) return ES_EINVAL; + if(!ISALIGNED(tik)) return ES_EALIGN; + if(!ISALIGNED(tmd)) return ES_EALIGN; + if(!ISALIGNED(tik_certs)) return ES_EALIGN; + if(!ISALIGNED(tmd_certs)) return ES_EALIGN; + if(!ISALIGNED(content)) return ES_EALIGN; + + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_IMPORTBOOT, "dddddd:", tik, tik_size, tik_certs, tik_certs_size, tmd, tmd_size, tmd_certs, tmd_certs_size, NULL, 0, content, content_size); +} + +s32 ES_OpenContent(u16 index) +{ + if(__es_fd<0) return ES_ENOTINIT; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENCONTENT, "i:", index); +} + +s32 ES_OpenTitleContent(u64 titleID, tikview *views, u16 index) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(!ISALIGNED(views)) return ES_EALIGN; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENTITLECONTENT, "qdi:", titleID, views, sizeof(tikview), index); +} + +s32 ES_ReadContent(s32 cfd, u8 *data, u32 data_size) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cfd<0) return ES_EINVAL; + if(!data || !data_size) return ES_EINVAL; + if(!ISALIGNED(data)) return ES_EALIGN; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_READCONTENT, "i:d", cfd, data, data_size); +} + +s32 ES_SeekContent(s32 cfd, s32 where, s32 whence) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cfd<0) return ES_EINVAL; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SEEKCONTENT, "iii:", cfd, where, whence); +} + +s32 ES_CloseContent(s32 cfd) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(cfd<0) return ES_EINVAL; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_CLOSECONTENT, "i:", cfd); +} + +s32 ES_DeleteTitle(u64 titleID) +{ + if(__es_fd<0) return ES_ENOTINIT; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLE, "q:", titleID); +} + +s32 ES_DeleteTitleContent(u64 titleID) +{ + if(__es_fd<0) return ES_ENOTINIT; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLECONTENT, "q:", titleID); +} + +s32 ES_Encrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(!iv || !source || !size || !dest) return ES_EINVAL; + if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ENCRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size); +} + +s32 ES_Decrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(!iv || !source || !size || !dest) return ES_EINVAL; + if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DECRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size); +} + +s32 ES_Sign(u8 *source, u32 size, u8 *sig, u8 *certs) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(!source || !size || !sig || !certs) return ES_EINVAL; + if(!ISALIGNED(source) || !ISALIGNED(sig) || !ISALIGNED(certs)) return ES_EALIGN; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SIGN, "d:dd", source, size, sig, 0x3C, certs, 0x180); +} + +s32 ES_GetDeviceCert(u8 *outbuf) +{ + if(__es_fd<0) return ES_ENOTINIT; + if(!outbuf) return ES_EINVAL; + if(!ISALIGNED(outbuf)) return ES_EALIGN; + return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICECERT, ":d", outbuf, 0x180); +} + +s32 ES_GetDeviceID(u32 *device_id) +{ + s32 ret; + u32 _device_id = 0; + + if(__es_fd<0) return ES_ENOTINIT; + if(!device_id) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICEID, ":i", &_device_id); + if (ret>=0) *device_id = _device_id; + + return ret; +} + +s32 ES_GetBoot2Version(u32 *version) +{ + s32 ret; + u32 _version = 0; + + if(__es_fd<0) return ES_ENOTINIT; + if(!version) return ES_EINVAL; + + ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETBOOT2VERSION, ":i", &_version); + if (ret>=0) *version = _version; + + return ret; +} + +// 64k buffer size for alignment +#define ES_READ_BUF_SIZE 65536 + +typedef struct { + s32 cfd; + u64 titleID; + tmd_content content; + void *iobuf; + mutex_t mutex; +} es_fd; + +// valid path formats: +// format example description +// es:%08x es:00000004 Content index for current title ID +// es:ID%08x es:ID00000033 Content ID for current title ID +// es:%016llx/%08x es:0000000100000002/00000004 Content index for some title ID (not fully implemented yet) +// es:%016llx/ID%08x es:0000000100000002/ID00000033 Content ID for some title ID (not fully implemented yet) +// leading zeroes may be omitted, 0x prefix allowed. All numbers in hex. + +static s32 _ES_decodepath (struct _reent *r, const char *path, u64 *titleID, tmd_content *content) +{ + u64 _tid = 0; + u32 tmd_size; + STACK_ALIGN(u8, _tmdbuf, MAX_SIGNED_TMD_SIZE, 32); + signed_blob *_stmd; + tmd *_tmd; + tmd_content *_contents; + tmd_content _content; + int is_cid; + u32 arg; + char *bad; + int i; + u64 mytid; + + // check the device + if(strncmp(path,"es:",3)) { + r->_errno = EINVAL; + return -1; + } + path += 3; + + // Get our Title ID + if(ES_GetTitleID(&mytid) < 0) { + r->_errno = EIO; + return -1; + } + + // Read in Title ID, if this is an absolute path + if(path[0] == '/') { + path++; + if(!path[0]) { + r->_errno = EINVAL; + return -1; + } + r->_errno = 0; + _tid = _strtoull_r(r, path, &bad, 16); + if(r->_errno) return -1; + if((bad == path) || (bad[0] != '/')) { + r->_errno = EINVAL; + return -1; + } + path = bad + 1; + } else { + _tid = mytid; + } + + // check if path is a content ID + if(!strncmp(path,"ID",2)) { + path += 2; + is_cid = 1; + } else { + is_cid = 0; + } + + // read in the argument (content ID or content index) + r->_errno = 0; + arg = _strtoul_r(r, path, &bad, 16); + if(r->_errno) return -1; + if((bad == path) || (bad[0] != 0)) { + r->_errno = EINVAL; + return -1; + } + + // now get the TMD and find the content entry + if(ES_GetStoredTMDSize(_tid, &tmd_size) < 0) { + r->_errno = ENOENT; + return -1; + } + + _stmd = (signed_blob*)_tmdbuf; + if(ES_GetStoredTMD(_tid, _stmd, tmd_size) < 0) { + r->_errno = EIO; + return -1; + } + if(!IS_VALID_SIGNATURE(_stmd)) { + r->_errno = EIO; + return -1; + } + _tmd = SIGNATURE_PAYLOAD(_stmd); + _contents = TMD_CONTENTS(_tmd); + + for(i=0;i<_tmd->num_contents;i++) { + if(is_cid) { + if(_contents[i].cid == arg) { + _content = _contents[i]; + break; + } + } else { + if(_contents[i].index == arg) { + _content = _contents[i]; + break; + } + } + } + if(i >= _tmd->num_contents) { + r->_errno = ENOENT; + return -1; + } + + if(titleID) { + if(_tid == mytid) *titleID = 0; + else *titleID = _tid; + } + if(content) *content = _content; + return 0; +} + +static int _ES_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { + es_fd *file = (es_fd *) fileStruct; + + // decode the path + if(_ES_decodepath(r, path, &file->titleID, &file->content) < 0) { + return -1; + } + + // writing not supported + if ((flags & 0x03) != O_RDONLY) { + r->_errno = EROFS; + return -1; + } + + // open the content + if(file->titleID == 0) + file->cfd = ES_OpenContent(file->content.index); + else + { + u32 cnt ATTRIBUTE_ALIGN(32); + ES_GetNumTicketViews(file->titleID, &cnt); + tikview *views = (tikview *)memalign( 32, sizeof(tikview)*cnt ); + if(views == NULL) + { + return -1; + } + ES_GetTicketViews(file->titleID, views, cnt); + file->cfd = ES_OpenTitleContent(file->titleID, views, file->content.index); + free(views); + } + + if(file->cfd<0) { + r->_errno = EIO; + return -1; + } + + file->iobuf = NULL; + + LWP_MutexInit(&file->mutex, false); + + return (int)file; +} + +static int _ES_close_r (struct _reent *r, void *fd) { + es_fd *file = (es_fd *) fd; + + LWP_MutexLock(file->mutex); + + if(ES_CloseContent(file->cfd) < 0) { + r->_errno = EBADF; + return -1; + } + file->cfd = -1; + + if(file->iobuf) _free_r(r,file->iobuf); + + LWP_MutexUnlock(file->mutex); + LWP_MutexDestroy(file->mutex); + return 0; +} + +static int _ES_read_r (struct _reent *r, void *fd, char *ptr, size_t len) { + es_fd *file = (es_fd *) fd; + int read = 0; + int res; + + + LWP_MutexLock(file->mutex); + if(file->cfd < 0) { + LWP_MutexUnlock(file->mutex); + r->_errno = EBADF; + return -1; + } + + // if aligned, just pass through the read + if(ISALIGNED(ptr)) + { + res = ES_ReadContent(file->cfd, (u8*)ptr, len); + if(res < 0) { + LWP_MutexUnlock(file->mutex); + // we don't really know what the error codes mean... + r->_errno = EIO; + return -1; + } + read = res; + // otherwise read in blocks to an aligned buffer + } else { + int chunk; + if(!file->iobuf) { + file->iobuf = _memalign_r(r, 32, ES_READ_BUF_SIZE); + if(!file->iobuf) { + r->_errno = ENOMEM; + return -1; + } + } + while(len) { + if(len > ES_READ_BUF_SIZE) chunk = ES_READ_BUF_SIZE; + else chunk = len; + res = ES_ReadContent(file->cfd, file->iobuf, chunk); + if(res < 0) { + LWP_MutexUnlock(file->mutex); + // we don't really know what the error codes mean... + r->_errno = EIO; + return -1; + } + len -= res; + read += res; + memcpy(ptr, file->iobuf, res); + ptr += res; + if(res < chunk) break; + } + } + + LWP_MutexUnlock(file->mutex); + return read; +} + +static off_t _ES_seek_r (struct _reent *r, void *fd, off_t where, int whence) { + es_fd *file = (es_fd *) fd; + s32 res; + + LWP_MutexLock(file->mutex); + if(file->cfd < 0) { + LWP_MutexUnlock(file->mutex); + r->_errno = EBADF; + return -1; + } + + res = ES_SeekContent(file->cfd, where, whence); + LWP_MutexUnlock(file->mutex); + + if(res < 0) { + r->_errno = EINVAL; + return -1; + } + return res; +} + +static void _ES_fillstat(u64 titleID, tmd_content *content, struct stat *st) { + memset(st, 0, sizeof(*st)); + // the inode is the content ID + // (pretend each Title ID is a different filesystem) + st->st_ino = content->cid; + // st_dev is only a short, so do the best we can and use the middle two letters + // of the title ID if it's not a system content, otherwise use the low 16 bits + if((titleID>>32) == 1) + st->st_dev = titleID & 0xFFFF; + else + st->st_dev = (titleID>>8) & 0xFFFF; + + // not necessarily true due to shared contents, but + // we're not going to implement shared content scan here and now + st->st_nlink = 1; + // instead, give the file group read permissions if it's a shared content + st->st_mode = S_IFREG | S_IRUSR; + if(content->type & 0x8000) + st->st_mode |= S_IRGRP; + + // use st_dev as a uid too, see above + st->st_uid = st->st_dev; + // no group + st->st_gid = 0; + // content size + st->st_size = content->size; + st->st_blocks = (st->st_size + 511) / 512; + // NAND fs cluster size (not like anyone cares, but...) + st->st_blksize = 16384; +} + +static int _ES_fstat_r (struct _reent *r, void *fd, struct stat *st) { + es_fd *file = (es_fd *) fd; + + LWP_MutexLock(file->mutex); + if(file->cfd < 0) { + LWP_MutexUnlock(file->mutex); + r->_errno = EBADF; + return -1; + } + + _ES_fillstat(file->titleID, &file->content, st); + LWP_MutexUnlock(file->mutex); + + return 0; +} + +static int _ES_stat_r (struct _reent *r, const char *path, struct stat *st) { + tmd_content content; + u64 titleID; + + if(_ES_decodepath(r, path, &titleID, &content) < 0) { + return -1; + } + _ES_fillstat(titleID, &content, st); + return 0; +} + +static const devoptab_t dotab_es = { + "es", + sizeof (es_fd), + _ES_open_r, + _ES_close_r, + NULL, + _ES_read_r, + _ES_seek_r, + _ES_fstat_r, + _ES_stat_r, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static void __ES_InitFS(void) { + AddDevice(&dotab_es); +} + +static void __ES_DeinitFS(void) { + RemoveDevice("es:"); +} + +#endif /* defined(HW_RVL) */ diff --git a/wii/libogc/libogc/exception.c b/wii/libogc/libogc/exception.c new file mode 100644 index 0000000000..b901efa8d5 --- /dev/null +++ b/wii/libogc/libogc/exception.c @@ -0,0 +1,266 @@ +/*------------------------------------------------------------- + +exception.c -- PPC exception handling support + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "cache.h" +#include "irq.h" +#include "context.h" + +#include "system.h" + +#include "gx.h" +#include "pad.h" +#include "consol.h" +#include "console.h" +#include "lwp_threads.h" +#include "ios.h" + +#include "ogc/video_types.h" + +#define CPU_STACK_TRACE_DEPTH 10 + +typedef struct _framerec { + struct _framerec *up; + void *lr; +} frame_rec, *frame_rec_t; + +static void *exception_xfb = (void*)0xC1700000; //we use a static address above ArenaHi. +static int reload_timer = -1; + +void __exception_sethandler(u32 nExcept, void (*pHndl)(frame_context*)); + +extern void udelay(int us); +extern void fpu_exceptionhandler(); +extern void irq_exceptionhandler(); +extern void dec_exceptionhandler(); +extern void default_exceptionhandler(); +extern void VIDEO_SetFramebuffer(void *); +extern void __reload(); + +extern s8 exceptionhandler_start[],exceptionhandler_end[],exceptionhandler_patch[]; +extern s8 systemcallhandler_start[],systemcallhandler_end[]; + +void (*_exceptionhandlertable[NUM_EXCEPTIONS])(frame_context*); + +static u32 exception_location[NUM_EXCEPTIONS] = { + 0x00000100, 0x00000200, 0x00000300, 0x00000400, + 0x00000500, 0x00000600, 0x00000700, 0x00000800, + 0x00000900, 0x00000C00, 0x00000D00, 0x00000F00, + 0x00001300, 0x00001400, 0x00001700 }; + +static const char *exception_name[NUM_EXCEPTIONS] = { + "System Reset", "Machine Check", "DSI", "ISI", + "Interrupt", "Alignment", "Program", "Floating Point", + "Decrementer", "System Call", "Trace", "Performance", + "IABR", "Reserved", "Thermal"}; + +void __exception_load(u32 nExc,void *data,u32 len,void *patch) +{ + void *pAddr = (void*)(0x80000000|exception_location[nExc]); + memcpy(pAddr,data,len); + if(patch) + *(u32*)((u32)pAddr+(patch-data)) |= nExc; + + DCFlushRangeNoSync(pAddr,len); + ICInvalidateRange(pAddr,len); + _sync(); +} + +void __systemcall_init() +{ + __exception_load(EX_SYS_CALL,systemcallhandler_start,(systemcallhandler_end-systemcallhandler_start),NULL); +} + +void __exception_init() +{ + s32 i; + // init all exceptions with the default handler & vector code + for(i=0;iup;p=p->up,i++) { + if(i%4) kprintf(" --> "); + else { + if(i>0) kprintf(" -->\n\t"); + else kprintf("\n\t"); + } + + switch(i) { + case 0: + if(pc) kprintf("%p",pc); + break; + case 1: + if(!l) l = (frame_rec_t)mfspr(8); + kprintf("%p",(void*)l); + break; + default: + kprintf("%p",(void*)(p->up->lr)); + break; + } + } +} + +void __exception_setreload(int t) +{ + reload_timer = t*50; +} + +static void waitForReload() +{ + u32 level; + + PAD_Init(); + + if(reload_timer > 0) + kprintf("\n\tReloading in %d seconds\n", reload_timer/50); + + while ( 1 ) + { + PAD_ScanPads(); + + int buttonsDown = PAD_ButtonsDown(0); + + if( (buttonsDown & PAD_TRIGGER_Z) || SYS_ResetButtonDown() || + reload_timer == 0 ) + { + kprintf("\n\tReload\n\n\n"); + _CPU_ISR_Disable(level); + __reload (); + } + + if ( buttonsDown & PAD_BUTTON_A ) + { + kprintf("\n\tReset\n\n\n"); +#if defined(HW_DOL) + SYS_ResetSystem(SYS_HOTRESET,0,FALSE); +#else + __reload (); +#endif + } + + udelay(20000); + if(reload_timer > 0) + reload_timer--; + } +} + +//just implement core for unrecoverable exceptions. +void c_default_exceptionhandler(frame_context *pCtx) +{ + GX_AbortFrame(); + VIDEO_SetFramebuffer(exception_xfb); + __console_init(exception_xfb,20,20,640,574,1280); + CON_EnableGecko(1, true); + + kprintf("\n\n\n\tException (%s) occurred!\n", exception_name[pCtx->EXCPT_Number]); + + kprintf("\tGPR00 %08X GPR08 %08X GPR16 %08X GPR24 %08X\n",pCtx->GPR[0], pCtx->GPR[8], pCtx->GPR[16], pCtx->GPR[24]); + kprintf("\tGPR01 %08X GPR09 %08X GPR17 %08X GPR25 %08X\n",pCtx->GPR[1], pCtx->GPR[9], pCtx->GPR[17], pCtx->GPR[25]); + kprintf("\tGPR02 %08X GPR10 %08X GPR18 %08X GPR26 %08X\n",pCtx->GPR[2], pCtx->GPR[10], pCtx->GPR[18], pCtx->GPR[26]); + kprintf("\tGPR03 %08X GPR11 %08X GPR19 %08X GPR27 %08X\n",pCtx->GPR[3], pCtx->GPR[11], pCtx->GPR[19], pCtx->GPR[27]); + kprintf("\tGPR04 %08X GPR12 %08X GPR20 %08X GPR28 %08X\n",pCtx->GPR[4], pCtx->GPR[12], pCtx->GPR[20], pCtx->GPR[28]); + kprintf("\tGPR05 %08X GPR13 %08X GPR21 %08X GPR29 %08X\n",pCtx->GPR[5], pCtx->GPR[13], pCtx->GPR[21], pCtx->GPR[29]); + kprintf("\tGPR06 %08X GPR14 %08X GPR22 %08X GPR30 %08X\n",pCtx->GPR[6], pCtx->GPR[14], pCtx->GPR[22], pCtx->GPR[30]); + kprintf("\tGPR07 %08X GPR15 %08X GPR23 %08X GPR31 %08X\n",pCtx->GPR[7], pCtx->GPR[15], pCtx->GPR[23], pCtx->GPR[31]); + kprintf("\tLR %08X SRR0 %08x SRR1 %08x MSR %08x\n", pCtx->LR, pCtx->SRR0, pCtx->SRR1,pCtx->MSR); + kprintf("\tDAR %08X DSISR %08X\n", mfspr(19), mfspr(18)); + + _cpu_print_stack((void*)pCtx->SRR0,(void*)pCtx->LR,(void*)pCtx->GPR[1]); + + if((pCtx->EXCPT_Number==EX_DSI) || (pCtx->EXCPT_Number==EX_FP)) { + u32 i; + u32 *pAdd = (u32*)pCtx->SRR0; + kprintf("\n\n\tCODE DUMP:\n"); + for (i=0; i<12; i+=4) + kprintf("\t%p: %08X %08X %08X %08X\n", + &(pAdd[i]),pAdd[i], pAdd[i+1], pAdd[i+2], pAdd[i+3]); + } + + waitForReload(); +} + diff --git a/wii/libogc/libogc/exception_handler.S b/wii/libogc/libogc/exception_handler.S new file mode 100644 index 0000000000..6ff209ad3d --- /dev/null +++ b/wii/libogc/libogc/exception_handler.S @@ -0,0 +1,243 @@ +/*------------------------------------------------------------- + +exception_handler.S -- PPC exception handling support + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include + +#define EXCEPTION_PROLOG \ + mfspr r0,912; \ + stw r0,GQR0_OFFSET(sp); \ + mfspr r0,913; \ + stw r0,GQR1_OFFSET(sp); \ + mfspr r0,914; \ + stw r0,GQR2_OFFSET(sp); \ + mfspr r0,915; \ + stw r0,GQR3_OFFSET(sp); \ + mfspr r0,916; \ + stw r0,GQR4_OFFSET(sp); \ + mfspr r0,917; \ + stw r0,GQR5_OFFSET(sp); \ + mfspr r0,918; \ + stw r0,GQR6_OFFSET(sp); \ + mfspr r0,919; \ + stw r0,GQR7_OFFSET(sp); \ + stw r6,GPR6_OFFSET(sp); \ + stw r7,GPR7_OFFSET(sp); \ + stw r8,GPR8_OFFSET(sp); \ + stw r9,GPR9_OFFSET(sp); \ + stw r10,GPR10_OFFSET(sp); \ + stw r11,GPR11_OFFSET(sp); \ + stw r12,GPR12_OFFSET(sp); \ + stw r13,GPR13_OFFSET(sp); \ + stw r14,GPR14_OFFSET(sp); \ + stw r15,GPR15_OFFSET(sp); + +#define EXCEPTION_EPILOG \ + lwz r4,GQR0_OFFSET(sp); \ + mtspr 912,r4; \ + lwz r4,GQR1_OFFSET(sp); \ + mtspr 913,r4; \ + lwz r4,GQR2_OFFSET(sp); \ + mtspr 914,r4; \ + lwz r4,GQR3_OFFSET(sp); \ + mtspr 915,r4; \ + lwz r4,GQR4_OFFSET(sp); \ + mtspr 916,r4; \ + lwz r4,GQR5_OFFSET(sp); \ + mtspr 917,r4; \ + lwz r4,GQR6_OFFSET(sp); \ + mtspr 918,r4; \ + lwz r4,GQR7_OFFSET(sp); \ + mtspr 919,r4; \ + lwz r15,GPR15_OFFSET(sp); \ + lwz r14,GPR14_OFFSET(sp); \ + lwz r13,GPR13_OFFSET(sp); \ + lwz r12,GPR12_OFFSET(sp); \ + lwz r11,GPR11_OFFSET(sp); \ + lwz r10,GPR10_OFFSET(sp); \ + lwz r9,GPR9_OFFSET(sp); \ + lwz r8,GPR8_OFFSET(sp); \ + lwz r7,GPR7_OFFSET(sp); \ + lwz r6,GPR6_OFFSET(sp); \ + lwz r5,GPR5_OFFSET(sp) + + + .globl exceptionhandler_start,exceptionhandler_end,exceptionhandler_patch +exceptionhandler_start: + mtspr SPRG3,r4 + clrlwi r4,sp,2 //make sp physical and move new value to r4 + stwu r4,-EXCEPTION_FRAME_END(r4) + stw r0,GPR0_OFFSET(r4) + stw sp,GPR1_OFFSET(r4) + stw toc,GPR2_OFFSET(r4) + stw r3,GPR3_OFFSET(r4) + mfspr r3,SPRG3 + stw r3,GPR4_OFFSET(r4) + stw r5,GPR5_OFFSET(r4) + mfcr r3 + stw r3,CR_OFFSET(r4) + mflr r3 + stw r3,LR_OFFSET(r4) + mfctr r3 + stw r3,CTR_OFFSET(r4) + mfxer r3 + stw r3,XER_OFFSET(r4) + mfmsr r3 + stw r3,MSR_OFFSET(r4) + mfdar r3 + stw r3,DAR_OFFSET(r4) + mfsrr0 r3 + stw r3,SRR0_OFFSET(r4) + mfsrr1 r3 + stw r3,SRR1_OFFSET(r4) + mr r5,r3 + nop + mfmsr r3 + ori r3,r3,MSR_IR|MSR_DR + mtsrr1 r3 + +exceptionhandler_patch: + li r3,0 + stw r3,EXCEPTION_NUMBER(r4) + + rlwinm. r5,r5,0,30,30 + lis r5,default_exceptionhandler@h + ori r5,r5,default_exceptionhandler@l + beq 1f + lis r5,_exceptionhandlertable@h + ori r5,r5,_exceptionhandlertable@l + clrlwi r5,r5,2 + clrlslwi r3,r3,24,2 + lwzx r5,r3,r5 +1: + mtsrr0 r5 + rfi +exceptionhandler_end: + nop + + .extern c_default_exceptionhandler + .globl default_exceptionhandler +default_exceptionhandler: + stwu sp,-EXCEPTION_FRAME_END(sp) //now we're able to adjust the stackpointer with it's cached address + + EXCEPTION_PROLOG + + stmw r16,GPR16_OFFSET(sp) + + addi r3,sp,0x08 + bl c_default_exceptionhandler + + lwz r4,CR_OFFSET(sp) + mtcr r4 + lwz r4,LR_OFFSET(sp) + mtlr r4 + lwz r4,CTR_OFFSET(sp) + mtctr r4 + lwz r4,XER_OFFSET(sp) + mtxer r4 + + EXCEPTION_EPILOG + + lmw r16,GPR16_OFFSET(sp) + + lwz toc,GPR2_OFFSET(sp) + lwz r0,GPR0_OFFSET(sp) + + lwz r4,SRR0_OFFSET(sp) + mtsrr0 r4 + lwz r4,SRR1_OFFSET(sp) + mtsrr1 r4 + + lwz r4,GPR4_OFFSET(sp) + lwz r3,GPR3_OFFSET(sp) + addi sp,sp,EXCEPTION_FRAME_END + rfi + + .extern _cpu_context_save_fp,_cpu_context_restore_fp + .globl fpu_exceptionhandler +fpu_exceptionhandler: + stwu sp,-EXCEPTION_FRAME_END(sp) //now we're able to adjust the stackpointer with it's cached address + + EXCEPTION_PROLOG + + mfmsr r4 + ori r4,r4,MSR_FP + mtmsr r4 + isync + + bl __thread_dispatch_fp + + lwz r4,CR_OFFSET(sp) + mtcr r4 + lwz r4,LR_OFFSET(sp) + mtlr r4 + lwz r4,CTR_OFFSET(sp) + mtctr r4 + lwz r4,XER_OFFSET(sp) + mtxer r4 + + EXCEPTION_EPILOG + + mfmsr r4 + rlwinm r4,r4,0,19,17 + mtmsr r4 + isync + + lwz toc,GPR2_OFFSET(sp) + lwz r0,GPR0_OFFSET(sp) + + lwz r4,SRR0_OFFSET(sp) + mtsrr0 r4 + lwz r4,SRR1_OFFSET(sp) + ori r4,r4,MSR_FP + mtsrr1 r4 + + lwz r4,GPR4_OFFSET(sp) + lwz r3,GPR3_OFFSET(sp) + addi sp,sp,EXCEPTION_FRAME_END + rfi + + .global systemcallhandler_start,systemcallhandler_end +systemcallhandler_start: + mtspr SPRG2,r9 + mtspr SPRG3,r10 + mfspr r9,HID0 + ori r10,r9,0x0008 + mtspr HID0,r10 + isync + sync + mtspr HID0,r9 + mfspr r9,SPRG2 + mfspr r10,SPRG3 + rfi +systemcallhandler_end: + nop + + + diff --git a/wii/libogc/libogc/exi.c b/wii/libogc/libogc/exi.c new file mode 100644 index 0000000000..961fd46592 --- /dev/null +++ b/wii/libogc/libogc/exi.c @@ -0,0 +1,866 @@ +/*------------------------------------------------------------- + +exi.c -- EXI subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include +#include "asm.h" +#include "irq.h" +#include "processor.h" +#include "spinlock.h" +#include "exi.h" + +#define EXI_LOCK_DEVS 32 + +#define EXI_MAX_CHANNELS 3 +#define EXI_MAX_DEVICES 3 + +#define EXI_DEVICE0 0x0080 +#define EXI_DEVICE1 0x0100 +#define EXI_DEVICE2 0x0200 + +#define EXI_EXI_IRQ 0x0002 +#define EXI_TC_IRQ 0x0008 +#define EXI_EXT_IRQ 0x0800 +#define EXI_EXT_BIT 0x1000 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + + +struct _lck_dev { + lwp_node node; + u32 dev; + EXICallback unlockcb; +}; + +typedef struct _exibus_priv { + EXICallback CallbackEXI; + EXICallback CallbackTC; + EXICallback CallbackEXT; + + u32 imm_len; + void *imm_buff; + u32 lockeddev; + u32 flags; + u32 lck_cnt; + u32 exi_id; + u64 exi_idtime; + lwp_queue lckd_dev; + u32 lckd_dev_bits; +} exibus_priv; + +static lwp_queue _lckdev_queue; +static struct _lck_dev lckdevs[EXI_LOCK_DEVS]; +static exibus_priv eximap[EXI_MAX_CHANNELS]; +static u64 last_exi_idtime[EXI_MAX_CHANNELS]; + +static u32 exi_id_serport1 = 0; + +static u32 exi_uart_chan = EXI_CHANNEL_0; +static u32 exi_uart_dev = EXI_DEVICE_0; +static u32 exi_uart_barnacle_enabled = 0; +static u32 exi_uart_enabled = 0; + +static void __exi_irq_handler(u32,void *); +static void __tc_irq_handler(u32,void *); +static void __ext_irq_handler(u32,void *); + +#if defined(HW_DOL) + static vu32* const _exiReg = (u32*)0xCC006800; +#elif defined(HW_RVL) + static vu32* const _exiReg = (u32*)0xCD006800; +#else + #error HW model unknown. +#endif + +static __inline__ void __exi_clearirqs(s32 nChn,u32 nEXIIrq,u32 nTCIrq,u32 nEXTIrq) +{ + u32 d; + d = (_exiReg[nChn*5]&~(EXI_EXI_IRQ|EXI_TC_IRQ|EXI_EXT_IRQ)); + if(nEXIIrq) d |= EXI_EXI_IRQ; + if(nTCIrq) d |= EXI_TC_IRQ; + if(nEXTIrq) d |= EXI_EXT_IRQ; + _exiReg[nChn*5] = d; +} + +static __inline__ void __exi_setinterrupts(s32 nChn,exibus_priv *exi) +{ + exibus_priv *pexi = &eximap[EXI_CHANNEL_2]; + if(nChn==EXI_CHANNEL_0) { + __MaskIrq((IRQMASK(IRQ_EXI0_EXI)|IRQMASK(IRQ_EXI2_EXI))); + if(!(exi->flags&EXI_FLAG_LOCKED) && (exi->CallbackEXI || pexi->CallbackEXI)) + __UnmaskIrq((IRQMASK(IRQ_EXI0_EXI)|IRQMASK(IRQ_EXI2_EXI))); + } else if(nChn==EXI_CHANNEL_1) { + __MaskIrq(IRQMASK(IRQ_EXI1_EXI)); + if(!(exi->flags&EXI_FLAG_LOCKED) && exi->CallbackEXI) __UnmaskIrq(IRQMASK(IRQ_EXI1_EXI)); + } else if(nChn==EXI_CHANNEL_2) { //explicitly use of channel 2 only if debugger is attached. + __MaskIrq(IRQMASK(IRQ_EXI0_EXI)); + if(!(exi->flags&EXI_FLAG_LOCKED) && IRQ_GetHandler(IRQ_PI_DEBUG)) __UnmaskIrq(IRQMASK(IRQ_EXI2_EXI)); + } +} + +static void __exi_initmap(exibus_priv *exim) +{ + s32 i; + exibus_priv *m; + + __lwp_queue_initialize(&_lckdev_queue,lckdevs,EXI_LOCK_DEVS,sizeof(struct _lck_dev)); + + for(i=0;iCallbackEXI = NULL; + m->CallbackEXT = NULL; + m->CallbackTC = NULL; + m->imm_buff = NULL; + m->exi_id = 0; + m->exi_idtime = 0; + m->flags = 0; + m->imm_len = 0; + m->lck_cnt = 0; + m->lockeddev = 0; + m->lckd_dev_bits = 0; + __lwp_queue_init_empty(&m->lckd_dev); + } +} + +static s32 __exi_probe(s32 nChn) +{ + u64 time; + s32 ret = 1; + u32 level; + u32 val; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + val = _exiReg[nChn*5]; + if(!(exi->flags&EXI_FLAG_ATTACH)) { + if(val&EXI_EXT_IRQ) { + __exi_clearirqs(nChn,0,0,1); + exi->exi_idtime = 0; + last_exi_idtime[nChn] = 0; + } + if(_exiReg[nChn*5]&EXI_EXT_BIT) { + time = gettime(); + if(last_exi_idtime[nChn]==0) last_exi_idtime[nChn] = time; + if((val=diff_usec(last_exi_idtime[nChn],time)+10)<30) ret = 0; + else ret = 1; + _CPU_ISR_Restore(level); + return ret; + } else { + exi->exi_idtime = 0; + last_exi_idtime[nChn] = 0; + _CPU_ISR_Restore(level); + return 0; + } + } + + if(!(_exiReg[nChn*5]&EXI_EXT_BIT) || (_exiReg[nChn*5]&EXI_EXT_IRQ)) { + exi->exi_idtime = 0; + last_exi_idtime[nChn] = 0; + ret = 0; + } + _CPU_ISR_Restore(level); + return ret; +} + +static s32 __exi_attach(s32 nChn,EXICallback ext_cb) +{ + s32 ret; + u32 level; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + ret = 0; + if(!(exi->flags&EXI_FLAG_ATTACH)) { + if(__exi_probe(nChn)==1) { + __exi_clearirqs(nChn,1,0,0); + exi->CallbackEXT = ext_cb; + __UnmaskIrq(((IRQMASK(IRQ_EXI0_EXT))>>(nChn*3))); + exi->flags |= EXI_FLAG_ATTACH; + ret = 1; + } + } + _CPU_ISR_Restore(level); + return ret; +} + +s32 EXI_Lock(s32 nChn,s32 nDev,EXICallback unlockCB) +{ + u32 level; + struct _lck_dev *lckd; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + if(exi->flags&EXI_FLAG_LOCKED) { + if(unlockCB && !(exi->lckd_dev_bits&(1<lck_cnt++; + exi->lckd_dev_bits |= (1<dev = nDev; + lckd->unlockcb = unlockCB; + __lwp_queue_appendI(&exi->lckd_dev,&lckd->node); + } + } + _CPU_ISR_Restore(level); + return 0; + } + + exi->lockeddev = nDev; + exi->flags |= EXI_FLAG_LOCKED; + __exi_setinterrupts(nChn,exi); + + _CPU_ISR_Restore(level); + return 1; +} + +s32 EXI_Unlock(s32 nChn) +{ + u32 level,dev; + EXICallback cb; + struct _lck_dev *lckd; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + if(!(exi->flags&EXI_FLAG_LOCKED)) { + _CPU_ISR_Restore(level); + return 0; + } + + exi->flags &= ~EXI_FLAG_LOCKED; + __exi_setinterrupts(nChn,exi); + + if(!exi->lck_cnt) { + _CPU_ISR_Restore(level); + return 1; + } + + exi->lck_cnt--; + lckd = (struct _lck_dev*)__lwp_queue_getI(&exi->lckd_dev); + __lwp_queue_appendI(&_lckdev_queue,&lckd->node); + + cb = lckd->unlockcb; + dev = lckd->dev; + exi->lckd_dev_bits &= ~(1<flags&EXI_FLAG_SELECT) { + _CPU_ISR_Restore(level); + return 0; + } + + if(nChn!=EXI_CHANNEL_2) { + if(nDev==EXI_DEVICE_0 && !(exi->flags&EXI_FLAG_ATTACH)) { + if(__exi_probe(nChn)==0) { + _CPU_ISR_Restore(level); + return 0; + } + } + if(!(exi->flags&EXI_FLAG_LOCKED) || exi->lockeddev!=nDev) { + _CPU_ISR_Restore(level); + return 0; + } + } + + exi->flags |= EXI_FLAG_SELECT; + val = _exiReg[nChn*5]; + val = (val&0x405)|(0x80<flags&EXI_FLAG_ATTACH) { + if(nChn==EXI_CHANNEL_0) __MaskIrq(IRQMASK(IRQ_EXI0_EXT)); + else if(nChn==EXI_CHANNEL_1) __MaskIrq(IRQMASK(IRQ_EXI1_EXT)); + } + + _CPU_ISR_Restore(level); + return 1; +} + +s32 EXI_SelectSD(s32 nChn,s32 nDev,s32 nFrq) +{ + u32 val,id; + s32 ret; + u32 level; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + + if(exi->flags&EXI_FLAG_SELECT) { + _CPU_ISR_Restore(level); + return 0; + } + + if(nChn!=EXI_CHANNEL_2) { + if(nDev==EXI_DEVICE_0 && !(exi->flags&EXI_FLAG_ATTACH)) { + if((ret=__exi_probe(nChn))==1) { + if(!exi->exi_idtime) ret = EXI_GetID(nChn,EXI_DEVICE_0,&id); + } + if(ret==0) { + _CPU_ISR_Restore(level); + return 0; + } + } + if(!(exi->flags&EXI_FLAG_LOCKED) || exi->lockeddev!=nDev) { + _CPU_ISR_Restore(level); + return 0; + } + } + + exi->flags |= EXI_FLAG_SELECT; + val = _exiReg[nChn*5]; + val = (val&0x405)|(nFrq<<4); + _exiReg[nChn*5] = val; + + if(exi->flags&EXI_FLAG_ATTACH) { + if(nChn==EXI_CHANNEL_0) __MaskIrq(IRQMASK(IRQ_EXI0_EXT)); + else if(nChn==EXI_CHANNEL_1) __MaskIrq(IRQMASK(IRQ_EXI1_EXT)); + } + + _CPU_ISR_Restore(level); + return 1; +} + +s32 EXI_Deselect(s32 nChn) +{ + u32 val; + u32 level; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + + if(!(exi->flags&EXI_FLAG_SELECT)) { + _CPU_ISR_Restore(level); + return 0; + } + + exi->flags &= ~EXI_FLAG_SELECT; + val = _exiReg[nChn*5]; + _exiReg[nChn*5] = (val&0x405); + + if(exi->flags&EXI_FLAG_ATTACH) { + if(nChn==EXI_CHANNEL_0) __UnmaskIrq(IRQMASK(IRQ_EXI0_EXT)); + else if(nChn==EXI_CHANNEL_1) __UnmaskIrq(IRQMASK(IRQ_EXI1_EXT)); + } + + if(nChn!=EXI_CHANNEL_2 && val&EXI_DEVICE0) { + if(__exi_probe(nChn)==0) { + _CPU_ISR_Restore(level); + return 0; + } + } + _CPU_ISR_Restore(level); + return 1; +} + +s32 EXI_Sync(s32 nChn) +{ + u8 *buf; + s32 ret; + u32 level,i,cnt,val; + exibus_priv *exi = &eximap[nChn]; + while(_exiReg[nChn*5+3]&0x0001); + + _CPU_ISR_Disable(level); + + ret = 0; + if(exi->flags&EXI_FLAG_SELECT && exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM)) { + if(exi->flags&EXI_FLAG_IMM) { + cnt = exi->imm_len; + buf = exi->imm_buff; + if(buf && cnt>0) { + val = _exiReg[nChn*5+4]; + for(i=0;i>((3-i)*8))&0xFF; + } + } + exi->flags &= ~(EXI_FLAG_DMA|EXI_FLAG_IMM); + ret = 1; + } + _CPU_ISR_Restore(level); + return ret; +} + +s32 EXI_Imm(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb) +{ + u32 level; + u32 value,i; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + + if(exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM) || !(exi->flags&EXI_FLAG_SELECT)) { + _CPU_ISR_Restore(level); + return 0; + } + + exi->CallbackTC = tc_cb; + if(tc_cb) { + __exi_clearirqs(nChn,0,1,0); + __UnmaskIrq(IRQMASK((IRQ_EXI0_TC+(nChn*3)))); + } + exi->flags |= EXI_FLAG_IMM; + + exi->imm_buff = pData; + exi->imm_len = nLen; + if(nMode!=EXI_READ) { + for(i=0,value=0;iimm_len = 0; + + _exiReg[nChn*5+3] = (((nLen-1)&0x03)<<4)|((nMode&0x03)<<2)|0x01; + + _CPU_ISR_Restore(level); + return 1; +} + +s32 EXI_ImmEx(s32 nChn,void *pData,u32 nLen,u32 nMode) +{ + u8 *buf = pData; + u32 tc; + s32 ret = 0; + while(nLen) { + ret = 0; + tc = nLen; + if(tc>4) tc = 4; + + if(!EXI_Imm(nChn,buf,tc,nMode,NULL)) break; + if(!EXI_Sync(nChn)) break; + nLen -= tc; + buf += tc; + + ret = 1; + } + return ret; +} + +s32 EXI_Dma(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb) +{ + u32 level; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + + if(exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM) || !(exi->flags&EXI_FLAG_SELECT)) { + _CPU_ISR_Restore(level); + return 0; + } + exi->CallbackTC = tc_cb; + if(tc_cb) { + __exi_clearirqs(nChn,0,1,0); + __UnmaskIrq((IRQMASK((IRQ_EXI0_TC+(nChn*3))))); + } + + exi->imm_buff = NULL; + exi->imm_len = 0; + exi->flags |= EXI_FLAG_DMA; + + _exiReg[nChn*5+1] = (u32)pData&0x03FFFFE0; + _exiReg[nChn*5+2] = nLen; + _exiReg[nChn*5+3] = ((nMode&0x03)<<2)|0x03; + + _CPU_ISR_Restore(level); + return 1; +} + +s32 EXI_GetState(s32 nChn) +{ + exibus_priv *exi = &eximap[nChn]; + return exi->flags; +} + +static s32 __unlocked_handler(s32 nChn,s32 nDev) +{ + u32 nId; + EXI_GetID(nChn,nDev,&nId); + return 1; +} + +s32 EXI_GetID(s32 nChn,s32 nDev,u32 *nId) +{ + u64 idtime = 0; + s32 ret,lck; + u32 reg,level; + exibus_priv *exi = &eximap[nChn]; + + if(nChnexi_idtime==last_exi_idtime[nChn]) { + *nId = exi->exi_id; + return 1; + } + if(__exi_attach(nChn,NULL)==0) return 0; + idtime = last_exi_idtime[nChn]; + } + lck = 0; + if(nChnexi_idtime = idtime; + exi->exi_id = *nId; + ret = 1; + } + _CPU_ISR_Restore(level); + } + return ret; +} + +s32 EXI_Attach(s32 nChn,EXICallback ext_cb) +{ + s32 ret; + u32 level; + exibus_priv *exi = &eximap[nChn]; + EXI_Probe(nChn); + + _CPU_ISR_Disable(level); + if(exi->exi_idtime) { + ret = __exi_attach(nChn,ext_cb); + } else + ret = 0; + _CPU_ISR_Restore(level); + return ret; +} + +s32 EXI_Detach(s32 nChn) +{ + u32 level; + s32 ret = 1; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + if(exi->flags&EXI_FLAG_ATTACH) { + if(exi->flags&EXI_FLAG_LOCKED && exi->lockeddev!=EXI_DEVICE_0) ret = 0; + else { + exi->flags &= ~EXI_FLAG_ATTACH; + __MaskIrq(((IRQMASK(IRQ_EXI0_EXI)|IRQMASK(IRQ_EXI0_TC)|IRQMASK(IRQ_EXI0_EXT))>>(nChn*3))); + } + } + _CPU_ISR_Restore(level); + return ret; +} + +EXICallback EXI_RegisterEXICallback(s32 nChn,EXICallback exi_cb) +{ + u32 level; + EXICallback old = NULL; + exibus_priv *exi = &eximap[nChn]; + _CPU_ISR_Disable(level); + old = exi->CallbackEXI; + exi->CallbackEXI = exi_cb; + if(nChn==EXI_CHANNEL_2) __exi_setinterrupts(EXI_CHANNEL_0,&eximap[EXI_CHANNEL_0]); + else __exi_setinterrupts(nChn,exi); + _CPU_ISR_Restore(level); + return old; +} + +s32 EXI_Probe(s32 nChn) +{ + s32 ret; + u32 id; + exibus_priv *exi = &eximap[nChn]; + if((ret=__exi_probe(nChn))==1) { + if(exi->exi_idtime==0) { + if(EXI_GetID(nChn,EXI_DEVICE_0,&id)==0) ret = 0; + } + } + return ret; +} + +s32 EXI_ProbeEx(s32 nChn) +{ + if(EXI_Probe(nChn)==1) return 1; + if(last_exi_idtime[nChn]==0) return -1; + return 0; +} + +void EXI_ProbeReset() +{ + last_exi_idtime[0] = 0; + last_exi_idtime[1] = 0; + + eximap[0].exi_idtime = 0; + eximap[1].exi_idtime = 0; + + __exi_probe(0); + __exi_probe(1); + EXI_GetID(EXI_CHANNEL_0,EXI_DEVICE_2,&exi_id_serport1); +} + +void __exi_init() +{ + __MaskIrq(IM_EXI); + + _exiReg[0] = 0; + _exiReg[5] = 0; + _exiReg[10] = 0; + + _exiReg[0] = 0x2000; + + __exi_initmap(eximap); + + IRQ_Request(IRQ_EXI0_EXI,__exi_irq_handler,NULL); + IRQ_Request(IRQ_EXI0_TC,__tc_irq_handler,NULL); + IRQ_Request(IRQ_EXI0_EXT,__ext_irq_handler,NULL); + IRQ_Request(IRQ_EXI1_EXI,__exi_irq_handler,NULL); + IRQ_Request(IRQ_EXI1_TC,__tc_irq_handler,NULL); + IRQ_Request(IRQ_EXI1_EXT,__ext_irq_handler,NULL); + IRQ_Request(IRQ_EXI2_EXI,__exi_irq_handler,NULL); + IRQ_Request(IRQ_EXI2_TC,__tc_irq_handler,NULL); + + EXI_ProbeReset(); +} + +void __exi_irq_handler(u32 nIrq,void *pCtx) +{ + u32 chan,dev; + exibus_priv *exi = NULL; + const u32 fact = 0x55555556; + + chan = ((fact*(nIrq-IRQ_EXI0_EXI))>>1)&0x0f; + dev = _SHIFTR((_exiReg[chan*5]&0x380),8,2); + + exi = &eximap[chan]; + __exi_clearirqs(chan,1,0,0); + + if(!exi->CallbackEXI) return; + exi->CallbackEXI(chan,dev); +} + +void __tc_irq_handler(u32 nIrq,void *pCtx) +{ + u32 cnt,len,d,chan,dev; + EXICallback tccb; + void *buf = NULL; + exibus_priv *exi = NULL; + const u32 fact = 0x55555556; + + chan = ((fact*(nIrq-IRQ_EXI0_TC))>>1)&0x0f; + dev = _SHIFTR((_exiReg[chan*5]&0x380),8,2); + + exi = &eximap[chan]; + __MaskIrq(IRQMASK(nIrq)); + __exi_clearirqs(chan,0,1,0); + + tccb = exi->CallbackTC; + if(!tccb) return; + + exi->CallbackTC = NULL; + if(exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM)) { + if(exi->flags&EXI_FLAG_IMM) { + len = exi->imm_len; + buf = exi->imm_buff; + if(len>0 && buf) { + d = _exiReg[chan*5+4]; + if(d>0) { + for(cnt=0;cnt>((3-cnt)*8))&0xFF; + } + } + } + exi->flags &= ~(EXI_FLAG_DMA|EXI_FLAG_IMM); + } + tccb(chan,dev); +} + +void __ext_irq_handler(u32 nIrq,void *pCtx) +{ + + u32 chan,dev; + exibus_priv *exi = NULL; + const u32 fact = 0x55555556; + + chan = ((fact*(nIrq-IRQ_EXI0_EXT))>>1)&0x0f; + dev = _SHIFTR((_exiReg[chan*5]&0x380),8,2); + + exi = &eximap[chan]; + __MaskIrq(IRQMASK(nIrq)); + __exi_clearirqs(chan,0,0,1); + + exi->flags &= ~EXI_FLAG_ATTACH; + if(exi->CallbackEXT) exi->CallbackEXT(chan,dev); +} + + +/* EXI UART stuff */ +static s32 __probebarnacle(s32 chn,u32 dev,u32 *rev) +{ + u32 ret,reg; + + if(chn!=EXI_CHANNEL_2 && dev==EXI_DEVICE_0) { + if(EXI_Attach(chn,NULL)==0) return 0; + } + + ret = 0; + if(EXI_Lock(chn,dev,NULL)==1) { + if(EXI_Select(chn,dev,EXI_SPEED1MHZ)==1) { + reg = 0x20011300; + if(EXI_Imm(chn,®,sizeof(u32),EXI_WRITE,NULL)==0) ret |= 0x0001; + if(EXI_Sync(chn)==0) ret |= 0x0002; + if(EXI_Imm(chn,rev,sizeof(u32),EXI_READ,NULL)==0) ret |= 0x0004; + if(EXI_Sync(chn)==0) ret |= 0x0008; + if(EXI_Deselect(chn)==0) ret |= 0x0010; + + } + EXI_Unlock(chn); + } + + if(chn!=EXI_CHANNEL_2 && dev==EXI_DEVICE_0) EXI_Detach(chn); + + if(ret) return 0; + if((*rev+0x00010000)==0xffff) return 0; + + return 1; +} + +static s32 __queuelength() +{ + u32 reg; + u8 len = 0; + + if(EXI_Select(exi_uart_chan,exi_uart_dev,EXI_SPEED8MHZ)==0) return -1; + + reg = 0x20010000; + EXI_Imm(exi_uart_chan,®,sizeof(u32),EXI_WRITE,NULL); + EXI_Sync(exi_uart_chan); + EXI_Imm(exi_uart_chan,&len,sizeof(u8),EXI_READ,NULL); + EXI_Sync(exi_uart_chan); + + EXI_Deselect(exi_uart_chan); + + return (16-len); +} + +void __SYS_EnableBarnacle(s32 chn,u32 dev) +{ + u32 id,rev; + + if(EXI_GetID(chn,dev,&id)==0) return; + + if(id==0x01020000 || id==0x0004 || id==0x80000010 || id==0x80000008 + || id==0x80000004 || id==0xffff || id==0x80000020 || id==0x0020 + || id==0x0010 || id==0x0008 || id==0x01010000 || id==0x04040404 + || id==0x04021000 || id==0x03010000 || id==0x02020000 + || id==0x04020300 || id==0x04020200 || id==0x04130000 + || id==0x04120000 || id==0x04060000 || id==0x04220000) return; + + if(__probebarnacle(chn,dev,&rev)==0) return; + + + exi_uart_chan = chn; + exi_uart_dev = dev; + exi_uart_barnacle_enabled = 0xa5ff005a; + exi_uart_enabled = 0xa5ff005a; +} + +s32 InitializeUART() +{ + if((exi_uart_enabled+0x5a010000)==0x005a) return 0; + + exi_uart_chan = EXI_CHANNEL_0; + exi_uart_dev = EXI_DEVICE_1; + + exi_uart_enabled = 0xa5ff005a; + return 0; +} + +s32 WriteUARTN(void *buf,u32 len) +{ + u8 *ptr; + u32 reg; + s32 ret,qlen,cnt; + + if((exi_uart_enabled+0x5a010000)!=0x005a) return 2; + if(EXI_Lock(exi_uart_chan,exi_uart_dev,NULL)==0) return 0; + + ptr = buf; + while((ptr-(u8*)buf)=12 || qlen>=len) { + if(EXI_Select(exi_uart_chan,exi_uart_dev,EXI_SPEED8MHZ)==0) { + ret = 3; + break; + } + + reg = 0xa0010000; + EXI_Imm(exi_uart_chan,®,sizeof(u32),EXI_WRITE,NULL); + EXI_Sync(exi_uart_chan); + + while(qlen>0 && len>0) { + cnt = 4; + if(qlen>=0x0004) { + if(len<4) cnt = len; + if(qlen + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include + +static int __gcsd_init = 0; + +static bool __gcsd_isInserted(int n) +{ + if(sdgecko_readStatus(n) == CARDIO_ERROR_NOCARD) + return false; + return true; +} + +static bool __gcsd_startup(int n) +{ + if(__gcsd_init == 1) + return __gcsd_isInserted(n); + sdgecko_initBufferPool(); + sdgecko_initIODefault(); + __gcsd_init = 1; + return __gcsd_isInserted(n); +} + + +static bool __gcsd_readSectors(int n, u32 sector, u32 numSectors, void *buffer) +{ + s32 ret; + + ret = sdgecko_readSectors(n,sector,numSectors,buffer); + if(ret == CARDIO_ERROR_READY) + return true; + + return false; +} + +static bool __gcsd_writeSectors(int n, u32 sector, u32 numSectors, const void *buffer) +{ + s32 ret; + + ret = sdgecko_writeSectors(n,sector,numSectors,buffer); + if(ret == CARDIO_ERROR_READY) + return true; + + return false; +} + +static bool __gcsd_clearStatus(int n) +{ + return true; // FIXME +} + +static bool __gcsd_shutdown(int n) +{ + sdgecko_doUnmount(n); + return true; +} + + +static bool __gcsda_startup(void) +{ + return __gcsd_startup(0); +} + +static bool __gcsda_isInserted(void) +{ + return __gcsd_isInserted(0); +} + +static bool __gcsda_readSectors(u32 sector, u32 numSectors, void *buffer) +{ + return __gcsd_readSectors(0, sector, numSectors, buffer); +} + +static bool __gcsda_writeSectors(u32 sector, u32 numSectors, void *buffer) +{ + return __gcsd_writeSectors(0, sector, numSectors, buffer); +} + +static bool __gcsda_clearStatus(void) +{ + return __gcsd_clearStatus(0); +} + +static bool __gcsda_shutdown(void) +{ + return __gcsd_shutdown(0); +} + + + +static bool __gcsdb_startup(void) +{ + return __gcsd_startup(1); +} + +static bool __gcsdb_isInserted(void) +{ + return __gcsd_isInserted(1); +} + +static bool __gcsdb_readSectors(u32 sector, u32 numSectors, void *buffer) +{ + return __gcsd_readSectors(1, sector, numSectors, buffer); +} + +static bool __gcsdb_writeSectors(u32 sector, u32 numSectors, void *buffer) +{ + return __gcsd_writeSectors(1, sector, numSectors, buffer); +} + +static bool __gcsdb_clearStatus(void) +{ + return __gcsd_clearStatus(1); +} + +static bool __gcsdb_shutdown(void) +{ + return __gcsd_shutdown(1); +} + +const DISC_INTERFACE __io_gcsda = { + DEVICE_TYPE_GC_SD, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_GAMECUBE_SLOTA, + (FN_MEDIUM_STARTUP)&__gcsda_startup, + (FN_MEDIUM_ISINSERTED)&__gcsda_isInserted, + (FN_MEDIUM_READSECTORS)&__gcsda_readSectors, + (FN_MEDIUM_WRITESECTORS)&__gcsda_writeSectors, + (FN_MEDIUM_CLEARSTATUS)&__gcsda_clearStatus, + (FN_MEDIUM_SHUTDOWN)&__gcsda_shutdown +} ; +const DISC_INTERFACE __io_gcsdb = { + DEVICE_TYPE_GC_SD, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_GAMECUBE_SLOTB, + (FN_MEDIUM_STARTUP)&__gcsdb_startup, + (FN_MEDIUM_ISINSERTED)&__gcsdb_isInserted, + (FN_MEDIUM_READSECTORS)&__gcsdb_readSectors, + (FN_MEDIUM_WRITESECTORS)&__gcsdb_writeSectors, + (FN_MEDIUM_CLEARSTATUS)&__gcsdb_clearStatus, + (FN_MEDIUM_SHUTDOWN)&__gcsdb_shutdown +} ; diff --git a/wii/libogc/libogc/gu.c b/wii/libogc/libogc/gu.c new file mode 100644 index 0000000000..8ee3e3052e --- /dev/null +++ b/wii/libogc/libogc/gu.c @@ -0,0 +1,916 @@ +#include +#include + +extern void __ps_guMtxRotAxisRadInternal(register Mtx mt,const register guVector *axis,register f32 sT,register f32 cT); + +void guFrustum(Mtx44 mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 f) +{ + f32 tmp; + + tmp = 1.0f/(r-l); + mt[0][0] = (2*n)*tmp; + mt[0][1] = 0.0f; + mt[0][2] = (r+l)*tmp; + mt[0][3] = 0.0f; + + tmp = 1.0f/(t-b); + mt[1][0] = 0.0f; + mt[1][1] = (2*n)*tmp; + mt[1][2] = (t+b)*tmp; + mt[1][3] = 0.0f; + + tmp = 1.0f/(f-n); + mt[2][0] = 0.0f; + mt[2][1] = 0.0f; + mt[2][2] = -(n)*tmp; + mt[2][3] = -(f*n)*tmp; + + mt[3][0] = 0.0f; + mt[3][1] = 0.0f; + mt[3][2] = -1.0f; + mt[3][3] = 0.0f; +} + +void guPerspective(Mtx44 mt,f32 fovy,f32 aspect,f32 n,f32 f) +{ + f32 cot,angle,tmp; + + angle = fovy*0.5f; + angle = DegToRad(angle); + + cot = 1.0f/tanf(angle); + + mt[0][0] = cot/aspect; + mt[0][1] = 0.0f; + mt[0][2] = 0.0f; + mt[0][3] = 0.0f; + + mt[1][0] = 0.0f; + mt[1][1] = cot; + mt[1][2] = 0.0f; + mt[1][3] = 0.0f; + + tmp = 1.0f/(f-n); + mt[2][0] = 0.0f; + mt[2][1] = 0.0f; + mt[2][2] = -(n)*tmp; + mt[2][3] = -(f*n)*tmp; + + mt[3][0] = 0.0f; + mt[3][1] = 0.0f; + mt[3][2] = -1.0f; + mt[3][3] = 0.0f; +} + +void guOrtho(Mtx44 mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 f) +{ + f32 tmp; + + tmp = 1.0f/(r-l); + mt[0][0] = 2.0f*tmp; + mt[0][1] = 0.0f; + mt[0][2] = 0.0f; + mt[0][3] = -(r+l)*tmp; + + tmp = 1.0f/(t-b); + mt[1][0] = 0.0f; + mt[1][1] = 2.0f*tmp; + mt[1][2] = 0.0f; + mt[1][3] = -(t+b)*tmp; + + tmp = 1.0f/(f-n); + mt[2][0] = 0.0f; + mt[2][1] = 0.0f; + mt[2][2] = -(1.0f)*tmp; + mt[2][3] = -(f)*tmp; + + mt[3][0] = 0.0f; + mt[3][1] = 0.0f; + mt[3][2] = 0.0f; + mt[3][3] = 1.0f; +} + +void guLightPerspective(Mtx mt,f32 fovY,f32 aspect,f32 scaleS,f32 scaleT,f32 transS,f32 transT) +{ + f32 angle; + f32 cot; + + angle = fovY*0.5f; + angle = DegToRad(angle); + + cot = 1.0f/tanf(angle); + + mt[0][0] = (cot / aspect) * scaleS; + mt[0][1] = 0.0f; + mt[0][2] = -transS; + mt[0][3] = 0.0f; + + mt[1][0] = 0.0f; + mt[1][1] = cot * scaleT; + mt[1][2] = -transT; + mt[1][3] = 0.0f; + + mt[2][0] = 0.0f; + mt[2][1] = 0.0f; + mt[2][2] = -1.0f; + mt[2][3] = 0.0f; +} + +void guLightOrtho(Mtx mt,f32 t,f32 b,f32 l,f32 r,f32 scaleS,f32 scaleT,f32 transS,f32 transT) +{ + f32 tmp; + + tmp = 1.0f / (r - l); + mt[0][0] = (2.0f * tmp * scaleS); + mt[0][1] = 0.0f; + mt[0][2] = 0.0f; + mt[0][3] = ((-(r + l) * tmp) * scaleS) + transS; + + tmp = 1.0f / (t - b); + mt[1][0] = 0.0f; + mt[1][1] = (2.0f * tmp) * scaleT; + mt[1][2] = 0.0f; + mt[1][3] = ((-(t + b) * tmp)* scaleT) + transT; + + mt[2][0] = 0.0f; + mt[2][1] = 0.0f; + mt[2][2] = 0.0f; + mt[2][3] = 1.0f; +} + +void guLightFrustum(Mtx mt,f32 t,f32 b,f32 l,f32 r,f32 n,f32 scaleS,f32 scaleT,f32 transS,f32 transT) +{ + f32 tmp; + + tmp = 1.0f / (r - l); + mt[0][0] = ((2*n) * tmp) * scaleS; + mt[0][1] = 0.0f; + mt[0][2] = (((r + l) * tmp) * scaleS) - transS; + mt[0][3] = 0.0f; + + tmp = 1.0f / (t - b); + mt[1][0] = 0.0f; + mt[1][1] = ((2*n) * tmp) * scaleT; + mt[1][2] = (((t + b) * tmp) * scaleT) - transT; + mt[1][3] = 0.0f; + + mt[2][0] = 0.0f; + mt[2][1] = 0.0f; + mt[2][2] = -1.0f; + mt[2][3] = 0.0f; +} + +void guLookAt(Mtx mt,guVector *camPos,guVector *camUp,guVector *target) +{ + guVector vLook,vRight,vUp; + + vLook.x = camPos->x - target->x; + vLook.y = camPos->y - target->y; + vLook.z = camPos->z - target->z; + guVecNormalize(&vLook); + + guVecCross(camUp,&vLook,&vRight); + guVecNormalize(&vRight); + + guVecCross(&vLook,&vRight,&vUp); + + mt[0][0] = vRight.x; + mt[0][1] = vRight.y; + mt[0][2] = vRight.z; + mt[0][3] = -( camPos->x * vRight.x + camPos->y * vRight.y + camPos->z * vRight.z ); + + mt[1][0] = vUp.x; + mt[1][1] = vUp.y; + mt[1][2] = vUp.z; + mt[1][3] = -( camPos->x * vUp.x + camPos->y * vUp.y + camPos->z * vUp.z ); + + mt[2][0] = vLook.x; + mt[2][1] = vLook.y; + mt[2][2] = vLook.z; + mt[2][3] = -( camPos->x * vLook.x + camPos->y * vLook.y + camPos->z * vLook.z ); +} + +void c_guMtxIdentity(Mtx mt) +{ + s32 i,j; + + for(i=0;i<3;i++) { + for(j=0;j<4;j++) { + if(i==j) mt[i][j] = 1.0; + else mt[i][j] = 0.0; + } + } +} + +void c_guMtxRotRad(Mtx mt,const char axis,f32 rad) +{ + f32 sinA,cosA; + + sinA = sinf(rad); + cosA = cosf(rad); + + c_guMtxRotTrig(mt,axis,sinA,cosA); +} + +#ifdef GEKKO +void ps_guMtxRotRad(register Mtx mt,const register char axis,register f32 rad) +{ + register f32 sinA = sinf(rad); + register f32 cosA = cosf(rad); + + ps_guMtxRotTrig(mt,axis,sinA,cosA); +} + +void ps_guMtxRotAxisRad(Mtx mt,guVector *axis,f32 rad) +{ + f32 sinT = sinf(rad); + f32 cosT = cosf(rad); + + __ps_guMtxRotAxisRadInternal(mt,axis,sinT,cosT); +} + +#endif + +void c_guMtxRotTrig(Mtx mt,const char axis,f32 sinA,f32 cosA) +{ + switch(axis) { + case 'x': + case 'X': + mt[0][0] = 1.0f; mt[0][1] = 0.0f; mt[0][2] = 0.0f; mt[0][3] = 0.0f; + mt[1][0] = 0.0f; mt[1][1] = cosA; mt[1][2] = -sinA; mt[1][3] = 0.0f; + mt[2][0] = 0.0f; mt[2][1] = sinA; mt[2][2] = cosA; mt[2][3] = 0.0f; + break; + case 'y': + case 'Y': + mt[0][0] = cosA; mt[0][1] = 0.0f; mt[0][2] = sinA; mt[0][3] = 0.0f; + mt[1][0] = 0.0f; mt[1][1] = 1.0f; mt[1][2] = 0.0f; mt[1][3] = 0.0f; + mt[2][0] = -sinA; mt[2][1] = 0.0f; mt[2][2] = cosA; mt[2][3] = 0.0f; + break; + case 'z': + case 'Z': + mt[0][0] = cosA; mt[0][1] = -sinA; mt[0][2] = 0.0f; mt[0][3] = 0.0f; + mt[1][0] = sinA; mt[1][1] = cosA; mt[1][2] = 0.0f; mt[1][3] = 0.0f; + mt[2][0] = 0.0f; mt[2][1] = 0.0f; mt[2][2] = 1.0f; mt[2][3] = 0.0f; + break; + default: + break; + } +} + +void c_guMtxRotAxisRad(Mtx mt,guVector *axis,f32 rad) +{ + f32 s,c; + f32 t; + f32 x,y,z; + f32 xSq,ySq,zSq; + + s = sinf(rad); + c = cosf(rad); + t = 1.0f-c; + + c_guVecNormalize(axis); + + x = axis->x; + y = axis->y; + z = axis->z; + + xSq = x*x; + ySq = y*y; + zSq = z*z; + + mt[0][0] = ( t * xSq ) + ( c ); + mt[0][1] = ( t * x * y ) - ( s * z ); + mt[0][2] = ( t * x * z ) + ( s * y ); + mt[0][3] = 0.0f; + + mt[1][0] = ( t * x * y ) + ( s * z ); + mt[1][1] = ( t * ySq ) + ( c ); + mt[1][2] = ( t * y * z ) - ( s * x ); + mt[1][3] = 0.0f; + + mt[2][0] = ( t * x * z ) - ( s * y ); + mt[2][1] = ( t * y * z ) + ( s * x ); + mt[2][2] = ( t * zSq ) + ( c ); + mt[2][3] = 0.0f; + +} + +void c_guMtxCopy(Mtx src,Mtx dst) +{ + if(src==dst) return; + + dst[0][0] = src[0][0]; dst[0][1] = src[0][1]; dst[0][2] = src[0][2]; dst[0][3] = src[0][3]; + dst[1][0] = src[1][0]; dst[1][1] = src[1][1]; dst[1][2] = src[1][2]; dst[1][3] = src[1][3]; + dst[2][0] = src[2][0]; dst[2][1] = src[2][1]; dst[2][2] = src[2][2]; dst[2][3] = src[2][3]; +} + +void c_guMtxConcat(Mtx a,Mtx b,Mtx ab) +{ + Mtx tmp; + MtxP m; + + if(ab==b || ab==a) + m = tmp; + else + m = ab; + + m[0][0] = a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0]; + m[0][1] = a[0][0]*b[0][1] + a[0][1]*b[1][1] + a[0][2]*b[2][1]; + m[0][2] = a[0][0]*b[0][2] + a[0][1]*b[1][2] + a[0][2]*b[2][2]; + m[0][3] = a[0][0]*b[0][3] + a[0][1]*b[1][3] + a[0][2]*b[2][3] + a[0][3]; + + m[1][0] = a[1][0]*b[0][0] + a[1][1]*b[1][0] + a[1][2]*b[2][0]; + m[1][1] = a[1][0]*b[0][1] + a[1][1]*b[1][1] + a[1][2]*b[2][1]; + m[1][2] = a[1][0]*b[0][2] + a[1][1]*b[1][2] + a[1][2]*b[2][2]; + m[1][3] = a[1][0]*b[0][3] + a[1][1]*b[1][3] + a[1][2]*b[2][3] + a[1][3]; + + m[2][0] = a[2][0]*b[0][0] + a[2][1]*b[1][0] + a[2][2]*b[2][0]; + m[2][1] = a[2][0]*b[0][1] + a[2][1]*b[1][1] + a[2][2]*b[2][1]; + m[2][2] = a[2][0]*b[0][2] + a[2][1]*b[1][2] + a[2][2]*b[2][2]; + m[2][3] = a[2][0]*b[0][3] + a[2][1]*b[1][3] + a[2][2]*b[2][3] + a[2][3]; + + if(m==tmp) + c_guMtxCopy(tmp,ab); +} + +void c_guMtxScale(Mtx mt,f32 xS,f32 yS,f32 zS) +{ + mt[0][0] = xS; mt[0][1] = 0.0f; mt[0][2] = 0.0f; mt[0][3] = 0.0f; + mt[1][0] = 0.0f; mt[1][1] = yS; mt[1][2] = 0.0f; mt[1][3] = 0.0f; + mt[2][0] = 0.0f; mt[2][1] = 0.0f; mt[2][2] = zS; mt[2][3] = 0.0f; +} + +void c_guMtxScaleApply(Mtx src,Mtx dst,f32 xS,f32 yS,f32 zS) +{ + dst[0][0] = src[0][0] * xS; dst[0][1] = src[0][1] * xS; + dst[0][2] = src[0][2] * xS; dst[0][3] = src[0][3] * xS; + + dst[1][0] = src[1][0] * yS; dst[1][1] = src[1][1] * yS; + dst[1][2] = src[1][2] * yS; dst[1][3] = src[1][3] * yS; + + dst[2][0] = src[2][0] * zS; dst[2][1] = src[2][1] * zS; + dst[2][2] = src[2][2] * zS; dst[2][3] = src[2][3] * zS; +} + +void c_guMtxApplyScale(Mtx src,Mtx dst,f32 xS,f32 yS,f32 zS) +{ + dst[0][0] = src[0][0] * xS; dst[0][1] = src[0][1] * yS; + dst[0][2] = src[0][2] * zS; dst[0][3] = src[0][3]; + + dst[1][0] = src[1][0] * xS; dst[1][1] = src[1][1] * yS; + dst[1][2] = src[1][2] * zS; dst[1][3] = src[1][3]; + + dst[2][0] = src[2][0] * xS; dst[2][1] = src[2][1] * yS; + dst[2][2] = src[2][2] * zS; dst[2][3] = src[2][3]; +} + +void c_guMtxTrans(Mtx mt,f32 xT,f32 yT,f32 zT) +{ + mt[0][0] = 1.0f; mt[0][1] = 0.0f; mt[0][2] = 0.0f; mt[0][3] = xT; + mt[1][0] = 0.0f; mt[1][1] = 1.0f; mt[1][2] = 0.0f; mt[1][3] = yT; + mt[2][0] = 0.0f; mt[2][1] = 0.0f; mt[2][2] = 1.0f; mt[2][3] = zT; +} + +void c_guMtxTransApply(Mtx src,Mtx dst,f32 xT,f32 yT,f32 zT) +{ + if ( src != dst ) + { + dst[0][0] = src[0][0]; dst[0][1] = src[0][1]; dst[0][2] = src[0][2]; + dst[1][0] = src[1][0]; dst[1][1] = src[1][1]; dst[1][2] = src[1][2]; + dst[2][0] = src[2][0]; dst[2][1] = src[2][1]; dst[2][2] = src[2][2]; + } + + dst[0][3] = src[0][3] + xT; + dst[1][3] = src[1][3] + yT; + dst[2][3] = src[2][3] + zT; +} + +void c_guMtxApplyTrans(Mtx src,Mtx dst,f32 xT,f32 yT,f32 zT) +{ + if ( src != dst ) + { + dst[0][0] = src[0][0]; dst[0][1] = src[0][1]; dst[0][2] = src[0][2]; + dst[1][0] = src[1][0]; dst[1][1] = src[1][1]; dst[1][2] = src[1][2]; + dst[2][0] = src[2][0]; dst[2][1] = src[2][1]; dst[2][2] = src[2][2]; + } + + dst[0][3] = src[0][0]*xT + src[0][1]*yT + src[0][2]*zT + src[0][3]; + dst[1][3] = src[1][0]*xT + src[1][1]*yT + src[1][2]*zT + src[1][3]; + dst[2][3] = src[2][0]*xT + src[2][1]*yT + src[2][2]*zT + src[2][3]; +} + +u32 c_guMtxInverse(Mtx src,Mtx inv) +{ + Mtx mTmp; + MtxP m; + f32 det; + + if(src==inv) + m = mTmp; + else + m = inv; + + + // compute the determinant of the upper 3x3 submatrix + det = src[0][0]*src[1][1]*src[2][2] + src[0][1]*src[1][2]*src[2][0] + src[0][2]*src[1][0]*src[2][1] + - src[2][0]*src[1][1]*src[0][2] - src[1][0]*src[0][1]*src[2][2] - src[0][0]*src[2][1]*src[1][2]; + + + // check if matrix is singular + if(det==0.0f)return 0; + + + // compute the inverse of the upper submatrix: + + // find the transposed matrix of cofactors of the upper submatrix + // and multiply by (1/det) + + det = 1.0f / det; + + + m[0][0] = (src[1][1]*src[2][2] - src[2][1]*src[1][2]) * det; + m[0][1] = -(src[0][1]*src[2][2] - src[2][1]*src[0][2]) * det; + m[0][2] = (src[0][1]*src[1][2] - src[1][1]*src[0][2]) * det; + + m[1][0] = -(src[1][0]*src[2][2] - src[2][0]*src[1][2]) * det; + m[1][1] = (src[0][0]*src[2][2] - src[2][0]*src[0][2]) * det; + m[1][2] = -(src[0][0]*src[1][2] - src[1][0]*src[0][2]) * det; + + m[2][0] = (src[1][0]*src[2][1] - src[2][0]*src[1][1]) * det; + m[2][1] = -(src[0][0]*src[2][1] - src[2][0]*src[0][1]) * det; + m[2][2] = (src[0][0]*src[1][1] - src[1][0]*src[0][1]) * det; + + + // compute (invA)*(-C) + m[0][3] = -m[0][0]*src[0][3] - m[0][1]*src[1][3] - m[0][2]*src[2][3]; + m[1][3] = -m[1][0]*src[0][3] - m[1][1]*src[1][3] - m[1][2]*src[2][3]; + m[2][3] = -m[2][0]*src[0][3] - m[2][1]*src[1][3] - m[2][2]*src[2][3]; + + // copy back if needed + if( m == mTmp ) + c_guMtxCopy(mTmp,inv); + + return 1; +} + +void c_guMtxTranspose(Mtx src,Mtx xPose) +{ + Mtx mTmp; + MtxP m; + + if(src==xPose) + m = mTmp; + else + m = xPose; + + + m[0][0] = src[0][0]; m[0][1] = src[1][0]; m[0][2] = src[2][0]; m[0][3] = 0.0f; + m[1][0] = src[0][1]; m[1][1] = src[1][1]; m[1][2] = src[2][1]; m[1][3] = 0.0f; + m[2][0] = src[0][2]; m[2][1] = src[1][2]; m[2][2] = src[2][2]; m[2][3] = 0.0f; + + + // copy back if needed + if(m==mTmp) + c_guMtxCopy(mTmp,xPose); +} + +u32 c_guMtxInvXpose(Mtx src, Mtx xPose) +{ + Mtx mTmp; + MtxP m; + f32 det; + + if(src == xPose) + m = mTmp; + else + m = xPose; + + // Compute the determinant of the upper 3x3 submatrix + det = src[0][0]*src[1][1]*src[2][2] + src[0][1]*src[1][2]*src[2][0] + src[0][2]*src[1][0]*src[2][1] + - src[2][0]*src[1][1]*src[0][2] - src[1][0]*src[0][1]*src[2][2] - src[0][0]*src[2][1]*src[1][2]; + + // Check if matrix is singular + if(det == 0.0f) return 0; + + // Compute the inverse of the upper submatrix: + + // Find the transposed matrix of cofactors of the upper submatrix + // and multiply by (1/det) + + det = 1.0f / det; + + m[0][0] = (src[1][1]*src[2][2] - src[2][1]*src[1][2]) * det; + m[0][1] = -(src[1][0]*src[2][2] - src[2][0]*src[1][2]) * det; + m[0][2] = (src[1][0]*src[2][1] - src[2][0]*src[1][1]) * det; + + m[1][0] = -(src[0][1]*src[2][2] - src[2][1]*src[0][2]) * det; + m[1][1] = (src[0][0]*src[2][2] - src[2][0]*src[0][2]) * det; + m[1][2] = -(src[0][0]*src[2][1] - src[2][0]*src[0][1]) * det; + + m[2][0] = (src[0][1]*src[1][2] - src[1][1]*src[0][2]) * det; + m[2][1] = -(src[0][0]*src[1][2] - src[1][0]*src[0][2]) * det; + m[2][2] = (src[0][0]*src[1][1] - src[1][0]*src[0][1]) * det; + + + // The 4th columns should be zero + m[0][3] = 0.0F; + m[1][3] = 0.0F; + m[2][3] = 0.0F; + + // Copy back if needed + if(m == mTmp) + c_guMtxCopy(mTmp, xPose); + + return 1; +} + +void c_guMtxReflect(Mtx m,guVector *p,guVector *n) +{ + f32 vxy, vxz, vyz, pdotn; + + vxy = -2.0f * n->x * n->y; + vxz = -2.0f * n->x * n->z; + vyz = -2.0f * n->y * n->z; + pdotn = 2.0f * c_guVecDotProduct(p,n); + + m[0][0] = 1.0f - 2.0f * n->x * n->x; + m[0][1] = vxy; + m[0][2] = vxz; + m[0][3] = pdotn * n->x; + + m[1][0] = vxy; + m[1][1] = 1.0f - 2.0f * n->y * n->y; + m[1][2] = vyz; + m[1][3] = pdotn * n->y; + + m[2][0] = vxz; + m[2][1] = vyz; + m[2][2] = 1.0f - 2.0f * n->z * n->z; + m[2][3] = pdotn * n->z; +} + + +void c_guVecAdd(guVector *a,guVector *b,guVector *ab) +{ + ab->x = a->x + b->x; + ab->y = a->y + b->y; + ab->z = a->z + b->z; +} + +void c_guVecSub(guVector *a,guVector *b,guVector *ab) +{ + ab->x = a->x - b->x; + ab->y = a->y - b->y; + ab->z = a->z - b->z; +} + +void c_guVecScale(guVector *src,guVector *dst,f32 scale) +{ + dst->x = src->x * scale; + dst->y = src->y * scale; + dst->z = src->z * scale; +} + + +void c_guVecNormalize(guVector *v) +{ + f32 m; + + m = ((v->x)*(v->x)) + ((v->y)*(v->y)) + ((v->z)*(v->z)); + m = 1/sqrtf(m); + v->x *= m; + v->y *= m; + v->z *= m; +} + +void c_guVecCross(guVector *a,guVector *b,guVector *axb) +{ + guVector vTmp; + + vTmp.x = (a->y*b->z)-(a->z*b->y); + vTmp.y = (a->z*b->x)-(a->x*b->z); + vTmp.z = (a->x*b->y)-(a->y*b->x); + + axb->x = vTmp.x; + axb->y = vTmp.y; + axb->z = vTmp.z; +} + +void c_guVecMultiply(Mtx mt,guVector *src,guVector *dst) +{ + guVector tmp; + + tmp.x = mt[0][0]*src->x + mt[0][1]*src->y + mt[0][2]*src->z + mt[0][3]; + tmp.y = mt[1][0]*src->x + mt[1][1]*src->y + mt[1][2]*src->z + mt[1][3]; + tmp.z = mt[2][0]*src->x + mt[2][1]*src->y + mt[2][2]*src->z + mt[2][3]; + + dst->x = tmp.x; + dst->y = tmp.y; + dst->z = tmp.z; +} + +void c_guVecMultiplySR(Mtx mt,guVector *src,guVector *dst) +{ + guVector tmp; + + tmp.x = mt[0][0]*src->x + mt[0][1]*src->y + mt[0][2]*src->z; + tmp.y = mt[1][0]*src->x + mt[1][1]*src->y + mt[1][2]*src->z; + tmp.z = mt[2][0]*src->x + mt[2][1]*src->y + mt[2][2]*src->z; + + // copy back + dst->x = tmp.x; + dst->y = tmp.y; + dst->z = tmp.z; +} + +f32 c_guVecDotProduct(guVector *a,guVector *b) +{ + f32 dot; + + dot = (a->x * b->x) + (a->y * b->y) + (a->z * b->z); + + return dot; +} + +void c_guQuatAdd(guQuaternion *a,guQuaternion *b,guQuaternion *ab) +{ + ab->x = a->x + b->x; + ab->y = a->x + b->y; + ab->z = a->x + b->z; + ab->w = a->x + b->w; +} + +#ifdef GEKKO +void ps_guQuatAdd(register guQuaternion *a,register guQuaternion *b,register guQuaternion *ab) +{ + register f32 tmp0,tmp1; + + __asm__ __volatile__ ( + "psq_l %0,0(%2),0,0\n" // [ax][ay] + "psq_l %1,0(%3),0,0\n" // [bx][by] + "ps_add %1,%0,%1\n" // [ax+bx][ay+by] + "psq_st %1,0(%4),0,0\n" // X = [ax+bx], Y = [ay+by] + "psq_l %0,8(%2),0,0\n" // [az][aw] + "psq_l %1,8(%3),0,0\n" // [bz][bw] + "ps_add %1,%0,%1\n" // [az+bz][aw+bw] + "psq_st %1,8(%4),0,0" // Z = [az+bz], W = [aw+bw] + : "=&f"(tmp0),"=&f"(tmp1) + : "b"(a),"b"(b),"b"(ab) + : "memory" + ); +} +#endif + +void c_guQuatSub(guQuaternion *a,guQuaternion *b,guQuaternion *ab) +{ + ab->x = a->x - b->x; + ab->y = a->x - b->y; + ab->z = a->x - b->z; + ab->w = a->x - b->w; +} + +#ifdef GEKKO +void ps_guQuatSub(register guQuaternion *a,register guQuaternion *b,register guQuaternion *ab) +{ + register f32 tmp0,tmp1; + + __asm__ __volatile__ ( + "psq_l %0,0(%2),0,0\n" // [ax][ay] + "psq_l %1,0(%3),0,0\n" // [bx][by] + "ps_sub %1,%0,%1\n" // [ax-bx][ay-by] + "psq_st %1,0(%4),0,0\n" // X = [ax-bx], Y = [ay-by] + "psq_l %0,8(%2),0,0\n" // [az][aw] + "psq_l %1,8(%3),0,0\n" // [bz][bw] + "ps_sub %1,%0,%1\n" // [az-bz][aw-bw] + "psq_st %1,8(%4),0,0" // Z = [az-bz], W = [aw-bw] + : "=&f"(tmp0),"=&f"(tmp1) + : "b"(a),"b"(b),"b"(ab) + : "memory" + ); +} +#endif + +void c_guQuatMultiply(guQuaternion *a,guQuaternion *b,guQuaternion *ab) +{ + guQuaternion *r; + guQuaternion ab_tmp; + + if(a==ab || b==ab) r = &ab_tmp; + else r = ab; + + r->w = a->w*b->w - a->x*b->x - a->y*b->y - a->z*b->z; + r->x = a->w*b->x + a->x*b->w + a->y*b->z - a->z*b->y; + r->y = a->w*b->y + a->y*b->w + a->z*b->x - a->x*b->z; + r->z = a->w*b->z + a->z*b->w + a->x*b->y - a->y*b->x; + + if(r==&ab_tmp) *ab = ab_tmp; +} + +#ifdef GEKKO +void ps_guQuatMultiply(register guQuaternion *a,register guQuaternion *b,register guQuaternion *ab) +{ + register f32 aXY,aZW,bXY,bZW; + register f32 tmp0,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7; + + __asm__ __volatile__ ( + "psq_l %0,0(%12),0,0\n" // [px][py] + "psq_l %1,8(%12),0,0\n" // [pz][pw] + "psq_l %2,0(%13),0,0\n" // [qx][qy] + "ps_neg %4,%0\n" // [-px][-py] + "psq_l %3,8(%13),0,0\n" // [qz][qw] + "ps_neg %5,%1\n" // [-pz][-pw] + "ps_merge01 %6,%4,%0\n" // [-px][py] + "ps_muls0 %8,%1,%2\n" // [pz*qx][pw*qx] + "ps_muls0 %9,%4,%2\n" // [-px*qx][-py*qx] + "ps_merge01 %7,%5,%1\n" // [-pz][pw] + "ps_muls1 %11,%6,%2\n" // [-px*qy][py*qy] + "ps_madds0 %8,%6,%3,%8\n" // [-px*qz+pz*qx][py*qz+pw*qx] + "ps_muls1 %10,%7,%2\n" // [-pz*qy][pw*qy] + "ps_madds0 %9,%7,%3,%9\n" // [-pz*qz+-px*qx][pw*qz+-py*qx] + "ps_madds1 %11,%5,%3,%11\n" // [-pz*qw+-px*qy][-pw*qw+py*qy] + "ps_merge10 %8,%8,%8\n" // [py*qz+pw*qx][-px*qz+pz*qx] + "ps_madds1 %10,%0,%3,%10\n" // [px*qw+-pz*qy][py*qw+pw*qy] + "ps_merge10 %9,%9,%9\n" // [pw*qz+-py*qx][-pz*qz+-px*qx] + "ps_add %8,%8,%10\n" // [py*qz+pw*qx+px*qw+-pz*qy][-px*qz+pz*qx+py*qw+pw*qy] + "psq_st %8,0(%14),0,0\n" // X = [py*qz+pw*qx+px*qw+-pz*qy], Y = [-px*qz+pz*qx+py*qw+pw*qy] + "ps_sub %9,%9,%11\n" // [pw*qz+-py*qx--pz*qw+-px*qy][-pz*qz+-px*qx--pw*qw+py*qy] + "psq_st %9,8(%14),0,0" // Z = [pw*qz+-py*qx--pz*qw+-px*qy], W = [-pz*qz+-px*qx--pw*qw+py*qy] + : "=&f"(aXY),"=&f"(aZW),"=&f"(bXY),"=&f"(bZW),"=&f"(tmp0),"=&f"(tmp1),"=&f"(tmp2),"=&f"(tmp3),"=&f"(tmp4),"=&f"(tmp5),"=&f"(tmp6),"=&f"(tmp7) + : "b"(a),"b"(b),"b"(ab) + : "memory" + ); +} +#endif + +void c_guQuatNormalize(guQuaternion *a,guQuaternion *d) +{ + f32 dot,scale; + + dot = (a->x*a->x) + (a->y*a->y) + (a->z*a->z) + (a->w*a->w); + if(dot==0.0f) d->x = d->y = d->z = d->w = 0.0f; + else { + scale = 1.0f/sqrtf(dot); + d->x = a->x*scale; + d->y = a->y*scale; + d->z = a->z*scale; + d->w = a->w*scale; + } +} + +#ifdef GEKKO +void ps_guQuatNormalize(register guQuaternion *a,register guQuaternion *d) +{ + register f32 c_zero = 0.0f; + register f32 c_half = 0.5f; + register f32 c_three = 3.0f; + register f32 axy,azw,tmp0,tmp1,tmp2,tmp3; + + __asm__ __volatile__ ( + "psq_l %0,0(%6),0,0\n" // [ax][ay] + "ps_mul %2,%0,%0\n" // [ax*ax][ay*ay] + "psq_l %1,8(%6),0,0\n" // [az][aw] + "ps_madd %2,%1,%1,%2\n" // [az*az+ax*ax][aw*aw+ay*ay] + "ps_sum0 %2,%2,%2,%2\n" // [az*az+ax*ax+aw*aw+ay*ay][aw*aw+ay*ay] + "frsqrte %3,%2\n" // reciprocal sqrt estimated + //Newton-Raphson refinement 1 step: (E/2)*(3 - x*E*E) + "fmul %4,%3,%3\n" // E*E + "fmul %5,%3,%8\n" // E*0.5 = E/2 + "fnmsub %4,%4,%2,%9\n" // -(E*E*x - 3) = (3 - x*E*E) + "fmul %3,%4,%5\n" // (E/2)*(3 - x*E*E) + "ps_sel %3,%2,%3,%10\n" // NaN check: if(mag==0.0f) + "ps_muls0 %0,%0,%3\n" // [ax*rsqmag][ay*rsqmag] + "ps_muls0 %1,%1,%3\n" // [az*rsqmag][aw*rsqmag] + "psq_st %0,0(%7),0,0\n" // X = [az*rsqmag], Y = [aw*rsqmag] + "psq_st %1,8(%7),0,0\n" // Z = [az*rsqmag], W = [aw*rsqmag] + : "=&f"(axy),"=&f"(azw),"=&f"(tmp0),"=&f"(tmp1),"=&f"(tmp2),"=&f"(tmp3) + : "b"(a),"b"(d),"f"(c_half),"f"(c_three),"f"(c_zero) + : "memory" + ); +} +#endif + +void c_guQuatInverse(guQuaternion *a,guQuaternion *d) +{ + f32 mag,nrminv; + + mag = (a->x*a->x) + (a->y*a->y) + (a->z*a->z) + (a->w*a->w); + if(mag==0.0f) mag = 1.0f; + + nrminv = 1.0f/mag; + d->x = -a->x*nrminv; + d->y = -a->y*nrminv; + d->z = -a->z*nrminv; + d->w = a->w*nrminv; +} + +#ifdef GEKKO +void ps_guQuatInverse(register guQuaternion *a,register guQuaternion *d) +{ + register f32 c_one = 1.0f; + register f32 axy,azw,tmp0,tmp1,tmp2,tmp3,tmp4,tmp5; + + __asm__ __volatile__ ( + "psq_l %0,0(%8),0,0\n" // [ax][ay] + "ps_mul %2,%0,%0\n" // [ax*ax][ay*ay] + "ps_sub %3,%10,%10\n" // [1 - 1][1 - 1] + "psq_l %1,8(%8),0,0\n" // [az][aw] + "ps_madd %2,%1,%1,%2\n" // [az*az+ax*ax][aw*aw+ay*ay] + "ps_add %7,%0,%10\n" // [1 + 1][1 + 1] + "ps_sum0 %2,%2,%2,%2\n" // [az*az+ax*ax+aw*aw+ay*ay][aw*aw+ay*ay] + "fcmpu cr0,%2,%3\n" // [az*az+ax*ax+aw*aw+ay*ay] == 0.0f + "beq- 1f\n" + "fres %4,%2\n" // 1.0f/mag + "ps_neg %5,%2\n" // -mag + // Newton-Rapson refinement (x1) : E' = 2E-X*E*E + "ps_nmsub %6,%2,%4,%7\n" // + "ps_mul %4,%4,%6\n" // + "b 2f\n" + "1:\n" + "fmr %4,%10\n" + "2:\n" + "ps_neg %7,%4\n" + "ps_muls1 %5,%4,%1\n" + "ps_muls0 %0,%0,%7\n" + "psq_st %5,12(%9),1,0\n" + "ps_muls0 %6,%1,%7\n" + "psq_st %0,0(%9),0,0\n" + "psq_st %6,8(%9),1,0\n" + : "=&f"(axy),"=&f"(azw),"=&f"(tmp0),"=&f"(tmp1),"=&f"(tmp2),"=&f"(tmp3),"=&f"(tmp4),"=&f"(tmp5) + : "b"(a),"b"(d),"f"(c_one) + ); +} +#endif + +void c_guQuatMtx(guQuaternion *a,Mtx m) +{ + const f32 diag = guMtxRowCol(m,0,0) + guMtxRowCol(m,1,1) + guMtxRowCol(m,2,2) + 1; + + if(diag>0.0f) { + const f32 scale = sqrtf(diag)*2.0f; + + a->x = (guMtxRowCol(m,2,1) - guMtxRowCol(m,1,2))/scale; + a->y = (guMtxRowCol(m,0,2) - guMtxRowCol(m,2,0))/scale; + a->z = (guMtxRowCol(m,1,0) - guMtxRowCol(m,0,1))/scale; + a->w = 0.25f*scale; + } else { + if(guMtxRowCol(m,0,0)>guMtxRowCol(m,1,1) && guMtxRowCol(m,0,0)>guMtxRowCol(m,2,2)) { + const f32 scale = sqrtf(1.0f + guMtxRowCol(m,0,0) + guMtxRowCol(m,1,1) + guMtxRowCol(m,2,2))*2.0f; + + a->x = 0.25f*scale; + a->y = (guMtxRowCol(m,0,1) + guMtxRowCol(m,1,0))/scale; + a->z = (guMtxRowCol(m,2,0) + guMtxRowCol(m,0,2))/scale; + a->w = (guMtxRowCol(m,2,1) - guMtxRowCol(m,1,2))/scale; + } else if(guMtxRowCol(m,1,1)>guMtxRowCol(m,2,2)) { + const f32 scale = sqrtf(1.0f + guMtxRowCol(m,0,0) + guMtxRowCol(m,1,1) + guMtxRowCol(m,2,2))*2.0f; + + a->x = (guMtxRowCol(m,0,1) + guMtxRowCol(m,1,0))/scale; + a->y = 0.25f*scale; + a->z = (guMtxRowCol(m,1,2) + guMtxRowCol(m,2,1))/scale; + a->w = (guMtxRowCol(m,0,2) - guMtxRowCol(m,2,0))/scale; + } else { + const f32 scale = sqrtf(1.0f + guMtxRowCol(m,0,0) + guMtxRowCol(m,1,1) + guMtxRowCol(m,2,2))*2.0f; + + a->x = (guMtxRowCol(m,0,2) + guMtxRowCol(m,2,0))/scale; + a->y = (guMtxRowCol(m,1,2) + guMtxRowCol(m,2,1))/scale; + a->z = 0.25f*scale; + a->w = (guMtxRowCol(m,1,0) - guMtxRowCol(m,0,1))/scale; + } + } + c_guQuatNormalize(a,a); +} + +void c_guMtxQuat(Mtx m,guQuaternion *a) +{ + guMtxRowCol(m,0,0) = 1.0f - 2.0f*a->y*a->y - 2.0f*a->z*a->z; + guMtxRowCol(m,1,0) = 2.0f*a->x*a->y - 2.0f*a->z*a->w; + guMtxRowCol(m,2,0) = 2.0f*a->x*a->z + 2.0f*a->y*a->w; + + guMtxRowCol(m,0,1) = 2.0f*a->x*a->y + 2.0f*a->z*a->w; + guMtxRowCol(m,1,1) = 1.0f - 2.0f*a->x*a->x - 2.0f*a->z*a->z; + guMtxRowCol(m,2,1) = 2.0f*a->z*a->y - 2.0f*a->x*a->w; + + guMtxRowCol(m,0,2) = 2.0f*a->x*a->z - 2.0f*a->y*a->w; + guMtxRowCol(m,1,2) = 2.0f*a->z*a->y + 2.0f*a->x*a->w; + guMtxRowCol(m,2,2) = 1.0f - 2.0f*a->x*a->x - 2.0f*a->y*a->y; +} + +void guVecHalfAngle(guVector *a,guVector *b,guVector *half) +{ + guVector tmp1,tmp2,tmp3; + + tmp1.x = -a->x; + tmp1.y = -a->y; + tmp1.z = -a->z; + + tmp2.x = -b->x; + tmp2.y = -b->y; + tmp2.z = -b->z; + + guVecNormalize(&tmp1); + guVecNormalize(&tmp2); + + guVecAdd(&tmp1,&tmp2,&tmp3); + if(guVecDotProduct(&tmp3,&tmp3)>0.0f) guVecNormalize(&tmp3); + + *half = tmp3; +} diff --git a/wii/libogc/libogc/gu_psasm.S b/wii/libogc/libogc/gu_psasm.S new file mode 100644 index 0000000000..485499c29d --- /dev/null +++ b/wii/libogc/libogc/gu_psasm.S @@ -0,0 +1,723 @@ +#include + +#define A00_A01 fr0 +#define A02_A03 fr1 +#define A10_A11 fr2 +#define A12_A13 fr3 +#define A20_A21 fr4 +#define A22_A23 fr5 + +#define B00_B01 fr6 +#define B02_B03 fr7 +#define B10_B11 fr8 +#define B12_B13 fr9 +#define B20_B21 fr10 +#define B22_B23 fr11 + +#define D00_D01 fr12 +#define D02_D03 fr13 +#define D10_D11 fr14 +#define D12_D13 fr15 +#define D20_D21 fr2 +#define D22_D23 fr0 + +#define UNIT01 fr31 + +#define RET_REG fr1 +#define V1_XY fr2 +#define V1_Z fr3 +#define V2_XY fr4 +#define V2_Z fr5 +#define D1_XY fr6 +#define D1_Z fr7 +#define D2_XY fr8 +#define D2_Z fr9 +#define W1_XY fr10 +#define W1_Z fr11 +#define W2_XY fr12 +#define W2_Z fr13 + + .globl ps_guMtxConcat + //r3 = mtxA, r4 = mtxB, r5 = mtxAB +ps_guMtxConcat: + stwu r1,-64(r1) + psq_l A00_A01,0(r3),0,0 + stfd fr14,8(r1) + psq_l B00_B01,0(r4),0,0 + psq_l B02_B03,8(r4),0,0 + stfd fr15,16(r1) + stfd fr31,40(r1) + psq_l B10_B11,16(r4),0,0 + ps_muls0 D00_D01,B00_B01,A00_A01 + psq_l A10_A11,16(r3),0,0 + ps_muls0 D02_D03,B02_B03,A00_A01 + psq_l UNIT01,Unit01@sdarel(r13),0,0 + ps_muls0 D10_D11,B00_B01,A10_A11 + psq_l B12_B13,24(r4),0,0 + ps_muls0 D12_D13,B02_B03,A10_A11 + psq_l A02_A03,8(r3),0,0 + ps_madds1 D00_D01,B10_B11,A00_A01,D00_D01 + psq_l A12_A13,24(r3),0,0 + ps_madds1 D10_D11,B10_B11,A10_A11,D10_D11 + psq_l B20_B21,32(r4),0,0 + ps_madds1 D02_D03,B12_B13,A00_A01,D02_D03 + psq_l B22_B23,40(r4),0,0 + ps_madds1 D12_D13,B12_B13,A10_A11,D12_D13 + psq_l A20_A21,32(r3),0,0 + psq_l A22_A23,40(r3),0,0 + ps_madds0 D00_D01,B20_B21,A02_A03,D00_D01 + ps_madds0 D02_D03,B22_B23,A02_A03,D02_D03 + ps_madds0 D10_D11,B20_B21,A12_A13,D10_D11 + ps_madds0 D12_D13,B22_B23,A12_A13,D12_D13 + psq_st D00_D01,0(r5),0,0 + ps_muls0 D20_D21,B00_B01,A20_A21 + ps_madds1 D02_D03,UNIT01,A02_A03,D02_D03 + ps_muls0 D22_D23,B02_B03,A20_A21 + psq_st D10_D11,16(r5),0,0 + ps_madds1 D12_D13,UNIT01,A12_A13,D12_D13 + psq_st D02_D03,8(r5),0,0 + ps_madds1 D20_D21,B10_B11,A20_A21,D20_D21 + ps_madds1 D22_D23,B12_B13,A20_A21,D22_D23 + ps_madds0 D20_D21,B20_B21,A22_A23,D20_D21 + lfd fr14,8(r1) + psq_st D12_D13,24(r5),0,0 + ps_madds0 D22_D23,B22_B23,A22_A23,D22_D23 + psq_st D20_D21,32(r5),0,0 + ps_madds1 D22_D23,UNIT01,A22_A23,D22_D23 + lfd fr15,16(r1) + psq_st D22_D23,40(r5),0,0 + lfd fr31,40(r1) + addi r1,r1,64 + blr + + .globl ps_guMtxIdentity + //r3 == mtx +ps_guMtxIdentity: + lfs fr0,Unit01@sdarel(r13) + lfs fr1,Unit01+4@sdarel(r13) + psq_st fr0,8(r3),0,0 + ps_merge01 fr2,fr0,fr1 + psq_st fr0,24(r3),0,0 + ps_merge10 fr3,fr1,fr0 + psq_st fr0,32(r3),0,0 + psq_st fr2,16(r3),0,0 + psq_st fr3,0(r3),0,0 + psq_st fr3,40(r3),0,0 + blr + + .globl ps_guMtxCopy + //r3 = src, r4 = dst +ps_guMtxCopy: + psq_l fr0,0(r3),0,0 + psq_st fr0,0(r4),0,0 + psq_l fr1,8(r3),0,0 + psq_st fr1,8(r4),0,0 + psq_l fr2,16(r3),0,0 + psq_st fr2,16(r4),0,0 + psq_l fr3,24(r3),0,0 + psq_st fr3,24(r4),0,0 + psq_l fr4,32(r3),0,0 + psq_st fr4,32(r4),0,0 + psq_l fr5,40(r3),0,0 + psq_st fr5,40(r4),0,0 + blr + + .globl ps_guMtxTranspose + //r3 = src, r4 = xpose +ps_guMtxTranspose: + lfs fr0,Unit01@sdarel(r13) + psq_l fr1,0(r3),0,0 + stfs fr0,44(r4) + psq_l fr2,16(r3),0,0 + ps_merge00 fr5,fr1,fr2 + psq_l fr3,8(r3),1,0 + ps_merge11 fr6,fr1,fr2 + psq_l fr4,24(r3),1,0 + psq_st fr5,0(r4),0,0 + psq_l fr1,32(r3),0,0 + ps_merge00 fr7,fr3,fr4 + psq_st fr6,16(r4),0,0 + ps_merge00 fr5,fr1,fr0 + psq_st fr7,32(r4),0,0 + ps_merge10 fr6,fr1,fr0 + psq_st fr5,8(r4),0,0 + lfs fr3,40(r3) + psq_st fr6,24(r4),0,0 + stfs fr3,40(r4) + blr + + .globl ps_guMtxInverse + //r3 = src, r4 = inv +ps_guMtxInverse: + psq_l fr0,0(r3),1,0 + psq_l fr1,4(r3),0,0 + psq_l fr2,16(r3),1,0 + ps_merge10 fr6,fr1,fr0 + psq_l fr3,20(r3),0,0 + psq_l fr4,32(r3),1,0 + ps_merge10 fr7,fr3,fr2 + psq_l fr5,36(r3),0,0 + ps_mul fr11,fr3,fr6 + ps_mul fr13,fr5,fr7 + ps_merge10 fr8,fr5,fr4 + ps_msub fr11,fr1,fr7,fr11 + ps_mul fr12,fr1,fr8 + ps_msub fr13,fr3,fr8,fr13 + ps_mul fr10,fr3,fr4 + ps_msub fr12,fr5,fr6,fr12 + ps_mul fr9,fr0,fr5 + ps_mul fr8,fr1,fr2 + ps_sub fr6,fr6,fr6 + ps_msub fr10,fr2,fr5,fr10 + ps_mul fr7,fr0,fr13 + ps_msub fr9,fr1,fr4,fr9 + ps_madd fr7,fr2,fr12,fr7 + ps_msub fr8,fr0,fr3,fr8 + ps_madd fr7,fr4,fr11,fr7 + ps_cmpo0 cr0,fr7,fr6 + bne 0f + li r3,0 + blr + +0: fres fr0,fr7 + ps_add fr6,fr0,fr0 + ps_mul fr5,fr0,fr0 + ps_nmsub fr0,fr7,fr5,fr6 + lfs fr1,12(r3) + ps_muls0 fr13,fr13,fr0 + lfs fr2,28(r3) + ps_muls0 fr12,fr12,fr0 + lfs fr3,44(r3) + ps_muls0 fr11,fr11,fr0 + ps_merge00 fr5,fr13,fr12 + ps_muls0 fr10,fr10,fr0 + ps_merge11 fr4,fr13,fr12 + ps_muls0 fr9,fr9,fr0 + psq_st fr5,0(r4),0,0 + ps_mul fr6,fr13,fr1 + psq_st fr4,16(r4),0,0 + ps_muls0 fr8,fr8,fr0 + ps_madd fr6,fr12,fr2,fr6 + psq_st fr10,32(r4),1,0 + ps_nmadd fr6,fr11,fr3,fr6 + psq_st fr9,36(r4),1,0 + ps_mul fr7,fr10,fr1 + ps_merge00 fr5,fr11,fr6 + psq_st fr8,40(r4),1,0 + ps_merge11 fr4,fr11,fr6 + psq_st fr5,8(r4),0,0 + ps_madd fr7,fr9,fr2,fr7 + psq_st fr4,24(r4),0,0 + ps_nmadd fr7,fr8,fr3,fr7 + li r3,1 + psq_st fr7,44(r4),1,0 + blr + + .globl ps_guMtxInvXpose + //r3 = src, r4 = invx +ps_guMtxInvXpose: + psq_l fr0, 0(r3), 1, 0 + psq_l fr1, 4(r3), 0, 0 + psq_l fr2, 16(r3), 1, 0 + ps_merge10 fr6, fr1, fr0 + psq_l fr3, 20(r3), 0, 0 + psq_l fr4, 32(r3), 1, 0 + ps_merge10 fr7, fr3, fr2 + psq_l fr5, 36(r3), 0, 0 + ps_mul fr11, fr3, fr6 + ps_merge10 fr8, fr5, fr4 + ps_mul fr13, fr5, fr7 + ps_msub fr11, fr1, fr7, fr11 + ps_mul fr12, fr1, fr8 + ps_msub fr13, fr3, fr8, fr13 + ps_msub fr12, fr5, fr6, fr12 + ps_mul fr10, fr3, fr4 + ps_mul fr9, fr0, fr5 + ps_mul fr8, fr1, fr2 + ps_msub fr10, fr2, fr5, fr10 + ps_msub fr9, fr1, fr4, fr9 + ps_msub fr8, fr0, fr3, fr8 + ps_mul fr7, fr0, fr13 + ps_sub fr1, fr1, fr1 + ps_madd fr7, fr2, fr12, fr7 + ps_madd fr7, fr4, fr11, fr7 + ps_cmpo0 cr0, fr7, fr1 + bne 0f + addi r3, 0, 0 + blr + +0: fres fr0, fr7 + psq_st fr1, 12(r4), 1, 0 + ps_add fr6, fr0, fr0 + ps_mul fr5, fr0, fr0 + psq_st fr1, 28(r4), 1, 0 + ps_nmsub fr0, fr7, fr5, fr6 + psq_st fr1, 44(r4), 1, 0 + ps_muls0 fr13, fr13, fr0 + ps_muls0 fr12, fr12, fr0 + ps_muls0 fr11, fr11, fr0 + psq_st fr13, 0(r4), 0, 0 + psq_st fr12, 16(r4), 0, 0 + ps_muls0 fr10, fr10, fr0 + ps_muls0 fr9, fr9, fr0 + psq_st fr11, 32(r4), 0, 0 + psq_st fr10, 8(r4), 1, 0 + ps_muls0 fr8, fr8, fr0 + addi r3, 0, 1 + psq_st fr9, 24(r4), 1, 0 + psq_st fr8, 40(r4), 1, 0 + blr + + .globl ps_guMtxScale + //r3 = mtx,fr1 = xS,fr2 = yS,fr3 = zS +ps_guMtxScale: + lfs fr0,Unit01@sdarel(r13) + stfs fr1,0(r3) + psq_st fr0,4(r3),0,0 + psq_st fr0,12(r3),0,0 + stfs fr2,20(r3) + psq_st fr0,24(r3),0,0 + psq_st fr0,32(r3),0,0 + stfs fr3,40(r3) + stfs fr0,44(r3) + blr + + .globl ps_guMtxScaleApply + //r3 = src,r4 = dst,fr1 = xS,fr2 = yS,fr3 = zS +ps_guMtxScaleApply: + frsp fr1,fr1 + psq_l fr4,0(r3),0,0 + frsp fr2,fr2 + psq_l fr5,8(r3),0,0 + frsp fr3,fr3 + ps_muls0 fr4,fr4,fr1 + psq_l fr6,16(r3),0,0 + ps_muls0 fr5,fr5,fr1 + psq_l fr7,24(r3),0,0 + ps_muls0 fr6,fr6,fr2 + psq_l fr8,32(r3),0,0 + psq_st fr4,0(r4),0,0 + ps_muls0 fr7,fr7,fr2 + psq_l fr2,40(r3),0,0 + psq_st fr5,8(r4),0,0 + ps_muls0 fr8,fr8,fr3 + psq_st fr6,16(r4),0,0 + ps_muls0 fr2,fr2,fr3 + psq_st fr7,24(r4),0,0 + psq_st fr8,32(r4),0,0 + psq_st fr2,40(r4),0,0 + blr + + .globl ps_guMtxApplyScale + //r3 = src,r4 = dst,fr1 = xS,fr2 = yS,fr3 = zS +ps_guMtxApplyScale: + lfs fr6,Unit01+4@sdarel(r13) + frsp fr1,fr1 + psq_l fr4,0(r3),0,0 + frsp fr2,fr2 + psq_l fr5,8(r3),0,0 + frsp fr3,fr3 + ps_merge00 fr10,fr1,fr2 + ps_merge00 fr11,fr3,fr6 + ps_mul fr4,fr4,fr10 + psq_l fr6,16(r3),0,0 + ps_mul fr5,fr5,fr11 + psq_l fr7,24(r3),0,0 + ps_mul fr6,fr6,fr10 + psq_l fr8,32(r3),0,0 + psq_st fr4,0(r4),0,0 + ps_mul fr7,fr7,fr11 + psq_l fr2,40(r3),0,0 + psq_st fr5,8(r4),0,0 + ps_mul fr8,fr8,fr10 + psq_st fr6,16(r4),0,0 + ps_mul fr2,fr2,fr11 + psq_st fr7,24(r4),0,0 + psq_st fr8,32(r4),0,0 + psq_st fr2,40(r4),0,0 + blr + + .globl ps_guMtxTrans + //r3 = mtx,fr1 = xT,fr2 = yT,fr3 = zT +ps_guMtxTrans: + lfs fr4,Unit01@sdarel(r13) + lfs fr5,Unit01+4@sdarel(r13) + stfs fr4,16(r3) + stfs fr1,12(r3) + stfs fr2,28(r3) + psq_st fr4,4(r3),0,0 + psq_st fr4,32(r3),0,0 + stfs fr5,20(r3) + stfs fr4,24(r3) + stfs fr5,40(r3) + stfs fr3,44(r3) + stfs fr5,0(r3) + blr + + .globl ps_guMtxTransApply + //r3 = src,r4 = dst,fr1 = xT,fr2 = yT,fr3 = zT +ps_guMtxTransApply: + psq_l fr4,0(r3),0,0 + frsp fr1,fr1 + psq_l fr5,8(r3),0,0 + frsp fr2,fr2 + psq_l fr7,24(r3),0,0 + frsp fr3,fr3 + psq_l fr8,40(r3),0,0 + ps_sum1 fr5,fr1,fr5,fr5 + psq_l fr6,16(r3),0,0 + ps_sum1 fr7,fr2,fr7,fr7 + psq_l fr9,32(r3),0,0 + ps_sum1 fr8,fr3,fr8,fr8 + psq_st fr4,0(r4),0,0 + psq_st fr5,8(r4),0,0 + psq_st fr6,16(r4),0,0 + psq_st fr7,24(r4),0,0 + psq_st fr9,32(r4),0,0 + psq_st fr8,40(r4),0,0 + blr + + .globl ps_guMtxApplyTrans + //r3 = src,r4 = dst,fr1 = xT,fr2 = yT,fr3 = zT +ps_guMtxApplyTrans: + lfs fr6,Unit01+4@sdarel(r13) + psq_l fr4,0(r3),0,0 + frsp fr1,fr1 + psq_l fr5,8(r3),0,0 + frsp fr2,fr2 + ps_merge00 fr10,fr1,fr2 + psq_l fr7,24(r3),0,0 + frsp fr3,fr3 + ps_mul fr1,fr4,fr10 + ps_merge00 fr11,fr3,fr6 + psq_l fr8,40(r3),0,0 + ps_madd fr2,fr5,fr11,fr1 + psq_l fr6,16(r3),0,0 + ps_sum0 fr3,fr2,fr3,fr2 + psq_l fr9,32(r3),0,0 + ps_mul fr12,fr6,fr10 + psq_st fr4,0(r4),0,0 + ps_madd fr4,fr7,fr11,fr12 + psq_st fr5,8(r4),1,0 + ps_sum0 fr12,fr4,fr12,fr4 + psq_st fr3,12(r4),1,0 + ps_mul fr3,fr9,fr10 + psq_st fr6,16(r4),0,0 + ps_madd fr2,fr8,fr11,fr3 + psq_st fr7,24(r4),1,0 + ps_sum0 fr3,fr2,fr3,fr2 + psq_st fr12,28(r4),1,0 + psq_st fr9,32(r4),0,0 + psq_st fr8,40(r4),1,0 + psq_st fr3,44(r4),1,0 + blr + + .globl ps_guMtxRotTrig + //r3 = mt,r4 = axis,fr1 = sinA,fr2 = cosA +ps_guMtxRotTrig: + frsp fr1,fr1 + lfs fr3,Unit01@sdarel(r13) + frsp fr2,fr2 + lfs fr4,Unit01+4@sdarel(r13) + ori r4,r4,0x20 + ps_neg fr5,fr1 + cmplwi r4,'x' + beq 0f + cmplwi r4,'y' + beq 1f + cmplwi r4,'z' + beq 2f + b 3f +0: + psq_st fr4,0(r3),1,0 + psq_st fr3,4(r3),0,0 + ps_merge00 fr6,fr1,fr2 + psq_st fr3,12(r3),0,0 + ps_merge00 fr7,fr2,fr5 + psq_st fr3,28(r3),0,0 + psq_st fr3,44(r3),1,0 + psq_st fr6,36(r3),0,0 + psq_st fr7,20(r3),0,0 + b 3f +1: + ps_merge00 fr6,fr2,fr3 + ps_merge00 fr7,fr3,fr4 + psq_st fr3,24(r3),0,0 + psq_st fr6,0(r3),0,0 + ps_merge00 fr8,fr5,fr3 + ps_merge00 fr9,fr1,fr3 + psq_st fr6,40(r3),0,0 + psq_st fr7,16(r3),0,0 + psq_st fr9,8(r3),0,0 + psq_st fr8,32(r3),0,0 + b 3f +2: + psq_st fr3,8(r3),0,0 + ps_merge00 fr6,fr1,fr2 + ps_merge00 fr8,fr2,fr5 + psq_st fr3,24(r3),0,0 + psq_st fr3,32(r3),0,0 + ps_merge00 fr7,fr4,fr3 + psq_st fr6,16(r3),0,0 + psq_st fr8,0(r3),0,0 + psq_st fr7,40(r3),0,0 +3: + blr + + .globl __ps_guMtxRotAxisRadInternal + //r3 = mtx, r4 = vec, fr1 = sT, fr2 = cT +__ps_guMtxRotAxisRadInternal: + stwu r1,-64(r1) + frsp fr2,fr2 + psq_l fr3,0(r4),0,0 + frsp fr1,fr1 + stfd fr14,8(r1) + lfs fr11,NrmData+4@sdarel(r13) + lfs fr12,NrmData@sdarel(r13) + ps_mul fr5,fr3,fr3 + lfs fr4,8(r4) + fadds fr10,fr12,fr12 + ps_madd fr6,fr4,fr4,fr5 + fsubs fr14,fr12,fr12 + ps_sum0 fr7,fr6,fr4,fr5 + fsubs fr13,fr10,fr2 + frsqrte fr8,fr7 + fmuls fr5,fr8,fr8 + fmuls fr6,fr8,fr12 + fnmsubs fr5,fr5,fr7,fr11 + fmuls fr8,fr5,fr6 + ps_merge00 fr2,fr2,fr2 + ps_muls0 fr3,fr3,fr8 + ps_muls0 fr4,fr4,fr8 + ps_muls0 fr7,fr3,fr13 + ps_muls0 fr12,fr3,fr1 + ps_muls0 fr8,fr4,fr13 + ps_muls1 fr6,fr7,fr3 + ps_muls0 fr5,fr7,fr3 + ps_muls0 fr7,fr7,fr4 + fnmsubs fr9,fr4,fr1,fr6 + fmadds fr10,fr4,fr1,fr6 + ps_neg fr3,fr12 + ps_sum0 fr11,fr7,fr14,fr12 + ps_sum0 fr5,fr5,fr9,fr2 + ps_sum1 fr6,fr2,fr10,fr6 + ps_sum0 fr9,fr3,fr14,fr7 + psq_st fr11,8(r3),0,0 + ps_sum0 fr3,fr7,fr7,fr3 + psq_st fr5,0(r3),0,0 + ps_muls0 fr8,fr8,fr4 + psq_st fr6,16(r3),0,0 + ps_sum1 fr7,fr12,fr3,fr7 + psq_st fr9,24(r3),0,0 + ps_sum0 fr8,fr8,fr14,fr2 + psq_st fr7,32(r3),0,0 + psq_st fr8,40(r3),0,0 + lfd fr14,8(r1) + addi r1,r1,64 + blr + + .globl ps_guMtxReflect + //r3 = mtx,r4 = vec1,r5 = vec2 +ps_guMtxReflect: + lfs fr0,Unit01+4@sdarel(r13) + psq_l fr1,8(r5),1,0 + psq_l fr2,0(r5),0,0 + psq_l fr3,0(r4),0,0 + ps_nmadd fr5,fr1,fr0,fr1 + psq_l fr4,8(r4),1,0 + ps_nmadd fr6,fr2,fr0,fr2 + ps_muls0 fr7,fr2,fr5 + ps_mul fr8,fr6,fr3 + ps_muls0 fr9,fr2,fr6 + ps_sum0 fr8,fr8,fr8,fr8 + ps_muls1 fr10,fr2,fr6 + psq_st fr7,32(r3),0,0 + ps_sum0 fr2,fr2,fr2,fr0 + ps_nmadd fr8,fr5,fr4,fr8 + ps_sum1 fr10,fr0,fr10,fr10 + psq_st fr9,0(r3),0,0 + ps_muls0 fr11,fr2,fr8 + ps_merge00 fr12,fr5,fr8 + psq_st fr10,16(r3),0,0 + ps_merge00 fr13,fr7,fr11 + ps_muls0 fr12,fr12,fr1 + ps_merge11 fr11,fr7,fr11 + psq_st fr13,8(r3),0,0 + ps_sum0 fr12,fr12,fr12,fr0 + psq_st fr11,24(r3),0,0 + psq_st fr12,40(r3),0,0 + blr + + .globl ps_guVecAdd + //r3 = v1,r4 = v2,r5 = dst +ps_guVecAdd: + psq_l V1_XY,0(r3),0,0 + psq_l V2_XY,0(r4),0,0 + ps_add D1_XY,V1_XY,V2_XY + psq_st D1_XY,0(r5),0,0 + psq_l V1_Z,8(r3),1,0 + psq_l V2_Z,8(r4),1,0 + ps_add D1_Z,V1_Z,V2_Z + psq_st D1_Z,8(r5),1,0 + blr + + .globl ps_guVecSub + //r3 = v1,r4 = v2,r5 = dst +ps_guVecSub: + psq_l V1_XY,0(r3),0,0 + psq_l V2_XY,0(r4),0,0 + ps_sub D1_XY,V1_XY,V2_XY + psq_st D1_XY,0(r5),0,0 + psq_l V1_Z,8(r3),1,0 + psq_l V2_Z,8(r4),1,0 + ps_sub D1_Z,V1_Z,V2_Z + psq_st D1_Z,8(r5),1,0 + blr + + .globl ps_guVecScale + //r3 = src,r4 = dst,fr1 = S +ps_guVecScale: + psq_l fr2,0(r3),0,0 + psq_l fr3,8(r3),1,0 + ps_muls0 fr4,fr2,fr1 + psq_st fr4,0(r4),0,0 + ps_muls0 fr4,fr3,fr1 + psq_st fr4,8(r4),1,0 + blr + + .globl ps_guVecNormalize + //r3 = v +ps_guVecNormalize: + lfs fr0,NrmData@sdarel(r13) + lfs fr1,NrmData+4@sdarel(r13) + psq_l fr2,0(r3),0,0 + ps_mul fr4,fr2,fr2 + psq_l fr3,8(r3),1,0 + ps_madd fr5,fr3,fr3,fr4 + ps_sum0 fr6,fr5,fr3,fr4 + frsqrte fr7,fr6 + fmuls fr8,fr7,fr7 + fmuls fr9,fr7,fr0 + fnmsubs fr8,fr8,fr6,fr1 + fmuls fr7,fr8,fr9 + ps_muls0 fr2,fr2,fr7 + psq_st fr2,0(r3),0,0 + ps_muls0 fr3,fr3,fr7 + psq_st fr3,8(r3),1,0 + blr + + .globl ps_guVecCross + //r3 = v1,r4 = v2,r5 = v12 +ps_guVecCross: + psq_l fr1,0(r4),0,0 + lfs fr2,8(r3) + psq_l fr0,0(r3),0,0 + ps_merge10 fr6,fr1,fr1 + lfs fr3,8(r4) + ps_mul fr4,fr1,fr2 + ps_muls0 fr7,fr1,fr0 + ps_msub fr5,fr0,fr3,fr4 + ps_msub fr8,fr0,fr6,fr7 + ps_merge11 fr9,fr5,fr5 + ps_merge01 fr10,fr5,fr8 + psq_st fr9,0(r5),1,0 + ps_neg fr10,fr10 + psq_st fr10,4(r5),0,0 + blr + + .globl ps_guVecDotProduct + //r3 = vec1,r4 = vec2 +ps_guVecDotProduct: + psq_l fr2,4(r3),0,0 + psq_l fr3,4(r4),0,0 + ps_mul fr2,fr2,fr3 + psq_l fr5,0(r3),0,0 + psq_l fr4,0(r4),0,0 + ps_madd fr3,fr5,fr4,fr2 + ps_sum0 fr1,fr3,fr2,fr2 + blr + + .globl ps_guVecMultiply +ps_guVecMultiply: + psq_l fr0,0(r4),0,0 + psq_l fr2,0(r3),0,0 + psq_l fr1,8(r4),1,0 + ps_mul fr4,fr2,fr0 + psq_l fr3,8(r3),0,0 + ps_madd fr5,fr3,fr1,fr4 + psq_l fr8,16(r3),0,0 + ps_sum0 fr6,fr5,fr6,fr5 + psq_l fr9,24(r3),0,0 + ps_mul fr10,fr8,fr0 + psq_st fr6,0(r5),1,0 + ps_madd fr11,fr9,fr1,fr10 + psq_l fr2,32(r3),0,0 + ps_sum0 fr12,fr11,fr12,fr11 + psq_l fr3,40(r3),0,0 + ps_mul fr4,fr2,fr0 + psq_st fr12,4(r5),1,0 + ps_madd fr5,fr3,fr1,fr4 + ps_sum0 fr6,fr5,fr6,fr5 + psq_st fr6,8(r5),1,0 + blr + + .globl ps_guVecMultiplySR + // r3 = mt, r4 = src, r5 = dst +ps_guVecMultiplySR: + psq_l fr0,0(r3),0,0 // m[0][0], m[0][1] GQR0 = 0 + // fp6 - x y + psq_l fr6,0(r4),0,0 + psq_l fr2,16(r3),0,0 // m[1][0], m[1][1] + // fp8 = m00x m01y // next X + ps_mul fr8,fr0,fr6 + psq_l fr4,32(r3),0,0 // m[2][0], m[2][1] + // fp10 = m10x m11y // next Y + ps_mul fr10,fr2,fr6 + psq_l fr7,8(r4),1,0 // fp7 - z,1.0 + // fp12 = m20x m21y // next Z + ps_mul fr12,fr4,fr6 // YYY last FP6 usage + psq_l fr3,24(r3),0,0 // m[1][2], m[1][3] + ps_sum0 fr8,fr8,fr8,fr8 + psq_l fr5,40(r3),0,0 // m[2][2], m[2][3] + ps_sum0 fr10,fr10,fr10,fr10 + psq_l fr1,8(r3),0,0 // m[0][2], m[0][3] + ps_sum0 fr12,fr12,fr12,fr12 + ps_madd fr9,fr1,fr7,fr8 + psq_st fr9,0(r5),1,0 // store X + ps_madd fr11,fr3,fr7,fr10 + psq_st fr11,4(r5),1,0 // store Y + ps_madd fr13,fr5,fr7,fr12 + psq_st fr13,8(r5),1,0 // sore Z + blr + + .globl ps_quQuatScale + //r3 = q,r4 = r, fr1 = scale +ps_guQuatScale: + psq_l fr4,0(r3),0,0 + psq_l fr5,8(r3),0,0 + ps_muls0 fr4,fr4,fr1 + psq_st fr4,0(r4),0,0 + ps_muls0 fr5,fr5,fr1 + psq_st fr5,8(r4),0,0 + blr + + .globl ps_guQuatDotProduct + //r3 = p, r4 = q ; fr1 = res +ps_guQuatDotProduct: + psq_l fr2,0(r3),0,0 + psq_l fr4,0(r4),0,0 + ps_mul fr1,fr2,fr4 + psq_l fr3,8(r3),0,0 + psq_l fr5,8(r4),0,0 + ps_madd fr1,fr3,fr5,fr1 + ps_sum0 fr1,fr1,fr1,fr1 + blr + + .section .sdata + .balign 16 +Unit01: + .float 0.0, 1.0 +QuatEpsilon: + .float 0.00001 +NrmData: + .float 0.5, 3.0 diff --git a/wii/libogc/libogc/gx.c b/wii/libogc/libogc/gx.c new file mode 100644 index 0000000000..ff9b413e78 --- /dev/null +++ b/wii/libogc/libogc/gx.c @@ -0,0 +1,5099 @@ +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "irq.h" +#include "lwp.h" +#include "system.h" +#include "video.h" +#include "video_types.h" +#include "lwp_watchdog.h" +#include "gx.h" +#include "gx_regdef.h" + +#define TEXCACHE_TESTING + + +#define GX_FINISH 2 + +#if defined(HW_DOL) + #define LARGE_NUMBER (-1048576.0f) +#elif defined(HW_RVL) + #define LARGE_NUMBER (-1.0e+18f) +#endif + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +#define GX_LOAD_BP_REG(x) \ + do { \ + wgPipe->U8 = 0x61; \ + asm volatile ("" ::: "memory" ); \ + wgPipe->U32 = (u32)(x); \ + asm volatile ("" ::: "memory" ); \ + } while(0) + +#define GX_LOAD_CP_REG(x, y) \ + do { \ + wgPipe->U8 = 0x08; \ + asm volatile ("" ::: "memory" ); \ + wgPipe->U8 = (u8)(x); \ + asm volatile ("" ::: "memory" ); \ + wgPipe->U32 = (u32)(y); \ + asm volatile ("" ::: "memory" ); \ + } while(0) + +#define GX_LOAD_XF_REG(x, y) \ + do { \ + wgPipe->U8 = 0x10; \ + asm volatile ("" ::: "memory" ); \ + wgPipe->U32 = (u32)((x)&0xffff); \ + asm volatile ("" ::: "memory" ); \ + wgPipe->U32 = (u32)(y); \ + asm volatile ("" ::: "memory" ); \ + } while(0) + +#define GX_LOAD_XF_REGS(x, n) \ + do { \ + wgPipe->U8 = 0x10; \ + asm volatile ("" ::: "memory" ); \ + wgPipe->U32 = (u32)(((((n)&0xffff)-1)<<16)|((x)&0xffff)); \ + asm volatile ("" ::: "memory" ); \ + } while(0) + +#define XY(x, y) (((y) << 10) | (x)) + +#define GX_DEFAULT_BG {64,64,64,255} +#define BLACK {0,0,0,0} +#define WHITE {255,255,255,255} + +WGPipe* const wgPipe = (WGPipe*)0xCC008000; + +static GXFifoObj _gpfifo; +static GXFifoObj _cpufifo; +static GXFifoObj _gxfifoobj; +static GXFifoObj _gx_dl_fifoobj; +static GXFifoObj _gx_old_cpufifo; +static void *_gxcurrbp = NULL; +static lwp_t _gxcurrentlwp = LWP_THREAD_NULL; + +static u32 _gxcpufifoready = 0; +static u32 _gxgpfifoready = 0; +static u32 _cpgplinked = 0; +static u16 _gxgpstatus = 0; +static vu32 _gxoverflowsuspend = 0; +static vu32 _gxoverflowcount = 0; +static vu32 _gxfinished = 0; +static lwpq_t _gxwaitfinish; + +static GXBreakPtCallback breakPtCB = NULL; +static GXDrawDoneCallback drawDoneCB = NULL; +static GXDrawSyncCallback tokenCB = NULL; + +static GXTexRegionCallback regionCB = NULL; +static GXTlutRegionCallback tlut_regionCB = NULL; + +static vu32* const _piReg = (u32*)0xCC003000; +static vu16* const _cpReg = (u16*)0xCC000000; +static vu16* const _peReg = (u16*)0xCC001000; +static vu16* const _memReg = (u16*)0xCC004000; + +static u8 _gxtevcolid[9] = {0,1,0,1,0,1,7,5,6}; +static u8 _gxtexmode0ids[8] = {0x80,0x81,0x82,0x83,0xA0,0xA1,0xA2,0xA3}; +static u8 _gxtexmode1ids[8] = {0x84,0x85,0x86,0x87,0xA4,0xA5,0xA6,0xA7}; +static u8 _gxteximg0ids[8] = {0x88,0x89,0x8A,0x8B,0xA8,0xA9,0xAA,0xAB}; +static u8 _gxteximg1ids[8] = {0x8C,0x8D,0x8E,0x8F,0xAC,0xAD,0xAE,0xAF}; +static u8 _gxteximg2ids[8] = {0x90,0x91,0x92,0x93,0xB0,0xB1,0xB2,0xB3}; +static u8 _gxteximg3ids[8] = {0x94,0x95,0x96,0x97,0xB4,0xB5,0xB6,0xB7}; +static u8 _gxtextlutids[8] = {0x98,0x99,0x9A,0x9B,0xB8,0xB9,0xBA,0xBB}; + +#if defined(HW_RVL) +static u32 _gxtexregionaddrtable[48] = +{ + 0x00000000,0x00010000,0x00020000,0x00030000, + 0x00040000,0x00050000,0x00060000,0x00070000, + 0x00008000,0x00018000,0x00028000,0x00038000, + 0x00048000,0x00058000,0x00068000,0x00078000, + 0x00000000,0x00090000,0x00020000,0x000B0000, + 0x00040000,0x00098000,0x00060000,0x000B8000, + 0x00080000,0x00010000,0x000A0000,0x00030000, + 0x00088000,0x00050000,0x000A8000,0x00070000, + 0x00000000,0x00090000,0x00020000,0x000B0000, + 0x00040000,0x00090000,0x00060000,0x000B0000, + 0x00080000,0x00010000,0x000A0000,0x00030000, + 0x00080000,0x00050000,0x000A0000,0x00070000 +}; +#endif + + +extern u8 __gxregs[]; +static struct __gx_regdef *__gx = (struct __gx_regdef*)__gxregs; +static u8 _gx_saved_data[STRUCT_REGDEF_SIZE] ATTRIBUTE_ALIGN(32); + +static s32 __gx_onreset(s32 final); + +static sys_resetinfo __gx_resetinfo = { + {}, + __gx_onreset, + 127 +}; + +static __inline__ BOOL IsWriteGatherBufferEmpty() +{ + return !(mfwpar()&1); +} + +static __inline__ void DisableWriteGatherPipe() +{ + mthid2((mfhid2()&~0x40000000)); +} + +static __inline__ void EnableWriteGatherPipe() +{ + mtwpar(0x0C008000); + mthid2((mfhid2()|0x40000000)); +} + +static __inline__ void __GX_ResetWriteGatherPipe() +{ + while(mfwpar()&1); + mtwpar(0x0C008000); +} + +static __inline__ void __GX_FifoLink(u8 enable) +{ + __gx->cpCRreg = ((__gx->cpCRreg&~0x10)|(_SHIFTL(enable,4,1))); + _cpReg[1] = __gx->cpCRreg; +} + +static __inline__ void __GX_WriteFifoIntReset(u8 inthi,u8 intlo) +{ + __gx->cpCLreg = ((__gx->cpCLreg&~0x03)|(_SHIFTL(intlo,1,1))|(inthi&1)); + _cpReg[2] = __gx->cpCLreg; +} + +static __inline__ void __GX_WriteFifoIntEnable(u8 inthi, u8 intlo) +{ + __gx->cpCRreg = ((__gx->cpCRreg&~0x0C)|(_SHIFTL(intlo,3,1))|(_SHIFTL(inthi,2,1))); + _cpReg[1] = __gx->cpCRreg; +} + +static __inline__ void __GX_FifoReadEnable() +{ + __gx->cpCRreg = ((__gx->cpCRreg&~0x01)|1); + _cpReg[1] = __gx->cpCRreg; +} + +static __inline__ void __GX_FifoReadDisable() +{ + __gx->cpCRreg = ((__gx->cpCRreg&~0x01)|0); + _cpReg[1] = __gx->cpCRreg; +} + +static s32 __gx_onreset(s32 final) +{ + if(final==FALSE) { + GX_Flush(); + GX_AbortFrame(); + } + return 1; +} + +static u32 __GX_IsGPFifoReady() +{ + return _gxgpfifoready; +} + +static u32 __GX_CPGPLinkCheck() +{ + struct __gxfifo *gpfifo = (struct __gxfifo*)&_gpfifo; + struct __gxfifo *cpufifo = (struct __gxfifo*)&_cpufifo; + + if(!_gxcpufifoready || !_gxgpfifoready) return 0; + + if((cpufifo->buf_start==gpfifo->buf_start)&&(cpufifo->buf_end==gpfifo->buf_end)) return 1; + + return 0; +} + +static void __GX_InitRevBits() +{ + s32 i; + + i=0; + while(i<8) { + __gx->VAT0reg[i] = 0x40000000; + __gx->VAT1reg[i] = 0x80000000; + GX_LOAD_CP_REG((0x0080|i),__gx->VAT1reg[i]); + i++; + } + + GX_LOAD_XF_REG(0x1000,0x3f); + GX_LOAD_XF_REG(0x1012,0x01); + + GX_LOAD_BP_REG(0x5800000f); + +} + +static void __GX_WaitAbort(u32 delay) +{ + u64 start,end; + + start = gettime(); + while(1) { + end = gettime(); + if(diff_ticks(start,end)>=(u64)delay) break; + }; +} + +#ifdef HW_RVL +static u32 __GX_ReadMemCounterU32(u32 reg) +{ + u16 lcnt,ucnt,tmp; + + tmp = _memReg[reg]; + do { + ucnt = tmp; + lcnt = _memReg[reg+1]; + tmp = _memReg[reg]; + } while(tmp!=ucnt); + return (u32)((ucnt<<16)|lcnt); +} + +static void __GX_WaitAbortPixelEngine() +{ + u32 cnt,tmp; + + cnt = __GX_ReadMemCounterU32(39); + do { + tmp = cnt; + __GX_WaitAbort(8); + cnt = __GX_ReadMemCounterU32(39); + } while(cnt!=tmp); +} + +static void __GX_Abort() +{ + if(__gx->gxFifoInited && __GX_IsGPFifoReady()) + __GX_WaitAbortPixelEngine(); + + _piReg[6] = 1; + __GX_WaitAbort(50); + + _piReg[6] = 0; + __GX_WaitAbort(5); +} +#endif + +static void __GX_SaveFifo() +{ + s32 rdwt_dst; + u32 level,val; + struct __gxfifo *cpufifo = (struct __gxfifo*)&_cpufifo; + struct __gxfifo *gpfifo = (struct __gxfifo*)&_gpfifo; + + _CPU_ISR_Disable(level); + + if(_gxcpufifoready) { + val = _piReg[0x05]; + cpufifo->wt_ptr = (u32)MEM_PHYSICAL_TO_K0((val&0x1FFFFFE0)); + cpufifo->fifo_wrap = ((val&0x20000000)==0x20000000); + } + + if(_gxgpfifoready) { + gpfifo->rd_ptr = (u32)MEM_PHYSICAL_TO_K0(_SHIFTL(_cpReg[29],16,16)|(_cpReg[28]&0xffff)); + gpfifo->rdwt_dst = (_SHIFTL(_cpReg[25],16,16)|(_cpReg[24]&0xffff)); + } + + if(_cpgplinked) { + cpufifo->rd_ptr = gpfifo->rd_ptr; + cpufifo->rdwt_dst = gpfifo->rdwt_dst; + gpfifo->wt_ptr = cpufifo->wt_ptr; + } else if(_gxcpufifoready) { + rdwt_dst = (cpufifo->wt_ptr - cpufifo->rd_ptr); + if(rdwt_dst<0) cpufifo->rdwt_dst = (cpufifo->rdwt_dst + cpufifo->size); + else cpufifo->rdwt_dst = rdwt_dst; + } + + _CPU_ISR_Restore(level); +} + +static void __GX_CleanGPFifo() +{ + u32 level; + struct __gxfifo *gpfifo = (struct __gxfifo*)&_gpfifo; + struct __gxfifo *cpufifo = (struct __gxfifo*)&_cpufifo; + + if(!_gxgpfifoready) return; + + _CPU_ISR_Disable(level); + __GX_FifoReadDisable(); + __GX_WriteFifoIntEnable(FALSE,FALSE); + + gpfifo->rd_ptr = gpfifo->wt_ptr; + gpfifo->rdwt_dst = 0; + + /* setup rd<->wd dist */ + _cpReg[24] = _SHIFTL(gpfifo->rdwt_dst,0,16); + _cpReg[25] = _SHIFTR(gpfifo->rdwt_dst,16,16); + + /* setup wt ptr */ + _cpReg[26] = _SHIFTL(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->wt_ptr),0,16); + _cpReg[27] = _SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->wt_ptr),16,16); + + /* setup rd ptr */ + _cpReg[28] = _SHIFTL(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->rd_ptr),0,16); + _cpReg[29] = _SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->rd_ptr),16,16); + ppcsync(); + + if(_cpgplinked) { + cpufifo->rd_ptr = gpfifo->rd_ptr; + cpufifo->wt_ptr = gpfifo->wt_ptr; + cpufifo->rdwt_dst = gpfifo->rdwt_dst; + + _piReg[5] = (cpufifo->wt_ptr&0x1FFFFFE0); + __GX_WriteFifoIntEnable(TRUE,FALSE); + __GX_FifoLink(TRUE); + } + __gx->cpCRreg &= ~0x22; + _cpReg[1] = __gx->cpCRreg; + breakPtCB = NULL; + + __GX_WriteFifoIntReset(TRUE,TRUE); + __GX_FifoReadEnable(); + _CPU_ISR_Restore(level); +} + +static void __GXOverflowHandler() +{ + if(!_gxoverflowsuspend) { + _gxoverflowsuspend = 1; + _gxoverflowcount++; + __GX_WriteFifoIntEnable(GX_DISABLE,GX_ENABLE); + __GX_WriteFifoIntReset(GX_TRUE,GX_FALSE); + LWP_SuspendThread(_gxcurrentlwp); + } +} + +static void __GXUnderflowHandler() +{ + if(_gxoverflowsuspend) { + _gxoverflowsuspend = 0; + LWP_ResumeThread(_gxcurrentlwp); + __GX_WriteFifoIntReset(GX_TRUE,GX_TRUE); + __GX_WriteFifoIntEnable(GX_ENABLE,GX_DISABLE); + } +} + +static void __GXCPInterruptHandler(u32 irq,void *ctx) +{ + __gx->cpSRreg = _cpReg[0]; + + if((__gx->cpCRreg&0x08) && (__gx->cpSRreg&0x02)) + __GXUnderflowHandler(); + + if((__gx->cpCRreg&0x04) && (__gx->cpSRreg&0x01)) + __GXOverflowHandler(); + + if((__gx->cpCRreg&0x20) && (__gx->cpSRreg&0x10)) { + __gx->cpCRreg &= ~0x20; + _cpReg[1] = __gx->cpCRreg; + if(breakPtCB) + breakPtCB(); + } +} + +static void __GXTokenInterruptHandler(u32 irq,void *ctx) +{ + u16 token = _peReg[7]; + + if(tokenCB) + tokenCB(token); + + _peReg[5] = (_peReg[5]&~0x04)|0x04; +} + +static void __GXFinishInterruptHandler(u32 irq,void *ctx) +{ + _peReg[5] = (_peReg[5]&~0x08)|0x08; + _gxfinished = 1; + + if(drawDoneCB) + drawDoneCB(); + + LWP_ThreadBroadcast(_gxwaitfinish); +} + +static void __GX_PEInit() +{ + IRQ_Request(IRQ_PI_PETOKEN,__GXTokenInterruptHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_PI_PETOKEN)); + + IRQ_Request(IRQ_PI_PEFINISH,__GXFinishInterruptHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_PI_PEFINISH)); + + _peReg[5] = 0x0F; +} + +static void __GX_FifoInit() +{ + IRQ_Request(IRQ_PI_CP,__GXCPInterruptHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_PI_CP)); + + memset(&_cpufifo,0,sizeof(GXFifoObj)); + memset(&_gpfifo,0,sizeof(GXFifoObj)); + + _gxcpufifoready = 0; + _gxgpfifoready = 0; + _cpgplinked = 0; + _gxoverflowsuspend = 0; + _gxcurrentlwp = LWP_GetSelf(); +} + +static void __GX_SetTmemConfig(u8 nr) +{ + if(nr==0) { + // Set_TextureImage0-3, GXTexMapID=0-3 tmem_offset=00000000, cache_width=32 kb, cache_height=32 kb, image_type=cached + GX_LOAD_BP_REG(0x8c0d8000); + GX_LOAD_BP_REG(0x900dc000); + GX_LOAD_BP_REG(0x8d0d8400); + GX_LOAD_BP_REG(0x910dc400); + GX_LOAD_BP_REG(0x8e0d8800); + GX_LOAD_BP_REG(0x920dc800); + GX_LOAD_BP_REG(0x8f0d8c00); + GX_LOAD_BP_REG(0x930dcc00); + + // Set_TextureImage0-3, GXTexMapID=4-7 tmem_offset=00010000, cache_width=32 kb, cache_height=32 kb, image_type=cached + GX_LOAD_BP_REG(0xac0d9000); + GX_LOAD_BP_REG(0xb00dd000); + GX_LOAD_BP_REG(0xad0d9400); + GX_LOAD_BP_REG(0xb10dd400); + GX_LOAD_BP_REG(0xae0d9800); + GX_LOAD_BP_REG(0xb20dd800); + GX_LOAD_BP_REG(0xaf0d9c00); + GX_LOAD_BP_REG(0xb30ddc00); + + return; + } + + if(nr==1) { + // Set_TextureImage0-3, GXTexMapID=0-3 tmem_offset=00000000, cache_width=32 kb, cache_height=32 kb, image_type=cached + GX_LOAD_BP_REG(0x8c0d8000); + GX_LOAD_BP_REG(0x900dc000); + GX_LOAD_BP_REG(0x8d0d8800); + GX_LOAD_BP_REG(0x910dc800); + GX_LOAD_BP_REG(0x8e0d9000); + GX_LOAD_BP_REG(0x920dd000); + GX_LOAD_BP_REG(0x8f0d9800); + GX_LOAD_BP_REG(0x930dd800); + + // Set_TextureImage0-3, GXTexMapID=4-7 tmem_offset=00010000, cache_width=32 kb, cache_height=32 kb, image_type=cached + GX_LOAD_BP_REG(0xac0da000); + GX_LOAD_BP_REG(0xb00de000); + GX_LOAD_BP_REG(0xad0da800); + GX_LOAD_BP_REG(0xb10de800); + GX_LOAD_BP_REG(0xae0db000); + GX_LOAD_BP_REG(0xb20df000); + GX_LOAD_BP_REG(0xaf0db800); + GX_LOAD_BP_REG(0xb30df800); + + return; + } + + if(nr==2) { + // Set_TextureImage0-3, GXTexMapID=0-3 tmem_offset=00000000, cache_width=32 kb, cache_height=32 kb, image_type=cached + GX_LOAD_BP_REG(0x8c0d8000); + GX_LOAD_BP_REG(0x900dc000); + GX_LOAD_BP_REG(0x8d0d8800); + GX_LOAD_BP_REG(0x910dc800); + GX_LOAD_BP_REG(0x8e0d9000); + GX_LOAD_BP_REG(0x920dd000); + GX_LOAD_BP_REG(0x8f0d9800); + GX_LOAD_BP_REG(0x930dd800); + + // Set_TextureImage0-3, GXTexMapID=4-7 tmem_offset=00010000, cache_width=32 kb, cache_height=32 kb, image_type=cached + GX_LOAD_BP_REG(0xac0da000); + GX_LOAD_BP_REG(0xb00dc400); + GX_LOAD_BP_REG(0xad0da800); + GX_LOAD_BP_REG(0xb10dcc00); + GX_LOAD_BP_REG(0xae0db000); + GX_LOAD_BP_REG(0xb20dd400); + GX_LOAD_BP_REG(0xaf0db800); + GX_LOAD_BP_REG(0xb30ddc00); + + return; + } +} + +#if defined(HW_RVL) +static GXTexRegion* __GXDefTexRegionCallback(GXTexObj *obj,u8 mapid) +{ + u32 fmt,mipmap; + GXTexRegion *ret = NULL; + + fmt = GX_GetTexObjFmt(obj); + mipmap = GX_GetTexObjMipMap(obj); + if(fmt>=GX_TF_CI4 && fmt<=GX_TF_CI14) + return &__gx->texRegion[mapid]; + else if(fmt==GX_TF_CMPR) + ret = &__gx->texRegion[mapid]; + else + ret = &__gx->texRegion[mapid+8]; + + if(mipmap) ret = &__gx->texRegion[mapid+16]; + + return ret; +} +#else +static GXTexRegion* __GXDefTexRegionCallback(GXTexObj *obj,u8 mapid) +{ + u32 fmt; + u32 idx; + static u32 regionA = 0; + static u32 regionB = 0; + GXTexRegion *ret = NULL; + + fmt = GX_GetTexObjFmt(obj); + if(fmt==0x0008 || fmt==0x0009 || fmt==0x000a) { + idx = regionB++; + ret = &__gx->texRegion[(idx&3)+8]; + } else { + idx = regionA++; + ret = &__gx->texRegion[(idx&7)]; + } + return ret; +} +#endif + +static GXTlutRegion* __GXDefTlutRegionCallback(u32 tlut_name) +{ + return &__gx->tlutRegion[tlut_name]; +} + +static void __GX_InitGX() +{ + s32 i; + u32 flag; + GXRModeObj *rmode; + Mtx identity_matrix = + { + {1,0,0,0}, + {0,1,0,0}, + {0,0,1,0} + }; + + rmode = VIDEO_GetPreferredMode(NULL); + + GX_SetCopyClear((GXColor)BLACK,0xffffff); + GX_SetTexCoordGen(GX_TEXCOORD0,GX_TG_MTX2x4,GX_TG_TEX0,GX_IDENTITY); + GX_SetTexCoordGen(GX_TEXCOORD1,GX_TG_MTX2x4,GX_TG_TEX1,GX_IDENTITY); + GX_SetTexCoordGen(GX_TEXCOORD2,GX_TG_MTX2x4,GX_TG_TEX2,GX_IDENTITY); + GX_SetTexCoordGen(GX_TEXCOORD3,GX_TG_MTX2x4,GX_TG_TEX3,GX_IDENTITY); + GX_SetTexCoordGen(GX_TEXCOORD4,GX_TG_MTX2x4,GX_TG_TEX4,GX_IDENTITY); + GX_SetTexCoordGen(GX_TEXCOORD5,GX_TG_MTX2x4,GX_TG_TEX5,GX_IDENTITY); + GX_SetTexCoordGen(GX_TEXCOORD6,GX_TG_MTX2x4,GX_TG_TEX6,GX_IDENTITY); + GX_SetTexCoordGen(GX_TEXCOORD7,GX_TG_MTX2x4,GX_TG_TEX7,GX_IDENTITY); + GX_SetNumTexGens(1); + GX_ClearVtxDesc(); + GX_InvVtxCache(); + + GX_SetLineWidth(6,GX_TO_ZERO); + GX_SetPointSize(6,GX_TO_ZERO); + + GX_EnableTexOffsets(GX_TEXCOORD0,GX_DISABLE,GX_DISABLE); + GX_EnableTexOffsets(GX_TEXCOORD1,GX_DISABLE,GX_DISABLE); + GX_EnableTexOffsets(GX_TEXCOORD2,GX_DISABLE,GX_DISABLE); + GX_EnableTexOffsets(GX_TEXCOORD3,GX_DISABLE,GX_DISABLE); + GX_EnableTexOffsets(GX_TEXCOORD4,GX_DISABLE,GX_DISABLE); + GX_EnableTexOffsets(GX_TEXCOORD5,GX_DISABLE,GX_DISABLE); + GX_EnableTexOffsets(GX_TEXCOORD6,GX_DISABLE,GX_DISABLE); + GX_EnableTexOffsets(GX_TEXCOORD7,GX_DISABLE,GX_DISABLE); + + GX_LoadPosMtxImm(identity_matrix,GX_PNMTX0); + GX_LoadNrmMtxImm(identity_matrix,GX_PNMTX0); + GX_SetCurrentMtx(GX_PNMTX0); + GX_LoadTexMtxImm(identity_matrix,GX_IDENTITY,GX_MTX3x4); + GX_LoadTexMtxImm(identity_matrix,GX_DTTIDENTITY,GX_MTX3x4); + + GX_SetViewport(0,0,rmode->fbWidth,rmode->efbHeight,0,1); + GX_SetCoPlanar(GX_DISABLE); + GX_SetCullMode(GX_CULL_BACK); + GX_SetClipMode(GX_CLIP_ENABLE); + + GX_SetScissor(0,0,rmode->fbWidth,rmode->efbHeight); + GX_SetScissorBoxOffset(0,0); + + GX_SetNumChans(0); + + GX_SetChanCtrl(GX_COLOR0A0,GX_DISABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHTNULL,GX_DF_NONE,GX_AF_NONE); + GX_SetChanAmbColor(GX_COLOR0A0,(GXColor)BLACK); + GX_SetChanMatColor(GX_COLOR0A0,(GXColor)WHITE); + + GX_SetChanCtrl(GX_COLOR1A1,GX_DISABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHTNULL,GX_DF_NONE,GX_AF_NONE); + GX_SetChanAmbColor(GX_COLOR1A1,(GXColor)BLACK); + GX_SetChanMatColor(GX_COLOR1A1,(GXColor)WHITE); + + GX_InvalidateTexAll(); + GX_SetTexRegionCallback(__GXDefTexRegionCallback); + GX_SetTlutRegionCallback(__GXDefTlutRegionCallback); + + GX_SetTevOrder(GX_TEVSTAGE0,GX_TEXCOORD0,GX_TEXMAP0,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE1,GX_TEXCOORD1,GX_TEXMAP1,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE2,GX_TEXCOORD2,GX_TEXMAP2,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE3,GX_TEXCOORD3,GX_TEXMAP3,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE4,GX_TEXCOORD4,GX_TEXMAP4,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE5,GX_TEXCOORD5,GX_TEXMAP5,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE6,GX_TEXCOORD6,GX_TEXMAP6,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE7,GX_TEXCOORD7,GX_TEXMAP7,GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE8,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetTevOrder(GX_TEVSTAGE9,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetTevOrder(GX_TEVSTAGE10,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetTevOrder(GX_TEVSTAGE11,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetTevOrder(GX_TEVSTAGE12,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetTevOrder(GX_TEVSTAGE13,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetTevOrder(GX_TEVSTAGE14,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetTevOrder(GX_TEVSTAGE15,GX_TEXCOORDNULL,GX_TEXMAP_NULL,GX_COLORNULL); + GX_SetNumTevStages(1); + GX_SetTevOp(GX_TEVSTAGE0,GX_REPLACE); + GX_SetAlphaCompare(GX_ALWAYS,0,GX_AOP_AND,GX_ALWAYS,0); + GX_SetZTexture(GX_ZT_DISABLE,GX_TF_Z8,0); + for(i=0;iviHeight==(rmode->xfbHeight<<1)) flag = 1; + GX_SetFieldMode(rmode->field_rendering,flag); + + GX_SetCopyClear((GXColor)GX_DEFAULT_BG,0x00ffffff); + GX_SetDispCopySrc(0,0,rmode->fbWidth,rmode->efbHeight); + GX_SetDispCopyDst(rmode->fbWidth,rmode->efbHeight); + GX_SetDispCopyYScale(1.0); + GX_SetCopyClamp(GX_CLAMP_TOP|GX_CLAMP_BOTTOM); + GX_SetCopyFilter(GX_FALSE,NULL,GX_FALSE,NULL); + GX_SetDispCopyGamma(GX_GM_1_0); + GX_SetDispCopyFrame2Field(GX_COPY_PROGRESSIVE); + GX_ClearBoundingBox(); + + GX_PokeColorUpdate(GX_TRUE); + GX_PokeAlphaUpdate(GX_TRUE); + GX_PokeDither(GX_FALSE); + GX_PokeBlendMode(GX_BM_NONE,GX_BL_ZERO,GX_BL_ONE,GX_LO_SET); + GX_PokeAlphaMode(GX_ALWAYS,0); + GX_PokeAlphaRead(GX_READ_FF); + GX_PokeDstAlpha(GX_DISABLE,0); + GX_PokeZMode(GX_TRUE,GX_ALWAYS,GX_TRUE); + + GX_SetGPMetric(GX_PERF0_NONE,GX_PERF1_NONE); + GX_ClearGPMetric(); +} + +static void __GX_FlushTextureState() +{ + GX_LOAD_BP_REG(__gx->tevIndMask); +} + +static void __GX_XfVtxSpecs() +{ + u32 xfvtxspecs = 0; + u32 nrms,texs,cols; + + cols = 0; + if(__gx->vcdLo&0x6000) cols++; + if(__gx->vcdLo&0x18000) cols++; + + nrms = 0; + if(__gx->vcdNrms==1) nrms = 1; + else if(__gx->vcdNrms==2) nrms = 2; + + texs = 0; + if(__gx->vcdHi&0x3) texs++; + if(__gx->vcdHi&0xc) texs++; + if(__gx->vcdHi&0x30) texs++; + if(__gx->vcdHi&0xc0) texs++; + if(__gx->vcdHi&0x300) texs++; + if(__gx->vcdHi&0xc00) texs++; + if(__gx->vcdHi&0x3000) texs++; + if(__gx->vcdHi&0xc000) texs++; + + xfvtxspecs = (_SHIFTL(texs,4,4))|(_SHIFTL(nrms,2,2))|(cols&0x3); + GX_LOAD_XF_REG(0x1008,xfvtxspecs); +} + +static void __GX_SetMatrixIndex(u32 mtx) +{ + if(mtx<5) { + GX_LOAD_CP_REG(0x30,__gx->mtxIdxLo); + GX_LOAD_XF_REG(0x1018,__gx->mtxIdxLo); + } else { + GX_LOAD_CP_REG(0x40,__gx->mtxIdxHi); + GX_LOAD_XF_REG(0x1019,__gx->mtxIdxHi); + } +} + +static void __GX_SendFlushPrim() +{ + u32 tmp,tmp2,cnt; + + tmp = (__gx->xfFlush*__gx->xfFlushExp); + + wgPipe->U8 = 0x98; + wgPipe->U16 = __gx->xfFlush; + + tmp2 = (tmp+3)/4; + if(tmp>0) { + cnt = tmp2/8; + while(cnt) { + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + cnt--; + } + tmp2 &= 0x0007; + if(tmp2) { + while(tmp2) { + wgPipe->U32 = 0; + tmp2--; + } + } + } + __gx->xfFlush = 1; +} + +static void __GX_SetVCD() +{ + GX_LOAD_CP_REG(0x50,__gx->vcdLo); + GX_LOAD_CP_REG(0x60,__gx->vcdHi); + __GX_XfVtxSpecs(); +} + +static void __GX_SetVAT() +{ + u8 setvtx = 0; + s32 i; + + for(i=0;i<8;i++) { + setvtx = (1<VATTable&setvtx) { + GX_LOAD_CP_REG((0x70+(i&7)),__gx->VAT0reg[i]); + GX_LOAD_CP_REG((0x80+(i&7)),__gx->VAT1reg[i]); + GX_LOAD_CP_REG((0x90+(i&7)),__gx->VAT2reg[i]); + } + } + __gx->VATTable = 0; +} + +static void __SetSURegs(u8 texmap,u8 texcoord) +{ + u32 reg; + u16 wd,ht; + u8 wrap_s,wrap_t; + + wd = __gx->texMapSize[texmap]&0x3ff; + ht = _SHIFTR(__gx->texMapSize[texmap],10,10); + wrap_s = __gx->texMapWrap[texmap]&3; + wrap_t = _SHIFTR(__gx->texMapWrap[texmap],2,2); + + reg = (texcoord&0x7); + __gx->suSsize[reg] = (__gx->suSsize[reg]&~0x0000ffff)|wd; + __gx->suTsize[reg] = (__gx->suTsize[reg]&~0x0000ffff)|ht; + __gx->suSsize[reg] = (__gx->suSsize[reg]&~0x00010000)|(_SHIFTL(wrap_s,16,1)); + __gx->suTsize[reg] = (__gx->suTsize[reg]&~0x00010000)|(_SHIFTL(wrap_t,16,1)); + + GX_LOAD_BP_REG(__gx->suSsize[reg]); + GX_LOAD_BP_REG(__gx->suTsize[reg]); +} + +static void __GX_SetSUTexRegs() +{ + u32 i; + u32 indtev,dirtev; + u8 texcoord,texmap; + u32 tevreg,tevm,texcm; + + dirtev = (_SHIFTR(__gx->genMode,10,4))+1; + indtev = _SHIFTR(__gx->genMode,16,3); + + //indirect texture order + for(i=0;itevRasOrder[2]&7; + texcoord = _SHIFTR(__gx->tevRasOrder[2],3,3); + break; + case GX_INDTEXSTAGE1: + texmap = _SHIFTR(__gx->tevRasOrder[2],6,3); + texcoord = _SHIFTR(__gx->tevRasOrder[2],9,3); + break; + case GX_INDTEXSTAGE2: + texmap = _SHIFTR(__gx->tevRasOrder[2],12,3); + texcoord = _SHIFTR(__gx->tevRasOrder[2],15,3); + break; + case GX_INDTEXSTAGE3: + texmap = _SHIFTR(__gx->tevRasOrder[2],18,3); + texcoord = _SHIFTR(__gx->tevRasOrder[2],21,3); + break; + default: + texmap = 0; + texcoord = 0; + break; + } + + texcm = _SHIFTL(1,texcoord,1); + if(!(__gx->texCoordManually&texcm)) + __SetSURegs(texmap,texcoord); + } + + //direct texture order + for(i=0;itevTexMap[i]&0xff); + + if(i&1) texcoord = _SHIFTR(__gx->tevRasOrder[tevreg],15,3); + else texcoord = _SHIFTR(__gx->tevRasOrder[tevreg],3,3); + + tevm = _SHIFTL(1,i,1); + texcm = _SHIFTL(1,texcoord,1); + if(texmap!=0xff && (__gx->tevTexCoordEnable&tevm) && !(__gx->texCoordManually&texcm)) { + __SetSURegs(texmap,texcoord); + } + } +} + +static void __GX_SetGenMode() +{ + GX_LOAD_BP_REG(__gx->genMode); + __gx->xfFlush = 0; +} + +static void __GX_UpdateBPMask() +{ +#if defined(HW_DOL) + u32 i; + u32 nbmp,nres; + u8 ntexmap; + + nbmp = _SHIFTR(__gx->genMode,16,3); + + nres = 0; + for(i=0;itevRasOrder[2]&7; + break; + case GX_INDTEXSTAGE1: + ntexmap = _SHIFTR(__gx->tevRasOrder[2],6,3); + break; + case GX_INDTEXSTAGE2: + ntexmap = _SHIFTR(__gx->tevRasOrder[2],12,3); + break; + case GX_INDTEXSTAGE3: + ntexmap = _SHIFTR(__gx->tevRasOrder[2],18,3); + break; + default: + ntexmap = 0; + break; + } + nres |= (1<tevIndMask&0xff)!=nres) { + __gx->tevIndMask = (__gx->tevIndMask&~0xff)|(nres&0xff); + GX_LOAD_BP_REG(__gx->tevIndMask); + } +#endif +} + +static void __GX_SetIndirectMask(u32 mask) +{ + __gx->tevIndMask = ((__gx->tevIndMask&~0xff)|(mask&0xff)); + GX_LOAD_BP_REG(__gx->tevIndMask); +} + +static void __GX_SetTexCoordGen() +{ + u32 i,mask; + u32 texcoord; + + if(__gx->dirtyState&0x02000000) GX_LOAD_XF_REG(0x103f,(__gx->genMode&0xf)); + + i = 0; + texcoord = 0x1040; + mask = _SHIFTR(__gx->dirtyState,16,8); + while(mask) { + if(mask&0x0001) { + GX_LOAD_XF_REG(texcoord,__gx->texCoordGen[i]); + GX_LOAD_XF_REG((texcoord+0x10),__gx->texCoordGen2[i]); + } + mask >>= 1; + texcoord++; + i++; + } +} + +static void __GX_SetChanColor() +{ + if(__gx->dirtyState&0x0100) + GX_LOAD_XF_REG(0x100a,__gx->chnAmbColor[0]); + if(__gx->dirtyState&0x0200) + GX_LOAD_XF_REG(0x100b,__gx->chnAmbColor[1]); + if(__gx->dirtyState&0x0400) + GX_LOAD_XF_REG(0x100c,__gx->chnMatColor[0]); + if(__gx->dirtyState&0x0800) + GX_LOAD_XF_REG(0x100d,__gx->chnMatColor[1]); +} + +static void __GX_SetChanCntrl() +{ + u32 i,chan,mask; + + if(__gx->dirtyState&0x01000000) GX_LOAD_XF_REG(0x1009,(_SHIFTR(__gx->genMode,4,3))); + + i = 0; + chan = 0x100e; + mask = _SHIFTR(__gx->dirtyState,12,4); + while(mask) { + if(mask&0x0001) GX_LOAD_XF_REG(chan,__gx->chnCntrl[i]); + + mask >>= 1; + chan++; + i++; + } +} + +static void __GX_SetDirtyState() +{ + if(__gx->dirtyState&0x0001) { + __GX_SetSUTexRegs(); + } + if(__gx->dirtyState&0x0002) { + __GX_UpdateBPMask(); + } + if(__gx->dirtyState&0x0004) { + __GX_SetGenMode(); + } + if(__gx->dirtyState&0x0008) { + __GX_SetVCD(); + } + if(__gx->dirtyState&0x0010) { + __GX_SetVAT(); + } + if(__gx->dirtyState&~0xff) { + if(__gx->dirtyState&0x0f00) { + __GX_SetChanColor(); + } + if(__gx->dirtyState&0x0100f000) { + __GX_SetChanCntrl(); + } + if(__gx->dirtyState&0x02ff0000) { + __GX_SetTexCoordGen(); + } + if(__gx->dirtyState&0x04000000) { + __GX_SetMatrixIndex(0); + __GX_SetMatrixIndex(5); + } + } + __gx->dirtyState = 0; +} + +static u32 __GX_GetNumXfbLines(u16 efbHeight,u32 yscale) +{ + u32 tmp,tmp1; + + tmp = (((efbHeight-1)<<8)/yscale)+1; + if(yscale>128 && yscale<256) { + while(yscale&0x01) yscale >>= 1; + tmp1 = yscale*(efbHeight/yscale); + if(!(efbHeight-tmp1)) tmp++; + } + if(tmp>1024) tmp = 1024; + + return tmp; +} + +GXFifoObj* GX_Init(void *base,u32 size) +{ + s32 i,re0,re1; +#if defined(HW_RVL) + u32 tmem; +#else + u32 tmem_even,tmem_odd; +#endif + u32 divis,res; + u32 divid = TB_BUS_CLOCK; + GXTexRegion *region = NULL; + GXTlutRegion *tregion = NULL; + + LWP_InitQueue(&_gxwaitfinish); + SYS_RegisterResetFunc(&__gx_resetinfo); + + memset(__gxregs,0,STRUCT_REGDEF_SIZE); + + __GX_FifoInit(); + GX_InitFifoBase(&_gxfifoobj,base,size); + GX_SetCPUFifo(&_gxfifoobj); + GX_SetGPFifo(&_gxfifoobj); + __GX_PEInit(); + EnableWriteGatherPipe(); + + __gx->gxFifoInited = 1; + + __gx->tevIndMask = 0xff; + __gx->tevIndMask = (__gx->tevIndMask&~0xff000000)|(_SHIFTL(0x0f,24,8)); + + i=0; + re0 = 0xc0; + re1 = 0xc1; + while(i<16) { + __gx->tevColorEnv[i] = (__gx->tevColorEnv[i]&~0xff000000)|(_SHIFTL(re0,24,8)); + __gx->tevAlphaEnv[i] = (__gx->tevAlphaEnv[i]&~0xff000000)|(_SHIFTL(re1,24,8)); + re0 += 2; re1 += 2; i++; + } + + __gx->texCoordManually = 0; + __gx->dirtyState = 0; + + __gx->saveDLctx = 1; + __gx->gxFifoUnlinked = 0; + + __gx->sciTLcorner = (__gx->sciTLcorner&~0xff000000)|(_SHIFTL(0x20,24,8)); + __gx->sciBRcorner = (__gx->sciBRcorner&~0xff000000)|(_SHIFTL(0x21,24,8)); + __gx->lpWidth = (__gx->lpWidth&~0xff000000)|(_SHIFTL(0x22,24,8)); + __gx->genMode = (__gx->genMode&~0xff000000)|(_SHIFTL(0x00,24,8)); + + i=0; + re0 = 0x30; + re1 = 0x31; + while(i<8) { + __gx->suSsize[i] = (__gx->suSsize[i]&~0xff000000)|(_SHIFTL(re0,24,8)); + __gx->suTsize[i] = (__gx->suTsize[i]&~0xff000000)|(_SHIFTL(re1,24,8)); + re0 += 2; re1 += 2; i++; + } + + __gx->peZMode = (__gx->peZMode&~0xff000000)|(_SHIFTL(0x40,24,8)); + __gx->peCMode0 = (__gx->peCMode0&~0xff000000)|(_SHIFTL(0x41,24,8)); + __gx->peCMode1 = (__gx->peCMode1&~0xff000000)|(_SHIFTL(0x42,24,8)); + __gx->peCntrl = (__gx->peCntrl&~0xff000000)|(_SHIFTL(0x43,24,8)); + + i=0; + re0 = 0x25; + while(i<11) { + __gx->tevRasOrder[i] = (__gx->tevRasOrder[i]&~0xff000000)|(_SHIFTL(re0,24,8)); + re0++; i++; + } + + divis = 500; + res = (u32)(divid/divis); + __GX_FlushTextureState(); + GX_LOAD_BP_REG(0x69000000|((_SHIFTR(res,11,24))|0x0400)); + + divis = 4224; + res = (u32)(res/divis); + __GX_FlushTextureState(); + GX_LOAD_BP_REG(0x46000000|(res|0x0200)); + + i=0; + re0 = 0xf6; + while(i<8) { + __gx->tevSwapModeTable[i] = (__gx->tevSwapModeTable[i]&~0xff000000)|(_SHIFTL(re0,24,8)); + re0++; i++; + } + + __gx->tevTexCoordEnable = 0; + __gx->perf0Mode = GX_PERF0_NONE; + __gx->perf1Mode = GX_PERF1_NONE; + __gx->cpPerfMode = 0; + + __GX_InitRevBits(); + + i=0; + while(i<16) { + __gx->tevTexMap[i] = 0xff; + i++; + } + +#if defined(HW_RVL) + i = 0; + while(i<8) { + region = &__gx->texRegion[i]; + GX_InitTexCacheRegion(region,GX_FALSE,_gxtexregionaddrtable[i+0],GX_TEXCACHE_32K,_gxtexregionaddrtable[i+8],GX_TEXCACHE_32K); + + region = &__gx->texRegion[i+8]; + GX_InitTexCacheRegion(region,GX_FALSE,_gxtexregionaddrtable[i+16],GX_TEXCACHE_32K,_gxtexregionaddrtable[i+24],GX_TEXCACHE_32K); + + region = &__gx->texRegion[i+16]; + GX_InitTexCacheRegion(region,GX_TRUE,_gxtexregionaddrtable[i+32],GX_TEXCACHE_32K,_gxtexregionaddrtable[i+40],GX_TEXCACHE_32K); + + i++; + } + + i=0; + while(i<16) { + tmem = 0x000C0000+(i<<13); + tregion = &__gx->tlutRegion[i]; + GX_InitTlutRegion(tregion,tmem,GX_TLUT_256); + i++; + } + + i=0; + while(i<4) { + tmem = 0x000E0000+(i<<15); + tregion = &__gx->tlutRegion[i+16]; + GX_InitTlutRegion(tregion,tmem,GX_TLUT_1K); + i++; + } +#else + for(i=0;i<8;i++) { + tmem_even = tmem_odd = (i<<15); + region = &__gx->texRegion[i]; + GX_InitTexCacheRegion(region,GX_FALSE,tmem_even,GX_TEXCACHE_32K,(tmem_odd+0x00080000),GX_TEXCACHE_32K); + } + for(i=0;i<4;i++) { + tmem_even = ((0x08+(i<<1))<<15); + tmem_odd = ((0x09+(i<<1))<<15); + region = &__gx->texRegion[i+8]; + GX_InitTexCacheRegion(region,GX_FALSE,tmem_even,GX_TEXCACHE_32K,tmem_odd,GX_TEXCACHE_32K); + } + for(i=0;i<16;i++) { + tmem_even = (i<<13)+0x000C0000; + tregion = &__gx->tlutRegion[i]; + GX_InitTlutRegion(tregion,tmem_even,GX_TLUT_256); + } + for(i=0;i<4;i++) { + tmem_even = (i<<15)+0x000E0000; + tregion = &__gx->tlutRegion[i+16]; + GX_InitTlutRegion(tregion,tmem_even,GX_TLUT_1K); + } +#endif + _cpReg[3] = 0; + GX_LOAD_CP_REG(0x20,0x00000000); + GX_LOAD_XF_REG(0x1006,0x0); + + GX_LOAD_BP_REG(0x23000000); + GX_LOAD_BP_REG(0x24000000); + GX_LOAD_BP_REG(0x67000000); + + __GX_SetIndirectMask(0); +#if defined(HW_RVL) + __GX_SetTmemConfig(2); +#else + __GX_SetTmemConfig(0); +#endif + __GX_InitGX(); + + return &_gxfifoobj; +} + +void GX_InitFifoBase(GXFifoObj *fifo,void *base,u32 size) +{ + struct __gxfifo *ptr = (struct __gxfifo*)fifo; + + if(!ptr || sizebuf_start = (u32)base; + ptr->buf_end = (u32)base + size - 4; + ptr->size = size; + ptr->rdwt_dst = 0; + + GX_InitFifoLimits(fifo,(size-GX_FIFO_HIWATERMARK),((size>>1)&0x7fffffe0)); + GX_InitFifoPtrs(fifo,base,base); +} + +void GX_InitFifoLimits(GXFifoObj *fifo,u32 hiwatermark,u32 lowatermark) +{ + struct __gxfifo *ptr = (struct __gxfifo*)fifo; + + ptr->hi_mark = hiwatermark; + ptr->lo_mark = lowatermark; +} + +void GX_InitFifoPtrs(GXFifoObj *fifo,void *rd_ptr,void *wt_ptr) +{ + u32 level; + s32 rdwt_dst; + struct __gxfifo *ptr = (struct __gxfifo*)fifo; + + _CPU_ISR_Disable(level); + rdwt_dst = wt_ptr-rd_ptr; + ptr->rd_ptr = (u32)rd_ptr; + ptr->wt_ptr = (u32)wt_ptr; + ptr->rdwt_dst = rdwt_dst; + if(rdwt_dst<0) { + rdwt_dst += ptr->size; + ptr->rd_ptr = rdwt_dst; + } + _CPU_ISR_Restore(level); +} + +void GX_GetFifoPtrs(GXFifoObj *fifo,void **rd_ptr,void **wt_ptr) +{ + struct __gxfifo *ptr = (struct __gxfifo*)fifo; + *rd_ptr = (void*)ptr->rd_ptr; + *wt_ptr = (void*)ptr->wt_ptr; +} + +void GX_SetCPUFifo(GXFifoObj *fifo) +{ + u32 level; + struct __gxfifo *ptr = (struct __gxfifo*)fifo; + struct __gxfifo *cpufifo = (struct __gxfifo*)&_cpufifo; + + _CPU_ISR_Disable(level); + if(!fifo) { + _gxcpufifoready = 0; + _cpgplinked = 0; + cpufifo->gpfifo_ready = 0; + cpufifo->cpufifo_ready = 0; + _CPU_ISR_Restore(level); + return; + } + + cpufifo->buf_start = ptr->buf_start; + cpufifo->buf_end = ptr->buf_end; + cpufifo->size = ptr->size; + cpufifo->hi_mark = ptr->hi_mark; + cpufifo->lo_mark = ptr->lo_mark; + cpufifo->rd_ptr = ptr->rd_ptr; + cpufifo->wt_ptr = ptr->wt_ptr; + cpufifo->rdwt_dst = ptr->rdwt_dst; + cpufifo->fifo_wrap = ptr->fifo_wrap; + cpufifo->gpfifo_ready = ptr->gpfifo_ready; + cpufifo->cpufifo_ready = 1; + + _gxcpufifoready = 1; + if(__GX_CPGPLinkCheck()) { + _cpgplinked = 1; + cpufifo->gpfifo_ready = 1; + + _piReg[3] = MEM_VIRTUAL_TO_PHYSICAL(cpufifo->buf_start); + _piReg[4] = MEM_VIRTUAL_TO_PHYSICAL(cpufifo->buf_end); + _piReg[5] = (cpufifo->wt_ptr&0x1FFFFFE0); + + __GX_WriteFifoIntReset(GX_TRUE,GX_TRUE); + __GX_WriteFifoIntEnable(GX_ENABLE,GX_DISABLE); + __GX_FifoLink(GX_TRUE); + + _CPU_ISR_Restore(level); + return; + } + + if(_cpgplinked) { + __GX_FifoLink(GX_FALSE); + _cpgplinked = 0; + } + + __GX_WriteFifoIntEnable(GX_DISABLE,GX_DISABLE); + + _piReg[3] = MEM_VIRTUAL_TO_PHYSICAL(cpufifo->buf_start); + _piReg[4] = MEM_VIRTUAL_TO_PHYSICAL(cpufifo->buf_end); + _piReg[5] = (cpufifo->wt_ptr&0x1FFFFFE0); + ppcsync(); + + _CPU_ISR_Restore(level); +} + +void GX_GetCPUFifo(GXFifoObj *fifo) +{ + struct __gxfifo* ptr = (struct __gxfifo*)fifo; + struct __gxfifo* cpufifo = (struct __gxfifo*)&_cpufifo; + + if(!_gxcpufifoready) return; + + GX_Flush(); + __GX_SaveFifo(); + + ptr->buf_start = cpufifo->buf_start; + ptr->buf_end = cpufifo->buf_end; + ptr->size = cpufifo->size; + ptr->rd_ptr = cpufifo->rd_ptr; + ptr->wt_ptr = cpufifo->wt_ptr; + ptr->rdwt_dst = cpufifo->rdwt_dst; + ptr->hi_mark = cpufifo->hi_mark; + ptr->lo_mark = cpufifo->lo_mark; + ptr->fifo_wrap = cpufifo->fifo_wrap; + ptr->cpufifo_ready = cpufifo->cpufifo_ready; + ptr->gpfifo_ready = cpufifo->gpfifo_ready; +} + +void GX_SetGPFifo(GXFifoObj *fifo) +{ + u32 level; + struct __gxfifo *ptr = (struct __gxfifo*)fifo; + struct __gxfifo *gpfifo = (struct __gxfifo*)&_gpfifo; + + _CPU_ISR_Disable(level); + __GX_FifoReadDisable(); + __GX_WriteFifoIntEnable(GX_DISABLE,GX_DISABLE); + + if(!fifo) { + _gxgpfifoready = 0; + _cpgplinked = 0; + gpfifo->cpufifo_ready = 0; + gpfifo->gpfifo_ready = 0; + __GX_FifoLink(GX_FALSE); + _CPU_ISR_Restore(level); + return; + } + + gpfifo->buf_start = ptr->buf_start; + gpfifo->buf_end = ptr->buf_end; + gpfifo->size = ptr->size; + gpfifo->hi_mark = ptr->hi_mark; + gpfifo->lo_mark = ptr->lo_mark; + gpfifo->rd_ptr = ptr->rd_ptr; + gpfifo->wt_ptr = ptr->wt_ptr; + gpfifo->rdwt_dst = ptr->rdwt_dst; + gpfifo->fifo_wrap = ptr->fifo_wrap; + gpfifo->cpufifo_ready = ptr->cpufifo_ready; + gpfifo->gpfifo_ready = 1; + _gxgpfifoready = 1; + + /* setup fifo base */ + _cpReg[16] = _SHIFTL(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->buf_start),0,16); + _cpReg[17] = _SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->buf_start),16,16); + + /* setup fifo end */ + _cpReg[18] = _SHIFTL(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->buf_end),0,16); + _cpReg[19] = _SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->buf_end),16,16); + + /* setup hiwater mark */ + _cpReg[20] = _SHIFTL(gpfifo->hi_mark,0,16); + _cpReg[21] = _SHIFTR(gpfifo->hi_mark,16,16); + + /* setup lowater mark */ + _cpReg[22] = _SHIFTL(gpfifo->lo_mark,0,16); + _cpReg[23] = _SHIFTR(gpfifo->lo_mark,16,16); + + /* setup rd<->wd dist */ + _cpReg[24] = _SHIFTL(gpfifo->rdwt_dst,0,16); + _cpReg[25] = _SHIFTR(gpfifo->rdwt_dst,16,16); + + /* setup wt ptr */ + _cpReg[26] = _SHIFTL(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->wt_ptr),0,16); + _cpReg[27] = _SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->wt_ptr),16,16); + + /* setup rd ptr */ + _cpReg[28] = _SHIFTL(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->rd_ptr),0,16); + _cpReg[29] = _SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(gpfifo->rd_ptr),16,16); + ppcsync(); + + if(__GX_CPGPLinkCheck()) { + _cpgplinked = 1; + gpfifo->cpufifo_ready = 1; + __GX_WriteFifoIntEnable(GX_ENABLE,GX_DISABLE); + __GX_FifoLink(GX_TRUE); + } else { + _cpgplinked = 0; + gpfifo->cpufifo_ready = 0; + __GX_WriteFifoIntEnable(GX_DISABLE,GX_DISABLE); + __GX_FifoLink(GX_FALSE); + } + + __GX_WriteFifoIntReset(GX_TRUE,GX_TRUE); + __GX_FifoReadEnable(); + _CPU_ISR_Restore(level); +} + +void GX_GetGPFifo(GXFifoObj *fifo) +{ + struct __gxfifo* ptr = (struct __gxfifo*)fifo; + struct __gxfifo* gpfifo = (struct __gxfifo*)&_gpfifo; + + if(!_gxgpfifoready) return; + + __GX_SaveFifo(); + + ptr->buf_start = gpfifo->buf_start; + ptr->buf_end = gpfifo->buf_end; + ptr->size = gpfifo->size; + ptr->rd_ptr = gpfifo->rd_ptr; + ptr->wt_ptr = gpfifo->wt_ptr; + ptr->rdwt_dst = gpfifo->rdwt_dst; + ptr->hi_mark = gpfifo->hi_mark; + ptr->lo_mark = gpfifo->lo_mark; + ptr->fifo_wrap = gpfifo->fifo_wrap; + ptr->gpfifo_ready = gpfifo->gpfifo_ready; + ptr->cpufifo_ready = gpfifo->cpufifo_ready; +} + +void* GX_GetFifoBase(GXFifoObj *fifo) +{ + return (void*)((struct __gxfifo*)fifo)->buf_start; +} + +u32 GX_GetFifoSize(GXFifoObj *fifo) +{ + return ((struct __gxfifo*)fifo)->size; +} + +u32 GX_GetFifoCount(GXFifoObj *fifo) +{ + return ((struct __gxfifo*)fifo)->rdwt_dst; +} + +u8 GX_GetFifoWrap(GXFifoObj *fifo) +{ + return ((struct __gxfifo*)fifo)->fifo_wrap; +} + +u32 GX_GetOverflowCount() +{ + return _gxoverflowcount; +} + +u32 GX_ResetOverflowCount() +{ + u32 ret = _gxoverflowcount; + _gxoverflowcount = 0; + return ret; +} + +lwp_t GX_GetCurrentGXThread() +{ + return _gxcurrentlwp; +} + +lwp_t GX_SetCurrentGXThread() +{ + u32 level; + + _CPU_ISR_Disable(level); + lwp_t ret = _gxcurrentlwp; + _gxcurrentlwp = LWP_GetSelf(); + _CPU_ISR_Restore(level); + + return ret; +} + +volatile void* GX_RedirectWriteGatherPipe(void *ptr) +{ + u32 level; + struct __gxfifo *cpufifo = (struct __gxfifo*)&_cpufifo; + + _CPU_ISR_Disable(level); + GX_Flush(); + while(!IsWriteGatherBufferEmpty()); + + mtwpar(0x0C008000); + if(_cpgplinked) { + __GX_FifoLink(GX_FALSE); + __GX_WriteFifoIntEnable(GX_DISABLE,GX_DISABLE); + } + cpufifo->wt_ptr = (u32)MEM_PHYSICAL_TO_K0(_piReg[5]&~0x04000000); + + _piReg[3] = 0; + _piReg[4] = 0x04000000; + _piReg[5] = (((u32)ptr&0x3FFFFFE0)&~0x04000000); + _sync(); + + _CPU_ISR_Restore(level); + + return (volatile void*)0x0C008000; +} + +void GX_RestoreWriteGatherPipe() +{ + u32 level; + struct __gxfifo *cpufifo = (struct __gxfifo*)&_cpufifo; + + _CPU_ISR_Disable(level); + + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + + ppcsync(); + while(!IsWriteGatherBufferEmpty()); + + mtwpar(0x0C008000); + _piReg[3] = MEM_VIRTUAL_TO_PHYSICAL(cpufifo->buf_start); + _piReg[4] = MEM_VIRTUAL_TO_PHYSICAL(cpufifo->buf_end); + _piReg[5] = (((u32)cpufifo->wt_ptr&0x3FFFFFE0)&~0x04000000); + if(_cpgplinked) { + __GX_WriteFifoIntReset(GX_TRUE,GX_TRUE); + __GX_WriteFifoIntEnable(GX_ENABLE,GX_DISABLE); + __GX_FifoLink(GX_TRUE); + } + _CPU_ISR_Restore(level); +} + +void GX_Flush() +{ + if(__gx->dirtyState) + __GX_SetDirtyState(); + + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + + ppcsync(); +} + +void GX_EnableBreakPt(void *break_pt) +{ + u32 level = 0; + _CPU_ISR_Disable(level); + __GX_FifoReadDisable(); + _cpReg[30] = _SHIFTL(MEM_VIRTUAL_TO_PHYSICAL(break_pt),0,16); + _cpReg[31] = _SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(break_pt),16,16); + __gx->cpCRreg = (__gx->cpCRreg&~0x22)|0x22; + _cpReg[1] = __gx->cpCRreg; + _gxcurrbp = break_pt; + __GX_FifoReadEnable(); + _CPU_ISR_Restore(level); +} + +void GX_DisableBreakPt() +{ + u32 level = 0; + _CPU_ISR_Disable(level); + __gx->cpCRreg = (__gx->cpCRreg&~0x22); + _cpReg[1] = __gx->cpCRreg; + _gxcurrbp = NULL; + _CPU_ISR_Restore(level); +} + +#if defined(HW_DOL) +void GX_AbortFrame() +{ + _piReg[6] = 1; + __GX_WaitAbort(50); + _piReg[6] = 0; + __GX_WaitAbort(5); + + if(__GX_IsGPFifoReady()) + __GX_CleanGPFifo(); +} +#elif defined(HW_RVL) +void GX_AbortFrame() +{ + __GX_Abort(); + if(__GX_IsGPFifoReady()) { + __GX_CleanGPFifo(); + __GX_InitRevBits(); + + __gx->dirtyState = 0; + GX_Flush(); + } +} +#endif + +void GX_SetDrawSync(u16 token) +{ + u32 level = 0; + _CPU_ISR_Disable(level); + GX_LOAD_BP_REG(0x48000000 | token); + GX_LOAD_BP_REG(0x47000000 | token); + GX_Flush(); + _CPU_ISR_Restore(level); +} + +u16 GX_GetDrawSync() +{ + return _peReg[7]; +} + +void GX_SetDrawDone() +{ + u32 level; + _CPU_ISR_Disable(level); + GX_LOAD_BP_REG(0x45000002); // set draw done! + GX_Flush(); + _gxfinished = 0; + _CPU_ISR_Restore(level); +} + + +void GX_WaitDrawDone() +{ + u32 level; + _CPU_ISR_Disable(level); + while(!_gxfinished) + LWP_ThreadSleep(_gxwaitfinish); + _CPU_ISR_Restore(level); +} + +void GX_DrawDone() +{ + u32 level; + + _CPU_ISR_Disable(level); + GX_LOAD_BP_REG(0x45000002); // set draw done! + GX_Flush(); + + _gxfinished = 0; + _CPU_ISR_Flash(level); + + while(!_gxfinished) + LWP_ThreadSleep(_gxwaitfinish); + _CPU_ISR_Restore(level); +} + +GXDrawDoneCallback GX_SetDrawDoneCallback(GXDrawDoneCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + GXDrawDoneCallback ret = drawDoneCB; + drawDoneCB = cb; + _CPU_ISR_Restore(level); + return ret; +} + +GXDrawSyncCallback GX_SetDrawSyncCallback(GXDrawSyncCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + GXDrawSyncCallback ret = tokenCB; + tokenCB = cb; + _CPU_ISR_Restore(level); + return ret; +} + +GXBreakPtCallback GX_SetBreakPtCallback(GXBreakPtCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + GXBreakPtCallback ret = breakPtCB; + breakPtCB = cb; + _CPU_ISR_Restore(level); + return ret; +} + +void GX_PixModeSync() +{ + GX_LOAD_BP_REG(__gx->peCntrl); +} + +void GX_TexModeSync() +{ + GX_LOAD_BP_REG(0x63000000); +} + +void GX_SetMisc(u32 token,u32 value) +{ + u32 cnt; + + if(token==GX_MT_XF_FLUSH) { + __gx->xfFlushSafe = value; + cnt = cntlzw(__gx->xfFlushSafe); + __gx->xfFlushExp = _SHIFTR(cnt,5,16); + + __gx->xfFlush = 1; + if(!__gx->xfFlushSafe) return; + + __gx->dirtyState |= 0x0008; + } else if(token==GX_MT_DL_SAVE_CTX) { + __gx->saveDLctx = (value&0xff); + } + return; +} + +void GX_SetViewportJitter(f32 xOrig,f32 yOrig,f32 wd,f32 ht,f32 nearZ,f32 farZ,u32 field) +{ + f32 x0,y0,x1,y1,n,f,z; + static f32 Xfactor = 0.5; + static f32 Yfactor = 342.0; + static f32 Zfactor = 16777215.0; + + if(!field) yOrig -= Xfactor; + + x0 = wd*Xfactor; + y0 = (-ht)*Xfactor; + x1 = (xOrig+(wd*Xfactor))+Yfactor; + y1 = (yOrig+(ht*Xfactor))+Yfactor; + n = Zfactor*nearZ; + f = Zfactor*farZ; + z = f-n; + + GX_LOAD_XF_REGS(0x101a,6); + wgPipe->F32 = x0; + wgPipe->F32 = y0; + wgPipe->F32 = z; + wgPipe->F32 = x1; + wgPipe->F32 = y1; + wgPipe->F32 = f; +} + +void GX_SetViewport(f32 xOrig,f32 yOrig,f32 wd,f32 ht,f32 nearZ,f32 farZ) +{ + GX_SetViewportJitter(xOrig,yOrig,wd,ht,nearZ,farZ,1); +} + +void GX_LoadProjectionMtx(Mtx44 mt,u8 type) +{ + f32 tmp[7]; + + ((u32*)((void*)tmp))[6] = (u32)type; + tmp[0] = mt[0][0]; + tmp[2] = mt[1][1]; + tmp[4] = mt[2][2]; + tmp[5] = mt[2][3]; + + switch(type) { + case GX_PERSPECTIVE: + tmp[1] = mt[0][2]; + tmp[3] = mt[1][2]; + break; + case GX_ORTHOGRAPHIC: + tmp[1] = mt[0][3]; + tmp[3] = mt[1][3]; + break; + default: + tmp[1] = 0.0; + tmp[3] = 0.0; + break; + } + + GX_LOAD_XF_REGS(0x1020,7); + wgPipe->F32 = tmp[0]; + wgPipe->F32 = tmp[1]; + wgPipe->F32 = tmp[2]; + wgPipe->F32 = tmp[3]; + wgPipe->F32 = tmp[4]; + wgPipe->F32 = tmp[5]; + wgPipe->F32 = tmp[6]; +} + +static void __GetImageTileCount(u32 fmt,u16 wd,u16 ht,u32 *xtiles,u32 *ytiles,u32 *zplanes) +{ + u32 xshift,yshift,tile; + + switch(fmt) { + case GX_TF_I4: + case GX_TF_IA4: + case GX_CTF_R4: + case GX_CTF_RA4: + case GX_CTF_Z4: + xshift = 3; + yshift = 3; + break; + case GX_TF_Z8: + case GX_TF_I8: + case GX_CTF_A8: + case GX_CTF_R8: + case GX_CTF_G8: + case GX_CTF_B8: + case GX_CTF_Z8M: + case GX_CTF_Z8L: + xshift = 3; + yshift = 2; + break; + case GX_TF_IA8: + case GX_CTF_RA8: + case GX_CTF_RG8: + case GX_CTF_GB8: + case GX_TF_Z16: + case GX_TF_Z24X8: + case GX_CTF_Z16L: + case GX_TF_RGB565: + case GX_TF_RGB5A3: + case GX_TF_RGBA8: + xshift = 2; + yshift = 2; + break; + default: + xshift = 0; + yshift = 0; + break; + } + + if(!(wd&0xffff)) wd = 1; + if(!(ht&0xffff)) ht = 1; + + wd &= 0xffff; + tile = (wd+((1<>xshift; + *xtiles = tile; + + ht &= 0xffff; + tile = (ht+((1<>yshift; + *ytiles = tile; + + *zplanes = 1; + if(fmt==GX_TF_RGBA8 || fmt==GX_TF_Z24X8) *zplanes = 2; +} + +void GX_SetCopyClear(GXColor color,u32 zvalue) +{ + u32 val; + + val = (_SHIFTL(color.a,8,8))|(color.r&0xff); + GX_LOAD_BP_REG(0x4f000000|val); + + val = (_SHIFTL(color.g,8,8))|(color.b&0xff); + GX_LOAD_BP_REG(0x50000000|val); + + val = zvalue&0x00ffffff; + GX_LOAD_BP_REG(0x51000000|val); +} + +void GX_SetCopyClamp(u8 clamp) +{ + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~1)|(clamp&1); + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~2)|(clamp&2); +} + +void GX_SetDispCopyGamma(u8 gamma) +{ + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~0x180)|(_SHIFTL(gamma,7,2)); +} + +void GX_SetCopyFilter(u8 aa,u8 sample_pattern[12][2],u8 vf,u8 vfilter[7]) +{ + u32 reg01=0,reg02=0,reg03=0,reg04=0,reg53=0,reg54=0; + + if(aa) { + reg01 = sample_pattern[0][0]&0xf; + reg01 = (reg01&~0xf0)|(_SHIFTL(sample_pattern[0][1],4,4)); + reg01 = (reg01&~0xf00)|(_SHIFTL(sample_pattern[1][0],8,4)); + reg01 = (reg01&~0xf000)|(_SHIFTL(sample_pattern[1][1],12,4)); + reg01 = (reg01&~0xf0000)|(_SHIFTL(sample_pattern[2][0],16,4)); + reg01 = (reg01&~0xf00000)|(_SHIFTL(sample_pattern[2][1],20,4)); + reg01 = (reg01&~0xff000000)|(_SHIFTL(0x01,24,8)); + + reg02 = sample_pattern[3][0]&0xf; + reg02 = (reg02&~0xf0)|(_SHIFTL(sample_pattern[3][1],4,4)); + reg02 = (reg02&~0xf00)|(_SHIFTL(sample_pattern[4][0],8,4)); + reg02 = (reg02&~0xf000)|(_SHIFTL(sample_pattern[4][1],12,4)); + reg02 = (reg02&~0xf0000)|(_SHIFTL(sample_pattern[5][0],16,4)); + reg02 = (reg02&~0xf00000)|(_SHIFTL(sample_pattern[5][1],20,4)); + reg02 = (reg02&~0xff000000)|(_SHIFTL(0x02,24,8)); + + reg03 = sample_pattern[6][0]&0xf; + reg03 = (reg03&~0xf0)|(_SHIFTL(sample_pattern[6][1],4,4)); + reg03 = (reg03&~0xf00)|(_SHIFTL(sample_pattern[7][0],8,4)); + reg03 = (reg03&~0xf000)|(_SHIFTL(sample_pattern[7][1],12,4)); + reg03 = (reg03&~0xf0000)|(_SHIFTL(sample_pattern[8][0],16,4)); + reg03 = (reg03&~0xf00000)|(_SHIFTL(sample_pattern[8][1],20,4)); + reg03 = (reg03&~0xff000000)|(_SHIFTL(0x03,24,8)); + + reg04 = sample_pattern[9][0]&0xf; + reg04 = (reg04&~0xf0)|(_SHIFTL(sample_pattern[9][1],4,4)); + reg04 = (reg04&~0xf00)|(_SHIFTL(sample_pattern[10][0],8,4)); + reg04 = (reg04&~0xf000)|(_SHIFTL(sample_pattern[10][1],12,4)); + reg04 = (reg04&~0xf0000)|(_SHIFTL(sample_pattern[11][0],16,4)); + reg04 = (reg04&~0xf00000)|(_SHIFTL(sample_pattern[11][1],20,4)); + reg04 = (reg04&~0xff000000)|(_SHIFTL(0x04,24,8)); + } else { + reg01 = 0x01666666; + reg02 = 0x02666666; + reg03 = 0x03666666; + reg04 = 0x04666666; + } + GX_LOAD_BP_REG(reg01); + GX_LOAD_BP_REG(reg02); + GX_LOAD_BP_REG(reg03); + GX_LOAD_BP_REG(reg04); + + reg53 = 0x53595000; + reg54 = 0x54000015; + if(vf) { + reg53 = 0x53000000|(vfilter[0]&0x3f); + reg53 = (reg53&~0xfc0)|(_SHIFTL(vfilter[1],6,6)); + reg53 = (reg53&~0x3f000)|(_SHIFTL(vfilter[2],12,6)); + reg53 = (reg53&~0xfc0000)|(_SHIFTL(vfilter[3],18,6)); + + reg54 = 0x54000000|(vfilter[4]&0x3f); + reg54 = (reg54&~0xfc0)|(_SHIFTL(vfilter[5],6,6)); + reg54 = (reg54&~0x3f000)|(_SHIFTL(vfilter[6],12,6)); + } + GX_LOAD_BP_REG(reg53); + GX_LOAD_BP_REG(reg54); +} + +void GX_SetDispCopyFrame2Field(u8 mode) +{ + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~0x3000)|(_SHIFTL(mode,12,2)); +} + +u32 GX_SetDispCopyYScale(f32 yscale) +{ + u32 ht,yScale = 0; + + yScale = ((u32)(256.0f/yscale))&0x1ff; + GX_LOAD_BP_REG(0x4e000000|yScale); + + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~0x400)|(_SHIFTL(((256-yScale)>0),10,1)); + ht = _SHIFTR(__gx->dispCopyWH,12,10)+1; + return __GX_GetNumXfbLines(ht,yScale); +} + +void GX_SetDispCopyDst(u16 wd,u16 ht) +{ + __gx->dispCopyDst = (__gx->dispCopyDst&~0x3ff)|(_SHIFTR(wd,4,10)); + __gx->dispCopyDst = (__gx->dispCopyDst&~0xff000000)|(_SHIFTL(0x4d,24,8)); +} + +void GX_SetDispCopySrc(u16 left,u16 top,u16 wd,u16 ht) +{ + __gx->dispCopyTL = (__gx->dispCopyTL&~0x00ffffff)|XY(left,top); + __gx->dispCopyTL = (__gx->dispCopyTL&~0xff000000)|(_SHIFTL(0x49,24,8)); + __gx->dispCopyWH = (__gx->dispCopyWH&~0x00ffffff)|XY((wd-1),(ht-1)); + __gx->dispCopyWH = (__gx->dispCopyWH&~0xff000000)|(_SHIFTL(0x4a,24,8)); +} + +void GX_CopyDisp(void *dest,u8 clear) +{ + u8 clflag; + u32 val; + + if(clear) { + val= (__gx->peZMode&~0xf)|0xf; + GX_LOAD_BP_REG(val); + val = (__gx->peCMode0&~0x3); + GX_LOAD_BP_REG(val); + } + + clflag = 0; + if(clear || (__gx->peCntrl&0x7)==0x0003) { + if(__gx->peCntrl&0x40) { + clflag = 1; + val = (__gx->peCntrl&~0x40); + GX_LOAD_BP_REG(val); + } + } + + GX_LOAD_BP_REG(__gx->dispCopyTL); // set source top + GX_LOAD_BP_REG(__gx->dispCopyWH); + + GX_LOAD_BP_REG(__gx->dispCopyDst); + + val = 0x4b000000|(_SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(dest),5,24)); + GX_LOAD_BP_REG(val); + + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~0x800)|(_SHIFTL(clear,11,1)); + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~0x4000)|0x4000; + __gx->dispCopyCntrl = (__gx->dispCopyCntrl&~0xff000000)|(_SHIFTL(0x52,24,8)); + + GX_LOAD_BP_REG(__gx->dispCopyCntrl); + + if(clear) { + GX_LOAD_BP_REG(__gx->peZMode); + GX_LOAD_BP_REG(__gx->peCMode0); + } + if(clflag) GX_LOAD_BP_REG(__gx->peCntrl); +} + +void GX_CopyTex(void *dest,u8 clear) +{ + u8 clflag; + u32 val; + + if(clear) { + val = (__gx->peZMode&~0xf)|0xf; + GX_LOAD_BP_REG(val); + val = (__gx->peCMode0&~0x3); + GX_LOAD_BP_REG(val); + } + + clflag = 0; + val = __gx->peCntrl; + if(__gx->texCopyZTex && (val&0x7)!=0x0003) { + clflag = 1; + val = (val&~0x7)|0x0003; + } + if(clear || (val&0x7)==0x0003) { + if(val&0x40) { + clflag = 1; + val = (val&~0x40); + } + } + if(clflag) GX_LOAD_BP_REG(val); + + val = 0x4b000000|(_SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(dest),5,24)); + + GX_LOAD_BP_REG(__gx->texCopyTL); + GX_LOAD_BP_REG(__gx->texCopyWH); + GX_LOAD_BP_REG(__gx->texCopyDst); + GX_LOAD_BP_REG(val); + + __gx->texCopyCntrl = (__gx->texCopyCntrl&~0x800)|(_SHIFTL(clear,11,1)); + __gx->texCopyCntrl = (__gx->texCopyCntrl&~0x4000); + __gx->texCopyCntrl = (__gx->texCopyCntrl&~0xff000000)|(_SHIFTL(0x52,24,8)); + GX_LOAD_BP_REG(__gx->texCopyCntrl); + + if(clear) { + GX_LOAD_BP_REG(__gx->peZMode); + GX_LOAD_BP_REG(__gx->peCMode0); + } + if(clflag) GX_LOAD_BP_REG(__gx->peCntrl); +} + +void GX_SetTexCopySrc(u16 left,u16 top,u16 wd,u16 ht) +{ + __gx->texCopyTL = (__gx->texCopyTL&~0x00ffffff)|XY(left,top); + __gx->texCopyTL = (__gx->texCopyTL&~0xff000000)|(_SHIFTL(0x49,24,8)); + __gx->texCopyWH = (__gx->texCopyWH&~0x00ffffff)|XY((wd-1),(ht-1)); + __gx->texCopyWH = (__gx->texCopyWH&~0xff000000)|(_SHIFTL(0x4a,24,8)); +} + +void GX_SetTexCopyDst(u16 wd,u16 ht,u32 fmt,u8 mipmap) +{ + u8 lfmt = fmt&0xf; + u32 xtiles,ytiles,zplanes; + + __GetImageTileCount(fmt,wd,ht,&xtiles,&ytiles,&zplanes); + __gx->texCopyDst = (__gx->texCopyDst&~0x3ff)|((xtiles*zplanes)&0x3ff); + + if(fmt==GX_TF_Z16) lfmt = 11; + if(fmt==GX_CTF_YUVA8 || (fmt>=GX_TF_I4 && fmttexCopyCntrl = (__gx->texCopyCntrl&~0x18000)|0x18000; + else __gx->texCopyCntrl = (__gx->texCopyCntrl&~0x18000)|0x10000; + + __gx->texCopyCntrl = (__gx->texCopyCntrl&~0x8)|(lfmt&0x8); + __gx->texCopyCntrl = (__gx->texCopyCntrl&~0x200)|(_SHIFTL(mipmap,9,1)); + __gx->texCopyCntrl = (__gx->texCopyCntrl&~0x70)|(_SHIFTL(lfmt,4,3)); + + __gx->texCopyDst = (__gx->texCopyDst&~0xff000000)|(_SHIFTL(0x4d,24,8)); + + __gx->texCopyZTex = ((fmt&_GX_TF_ZTF)==_GX_TF_ZTF); +} + +void GX_ClearBoundingBox() +{ + GX_LOAD_BP_REG(0x550003ff); + GX_LOAD_BP_REG(0x560003ff); +} + +void GX_BeginDispList(void *list,u32 size) +{ + struct __gxfifo *fifo; + + if(__gx->dirtyState) + __GX_SetDirtyState(); + + if(__gx->saveDLctx) + memcpy(_gx_saved_data,__gxregs,STRUCT_REGDEF_SIZE); + + fifo = (struct __gxfifo*)&_gx_dl_fifoobj; + fifo->buf_start = (u32)list; + fifo->buf_end = (u32)list + size - 4; + fifo->size = size; + + fifo->rd_ptr = (u32)list; + fifo->wt_ptr = (u32)list; + fifo->rdwt_dst = 0; + + __gx->gxFifoUnlinked = 1; + + GX_GetCPUFifo(&_gx_old_cpufifo); + GX_SetCPUFifo(&_gx_dl_fifoobj); + __GX_ResetWriteGatherPipe(); +} + +u32 GX_EndDispList() +{ + u32 level; + u8 wrap = 0; + + GX_GetCPUFifo(&_gx_dl_fifoobj); + GX_SetCPUFifo(&_gx_old_cpufifo); + + if(__gx->saveDLctx) { + _CPU_ISR_Disable(level); + memcpy(__gxregs,_gx_saved_data,STRUCT_REGDEF_SIZE); + _CPU_ISR_Restore(level); + } + + __gx->gxFifoUnlinked = 0; + + wrap = GX_GetFifoWrap(&_gx_dl_fifoobj); + if(wrap) return 0; + + return GX_GetFifoCount(&_gx_dl_fifoobj); +} + +void GX_CallDispList(void *list,u32 nbytes) +{ + if(__gx->dirtyState) + __GX_SetDirtyState(); + + if(!__gx->vcdClear) + __GX_SendFlushPrim(); + + wgPipe->U8 = 0x40; //call displaylist + wgPipe->U32 = MEM_VIRTUAL_TO_PHYSICAL(list); + wgPipe->U32 = nbytes; +} + +void GX_SetChanCtrl(s32 channel,u8 enable,u8 ambsrc,u8 matsrc,u8 litmask,u8 diff_fn,u8 attn_fn) +{ + u32 reg,difffn = (attn_fn==GX_AF_SPEC)?GX_DF_NONE:diff_fn; + u32 val = (matsrc&1)|(_SHIFTL(enable,1,1))|(_SHIFTL(litmask,2,4))|(_SHIFTL(ambsrc,6,1))|(_SHIFTL(difffn,7,2))|(_SHIFTL(((GX_AF_NONE-attn_fn)>0),9,1))|(_SHIFTL((attn_fn>0),10,1))|(_SHIFTL((_SHIFTR(litmask,4,4)),11,4)); + + reg = (channel&0x03); + __gx->chnCntrl[reg] = val; + __gx->dirtyState |= (0x1000<chnCntrl[2] = val; + __gx->dirtyState |= 0x5000; + } else { + __gx->chnCntrl[3] = val; + __gx->dirtyState |= 0xa000; + } +} + +void GX_SetChanAmbColor(s32 channel,GXColor color) +{ + u32 reg,val = (_SHIFTL(color.r,24,8))|(_SHIFTL(color.g,16,8))|(_SHIFTL(color.b,8,8))|0x00; + switch(channel) { + case GX_COLOR0: + reg = 0; + val |= (__gx->chnAmbColor[0]&0xff); + break; + case GX_COLOR1: + reg = 1; + val |= (__gx->chnAmbColor[1]&0xff); + break; + case GX_ALPHA0: + reg = 0; + val = ((__gx->chnAmbColor[0]&~0xff)|(color.a&0xff)); + break; + case GX_ALPHA1: + reg = 1; + val = ((__gx->chnAmbColor[1]&~0xff)|(color.a&0xff)); + break; + case GX_COLOR0A0: + reg = 0; + val |= (color.a&0xFF); + break; + case GX_COLOR1A1: + reg = 1; + val |= (color.a&0xFF); + break; + default: + return; + } + + __gx->chnAmbColor[reg] = val; + __gx->dirtyState |= (0x0100<chnMatColor[0]&0xff); + break; + case GX_COLOR1: + reg = 1; + val |= (__gx->chnMatColor[1]&0xff); + break; + case GX_ALPHA0: + reg = 0; + val = ((__gx->chnMatColor[0]&~0xff)|(color.a&0xff)); + break; + case GX_ALPHA1: + reg = 1; + val = ((__gx->chnMatColor[1]&~0xff)|(color.a&0xff)); + break; + case GX_COLOR0A0: + reg = 0; + val |= (color.a&0xFF); + break; + case GX_COLOR1A1: + reg = 1; + val |= (color.a&0xFF); + break; + default: + return; + } + + __gx->chnMatColor[reg] = val; + __gx->dirtyState |= (0x0400<=GX_VA_POS && attr<=GX_LIGHTARRAY) { + idx = attr-GX_VA_POS; + GX_LOAD_CP_REG((0xA0+idx),(u32)MEM_VIRTUAL_TO_PHYSICAL(ptr)); + GX_LOAD_CP_REG((0xB0+idx),(u32)stride); + } +} + +static __inline__ void __SETVCDATTR(u8 attr,u8 type) +{ + switch(attr) { + case GX_VA_PTNMTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x1)|(type&0x1); + break; + case GX_VA_TEX0MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x2)|(_SHIFTL(type,1,1)); + break; + case GX_VA_TEX1MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x4)|(_SHIFTL(type,2,1)); + break; + case GX_VA_TEX2MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x8)|(_SHIFTL(type,3,1)); + break; + case GX_VA_TEX3MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x10)|(_SHIFTL(type,4,1)); + break; + case GX_VA_TEX4MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x20)|(_SHIFTL(type,5,1)); + break; + case GX_VA_TEX5MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x40)|(_SHIFTL(type,6,1)); + break; + case GX_VA_TEX6MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x80)|(_SHIFTL(type,7,1)); + break; + case GX_VA_TEX7MTXIDX: + __gx->vcdLo = (__gx->vcdLo&~0x100)|(_SHIFTL(type,8,1)); + break; + case GX_VA_POS: + __gx->vcdLo = (__gx->vcdLo&~0x600)|(_SHIFTL(type,9,2)); + break; + case GX_VA_NRM: + __gx->vcdLo = (__gx->vcdLo&~0x1800)|(_SHIFTL(type,11,2)); + __gx->vcdNrms = 1; + break; + case GX_VA_NBT: + __gx->vcdLo = (__gx->vcdLo&~0x1800)|(_SHIFTL(type,11,2)); + __gx->vcdNrms = 2; + break; + case GX_VA_CLR0: + __gx->vcdLo = (__gx->vcdLo&~0x6000)|(_SHIFTL(type,13,2)); + break; + case GX_VA_CLR1: + __gx->vcdLo = (__gx->vcdLo&~0x18000)|(_SHIFTL(type,15,2)); + break; + case GX_VA_TEX0: + __gx->vcdHi = (__gx->vcdHi&~0x3)|(type&0x3); + break; + case GX_VA_TEX1: + __gx->vcdHi = (__gx->vcdHi&~0xc)|(_SHIFTL(type,2,2)); + break; + case GX_VA_TEX2: + __gx->vcdHi = (__gx->vcdHi&~0x30)|(_SHIFTL(type,4,2)); + break; + case GX_VA_TEX3: + __gx->vcdHi = (__gx->vcdHi&~0xc0)|(_SHIFTL(type,6,2)); + break; + case GX_VA_TEX4: + __gx->vcdHi = (__gx->vcdHi&~0x300)|(_SHIFTL(type,8,2)); + break; + case GX_VA_TEX5: + __gx->vcdHi = (__gx->vcdHi&~0xc00)|(_SHIFTL(type,10,2)); + break; + case GX_VA_TEX6: + __gx->vcdHi = (__gx->vcdHi&~0x3000)|(_SHIFTL(type,12,2)); + break; + case GX_VA_TEX7: + __gx->vcdHi = (__gx->vcdHi&~0xc000)|(_SHIFTL(type,14,2)); + break; + } +} + +void GX_SetVtxDesc(u8 attr,u8 type) +{ + __SETVCDATTR(attr,type); + __gx->dirtyState |= 0x0008; +} + +void GX_SetVtxDescv(GXVtxDesc *attr_list) +{ + u32 i; + + if(!attr_list) return; + + for(i=0;idirtyState |= 0x0008; +} + +void GX_GetVtxDescv(GXVtxDesc *attr_list) +{ + u32 count; + + // Clear everything first + for(count=0;countvcdLo&0x1) { + attr_list[count].attr = GX_VA_PTNMTXIDX; + attr_list[count].type = __gx->vcdLo&0x1; + count++; + } + + if(__gx->vcdLo&0x2) { + attr_list[count].attr = GX_VA_TEX0MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x2,1,1); + count++; + } + + if(__gx->vcdLo&0x4) { + attr_list[count].attr = GX_VA_TEX1MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x4,2,1); + count++; + } + + if(__gx->vcdLo&0x8) { + attr_list[count].attr = GX_VA_TEX2MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x8,3,1); + count++; + } + + if(__gx->vcdLo&0x10) { + attr_list[count].attr = GX_VA_TEX3MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x10,4,1); + count++; + } + + if(__gx->vcdLo&0x20) { + attr_list[count].attr = GX_VA_TEX4MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x20,5,1); + count++; + } + + if(__gx->vcdLo&0x40) { + attr_list[count].attr = GX_VA_TEX5MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x40,6,1); + count++; + } + + if(__gx->vcdLo&0x80) { + attr_list[count].attr = GX_VA_TEX6MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x80,7,1); + count++; + } + + if(__gx->vcdLo&0x100) { + attr_list[count].attr = GX_VA_TEX7MTXIDX; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x100,8,1); + count++; + } + + if(__gx->vcdLo&0x600) { + attr_list[count].attr = GX_VA_POS; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x600,9,2); + count++; + } + + if(__gx->vcdLo&0x1800) { + if(__gx->vcdNrms==1) { + attr_list[count].attr = GX_VA_NRM; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x1800,11,2); + count++; + } else if(__gx->vcdNrms==2){ + attr_list[count].attr = GX_VA_NBT; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x1800,11,2); + count++; + } + } + + if(__gx->vcdLo&0x6000) { + attr_list[count].attr = GX_VA_CLR0; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x6000,13,2); + count++; + } + + if(__gx->vcdLo&0x18000) { + attr_list[count].attr = GX_VA_CLR1; + attr_list[count].type = _SHIFTR(__gx->vcdLo&0x18000,15,2); + count++; + } + + if(__gx->vcdHi&0x3) { + attr_list[count].attr = GX_VA_TEX0; + attr_list[count].type = __gx->vcdHi&0x3; + count++; + } + + if(__gx->vcdHi&0xc) { + attr_list[count].attr = GX_VA_TEX1; + attr_list[count].type = _SHIFTR(__gx->vcdHi&0xc,2,2); + count++; + } + + if(__gx->vcdHi&0x30) { + attr_list[count].attr = GX_VA_TEX2; + attr_list[count].type = _SHIFTR(__gx->vcdHi&0x30,4,2); + count++; + } + + if(__gx->vcdHi&0xc0) { + attr_list[count].attr = GX_VA_TEX3; + attr_list[count].type = _SHIFTR(__gx->vcdHi&0xc0,6,2); + count++; + } + + if(__gx->vcdHi&0x300) { + attr_list[count].attr = GX_VA_TEX4; + attr_list[count].type = _SHIFTR(__gx->vcdHi&0x300,8,2); + count++; + } + + if(__gx->vcdHi&0xc00) { + attr_list[count].attr = GX_VA_TEX5; + attr_list[count].type = _SHIFTR(__gx->vcdHi&0xc00,10,2); + count++; + } + + if(__gx->vcdHi&0x3000) { + attr_list[count].attr = GX_VA_TEX6; + attr_list[count].type = _SHIFTR(__gx->vcdHi&0x3000,12,2); + count++; + } + + if(__gx->vcdHi&0xc000) { + attr_list[count].attr = GX_VA_TEX7; + attr_list[count].type = _SHIFTR(__gx->vcdHi&0xc000,14,2); + count++; + } +} + +static __inline__ void __SETVCDFMT(u8 vtxfmt,u32 vtxattr,u32 comptype,u32 compsize,u32 frac) +{ + u8 vat = (vtxfmt&7); + + if(vtxattr==GX_VA_POS && (comptype==GX_POS_XY || comptype==GX_POS_XYZ) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x1)|(comptype&1); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0xe)|(_SHIFTL(compsize,1,3)); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x1f0)|(_SHIFTL(frac,4,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_NRM && comptype==GX_NRM_XYZ + && (compsize==GX_S8 || compsize==GX_S16 || compsize==GX_F32)) { + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x200); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x1C00)|(_SHIFTL(compsize,10,3)); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x80000000); + } else if(vtxattr==GX_VA_NBT && (comptype==GX_NRM_NBT || comptype==GX_NRM_NBT3) + && (compsize==GX_S8 || compsize==GX_S16 || compsize==GX_F32)) { + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x200)|0x200; + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x1C00)|(_SHIFTL(compsize,10,3)); + if(comptype==GX_NRM_NBT3) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x80000000)|0x80000000; + } else if(vtxattr==GX_VA_CLR0 && (comptype==GX_CLR_RGB || comptype==GX_CLR_RGBA) + && (compsize>=GX_RGB565 && compsize<=GX_RGBA8)) { + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x2000)|(_SHIFTL(comptype,13,1)); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x1C000)|(_SHIFTL(compsize,14,3)); + } else if(vtxattr==GX_VA_CLR1 && (comptype==GX_CLR_RGB || comptype==GX_CLR_RGBA) + && (compsize>=GX_RGB565 && compsize<=GX_RGBA8)) { + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x20000)|(_SHIFTL(comptype,17,1)); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x1C0000)|(_SHIFTL(compsize,18,3)); + } else if(vtxattr==GX_VA_TEX0 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x200000)|(_SHIFTL(comptype,21,1)); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x1C00000)|(_SHIFTL(compsize,22,3)); + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x3E000000)|(_SHIFTL(frac,25,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_TEX1 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x1)|(comptype&1); + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0xe)|(_SHIFTL(compsize,1,3)); + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x1F0)|(_SHIFTL(frac,4,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_TEX2 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x200)|(_SHIFTL(comptype,9,1)); + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x1C00)|(_SHIFTL(compsize,10,3)); + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x3E000)|(_SHIFTL(frac,13,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_TEX3 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x40000)|(_SHIFTL(comptype,18,1)); + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x380000)|(_SHIFTL(compsize,19,3)); + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x7C00000)|(_SHIFTL(frac,22,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_TEX4 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x8000000)|(_SHIFTL(comptype,27,1)); + __gx->VAT1reg[vat] = (__gx->VAT1reg[vat]&~0x70000000)|(_SHIFTL(compsize,28,3)); + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x1f)|(frac&0x1f); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_TEX5 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x20)|(_SHIFTL(comptype,5,1)); + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x1C0)|(_SHIFTL(compsize,6,3)); + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x3E00)|(_SHIFTL(frac,9,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_TEX6 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x4000)|(_SHIFTL(comptype,14,1)); + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x38000)|(_SHIFTL(compsize,15,3)); + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x7C0000)|(_SHIFTL(frac,18,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } else if(vtxattr==GX_VA_TEX7 && (comptype==GX_TEX_S || comptype==GX_TEX_ST) + && (compsize>=GX_U8 && compsize<=GX_F32)) { + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x800000)|(_SHIFTL(comptype,23,1)); + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0x7000000)|(_SHIFTL(compsize,24,3)); + __gx->VAT2reg[vat] = (__gx->VAT2reg[vat]&~0xF8000000)|(_SHIFTL(frac,27,5)); + if(frac) + __gx->VAT0reg[vat] = (__gx->VAT0reg[vat]&~0x40000000)|0x40000000; + } +} + +void GX_SetVtxAttrFmt(u8 vtxfmt,u32 vtxattr,u32 comptype,u32 compsize,u32 frac) +{ + __SETVCDFMT(vtxfmt,vtxattr,comptype,compsize,frac); + __gx->VATTable |= (1<dirtyState |= 0x0010; +} + +void GX_SetVtxAttrFmtv(u8 vtxfmt,GXVtxAttrFmt *attr_list) +{ + u32 i; + + for(i=0;iVATTable |= (1<dirtyState |= 0x0010; +} + +void GX_Begin(u8 primitve,u8 vtxfmt,u16 vtxcnt) +{ + u8 reg = primitve|(vtxfmt&7); + + if(__gx->dirtyState) + __GX_SetDirtyState(); + + wgPipe->U8 = reg; + wgPipe->U16 = vtxcnt; +} + +void GX_SetTexCoordGen(u16 texcoord,u32 tgen_typ,u32 tgen_src,u32 mtxsrc) +{ + GX_SetTexCoordGen2(texcoord,tgen_typ,tgen_src,mtxsrc,GX_FALSE,GX_DTTIDENTITY); +} + +void GX_SetTexCoordGen2(u16 texcoord,u32 tgen_typ,u32 tgen_src,u32 mtxsrc,u32 normalize,u32 postmtx) +{ + u32 txc; + u32 texcoords; + u8 vtxrow,stq; + + if(texcoord>=GX_MAXCOORD) return; + + stq = 0; + switch(tgen_src) { + case GX_TG_POS: + vtxrow = 0; + stq = 1; + break; + case GX_TG_NRM: + vtxrow = 1; + stq = 1; + break; + case GX_TG_BINRM: + vtxrow = 3; + stq = 1; + break; + case GX_TG_TANGENT: + vtxrow = 4; + stq = 1; + break; + case GX_TG_COLOR0: + vtxrow = 2; + break; + case GX_TG_COLOR1: + vtxrow = 2; + break; + case GX_TG_TEX0: + vtxrow = 5; + break; + case GX_TG_TEX1: + vtxrow = 6; + break; + case GX_TG_TEX2: + vtxrow = 7; + break; + case GX_TG_TEX3: + vtxrow = 8; + break; + case GX_TG_TEX4: + vtxrow = 9; + break; + case GX_TG_TEX5: + vtxrow = 10; + break; + case GX_TG_TEX6: + vtxrow = 11; + break; + case GX_TG_TEX7: + vtxrow = 12; + break; + default: + vtxrow = 5; + break; + } + + texcoords = 0; + txc = (texcoord&7); + if((tgen_typ==GX_TG_MTX3x4 || tgen_typ==GX_TG_MTX2x4)) + { + if(tgen_typ==GX_TG_MTX3x4) texcoords = 0x02; + + texcoords |= (_SHIFTL(stq,2,1)); + texcoords |= (_SHIFTL(vtxrow,7,5)); + } else if((tgen_typ>=GX_TG_BUMP0 && tgen_typ<=GX_TG_BUMP7)) + { + tgen_src -= GX_TG_TEXCOORD0; + tgen_typ -= GX_TG_BUMP0; + + texcoords = 0x10; + texcoords |= (_SHIFTL(stq,2,1)); + texcoords |= (_SHIFTL(vtxrow,7,5)); + texcoords |= (_SHIFTL(tgen_src,12,3)); + texcoords |= (_SHIFTL(tgen_typ,15,3)); + } else if(tgen_typ==GX_TG_SRTG) { + if(tgen_src==GX_TG_COLOR0) texcoords = 0x20; + else if(tgen_src==GX_TG_COLOR1) texcoords = 0x30; + texcoords |= (_SHIFTL(stq,2,1)); + texcoords |= (_SHIFTL(2,7,5)); + } + + postmtx -= GX_DTTMTX0; + __gx->texCoordGen[txc] = texcoords; + __gx->texCoordGen2[txc] = ((_SHIFTL(normalize,8,1))|(postmtx&0x3f)); + + switch(texcoord) { + case GX_TEXCOORD0: + __gx->mtxIdxLo = (__gx->mtxIdxLo&~0xfc0)|(_SHIFTL(mtxsrc,6,6)); + break; + case GX_TEXCOORD1: + __gx->mtxIdxLo = (__gx->mtxIdxLo&~0x3f000)|(_SHIFTL(mtxsrc,12,6)); + break; + case GX_TEXCOORD2: + __gx->mtxIdxLo = (__gx->mtxIdxLo&~0xfc0000)|(_SHIFTL(mtxsrc,18,6)); + break; + case GX_TEXCOORD3: + __gx->mtxIdxLo = (__gx->mtxIdxLo&~0x3f000000)|(_SHIFTL(mtxsrc,24,6)); + break; + case GX_TEXCOORD4: + __gx->mtxIdxHi = (__gx->mtxIdxHi&~0x3f)|(mtxsrc&0x3f); + break; + case GX_TEXCOORD5: + __gx->mtxIdxHi = (__gx->mtxIdxHi&~0xfc0)|(_SHIFTL(mtxsrc,6,6)); + break; + case GX_TEXCOORD6: + __gx->mtxIdxHi = (__gx->mtxIdxHi&~0x3f000)|(_SHIFTL(mtxsrc,12,6)); + break; + case GX_TEXCOORD7: + __gx->mtxIdxHi = (__gx->mtxIdxHi&~0xfc0000)|(_SHIFTL(mtxsrc,18,6)); + break; + } + __gx->dirtyState |= (0x04000000|(0x00010000<U8 = 0x20; + wgPipe->U32 = ((_SHIFTL(mtxidx,16,16))|0xb000|(_SHIFTL(pnidx,2,8))); +} + +void GX_LoadNrmMtxImm(Mtx mt,u32 pnidx) +{ + GX_LOAD_XF_REGS((0x0400|(pnidx*3)),9); + WriteMtxPS3x3from4x3(mt,(void*)wgPipe); +} + +void GX_LoadNrmMtxImm3x3(Mtx33 mt,u32 pnidx) +{ + GX_LOAD_XF_REGS((0x0400|(pnidx*3)),9); + WriteMtxPS3x3(mt,(void*)wgPipe); +} + +void GX_LoadNrmMtxIdx3x3(u16 mtxidx,u32 pnidx) +{ + wgPipe->U8 = 0x28; + wgPipe->U32 = ((_SHIFTL(mtxidx,16,16))|0x8000|(0x0400|(pnidx*3))); +} + +void GX_LoadTexMtxImm(Mtx mt,u32 texidx,u8 type) +{ + u32 addr = 0; + u32 rows = (type==GX_MTX2x4)?2:3; + + if(texidxU8 = 0x30; + wgPipe->U32 = ((_SHIFTL(mtxidx,16,16))|(_SHIFTL(size,12,4))|addr); +} + +void GX_SetCurrentMtx(u32 mtx) +{ + __gx->mtxIdxLo = (__gx->mtxIdxLo&~0x3f)|(mtx&0x3f); + __gx->dirtyState |= 0x04000000; +} + +void GX_SetNumTexGens(u32 nr) +{ + __gx->genMode = (__gx->genMode&~0xf)|(nr&0xf); + __gx->dirtyState |= 0x02000004; +} + +void GX_InvVtxCache() +{ + wgPipe->U8 = 0x48; // vertex cache weg +} + +void GX_SetZMode(u8 enable,u8 func,u8 update_enable) +{ + __gx->peZMode = (__gx->peZMode&~0x1)|(enable&1); + __gx->peZMode = (__gx->peZMode&~0xe)|(_SHIFTL(func,1,3)); + __gx->peZMode = (__gx->peZMode&~0x10)|(_SHIFTL(update_enable,4,1)); + GX_LOAD_BP_REG(__gx->peZMode); +} + +u32 GX_GetTexObjFmt(GXTexObj *obj) +{ + return ((struct __gx_texobj*)obj)->tex_fmt; +} + +u32 GX_GetTexObjMipMap(GXTexObj *obj) +{ + return (((struct __gx_texobj*)obj)->tex_flag&0x01); +} +void* GX_GetTexObjData(GXTexObj *obj) +{ + return (void*)(_SHIFTL(((struct __gx_texobj*)obj)->tex_maddr & 0x00ffffff,5,24)); +} + +u8 GX_GetTexObjWrapS(GXTexObj* obj) +{ + return ((struct __gx_texobj*)obj)->tex_filt & 0x03; +} + +u8 GX_GetTexObjWrapT(GXTexObj* obj) +{ + return _SHIFTR(((struct __gx_texobj*)obj)->tex_filt & 0x0c, 2, 2); +} + +u16 GX_GetTexObjHeight(GXTexObj* obj) +{ + return _SHIFTR(((struct __gx_texobj*)obj)->tex_size & 0xffc00, 10, 10) + 1; +} + +u16 GX_GetTexObjWidth(GXTexObj* obj) +{ + return (((struct __gx_texobj*)obj)->tex_size & 0x3ff) + 1; +} + + +void GX_GetTexObjAll(GXTexObj* obj, void** image_ptr, u16* width, u16* height, + u8* format, u8* wrap_s, u8* wrap_t, u8* mipmap) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + *image_ptr = (void*)(_SHIFTL(ptr->tex_maddr & 0x00ffffff,5,24)); + *width = (ptr->tex_size & 0x3ff) + 1; + *height = _SHIFTR(ptr->tex_size & 0xffc00, 10, 10) + 1; + *format = ptr->tex_fmt; + *wrap_s = ptr->tex_filt & 0x03; + *wrap_t = _SHIFTR(ptr->tex_filt & 0x0c, 2, 2); + *mipmap = ptr->tex_flag & 0x01; +} +u32 GX_GetTexBufferSize(u16 wd,u16 ht,u32 fmt,u8 mipmap,u8 maxlod) +{ + u32 xshift,yshift,xtiles,ytiles,bitsize,size; + + switch(fmt) { + case GX_TF_I4: + case GX_TF_CMPR: + case GX_CTF_R4: + case GX_CTF_RA4: + case GX_CTF_Z4: + xshift = 3; + yshift = 3; + break; + case GX_TF_Z8: + case GX_TF_I8: + case GX_TF_IA4: + case GX_CTF_A8: + case GX_CTF_R8: + case GX_CTF_G8: + case GX_CTF_B8: + case GX_CTF_RG8: + case GX_CTF_GB8: + case GX_CTF_Z8M: + case GX_CTF_Z8L: + xshift = 3; + yshift = 2; + break; + case GX_TF_IA8: + case GX_TF_Z16: + case GX_TF_Z24X8: + case GX_TF_RGB565: + case GX_TF_RGB5A3: + case GX_TF_RGBA8: + case GX_CTF_Z16L: + case GX_CTF_RA8: + xshift = 2; + yshift = 2; + break; + default: + xshift = 2; + yshift = 2; + break; + } + + bitsize = 32; + if(fmt==GX_TF_RGBA8 || fmt==GX_TF_Z24X8) bitsize = 64; + + size = 0; + if(mipmap) { + u32 cnt = (maxlod&0xff); + while(cnt) { + u32 w = wd&0xffff; + u32 h = ht&0xffff; + xtiles = ((w+(1<>xshift; + ytiles = ((h+(1<>yshift; + if(cnt==0) return size; + + size += ((xtiles*ytiles)*bitsize); + if(w==0x0001 && h==0x0001) return size; + if(wd>0x0001) wd = (w>>1); + else wd = 0x0001; + if(ht>0x0001) ht = (h>>1); + else ht = 0x0001; + + --cnt; + } + return size; + } + + wd &= 0xffff; + xtiles = (wd+((1<>xshift; + + ht &= 0xffff; + ytiles = (ht+((1<>yshift; + + size = ((xtiles*ytiles)*bitsize); + + return size; +} + +void GX_InitTexCacheRegion(GXTexRegion *region,u8 is32bmipmap,u32 tmem_even,u8 size_even,u32 tmem_odd,u8 size_odd) +{ + u32 sze = 0; + struct __gx_texregion *ptr = (struct __gx_texregion*)region; + + switch(size_even) { + case GX_TEXCACHE_32K: + sze = 3; + break; + case GX_TEXCACHE_128K: + sze = 4; + break; + case GX_TEXCACHE_512K: + sze = 5; + break; + default: + sze = 3; + break; + } + ptr->tmem_even = 0; + ptr->tmem_even = (ptr->tmem_even&~0x7fff)|(_SHIFTR(tmem_even,5,15)); + ptr->tmem_even = (ptr->tmem_even&~0x38000)|(_SHIFTL(sze,15,3)); + ptr->tmem_even = (ptr->tmem_even&~0x1C0000)|(_SHIFTL(sze,18,3)); + + switch(size_odd) { + case GX_TEXCACHE_32K: + sze = 3; + break; + case GX_TEXCACHE_128K: + sze = 4; + break; + case GX_TEXCACHE_512K: + sze = 5; + break; + default: + sze = 3; + break; + } + ptr->tmem_odd = 0; + ptr->tmem_odd = (ptr->tmem_odd&~0x7fff)|(_SHIFTR(tmem_odd,5,15)); + ptr->tmem_odd = (ptr->tmem_odd&~0x38000)|(_SHIFTL(sze,15,3)); + ptr->tmem_odd = (ptr->tmem_odd&~0x1C0000)|(_SHIFTL(sze,18,3)); + + ptr->ismipmap = is32bmipmap; + ptr->iscached = 1; +} + +void GX_InitTexPreloadRegion(GXTexRegion *region,u32 tmem_even,u32 size_even,u32 tmem_odd,u32 size_odd) +{ + struct __gx_texregion *ptr = (struct __gx_texregion*)region; + + ptr->tmem_even = 0; + ptr->tmem_even = (ptr->tmem_even&~0x7FFF)|(_SHIFTR(tmem_even,5,15)); + ptr->tmem_even = (ptr->tmem_even&~0x200000)|0x200000; + + ptr->tmem_odd = 0; + ptr->tmem_odd = (ptr->tmem_odd&~0x7FFF)|(_SHIFTR(tmem_odd,5,15)); + + ptr->size_even = _SHIFTR(size_even,5,16); + ptr->size_odd = _SHIFTR(size_odd,5,16); + + ptr->ismipmap = 0; + ptr->iscached = 0; +} + +void GX_InitTlutRegion(GXTlutRegion *region,u32 tmem_addr,u8 tlut_sz) +{ + struct __gx_tlutregion *ptr = (struct __gx_tlutregion*)region; + + tmem_addr -= 0x80000; + + ptr->tmem_addr_conf = 0; + ptr->tmem_addr_conf = (ptr->tmem_addr_conf&~0x3ff)|(_SHIFTR(tmem_addr,9,10)); + ptr->tmem_addr_conf = (ptr->tmem_addr_conf&~0x1FFC00)|(_SHIFTL(tlut_sz,10,10)); + ptr->tmem_addr_conf = (ptr->tmem_addr_conf&~0xff000000)|(_SHIFTL(0x65,24,8)); +} + +void GX_InitTexObj(GXTexObj *obj,void *img_ptr,u16 wd,u16 ht,u8 fmt,u8 wrap_s,u8 wrap_t,u8 mipmap) +{ + u32 nwd,nht; + u32 xshift,yshift; + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + + if(!obj) return; + + memset(obj,0,sizeof(GXTexObj)); + + ptr->tex_filt = (ptr->tex_filt&~0x03)|(wrap_s&3); + ptr->tex_filt = (ptr->tex_filt&~0x0c)|(_SHIFTL(wrap_t,2,2)); + ptr->tex_filt = (ptr->tex_filt&~0x10)|0x10; + + if(mipmap) { + ptr->tex_flag |= 0x01; + if(fmt==GX_TF_CI4 || fmt==GX_TF_CI8 || fmt==GX_TF_CI14) + ptr->tex_filt = (ptr->tex_filt&~0xe0)|0x00a0; + else + ptr->tex_filt = (ptr->tex_filt&~0xe0)|0x00c0; + } else + ptr->tex_filt= (ptr->tex_filt&~0xE0)|0x0080; + + ptr->tex_fmt = fmt; + ptr->tex_size = (ptr->tex_size&~0x3ff)|((wd-1)&0x3ff); + ptr->tex_size = (ptr->tex_size&~0xFFC00)|(_SHIFTL((ht-1),10,10)); + ptr->tex_size = (ptr->tex_size&~0xF00000)|(_SHIFTL(fmt,20,4)); + ptr->tex_maddr = (ptr->tex_maddr&~0x00ffffff)|(_SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(img_ptr),5,24)); + + switch(fmt) { + case GX_TF_I4: + case GX_TF_CI4: + xshift = 3; + yshift = 3; + ptr->tex_tile_type = 1; + break; + case GX_TF_I8: + case GX_TF_IA4: + case GX_TF_CI8: + xshift = 3; + yshift = 2; + ptr->tex_tile_type = 2; + break; + case GX_TF_IA8: + case GX_TF_RGB565: + case GX_TF_RGB5A3: + case GX_TF_RGBA8: + xshift = 2; + yshift = 2; + ptr->tex_tile_type = 2; + break; + case GX_TF_CI14: + xshift = 2; + yshift = 2; + ptr->tex_tile_type = 3; + break; + case GX_TF_CMPR: + xshift = 3; + yshift = 3; + ptr->tex_tile_type = 0; + break; + default: + xshift = 2; + yshift = 2; + ptr->tex_tile_type = 2; + break; + } + + nwd = ((wd+(1<>xshift; + nht = ((ht+(1<>yshift; + ptr->tex_tile_cnt = (nwd*nht)&0x7fff; + + ptr->tex_flag |= 0x0002; +} + +void GX_InitTexObjCI(GXTexObj *obj,void *img_ptr,u16 wd,u16 ht,u8 fmt,u8 wrap_s,u8 wrap_t,u8 mipmap,u32 tlut_name) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + + GX_InitTexObj(obj,img_ptr,wd,ht,fmt,wrap_s,wrap_t,mipmap); + ptr->tex_flag &= ~0x02; + ptr->tex_tlut = tlut_name; +} + +void GX_InitTexObjLOD(GXTexObj *obj,u8 minfilt,u8 magfilt,f32 minlod,f32 maxlod,f32 lodbias,u8 biasclamp,u8 edgelod,u8 maxaniso) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + static u8 GX2HWFiltConv[] = {0x00,0x04,0x01,0x05,0x02,0x06,0x00,0x00}; + //static u8 HW2GXFiltConv[] = {0x00,0x02,0x04,0x00,0x01,0x03,0x05,0x00}; + + if(lodbias<-4.0f) lodbias = -4.0f; + else if(lodbias==4.0f) lodbias = 3.99f; + + ptr->tex_filt = (ptr->tex_filt&~0x1fe00)|(_SHIFTL(((u32)(32.0f*lodbias)),9,8)); + ptr->tex_filt = (ptr->tex_filt&~0x10)|(_SHIFTL((magfilt==GX_LINEAR?1:0),4,1)); + ptr->tex_filt = (ptr->tex_filt&~0xe0)|(_SHIFTL(GX2HWFiltConv[minfilt],5,3)); + ptr->tex_filt = (ptr->tex_filt&~0x100)|(_SHIFTL(!(edgelod&0xff),8,1)); + ptr->tex_filt = (ptr->tex_filt&~0x180000)|(_SHIFTL(maxaniso,19,2)); + ptr->tex_filt = (ptr->tex_filt&~0x200000)|(_SHIFTL(biasclamp,21,1)); + + if(minlod<0.0f) minlod = 0.0f; + else if(minlod>10.0f) minlod = 10.0f; + + if(maxlod<0.0f) maxlod = 0.0f; + else if(maxlod>10.0f) maxlod = 10.0f; + + ptr->tex_lod = (ptr->tex_lod&~0xff)|(((u32)(16.0f*minlod))&0xff); + ptr->tex_lod = (ptr->tex_lod&~0xff00)|(_SHIFTL(((u32)(16.0f*maxlod)),8,8)); +} + +void GX_InitTexObjData(GXTexObj *obj,void *img_ptr) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + ptr->tex_maddr = (ptr->tex_maddr&~0x00ffffff)|(_SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(img_ptr),5,24)); +} + +void GX_InitTexObjTlut(GXTexObj *obj,u32 tlut_name) +{ + ((struct __gx_texobj*)obj)->tex_tlut = tlut_name; +} + +void GX_InitTexObjWrapMode(GXTexObj *obj,u8 wrap_s,u8 wrap_t) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + + ptr->tex_filt = (ptr->tex_filt&~0x03)|(wrap_s&3); + ptr->tex_filt = (ptr->tex_filt&~0x0c)|(_SHIFTL(wrap_t,2,2)); +} + +void GX_InitTexObjFilterMode(GXTexObj *obj,u8 minfilt,u8 magfilt) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + static u8 GX2HWFiltConv[] = {0x00,0x04,0x01,0x05,0x02,0x06,0x00,0x00}; + + ptr->tex_filt = (ptr->tex_filt&~0x10)|(_SHIFTL((magfilt==GX_LINEAR?1:0),4,1)); + ptr->tex_filt = (ptr->tex_filt&~0xe0)|(_SHIFTL(GX2HWFiltConv[minfilt],5,3)); +} + +void GX_InitTexObjMinLOD(GXTexObj *obj,f32 minlod) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + + if(minlod<0.0f) minlod = 0.0f; + else if(minlod>10.0f) minlod = 10.0f; + + ptr->tex_lod = (ptr->tex_lod&~0xff)|(((u32)(16.0f*minlod))&0xff); +} + +void GX_InitTexObjMaxLOD(GXTexObj *obj,f32 maxlod) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + + if(maxlod<0.0f) maxlod = 0.0f; + else if(maxlod>10.0f) maxlod = 10.0f; + + ptr->tex_lod = (ptr->tex_lod&~0xff00)|(_SHIFTL(((u32)(16.0f*maxlod)),8,8)); +} + +void GX_InitTexObjLODBias(GXTexObj *obj,f32 lodbias) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + + if(lodbias<-4.0f) lodbias = -4.0f; + else if(lodbias==4.0f) lodbias = 3.99f; + + ptr->tex_filt = (ptr->tex_filt&~0x1fe00)|(_SHIFTL(((u32)(32.0f*lodbias)),9,8)); +} + +void GX_InitTexObjBiasClamp(GXTexObj *obj,u8 biasclamp) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + ptr->tex_filt = (ptr->tex_filt&~0x200000)|(_SHIFTL(biasclamp,21,1)); +} + +void GX_InitTexObjEdgeLOD(GXTexObj *obj,u8 edgelod) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + ptr->tex_filt = (ptr->tex_filt&~0x100)|(_SHIFTL(!(edgelod&0xff),8,1)); +} + +void GX_InitTexObjMaxAniso(GXTexObj *obj,u8 maxaniso) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + ptr->tex_filt = (ptr->tex_filt&~0x180000)|(_SHIFTL(maxaniso,19,2)); +} + +void GX_InitTexObjUserData(GXTexObj *obj,void *userdata) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + ptr->usr_data = (u32)userdata; +} + +void* GX_GetTexObjUserData(GXTexObj *obj) +{ + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + return (void*)ptr->usr_data; +} + +void GX_InitTlutObj(GXTlutObj *obj,void *lut,u8 fmt,u16 entries) +{ + struct __gx_tlutobj *ptr = (struct __gx_tlutobj*)obj; + + memset(obj,0,sizeof(GXTlutObj)); + + ptr->tlut_fmt = _SHIFTL(fmt,10,2); + ptr->tlut_maddr = (ptr->tlut_maddr&~0x00ffffff)|(_SHIFTR(MEM_VIRTUAL_TO_PHYSICAL(lut),5,24)); + ptr->tlut_maddr = (ptr->tlut_maddr&~0xff000000)|(_SHIFTL(0x64,24,8)); + ptr->tlut_nentries = entries; +} + +void GX_LoadTexObj(GXTexObj *obj,u8 mapid) +{ + GXTexRegion *region = NULL; + + if(regionCB) + region = regionCB(obj,mapid); + + GX_LoadTexObjPreloaded(obj,region,mapid); +} + +void GX_LoadTexObjPreloaded(GXTexObj *obj,GXTexRegion *region,u8 mapid) +{ + u8 type; + struct __gx_tlutregion *tlut = NULL; + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + struct __gx_texregion *reg = (struct __gx_texregion*)region; + + ptr->tex_filt = (ptr->tex_filt&~0xff000000)|(_SHIFTL(_gxtexmode0ids[mapid],24,8)); + ptr->tex_lod = (ptr->tex_lod&~0xff000000)|(_SHIFTL(_gxtexmode1ids[mapid],24,8)); + ptr->tex_size = (ptr->tex_size&~0xff000000)|(_SHIFTL(_gxteximg0ids[mapid],24,8)); + ptr->tex_maddr = (ptr->tex_maddr&~0xff000000)|(_SHIFTL(_gxteximg3ids[mapid],24,8)); + + reg->tmem_even = (reg->tmem_even&~0xff000000)|(_SHIFTL(_gxteximg1ids[mapid],24,8)); + reg->tmem_odd = (reg->tmem_odd&~0xff000000)|(_SHIFTL(_gxteximg2ids[mapid],24,8)); + + GX_LOAD_BP_REG(ptr->tex_filt); + GX_LOAD_BP_REG(ptr->tex_lod); + GX_LOAD_BP_REG(ptr->tex_size); + + GX_LOAD_BP_REG(reg->tmem_even); + GX_LOAD_BP_REG(reg->tmem_odd); + + GX_LOAD_BP_REG(ptr->tex_maddr); + + type = ptr->tex_flag; + if(!(type&0x02)) { + if(tlut_regionCB) + tlut = (struct __gx_tlutregion*)tlut_regionCB(ptr->tex_tlut); + tlut->tmem_addr_base = (tlut->tmem_addr_base&~0xff000000)|(_SHIFTL(_gxtextlutids[mapid],24,8)); + GX_LOAD_BP_REG(tlut->tmem_addr_base); + } + + __gx->texMapSize[mapid] = ptr->tex_size; + __gx->texMapWrap[mapid] = ptr->tex_filt; + + __gx->dirtyState |= 0x0001; +} + +void GX_PreloadEntireTexture(GXTexObj *obj,GXTexRegion *region) +{ + u32 i,fmt; + s32 wd,ht; + u16 cnt = 0; + u32 regA = 0; + u32 regB = 0; + u32 regC = 0; + u32 regD = 0; + struct __gx_texobj *ptr = (struct __gx_texobj*)obj; + struct __gx_texregion *reg = (struct __gx_texregion*)region; + + regA = (regA&~0xff000000)|(_SHIFTL(0x60,24,8)); + regA = (regA&~0x00ffffff)|(ptr->tex_maddr&~0xff000000); + + regB = (regB&~0xff000000)|(_SHIFTL(0x61,24,8)); + regB = (regB&~0x00007fff)|(reg->tmem_even&0x00007fff); + + regC = (regC&~0xff000000)|(_SHIFTL(0x62,24,8)); + regC = (regC&~0x00007fff)|(reg->tmem_odd&0x00007fff); + + regD = (regD&~0xff000000)|(_SHIFTL(0x63,24,8)); + regD = (regD&~0x00007fff)|(ptr->tex_tile_cnt&0x00007fff); + regD = (regD&~0x00018000)|(_SHIFTL(ptr->tex_tile_type,15,2)); + + fmt = _SHIFTR(ptr->tex_size,20,4); + + __GX_FlushTextureState(); + GX_LOAD_BP_REG(regA); + GX_LOAD_BP_REG(regB); + GX_LOAD_BP_REG(regC); + GX_LOAD_BP_REG(regD); + + if(ptr->tex_flag&0x01) { + wd = (ptr->tex_size&0x3ff)+1; + ht = _SHIFTR(ptr->tex_size,10,10)+1; + if(wd>ht) + cnt = (31 - (cntlzw(wd))); + else + cnt = (31 - (cntlzw(ht))); + } + + if(cnt>0) { + u32 tmem_even,tmem_odd,maddr; + u32 tile_cnt = ptr->tex_tile_cnt; + + tmem_even = (reg->tmem_even&0xffff); + tmem_odd = (reg->tmem_odd&0xffff); + maddr = (ptr->tex_maddr&~0xff000000); + + i = 0; + while(cnt) { + u32 w,h; + u32 te,to; + u32 xshift,yshift; + + if(fmt==GX_TF_RGBA8) { + tmem_even += tile_cnt; + tmem_odd += tile_cnt; + maddr += (tile_cnt<<1); + } else { + maddr += tile_cnt; + if(i&1) tmem_odd += tile_cnt; + else tmem_even += tile_cnt; + } + + te = tmem_even; + to = tmem_odd; + if(i&1) { + te = tmem_odd; + to = tmem_even; + } + + w = wd>>(i+1); + h = wd>>(i+1); + switch(ptr->tex_fmt) { + case GX_TF_I4: + case GX_TF_IA4: + case GX_TF_CI4: + case GX_TF_CMPR: + xshift = 3; + yshift = 3; + break; + case GX_TF_I8: + case GX_TF_CI8: + xshift = 3; + yshift = 2; + break; + case GX_TF_IA8: + case GX_TF_RGB5A3: + case GX_TF_RGB565: + case GX_TF_CI14: + xshift = 2; + yshift = 2; + break; + default: + xshift = 0; + yshift = 0; + break; + } + + if(!w) w = 1; + if(!h) h = 1; + + regA = ((regA&~0x00ffffff)|(maddr&0x00ffffff)); + GX_LOAD_BP_REG(regA); + + regB = ((regB&~0x00007fff)|(te&0x00007fff)); + GX_LOAD_BP_REG(regB); + + regC = ((regC&~0x00007fff)|(to&0x00007fff)); + GX_LOAD_BP_REG(regC); + + tile_cnt = (((w+(1<>xshift)*(((h+(1<>yshift); + regD = ((regD&~0x00007fff)|(tile_cnt&0x00007fff)); + GX_LOAD_BP_REG(regD); + + ++i; + --cnt; + } + } + __GX_FlushTextureState(); +} + +void GX_InvalidateTexAll() +{ + __GX_FlushTextureState(); + GX_LOAD_BP_REG(0x66001000); + GX_LOAD_BP_REG(0x66001100); + __GX_FlushTextureState(); +} + +void GX_InvalidateTexRegion(GXTexRegion *region) +{ + u8 ismipmap; + s32 cw_e,ch_e,cw_o,ch_o; + u32 size,tmp,regvalA = 0,regvalB = 0; + struct __gx_texregion *ptr = (struct __gx_texregion*)region; + + cw_e = (_SHIFTR(ptr->tmem_even,15,3))-1; + ch_e = (_SHIFTR(ptr->tmem_even,18,3))-1; + + cw_o = (_SHIFTR(ptr->tmem_odd,15,3))-1; + ch_o = (_SHIFTR(ptr->tmem_odd,18,3))-1; + + if(cw_e<0) cw_e = 0; + if(ch_e<0) ch_e = 0; + if(cw_o<0) cw_o = 0; + if(ch_o<0) ch_o = 0; + + ismipmap = ptr->ismipmap; + + tmp = size = cw_e+ch_e; + if(ismipmap) size = (tmp+cw_o+ch_o)-2; + regvalA = _SHIFTR((ptr->tmem_even&0x7fff),6,9)|(_SHIFTL(size,9,4))|(_SHIFTL(0x66,24,8)); + + if(cw_o!=0) { + size = cw_o+ch_o; + if(ismipmap) size += (tmp-2); + regvalB = _SHIFTR((ptr->tmem_odd&0x7fff),6,9)|(_SHIFTL(size,9,4))|(_SHIFTL(0x66,24,8)); + } + __GX_FlushTextureState(); + GX_LOAD_BP_REG(regvalA); + if(cw_o!=0) GX_LOAD_BP_REG(regvalB); + __GX_FlushTextureState(); +} + +void GX_LoadTlut(GXTlutObj *obj,u32 tlut_name) +{ + struct __gx_tlutregion *region = NULL; + struct __gx_tlutobj *ptr = (struct __gx_tlutobj*)obj; + + if(tlut_regionCB) + region = (struct __gx_tlutregion*)tlut_regionCB(tlut_name); + + __GX_FlushTextureState(); + GX_LOAD_BP_REG(ptr->tlut_maddr); + GX_LOAD_BP_REG(region->tmem_addr_conf); + __GX_FlushTextureState(); + + region->tmem_addr_base = (ptr->tlut_fmt&~0x3ff)|(region->tmem_addr_conf&0x3ff); + region->tlut_maddr = ptr->tlut_maddr; + region->tlut_nentries = ptr->tlut_nentries; +} + +void GX_SetTexCoordScaleManually(u8 texcoord,u8 enable,u16 ss,u16 ts) +{ + u32 reg; + + __gx->texCoordManually = (__gx->texCoordManually&~(_SHIFTL(1,texcoord,1)))|(_SHIFTL(enable,texcoord,1)); + if(!enable) return; + + reg = (texcoord&0x7); + __gx->suSsize[reg] = (__gx->suSsize[reg]&~0xffff)|((ss-1)&0xffff); + __gx->suTsize[reg] = (__gx->suTsize[reg]&~0xffff)|((ts-1)&0xffff); + + GX_LOAD_BP_REG(__gx->suSsize[reg]); + GX_LOAD_BP_REG(__gx->suTsize[reg]); +} + +void GX_SetTexCoordCylWrap(u8 texcoord,u8 s_enable,u8 t_enable) +{ + u32 reg; + + reg = (texcoord&0x7); + __gx->suSsize[reg] = (__gx->suSsize[reg]&~0x20000)|(_SHIFTL(s_enable,17,1)); + __gx->suTsize[reg] = (__gx->suTsize[reg]&~0x20000)|(_SHIFTL(t_enable,17,1)); + + if(!(__gx->texCoordManually&(_SHIFTL(1,texcoord,1)))) return; + + GX_LOAD_BP_REG(__gx->suSsize[reg]); + GX_LOAD_BP_REG(__gx->suTsize[reg]); +} + +void GX_SetTexCoordBias(u8 texcoord,u8 s_enable,u8 t_enable) +{ + u32 reg; + + reg = (texcoord&0x7); + __gx->suSsize[reg] = (__gx->suSsize[reg]&~0x10000)|(_SHIFTL(s_enable,16,1)); + __gx->suTsize[reg] = (__gx->suTsize[reg]&~0x10000)|(_SHIFTL(t_enable,16,1)); + + if(!(__gx->texCoordManually&(_SHIFTL(1,texcoord,1)))) return; + + GX_LOAD_BP_REG(__gx->suSsize[reg]); + GX_LOAD_BP_REG(__gx->suTsize[reg]); +} + +GXTexRegionCallback GX_SetTexRegionCallback(GXTexRegionCallback cb) +{ + u32 level; + GXTexRegionCallback ret; + + _CPU_ISR_Disable(level); + ret = regionCB; + regionCB = cb; + _CPU_ISR_Restore(level); + + return ret; +} + +GXTlutRegionCallback GX_SetTlutRegionCallback(GXTlutRegionCallback cb) +{ + u32 level; + GXTlutRegionCallback ret; + + _CPU_ISR_Disable(level); + ret = tlut_regionCB; + tlut_regionCB = cb; + _CPU_ISR_Restore(level); + + return ret; +} + +void GX_SetBlendMode(u8 type,u8 src_fact,u8 dst_fact,u8 op) +{ + __gx->peCMode0 = (__gx->peCMode0&~0x1); + if(type==GX_BM_BLEND || type==GX_BM_SUBTRACT) __gx->peCMode0 |= 0x1; + + __gx->peCMode0 = (__gx->peCMode0&~0x800); + if(type==GX_BM_SUBTRACT) __gx->peCMode0 |= 0x800; + + __gx->peCMode0 = (__gx->peCMode0&~0x2); + if(type==GX_BM_LOGIC) __gx->peCMode0 |= 0x2; + + __gx->peCMode0 = (__gx->peCMode0&~0xF000)|(_SHIFTL(op,12,4)); + __gx->peCMode0 = (__gx->peCMode0&~0xE0)|(_SHIFTL(dst_fact,5,3)); + __gx->peCMode0 = (__gx->peCMode0&~0x700)|(_SHIFTL(src_fact,8,3)); + + GX_LOAD_BP_REG(__gx->peCMode0); +} + +void GX_ClearVtxDesc() +{ + __gx->vcdNrms = 0; + __gx->vcdClear = ((__gx->vcdClear&~0x0600)|0x0200); + __gx->vcdLo = __gx->vcdHi = 0; + __gx->dirtyState |= 0x0008; +} + +void GX_SetLineWidth(u8 width,u8 fmt) +{ + __gx->lpWidth = (__gx->lpWidth&~0xff)|(width&0xff); + __gx->lpWidth = (__gx->lpWidth&~0x70000)|(_SHIFTL(fmt,16,3)); + GX_LOAD_BP_REG(__gx->lpWidth); +} + +void GX_SetPointSize(u8 width,u8 fmt) +{ + __gx->lpWidth = (__gx->lpWidth&~0xFF00)|(_SHIFTL(width,8,8)); + __gx->lpWidth = (__gx->lpWidth&~0x380000)|(_SHIFTL(fmt,19,3)); + GX_LOAD_BP_REG(__gx->lpWidth); +} + +void GX_SetTevColor(u8 tev_regid,GXColor color) +{ + u32 reg; + + reg = (_SHIFTL((0xe0+(tev_regid<<1)),24,8)|(_SHIFTL(color.a,12,8))|(color.r&0xff)); + GX_LOAD_BP_REG(reg); + + reg = (_SHIFTL((0xe1+(tev_regid<<1)),24,8)|(_SHIFTL(color.g,12,8))|(color.b&0xff)); + GX_LOAD_BP_REG(reg); + + //this two calls should obviously flush the Write Gather Pipe. + GX_LOAD_BP_REG(reg); + GX_LOAD_BP_REG(reg); +} + +void GX_SetTevColorS10(u8 tev_regid,GXColorS10 color) +{ + u32 reg; + + reg = (_SHIFTL((0xe0+(tev_regid<<1)),24,8)|(_SHIFTL(color.a,12,11))|(color.r&0x7ff)); + GX_LOAD_BP_REG(reg); + + reg = (_SHIFTL((0xe1+(tev_regid<<1)),24,8)|(_SHIFTL(color.g,12,11))|(color.b&0x7ff)); + GX_LOAD_BP_REG(reg); + + //this two calls should obviously flush the Write Gather Pipe. + GX_LOAD_BP_REG(reg); + GX_LOAD_BP_REG(reg); +} + +void GX_SetTevKColor(u8 tev_kregid,GXColor color) +{ + u32 reg; + + reg = (_SHIFTL((0xe0+(tev_kregid<<1)),24,8)|(_SHIFTL(1,23,1))|(_SHIFTL(color.a,12,8))|(color.r&0xff)); + GX_LOAD_BP_REG(reg); + + reg = (_SHIFTL((0xe1+(tev_kregid<<1)),24,8)|(_SHIFTL(1,23,1))|(_SHIFTL(color.g,12,8))|(color.b&0xff)); + GX_LOAD_BP_REG(reg); + + //this two calls should obviously flush the Write Gather Pipe. + GX_LOAD_BP_REG(reg); + GX_LOAD_BP_REG(reg); +} + +void GX_SetTevKColorS10(u8 tev_kregid,GXColorS10 color) +{ + u32 reg; + + reg = (_SHIFTL((0xe0+(tev_kregid<<1)),24,8)|(_SHIFTL(1,23,1))|(_SHIFTL(color.a,12,11))|(color.r&0x7ff)); + GX_LOAD_BP_REG(reg); + + reg = (_SHIFTL((0xe1+(tev_kregid<<1)),24,8)|(_SHIFTL(1,23,1))|(_SHIFTL(color.g,12,11))|(color.b&0x7ff)); + GX_LOAD_BP_REG(reg); + + //this two calls should obviously flush the Write Gather Pipe. + GX_LOAD_BP_REG(reg); + GX_LOAD_BP_REG(reg); +} + +void GX_SetTevOp(u8 tevstage,u8 mode) +{ + u8 defcolor = GX_CC_RASC; + u8 defalpha = GX_CA_RASA; + + if(tevstage!=GX_TEVSTAGE0) { + defcolor = GX_CC_CPREV; + defalpha = GX_CA_APREV; + } + + switch(mode) { + case GX_MODULATE: + GX_SetTevColorIn(tevstage,GX_CC_ZERO,GX_CC_TEXC,defcolor,GX_CC_ZERO); + GX_SetTevAlphaIn(tevstage,GX_CA_ZERO,GX_CA_TEXA,defalpha,GX_CA_ZERO); + break; + case GX_DECAL: + GX_SetTevColorIn(tevstage,defcolor,GX_CC_TEXC,GX_CC_TEXA,GX_CC_ZERO); + GX_SetTevAlphaIn(tevstage,GX_CA_ZERO,GX_CA_ZERO,GX_CA_ZERO,defalpha); + break; + case GX_BLEND: + GX_SetTevColorIn(tevstage,defcolor,GX_CC_ONE,GX_CC_TEXC,GX_CC_ZERO); + GX_SetTevAlphaIn(tevstage,GX_CA_ZERO,GX_CA_TEXA,defalpha,GX_CA_RASA); + break; + case GX_REPLACE: + GX_SetTevColorIn(tevstage,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_TEXC); + GX_SetTevAlphaIn(tevstage,GX_CA_ZERO,GX_CA_ZERO,GX_CA_ZERO,GX_CA_TEXA); + break; + case GX_PASSCLR: + GX_SetTevColorIn(tevstage,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,defcolor); + GX_SetTevAlphaIn(tevstage,GX_CC_A2,GX_CC_A2,GX_CC_A2,defalpha); + break; + } + GX_SetTevColorOp(tevstage,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV); + GX_SetTevAlphaOp(tevstage,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV); +} + +void GX_SetTevColorIn(u8 tevstage,u8 a,u8 b,u8 c,u8 d) +{ + u32 reg = (tevstage&0xf); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0xF000)|(_SHIFTL(a,12,4)); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0xF00)|(_SHIFTL(b,8,4)); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0xF0)|(_SHIFTL(c,4,4)); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0xf)|(d&0xf); + + GX_LOAD_BP_REG(__gx->tevColorEnv[reg]); +} + +void GX_SetTevAlphaIn(u8 tevstage,u8 a,u8 b,u8 c,u8 d) +{ + u32 reg = (tevstage&0xf); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0xE000)|(_SHIFTL(a,13,3)); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x1C00)|(_SHIFTL(b,10,3)); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x380)|(_SHIFTL(c,7,3)); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x70)|(_SHIFTL(d,4,3)); + + GX_LOAD_BP_REG(__gx->tevAlphaEnv[reg]); +} + +void GX_SetTevColorOp(u8 tevstage,u8 tevop,u8 tevbias,u8 tevscale,u8 clamp,u8 tevregid) +{ + /* set tev op add/sub*/ + u32 reg = (tevstage&0xf); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0x40000)|(_SHIFTL(tevop,18,1)); + if(tevop<=GX_TEV_SUB) { + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0x300000)|(_SHIFTL(tevscale,20,2)); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0x30000)|(_SHIFTL(tevbias,16,2)); + } else { + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0x300000)|((_SHIFTL(tevop,19,4))&0x300000); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0x30000)|0x30000; + } + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0x80000)|(_SHIFTL(clamp,19,1)); + __gx->tevColorEnv[reg] = (__gx->tevColorEnv[reg]&~0xC00000)|(_SHIFTL(tevregid,22,2)); + + GX_LOAD_BP_REG(__gx->tevColorEnv[reg]); +} + +void GX_SetTevAlphaOp(u8 tevstage,u8 tevop,u8 tevbias,u8 tevscale,u8 clamp,u8 tevregid) +{ + /* set tev op add/sub*/ + u32 reg = (tevstage&0xf); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x40000)|(_SHIFTL(tevop,18,1)); + if(tevop<=GX_TEV_SUB) { + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x300000)|(_SHIFTL(tevscale,20,2)); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x30000)|(_SHIFTL(tevbias,16,2)); + } else { + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x300000)|((_SHIFTL(tevop,19,4))&0x300000); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x30000)|0x30000; + } + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x80000)|(_SHIFTL(clamp,19,1)); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0xC00000)|(_SHIFTL(tevregid,22,2)); + + GX_LOAD_BP_REG(__gx->tevAlphaEnv[reg]); +} + +void GX_SetCullMode(u8 mode) +{ + static u8 cm2hw[] = { 0, 2, 1, 3 }; + + __gx->genMode = (__gx->genMode&~0xC000)|(_SHIFTL(cm2hw[mode],14,2)); + __gx->dirtyState |= 0x0004; +} + +void GX_SetCoPlanar(u8 enable) +{ + __gx->genMode = (__gx->genMode&~0x80000)|(_SHIFTL(enable,19,1)); + GX_LOAD_BP_REG(0xFE080000); + GX_LOAD_BP_REG(__gx->genMode); +} + +void GX_EnableTexOffsets(u8 coord,u8 line_enable,u8 point_enable) +{ + u32 reg = (coord&0x7); + __gx->suSsize[reg] = (__gx->suSsize[reg]&~0x40000)|(_SHIFTL(line_enable,18,1)); + __gx->suSsize[reg] = (__gx->suSsize[reg]&~0x80000)|(_SHIFTL(point_enable,19,1)); + GX_LOAD_BP_REG(__gx->suSsize[reg]); +} + +void GX_SetClipMode(u8 mode) +{ + GX_LOAD_XF_REG(0x1005,(mode&1)); +} + +void GX_SetScissor(u32 xOrigin,u32 yOrigin,u32 wd,u32 ht) +{ + u32 xo = xOrigin+0x156; + u32 yo = yOrigin+0x156; + u32 nwd = xo+(wd-1); + u32 nht = yo+(ht-1); + + __gx->sciTLcorner = (__gx->sciTLcorner&~0x7ff)|(yo&0x7ff); + __gx->sciTLcorner = (__gx->sciTLcorner&~0x7FF000)|(_SHIFTL(xo,12,11)); + + __gx->sciBRcorner = (__gx->sciBRcorner&~0x7ff)|(nht&0xfff); + __gx->sciBRcorner = (__gx->sciBRcorner&~0x7FF000)|(_SHIFTL(nwd,12,11)); + + GX_LOAD_BP_REG(__gx->sciTLcorner); + GX_LOAD_BP_REG(__gx->sciBRcorner); +} + +void GX_SetScissorBoxOffset(s32 xoffset,s32 yoffset) +{ + s32 xoff = _SHIFTR((xoffset+0x156),1,24); + s32 yoff = _SHIFTR((yoffset+0x156),1,24); + + GX_LOAD_BP_REG((0x59000000|(_SHIFTL(yoff,10,10))|(xoff&0x3ff))); +} + +void GX_SetNumChans(u8 num) +{ + __gx->genMode = (__gx->genMode&~0x70)|(_SHIFTL(num,4,3)); + __gx->dirtyState |= 0x01000004; +} + +void GX_SetTevOrder(u8 tevstage,u8 texcoord,u32 texmap,u8 color) +{ + u8 colid; + u32 texm,texc,tmp; + u32 reg = 3+(_SHIFTR(tevstage,1,3)); + + __gx->tevTexMap[(tevstage&0xf)] = texmap; + + texm = (texmap&~0x100); + if(texm>=GX_MAX_TEXMAP) texm = 0; + if(texcoord>=GX_MAXCOORD) { + texc = 0; + __gx->tevTexCoordEnable &= ~(_SHIFTL(1,tevstage,1)); + } else { + texc = texcoord; + __gx->tevTexCoordEnable |= (_SHIFTL(1,tevstage,1)); + } + + if(tevstage&1) { + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x7000)|(_SHIFTL(texm,12,3)); + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x38000)|(_SHIFTL(texc,15,3)); + + colid = GX_ALPHA_BUMP; + if(color!=GX_COLORNULL) colid = _gxtevcolid[color]; + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x380000)|(_SHIFTL(colid,19,3)); + + tmp = 1; + if(texmap==GX_TEXMAP_NULL || texmap&0x100) tmp = 0; + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x40000)|(_SHIFTL(tmp,18,1)); + } else { + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x7)|(texm&0x7); + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x38)|(_SHIFTL(texc,3,3)); + + colid = GX_ALPHA_BUMP; + if(color!=GX_COLORNULL) colid = _gxtevcolid[color]; + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x380)|(_SHIFTL(colid,7,3)); + + tmp = 1; + if(texmap==GX_TEXMAP_NULL || texmap&0x100) tmp = 0; + __gx->tevRasOrder[reg] = (__gx->tevRasOrder[reg]&~0x40)|(_SHIFTL(tmp,6,1)); + } + GX_LOAD_BP_REG(__gx->tevRasOrder[reg]); + __gx->dirtyState |= 0x0001; +} + +void GX_SetNumTevStages(u8 num) +{ + __gx->genMode = (__gx->genMode&~0x3C00)|(_SHIFTL((num-1),10,4)); + __gx->dirtyState |= 0x0004; +} + +void GX_SetAlphaCompare(u8 comp0,u8 ref0,u8 aop,u8 comp1,u8 ref1) +{ + u32 val = 0; + val = (_SHIFTL(aop,22,2))|(_SHIFTL(comp1,19,3))|(_SHIFTL(comp0,16,3))|(_SHIFTL(ref1,8,8))|(ref0&0xff); + GX_LOAD_BP_REG(0xf3000000|val); +} + +void GX_SetTevKColorSel(u8 tevstage,u8 sel) +{ + u32 reg = (_SHIFTR(tevstage,1,3)); + + if(tevstage&1) + __gx->tevSwapModeTable[reg] = (__gx->tevSwapModeTable[reg]&~0x7C000)|(_SHIFTL(sel,14,5)); + else + __gx->tevSwapModeTable[reg] = (__gx->tevSwapModeTable[reg]&~0x1F0)|(_SHIFTL(sel,4,5)); + GX_LOAD_BP_REG(__gx->tevSwapModeTable[reg]); +} + +void GX_SetTevKAlphaSel(u8 tevstage,u8 sel) +{ + u32 reg = (_SHIFTR(tevstage,1,3)); + + if(tevstage&1) + __gx->tevSwapModeTable[reg] = (__gx->tevSwapModeTable[reg]&~0xF80000)|(_SHIFTL(sel,19,5)); + else + __gx->tevSwapModeTable[reg] = (__gx->tevSwapModeTable[reg]&~0x3E00)|(_SHIFTL(sel,9,5)); + GX_LOAD_BP_REG(__gx->tevSwapModeTable[reg]); +} + +void GX_SetTevSwapMode(u8 tevstage,u8 ras_sel,u8 tex_sel) +{ + u32 reg = (tevstage&0xf); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0x3)|(ras_sel&0x3); + __gx->tevAlphaEnv[reg] = (__gx->tevAlphaEnv[reg]&~0xC)|(_SHIFTL(tex_sel,2,2)); + GX_LOAD_BP_REG(__gx->tevAlphaEnv[reg]); +} + +void GX_SetTevSwapModeTable(u8 swapid,u8 r,u8 g,u8 b,u8 a) +{ + u32 regA = 0+(_SHIFTL(swapid,1,3)); + u32 regB = 1+(_SHIFTL(swapid,1,3)); + + __gx->tevSwapModeTable[regA] = (__gx->tevSwapModeTable[regA]&~0x3)|(r&0x3); + __gx->tevSwapModeTable[regA] = (__gx->tevSwapModeTable[regA]&~0xC)|(_SHIFTL(g,2,2)); + GX_LOAD_BP_REG(__gx->tevSwapModeTable[regA]); + + __gx->tevSwapModeTable[regB] = (__gx->tevSwapModeTable[regB]&~0x3)|(b&0x3); + __gx->tevSwapModeTable[regB] = (__gx->tevSwapModeTable[regB]&~0xC)|(_SHIFTL(a,2,2)); + GX_LOAD_BP_REG(__gx->tevSwapModeTable[regB]); +} + +void GX_SetTevIndirect(u8 tevstage,u8 indtexid,u8 format,u8 bias,u8 mtxid,u8 wrap_s,u8 wrap_t,u8 addprev,u8 utclod,u8 a) +{ + u32 val = (0x10000000|(_SHIFTL(tevstage,24,4)))|(indtexid&3)|(_SHIFTL(format,2,2))|(_SHIFTL(bias,4,3))|(_SHIFTL(a,7,2))|(_SHIFTL(mtxid,9,4))|(_SHIFTL(wrap_s,13,3))|(_SHIFTL(wrap_t,16,3))|(_SHIFTL(utclod,19,1))|(_SHIFTL(addprev,20,1)); + GX_LOAD_BP_REG(val); +} + +void GX_SetTevDirect(u8 tevstage) +{ + GX_SetTevIndirect(tevstage,GX_INDTEXSTAGE0,GX_ITF_8,GX_ITB_NONE,GX_ITM_OFF,GX_ITW_OFF,GX_ITW_OFF,GX_FALSE,GX_FALSE,GX_ITBA_OFF); +} + +void GX_SetNumIndStages(u8 nstages) +{ + __gx->genMode = (__gx->genMode&~0x70000)|(_SHIFTL(nstages,16,3)); + __gx->dirtyState |= 0x0006; +} + +void GX_SetIndTexMatrix(u8 indtexmtx,f32 offset_mtx[2][3],s8 scale_exp) +{ + u32 ma,mb; + u32 val,s,idx; + + if(indtexmtx>0x00 && indtexmtx<0x04) indtexmtx -= 0x01; + else if(indtexmtx>0x04 && indtexmtx<0x08) indtexmtx -= 0x05; + else if(indtexmtx>0x08 && indtexmtx<0x0C) indtexmtx -= 0x09; + else indtexmtx = 0x00; + + s = (scale_exp+17); + idx = ((indtexmtx<<2)-indtexmtx); + + ma = (u32)(offset_mtx[0][0]*1024.0F); + mb = (u32)(offset_mtx[1][0]*1024.0F); + val = (_SHIFTL((0x06+idx),24,8)|_SHIFTL(s,22,2)|_SHIFTL(mb,11,11)|_SHIFTL(ma,0,11)); + GX_LOAD_BP_REG(val); + + ma = (u32)(offset_mtx[0][1]*1024.0F); + mb = (u32)(offset_mtx[1][1]*1024.0F); + val = (_SHIFTL((0x07+idx),24,8)|_SHIFTL((s>>2),22,2)|_SHIFTL(mb,11,11)|_SHIFTL(ma,0,11)); + GX_LOAD_BP_REG(val); + + ma = (u32)(offset_mtx[0][2]*1024.0F); + mb = (u32)(offset_mtx[1][2]*1024.0F); + val = (_SHIFTL((0x08+idx),24,8)|_SHIFTL((s>>4),22,2)|_SHIFTL(mb,11,11)|_SHIFTL(ma,0,11)); + GX_LOAD_BP_REG(val); +} + +void GX_SetTevIndBumpST(u8 tevstage,u8 indstage,u8 mtx_sel) +{ + u8 sel_s,sel_t; + + switch(mtx_sel) { + case GX_ITM_0: + sel_s = GX_ITM_S0; + sel_t = GX_ITM_T0; + break; + case GX_ITM_1: + sel_s = GX_ITM_S1; + sel_t = GX_ITM_T1; + break; + case GX_ITM_2: + sel_s = GX_ITM_S2; + sel_t = GX_ITM_T2; + break; + default: + sel_s = GX_ITM_OFF; + sel_t = GX_ITM_OFF; + break; + } + + GX_SetTevIndirect((tevstage+0),indstage,GX_ITF_8,GX_ITB_ST,sel_s,GX_ITW_0,GX_ITW_0,GX_FALSE,GX_FALSE,GX_ITBA_OFF); + GX_SetTevIndirect((tevstage+1),indstage,GX_ITF_8,GX_ITB_ST,sel_t,GX_ITW_0,GX_ITW_0,GX_TRUE,GX_FALSE,GX_ITBA_OFF); + GX_SetTevIndirect((tevstage+2),indstage,GX_ITF_8,GX_ITB_NONE,GX_ITM_OFF,GX_ITW_OFF,GX_ITW_OFF,GX_TRUE,GX_FALSE,GX_ITBA_OFF); +} + +void GX_SetTevIndBumpXYZ(u8 tevstage,u8 indstage,u8 mtx_sel) +{ + GX_SetTevIndirect(tevstage,indstage,GX_ITF_8,GX_ITB_STU,mtx_sel,GX_ITW_OFF,GX_ITW_OFF,GX_FALSE,GX_FALSE,GX_ITBA_OFF); +} + +void GX_SetTevIndRepeat(u8 tevstage) +{ + GX_SetTevIndirect(tevstage,GX_INDTEXSTAGE0,GX_ITF_8,GX_ITB_NONE,GX_ITM_OFF,GX_ITW_0,GX_ITW_0,GX_TRUE,GX_FALSE,GX_ITBA_OFF); +} + +void GX_SetIndTexCoordScale(u8 indtexid,u8 scale_s,u8 scale_t) +{ + switch(indtexid) { + case GX_INDTEXSTAGE0: + __gx->tevRasOrder[0] = (__gx->tevRasOrder[0]&~0x0f)|(scale_s&0x0f); + __gx->tevRasOrder[0] = (__gx->tevRasOrder[0]&~0xF0)|(_SHIFTL(scale_t,4,4)); + GX_LOAD_BP_REG(__gx->tevRasOrder[0]); + break; + case GX_INDTEXSTAGE1: + __gx->tevRasOrder[0] = (__gx->tevRasOrder[0]&~0xF00)|(_SHIFTL(scale_s,8,4)); + __gx->tevRasOrder[0] = (__gx->tevRasOrder[0]&~0xF000)|(_SHIFTL(scale_t,12,4)); + GX_LOAD_BP_REG(__gx->tevRasOrder[0]); + break; + case GX_INDTEXSTAGE2: + __gx->tevRasOrder[1] = (__gx->tevRasOrder[1]&~0x0f)|(scale_s&0x0f); + __gx->tevRasOrder[1] = (__gx->tevRasOrder[1]&~0xF0)|(_SHIFTL(scale_t,4,4)); + GX_LOAD_BP_REG(__gx->tevRasOrder[1]); + break; + case GX_INDTEXSTAGE3: + __gx->tevRasOrder[1] = (__gx->tevRasOrder[1]&~0xF00)|(_SHIFTL(scale_s,8,4)); + __gx->tevRasOrder[1] = (__gx->tevRasOrder[1]&~0xF000)|(_SHIFTL(scale_t,12,4)); + GX_LOAD_BP_REG(__gx->tevRasOrder[1]); + break; + } +} + +void GX_SetTevIndTile(u8 tevstage,u8 indtexid,u16 tilesize_x,u16 tilesize_y,u16 tilespacing_x,u16 tilespacing_y,u8 indtexfmt,u8 indtexmtx,u8 bias_sel,u8 alpha_sel) +{ + s32 wrap_s,wrap_t; + f32 offset_mtx[2][3]; + f64 fdspace_x,fdspace_y; + u32 fbuf_x[2] = { 0x43300000,tilespacing_x }; + u32 fbuf_y[2] = { 0x43300000,tilespacing_y }; + + wrap_s = GX_ITW_OFF; + if(tilesize_x==0x0010) wrap_s = GX_ITW_16; + else if(tilesize_x==0x0020) wrap_s = GX_ITW_32; + else if(tilesize_x==0x0040) wrap_s = GX_ITW_64; + else if(tilesize_x==0x0080) wrap_s = GX_ITW_128; + else if(tilesize_x==0x0100) wrap_s = GX_ITW_256; + + wrap_t = GX_ITW_OFF; + if(tilesize_y==0x0010) wrap_t = GX_ITW_16; + else if(tilesize_y==0x0020) wrap_t = GX_ITW_32; + else if(tilesize_y==0x0040) wrap_t = GX_ITW_64; + else if(tilesize_y==0x0080) wrap_t = GX_ITW_128; + else if(tilesize_y==0x0100) wrap_t = GX_ITW_256; + + fdspace_x = *(f64*)((void*)fbuf_x); + fdspace_y = *(f64*)((void*)fbuf_y); + + offset_mtx[0][0] = (f32)((fdspace_x - 4503599627370496.0F)*0.00097656250F); + offset_mtx[0][1] = 0.0F; + offset_mtx[0][2] = 0.0F; + offset_mtx[1][0] = 0.0F; + offset_mtx[1][1] = (f32)((fdspace_y - 4503599627370496.0F)*0.00097656250F); + offset_mtx[1][2] = 0.0F; + + GX_SetIndTexMatrix(indtexmtx,offset_mtx,10); + GX_SetTevIndirect(tevstage,indtexid,indtexfmt,bias_sel,indtexmtx,wrap_s,wrap_t,GX_FALSE,GX_TRUE,alpha_sel); +} + +void GX_SetFog(u8 type,f32 startz,f32 endz,f32 nearz,f32 farz,GXColor col) +{ + f32 A, B, B_mant, C, A_f; + u32 b_expn, b_m, a_hex, c_hex,val,proj = 0; + union ieee32 { f32 f; u32 i; } v; + + proj = _SHIFTR(type,3,1); + + // Calculate constants a, b, and c (TEV HW requirements). + if(proj) { // Orthographic Fog Type + if((farz==nearz) || (endz==startz)) { + // take care of the odd-ball case. + A_f = 0.0f; + C = 0.0f; + } else { + A = 1.0f/(endz-startz); + A_f = (farz-nearz) * A; + C = (startz-nearz) * A; + } + + b_expn = 0; + b_m = 0; + } else { // Perspective Fog Type + // Calculate constants a, b, and c (TEV HW requirements). + if((farz==nearz) || (endz==startz)) { + // take care of the odd-ball case. + A = 0.0f; + B = 0.5f; + C = 0.0f; + } else { + A = (farz*nearz)/((farz-nearz)*(endz-startz)); + B = farz/(farz-nearz); + C = startz/(endz-startz); + } + + B_mant = B; + b_expn = 1; + while(B_mant>1.0f) { + B_mant /= 2.0f; + b_expn++; + } + + while((B_mant>0.0f) && (B_mant<0.5f)) { + B_mant *= 2.0f; + b_expn--; + } + + A_f = A/(1<<(b_expn)); + b_m = (u32)(B_mant * 8388638.0f); + } + v.f = A_f; + a_hex = v.i; + + v.f = C; + c_hex = v.i; + + val = 0xee000000|(_SHIFTR(a_hex,12,20)); + GX_LOAD_BP_REG(val); + + val = 0xef000000|(b_m&0x00ffffff); + GX_LOAD_BP_REG(val); + + val = 0xf0000000|(b_expn&0x1f); + GX_LOAD_BP_REG(val); + + val = 0xf1000000|(_SHIFTL(type,21,3))|(_SHIFTL(proj,20,1))|(_SHIFTR(c_hex,12,20)); + GX_LOAD_BP_REG(val); + + val = 0xf2000000|(_SHIFTL(col.r,16,8))|(_SHIFTL(col.g,8,8))|(col.b&0xff); + GX_LOAD_BP_REG(val); +} + +void GX_InitFogAdjTable(GXFogAdjTbl *table,u16 width,f32 projmtx[4][4]) +{ + u32 i,val7; + f32 val0,val1,val2,val4,val5,val6; + + if(projmtx[3][3]==0.0f) { + val0 = projmtx[2][3]/(projmtx[2][2] - 1.0f); + val1 = val0/projmtx[0][0]; + } else { + val1 = 1.0f/projmtx[0][0]; + val0 = val1*1.7320499f; + } + + val2 = val0*val0; + val4 = 2.0f/(f32)width; + for(i=0;i<10;i++) { + val5 = (i+1)*32.0f; + val5 *= val4; + val5 *= val1; + val5 *= val5; + val5 /= val2; + val6 = sqrtf(val5 + 1.0f); + val7 = (u32)(val6*256.0f); + table->r[i] = (val7&0x0fff); + } +} + +void GX_SetFogRangeAdj(u8 enable,u16 center,GXFogAdjTbl *table) +{ + u32 val; + + if(enable) { + val = 0xe9000000|(_SHIFTL(table->r[1],12,12))|(table->r[0]&0x0fff); + GX_LOAD_BP_REG(val); + + val = 0xea000000|(_SHIFTL(table->r[3],12,12))|(table->r[2]&0x0fff); + GX_LOAD_BP_REG(val); + + val = 0xeb000000|(_SHIFTL(table->r[5],12,12))|(table->r[4]&0x0fff); + GX_LOAD_BP_REG(val); + + val = 0xec000000|(_SHIFTL(table->r[7],12,12))|(table->r[6]&0x0fff); + GX_LOAD_BP_REG(val); + + val = 0xed000000|(_SHIFTL(table->r[9],12,12))|(table->r[8]&0x0fff); + GX_LOAD_BP_REG(val); + } + val = 0xe8000000|(_SHIFTL(enable,10,1))|((center + 342)&0x03ff); + GX_LOAD_BP_REG(val); +} + +void GX_SetFogColor(GXColor color) +{ + GX_LOAD_BP_REG(0xf2000000|(_SHIFTL(color.r,16,8)|_SHIFTL(color.g,8,8)|(color.b&0xff))); +} + +void GX_SetColorUpdate(u8 enable) +{ + __gx->peCMode0 = (__gx->peCMode0&~0x8)|(_SHIFTL(enable,3,1)); + GX_LOAD_BP_REG(__gx->peCMode0); +} + +void GX_SetAlphaUpdate(u8 enable) +{ + __gx->peCMode0 = (__gx->peCMode0&~0x10)|(_SHIFTL(enable,4,1)); + GX_LOAD_BP_REG(__gx->peCMode0); +} + +void GX_SetZCompLoc(u8 before_tex) +{ + __gx->peCntrl = (__gx->peCntrl&~0x40)|(_SHIFTL(before_tex,6,1)); + GX_LOAD_BP_REG(__gx->peCntrl); +} + +void GX_SetPixelFmt(u8 pix_fmt,u8 z_fmt) +{ + u8 ms_en = 0; + u32 realfmt[8] = {0,1,2,3,4,4,4,5}; + + __gx->peCntrl = (__gx->peCntrl&~0x7)|(realfmt[pix_fmt]&0x7); + __gx->peCntrl = (__gx->peCntrl&~0x38)|(_SHIFTL(z_fmt,3,3)); + GX_LOAD_BP_REG(__gx->peCntrl); + __gx->dirtyState |= 0x0004; + + if(pix_fmt==GX_PF_RGB565_Z16) ms_en = 1; + __gx->genMode = (__gx->genMode&~0x200)|(_SHIFTL(ms_en,9,1)); + + if(realfmt[pix_fmt]==GX_PF_Y8) { + pix_fmt -= GX_PF_Y8; + __gx->peCMode1 = (__gx->peCMode1&~0xC00)|(_SHIFTL(pix_fmt,10,2)); + GX_LOAD_BP_REG(__gx->peCMode1); + } +} + +void GX_SetDither(u8 dither) +{ + __gx->peCMode0 = (__gx->peCMode0&~0x4)|(_SHIFTL(dither,2,1)); + GX_LOAD_BP_REG(__gx->peCMode0); +} + +void GX_SetDstAlpha(u8 enable,u8 a) +{ + __gx->peCMode1 = (__gx->peCMode1&~0xff)|(a&0xff); + __gx->peCMode1 = (__gx->peCMode1&~0x100)|(_SHIFTL(enable,8,1)); + GX_LOAD_BP_REG(__gx->peCMode1); +} + +void GX_SetFieldMask(u8 even_mask,u8 odd_mask) +{ + u32 val = 0; + + val = (_SHIFTL(even_mask,1,1))|(odd_mask&1); + GX_LOAD_BP_REG(0x44000000|val); +} + +void GX_SetFieldMode(u8 field_mode,u8 half_aspect_ratio) +{ + __gx->lpWidth = (__gx->lpWidth&~0x400000)|(_SHIFTL(half_aspect_ratio,22,1)); + GX_LOAD_BP_REG(__gx->lpWidth); + + __GX_FlushTextureState(); + GX_LOAD_BP_REG(0x68000000|(field_mode&1)); + __GX_FlushTextureState(); +} + +void GX_PokeAlphaMode(u8 func,u8 threshold) +{ + _peReg[3] = (_SHIFTL(func,8,8))|(threshold&0xFF); +} + +void GX_PokeAlphaRead(u8 mode) +{ + _peReg[4] = (mode&~0x4)|0x4; +} + +void GX_PokeDstAlpha(u8 enable,u8 a) +{ + _peReg[2] = (_SHIFTL(enable,8,1))|(a&0xff); +} + +void GX_PokeAlphaUpdate(u8 update_enable) +{ + _peReg[1] = (_peReg[1]&~0x10)|(_SHIFTL(update_enable,4,1)); +} + +void GX_PokeColorUpdate(u8 update_enable) +{ + _peReg[1] = (_peReg[1]&~0x8)|(_SHIFTL(update_enable,3,1)); +} + +void GX_PokeDither(u8 dither) +{ + _peReg[1] = (_peReg[1]&~0x4)|(_SHIFTL(dither,2,1)); +} + +void GX_PokeBlendMode(u8 type,u8 src_fact,u8 dst_fact,u8 op) +{ + u32 regval = _peReg[1]; + + regval = (regval&~0x1); + if(type==GX_BM_BLEND || type==GX_BM_SUBTRACT) regval |= 0x1; + + regval = (regval&~0x800); + if(type==GX_BM_SUBTRACT) regval |= 0x800; + + regval = (regval&~0x2); + if(type==GX_BM_LOGIC) regval |= 0x2; + + regval = (regval&~0xF000)|(_SHIFTL(op,12,4)); + regval = (regval&~0xE0)|(_SHIFTL(dst_fact,5,3)); + regval = (regval&~0x700)|(_SHIFTL(src_fact,8,3)); + + regval |= 0x41000000; + _peReg[1] = (u16)regval; +} + +void GX_PokeARGB(u16 x,u16 y,GXColor color) +{ + u32 regval; + + regval = 0xc8000000|(_SHIFTL(x,2,10)); + regval = (regval&~0x3FF000)|(_SHIFTL(y,12,10)); + *(u32*)regval = _SHIFTL(color.a,24,8)|_SHIFTL(color.r,16,8)|_SHIFTL(color.g,8,8)|(color.b&0xff); +} + +void GX_PeekARGB(u16 x,u16 y,GXColor *color) +{ + u32 regval,val; + + regval = 0xc8000000|(_SHIFTL(x,2,10)); + regval = (regval&~0x3FF000)|(_SHIFTL(y,12,10)); + val = *(u32*)regval; + color->a = _SHIFTR(val,24,8); + color->r = _SHIFTR(val,16,8); + color->g = _SHIFTR(val,8,8); + color->b = val&0xff; +} + +void GX_PokeZ(u16 x,u16 y,u32 z) +{ + u32 regval; + + regval = 0xc8000000|(_SHIFTL(x,2,10)); + regval = (regval&~0x3FF000)|(_SHIFTL(y,12,10)); + regval = (regval&~0xC00000)|0x400000; + *(u32*)regval = z; +} + +void GX_PeekZ(u16 x,u16 y,u32 *z) +{ + u32 regval; + + regval = 0xc8000000|(_SHIFTL(x,2,10)); + regval = (regval&~0x3FF000)|(_SHIFTL(y,12,10)); + regval = (regval&~0xC00000)|0x400000; + *z = *(u32*)regval; +} + +void GX_PokeZMode(u8 comp_enable,u8 func,u8 update_enable) +{ + u16 regval; + regval = comp_enable&0x1; + regval = (regval&~0xE)|(_SHIFTL(func,1,3)); + regval = (regval&0x10)|(_SHIFTL(update_enable,4,1)); + _peReg[0] = regval; +} + +void GX_SetIndTexOrder(u8 indtexstage,u8 texcoord,u8 texmap) +{ + switch(indtexstage) { + case GX_INDTEXSTAGE0: + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0x7)|(texmap&0x7); + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0x38)|(_SHIFTL(texcoord,3,3)); + break; + case GX_INDTEXSTAGE1: + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0x1C0)|(_SHIFTL(texmap,6,3)); + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0xE00)|(_SHIFTL(texcoord,9,3)); + break; + case GX_INDTEXSTAGE2: + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0x7000)|(_SHIFTL(texmap,12,3)); + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0x38000)|(_SHIFTL(texcoord,15,3)); + break; + case GX_INDTEXSTAGE3: + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0x1C0000)|(_SHIFTL(texmap,18,3)); + __gx->tevRasOrder[2] = (__gx->tevRasOrder[2]&~0xE00000)|(_SHIFTL(texcoord,21,3)); + break; + } + GX_LOAD_BP_REG(__gx->tevRasOrder[2]); + __gx->dirtyState |= 0x0003; +} + +void GX_InitLightPos(GXLightObj *lit_obj,f32 x,f32 y,f32 z) +{ + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + lit->px = x; + lit->py = y; + lit->pz = z; +} + +void GX_InitLightColor(GXLightObj *lit_obj,GXColor col) +{ + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + lit->col = ((_SHIFTL(col.r,24,8))|(_SHIFTL(col.g,16,8))|(_SHIFTL(col.b,8,8))|(col.a&0xff)); +} + +void GX_LoadLightObj(GXLightObj *lit_obj,u8 lit_id) +{ + u32 id; + u16 reg; + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + switch(lit_id) { + case GX_LIGHT0: + id = 0; + break; + case GX_LIGHT1: + id = 1; + break; + case GX_LIGHT2: + id = 2; + break; + case GX_LIGHT3: + id = 3; + break; + case GX_LIGHT4: + id = 4; + break; + case GX_LIGHT5: + id = 5; + break; + case GX_LIGHT6: + id = 6; + break; + case GX_LIGHT7: + id = 7; + break; + default: + id = 0; + break; + } + + reg = 0x600|(_SHIFTL(id,4,8)); + GX_LOAD_XF_REGS(reg,16); + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = 0; + wgPipe->U32 = lit->col; + wgPipe->F32 = lit->a0; + wgPipe->F32 = lit->a1; + wgPipe->F32 = lit->a2; + wgPipe->F32 = lit->k0; + wgPipe->F32 = lit->k1; + wgPipe->F32 = lit->k2; + wgPipe->F32 = lit->px; + wgPipe->F32 = lit->py; + wgPipe->F32 = lit->pz; + wgPipe->F32 = lit->nx; + wgPipe->F32 = lit->ny; + wgPipe->F32 = lit->nz; +} + +void GX_LoadLightObjIdx(u32 litobjidx,u8 litid) +{ + u32 reg; + u32 idx = 0; + + switch(litid) { + case GX_LIGHT0: + idx = 0; + break; + case GX_LIGHT1: + idx = 1; + break; + case GX_LIGHT2: + idx = 2; + break; + case GX_LIGHT3: + idx = 3; + break; + case GX_LIGHT4: + idx = 4; + break; + case GX_LIGHT5: + idx = 5; + break; + case GX_LIGHT6: + idx = 6; + break; + case GX_LIGHT7: + idx = 7; + break; + default: + idx = 0; + break; + + } + + reg = 0xf600|(_SHIFTL(idx,4,8)); + reg = (reg&~0xffff0000)|(_SHIFTL(litobjidx,16,16)); + + wgPipe->U8 = 0x38; + wgPipe->U32 = reg; +} + +void GX_InitLightDir(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz) +{ + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + lit->nx = -(nx); + lit->ny = -(ny); + lit->nz = -(nz); +} + +void GX_InitLightDistAttn(GXLightObj *lit_obj,f32 ref_dist,f32 ref_brite,u8 dist_fn) +{ + f32 k0,k1,k2; + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + if(ref_dist<0.0f || + ref_brite<0.0f || ref_brite>=1.0f) dist_fn = GX_DA_OFF; + + switch(dist_fn) { + case GX_DA_GENTLE: + k0 = 1.0f; + k1 = (1.0f-ref_brite)/(ref_brite*ref_dist); + k2 = 0.0f; + break; + case GX_DA_MEDIUM: + k0 = 1.0f; + k1 = 0.5f*(1.0f-ref_brite)/(ref_brite*ref_dist); + k2 = 0.5f*(1.0f-ref_brite)/(ref_brite*ref_dist*ref_dist); + break; + case GX_DA_STEEP: + k0 = 1.0f; + k1 = 0.0f; + k2 = (1.0f-ref_brite)/(ref_brite*ref_dist*ref_dist); + break; + case GX_DA_OFF: + default: + k0 = 1.0f; + k1 = 0.0f; + k2 = 0.0f; + break; + } + + lit->k0 = k0; + lit->k1 = k1; + lit->k2 = k2; +} + +void GX_InitLightAttn(GXLightObj *lit_obj,f32 a0,f32 a1,f32 a2,f32 k0,f32 k1,f32 k2) +{ + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + lit->a0 = a0; + lit->a1 = a1; + lit->a2 = a2; + lit->k0 = k0; + lit->k1 = k1; + lit->k2 = k2; +} + +void GX_InitLightAttnA(GXLightObj *lit_obj,f32 a0,f32 a1,f32 a2) +{ + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + lit->a0 = a0; + lit->a1 = a1; + lit->a2 = a2; +} + +void GX_InitLightAttnK(GXLightObj *lit_obj,f32 k0,f32 k1,f32 k2) +{ + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + lit->k0 = k0; + lit->k1 = k1; + lit->k2 = k2; +} + +void GX_InitSpecularDirHA(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz,f32 hx,f32 hy,f32 hz) +{ + f32 px, py, pz; + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + px = (nx * LARGE_NUMBER); + py = (ny * LARGE_NUMBER); + pz = (nz * LARGE_NUMBER); + + lit->px = px; + lit->py = py; + lit->pz = pz; + lit->nx = hx; + lit->ny = hy; + lit->nz = hz; +} + +void GX_InitSpecularDir(GXLightObj *lit_obj,f32 nx,f32 ny,f32 nz) +{ + f32 px, py, pz; + f32 hx, hy, hz, mag; + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + // Compute half-angle vector + hx = -nx; + hy = -ny; + hz = (-nz + 1.0f); + mag = ((hx * hx) + (hy * hy) + (hz * hz)); + if(mag!=0.0f) mag = 1.0f / sqrtf(mag); + + hx *= mag; + hy *= mag; + hz *= mag; + + px = (nx * LARGE_NUMBER); + py = (ny * LARGE_NUMBER); + pz = (nz * LARGE_NUMBER); + + lit->px = px; + lit->py = py; + lit->pz = pz; + lit->nx = hx; + lit->ny = hy; + lit->nz = hz; +} + +void GX_InitLightSpot(GXLightObj *lit_obj,f32 cut_off,u8 spotfn) +{ + f32 r,d,cr,a0,a1,a2; + struct __gx_litobj *lit = (struct __gx_litobj*)lit_obj; + + if(cut_off<0.0f || cut_off>90.0f) spotfn = GX_SP_OFF; + + r = (cut_off*M_PI)/180.0f; + cr = cosf(r); + + switch(spotfn) { + case GX_SP_FLAT: + a0 = -1000.0f*cr; + a1 = 1000.0f; + a2 = 0.0f; + break; + case GX_SP_COS: + a0 = -cr/(1.0f-cr); + a1 = 1.0f/(1.0f-cr); + a2 = 0.0f; + break; + case GX_SP_COS2: + a0 = 0.0f; + a1 = -cr/(1.0f-cr); + a2 = 1.0f/(1.0f-cr); + break; + case GX_SP_SHARP: + d = (1.0f-cr)*(1.0f-cr); + a0 = cr*(cr-2.0f); + a1 = 2.0f/d; + a2 = -1.0/d; + break; + case GX_SP_RING1: + d = (1.0f-cr)*(1.0f-cr); + a0 = -4.0f*cr/d; + a1 = 4.0f*(1.0f+cr)/d; + a2 = -4.0f/d; + break; + case GX_SP_RING2: + d = (1.0f-cr)*(1.0f-cr); + a0 = 1.0f-2.0f*cr*cr/d; + a1 = 4.0f*cr/d; + a2 = -2.0f/d; + break; + case GX_SP_OFF: + default: + a0 = 1.0f; + a1 = 0.0f; + a2 = 0.0f; + break; + } + + lit->a0 = a0; + lit->a1 = a1; + lit->a2 = a2; +} + +void GX_SetGPMetric(u32 perf0,u32 perf1) +{ + // check last setted perf0 counters + if(__gx->perf0Mode>=GX_PERF0_TRIANGLES && __gx->perf0Modeperf0Mode>=GX_PERF0_QUAD_0CVG && __gx->perf0Modeperf0Mode>=GX_PERF0_VERTICES && __gx->perf0Mode<=GX_PERF0_CLOCKS) + GX_LOAD_XF_REG(0x1006,0); + + // check last setted perf1 counters + if(__gx->perf1Mode>=GX_PERF1_VC_ELEMQ_FULL && __gx->perf1ModecpPerfMode = (__gx->cpPerfMode&~0xf0); + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + } else if(__gx->perf1Mode>=GX_PERF1_FIFO_REQ && __gx->perf1Modeperf1Mode>=GX_PERF1_TEXELS && __gx->perf1Mode<=GX_PERF1_CLOCKS) { + GX_LOAD_BP_REG(0x67000000); + } + + __gx->perf0Mode = perf0; + switch(__gx->perf0Mode) { + case GX_PERF0_CLOCKS: + GX_LOAD_XF_REG(0x1006,0x00000273); + break; + case GX_PERF0_VERTICES: + GX_LOAD_XF_REG(0x1006,0x0000014a); + break; + case GX_PERF0_CLIP_VTX: + GX_LOAD_XF_REG(0x1006,0x0000016b); + break; + case GX_PERF0_CLIP_CLKS: + GX_LOAD_XF_REG(0x1006,0x00000084); + break; + case GX_PERF0_XF_WAIT_IN: + GX_LOAD_XF_REG(0x1006,0x000000c6); + break; + case GX_PERF0_XF_WAIT_OUT: + GX_LOAD_XF_REG(0x1006,0x00000210); + break; + case GX_PERF0_XF_XFRM_CLKS: + GX_LOAD_XF_REG(0x1006,0x00000252); + break; + case GX_PERF0_XF_LIT_CLKS: + GX_LOAD_XF_REG(0x1006,0x00000231); + break; + case GX_PERF0_XF_BOT_CLKS: + GX_LOAD_XF_REG(0x1006,0x000001ad); + break; + case GX_PERF0_XF_REGLD_CLKS: + GX_LOAD_XF_REG(0x1006,0x000001ce); + break; + case GX_PERF0_XF_REGRD_CLKS: + GX_LOAD_XF_REG(0x1006,0x00000021); + break; + case GX_PERF0_CLIP_RATIO: + GX_LOAD_XF_REG(0x1006,0x00000153); + break; + case GX_PERF0_TRIANGLES: + GX_LOAD_BP_REG(0x2300AE7F); + break; + case GX_PERF0_TRIANGLES_CULLED: + GX_LOAD_BP_REG(0x23008E7F); + break; + case GX_PERF0_TRIANGLES_PASSED: + GX_LOAD_BP_REG(0x23009E7F); + break; + case GX_PERF0_TRIANGLES_SCISSORED: + GX_LOAD_BP_REG(0x23001E7F); + break; + case GX_PERF0_TRIANGLES_0TEX: + GX_LOAD_BP_REG(0x2300AC3F); + break; + case GX_PERF0_TRIANGLES_1TEX: + GX_LOAD_BP_REG(0x2300AC7F); + break; + case GX_PERF0_TRIANGLES_2TEX: + GX_LOAD_BP_REG(0x2300ACBF); + break; + case GX_PERF0_TRIANGLES_3TEX: + GX_LOAD_BP_REG(0x2300ACFF); + break; + case GX_PERF0_TRIANGLES_4TEX: + GX_LOAD_BP_REG(0x2300AD3F); + break; + case GX_PERF0_TRIANGLES_5TEX: + GX_LOAD_BP_REG(0x2300AD7F); + break; + case GX_PERF0_TRIANGLES_6TEX: + GX_LOAD_BP_REG(0x2300ADBF); + break; + case GX_PERF0_TRIANGLES_7TEX: + GX_LOAD_BP_REG(0x2300ADFF); + break; + case GX_PERF0_TRIANGLES_8TEX: + GX_LOAD_BP_REG(0x2300AE3F); + break; + case GX_PERF0_TRIANGLES_0CLR: + GX_LOAD_BP_REG(0x2300A27F); + break; + case GX_PERF0_TRIANGLES_1CLR: + GX_LOAD_BP_REG(0x2300A67F); + break; + case GX_PERF0_TRIANGLES_2CLR: + GX_LOAD_BP_REG(0x2300AA7F); + break; + case GX_PERF0_QUAD_0CVG: + GX_LOAD_BP_REG(0x2402C0C6); + break; + case GX_PERF0_QUAD_NON0CVG: + GX_LOAD_BP_REG(0x2402C16B); + break; + case GX_PERF0_QUAD_1CVG: + GX_LOAD_BP_REG(0x2402C0E7); + break; + case GX_PERF0_QUAD_2CVG: + GX_LOAD_BP_REG(0x2402C108); + break; + case GX_PERF0_QUAD_3CVG: + GX_LOAD_BP_REG(0x2402C129); + break; + case GX_PERF0_QUAD_4CVG: + GX_LOAD_BP_REG(0x2402C14A); + break; + case GX_PERF0_AVG_QUAD_CNT: + GX_LOAD_BP_REG(0x2402C1AD); + break; + case GX_PERF0_NONE: + break; + } + + __gx->perf1Mode = perf1; + switch(__gx->perf1Mode) { + case GX_PERF1_CLOCKS: + GX_LOAD_BP_REG(0x67000042); + break; + case GX_PERF1_TEXELS: + GX_LOAD_BP_REG(0x67000084); + break; + case GX_PERF1_TX_IDLE: + GX_LOAD_BP_REG(0x67000063); + break; + case GX_PERF1_TX_REGS: + GX_LOAD_BP_REG(0x67000129); + break; + case GX_PERF1_TX_MEMSTALL: + GX_LOAD_BP_REG(0x67000252); + break; + case GX_PERF1_TC_CHECK1_2: + GX_LOAD_BP_REG(0x67000021); + break; + case GX_PERF1_TC_CHECK3_4: + GX_LOAD_BP_REG(0x6700014b); + break; + case GX_PERF1_TC_CHECK5_6: + GX_LOAD_BP_REG(0x6700018d); + break; + case GX_PERF1_TC_CHECK7_8: + GX_LOAD_BP_REG(0x670001cf); + break; + case GX_PERF1_TC_MISS: + GX_LOAD_BP_REG(0x67000211); + break; + case GX_PERF1_VC_ELEMQ_FULL: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x20; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_VC_MISSQ_FULL: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x30; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_VC_MEMREQ_FULL: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x40; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_VC_STATUS7: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x50; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_VC_MISSREP_FULL: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x60; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_VC_STREAMBUF_LOW: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x70; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_VC_ALL_STALLS: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x90; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_VERTICES: + __gx->cpPerfMode = (__gx->cpPerfMode&~0xf0)|0x80; + GX_LOAD_CP_REG(0x20,__gx->cpPerfMode); + break; + case GX_PERF1_FIFO_REQ: + _cpReg[3] = 2; + break; + case GX_PERF1_CALL_REQ: + _cpReg[3] = 3; + break; + case GX_PERF1_VC_MISS_REQ: + _cpReg[3] = 4; + break; + case GX_PERF1_CP_ALL_REQ: + _cpReg[3] = 5; + break; + case GX_PERF1_NONE: + break; + } + +} + +void GX_ClearGPMetric() +{ + _cpReg[2] = 4; +} + +void GX_InitXfRasMetric() +{ + GX_LOAD_BP_REG(0x2402C022); + GX_LOAD_XF_REG(0x1006,0x31000); +} + +void GX_ReadXfRasMetric(u32 *xfwaitin,u32 *xfwaitout,u32 *rasbusy,u32 *clks) +{ + *rasbusy = _SHIFTL(_cpReg[33],16,16)|(_cpReg[32]&0xffff); + *clks = _SHIFTL(_cpReg[35],16,16)|(_cpReg[34]&0xffff); + *xfwaitin = _SHIFTL(_cpReg[37],16,16)|(_cpReg[36]&0xffff); + *xfwaitout = _SHIFTL(_cpReg[39],16,16)|(_cpReg[38]&0xffff); +} + +u32 GX_ReadClksPerVtx() +{ + GX_DrawDone(); + _cpReg[49] = 0x1007; + _cpReg[48] = 0x1007; + return (_cpReg[50]<<8); +} + +void GX_ClearVCacheMetric() +{ + GX_LOAD_CP_REG(0,0); +} + +void GX_ReadVCacheMetric(u32 *check,u32 *miss,u32 *stall) +{ + *check = _SHIFTL(_cpReg[41],16,16)|(_cpReg[40]&0xffff); + *miss = _SHIFTL(_cpReg[43],16,16)|(_cpReg[42]&0xffff); + *stall = _SHIFTL(_cpReg[45],16,16)|(_cpReg[44]&0xffff); +} + +void GX_SetVCacheMetric(u32 attr) +{ +} + +void GX_GetGPStatus(u8 *overhi,u8 *underlow,u8 *readIdle,u8 *cmdIdle,u8 *brkpt) +{ + _gxgpstatus = _cpReg[0]; + *overhi = !!(_gxgpstatus&1); + *underlow = !!(_gxgpstatus&2); + *readIdle = !!(_gxgpstatus&4); + *cmdIdle = !!(_gxgpstatus&8); + *brkpt = !!(_gxgpstatus&16); +} + +void GX_ReadGPMetric(u32 *cnt0,u32 *cnt1) +{ + u32 tmp,reg1,reg2; + + reg1 = (_SHIFTL(_cpReg[33],16,16))|(_cpReg[32]&0xffff); + reg2 = (_SHIFTL(_cpReg[35],16,16))|(_cpReg[34]&0xffff); + //reg3 = (_SHIFTL(_cpReg[37],16,16))|(_cpReg[36]&0xffff); + //reg4 = (_SHIFTL(_cpReg[39],16,16))|(_cpReg[38]&0xffff); + + *cnt0 = 0; + if(__gx->perf0Mode==GX_PERF0_CLIP_RATIO) { + tmp = reg2*1000; + *cnt0 = tmp/reg1; + } else if(__gx->perf0Mode>=GX_PERF0_VERTICES && __gx->perf0ModefbWidth = rmin->fbWidth-(hor<<1); + rmout->efbHeight = rmin->efbHeight-((rmin->efbHeight*(ver<<1))/rmin->xfbHeight); + if(rmin->xfbMode==VI_XFBMODE_SF && !(rmin->viTVMode&VI_PROGRESSIVE)) rmout->xfbHeight = rmin->xfbHeight-ver; + else rmout->xfbHeight = rmin->xfbHeight-(ver<<1); + + rmout->viWidth = rmin->viWidth-(hor<<1); + if(rmin->viTVMode&VI_PROGRESSIVE) rmout->viHeight = rmin->viHeight-(ver<<2); + else rmout->viHeight = rmin->viHeight-(ver<<1); + + rmout->viXOrigin += hor; + rmout->viYOrigin += ver; +} + +f32 GX_GetYScaleFactor(u16 efbHeight,u16 xfbHeight) +{ + u32 yScale,xfblines,cnt; + f32 yscale; + + yscale = (f32)efbHeight/(f32)xfbHeight; + yScale = (u32)((f32)256.0/yscale)&0x1ff; + + cnt = xfbHeight; + xfblines = __GX_GetNumXfbLines(efbHeight,yScale); + while(xfblines>=xfbHeight) { + yscale = (f32)(cnt--)/(f32)efbHeight; + yScale = (u32)((f32)256.0/yscale)&0x1ff; + xfblines = __GX_GetNumXfbLines(efbHeight,yScale); + } + + while(xfblines + +#define STRUCT_REGDEF_SIZE 1440 + +struct __gx_regdef +{ + u16 cpSRreg; + u16 cpCRreg; + u16 cpCLreg; + u16 xfFlush; + u16 xfFlushExp; + u16 xfFlushSafe; + u32 gxFifoInited; + u32 vcdClear; + u32 VATTable; + u32 mtxIdxLo; + u32 mtxIdxHi; + u32 texCoordManually; + u32 vcdLo; + u32 vcdHi; + u32 vcdNrms; + u32 dirtyState; + u32 perf0Mode; + u32 perf1Mode; + u32 cpPerfMode; + u32 VAT0reg[8]; + u32 VAT1reg[8]; + u32 VAT2reg[8]; + u32 texMapSize[8]; + u32 texMapWrap[8]; + u32 sciTLcorner; + u32 sciBRcorner; + u32 lpWidth; + u32 genMode; + u32 suSsize[8]; + u32 suTsize[8]; + u32 tevTexMap[16]; + u32 tevColorEnv[16]; + u32 tevAlphaEnv[16]; + u32 tevSwapModeTable[8]; + u32 tevRasOrder[11]; + u32 tevTexCoordEnable; + u32 tevIndMask; + u32 texCoordGen[8]; + u32 texCoordGen2[8]; + u32 dispCopyCntrl; + u32 dispCopyDst; + u32 dispCopyTL; + u32 dispCopyWH; + u32 texCopyCntrl; + u32 texCopyDst; + u32 texCopyTL; + u32 texCopyWH; + u32 peZMode; + u32 peCMode0; + u32 peCMode1; + u32 peCntrl; + u32 chnAmbColor[2]; + u32 chnMatColor[2]; + u32 chnCntrl[4]; + GXTexRegion texRegion[24]; + GXTlutRegion tlutRegion[20]; + u8 saveDLctx; + u8 gxFifoUnlinked; + u8 texCopyZTex; + u8 _pad; +} __attribute__((packed)); + +struct __gxfifo { + vu32 buf_start; + vu32 buf_end; + vu32 size; + vu32 hi_mark; + vu32 lo_mark; + vu32 rd_ptr; + vu32 wt_ptr; + vu32 rdwt_dst; + vu8 fifo_wrap; + vu8 cpufifo_ready; + vu8 gpfifo_ready; + u8 _pad[93]; +} __attribute__((packed)); + +struct __gx_litobj +{ + u32 _pad[3]; + u32 col; + f32 a0; + f32 a1; + f32 a2; + f32 k0; + f32 k1; + f32 k2; + f32 px; + f32 py; + f32 pz; + f32 nx; + f32 ny; + f32 nz; +} __attribute__((packed)); + +struct __gx_texobj +{ + u32 tex_filt; + u32 tex_lod; + u32 tex_size; + u32 tex_maddr; + u32 usr_data; + u32 tex_fmt; + u32 tex_tlut; + u16 tex_tile_cnt; + u8 tex_tile_type; + u8 tex_flag; +} __attribute__((packed)); + +struct __gx_tlutobj +{ + u32 tlut_fmt; + u32 tlut_maddr; + u16 tlut_nentries; + u8 _pad[2]; +} __attribute__((packed)); + +struct __gx_texregion +{ + u32 tmem_even; + u32 tmem_odd; + u16 size_even; + u16 size_odd; + u8 ismipmap; + u8 iscached; + u8 _pad[2]; +} __attribute__((packed)); + +struct __gx_tlutregion +{ + u32 tmem_addr_conf; + u32 tmem_addr_base; + u32 tlut_maddr; + u16 tlut_nentries; + u8 _pad[2]; +} __attribute__((packed)); + +#endif diff --git a/wii/libogc/libogc/ios.c b/wii/libogc/libogc/ios.c new file mode 100644 index 0000000000..05f043651d --- /dev/null +++ b/wii/libogc/libogc/ios.c @@ -0,0 +1,379 @@ +/*------------------------------------------------------------- + +ios.c -- IOS control + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include +#include "asm.h" +#include "processor.h" +#include "cache.h" +#include "ipc.h" +#include "stm.h" +#include "es.h" +#include "ios.h" +#include "irq.h" + +#define IOS_HEAP_SIZE 0x1000 +#define MAX_IPC_RETRIES 400 + +//#define DEBUG_IOS + +#define IOS_MAX_VERSION 61 +#define IOS_MIN_VERSION 28 + +static s32 __ios_hid = -1; +extern void udelay(int us); + +s32 __IOS_InitHeap(void) +{ + if(__ios_hid <0 ) { + __ios_hid = iosCreateHeap(IOS_HEAP_SIZE); + if(__ios_hid < 0) return __ios_hid; + } + return 0; +} + +// These two functions deal with the "internal" IOS subsystems that are used by default by libogc +// Other stuff should be inited by the user and deinited by the exit callbacks. The user is also responsible +// for deiniting other stuff before an IOS reload and reiniting them after. +s32 __IOS_InitializeSubsystems(void) +{ + s32 res; + s32 ret = 0; +#ifdef DEBUG_IOS + printf("IOS Subsystem Init\n"); +#endif + res = __ES_Init(); + if(res < 0) { + ret = res; +#ifdef DEBUG_IOS + printf("ES Init failed: %d\n",ret); +#endif + } + res = __STM_Init(); + if(res < 0) { + ret = res; +#ifdef DEBUG_IOS + printf("STM Init failed: %d\n",ret); +#endif + } +#ifdef DEBUG_IOS + printf("IOS Subsystem Init Done: %d\n",ret); +#endif + return ret; +} + +s32 __IOS_ShutdownSubsystems(void) +{ + s32 res; + s32 ret = 0; +#ifdef DEBUG_IOS + printf("IOS Subsystem Close\n"); +#endif + res = __STM_Close(); + if(res < 0) ret = res; + res = __ES_Close(); + if(res < 0) ret = res; +#ifdef DEBUG_IOS + printf("IOS Subsystem Close Done: %d\n",ret); +#endif + return ret; +} + +s32 IOS_GetPreferredVersion() +{ + int ver = IOS_EBADVERSION; + s32 res; + u32 count; + u64 *titles; + u32 tmd_size; + u32 i; + u32 a,b; + + res = __IOS_InitHeap(); + if(res<0) return res; + + res = ES_GetNumTitles(&count); + if(res < 0) { +#ifdef DEBUG_IOS + printf(" GetNumTitles failed: %d\n",res); +#endif + return res; + } +#ifdef DEBUG_IOS + printf(" %d titles on card:\n",count); +#endif + titles = iosAlloc(__ios_hid, sizeof(u64)*count); + if(!titles) { + printf(" iosAlloc titles failed\n"); + return -1; + } + res = ES_GetTitles(titles, count); + if(res < 0) { +#ifdef DEBUG_IOS + printf(" GetTitles failed: %d\n",res); +#endif + iosFree(__ios_hid, titles); + return res; + } + + u32 *tmdbuffer = memalign(32, MAX_SIGNED_TMD_SIZE); + + if(!tmdbuffer) + { + iosFree(__ios_hid, titles); + return -1; + } + + for(i=0; i>32; + b = titles[i]&0xFFFFFFFF; + if(a != 1) continue; + if(b < IOS_MIN_VERSION) continue; + if(b > IOS_MAX_VERSION) continue; + + if (ES_GetStoredTMDSize(titles[i], &tmd_size) < 0) + continue; + + if (tmd_size < 0 || tmd_size > 4096) + continue; + + if(ES_GetStoredTMD(titles[i], (signed_blob *)tmdbuffer, tmd_size) < 0) + continue; + + if (!tmdbuffer[1] && !tmdbuffer[2]) + continue; + + if((((s32)b) > ((s32)ver) && ver != 58) || b == 58) ver = b; + } +#ifdef DEBUG_IOS + printf(" Preferred verson: %d\n",ver); +#endif + iosFree(__ios_hid, titles); + free(tmdbuffer); + return ver; +} + +s32 IOS_GetVersion() +{ + u32 vercode; + u16 version; + DCInvalidateRange((void*)0x80003140,8); + vercode = *((u32*)0x80003140); + version = vercode >> 16; + if(version == 0) return IOS_EBADVERSION; + if(version > 0xff) return IOS_EBADVERSION; + return version; +} + +s32 IOS_GetRevision() +{ + u32 vercode; + u16 rev; + DCInvalidateRange((void*)0x80003140,8); + vercode = *((u32*)0x80003140); + rev = vercode & 0xFFFF; + if(vercode == 0 || rev == 0) return IOS_EBADVERSION; + return rev; +} + +s32 IOS_GetRevisionMajor() +{ + s32 rev; + rev = IOS_GetRevision(); + if(rev < 0) return rev; + return (rev>>8)&0xFF; +} + +s32 IOS_GetRevisionMinor() +{ + s32 rev; + rev = IOS_GetRevision(); + if(rev < 0) return rev; + return rev&0xFF; +} + +s32 __IOS_LaunchNewIOS(int version) +{ + u32 numviews; + s32 res; + u64 titleID = 0x100000000LL; + raw_irq_handler_t irq_handler; + u32 counter; + + STACK_ALIGN(tikview,views,4,32); +#ifdef DEBUG_IOS + s32 oldversion; +#endif + s32 newversion; + + if(version < 3 || version > 0xFF) { + return IOS_EBADVERSION; + } + +#ifdef DEBUG_IOS + oldversion = IOS_GetVersion(); + if(oldversion>0) printf("Current IOS Version: IOS%d\n",oldversion); +#endif + + titleID |= version; +#ifdef DEBUG_IOS + printf("Launching IOS TitleID: %016llx\n",titleID); +#endif + + res = ES_GetNumTicketViews(titleID, &numviews); + if(res < 0) { +#ifdef DEBUG_IOS + printf(" GetNumTicketViews failed: %d\n",res); +#endif + return res; + } + if(numviews > 4) { + printf(" GetNumTicketViews too many views: %lu\n",numviews); + return IOS_ETOOMANYVIEWS; + } + res = ES_GetTicketViews(titleID, views, numviews); + if(res < 0) { +#ifdef DEBUG_IOS + printf(" GetTicketViews failed: %d\n",res); +#endif + return res; + } + + write32(0x80003140, 0); + + res = ES_LaunchTitleBackground(titleID, &views[0]); + if(res < 0) { +#ifdef DEBUG_IOS + printf(" LaunchTitleBackground failed: %d\n",res); +#endif + return res; + } + + __ES_Reset(); + + // Mask IPC IRQ while we're busy reloading + __MaskIrq(IRQ_PI_ACR); + irq_handler = IRQ_Free(IRQ_PI_ACR); + +#ifdef DEBUG_IOS + printf("Waiting for IOS ...\n"); +#endif + while ((read32(0x80003140) >> 16) == 0) + udelay(1000); + +#ifdef DEBUG_IOS + u32 v = read32(0x80003140); + printf("IOS loaded: IOS%d v%d.%d\n", v >> 16, (v >> 8) & 0xff, v & 0xff); +#endif + +#ifdef DEBUG_IOS + printf("Waiting for IPC ...\n"); +#endif + for (counter = 0; !(read32(0x0d000004) & 2); counter++) { + udelay(1000); + + if (counter >= MAX_IPC_RETRIES) + break; + } + +#ifdef DEBUG_IOS + printf("IPC started (%u)\n", counter); +#endif + + IRQ_Request(IRQ_PI_ACR, irq_handler, NULL); + __UnmaskIrq(IRQ_PI_ACR); + + __IPC_Reinitialize(); + + newversion = IOS_GetVersion(); + + if(newversion != version) { +#ifdef DEBUG_IOS + printf(" Version mismatch!\n"); +#endif + return IOS_EMISMATCH; + } + + return version; +} + +s32 __attribute__((weak)) __IOS_LoadStartupIOS() +{ + return 0; +} + +s32 IOS_ReloadIOS(int version) +{ + int ret = 0; + int res; + +#ifdef DEBUG_IOS + printf("Reloading to IOS%d\n",version); +#endif + + res = __IOS_ShutdownSubsystems(); + if(res < 0) { +#ifdef DEBUG_IOS + printf("__IOS_ShutdownSubsystems failed: %d\n", res); +#endif + ret = res; + } + + res = __ES_Init(); + if(res < 0) { +#ifdef DEBUG_IOS + printf("__ES_Init failed: %d\n", res); +#endif + ret = res; + } else { + res = __IOS_LaunchNewIOS(version); + if(res < 0) { +#ifdef DEBUG_IOS + printf("__IOS_LaunchNewIOS failed: %d\n", res); +#endif + ret = res; + __ES_Close(); + } + } + + res = __IOS_InitializeSubsystems(); + if(res < 0) { +#ifdef DEBUG_IOS + printf("__IOS_InitializeSubsystems failed: %d\n", res); +#endif + ret = res; + } + + return ret; +} + +#endif /* defined(HW_RVL) */ diff --git a/wii/libogc/libogc/ipc.c b/wii/libogc/libogc/ipc.c new file mode 100644 index 0000000000..10fed37bce --- /dev/null +++ b/wii/libogc/libogc/ipc.c @@ -0,0 +1,1286 @@ +/*------------------------------------------------------------- + +ipc.c -- Interprocess Communication with Starlet + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include +#include +#include +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "lwp.h" +#include "irq.h" +#include "ipc.h" +#include "cache.h" +#include "system.h" +#include "lwp_heap.h" +#include "lwp_wkspace.h" + +#define IPC_HEAP_SIZE 4096 +#define IPC_REQUESTSIZE 64 +#define IPC_NUMHEAPS 16 + +#define IOS_MAXFMT_PARAMS 32 + +#define IOS_OPEN 0x01 +#define IOS_CLOSE 0x02 +#define IOS_READ 0x03 +#define IOS_WRITE 0x04 +#define IOS_SEEK 0x05 +#define IOS_IOCTL 0x06 +#define IOS_IOCTLV 0x07 + +#define RELNCH_RELAUNCH 1 +#define RELNCH_BACKGROUND 2 + +struct _ipcreq +{ //ipc struct size: 32 + u32 cmd; //0 + s32 result; //4 + union { //8 + s32 fd; + u32 req_cmd; + }; + union { + struct { + char *filepath; + u32 mode; + } open; + struct { + void *data; + u32 len; + } read, write; + struct { + s32 where; + s32 whence; + } seek; + struct { + u32 ioctl; + void *buffer_in; + u32 len_in; + void *buffer_io; + u32 len_io; + } ioctl; + struct { + u32 ioctl; + u32 argcin; + u32 argcio; + struct _ioctlv *argv; + } ioctlv; + u32 args[5]; + }; + + ipccallback cb; //32 + void *usrdata; //36 + u32 relnch; //40 + lwpq_t syncqueue; //44 + u32 magic; //48 - used to avoid spurious responses, like from zelda. + u8 pad1[12]; //52 - 60 +} ATTRIBUTE_PACKED; + +struct _ipcreqres +{ + u32 cnt_sent; + u32 cnt_queue; + u32 req_send_no; + u32 req_queue_no; + struct _ipcreq *reqs[16]; +}; + +struct _ipcheap +{ + void *membase; + u32 size; + heap_cntrl heap; +}; + +struct _ioctlvfmt_bufent +{ + void *ipc_buf; + void *io_buf; + s32 copy_len; +}; + +struct _ioctlvfmt_cbdata +{ + ipccallback user_cb; + void *user_data; + s32 num_bufs; + u32 hId; + struct _ioctlvfmt_bufent *bufs; +}; + +static u32 IPC_REQ_MAGIC; + +static s32 _ipc_hid = -1; +static s32 _ipc_mailboxack = 1; +static u32 _ipc_relnchFl = 0; +static u32 _ipc_initialized = 0; +static u32 _ipc_clntinitialized = 0; +static u64 _ipc_spuriousresponsecnt = 0; +static struct _ipcreq *_ipc_relnchRpc = NULL; + +static void *_ipc_bufferlo = NULL; +static void *_ipc_bufferhi = NULL; +static void *_ipc_currbufferlo = NULL; +static void *_ipc_currbufferhi = NULL; + +static u32 _ipc_seed = 0xffffffff; + +static struct _ipcreqres _ipc_responses; + +static struct _ipcheap _ipc_heaps[IPC_NUMHEAPS] = +{ + {NULL, 0, {}} // all other elements should be inited to zero, says C standard, so this should do +}; + +static vu32* const _ipcReg = (u32*)0xCD000000; + +extern void __MaskIrq(u32 nMask); +extern void __UnmaskIrq(u32 nMask); +extern void* __SYS_GetIPCBufferLo(void); +extern void* __SYS_GetIPCBufferHi(void); + +extern u32 gettick(); + +static __inline__ u32 IPC_ReadReg(u32 reg) +{ + return _ipcReg[reg]; +} + +static __inline__ void IPC_WriteReg(u32 reg,u32 val) +{ + _ipcReg[reg] = val; +} + +static __inline__ void ACR_WriteReg(u32 reg,u32 val) +{ + _ipcReg[reg>>2] = val; +} + +static __inline__ void* __ipc_allocreq() +{ + return iosAlloc(_ipc_hid,IPC_REQUESTSIZE); +} + +static __inline__ void __ipc_freereq(void *ptr) +{ + iosFree(_ipc_hid,ptr); +} + +static __inline__ void __ipc_srand(u32 seed) +{ + _ipc_seed = seed; +} + +static __inline__ u32 __ipc_rand() +{ + _ipc_seed = (214013*_ipc_seed) + 2531011; + return _ipc_seed; +} + +static s32 __ioctlvfmtCB(s32 result,void *userdata) +{ + ipccallback user_cb; + void *user_data; + struct _ioctlvfmt_cbdata *cbdata; + struct _ioctlvfmt_bufent *pbuf; + + cbdata = (struct _ioctlvfmt_cbdata*)userdata; + + // deal with data buffers + if(cbdata->bufs) { + pbuf = cbdata->bufs; + while(cbdata->num_bufs--) { + if(pbuf->ipc_buf) { + // copy data if needed + if(pbuf->io_buf && pbuf->copy_len) + memcpy(pbuf->io_buf, pbuf->ipc_buf, pbuf->copy_len); + // then free the buffer + iosFree(cbdata->hId, pbuf->ipc_buf); + } + pbuf++; + } + } + + user_cb = cbdata->user_cb; + user_data = cbdata->user_data; + + // free buffer list + __lwp_wkspace_free(cbdata->bufs); + + // free callback data + __lwp_wkspace_free(cbdata); + + // call the user callback + if(user_cb) + return user_cb(result, user_data); + + return result; +} + +static s32 __ipc_queuerequest(struct _ipcreq *req) +{ + u32 cnt; + u32 level; + _CPU_ISR_Disable(level); + + cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent); + if(cnt>=16) { + _CPU_ISR_Restore(level); + return IPC_EQUEUEFULL; + } + + _ipc_responses.reqs[_ipc_responses.req_queue_no] = req; + _ipc_responses.req_queue_no = ((_ipc_responses.req_queue_no+1)&0x0f); + _ipc_responses.cnt_queue++; + + _CPU_ISR_Restore(level); + return IPC_OK; +} + +static s32 __ipc_syncqueuerequest(struct _ipcreq *req) +{ + u32 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent); + if(cnt>=16) { + return IPC_EQUEUEFULL; + } + + _ipc_responses.reqs[_ipc_responses.req_queue_no] = req; + _ipc_responses.req_queue_no = ((_ipc_responses.req_queue_no+1)&0x0f); + _ipc_responses.cnt_queue++; + + return IPC_OK; +} + +static void __ipc_sendrequest() +{ + u32 ipc_send; + struct _ipcreq *req; + u32 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent); + if(cnt>0) { + req = _ipc_responses.reqs[_ipc_responses.req_send_no]; + if(req!=NULL) { + req->magic = IPC_REQ_MAGIC; + if(req->relnch&RELNCH_RELAUNCH) { + _ipc_relnchFl = 1; + _ipc_relnchRpc = req; + if(!(req->relnch&RELNCH_BACKGROUND)) + _ipc_mailboxack--; + } + DCFlushRange(req,sizeof(struct _ipcreq)); + + IPC_WriteReg(0,MEM_VIRTUAL_TO_PHYSICAL(req)); + _ipc_responses.req_send_no = ((_ipc_responses.req_send_no+1)&0x0f); + _ipc_responses.cnt_sent++; + _ipc_mailboxack--; + + ipc_send = ((IPC_ReadReg(1)&0x30)|0x01); + IPC_WriteReg(1,ipc_send); + } + } +} + +static void __ipc_replyhandler() +{ + u32 ipc_ack,cnt; + ioctlv *v = NULL; + struct _ipcreq *req = (struct _ipcreq*)IPC_ReadReg(2); + if(req==NULL) return; + + ipc_ack = ((IPC_ReadReg(1)&0x30)|0x04); + IPC_WriteReg(1,ipc_ack); + ACR_WriteReg(48,0x40000000); + + req = MEM_PHYSICAL_TO_K0(req); + DCInvalidateRange(req,32); + + if(req->magic==IPC_REQ_MAGIC) { + if(req->req_cmd==IOS_READ) { + if(req->read.data!=NULL) { + req->read.data = MEM_PHYSICAL_TO_K0(req->read.data); + if(req->result>0) DCInvalidateRange(req->read.data,req->result); + } + } else if(req->req_cmd==IOS_IOCTL) { + if(req->ioctl.buffer_io!=NULL) { + req->ioctl.buffer_io = MEM_PHYSICAL_TO_K0(req->ioctl.buffer_io); + DCInvalidateRange(req->ioctl.buffer_io,req->ioctl.len_io); + } + DCInvalidateRange(req->ioctl.buffer_in,req->ioctl.len_in); + } else if(req->req_cmd==IOS_IOCTLV) { + if(req->ioctlv.argv!=NULL) { + req->ioctlv.argv = MEM_PHYSICAL_TO_K0(req->ioctlv.argv); + DCInvalidateRange(req->ioctlv.argv,((req->ioctlv.argcin+req->ioctlv.argcio)*sizeof(struct _ioctlv))); + } + + cnt = 0; + v = (ioctlv*)req->ioctlv.argv; + while(cnt<(req->ioctlv.argcin+req->ioctlv.argcio)) { + if(v[cnt].data!=NULL) { + v[cnt].data = MEM_PHYSICAL_TO_K0(v[cnt].data); + DCInvalidateRange(v[cnt].data,v[cnt].len); + } + cnt++; + } + if(_ipc_relnchFl && _ipc_relnchRpc==req) { + _ipc_relnchFl = 0; + if(_ipc_mailboxack<1) _ipc_mailboxack++; + } + + } + + if(req->cb!=NULL) { + req->cb(req->result,req->usrdata); + __ipc_freereq(req); + } else + LWP_ThreadSignal(req->syncqueue); + } else { + // NOTE: we really want to find out if this ever happens + // and take steps to prevent it beforehand (because it will + // clobber memory, among other things). I suggest leaving this in + // even in non-DEBUG mode. Maybe even cause a system halt. + // It is the responsibility of the loader to clear these things, + // but we want to find out if they happen so loaders can be fixed. + _ipc_spuriousresponsecnt++; + } + ipc_ack = ((IPC_ReadReg(1)&0x30)|0x08); + IPC_WriteReg(1,ipc_ack); +} + +static void __ipc_ackhandler() +{ + u32 ipc_ack; + ipc_ack = ((IPC_ReadReg(1)&0x30)|0x02); + IPC_WriteReg(1,ipc_ack); + ACR_WriteReg(48,0x40000000); + + if(_ipc_mailboxack<1) _ipc_mailboxack++; + if(_ipc_mailboxack>0) { + if(_ipc_relnchFl){ + _ipc_relnchRpc->result = 0; + _ipc_relnchFl = 0; + + LWP_ThreadSignal(_ipc_relnchRpc->syncqueue); + + ipc_ack = ((IPC_ReadReg(1)&0x30)|0x08); + IPC_WriteReg(1,ipc_ack); + } + __ipc_sendrequest(); + } + +} + +static void __ipc_interrupthandler(u32 irq,void *ctx) +{ + u32 ipc_int = IPC_ReadReg(1); + if((ipc_int&0x0014)==0x0014) __ipc_replyhandler(); + + ipc_int = IPC_ReadReg(1); + if((ipc_int&0x0022)==0x0022) __ipc_ackhandler(); +} + +static s32 __ios_ioctlvformat_parse(const char *format,va_list args,struct _ioctlvfmt_cbdata *cbdata,s32 *cnt_in,s32 *cnt_io,struct _ioctlv **argv,s32 hId) +{ + s32 ret,i; + void *pdata; + void *iodata; + char type,*ps; + s32 len,maxbufs = 0; + ioctlv *argp = NULL; + struct _ioctlvfmt_bufent *bufp; + + if(hId == IPC_HEAP) hId = _ipc_hid; + if(hId < 0) return IPC_EINVAL; + + maxbufs = strnlen(format,IOS_MAXFMT_PARAMS); + if(maxbufs>=IOS_MAXFMT_PARAMS) return IPC_EINVAL; + + cbdata->hId = hId; + cbdata->bufs = __lwp_wkspace_allocate((sizeof(struct _ioctlvfmt_bufent)*(maxbufs+1))); + if(cbdata->bufs==NULL) return IPC_ENOMEM; + + argp = iosAlloc(hId,(sizeof(struct _ioctlv)*(maxbufs+1))); + if(argp==NULL) { + __lwp_wkspace_free(cbdata->bufs); + return IPC_ENOMEM; + } + + *argv = argp; + bufp = cbdata->bufs; + memset(argp,0,(sizeof(struct _ioctlv)*(maxbufs+1))); + memset(bufp,0,(sizeof(struct _ioctlvfmt_bufent)*(maxbufs+1))); + + cbdata->num_bufs = 1; + bufp->ipc_buf = argp; + bufp++; + + *cnt_in = 0; + *cnt_io = 0; + + ret = IPC_OK; + while(*format) { + type = tolower((int)*format); + switch(type) { + case 'b': + pdata = iosAlloc(hId,sizeof(u8)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + *(u8*)pdata = va_arg(args,u32); + argp->data = pdata; + argp->len = sizeof(u8); + bufp->ipc_buf = pdata; + cbdata->num_bufs++; + (*cnt_in)++; + argp++; + bufp++; + break; + case 'h': + pdata = iosAlloc(hId,sizeof(u16)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + *(u16*)pdata = va_arg(args,u32); + argp->data = pdata; + argp->len = sizeof(u16); + bufp->ipc_buf = pdata; + cbdata->num_bufs++; + (*cnt_in)++; + argp++; + bufp++; + break; + case 'i': + pdata = iosAlloc(hId,sizeof(u32)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + *(u32*)pdata = va_arg(args,u32); + argp->data = pdata; + argp->len = sizeof(u32); + bufp->ipc_buf = pdata; + cbdata->num_bufs++; + (*cnt_in)++; + argp++; + bufp++; + break; + case 'q': + pdata = iosAlloc(hId,sizeof(u64)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + *(u64*)pdata = va_arg(args,u64); + argp->data = pdata; + argp->len = sizeof(u64); + bufp->ipc_buf = pdata; + cbdata->num_bufs++; + (*cnt_in)++; + argp++; + bufp++; + break; + case 'd': + argp->data = va_arg(args, void*); + argp->len = va_arg(args, u32); + (*cnt_in)++; + argp++; + break; + case 's': + ps = va_arg(args, char*); + len = strnlen(ps,256); + if(len>=256) { + ret = IPC_EINVAL; + goto free_and_error; + } + + pdata = iosAlloc(hId,(len+1)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + memcpy(pdata,ps,(len+1)); + argp->data = pdata; + argp->len = (len+1); + bufp->ipc_buf = pdata; + cbdata->num_bufs++; + (*cnt_in)++; + argp++; + bufp++; + break; + case ':': + format++; + goto parse_io_params; + default: + ret = IPC_EINVAL; + goto free_and_error; + } + format++; + } + +parse_io_params: + while(*format) { + type = tolower((int)*format); + switch(type) { + case 'b': + pdata = iosAlloc(hId,sizeof(u8)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + iodata = va_arg(args,u8*); + *(u8*)pdata = *(u8*)iodata; + argp->data = pdata; + argp->len = sizeof(u8); + bufp->ipc_buf = pdata; + bufp->io_buf = iodata; + bufp->copy_len = sizeof(u8); + cbdata->num_bufs++; + (*cnt_io)++; + argp++; + bufp++; + break; + case 'h': + pdata = iosAlloc(hId,sizeof(u16)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + iodata = va_arg(args,u16*); + *(u16*)pdata = *(u16*)iodata; + argp->data = pdata; + argp->len = sizeof(u16); + bufp->ipc_buf = pdata; + bufp->io_buf = iodata; + bufp->copy_len = sizeof(u16); + cbdata->num_bufs++; + (*cnt_io)++; + argp++; + bufp++; + break; + case 'i': + pdata = iosAlloc(hId,sizeof(u32)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + iodata = va_arg(args,u32*); + *(u32*)pdata = *(u32*)iodata; + argp->data = pdata; + argp->len = sizeof(u32); + bufp->ipc_buf = pdata; + bufp->io_buf = iodata; + bufp->copy_len = sizeof(u32); + cbdata->num_bufs++; + (*cnt_io)++; + argp++; + bufp++; + break; + case 'q': + pdata = iosAlloc(hId,sizeof(u64)); + if(pdata==NULL) { + ret = IPC_ENOMEM; + goto free_and_error; + } + iodata = va_arg(args,u64*); + *(u64*)pdata = *(u64*)iodata; + argp->data = pdata; + argp->len = sizeof(u64); + bufp->ipc_buf = pdata; + bufp->io_buf = iodata; + bufp->copy_len = sizeof(u64); + cbdata->num_bufs++; + (*cnt_io)++; + argp++; + bufp++; + break; + case 'd': + argp->data = va_arg(args, void*); + argp->len = va_arg(args, u32); + (*cnt_io)++; + argp++; + break; + default: + ret = IPC_EINVAL; + goto free_and_error; + } + format++; + } + return IPC_OK; + +free_and_error: + for(i=0;inum_bufs;i++) { + if(cbdata->bufs[i].ipc_buf!=NULL) iosFree(hId,cbdata->bufs[i].ipc_buf); + } + __lwp_wkspace_free(cbdata->bufs); + return ret; +} + +static s32 __ipc_asyncrequest(struct _ipcreq *req) +{ + s32 ret; + u32 level; + + ret = __ipc_queuerequest(req); + if(ret) __ipc_freereq(req); + else { + _CPU_ISR_Disable(level); + if(_ipc_mailboxack>0) __ipc_sendrequest(); + _CPU_ISR_Restore(level); + } + return ret; +} + +static s32 __ipc_syncrequest(struct _ipcreq *req) +{ + s32 ret; + u32 level; + + LWP_InitQueue(&req->syncqueue); + + _CPU_ISR_Disable(level); + ret = __ipc_syncqueuerequest(req); + if(ret==0) { + if(_ipc_mailboxack>0) __ipc_sendrequest(); + LWP_ThreadSleep(req->syncqueue); + ret = req->result; + } + _CPU_ISR_Restore(level); + + LWP_CloseQueue(req->syncqueue); + return ret; +} + +s32 iosCreateHeap(s32 size) +{ + s32 i,ret; + s32 free; + u32 level; + u32 ipclo,ipchi; + _CPU_ISR_Disable(level); + + i=0; + while(i=IPC_NUMHEAPS) { + _CPU_ISR_Restore(level); + return IPC_ENOHEAP; + } + + ipclo = (((u32)IPC_GetBufferLo()+0x1f)&~0x1f); + ipchi = (u32)IPC_GetBufferHi(); + free = (ipchi - (ipclo + size)); + if(free<0) return IPC_ENOMEM; + + _ipc_heaps[i].membase = (void*)ipclo; + _ipc_heaps[i].size = size; + + ret = __lwp_heap_init(&_ipc_heaps[i].heap,(void*)ipclo,size,PPC_CACHE_ALIGNMENT); + if(ret<=0) return IPC_ENOMEM; + + IPC_SetBufferLo((void*)(ipclo+size)); + _CPU_ISR_Restore(level); + return i; +} + +void* iosAlloc(s32 hid,s32 size) +{ + if(hid<0 || hid>=IPC_NUMHEAPS || size<=0) return NULL; + return __lwp_heap_allocate(&_ipc_heaps[hid].heap,size); +} + +void iosFree(s32 hid,void *ptr) +{ + if(hid<0 || hid>=IPC_NUMHEAPS || ptr==NULL) return; + __lwp_heap_free(&_ipc_heaps[hid].heap,ptr); +} + +void* IPC_GetBufferLo() +{ + return _ipc_currbufferlo; +} + +void* IPC_GetBufferHi() +{ + return _ipc_currbufferhi; +} + +void IPC_SetBufferLo(void *bufferlo) +{ + if(_ipc_bufferlo<=bufferlo) _ipc_currbufferlo = bufferlo; +} + +void IPC_SetBufferHi(void *bufferhi) +{ + if(bufferhi<=_ipc_bufferhi) _ipc_currbufferhi = bufferhi; +} + +void __IPC_Init(void) +{ + if(!_ipc_initialized) { + _ipc_bufferlo = _ipc_currbufferlo = __SYS_GetIPCBufferLo(); + _ipc_bufferhi = _ipc_currbufferhi = __SYS_GetIPCBufferHi(); + _ipc_initialized = 1; + } +} + +u32 __IPC_ClntInit(void) +{ + if(!_ipc_clntinitialized) { + _ipc_clntinitialized = 1; + + // generate a random request magic + __ipc_srand(gettick()); + IPC_REQ_MAGIC = __ipc_rand(); + + __IPC_Init(); + + _ipc_hid = iosCreateHeap(IPC_HEAP_SIZE); + IRQ_Request(IRQ_PI_ACR,__ipc_interrupthandler,NULL); + __UnmaskIrq(IM_PI_ACR); + IPC_WriteReg(1,56); + } + return IPC_OK; +} + +void __IPC_Reinitialize(void) +{ + u32 level; + + _CPU_ISR_Disable(level); + + IPC_WriteReg(1,56); + + _ipc_mailboxack = 1; + _ipc_relnchFl = 0; + _ipc_relnchRpc = NULL; + + _ipc_responses.req_queue_no = 0; + _ipc_responses.cnt_queue = 0; + _ipc_responses.req_send_no = 0; + _ipc_responses.cnt_sent = 0; + + _CPU_ISR_Restore(level); +} + +s32 IOS_Open(const char *filepath,u32 mode) +{ + s32 ret; + struct _ipcreq *req; + + if(filepath==NULL) return IPC_EINVAL; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_OPEN; + req->cb = NULL; + req->relnch = 0; + + DCFlushRange((void*)filepath,strnlen(filepath,IPC_MAXPATH_LEN) + 1); + + req->open.filepath = (char*)MEM_VIRTUAL_TO_PHYSICAL(filepath); + req->open.mode = mode; + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +s32 IOS_OpenAsync(const char *filepath,u32 mode,ipccallback ipc_cb,void *usrdata) +{ + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_OPEN; + req->cb = ipc_cb; + req->usrdata = usrdata; + req->relnch = 0; + + DCFlushRange((void*)filepath,strnlen(filepath,IPC_MAXPATH_LEN) + 1); + + req->open.filepath = (char*)MEM_VIRTUAL_TO_PHYSICAL(filepath); + req->open.mode = mode; + + return __ipc_asyncrequest(req); +} + +s32 IOS_Close(s32 fd) +{ + s32 ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_CLOSE; + req->fd = fd; + req->cb = NULL; + req->relnch = 0; + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +s32 IOS_CloseAsync(s32 fd,ipccallback ipc_cb,void *usrdata) +{ + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_CLOSE; + req->fd = fd; + req->cb = ipc_cb; + req->usrdata = usrdata; + req->relnch = 0; + + return __ipc_asyncrequest(req); +} + +s32 IOS_Read(s32 fd,void *buf,s32 len) +{ + s32 ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_READ; + req->fd = fd; + req->cb = NULL; + req->relnch = 0; + + DCInvalidateRange(buf,len); + req->read.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf); + req->read.len = len; + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +s32 IOS_ReadAsync(s32 fd,void *buf,s32 len,ipccallback ipc_cb,void *usrdata) +{ + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_READ; + req->fd = fd; + req->cb = ipc_cb; + req->usrdata = usrdata; + req->relnch = 0; + + DCInvalidateRange(buf,len); + req->read.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf); + req->read.len = len; + + return __ipc_asyncrequest(req); +} + +s32 IOS_Write(s32 fd,const void *buf,s32 len) +{ + s32 ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_WRITE; + req->fd = fd; + req->cb = NULL; + req->relnch = 0; + + DCFlushRange((void*)buf,len); + req->write.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf); + req->write.len = len; + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +s32 IOS_WriteAsync(s32 fd,const void *buf,s32 len,ipccallback ipc_cb,void *usrdata) +{ + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_WRITE; + req->fd = fd; + req->cb = ipc_cb; + req->usrdata = usrdata; + req->relnch = 0; + + DCFlushRange((void*)buf,len); + req->write.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf); + req->write.len = len; + + return __ipc_asyncrequest(req); +} + +s32 IOS_Seek(s32 fd,s32 where,s32 whence) +{ + s32 ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_SEEK; + req->fd = fd; + req->cb = NULL; + req->relnch = 0; + + req->seek.where = where; + req->seek.whence = whence; + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +s32 IOS_SeekAsync(s32 fd,s32 where,s32 whence,ipccallback ipc_cb,void *usrdata) +{ + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_SEEK; + req->fd = fd; + req->cb = ipc_cb; + req->usrdata = usrdata; + req->relnch = 0; + + req->seek.where = where; + req->seek.whence = whence; + + return __ipc_asyncrequest(req); +} + +s32 IOS_Ioctl(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io) +{ + s32 ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_IOCTL; + req->fd = fd; + req->cb = NULL; + req->relnch = 0; + + req->ioctl.ioctl = ioctl; + req->ioctl.buffer_in = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_in); + req->ioctl.len_in = len_in; + req->ioctl.buffer_io = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_io); + req->ioctl.len_io = len_io; + + DCFlushRange(buffer_in,len_in); + DCFlushRange(buffer_io,len_io); + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +s32 IOS_IoctlAsync(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io,ipccallback ipc_cb,void *usrdata) +{ + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_IOCTL; + req->fd = fd; + req->cb = ipc_cb; + req->usrdata = usrdata; + req->relnch = 0; + + req->ioctl.ioctl = ioctl; + req->ioctl.buffer_in = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_in); + req->ioctl.len_in = len_in; + req->ioctl.buffer_io = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_io); + req->ioctl.len_io = len_io; + + DCFlushRange(buffer_in,len_in); + DCFlushRange(buffer_io,len_io); + + return __ipc_asyncrequest(req); +} + +s32 IOS_Ioctlv(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv) +{ + s32 i,ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_IOCTLV; + req->fd = fd; + req->cb = NULL; + req->relnch = 0; + + req->ioctlv.ioctl = ioctl; + req->ioctlv.argcin = cnt_in; + req->ioctlv.argcio = cnt_io; + req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv); + + i = 0; + while(i0) { + DCFlushRange(argv[i].data,argv[i].len); + argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data); + } + i++; + } + + i = 0; + while(i0) { + DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len); + argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data); + } + i++; + } + DCFlushRange(argv,((cnt_in+cnt_io)<<3)); + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + + +s32 IOS_IoctlvAsync(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv,ipccallback ipc_cb,void *usrdata) +{ + s32 i; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_IOCTLV; + req->fd = fd; + req->cb = ipc_cb; + req->usrdata = usrdata; + req->relnch = 0; + + req->ioctlv.ioctl = ioctl; + req->ioctlv.argcin = cnt_in; + req->ioctlv.argcio = cnt_io; + req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv); + + i = 0; + while(i0) { + DCFlushRange(argv[i].data,argv[i].len); + argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data); + } + i++; + } + + i = 0; + while(i0) { + DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len); + argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data); + } + i++; + } + DCFlushRange(argv,((cnt_in+cnt_io)<<3)); + + return __ipc_asyncrequest(req); +} + +s32 IOS_IoctlvFormat(s32 hId,s32 fd,s32 ioctl,const char *format,...) +{ + s32 ret; + va_list args; + s32 cnt_in,cnt_io; + struct _ioctlv *argv; + struct _ioctlvfmt_cbdata *cbdata; + + cbdata = __lwp_wkspace_allocate(sizeof(struct _ioctlvfmt_cbdata)); + if(cbdata==NULL) return IPC_ENOMEM; + + memset(cbdata,0,sizeof(struct _ioctlvfmt_cbdata)); + + va_start(args,format); + ret = __ios_ioctlvformat_parse(format,args,cbdata,&cnt_in,&cnt_io,&argv,hId); + va_end(args); + if(ret<0) { + __lwp_wkspace_free(cbdata); + return ret; + } + + ret = IOS_Ioctlv(fd,ioctl,cnt_in,cnt_io,argv); + __ioctlvfmtCB(ret,cbdata); + + return ret; +} + +s32 IOS_IoctlvFormatAsync(s32 hId,s32 fd,s32 ioctl,ipccallback usr_cb,void *usr_data,const char *format,...) +{ + s32 ret; + va_list args; + s32 cnt_in,cnt_io; + struct _ioctlv *argv; + struct _ioctlvfmt_cbdata *cbdata; + + cbdata = __lwp_wkspace_allocate(sizeof(struct _ioctlvfmt_cbdata)); + if(cbdata==NULL) return IPC_ENOMEM; + + memset(cbdata,0,sizeof(struct _ioctlvfmt_cbdata)); + + va_start(args,format); + ret = __ios_ioctlvformat_parse(format,args,cbdata,&cnt_in,&cnt_io,&argv,hId); + va_end(args); + if(ret<0) { + __lwp_wkspace_free(cbdata); + return ret; + } + + cbdata->user_cb = usr_cb; + cbdata->user_data = usr_data; + return IOS_IoctlvAsync(fd,ioctl,cnt_in,cnt_io,argv,__ioctlvfmtCB,cbdata); +} + +s32 IOS_IoctlvReboot(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv) +{ + s32 i,ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_IOCTLV; + req->fd = fd; + req->cb = NULL; + req->relnch = RELNCH_RELAUNCH; + + req->ioctlv.ioctl = ioctl; + req->ioctlv.argcin = cnt_in; + req->ioctlv.argcio = cnt_io; + req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv); + + i = 0; + while(i0) { + DCFlushRange(argv[i].data,argv[i].len); + argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data); + } + i++; + } + + i = 0; + while(i0) { + DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len); + argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data); + } + i++; + } + DCFlushRange(argv,((cnt_in+cnt_io)<<3)); + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +s32 IOS_IoctlvRebootBackground(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv) +{ + s32 i,ret; + struct _ipcreq *req; + + req = __ipc_allocreq(); + if(req==NULL) return IPC_ENOMEM; + + req->cmd = IOS_IOCTLV; + req->result = 0; + req->fd = fd; + req->cb = NULL; + req->relnch = RELNCH_BACKGROUND|RELNCH_RELAUNCH; + + req->ioctlv.ioctl = ioctl; + req->ioctlv.argcin = cnt_in; + req->ioctlv.argcio = cnt_io; + req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv); + + i = 0; + while(i0) { + DCFlushRange(argv[i].data,argv[i].len); + argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data); + } + i++; + } + + i = 0; + while(i0) { + DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len); + argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data); + } + i++; + } + DCFlushRange(argv,((cnt_in+cnt_io)<<3)); + + ret = __ipc_syncrequest(req); + + if(req!=NULL) __ipc_freereq(req); + return ret; +} + +#endif diff --git a/wii/libogc/libogc/irq.c b/wii/libogc/libogc/irq.c new file mode 100644 index 0000000000..0e59f51e2b --- /dev/null +++ b/wii/libogc/libogc/irq.c @@ -0,0 +1,421 @@ +/*------------------------------------------------------------- + +irq.h -- Interrupt subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include "asm.h" +#include "cache.h" +#include "context.h" +#include "processor.h" +#include "lwp_threads.h" +#include "irq.h" +#include "console.h" + +#define CPU_STACK_ALIGNMENT 8 +#define CPU_MINIMUM_STACK_FRAME_SIZE 16 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +struct irq_handler_s { + raw_irq_handler_t pHndl; + void *pCtx; +}; + +static u64 spuriousIrq = 0; +static u32 prevIrqMask = 0; +static u32 currIrqMask = 0; +static struct irq_handler_s g_IRQHandler[32]; + +static vu32* const _piReg = (u32*)0xCC003000; +static vu16* const _memReg = (u16*)0xCC004000; +static vu16* const _dspReg = (u16*)0xCC005000; + +#if defined(HW_DOL) +static vu32* const _exiReg = (u32*)0xCC006800; +static vu32* const _aiReg = (u32*)0xCC006C00; +#elif defined(HW_RVL) +static vu32* const _exiReg = (u32*)0xCD006800; +static vu32* const _aiReg = (u32*)0xCD006C00; +#endif + +static u32 const _irqPrio[] = {IM_PI_ERROR,IM_PI_DEBUG,IM_MEM,IM_PI_RSW, + IM_PI_VI,(IM_PI_PETOKEN|IM_PI_PEFINISH), + IM_PI_HSP, + (IM_DSP_ARAM|IM_DSP_DSP|IM_AI|IM_EXI|IM_PI_SI|IM_PI_DI), + IM_DSP_AI,IM_PI_CP, +#if defined(HW_RVL) + IM_PI_ACR, +#endif + 0xffffffff}; + +extern void __exception_load(u32,void *,u32,void *); + +extern s8 irqhandler_start[],irqhandler_end[]; +extern u8 __intrstack_addr[],__intrstack_end[]; + +void c_irqdispatcher(frame_context *ctx) +{ + u32 i,icause,intmask,irq = 0; + u32 cause,mask; + + cause = _piReg[0]&~0x10000; + mask = _piReg[1]; + + if(!cause || !(cause&mask)) { + spuriousIrq++; + return; + } + + intmask = 0; + if(cause&0x00000080) { //Memory Interface + icause = _memReg[15]; + if(icause&0x00000001) { + intmask |= IRQMASK(IRQ_MEM0); + } + if(icause&0x00000002) { + intmask |= IRQMASK(IRQ_MEM1); + } + if(icause&0x00000004) { + intmask |= IRQMASK(IRQ_MEM2); + } + if(icause&0x00000008) { + intmask |= IRQMASK(IRQ_MEM3); + } + if(icause&0x00000010) { + intmask |= IRQMASK(IRQ_MEMADDRESS); + } + } + if(cause&0x00000040) { //DSP + icause = _dspReg[5]; + if(icause&0x00000008){ + intmask |= IRQMASK(IRQ_DSP_AI); + } + if(icause&0x00000020){ + intmask |= IRQMASK(IRQ_DSP_ARAM); + } + if(icause&0x00000080){ + intmask |= IRQMASK(IRQ_DSP_DSP); + } + } + if(cause&0x00000020) { //Streaming + icause = _aiReg[0]; + if(icause&0x00000008) { + intmask |= IRQMASK(IRQ_AI); + } + } + if(cause&0x00000010) { //EXI + //EXI 0 + icause = _exiReg[0]; + if(icause&0x00000002) { + intmask |= IRQMASK(IRQ_EXI0_EXI); + } + if(icause&0x00000008) { + intmask |= IRQMASK(IRQ_EXI0_TC); + } + if(icause&0x00000800) { + intmask |= IRQMASK(IRQ_EXI0_EXT); + } + //EXI 1 + icause = _exiReg[5]; + if(icause&0x00000002) { + intmask |= IRQMASK(IRQ_EXI1_EXI); + } + if(icause&0x00000008) { + intmask |= IRQMASK(IRQ_EXI1_TC); + } + if(icause&0x00000800) { + intmask |= IRQMASK(IRQ_EXI1_EXT); + } + //EXI 2 + icause = _exiReg[10]; + if(icause&0x00000002) { + intmask |= IRQMASK(IRQ_EXI2_EXI); + } + if(icause&0x00000008) { + intmask |= IRQMASK(IRQ_EXI2_TC); + } + } + if(cause&0x00002000) { //High Speed Port + intmask |= IRQMASK(IRQ_PI_HSP); + } + if(cause&0x00001000) { //External Debugger + intmask |= IRQMASK(IRQ_PI_DEBUG); + } + if(cause&0x00000400) { //Frame Ready (PE_FINISH) + intmask |= IRQMASK(IRQ_PI_PEFINISH); + } + if(cause&0x00000200) { //Token Assertion (PE_TOKEN) + intmask |= IRQMASK(IRQ_PI_PETOKEN); + } + if(cause&0x00000100) { //Video Interface + intmask |= IRQMASK(IRQ_PI_VI); + } + if(cause&0x00000008) { //Serial + intmask |= IRQMASK(IRQ_PI_SI); + } + if(cause&0x00000004) { //DVD + intmask |= IRQMASK(IRQ_PI_DI); + } + if(cause&0x00000002) { //Reset Switch + intmask |= IRQMASK(IRQ_PI_RSW); + } + if(cause&0x00000800) { //Command FIFO + intmask |= IRQMASK(IRQ_PI_CP); + } + if(cause&0x00000001) { //GP Runtime Error + intmask |= IRQMASK(IRQ_PI_ERROR); + } +#if defined(HW_RVL) + if(cause&0x00004000) { + intmask |= IRQMASK(IRQ_PI_ACR); + } +#endif + mask = intmask&~(prevIrqMask|currIrqMask); + if(mask) { + i=0; + irq = 0; + while(i<(sizeof(_irqPrio)/sizeof(u32))) { + if((irq=(mask&_irqPrio[i]))) { + irq = cntlzw(irq); + break; + } + i++; + } + + if(g_IRQHandler[irq].pHndl) g_IRQHandler[irq].pHndl(irq,g_IRQHandler[irq].pCtx); + } +} + +static u32 __SetInterrupts(u32 iMask,u32 nMask) +{ + u32 imask; + u32 irq = cntlzw(iMask); + + if(irq<=IRQ_MEMADDRESS) + { + imask = 0; + if(!(nMask&IM_MEM0)) imask |= 0x0001; + if(!(nMask&IM_MEM1)) imask |= 0x0002; + if(!(nMask&IM_MEM2)) imask |= 0x0004; + if(!(nMask&IM_MEM3)) imask |= 0x0008; + if(!(nMask&IM_MEMADDRESS)) imask |= 0x0010; + _memReg[14] = (u16)imask; + return (iMask&~IM_MEM); + } + + if(irq>=IRQ_DSP_AI && irq<=IRQ_DSP_DSP) { + imask = _dspReg[5]&~0x1f8; + if(!(nMask&IM_DSP_AI)) imask |= 0x0010; + if(!(nMask&IM_DSP_ARAM)) imask |= 0x0040; + if(!(nMask&IM_DSP_DSP)) imask |= 0x0100; + _dspReg[5] = (u16)imask; + return (iMask&~IM_DSP); + } + + if(irq==IRQ_AI) { + imask = _aiReg[0]&~0x2c; + if(!(nMask&IM_AI)) imask |= 0x0004; + _aiReg[0] = imask; + return (iMask&~IM_AI); + } + if(irq>=IRQ_EXI0_EXI && irq<=IRQ_EXI0_EXT) { + imask = _exiReg[0]&~0x2c0f; + if(!(nMask&IM_EXI0_EXI)) imask |= 0x0001; + if(!(nMask&IM_EXI0_TC)) imask |= 0x0004; + if(!(nMask&IM_EXI0_EXT)) imask |= 0x0400; + _exiReg[0] = imask; + return (iMask&~IM_EXI0); + } + + if(irq>=IRQ_EXI1_EXI && irq<=IRQ_EXI1_EXT) { + imask = _exiReg[5]&~0x0c0f; + if(!(nMask&IM_EXI1_EXI)) imask |= 0x0001; + if(!(nMask&IM_EXI1_TC)) imask |= 0x0004; + if(!(nMask&IM_EXI1_EXT)) imask |= 0x0400; + _exiReg[5] = imask; + return (iMask&~IM_EXI1); + } + + if(irq>=IRQ_EXI2_EXI && irq<=IRQ_EXI2_TC) { + imask = _exiReg[10]&~0x000f; + if(!(nMask&IM_EXI2_EXI)) imask |= 0x0001; + if(!(nMask&IM_EXI2_TC)) imask |= 0x0004; + _exiReg[10] = imask; + return (iMask&~IM_EXI2); + } + +#if defined(HW_DOL) + if(irq>=IRQ_PI_CP && irq<=IRQ_PI_HSP) { +#elif defined(HW_RVL) + if(irq>=IRQ_PI_CP && irq<=IRQ_PI_ACR) { +#endif + imask = 0xf0; + if(!(nMask&IM_PI_ERROR)) { + imask |= 0x00000001; + } + if(!(nMask&IM_PI_RSW)) { + imask |= 0x00000002; + } + if(!(nMask&IM_PI_DI)) { + imask |= 0x00000004; + } + if(!(nMask&IM_PI_SI)) { + imask |= 0x00000008; + } + if(!(nMask&IM_PI_VI)) { + imask |= 0x00000100; + } + if(!(nMask&IM_PI_PETOKEN)) { + imask |= 0x00000200; + } + if(!(nMask&IM_PI_PEFINISH)) { + imask |= 0x00000400; + } + if(!(nMask&IM_PI_CP)) { + imask |= 0x00000800; + } + if(!(nMask&IM_PI_DEBUG)) { + imask |= 0x00001000; + } + if(!(nMask&IM_PI_HSP)) { + imask |= 0x00002000; + } +#if defined(HW_RVL) + if(!(nMask&IM_PI_ACR)) { + imask |= 0x00004000; + } +#endif + _piReg[1] = imask; + return (iMask&~IM_PI); + } + return 0; +} + +void __UnmaskIrq(u32 nMask) +{ + u32 level; + u32 mask; + + _CPU_ISR_Disable(level); + mask = (nMask&(prevIrqMask|currIrqMask)); + nMask = (prevIrqMask&~nMask); + prevIrqMask = nMask; + while((mask=__SetInterrupts(mask,(nMask|currIrqMask)))!=0); + _CPU_ISR_Restore(level); +} + +void __MaskIrq(u32 nMask) +{ + u32 level; + u32 mask; + + _CPU_ISR_Disable(level); + mask = (nMask&~(prevIrqMask|currIrqMask)); + nMask = (nMask|prevIrqMask); + prevIrqMask = nMask; + while((mask=__SetInterrupts(mask,(nMask|currIrqMask)))!=0); + _CPU_ISR_Restore(level); +} + +void __irq_init() +{ + register u32 intrStack = (u32)__intrstack_addr; + register u32 intrStack_end = (u32)__intrstack_end; + register u32 irqNestingLevel = 0; + + memset(g_IRQHandler,0,32*sizeof(struct irq_handler_s)); + + *((u32*)intrStack_end) = 0xDEADBEEF; + intrStack = intrStack - CPU_MINIMUM_STACK_FRAME_SIZE; + intrStack &= ~(CPU_STACK_ALIGNMENT-1); + *((u32*)intrStack) = 0; + + mtspr(272,irqNestingLevel); + mtspr(273,intrStack); + + prevIrqMask = 0; + currIrqMask = 0; + _piReg[1] = 0xf0; + + __MaskIrq(-32); + + _piReg[0] = 0x01; + __UnmaskIrq(IM_PI_ERROR); +} + +raw_irq_handler_t IRQ_Request(u32 nIrq,raw_irq_handler_t pHndl,void *pCtx) +{ + u32 level; + + _CPU_ISR_Disable(level); + raw_irq_handler_t old = g_IRQHandler[nIrq].pHndl; + g_IRQHandler[nIrq].pHndl = pHndl; + g_IRQHandler[nIrq].pCtx = pCtx; + _CPU_ISR_Restore(level); + return old; +} + +raw_irq_handler_t IRQ_GetHandler(u32 nIrq) +{ + u32 level; + raw_irq_handler_t ret; + + _CPU_ISR_Disable(level); + ret = g_IRQHandler[nIrq].pHndl; + _CPU_ISR_Restore(level); + return ret; +} + +raw_irq_handler_t IRQ_Free(u32 nIrq) +{ + u32 level; + + _CPU_ISR_Disable(level); + raw_irq_handler_t old = g_IRQHandler[nIrq].pHndl; + g_IRQHandler[nIrq].pHndl = NULL; + g_IRQHandler[nIrq].pCtx = NULL; + _CPU_ISR_Restore(level); + return old; +} + +u32 IRQ_Disable() +{ + u32 level; + _CPU_ISR_Disable(level); + return level; +} + +void IRQ_Restore(u32 level) +{ + _CPU_ISR_Restore(level); +} diff --git a/wii/libogc/libogc/irq_handler.S b/wii/libogc/libogc/irq_handler.S new file mode 100644 index 0000000000..da37e43d81 --- /dev/null +++ b/wii/libogc/libogc/irq_handler.S @@ -0,0 +1,166 @@ +/*------------------------------------------------------------- + +irq_handler.S -- Interrupt subsystem + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include + +#define EXCEPTION_PROLOG \ + mfspr r0,912; \ + stw r0,GQR0_OFFSET(sp); \ + mfspr r0,913; \ + stw r0,GQR1_OFFSET(sp); \ + mfspr r0,914; \ + stw r0,GQR2_OFFSET(sp); \ + mfspr r0,915; \ + stw r0,GQR3_OFFSET(sp); \ + mfspr r0,916; \ + stw r0,GQR4_OFFSET(sp); \ + mfspr r0,917; \ + stw r0,GQR5_OFFSET(sp); \ + mfspr r0,918; \ + stw r0,GQR6_OFFSET(sp); \ + mfspr r0,919; \ + stw r0,GQR7_OFFSET(sp); \ + stw r6,GPR6_OFFSET(sp); \ + stw r7,GPR7_OFFSET(sp); \ + stw r8,GPR8_OFFSET(sp); \ + stw r9,GPR9_OFFSET(sp); \ + stw r10,GPR10_OFFSET(sp); \ + stw r11,GPR11_OFFSET(sp); \ + stw r12,GPR12_OFFSET(sp); \ + stw r13,GPR13_OFFSET(sp); \ + stw r14,GPR14_OFFSET(sp); \ + stw r15,GPR15_OFFSET(sp) + +#define EXCEPTION_EPILOG \ + lwz r4,GQR0_OFFSET(sp); \ + mtspr 912,r4; \ + lwz r4,GQR1_OFFSET(sp); \ + mtspr 913,r4; \ + lwz r4,GQR2_OFFSET(sp); \ + mtspr 914,r4; \ + lwz r4,GQR3_OFFSET(sp); \ + mtspr 915,r4; \ + lwz r4,GQR4_OFFSET(sp); \ + mtspr 916,r4; \ + lwz r4,GQR5_OFFSET(sp); \ + mtspr 917,r4; \ + lwz r4,GQR6_OFFSET(sp); \ + mtspr 918,r4; \ + lwz r4,GQR7_OFFSET(sp); \ + mtspr 919,r4; \ + lwz r15,GPR15_OFFSET(sp); \ + lwz r14,GPR14_OFFSET(sp); \ + lwz r13,GPR13_OFFSET(sp); \ + lwz r12,GPR12_OFFSET(sp); \ + lwz r11,GPR11_OFFSET(sp); \ + lwz r10,GPR10_OFFSET(sp); \ + lwz r9,GPR9_OFFSET(sp); \ + lwz r8,GPR8_OFFSET(sp); \ + lwz r7,GPR7_OFFSET(sp); \ + lwz r6,GPR6_OFFSET(sp); \ + lwz r5,GPR5_OFFSET(sp) + + .extern c_irqdispatcher + .globl irq_exceptionhandler +irq_exceptionhandler: + stwu sp,-EXCEPTION_FRAME_END(sp) //now we're able to adjust the stackpointer with it's cached address + + EXCEPTION_PROLOG + + mfmsr r3 + ori r3,r3,MSR_RI + mtmsr r3 + isync + + addi r14,sp,0 + lis r15,_thread_dispatch_disable_level@ha + + mfspr r3,SPRG0 + cmpwi r3,0 + bne nested + mfspr sp,SPRG1 + +nested: + addi r3,r3,1 + lwz r6,_thread_dispatch_disable_level@l(r15) + mtspr SPRG0,r3 + addi r6,r6,1 + stw r6,_thread_dispatch_disable_level@l(r15) + + addi r3,r14,0x08 + bl c_irqdispatcher + + mfspr r4,SPRG0 + lwz r3,_thread_dispatch_disable_level@l(r15) + addi r4,r4,-1 + addic. r3,r3,-1 + mtspr SPRG0,r4 + stw r3,_thread_dispatch_disable_level@l(r15) + addi sp,r14,0 + bne easy_exit + + lis r4,_context_switch_want@ha + lwz r5,_context_switch_want@l(r4) + cmpwi r5,0 + beq easy_exit + +switch: + bl __thread_dispatch + +easy_exit: + lwz r4,CR_OFFSET(sp) + mtcr r4 + lwz r4,LR_OFFSET(sp) + mtlr r4 + lwz r4,CTR_OFFSET(sp) + mtctr r4 + lwz r4,XER_OFFSET(sp) + mtxer r4 + + EXCEPTION_EPILOG + + mfmsr r4 + rlwinm r4,r4,0,31,29 + mtmsr r4 + isync + + lwz r0,GPR0_OFFSET(sp) + lwz toc,GPR2_OFFSET(sp) + + lwz r4,SRR0_OFFSET(sp) + mtsrr0 r4 + lwz r4,SRR1_OFFSET(sp) + rlwinm r4, r4, 0, 19, 17 + mtsrr1 r4 + + lwz r4,GPR4_OFFSET(sp) + lwz r3,GPR3_OFFSET(sp) + addi sp,sp,EXCEPTION_FRAME_END + rfi diff --git a/wii/libogc/libogc/isfs.c b/wii/libogc/libogc/isfs.c new file mode 100644 index 0000000000..d7e768f7bf --- /dev/null +++ b/wii/libogc/libogc/isfs.c @@ -0,0 +1,844 @@ +/*------------------------------------------------------------- + +es.c -- ETicket services + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include +#include +#include +#include +#include +#include + +#include "isfs.h" + +#define ISFS_STRUCTSIZE (sizeof(struct isfs_cb)) +#define ISFS_HEAPSIZE (ISFS_STRUCTSIZE<<4) + +#define ISFS_FUNCNULL 0 +#define ISFS_FUNCGETSTAT 1 +#define ISFS_FUNCREADDIR 2 +#define ISFS_FUNCGETATTR 3 +#define ISFS_FUNCGETUSAGE 4 + +#define ISFS_IOCTL_FORMAT 1 +#define ISFS_IOCTL_GETSTATS 2 +#define ISFS_IOCTL_CREATEDIR 3 +#define ISFS_IOCTL_READDIR 4 +#define ISFS_IOCTL_SETATTR 5 +#define ISFS_IOCTL_GETATTR 6 +#define ISFS_IOCTL_DELETE 7 +#define ISFS_IOCTL_RENAME 8 +#define ISFS_IOCTL_CREATEFILE 9 +#define ISFS_IOCTL_SETFILEVERCTRL 10 +#define ISFS_IOCTL_GETFILESTATS 11 +#define ISFS_IOCTL_GETUSAGE 12 +#define ISFS_IOCTL_SHUTDOWN 13 + +struct isfs_cb +{ + char filepath[ISFS_MAXPATH]; + union { + struct { + char filepathOld[ISFS_MAXPATH]; + char filepathNew[ISFS_MAXPATH]; + } fsrename; + struct { + u32 owner_id; + u16 group_id; + char filepath[ISFS_MAXPATH]; + u8 ownerperm; + u8 groupperm; + u8 otherperm; + u8 attributes; + u8 pad0[2]; + } fsattr; + struct { + ioctlv vector[4]; + u32 no_entries; + } fsreaddir; + struct { + ioctlv vector[4]; + u32 usage1; + u8 pad0[28]; + u32 usage2; + } fsusage; + struct { + u32 a; + u32 b; + u32 c; + u32 d; + u32 e; + u32 f; + u32 g; + } fsstats; + }; + + isfscallback cb; + void *usrdata; + u32 functype; + void *funcargv[8]; +}; + + +static s32 hId = -1; +static s32 _fs_fd = -1; +static char _dev_fs[] ATTRIBUTE_ALIGN(32) = "/dev/fs"; + +static s32 __isfsGetStatsCB(s32 result,void *usrdata) +{ + struct isfs_cb *param = (struct isfs_cb*)usrdata; + if(result==0) memcpy(param->funcargv[0],¶m->fsstats,sizeof(param->fsstats)); + return result; +} + +static s32 __isfsGetAttrCB(s32 result,void *usrdata) +{ + struct isfs_cb *param = (struct isfs_cb*)usrdata; + if(result==0) { + *(u32*)(param->funcargv[0]) = param->fsattr.owner_id; + *(u16*)(param->funcargv[1]) = param->fsattr.group_id; + *(u8*)(param->funcargv[2]) = param->fsattr.attributes; + *(u8*)(param->funcargv[3]) = param->fsattr.ownerperm; + *(u8*)(param->funcargv[4]) = param->fsattr.groupperm; + *(u8*)(param->funcargv[5]) = param->fsattr.otherperm; + } + return result; +} + +static s32 __isfsGetUsageCB(s32 result,void *usrdata) +{ + struct isfs_cb *param = (struct isfs_cb*)usrdata; + if(result==0) { + *(u32*)(param->funcargv[0]) = param->fsusage.usage1; + *(u32*)(param->funcargv[1]) = param->fsusage.usage2; + } + return result; + +} +static s32 __isfsReadDirCB(s32 result,void *usrdata) +{ + struct isfs_cb *param = (struct isfs_cb*)usrdata; + if(result==0) *(u32*)(param->funcargv[0]) = param->fsreaddir.no_entries; + return result; +} + +static s32 __isfsFunctionCB(s32 result,void *usrdata) +{ + struct isfs_cb *param = (struct isfs_cb*)usrdata; + + if(result>=0) { + if(param->functype==ISFS_FUNCGETSTAT) __isfsGetStatsCB(result,usrdata); + else if(param->functype==ISFS_FUNCREADDIR) __isfsReadDirCB(result,usrdata); + else if(param->functype==ISFS_FUNCGETATTR) __isfsGetAttrCB(result,usrdata); + else if(param->functype==ISFS_FUNCGETUSAGE) __isfsGetUsageCB(result,usrdata); + } + if(param->cb!=NULL) param->cb(result,param->usrdata); + + iosFree(hId,param); + return result; +} + +s32 ISFS_Initialize() +{ + s32 ret = IPC_OK; + + if(_fs_fd<0) { + _fs_fd = IOS_Open(_dev_fs,0); + if(_fs_fd<0) return _fs_fd; + } + + if(hId<0) { + hId = iosCreateHeap(ISFS_HEAPSIZE); + if(hId<0) return IPC_ENOMEM; + } + return ret; +} + +s32 ISFS_Deinitialize() +{ + if(_fs_fd<0) return ISFS_EINVAL; + + IOS_Close(_fs_fd); + _fs_fd = -1; + + return 0; +} + +s32 ISFS_ReadDir(const char *filepath,char *name_list,u32 *num) +{ + s32 ret; + s32 len,cnt; + s32 ilen,olen; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL || num==NULL) return ISFS_EINVAL; + if(name_list!=NULL && ((u32)name_list%32)!=0) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->filepath,filepath,(len+1)); + + param->fsreaddir.vector[0].data = param->filepath; + param->fsreaddir.vector[0].len = ISFS_MAXPATH; + param->fsreaddir.vector[1].data = ¶m->fsreaddir.no_entries; + param->fsreaddir.vector[1].len = sizeof(u32); + + if(name_list!=NULL) { + ilen = olen = 2; + cnt = *num; + param->fsreaddir.no_entries = cnt; + param->fsreaddir.vector[2].data = name_list; + param->fsreaddir.vector[2].len = (cnt*13); + param->fsreaddir.vector[3].data = ¶m->fsreaddir.no_entries; + param->fsreaddir.vector[3].len = sizeof(u32); + } else + ilen = olen = 1; + + ret = IOS_Ioctlv(_fs_fd,ISFS_IOCTL_READDIR,ilen,olen,param->fsreaddir.vector); + if(ret==0) *num = param->fsreaddir.no_entries; + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_ReadDirAsync(const char *filepath,char *name_list,u32 *num,isfscallback cb,void *usrdata) +{ + s32 len,cnt; + s32 ilen,olen; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL || num==NULL) return ISFS_EINVAL; + if(name_list!=NULL && ((u32)name_list%32)!=0) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->funcargv[0] = num; + param->functype = ISFS_FUNCREADDIR; + memcpy(param->filepath,filepath,(len+1)); + + param->fsreaddir.vector[0].data = param->filepath; + param->fsreaddir.vector[0].len = ISFS_MAXPATH; + param->fsreaddir.vector[1].data = ¶m->fsreaddir.no_entries; + param->fsreaddir.vector[1].len = sizeof(u32); + + if(name_list!=NULL) { + ilen = olen = 2; + cnt = *num; + param->fsreaddir.no_entries = cnt; + param->fsreaddir.vector[2].data = name_list; + param->fsreaddir.vector[2].len = (cnt*13); + param->fsreaddir.vector[3].data = ¶m->fsreaddir.no_entries; + param->fsreaddir.vector[3].len = sizeof(u32); + } else + ilen = olen = 1; + + return IOS_IoctlvAsync(_fs_fd,ISFS_IOCTL_READDIR,ilen,olen,param->fsreaddir.vector,__isfsFunctionCB,param); +} + +s32 ISFS_CreateDir(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm) +{ + s32 ret; + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->fsattr.filepath ,filepath,(len+1)); + + param->fsattr.attributes = attributes; + param->fsattr.ownerperm = owner_perm; + param->fsattr.groupperm = group_perm; + param->fsattr.otherperm = other_perm; + ret = IOS_Ioctl(_fs_fd,ISFS_IOCTL_CREATEDIR,¶m->fsattr,sizeof(param->fsattr),NULL,0); + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_CreateDirAsync(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm,isfscallback cb,void *usrdata) +{ + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + memcpy(param->fsattr.filepath,filepath,(len+1)); + + param->fsattr.attributes = attributes; + param->fsattr.ownerperm = owner_perm; + param->fsattr.groupperm = group_perm; + param->fsattr.otherperm = other_perm; + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_CREATEDIR,¶m->fsattr,sizeof(param->fsattr),NULL,0,__isfsFunctionCB,param); +} + +s32 ISFS_Open(const char *filepath,u8 mode) +{ + s32 ret; + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->filepath,filepath,(len+1)); + ret = IOS_Open(param->filepath,mode); + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_OpenAsync(const char *filepath,u8 mode,isfscallback cb,void *usrdata) +{ + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + memcpy(param->filepath,filepath,(len+1)); + return IOS_OpenAsync(param->filepath,mode,__isfsFunctionCB,param); +} + +s32 ISFS_Format() +{ + if(_fs_fd<0) return ISFS_EINVAL; + + return IOS_Ioctl(_fs_fd,ISFS_IOCTL_FORMAT,NULL,0,NULL,0); +} + +s32 ISFS_FormatAsync(isfscallback cb,void *usrdata) +{ + struct isfs_cb *param; + + if(_fs_fd<0) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_FORMAT,NULL,0,NULL,0,__isfsFunctionCB,param); +} + +s32 ISFS_GetStats(void *stats) +{ + s32 ret = ISFS_OK; + struct isfs_cb *param; + + if(_fs_fd<0 || stats==NULL) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + ret = IOS_Ioctl(_fs_fd,ISFS_IOCTL_GETSTATS,NULL,0,¶m->fsstats,sizeof(param->fsstats)); + if(ret==IPC_OK) memcpy(stats,¶m->fsstats,sizeof(param->fsstats)); + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_GetStatsAsync(void *stats,isfscallback cb,void *usrdata) +{ + struct isfs_cb *param; + + if(_fs_fd<0 || stats==NULL) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCGETSTAT; + param->funcargv[0] = stats; + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_GETSTATS,NULL,0,¶m->fsstats,sizeof(param->fsstats),__isfsFunctionCB,param); +} + +s32 ISFS_Write(s32 fd,const void *buffer,u32 length) +{ + if(length<=0 || buffer==NULL) return ISFS_EINVAL; + + return IOS_Write(fd,buffer,length); +} + +s32 ISFS_WriteAsync(s32 fd,const void *buffer,u32 length,isfscallback cb,void *usrdata) +{ + struct isfs_cb *param; + + if(length<=0 || buffer==NULL) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + return IOS_WriteAsync(fd,buffer,length,__isfsFunctionCB,param); +} + +s32 ISFS_Read(s32 fd,void *buffer,u32 length) +{ + if(length<=0 || buffer==NULL || ((u32)buffer%32)!=0) return ISFS_EINVAL; + + return IOS_Read(fd,buffer,length); +} + +s32 ISFS_ReadAsync(s32 fd,void *buffer,u32 length,isfscallback cb,void *usrdata) +{ + struct isfs_cb *param; + + if(length<=0 || buffer==NULL || ((u32)buffer%32)!=0) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + return IOS_ReadAsync(fd,buffer,length,__isfsFunctionCB,param); +} + +s32 ISFS_Seek(s32 fd,s32 where,s32 whence) +{ + return IOS_Seek(fd,where,whence); +} + +s32 ISFS_SeekAsync(s32 fd,s32 where,s32 whence,isfscallback cb,void *usrdata) +{ + struct isfs_cb *param; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + return IOS_SeekAsync(fd,where,whence,__isfsFunctionCB,param); +} + +s32 ISFS_CreateFile(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm) +{ + s32 ret; + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->fsattr.filepath,filepath,(len+1)); + + param->fsattr.attributes = attributes; + param->fsattr.ownerperm = owner_perm; + param->fsattr.groupperm = group_perm; + param->fsattr.otherperm = other_perm; + ret = IOS_Ioctl(_fs_fd,ISFS_IOCTL_CREATEFILE,¶m->fsattr,sizeof(param->fsattr),NULL,0); + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_CreateFileAsync(const char *filepath,u8 attributes,u8 owner_perm,u8 group_perm,u8 other_perm,isfscallback cb,void *usrdata) +{ + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + memcpy(param->fsattr.filepath,filepath,(len+1)); + + param->fsattr.attributes = attributes; + param->fsattr.ownerperm = owner_perm; + param->fsattr.groupperm = group_perm; + param->fsattr.otherperm = other_perm; + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_CREATEFILE,¶m->fsattr,sizeof(param->fsattr),NULL,0,__isfsFunctionCB,param); +} + +s32 ISFS_Delete(const char *filepath) +{ + s32 ret; + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->filepath,filepath,(len+1)); + ret = IOS_Ioctl(_fs_fd,ISFS_IOCTL_DELETE,param->filepath,ISFS_MAXPATH,NULL,0); + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_DeleteAsync(const char *filepath,isfscallback cb,void *usrdata) +{ + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + memcpy(param->filepath,filepath,(len+1)); + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_DELETE,param->filepath,ISFS_MAXPATH,NULL,0,__isfsFunctionCB,param); +} + +s32 ISFS_Close(s32 fd) +{ + if(fd<0) return 0; + + return IOS_Close(fd); +} + +s32 ISFS_CloseAsync(s32 fd,isfscallback cb,void *usrdata) +{ + struct isfs_cb *param; + + if(fd<0) return 0; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + return IOS_CloseAsync(fd,__isfsFunctionCB,param); +} + +s32 ISFS_GetFileStats(s32 fd,fstats *status) +{ + if(status==NULL || ((u32)status%32)!=0) return ISFS_EINVAL; + + return IOS_Ioctl(fd,ISFS_IOCTL_GETFILESTATS,NULL,0,status,sizeof(fstats)); +} + +s32 ISFS_GetFileStatsAsync(s32 fd,fstats *status,isfscallback cb,void *usrdata) +{ + struct isfs_cb *param; + + if(status==NULL || ((u32)status%32)!=0) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + return IOS_IoctlAsync(fd,ISFS_IOCTL_GETFILESTATS,NULL,0,status,sizeof(fstats),__isfsFunctionCB,param); +} + +s32 ISFS_GetAttr(const char *filepath,u32 *ownerID,u16 *groupID,u8 *attributes,u8 *ownerperm,u8 *groupperm,u8 *otherperm) +{ + s32 ret; + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL || ownerID==NULL || groupID==NULL + || attributes==NULL || ownerperm==NULL || groupperm==NULL || otherperm==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->filepath,filepath,(len+1)); + ret = IOS_Ioctl(_fs_fd,ISFS_IOCTL_GETATTR,param->filepath,ISFS_MAXPATH,¶m->fsattr,sizeof(param->fsattr)); + if(ret==IPC_OK) { + *ownerID = param->fsattr.owner_id; + *groupID = param->fsattr.group_id; + *ownerperm = param->fsattr.ownerperm; + *groupperm = param->fsattr.groupperm; + *otherperm = param->fsattr.otherperm; + *attributes = param->fsattr.attributes; + } + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_GetAttrAsync(const char *filepath,u32 *ownerID,u16 *groupID,u8 *attributes,u8 *ownerperm,u8 *groupperm,u8 *otherperm,isfscallback cb,void *usrdata) +{ + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL || ownerID==NULL || groupID==NULL + || attributes==NULL || ownerperm==NULL || groupperm==NULL || otherperm==NULL) return ISFS_EINVAL; + + len = strnlen(filepath,ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCGETATTR; + param->funcargv[0] = ownerID; + param->funcargv[1] = groupID; + param->funcargv[2] = attributes; + param->funcargv[3] = ownerperm; + param->funcargv[4] = groupperm; + param->funcargv[5] = otherperm; + memcpy(param->filepath,filepath,(len+1)); + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_GETATTR,param->filepath,ISFS_MAXPATH,¶m->fsattr,sizeof(param->fsattr),__isfsFunctionCB,param); +} + +s32 ISFS_Rename(const char *filepathOld,const char *filepathNew) +{ + s32 ret; + s32 len0,len1; + struct isfs_cb *param; + + if(_fs_fd<0 || filepathOld==NULL || filepathNew==NULL) return ISFS_EINVAL; + + len0 = strnlen(filepathOld,ISFS_MAXPATH); + if(len0>=ISFS_MAXPATH) return ISFS_EINVAL; + + len1 = strnlen(filepathNew,ISFS_MAXPATH); + if(len1>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->fsrename.filepathOld,filepathOld,(len0+1)); + memcpy(param->fsrename.filepathNew,filepathNew,(len1+1)); + ret = IOS_Ioctl(_fs_fd,ISFS_IOCTL_RENAME,¶m->fsrename,sizeof(param->fsrename),NULL,0); + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_RenameAsync(const char *filepathOld,const char *filepathNew,isfscallback cb,void *usrdata) +{ + s32 len0,len1; + struct isfs_cb *param; + + if(_fs_fd<0 || filepathOld==NULL || filepathNew==NULL) return ISFS_EINVAL; + + len0 = strnlen(filepathOld,ISFS_MAXPATH); + if(len0>=ISFS_MAXPATH) return ISFS_EINVAL; + + len1 = strnlen(filepathNew,ISFS_MAXPATH); + if(len1>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId,ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + memcpy(param->fsrename.filepathOld,filepathOld,(len0+1)); + memcpy(param->fsrename.filepathNew,filepathNew,(len1+1)); + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_RENAME,¶m->fsrename,sizeof(param->fsrename),NULL,0,__isfsFunctionCB,param); +} + +s32 ISFS_SetAttr(const char *filepath,u32 ownerID,u16 groupID,u8 attributes,u8 ownerperm,u8 groupperm,u8 otherperm) +{ + s32 ret, len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath, ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId, ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->fsattr.filepath, filepath, (len+1)); + param->fsattr.owner_id = ownerID; + param->fsattr.group_id = groupID; + param->fsattr.ownerperm = ownerperm; + param->fsattr.groupperm = groupperm; + param->fsattr.otherperm = otherperm; + param->fsattr.attributes = attributes; + + ret = IOS_Ioctl(_fs_fd,ISFS_IOCTL_SETATTR,¶m->fsattr,sizeof(param->fsattr),NULL,0); + + if(param!=NULL) iosFree(hId,param); + return ret; +} + +s32 ISFS_SetAttrAsync(const char *filepath,u32 ownerID,u16 groupID,u8 attributes,u8 ownerperm,u8 groupperm,u8 otherperm,isfscallback cb,void *usrdata) +{ + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL) return ISFS_EINVAL; + + len = strnlen(filepath, ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId, ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCNULL; + memcpy(param->fsattr.filepath, filepath, (len+1)); + param->fsattr.owner_id = ownerID; + param->fsattr.group_id = groupID; + param->fsattr.ownerperm = ownerperm; + param->fsattr.groupperm = groupperm; + param->fsattr.otherperm = otherperm; + param->fsattr.attributes = attributes; + return IOS_IoctlAsync(_fs_fd,ISFS_IOCTL_SETATTR,¶m->fsattr,sizeof(param->fsattr),NULL,0,__isfsFunctionCB,param); +} + +s32 ISFS_GetUsage(const char* filepath, u32* usage1, u32* usage2) +{ + s32 ret,len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL || usage1==NULL || usage2 == NULL) + return ISFS_EINVAL; + + len = strnlen(filepath, ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId, ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + memcpy(param->filepath,filepath,(len+1)); + + param->fsusage.vector[0].data = param->filepath; + param->fsusage.vector[0].len = ISFS_MAXPATH; + param->fsusage.vector[1].data = ¶m->fsusage.usage1; + param->fsusage.vector[1].len = sizeof(u32); + param->fsusage.vector[2].data = ¶m->fsusage.usage2; + param->fsusage.vector[2].len = sizeof(u32); + ret = IOS_Ioctlv(_fs_fd,ISFS_IOCTL_GETUSAGE,1,2,param->fsusage.vector); + if(ret==IPC_OK) { + *usage1 = param->fsusage.usage1; + *usage2 = param->fsusage.usage2; + } + + if(param!=NULL) iosFree(hId, param); + return ret; +} + +s32 ISFS_GetUsageAsync(const char* filepath, u32* usage1, u32* usage2,isfscallback cb,void *usrdata) +{ + s32 len; + struct isfs_cb *param; + + if(_fs_fd<0 || filepath==NULL || usage1==NULL || usage2 == NULL) + return ISFS_EINVAL; + + len = strnlen(filepath, ISFS_MAXPATH); + if(len>=ISFS_MAXPATH) return ISFS_EINVAL; + + param = (struct isfs_cb*)iosAlloc(hId, ISFS_STRUCTSIZE); + if(param==NULL) return ISFS_ENOMEM; + + param->cb = cb; + param->usrdata = usrdata; + param->functype = ISFS_FUNCGETUSAGE; + param->funcargv[0] = usage1; + param->funcargv[1] = usage2; + memcpy(param->filepath,filepath,(len+1)); + + param->fsusage.vector[0].data = param->filepath; + param->fsusage.vector[0].len = ISFS_MAXPATH; + param->fsusage.vector[1].data = ¶m->fsusage.usage1; + param->fsusage.vector[1].len = sizeof(u32); + param->fsusage.vector[2].data = ¶m->fsusage.usage2; + param->fsusage.vector[2].len = sizeof(u32); + return IOS_IoctlvAsync(_fs_fd,ISFS_IOCTL_GETUSAGE,1,2,param->fsusage.vector,__isfsFunctionCB,param); +} + + +#endif /* defined(HW_RVL) */ diff --git a/wii/libogc/libogc/kprintf.c b/wii/libogc/libogc/kprintf.c new file mode 100644 index 0000000000..976a756704 --- /dev/null +++ b/wii/libogc/libogc/kprintf.c @@ -0,0 +1,291 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +int kvsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +#define __DOUTBUFSIZE 256 + +char __outstr[__DOUTBUFSIZE]; + +//--------------------------------------------------------------------------------- +void kprintf(const char *str, ...) +//--------------------------------------------------------------------------------- +{ + + int len; + + va_list args; + + va_start(args, str); + len=kvsprintf(__outstr,str,args); + va_end(args); + + write(2, __outstr, len); +} diff --git a/wii/libogc/libogc/lock_supp.c b/wii/libogc/libogc/lock_supp.c new file mode 100644 index 0000000000..6a30c37bf0 --- /dev/null +++ b/wii/libogc/libogc/lock_supp.c @@ -0,0 +1,64 @@ +#include <_ansi.h> +#include <_syslist.h> +#include +#include +#include +#ifndef REENTRANT_SYSCALLS_PROVIDED +#include +#endif +#include + +#include "asm.h" +#include "processor.h" +#include "mutex.h" + + +int __libogc_lock_init(int *lock,int recursive) +{ + s32 ret; + mutex_t retlck = LWP_MUTEX_NULL; + + if(!lock) return -1; + + *lock = 0; + ret = LWP_MutexInit(&retlck,(recursive?TRUE:FALSE)); + if(ret==0) *lock = (int)retlck; + + return ret; +} + +int __libogc_lock_close(int *lock) +{ + s32 ret; + mutex_t plock; + + if(!lock || *lock==0) return -1; + + plock = (mutex_t)*lock; + ret = LWP_MutexDestroy(plock); + if(ret==0) *lock = 0; + + return ret; +} + +int __libogc_lock_acquire(int *lock) +{ + mutex_t plock; + + if(!lock || *lock==0) return -1; + + plock = (mutex_t)*lock; + return LWP_MutexLock(plock); +} + + +int __libogc_lock_release(int *lock) +{ + mutex_t plock; + + if(!lock || *lock==0) return -1; + + plock = (mutex_t)*lock; + return LWP_MutexUnlock(plock); +} + diff --git a/wii/libogc/libogc/lwp.c b/wii/libogc/libogc/lwp.c new file mode 100644 index 0000000000..5927ebb638 --- /dev/null +++ b/wii/libogc/libogc/lwp.c @@ -0,0 +1,415 @@ +/*------------------------------------------------------------- + +lwp.c -- Thread subsystem I + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include "asm.h" +#include "processor.h" +#include "lwp_threadq.h" +#include "lwp_threads.h" +#include "lwp_wkspace.h" +#include "lwp_objmgr.h" +#include "lwp_config.h" +#include "lwp.h" + +#define LWP_OBJTYPE_THREAD 1 +#define LWP_OBJTYPE_TQUEUE 2 + +#define LWP_CHECK_THREAD(hndl) \ +{ \ + if(((hndl)==LWP_THREAD_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_THREAD)) \ + return NULL; \ +} + +#define LWP_CHECK_TQUEUE(hndl) \ +{ \ + if(((hndl)==LWP_TQUEUE_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_TQUEUE)) \ + return NULL; \ +} + +typedef struct _tqueue_st { + lwp_obj object; + lwp_thrqueue tqueue; +} tqueue_st; + +lwp_objinfo _lwp_thr_objects; +lwp_objinfo _lwp_tqueue_objects; + +extern int __crtmain(); + +extern u8 __stack_addr[],__stack_end[]; + +static __inline__ u32 __lwp_priotocore(u32 prio) +{ + return (255 - prio); +} + +static __inline__ lwp_cntrl* __lwp_cntrl_open(lwp_t thr_id) +{ + LWP_CHECK_THREAD(thr_id); + return (lwp_cntrl*)__lwp_objmgr_get(&_lwp_thr_objects,LWP_OBJMASKID(thr_id)); +} + +static __inline__ tqueue_st* __lwp_tqueue_open(lwpq_t tqueue) +{ + LWP_CHECK_TQUEUE(tqueue); + return (tqueue_st*)__lwp_objmgr_get(&_lwp_tqueue_objects,LWP_OBJMASKID(tqueue)); +} + +static lwp_cntrl* __lwp_cntrl_allocate() +{ + lwp_cntrl *thethread; + + __lwp_thread_dispatchdisable(); + thethread = (lwp_cntrl*)__lwp_objmgr_allocate(&_lwp_thr_objects); + if(thethread) { + __lwp_objmgr_open(&_lwp_thr_objects,&thethread->object); + return thethread; + } + __lwp_thread_dispatchenable(); + return NULL; +} + +static tqueue_st* __lwp_tqueue_allocate() +{ + tqueue_st *tqueue; + + __lwp_thread_dispatchdisable(); + tqueue = (tqueue_st*)__lwp_objmgr_allocate(&_lwp_tqueue_objects); + if(tqueue) { + __lwp_objmgr_open(&_lwp_tqueue_objects,&tqueue->object); + return tqueue; + } + __lwp_thread_dispatchenable(); + return NULL; +} + +static __inline__ void __lwp_cntrl_free(lwp_cntrl *thethread) +{ + __lwp_objmgr_close(&_lwp_thr_objects,&thethread->object); + __lwp_objmgr_free(&_lwp_thr_objects,&thethread->object); +} + +static __inline__ void __lwp_tqueue_free(tqueue_st *tq) +{ + __lwp_objmgr_close(&_lwp_tqueue_objects,&tq->object); + __lwp_objmgr_free(&_lwp_tqueue_objects,&tq->object); +} + +static void* idle_func(void *arg) +{ + while(1); + return 0; +} + +void __lwp_sysinit() +{ + __lwp_objmgr_initinfo(&_lwp_thr_objects,LWP_MAX_THREADS,sizeof(lwp_cntrl)); + __lwp_objmgr_initinfo(&_lwp_tqueue_objects,LWP_MAX_TQUEUES,sizeof(tqueue_st)); + + // create idle thread, is needed iff all threads are locked on a queue + _thr_idle = (lwp_cntrl*)__lwp_objmgr_allocate(&_lwp_thr_objects); + __lwp_thread_init(_thr_idle,NULL,0,255,0,TRUE); + _thr_executing = _thr_heir = _thr_idle; + __lwp_thread_start(_thr_idle,idle_func,NULL); + __lwp_objmgr_open(&_lwp_thr_objects,&_thr_idle->object); + + // create main thread, as this is our entry point + // for every GC application. + _thr_main = (lwp_cntrl*)__lwp_objmgr_allocate(&_lwp_thr_objects); + __lwp_thread_init(_thr_main,__stack_end,((u32)__stack_addr-(u32)__stack_end),191,0,TRUE); + __lwp_thread_start(_thr_main,(void*)__crtmain,NULL); + __lwp_objmgr_open(&_lwp_thr_objects,&_thr_main->object); +} + +BOOL __lwp_thread_isalive(lwp_t thr_id) +{ + if(thr_id==LWP_THREAD_NULL || LWP_OBJTYPE(thr_id)!=LWP_OBJTYPE_THREAD) return FALSE; + + lwp_cntrl *thethread = (lwp_cntrl*)__lwp_objmgr_getnoprotection(&_lwp_thr_objects,LWP_OBJMASKID(thr_id)); + + if(thethread) { + u32 *stackbase = thethread->stack; + if(stackbase[0]==0xDEADBABE && !__lwp_statedormant(thethread->cur_state) && !__lwp_statetransient(thethread->cur_state)) + return TRUE; + } + + return FALSE; +} + +lwp_t __lwp_thread_currentid() +{ + return _thr_executing->object.id; +} + +BOOL __lwp_thread_exists(lwp_t thr_id) +{ + if(thr_id==LWP_THREAD_NULL || LWP_OBJTYPE(thr_id)!=LWP_OBJTYPE_THREAD) return FALSE; + return (__lwp_objmgr_getnoprotection(&_lwp_thr_objects,LWP_OBJMASKID(thr_id))!=NULL); +} + +frame_context* __lwp_thread_context(lwp_t thr_id) +{ + lwp_cntrl *thethread; + frame_context *pctx = NULL; + + LWP_CHECK_THREAD(thr_id); + thethread = (lwp_cntrl*)__lwp_objmgr_getnoprotection(&_lwp_thr_objects,LWP_OBJMASKID(thr_id)); + if(thethread) pctx = &thethread->context; + + return pctx; +} + +s32 LWP_CreateThread(lwp_t *thethread,void* (*entry)(void *),void *arg,void *stackbase,u32 stack_size,u8 prio) +{ + u32 status; + lwp_cntrl *lwp_thread; + + if(!thethread || !entry) return -1; + + lwp_thread = __lwp_cntrl_allocate(); + if(!lwp_thread) return -1; + + status = __lwp_thread_init(lwp_thread,stackbase,stack_size,__lwp_priotocore(prio),0,TRUE); + if(!status) { + __lwp_cntrl_free(lwp_thread); + __lwp_thread_dispatchenable(); + return -1; + } + + status = __lwp_thread_start(lwp_thread,entry,arg); + if(!status) { + __lwp_cntrl_free(lwp_thread); + __lwp_thread_dispatchenable(); + return -1; + } + + *thethread = (lwp_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_THREAD)|LWP_OBJMASKID(lwp_thread->object.id)); + __lwp_thread_dispatchenable(); + + return 0; +} + +s32 LWP_SuspendThread(lwp_t thethread) +{ + lwp_cntrl *lwp_thread; + + lwp_thread = __lwp_cntrl_open(thethread); + if(!lwp_thread) return -1; + + if(!__lwp_statesuspended(lwp_thread->cur_state)) { + __lwp_thread_suspend(lwp_thread); + __lwp_thread_dispatchenable(); + return LWP_SUCCESSFUL; + } + __lwp_thread_dispatchenable(); + return LWP_ALREADY_SUSPENDED; +} + +s32 LWP_ResumeThread(lwp_t thethread) +{ + lwp_cntrl *lwp_thread; + + lwp_thread = __lwp_cntrl_open(thethread); + if(!lwp_thread) return -1; + + if(__lwp_statesuspended(lwp_thread->cur_state)) { + __lwp_thread_resume(lwp_thread,TRUE); + __lwp_thread_dispatchenable(); + return LWP_SUCCESSFUL; + } + __lwp_thread_dispatchenable(); + return LWP_NOT_SUSPENDED; +} + +lwp_t LWP_GetSelf() +{ + lwp_t ret; + + __lwp_thread_dispatchdisable(); + ret = (lwp_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_THREAD)|LWP_OBJMASKID(_thr_executing->object.id)); + __lwp_thread_dispatchunnest(); + + return ret; +} + +void LWP_SetThreadPriority(lwp_t thethread,u32 prio) +{ + lwp_cntrl *lwp_thread; + + if(thethread==LWP_THREAD_NULL) thethread = LWP_GetSelf(); + + lwp_thread = __lwp_cntrl_open(thethread); + if(!lwp_thread) return; + + __lwp_thread_changepriority(lwp_thread,__lwp_priotocore(prio),TRUE); + __lwp_thread_dispatchenable(); +} + +void LWP_YieldThread() +{ + __lwp_thread_dispatchdisable(); + __lwp_thread_yield(); + __lwp_thread_dispatchenable(); +} + +void LWP_Reschedule(u32 prio) +{ + __lwp_thread_dispatchdisable(); + __lwp_rotate_readyqueue(prio); + __lwp_thread_dispatchenable(); +} + +BOOL LWP_ThreadIsSuspended(lwp_t thethread) +{ + BOOL state; + lwp_cntrl *lwp_thread; + + lwp_thread = __lwp_cntrl_open(thethread); + if(!lwp_thread) return FALSE; + + state = (__lwp_statesuspended(lwp_thread->cur_state) ? TRUE : FALSE); + + __lwp_thread_dispatchenable(); + return state; +} + + +s32 LWP_JoinThread(lwp_t thethread,void **value_ptr) +{ + u32 level; + void *return_ptr; + lwp_cntrl *exec,*lwp_thread; + + lwp_thread = __lwp_cntrl_open(thethread); + if(!lwp_thread) return 0; + + if(__lwp_thread_isexec(lwp_thread)) { + __lwp_thread_dispatchenable(); + return EDEADLK; //EDEADLK + } + + exec = _thr_executing; + _CPU_ISR_Disable(level); + __lwp_threadqueue_csenter(&lwp_thread->join_list); + exec->wait.ret_code = 0; + exec->wait.ret_arg_1 = NULL; + exec->wait.ret_arg = (void*)&return_ptr; + exec->wait.queue = &lwp_thread->join_list; + exec->wait.id = thethread; + _CPU_ISR_Restore(level); + __lwp_threadqueue_enqueue(&lwp_thread->join_list,LWP_WD_NOTIMEOUT); + __lwp_thread_dispatchenable(); + + if(value_ptr) *value_ptr = return_ptr; + return 0; +} + +s32 LWP_InitQueue(lwpq_t *thequeue) +{ + tqueue_st *tq; + + if(!thequeue) return -1; + + tq = __lwp_tqueue_allocate(); + if(!tq) return -1; + + __lwp_threadqueue_init(&tq->tqueue,LWP_THREADQ_MODEFIFO,LWP_STATES_WAITING_ON_THREADQ,0); + + *thequeue = (lwpq_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_TQUEUE)|LWP_OBJMASKID(tq->object.id)); + __lwp_thread_dispatchenable(); + + return 0; +} + +void LWP_CloseQueue(lwpq_t thequeue) +{ + lwp_cntrl *thethread; + tqueue_st *tq = (tqueue_st*)thequeue; + + tq = __lwp_tqueue_open(thequeue); + if(!tq) return; + + do { + thethread = __lwp_threadqueue_dequeue(&tq->tqueue); + } while(thethread); + __lwp_thread_dispatchenable(); + + __lwp_tqueue_free(tq); + return; +} + +s32 LWP_ThreadSleep(lwpq_t thequeue) +{ + u32 level; + tqueue_st *tq; + lwp_cntrl *exec = NULL; + + tq = __lwp_tqueue_open(thequeue); + if(!tq) return -1; + + exec = _thr_executing; + _CPU_ISR_Disable(level); + __lwp_threadqueue_csenter(&tq->tqueue); + exec->wait.ret_code = 0; + exec->wait.ret_arg = NULL; + exec->wait.ret_arg_1 = NULL; + exec->wait.queue = &tq->tqueue; + exec->wait.id = thequeue; + _CPU_ISR_Restore(level); + __lwp_threadqueue_enqueue(&tq->tqueue,LWP_THREADQ_NOTIMEOUT); + __lwp_thread_dispatchenable(); + return 0; +} + +void LWP_ThreadBroadcast(lwpq_t thequeue) +{ + tqueue_st *tq; + lwp_cntrl *thethread; + + tq = __lwp_tqueue_open(thequeue); + if(!tq) return; + + do { + thethread = __lwp_threadqueue_dequeue(&tq->tqueue); + } while(thethread); + __lwp_thread_dispatchenable(); +} + +void LWP_ThreadSignal(lwpq_t thequeue) +{ + tqueue_st *tq; + + tq = __lwp_tqueue_open(thequeue); + if(!tq) return; + + __lwp_threadqueue_dequeue(&tq->tqueue); + __lwp_thread_dispatchenable(); +} diff --git a/wii/libogc/libogc/lwp_handler.S b/wii/libogc/libogc/lwp_handler.S new file mode 100644 index 0000000000..edb8e633cd --- /dev/null +++ b/wii/libogc/libogc/lwp_handler.S @@ -0,0 +1,565 @@ +#include + + .set FP_SIZE, 8 + + .set GP_SRR0, (SRR0_OFFSET - 8) + .set GP_SRR1, (GP_SRR0 + 4) + + .set GP_1, (GPR1_OFFSET - 8) + .set GP_2, (GP_1 + 4) +#ifdef _DEBUG + .set GP_5, (GPR5_OFFSET - 8) + .set GP_6, (GP_5 + 4) +#endif + .set GP_13, (GPR13_OFFSET - 8) + .set GP_14, (GP_13 + 4) + .set GP_15, (GP_14 + 4) + .set GP_16, (GP_15 + 4) + .set GP_17, (GP_16 + 4) + .set GP_18, (GP_17 + 4) + .set GP_19, (GP_18 + 4) + .set GP_20, (GP_19 + 4) + .set GP_21, (GP_20 + 4) + .set GP_22, (GP_21 + 4) + .set GP_23, (GP_22 + 4) + .set GP_24, (GP_23 + 4) + .set GP_25, (GP_24 + 4) + .set GP_26, (GP_25 + 4) + .set GP_27, (GP_26 + 4) + .set GP_28, (GP_27 + 4) + .set GP_29, (GP_28 + 4) + .set GP_30, (GP_29 + 4) + .set GP_31, (GP_30 + 4) + + .set GQ_0, (GP_31 + 4) + .set GQ_1, (GQ_0 + 4) + .set GQ_2, (GQ_1 + 4) + .set GQ_3, (GQ_2 + 4) + .set GQ_4, (GQ_3 + 4) + .set GQ_5, (GQ_4 + 4) + .set GQ_6, (GQ_5 + 4) + .set GQ_7, (GQ_6 + 4) + + .set GP_CR, (GQ_7 + 4) + .set GP_LR, (GP_CR + 4) + .set GP_CTR, (GP_LR + 4) + .set GP_XER, (GP_CTR + 4) + .set GP_MSR, (GP_XER + 4) + .set GP_DAR, (GP_MSR + 4) + + .set STATE, (GP_DAR + 4) + .set MODE, (STATE + 2) + + .set FP_0, (FPR0_OFFSET - 8) + .set FP_1, (FP_0 + FP_SIZE) + .set FP_2, (FP_1 + FP_SIZE) + .set FP_3, (FP_2 + FP_SIZE) + .set FP_4, (FP_3 + FP_SIZE) + .set FP_5, (FP_4 + FP_SIZE) + .set FP_6, (FP_5 + FP_SIZE) + .set FP_7, (FP_6 + FP_SIZE) + .set FP_8, (FP_7 + FP_SIZE) + .set FP_9, (FP_8 + FP_SIZE) + .set FP_10, (FP_9 + FP_SIZE) + .set FP_11, (FP_10 + FP_SIZE) + .set FP_12, (FP_11 + FP_SIZE) + .set FP_13, (FP_12 + FP_SIZE) + .set FP_14, (FP_13 + FP_SIZE) + .set FP_15, (FP_14 + FP_SIZE) + .set FP_16, (FP_15 + FP_SIZE) + .set FP_17, (FP_16 + FP_SIZE) + .set FP_18, (FP_17 + FP_SIZE) + .set FP_19, (FP_18 + FP_SIZE) + .set FP_20, (FP_19 + FP_SIZE) + .set FP_21, (FP_20 + FP_SIZE) + .set FP_22, (FP_21 + FP_SIZE) + .set FP_23, (FP_22 + FP_SIZE) + .set FP_24, (FP_23 + FP_SIZE) + .set FP_25, (FP_24 + FP_SIZE) + .set FP_26, (FP_25 + FP_SIZE) + .set FP_27, (FP_26 + FP_SIZE) + .set FP_28, (FP_27 + FP_SIZE) + .set FP_29, (FP_28 + FP_SIZE) + .set FP_30, (FP_29 + FP_SIZE) + .set FP_31, (FP_30 + FP_SIZE) + .set FP_FPSCR, (FP_31 + FP_SIZE) + .set PSFP_0, (FP_FPSCR + FP_SIZE) + .set PSFP_1, (PSFP_0 + FP_SIZE) + .set PSFP_2, (PSFP_1 + FP_SIZE) + .set PSFP_3, (PSFP_2 + FP_SIZE) + .set PSFP_4, (PSFP_3 + FP_SIZE) + .set PSFP_5, (PSFP_4 + FP_SIZE) + .set PSFP_6, (PSFP_5 + FP_SIZE) + .set PSFP_7, (PSFP_6 + FP_SIZE) + .set PSFP_8, (PSFP_7 + FP_SIZE) + .set PSFP_9, (PSFP_8 + FP_SIZE) + .set PSFP_10, (PSFP_9 + FP_SIZE) + .set PSFP_11, (PSFP_10 + FP_SIZE) + .set PSFP_12, (PSFP_11 + FP_SIZE) + .set PSFP_13, (PSFP_12 + FP_SIZE) + .set PSFP_14, (PSFP_13 + FP_SIZE) + .set PSFP_15, (PSFP_14 + FP_SIZE) + .set PSFP_16, (PSFP_15 + FP_SIZE) + .set PSFP_17, (PSFP_16 + FP_SIZE) + .set PSFP_18, (PSFP_17 + FP_SIZE) + .set PSFP_19, (PSFP_18 + FP_SIZE) + .set PSFP_20, (PSFP_19 + FP_SIZE) + .set PSFP_21, (PSFP_20 + FP_SIZE) + .set PSFP_22, (PSFP_21 + FP_SIZE) + .set PSFP_23, (PSFP_22 + FP_SIZE) + .set PSFP_24, (PSFP_23 + FP_SIZE) + .set PSFP_25, (PSFP_24 + FP_SIZE) + .set PSFP_26, (PSFP_25 + FP_SIZE) + .set PSFP_27, (PSFP_26 + FP_SIZE) + .set PSFP_28, (PSFP_27 + FP_SIZE) + .set PSFP_29, (PSFP_28 + FP_SIZE) + .set PSFP_30, (PSFP_29 + FP_SIZE) + .set PSFP_31, (PSFP_30 + FP_SIZE) + + .align 5 + .globl _cpu_context_save_fp +_cpu_context_save_fp: + lhz r4,STATE(r3) + ori r4,r4,0x0001 + sth r4,STATE(r3) + stfd fr0, FP_0(r3) + stfd fr1, FP_1(r3) + stfd fr2, FP_2(r3) + stfd fr3, FP_3(r3) + stfd fr4, FP_4(r3) + stfd fr5, FP_5(r3) + stfd fr6, FP_6(r3) + stfd fr7, FP_7(r3) + stfd fr8, FP_8(r3) + stfd fr9, FP_9(r3) + stfd fr10, FP_10(r3) + stfd fr11, FP_11(r3) + stfd fr12, FP_12(r3) + stfd fr13, FP_13(r3) + stfd fr14, FP_14(r3) + stfd fr15, FP_15(r3) + stfd fr16, FP_16(r3) + stfd fr17, FP_17(r3) + stfd fr18, FP_18(r3) + stfd fr19, FP_19(r3) + stfd fr20, FP_20(r3) + stfd fr21, FP_21(r3) + stfd fr22, FP_22(r3) + stfd fr23, FP_23(r3) + stfd fr24, FP_24(r3) + stfd fr25, FP_25(r3) + stfd fr26, FP_26(r3) + stfd fr27, FP_27(r3) + stfd fr28, FP_28(r3) + stfd fr29, FP_29(r3) + stfd fr30, FP_30(r3) + stfd fr31, FP_31(r3) + mffs fr0 + stfd fr0, FP_FPSCR(r3) + lfd fr0, FP_0(r3) + mfspr r4,920 + extrwi. r4,r4,1,2 + beq 1f + psq_st fr0,PSFP_0(r3),0,0 + psq_st fr1,PSFP_1(r3),0,0 + psq_st fr2,PSFP_2(r3),0,0 + psq_st fr3,PSFP_3(r3),0,0 + psq_st fr4,PSFP_4(r3),0,0 + psq_st fr5,PSFP_5(r3),0,0 + psq_st fr6,PSFP_6(r3),0,0 + psq_st fr7,PSFP_7(r3),0,0 + psq_st fr8,PSFP_8(r3),0,0 + psq_st fr9,PSFP_9(r3),0,0 + psq_st fr10,PSFP_10(r3),0,0 + psq_st fr11,PSFP_11(r3),0,0 + psq_st fr12,PSFP_12(r3),0,0 + psq_st fr13,PSFP_13(r3),0,0 + psq_st fr14,PSFP_14(r3),0,0 + psq_st fr15,PSFP_15(r3),0,0 + psq_st fr16,PSFP_16(r3),0,0 + psq_st fr17,PSFP_17(r3),0,0 + psq_st fr18,PSFP_18(r3),0,0 + psq_st fr19,PSFP_19(r3),0,0 + psq_st fr20,PSFP_20(r3),0,0 + psq_st fr21,PSFP_21(r3),0,0 + psq_st fr22,PSFP_22(r3),0,0 + psq_st fr23,PSFP_23(r3),0,0 + psq_st fr24,PSFP_24(r3),0,0 + psq_st fr25,PSFP_25(r3),0,0 + psq_st fr26,PSFP_26(r3),0,0 + psq_st fr27,PSFP_27(r3),0,0 + psq_st fr28,PSFP_28(r3),0,0 + psq_st fr29,PSFP_29(r3),0,0 + psq_st fr30,PSFP_30(r3),0,0 + psq_st fr31,PSFP_31(r3),0,0 +1: blr + + .align 5 + .globl _cpu_context_restore_fp +_cpu_context_restore_fp: + lhz r4,STATE(r3) + clrlwi. r4,r4,31 + beq 2f + lfd fr0, FP_FPSCR(r3) + mtfsf 255, fr0 + mfspr r4,920 + extrwi. r4,r4,1,2 + beq 1f + psq_l fr0,PSFP_0(r3),0,0 + psq_l fr1,PSFP_1(r3),0,0 + psq_l fr2,PSFP_2(r3),0,0 + psq_l fr3,PSFP_3(r3),0,0 + psq_l fr4,PSFP_4(r3),0,0 + psq_l fr5,PSFP_5(r3),0,0 + psq_l fr6,PSFP_6(r3),0,0 + psq_l fr7,PSFP_7(r3),0,0 + psq_l fr8,PSFP_8(r3),0,0 + psq_l fr9,PSFP_9(r3),0,0 + psq_l fr10,PSFP_10(r3),0,0 + psq_l fr11,PSFP_11(r3),0,0 + psq_l fr12,PSFP_12(r3),0,0 + psq_l fr13,PSFP_13(r3),0,0 + psq_l fr14,PSFP_14(r3),0,0 + psq_l fr15,PSFP_15(r3),0,0 + psq_l fr16,PSFP_16(r3),0,0 + psq_l fr17,PSFP_17(r3),0,0 + psq_l fr18,PSFP_18(r3),0,0 + psq_l fr19,PSFP_19(r3),0,0 + psq_l fr20,PSFP_20(r3),0,0 + psq_l fr21,PSFP_21(r3),0,0 + psq_l fr22,PSFP_22(r3),0,0 + psq_l fr23,PSFP_23(r3),0,0 + psq_l fr24,PSFP_24(r3),0,0 + psq_l fr25,PSFP_25(r3),0,0 + psq_l fr26,PSFP_26(r3),0,0 + psq_l fr27,PSFP_27(r3),0,0 + psq_l fr28,PSFP_28(r3),0,0 + psq_l fr29,PSFP_29(r3),0,0 + psq_l fr30,PSFP_30(r3),0,0 + psq_l fr31,PSFP_31(r3),0,0 +1: lfd fr0, FP_0(r3) + lfd fr1, FP_1(r3) + lfd fr2, FP_2(r3) + lfd fr3, FP_3(r3) + lfd fr4, FP_4(r3) + lfd fr5, FP_5(r3) + lfd fr6, FP_6(r3) + lfd fr7, FP_7(r3) + lfd fr8, FP_8(r3) + lfd fr9, FP_9(r3) + lfd fr10, FP_10(r3) + lfd fr11, FP_11(r3) + lfd fr12, FP_12(r3) + lfd fr13, FP_13(r3) + lfd fr14, FP_14(r3) + lfd fr15, FP_15(r3) + lfd fr16, FP_16(r3) + lfd fr17, FP_17(r3) + lfd fr18, FP_18(r3) + lfd fr19, FP_19(r3) + lfd fr20, FP_20(r3) + lfd fr21, FP_21(r3) + lfd fr22, FP_22(r3) + lfd fr23, FP_23(r3) + lfd fr24, FP_24(r3) + lfd fr25, FP_25(r3) + lfd fr26, FP_26(r3) + lfd fr27, FP_27(r3) + lfd fr28, FP_28(r3) + lfd fr29, FP_29(r3) + lfd fr30, FP_30(r3) + lfd fr31, FP_31(r3) +2: blr + + .align 5 + .globl _cpu_context_switch +_cpu_context_switch: + sync + isync + + stw sp,GP_1(r3) + lwz sp,GP_1(r4) + stw toc,GP_2(r3) + lwz toc,GP_2(r4) + + stmw r13,GP_13(r3) + lmw r13,GP_13(r4) + + mfspr r5,912 + stw r5,GQ_0(r3) + lwz r6,GQ_0(r4) + mtspr 912,r6 + mfspr r5,913 + stw r5,GQ_1(r3) + lwz r6,GQ_1(r4) + mtspr 913,r6 + mfspr r5,914 + stw r5,GQ_2(r3) + lwz r6,GQ_2(r4) + mtspr 914,r6 + mfspr r5,915 + stw r5,GQ_3(r3) + lwz r6,GQ_3(r4) + mtspr 915,r6 + mfspr r5,916 + stw r5,GQ_4(r3) + lwz r6,GQ_4(r4) + mtspr 916,r6 + mfspr r5,917 + stw r5,GQ_5(r3) + lwz r6,GQ_5(r4) + mtspr 917,r6 + mfspr r5,918 + stw r5,GQ_6(r3) + lwz r6,GQ_6(r4) + mtspr 918,r6 + mfspr r5,919 + stw r5,GQ_7(r3) + lwz r6,GQ_7(r4) + mtspr 919,r6 + + mfcr r5 + stw r5, GP_CR(r3) + lwz r6, GP_CR(r4) + mtcrf 255, r6 + mflr r5 + stw r5, GP_LR(r3) + lwz r6, GP_LR(r4) + mtlr r6 + mfmsr r5 + stw r5, GP_MSR(r3) + lwz r6, GP_MSR(r4) + rlwinm r6, r6, 0, 19, 17 + mtmsr r6 + + blr + + .align 5 + .globl _cpu_context_save +_cpu_context_save: + sync + isync + + stw sp,GPR1_OFFSET-8(r3) + stw toc,GPR2_OFFSET-8(r3) + stmw r13,GPR13_OFFSET-8(r3) + + mfctr r6 + stw r6, CTR_OFFSET-8(r3) + mfcr r6 + stw r6, CR_OFFSET-8(r3) + mflr r7 + stw r7, LR_OFFSET-8(r3) + mfmsr r8 + stw r8, MSR_OFFSET-8(r3) + + mfspr r6,913 + stw r6,GQR1_OFFSET-8(r3) + mfspr r6,914 + stw r6,GQR2_OFFSET-8(r3) + mfspr r6,915 + stw r6,GQR3_OFFSET-8(r3) + mfspr r6,916 + stw r6,GQR4_OFFSET-8(r3) + mfspr r6,917 + stw r6,GQR5_OFFSET-8(r3) + mfspr r6,918 + stw r6,GQR6_OFFSET-8(r3) + mfspr r6,919 + stw r6,GQR7_OFFSET-8(r3) + + blr + + .align 5 + .globl _cpu_context_restore +_cpu_context_restore: + lwz sp,GPR1_OFFSET-8(r3) + lwz toc,GPR2_OFFSET-8(r3) + lmw r13,GPR13_OFFSET-8(r3) + + lwz r6, CTR_OFFSET-8(r3) + mtctr r6 + lwz r6, CR_OFFSET-8(r3) + mtcrf 255, r6 + lwz r7, LR_OFFSET-8(r3) + mtlr r7 + lwz r8, MSR_OFFSET-8(r3) + rlwinm r8,r8,0,19,17 + mtmsr r8 + + lwz r6, GQR1_OFFSET-8(r3) + mtspr 913,r6 + lwz r6, GQR2_OFFSET-8(r3) + mtspr 914,r6 + lwz r6, GQR3_OFFSET-8(r3) + mtspr 915,r6 + lwz r6, GQR4_OFFSET-8(r3) + mtspr 916,r6 + lwz r6, GQR5_OFFSET-8(r3) + mtspr 917,r6 + lwz r6, GQR6_OFFSET-8(r3) + mtspr 918,r6 + lwz r6, GQR7_OFFSET-8(r3) + mtspr 919,r6 + + blr + +#ifdef _DEBUG + .align 5 + .globl _cpu_context_switch_ex +_cpu_context_switch_ex: + sync + isync + + stw sp,GP_1(r3) + lwz sp,GP_1(r4) + stw toc,GP_2(r3) + lwz toc,GP_2(r4) + + stmw r5,GP_5(r3) + + mfspr r5,912 + stw r5,GQ_0(r3) + lwz r5,GQ_0(r4) + mfspr r6,913 + mtspr 912,r5 + stw r6,GQ_1(r3) + lwz r6,GQ_1(r4) + mfspr r5,914 + mtspr 913,r6 + stw r5,GQ_2(r3) + lwz r5,GQ_2(r4) + mfspr r6,915 + mtspr 914,r5 + stw r6,GQ_3(r3) + lwz r6,GQ_3(r4) + mfspr r5,916 + mtspr 915,r6 + stw r5,GQ_4(r3) + lwz r5,GQ_4(r4) + mfspr r6,917 + mtspr 916,r5 + stw r6,GQ_5(r3) + lwz r6,GQ_5(r4) + mfspr r5,918 + mtspr 917,r6 + stw r5,GQ_6(r3) + lwz r5,GQ_6(r4) + mfspr r6,919 + mtspr 918,r5 + stw r6,GQ_7(r3) + lwz r6,GQ_7(r4) + mtspr 919,r6 + + mfsrr0 r5 + stw r5, GP_SRR0(r3) + lwz r5, GP_SRR0(r4) + mfsrr1 r6 + mtsrr0 r5 + stw r6, GP_SRR1(r3) + lwz r6, GP_SRR1(r4) + mtsrr1 r6 + mfcr r5 + stw r5, GP_CR(r3) + lwz r5, GP_CR(r4) + mflr r6 + mtcrf 255, r5 + stw r6, GP_LR(r3) + lwz r6, GP_LR(r4) + mfmsr r5 + mtlr r6 + stw r5, GP_MSR(r3) + lwz r5, GP_MSR(r4) + lmw r6, GP_6(r4) + rlwinm r5, r5, 0, 19, 17 + mtmsr r5 + + lwz r5,GP_5(r4) + blr + + .align 5 + .globl _cpu_context_save_ex +_cpu_context_save_ex: + sync + isync + + stw r0,GPR0_OFFSET-8(r3) + stw sp,GPR1_OFFSET-8(r3) + stw toc,GPR2_OFFSET-8(r3) + stmw r3,GPR3_OFFSET-8(r3) + + mfctr r6 + stw r6, CTR_OFFSET-8(r3) + mfcr r6 + stw r6, CR_OFFSET-8(r3) + mflr r7 + stw r7, LR_OFFSET-8(r3) + mfxer r7 + stw r8, XER_OFFSET-8(r3) + mfmsr r8 + stw r8, MSR_OFFSET-8(r3) + mfdar r8 + stw r8, DAR_OFFSET-8(r3) + mfsrr0 r8 + stw r8, SRR0_OFFSET-8(r3) + mfsrr1 r8 + stw r8, SRR1_OFFSET-8(r3) + + mfspr r6,913 + stw r6,GQR1_OFFSET-8(r3) + mfspr r6,914 + stw r6,GQR2_OFFSET-8(r3) + mfspr r6,915 + stw r6,GQR3_OFFSET-8(r3) + mfspr r6,916 + stw r6,GQR4_OFFSET-8(r3) + mfspr r6,917 + stw r6,GQR5_OFFSET-8(r3) + mfspr r6,918 + stw r6,GQR6_OFFSET-8(r3) + mfspr r6,919 + stw r6,GQR7_OFFSET-8(r3) + + blr + + .align 5 + .globl _cpu_context_restore_ex +_cpu_context_restore_ex: + + lwz r6, CTR_OFFSET-8(r3) + mtctr r6 + lwz r6, CR_OFFSET-8(r3) + mtcrf 255, r6 + lwz r7, LR_OFFSET-8(r3) + mtlr r7 + lwz r7, XER_OFFSET-8(r3) + mtxer r7 + lwz r8, MSR_OFFSET-8(r3) + mtmsr r8 + lwz r8, SRR0_OFFSET-8(r3) + mtsrr0 r8 + lwz r8, SRR1_OFFSET-8(r3) + mtsrr1 r8 + + lwz r6, GQR1_OFFSET-8(r3) + mtspr 913,r6 + lwz r6, GQR2_OFFSET-8(r3) + mtspr 914,r6 + lwz r6, GQR3_OFFSET-8(r3) + mtspr 915,r6 + lwz r6, GQR4_OFFSET-8(r3) + mtspr 916,r6 + lwz r6, GQR5_OFFSET-8(r3) + mtspr 917,r6 + lwz r6, GQR6_OFFSET-8(r3) + mtspr 918,r6 + lwz r6, GQR7_OFFSET-8(r3) + mtspr 919,r6 + + lwz sp,GPR1_OFFSET-8(r3) + lwz toc,GPR2_OFFSET-8(r3) + lmw r4,GPR4_OFFSET-8(r3) + lwz r3,GPR3_OFFSET-8(r3) + + blr +#endif diff --git a/wii/libogc/libogc/lwp_heap.c b/wii/libogc/libogc/lwp_heap.c new file mode 100644 index 0000000000..5507dcca55 --- /dev/null +++ b/wii/libogc/libogc/lwp_heap.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include + +#include "lwp_heap.h" + + +u32 __lwp_heap_init(heap_cntrl *theheap,void *start_addr,u32 size,u32 pg_size) +{ + u32 dsize,level; + heap_block *block; + + if(!__lwp_heap_pgsize_valid(pg_size) || sizepg_size = pg_size; + dsize = (size - HEAP_OVERHEAD); + + block = (heap_block*)start_addr; + block->back_flag = HEAP_DUMMY_FLAG; + block->front_flag = dsize; + block->next = __lwp_heap_tail(theheap); + block->prev = __lwp_heap_head(theheap); + + theheap->start = block; + theheap->first = block; + theheap->perm_null = NULL; + theheap->last = block; + + block = __lwp_heap_nextblock(block); + block->back_flag = dsize; + block->front_flag = HEAP_DUMMY_FLAG; + theheap->final = block; + _CPU_ISR_Restore(level); + + return (dsize - HEAP_BLOCK_USED_OVERHEAD); +} + +void* __lwp_heap_allocate(heap_cntrl *theheap,u32 size) +{ + u32 excess; + u32 dsize; + heap_block *block; + heap_block *next_block; + heap_block *tmp_block; + void *ptr; + u32 offset,level; + + + if(size>=(-1-HEAP_BLOCK_USED_OVERHEAD)) return NULL; + + _CPU_ISR_Disable(level); + excess = (size % theheap->pg_size); + dsize = (size + theheap->pg_size + HEAP_BLOCK_USED_OVERHEAD); + + if(excess) + dsize += (theheap->pg_size - excess); + + if(dsizefirst;;block=block->next) { + if(block==__lwp_heap_tail(theheap)) { + _CPU_ISR_Restore(level); + return NULL; + } + if(block->front_flag>=dsize) break; + } + + if((block->front_flag-dsize)>(theheap->pg_size+HEAP_BLOCK_USED_OVERHEAD)) { + block->front_flag -= dsize; + next_block = __lwp_heap_nextblock(block); + next_block->back_flag = block->front_flag; + + tmp_block = __lwp_heap_blockat(next_block,dsize); + tmp_block->back_flag = next_block->front_flag = __lwp_heap_buildflag(dsize,HEAP_BLOCK_USED); + + ptr = __lwp_heap_startuser(next_block); + } else { + next_block = __lwp_heap_nextblock(block); + next_block->back_flag = __lwp_heap_buildflag(block->front_flag,HEAP_BLOCK_USED); + + block->front_flag = next_block->back_flag; + block->next->prev = block->prev; + block->prev->next = block->next; + + ptr = __lwp_heap_startuser(block); + } + + offset = (theheap->pg_size - ((u32)ptr&(theheap->pg_size-1))); + ptr += offset; + *(((u32*)ptr)-1) = offset; + _CPU_ISR_Restore(level); + + return ptr; +} + +BOOL __lwp_heap_free(heap_cntrl *theheap,void *ptr) +{ + heap_block *block; + heap_block *next_block; + heap_block *new_next; + heap_block *prev_block; + heap_block *tmp_block; + u32 dsize,level; + + _CPU_ISR_Disable(level); + + block = __lwp_heap_usrblockat(ptr); + if(!__lwp_heap_blockin(theheap,block) || __lwp_heap_blockfree(block)) { + _CPU_ISR_Restore(level); + return FALSE; + } + + dsize = __lwp_heap_blocksize(block); + next_block = __lwp_heap_blockat(block,dsize); + + if(!__lwp_heap_blockin(theheap,next_block) || (block->front_flag!=next_block->back_flag)) { + _CPU_ISR_Restore(level); + return FALSE; + } + + if(__lwp_heap_prev_blockfree(block)) { + prev_block = __lwp_heap_prevblock(block); + if(!__lwp_heap_blockin(theheap,prev_block)) { + _CPU_ISR_Restore(level); + return FALSE; + } + + if(__lwp_heap_blockfree(next_block)) { + prev_block->front_flag += next_block->front_flag+dsize; + tmp_block = __lwp_heap_nextblock(prev_block); + tmp_block->back_flag = prev_block->front_flag; + next_block->next->prev = next_block->prev; + next_block->prev->next = next_block->next; + } else { + prev_block->front_flag = next_block->back_flag = prev_block->front_flag+dsize; + } + } else if(__lwp_heap_blockfree(next_block)) { + block->front_flag = dsize+next_block->front_flag; + new_next = __lwp_heap_nextblock(block); + new_next->back_flag = block->front_flag; + block->next = next_block->next; + block->prev = next_block->prev; + next_block->prev->next = block; + next_block->next->prev = block; + + if(theheap->first==next_block) theheap->first = block; + } else { + next_block->back_flag = block->front_flag = dsize; + block->prev = __lwp_heap_head(theheap); + block->next = theheap->first; + theheap->first = block; + block->next->prev = block; + } + _CPU_ISR_Restore(level); + + return TRUE; +} + +u32 __lwp_heap_getinfo(heap_cntrl *theheap,heap_iblock *theinfo) +{ + u32 not_done = 1; + heap_block *theblock = NULL; + heap_block *nextblock = NULL; + + theinfo->free_blocks = 0; + theinfo->free_size = 0; + theinfo->used_blocks = 0; + theinfo->used_size = 0; + + if(!__sys_state_up(__sys_state_get())) return 1; + + theblock = theheap->start; + if(theblock->back_flag!=HEAP_DUMMY_FLAG) return 2; + + while(not_done) { + if(__lwp_heap_blockfree(theblock)) { + theinfo->free_blocks++; + theinfo->free_size += __lwp_heap_blocksize(theblock); + } else { + theinfo->used_blocks++; + theinfo->used_size += __lwp_heap_blocksize(theblock); + } + + if(theblock->front_flag!=HEAP_DUMMY_FLAG) { + nextblock = __lwp_heap_nextblock(theblock); + if(theblock->front_flag!=nextblock->back_flag) return 2; + } + + if(theblock->front_flag==HEAP_DUMMY_FLAG) + not_done = 0; + else + theblock = nextblock; + } + return 0; +} diff --git a/wii/libogc/libogc/lwp_heap.inl b/wii/libogc/libogc/lwp_heap.inl new file mode 100644 index 0000000000..913a84a79f --- /dev/null +++ b/wii/libogc/libogc/lwp_heap.inl @@ -0,0 +1,75 @@ +#ifndef __LWP_HEAP_INL__ +#define __LWP_HEAP_INL__ + +static __inline__ heap_block* __lwp_heap_head(heap_cntrl *theheap) +{ + return (heap_block*)&theheap->start; +} + +static __inline__ heap_block* __lwp_heap_tail(heap_cntrl *heap) +{ + return (heap_block*)&heap->final; +} + +static __inline__ heap_block* __lwp_heap_prevblock(heap_block *block) +{ + return (heap_block*)((char*)block - (block->back_flag&~HEAP_BLOCK_USED)); +} + +static __inline__ heap_block* __lwp_heap_nextblock(heap_block *block) +{ + return (heap_block*)((char*)block + (block->front_flag&~HEAP_BLOCK_USED)); +} + +static __inline__ heap_block* __lwp_heap_blockat(heap_block *block,u32 offset) +{ + return (heap_block*)((char*)block + offset); +} + +static __inline__ heap_block* __lwp_heap_usrblockat(void *ptr) +{ + u32 offset = *(((u32*)ptr)-1); + return __lwp_heap_blockat(ptr,-offset+-HEAP_BLOCK_USED_OVERHEAD); +} + +static __inline__ bool __lwp_heap_prev_blockfree(heap_block *block) +{ + return !(block->back_flag&HEAP_BLOCK_USED); +} + +static __inline__ bool __lwp_heap_blockfree(heap_block *block) +{ + return !(block->front_flag&HEAP_BLOCK_USED); +} + +static __inline__ bool __lwp_heap_blockused(heap_block *block) +{ + return (block->front_flag&HEAP_BLOCK_USED); +} + +static __inline__ u32 __lwp_heap_blocksize(heap_block *block) +{ + return (block->front_flag&~HEAP_BLOCK_USED); +} + +static __inline__ void* __lwp_heap_startuser(heap_block *block) +{ + return (void*)&block->next; +} + +static __inline__ bool __lwp_heap_blockin(heap_cntrl *heap,heap_block *block) +{ + return ((u32)block>=(u32)heap->start && (u32)block<=(u32)heap->final); +} + +static __inline__ bool __lwp_heap_pgsize_valid(u32 pgsize) +{ + return (pgsize!=0 && ((pgsize%PPC_ALIGNMENT)==0)); +} + +static __inline__ u32 __lwp_heap_buildflag(u32 size,u32 flag) +{ + return (size|flag); +} + +#endif diff --git a/wii/libogc/libogc/lwp_messages.c b/wii/libogc/libogc/lwp_messages.c new file mode 100644 index 0000000000..284de8a45c --- /dev/null +++ b/wii/libogc/libogc/lwp_messages.c @@ -0,0 +1,258 @@ +#include +#include "asm.h" +#include "lwp_messages.h" +#include "lwp_wkspace.h" + +void __lwpmq_msg_insert(mq_cntrl *mqueue,mq_buffercntrl *msg,u32 type) +{ + ++mqueue->num_pendingmsgs; + msg->prio = type; + +#ifdef _LWPMQ_DEBUG + printf("__lwpmq_msg_insert(%p,%p,%d)\n",mqueue,msg,type); +#endif + + switch(type) { + case LWP_MQ_SEND_REQUEST: + __lwpmq_msg_append(mqueue,msg); + break; + case LWP_MQ_SEND_URGENT: + __lwpmq_msg_prepend(mqueue,msg); + break; + default: + { + mq_buffercntrl *tmsg; + lwp_node *node; + lwp_queue *header; + + header = &mqueue->pending_msgs; + node = header->first; + while(!__lwp_queue_istail(header,node)) { + tmsg = (mq_buffercntrl*)node; + if(tmsg->prio<=msg->prio) { + node = node->next; + continue; + } + break; + } + __lwp_queue_insert(node->prev,&msg->node); + } + break; + } + + if(mqueue->num_pendingmsgs==1 && mqueue->notify_handler) + mqueue->notify_handler(mqueue->notify_arg); +} + +u32 __lwpmq_initialize(mq_cntrl *mqueue,mq_attr *attrs,u32 max_pendingmsgs,u32 max_msgsize) +{ + u32 alloc_msgsize; + u32 buffering_req; + +#ifdef _LWPMQ_DEBUG + printf("__lwpmq_initialize(%p,%p,%d,%d)\n",mqueue,attrs,max_pendingmsgs,max_msgsize); +#endif + mqueue->max_pendingmsgs = max_pendingmsgs; + mqueue->num_pendingmsgs = 0; + mqueue->max_msgsize = max_msgsize; + __lwpmq_set_notify(mqueue,NULL,NULL); + + alloc_msgsize = max_msgsize; + if(alloc_msgsize&(sizeof(u32)-1)) + alloc_msgsize = (alloc_msgsize+sizeof(u32))&~(sizeof(u32)-1); + + buffering_req = max_pendingmsgs*(alloc_msgsize+sizeof(mq_buffercntrl)); + mqueue->msq_buffers = (mq_buffer*)__lwp_wkspace_allocate(buffering_req); + + if(!mqueue->msq_buffers) return 0; + + __lwp_queue_initialize(&mqueue->inactive_msgs,mqueue->msq_buffers,max_pendingmsgs,(alloc_msgsize+sizeof(mq_buffercntrl))); + __lwp_queue_init_empty(&mqueue->pending_msgs); + __lwp_threadqueue_init(&mqueue->wait_queue,__lwpmq_is_priority(attrs)?LWP_THREADQ_MODEPRIORITY:LWP_THREADQ_MODEFIFO,LWP_STATES_WAITING_FOR_MESSAGE,LWP_MQ_STATUS_TIMEOUT); + + return 1; +} + +u32 __lwpmq_seize(mq_cntrl *mqueue,u32 id,void *buffer,u32 *size,u32 wait,u64 timeout) +{ + u32 level; + mq_buffercntrl *msg; + lwp_cntrl *exec,*thread; + + exec = _thr_executing; + exec->wait.ret_code = LWP_MQ_STATUS_SUCCESSFUL; +#ifdef _LWPMQ_DEBUG + printf("__lwpmq_seize(%p,%d,%p,%p,%d,%d)\n",mqueue,id,buffer,size,wait,mqueue->num_pendingmsgs); +#endif + + _CPU_ISR_Disable(level); + if(mqueue->num_pendingmsgs!=0) { + --mqueue->num_pendingmsgs; + msg = __lwpmq_get_pendingmsg(mqueue); + _CPU_ISR_Restore(level); + + *size = msg->contents.size; + exec->wait.cnt = msg->prio; + __lwpmq_buffer_copy(buffer,msg->contents.buffer,*size); + + thread = __lwp_threadqueue_dequeue(&mqueue->wait_queue); + if(!thread) { + __lwpmq_free_msg(mqueue,msg); + return LWP_MQ_STATUS_SUCCESSFUL; + } + + msg->prio = thread->wait.cnt; + msg->contents.size = (u32)thread->wait.ret_arg_1; + __lwpmq_buffer_copy(msg->contents.buffer,thread->wait.ret_arg,msg->contents.size); + + __lwpmq_msg_insert(mqueue,msg,msg->prio); + return LWP_MQ_STATUS_SUCCESSFUL; + } + + if(!wait) { + _CPU_ISR_Restore(level); + exec->wait.ret_code = LWP_MQ_STATUS_UNSATISFIED_NOWAIT; + return LWP_MQ_STATUS_UNSATISFIED_NOWAIT; + } + + __lwp_threadqueue_csenter(&mqueue->wait_queue); + exec->wait.queue = &mqueue->wait_queue; + exec->wait.id = id; + exec->wait.ret_arg = (void*)buffer; + exec->wait.ret_arg_1 = (void*)size; + _CPU_ISR_Restore(level); + + __lwp_threadqueue_enqueue(&mqueue->wait_queue,timeout); + return LWP_MQ_STATUS_SUCCESSFUL; +} + +u32 __lwpmq_submit(mq_cntrl *mqueue,u32 id,void *buffer,u32 size,u32 type,u32 wait,u64 timeout) +{ + u32 level; + lwp_cntrl *thread; + mq_buffercntrl *msg; + +#ifdef _LWPMQ_DEBUG + printf("__lwpmq_submit(%p,%p,%d,%d,%d,%d)\n",mqueue,buffer,size,id,type,wait); +#endif + if(size>mqueue->max_msgsize) + return LWP_MQ_STATUS_INVALID_SIZE; + + if(mqueue->num_pendingmsgs==0) { + thread = __lwp_threadqueue_dequeue(&mqueue->wait_queue); + if(thread) { + __lwpmq_buffer_copy(thread->wait.ret_arg,buffer,size); + *(u32*)thread->wait.ret_arg_1 = size; + thread->wait.cnt = type; + return LWP_MQ_STATUS_SUCCESSFUL; + } + } + + if(mqueue->num_pendingmsgsmax_pendingmsgs) { + msg = __lwpmq_allocate_msg(mqueue); + if(!msg) return LWP_MQ_STATUS_UNSATISFIED; + + __lwpmq_buffer_copy(msg->contents.buffer,buffer,size); + msg->contents.size = size; + msg->prio = type; + __lwpmq_msg_insert(mqueue,msg,type); + return LWP_MQ_STATUS_SUCCESSFUL; + } + + if(!wait) return LWP_MQ_STATUS_TOO_MANY; + if(__lwp_isr_in_progress()) return LWP_MQ_STATUS_UNSATISFIED; + + { + lwp_cntrl *exec = _thr_executing; + + _CPU_ISR_Disable(level); + __lwp_threadqueue_csenter(&mqueue->wait_queue); + exec->wait.queue = &mqueue->wait_queue; + exec->wait.id = id; + exec->wait.ret_arg = (void*)buffer; + exec->wait.ret_arg_1 = (void*)size; + exec->wait.cnt = type; + _CPU_ISR_Restore(level); + + __lwp_threadqueue_enqueue(&mqueue->wait_queue,timeout); + } + return LWP_MQ_STATUS_UNSATISFIED_WAIT; +} + +u32 __lwpmq_broadcast(mq_cntrl *mqueue,void *buffer,u32 size,u32 id,u32 *count) +{ + lwp_cntrl *thread; + u32 num_broadcast; + lwp_waitinfo *waitp; + u32 rsize; +#ifdef _LWPMQ_DEBUG + printf("__lwpmq_broadcast(%p,%p,%d,%d,%p)\n",mqueue,buffer,size,id,count); +#endif + if(mqueue->num_pendingmsgs!=0) { + *count = 0; + return LWP_MQ_STATUS_SUCCESSFUL; + } + + num_broadcast = 0; + while((thread=__lwp_threadqueue_dequeue(&mqueue->wait_queue))) { + waitp = &thread->wait; + ++num_broadcast; + + rsize = size; + if(size>mqueue->max_msgsize) + rsize = mqueue->max_msgsize; + + __lwpmq_buffer_copy(waitp->ret_arg,buffer,rsize); + *(u32*)waitp->ret_arg_1 = size; + } + *count = num_broadcast; + return LWP_MQ_STATUS_SUCCESSFUL; +} + +void __lwpmq_close(mq_cntrl *mqueue,u32 status) +{ + __lwp_threadqueue_flush(&mqueue->wait_queue,status); + __lwpmq_flush_support(mqueue); + __lwp_wkspace_free(mqueue->msq_buffers); +} + +u32 __lwpmq_flush(mq_cntrl *mqueue) +{ + if(mqueue->num_pendingmsgs!=0) + return __lwpmq_flush_support(mqueue); + else + return 0; +} + +u32 __lwpmq_flush_support(mq_cntrl *mqueue) +{ + u32 level; + lwp_node *inactive; + lwp_node *mqueue_first; + lwp_node *mqueue_last; + u32 cnt; + + _CPU_ISR_Disable(level); + + inactive = mqueue->inactive_msgs.first; + mqueue_first = mqueue->pending_msgs.first; + mqueue_last = mqueue->pending_msgs.last; + + mqueue->inactive_msgs.first = mqueue_first; + mqueue_last->next = inactive; + inactive->prev = mqueue_last; + mqueue_first->prev = __lwp_queue_head(&mqueue->inactive_msgs); + + __lwp_queue_init_empty(&mqueue->pending_msgs); + + cnt = mqueue->num_pendingmsgs; + mqueue->num_pendingmsgs = 0; + + _CPU_ISR_Restore(level); + return cnt; +} + +void __lwpmq_flush_waitthreads(mq_cntrl *mqueue) +{ + __lwp_threadqueue_flush(&mqueue->wait_queue,LWP_MQ_STATUS_UNSATISFIED_NOWAIT); +} diff --git a/wii/libogc/libogc/lwp_messages.inl b/wii/libogc/libogc/lwp_messages.inl new file mode 100644 index 0000000000..db023fa99e --- /dev/null +++ b/wii/libogc/libogc/lwp_messages.inl @@ -0,0 +1,62 @@ +#ifndef __MESSAGE_INL__ +#define __MESSAGE_INL__ + +static __inline__ void __lwpmq_set_notify(mq_cntrl *mqueue,mq_notifyhandler handler,void *arg) +{ + mqueue->notify_handler = handler; + mqueue->notify_arg = arg; +} + +static __inline__ u32 __lwpmq_is_priority(mq_attr *attr) +{ + return (attr->mode==LWP_MQ_PRIORITY); +} + +static __inline__ mq_buffercntrl* __lwpmq_allocate_msg(mq_cntrl *mqueue) +{ + return (mq_buffercntrl*)__lwp_queue_get(&mqueue->inactive_msgs); +} + +static __inline__ void __lwpmq_free_msg(mq_cntrl *mqueue,mq_buffercntrl *msg) +{ + __lwp_queue_append(&mqueue->inactive_msgs,&msg->node); +} + +static __inline__ void __lwpmq_msg_append(mq_cntrl *mqueue,mq_buffercntrl *msg) +{ +#ifdef _LWPMQ_DEBUG + printf("__lwpmq_msq_append(%p,%p,%p)\n",mqueue,&mqueue->inactive_msgs,msg); +#endif + __lwp_queue_append(&mqueue->pending_msgs,&msg->node); +} + +static __inline__ void __lwpmq_msg_prepend(mq_cntrl *mqueue,mq_buffercntrl *msg) +{ +#ifdef _LWPMQ_DEBUG + printf("__lwpmq_msq_prepend(%p,%p,%p)\n",mqueue,&mqueue->inactive_msgs,msg); +#endif + __lwp_queue_prepend(&mqueue->pending_msgs,&msg->node); +} + +static __inline__ u32 __lwpmq_send(mq_cntrl *mqueue,u32 id,void *buffer,u32 size,u32 wait,u32 timeout) +{ + return __lwpmq_submit(mqueue,id,buffer,size,LWP_MQ_SEND_REQUEST,wait,timeout); +} + +static __inline__ u32 __lwpmq_urgent(mq_cntrl *mqueue,void *buffer,u32 size,u32 id,u32 wait,u32 timeout) +{ + return __lwpmq_submit(mqueue,id,buffer,size,LWP_MQ_SEND_URGENT,wait,timeout); +} + +static __inline__ mq_buffercntrl* __lwpmq_get_pendingmsg(mq_cntrl *mqueue) +{ + return (mq_buffercntrl*)__lwp_queue_getI(&mqueue->pending_msgs); +} + +static __inline__ void __lwpmq_buffer_copy(void *dest,const void *src,u32 size) +{ + if(size==sizeof(u32)) *(u32*)dest = *(u32*)src; + else memcpy(dest,src,size); +} + +#endif diff --git a/wii/libogc/libogc/lwp_mutex.c b/wii/libogc/libogc/lwp_mutex.c new file mode 100644 index 0000000000..205074a952 --- /dev/null +++ b/wii/libogc/libogc/lwp_mutex.c @@ -0,0 +1,95 @@ +#include "asm.h" +#include "lwp_mutex.h" + +void __lwp_mutex_initialize(lwp_mutex *mutex,lwp_mutex_attr *attrs,u32 init_lock) +{ + mutex->atrrs = *attrs; + mutex->lock = init_lock; + mutex->blocked_cnt = 0; + + if(init_lock==LWP_MUTEX_LOCKED) { + mutex->nest_cnt = 1; + mutex->holder = _thr_executing; + if(__lwp_mutex_isinheritprio(attrs) || __lwp_mutex_isprioceiling(attrs)) + _thr_executing->res_cnt++; + } else { + mutex->nest_cnt = 0; + mutex->holder = NULL; + } + + __lwp_threadqueue_init(&mutex->wait_queue,__lwp_mutex_isfifo(attrs)?LWP_THREADQ_MODEFIFO:LWP_THREADQ_MODEPRIORITY,LWP_STATES_WAITING_FOR_MUTEX,LWP_MUTEX_TIMEOUT); +} + +u32 __lwp_mutex_surrender(lwp_mutex *mutex) +{ + lwp_cntrl *thethread; + lwp_cntrl *holder; + + holder = mutex->holder; + + if(mutex->atrrs.onlyownerrelease) { + if(!__lwp_thread_isexec(holder)) + return LWP_MUTEX_NOTOWNER; + } + + if(!mutex->nest_cnt) + return LWP_MUTEX_SUCCESSFUL; + + mutex->nest_cnt--; + if(mutex->nest_cnt!=0) { + switch(mutex->atrrs.nest_behavior) { + case LWP_MUTEX_NEST_ACQUIRE: + return LWP_MUTEX_SUCCESSFUL; + case LWP_MUTEX_NEST_ERROR: + return LWP_MUTEX_NEST_NOTALLOWED; + case LWP_MUTEX_NEST_BLOCK: + break; + } + } + + if(__lwp_mutex_isinheritprio(&mutex->atrrs) || __lwp_mutex_isprioceiling(&mutex->atrrs)) + holder->res_cnt--; + + mutex->holder = NULL; + if(__lwp_mutex_isinheritprio(&mutex->atrrs) || __lwp_mutex_isprioceiling(&mutex->atrrs)) { + if(holder->res_cnt==0 && holder->real_prio!=holder->cur_prio) + __lwp_thread_changepriority(holder,holder->real_prio,TRUE); + } + + if((thethread=__lwp_threadqueue_dequeue(&mutex->wait_queue))) { + mutex->nest_cnt = 1; + mutex->holder = thethread; + if(__lwp_mutex_isinheritprio(&mutex->atrrs) || __lwp_mutex_isprioceiling(&mutex->atrrs)) + thethread->res_cnt++; + } else + mutex->lock = LWP_MUTEX_UNLOCKED; + + return LWP_MUTEX_SUCCESSFUL; +} + +void __lwp_mutex_seize_irq_blocking(lwp_mutex *mutex,u64 timeout) +{ + lwp_cntrl *exec; + + exec = _thr_executing; + if(__lwp_mutex_isinheritprio(&mutex->atrrs)){ + if(mutex->holder->cur_prio>exec->cur_prio) + __lwp_thread_changepriority(mutex->holder,exec->cur_prio,FALSE); + } + + mutex->blocked_cnt++; + __lwp_threadqueue_enqueue(&mutex->wait_queue,timeout); + + if(_thr_executing->wait.ret_code==LWP_MUTEX_SUCCESSFUL) { + if(__lwp_mutex_isprioceiling(&mutex->atrrs)) { + if(mutex->atrrs.prioceilcur_prio) + __lwp_thread_changepriority(exec,mutex->atrrs.prioceil,FALSE); + } + } + __lwp_thread_dispatchenable(); +} + +void __lwp_mutex_flush(lwp_mutex *mutex,u32 status) +{ + __lwp_threadqueue_flush(&mutex->wait_queue,status); +} diff --git a/wii/libogc/libogc/lwp_mutex.inl b/wii/libogc/libogc/lwp_mutex.inl new file mode 100644 index 0000000000..afa9c82396 --- /dev/null +++ b/wii/libogc/libogc/lwp_mutex.inl @@ -0,0 +1,88 @@ +#ifndef __LWP_MUTEX_INL__ +#define __LWP_MUTEX_INL__ + +static __inline__ u32 __lwp_mutex_locked(lwp_mutex *mutex) +{ + return (mutex->lock==LWP_MUTEX_LOCKED); +} + +static __inline__ u32 __lwp_mutex_ispriority(lwp_mutex_attr *attrs) +{ + return (attrs->mode==LWP_MUTEX_PRIORITY); +} + +static __inline__ u32 __lwp_mutex_isfifo(lwp_mutex_attr *attrs) +{ + return (attrs->mode==LWP_MUTEX_FIFO); +} + +static __inline__ u32 __lwp_mutex_isinheritprio(lwp_mutex_attr *attrs) +{ + return (attrs->mode==LWP_MUTEX_INHERITPRIO); +} + +static __inline__ u32 __lwp_mutex_isprioceiling(lwp_mutex_attr *attrs) +{ + return (attrs->mode==LWP_MUTEX_PRIORITYCEIL); +} + +static __inline__ u32 __lwp_mutex_seize_irq_trylock(lwp_mutex *mutex,u32 *isr_level) +{ + lwp_cntrl *exec; + u32 level = *isr_level; + + exec = _thr_executing; + exec->wait.ret_code = LWP_MUTEX_SUCCESSFUL; + if(!__lwp_mutex_locked(mutex)) { + mutex->lock = LWP_MUTEX_LOCKED; + mutex->holder = exec; + mutex->nest_cnt = 1; + if(__lwp_mutex_isinheritprio(&mutex->atrrs) || __lwp_mutex_isprioceiling(&mutex->atrrs)) + exec->res_cnt++; + if(!__lwp_mutex_isprioceiling(&mutex->atrrs)) { + _CPU_ISR_Restore(level); + return 0; + } + { + u32 prioceiling,priocurr; + + prioceiling = mutex->atrrs.prioceil; + priocurr = exec->cur_prio; + if(priocurr==prioceiling) { + _CPU_ISR_Restore(level); + return 0; + } + if(priocurr>prioceiling) { + __lwp_thread_dispatchdisable(); + _CPU_ISR_Restore(level); + __lwp_thread_changepriority(mutex->holder,mutex->atrrs.prioceil,FALSE); + __lwp_thread_dispatchenable(); + return 0; + } + exec->wait.ret_code = LWP_MUTEX_CEILINGVIOL; + mutex->nest_cnt = 0; + exec->res_cnt--; + _CPU_ISR_Restore(level); + return 0; + } + return 0; + } + + if(__lwp_thread_isexec(mutex->holder)) { + switch(mutex->atrrs.nest_behavior) { + case LWP_MUTEX_NEST_ACQUIRE: + mutex->nest_cnt++; + _CPU_ISR_Restore(level); + return 0; + case LWP_MUTEX_NEST_ERROR: + exec->wait.ret_code = LWP_MUTEX_NEST_NOTALLOWED; + _CPU_ISR_Restore(level); + return 0; + case LWP_MUTEX_NEST_BLOCK: + break; + } + } + return 1; +} + +#endif diff --git a/wii/libogc/libogc/lwp_objmgr.c b/wii/libogc/libogc/lwp_objmgr.c new file mode 100644 index 0000000000..9b2149baff --- /dev/null +++ b/wii/libogc/libogc/lwp_objmgr.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lwp_objmgr.h" + +static u32 _lwp_objmgr_memsize = 0; +static lwp_obj *null_local_table = NULL; + +u32 __lwp_objmgr_memsize() +{ + return _lwp_objmgr_memsize; +} + +void __lwp_objmgr_initinfo(lwp_objinfo *info,u32 max_nodes,u32 node_size) +{ + u32 idx,i,size; + lwp_obj *object; + lwp_queue inactives; + void **local_table; + + info->min_id = 0; + info->max_id = 0; + info->inactives_cnt = 0; + info->node_size = node_size; + info->max_nodes = max_nodes; + info->obj_blocks = NULL; + info->local_table = &null_local_table; + + __lwp_queue_init_empty(&info->inactives); + + size = ((info->max_nodes*sizeof(lwp_obj*))+(info->max_nodes*info->node_size)); + local_table = (void**)__lwp_wkspace_allocate(info->max_nodes*sizeof(lwp_obj*)); + if(!local_table) return; + + info->local_table = (lwp_obj**)local_table; + for(i=0;imax_nodes;i++) { + local_table[i] = NULL; + } + + info->obj_blocks = __lwp_wkspace_allocate(info->max_nodes*info->node_size); + if(!info->obj_blocks) { + __lwp_wkspace_free(local_table); + return; + } + + __lwp_queue_initialize(&inactives,info->obj_blocks,info->max_nodes,info->node_size); + + idx = info->min_id; + while((object=(lwp_obj*)__lwp_queue_get(&inactives))!=NULL) { + object->id = idx; + object->information = NULL; + __lwp_queue_append(&info->inactives,&object->node); + idx++; + } + + info->max_id += info->max_nodes; + info->inactives_cnt += info->max_nodes; + _lwp_objmgr_memsize += size; +} + +lwp_obj* __lwp_objmgr_getisrdisable(lwp_objinfo *info,u32 id,u32 *p_level) +{ + u32 level; + lwp_obj *object = NULL; + + _CPU_ISR_Disable(level); + if(info->max_id>=id) { + if((object=info->local_table[id])!=NULL) { + *p_level = level; + return object; + } + } + _CPU_ISR_Restore(level); + return NULL; +} + +lwp_obj* __lwp_objmgr_getnoprotection(lwp_objinfo *info,u32 id) +{ + lwp_obj *object = NULL; + + if(info->max_id>=id) { + if((object=info->local_table[id])!=NULL) return object; + } + return NULL; +} + +lwp_obj* __lwp_objmgr_get(lwp_objinfo *info,u32 id) +{ + lwp_obj *object = NULL; + + if(info->max_id>=id) { + __lwp_thread_dispatchdisable(); + if((object=info->local_table[id])!=NULL) return object; + __lwp_thread_dispatchenable(); + } + return NULL; +} + +lwp_obj* __lwp_objmgr_allocate(lwp_objinfo *info) +{ + u32 level; + lwp_obj* object; + + _CPU_ISR_Disable(level); + object = (lwp_obj*)__lwp_queue_getI(&info->inactives); + if(object) { + object->information = info; + info->inactives_cnt--; + } + _CPU_ISR_Restore(level); + + return object; +} + +void __lwp_objmgr_free(lwp_objinfo *info,lwp_obj *object) +{ + u32 level; + + _CPU_ISR_Disable(level); + __lwp_queue_appendI(&info->inactives,&object->node); + object->information = NULL; + info->inactives_cnt++; + _CPU_ISR_Restore(level); +} diff --git a/wii/libogc/libogc/lwp_objmgr.inl b/wii/libogc/libogc/lwp_objmgr.inl new file mode 100644 index 0000000000..357d16c7a6 --- /dev/null +++ b/wii/libogc/libogc/lwp_objmgr.inl @@ -0,0 +1,19 @@ +#ifndef __LWP_OBJMGR_INL__ +#define __LWP_OBJMGR_INL__ + +static __inline__ void __lwp_objmgr_setlocal(lwp_objinfo *info,u32 idx,lwp_obj *object) +{ + if(idxmax_nodes) info->local_table[idx] = object; +} + +static __inline__ void __lwp_objmgr_open(lwp_objinfo *info,lwp_obj *object) +{ + __lwp_objmgr_setlocal(info,object->id,object); +} + +static __inline__ void __lwp_objmgr_close(lwp_objinfo *info,lwp_obj *object) +{ + __lwp_objmgr_setlocal(info,object->id,NULL); +} + +#endif diff --git a/wii/libogc/libogc/lwp_priority.c b/wii/libogc/libogc/lwp_priority.c new file mode 100644 index 0000000000..d8d0e4c700 --- /dev/null +++ b/wii/libogc/libogc/lwp_priority.c @@ -0,0 +1,14 @@ +#include + +vu32 _prio_major_bitmap; +u32 _prio_bitmap[16] __attribute__((aligned(32))); + +void __lwp_priority_init() +{ + u32 index; + + _prio_major_bitmap = 0; + for(index=0;index<16;index++) + _prio_bitmap[index] = 0; + +} diff --git a/wii/libogc/libogc/lwp_priority.inl b/wii/libogc/libogc/lwp_priority.inl new file mode 100644 index 0000000000..3b4b54bba8 --- /dev/null +++ b/wii/libogc/libogc/lwp_priority.inl @@ -0,0 +1,42 @@ +#ifndef __LWP_PRIORITY_INL__ +#define __LWP_PRIORITY_INL__ + +static __inline__ void __lwp_priomap_init(prio_cntrl *theprio,u32 prio) +{ + u32 mask; + + u32 major = prio/16; + u32 minor = prio%16; + + theprio->minor = &_prio_bitmap[major]; + + mask = 0x80000000>>major; + theprio->ready_major = mask; + theprio->block_major = ~mask; + + mask = 0x80000000>>minor; + theprio->ready_minor = mask; + theprio->block_minor = ~mask; +} + +static __inline__ void __lwp_priomap_addto(prio_cntrl *theprio) +{ + *theprio->minor |= theprio->ready_minor; + _prio_major_bitmap |= theprio->ready_major; +} + +static __inline__ void __lwp_priomap_removefrom(prio_cntrl *theprio) +{ + *theprio->minor &= theprio->block_minor; + if(*theprio->minor==0) + _prio_major_bitmap &= theprio->block_major; +} + +static __inline__ u32 __lwp_priomap_highest() +{ + u32 major = cntlzw(_prio_major_bitmap); + u32 minor = cntlzw(_prio_bitmap[major]); + return ((major<<4)+minor); +} + +#endif diff --git a/wii/libogc/libogc/lwp_queue.c b/wii/libogc/libogc/lwp_queue.c new file mode 100644 index 0000000000..cb359c9ed5 --- /dev/null +++ b/wii/libogc/libogc/lwp_queue.c @@ -0,0 +1,68 @@ +#include +#include "asm.h" +#include "processor.h" +#include "lwp_queue.h" + +void __lwp_queue_initialize(lwp_queue *queue,void *start_addr,u32 num_nodes,u32 node_size) +{ + u32 count; + lwp_node *curr; + lwp_node *next; + +#ifdef _LWPQ_DEBUG + printf("__lwp_queue_initialize(%p,%p,%d,%d)\n",queue,start_addr,num_nodes,node_size); +#endif + count = num_nodes; + curr = __lwp_queue_head(queue); + queue->perm_null = NULL; + next = (lwp_node*)start_addr; + + while(count--) { + curr->next = next; + next->prev = curr; + curr = next; + next = (lwp_node*)(((void*)next)+node_size); + } + curr->next = __lwp_queue_tail(queue); + queue->last = curr; +} + +lwp_node* __lwp_queue_get(lwp_queue *queue) +{ + u32 level; + lwp_node *ret = NULL; + + _CPU_ISR_Disable(level); + if(!__lwp_queue_isempty(queue)) { + ret = __lwp_queue_firstnodeI(queue); + } + _CPU_ISR_Restore(level); + return ret; +} + +void __lwp_queue_append(lwp_queue *queue,lwp_node *node) +{ + u32 level; + + _CPU_ISR_Disable(level); + __lwp_queue_appendI(queue,node); + _CPU_ISR_Restore(level); +} + +void __lwp_queue_extract(lwp_node *node) +{ + u32 level; + + _CPU_ISR_Disable(level); + __lwp_queue_extractI(node); + _CPU_ISR_Restore(level); +} + +void __lwp_queue_insert(lwp_node *after,lwp_node *node) +{ + u32 level; + + _CPU_ISR_Disable(level); + __lwp_queue_insertI(after,node); + _CPU_ISR_Restore(level); +} diff --git a/wii/libogc/libogc/lwp_queue.inl b/wii/libogc/libogc/lwp_queue.inl new file mode 100644 index 0000000000..809aaa3d1c --- /dev/null +++ b/wii/libogc/libogc/lwp_queue.inl @@ -0,0 +1,96 @@ +#ifndef __LWP_QUEUE_INL__ +#define __LWP_QUEUE_INL__ + +static __inline__ lwp_node* __lwp_queue_head(lwp_queue *queue) +{ + return (lwp_node*)queue; +} + +static __inline__ lwp_node* __lwp_queue_tail(lwp_queue *queue) +{ + return (lwp_node*)&queue->perm_null; +} + +static __inline__ u32 __lwp_queue_istail(lwp_queue *queue,lwp_node *node) +{ + return (node==__lwp_queue_tail(queue)); +} + +static __inline__ u32 __lwp_queue_ishead(lwp_queue *queue,lwp_node *node) +{ + return (node==__lwp_queue_head(queue)); +} + +static __inline__ lwp_node* __lwp_queue_firstnodeI(lwp_queue *queue) +{ + lwp_node *ret = queue->first; + lwp_node *new_first = ret->next; + queue->first = new_first; + new_first->prev = __lwp_queue_head(queue); + return ret; +} + +static __inline__ void __lwp_queue_init_empty(lwp_queue *queue) +{ + queue->first = __lwp_queue_tail(queue); + queue->perm_null = NULL; + queue->last = __lwp_queue_head(queue); +} + +static __inline__ u32 __lwp_queue_isempty(lwp_queue *queue) +{ + return (queue->first==__lwp_queue_tail(queue)); +} + +static __inline__ u32 __lwp_queue_onenode(lwp_queue *queue) +{ + return (queue->first==queue->last); +} + +static __inline__ void __lwp_queue_appendI(lwp_queue *queue,lwp_node *node) +{ + lwp_node *old; + node->next = __lwp_queue_tail(queue); + old = queue->last; + queue->last = node; + old->next = node; + node->prev = old; +} + +static __inline__ void __lwp_queue_extractI(lwp_node *node) +{ + lwp_node *next = node->next; + lwp_node *prev = node->prev; + next->prev = prev; + prev->next = next; +} + +static __inline__ void __lwp_queue_insertI(lwp_node *after,lwp_node *node) +{ + lwp_node *before; + + node->prev = after; + before = after->next; + after->next = node; + node->next = before; + before->prev = node; +} + +static __inline__ void __lwp_queue_prepend(lwp_queue *queue,lwp_node *node) +{ + __lwp_queue_insert(__lwp_queue_head(queue),node); +} + +static __inline__ void __lwp_queue_prependI(lwp_queue *queue,lwp_node *node) +{ + __lwp_queue_insertI(__lwp_queue_head(queue),node); +} + +static __inline__ lwp_node* __lwp_queue_getI(lwp_queue *queue) +{ + if(!__lwp_queue_isempty(queue)) + return __lwp_queue_firstnodeI(queue); + return NULL; +} + +#endif diff --git a/wii/libogc/libogc/lwp_sema.c b/wii/libogc/libogc/lwp_sema.c new file mode 100644 index 0000000000..49b1901da2 --- /dev/null +++ b/wii/libogc/libogc/lwp_sema.c @@ -0,0 +1,63 @@ +#include "asm.h" +#include "lwp_sema.h" + +void __lwp_sema_initialize(lwp_sema *sema,lwp_semattr *attrs,u32 init_count) +{ + sema->attrs = *attrs; + sema->count = init_count; + + __lwp_threadqueue_init(&sema->wait_queue,__lwp_sema_ispriority(attrs)?LWP_THREADQ_MODEPRIORITY:LWP_THREADQ_MODEFIFO,LWP_STATES_WAITING_FOR_SEMAPHORE,LWP_SEMA_TIMEOUT); +} + +u32 __lwp_sema_surrender(lwp_sema *sema,u32 id) +{ + u32 level,ret; + lwp_cntrl *thethread; + + ret = LWP_SEMA_SUCCESSFUL; + if((thethread=__lwp_threadqueue_dequeue(&sema->wait_queue))) return ret; + else { + _CPU_ISR_Disable(level); + if(sema->count<=sema->attrs.max_cnt) + ++sema->count; + else + ret = LWP_SEMA_MAXCNT_EXCEEDED; + _CPU_ISR_Restore(level); + } + return ret; +} + +u32 __lwp_sema_seize(lwp_sema *sema,u32 id,u32 wait,u64 timeout) +{ + u32 level; + lwp_cntrl *exec; + + exec = _thr_executing; + exec->wait.ret_code = LWP_SEMA_SUCCESSFUL; + + _CPU_ISR_Disable(level); + if(sema->count!=0) { + --sema->count; + _CPU_ISR_Restore(level); + return LWP_SEMA_SUCCESSFUL; + } + + if(!wait) { + _CPU_ISR_Restore(level); + exec->wait.ret_code = LWP_SEMA_UNSATISFIED_NOWAIT; + return LWP_SEMA_UNSATISFIED_NOWAIT; + } + + __lwp_threadqueue_csenter(&sema->wait_queue); + exec->wait.queue = &sema->wait_queue; + exec->wait.id = id; + _CPU_ISR_Restore(level); + + __lwp_threadqueue_enqueue(&sema->wait_queue,timeout); + return LWP_SEMA_SUCCESSFUL; +} + +void __lwp_sema_flush(lwp_sema *sema,u32 status) +{ + __lwp_threadqueue_flush(&sema->wait_queue,status); +} diff --git a/wii/libogc/libogc/lwp_sema.inl b/wii/libogc/libogc/lwp_sema.inl new file mode 100644 index 0000000000..0f57c6dcda --- /dev/null +++ b/wii/libogc/libogc/lwp_sema.inl @@ -0,0 +1,38 @@ +#ifndef __LWP_SEMA_INL__ +#define __LWP_SEMA_INL__ + +static __inline__ u32 __lwp_sema_ispriority(lwp_semattr *attr) +{ + return (attr->mode==LWP_SEMA_MODEPRIORITY); +} + +static __inline__ void __lwp_sema_seize_isrdisable(lwp_sema *sema,u32 id,u32 wait,u32 *isrlevel) +{ + lwp_cntrl *exec; + u32 level = *isrlevel; + + exec = _thr_executing; + exec->wait.ret_code = LWP_SEMA_SUCCESSFUL; + if(sema->count!=0) { + --sema->count; + _CPU_ISR_Restore(level); + return; + } + + if(!wait) { + _CPU_ISR_Restore(level); + exec->wait.ret_code = LWP_SEMA_UNSATISFIED_NOWAIT; + return; + } + + __lwp_thread_dispatchdisable(); + __lwp_threadqueue_csenter(&sema->wait_queue); + exec->wait.queue = &sema->wait_queue; + exec->wait.id = id; + _CPU_ISR_Restore(level); + + __lwp_threadqueue_enqueue(&sema->wait_queue,0); + __lwp_thread_dispatchenable(); +} + +#endif diff --git a/wii/libogc/libogc/lwp_stack.c b/wii/libogc/libogc/lwp_stack.c new file mode 100644 index 0000000000..05eadebfc4 --- /dev/null +++ b/wii/libogc/libogc/lwp_stack.c @@ -0,0 +1,27 @@ +#include +#include "lwp_stack.h" +#include "lwp_wkspace.h" + +u32 __lwp_stack_allocate(lwp_cntrl *thethread,u32 size) +{ + void *stack_addr = NULL; + + if(!__lwp_stack_isenough(size)) + size = CPU_MINIMUM_STACK_SIZE; + + size = __lwp_stack_adjust(size); + stack_addr = __lwp_wkspace_allocate(size); + + if(!stack_addr) size = 0; + + thethread->stack = stack_addr; + return size; +} + +void __lwp_stack_free(lwp_cntrl *thethread) +{ + if(!thethread->stack_allocated) + return; + + __lwp_wkspace_free(thethread->stack); +} diff --git a/wii/libogc/libogc/lwp_stack.inl b/wii/libogc/libogc/lwp_stack.inl new file mode 100644 index 0000000000..65a2cd5df7 --- /dev/null +++ b/wii/libogc/libogc/lwp_stack.inl @@ -0,0 +1,14 @@ +#ifndef __LWP_STACK_INL__ +#define __LWP_STACK_INL__ + +static __inline__ u32 __lwp_stack_isenough(u32 size) +{ + return (size>=CPU_MINIMUM_STACK_SIZE); +} + +static __inline__ u32 __lwp_stack_adjust(u32 size) +{ + return (size+CPU_STACK_ALIGNMENT); +} + +#endif diff --git a/wii/libogc/libogc/lwp_states.inl b/wii/libogc/libogc/lwp_states.inl new file mode 100644 index 0000000000..79ee4ecf70 --- /dev/null +++ b/wii/libogc/libogc/lwp_states.inl @@ -0,0 +1,109 @@ +#ifndef __LWP_STATES_INL__ +#define __LWP_STATES_INL__ + +static __inline__ u32 __lwp_setstate(u32 curr_state,u32 stateset) +{ + return (curr_state|stateset); +} + +static __inline__ u32 __lwp_clearstate(u32 curr_state,u32 stateclear) +{ + return (curr_state&~stateclear); +} + +static __inline__ u32 __lwp_stateready(u32 curr_state) +{ + return (curr_state==LWP_STATES_READY); +} + +static __inline__ u32 __lwp_stateonlydormant(u32 curr_state) +{ + return (curr_state==LWP_STATES_DORMANT); +} + +static __inline__ u32 __lwp_statedormant(u32 curr_state) +{ + return (curr_state&LWP_STATES_DORMANT); +} + +static __inline__ u32 __lwp_statesuspended(u32 curr_state) +{ + return (curr_state&LWP_STATES_SUSPENDED); +} + +static __inline__ u32 __lwp_statetransient(u32 curr_state) +{ + return (curr_state&LWP_STATES_TRANSIENT); +} + +static __inline__ u32 __lwp_statedelaying(u32 curr_state) +{ + return (curr_state&LWP_STATES_DELAYING); +} + +static __inline__ u32 __lwp_statewaitbuffer(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_BUFFER); +} + +static __inline__ u32 __lwp_statewaitsegment(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_SEGMENT); +} + +static __inline__ u32 __lwp_statewaitmessage(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_MESSAGE); +} + +static __inline__ u32 __lwp_statewaitevent(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_EVENT); +} + +static __inline__ u32 __lwp_statewaitmutex(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_MUTEX); +} + +static __inline__ u32 __lwp_statewaitsemaphore(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_SEMAPHORE); +} + +static __inline__ u32 __lwp_statewaittime(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_TIME); +} + +static __inline__ u32 __lwp_statewaitrpcreply(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_RPCREPLAY); +} + +static __inline__ u32 __lwp_statewaitperiod(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_FOR_PERIOD); +} + +static __inline__ u32 __lwp_statewaitlocallyblocked(u32 curr_state) +{ + return (curr_state&LWP_STATES_LOCALLY_BLOCKED); +} + +static __inline__ u32 __lwp_statewaitthreadqueue(u32 curr_state) +{ + return (curr_state&LWP_STATES_WAITING_ON_THREADQ); +} + +static __inline__ u32 __lwp_stateblocked(u32 curr_state) +{ + return (curr_state&LWP_STATES_BLOCKED); +} + +static __inline__ u32 __lwp_statesset(u32 curr_state,u32 mask) +{ + return ((curr_state&mask)!=LWP_STATES_READY); +} + +#endif diff --git a/wii/libogc/libogc/lwp_threadq.c b/wii/libogc/libogc/lwp_threadq.c new file mode 100644 index 0000000000..285202be20 --- /dev/null +++ b/wii/libogc/libogc/lwp_threadq.c @@ -0,0 +1,497 @@ +#include +#include +#include "asm.h" +#include "lwp_threadq.h" + +//#define _LWPTHRQ_DEBUG + +static void __lwp_threadqueue_timeout(void *usr_data) +{ + lwp_cntrl *thethread; + lwp_thrqueue *thequeue; + + __lwp_thread_dispatchdisable(); + thethread = (lwp_cntrl*)usr_data; + thequeue = thethread->wait.queue; + if(thequeue->sync_state!=LWP_THREADQ_SYNCHRONIZED && __lwp_thread_isexec(thethread)) { + if(thequeue->sync_state!=LWP_THREADQ_SATISFIED) thequeue->sync_state = LWP_THREADQ_TIMEOUT; + } else { + thethread->wait.ret_code = thethread->wait.queue->timeout_state; + __lwp_threadqueue_extract(thethread->wait.queue,thethread); + } + __lwp_thread_dispatchunnest(); +} + +lwp_cntrl* __lwp_threadqueue_firstfifo(lwp_thrqueue *queue) +{ + if(!__lwp_queue_isempty(&queue->queues.fifo)) + return (lwp_cntrl*)queue->queues.fifo.first; + + return NULL; +} + +lwp_cntrl* __lwp_threadqueue_firstpriority(lwp_thrqueue *queue) +{ + u32 index; + + for(index=0;indexqueues.priority[index])) + return (lwp_cntrl*)queue->queues.priority[index].first; + } + return NULL; +} + +void __lwp_threadqueue_enqueuefifo(lwp_thrqueue *queue,lwp_cntrl *thethread,u64 timeout) +{ + u32 level,sync_state; + + _CPU_ISR_Disable(level); + + sync_state = queue->sync_state; + queue->sync_state = LWP_THREADQ_SYNCHRONIZED; +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_enqueuefifo(%p,%d)\n",thethread,sync_state); +#endif + switch(sync_state) { + case LWP_THREADQ_SYNCHRONIZED: + break; + case LWP_THREADQ_NOTHINGHAPPEND: + __lwp_queue_appendI(&queue->queues.fifo,&thethread->object.node); + _CPU_ISR_Restore(level); + return; + case LWP_THREADQ_TIMEOUT: + thethread->wait.ret_code = thethread->wait.queue->timeout_state; + _CPU_ISR_Restore(level); + break; + case LWP_THREADQ_SATISFIED: + if(__lwp_wd_isactive(&thethread->timer)) { + __lwp_wd_deactivate(&thethread->timer); + _CPU_ISR_Restore(level); + __lwp_wd_remove_ticks(&thethread->timer); + } else + _CPU_ISR_Restore(level); + + break; + } + __lwp_thread_unblock(thethread); +} + +lwp_cntrl* __lwp_threadqueue_dequeuefifo(lwp_thrqueue *queue) +{ + u32 level; + lwp_cntrl *ret; + + _CPU_ISR_Disable(level); + if(!__lwp_queue_isempty(&queue->queues.fifo)) { + ret = (lwp_cntrl*)__lwp_queue_firstnodeI(&queue->queues.fifo); + if(!__lwp_wd_isactive(&ret->timer)) { + _CPU_ISR_Restore(level); + __lwp_thread_unblock(ret); + } else { + __lwp_wd_deactivate(&ret->timer); + _CPU_ISR_Restore(level); + __lwp_wd_remove_ticks(&ret->timer); + __lwp_thread_unblock(ret); + } + return ret; + } + + switch(queue->sync_state) { + case LWP_THREADQ_SYNCHRONIZED: + case LWP_THREADQ_SATISFIED: + _CPU_ISR_Restore(level); + return NULL; + case LWP_THREADQ_NOTHINGHAPPEND: + case LWP_THREADQ_TIMEOUT: + queue->sync_state = LWP_THREADQ_SATISFIED; + _CPU_ISR_Restore(level); + return _thr_executing; + } + return NULL; +} + +void __lwp_threadqueue_enqueuepriority(lwp_thrqueue *queue,lwp_cntrl *thethread,u64 timeout) +{ + u32 level,search_prio,header_idx,prio,block_state,sync_state; + lwp_cntrl *search_thread; + lwp_queue *header; + lwp_node *cur_node,*next_node,*prev_node,*search_node; + + __lwp_queue_init_empty(&thethread->wait.block2n); + + prio = thethread->cur_prio; + header_idx = prio/LWP_THREADQ_PRIOPERHEADER; + header = &queue->queues.priority[header_idx]; + block_state = queue->state; + + if(prio&LWP_THREADQ_REVERSESEARCHMASK) { +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_enqueuepriority(%p,reverse_search)\n",thethread); +#endif + goto reverse_search; + } + +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_enqueuepriority(%p,forward_search)\n",thethread); +#endif +forward_search: + search_prio = LWP_PRIO_MIN - 1; + _CPU_ISR_Disable(level); + search_thread = (lwp_cntrl*)header->first; + while(!__lwp_queue_istail(header,(lwp_node*)search_thread)) { + search_prio = search_thread->cur_prio; + if(prio<=search_prio) break; + _CPU_ISR_Flash(level); + + if(!__lwp_statesset(search_thread->cur_state,block_state)) { + _CPU_ISR_Restore(level); + goto forward_search; + } + search_thread = (lwp_cntrl*)search_thread->object.node.next; + } + if(queue->sync_state!=LWP_THREADQ_NOTHINGHAPPEND) goto synchronize; + queue->sync_state = LWP_THREADQ_SYNCHRONIZED; + if(prio==search_prio) goto equal_prio; + + search_node = (lwp_node*)search_thread; + prev_node = search_node->prev; + cur_node = (lwp_node*)thethread; + + cur_node->next = search_node; + cur_node->prev = prev_node; + prev_node->next = cur_node; + search_node->prev = cur_node; + _CPU_ISR_Restore(level); + return; + +reverse_search: + search_prio = LWP_PRIO_MAX + 1; + _CPU_ISR_Disable(level); + search_thread = (lwp_cntrl*)header->last; + while(!__lwp_queue_ishead(header,(lwp_node*)search_thread)) { + search_prio = search_thread->cur_prio; + if(prio>=search_prio) break; + _CPU_ISR_Flash(level); + + if(!__lwp_statesset(search_thread->cur_state,block_state)) { + _CPU_ISR_Restore(level); + goto reverse_search; + } + search_thread = (lwp_cntrl*)search_thread->object.node.prev; + } + if(queue->sync_state!=LWP_THREADQ_NOTHINGHAPPEND) goto synchronize; + queue->sync_state = LWP_THREADQ_SYNCHRONIZED; + if(prio==search_prio) goto equal_prio; + + search_node = (lwp_node*)search_thread; + next_node = search_node->next; + cur_node = (lwp_node*)thethread; + + cur_node->next = next_node; + cur_node->prev = search_node; + search_node->next = cur_node; + next_node->prev = cur_node; + _CPU_ISR_Restore(level); + return; + +equal_prio: +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_enqueuepriority(%p,equal_prio)\n",thethread); +#endif + search_node = __lwp_queue_tail(&search_thread->wait.block2n); + prev_node = search_node->prev; + cur_node = (lwp_node*)thethread; + + cur_node->next = search_node; + cur_node->prev = prev_node; + prev_node->next = cur_node; + search_node->prev = cur_node; + _CPU_ISR_Restore(level); + return; + +synchronize: + sync_state = queue->sync_state; + queue->sync_state = LWP_THREADQ_SYNCHRONIZED; + +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_enqueuepriority(%p,sync_state = %d)\n",thethread,sync_state); +#endif + switch(sync_state) { + case LWP_THREADQ_SYNCHRONIZED: + break; + case LWP_THREADQ_NOTHINGHAPPEND: + break; + case LWP_THREADQ_TIMEOUT: + thethread->wait.ret_code = thethread->wait.queue->timeout_state; + _CPU_ISR_Restore(level); + break; + case LWP_THREADQ_SATISFIED: + if(__lwp_wd_isactive(&thethread->timer)) { + __lwp_wd_deactivate(&thethread->timer); + _CPU_ISR_Restore(level); + __lwp_wd_remove_ticks(&thethread->timer); + } else + _CPU_ISR_Restore(level); + break; + } + __lwp_thread_unblock(thethread); +} + +lwp_cntrl* __lwp_threadqueue_dequeuepriority(lwp_thrqueue *queue) +{ + u32 level,idx; + lwp_cntrl *newfirstthr,*ret = NULL; + lwp_node *newfirstnode,*newsecnode,*last_node,*next_node,*prev_node; + + _CPU_ISR_Disable(level); + for(idx=0;idxqueues.priority[idx])) { + ret = (lwp_cntrl*)queue->queues.priority[idx].first; + goto dequeue; + } + } + +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_dequeuepriority(%p,sync_state = %d)\n",ret,queue->sync_state); +#endif + switch(queue->sync_state) { + case LWP_THREADQ_SYNCHRONIZED: + case LWP_THREADQ_SATISFIED: + _CPU_ISR_Restore(level); + return NULL; + case LWP_THREADQ_NOTHINGHAPPEND: + case LWP_THREADQ_TIMEOUT: + queue->sync_state = LWP_THREADQ_SATISFIED; + _CPU_ISR_Restore(level); + return _thr_executing; + } + +dequeue: +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_dequeuepriority(%p,dequeue)\n",ret); +#endif + newfirstnode = ret->wait.block2n.first; + newfirstthr = (lwp_cntrl*)newfirstnode; + next_node = ret->object.node.next; + prev_node = ret->object.node.prev; + if(!__lwp_queue_isempty(&ret->wait.block2n)) { + last_node = ret->wait.block2n.last; + newsecnode = newfirstnode->next; + prev_node->next = newfirstnode; + next_node->prev = newfirstnode; + newfirstnode->next = next_node; + newfirstnode->prev = prev_node; + + if(!__lwp_queue_onenode(&ret->wait.block2n)) { + newsecnode->prev = __lwp_queue_head(&newfirstthr->wait.block2n); + newfirstthr->wait.block2n.first = newsecnode; + newfirstthr->wait.block2n.last = last_node; + last_node->next = __lwp_queue_tail(&newfirstthr->wait.block2n); + } + } else { + prev_node->next = next_node; + next_node->prev = prev_node; + } + + if(!__lwp_wd_isactive(&ret->timer)) { + _CPU_ISR_Restore(level); + __lwp_thread_unblock(ret); + } else { + __lwp_wd_deactivate(&ret->timer); + _CPU_ISR_Restore(level); + __lwp_wd_remove_ticks(&ret->timer); + __lwp_thread_unblock(ret); + } + return ret; +} + +void __lwp_threadqueue_init(lwp_thrqueue *queue,u32 mode,u32 state,u32 timeout_state) +{ + u32 index; + + queue->state = state; + queue->mode = mode; + queue->timeout_state = timeout_state; + queue->sync_state = LWP_THREADQ_SYNCHRONIZED; +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_init(%p,%08x,%d,%d)\n",queue,state,timeout_state,mode); +#endif + switch(mode) { + case LWP_THREADQ_MODEFIFO: + __lwp_queue_init_empty(&queue->queues.fifo); + break; + case LWP_THREADQ_MODEPRIORITY: + for(index=0;indexqueues.priority[index]); + break; + } +} + +lwp_cntrl* __lwp_threadqueue_first(lwp_thrqueue *queue) +{ + lwp_cntrl *ret; + + switch(queue->mode) { + case LWP_THREADQ_MODEFIFO: + ret = __lwp_threadqueue_firstfifo(queue); + break; + case LWP_THREADQ_MODEPRIORITY: + ret = __lwp_threadqueue_firstpriority(queue); + break; + default: + ret = NULL; + break; + } + + return ret; +} + +void __lwp_threadqueue_enqueue(lwp_thrqueue *queue,u64 timeout) +{ + lwp_cntrl *thethread; + + thethread = _thr_executing; + __lwp_thread_setstate(thethread,queue->state); + + if(timeout) { + __lwp_wd_initialize(&thethread->timer,__lwp_threadqueue_timeout,thethread->object.id,thethread); + __lwp_wd_insert_ticks(&thethread->timer,timeout); + } + +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_enqueue(%p,%p,%d)\n",queue,thethread,queue->mode); +#endif + switch(queue->mode) { + case LWP_THREADQ_MODEFIFO: + __lwp_threadqueue_enqueuefifo(queue,thethread,timeout); + break; + case LWP_THREADQ_MODEPRIORITY: + __lwp_threadqueue_enqueuepriority(queue,thethread,timeout); + break; + } +} + +lwp_cntrl* __lwp_threadqueue_dequeue(lwp_thrqueue *queue) +{ + lwp_cntrl *ret = NULL; + +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_dequeue(%p,%p,%d,%d)\n",queue,_thr_executing,queue->mode,queue->sync_state); +#endif + switch(queue->mode) { + case LWP_THREADQ_MODEFIFO: + ret = __lwp_threadqueue_dequeuefifo(queue); + break; + case LWP_THREADQ_MODEPRIORITY: + ret = __lwp_threadqueue_dequeuepriority(queue); + break; + default: + ret = NULL; + break; + } +#ifdef _LWPTHRQ_DEBUG + printf("__lwp_threadqueue_dequeue(%p,%p,%d,%d)\n",queue,ret,queue->mode,queue->sync_state); +#endif + return ret; +} + +void __lwp_threadqueue_flush(lwp_thrqueue *queue,u32 status) +{ + lwp_cntrl *thethread; + while((thethread=__lwp_threadqueue_dequeue(queue))) { + thethread->wait.ret_code = status; + } +} + +void __lwp_threadqueue_extract(lwp_thrqueue *queue,lwp_cntrl *thethread) +{ + switch(queue->mode) { + case LWP_THREADQ_MODEFIFO: + __lwp_threadqueue_extractfifo(queue,thethread); + break; + case LWP_THREADQ_MODEPRIORITY: + __lwp_threadqueue_extractpriority(queue,thethread); + break; + } + +} + +void __lwp_threadqueue_extractfifo(lwp_thrqueue *queue,lwp_cntrl *thethread) +{ + u32 level; + + _CPU_ISR_Disable(level); + if(!__lwp_statewaitthreadqueue(thethread->cur_state)) { + _CPU_ISR_Restore(level); + return; + } + + __lwp_queue_extractI(&thethread->object.node); + if(!__lwp_wd_isactive(&thethread->timer)) { + _CPU_ISR_Restore(level); + } else { + __lwp_wd_deactivate(&thethread->timer); + _CPU_ISR_Restore(level); + __lwp_wd_remove_ticks(&thethread->timer); + } + __lwp_thread_unblock(thethread); +} + +void __lwp_threadqueue_extractpriority(lwp_thrqueue *queue,lwp_cntrl *thethread) +{ + u32 level; + lwp_cntrl *first; + lwp_node *curr,*next,*prev,*new_first,*new_sec,*last; + + curr = (lwp_node*)thethread; + + _CPU_ISR_Disable(level); + if(__lwp_statewaitthreadqueue(thethread->cur_state)) { + next = curr->next; + prev = curr->prev; + + if(!__lwp_queue_isempty(&thethread->wait.block2n)) { + new_first = thethread->wait.block2n.first; + first = (lwp_cntrl*)new_first; + last = thethread->wait.block2n.last; + new_sec = new_first->next; + + prev->next = new_first; + next->prev = new_first; + new_first->next = next; + new_first->prev = prev; + + if(!__lwp_queue_onenode(&thethread->wait.block2n)) { + new_sec->prev = __lwp_queue_head(&first->wait.block2n); + first->wait.block2n.first = new_sec; + first->wait.block2n.last = last; + last->next = __lwp_queue_tail(&first->wait.block2n); + } + } else { + prev->next = next; + next->prev = prev; + } + if(!__lwp_wd_isactive(&thethread->timer)) { + _CPU_ISR_Restore(level); + __lwp_thread_unblock(thethread); + } else { + __lwp_wd_deactivate(&thethread->timer); + _CPU_ISR_Restore(level); + __lwp_wd_remove_ticks(&thethread->timer); + __lwp_thread_unblock(thethread); + } + } else + _CPU_ISR_Restore(level); +} + +u32 __lwp_threadqueue_extractproxy(lwp_cntrl *thethread) +{ + u32 state; + + state = thethread->cur_state; + if(__lwp_statewaitthreadqueue(state)) { + __lwp_threadqueue_extract(thethread->wait.queue,thethread); + return TRUE; + } + return FALSE; +} diff --git a/wii/libogc/libogc/lwp_threadq.inl b/wii/libogc/libogc/lwp_threadq.inl new file mode 100644 index 0000000000..cce5c04ad4 --- /dev/null +++ b/wii/libogc/libogc/lwp_threadq.inl @@ -0,0 +1,9 @@ +#ifndef __LWP_THREADQ_INL__ +#define __LWP_THREADQ_INL__ + +static __inline__ void __lwp_threadqueue_csenter(lwp_thrqueue *queue) +{ + queue->sync_state = LWP_THREADQ_NOTHINGHAPPEND; +} + +#endif diff --git a/wii/libogc/libogc/lwp_threads.c b/wii/libogc/libogc/lwp_threads.c new file mode 100644 index 0000000000..f6fe307d1b --- /dev/null +++ b/wii/libogc/libogc/lwp_threads.c @@ -0,0 +1,750 @@ +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "sys_state.h" +#include "lwp_stack.h" +#include "lwp_threads.h" +#include "lwp_threadq.h" +#include "lwp_watchdog.h" + +#define LWP_MAXPRIORITIES 256 + +/* new one */ +frame_context core_context; + +lwp_cntrl *_thr_main = NULL; +lwp_cntrl *_thr_idle = NULL; + +lwp_cntrl *_thr_executing = NULL; +lwp_cntrl *_thr_heir = NULL; +lwp_cntrl *_thr_allocated_fp = NULL; + +vu32 _context_switch_want; +vu32 _thread_dispatch_disable_level; + +wd_cntrl _lwp_wd_timeslice; +u32 _lwp_ticks_per_timeslice = 0; +void **__lwp_thr_libc_reent = NULL; +lwp_queue _lwp_thr_ready[LWP_MAXPRIORITIES]; + +static void (*_lwp_exitfunc)(void); + +extern void _cpu_context_switch(void *,void *); +extern void _cpu_context_switch_ex(void *,void *); +extern void _cpu_context_save(void *); +extern void _cpu_context_restore(void *); +extern void _cpu_context_save_fp(void *); +extern void _cpu_context_restore_fp(void *); + +extern int __libc_create_hook(lwp_cntrl *,lwp_cntrl *); +extern int __libc_start_hook(lwp_cntrl *,lwp_cntrl *); +extern int __libc_delete_hook(lwp_cntrl *, lwp_cntrl *); + +extern void kprintf(const char *str, ...); + +#ifdef _LWPTHREADS_DEBUG +static void __lwp_dumpcontext(frame_context *ctx) +{ + kprintf("GPR00 %08x GPR08 %08x GPR16 %08x GPR24 %08x\n",ctx->GPR[0], ctx->GPR[8], ctx->GPR[16], ctx->GPR[24]); + kprintf("GPR01 %08x GPR09 %08x GPR17 %08x GPR25 %08x\n",ctx->GPR[1], ctx->GPR[9], ctx->GPR[17], ctx->GPR[25]); + kprintf("GPR02 %08x GPR10 %08x GPR18 %08x GPR26 %08x\n",ctx->GPR[2], ctx->GPR[10], ctx->GPR[18], ctx->GPR[26]); + kprintf("GPR03 %08x GPR11 %08x GPR19 %08x GPR27 %08x\n",ctx->GPR[3], ctx->GPR[11], ctx->GPR[19], ctx->GPR[27]); + kprintf("GPR04 %08x GPR12 %08x GPR20 %08x GPR28 %08x\n",ctx->GPR[4], ctx->GPR[12], ctx->GPR[20], ctx->GPR[28]); + kprintf("GPR05 %08x GPR13 %08x GPR21 %08x GPR29 %08x\n",ctx->GPR[5], ctx->GPR[13], ctx->GPR[21], ctx->GPR[29]); + kprintf("GPR06 %08x GPR14 %08x GPR22 %08x GPR30 %08x\n",ctx->GPR[6], ctx->GPR[14], ctx->GPR[22], ctx->GPR[30]); + kprintf("GPR07 %08x GPR15 %08x GPR23 %08x GPR31 %08x\n",ctx->GPR[7], ctx->GPR[15], ctx->GPR[23], ctx->GPR[31]); + kprintf("LR %08x SRR0 %08x SRR1 %08x MSR %08x\n\n", ctx->LR, ctx->SRR0, ctx->SRR1,ctx->MSR); +} + +void __lwp_showmsr() +{ + register u32 msr; + _CPU_MSR_GET(msr); + kprintf("msr: %08x\n",msr); +} + +void __lwp_dumpcontext_fp(lwp_cntrl *thrA,lwp_cntrl *thrB) +{ + kprintf("_cpu_contextfp_dump(%p,%p)\n",thrA,thrB); +} +#endif + +/* +void __lwp_getthreadlist(lwp_obj **thrs) +{ + *thrs = _lwp_objects; +} +*/ +u32 __lwp_isr_in_progress() +{ + register u32 isr_nest_level; + isr_nest_level = mfspr(272); + return isr_nest_level; +} + +static inline void __lwp_msr_setlevel(u32 level) +{ + register u32 msr; + _CPU_MSR_GET(msr); + if(!(level&CPU_MODES_INTERRUPT_MASK)) + msr |= MSR_EE; + else + msr &= ~MSR_EE; + _CPU_MSR_SET(msr); +} + +static inline u32 __lwp_msr_getlevel() +{ + register u32 msr; + _CPU_MSR_GET(msr); + if(msr&MSR_EE) return 0; + else return 1; +} + +void __lwp_thread_delayended(void *arg) +{ + lwp_cntrl *thethread = (lwp_cntrl*)arg; +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_delayended(%p)\n",thethread); +#endif + if(!thethread) return; + + __lwp_thread_dispatchdisable(); + __lwp_thread_unblock(thethread); + __lwp_thread_dispatchunnest(); +} + +void __lwp_thread_tickle_timeslice(void *arg) +{ + s64 ticks; + lwp_cntrl *exec; + + exec = _thr_executing; + ticks = millisecs_to_ticks(1); + + __lwp_thread_dispatchdisable(); + + if(!exec->is_preemptible) { + __lwp_wd_insert_ticks(&_lwp_wd_timeslice,ticks); + __lwp_thread_dispatchunnest(); + return; + } + if(!__lwp_stateready(exec->cur_state)) { + __lwp_wd_insert_ticks(&_lwp_wd_timeslice,ticks); + __lwp_thread_dispatchunnest(); + return; + } + + switch(exec->budget_algo) { + case LWP_CPU_BUDGET_ALGO_NONE: + break; + case LWP_CPU_BUDGET_ALGO_TIMESLICE: + if((--exec->cpu_time_budget)==0) { + __lwp_thread_resettimeslice(); + exec->cpu_time_budget = _lwp_ticks_per_timeslice; + } + break; + } + + __lwp_wd_insert_ticks(&_lwp_wd_timeslice,ticks); + __lwp_thread_dispatchunnest(); +} + +void __thread_dispatch_fp() +{ + u32 level; + lwp_cntrl *exec; + + _CPU_ISR_Disable(level); + exec = _thr_executing; +#ifdef _LWPTHREADS_DEBUG + __lwp_dumpcontext_fp(exec,_thr_allocated_fp); +#endif + if(!__lwp_thread_isallocatedfp(exec)) { + if(_thr_allocated_fp) _cpu_context_save_fp(&_thr_allocated_fp->context); + _cpu_context_restore_fp(&exec->context); + _thr_allocated_fp = exec; + } + _CPU_ISR_Restore(level); +} + +void __thread_dispatch() +{ + u32 level; + lwp_cntrl *exec,*heir; + + _CPU_ISR_Disable(level); + exec = _thr_executing; + while(_context_switch_want==TRUE) { + heir = _thr_heir; + _thread_dispatch_disable_level = 1; + _context_switch_want = FALSE; + _thr_executing = heir; + _CPU_ISR_Restore(level); + + if(__lwp_thr_libc_reent) { + exec->libc_reent = *__lwp_thr_libc_reent; + *__lwp_thr_libc_reent = heir->libc_reent; + } +#ifdef _DEBUG + _cpu_context_switch_ex((void*)&exec->context,(void*)&heir->context); +#else + _cpu_context_switch((void*)&exec->context,(void*)&heir->context); +#endif + exec = _thr_executing; + _CPU_ISR_Disable(level); + } + _thread_dispatch_disable_level = 0; + _CPU_ISR_Restore(level); +} + +static void __lwp_thread_handler() +{ + u32 level; + lwp_cntrl *exec; + + exec = _thr_executing; +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_handler(%p,%d)\n",exec,_thread_dispatch_disable_level); +#endif + level = exec->isr_level; + __lwp_msr_setlevel(level); + __lwp_thread_dispatchenable(); + exec->wait.ret_arg = exec->entry(exec->arg); + + __lwp_thread_exit(exec->wait.ret_arg); +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_handler(%p): thread returned(%p)\n",exec,exec->wait.ret_arg); +#endif +} + +void __lwp_rotate_readyqueue(u32 prio) +{ + u32 level; + lwp_cntrl *exec; + lwp_queue *ready; + lwp_node *node; + + ready = &_lwp_thr_ready[prio]; + exec = _thr_executing; + + if(ready==exec->ready) { + __lwp_thread_yield(); + return; + } + + _CPU_ISR_Disable(level); + if(!__lwp_queue_isempty(ready) && !__lwp_queue_onenode(ready)) { + node = __lwp_queue_firstnodeI(ready); + __lwp_queue_appendI(ready,node); + } + _CPU_ISR_Flash(level); + + if(_thr_heir->ready==ready) + _thr_heir = (lwp_cntrl*)ready->first; + + if(exec!=_thr_heir) + _context_switch_want = TRUE; + +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_rotate_readyqueue(%d,%p,%p)\n",prio,exec,_thr_heir); +#endif + _CPU_ISR_Restore(level); +} + +void __lwp_thread_yield() +{ + u32 level; + lwp_cntrl *exec; + lwp_queue *ready; + + exec = _thr_executing; + ready = exec->ready; + + _CPU_ISR_Disable(level); + if(!__lwp_queue_onenode(ready)) { + __lwp_queue_extractI(&exec->object.node); + __lwp_queue_appendI(ready,&exec->object.node); + _CPU_ISR_Flash(level); + if(__lwp_thread_isheir(exec)) + _thr_heir = (lwp_cntrl*)ready->first; + _context_switch_want = TRUE; + } else if(!__lwp_thread_isheir(exec)) + _context_switch_want = TRUE; + _CPU_ISR_Restore(level); +} + +void __lwp_thread_resettimeslice() +{ + u32 level; + lwp_cntrl *exec; + lwp_queue *ready; + + exec = _thr_executing; + ready = exec->ready; + + _CPU_ISR_Disable(level); + if(__lwp_queue_onenode(ready)) { + _CPU_ISR_Restore(level); + return; + } + + __lwp_queue_extractI(&exec->object.node); + __lwp_queue_appendI(ready,&exec->object.node); + + _CPU_ISR_Flash(level); + + if(__lwp_thread_isheir(exec)) + _thr_heir = (lwp_cntrl*)ready->first; + + _context_switch_want = TRUE; + _CPU_ISR_Restore(level); +} + +void __lwp_thread_setstate(lwp_cntrl *thethread,u32 state) +{ + u32 level; + lwp_queue *ready; + + ready = thethread->ready; +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_setstate(%d,%p,%p,%08x)\n",_context_switch_want,_thr_heir,thethread,thethread->cur_state); +#endif + _CPU_ISR_Disable(level); + if(!__lwp_stateready(thethread->cur_state)) { + thethread->cur_state = __lwp_clearstate(thethread->cur_state,state); + _CPU_ISR_Restore(level); + return; + } + + thethread->cur_state = state; + if(__lwp_queue_onenode(ready)) { + __lwp_queue_init_empty(ready); + __lwp_priomap_removefrom(&thethread->priomap); + } else + __lwp_queue_extractI(&thethread->object.node); + _CPU_ISR_Flash(level); + + if(__lwp_thread_isheir(thethread)) + __lwp_thread_calcheir(); + if(__lwp_thread_isexec(thethread)) + _context_switch_want = TRUE; +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_setstate(%d,%p,%p,%08x)\n",_context_switch_want,_thr_heir,thethread,thethread->cur_state); +#endif + _CPU_ISR_Restore(level); +} + +void __lwp_thread_clearstate(lwp_cntrl *thethread,u32 state) +{ + u32 level,cur_state; + + _CPU_ISR_Disable(level); + + cur_state = thethread->cur_state; + if(cur_state&state) { + cur_state = thethread->cur_state = __lwp_clearstate(cur_state,state); + if(__lwp_stateready(cur_state)) { + __lwp_priomap_addto(&thethread->priomap); + __lwp_queue_appendI(thethread->ready,&thethread->object.node); + _CPU_ISR_Flash(level); + + if(thethread->cur_prio<_thr_heir->cur_prio) { + _thr_heir = thethread; + if(_thr_executing->is_preemptible + || thethread->cur_prio==0) + _context_switch_want = TRUE; + } + } + } + + _CPU_ISR_Restore(level); +} + +u32 __lwp_evaluatemode() +{ + lwp_cntrl *exec; + + exec = _thr_executing; + if(!__lwp_stateready(exec->cur_state) + || (!__lwp_thread_isheir(exec) && exec->is_preemptible)){ + _context_switch_want = TRUE; + return TRUE; + } + return FALSE; +} + +void __lwp_thread_changepriority(lwp_cntrl *thethread,u32 prio,u32 prependit) +{ + u32 level; + + __lwp_thread_settransient(thethread); + + if(thethread->cur_prio!=prio) + __lwp_thread_setpriority(thethread,prio); + + _CPU_ISR_Disable(level); + + thethread->cur_state = __lwp_clearstate(thethread->cur_state,LWP_STATES_TRANSIENT); + if(!__lwp_stateready(thethread->cur_state)) { + _CPU_ISR_Restore(level); + return; + } + + __lwp_priomap_addto(&thethread->priomap); + if(prependit) + __lwp_queue_prependI(thethread->ready,&thethread->object.node); + else + __lwp_queue_appendI(thethread->ready,&thethread->object.node); + + _CPU_ISR_Flash(level); + + __lwp_thread_calcheir(); + + if(!(_thr_executing==_thr_heir) + && _thr_executing->is_preemptible) + _context_switch_want = TRUE; + + _CPU_ISR_Restore(level); +} + +void __lwp_thread_setpriority(lwp_cntrl *thethread,u32 prio) +{ + thethread->cur_prio = prio; + thethread->ready = &_lwp_thr_ready[prio]; + __lwp_priomap_init(&thethread->priomap,prio); +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_setpriority(%p,%d,%p)\n",thethread,prio,thethread->ready); +#endif +} + +void __lwp_thread_suspend(lwp_cntrl *thethread) +{ + u32 level; + lwp_queue *ready; + + ready = thethread->ready; + + _CPU_ISR_Disable(level); + thethread->suspendcnt++; + if(!__lwp_stateready(thethread->cur_state)) { + thethread->cur_state = __lwp_setstate(thethread->cur_state,LWP_STATES_SUSPENDED); + _CPU_ISR_Restore(level); + return; + } + + thethread->cur_state = LWP_STATES_SUSPENDED; + if(__lwp_queue_onenode(ready)) { + __lwp_queue_init_empty(ready); + __lwp_priomap_removefrom(&thethread->priomap); + } else { + __lwp_queue_extractI(&thethread->object.node); + } + _CPU_ISR_Flash(level); + + if(__lwp_thread_isheir(thethread)) + __lwp_thread_calcheir(); + + if(__lwp_thread_isexec(thethread)) + _context_switch_want = TRUE; + + _CPU_ISR_Restore(level); +} + +void __lwp_thread_settransient(lwp_cntrl *thethread) +{ + u32 level,oldstates; + lwp_queue *ready; + + ready = thethread->ready; + + _CPU_ISR_Disable(level); + + oldstates = thethread->cur_state; + thethread->cur_state = __lwp_setstate(oldstates,LWP_STATES_TRANSIENT); + + if(__lwp_stateready(oldstates)) { + if(__lwp_queue_onenode(ready)) { + __lwp_queue_init_empty(ready); + __lwp_priomap_removefrom(&thethread->priomap); + } else { + __lwp_queue_extractI(&thethread->object.node); + } + } + + _CPU_ISR_Restore(level); +} + +void __lwp_thread_resume(lwp_cntrl *thethread,u32 force) +{ + u32 level,state; + + _CPU_ISR_Disable(level); + + if(force==TRUE) + thethread->suspendcnt = 0; + else + thethread->suspendcnt--; + + if(thethread->suspendcnt>0) { + _CPU_ISR_Restore(level); + return; + } + + state = thethread->cur_state; + if(state&LWP_STATES_SUSPENDED) { + state = thethread->cur_state = __lwp_clearstate(thethread->cur_state,LWP_STATES_SUSPENDED); + if(__lwp_stateready(state)) { + __lwp_priomap_addto(&thethread->priomap); + __lwp_queue_appendI(thethread->ready,&thethread->object.node); + _CPU_ISR_Flash(level); + if(thethread->cur_prio<_thr_heir->cur_prio) { + _thr_heir = thethread; + if(_thr_executing->is_preemptible + || thethread->cur_prio==0) + _context_switch_want = TRUE; + } + } + } + _CPU_ISR_Restore(level); +} + +void __lwp_thread_loadenv(lwp_cntrl *thethread) +{ + u32 stackbase,sp,size; + u32 r2,r13,msr_value; + + thethread->context.FPSCR = 0x000000f8; + + stackbase = (u32)thethread->stack; + size = thethread->stack_size; + + // tag both bottom & head of stack + *((u32*)stackbase) = 0xDEADBABE; + sp = stackbase+size-CPU_MINIMUM_STACK_FRAME_SIZE; + sp &= ~(CPU_STACK_ALIGNMENT-1); + *((u32*)sp) = 0; + + thethread->context.GPR[1] = sp; + + msr_value = (MSR_ME|MSR_IR|MSR_DR|MSR_RI); + if(!(thethread->isr_level&CPU_MODES_INTERRUPT_MASK)) + msr_value |= MSR_EE; + + thethread->context.MSR = msr_value; + thethread->context.LR = (u32)__lwp_thread_handler; + + __asm__ __volatile__ ("mr %0,2; mr %1,13" : "=r" ((r2)), "=r" ((r13))); + thethread->context.GPR[2] = r2; + thethread->context.GPR[13] = r13; + +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_loadenv(%p,%p,%d,%p)\n",thethread,(void*)stackbase,size,(void*)sp); +#endif + +} + +void __lwp_thread_ready(lwp_cntrl *thethread) +{ + u32 level; + lwp_cntrl *heir; + + _CPU_ISR_Disable(level); +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_ready(%p)\n",thethread); +#endif + thethread->cur_state = LWP_STATES_READY; + __lwp_priomap_addto(&thethread->priomap); + __lwp_queue_appendI(thethread->ready,&thethread->object.node); + _CPU_ISR_Flash(level); + + __lwp_thread_calcheir(); + heir = _thr_heir; + if(!(__lwp_thread_isexec(heir)) && _thr_executing->is_preemptible) + _context_switch_want = TRUE; + + _CPU_ISR_Restore(level); +} + +u32 __lwp_thread_init(lwp_cntrl *thethread,void *stack_area,u32 stack_size,u32 prio,u32 isr_level,bool is_preemtible) +{ + u32 act_stack_size = 0; + +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_init(%p,%p,%d,%d,%d)\n",thethread,stack_area,stack_size,prio,isr_level); +#endif + + if(!stack_area) { + if(!__lwp_stack_isenough(stack_size)) + act_stack_size = CPU_MINIMUM_STACK_SIZE; + else + act_stack_size = stack_size; + + act_stack_size = __lwp_stack_allocate(thethread,act_stack_size); + if(!act_stack_size) return 0; + + thethread->stack_allocated = TRUE; + } else { + thethread->stack = stack_area; + act_stack_size = stack_size; + thethread->stack_allocated = FALSE; + } + thethread->stack_size = act_stack_size; + + __lwp_threadqueue_init(&thethread->join_list,LWP_THREADQ_MODEFIFO,LWP_STATES_WAITING_FOR_JOINATEXIT,0); + + memset(&thethread->context,0,sizeof(thethread->context)); + memset(&thethread->wait,0,sizeof(thethread->wait)); + + thethread->budget_algo = (prio<128 ? LWP_CPU_BUDGET_ALGO_NONE : LWP_CPU_BUDGET_ALGO_TIMESLICE); + thethread->is_preemptible = is_preemtible; + thethread->isr_level = isr_level; + thethread->real_prio = prio; + thethread->cur_state = LWP_STATES_DORMANT; + thethread->cpu_time_budget = _lwp_ticks_per_timeslice; + thethread->suspendcnt = 0; + thethread->res_cnt = 0; + __lwp_thread_setpriority(thethread,prio); + + __libc_create_hook(_thr_executing,thethread); + + return 1; +} + +void __lwp_thread_close(lwp_cntrl *thethread) +{ + u32 level; + void **value_ptr; + lwp_cntrl *p; + + __lwp_thread_setstate(thethread,LWP_STATES_TRANSIENT); + + if(!__lwp_threadqueue_extractproxy(thethread)) { + if(__lwp_wd_isactive(&thethread->timer)) + __lwp_wd_remove_ticks(&thethread->timer); + } + + _CPU_ISR_Disable(level); + value_ptr = (void**)thethread->wait.ret_arg; + while((p=__lwp_threadqueue_dequeue(&thethread->join_list))!=NULL) { + *(void**)p->wait.ret_arg = value_ptr; + } + thethread->cpu_time_budget = 0; + thethread->budget_algo = LWP_CPU_BUDGET_ALGO_NONE; + _CPU_ISR_Restore(level); + + __libc_delete_hook(_thr_executing,thethread); + + if(__lwp_thread_isallocatedfp(thethread)) + __lwp_thread_deallocatefp(); + + __lwp_stack_free(thethread); + + __lwp_objmgr_close(thethread->object.information,&thethread->object); + __lwp_objmgr_free(thethread->object.information,&thethread->object); +} + +void __lwp_thread_closeall() +{ + u32 i,level; + lwp_queue *header; + lwp_cntrl *ptr,*next; +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_closeall(enter)\n"); +#endif + _CPU_ISR_Disable(level); + for(i=0;ifirst; + while(ptr!=(lwp_cntrl*)__lwp_queue_tail(&_lwp_thr_ready[i])) { + next = (lwp_cntrl*)ptr->object.node.next; + if(ptr!=_thr_executing) + __lwp_thread_close(ptr); + + ptr = next; + } + } + _CPU_ISR_Restore(level); +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_closeall(leave)\n"); +#endif +} + +void __lwp_thread_exit(void *value_ptr) +{ + __lwp_thread_dispatchdisable(); + _thr_executing->wait.ret_arg = (u32*)value_ptr; + __lwp_thread_close(_thr_executing); + __lwp_thread_dispatchenable(); +} + +u32 __lwp_thread_start(lwp_cntrl *thethread,void* (*entry)(void*),void *arg) +{ +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_thread_start(%p,%p,%p,%d)\n",thethread,entry,arg,thethread->cur_state); +#endif + if(__lwp_statedormant(thethread->cur_state)) { + thethread->entry = entry; + thethread->arg = arg; + __lwp_thread_loadenv(thethread); + __lwp_thread_ready(thethread); + __libc_start_hook(_thr_executing,thethread); + return 1; + } + return 0; +} + +void __lwp_thread_startmultitasking() +{ + _lwp_exitfunc = NULL; + + __sys_state_set(SYS_STATE_BEGIN_MT); + __sys_state_set(SYS_STATE_UP); + + _context_switch_want = FALSE; + _thr_executing = _thr_heir; +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_start_multitasking(%p,%p)\n",_thr_executing,_thr_heir); +#endif + __lwp_thread_starttimeslice(); + _cpu_context_switch((void*)&core_context,(void*)&_thr_heir->context); + + if(_lwp_exitfunc) _lwp_exitfunc(); +} + +void __lwp_thread_stopmultitasking(void (*exitfunc)()) +{ + _lwp_exitfunc = exitfunc; + if(__sys_state_get()!=SYS_STATE_SHUTDOWN) { + __lwp_thread_stoptimeslice(); + __sys_state_set(SYS_STATE_SHUTDOWN); + _cpu_context_switch((void*)&_thr_executing->context,(void*)&core_context); + } +} + +void __lwp_thread_coreinit() +{ + u32 index; + +#ifdef _LWPTHREADS_DEBUG + kprintf("__lwp_sys_init()\n\n"); +#endif + __lwp_thread_dispatchinitialize(); + __lwp_thread_inittimeslice(); + + _context_switch_want = FALSE; + _thr_executing = NULL; + _thr_heir = NULL; + _thr_allocated_fp = NULL; + _lwp_ticks_per_timeslice = 10; + + memset(&core_context,0,sizeof(core_context)); + + for(index=0;index<=LWP_PRIO_MAX;index++) + __lwp_queue_init_empty(&_lwp_thr_ready[index]); + + __sys_state_set(SYS_STATE_BEFORE_MT); +} + diff --git a/wii/libogc/libogc/lwp_threads.inl b/wii/libogc/libogc/lwp_threads.inl new file mode 100644 index 0000000000..b6a7278eff --- /dev/null +++ b/wii/libogc/libogc/lwp_threads.inl @@ -0,0 +1,90 @@ +#ifndef __LWP_INL__ +#define __LWP_INL__ + +static __inline__ u32 __lwp_thread_isexec(lwp_cntrl *thethread) +{ + return (thethread==_thr_executing); +} + +static __inline__ u32 __lwp_thread_isheir(lwp_cntrl *thethread) +{ + return (thethread==_thr_heir); +} + +static __inline__ void __lwp_thread_calcheir() +{ + _thr_heir = (lwp_cntrl*)_lwp_thr_ready[__lwp_priomap_highest()].first; +} + +static __inline__ u32 __lwp_thread_isallocatedfp(lwp_cntrl *thethread) +{ + return (thethread==_thr_allocated_fp); +} + +static __inline__ void __lwp_thread_deallocatefp() +{ + _thr_allocated_fp = NULL; +} + +static __inline__ void __lwp_thread_dispatchinitialize() +{ + _thread_dispatch_disable_level = 1; +} + +static __inline__ void __lwp_thread_dispatchenable() +{ + if((--_thread_dispatch_disable_level)==0) + __thread_dispatch(); +} + +static __inline__ void __lwp_thread_dispatchdisable() +{ + ++_thread_dispatch_disable_level; +} + +static __inline__ void __lwp_thread_dispatchunnest() +{ + --_thread_dispatch_disable_level; +} + +static __inline__ void __lwp_thread_unblock(lwp_cntrl *thethread) +{ + __lwp_thread_clearstate(thethread,LWP_STATES_BLOCKED); +} + +static __inline__ void** __lwp_thread_getlibcreent() +{ + return __lwp_thr_libc_reent; +} + +static __inline__ void __lwp_thread_setlibcreent(void **libc_reent) +{ + __lwp_thr_libc_reent = libc_reent; +} + +static __inline__ bool __lwp_thread_isswitchwant() +{ + + return _context_switch_want; +} + +static __inline__ bool __lwp_thread_isdispatchenabled() +{ + return (_thread_dispatch_disable_level==0); +} + +static __inline__ void __lwp_thread_inittimeslice() +{ + __lwp_wd_initialize(&_lwp_wd_timeslice,__lwp_thread_tickle_timeslice,LWP_TIMESLICE_TIMER_ID,NULL); +} + +static __inline__ void __lwp_thread_starttimeslice() +{ + __lwp_wd_insert_ticks(&_lwp_wd_timeslice,millisecs_to_ticks(1)); +} + +static __inline__ void __lwp_thread_stoptimeslice() +{ + __lwp_wd_remove_ticks(&_lwp_wd_timeslice); +} +#endif diff --git a/wii/libogc/libogc/lwp_watchdog.c b/wii/libogc/libogc/lwp_watchdog.c new file mode 100644 index 0000000000..63390bb358 --- /dev/null +++ b/wii/libogc/libogc/lwp_watchdog.c @@ -0,0 +1,192 @@ +#include +#include +#include "asm.h" +#include "lwp_threads.h" +#include "lwp_watchdog.h" + +//#define _LWPWD_DEBUG + +#ifdef _LWPWD_DEBUG +#include +#endif + +vu32 _wd_sync_level; +vu32 _wd_sync_count; +u32 _wd_ticks_since_boot; + +lwp_queue _wd_ticks_queue; + +static void __lwp_wd_settimer(wd_cntrl *wd) +{ + u64 now; + s64 diff; + union uulc { + u64 ull; + u32 ul[2]; + } v; + + now = gettime(); + v.ull = diff = diff_ticks(now,wd->fire); +#ifdef _LWPWD_DEBUG + printf("__lwp_wd_settimer(%p,%llu,%lld)\n",wd,wd->fire,diff); +#endif + if(diff<=0) { +#ifdef _LWPWD_DEBUG + printf(" __lwp_wd_settimer(0): %lld<=0\n",diff); +#endif + wd->fire = 0; + mtdec(0); + } else if(diff<0x0000000080000000LL) { +#ifdef _LWPWD_DEBUG + printf("__lwp_wd_settimer(%d): %lld<0x0000000080000000LL\n",v.ul[1],diff); +#endif + mtdec(v.ul[1]); + } else { +#ifdef _LWPWD_DEBUG + printf("__lwp_wd_settimer(0x7fffffff)\n"); +#endif + mtdec(0x7fffffff); + } +} + +void __lwp_watchdog_init() +{ + _wd_sync_level = 0; + _wd_sync_count = 0; + _wd_ticks_since_boot = 0; + + __lwp_queue_init_empty(&_wd_ticks_queue); +} + +void __lwp_wd_insert(lwp_queue *header,wd_cntrl *wd) +{ + u32 level; + u64 fire; + u32 isr_nest_level; + wd_cntrl *after; +#ifdef _LWPWD_DEBUG + printf("__lwp_wd_insert(%p,%llu,%llu)\n",wd,wd->start,wd->fire); +#endif + isr_nest_level = __lwp_isr_in_progress(); + wd->state = LWP_WD_INSERTED; + + _wd_sync_count++; +restart: + _CPU_ISR_Disable(level); + fire = wd->fire; + for(after=__lwp_wd_first(header);;after=__lwp_wd_next(after)) { + if(fire==0 || !__lwp_wd_next(after)) break; + if(firefire) break; + + _CPU_ISR_Flash(level); + if(wd->state!=LWP_WD_INSERTED) goto exit_insert; + if(_wd_sync_level>isr_nest_level) { + _wd_sync_level = isr_nest_level; + _CPU_ISR_Restore(level); + goto restart; + } + } + __lwp_wd_activate(wd); + wd->fire = fire; + __lwp_queue_insertI(after->node.prev,&wd->node); + if(__lwp_wd_first(header)==wd) __lwp_wd_settimer(wd); + +exit_insert: + _wd_sync_level = isr_nest_level; + _wd_sync_count--; + _CPU_ISR_Restore(level); + return; +} + +u32 __lwp_wd_remove(lwp_queue *header,wd_cntrl *wd) +{ + u32 level; + u32 prev_state; + wd_cntrl *next; +#ifdef _LWPWD_DEBUG + printf("__lwp_wd_remove(%p)\n",wd); +#endif + _CPU_ISR_Disable(level); + prev_state = wd->state; + switch(prev_state) { + case LWP_WD_INACTIVE: + break; + case LWP_WD_INSERTED: + wd->state = LWP_WD_INACTIVE; + break; + case LWP_WD_ACTIVE: + case LWP_WD_REMOVE: + wd->state = LWP_WD_INACTIVE; + next = __lwp_wd_next(wd); + if(_wd_sync_count) _wd_sync_level = __lwp_isr_in_progress(); + __lwp_queue_extractI(&wd->node); + if(!__lwp_queue_isempty(header) && __lwp_wd_first(header)==next) __lwp_wd_settimer(next); + break; + } + _CPU_ISR_Restore(level); + return prev_state; +} + +void __lwp_wd_tickle(lwp_queue *queue) +{ + wd_cntrl *wd; + u64 now; + s64 diff; + + if(__lwp_queue_isempty(queue)) return; + + wd = __lwp_wd_first(queue); + now = gettime(); + diff = diff_ticks(now,wd->fire); +#ifdef _LWPWD_DEBUG + printf("__lwp_wd_tickle(%p,%08x%08x,%08x%08x,%08x%08x,%08x%08x)\n",wd,(u32)(now>>32),(u32)now,(u32)(wd->start>>32),(u32)wd->start,(u32)(wd->fire>>32),(u32)wd->fire,(u32)(diff>>32),(u32)diff); +#endif + if(diff<=0) { + do { + switch(__lwp_wd_remove(queue,wd)) { + case LWP_WD_ACTIVE: + wd->routine(wd->usr_data); + break; + case LWP_WD_INACTIVE: + break; + case LWP_WD_INSERTED: + break; + case LWP_WD_REMOVE: + break; + } + wd = __lwp_wd_first(queue); + } while(!__lwp_queue_isempty(queue) && wd->fire==0); + } else { + __lwp_wd_reset(wd); + } +} + +void __lwp_wd_adjust(lwp_queue *queue,u32 dir,s64 interval) +{ + u32 level; + u64 abs_int; + + _CPU_ISR_Disable(level); + abs_int = gettime()+LWP_WD_ABS(interval); + if(!__lwp_queue_isempty(queue)) { + switch(dir) { + case LWP_WD_BACKWARD: + __lwp_wd_first(queue)->fire += LWP_WD_ABS(interval); + break; + case LWP_WD_FORWARD: + while(abs_int) { + if(abs_int<__lwp_wd_first(queue)->fire) { + __lwp_wd_first(queue)->fire -= LWP_WD_ABS(interval); + break; + } else { + abs_int -= __lwp_wd_first(queue)->fire; + __lwp_wd_first(queue)->fire = gettime(); + __lwp_wd_tickle(queue); + if(__lwp_queue_isempty(queue)) break; + } + } + break; + } + } + _CPU_ISR_Restore(level); +} diff --git a/wii/libogc/libogc/lwp_watchdog.inl b/wii/libogc/libogc/lwp_watchdog.inl new file mode 100644 index 0000000000..5216e10996 --- /dev/null +++ b/wii/libogc/libogc/lwp_watchdog.inl @@ -0,0 +1,84 @@ +#ifndef __LWP_WATCHDOG_INL__ +#define __LWP_WATCHDOG_INL__ + +static __inline__ void __lwp_wd_initialize(wd_cntrl *wd,wd_service_routine routine,u32 id,void *usr_data) +{ + wd->state = LWP_WD_INACTIVE; + wd->id = id; + wd->routine = routine; + wd->usr_data = usr_data; +} + +static __inline__ wd_cntrl* __lwp_wd_first(lwp_queue *queue) +{ + return (wd_cntrl*)queue->first; +} + +static __inline__ wd_cntrl* __lwp_wd_last(lwp_queue *queue) +{ + return (wd_cntrl*)queue->last; +} + +static __inline__ wd_cntrl* __lwp_wd_next(wd_cntrl *wd) +{ + return (wd_cntrl*)wd->node.next; +} + +static __inline__ wd_cntrl* __lwp_wd_prev(wd_cntrl *wd) +{ + return (wd_cntrl*)wd->node.prev; +} + +static __inline__ void __lwp_wd_activate(wd_cntrl *wd) +{ + wd->state = LWP_WD_ACTIVE; +} + +static __inline__ void __lwp_wd_deactivate(wd_cntrl *wd) +{ + wd->state = LWP_WD_REMOVE; +} + +static __inline__ u32 __lwp_wd_isactive(wd_cntrl *wd) +{ + return (wd->state==LWP_WD_ACTIVE); +} + +static __inline__ u64 __lwp_wd_calc_ticks(const struct timespec *time) +{ + u64 ticks; + + ticks = secs_to_ticks(time->tv_sec); + ticks += nanosecs_to_ticks(time->tv_nsec); + + return ticks; +} + +static __inline__ void __lwp_wd_tickle_ticks() +{ + __lwp_wd_tickle(&_wd_ticks_queue); +} + +static __inline__ void __lwp_wd_insert_ticks(wd_cntrl *wd,s64 interval) +{ + wd->start = gettime(); + wd->fire = (wd->start+LWP_WD_ABS(interval)); + __lwp_wd_insert(&_wd_ticks_queue,wd); +} + +static __inline__ void __lwp_wd_adjust_ticks(u32 dir,s64 interval) +{ + __lwp_wd_adjust(&_wd_ticks_queue,dir,interval); +} + +static __inline__ void __lwp_wd_remove_ticks(wd_cntrl *wd) +{ + __lwp_wd_remove(&_wd_ticks_queue,wd); +} + +static __inline__ void __lwp_wd_reset(wd_cntrl *wd) +{ + __lwp_wd_remove(&_wd_ticks_queue,wd); + __lwp_wd_insert(&_wd_ticks_queue,wd); +} +#endif diff --git a/wii/libogc/libogc/lwp_wkspace.c b/wii/libogc/libogc/lwp_wkspace.c new file mode 100644 index 0000000000..a9d92d4968 --- /dev/null +++ b/wii/libogc/libogc/lwp_wkspace.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include "system.h" +#include "lwp_wkspace.h" + +#define ROUND32UP(v) (((u32)(v)+31)&~31) + +heap_cntrl __wkspace_heap; +static heap_iblock __wkspace_iblock; +static u32 __wkspace_heap_size = 0; + +u32 __lwp_wkspace_heapsize() +{ + return __wkspace_heap_size; +} + +u32 __lwp_wkspace_heapfree() +{ + __lwp_heap_getinfo(&__wkspace_heap,&__wkspace_iblock); + return __wkspace_iblock.free_size; +} + +u32 __lwp_wkspace_heapused() +{ + __lwp_heap_getinfo(&__wkspace_heap,&__wkspace_iblock); + return __wkspace_iblock.used_size; +} + +void __lwp_wkspace_init(u32 size) +{ + u32 arLo,level,dsize; + + // Get current ArenaLo and adjust to 32-byte boundary + _CPU_ISR_Disable(level); + arLo = ROUND32UP(SYS_GetArenaLo()); + dsize = (size - (arLo - (u32)SYS_GetArenaLo())); + SYS_SetArenaLo((void*)(arLo+dsize)); + _CPU_ISR_Restore(level); + + memset((void*)arLo,0,dsize); + __wkspace_heap_size += __lwp_heap_init(&__wkspace_heap,(void*)arLo,dsize,PPC_ALIGNMENT); +} diff --git a/wii/libogc/libogc/lwp_wkspace.inl b/wii/libogc/libogc/lwp_wkspace.inl new file mode 100644 index 0000000000..4aa8f0faf0 --- /dev/null +++ b/wii/libogc/libogc/lwp_wkspace.inl @@ -0,0 +1,14 @@ +#ifndef __LWP_WKSPACE_INL__ +#define __LWP_WKSPACE_INL__ + +static __inline__ void* __lwp_wkspace_allocate(u32 size) +{ + return __lwp_heap_allocate(&__wkspace_heap,size); +} + +static __inline__ BOOL __lwp_wkspace_free(void *ptr) +{ + return __lwp_heap_free(&__wkspace_heap,ptr); +} + +#endif diff --git a/wii/libogc/libogc/malloc_lock.c b/wii/libogc/libogc/malloc_lock.c new file mode 100644 index 0000000000..c907f86171 --- /dev/null +++ b/wii/libogc/libogc/malloc_lock.c @@ -0,0 +1,81 @@ +#include <_ansi.h> +#include <_syslist.h> +#ifndef REENTRANT_SYSCALLS_PROVIDED +#include +#endif +#include +#undef errno +extern int errno; + +#include "asm.h" +#include "processor.h" +#include "lwp_mutex.h" + +#define MEMLOCK_MUTEX_ID 0x00030040 + +static int initialized = 0; +static lwp_mutex mem_lock; + +void __memlock_init() +{ + __lwp_thread_dispatchdisable(); + if(!initialized) { + lwp_mutex_attr attr; + + initialized = 1; + + attr.mode = LWP_MUTEX_FIFO; + attr.nest_behavior = LWP_MUTEX_NEST_ACQUIRE; + attr.onlyownerrelease = TRUE; + attr.prioceil = 1; + __lwp_mutex_initialize(&mem_lock,&attr,LWP_MUTEX_UNLOCKED); + } + __lwp_thread_dispatchunnest(); +} + +#ifndef REENTRANT_SYSCALLS_PROVIDED +void _DEFUN(__libogc_malloc_lock,(r), + struct _reent *r) +{ + u32 level; + + if(!initialized) return; + + _CPU_ISR_Disable(level); + __lwp_mutex_seize(&mem_lock,MEMLOCK_MUTEX_ID,TRUE,LWP_THREADQ_NOTIMEOUT,level); +} + +void _DEFUN(__libogc_malloc_unlock,(r), + struct _reent *r) +{ + if(!initialized) return; + + __lwp_thread_dispatchdisable(); + __lwp_mutex_surrender(&mem_lock); + __lwp_thread_dispatchenable(); +} + +#else +void _DEFUN(__libogc_malloc_lock,(ptr), + struct _reent *ptr) +{ + unsigned int level; + + if(!initialized) return; + + _CPU_ISR_Disable(level); + __lwp_mutex_seize(&mem_lock,MEMLOCK_MUTEX_ID,TRUE,LWP_THREADQ_NOTIMEOUT,level); + ptr->_errno = _thr_executing->wait.ret_code; +} + +void _DEFUN(__libogc_malloc_unlock,(ptr), + struct _reent *ptr) +{ + if(!initialized) return; + + __lwp_thread_dispatchdisable(); + ptr->_errno = __lwp_mutex_surrender(&mem_lock); + __lwp_thread_dispatchenable(); +} + +#endif diff --git a/wii/libogc/libogc/message.c b/wii/libogc/libogc/message.c new file mode 100644 index 0000000000..4a529de321 --- /dev/null +++ b/wii/libogc/libogc/message.c @@ -0,0 +1,167 @@ +/*------------------------------------------------------------- + +message.c -- Thread subsystem II + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include +#include "message.h" + +#define LWP_OBJTYPE_MBOX 6 + +#define LWP_CHECK_MBOX(hndl) \ +{ \ + if(((hndl)==MQ_BOX_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_MBOX)) \ + return NULL; \ +} + +typedef struct _mqbox_st +{ + lwp_obj object; + mq_cntrl mqueue; +} mqbox_st; + +lwp_objinfo _lwp_mqbox_objects; + +void __lwp_mqbox_init() +{ + __lwp_objmgr_initinfo(&_lwp_mqbox_objects,LWP_MAX_MQUEUES,sizeof(mqbox_st)); +} + +static __inline__ mqbox_st* __lwp_mqbox_open(mqbox_t mbox) +{ + LWP_CHECK_MBOX(mbox); + return (mqbox_st*)__lwp_objmgr_get(&_lwp_mqbox_objects,LWP_OBJMASKID(mbox)); +} + +static __inline__ void __lwp_mqbox_free(mqbox_st *mqbox) +{ + __lwp_objmgr_close(&_lwp_mqbox_objects,&mqbox->object); + __lwp_objmgr_free(&_lwp_mqbox_objects,&mqbox->object); +} + +static mqbox_st* __lwp_mqbox_allocate() +{ + mqbox_st *mqbox; + + __lwp_thread_dispatchdisable(); + mqbox = (mqbox_st*)__lwp_objmgr_allocate(&_lwp_mqbox_objects); + if(mqbox) { + __lwp_objmgr_open(&_lwp_mqbox_objects,&mqbox->object); + return mqbox; + } + __lwp_thread_dispatchenable(); + return NULL; +} + +s32 MQ_Init(mqbox_t *mqbox,u32 count) +{ + mq_attr attr; + mqbox_st *ret = NULL; + + if(!mqbox) return -1; + + ret = __lwp_mqbox_allocate(); + if(!ret) return MQ_ERROR_TOOMANY; + + attr.mode = LWP_MQ_FIFO; + if(!__lwpmq_initialize(&ret->mqueue,&attr,count,sizeof(mqmsg_t))) { + __lwp_mqbox_free(ret); + __lwp_thread_dispatchenable(); + return MQ_ERROR_TOOMANY; + } + + *mqbox = (mqbox_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_MBOX)|LWP_OBJMASKID(ret->object.id)); + __lwp_thread_dispatchenable(); + return MQ_ERROR_SUCCESSFUL; +} + +void MQ_Close(mqbox_t mqbox) +{ + mqbox_st *mbox; + + mbox = __lwp_mqbox_open(mqbox); + if(!mbox) return; + + __lwpmq_close(&mbox->mqueue,0); + __lwp_thread_dispatchenable(); + + __lwp_mqbox_free(mbox); +} + +BOOL MQ_Send(mqbox_t mqbox,mqmsg_t msg,u32 flags) +{ + BOOL ret; + mqbox_st *mbox; + u32 wait = (flags==MQ_MSG_BLOCK)?TRUE:FALSE; + + mbox = __lwp_mqbox_open(mqbox); + if(!mbox) return FALSE; + + ret = FALSE; + if(__lwpmq_submit(&mbox->mqueue,mbox->object.id,(void*)&msg,sizeof(mqmsg_t),LWP_MQ_SEND_REQUEST,wait,LWP_THREADQ_NOTIMEOUT)==LWP_MQ_STATUS_SUCCESSFUL) ret = TRUE; + __lwp_thread_dispatchenable(); + + return ret; +} + +BOOL MQ_Receive(mqbox_t mqbox,mqmsg_t *msg,u32 flags) +{ + BOOL ret; + mqbox_st *mbox; + u32 tmp,wait = (flags==MQ_MSG_BLOCK)?TRUE:FALSE; + + mbox = __lwp_mqbox_open(mqbox); + if(!mbox) return FALSE; + + ret = FALSE; + if(__lwpmq_seize(&mbox->mqueue,mbox->object.id,(void*)msg,&tmp,wait,LWP_THREADQ_NOTIMEOUT)==LWP_MQ_STATUS_SUCCESSFUL) ret = TRUE; + __lwp_thread_dispatchenable(); + + return ret; +} + +BOOL MQ_Jam(mqbox_t mqbox,mqmsg_t msg,u32 flags) +{ + BOOL ret; + mqbox_st *mbox; + u32 wait = (flags==MQ_MSG_BLOCK)?TRUE:FALSE; + + mbox = __lwp_mqbox_open(mqbox); + if(!mbox) return FALSE; + + ret = FALSE; + if(__lwpmq_submit(&mbox->mqueue,mbox->object.id,(void*)&msg,sizeof(mqmsg_t),LWP_MQ_SEND_URGENT,wait,LWP_THREADQ_NOTIMEOUT)==LWP_MQ_STATUS_SUCCESSFUL) ret = TRUE; + __lwp_thread_dispatchenable(); + + return ret; +} diff --git a/wii/libogc/libogc/mutex.c b/wii/libogc/libogc/mutex.c new file mode 100644 index 0000000000..546dad1402 --- /dev/null +++ b/wii/libogc/libogc/mutex.c @@ -0,0 +1,160 @@ +/*------------------------------------------------------------- + +mutex.c -- Thread subsystem III + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include +#include +#include "asm.h" +#include "lwp_mutex.h" +#include "lwp_objmgr.h" +#include "lwp_config.h" +#include "mutex.h" + +#define LWP_OBJTYPE_MUTEX 3 + +#define LWP_CHECK_MUTEX(hndl) \ +{ \ + if(((hndl)==LWP_MUTEX_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_MUTEX)) \ + return NULL; \ +} + +typedef struct _mutex_st +{ + lwp_obj object; + lwp_mutex mutex; +} mutex_st; + +lwp_objinfo _lwp_mutex_objects; + +static s32 __lwp_mutex_locksupp(mutex_t lock,u32 timeout,u8 block) +{ + u32 level; + mutex_st *p; + + if(lock==LWP_MUTEX_NULL || LWP_OBJTYPE(lock)!=LWP_OBJTYPE_MUTEX) return -1; + + p = (mutex_st*)__lwp_objmgr_getisrdisable(&_lwp_mutex_objects,LWP_OBJMASKID(lock),&level); + if(!p) return -1; + + __lwp_mutex_seize(&p->mutex,p->object.id,block,timeout,level); + return _thr_executing->wait.ret_code; +} + +void __lwp_mutex_init() +{ + __lwp_objmgr_initinfo(&_lwp_mutex_objects,LWP_MAX_MUTEXES,sizeof(mutex_st)); +} + + +static __inline__ mutex_st* __lwp_mutex_open(mutex_t lock) +{ + LWP_CHECK_MUTEX(lock); + return (mutex_st*)__lwp_objmgr_get(&_lwp_mutex_objects,LWP_OBJMASKID(lock)); +} + +static __inline__ void __lwp_mutex_free(mutex_st *lock) +{ + __lwp_objmgr_close(&_lwp_mutex_objects,&lock->object); + __lwp_objmgr_free(&_lwp_mutex_objects,&lock->object); +} + +static mutex_st* __lwp_mutex_allocate() +{ + mutex_st *lock; + + __lwp_thread_dispatchdisable(); + lock = (mutex_st*)__lwp_objmgr_allocate(&_lwp_mutex_objects); + if(lock) { + __lwp_objmgr_open(&_lwp_mutex_objects,&lock->object); + return lock; + } + __lwp_thread_dispatchunnest(); + return NULL; +} + +s32 LWP_MutexInit(mutex_t *mutex,bool use_recursive) +{ + lwp_mutex_attr attr; + mutex_st *ret; + + if(!mutex) return -1; + + ret = __lwp_mutex_allocate(); + if(!ret) return -1; + + attr.mode = LWP_MUTEX_FIFO; + attr.nest_behavior = use_recursive?LWP_MUTEX_NEST_ACQUIRE:LWP_MUTEX_NEST_ERROR; + attr.onlyownerrelease = TRUE; + attr.prioceil = 1; //__lwp_priotocore(LWP_PRIO_MAX-1); + __lwp_mutex_initialize(&ret->mutex,&attr,LWP_MUTEX_UNLOCKED); + + *mutex = (mutex_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_MUTEX)|LWP_OBJMASKID(ret->object.id)); + __lwp_thread_dispatchunnest(); + return 0; +} + +s32 LWP_MutexDestroy(mutex_t mutex) +{ + mutex_st *p = __lwp_mutex_open(mutex); + if(!p) return 0; + + if(__lwp_mutex_locked(&p->mutex)) { + __lwp_thread_dispatchenable(); + return EBUSY; + } + __lwp_mutex_flush(&p->mutex,EINVAL); + __lwp_thread_dispatchenable(); + + __lwp_mutex_free(p); + return 0; +} + +s32 LWP_MutexLock(mutex_t mutex) +{ + return __lwp_mutex_locksupp(mutex,LWP_THREADQ_NOTIMEOUT,TRUE); +} + +s32 LWP_MutexTryLock(mutex_t mutex) +{ + return __lwp_mutex_locksupp(mutex,LWP_THREADQ_NOTIMEOUT,FALSE); +} + +s32 LWP_MutexUnlock(mutex_t mutex) +{ + u32 ret; + mutex_st *lock; + + lock = __lwp_mutex_open(mutex); + if(!lock) return -1; + + ret = __lwp_mutex_surrender(&lock->mutex); + __lwp_thread_dispatchenable(); + + return ret; +} diff --git a/wii/libogc/libogc/network_common.c b/wii/libogc/libogc/network_common.c new file mode 100644 index 0000000000..7442a35ec3 --- /dev/null +++ b/wii/libogc/libogc/network_common.c @@ -0,0 +1,198 @@ +#include "lwip/def.h" +#include "lwip/inet.h" + +/* Here for now until needed in other places in lwIP */ +#ifndef isascii +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isascii(c) in_range(c, 0x20, 0x7f) +#define isdigit(c) in_range(c, '0', '9') +#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#endif + + + /* + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ + + /* */ + /* inet_addr */ + u32_t inet_addr(const char *cp) + { + struct in_addr val; + + if (inet_aton(cp, &val)) { + return (val.s_addr); + } + return (INADDR_NONE); + } + + /* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ + /* */ + /* inet_aton */ + s8_t + inet_aton(const char *cp, struct in_addr *addr) + { + u32_t val; + s32_t base, n; + char c; + u32_t parts[4]; + u32_t* pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else + base = 8; + } + for (;;) { + if (isdigit(c)) { + val = (val * base) + (s16_t)(c - '0'); + c = *++cp; + } else if (base == 16 && isxdigit(c)) { + val = (val << 4) | + (s16_t)(c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace(c))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); + } + +/* Convert numeric IP address into decimal dotted ASCII representation. + * returns ptr to static buffer; not reentrant! + */ +char *inet_ntoa(struct in_addr addr) +{ + static char str[16]; + u32_t s_addr = addr.s_addr; + char inv[3]; + char *rp; + u8_t *ap; + u8_t rem; + u8_t n; + u8_t i; + + rp = str; + ap = (u8_t *)&s_addr; + for(n = 0; n < 4; n++) { + i = 0; + do { + rem = *ap % (u8_t)10; + *ap /= (u8_t)10; + inv[i++] = '0' + rem; + } while(*ap); + while(i--) + *rp++ = inv[i]; + *rp++ = '.'; + ap++; + } + *--rp = 0; + return str; +} + + +#ifndef BYTE_ORDER +#error BYTE_ORDER is not defined +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + +u16_t +htons(u16_t n) +{ + return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); +} + +u16_t +ntohs(u16_t n) +{ + return htons(n); +} + +u32_t +htonl(u32_t n) +{ + return ((n & 0xff) << 24) | + ((n & 0xff00) << 8) | + ((n & 0xff0000) >> 8) | + ((n & 0xff000000) >> 24); +} + +u32_t +ntohl(u32_t n) +{ + return htonl(n); +} + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ diff --git a/wii/libogc/libogc/network_wii.c b/wii/libogc/libogc/network_wii.c new file mode 100644 index 0000000000..5c76cd8f49 --- /dev/null +++ b/wii/libogc/libogc/network_wii.c @@ -0,0 +1,1167 @@ +/*------------------------------------------------------------- + +network_wii.c -- Wii network subsystem + +Copyright (C) 2008 bushing + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + + +#define MAX_IP_RETRIES 100 +#define MAX_INIT_RETRIES 32 + +//#define DEBUG_NET + +#ifdef DEBUG_NET +#define debug_printf(fmt, args...) \ + do { \ + fprintf(stderr, "%s:%d:" fmt, __FUNCTION__, __LINE__, ##args); \ + } while (0) +#else +#define debug_printf(fmt, args...) do { } while (0) +#endif // DEBUG_NET + +#include +#include +#include +#define __LINUX_ERRNO_EXTENSIONS__ +#include +#include +#include +#include + +#include "ipc.h" +#include "processor.h" +#include "network.h" +#include "ogcsys.h" +#include "lwp_heap.h" + +#define NET_HEAP_SIZE 64*1024 + +#define IOS_O_NONBLOCK 0x04 //(O_NONBLOCK >> 16) - it's in octal representation, so this shift leads to 0 and hence nonblocking sockets didn't work. changed it to the right value. + +#define IOCTL_NWC24_STARTUP 0x06 + +#define IOCTL_NCD_SETIFCONFIG3 0x03 +#define IOCTL_NCD_SETIFCONFIG4 0x04 +#define IOCTL_NCD_GETLINKSTATUS 0x07 +#define IOCTLV_NCD_GETMACADDRESS 0x08 + +#define NET_UNKNOWN_ERROR_OFFSET -10000 + +enum { + IOCTL_SO_ACCEPT = 1, + IOCTL_SO_BIND, + IOCTL_SO_CLOSE, + IOCTL_SO_CONNECT, + IOCTL_SO_FCNTL, + IOCTL_SO_GETPEERNAME, // todo + IOCTL_SO_GETSOCKNAME, // todo + IOCTL_SO_GETSOCKOPT, // todo 8 + IOCTL_SO_SETSOCKOPT, + IOCTL_SO_LISTEN, + IOCTL_SO_POLL, // todo b + IOCTLV_SO_RECVFROM, + IOCTLV_SO_SENDTO, + IOCTL_SO_SHUTDOWN, // todo e + IOCTL_SO_SOCKET, + IOCTL_SO_GETHOSTID, + IOCTL_SO_GETHOSTBYNAME, + IOCTL_SO_GETHOSTBYADDR,// todo + IOCTLV_SO_GETNAMEINFO, // todo 13 + IOCTL_SO_UNK14, // todo + IOCTL_SO_INETATON, // todo + IOCTL_SO_INETPTON, // todo + IOCTL_SO_INETNTOP, // todo + IOCTLV_SO_GETADDRINFO, // todo + IOCTL_SO_SOCKATMARK, // todo + IOCTLV_SO_UNK1A, // todo + IOCTLV_SO_UNK1B, // todo + IOCTLV_SO_GETINTERFACEOPT, // todo + IOCTLV_SO_SETINTERFACEOPT, // todo + IOCTL_SO_SETINTERFACE, // todo + IOCTL_SO_STARTUP, // 0x1f + IOCTL_SO_ICMPSOCKET = 0x30, // todo + IOCTLV_SO_ICMPPING, // todo + IOCTL_SO_ICMPCANCEL, // todo + IOCTL_SO_ICMPCLOSE // todo +}; + +struct init_data { + u32 state; + s32 fd; + s32 prevres; + s32 result; + syswd_t alarm; + u32 retries; + netcallback cb; + void *usrdata; + u8 *buf; +}; + +struct init_default_cb { + lwpq_t queue; + s32 result; +}; + +struct bind_params { + u32 socket; + u32 has_name; + u8 name[28]; +}; + +struct connect_params { + u32 socket; + u32 has_addr; + u8 addr[28]; +}; + +struct sendto_params { + u32 socket; + u32 flags; + u32 has_destaddr; + u8 destaddr[28]; +}; + +struct setsockopt_params { + u32 socket; + u32 level; + u32 optname; + u32 optlen; + u8 optval[20]; +}; + +// 0 means we don't know what this error code means +// I sense a pattern here... +static u8 _net_error_code_map[] = { + 0, // 0 + E2BIG, + EACCES, + EADDRINUSE, + EADDRNOTAVAIL, + EAFNOSUPPORT, // 5 + EAGAIN, + EALREADY, + EBADFD, + EBADMSG, + EBUSY, // 10 + ECANCELED, + ECHILD, + ECONNABORTED, + ECONNREFUSED, + ECONNRESET, // 15 + EDEADLK, + EDESTADDRREQ, + EDOM, + EDQUOT, + EEXIST, // 20 + EFAULT, + EFBIG, + EHOSTUNREACH, + EIDRM, + EILSEQ, // 25 + EINPROGRESS, + EINTR, + EINVAL, + EIO, + EISCONN, // 30 + EISDIR, + ELOOP, + EMFILE, + EMLINK, + EMSGSIZE, // 35 + EMULTIHOP, + ENAMETOOLONG, + ENETDOWN, + ENETRESET, + ENETUNREACH, // 40 + ENFILE, + ENOBUFS, + ENODATA, + ENODEV, + ENOENT, // 45 + ENOEXEC, + ENOLCK, + ENOLINK, + ENOMEM, + ENOMSG, // 50 + ENOPROTOOPT, + ENOSPC, + ENOSR, + ENOSTR, + ENOSYS, // 55 + ENOTCONN, + ENOTDIR, + ENOTEMPTY, + ENOTSOCK, + ENOTSUP, // 60 + ENOTTY, + ENXIO, + EOPNOTSUPP, + EOVERFLOW, + EPERM, // 65 + EPIPE, + EPROTO, + EPROTONOSUPPORT, + EPROTOTYPE, + ERANGE, // 70 + EROFS, + ESPIPE, + ESRCH, + ESTALE, + ETIME, // 75 + ETIMEDOUT, +}; + +static volatile bool _init_busy = false; +static volatile bool _init_abort = false; +static vs32 _last_init_result = -ENETDOWN; +static s32 net_ip_top_fd = -1; +static u8 __net_heap_inited = 0; +static s32 __net_hid=-1; +static heap_cntrl __net_heap; + +static char __manage_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/ncd/manage"; +static char __iptop_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/ip/top"; +static char __kd_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/kd/request"; + +#define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f) + +static s32 NetCreateHeap() +{ + u32 level; + void *net_heap_ptr; + + _CPU_ISR_Disable(level); + + if(__net_heap_inited) + { + _CPU_ISR_Restore(level); + return IPC_OK; + } + + net_heap_ptr = (void *)ROUNDDOWN32(((u32)SYS_GetArena2Hi() - NET_HEAP_SIZE)); + if((u32)net_heap_ptr < (u32)SYS_GetArena2Lo()) + { + _CPU_ISR_Restore(level); + return IPC_ENOMEM; + } + SYS_SetArena2Hi(net_heap_ptr); + __lwp_heap_init(&__net_heap, net_heap_ptr, NET_HEAP_SIZE, 32); + __net_heap_inited=1; + _CPU_ISR_Restore(level); + return IPC_OK; +} + +static void* net_malloc(u32 size) +{ + return __lwp_heap_allocate(&__net_heap, size); +} + +static BOOL net_free(void *ptr) +{ + return __lwp_heap_free(&__net_heap, ptr); +} + +static s32 _net_convert_error(s32 ios_retval) +{ +// return ios_retval; + if (ios_retval >= 0) return ios_retval; + if (ios_retval < -sizeof(_net_error_code_map) + || !_net_error_code_map[-ios_retval]) + return NET_UNKNOWN_ERROR_OFFSET + ios_retval; + return -_net_error_code_map[-ios_retval]; +} + +u32 net_gethostip(void) +{ + u32 ip_addr=0; + int retries; + + if (net_ip_top_fd < 0) return 0; + for (retries=0, ip_addr=0; !ip_addr && retries < 5; retries++) { + ip_addr = IOS_Ioctl(net_ip_top_fd, IOCTL_SO_GETHOSTID, 0, 0, 0, 0); +#ifdef DEBUG_NET + debug_printf("."); + fflush(stdout); +#endif + if (!ip_addr) + usleep(100000); + } + + return ip_addr; +} + +static s32 net_init_chain(s32 result, void *usrdata); + +static void net_init_alarm(syswd_t alarm, void *cb_arg) { + debug_printf("net_init alarm\n"); + net_init_chain(0, cb_arg); +} + +static s32 net_init_chain(s32 result, void *usrdata) { + struct init_data *data = (struct init_data *) usrdata; + struct timespec tb; + + debug_printf("net_init chain entered: %u %d\n", data->state, result); + + if (_init_abort) { + data->state = 0xff; + goto error; + } + + switch (data->state) { + case 0: // open manage fd + data->state = 1; + data->result = IOS_OpenAsync(__manage_fs, 0, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + goto done; + } + return 0; + + case 1: // get link status + if (result == IPC_ENOENT) { + debug_printf("IPC_ENOENT, retrying...\n"); + data->state = 0; + tb.tv_sec = 0; + tb.tv_nsec = 100000000; + data->result = SYS_SetAlarm(data->alarm, &tb, net_init_alarm, data); + if (data->result) { + debug_printf("error setting the alarm: %d\n", data->result); + goto done; + } + return 0; + } + + if (result < 0) { + data->result = _net_convert_error(result); + debug_printf("error opening the manage fd: %d\n", data->result); + goto done; + } + + data->fd = result; + data->state = 2; + data->result = IOS_IoctlvFormatAsync(__net_hid, data->fd, IOCTL_NCD_GETLINKSTATUS, net_init_chain, data, ":d", data->buf, 0x20); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + data->state = 0xff; + if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0) + goto done; + } + return 0; + + case 2: // close manage fd + data->prevres = result; + data->state = 3; + data->result = IOS_CloseAsync(data->fd, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + goto done; + } + return 0; + + case 3: // open top fd + if (data->prevres < 0) { + data->result = _net_convert_error(data->prevres); + debug_printf("invalid link status %d\n", data->result); + goto done; + } + + data->state = 4; + data->result = IOS_OpenAsync(__iptop_fs, 0, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + goto done; + } + return 0; + + case 4: // open request fd + if (result < 0) { + data->result = _net_convert_error(result); + debug_printf("error opening the top fd: %d\n", data->result); + goto done; + } + + net_ip_top_fd = result; + data->state = 5; + data->result = IOS_OpenAsync(__kd_fs, 0, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + data->state = 0xff; + goto error; + } + return 0; + + case 5: // NWC24 startup + if (result < 0) { + data->result = _net_convert_error(result); + debug_printf("error opening the request fd: %d\n", data->result); + data->state = 0xff; + goto error; + } + + data->fd = result; + data->retries = MAX_INIT_RETRIES; + case 6: + data->state = 7; + data->result = IOS_IoctlAsync(data->fd, IOCTL_NWC24_STARTUP, NULL, 0, data->buf, 0x20, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + data->state = 0xff; + if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0) + goto done; + } + return 0; + case 7: + if (result==0) { + memcpy(&result, data->buf, sizeof(result)); + if(result==-29 && --data->retries) { + data->state = 6; + tb.tv_sec = 0; + tb.tv_nsec = 100000000; + data->result = SYS_SetAlarm(data->alarm, &tb, net_init_alarm, data); + if (data->result) { + data->state = 0xff; + debug_printf("error setting the alarm: %d\n", data->result); + if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0) + goto error; + } + return 0; + } else if (result == -15) // this happens if it's already been started + result = 0; + } + + data->prevres = result; + data->state = 8; + data->result = IOS_CloseAsync(data->fd, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + data->state = 0xff; + goto error; + } + return 0; + + case 8: // socket startup + if (data->prevres < 0) { + data->result = _net_convert_error(data->prevres); + debug_printf("NWC24 startup failed: %d\n", data->result); + data->state = 0xff; + goto error; + } + + data->state = 9; + data->retries = MAX_IP_RETRIES; + data->result = IOS_IoctlAsync(net_ip_top_fd, IOCTL_SO_STARTUP, 0, 0, 0, 0, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + data->state = 0xff; + goto error; + } + return 0; + + case 9: // check ip + if (result < 0) { + data->result = _net_convert_error(result); + debug_printf("socket startup failed: %d\n", data->result); + data->state = 0xff; + goto error; + } + + data->state = 10; + data->result = IOS_IoctlAsync(net_ip_top_fd, IOCTL_SO_GETHOSTID, 0, 0, 0, 0, net_init_chain, data); + if (data->result < 0) { + data->result = _net_convert_error(data->result); + data->state = 0xff; + goto error; + } + return 0; + + case 10: // done, check result + if (result == 0) { + if (!data->retries) { + data->result = -ETIMEDOUT; + debug_printf("unable to obtain ip\n"); + data->state = 0xff; + goto error; + } + + debug_printf("unable to obtain ip, retrying...\n"); + data->state = 9; + data->retries--; + tb.tv_sec = 0; + tb.tv_nsec = 100000000; + data->result = SYS_SetAlarm(data->alarm, &tb, net_init_alarm, data); + if (data->result) { + data->state = 0xff; + debug_printf("error setting the alarm: %d\n", data->result); + goto error; + } + return 0; + } + + data->result = 0; + goto done; + +error: + case 0xff: // error occured before, last async call finished + if (net_ip_top_fd >= 0) { + data->fd = net_ip_top_fd; + net_ip_top_fd = -1; + if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0) + goto done; + return 0; + } + goto done; + + default: + debug_printf("unknown state in chain %d\n", data->state); + data->result = -1; + + break; + } + +done: + SYS_RemoveAlarm(data->alarm); + + _last_init_result = data->result; + + if (data->cb) + data->cb(data->result, data->usrdata); + + free(data->buf); + free(data); + + _init_busy = false; + + return 0; +} + +s32 net_init_async(netcallback cb, void *usrdata) { + s32 ret; + struct init_data *data; + + if (net_ip_top_fd >= 0) + return 0; + + if (_init_busy) + return -EBUSY; + + ret = NetCreateHeap(); + if (ret != IPC_OK) + return ret; + + if (__net_hid == -1) + __net_hid = iosCreateHeap(1024); //only needed for ios calls + + if (__net_hid < 0) + return __net_hid; + + data = malloc(sizeof(struct init_data)); + if (!data) + return -1; + + memset(data, 0, sizeof(struct init_data)); + + if (SYS_CreateAlarm(&data->alarm)) { + debug_printf("error creating alarm\n"); + free(data); + return -1; + } + + data->buf = memalign(32, 0x20); + if (!data->buf) { + free(data); + return -1; + } + + data->cb = cb; + data->usrdata = usrdata; + + // kick off the callback chain + _init_busy = true; + _init_abort = false; + _last_init_result = -EBUSY; + net_init_chain(IPC_ENOENT, data); + + return 0; +} + +static void net_init_callback(s32 result, void *usrdata) { + struct init_default_cb *data = (struct init_default_cb *) usrdata; + + data->result = result; + LWP_ThreadBroadcast(data->queue); + + return; +} + +s32 net_init(void) { + struct init_default_cb data; + + if (net_ip_top_fd >= 0) + return 0; + + LWP_InitQueue(&data.queue); + net_init_async((netcallback)net_init_callback, &data); + LWP_ThreadSleep(data.queue); + LWP_CloseQueue(data.queue); + + return data.result; +} + +s32 net_get_status(void) { + return _last_init_result; +} + +void net_deinit() { + if (_init_busy) { + debug_printf("aborting net_init_async\n"); + _init_abort = true; + while (_init_busy) + usleep(50); + debug_printf("net_init_async done\n"); + } + + if (net_ip_top_fd >= 0) IOS_Close(net_ip_top_fd); + net_ip_top_fd = -1; + _last_init_result = -ENETDOWN; +} + +void net_wc24cleanup() { + s32 kd_fd; + STACK_ALIGN(u8, kd_buf, 0x20, 32); + + kd_fd = IOS_Open(__kd_fs, 0); + if (kd_fd >= 0) { + IOS_Ioctl(kd_fd, 7, NULL, 0, kd_buf, 0x20); + IOS_Close(kd_fd); + } +} + +s32 net_get_mac_address(void *mac_buf) { + s32 fd; + s32 result; + void *_mac_buf; + STACK_ALIGN(u32, manage_buf, 0x20, 32); + + if (mac_buf==NULL) return -EINVAL; + + result = NetCreateHeap(); + if (result!=IPC_OK) return result; + + _mac_buf = net_malloc(6); + if (_mac_buf==NULL) return IPC_ENOMEM; + + fd = IOS_Open(__manage_fs, 0); + if (fd<0) { + net_free(_mac_buf); + return fd; + } + + result = IOS_IoctlvFormat(__net_hid, fd, IOCTLV_NCD_GETMACADDRESS, ":dd", manage_buf, 0x20, _mac_buf, 0x06); + IOS_Close(fd); + + if (result>=0) { + memcpy(mac_buf, _mac_buf, 6); + if (manage_buf[0]) result = manage_buf[0]; + } + + net_free(_mac_buf); + return result; +} + +/* Returned value is a static buffer -- this function is not threadsafe! */ +struct hostent * net_gethostbyname(const char *addrString) +{ + s32 ret, len, i; + u8 *params; + struct hostent *ipData; + u32 addrOffset; + static u8 ipBuffer[0x460] ATTRIBUTE_ALIGN(32); + + memset(ipBuffer, 0, 0x460); + + if (net_ip_top_fd < 0) { + errno = -ENXIO; + return NULL; + } + + len = strlen(addrString) + 1; + params = net_malloc(len); + if (params==NULL) { + errno = IPC_ENOMEM; + return NULL; + } + + memcpy(params, addrString, len); + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_GETHOSTBYNAME, params, len, ipBuffer, 0x460)); + + if(params!=NULL) net_free(params); + + if (ret < 0) { + errno = ret; + return NULL; + } + + ipData = ((struct hostent*)ipBuffer); + addrOffset = (u32)MEM_PHYSICAL_TO_K0(ipData->h_name) - ((u32)ipBuffer + 0x10); + + ipData->h_name = MEM_PHYSICAL_TO_K0(ipData->h_name) - addrOffset; + ipData->h_aliases = MEM_PHYSICAL_TO_K0(ipData->h_aliases) - addrOffset; + + for (i=0; (i < 0x40) && (ipData->h_aliases[i] != 0); i++) { + ipData->h_aliases[i] = MEM_PHYSICAL_TO_K0(ipData->h_aliases[i]) - addrOffset; + } + + ipData->h_addr_list = MEM_PHYSICAL_TO_K0(ipData->h_addr_list) - addrOffset; + + for (i=0; (i < 0x40) && (ipData->h_addr_list[i] != 0); i++) { + ipData->h_addr_list[i] = MEM_PHYSICAL_TO_K0(ipData->h_addr_list[i]) - addrOffset; + } + + errno = 0; + return ipData; +} + +s32 net_socket(u32 domain, u32 type, u32 protocol) +{ + s32 ret; + STACK_ALIGN(u32, params, 3, 32); + + if (net_ip_top_fd < 0) return -ENXIO; + + params[0] = domain; + params[1] = type; + params[2] = protocol; + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_SOCKET, params, 12, NULL, 0)); + if(ret>=0) // set tcp window size to 32kb + { + int window_size = 32768; + net_setsockopt(ret, SOL_SOCKET, SO_RCVBUF, (char *) &window_size, sizeof(window_size)); + } + debug_printf("net_socket(%d, %d, %d)=%d\n", domain, type, protocol, ret); + return ret; +} + +s32 net_shutdown(s32 s, u32 how) +{ + s32 ret; + STACK_ALIGN(u32, params, 2, 32); + + if (net_ip_top_fd < 0) return -ENXIO; + + params[0] = s; + params[1] = how; + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_SHUTDOWN, params, 8, NULL, 0)); + + debug_printf("net_shutdown(%d, %d)=%d\n", s, how, ret); + return ret; +} + +s32 net_bind(s32 s, struct sockaddr *name, socklen_t namelen) +{ + s32 ret; + STACK_ALIGN(struct bind_params,params,1,32); + + if (net_ip_top_fd < 0) return -ENXIO; + if (name->sa_family != AF_INET) return -EAFNOSUPPORT; + + name->sa_len = 8; + + memset(params, 0, sizeof(struct bind_params)); + params->socket = s; + params->has_name = 1; + memcpy(params->name, name, 8); + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_BIND, params, sizeof (struct bind_params), NULL, 0)); + debug_printf("net_bind(%d, %p)=%d\n", s, name, ret); + + return ret; +} + +s32 net_listen(s32 s, u32 backlog) +{ + s32 ret; + STACK_ALIGN(u32, params, 2, 32); + + if (net_ip_top_fd < 0) return -ENXIO; + + params[0] = s; + params[1] = backlog; + + debug_printf("calling ios_ioctl(%d, %d, %p, %d)\n", net_ip_top_fd, IOCTL_SO_SOCKET, params, 8); + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_LISTEN, params, 8, NULL, 0)); + debug_printf("net_listen(%d, %d)=%d\n", s, backlog, ret); + return ret; +} + +s32 net_accept(s32 s, struct sockaddr *addr, socklen_t *addrlen) +{ + s32 ret; + STACK_ALIGN(u32, _socket, 1, 32); + + debug_printf("net_accept()\n"); + + if (net_ip_top_fd < 0) return -ENXIO; + + if (!addr) return -EINVAL; + addr->sa_len = 8; + addr->sa_family = AF_INET; + + if (!addrlen) return -EINVAL; + + if (*addrlen < 8) return -ENOMEM; + + *addrlen = 8; + + *_socket = s; + debug_printf("calling ios_ioctl(%d, %d, %p, %d)\n", net_ip_top_fd, IOCTL_SO_ACCEPT, _socket, 4); + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_ACCEPT, _socket, 4, addr, *addrlen)); + + debug_printf("net_accept(%d, %p)=%d\n", s, addr, ret); + return ret; +} + +s32 net_connect(s32 s, struct sockaddr *addr, socklen_t addrlen) +{ + s32 ret; + STACK_ALIGN(struct connect_params,params,1,32); + + if (net_ip_top_fd < 0) return -ENXIO; + if (addr->sa_family != AF_INET) return -EAFNOSUPPORT; + if (addrlen < 8) return -EINVAL; + + addr->sa_len = 8; + + memset(params, 0, sizeof(struct connect_params)); + params->socket = s; + params->has_addr = 1; + memcpy(¶ms->addr, addr, addrlen); + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_CONNECT, params, sizeof(struct connect_params), NULL, 0)); + if (ret < 0) + debug_printf("SOConnect(%d, %p)=%d\n", s, addr, ret); + + return ret; +} + +s32 net_write(s32 s, const void *data, s32 size) +{ + return net_send(s, data, size, 0); +} + +s32 net_send(s32 s, const void *data, s32 size, u32 flags) +{ + return net_sendto(s, data, size, flags, NULL, 0); +} + +s32 net_sendto(s32 s, const void *data, s32 len, u32 flags, struct sockaddr *to, socklen_t tolen) +{ + s32 ret; + u8 * message_buf = NULL; + STACK_ALIGN(struct sendto_params,params,1,32); + + if (net_ip_top_fd < 0) return -ENXIO; + if (tolen > 28) return -EOVERFLOW; + + message_buf = net_malloc(len); + if (message_buf == NULL) { + debug_printf("net_send: failed to alloc %d bytes\n", len); + return IPC_ENOMEM; + } + + debug_printf("net_sendto(%d, %p, %d, %d, %p, %d)\n", s, data, len, flags, to, tolen); + + if (to && to->sa_len != tolen) { + debug_printf("warning: to->sa_len was %d, setting to %d\n", to->sa_len, tolen); + to->sa_len = tolen; + } + + memset(params, 0, sizeof(struct sendto_params)); + memcpy(message_buf, data, len); // ensure message buf is aligned + + params->socket = s; + params->flags = flags; + if (to) { + params->has_destaddr = 1; + memcpy(params->destaddr, to, to->sa_len); + } else { + params->has_destaddr = 0; + } + + ret = _net_convert_error(IOS_IoctlvFormat(__net_hid, net_ip_top_fd, IOCTLV_SO_SENDTO, "dd:", message_buf, len, params, sizeof(struct sendto_params))); + debug_printf("net_send retuned %d\n", ret); + + if(message_buf!=NULL) net_free(message_buf); + return ret; +} + +s32 net_recv(s32 s, void *mem, s32 len, u32 flags) +{ + return net_recvfrom(s, mem, len, flags, NULL, NULL); +} + +s32 net_recvfrom(s32 s, void *mem, s32 len, u32 flags, struct sockaddr *from, socklen_t *fromlen) +{ + s32 ret; + u8* message_buf = NULL; + STACK_ALIGN(u32, params, 2, 32); + + if (net_ip_top_fd < 0) return -ENXIO; + if (len<=0) return -EINVAL; + + if (fromlen && from->sa_len != *fromlen) { + debug_printf("warning: from->sa_len was %d, setting to %d\n",from->sa_len, *fromlen); + from->sa_len = *fromlen; + } + + message_buf = net_malloc(len); + if (message_buf == NULL) { + debug_printf("SORecv: failed to alloc %d bytes\n", len); + return IPC_ENOMEM; + } + + debug_printf("net_recvfrom(%d, '%s', %d, %d, %p, %d)\n", s, (char *)mem, len, flags, from, fromlen?*fromlen:0); + + memset(message_buf, 0, len); + params[0] = s; + params[1] = flags; + + ret = _net_convert_error(IOS_IoctlvFormat(__net_hid, net_ip_top_fd, IOCTLV_SO_RECVFROM, "d:dd", params, 8, message_buf, len, from, (fromlen?*fromlen:0))); + debug_printf("net_recvfrom returned %d\n", ret); + + if (ret > 0) { + if (ret > len) { + ret = -EOVERFLOW; + goto done; + } + + memcpy(mem, message_buf, ret); + } + + if (fromlen && from) *fromlen = from->sa_len; + +done: + if(message_buf!=NULL) net_free(message_buf); + return ret; +} + +s32 net_read(s32 s, void *mem, s32 len) +{ + return net_recvfrom(s, mem, len, 0, NULL, NULL); +} + +s32 net_close(s32 s) +{ + s32 ret; + STACK_ALIGN(u32, _socket, 1, 32); + + if (net_ip_top_fd < 0) return -ENXIO; + + *_socket = s; + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_CLOSE, _socket, 4, NULL, 0)); + + if (ret < 0) + debug_printf("net_close(%d)=%d\n", s, ret); + + return ret; +} + +s32 net_select(s32 maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout) +{ + // not yet implemented + return -EINVAL; +} + +s32 net_setsockopt(s32 s, u32 level, u32 optname, const void *optval, socklen_t optlen) +{ + s32 ret; + STACK_ALIGN(struct setsockopt_params,params,1,32); + + if (net_ip_top_fd < 0) return -ENXIO; + if (optlen < 0 || optlen > 20) return -EINVAL; + + memset(params, 0, sizeof(struct setsockopt_params)); + params->socket = s; + params->level = level; + params->optname = optname; + params->optlen = optlen; + if (optval && optlen) memcpy (params->optval, optval, optlen); + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_SETSOCKOPT, params, sizeof(struct setsockopt_params), NULL, 0)); + + debug_printf("net_setsockopt(%d, %u, %u, %p, %d)=%d\n", s, level, optname, optval, optlen, ret); + return ret; +} + +s32 net_ioctl(s32 s, u32 cmd, void *argp) +{ + u32 flags; + u32 *intp = (u32 *)argp; + + if (net_ip_top_fd < 0) return -ENXIO; + if (!intp) return -EINVAL; + + switch (cmd) { + case FIONBIO: + flags = net_fcntl(s, F_GETFL, 0); + flags &= ~IOS_O_NONBLOCK; + if (*intp) flags |= IOS_O_NONBLOCK; + return net_fcntl(s, F_SETFL, flags); + default: + return -EINVAL; + } +} + +s32 net_fcntl(s32 s, u32 cmd, u32 flags) +{ + s32 ret; + STACK_ALIGN(u32, params, 3, 32); + + if (net_ip_top_fd < 0) return -ENXIO; + if (cmd != F_GETFL && cmd != F_SETFL) return -EINVAL; + + + params[0] = s; + params[1] = cmd; + params[2] = flags; + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_FCNTL, params, 12, NULL, 0)); + + debug_printf("net_fcntl(%d, %d, %x)=%d\n", params[0], params[1], params[2], ret); + + return ret; +} + + +/*! + * \fn s32 net_poll(struct pollsd *sds, u32 nsds, s64 timeout) + * \brief Poll a set of sockets for a set of events. + * + * \param[in] sds a pointer to an array of pollsd structures + * \param[in] nsds the number of elements in the sds array + * \param[in] time in milliseconds before the function should timeout + * + * \return the number of structures in sds that now have non-zero revent fields + */ +s32 net_poll(struct pollsd *sds,s32 nsds,s32 timeout) +{ + union ullc { + u64 ull; + u32 ul[2]; + }; + + s32 ret; + union ullc outv; + struct pollsd *psds; + STACK_ALIGN(u64,params,1,32); + + if(net_ip_top_fd<0) return -ENXIO; + if(sds==NULL || nsds==0) return -EINVAL; + + psds = net_malloc((nsds*sizeof(struct pollsd))); + if(psds==NULL) { + debug_printf("net_poll: failed to alloc %d bytes\n", nsds * sizeof(struct pollsd)); + return IPC_ENOMEM; + } + + outv.ul[0] = 0; + outv.ul[1] = timeout; + params[0] = outv.ull; + memcpy(psds,sds,(nsds*sizeof(struct pollsd))); + + ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_POLL, params, 8, psds, (nsds * sizeof(struct pollsd)))); + + memcpy(sds,psds,(nsds*sizeof(struct pollsd))); + + net_free(psds); + + debug_printf("net_poll(sds, %d, %lld)=%d\n", nsds, params[0], ret); + + return ret; +} + +s32 if_config(char *local_ip, char *netmask, char *gateway,bool use_dhcp, int max_retries) +{ + s32 i,ret; + struct in_addr hostip; + + if (!use_dhcp) + return -EINVAL; + + for (i = 0; i < MAX_INIT_RETRIES; ++i) { + ret = net_init(); + + if ((ret != -EAGAIN) && (ret != -ETIMEDOUT)) + break; + + usleep(50 * 1000); + } + + if (ret < 0) + return ret; + + hostip.s_addr = net_gethostip(); + if (local_ip && hostip.s_addr) { + strcpy(local_ip, inet_ntoa(hostip)); + return 0; + } + + return -1; +} + +s32 if_configex(struct in_addr *local_ip, struct in_addr *netmask, struct in_addr *gateway,bool use_dhcp, int max_retries) +{ + s32 i,ret; + struct in_addr hostip; + + if (!use_dhcp) + return -EINVAL; + + for (i = 0; i < MAX_INIT_RETRIES; ++i) { + ret = net_init(); + + if ((ret != -EAGAIN) && (ret != -ETIMEDOUT)) + break; + + usleep(50 * 1000); + } + + if (ret < 0) + return ret; + + hostip.s_addr = net_gethostip(); + if (local_ip && hostip.s_addr) { + *local_ip = hostip; + return 0; + } + + return -1; +} + +#endif /* defined(HW_RVL) */ diff --git a/wii/libogc/libogc/newlibc.c b/wii/libogc/libogc/newlibc.c new file mode 100644 index 0000000000..c9ab5624fa --- /dev/null +++ b/wii/libogc/libogc/newlibc.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "sys_state.h" +#include "lwp_threads.h" + +int libc_reentrant; +struct _reent libc_globl_reent; + +extern void _wrapup_reent(struct _reent *); +extern void _reclaim_reent(struct _reent *); + +int __libc_create_hook(lwp_cntrl *curr_thr,lwp_cntrl *create_thr) +{ + create_thr->libc_reent = NULL; + return 1; +} + +int __libc_start_hook(lwp_cntrl *curr_thr,lwp_cntrl *start_thr) +{ + struct _reent *ptr; + + ptr = (struct _reent*)calloc(1,sizeof(struct _reent)); + if(!ptr) abort(); + + _REENT_INIT_PTR((ptr)); + + start_thr->libc_reent = ptr; + return 1; +} + +int __libc_delete_hook(lwp_cntrl *curr_thr, lwp_cntrl *delete_thr) +{ + struct _reent *ptr; + + if(curr_thr==delete_thr) + ptr = _REENT; + else + ptr = (struct _reent*)delete_thr->libc_reent; + + if(ptr && ptr!=&libc_globl_reent) { + _reclaim_reent(ptr); + free(ptr); + } + delete_thr->libc_reent = 0; + + if(curr_thr==delete_thr) _REENT = 0; + + return 1; +} + +void __libc_init(int reentrant) +{ + libc_globl_reent = (struct _reent)_REENT_INIT((libc_globl_reent)); + _REENT = &libc_globl_reent; + + if(reentrant) { + __lwp_thread_setlibcreent((void*)&_REENT); + libc_reentrant = reentrant; + } +} + +void __libc_wrapup() +{ + if(!__sys_state_up(__sys_state_get())) return; + if(_REENT!=&libc_globl_reent) { + _wrapup_reent(&libc_globl_reent); + _REENT = &libc_globl_reent; + } +} + + diff --git a/wii/libogc/libogc/ogc_crt0.S b/wii/libogc/libogc/ogc_crt0.S new file mode 100644 index 0000000000..57f56026b3 --- /dev/null +++ b/wii/libogc/libogc/ogc_crt0.S @@ -0,0 +1,157 @@ +#include + + .text + .section .init + + # crt0.s file for the GameCube V1.1 by Costis (costis@gbaemu.com)! + # + # Updates: Added support for clearing the BSS section so that global + # variables are cleared to 0 upon start-up. + # + # This is start-up code for initializing the GameCube system and hardware + # before executing the actual user program code. It clears the GPR's, + # initializes the FPR's, initializes the Data, Code, and L2 caches, clears + # and initializes SPR's, and disables exceptions (interrupts). + # + # Have fun!!! Please e-mail any suggestions or bugs to costis@gbaemu.com. + + # Entry Point + + .extern __InitBATS + .extern __InitPS + .extern __InitFPRS + .extern __InitCache + .extern __InitSystem + .extern __sbss_start, __bss_end, __CheckARGV + .globl _start, __main, __system_argv +_start: + b startup + .long 0x5f617267 +__argv: + .long 0 # argv magic + .long 0 # command line + .long 0 # command line length + .long 0 # argc + .long 0 # argv + .long 0 # end address of argv + +startup: + bl __InitBATS # Initialize BATs to a clear and known state + bl __InitGPRS # Initialize the General Purpose Registers + bl __InitHardware # Initialize some aspects of the Hardware + bl __InitSystem # Initialize more cache aspects, clear a few SPR's, and disable interrupts. + + bl __CheckARGV # check for argv & initialise struct + + lis r3,__isIPL@h + ori r3,r3,__isIPL@l + cmplwi r3,0 + bne 1f + + # Clear the SBSS section! + lis r3,__sbss_start@h + ori r3,r3,__sbss_start@l + li r4,0 + lis r5,__sbss_end@h + ori r5,r5,__sbss_end@l + sub r5,r5,r3 + bl _memset + + # Clear the BSS section! + lis r3,__bss_start@h + ori r3,r3,__bss_start@l + li r4,0 + lis r5,__bss_end@h + ori r5,r5,__bss_end@l + sub r5,r5,r3 + bl _memset + +1: + b SYS_Init # Branch to the user code! + +__InitGPRS: + # Clear all of the GPR's to 0 + li r0,0 + li r3,0 + li r4,0 + li r5,0 + li r6,0 + li r7,0 + li r8,0 + li r9,0 + li r10,0 + li r11,0 + li r12,0 + li r14,0 + li r15,0 + li r16,0 + li r17,0 + li r18,0 + li r19,0 + li r20,0 + li r21,0 + li r22,0 + li r23,0 + li r24,0 + li r25,0 + li r26,0 + li r27,0 + li r28,0 + li r29,0 + li r30,0 + li r31,0 + + lis sp,__crt0stack@h # we take 0x8173FFF0 as the topmost starting point for our stack,this gives us ~128Kb Stack + ori sp,sp,__crt0stack@l + addi sp,sp,-4 + stw r0,0(sp) + stwu sp,-56(sp) + + lis r2,_SDA2_BASE_@h + ori r2,r2,_SDA2_BASE_@l # Set the Small Data 2 (Read Only) base register. + lis r13,_SDA_BASE_@h + ori r13,r13,_SDA_BASE_@l # Set the Small Data (Read\Write) base register. + blr + +__InitHardware: + # Enable the Floating Point Registers + mfmsr r3 + ori r3,r3,MSR_FP + mtmsr r3 + + mflr r31 + bl __InitPS # Initialize Paired Singles + bl __InitFPRS # Initialize the FPR's + bl __InitCache # Initialize the system caches + mtlr r31 + blr + + //r3 = ptr, r4 = fill, r5 = size + .globl _memset +_memset: + clrlwi. r6,r5,29 + srwi r5,r5,2 + subi r3,r3,4 + mtctr r5 +1: stwu r4,4(r3) + bdnz 1b + cmplwi r6,0 + beq 3f +2: stbu r4,1(r3) + addic. r6,r6,-1 + bne+ 2b +3: blr + + .section .bss + .balign 8 +__crt0stack_end: + .space 0x4000 +__crt0stack: + + .globl __system_argv + .section .sdata,"aw",@progbits + .align 2 + .type __system_argv, @object + .size __system_argv, 4 +__system_argv: + .long __argv diff --git a/wii/libogc/libogc/pad.c b/wii/libogc/libogc/pad.c new file mode 100644 index 0000000000..8a77a8b278 --- /dev/null +++ b/wii/libogc/libogc/pad.c @@ -0,0 +1,756 @@ +#include +#include +#include +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "si.h" +#include "pad.h" + +#define PAD_PRODPADS 6 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +#define PAD_ENABLEDMASK(chan) (0x80000000>>chan); + +typedef struct _keyinput { + s8 stickX; + s8 stickY; + s8 substickX; + s8 substickY; + u8 triggerL; + u8 triggerR; + u16 up; + u16 down; + u16 state; + u32 chan; +} keyinput; + +typedef void (*SPECCallback)(u32,u32*,PADStatus*); + +static sampling_callback __pad_samplingcallback = NULL; +static SPECCallback __pad_makestatus = NULL; +static u32 __pad_initialized = 0; +static u32 __pad_enabledbits = 0; +static u32 __pad_resettingbits = 0; +static u32 __pad_recalibratebits = 0; +static u32 __pad_waitingbits = 0; +static u32 __pad_pendingbits = 0; +static u32 __pad_checkingbits = 0; +static u32 __pad_resettingchan = 32; +static u32 __pad_spec = 5; + +static u32 __pad_analogmode = 0x00000300; +static u32 __pad_cmdreadorigin = 0x41000000; +static u32 __pad_cmdcalibrate = 0x42000000; +static u32 __pad_xpatchbits = 0xf0000000; + +static u32 __pad_recalibrated$207 = 0; + +static u32 __pad_type[PAD_CHANMAX]; +static s8 __pad_origin[PAD_CHANMAX][12]; +static u32 __pad_cmdprobedevice[PAD_CHANMAX]; + +static keyinput __pad_keys[PAD_CHANMAX]; +static u8 __pad_clampregion[8] = {30, 180, 15, 72, 40, 15, 59, 31}; + +static vu32* const _siReg = (u32*)0xCC006400; +static vu16* const _viReg = (u16*)0xCC002000; + +extern u32 __PADFixBits; + +static void __pad_enable(u32 chan); +static void __pad_disable(u32 chan); +static void __pad_doreset(); +static s32 __pad_onreset(s32 final); + +static sys_resetinfo pad_resetinfo = { + {}, + __pad_onreset, + 127 +}; + +extern void udelay(int); + +static s32 __pad_onreset(s32 final) +{ + u32 ret; + + if(__pad_samplingcallback!=NULL) PAD_SetSamplingCallback(NULL); + + if(final==FALSE) { + ret = PAD_Sync(); + if(__pad_recalibrated$207==0 && ret) { + __pad_recalibrated$207 = PAD_Recalibrate(0xf0000000); + return 0; + } + return ret; + } + __pad_recalibrated$207 = 0; + return 1; +} + +static void SPEC0_MakeStatus(u32 chan,u32 *data,PADStatus *status) +{ + status->button = 0; + + if(data[0]&0x00080000) status->button |= 0x0100; + if(data[0]&0x00200000) status->button |= 0x0200; + if(data[0]&0x01000000) status->button |= 0x0400; + if(data[0]&0x00010000) status->button |= 0x0800; + if(data[0]&0x00100000) status->button |= 0x1000; + + status->stickX = (s8)(data[1]>>16); + status->stickY = (s8)(data[1]>>24); + status->substickX = (s8)data[1]; + status->substickY = (s8)(data[1]>>8); + status->triggerL = (u8)_SHIFTR(data[0],8,8); + status->triggerR = (u8)(data[0]&0xff); + status->analogA = 0; + status->analogB = 0; + + if(status->triggerL>=0xaa) status->button |= 0x40; + if(status->triggerR>=0xaa) status->button |= 0x20; + + status->stickX -= 128; + status->stickY -= 128; + status->substickX -= 128; + status->substickY -= 128; +} + +static void SPEC1_MakeStatus(u32 chan,u32 *data,PADStatus *status) +{ + status->button = 0; + + if(data[0]&0x00800000) status->button |= 0x0100; + if(data[0]&0x01000000) status->button |= 0x0200; + if(data[0]&0x00200000) status->button |= 0x0400; + if(data[0]&0x00100000) status->button |= 0x0800; + if(data[0]&0x02000000) status->button |= 0x1000; + + status->stickX = (s8)(data[1]>>16); + status->stickY = (s8)(data[1]>>24); + status->substickX = (s8)data[1]; + status->substickY = (s8)(data[1]>>8); + status->triggerL = (u8)_SHIFTR(data[0],8,8); + status->triggerR = (u8)data[0]&0xff; + status->analogA = 0; + status->analogB = 0; + + if(status->triggerL>=0xaa) status->button |= 0x40; + if(status->triggerR>=0xaa) status->button |= 0x20; + + status->stickX -= 128; + status->stickY -= 128; + status->substickX -= 128; + status->substickY -= 128; +} + +static s8 __pad_clampS8(s8 var,s8 org) +{ + s32 siorg = (s32)org; + if(siorg>0) { + siorg -= 128; + if((s32)varbutton = _SHIFTR(data[0],16,14); + + status->stickX = (s8)(data[0]>>8); + status->stickY = (s8)data[0]; + mode = __pad_analogmode&0x0700; + if(mode==0x100) { + status->substickX = (s8)((data[1]>>24)&0xf0); + status->substickY = (s8)((data[1]>>8)&0xff); + status->triggerL = (u8)((data[1]>>16)&0xff); + status->triggerR = (u8)((data[1]>>8)&0xff); + status->analogA = (u8)(data[1]&0xf0); + status->analogB = (u8)((data[1]<<4)&0xf0); + } else if(mode==0x200) { + status->substickX = (s8)((data[1]>>24)&0xf0); + status->substickY = (s8)((data[1]>>20)&0xf0); + status->triggerL = (u8)((data[1]>>16)&0xf0); + status->triggerR = (u8)((data[1]>>12)&0xf0); + status->analogA = (u8)((data[1]>>8)&0xff); + status->analogB = (s8)data[1]&0xff; + } else if(mode==0x300) { + status->substickX = (s8)((data[1]>>24)&0xff); + status->substickY = (s8)((data[1]>>16)&0xff); + status->triggerL = (u8)((data[1]>>8)&0xff); + status->triggerR = (u8)data[1]&0xff; + status->analogA = 0; + status->analogB = 0; + } else if(mode==0x400) { + status->substickX = (s8)((data[1]>>24)&0xff); + status->substickY = (s8)((data[1]>>16)&0xff); + status->triggerL = 0; + status->triggerR = 0; + status->analogA = (u8)((data[1]>>8)&0xff); + status->analogB = (u8)data[1]&0xff ; + } else if(!mode || mode==0x500 || mode==0x600 || mode==0x700) { + status->substickX = (s8)((data[1]>>24)&0xff); + status->substickY = (s8)((data[1]>>16)&0xff); + status->triggerL = (u8)((data[1]>>8)&0xf0); + status->triggerR = (u8)((data[1]>>4)&0xf0); + status->analogA = (u8)(data[1]&0xf0); + status->analogB = (u8)((data[1]<<4)&0xf0); + } + + status->stickX -= 128; + status->stickY -= 128; + status->substickX -= 128; + status->substickY -= 128; + status->stickX = __pad_clampS8(status->stickX,__pad_origin[chan][2]); + status->stickY = __pad_clampS8(status->stickY,__pad_origin[chan][3]); + status->substickX = __pad_clampS8(status->substickX,__pad_origin[chan][4]); + status->substickY = __pad_clampS8(status->substickY,__pad_origin[chan][5]); + status->triggerL = __pad_clampU8(status->triggerL,__pad_origin[chan][6]); + status->triggerR = __pad_clampU8(status->triggerR,__pad_origin[chan][7]); +} + +static void __pad_clampstick(s8 *px,s8 *py,s8 max,s8 xy,s8 min) +{ + s32 x,y,signX,signY,d; + + x = *px; + y = *py; + if(x>=0) signX = 1; + else { signX = -1; x = -(x); } + + if(y>=0) signY = 1; + else { signY = -1; y = -(y); } + + if(x<=min) x = 0; + else x -= min; + + if(y<=min) y = 0; + else y -= min; + + if(x!=0 || y!=0) { + s32 xx,yy,maxy; + + xx = (x * xy); + yy= (y * xy); + maxy = (max * xy); + if(yy<=xx) { + d = ((x * xy) + (y * (max - xy))); + if(maxy*trigger) *trigger = 0; + else if(max<*trigger) *trigger = (max - min); + else *trigger -= min; +} + +static void __pad_updateorigin(s32 chan) +{ + u32 mode,mask,type; + + mask = PAD_ENABLEDMASK(chan); + mode = __pad_analogmode&0x0700; + if(mode==0x0100) { + __pad_origin[chan][4] &= ~0x0f; + __pad_origin[chan][5] &= ~0x0f; + __pad_origin[chan][8] &= ~0x0f; + __pad_origin[chan][9] &= ~0x0f; + } else if(mode==0x200) { + __pad_origin[chan][4] &= ~0x0f; + __pad_origin[chan][5] &= ~0x0f; + __pad_origin[chan][6] &= ~0x0f; + __pad_origin[chan][7] &= ~0x0f; + } + + __pad_origin[chan][2] -= 128; + __pad_origin[chan][3] -= 128; + __pad_origin[chan][4] -= 128; + __pad_origin[chan][5] -= 128; + + if(__pad_xpatchbits&mask && (s32)__pad_origin[chan][2]>64) { + type = SI_GetType(chan)&~0xffff; + if(!(type&~0x09ffffff)) __pad_origin[chan][2] = 0; + } +} + +static void __pad_probecallback(s32 chan,u32 type) +{ + if(!(type&0x0f)) { + __pad_enable(__pad_resettingchan); + __pad_waitingbits |= PAD_ENABLEDMASK(__pad_resettingchan); + } + __pad_doreset(); +} + +static void __pad_origincallback(s32 chan,u32 type) +{ + if(!(type&0x0f)) { + __pad_updateorigin(__pad_resettingchan); + __pad_enable(__pad_resettingchan); + } + __pad_doreset(); +} + +static void __pad_originupdatecallback(s32 chan,u32 type) +{ + u32 en_bits = __pad_enabledbits&PAD_ENABLEDMASK(chan); + + if(en_bits) { + if(!(type&0x0f)) __pad_updateorigin(chan); + if(type&SI_ERROR_NO_RESPONSE) __pad_disable(chan); + } +} + +static void __pad_typeandstatuscallback(s32 chan,u32 type) +{ + u32 recal_bits,mask,ret = 0; + mask = PAD_ENABLEDMASK(__pad_resettingchan); + recal_bits = __pad_recalibratebits&mask; + __pad_recalibratebits &= ~mask; + + if(type&0x0f) { + __pad_doreset(); + return; + } + + __pad_type[__pad_resettingchan] = (type&~0xff); + if(((type&SI_TYPE_MASK)-SI_TYPE_GC) + || !(type&SI_GC_STANDARD)) { + __pad_doreset(); + return; + } + + if(__pad_spec<2) { + __pad_enable(__pad_resettingchan); + __pad_doreset(); + return; + } + + if(!(type&SI_GC_WIRELESS) || type&SI_WIRELESS_IR) { + if(recal_bits) ret = SI_Transfer(__pad_resettingchan,&__pad_cmdcalibrate,3,__pad_origin[__pad_resettingchan],10,__pad_origincallback,0); + else ret = SI_Transfer(__pad_resettingchan,&__pad_cmdreadorigin,1,__pad_origin[__pad_resettingchan],10,__pad_origincallback,0); + } else if(type&SI_WIRELESS_FIX_ID && !(type&SI_WIRELESS_CONT_MASK) && !(type&SI_WIRELESS_LITE)) { + if(type&SI_WIRELESS_RECEIVED) ret = SI_Transfer(__pad_resettingchan,&__pad_cmdreadorigin,1,__pad_origin[__pad_resettingchan],10,__pad_origincallback,0); + else ret = SI_Transfer(__pad_resettingchan,&__pad_cmdprobedevice[__pad_resettingchan],3,__pad_origin[__pad_resettingchan],8,__pad_probecallback,0); + } + if(!ret) { + __pad_pendingbits |= mask; + __pad_doreset(); + } +} + +static void __pad_receivecheckcallback(s32 chan,u32 type) +{ + u32 mask,tmp; + mask = PAD_ENABLEDMASK(chan); + if(__pad_enabledbits&mask) { + tmp = type&0xff; + type &= ~0xff; + __pad_waitingbits &= ~mask; + __pad_checkingbits &= ~mask; + if(!(tmp&0x0f) + && (type&SI_GC_WIRELESS) && (type&SI_WIRELESS_RECEIVED) && (type&SI_WIRELESS_FIX_ID) + && !(type&SI_WIRELESS_IR) && !(type&SI_WIRELESS_CONT_MASK) && !(type&SI_WIRELESS_LITE)) SI_Transfer(chan,&__pad_cmdreadorigin,1,__pad_origin[chan],10,__pad_originupdatecallback,0); + else __pad_disable(chan); + } +} + +static void __pad_enable(u32 chan) +{ + u32 buf[2]; + __pad_enabledbits |= PAD_ENABLEDMASK(chan); + SI_GetResponse(chan,(void*)buf); + SI_SetCommand(chan,(__pad_analogmode|0x00400000)); + SI_EnablePolling(__pad_enabledbits); +} + +static void __pad_disable(u32 chan) +{ + u32 level,mask; + _CPU_ISR_Disable(level); + mask = PAD_ENABLEDMASK(chan); + SI_DisablePolling(mask); + __pad_enabledbits &= ~mask; + __pad_waitingbits &= ~mask; + __pad_pendingbits &= ~mask; + __pad_checkingbits &= ~mask; + SYS_SetWirelessID(chan,0); + _CPU_ISR_Restore(level); +} + +static void __pad_doreset() +{ + __pad_resettingchan = cntlzw(__pad_resettingbits); + if(__pad_resettingchan==32) return; + __pad_resettingbits &= ~PAD_ENABLEDMASK(__pad_resettingchan); + + memset(__pad_origin[__pad_resettingchan],0,12); + SI_GetTypeAsync(__pad_resettingchan,__pad_typeandstatuscallback); +} + +static void __pad_samplinghandler(u32 irq,void *ctx) +{ +} + +u32 __PADDisableRecalibration(s32 disable) +{ + u32 level,ret; + u8 *ram_recaldis = (u8*)0x800030e3; + + _CPU_ISR_Disable(level); + + ret = 0; + if(ram_recaldis[0]&0x40) ret = 1; + + ram_recaldis[0] &= 0xbf; + if(disable) ram_recaldis[0] |= 0x40; + + _CPU_ISR_Restore(level); + + return ret; +} + +u32 PAD_Init() +{ + u32 chan; + u16 prodpads = PAD_PRODPADS; + if(__pad_initialized) return 1; + + if(__pad_spec) PAD_SetSpec(__pad_spec); + + memset(__pad_keys,0,sizeof(keyinput)*PAD_CHANMAX); + + __pad_recalibratebits = 0xf0000000; + + chan = 0; + while(chan<4) { + __pad_keys[chan].chan = -1; + __pad_cmdprobedevice[chan] = 0x4d000000|(chan<<22)|_SHIFTL(prodpads,8,14); + chan++; + } + + SI_RefreshSamplingRate(); + SYS_RegisterResetFunc(&pad_resetinfo); + + __pad_initialized = 1; + return PAD_Reset(0xf0000000); +} + +u32 PAD_Read(PADStatus *status) +{ + u32 chan,mask,ret; + u32 level,sistatus,type; + u32 buf[2]; + _CPU_ISR_Disable(level); + chan = 0; + ret = 0; + while(chan<4) { + mask = PAD_ENABLEDMASK(chan); + if(__pad_pendingbits&mask) { + PAD_Reset(0); + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_NOT_READY; + } else if(__pad_resettingbits&mask || __pad_resettingchan==chan) { + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_NOT_READY; + } else if(!(__pad_enabledbits&mask)) { + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_NO_CONTROLLER; + } else { + if(SI_IsChanBusy(chan)) { + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_TRANSFER; + } else { + sistatus = SI_GetStatus(chan); + if(sistatus&SI_ERROR_NO_RESPONSE) { + SI_GetResponse(chan,(void*)buf); + if(!(__pad_waitingbits&mask)) { + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_NONE; + if(!(__pad_checkingbits&mask)) { + __pad_checkingbits |= mask; + SI_GetTypeAsync(chan,__pad_receivecheckcallback); + } + } else { + __pad_disable(chan); + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_NO_CONTROLLER; + } + } else { + type = SI_GetType(chan); + if(!(type&SI_WIRELESS_STATE)) ret |= mask; + if(!SI_GetResponse(chan,buf) + || buf[0]&0x80000000) { + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_TRANSFER; + } else { + __pad_makestatus(chan,buf,&status[chan]); + if(status[chan].button&0x00002000) { + memset(&status[chan],0,sizeof(PADStatus)); + status[chan].err = PAD_ERR_TRANSFER; + SI_Transfer(chan,&__pad_cmdreadorigin,1,__pad_origin[chan],10,__pad_originupdatecallback,0); + } else { + status[chan].err = PAD_ERR_NONE; + status[chan].button &= ~0x80; + } + } + } + } + } + chan++; + + } + _CPU_ISR_Restore(level); + + return ret; +} + +u32 PAD_Reset(u32 mask) +{ + u32 level; + u32 pend_bits,en_bits; + + _CPU_ISR_Disable(level); + pend_bits = (__pad_pendingbits|mask); + __pad_pendingbits = 0; + + pend_bits &= ~(__pad_waitingbits|__pad_checkingbits); + __pad_resettingbits |= pend_bits; + + en_bits = (__pad_resettingbits&__pad_enabledbits); + __pad_enabledbits &= ~pend_bits; + + if(__pad_spec==4) __pad_recalibratebits |= pend_bits; + + SI_DisablePolling(en_bits); + if(__pad_resettingchan==32) __pad_doreset(); + _CPU_ISR_Restore(level); + + return 1; +} + +u32 PAD_Recalibrate(u32 mask) +{ + u32 level; + + _CPU_ISR_Disable(level); + + _CPU_ISR_Restore(level); + return 1; +} + +u32 PAD_Sync() +{ + u32 ret = 0; + + if(!__pad_resettingbits && __pad_resettingchan==32) { + if(SI_Busy()==0) ret = 1; + } + return ret; +} + +void PAD_SetSpec(u32 spec) +{ + if(__pad_initialized) return; + + __pad_spec = 0; + if(spec==0) __pad_makestatus = SPEC0_MakeStatus; + else if(spec==1) __pad_makestatus = SPEC1_MakeStatus; + else if(spec<6) __pad_makestatus = SPEC2_MakeStatus; + + __pad_spec = spec; +} + +void PAD_ControlMotor(s32 chan,u32 cmd) +{ + u32 level; + u32 mask,type; + + _CPU_ISR_Disable(level); + + mask = PAD_ENABLEDMASK(chan); + if(__pad_enabledbits&mask) { + type = SI_GetType(chan); + if(!(type&SI_GC_NOMOTOR)) { + if(__pad_spec<2 && cmd==PAD_MOTOR_STOP_HARD) cmd = 0; + + cmd = 0x00400000|__pad_analogmode|(cmd&0x03); + SI_SetCommand(chan,cmd); + SI_TransferCommands(); + } + } + _CPU_ISR_Restore(level); +} + +sampling_callback PAD_SetSamplingCallback(sampling_callback cb) +{ + sampling_callback ret; + + ret = __pad_samplingcallback; + __pad_samplingcallback = cb; + if(cb) { + SI_RegisterPollingHandler(__pad_samplinghandler); + } else { + SI_UnregisterPollingHandler(__pad_samplinghandler); + } + + return ret; +} + +void PAD_Clamp(PADStatus *status) +{ + s32 i; + + for(i=0;i>i); + + switch(padstatus[i].err) { + case PAD_ERR_NONE: + oldstate = __pad_keys[i].state; + state = padstatus[i].button; + __pad_keys[i].stickX = padstatus[i].stickX; + __pad_keys[i].stickY = padstatus[i].stickY; + __pad_keys[i].substickX = padstatus[i].substickX; + __pad_keys[i].substickY = padstatus[i].substickY; + __pad_keys[i].triggerL = padstatus[i].triggerL; + __pad_keys[i].triggerR = padstatus[i].triggerR; + __pad_keys[i].up = oldstate & ~state; + __pad_keys[i].down = state & (state ^ oldstate); + __pad_keys[i].state = state; + __pad_keys[i].chan = i; + + connected |= (1<PAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].up; +} + +u16 PAD_ButtonsDown(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].down; +} + +u16 PAD_ButtonsHeld(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].state; +} + +s8 PAD_SubStickX(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].substickX; +} + +s8 PAD_SubStickY(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].substickY; +} + +s8 PAD_StickX(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].stickX; +} + +s8 PAD_StickY(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].stickY; +} + +u8 PAD_TriggerL(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].triggerL; +} + +u8 PAD_TriggerR(int pad) +{ + if(padPAD_CHAN3 || __pad_keys[pad].chan==-1) return 0; + return __pad_keys[pad].triggerR; +} diff --git a/wii/libogc/libogc/sbrk.c b/wii/libogc/libogc/sbrk.c new file mode 100644 index 0000000000..f74bc977f9 --- /dev/null +++ b/wii/libogc/libogc/sbrk.c @@ -0,0 +1,92 @@ +#include <_ansi.h> +#include <_syslist.h> +#include +#include +#include +#include + +#include "asm.h" +#include "processor.h" +#include "system.h" + +#if defined(HW_RVL) +u32 MALLOC_MEM2 __attribute__((weak)) = 1; +#endif + +void* _DEFUN(__libogc_sbrk_r,(ptr,incr), + struct _reent *ptr _AND + ptrdiff_t incr) +{ + u32 level; + char *heap_end = 0; + char *prev_heap = 0; +#if defined(HW_RVL) + static char *mem2_start = NULL; +#endif + + _CPU_ISR_Disable(level); +#if defined(HW_RVL) + if(MALLOC_MEM2) { + // use MEM2 aswell for malloc + if(mem2_start==NULL) + heap_end = (char*)SYS_GetArenaLo(); + else + heap_end = (char*)SYS_GetArena2Lo(); + + if(mem2_start) { + // we're in MEM2 + if((heap_end+incr)>(char*)SYS_GetArena2Hi()) { + // out of MEM2 case + ptr->_errno = ENOMEM; + prev_heap = (char *)-1; + } else if ((heap_end+incr) < mem2_start) { + // trying to sbrk() back below the MEM2 start barrier + ptr->_errno = EINVAL; + prev_heap = (char *)-1; + } else { + // success case + prev_heap = heap_end; + SYS_SetArena2Lo((void*)(heap_end+incr)); + } + // if MEM2 area is exactly at the barrier, transition back to MEM1 again + if(SYS_GetArena2Lo() == mem2_start) mem2_start = NULL; + } else { + // we're in MEM1 + if((heap_end+incr)>(char*)SYS_GetArenaHi()) { + // out of MEM1, transition into MEM2 + if(((char*)SYS_GetArena2Lo() + incr) > (char*)SYS_GetArena2Hi()) { + // this increment doesn't fit in available MEM2 + ptr->_errno = ENOMEM; + prev_heap = (char *)-1; + } else { + // MEM2 is available, move into it + mem2_start = heap_end = prev_heap = SYS_GetArena2Lo(); + SYS_SetArena2Lo((void*)(heap_end+incr)); + } + } else { + // MEM1 is available (or we're freeing memory) + prev_heap = heap_end; + SYS_SetArenaLo((void*)(heap_end+incr)); + } + } + } else { +#endif + heap_end = (char*)SYS_GetArenaLo(); + + if((heap_end+incr)>(char*)SYS_GetArenaHi()) { + + ptr->_errno = ENOMEM; + prev_heap = (char *)-1; + + } else { + + prev_heap = heap_end; + SYS_SetArenaLo((void*)(heap_end+incr)); + } +#if defined(HW_RVL) + } +#endif + _CPU_ISR_Restore(level); + + return (void*)prev_heap; +} diff --git a/wii/libogc/libogc/sdgecko_buf.c b/wii/libogc/libogc/sdgecko_buf.c new file mode 100644 index 0000000000..fd48531fd2 --- /dev/null +++ b/wii/libogc/libogc/sdgecko_buf.c @@ -0,0 +1,47 @@ +#include +#include + +#include "card_cmn.h" +#include "card_buf.h" + +#define BUF_POOL_CNT 3 + +typedef struct _buf_node { + struct _buf_node *next; + u8 data[SECTOR_SIZE+2]; + +} BufNode; + +static BufNode s_buf[BUF_POOL_CNT]; +static BufNode *s_freepool; + +void sdgecko_initBufferPool() +{ + u32 i; + for(i=0;idata; + s_freepool = s_freepool->next; + } + + return buf; +} + +void sdgecko_freeBuffer(u8 *buf) +{ + if(buf) { + BufNode *node = (BufNode*)(buf-offsetof(BufNode,data)); + node->next = s_freepool; + s_freepool = node; + } +} diff --git a/wii/libogc/libogc/sdgecko_io.c b/wii/libogc/libogc/sdgecko_io.c new file mode 100644 index 0000000000..13358dcdea --- /dev/null +++ b/wii/libogc/libogc/sdgecko_io.c @@ -0,0 +1,1356 @@ +#include +#include +#include +#include +#include + +#include "asm.h" +#include "processor.h" +#include "exi.h" +#include "lwp.h" +#include "system.h" +#include "semaphore.h" +#include "card_cmn.h" +//#include "card_fat.h" +#include "card_io.h" + +// SDHC support +// added by emu_kidid +#define SECTOR_ADDRESSING 0 +#define BYTE_ADDRESSING 1 +#define TYPE_SD 0 +#define TYPE_SDHC 1 + +#define MMC_ERROR_PARAM 0x0040 +#define MMC_ERROR_ADDRESS 0x0020 +#define MMC_ERROR_ERASE_SEQ 0x0010 +#define MMC_ERROR_CRC 0x0008 +#define MMC_ERROR_ILL 0x0004 +#define MMC_ERROR_ERASE_RES 0x0002 +#define MMC_ERROR_IDLE 0x0001 + +#define CARDIO_OP_INITFAILED 0x8000 +#define CARDIO_OP_TIMEDOUT 0x4000 +#define CARDIO_OP_IOERR_IDLE 0x2000 +#define CARDIO_OP_IOERR_PARAM 0x1000 +#define CARDIO_OP_IOERR_WRITE 0x0200 +#define CARDIO_OP_IOERR_ADDR 0x0100 +#define CARDIO_OP_IOERR_CRC 0x0002 +#define CARDIO_OP_IOERR_ILL 0x0001 +#define CARDIO_OP_IOERR_FATAL (CARDIO_OP_IOERR_PARAM|CARDIO_OP_IOERR_WRITE|CARDIO_OP_IOERR_ADDR|CARDIO_OP_IOERR_CRC|CARDIO_OP_IOERR_ILL) + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +typedef s32 (*cardiocallback)(s32 drv_no); + +u8 g_CID[MAX_DRIVE][16]; +u8 g_CSD[MAX_DRIVE][16]; +u8 g_CardStatus[MAX_DRIVE][64]; + +u8 g_mCode[MAX_MI_NUM] = { 0x03 }; + +u16 g_dCode[MAX_MI_NUM][MAX_DI_NUM] = +{ + { + 0x033f, /* SD 8Mb */ + 0x0383, /* SD 16Mb */ + 0x074b, /* SD 32Mb */ + 0x0edf, /* SD 64Mb */ + 0x0f03 /* SD 128Mb */ + } +}; + +static u8 _ioWPFlag; +static u8 _ioClrFlag; +static u32 _ioCardFreq; +static u32 _ioRetryCnt; +static cardiocallback _ioRetryCB = NULL; + +static lwpq_t _ioEXILock[MAX_DRIVE]; + +static u32 _ioPageSize[MAX_DRIVE]; +static u32 _ioFlag[MAX_DRIVE]; +static u32 _ioError[MAX_DRIVE]; +static bool _ioCardInserted[MAX_DRIVE]; + +static u8 _ioResponse[MAX_DRIVE][128]; +static u8 _ioCrc7Table[256]; +static u16 _ioCrc16Table[256]; + +// SDHC support +static u32 _initType[MAX_DRIVE]; +static u32 _ioAddressingType[MAX_DRIVE]; + +extern unsigned long gettick(); + +static __inline__ u32 __check_response(s32 drv_no,u8 res) +{ + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + _ioError[drv_no] = 0; + if(_ioFlag[drv_no]==INITIALIZING && res&MMC_ERROR_IDLE) { + _ioError[drv_no] |= CARDIO_OP_IOERR_IDLE; + return CARDIO_ERROR_READY; + } else { + if(res&MMC_ERROR_PARAM) _ioError[drv_no] |= CARDIO_OP_IOERR_PARAM; + if(res&MMC_ERROR_ADDRESS) _ioError[drv_no] |= CARDIO_OP_IOERR_ADDR; + if(res&MMC_ERROR_CRC) _ioError[drv_no] |= CARDIO_OP_IOERR_CRC; + if(res&MMC_ERROR_ILL) _ioError[drv_no] |= CARDIO_OP_IOERR_ILL; + } + return ((_ioError[drv_no]&CARDIO_OP_IOERR_FATAL)?CARDIO_ERROR_INTERNAL:CARDIO_ERROR_READY); +} + +static void __init_crc7() +{ + s32 i,j; + u8 c,crc7; + + crc7 = 0; + for(i=0;i<256;i++) { + c = i; + crc7 = 0; + for(j=0;j<8;j++) { + crc7 <<= 1; + if((crc7^c)&0x80) crc7 ^= 0x09; + c <<= 1; + } + crc7 &= 0x7f; + _ioCrc7Table[i] = crc7; + } +} + +static u8 __make_crc7(void *buffer,u32 len) +{ + s32 i; + u8 crc7; + u8 *ptr; + + crc7 = 0; + ptr = buffer; + for(i=0;i>bcnt)&0xff); + if(mask&val) { + res |= 0x01; + if(!(res&0x0008)) res |= 0x0008; + else res &= ~0x0008; + + } else if(res&0x0008) res |= 0x0008; + else res &= ~0x0008; + + mask >>= 1; + bcnt++; + } + ptr++; + cnt++; + } + return (res<<1)&0xff; +} +*/ +static void __init_crc16() +{ + s32 i,j; + u16 crc16,c; + + for(i=0;i<256;i++) { + crc16 = 0; + c = ((u16)i)<<8; + for(j=0;j<8;j++) { + if((crc16^c)&0x8000) crc16 = (crc16<<1)^0x1021; + else crc16 <<= 1; + + c <<= 1; + } + + _ioCrc16Table[i] = crc16; + } +} + +static u16 __make_crc16(void *buffer,u32 len) +{ + s32 i; + u8 *ptr; + u16 crc16; + + crc16 = 0; + ptr = buffer; + for(i=0;i>8)^(u16)(ptr[i]))]; + + return crc16; +} + +/* Old way, realtime +static u16 __make_crc16(void *buffer,u32 len) +{ + u32 mask,cnt,bcnt; + u32 res,val,tmp; + u8 *ptr = (u8*)buffer; + + cnt = 0; + res = 0; + while(cnt>(bcnt+8))&0xff); + if(mask&tmp) { + res = (res<<1)|0x0001; + if(!(res&0x0020)) res |= 0x0020; + else res &= ~0x0020; + if(!(res&0x1000)) res |= 0x1000; + else res &= ~0x1000; + } else { + res = (res<<1)&~0x0001; + if(res&0x0020) res |= 0x0020; + else res &= ~0x0020; + if(res&0x1000) res |= 0x1000; + else res &= ~0x1000; + } + mask >>= 1; + bcnt++; + } + ptr++; + cnt++; + } + + return (res&0xffff); +} +*/ + +static u32 __card_checktimeout(s32 drv_no,u32 startT,u32 timeout) +{ + u32 endT,diff; + u32 msec; + + endT = gettick(); + if(endT=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + _ioClrFlag = 0xff; + cmd[0] = 0x40; + crc = __make_crc7(cmd,5); + + if(_ioWPFlag) { + _ioClrFlag = 0x00; + for(cnt=0;cnt<5;cnt++) cmd[cnt] ^= -1; + } + + for(cnt=0;cnt<128;cnt++) dummy[cnt] = _ioClrFlag; + + __exi_wait(drv_no); + + if(EXI_SelectSD(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + + cnt = 0; + while(cnt<20) { + if(EXI_ImmEx(drv_no,dummy,128,EXI_WRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + cnt++; + } + EXI_Deselect(drv_no); + + if(EXI_Select(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + crc |= 0x01; + if(_ioWPFlag) crc ^= -1; + if(EXI_ImmEx(drv_no,cmd,5,EXI_WRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + if(EXI_ImmEx(drv_no,&crc,1,EXI_WRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_READY; +} + +static s32 __card_writecmd(s32 drv_no,void *buf,s32 len) +{ + u8 crc,*ptr; + u8 dummy[32]; + u32 cnt; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ptr = buf; + ptr[0] |= 0x40; + crc = __make_crc7(buf,len); + + if(_ioWPFlag) { + for(cnt=0;cnt=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ret = CARDIO_ERROR_READY; + ptr = buf; + *ptr = _ioClrFlag; + + __exi_wait(drv_no); + + if(EXI_Select(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + startT = gettick(); + while(*ptr&0x80) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(!(*ptr&0x80)) break; + if(__card_checktimeout(drv_no,startT,500)!=0) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(*ptr&0x80) ret = CARDIO_ERROR_IOTIMEOUT; + break; + } + } + if(len>1 && ret==CARDIO_ERROR_READY) { + *(++ptr) = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,len-1,EXI_READWRITE)==0) ret = CARDIO_ERROR_IOERROR; + } + + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return ret; +} + +static s32 __card_stopreadresponse(s32 drv_no,void *buf,s32 len) +{ + u8 *ptr,tmp; + s32 startT,ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ptr = buf; + + __exi_wait(drv_no); + + if(EXI_Select(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + ret = CARDIO_ERROR_READY; + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + startT = gettick(); + while(*ptr&0x80) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(!(*ptr&0x80)) break; + if(__card_checktimeout(drv_no,startT,1500)!=0) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(*ptr&0x80) ret = CARDIO_ERROR_IOTIMEOUT; + break; + } + } + + tmp = *ptr; + while(*ptr!=0xff) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(*ptr==0xff) break; + if(__card_checktimeout(drv_no,startT,1500)!=0) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(*ptr!=0xff) ret = CARDIO_ERROR_IOTIMEOUT; + break; + } + } + *ptr = tmp; + + if(len>1 && ret==CARDIO_ERROR_READY) { + *(++ptr) = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,len-1,EXI_READWRITE)==0) ret = CARDIO_ERROR_IOERROR; + } + + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return ret; +} + +static s32 __card_datares(s32 drv_no,void *buf) +{ + u8 *ptr; + s32 startT,ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ptr = buf; + + __exi_wait(drv_no); + + if(EXI_Select(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + ret = CARDIO_ERROR_READY; + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + startT = gettick(); + while(*ptr&0x10) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(!(*ptr&0x10)) break; + if(__card_checktimeout(drv_no,startT,1500)!=0) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(*ptr&0x10) ret = CARDIO_ERROR_IOTIMEOUT; + break; + } + } + + *(++ptr) = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + startT = gettick(); + while(!*ptr) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(*ptr) break; + if(__card_checktimeout(drv_no,startT,1500)!=0) { + *ptr = _ioClrFlag; + if(EXI_ImmEx(drv_no,ptr,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(!*ptr) ret = CARDIO_ERROR_IOTIMEOUT; + break; + } + } + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + + return ret; +} + +static s32 __card_stopresponse(s32 drv_no) +{ + s32 ret; + + if((ret=__card_stopreadresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + ret = __check_response(drv_no,_ioResponse[drv_no][0]); + + return ret; +} + +static s32 __card_dataresponse(s32 drv_no) +{ + s32 ret; + u8 res; + + if((ret=__card_datares(drv_no,_ioResponse[drv_no]))!=0) return ret; + res = _SHIFTR(_ioResponse[drv_no][0],1,3); + if(res==0x0005) ret = CARDIO_OP_IOERR_CRC; + else if(res==0x0006) ret = CARDIO_OP_IOERR_WRITE; + + return ret; +} + +static s32 __card_dataread(s32 drv_no,void *buf,u32 len) +{ + u8 *ptr; + u32 cnt; + u8 res[2]; + u16 crc,crc_org; + s32 startT,ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + __exi_wait(drv_no); + + if(EXI_Select(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + ret = CARDIO_ERROR_READY; + ptr = buf; + for(cnt=0;cnt=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + for(cnt=0;cnt<32;cnt++) dummy[cnt] = _ioClrFlag; + crc = __make_crc16(buf,len); + + __exi_wait(drv_no); + + if(EXI_Select(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + dummy[0] = 0xfc; + if(EXI_ImmEx(drv_no,dummy,1,EXI_WRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + if(EXI_ImmEx(drv_no,buf,len,EXI_WRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + /* sleep 1us*/ + usleep(1); + + ret = CARDIO_ERROR_READY; + if(EXI_ImmEx(drv_no,&crc,2,EXI_WRITE)==0) ret = CARDIO_ERROR_IOERROR; + + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + + return ret; +} + +static s32 __card_multiwritestop(s32 drv_no) +{ + s32 ret,cnt,startT; + u8 dummy[32]; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + for(cnt=0;cnt<32;cnt++) dummy[cnt] = _ioClrFlag; + + __exi_wait(drv_no); + + if(EXI_Select(drv_no,EXI_DEVICE_0,_ioCardFreq)==0) { + EXI_Unlock(drv_no); + return CARDIO_ERROR_NOCARD; + } + + ret = CARDIO_ERROR_READY; + dummy[0] = 0xfd; + if(_ioWPFlag) dummy[0] = 0x02; //!0xfd + if(EXI_ImmEx(drv_no,dummy,1,EXI_WRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + dummy[0] = _ioClrFlag; + if(EXI_ImmEx(drv_no,dummy,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + dummy[0] = _ioClrFlag; + if(EXI_ImmEx(drv_no,dummy,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + dummy[0] = _ioClrFlag; + if(EXI_ImmEx(drv_no,dummy,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + dummy[0] = _ioClrFlag; + if(EXI_ImmEx(drv_no,dummy,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + + startT = gettick(); + ret = CARDIO_ERROR_READY; + while(dummy[0]==0) { + dummy[0] = _ioClrFlag; + if(EXI_ImmEx(drv_no,dummy,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(dummy[0]) break; + if(__card_checktimeout(drv_no,startT,1500)!=0) { + dummy[0] = _ioClrFlag; + if(EXI_ImmEx(drv_no,dummy,1,EXI_READWRITE)==0) { + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return CARDIO_ERROR_IOERROR; + } + if(!dummy[0]) ret = CARDIO_ERROR_IOTIMEOUT; + break; + } + } + + EXI_Deselect(drv_no); + EXI_Unlock(drv_no); + return ret; +} + +static s32 __card_response1(s32 drv_no) +{ + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + return __check_response(drv_no,_ioResponse[drv_no][0]); +} + +static s32 __card_response2(s32 drv_no) +{ + u32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],2))!=0) return ret; + if(!(_ioResponse[drv_no][0]&0x7c) && !(_ioResponse[drv_no][1]&0x9e)) return CARDIO_ERROR_READY; + return CARDIO_ERROR_FATALERROR; +} + +static s32 __card_sendappcmd(s32 drv_no) +{ + s32 ret; + u8 ccmd[5] = {0,0,0,0,0}; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ccmd[0] = 0x37; + if((ret=__card_writecmd(drv_no,ccmd,5))!=0) { + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + ret = __check_response(drv_no,_ioResponse[drv_no][0]); + + return ret; +} + +static s32 __card_sendopcond(s32 drv_no) +{ + u8 ccmd[5] = {0,0,0,0,0}; + s32 ret; + s32 startT; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + ret = 0; + startT = gettick(); + do { + if(_initType[drv_no]==TYPE_SDHC) { + __card_sendappcmd(drv_no); + ccmd[0] = 0x29; + ccmd[1] = 0x40; + } else + ccmd[0] = 0x01; + + if((ret=__card_writecmd(drv_no,ccmd,5))!=0) { + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + if((ret=__check_response(drv_no,_ioResponse[drv_no][0]))!=0) return ret; + if(!(_ioError[drv_no]&CARDIO_OP_IOERR_IDLE)) return CARDIO_ERROR_READY; + + ret = __card_checktimeout(drv_no,startT,1500); + } while(ret==0); + + if(_initType[drv_no]==TYPE_SDHC) { + __card_sendappcmd(drv_no); + ccmd[0] = 0x29; + ccmd[1] = 0x40; + } else + ccmd[0] = 0x01; + + if((ret=__card_writecmd(drv_no,ccmd,5))!=0) { + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + if((ret=__check_response(drv_no,_ioResponse[drv_no][0]))!=0) return ret; + if(_ioError[drv_no]&CARDIO_OP_IOERR_IDLE) return CARDIO_ERROR_IOERROR; + + return CARDIO_ERROR_READY; +} + +static s32 __card_sendCMD8(s32 drv_no) +{ + s32 ret; + u8 ccmd[5] = {0,0,0,0,0}; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ccmd[0] = 0x08; + ccmd[3] = 0x01; + ccmd[4] = 0xAA; + if((ret=__card_writecmd(drv_no,ccmd,5))!=0){ + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],5))!=0) return ret; + ret = __check_response(drv_no,_ioResponse[drv_no][0]); + + return ret; +} + +static s32 __card_sendCMD58(s32 drv_no) +{ + s32 ret; + u8 ccmd[5] = {0,0,0,0,0}; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ccmd[0]= 0x3A; + if((ret=__card_writecmd(drv_no,ccmd,5))!=0) { + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],5))!=0) return ret; + ret = __check_response(drv_no,_ioResponse[drv_no][0]); + + return ret; +} + +static s32 __card_sendcmd(s32 drv_no,u8 cmd,u8 *arg) +{ + u8 ccmd[5] = {0,0,0,0,0}; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ccmd[0] = cmd; + if(arg) { + ccmd[1] = arg[0]; + ccmd[2] = arg[1]; + ccmd[3] = arg[2]; + ccmd[4] = arg[3]; + } + return __card_writecmd(drv_no,ccmd,5); +} + +static s32 __card_setblocklen(s32 drv_no,u32 block_len) +{ + u8 cmd[5]; + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + if(block_len>PAGE_SIZE512) block_len = PAGE_SIZE512; + + cmd[0] = 0x10; + cmd[1] = (block_len>>24)&0xff; + cmd[2] = (block_len>>16)&0xff; + cmd[3] = (block_len>>8)&0xff; + cmd[4] = block_len&0xff; + if((ret=__card_writecmd(drv_no,cmd,5))!=0) { + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))<0) return ret; + ret = __check_response(drv_no,_ioResponse[drv_no][0]); + + return ret; +} + +static s32 __card_readcsd(s32 drv_no) +{ + u8 ccmd[5] = {0,0,0,0,0}; + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + ret = 0; + ccmd[0] = 0x09; + if((ret=__card_writecmd(drv_no,ccmd,5))!=0) { + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + ret = __check_response(drv_no,_ioResponse[drv_no][0]); + if(ret==0) { + if((ret=__card_dataread(drv_no,g_CSD[drv_no],16))!=0) return ret; + } + return ret; +} + +static s32 __card_readcid(s32 drv_no) +{ + u8 ccmd[5] = {0,0,0,0,0}; + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + ret = 0; + ccmd[0] = 0x0A; + if((ret=__card_writecmd(drv_no,ccmd,5))!=0) { + return ret; + } + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + ret = __check_response(drv_no,_ioResponse[drv_no][0]); + if(ret==0) { + if((ret=__card_dataread(drv_no,g_CID[drv_no],16))!=0) return ret; + } + return ret; +} + +static s32 __card_sd_status(s32 drv_no) +{ + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + if(_ioPageSize[drv_no]!=64) { + _ioPageSize[drv_no] = 64; + if((ret=__card_setblocklen(drv_no,_ioPageSize[drv_no]))!=0) return ret; + } + if((ret=__card_sendappcmd(drv_no))!=0) return ret; + if((ret=__card_sendcmd(drv_no,0x0d,NULL))!=0) return ret; + if((ret=__card_response2(drv_no))!=0) return ret; + ret = __card_dataread(drv_no,g_CardStatus[drv_no],64); + + return ret; +} + +static s32 __card_softreset(s32 drv_no) +{ + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + ret = 0; + if((ret=__card_writecmd0(drv_no))!=0) { + return ret; + } + + if((ret=__card_readresponse(drv_no,_ioResponse[drv_no],1))!=0) return ret; + return __check_response(drv_no,_ioResponse[drv_no][0]); +} + +static bool __card_check(s32 drv_no) +{ + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return FALSE; + while((ret=EXI_ProbeEx(drv_no))==0); + if(ret!=1) return FALSE; + + if(!(EXI_GetState(drv_no)&EXI_FLAG_ATTACH)) { + if(EXI_Attach(drv_no,__card_exthandler)==0) return FALSE; + sdgecko_insertedCB(drv_no); + } + return TRUE; +} + +static s32 __card_retrycb(s32 drv_no) +{ + _ioRetryCB = NULL; + _ioRetryCnt++; + return sdgecko_initIO(drv_no); +} + +static void __convert_sector(s32 drv_no,u32 sector_no,u8 *arg) +{ + if(_ioAddressingType[drv_no]==BYTE_ADDRESSING) { + arg[0] = (sector_no>>15)&0xff; + arg[1] = (sector_no>>7)&0xff; + arg[2] = (sector_no<<1)&0xff; + arg[3] = (sector_no<<9)&0xff; + } else if(_ioAddressingType[drv_no]==SECTOR_ADDRESSING) { + arg[0] = (sector_no>>24)&0xff; + arg[1] = (sector_no>>16)&0xff; + arg[2] = (sector_no>>8)&0xff; + arg[3] = sector_no&0xff; + } +} + +void sdgecko_initIODefault() +{ + u32 i; + __init_crc7(); + __init_crc16(); + for(i=0;i=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + u32 id = 0; + EXI_GetID(drv_no,EXI_DEVICE_0,&id); + if ( id != -1 ) return CARDIO_ERROR_NOCARD; + + if(_ioRetryCnt>5) { + _ioRetryCnt = 0; + return CARDIO_ERROR_IOERROR; + } + + _ioCardInserted[drv_no] = __card_check(drv_no); + + if(_ioCardInserted[drv_no]==TRUE) { + _ioWPFlag = 0; + _ioCardFreq = EXI_SPEED16MHZ; + _initType[drv_no] = TYPE_SD; + _ioFlag[drv_no] = INITIALIZING; + _ioAddressingType[drv_no] = BYTE_ADDRESSING; + if(__card_softreset(drv_no)!=0) { + _ioWPFlag = 1; + if(__card_softreset(drv_no)!=0) goto exit; + } + + if(__card_sendCMD8(drv_no)!=0) goto exit; + if((_ioResponse[drv_no][3]==1) && (_ioResponse[drv_no][4]==0xAA)) _initType[drv_no] = TYPE_SDHC; + + if(__card_sendopcond(drv_no)!=0) goto exit; + if(__card_readcsd(drv_no)!=0) goto exit; + if(__card_readcid(drv_no)!=0) goto exit; + + if(_initType[drv_no]==TYPE_SDHC) { + if(__card_sendCMD58(drv_no)!=0) goto exit; + if(_ioResponse[drv_no][1]&0x40) _ioAddressingType[drv_no] = SECTOR_ADDRESSING; + } + + _ioPageSize[drv_no] = 1<=EXI_CHANNEL_2) return CARDIO_ERROR_NOCARD; + ret = sdgecko_preIO(drv_no); + if(ret!=0) return ret; + + return __card_readcid(drv_no); +} + +s32 sdgecko_readCSD(s32 drv_no) +{ + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + ret = sdgecko_preIO(drv_no); + if(ret!=0) return ret; + + return __card_readcsd(drv_no); +} + +s32 sdgecko_readStatus(s32 drv_no) +{ + s32 ret; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + ret = sdgecko_preIO(drv_no); + if(ret!=0) return ret; + + return __card_sd_status(drv_no); +} + +// Multiple sector read by emu_kidid +s32 sdgecko_readSectors(s32 drv_no,u32 sector_no,u32 num_sectors,void *buf) +{ + u32 i; + s32 ret; + u8 arg[4]; + char *ptr = (char*)buf; + + if(drv_no<0 || drv_no>=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ret = sdgecko_preIO(drv_no); + if(ret!=0) return ret; + + if(num_sectors<1) return CARDIO_ERROR_INTERNAL; + + + // Must be 512b, otherwise fail! + if(PAGE_SIZE512!=_ioPageSize[drv_no]) { + _ioPageSize[drv_no] = PAGE_SIZE512; + if((ret=__card_setblocklen(drv_no,PAGE_SIZE512))!=0) return ret; + } + + // SDHC support fix + __convert_sector(drv_no,sector_no,arg); + + if((ret=__card_sendcmd(drv_no,0x12,arg))!=0) return ret; + if((ret=__card_response1(drv_no))!=0) return ret; + + for(i=0;i=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + ret = sdgecko_preIO(drv_no); + if(ret!=0) return ret; + + if(num_sectors<1) return CARDIO_ERROR_INTERNAL; + + + if(PAGE_SIZE512!=_ioPageSize[drv_no]) { + _ioPageSize[drv_no] = PAGE_SIZE512; + if((ret=__card_setblocklen(drv_no,_ioPageSize[drv_no]))!=0) return ret; + } + + // send SET_WRITE_BLK_ERASE_CNT cmd + arg[0] = (num_sectors>>24)&0xff; + arg[1] = (num_sectors>>16)&0xff; + arg[2] = (num_sectors>>8)&0xff; + arg[3] = num_sectors&0xff; + if((ret=__card_sendappcmd(drv_no))!=0) return ret; + if((ret=__card_sendcmd(drv_no,0x17,arg))!=0) return ret; + if((ret=__card_response1(drv_no))!=0) return ret; + + // SDHC support fix + __convert_sector(drv_no,sector_no,arg); + + if((ret=__card_sendcmd(drv_no,0x19,arg))!=0) return ret; + if((ret=__card_response1(drv_no))!=0) return ret; + + for(i=0;i=MAX_DRIVE) return CARDIO_ERROR_NOCARD; + + if(__card_check(drv_no)==TRUE && _ioFlag[drv_no]!=NOT_INITIALIZED) { + if((ret=__card_sendappcmd(drv_no))!=0) goto exit; + if((ret=__card_sendcmd(drv_no,0x2a,NULL))!=0) goto exit; + ret = __card_response1(drv_no); + } + _ioFlag[drv_no] = NOT_INITIALIZED; + +exit: + if(_ioCardInserted[drv_no]==TRUE) { + _ioCardInserted[drv_no] = FALSE; + EXI_Detach(drv_no); + } + if(_ioRetryCB) + return _ioRetryCB(drv_no); + + return CARDIO_ERROR_READY; +} + +static void (*pfCallbackIN[MAX_DRIVE])(s32) = {NULL, NULL}; +static void (*pfCallbackOUT[MAX_DRIVE])(s32) = {NULL, NULL}; + +void sdgecko_insertedCB(s32 drv_no) +{ + if(pfCallbackIN[drv_no]) + pfCallbackIN[drv_no](drv_no); +} + +void sdgecko_ejectedCB(s32 drv_no) +{ + if(pfCallbackOUT[drv_no]) + pfCallbackOUT[drv_no](drv_no); +} + +void sdgecko_setSpeed(u32 freq) +{ + _ioCardFreq = freq; +} + +u32 sdgecko_getPageSize(s32 drv_no) +{ + return _ioPageSize[drv_no]; +} + +u32 sdgecko_setPageSize(s32 drv_no, int size) +{ + if(_ioPageSize[drv_no]!=size) + _ioPageSize[drv_no] = size; + + return __card_setblocklen(drv_no, _ioPageSize[drv_no]); +} + +u32 sdgecko_getAddressingType(s32 drv_no) +{ + return _ioAddressingType[drv_no]; +} diff --git a/wii/libogc/libogc/semaphore.c b/wii/libogc/libogc/semaphore.c new file mode 100644 index 0000000000..4164d62a0e --- /dev/null +++ b/wii/libogc/libogc/semaphore.c @@ -0,0 +1,150 @@ +/*------------------------------------------------------------- + +semaphore.c -- Thread subsystem IV + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + + +-------------------------------------------------------------*/ + + +#include +#include +#include +#include "lwp_sema.h" +#include "lwp_objmgr.h" +#include "lwp_config.h" +#include "semaphore.h" + +#define LWP_OBJTYPE_SEM 4 + +#define LWP_CHECK_SEM(hndl) \ +{ \ + if(((hndl)==LWP_SEM_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_SEM)) \ + return NULL; \ +} + + +typedef struct _sema_st +{ + lwp_obj object; + lwp_sema sema; +} sema_st; + +lwp_objinfo _lwp_sema_objects; + +void __lwp_sema_init() +{ + __lwp_objmgr_initinfo(&_lwp_sema_objects,LWP_MAX_SEMAS,sizeof(sema_st)); +} + +static __inline__ sema_st* __lwp_sema_open(sem_t sem) +{ + LWP_CHECK_SEM(sem); + return (sema_st*)__lwp_objmgr_get(&_lwp_sema_objects,LWP_OBJMASKID(sem)); +} + +static __inline__ void __lwp_sema_free(sema_st *sema) +{ + __lwp_objmgr_close(&_lwp_sema_objects,&sema->object); + __lwp_objmgr_free(&_lwp_sema_objects,&sema->object); +} + +static sema_st* __lwp_sema_allocate() +{ + sema_st *sema; + + __lwp_thread_dispatchdisable(); + sema = (sema_st*)__lwp_objmgr_allocate(&_lwp_sema_objects); + if(sema) { + __lwp_objmgr_open(&_lwp_sema_objects,&sema->object); + return sema; + } + __lwp_thread_dispatchenable(); + return NULL; +} + +s32 LWP_SemInit(sem_t *sem,u32 start,u32 max) +{ + lwp_semattr attr; + sema_st *ret; + + if(!sem) return -1; + + ret = __lwp_sema_allocate(); + if(!ret) return -1; + + attr.max_cnt = max; + attr.mode = LWP_SEMA_MODEFIFO; + __lwp_sema_initialize(&ret->sema,&attr,start); + + *sem = (sem_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_SEM)|LWP_OBJMASKID(ret->object.id)); + __lwp_thread_dispatchenable(); + return 0; +} + +s32 LWP_SemWait(sem_t sem) +{ + sema_st *lwp_sem = __lwp_sema_open(sem); + if(!lwp_sem) return -1; + + __lwp_sema_seize(&lwp_sem->sema,lwp_sem->object.id,TRUE,LWP_THREADQ_NOTIMEOUT); + __lwp_thread_dispatchenable(); + + switch(_thr_executing->wait.ret_code) { + case LWP_SEMA_SUCCESSFUL: + break; + case LWP_SEMA_UNSATISFIED_NOWAIT: + return EAGAIN; + case LWP_SEMA_DELETED: + return EAGAIN; + case LWP_SEMA_TIMEOUT: + return ETIMEDOUT; + + } + return 0; +} + +s32 LWP_SemPost(sem_t sem) +{ + sema_st *lwp_sem = __lwp_sema_open(sem); + if(!lwp_sem) return -1; + + __lwp_sema_surrender(&lwp_sem->sema,lwp_sem->object.id); + __lwp_thread_dispatchenable(); + + return 0; +} + +s32 LWP_SemDestroy(sem_t sem) +{ + sema_st *lwp_sem = __lwp_sema_open(sem); + if(!lwp_sem) return -1; + + __lwp_sema_flush(&lwp_sem->sema,-1); + __lwp_thread_dispatchenable(); + + __lwp_sema_free(lwp_sem); + return 0; +} diff --git a/wii/libogc/libogc/si.c b/wii/libogc/libogc/si.c new file mode 100644 index 0000000000..5c3bc8c30d --- /dev/null +++ b/wii/libogc/libogc/si.c @@ -0,0 +1,693 @@ +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "system.h" +#include "ogcsys.h" +#include "video.h" +#include "irq.h" +#include "si.h" +#include "lwp_watchdog.h" + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +#define SISR_ERRORMASK(chn) (0x0f000000>>((chn)<<3)) +#define SIPOLL_ENABLE(chn) (0x80000000>>((chn)+24)) + +#define SICOMCSR_TCINT (1<<31) +#define SICOMCSR_TCINT_ENABLE (1<<30) +#define SICOMCSR_COMERR (1<<29) +#define SICOMCSR_RDSTINT (1<<28) +#define SICOMCSR_RDSTINT_ENABLE (1<<27) +#define SICOMCSR_TSTART (1<<0) + +#define SISR_UNDERRUN 0x0001 +#define SISR_OVERRUN 0x0002 +#define SISR_COLLISION 0x0004 +#define SISR_NORESPONSE 0x0008 +#define SISR_WRST 0x0010 +#define SISR_RDST 0x0020 + +typedef union _sicomcsr { + u32 val; + struct { + u32 tcint : 1; + u32 tcintmsk : 1; + u32 comerr : 1; + u32 rdstint : 1; + u32 rdstintmsk : 1; + u32 pad2 : 4; + u32 outlen : 7; + u32 pad1 : 1; + u32 inlen : 7; + u32 pad0 : 5; + u32 channel : 2; + u32 tstart : 1; + } csrmap; +} sicomcsr; + +static struct _sipacket { + s32 chan; + void *out; + u32 out_bytes; + void *in; + u32 in_bytes; + SICallback callback; + u64 fire; +} sipacket[4]; + +static struct _sicntrl { + s32 chan; + u32 poll; + u32 in_bytes; + void *in; + SICallback callback; +} sicntrl = { + -1, + 0, + 0, + NULL, + NULL +}; + +static struct _xy { + u16 line; + u8 cnt; +} xy[2][12] = { + { + {0x00F6,0x02},{0x000F,0x12},{0x001E,0x09},{0x002C,0x06}, + {0x0034,0x05},{0x0041,0x04},{0x0057,0x03},{0x0057,0x03}, + {0x0057,0x03},{0x0083,0x02},{0x0083,0x02},{0x0083,0x02} + }, + + { + {0x0128,0x02},{0x000F,0x15},{0x001D,0x0B},{0x002D,0x07}, + {0x0034,0x06},{0x003F,0x05},{0x004E,0x04},{0x0068,0x03}, + {0x0068,0x03},{0x0068,0x03},{0x0068,0x03},{0x009C,0x02} + } +}; + +u32 __PADFixBits = 0; + +static u32 sampling_rate = 0; +static u32 cmdtypeandstatus$47 = 0; +static u32 cmdtypeandstatus$223 = 0; +static u32 cmdfixdevice[4] = {0,0,0,0}; +static u32 si_type[4] = {8,8,8,8}; +static u32 inputBufferVCount[4] = {0,0,0,0}; +static u32 inputBufferValid[4] = {0,0,0,0}; +static u32 inputBuffer[4][2] = {{0,0},{0,0},{0,0},{0,0}}; +static RDSTHandler rdstHandlers[4] = {NULL,NULL,NULL,NULL}; +static u64 typeTime[4] = {0,0,0,0}; +static u64 xferTime[4] = {0,0,0,0}; +static SICallback typeCallback[4][4] = {{NULL,NULL,NULL,NULL}, + {NULL,NULL,NULL,NULL}, + {NULL,NULL,NULL,NULL}, + {NULL,NULL,NULL,NULL}}; +static syswd_t si_alarm[4]; + +#if defined(HW_DOL) + static vu32* const _siReg = (u32*)0xCC006400; +#elif defined(HW_RVL) + static vu32* const _siReg = (u32*)0xCD006400; +#else + #error HW model unknown. +#endif + +static vu16* const _viReg = (u16*)0xCC002000; + +static u32 __si_transfer(s32 chan,void *out,u32 out_len,void *in,u32 in_len,SICallback cb); + +static __inline__ struct _xy* __si_getxy() +{ + switch(VIDEO_GetCurrentTvMode()) { + case VI_NTSC: + case VI_MPAL: + case VI_EURGB60: + return xy[0]; + break; + case VI_PAL: + return xy[1]; + break; + } + return NULL; +} + +static __inline__ void __si_cleartcinterrupt() +{ + _siReg[13] = (_siReg[13]|SICOMCSR_TCINT)&SICOMCSR_TCINT; +} + +static void __si_alarmhandler(syswd_t thealarm,void *cbarg) +{ + u32 chn = 0; + + while(chn<4) + { + if(si_alarm[chn]==thealarm) + break; + chn++; + } + if(chn==4) + return; + + if(sipacket[chn].chan!=-1) { + if(__si_transfer(sipacket[chn].chan,sipacket[chn].out,sipacket[chn].out_bytes,sipacket[chn].in,sipacket[chn].in_bytes,sipacket[chn].callback)) sipacket[chn].chan = -1; + } +} + +static u32 __si_completetransfer() +{ + u32 val,cnt,i; + u32 *in; + u32 sisr = _siReg[14]; + + __si_cleartcinterrupt(); + + if(sicntrl.chan==-1) return sisr; + + xferTime[sicntrl.chan] = gettime(); + + in = (u32*)sicntrl.in; + cnt = (sicntrl.in_bytes/4); + for(i=0;i>((3-i)*8))&0xff; + } + if(_siReg[13]&SICOMCSR_COMERR) { + sisr = (sisr>>((3-sicntrl.chan)*8))&0x0f; + if(sisr&SISR_NORESPONSE && !(si_type[sicntrl.chan]&SI_ERR_BUSY)) si_type[sicntrl.chan] = SI_ERROR_NO_RESPONSE; + if(!sisr) sisr = SISR_COLLISION; + } else { + typeTime[sicntrl.chan] = gettime(); + sisr = 0; + } + + sicntrl.chan = -1; + return sisr; +} + +static u32 __si_transfer(s32 chan,void *out,u32 out_len,void *in,u32 in_len,SICallback cb) +{ + u32 level,cnt,i; + sicomcsr csr; + _CPU_ISR_Disable(level); + if(sicntrl.chan!=-1) { + _CPU_ISR_Restore(level); + return 0; + } + _siReg[14] &= SISR_ERRORMASK(chan); + + sicntrl.chan = chan; + sicntrl.callback = cb; + sicntrl.in_bytes = in_len; + sicntrl.in = in; + cnt = ((out_len+3)/4); + for(i=0;i=0) { + if(!__si_transfer(sipacket[chan].chan,sipacket[chan].out,sipacket[chan].out_bytes,sipacket[chan].in,sipacket[chan].in_bytes,sipacket[chan].callback)) break; + SYS_CancelAlarm(si_alarm[chan]); + sipacket[chan].chan = -1; + } + } + cnt++; + } +} + +static void __si_interrupthandler(u32 irq,void *ctx) +{ + SICallback cb; + u32 chn,curr_line,line,ret; + sicomcsr csr; + + csr.val = _siReg[13]; + if(csr.csrmap.tcintmsk && csr.csrmap.tcint) { + chn = sicntrl.chan; + cb = sicntrl.callback; + sicntrl.callback = NULL; + + ret = __si_completetransfer(); + __si_transfernext(chn); + + if(cb) cb(chn,ret); + + _siReg[14] &= SISR_ERRORMASK(chn); + + if(si_type[chn]==SI_ERR_BUSY && !SI_IsChanBusy(chn)) SI_Transfer(chn,&cmdtypeandstatus$47,1,&si_type[chn],3,__si_gettypecallback,65); + } + + if(csr.csrmap.rdstintmsk && csr.csrmap.rdstint) { + curr_line = VIDEO_GetCurrentLine(); + curr_line++; + line = _SHIFTR(sicntrl.poll,16,10); + + chn = 0; + while(chn<4) { + if(SI_GetResponseRaw(chn)) inputBufferVCount[chn] = curr_line; + chn++; + } + + chn = 0; + while(chn<4) { + if(sicntrl.poll&SIPOLL_ENABLE(chn)) { + if(!inputBufferVCount[chn] || ((line>>1)+inputBufferVCount[chn])>= 24; + mask = (poll>>4)&0x0f; + sicntrl.poll &= ~mask; + + poll &= (0x03fffff0|mask); + + sicntrl.poll |= (poll&~0x03ffff00); + SI_TransferCommands(); + _siReg[12] = sicntrl.poll; + _CPU_ISR_Restore(level); +} + +void SI_DisablePolling(u32 poll) +{ + u32 level,mask; + _CPU_ISR_Disable(level); + mask = (poll>>24)&0xf0; + sicntrl.poll &= ~mask; + _siReg[12] = sicntrl.poll; + _CPU_ISR_Restore(level); +} + +void SI_SetSamplingRate(u32 samplingrate) +{ + u32 div,level; + struct _xy *xy = NULL; + + if(samplingrate>11) samplingrate = 11; + + _CPU_ISR_Disable(level); + sampling_rate = samplingrate; + xy = __si_getxy(); + + div = 1; + if(_viReg[54]&0x0001) div = 2; + + SI_SetXY(div*xy[samplingrate].line,xy[samplingrate].cnt); + _CPU_ISR_Restore(level); +} + +void SI_RefreshSamplingRate() +{ + SI_SetSamplingRate(sampling_rate); +} + +u32 SI_GetStatus(s32 chan) +{ + u32 level,sisr; + + _CPU_ISR_Disable(level); + sisr = (_siReg[14]>>((3-chan)<<3)); + if(sisr&SISR_NORESPONSE && !(si_type[chan]&SI_ERR_BUSY)) si_type[chan] = SI_ERROR_NO_RESPONSE; + _CPU_ISR_Restore(level); + return sisr; +} + +u32 SI_GetResponseRaw(s32 chan) +{ + u32 status,ret; + ret = 0; + status = SI_GetStatus(chan); + if(status&SISR_RDST) { + inputBuffer[chan][0] = _siReg[(chan*3)+1]; + inputBuffer[chan][1] = _siReg[(chan*3)+2]; + inputBufferValid[chan] = 1; + ret = 1; + } + return ret; +} + +u32 SI_GetResponse(s32 chan,void *buf) +{ + u32 level,valid; + _CPU_ISR_Disable(level); + SI_GetResponseRaw(chan); + valid = inputBufferValid[chan]; + inputBufferValid[chan] = 0; + if(valid) { + ((u32*)buf)[0] = inputBuffer[chan][0]; + ((u32*)buf)[1] = inputBuffer[chan][1]; + } + _CPU_ISR_Restore(level); + return valid; +} + +void SI_SetCommand(s32 chan,u32 cmd) +{ + _siReg[chan*3] = cmd; +} + +u32 SI_GetCommand(s32 chan) +{ + return (_siReg[chan*3]); +} + +u32 SI_Transfer(s32 chan,void *out,u32 out_len,void *in,u32 in_len,SICallback cb,u32 us_delay) +{ + u32 ret = 0; + u32 level; + s64 diff; + u64 now,fire; + struct timespec tb; + _CPU_ISR_Disable(level); + if(sipacket[chan].chan==-1 && sicntrl.chan!=chan) { + ret = 1; + fire = now = gettime(); + if(us_delay) fire = xferTime[chan]+microsecs_to_ticks(us_delay); + diff = (now - fire); + if(diff<0) { + tb.tv_sec = 0; + tb.tv_nsec = ticks_to_nanosecs((fire - now)); + SYS_SetAlarm(si_alarm[chan],&tb,__si_alarmhandler,NULL); + } else if(__si_transfer(chan,out,out_len,in,in_len,cb)) { + _CPU_ISR_Restore(level); + return ret; + } + sipacket[chan].chan = chan; + sipacket[chan].out = out; + sipacket[chan].out_bytes = out_len; + sipacket[chan].in = in; + sipacket[chan].in_bytes = in_len; + sipacket[chan].callback = cb; + sipacket[chan].fire = fire; + } + _CPU_ISR_Restore(level); + return ret; +} + +u32 SI_GetType(s32 chan) +{ + u32 level,type; + u64 now; + s64 diff; + _CPU_ISR_Disable(level); + now = gettime(); + type = si_type[chan]; + diff = (now - typeTime[chan]); + if(sicntrl.poll&(0x80>>chan)) { + if(type!=SI_ERROR_NO_RESPONSE) { + typeTime[chan] = gettime(); + _CPU_ISR_Restore(level); + return type; + } + si_type[chan] = type = SI_ERR_BUSY; + } else if(diff==millisecs_to_ticks(50) && type!=SI_ERROR_NO_RESPONSE) { + _CPU_ISR_Restore(level); + return type; + } else if(diff==millisecs_to_ticks(75)) si_type[chan] = SI_ERR_BUSY; + else si_type[chan] = type = SI_ERR_BUSY; + + typeTime[chan] = gettime(); + + SI_Transfer(chan,&cmdtypeandstatus$223,1,&si_type[chan],3,__si_gettypecallback,65); + _CPU_ISR_Restore(level); + + return type; +} + +u32 SI_GetTypeAsync(s32 chan,SICallback cb) +{ + u32 level; + u32 type,i; + _CPU_ISR_Disable(level); + type = SI_GetType(chan); + if(si_type[chan]&SI_ERR_BUSY) { + i=0; + for(i=0;i<4;i++) { + if(!typeCallback[chan][i] && typeCallback[chan][i]!=cb) { + typeCallback[chan][i] = cb; + break; + } + } + _CPU_ISR_Restore(level); + return type; + } + + cb(chan,type); + _CPU_ISR_Restore(level); + return type; +} + +void SI_TransferCommands() +{ + _siReg[14] = 0x80000000; +} + +u32 SI_RegisterPollingHandler(RDSTHandler handler) +{ + u32 level,i; + + _CPU_ISR_Disable(level); + + i = 0; + for(i=0;i<4;i++) { + if(rdstHandlers[i]==handler) { + _CPU_ISR_Restore(level); + return 1; + } + } + + for(i=0;i<4;i++) { + if(rdstHandlers[i]==NULL) { + rdstHandlers[i] = handler; + SI_EnablePollingInterrupt(TRUE); + _CPU_ISR_Restore(level); + return 1; + } + } + + _CPU_ISR_Restore(level); + return 0; +} + +u32 SI_UnregisterPollingHandler(RDSTHandler handler) +{ + u32 level,i; + + _CPU_ISR_Disable(level); + for(i=0;i<4;i++) { + if(rdstHandlers[i]==handler) { + rdstHandlers[i] = NULL; + for(i=0;i<4;i++) { + if(rdstHandlers[i]!=NULL) break; + } + if(i>=4) SI_EnablePollingInterrupt(FALSE); + + _CPU_ISR_Restore(level); + return 1; + } + } + _CPU_ISR_Restore(level); + return 0; +} + +u32 SI_EnablePollingInterrupt(s32 enable) +{ + sicomcsr csr; + u32 level,ret,i; + + _CPU_ISR_Disable(level); + + ret = 0; + csr.val = _siReg[13]; + if(csr.csrmap.rdstintmsk) ret = 1; + + if(enable) { + csr.csrmap.rdstintmsk = 1; + for(i=0;i<4;i++) inputBufferVCount[i] = 0; + } else + csr.csrmap.rdstintmsk = 0; + + csr.val &= 0x7ffffffe; + _siReg[13] = csr.val; + + _CPU_ISR_Restore(level); + return ret; +} + +void __si_init() +{ + u32 i; + for(i=0;i<4;i++) { + sipacket[i].chan = -1; + SYS_CreateAlarm(&si_alarm[i]); + } + sicntrl.poll = 0; + + SI_SetSamplingRate(0); + while(_siReg[13]&0x0001); + _siReg[13] = 0x80000000; + + _siReg[15] &= ~0x80000000; // permit exi clock to be set to 32MHz + + IRQ_Request(IRQ_PI_SI,__si_interrupthandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_PI_SI)); + + SI_GetType(0); + SI_GetType(1); + SI_GetType(2); + SI_GetType(3); +} diff --git a/wii/libogc/libogc/stm.c b/wii/libogc/libogc/stm.c new file mode 100644 index 0000000000..396e15509e --- /dev/null +++ b/wii/libogc/libogc/stm.c @@ -0,0 +1,243 @@ +/*------------------------------------------------------------- + +stm.c - System and miscellaneous hardware control functions + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include "ipc.h" +#include "system.h" +#include "asm.h" +#include "processor.h" +#include "stm.h" + +#define IOCTL_STM_EVENTHOOK 0x1000 +#define IOCTL_STM_GET_IDLEMODE 0x3001 +#define IOCTL_STM_RELEASE_EH 0x3002 +#define IOCTL_STM_HOTRESET 0x2001 +#define IOCTL_STM_HOTRESET_FOR_PD 0x2002 +#define IOCTL_STM_SHUTDOWN 0x2003 +#define IOCTL_STM_IDLE 0x2004 +#define IOCTL_STM_WAKEUP 0x2005 +#define IOCTL_STM_VIDIMMING 0x5001 +#define IOCTL_STM_LEDFLASH 0x6001 +#define IOCTL_STM_LEDMODE 0x6002 +#define IOCTL_STM_READVER 0x7001 +#define IOCTL_STM_READDDRREG 0x4001 +#define IOCTL_STM_READDDRREG2 0x4002 + +static s32 __stm_eh_fd = -1; +static s32 __stm_imm_fd = -1; +static u32 __stm_vdinuse = 0; +static u32 __stm_initialized= 0; +static u32 __stm_ehregistered= 0; +static u32 __stm_ehclear= 0; + +static u32 __stm_ehbufin[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; +static u32 __stm_ehbufout[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; +static u32 __stm_immbufin[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; +static u32 __stm_immbufout[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; + +static char __stm_eh_fs[] ATTRIBUTE_ALIGN(32) = "/dev/stm/eventhook"; +static char __stm_imm_fs[] ATTRIBUTE_ALIGN(32) = "/dev/stm/immediate"; + +s32 __STM_SetEventHook(); +s32 __STM_ReleaseEventHook(); +static s32 __STMEventHandler(s32 result,void *usrdata); + +stmcallback __stm_eventcb = NULL; + +static vu16* const _viReg = (u16*)0xCC002000; + +s32 __STM_Init() +{ + if(__stm_initialized==1) return 1; + + __stm_vdinuse = 0; + __stm_imm_fd = IOS_Open(__stm_imm_fs,0); + if(__stm_imm_fd<0) return 0; + + __stm_eh_fd = IOS_Open(__stm_eh_fs,0); + if(__stm_eh_fd<0) return 0; + + __stm_initialized = 1; + __STM_SetEventHook(); + return 1; +} + +s32 __STM_Close() +{ + s32 res; + s32 ret = 0; + __STM_ReleaseEventHook(); + + if(__stm_imm_fd >= 0) { + res = IOS_Close(__stm_imm_fd); + if(res < 0) ret = res; + __stm_imm_fd = -1; + } + if(__stm_eh_fd >= 0) { + res = IOS_Close(__stm_eh_fd); + if(res < 0) ret = res; + __stm_eh_fd = -1; + } + __stm_initialized = 0; + return ret; +} + +s32 __STM_SetEventHook() +{ + s32 ret; + u32 level; + + if(__stm_initialized==0) return STM_ENOTINIT; + + __stm_ehclear = 0; + + _CPU_ISR_Disable(level); + ret = IOS_IoctlAsync(__stm_eh_fd,IOCTL_STM_EVENTHOOK,__stm_ehbufin,0x20,__stm_ehbufout,0x20,__STMEventHandler,NULL); + if(ret<0) __stm_ehregistered = 0; + else __stm_ehregistered = 1; + _CPU_ISR_Restore(level); + + return ret; +} + +s32 __STM_ReleaseEventHook() +{ + s32 ret; + + if(__stm_initialized==0) return STM_ENOTINIT; + if(__stm_ehregistered==0) return STM_ENOHANDLER; + + __stm_ehclear = 1; + + ret = IOS_Ioctl(__stm_imm_fd,IOCTL_STM_RELEASE_EH,__stm_immbufin,0x20,__stm_immbufout,0x20); + if(ret>=0) __stm_ehregistered = 0; + + return ret; +} + +static s32 __STMEventHandler(s32 result,void *usrdata) +{ + __stm_ehregistered = 0; + + if(result < 0) { // shouldn't happen + return result; + } + + if(__stm_ehclear) { //release + return 0; + } + + if(__stm_eventcb) { + __stm_eventcb(__stm_ehbufout[0]); + } + + __STM_SetEventHook(); + + return 0; +} + +stmcallback STM_RegisterEventHandler(stmcallback newhandler) +{ + stmcallback old; + old = __stm_eventcb; + __stm_eventcb = newhandler; + return old; +} + +s32 STM_ShutdownToStandby() +{ + int res; + + _viReg[1] = 0; + if(__stm_initialized==0) { + return STM_ENOTINIT; + } + __stm_immbufin[0] = 0; + res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_SHUTDOWN,__stm_immbufin,0x20,__stm_immbufout,0x20); + if(res<0) { + } + return res; +} + +s32 STM_ShutdownToIdle() +{ + int res; + + _viReg[1] = 0; + if(__stm_initialized==0) { + return STM_ENOTINIT; + } + switch(SYS_GetHollywoodRevision()) { + case 0: + case 1: + case 2: + __stm_immbufin[0] = 0xFCA08280; + default: + __stm_immbufin[0] = 0xFCE082C0; + } + res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_IDLE,__stm_immbufin,0x20,__stm_immbufout,0x20); + if(res<0) { + } + return res; +} + +s32 STM_SetLedMode(u32 mode) +{ + int res; + if(__stm_initialized==0) { + return STM_ENOTINIT; + } + __stm_immbufin[0] = mode; + res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_LEDMODE,__stm_immbufin,0x20,__stm_immbufout,0x20); + if(res<0) { + } + return res; +} + +s32 STM_RebootSystem() +{ + int res; + + _viReg[1] = 0; + if(__stm_initialized==0) { + return STM_ENOTINIT; + } + __stm_immbufin[0] = 0; + res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_HOTRESET,__stm_immbufin,0x20,__stm_immbufout,0x20); + if(res<0) { + } + return res; +} + + + +#endif /* defined(HW_RVL) */ diff --git a/wii/libogc/libogc/sys_state.c b/wii/libogc/libogc/sys_state.c new file mode 100644 index 0000000000..32a96ef55b --- /dev/null +++ b/wii/libogc/libogc/sys_state.c @@ -0,0 +1,3 @@ +#include "sys_state.h" + +u32 _sys_state_curr; diff --git a/wii/libogc/libogc/sys_state.inl b/wii/libogc/libogc/sys_state.inl new file mode 100644 index 0000000000..a3835a96cb --- /dev/null +++ b/wii/libogc/libogc/sys_state.inl @@ -0,0 +1,44 @@ +#ifndef __SYS_STATE_INL__ +#define __SYS_STATE_INL__ + +static __inline__ void __sys_state_init() +{ + _sys_state_curr = SYS_STATE_BEFORE_INIT; +} + +static __inline__ void __sys_state_set(u32 sys_state) +{ + _sys_state_curr = sys_state; +} + +static __inline__ u32 __sys_state_get() +{ + return _sys_state_curr; +} + +static __inline__ u32 __sys_state_beforeinit(u32 statecode) +{ + return (statecode==SYS_STATE_BEFORE_INIT); +} + +static __inline__ u32 __sys_state_beforemultitasking(u32 statecode) +{ + return (statecode==SYS_STATE_BEFORE_MT); +} + +static __inline__ u32 __sys_state_beginmultitasking(u32 statecode) +{ + return (statecode==SYS_STATE_BEGIN_MT); +} + +static __inline__ u32 __sys_state_up(u32 statecode) +{ + return (statecode==SYS_STATE_UP); +} + +static __inline__ u32 __sys_state_failed(u32 statecode) +{ + return (statecode==SYS_STATE_FAILED); +} + +#endif diff --git a/wii/libogc/libogc/system.c b/wii/libogc/libogc/system.c new file mode 100644 index 0000000000..9e76ae3e07 --- /dev/null +++ b/wii/libogc/libogc/system.c @@ -0,0 +1,1723 @@ +/*------------------------------------------------------------- + +system.c -- OS functions and initialization + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +#include "asm.h" +#include "irq.h" +#include "exi.h" +#if defined(HW_RVL) +#include "ipc.h" +#include "ios.h" +#include "stm.h" +#include "es.h" +#include "conf.h" +#include "wiilaunch.h" +#endif +#include "cache.h" +#include "video.h" +#include "system.h" +#include "sys_state.h" +#include "lwp_threads.h" +#include "lwp_priority.h" +#include "lwp_watchdog.h" +#include "lwp_wkspace.h" +#include "lwp_objmgr.h" +#include "lwp_config.h" +#include "libversion.h" + +#define SYSMEM1_SIZE 0x01800000 +#if defined(HW_RVL) +#define SYSMEM2_SIZE 0x04000000 +#endif +#define KERNEL_HEAP (1*1024*1024) + +// DSPCR bits +#define DSPCR_DSPRESET 0x0800 // Reset DSP +#define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set +#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) +#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) +#define DSPCR_ARINTMSK 0x0040 +#define DSPCR_ARINT 0x0020 +#define DSPCR_AIINTMSK 0x0010 +#define DSPCR_AIINT 0x0008 +#define DSPCR_HALT 0x0004 // halt DSP +#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt +#define DSPCR_RES 0x0001 // reset DSP + +#define LWP_OBJTYPE_SYSWD 7 + +#define LWP_CHECK_SYSWD(hndl) \ +{ \ + if(((hndl)==SYS_WD_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_SYSWD)) \ + return NULL; \ +} + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +struct _sramcntrl { + u8 srambuf[64]; + u32 offset; + s32 enabled; + s32 locked; + s32 sync; +} sramcntrl ATTRIBUTE_ALIGN(32); + +typedef struct _alarm_st +{ + lwp_obj object; + wd_cntrl alarm; + u64 ticks; + u64 periodic; + u64 start_per; + alarmcallback alarmhandler; + void *cb_arg; +} alarm_st; + +typedef struct _yay0header { + unsigned int id ATTRIBUTE_PACKED; + unsigned int dec_size ATTRIBUTE_PACKED; + unsigned int links_offset ATTRIBUTE_PACKED; + unsigned int chunks_offset ATTRIBUTE_PACKED; +} yay0header; + +static u16 sys_fontenc = 0xffff; +static u32 sys_fontcharsinsheet = 0; +static u8 *sys_fontwidthtab = NULL; +static u8 *sys_fontimage = NULL; +static sys_fontheader *sys_fontdata = NULL; + +static lwp_queue sys_reset_func_queue; +static u32 system_initialized = 0; +static lwp_objinfo sys_alarm_objects; + +static void *__sysarena1lo = NULL; +static void *__sysarena1hi = NULL; + +#if defined(HW_RVL) +static void *__sysarena2lo = NULL; +static void *__sysarena2hi = NULL; +static void *__ipcbufferlo = NULL; +static void *__ipcbufferhi = NULL; +#endif + +static void __RSWDefaultHandler(); +static resetcallback __RSWCallback = NULL; +#if defined(HW_RVL) +static void __POWDefaultHandler(); +static powercallback __POWCallback = NULL; + +static u32 __sys_resetdown = 0; +#endif + +static vu16* const _viReg = (u16*)0xCC002000; +static vu32* const _piReg = (u32*)0xCC003000; +static vu16* const _memReg = (u16*)0xCC004000; +static vu16* const _dspReg = (u16*)0xCC005000; + +void __SYS_ReadROM(void *buf,u32 len,u32 offset); +void* SYS_AllocArena1MemLo(u32 size,u32 align); + +static s32 __sram_sync(void); +static s32 __sram_writecallback(s32 chn,s32 dev); +static s32 __mem_onreset(s32 final); + +extern void __lwp_thread_coreinit(void); +extern void __lwp_sysinit(void); +extern void __heap_init(void); +extern void __exception_init(void); +extern void __exception_closeall(void); +extern void __systemcall_init(void); +extern void __decrementer_init(void); +extern void __lwp_mutex_init(void); +extern void __lwp_cond_init(void); +extern void __lwp_mqbox_init(void); +extern void __lwp_sema_init(void); +extern void __exi_init(void); +extern void __si_init(void); +extern void __irq_init(void); +extern void __lwp_start_multitasking(void); +extern void __timesystem_init(void); +extern void __memlock_init(void); +extern void __libc_init(int); + +extern void __libogc_malloc_lock( struct _reent *ptr ); +extern void __libogc_malloc_unlock( struct _reent *ptr ); + +extern void __exception_console(void); +extern void __exception_printf(const char *str, ...); + +extern void __realmode(void*); +extern void __configMEM1_24Mb(void); +extern void __configMEM1_48Mb(void); +extern void __configMEM2_64Mb(void); +extern void __configMEM2_128Mb(void); +extern void __reset(u32 reset_code); + +extern u32 __IPC_ClntInit(void); +extern u32 __PADDisableRecalibration(s32 disable); + +extern void __console_init_ex(void *conbuffer,int tgt_xstart,int tgt_ystart,int tgt_stride,int con_xres,int con_yres,int con_stride); + +extern int clock_gettime(struct timespec *tp); +extern void timespec_subtract(const struct timespec *tp_start,const struct timespec *tp_end,struct timespec *result); + + +extern int __libogc_lock_init(int *lock,int recursive); +extern int __libogc_lock_close(int *lock); +extern int __libogc_lock_release(int *lock); +extern int __libogc_lock_acquire(int *lock); +extern void __libogc_exit(int status); +extern void * __libogc_sbrk_r(struct _reent *ptr, ptrdiff_t incr); +extern int __libogc_gettod_r(struct _reent *ptr, struct timeval *tp, struct timezone *tz); + +extern u8 __gxregs[]; +extern u8 __text_start[]; +extern u8 __isIPL[]; +extern u8 __Arena1Lo[], __Arena1Hi[]; +#if defined(HW_RVL) +extern u8 __Arena2Lo[], __Arena2Hi[]; +extern u8 __ipcbufferLo[], __ipcbufferHi[]; +#endif + +u8 *__argvArena1Lo = (u8*)0xdeadbeef; + +static u32 __sys_inIPL = (u32)__isIPL; + +static u32 _dsp_initcode[] = +{ + 0x029F0010,0x029F0033,0x029F0034,0x029F0035, + 0x029F0036,0x029F0037,0x029F0038,0x029F0039, + 0x12061203,0x12041205,0x00808000,0x0088FFFF, + 0x00841000,0x0064001D,0x02180000,0x81001C1E, + 0x00441B1E,0x00840800,0x00640027,0x191E0000, + 0x00DEFFFC,0x02A08000,0x029C0028,0x16FC0054, + 0x16FD4348,0x002102FF,0x02FF02FF,0x02FF02FF, + 0x02FF02FF,0x00000000,0x00000000,0x00000000 +}; + +static sys_resetinfo mem_resetinfo = { + {}, + __mem_onreset, + 127 +}; + +static const char *__sys_versiondate; +static const char *__sys_versionbuild; + +static __inline__ alarm_st* __lwp_syswd_open(syswd_t wd) +{ + LWP_CHECK_SYSWD(wd); + return (alarm_st*)__lwp_objmgr_get(&sys_alarm_objects,LWP_OBJMASKID(wd)); +} + +static __inline__ void __lwp_syswd_free(alarm_st *alarm) +{ + __lwp_objmgr_close(&sys_alarm_objects,&alarm->object); + __lwp_objmgr_free(&sys_alarm_objects,&alarm->object); +} + +#ifdef HW_DOL +#define SOFTRESET_ADR *((vu32*)0xCC003024) +void __reload() { SOFTRESET_ADR=0; } + +void __libogc_exit(int status) +{ + SYS_ResetSystem(SYS_SHUTDOWN,0,0); + __lwp_thread_stopmultitasking(__reload); +} +#else +static void (*reload)() = (void(*)())0x80001800; + +static bool __stub_found() +{ + u64 sig = ((u64)(*(u32*)0x80001804) << 32) + *(u32*)0x80001808; + if (sig == 0x5354554248415858ULL) // 'STUBHAXX' + return true; + return false; +} + +void __reload() +{ + if(__stub_found()) { + __exception_closeall(); + reload(); + } + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); +} + +void __libogc_exit(int status) +{ + if(__stub_found()) { + SYS_ResetSystem(SYS_SHUTDOWN,0,0); + __lwp_thread_stopmultitasking(reload); + } + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); +} + +#endif + +static void __init_syscall_array() { + __syscalls.sbrk_r = __libogc_sbrk_r; + __syscalls.lock_init = __libogc_lock_init; + __syscalls.lock_close = __libogc_lock_close; + __syscalls.lock_release = __libogc_lock_release; + __syscalls.lock_acquire = __libogc_lock_acquire; + __syscalls.malloc_lock = __libogc_malloc_lock; + __syscalls.malloc_unlock = __libogc_malloc_unlock; + __syscalls.exit = __libogc_exit; + __syscalls.gettod_r = __libogc_gettod_r; + +} + +static alarm_st* __lwp_syswd_allocate() +{ + alarm_st *alarm; + + __lwp_thread_dispatchdisable(); + alarm = (alarm_st*)__lwp_objmgr_allocate(&sys_alarm_objects); + if(alarm) { + __lwp_objmgr_open(&sys_alarm_objects,&alarm->object); + return alarm; + } + __lwp_thread_dispatchenable(); + return NULL; +} + +static s32 __mem_onreset(s32 final) +{ + if(final==TRUE) { + _memReg[8] = 255; + __UnmaskIrq(IM_MEM0|IM_MEM1|IM_MEM2|IM_MEM3); + } + return 1; +} + +static void __sys_alarmhandler(void *arg) +{ + alarm_st *alarm; + syswd_t thealarm = (syswd_t)arg; + + if(thealarm==SYS_WD_NULL || LWP_OBJTYPE(thealarm)!=LWP_OBJTYPE_SYSWD) return; + + __lwp_thread_dispatchdisable(); + alarm = (alarm_st*)__lwp_objmgr_getnoprotection(&sys_alarm_objects,LWP_OBJMASKID(thealarm)); + if(alarm) { + if(alarm->alarmhandler) alarm->alarmhandler(thealarm,alarm->cb_arg); + if(alarm->periodic) __lwp_wd_insert_ticks(&alarm->alarm,alarm->periodic); + } + __lwp_thread_dispatchunnest(); +} + +#if defined(HW_DOL) +static void __dohotreset(u32 resetcode) +{ + u32 level; + + _CPU_ISR_Disable(level); + _viReg[1] = 0; + ICFlashInvalidate(); + __reset(resetcode<<3); +} +#endif + +static s32 __call_resetfuncs(s32 final) +{ + s32 ret; + sys_resetinfo *info; + lwp_queue *header = &sys_reset_func_queue; + + ret = 1; + info = (sys_resetinfo*)header->first; + while(info!=(sys_resetinfo*)__lwp_queue_tail(header)) { + if(info->func && info->func(final)==0) ret |= (ret<<1); + info = (sys_resetinfo*)info->node.next; + } + if(__sram_sync()==0) ret |= (ret<<1); + + if(ret&~0x01) return 0; + return 1; +} + +#if defined(HW_DOL) +static void __doreboot(u32 resetcode,s32 force_menu) +{ + u32 level; + + _CPU_ISR_Disable(level); + + *((u32*)0x817ffffc) = 0; + *((u32*)0x817ffff8) = 0; + *((u32*)0x800030e2) = 1; +} +#endif + +static void __MEMInterruptHandler() +{ + _memReg[16] = 0; +} + +static void __RSWDefaultHandler() +{ + +} + +#if defined(HW_RVL) +static void __POWDefaultHandler() +{ +} +#endif + +#if defined(HW_DOL) +static void __RSWHandler() +{ + s64 now; + static s64 hold_down = 0; + + hold_down = gettime(); + do { + now = gettime(); + if(diff_usec(hold_down,now)>=100) break; + } while(!(_piReg[0]&0x10000)); + + if(_piReg[0]&0x10000) { + __MaskIrq(IRQMASK(IRQ_PI_RSW)); + + if(__RSWCallback) { + __RSWCallback(); + } + } + _piReg[0] = 2; +} +#endif + +#if defined(HW_RVL) +static void __STMEventHandler(u32 event) +{ + s32 ret; + u32 level; + + if(event==STM_EVENT_RESET) { + ret = SYS_ResetButtonDown(); + if(ret) { + _CPU_ISR_Disable(level); + __sys_resetdown = 1; + __RSWCallback(); + _CPU_ISR_Restore(level); + } + } + + if(event==STM_EVENT_POWER) { + _CPU_ISR_Disable(level); + __POWCallback(); + _CPU_ISR_Restore(level); + } +} +#endif + +void * __attribute__ ((weak)) __myArena1Lo = 0; +void * __attribute__ ((weak)) __myArena1Hi = 0; + +static void __lowmem_init() +{ + u32 *_gx = (u32*)__gxregs; + +#if defined(HW_DOL) + void *ram_start = (void*)0x80000000; + void *ram_end = (void*)(0x80000000|SYSMEM1_SIZE); + void *arena_start = (void*)0x80003000; +#elif defined(HW_RVL) + void *arena_start = (void*)0x80003F00; +#endif + + memset(_gx,0,2048); + memset(arena_start,0,0x100); + if ( __argvArena1Lo == (u8*)0xdeadbeef ) __argvArena1Lo = __Arena1Lo; + if (__myArena1Lo == 0) __myArena1Lo = __argvArena1Lo; + if (__myArena1Hi == 0) __myArena1Hi = __Arena1Hi; + +#if defined(HW_DOL) + memset(ram_start,0,0x100); + *((u32*)(ram_start+0x20)) = 0x0d15ea5e; // magic word "disease" + *((u32*)(ram_start+0x24)) = 1; // version + *((u32*)(ram_start+0x28)) = SYSMEM1_SIZE; // physical memory size + *((u32*)(ram_start+0x2C)) = 1 + ((*(u32*)0xCC00302c)>>28); + + *((u32*)(ram_start+0x30)) = (u32)__myArena1Lo; + *((u32*)(ram_start+0x34)) = (u32)__myArena1Hi; + + *((u32*)(ram_start+0xEC)) = (u32)ram_end; // ram_end (??) + *((u32*)(ram_start+0xF0)) = SYSMEM1_SIZE; // simulated memory size + *((u32*)(ram_start+0xF8)) = TB_BUS_CLOCK; // bus speed: 162 MHz + *((u32*)(ram_start+0xFC)) = TB_CORE_CLOCK; // cpu speed: 486 Mhz + + *((u16*)(arena_start+0xE0)) = 6; // production pads + *((u32*)(arena_start+0xE4)) = 0xC0008000; + + DCFlushRangeNoSync(ram_start, 0x100); +#endif + + DCFlushRangeNoSync(arena_start, 0x100); + DCFlushRangeNoSync(_gx, 2048); + _sync(); + + SYS_SetArenaLo((void*)__myArena1Lo); + SYS_SetArenaHi((void*)__myArena1Hi); +#if defined(HW_RVL) + SYS_SetArena2Lo((void*)__Arena2Lo); + SYS_SetArena2Hi((void*)__Arena2Hi); +#endif +} + +#if defined(HW_RVL) +static void __ipcbuffer_init() +{ + __ipcbufferlo = (void*)__ipcbufferLo; + __ipcbufferhi = (void*)__ipcbufferHi; +} +#endif + +static void __memprotect_init() +{ + u32 level; + + _CPU_ISR_Disable(level); + + __MaskIrq((IM_MEM0|IM_MEM1|IM_MEM2|IM_MEM3)); + + _memReg[16] = 0; + _memReg[8] = 255; + + IRQ_Request(IRQ_MEM0,__MEMInterruptHandler,NULL); + IRQ_Request(IRQ_MEM1,__MEMInterruptHandler,NULL); + IRQ_Request(IRQ_MEM2,__MEMInterruptHandler,NULL); + IRQ_Request(IRQ_MEM3,__MEMInterruptHandler,NULL); + IRQ_Request(IRQ_MEMADDRESS,__MEMInterruptHandler,NULL); + + SYS_RegisterResetFunc(&mem_resetinfo); + __UnmaskIrq(IM_MEMADDRESS); //only enable memaddress irq atm + + _CPU_ISR_Restore(level); +} + +static __inline__ u32 __get_fontsize(void *buffer) +{ + u8 *ptr = (u8*)buffer; + + if(ptr[0]=='Y' && ptr[1]=='a' && ptr[2]=='y') return (((u32*)ptr)[1]); + else return 0; +} + +static u32 __read_rom(void *buf,u32 len,u32 offset) +{ + u32 ret; + u32 loff; + + DCInvalidateRange(buf,len); + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_1,NULL)==0) return 0; + if(EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_1,EXI_SPEED8MHZ)==0) { + EXI_Unlock(EXI_CHANNEL_0); + return 0; + } + + ret = 0; + loff = offset<<6; + if(EXI_Imm(EXI_CHANNEL_0,&loff,4,EXI_WRITE,NULL)==0) ret |= 0x0001; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x0002; + if(EXI_Dma(EXI_CHANNEL_0,buf,len,EXI_READ,NULL)==0) ret |= 0x0004; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x0008; + if(EXI_Deselect(EXI_CHANNEL_0)==0) ret |= 0x0010; + if(EXI_Unlock(EXI_CHANNEL_0)==0) ret |= 0x00020; + + if(ret) return 0; + return 1; +} + +static u32 __getrtc(u32 *gctime) +{ + u32 ret; + u32 cmd; + u32 time; + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_1,NULL)==0) return 0; + if(EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_1,EXI_SPEED8MHZ)==0) { + EXI_Unlock(EXI_CHANNEL_0); + return 0; + } + + ret = 0; + time = 0; + cmd = 0x20000000; + if(EXI_Imm(EXI_CHANNEL_0,&cmd,4,EXI_WRITE,NULL)==0) ret |= 0x01; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x02; + if(EXI_Imm(EXI_CHANNEL_0,&time,4,EXI_READ,NULL)==0) ret |= 0x04; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x08; + if(EXI_Deselect(EXI_CHANNEL_0)==0) ret |= 0x10; + + EXI_Unlock(EXI_CHANNEL_0); + *gctime = time; + if(ret) return 0; + + return 1; +} + +static u32 __sram_read(void *buffer) +{ + u32 command,ret; + + DCInvalidateRange(buffer,64); + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_1,NULL)==0) return 0; + if(EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_1,EXI_SPEED8MHZ)==0) { + EXI_Unlock(EXI_CHANNEL_0); + return 0; + } + + ret = 0; + command = 0x20000100; + if(EXI_Imm(EXI_CHANNEL_0,&command,4,EXI_WRITE,NULL)==0) ret |= 0x01; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x02; + if(EXI_Dma(EXI_CHANNEL_0,buffer,64,EXI_READ,NULL)==0) ret |= 0x04; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x08; + if(EXI_Deselect(EXI_CHANNEL_0)==0) ret |= 0x10; + if(EXI_Unlock(EXI_CHANNEL_0)==0) ret |= 0x20; + + if(ret) return 0; + return 1; +} + +static u32 __sram_write(void *buffer,u32 loc,u32 len) +{ + u32 cmd,ret; + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_1,__sram_writecallback)==0) return 0; + if(EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_1,EXI_SPEED8MHZ)==0) { + EXI_Unlock(EXI_CHANNEL_0); + return 0; + } + + ret = 0; + cmd = 0xa0000100+(loc<<6); + if(EXI_Imm(EXI_CHANNEL_0,&cmd,4,EXI_WRITE,NULL)==0) ret |= 0x01; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x02; + if(EXI_ImmEx(EXI_CHANNEL_0,buffer,len,EXI_WRITE)==0) ret |= 0x04; + if(EXI_Deselect(EXI_CHANNEL_0)==0) ret |= 0x08; + if(EXI_Unlock(EXI_CHANNEL_0)==0) ret |= 0x10; + + if(ret) return 0; + return 1; +} + +static s32 __sram_writecallback(s32 chn,s32 dev) +{ + sramcntrl.sync = __sram_write(sramcntrl.srambuf+sramcntrl.offset,sramcntrl.offset,(64-sramcntrl.offset)); + if(sramcntrl.sync) sramcntrl.offset = 64; + + return 1; +} + +static s32 __sram_sync() +{ + return sramcntrl.sync; +} + +void __sram_init() +{ + sramcntrl.enabled = 0; + sramcntrl.locked = 0; + sramcntrl.sync = __sram_read(sramcntrl.srambuf); + + sramcntrl.offset = 64; +} + +static void DisableWriteGatherPipe() +{ + mtspr(920,(mfspr(920)&~0x40000000)); +} + +static void __buildchecksum(u16 *buffer,u16 *c1,u16 *c2) +{ + u32 i; + + *c1 = 0; + *c2 = 0; + for(i=0;i<4;i++) { + *c1 += buffer[6+i]; + *c2 += buffer[6+i]^-1; + } +} + +static void* __locksram(u32 loc) +{ + u32 level; + + _CPU_ISR_Disable(level); + if(!sramcntrl.locked) { + sramcntrl.enabled = level; + sramcntrl.locked = 1; + return (void*)((u32)sramcntrl.srambuf+loc); + } + _CPU_ISR_Restore(level); + return NULL; +} + +static u32 __unlocksram(u32 write,u32 loc) +{ + syssram *sram = (syssram*)sramcntrl.srambuf; + + if(write) { + if(!loc) { + if((sram->flags&0x03)>0x02) sram->flags = (sram->flags&~0x03); + __buildchecksum((u16*)sramcntrl.srambuf,&sram->checksum,&sram->checksum_inv); + } + if(locsheet_format==0x0000) { + cnt = (sys_fontdata->sheet_fullsize/2)-1; + + while(cnt>=0) { + idx = _SHIFTR(src[cnt],6,2); + val1 = data[idx]; + + idx = _SHIFTR(src[cnt],4,2); + val2 = data[idx]; + + dest[(cnt<<1)+0] =((val1&0xf0)|(val2&0x0f)); + + idx = _SHIFTR(src[cnt],2,2); + val1 = data[idx]; + + idx = _SHIFTR(src[cnt],0,2); + val2 = data[idx]; + + dest[(cnt<<1)+1] =((val1&0xf0)|(val2&0x0f)); + + cnt--; + } + } + DCStoreRange(dest,sys_fontdata->sheet_fullsize); +} + +static void __dsp_bootstrap() +{ + u16 status; + u32 tick; + + memcpy(SYS_GetArenaHi()-128,(void*)0x81000000,128); + memcpy((void*)0x81000000,_dsp_initcode,128); + DCFlushRange((void*)0x81000000,128); + + _dspReg[9] = 67; + _dspReg[5] = (DSPCR_DSPRESET|DSPCR_DSPINT|DSPCR_ARINT|DSPCR_AIINT|DSPCR_HALT); + _dspReg[5] |= DSPCR_RES; + while(_dspReg[5]&DSPCR_RES); + + _dspReg[0] = 0; + while((_SHIFTL(_dspReg[2],16,16)|(_dspReg[3]&0xffff))&0x80000000); + + ((u32*)_dspReg)[8] = 0x01000000; + ((u32*)_dspReg)[9] = 0; + ((u32*)_dspReg)[10] = 32; + + status = _dspReg[5]; + while(!(status&DSPCR_ARINT)) status = _dspReg[5]; + _dspReg[5] = status; + + tick = gettick(); + while((gettick()-tick)<2194); + + ((u32*)_dspReg)[8] = 0x01000000; + ((u32*)_dspReg)[9] = 0; + ((u32*)_dspReg)[10] = 32; + + status = _dspReg[5]; + while(!(status&DSPCR_ARINT)) status = _dspReg[5]; + _dspReg[5] = status; + + _dspReg[5] &= ~DSPCR_DSPRESET; + while(_dspReg[5]&0x400); + + _dspReg[5] &= ~DSPCR_HALT; + while(!(_dspReg[2]&0x8000)); + status = _dspReg[3]; + + _dspReg[5] |= DSPCR_HALT; + _dspReg[5] = (DSPCR_DSPRESET|DSPCR_DSPINT|DSPCR_ARINT|DSPCR_AIINT|DSPCR_HALT); + _dspReg[5] |= DSPCR_RES; + while(_dspReg[5]&DSPCR_RES); + + memcpy((void*)0x81000000,SYS_GetArenaHi()-128,128); +#ifdef _SYS_DEBUG + printf("__audiosystem_init(finish)\n"); +#endif +} + +static void __dsp_shutdown() +{ + u32 tick; + + _dspReg[5] = (DSPCR_DSPRESET|DSPCR_HALT); + _dspReg[27] &= ~0x8000; + while(_dspReg[5]&0x400); + while(_dspReg[5]&0x200); + + _dspReg[5] = (DSPCR_DSPRESET|DSPCR_DSPINT|DSPCR_ARINT|DSPCR_AIINT|DSPCR_HALT); + _dspReg[0] = 0; + while((_SHIFTL(_dspReg[2],16,16)|(_dspReg[3]&0xffff))&0x80000000); + + tick = gettick(); + while((gettick()-tick)<44); + + _dspReg[5] |= DSPCR_RES; + while(_dspReg[5]&DSPCR_RES); +} + +static void decode_szp(void *src,void *dest) +{ + u32 i,k,link; + u8 *dest8,*tmp; + u32 loff,coff,roff; + u32 size,cnt,cmask,bcnt; + yay0header *header; + + dest8 = (u8*)dest; + header = (yay0header*)src; + size = header->dec_size; + loff = header->links_offset; + coff = header->chunks_offset; + + roff = sizeof(yay0header); + cmask = 0; + cnt = 0; + bcnt = 0; + + do { + if(!bcnt) { + cmask = *(u32*)(src+roff); + roff += 4; + bcnt = 32; + } + + if(cmask&0x80000000) { + dest8[cnt++] = *(u8*)(src+coff); + coff++; + } else { + link = *(u16*)(src+loff); + loff += 2; + + tmp = dest8+(cnt-(link&0x0fff)-1); + k = link>>12; + if(k==0) { + k = (*(u8*)(src+coff))+18; + coff++; + } else k += 2; + + for(i=0;i0) { + cpy_cnt = (len>256)?256:len; + while(__read_rom(buf,cpy_cnt,offset)==0); + offset += cpy_cnt; + buf += cpy_cnt; + len -= cpy_cnt; + } +} + +u32 __SYS_GetRTC(u32 *gctime) +{ + u32 cnt,ret; + u32 time1,time2; + + cnt = 0; + ret = 0; + while(cnt<16) { + if(__getrtc(&time1)==0) ret |= 0x01; + if(__getrtc(&time2)==0) ret |= 0x02; + if(ret) return 0; + if(time1==time2) { + *gctime = time1; + return 1; + } + cnt++; + } + return 0; +} + +void __SYS_SetTime(s64 time) +{ + u32 level; + s64 now; + s64 *pBootTime = (s64*)0x800030d8; + + _CPU_ISR_Disable(level); + now = gettime(); + now -= time; + now += *pBootTime; + *pBootTime = now; + settime(now); + EXI_ProbeReset(); + _CPU_ISR_Restore(level); +} + +s64 __SYS_GetSystemTime() +{ + u32 level; + s64 now; + s64 *pBootTime = (s64*)0x800030d8; + + _CPU_ISR_Disable(level); + now = gettime(); + now += *pBootTime; + _CPU_ISR_Restore(level); + return now; +} + +void __SYS_SetBootTime() +{ + u32 gctime; + + __SYS_LockSram(); + __SYS_GetRTC(&gctime); + __SYS_SetTime(secs_to_ticks(gctime)); + __SYS_UnlockSram(0); +} + +u32 __SYS_LoadFont(void *src,void *dest) +{ + if(__read_font(src)==0) return 0; + + decode_szp(src,dest); + + sys_fontdata = (sys_fontheader*)dest; + sys_fontwidthtab = (u8*)dest+sys_fontdata->width_table; + sys_fontcharsinsheet = sys_fontdata->sheet_column*sys_fontdata->sheet_row; + + /* TODO: implement SJIS handling */ + return 1; +} + +#if defined(HW_RVL) +void* __SYS_GetIPCBufferLo() +{ + return __ipcbufferlo; +} + +void* __SYS_GetIPCBufferHi() +{ + return __ipcbufferhi; +} + +#endif + +void _V_EXPORTNAME(void) +{ __sys_versionbuild = _V_STRING; __sys_versiondate = _V_DATE_; } + +#if defined(HW_RVL) +void __SYS_DoPowerCB(void) +{ + u32 level; + powercallback powcb; + + _CPU_ISR_Disable(level); + powcb = __POWCallback; + __POWCallback = __POWDefaultHandler; + powcb(); + _CPU_ISR_Restore(level); +} +#endif + +void __SYS_InitCallbacks() +{ +#if defined(HW_RVL) + __POWCallback = __POWDefaultHandler; + __sys_resetdown = 0; +#endif + __RSWCallback = __RSWDefaultHandler; +} + +void __attribute__((weak)) __SYS_PreInit() +{ + +} + +void SYS_Init() +{ + u32 level; + + _CPU_ISR_Disable(level); + + __SYS_PreInit(); + + if(system_initialized) return; + system_initialized = 1; + + _V_EXPORTNAME(); + + __init_syscall_array(); + __lowmem_init(); +#if defined(HW_RVL) + __ipcbuffer_init(); +#endif + __lwp_wkspace_init(KERNEL_HEAP); + __lwp_queue_init_empty(&sys_reset_func_queue); + __lwp_objmgr_initinfo(&sys_alarm_objects,LWP_MAX_WATCHDOGS,sizeof(alarm_st)); + __sys_state_init(); + __lwp_priority_init(); + __lwp_watchdog_init(); + __exception_init(); + __systemcall_init(); + __decrementer_init(); + __irq_init(); + __exi_init(); + __sram_init(); + __si_init(); + __lwp_thread_coreinit(); + __lwp_sysinit(); + __memlock_init(); + __lwp_mqbox_init(); + __lwp_sema_init(); + __lwp_mutex_init(); + __lwp_cond_init(); + __timesystem_init(); + __dsp_bootstrap(); + + if(!__sys_inIPL) + __memprotect_init(); + +#ifdef SDLOADER_FIX + __SYS_SetBootTime(); +#endif + DisableWriteGatherPipe(); + __SYS_InitCallbacks(); +#if defined(HW_RVL) + __IPC_ClntInit(); +#elif defined(HW_DOL) + IRQ_Request(IRQ_PI_RSW,__RSWHandler,NULL); + __MaskIrq(IRQMASK(IRQ_PI_RSW)); +#endif + __libc_init(1); + __lwp_thread_startmultitasking(); + _CPU_ISR_Restore(level); +} + +// This function gets called inside the main thread, prior to the application's main() function +void SYS_PreMain() +{ +#if defined(HW_RVL) + u32 i; + + for (i = 0; i < 32; ++i) + IOS_Close(i); + + __IOS_LoadStartupIOS(); + __IOS_InitializeSubsystems(); + STM_RegisterEventHandler(__STMEventHandler); + CONF_Init(); + WII_Initialize(); +#endif +} + +u32 SYS_ResetButtonDown() +{ + return (!(_piReg[0]&0x00010000)); +} + +#if defined(HW_DOL) +void SYS_ResetSystem(s32 reset,u32 reset_code,s32 force_menu) +{ + u32 ret = 0; + syssram *sram; + + __dsp_shutdown(); + + if(reset==SYS_SHUTDOWN) { + ret = __PADDisableRecalibration(TRUE); + } + + while(__call_resetfuncs(FALSE)==0); + + if(reset==SYS_HOTRESET && force_menu==TRUE) { + sram = __SYS_LockSram(); + sram->flags |= 0x40; + __SYS_UnlockSram(TRUE); + while(!__SYS_SyncSram()); + } + + __exception_closeall(); + __call_resetfuncs(TRUE); + + LCDisable(); + + __lwp_thread_dispatchdisable(); + if(reset==SYS_HOTRESET) { + __dohotreset(reset_code); + } else if(reset==SYS_RESTART) { + __lwp_thread_closeall(); + __lwp_thread_dispatchunnest(); + __doreboot(reset_code,force_menu); + } + + __lwp_thread_closeall(); + + memset((void*)0x80000040,0,140); + memset((void*)0x800000D4,0,20); + memset((void*)0x800000F4,0,4); + memset((void*)0x80003000,0,192); + memset((void*)0x800030C8,0,12); + memset((void*)0x800030E2,0,1); + + __PADDisableRecalibration(ret); +} +#endif + +#if defined(HW_RVL) + +void SYS_ResetSystem(s32 reset,u32 reset_code,s32 force_menu) +{ + u32 ret = 0; + + __dsp_shutdown(); + + if(reset==SYS_SHUTDOWN) { + ret = __PADDisableRecalibration(TRUE); + } + + while(__call_resetfuncs(FALSE)==0); + + switch(reset) { + case SYS_RESTART: + STM_RebootSystem(); + break; + case SYS_POWEROFF: + if(CONF_GetShutdownMode() == CONF_SHUTDOWN_IDLE) { + ret = CONF_GetIdleLedMode(); + if(ret <= 2) STM_SetLedMode(ret); + STM_ShutdownToIdle(); + } else { + STM_ShutdownToStandby(); + } + break; + case SYS_POWEROFF_STANDBY: + STM_ShutdownToStandby(); + break; + case SYS_POWEROFF_IDLE: + ret = CONF_GetIdleLedMode(); + if(ret >= 0 && ret <= 2) STM_SetLedMode(ret); + STM_ShutdownToIdle(); + break; + case SYS_RETURNTOMENU: + WII_ReturnToMenu(); + break; + } + + //TODO: implement SYS_HOTRESET + // either restart failed or this is SYS_SHUTDOWN + + __IOS_ShutdownSubsystems(); + + __exception_closeall(); + __call_resetfuncs(TRUE); + + LCDisable(); + + __lwp_thread_dispatchdisable(); + __lwp_thread_closeall(); + + memset((void*)0x80000040,0,140); + memset((void*)0x800000D4,0,20); + memset((void*)0x800000F4,0,4); + memset((void*)0x80003000,0,192); + memset((void*)0x800030C8,0,12); + memset((void*)0x800030E2,0,1); + + __PADDisableRecalibration(ret); +} +#endif + +void SYS_RegisterResetFunc(sys_resetinfo *info) +{ + u32 level; + sys_resetinfo *after; + lwp_queue *header = &sys_reset_func_queue; + + _CPU_ISR_Disable(level); + for(after=(sys_resetinfo*)header->first;after->node.next!=NULL && info->prio>=after->prio;after=(sys_resetinfo*)after->node.next); + __lwp_queue_insertI(after->node.prev,&info->node); + _CPU_ISR_Restore(level); +} + +void SYS_UnregisterResetFunc(sys_resetinfo *info) { + u32 level; + lwp_node *n; + + _CPU_ISR_Disable(level); + for (n = sys_reset_func_queue.first; n->next; n = n->next) { + if (n == &info->node) { + __lwp_queue_extractI(n); + break; + } + } + _CPU_ISR_Restore(level); +} + +void SYS_SetArena1Lo(void *newLo) +{ + u32 level; + + _CPU_ISR_Disable(level); + __sysarena1lo = newLo; + _CPU_ISR_Restore(level); +} + +void* SYS_GetArena1Lo() +{ + u32 level; + void *arenalo; + + _CPU_ISR_Disable(level); + arenalo = __sysarena1lo; + _CPU_ISR_Restore(level); + + return arenalo; +} + +void SYS_SetArena1Hi(void *newHi) +{ + u32 level; + + _CPU_ISR_Disable(level); + __sysarena1hi = newHi; + _CPU_ISR_Restore(level); +} + +void* SYS_GetArena1Hi() +{ + u32 level; + void *arenahi; + + _CPU_ISR_Disable(level); + arenahi = __sysarena1hi; + _CPU_ISR_Restore(level); + + return arenahi; +} + +u32 SYS_GetArena1Size() +{ + u32 level,size; + + _CPU_ISR_Disable(level); + size = ((u32)__sysarena1hi - (u32)__sysarena1lo); + _CPU_ISR_Restore(level); + + return size; +} + +void* SYS_AllocArena1MemLo(u32 size,u32 align) +{ + u32 mem1lo; + void *ptr = NULL; + + mem1lo = (u32)SYS_GetArena1Lo(); + ptr = (void*)((mem1lo+(align-1))&~(align-1)); + mem1lo = ((((u32)ptr+size+align)-1)&~(align-1)); + SYS_SetArena1Lo((void*)mem1lo); + + return ptr; +} + +#if defined(HW_RVL) +void SYS_SetArena2Lo(void *newLo) +{ + u32 level; + + _CPU_ISR_Disable(level); + __sysarena2lo = newLo; + _CPU_ISR_Restore(level); +} + +void* SYS_GetArena2Lo() +{ + u32 level; + void *arenalo; + + _CPU_ISR_Disable(level); + arenalo = __sysarena2lo; + _CPU_ISR_Restore(level); + + return arenalo; +} + +void SYS_SetArena2Hi(void *newHi) +{ + u32 level; + + _CPU_ISR_Disable(level); + __sysarena2hi = newHi; + _CPU_ISR_Restore(level); +} + +void* SYS_GetArena2Hi() +{ + u32 level; + void *arenahi; + + _CPU_ISR_Disable(level); + arenahi = __sysarena2hi; + _CPU_ISR_Restore(level); + + return arenahi; +} + +u32 SYS_GetArena2Size() +{ + u32 level,size; + + _CPU_ISR_Disable(level); + size = ((u32)__sysarena2hi - (u32)__sysarena2lo); + _CPU_ISR_Restore(level); + + return size; +} + +void* SYS_AllocArena2MemLo(u32 size,u32 align) +{ + u32 mem2lo; + void *ptr = NULL; + + mem2lo = (u32)SYS_GetArena2Lo(); + ptr = (void*)((mem2lo+(align-1))&~(align-1)); + mem2lo = ((((u32)ptr+size+align)-1)&~(align-1)); + SYS_SetArena2Lo((void*)mem2lo); + + return ptr; +} +#endif + +void SYS_ProtectRange(u32 chan,void *addr,u32 bytes,u32 cntrl) +{ + u16 rcntrl; + u32 pstart,pend,level; + + if(chansheet_image)+31)&~31); + __expand_font((u8*)font_data+font_data->sheet_image,sys_fontimage); + return 1; + } + + return 0; +} + +void SYS_GetFontTexture(s32 c,void **image,s32 *xpos,s32 *ypos,s32 *width) +{ + u32 sheets,rem; + + *xpos = 0; + *ypos = 0; + *image = NULL; + if(!sys_fontwidthtab || ! sys_fontimage) return; + + if(cfirst_char || c>sys_fontdata->last_char) c = sys_fontdata->inval_char; + else c -= sys_fontdata->first_char; + + sheets = c/sys_fontcharsinsheet; + rem = c%sys_fontcharsinsheet; + *image = sys_fontimage+(sys_fontdata->sheet_size*sheets); + *xpos = (rem%sys_fontdata->sheet_column)*sys_fontdata->cell_width; + *ypos = (rem/sys_fontdata->sheet_column)*sys_fontdata->cell_height; + *width = sys_fontwidthtab[c]; +} + +void SYS_GetFontTexel(s32 c,void *image,s32 pos,s32 stride,s32 *width) +{ + u32 sheets,rem; + u32 xoff,yoff; + u32 xpos,ypos; + u8 *img_start; + u8 *ptr1,*ptr2; + + if(!sys_fontwidthtab || ! sys_fontimage) return; + + if(cfirst_char || c>sys_fontdata->last_char) c = sys_fontdata->inval_char; + else c -= sys_fontdata->first_char; + + sheets = c/sys_fontcharsinsheet; + rem = c%sys_fontcharsinsheet; + xoff = (rem%sys_fontdata->sheet_column)*sys_fontdata->cell_width; + yoff = (rem/sys_fontdata->sheet_column)*sys_fontdata->cell_height; + img_start = sys_fontimage+(sys_fontdata->sheet_size*sheets); + + ypos = 0; + while(yposcell_height) { + xpos = 0; + while(xposcell_width) { + ptr1 = img_start+(((sys_fontdata->sheet_width/8)<<5)*((ypos+yoff)/8)); + ptr1 = ptr1+(((xpos+xoff)/8)<<5); + ptr1 = ptr1+(((ypos+yoff)%8)<<2); + ptr1 = ptr1+(((xpos+xoff)%8)/2); + + ptr2 = image+((ypos/8)*(((stride<<1)/8)<<5)); + ptr2 = ptr2+(((xpos+pos)/8)<<5); + ptr2 = ptr2+(((xpos+pos)%8)/2); + ptr2 = ptr2+((ypos%8)<<2); + + *ptr2 = *ptr1; + + xpos += 2; + } + ypos++; + } + *width = sys_fontwidthtab[c]; +} + +s32 SYS_CreateAlarm(syswd_t *thealarm) +{ + alarm_st *alarm; + + alarm = __lwp_syswd_allocate(); + if(!alarm) return -1; + + alarm->alarmhandler = NULL; + alarm->ticks = 0; + alarm->start_per = 0; + alarm->periodic = 0; + + *thealarm = (LWP_OBJMASKTYPE(LWP_OBJTYPE_SYSWD)|LWP_OBJMASKID(alarm->object.id)); + __lwp_thread_dispatchenable(); + return 0; +} + +s32 SYS_SetAlarm(syswd_t thealarm,const struct timespec *tp,alarmcallback cb,void *cbarg) +{ + alarm_st *alarm; + + alarm = __lwp_syswd_open(thealarm); + if(!alarm) return -1; + + alarm->cb_arg = cbarg; + alarm->alarmhandler = cb; + alarm->ticks = __lwp_wd_calc_ticks(tp); + + alarm->periodic = 0; + alarm->start_per = 0; + + __lwp_wd_initialize(&alarm->alarm,__sys_alarmhandler,alarm->object.id,(void*)thealarm); + __lwp_wd_insert_ticks(&alarm->alarm,alarm->ticks); + __lwp_thread_dispatchenable(); + return 0; +} + +s32 SYS_SetPeriodicAlarm(syswd_t thealarm,const struct timespec *tp_start,const struct timespec *tp_period,alarmcallback cb,void *cbarg) +{ + alarm_st *alarm; + + alarm = __lwp_syswd_open(thealarm); + if(!alarm) return -1; + + alarm->start_per = __lwp_wd_calc_ticks(tp_start); + alarm->periodic = __lwp_wd_calc_ticks(tp_period); + alarm->alarmhandler = cb; + alarm->cb_arg = cbarg; + + alarm->ticks = 0; + + __lwp_wd_initialize(&alarm->alarm,__sys_alarmhandler,alarm->object.id,(void*)thealarm); + __lwp_wd_insert_ticks(&alarm->alarm,alarm->start_per); + __lwp_thread_dispatchenable(); + return 0; +} + +s32 SYS_RemoveAlarm(syswd_t thealarm) +{ + alarm_st *alarm; + + alarm = __lwp_syswd_open(thealarm); + if(!alarm) return -1; + + alarm->alarmhandler = NULL; + alarm->ticks = 0; + alarm->periodic = 0; + alarm->start_per = 0; + + __lwp_wd_remove_ticks(&alarm->alarm); + __lwp_syswd_free(alarm); + __lwp_thread_dispatchenable(); + return 0; +} + +s32 SYS_CancelAlarm(syswd_t thealarm) +{ + alarm_st *alarm; + + alarm = __lwp_syswd_open(thealarm); + if(!alarm) return -1; + + alarm->alarmhandler = NULL; + alarm->ticks = 0; + alarm->periodic = 0; + alarm->start_per = 0; + + __lwp_wd_remove_ticks(&alarm->alarm); + __lwp_thread_dispatchenable(); + return 0; +} + +resetcallback SYS_SetResetCallback(resetcallback cb) +{ + u32 level; + resetcallback old; + + _CPU_ISR_Disable(level); + old = __RSWCallback; + __RSWCallback = cb; +#if defined(HW_DOL) + if(__RSWCallback) { + _piReg[0] = 2; + __UnmaskIrq(IRQMASK(IRQ_PI_RSW)); + } else + __MaskIrq(IRQMASK(IRQ_PI_RSW)); +#endif + _CPU_ISR_Restore(level); + return old; +} + +#if defined(HW_RVL) +powercallback SYS_SetPowerCallback(powercallback cb) +{ + u32 level; + powercallback old; + + _CPU_ISR_Disable(level); + old = __POWCallback; + __POWCallback = cb; + _CPU_ISR_Restore(level); + return old; +} +#endif + +void SYS_StartPMC(u32 mcr0val,u32 mcr1val) +{ + mtmmcr0(mcr0val); + mtmmcr1(mcr1val); +} + +void SYS_StopPMC() +{ + mtmmcr0(0); + mtmmcr1(0); +} + +void SYS_ResetPMC() +{ + mtpmc1(0); + mtpmc2(0); + mtpmc3(0); + mtpmc4(0); +} + +void SYS_DumpPMC() +{ + printf("<%lu load/stores / %lu miss cycles / %lu cycles / %lu instructions>\n",mfpmc1(),mfpmc2(),mfpmc3(),mfpmc4()); +} + +void SYS_SetWirelessID(u32 chan,u32 id) +{ + u32 write; + syssramex *sram; + + write = 0; + sram = __SYS_LockSramEx(); + if(sram->wirelessPad_id[chan]!=(u16)id) { + sram->wirelessPad_id[chan] = (u16)id; + write = 1; + } + __SYS_UnlockSramEx(write); +} + +u32 SYS_GetWirelessID(u32 chan) +{ + u16 id; + syssramex *sram; + + id = 0; + sram = __SYS_LockSramEx(); + id = sram->wirelessPad_id[chan]; + __SYS_UnlockSramEx(0); + return id; +} + +#if defined(HW_RVL) +u32 SYS_GetHollywoodRevision() +{ + u32 rev; + DCInvalidateRange((void*)0x80003138,8); + rev = *((u32*)0x80003138); + return rev; +} +#endif + +u64 SYS_Time() +{ + u64 current_time = 0; + u32 gmtime =0; + __SYS_GetRTC(&gmtime); + current_time = gmtime; +#ifdef HW_RVL + u32 bias; + if (CONF_GetCounterBias(&bias) >= 0) + current_time += bias; +#else + syssram* sram = __SYS_LockSram(); + current_time += sram->counter_bias; + __SYS_UnlockSram(0); +#endif + return (TB_TIMER_CLOCK * 1000) * current_time; +} diff --git a/wii/libogc/libogc/system_asm.S b/wii/libogc/libogc/system_asm.S new file mode 100644 index 0000000000..2b8580ca7e --- /dev/null +++ b/wii/libogc/libogc/system_asm.S @@ -0,0 +1,380 @@ +#include + + .globl __realmode +__realmode: + clrlwi r3,r3,2 + mtsrr0 r3 + mfmsr r3 + rlwinm r3,r3,0,28,25 + mtsrr1 r3 + rfi + + // complete init sequence taken from bootmii's ppc skeleton. thanks to segher + // after a talk with dhewg we came to that point that it's good to wipe+setup BATS correctly + .globl __configBATS +__configBATS: + // HID0 = 00110c64: + // bus checkstops off, sleep modes off, + // caches off, caches invalidate, + // store gathering off, enable data cache + // flush assist, enable branch target cache, + // enable branch history table + lis r3,0x0011 + ori r3,r3,0x0c64 + mtspr HID0,r3 + isync + +#if defined(HW_RVL) + lis r3,0x8200 //bits set: H4A(HID4 access), SBE(2nd BAT enabled) + mtspr HID4,r3 + isync +#endif + + // clear all BATs + li r0,0 + mtspr IBAT0U,r0; mtspr IBAT1U,r0; mtspr IBAT2U,r0; mtspr IBAT3U,r0 // IBAT0...3 + mtspr DBAT0U,r0; mtspr DBAT1U,r0; mtspr DBAT2U,r0; mtspr DBAT3U,r0 // DBAT0...3 +#if defined(HW_RVL) + mtspr IBAT4U,r0; mtspr IBAT5U,r0; mtspr IBAT6U,r0; mtspr IBAT7U,r0 // IBAT4...7 + mtspr DBAT4U,r0; mtspr DBAT5U,r0; mtspr DBAT6U,r0; mtspr DBAT7U,r0 // DBAT4...7 +#endif + isync + + // clear all SRs + lis r0,0x8000 + mtsr 0,r0; mtsr 1,r0; mtsr 2,r0; mtsr 3,r0; mtsr 4,r0; mtsr 5,r0; mtsr 6,r0 + mtsr 7,r0; mtsr 8,r0; mtsr 9,r0; mtsr 10,r0; mtsr 11,r0; mtsr 12,r0; mtsr 13,r0 + mtsr 14,r0; mtsr 15,r0 + isync + + // set [DI]BAT0 for 256MB@80000000, + // real 00000000, WIMG=0000, R/W + li r3,2 + lis r4,0x8000 + ori r4,r4,0x1fff + mtspr IBAT0L,r3 + mtspr IBAT0U,r4 + mtspr DBAT0L,r3 + mtspr DBAT0U,r4 + isync + +#if defined(HW_RVL) + // set [DI]BAT4 for 256MB@90000000, + // real 10000000, WIMG=0000, R/W + addis r3,r3,0x1000 + addis r4,r4,0x1000 + mtspr IBAT4L,r3 + mtspr IBAT4U,r4 + mtspr DBAT4L,r3 + mtspr DBAT4U,r4 + isync +#endif + + // set DBAT1 for 256MB@c0000000, + // real 00000000, WIMG=0101, R/W + li r3,0x2a + lis r4,0xc000 + ori r4,r4,0x1fff + mtspr DBAT1L,r3 + mtspr DBAT1U,r4 + isync + +#if defined(HW_RVL) + // set DBAT5 for 256MB@d0000000, + // real 10000000, WIMG=0101, R/W + addis r3,r3,0x1000 + addis r4,r4,0x1000 + mtspr DBAT5L,r3 + mtspr DBAT5U,r4 + isync +#endif + + mfmsr r3 + ori r3,r3,MSR_DR|MSR_IR + mtsrr1 r3 + mflr r3 + oris r3,r3,0x8000 + mtsrr0 r3 + rfi + + .globl __InitFPRS +__InitFPRS: + # Enable the Floating Point Registers + mfmsr r3 + ori r3,r3,MSR_FP + mtmsr r3 + mfspr r3,920 + extrwi. r3,r3,1,2 + beq 1f + + # Clear all of the PS FPR's to 0 + lis r3,zeroPS@ha + addi r3,r3,zeroPS@l + psq_l fr0,0(r3),0,0 + ps_mr fr1,fr0 + ps_mr fr2,fr0 + ps_mr fr3,fr0 + ps_mr fr4,fr0 + ps_mr fr5,fr0 + ps_mr fr6,fr0 + ps_mr fr7,fr0 + ps_mr fr8,fr0 + ps_mr fr9,fr0 + ps_mr fr10,fr0 + ps_mr fr11,fr0 + ps_mr fr12,fr0 + ps_mr fr13,fr0 + ps_mr fr14,fr0 + ps_mr fr15,fr0 + ps_mr fr16,fr0 + ps_mr fr17,fr0 + ps_mr fr18,fr0 + ps_mr fr19,fr0 + ps_mr fr20,fr0 + ps_mr fr21,fr0 + ps_mr fr22,fr0 + ps_mr fr23,fr0 + ps_mr fr24,fr0 + ps_mr fr25,fr0 + ps_mr fr26,fr0 + ps_mr fr27,fr0 + ps_mr fr28,fr0 + ps_mr fr29,fr0 + ps_mr fr30,fr0 + ps_mr fr31,fr0 + + # Clear all of the FPR's to 0 +1: lis r3,zeroF@ha + lfd fr0,zeroF@l(r3) + fmr fr1,fr0 + fmr fr2,fr0 + fmr fr3,fr0 + fmr fr4,fr0 + fmr fr5,fr0 + fmr fr6,fr0 + fmr fr7,fr0 + fmr fr8,fr0 + fmr fr9,fr0 + fmr fr10,fr0 + fmr fr11,fr0 + fmr fr12,fr0 + fmr fr13,fr0 + fmr fr14,fr0 + fmr fr15,fr0 + fmr fr16,fr0 + fmr fr17,fr0 + fmr fr18,fr0 + fmr fr19,fr0 + fmr fr20,fr0 + fmr fr21,fr0 + fmr fr22,fr0 + fmr fr23,fr0 + fmr fr24,fr0 + fmr fr25,fr0 + fmr fr26,fr0 + fmr fr27,fr0 + fmr fr28,fr0 + fmr fr29,fr0 + fmr fr30,fr0 + fmr fr31,fr0 + mtfsf 255,fr0 + + # Return + blr + + .extern ICFlashInvalidate + .globl __InitPS +__InitPS: + mflr r0 + stw r0,4(sp) + stwu sp,-8(sp) + mfspr r3,HID2 + oris r3,r3,0xA000 + mtspr HID2,r3 + isync + bl ICFlashInvalidate + sync + li r3,0 + mtspr GQR0,r3 + mtspr GQR1,r3 + mtspr GQR2,r3 + mtspr GQR3,r3 + mtspr GQR4,r3 + mtspr GQR5,r3 + mtspr GQR6,r3 + mtspr GQR7,r3 + isync + lwz r0,12(sp) + addi sp,sp,8 + mtlr r0 + blr + + .extern ICEnable + .extern DCEnable + .extern L2Init + .extern L2Enable + .globl __InitCache +__InitCache: + mflr r0 + stw r0, 4(sp) + stwu sp, -16(sp) + stw r31, 12(sp) + + mfspr r3,HID0 + rlwinm. r0,r3, 0, 16, 16 // Check if the Instruction Cache has been enabled or not. + bne ICEnabled + + bl ICEnable +ICEnabled: + mfspr r3, HID0 + rlwinm. r0, r3, 0, 17, 17 // Check if the Data Cache has been enabled or not. + bne DCEnabled + + bl DCEnable +DCEnabled: + + mfspr r3, L2CR + clrrwi. r0, r3, 31 // Check if the Locked Cache has been enabled or not. + bne L2Enabled + + bl L2Init + bl L2Enable + +L2Enabled: + # Restore the non-volatile registers to their previous values and return. + lwz r0, 20(sp) + lwz r31, 12(sp) + addi sp, sp, 16 + mtlr r0 + blr + + .globl __InitSystem +__InitSystem: + mflr r0 + stw r0, 4(sp) + stwu sp, -24(sp) + stmw r29, 12(sp) + + # Disable interrupts! + mfmsr r3 + rlwinm r4,r3,0,17,15 + rlwinm r4,r4,0,26,24 + mtmsr r4 + + # Clear various SPR's + li r3,0 + mtspr 952, r3 + mtspr 956, r3 + mtspr 953, r3 + mtspr 954, r3 + mtspr 957, r3 + mtspr 958, r3 + isync + +#if defined(HW_RVL) + mfspr r3,HID4 + oris r3,r3,0x0190 //set additional bits in HID4: SR0(store 0), LPE(PS LE exception), L2CFI(L2 castout prior to L2 inv. flash) + mtspr HID4,r3 + isync +#endif + + # Disable Speculative Bus Accesses to non-guarded space from both caches. + mfspr r3, HID0 + ori r3, r3, 0x0200 + mtspr HID0, r3 + isync + + # Set the Non-IEEE mode in the FPSCR + mtfsb1 29 + + # Disable Write Gather Pipe + mfspr r3,HID2 # (HID2) + rlwinm r3, r3, 0, 2, 0 + mtspr HID2,r3 # (HID2) + isync + + # Restore the non-volatile registers to their previous values and return. + lwz r0, 28(sp) + lmw r29,12(sp) + addi sp, sp, 24 + mtlr r0 + blr + + .globl __flush_cache +__flush_cache: + lis r5,0xffff + ori r5,r5,0xfff1 + and r5,r5,r3 + subf r3,r5,r3 + add r4,r4,r3 +1: dcbst r0,r5 + sync + icbi r0,r5 + addic r5,r5,8 + subic. r4,r4,8 + bge 1b + sync + blr + + .globl __reset +__reset: + b 1f +9: mfspr r8,HID0 + ori r8,r8,0x0008 + mtspr HID0,r8 + isync + sync + nop + b 2f +1: b 3f +2: mftb r5 +4: mftb r6 + subf r7,r5,r6 + cmplwi r7,0x1124 + blt 4b + nop + b 5f +3: b 6f +5: lis r8,0xCC00 + ori r8,r8,0x3000 + li r4,3 + stw r4,36(r8) + stw r3,36(r8) + nop + b 7f +6: b 8f +7: nop + b 7b +8: b 9b + + .globl __InitBATS +__InitBATS: + mflr r31 + oris r31,r31,0x8000 + lis r3,__configBATS@h + ori r3,r3,__configBATS@l + bl __realmode + mtlr r31 + blr + + .globl SYS_SwitchFiber +SYS_SwitchFiber: + mflr r0 + mr r9,sp + stwu r9,-8(r8) + mr sp,r8 + stw r0,4(r9) + mtlr r7 + blrl + lwz r5,0(sp) + lwz r0,4(r5) + mtlr r0 + mr sp,r5 + blr + + .section .data + .balign 4 +zeroF: + .double 0.0 +zeroPS: + .float 0.0,0.0 diff --git a/wii/libogc/libogc/texconv.c b/wii/libogc/libogc/texconv.c new file mode 100644 index 0000000000..f955b351aa --- /dev/null +++ b/wii/libogc/libogc/texconv.c @@ -0,0 +1,77 @@ +/*------------------------------------------------------------- + +texconv.c - Helper functions for GX texture conversion + +Copyright (C) 2008 +softdev +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ +#include + +void MakeTexture565(const void *src,void *dst,s32 width,s32 height) +{ + register u32 tmp0=0,tmp1=0,tmp2=0,tmp3=0; + + __asm__ __volatile__ ( + " srwi %6,%6,2\n" + " srwi %7,%7,2\n" + " subi %3,%4,4\n" + " subi %4,%4,8\n" + + "2: mtctr %6\n" + " mr %0,%5\n" + // + "1: lwz %1,0(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,4(%5)\n" + " stwu %2,8(%3)\n" + + " lwz %1,1024(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,1028(%5)\n" + " stwu %2,8(%3)\n" + + " lwz %1,2048(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,2052(%5)\n" + " stwu %2,8(%3)\n" + + " lwz %1,3072(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,3076(%5)\n" + " stwu %2,8(%3)\n" + + " addi %5,%5,8\n" + " bdnz 1b\n" + + " addi %5,%0,4096\n" + " subic. %7,%7,1\n" + " bne 2b" + // 0 1 2 3 + : "=&b"(tmp0), "=&r"(tmp1), "=&r"(tmp2), "=&b"(tmp3) + // 4 5 6 7 + : "b"(dst), "b"(src), "r"(width), "r"(height) + : "memory" + ); +} diff --git a/wii/libogc/libogc/timesupp.c b/wii/libogc/libogc/timesupp.c new file mode 100644 index 0000000000..bdb8770819 --- /dev/null +++ b/wii/libogc/libogc/timesupp.c @@ -0,0 +1,323 @@ +#include <_ansi.h> +#include <_syslist.h> + +#include "asm.h" +#include "processor.h" +#include "lwp.h" +#include "lwp_threadq.h" +#include "timesupp.h" +#include "exi.h" +#include "system.h" +#include "conf.h" + +#include +#include + +/* time variables */ +static u32 exi_wait_inited = 0; +static lwpq_t time_exi_wait; + +extern u32 __SYS_GetRTC(u32 *gctime); +extern syssram* __SYS_LockSram(); +extern u32 __SYS_UnlockSram(u32 write); + + + +u32 _DEFUN(gettick,(), + _NOARGS) + +{ + u32 result; + __asm__ __volatile__ ( + "mftb %0\n" + : "=r" (result) + ); + return result; +} + + +u64 _DEFUN(gettime,(), + _NOARGS) +{ + u32 tmp; + union uulc { + u64 ull; + u32 ul[2]; + } v; + + __asm__ __volatile__( + "1: mftbu %0\n\ + mftb %1\n\ + mftbu %2\n\ + cmpw %0,%2\n\ + bne 1b\n" + : "=r" (v.ul[0]), "=r" (v.ul[1]), "=&r" (tmp) + ); + return v.ull; +} + +void _DEFUN(settime,(t), + u64 t) +{ + u32 tmp; + union uulc { + u64 ull; + u32 ul[2]; + } v; + + v.ull = t; + __asm__ __volatile__ ( + "li %0,0\n\ + mttbl %0\n\ + mttbu %1\n\ + mttbl %2\n" + : "=&r" (tmp) + : "r" (v.ul[0]), "r" (v.ul[1]) + ); +} + +u32 diff_sec(u64 start,u64 end) +{ + u64 diff; + + diff = diff_ticks(start,end); + return ticks_to_secs(diff); +} + +u32 diff_msec(u64 start,u64 end) +{ + u64 diff = diff_ticks(start,end); + return ticks_to_millisecs(diff); +} + +u32 diff_usec(u64 start,u64 end) +{ + u64 diff = diff_ticks(start,end); + return ticks_to_microsecs(diff); +} + +u32 diff_nsec(u64 start,u64 end) +{ + u64 diff = diff_ticks(start,end); + return ticks_to_nanosecs(diff); +} + +void __timesystem_init() +{ + if(!exi_wait_inited) { + exi_wait_inited = 1; + LWP_InitQueue(&time_exi_wait); + } +} + +void timespec_subtract(const struct timespec *tp_start,const struct timespec *tp_end,struct timespec *result) +{ + struct timespec start_st = *tp_start; + struct timespec *start = &start_st; + u32 nsecpersec = TB_NSPERSEC; + + if(tp_end->tv_nsectv_nsec) { + int secs = (start->tv_nsec - tp_end->tv_nsec)/nsecpersec+1; + start->tv_nsec -= nsecpersec * secs; + start->tv_sec += secs; + } + if((tp_end->tv_nsec - start->tv_nsec)>nsecpersec) { + int secs = (start->tv_nsec - tp_end->tv_nsec)/nsecpersec; + start->tv_nsec += nsecpersec * secs; + start->tv_sec -= secs; + } + + result->tv_sec = (tp_end->tv_sec - start->tv_sec); + result->tv_nsec = (tp_end->tv_nsec - start->tv_nsec); +} + +unsigned long long timespec_to_ticks(const struct timespec *tp) +{ + return __lwp_wd_calc_ticks(tp); +} + +int clock_gettime(struct timespec *tp) +{ + u32 gctime; +#if defined(HW_RVL) + u32 wii_bias = 0; +#endif + + if(!tp) return -1; + + if(!__SYS_GetRTC(&gctime)) return -1; + +#if defined(HW_DOL) + syssram* sram = __SYS_LockSram(); + gctime += sram->counter_bias; + __SYS_UnlockSram(0); +#else + if(CONF_GetCounterBias(&wii_bias)>=0) gctime += wii_bias; +#endif + gctime += 946684800; + + tp->tv_sec = gctime; + tp->tv_nsec = ticks_to_nanosecs(gettick())%1000000000; + + return 0; +} + +// this function spins till timeout is reached +void _DEFUN(udelay,(us), + unsigned us) +{ + unsigned long long start, end; + start = gettime(); + while (1) + { + end = gettime(); + if (diff_usec(start,end) >= us) + break; + } +} + +unsigned int _DEFUN(nanosleep,(tb), + struct timespec *tb) +{ + u64 timeout; + + __lwp_thread_dispatchdisable(); + + timeout = __lwp_wd_calc_ticks(tb); + __lwp_thread_setstate(_thr_executing,LWP_STATES_DELAYING|LWP_STATES_INTERRUPTIBLE_BY_SIGNAL); + __lwp_wd_initialize(&_thr_executing->timer,__lwp_thread_delayended,_thr_executing->object.id,_thr_executing); + __lwp_wd_insert_ticks(&_thr_executing->timer,timeout); + + __lwp_thread_dispatchenable(); + return TB_SUCCESSFUL; +} + +static u32 __getrtc(u32 *gctime) +{ + u32 ret; + u32 cmd; + u32 time; + + if(EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_1,EXI_SPEED8MHZ)==0) { + return 0; + } + + ret = 0; + time = 0; + cmd = 0x20000000; + if(EXI_Imm(EXI_CHANNEL_0,&cmd,4,EXI_WRITE,NULL)==0) ret |= 0x01; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x02; + if(EXI_Imm(EXI_CHANNEL_0,&time,4,EXI_READ,NULL)==0) ret |= 0x04; + if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x08; + if(EXI_Deselect(EXI_CHANNEL_0)==0) ret |= 0x10; + + *gctime = time; + if(ret) return 0; + + return 1; +} + +static s32 __time_exi_unlock(s32 chn,s32 dev) +{ + LWP_ThreadBroadcast(time_exi_wait); + return 1; +} + +static void __time_exi_wait() +{ + u32 ret; + + do { + if((ret=EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_1,__time_exi_unlock))==1) break; + LWP_ThreadSleep(time_exi_wait); + }while(ret==0); +} + +static u32 __getRTC(u32 *gctime) +{ + u32 cnt,time1,time2; + + __time_exi_wait(); + + cnt = 0; + + while(cnt<16) { + if(__getrtc(&time1)==0 + || __getrtc(&time2)==0) { + EXI_Unlock(EXI_CHANNEL_0); + break; + } + if(time1==time2) { + *gctime = time1; + EXI_Unlock(EXI_CHANNEL_0); + return 1; + } + cnt++; + } + return 0; +} + +time_t _DEFUN(time,(timer), + time_t *timer) +{ + time_t gctime = 0; +#if defined(HW_RVL) + u32 wii_bias = 0; +#endif + + if(__getRTC((u32*)&gctime)==0) return (time_t)0; + +#if defined(HW_DOL) + syssram* sram = __SYS_LockSram(); + gctime += sram->counter_bias; + __SYS_UnlockSram(0); +#else + if(CONF_GetCounterBias(&wii_bias)>=0) gctime += wii_bias; +#endif + + gctime += 946684800; + + if(timer) *timer = gctime; + return gctime; +} + +unsigned int _DEFUN(sleep,(s), + unsigned int s) +{ + struct timespec tb; + + tb.tv_sec = s; + tb.tv_nsec = 0; + return nanosleep(&tb); +} + +unsigned int _DEFUN(usleep,(us), + unsigned int us) +{ + struct timespec tb; + u32 sec = us/TB_USPERSEC; + u32 rem = us - (sec*TB_USPERSEC); + + tb.tv_sec = sec; + tb.tv_nsec = rem*TB_NSPERUS; + return nanosleep(&tb); +} + +clock_t clock(void) { + return -1; +} + +int __libogc_gettod_r(struct _reent *ptr, struct timeval *tp, struct timezone *tz) { + + if (tp != NULL) { + tp->tv_sec = time(NULL); + tp->tv_usec = ticks_to_microsecs(gettick())%1000000; + } + if (tz != NULL) { + tz->tz_minuteswest = 0; + tz->tz_dsttime = 0; + + } + return 0; +} + diff --git a/wii/libogc/libogc/timesupp.h b/wii/libogc/libogc/timesupp.h new file mode 100644 index 0000000000..2e84d439d9 --- /dev/null +++ b/wii/libogc/libogc/timesupp.h @@ -0,0 +1,27 @@ +#ifndef __TIMESUPP_H__ +#define __TIMESUPP_H__ + +#define TB_REQ 250 +#define TB_SUCCESSFUL 0 + +#define TB_SECSPERMIN 60 +#define TB_MINSPERHR 60 +#define TB_MONSPERYR 12 +#define TB_DAYSPERYR 365 +#define TB_HRSPERDAY 24 +#define TB_SECSPERDAY (TB_SECSPERMIN*TB_MINSPERHR*TB_HRSPERDAY) +#define TB_SECSPERNYR (365*TB_SECSPERDAY) + +#define TB_MSPERSEC 1000 +#define TB_USPERSEC 1000000 +#define TB_NSPERSEC 1000000000 +#define TB_NSPERMS 1000000 +#define TB_NSPERUS 1000 +#define TB_USPERTICK 10000 + +#include + +time_t time(time_t *timer); +unsigned int nanosleep(struct timespec *tb); + +#endif diff --git a/wii/libogc/libogc/tpl.c b/wii/libogc/libogc/tpl.c new file mode 100644 index 0000000000..b6e027cdff --- /dev/null +++ b/wii/libogc/libogc/tpl.c @@ -0,0 +1,346 @@ +#include +#include +#include +#include +#include +#include +#include "tpl.h" +#include "processor.h" + +#define TPL_FILE_TYPE_DISC 0 +#define TPL_FILE_TYPE_MEM 1 + +#define TPL_HDR_VERSION_FIELD 0 +#define TPL_HDR_NTEXTURE_FIELD 4 +#define TPL_HDR_HDRSIZE_FIELD 8 +#define TPL_HDR_DESCR_FIELD 12 + +// texture header +typedef struct _tplimgheader TPLImgHeader; + +struct _tplimgheader { + u16 height; + u16 width; + u32 fmt; + void *data; + u32 wraps; + u32 wrapt; + u32 minfilter; + u32 magfilter; + f32 lodbias; + u8 edgelod; + u8 minlod; + u8 maxlod; + u8 unpacked; +} ATTRIBUTE_PACKED; + +// texture palette header +typedef struct _tplpalheader TPLPalHeader; + +struct _tplpalheader { + u16 nitems; + u8 unpacked; + u8 pad; + u32 fmt; + void *data; +} ATTRIBUTE_PACKED; + +// texture descriptor +typedef struct _tpldesc TPLDescHeader; + +struct _tpldesc { + TPLImgHeader *imghead; + TPLPalHeader *palhead; +} ATTRIBUTE_PACKED; + +static u32 TPL_GetTextureSize(u32 width,u32 height,u32 fmt) +{ + u32 size = 0; + + switch(fmt) { + case GX_TF_I4: + case GX_TF_CI4: + case GX_TF_CMPR: + size = ((width+7)>>3)*((height+7)>>3)*32; + break; + case GX_TF_I8: + case GX_TF_IA4: + case GX_TF_CI8: + size = ((width+7)>>3)*((height+7)>>2)*32; + break; + case GX_TF_IA8: + case GX_TF_CI14: + case GX_TF_RGB565: + case GX_TF_RGB5A3: + size = ((width+3)>>2)*((height+3)>>2)*32; + break; + case GX_TF_RGBA8: + size = ((width+3)>>2)*((height+3)>>2)*32*2; + break; + default: + break; + } + return size; +} + +s32 TPL_OpenTPLFromFile(TPLFile* tdf, const char* file_name) +{ + u32 c; + u32 version; + FILE *f = NULL; + TPLDescHeader *deschead = NULL; + TPLImgHeader *imghead = NULL; + TPLPalHeader *palhead = NULL; + + if(!file_name) return 0; + + f = fopen(file_name,"rb"); + if(!f) return -1; + + tdf->type = TPL_FILE_TYPE_DISC; + tdf->tpl_file = (FHANDLE)f; + + fread(&version,sizeof(u32),1,f); + fread(&tdf->ntextures,sizeof(u32),1,f); + + fseek(f,TPL_HDR_DESCR_FIELD,SEEK_SET); + + deschead = malloc(tdf->ntextures*sizeof(TPLDescHeader)); + if(deschead) { + fread(deschead,sizeof(TPLDescHeader),tdf->ntextures,f); + + for(c=0;cntextures;c++) { + imghead = deschead[c].imghead; + palhead = deschead[c].palhead; + + //now read in the image data. + fseek(f,(s32)imghead,SEEK_SET); + imghead = malloc(sizeof(TPLImgHeader)); + if(!imghead) goto error_open; + + fread(imghead,sizeof(TPLImgHeader),1,f); + deschead[c].imghead = imghead; + + if(palhead) { + fseek(f,(s32)palhead,SEEK_SET); + + palhead = malloc(sizeof(TPLPalHeader)); + if(!palhead) goto error_open; + + fread(palhead,sizeof(TPLPalHeader),1,f); + deschead[c].palhead = palhead; + } + } + tdf->texdesc = deschead; + + return 1; + } + +error_open: + if(deschead) free(deschead); + if(palhead) free(palhead); + + fclose(f); + return 0; +} + +s32 TPL_OpenTPLFromMemory(TPLFile* tdf, void *memory,u32 len) +{ + u32 c,pos; + const char *p = memory; + TPLDescHeader *deschead = NULL; + TPLImgHeader *imghead = NULL; + TPLPalHeader *palhead = NULL; + + if(!memory || !len) return -1; //TPL_ERR_INVALID + + tdf->type = TPL_FILE_TYPE_MEM; + tdf->tpl_file = (FHANDLE)NULL; + + //version = *(u32*)(p + TPL_HDR_VERSION_FIELD); + tdf->ntextures = *(u32*)(p + TPL_HDR_NTEXTURE_FIELD); + + deschead = (TPLDescHeader*)(p + TPL_HDR_DESCR_FIELD); + for(c=0;cntextures;c++) { + imghead = NULL; + palhead = NULL; + + pos = (u32)deschead[c].imghead; + imghead = (TPLImgHeader*)(p + pos); + + pos = (u32)imghead->data; + imghead->data = (char*)(p + pos); + + pos = (u32)deschead[c].palhead; + if(pos) { + palhead = (TPLPalHeader*)(p + pos); + + pos = (u32)palhead->data; + palhead->data = (char*)(p + pos); + } + deschead[c].imghead = imghead; + deschead[c].palhead = palhead; + } + tdf->texdesc = deschead; + + return 1; +} + +s32 TPL_GetTextureInfo(TPLFile *tdf,s32 id,u32 *fmt,u16 *width,u16 *height) +{ + TPLDescHeader *deschead = NULL; + TPLImgHeader *imghead = NULL; + + if(!tdf) return -1; + if(id<0 || id>=tdf->ntextures) return -1; + + deschead = (TPLDescHeader*)tdf->texdesc; + if(!deschead) return -1; + + imghead = deschead[id].imghead; + if(!imghead) return -1; + + if(fmt) *fmt = imghead->fmt; + if(width) *width = imghead->width; + if(height) *height = imghead->height; + + return 0; +} + +s32 TPL_GetTexture(TPLFile *tdf,s32 id,GXTexObj *texObj) +{ + s32 pos; + u32 size; + FILE *f = NULL; + TPLDescHeader *deschead = NULL; + TPLImgHeader *imghead = NULL; + s32 bMipMap = 0; + u8 biasclamp = GX_DISABLE; + + if(!tdf) return -1; + if(!texObj) return -1; + if(id<0 || id>=tdf->ntextures) return -1; + + deschead = (TPLDescHeader*)tdf->texdesc; + if(!deschead) return -1; + + imghead = deschead[id].imghead; + if(!imghead) return -1; + + size = TPL_GetTextureSize(imghead->width,imghead->height,imghead->fmt); + if(tdf->type==TPL_FILE_TYPE_DISC) { + f = (FILE*)tdf->tpl_file; + pos = (s32)imghead->data; + imghead->data = memalign(PPC_CACHE_ALIGNMENT,size); + if(!imghead->data) return -1; + + fseek(f,pos,SEEK_SET); + fread(imghead->data,1,size,f); + } + + if(imghead->maxlod>0) bMipMap = 1; + if(imghead->lodbias>0.0f) biasclamp = GX_ENABLE; + + DCFlushRange(imghead->data,size); + GX_InitTexObj(texObj,imghead->data,imghead->width,imghead->height,imghead->fmt,imghead->wraps,imghead->wrapt,bMipMap); + if(bMipMap) GX_InitTexObjLOD(texObj,imghead->minfilter,imghead->magfilter,imghead->minlod,imghead->maxlod, + imghead->lodbias,biasclamp,biasclamp,imghead->edgelod); + + return 0; +} + +s32 TPL_GetTextureCI(TPLFile *tdf,s32 id,GXTexObj *texObj,GXTlutObj *tlutObj,u8 tluts) +{ + s32 pos; + u32 size; + FILE *f = NULL; + TPLDescHeader *deschead = NULL; + TPLImgHeader *imghead = NULL; + TPLPalHeader *palhead = NULL; + s32 bMipMap = 0; + u8 biasclamp = GX_DISABLE; + + if(!tdf) return -1; + if(!texObj) return -1; + if(!tlutObj) return -1; + if(id<0 || id>=tdf->ntextures) return -1; + + deschead = (TPLDescHeader*)tdf->texdesc; + if(!deschead) return -1; + + imghead = deschead[id].imghead; + if(!imghead) return -1; + + palhead = deschead[id].palhead; + if(!palhead) return -1; + + size = TPL_GetTextureSize(imghead->width,imghead->height,imghead->fmt); + if(tdf->type==TPL_FILE_TYPE_DISC) { + f = (FILE*)tdf->tpl_file; + pos = (s32)imghead->data; + imghead->data = memalign(PPC_CACHE_ALIGNMENT,size); + if(!imghead->data) return -1; + + fseek(f,pos,SEEK_SET); + fread(imghead->data,1,size,f); + + pos = (s32)palhead->data; + palhead->data = memalign(PPC_CACHE_ALIGNMENT,(palhead->nitems*sizeof(u16))); + if(!palhead->data) { + free(imghead->data); + return -1; + } + + fseek(f,pos,SEEK_SET); + fread(palhead->data,1,(palhead->nitems*sizeof(u16)),f); + } + + if(imghead->maxlod>0) bMipMap = 1; + if(imghead->lodbias>0.0f) biasclamp = GX_ENABLE; + + DCFlushRange(imghead->data,size); + DCFlushRange(palhead->data,(palhead->nitems*sizeof(u16))); + GX_InitTlutObj(tlutObj,palhead->data,palhead->fmt,palhead->nitems); + GX_InitTexObjCI(texObj,imghead->data,imghead->width,imghead->height,imghead->fmt,imghead->wraps,imghead->wrapt,bMipMap,tluts); + if(bMipMap) GX_InitTexObjLOD(texObj,imghead->minfilter,imghead->magfilter,imghead->minlod,imghead->maxlod, + imghead->lodbias,biasclamp,biasclamp,imghead->edgelod); + + return 0; +} + +void TPL_CloseTPLFile(TPLFile *tdf) +{ + int i; + FILE *f; + TPLPalHeader *palhead; + TPLImgHeader *imghead; + TPLDescHeader *deschead; + + if(!tdf) return; + + if(tdf->type==TPL_FILE_TYPE_DISC) { + f = (FILE*)tdf->tpl_file; + if(f) fclose(f); + + deschead = (TPLDescHeader*)tdf->texdesc; + if(!deschead) return; + + for(i=0;intextures;i++) { + imghead = deschead[i].imghead; + palhead = deschead[i].palhead; + if(imghead) { + if(imghead->data) free(imghead->data); + free(imghead); + } + if(palhead) { + if(palhead->data) free(palhead->data); + free(palhead); + } + } + free(tdf->texdesc); + } + + tdf->ntextures = 0; + tdf->texdesc = NULL; + tdf->tpl_file = NULL; +} diff --git a/wii/libogc/libogc/usb.c b/wii/libogc/libogc/usb.c new file mode 100644 index 0000000000..f48c6ff2e4 --- /dev/null +++ b/wii/libogc/libogc/usb.c @@ -0,0 +1,1464 @@ +/*------------------------------------------------------------- + +usb.c -- USB lowlevel + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +tueidj + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +/* Note: There are 3 types of USB interfaces here, the early ones + * (V0: /dev/usb/oh0 and /dev/usb/oh1) and two later ones (V5: /dev/usb/ven + * and /dev/usb/hid) which are similar but have some small + * differences. There is also an earlier version of /dev/usb/hid (V4) + * found in IOSes 37,61,56,etc. and /dev/usb/msc found in IOS 57. + * These interfaces aren't implemented here and you may find some + * devices don't show up if you're running under those IOSes. + */ + +#if defined(HW_RVL) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb.h" + +#define USB_HEAPSIZE 16384 + +#define USBV0_IOCTL_CTRLMSG 0 +#define USBV0_IOCTL_BLKMSG 1 +#define USBV0_IOCTL_INTRMSG 2 +#define USBV0_IOCTL_SUSPENDDEV 5 +#define USBV0_IOCTL_RESUMEDEV 6 +#define USBV0_IOCTL_ISOMSG 9 +#define USBV0_IOCTL_GETDEVLIST 12 +#define USBV0_IOCTL_DEVREMOVALHOOK 26 +#define USBV0_IOCTL_DEVINSERTHOOK 27 +#define USBV0_IOCTL_DEVICECLASSCHANGE 28 + +#define USBV4_IOCTL_GETVERSION 6 // returns 0x40001 + +#define USBV5_IOCTL_GETVERSION 0 // should return 0x50001 +#define USBV5_IOCTL_GETDEVICECHANGE 1 +#define USBV5_IOCTL_SHUTDOWN 2 +#define USBV5_IOCTL_GETDEVPARAMS 3 +#define USBV5_IOCTL_ATTACHFINISH 6 +#define USBV5_IOCTL_SETALTERNATE 7 +#define USBV5_IOCTL_SUSPEND_RESUME 16 +#define USBV5_IOCTL_CANCELENDPOINT 17 +#define USBV5_IOCTL_CTRLMSG 18 +#define USBV5_IOCTL_INTRMSG 19 +#define USBV5_IOCTL_ISOMSG 20 +#define USBV5_IOCTL_BULKMSG 21 +#define USBV5_IOCTL_MSC_READWRITE_ASYNC 32 /* unimplemented */ +#define USBV5_IOCTL_MSC_READ_ASYNC 33 /* unimplemented */ +#define USBV5_IOCTL_MSC_WRITE_ASYNC 34 /* unimplemented */ +#define USBV5_IOCTL_MSC_READWRITE 35 /* unimplemented */ +#define USBV5_IOCTL_MSC_RESET 36 /* unimplemented */ + +#define USB_MAX_DEVICES 32 + +static s32 hId = -1; +static const char __oh0_path[] ATTRIBUTE_ALIGN(32) = "/dev/usb/oh0"; +static const char __ven_path[] ATTRIBUTE_ALIGN(32) = "/dev/usb/ven"; +static const char __hid_path[] ATTRIBUTE_ALIGN(32) = "/dev/usb/hid"; + +typedef struct _usb_cb_list { + usbcallback cb; + void *userdata; + union { + s32 device_id; + struct _usb_cb_list *next; + }; +} _usb_cb_list; + +struct _usbv5_host { + usb_device_entry attached_devices[USB_MAX_DEVICES]; + _usb_cb_list remove_cb[USB_MAX_DEVICES]; + s32 fd; + _usb_cb_list *device_change_notify; +}; + +static struct _usbv5_host* ven_host = NULL; +static struct _usbv5_host* hid_host = NULL; + +struct _usb_msg { + s32 fd; + u32 heap_buffers; + union { + struct { + u8 bmRequestType; + u8 bmRequest; + u16 wValue; + u16 wIndex; + u16 wLength; + void *rpData; + } ctrl; + + struct { + void *rpData; + u16 wLength; + u8 pad[4]; + u8 bEndpoint; + } bulk; + + struct { + void *rpData; + u16 wLength; + u8 bEndpoint; + } intr; + + struct { + void *rpData; + void *rpPacketSizes; + u8 bPackets; + u8 bEndpoint; + } iso; + + struct { + u16 pid; + u16 vid; + } notify; + + u8 class; + u32 hid_intr_dir; + + u32 align_pad[4]; // pad to 24 bytes + }; + usbcallback cb; + void *userdata; + ioctlv vec[7]; +}; + +static s32 __usbv5_devicechangeCB(s32 result, void *p); + +static s32 __usbv5_attachfinishCB(s32 result, void *p) +{ + _usb_cb_list *list; + struct _usbv5_host* host = (struct _usbv5_host*)p; + if(host==NULL) return IPC_EINVAL; + + /* the callback functions may attempt to set a new notify func, + * device_change_notify is set to NULL *before* calling it to + * avoid wiping out the new functions + */ + list = host->device_change_notify; + host->device_change_notify = NULL; + while (list) { + _usb_cb_list *next = list->next; + list->cb(result, list->userdata); + iosFree(hId, list); + list = next; + } + + if (result==0) + IOS_IoctlAsync(host->fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, host->attached_devices, 0x180, __usbv5_devicechangeCB, host); + + return IPC_OK; +} + +static s32 __usbv5_devicechangeCB(s32 result, void *p) +{ + int i, j; + struct _usbv5_host* host = (struct _usbv5_host*)p; + + if(host==NULL) return IPC_EINVAL; + + if (result>=0) { + // can't check the remove callbacks only if the number of devices has decreased, + // because devices may have been inserted as well as removed + for (i=0; iremove_cb[i].cb==NULL) + continue; + for (j=0; jremove_cb[i].device_id == host->attached_devices[j].device_id) + break; + } + + if (j==result) { // execute callback and remove it + host->remove_cb[i].cb(0, host->remove_cb[i].userdata); + host->remove_cb[i].cb = NULL; + } + } + // wipe unused device entries + memset(host->attached_devices+result, 0, sizeof(usb_device_entry)*(32-result)); + + IOS_IoctlAsync(host->fd, USBV5_IOCTL_ATTACHFINISH, NULL, 0, NULL, 0, __usbv5_attachfinishCB, host); + } + + return IPC_OK; +} + +static s32 add_devicechange_cb(_usb_cb_list **list, usbcallback cb, void *userdata) +{ + _usb_cb_list *new_cb = (_usb_cb_list*)iosAlloc(hId, sizeof(_usb_cb_list)); + if (new_cb==NULL) + return IPC_ENOMEM; + + new_cb->cb = cb; + new_cb->userdata = userdata; + new_cb->next = *list; + *list = new_cb; + + return IPC_OK; +} + +static s32 __usbv5_messageCB(s32 result,void *_msg) +{ + struct _usb_msg *msg = (struct _usb_msg*)_msg; + + if(msg==NULL) return IPC_EINVAL; + + if(msg->cb!=NULL) msg->cb(result, msg->userdata); + + iosFree(hId,msg); + + return IPC_OK; +} + +static s32 __usbv0_messageCB(s32 result,void *usrdata) +{ + u32 i; + struct _usb_msg *msg = (struct _usb_msg*)usrdata; + + if(msg==NULL) return IPC_EINVAL; + + if(msg->cb!=NULL) msg->cb(result, msg->userdata); + + for(i=0; iheap_buffers; i++) { + if(msg->vec[i].data!=NULL) + iosFree(hId,msg->vec[i].data); + } + + iosFree(hId,msg); + + return IPC_OK; +} + +static s32 __find_device_on_host(struct _usbv5_host *host, s32 device_id) +{ + int i; + if (host==NULL) return -1; + + for (i=0; host->attached_devices[i].device_id; i++) { + if (host->attached_devices[i].device_id == device_id) + return i; + } + + return -1; +} + +static s32 __usb_isochronous_message(s32 device_id,u8 bEndpoint,u8 bPackets,u16* rpPacketSizes,void* rpData,usbcallback cb,void *userdata) +{ + s32 ret = IPC_ENOMEM; + struct _usb_msg *msg; + u16 wLength=0; + u8 i; + + for (i=0; ifd = device_id; + msg->cb = cb; + msg->userdata = userdata; + + if (device_id>=0 && device_id<0x20) { + u8 *pEndp=NULL; + u16 *pLength=NULL; + u8 *pPackets=NULL; + + pEndp = (u8*)iosAlloc(hId,32); + if(pEndp==NULL) goto done; + *pEndp = bEndpoint; + + pLength = (u16*)iosAlloc(hId,32); + if(pLength==NULL) goto done; + // NOT byteswapped! + *pLength = wLength; + + pPackets = (u8*)iosAlloc(hId,32); + if(pPackets==NULL) goto done; + *pPackets = bPackets; + + msg->heap_buffers = 3; + + msg->vec[0].data = pEndp; + msg->vec[0].len = sizeof(u8); + msg->vec[1].data = pLength; + msg->vec[1].len = sizeof(u16); + msg->vec[2].data = pPackets; + msg->vec[2].len = sizeof(u8); + msg->vec[3].data = rpPacketSizes; + msg->vec[3].len = sizeof(u16)*bPackets; + msg->vec[4].data = rpData; + msg->vec[4].len = wLength; + + if (cb==NULL) + ret = IOS_Ioctlv(device_id, USBV0_IOCTL_ISOMSG, 3, 2, msg->vec); + else + return IOS_IoctlvAsync(device_id, USBV0_IOCTL_ISOMSG, 3, 2, msg->vec, __usbv0_messageCB, msg); + +done: + if(pEndp) iosFree(hId,pEndp); + if(pLength) iosFree(hId,pLength); + if(pPackets) iosFree(hId,pPackets); + } else { + u8 endpoint_dir = !!(bEndpoint&USB_ENDPOINT_IN); + s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd; + + msg->iso.rpData = rpData; + msg->iso.rpPacketSizes = rpPacketSizes; + msg->iso.bEndpoint = bEndpoint; + msg->iso.bPackets = bPackets; + + msg->vec[0].data = msg; + msg->vec[0].len = 64; + // block counts are used for both input and output + msg->vec[1].data = msg->vec[3].data = rpPacketSizes; + msg->vec[1].len = msg->vec[3].len = sizeof(u16)*bPackets; + msg->vec[2].data = rpData; + msg->vec[2].len = wLength; + + if (cb==NULL) + ret = IOS_Ioctlv(fd, USBV5_IOCTL_ISOMSG, 2-endpoint_dir, 2+endpoint_dir, msg->vec); + else + return IOS_IoctlvAsync(fd, USBV5_IOCTL_ISOMSG, 2-endpoint_dir, 2+endpoint_dir, msg->vec, __usbv5_messageCB, msg); + } + + if (msg!=NULL) iosFree(hId,msg); + + return ret; +} + +static s32 __usb_control_message(s32 device_id,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + s32 ret = IPC_ENOMEM; + struct _usb_msg *msg; + + if(((s32)rpData%32)!=0) return IPC_EINVAL; + if(wLength && !rpData) return IPC_EINVAL; + if(!wLength && rpData) return IPC_EINVAL; + + msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg)); + if(msg==NULL) return IPC_ENOMEM; + + memset(msg, 0, sizeof(struct _usb_msg)); + + msg->fd = device_id; + msg->cb = cb; + msg->userdata = userdata; + + if (device_id>=0 && device_id<0x20) { + u8 *pRqType = NULL,*pRq = NULL,*pNull = NULL; + u16 *pValue = NULL,*pIndex = NULL,*pLength = NULL; + + pRqType = (u8*)iosAlloc(hId,32); + if(pRqType==NULL) goto done; + *pRqType = bmRequestType; + + pRq = (u8*)iosAlloc(hId,32); + if(pRq==NULL) goto done; + *pRq = bmRequest; + + pValue = (u16*)iosAlloc(hId,32); + if(pValue==NULL) goto done; + *pValue = bswap16(wValue); + + pIndex = (u16*)iosAlloc(hId,32); + if(pIndex==NULL) goto done; + *pIndex = bswap16(wIndex); + + pLength = (u16*)iosAlloc(hId,32); + if(pLength==NULL) goto done; + *pLength = bswap16(wLength); + + pNull = (u8*)iosAlloc(hId,32); + if(pNull==NULL) goto done; + *pNull = 0; + + msg->heap_buffers = 6; + + msg->vec[0].data = pRqType; + msg->vec[0].len = sizeof(u8); + msg->vec[1].data = pRq; + msg->vec[1].len = sizeof(u8); + msg->vec[2].data = pValue; + msg->vec[2].len = sizeof(u16); + msg->vec[3].data = pIndex; + msg->vec[3].len = sizeof(u16); + msg->vec[4].data = pLength; + msg->vec[4].len = sizeof(u16); + msg->vec[5].data = pNull; + msg->vec[5].len = sizeof(u8); + msg->vec[6].data = rpData; + msg->vec[6].len = wLength; + + if (cb==NULL) + ret = IOS_Ioctlv(device_id, USBV0_IOCTL_CTRLMSG, 6, 1, msg->vec); + else + return IOS_IoctlvAsync(device_id, USBV0_IOCTL_CTRLMSG, 6, 1, msg->vec, __usbv0_messageCB, msg); + +done: + if(pRqType!=NULL) iosFree(hId,pRqType); + if(pRq!=NULL) iosFree(hId,pRq); + if(pValue!=NULL) iosFree(hId,pValue); + if(pIndex!=NULL) iosFree(hId,pIndex); + if(pLength!=NULL) iosFree(hId,pLength); + if(pNull!=NULL) iosFree(hId,pNull); + + } else { + u8 request_dir = !!(bmRequestType&USB_CTRLTYPE_DIR_DEVICE2HOST); + s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd; + + msg->ctrl.bmRequestType = bmRequestType; + msg->ctrl.bmRequest = bmRequest; + msg->ctrl.wValue = wValue; + msg->ctrl.wIndex = wIndex; + msg->ctrl.wLength = wLength; + msg->ctrl.rpData = rpData; + + msg->vec[0].data = msg; + msg->vec[0].len = 64; + msg->vec[1].data = rpData; + msg->vec[1].len = wLength; + + if (cb==NULL) + ret = IOS_Ioctlv(fd, USBV5_IOCTL_CTRLMSG, 2-request_dir, request_dir, msg->vec); + else + return IOS_IoctlvAsync(fd, USBV5_IOCTL_CTRLMSG, 2-request_dir, request_dir, msg->vec, __usbv5_messageCB, msg); + } + + if(msg!=NULL) iosFree(hId,msg); + + return ret; +} + +static inline s32 __usb_interrupt_bulk_message(s32 device_id,u8 ioctl,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + s32 ret = IPC_ENOMEM; + struct _usb_msg *msg; + + if(((s32)rpData%32)!=0) return IPC_EINVAL; + if(wLength && !rpData) return IPC_EINVAL; + if(!wLength && rpData) return IPC_EINVAL; + + msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg)); + if(msg==NULL) return IPC_ENOMEM; + + memset(msg, 0, sizeof(struct _usb_msg)); + + msg->fd = device_id; + msg->cb = cb; + msg->userdata = userdata; + + if (device_id>=0 && device_id<0x20) { + u8 *pEndP = NULL; + u16 *pLength = NULL; + + pEndP = (u8*)iosAlloc(hId,32); + if(pEndP==NULL) goto done; + *pEndP = bEndpoint; + + pLength = (u16*)iosAlloc(hId,32); + if(pLength==NULL) goto done; + *pLength = wLength; + + msg->vec[0].data = pEndP; + msg->vec[0].len = sizeof(u8); + msg->vec[1].data = pLength; + msg->vec[1].len = sizeof(u16); + msg->vec[2].data = rpData; + msg->vec[2].len = wLength; + + msg->heap_buffers = 2; + + if (cb==NULL) + ret = IOS_Ioctlv(device_id,ioctl,2,1,msg->vec); + else + return IOS_IoctlvAsync(device_id,ioctl,2,1,msg->vec,__usbv0_messageCB,msg); + +done: + if(pEndP!=NULL) iosFree(hId,pEndP); + if(pLength!=NULL) iosFree(hId,pLength); + + } else { + u8 endpoint_dir = !!(bEndpoint&USB_ENDPOINT_IN); + s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd; + + if (ioctl == USBV0_IOCTL_INTRMSG) { + // HID does this a little bit differently + if (device_id>=0) + msg->hid_intr_dir = !endpoint_dir; + else { + msg->intr.rpData = rpData; + msg->intr.wLength = wLength; + msg->intr.bEndpoint = bEndpoint; + } + ioctl = USBV5_IOCTL_INTRMSG; + } else { + msg->bulk.rpData = rpData; + msg->bulk.wLength = wLength; + msg->bulk.bEndpoint = bEndpoint; + ioctl = USBV5_IOCTL_BULKMSG; + } + + msg->vec[0].data = msg; + msg->vec[0].len = 64; + msg->vec[1].data = rpData; + msg->vec[1].len = wLength; + + if (cb==NULL) + ret = IOS_Ioctlv(fd, ioctl, 2-endpoint_dir, endpoint_dir, msg->vec); + else + return IOS_IoctlvAsync(fd, ioctl, 2-endpoint_dir, endpoint_dir, msg->vec, __usbv5_messageCB, msg); + } + + if(msg!=NULL) iosFree(hId,msg); + + return ret; +} + +static inline s32 __usb_getdesc(s32 fd, u8 *buffer, u8 valuehi, u8 valuelo, u16 index, u16 size) +{ + u8 requestType = USB_CTRLTYPE_DIR_DEVICE2HOST; + + if (valuehi==USB_DT_HID || valuehi==USB_DT_REPORT || valuehi==USB_DT_PHYSICAL) + requestType |= USB_CTRLTYPE_REC_INTERFACE; + + return __usb_control_message(fd, requestType, USB_REQ_GETDESCRIPTOR, (valuehi << 8) | valuelo, index, size, buffer, NULL, NULL); +} + +static u32 __find_next_endpoint(u8 *buffer,s32 size,u8 align) +{ + u8 *ptr = buffer; + + while(size>2 && buffer[0]) { // abort if buffer[0]==0 to avoid getting stuck + if(buffer[1]==USB_DT_ENDPOINT || buffer[1]==USB_DT_INTERFACE) + break; + + size -= (buffer[0]+align)&~align; + buffer += (buffer[0]+align)&~align; + } + + return (buffer - ptr); +} + +s32 USB_Initialize() +{ + if(hId==-1) hId = iosCreateHeap(USB_HEAPSIZE); + if(hId<0) return IPC_ENOMEM; + + if (ven_host==NULL) { + s32 ven_fd = IOS_Open(__ven_path, IPC_OPEN_NONE); + if (ven_fd>=0) { + ven_host = (struct _usbv5_host*)iosAlloc(hId, sizeof(*ven_host)); + if (ven_host==NULL) { + IOS_Close(ven_fd); + return IPC_ENOMEM; + } + memset(ven_host, 0, sizeof(*ven_host)); + ven_host->fd = ven_fd; + + u32 *ven_ver = (u32*)iosAlloc(hId, 0x20); + if (ven_ver==NULL) goto mem_error; + if (IOS_Ioctl(ven_fd, USBV5_IOCTL_GETVERSION, NULL, 0, ven_ver, 0x20)==0 && ven_ver[0]==0x50001) + IOS_IoctlAsync(ven_fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, ven_host->attached_devices, 0x180, __usbv5_devicechangeCB, ven_host); + else { + // wrong ven version + IOS_Close(ven_fd); + iosFree(hId, ven_host); + ven_host = NULL; + } + + iosFree(hId, ven_ver); + } + } + + if (hid_host==NULL) { + s32 hid_fd = IOS_Open(__hid_path, IPC_OPEN_NONE); + if (hid_fd>=0) { + hid_host = (struct _usbv5_host*)iosAlloc(hId, sizeof(*hid_host)); + if (hid_host==NULL) { + IOS_Close(hid_fd); + goto mem_error; + } + memset(hid_host, 0, sizeof(*hid_host)); + hid_host->fd = hid_fd; + + u32 *hid_ver = (u32*)iosAlloc(hId, 0x20); + if (hid_ver==NULL) goto mem_error; + // have to call the USB4 version first, to be safe + if (IOS_Ioctl(hid_fd, USBV4_IOCTL_GETVERSION, NULL, 0, NULL, 0)==0x40001 || \ + IOS_Ioctl(hid_fd, USBV5_IOCTL_GETVERSION, NULL, 0, hid_ver, 0x20) || hid_ver[0]!=0x50001) { + // wrong hid version + IOS_Close(hid_fd); + iosFree(hId, hid_host); + hid_host = NULL; + } else + IOS_IoctlAsync(hid_fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, hid_host->attached_devices, 0x180, __usbv5_devicechangeCB, hid_host); + + iosFree(hId, hid_ver); + } + } + + return IPC_OK; + +mem_error: + USB_Deinitialize(); + return IPC_ENOMEM; +} + +s32 USB_Deinitialize() +{ + if (hid_host) { + if (hid_host->fd>=0) { + IOS_Ioctl(hid_host->fd, USBV5_IOCTL_SHUTDOWN, NULL, 0, NULL, 0); + IOS_Close(hid_host->fd); + } + iosFree(hId, hid_host); + hid_host = NULL; + } + + if (ven_host) { + if (ven_host->fd>=0) { + IOS_Ioctl(ven_host->fd, USBV5_IOCTL_SHUTDOWN, NULL, 0, NULL, 0); + IOS_Close(ven_host->fd); + } + iosFree(hId, ven_host); + ven_host = NULL; + } + + return IPC_OK; +} + +s32 USB_OpenDevice(s32 device_id,u16 vid,u16 pid,s32 *fd) +{ + s32 ret = USB_OK; + char *devicepath = NULL; + *fd = -1; + + if (device_id && device_id!=USB_OH1_DEVICE_ID) { + int i; + + i = __find_device_on_host(ven_host, device_id); + if (i>=0) + USB_ResumeDevice(device_id); + else { + // HID V5 devices need their descriptors read before being used + usb_devdesc desc; + i = __find_device_on_host(hid_host, device_id); + if (i>=0) { + USB_ResumeDevice(device_id); + i = USB_GetDescriptors(device_id, &desc); + if (i>=0) + USB_FreeDescriptors(&desc); + else { + USB_SuspendDevice(device_id); + return i; + } + } + } + if (i>=0) { + *fd = device_id; + return 0; + } + } + + devicepath = iosAlloc(hId,USB_MAXPATH); + if(devicepath==NULL) return IPC_ENOMEM; + + if (device_id==USB_OH1_DEVICE_ID) + snprintf(devicepath,USB_MAXPATH,"/dev/usb/oh1/%x/%x",vid,pid); + else + snprintf(devicepath,USB_MAXPATH,"/dev/usb/oh0/%x/%x",vid,pid); + + *fd = IOS_Open(devicepath,0); + if(*fd<0) ret = *fd; + + if (devicepath!=NULL) iosFree(hId,devicepath); + return ret; +} + +s32 USBV5_CloseDevice(s32 device_id) +{ + int i; + struct _usbv5_host* host; + + if (__find_device_on_host(ven_host, device_id)>=0) + host = ven_host; + else if (__find_device_on_host(hid_host, device_id)>=0) + host = hid_host; + else + return IPC_EINVAL; + + for (i=0; i < USB_MAX_DEVICES; i++) { + if (host->remove_cb[i].cb==NULL) + continue; + + if (host->remove_cb[i].device_id==device_id) { + host->remove_cb[i].cb(0, host->remove_cb[i].userdata); + host->remove_cb[i].cb = NULL; + break; + } + } + //return USB_SuspendDevice(device_id); + return 0; +} + +s32 USB_CloseDevice(s32 *fd) +{ + s32 ret = IPC_EINVAL; + if (fd) { + ret = USBV5_CloseDevice(*fd); + if (ret==IPC_EINVAL && *fd>0) + ret = IOS_Close(*fd); + if (ret>=0) *fd = -1; + } + + return ret; +} + +s32 USB_CloseDeviceAsync(s32 *fd,usbcallback cb,void *userdata) +{ + s32 ret = IPC_EINVAL; + if(fd) { + ret = USBV5_CloseDevice(*fd); + if (ret!=IPC_EINVAL) { + if (cb) + return cb(ret, userdata); + else + return ret; + } + if (*fd>0) + return IOS_CloseAsync(*fd,cb,userdata); + } + + return ret; +} + +s32 USB_GetDeviceDescription(s32 fd,usb_devdesc *devdesc) +{ + s32 ret; + usb_devdesc *p; + + p = iosAlloc(hId,USB_DT_DEVICE_SIZE); + if(p==NULL) return IPC_ENOMEM; + + ret = __usb_control_message(fd,USB_CTRLTYPE_DIR_DEVICE2HOST,USB_REQ_GETDESCRIPTOR,(USB_DT_DEVICE<<8),0,USB_DT_DEVICE_SIZE,p,NULL,NULL); + if(ret>=0) memcpy(devdesc,p,USB_DT_DEVICE_SIZE); + devdesc->configurations = NULL; + + if(p!=NULL) iosFree(hId,p); + return ret; +} + +static s32 USBV5_GetDescriptors(s32 device_id, usb_devdesc *udd) +{ + s32 retval = IPC_ENOMEM; + u32 *io_buffer = NULL; + u8 *buffer = NULL; + usb_configurationdesc *ucd = NULL; + usb_interfacedesc *uid = NULL; + usb_endpointdesc *ued = NULL; + u32 iConf, iEndpoint; + s32 fd; + u32 desc_out_size, desc_start_offset; + + if (__find_device_on_host(ven_host, device_id)>=0) { + fd = ven_host->fd; + desc_out_size = 0xC0; + desc_start_offset = 20; + } else if (__find_device_on_host(hid_host, device_id)>=0) { + fd = hid_host->fd; + desc_out_size = 0x60; + desc_start_offset = 36; + } else + return IPC_EINVAL; + + io_buffer = (u32*)iosAlloc(hId, 0x20); + buffer = (u8*)iosAlloc(hId, desc_out_size); + if (io_buffer==NULL || buffer==NULL) goto free_bufs; + + io_buffer[0] = device_id; + io_buffer[2] = 0; + memset(buffer, 0, desc_out_size); + retval = IOS_Ioctl(fd, USBV5_IOCTL_GETDEVPARAMS, io_buffer, 0x20, buffer, desc_out_size); + if (retval==IPC_OK) { + u8 *next = buffer+desc_start_offset; + + memcpy(udd, next, sizeof(*udd)); + udd->configurations = calloc(udd->bNumConfigurations, sizeof(*udd->configurations)); + if(udd->configurations == NULL) goto free_bufs; + + next += (udd->bLength+3)&~3; + for (iConf = 0; iConf < udd->bNumConfigurations; iConf++) + { + ucd = &udd->configurations[iConf]; + memcpy(ucd, next, USB_DT_CONFIG_SIZE); + next += (USB_DT_CONFIG_SIZE+3)&~3; + + // ignore the actual value of bNumInterfaces; IOS presents each interface as a different device + // alternate settings will not show up here, if you want them you must explicitly request + // the interface descriptor + if (ucd->bNumInterfaces==0) + continue; + + ucd->bNumInterfaces = 1; + ucd->interfaces = calloc(1, sizeof(*ucd->interfaces)); + if (ucd->interfaces == NULL) goto free_bufs; + + uid = ucd->interfaces; + memcpy(uid, next, USB_DT_INTERFACE_SIZE); + next += (uid->bLength+3)&~3; + + /* This skips vendor and class specific descriptors */ + uid->extra_size = __find_next_endpoint(next, buffer+desc_out_size-next, 3); + if(uid->extra_size>0) + { + uid->extra = malloc(uid->extra_size); + if(uid->extra == NULL) + goto free_bufs; + memcpy(uid->extra, next, uid->extra_size); + // already rounded + next += uid->extra_size; + } + + if (uid->bNumEndpoints) { + uid->endpoints = calloc(uid->bNumEndpoints, sizeof(*uid->endpoints)); + if (uid->endpoints == NULL) goto free_bufs; + + for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++) + { + ued = &uid->endpoints[iEndpoint]; + memcpy(ued, next, USB_DT_ENDPOINT_SIZE); + next += (ued->bLength+3)&~3; + } + } + + } + + retval = IPC_OK; + } + +free_bufs: + if (io_buffer!=NULL) + iosFree(hId, io_buffer); + if (buffer!=NULL) + iosFree(hId, buffer); + if (retval<0) + USB_FreeDescriptors(udd); + return retval; +} + +s32 USB_GetDescriptors(s32 fd, usb_devdesc *udd) +{ + u8 *buffer = NULL; + u8 *ptr = NULL; + usb_configurationdesc *ucd = NULL; + usb_interfacedesc *uid = NULL; + usb_endpointdesc *ued = NULL; + s32 retval = 0; + u32 size; + u32 iConf, iInterface, iEndpoint; + + if (udd==NULL) + return IPC_EINVAL; + memset(udd, 0, sizeof(*udd)); + + if (fd>=0x20 || fd<-1) + return USBV5_GetDescriptors(fd, udd); + + buffer = iosAlloc(hId, sizeof(*udd)); + if(buffer == NULL) + { + retval = IPC_ENOHEAP; + goto free_and_error; + } + + retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, 0, USB_DT_DEVICE_SIZE); + if(retval < 0) + goto free_and_error; + memcpy(udd, buffer, USB_DT_DEVICE_SIZE); + iosFree(hId, buffer); + + udd->bcdUSB = bswap16(udd->bcdUSB); + udd->idVendor = bswap16(udd->idVendor); + udd->idProduct = bswap16(udd->idProduct); + udd->bcdDevice = bswap16(udd->bcdDevice); + + udd->configurations = calloc(udd->bNumConfigurations, sizeof(*udd->configurations)); + if(udd->configurations == NULL) + { + retval = IPC_ENOMEM; + goto free_and_error; + } + for(iConf = 0; iConf < udd->bNumConfigurations; iConf++) + { + buffer = iosAlloc(hId, USB_DT_CONFIG_SIZE); + if(buffer == NULL) + { + retval = IPC_ENOHEAP; + goto free_and_error; + } + + retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, 0, USB_DT_CONFIG_SIZE); + if (retval < 0) + goto free_and_error; + + ucd = &udd->configurations[iConf]; + memcpy(ucd, buffer, USB_DT_CONFIG_SIZE); + iosFree(hId, buffer); + + ucd->wTotalLength = bswap16(ucd->wTotalLength); + size = ucd->wTotalLength; + buffer = iosAlloc(hId, size); + if(buffer == NULL) + { + retval = IPC_ENOHEAP; + goto free_and_error; + } + + retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, 0, ucd->wTotalLength); + if(retval < 0) + goto free_and_error; + + ptr = buffer; + ptr += ucd->bLength; + size -= ucd->bLength; + + retval = IPC_ENOMEM; + + ucd->interfaces = calloc(ucd->bNumInterfaces, sizeof(*ucd->interfaces)); + if(ucd->interfaces == NULL) + goto free_and_error; + for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) + { + retval = __find_next_endpoint(ptr, size, 0); + if (retval>0) { + // FIXME: do something with this data + } + ptr += retval; + size -= retval; + + uid = ucd->interfaces+iInterface; + memcpy(uid, ptr, USB_DT_INTERFACE_SIZE); + ptr += uid->bLength; + size -= uid->bLength; + + /* This skips vendor and class specific descriptors */ + uid->extra_size = __find_next_endpoint(ptr, size, 0); + if(uid->extra_size>0) + { + uid->extra = malloc(uid->extra_size); + if(uid->extra == NULL) + goto free_and_error; + memcpy(uid->extra, ptr, uid->extra_size); + ptr += uid->extra_size; + size -= uid->extra_size; + } + + if (uid->bNumEndpoints) { + uid->endpoints = calloc(uid->bNumEndpoints, sizeof(*uid->endpoints)); + if(uid->endpoints == NULL) + goto free_and_error; + + for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++) + { + ued = &uid->endpoints[iEndpoint]; + memcpy(ued, ptr, USB_DT_ENDPOINT_SIZE); + ptr += ued->bLength; + size -= ued->bLength; + ued->wMaxPacketSize = bswap16(ued->wMaxPacketSize); + } + } + + if (iInterface==(ucd->bNumInterfaces-1) && size>2) { + // we've read all the interfaces but there's data left (probably alternate setting interfaces) + // see if we can find another interface descriptor + retval = __find_next_endpoint(ptr, size, 0); + if (size-retval >= USB_DT_INTERFACE_SIZE && ptr[retval+1] == USB_DT_INTERFACE) { + // found alternates, make room and loop + usb_interfacedesc *interfaces = realloc(ucd->interfaces, (iInterface+2)*sizeof(*interfaces)); + if (interfaces == NULL) + goto free_and_error; + interfaces[iInterface+1].endpoints = NULL; + interfaces[iInterface+1].extra = NULL; + ucd->bNumInterfaces++; + ucd->interfaces = interfaces; + } + } + } + iosFree(hId, buffer); + buffer = NULL; + } + retval = IPC_OK; + +free_and_error: + if(buffer != NULL) + iosFree(hId, buffer); + if(retval < 0) + USB_FreeDescriptors(udd); + return retval; +} + +s32 USB_GetGenericDescriptor(s32 fd,u8 type,u8 index,u8 interface,void *data,u32 size) { + u8 *buffer; + s32 retval; + + buffer = iosAlloc(hId,size); + if(buffer==NULL) { + retval = IPC_ENOMEM; + goto free_and_error; + } + + retval = __usb_getdesc(fd,buffer,type,index,interface,size); + if(retval<0) goto free_and_error; + + memcpy(data,buffer,size); + retval = IPC_OK; + +free_and_error: + if(buffer!=NULL) iosFree(hId,buffer); + return retval; +} + +s32 USB_GetHIDDescriptor(s32 fd,u8 interface,usb_hiddesc *uhd,u32 size) +{ + int i; + s32 retval; + + if (size < USB_DT_HID_SIZE) + return IPC_EINVAL; + + retval = USB_GetGenericDescriptor(fd, USB_DT_HID, 0, interface, uhd, size); + if (retval != IPC_OK) + return retval; + + uhd->bcdHID = bswap16(uhd->bcdHID); + uhd->descr[0].wDescriptorLength = bswap16(uhd->descr[0].wDescriptorLength); + size -= USB_DT_HID_SIZE; + for (i=1; ibNumDescriptors && size>=3; size -=3, i++) + uhd->descr[i].wDescriptorLength = bswap16(uhd->descr[i].wDescriptorLength); + + return retval; +} + +void USB_FreeDescriptors(usb_devdesc *udd) +{ + int iConf, iInterface; + usb_configurationdesc *ucd; + usb_interfacedesc *uid; + if(udd->configurations != NULL) + { + for(iConf = 0; iConf < udd->bNumConfigurations; iConf++) + { + ucd = &udd->configurations[iConf]; + if(ucd->interfaces != NULL) + { + for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) + { + uid = ucd->interfaces+iInterface; + free(uid->endpoints); + free(uid->extra); + } + free(ucd->interfaces); + } + } + free(udd->configurations); + } +} + +s32 USB_GetAsciiString(s32 fd,u8 bIndex,u16 wLangID,u16 wLength,void *rpData) +{ + s32 ret; + u8 bo, ro; + u8 *buf; + u8 *rp = (u8 *)rpData; + + if(wLength > 255) + wLength = 255; + + buf = iosAlloc(hId, 255); /* 255 is the highest possible length of a descriptor */ + if(buf == NULL) + return IPC_ENOMEM; + + ret = __usb_getdesc(fd, buf, USB_DT_STRING, bIndex, wLangID, 255); + + /* index 0 gets a list of supported languages */ + if(bIndex == 0) + { + if(ret > 0) + memcpy(rpData, buf, wLength); + iosFree(hId, buf); + return ret; + } + + if(ret > 0) + { + bo = 2; + ro = 0; + while(ro < (wLength - 1) && bo < buf[0]) + { + if(buf[bo + 1]) + rp[ro++] = '?'; + else + rp[ro++] = buf[bo]; + bo += 2; + } + rp[ro] = 0; + ret = ro - 1; + } + + iosFree(hId, buf); + return ret; +} + +s32 USB_ReadIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData) +{ + return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL); +} + +s32 USB_ReadIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata); +} + +s32 USB_WriteIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData) +{ + return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL); +} + +s32 USB_WriteIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata); +} + +s32 USB_ReadIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL); +} + +s32 USB_ReadIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata); +} + +s32 USB_WriteIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL); +} + +s32 USB_WriteIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata); +} + +s32 USB_ReadBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL); +} + +s32 USB_ReadBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata); +} + +s32 USB_WriteBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL); +} + +s32 USB_WriteBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata); +} + +s32 USB_ReadCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData) +{ + return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL); +} + +s32 USB_ReadCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata); +} + +s32 USB_WriteCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData) +{ + return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL); +} + +s32 USB_WriteCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata) +{ + return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata); +} + +static s32 USB5_RegisterDeviceRemoval(struct _usbv5_host *host, s32 device_id, usbcallback cb, void *userdata) +{ + int i; + + // check to make sure the device is present + if (__find_device_on_host(host, device_id)<0) + return IPC_ENOENT; + + // now make sure it's not hooked already + for (i=0; iremove_cb[i].cb && host->remove_cb[i].device_id==device_id) + return IPC_EINVAL; + } + + // find a free entry and add it + for (i=0; iremove_cb[i].cb==NULL) { + host->remove_cb[i].cb = cb; + host->remove_cb[i].userdata = userdata; + host->remove_cb[i].device_id = device_id; + return IPC_OK; + } + } + return IPC_EINVAL; +} + +s32 USB_DeviceRemovalNotifyAsync(s32 fd,usbcallback cb,void *userdata) +{ + s32 ret; + if (fd>=0 && fd<0x20) + return IOS_IoctlAsync(fd,USBV0_IOCTL_DEVREMOVALHOOK,NULL,0,NULL,0,cb,userdata); + + ret = USB5_RegisterDeviceRemoval(ven_host, fd, cb, userdata); + if (ret == IPC_ENOENT) + ret = USB5_RegisterDeviceRemoval(hid_host, fd, cb, userdata); + + return ret; +} + +static s32 USBV5_SuspendResume(s32 device_id, s32 resumed) +{ + s32 ret; + s32 fd; + + if (__find_device_on_host(ven_host, device_id)>=0) + fd = ven_host->fd; + else if (__find_device_on_host(hid_host, device_id)>=0) + fd = hid_host->fd; + else + return IPC_ENOENT; + + s32 *buf = (s32*)iosAlloc(hId, 32); + if (buf==NULL) return IPC_ENOMEM; + + buf[0] = device_id; + buf[2] = resumed; + ret = IOS_Ioctl(fd, USBV5_IOCTL_SUSPEND_RESUME, buf, 32, NULL, 0); + iosFree(hId, buf); + + return ret; +} + +s32 USB_SuspendDevice(s32 fd) +{ + if (fd>=0x20 || fd<-1) + return USBV5_SuspendResume(fd, 0); + + return IOS_Ioctl(fd,USBV0_IOCTL_SUSPENDDEV,NULL,0,NULL,0); +} + +s32 USB_ResumeDevice(s32 fd) +{ + if (fd>=0x20 || fd<-1) + return USBV5_SuspendResume(fd, 1); + + return IOS_Ioctl(fd,USBV0_IOCTL_RESUMEDEV,NULL,0,NULL,0); +} + +s32 USB_DeviceChangeNotifyAsync(u8 interface_class, usbcallback cb, void* userdata) +{ + s32 ret=IPC_ENOENT; + + if (ven_host==NULL) { + s32 fd; + struct _usb_msg *msg; + + fd = IOS_Open(__oh0_path,IPC_OPEN_NONE); + if (fd<0) return fd; + + msg = iosAlloc(hId,sizeof(*msg)); + if (msg==NULL) { + IOS_Close(fd); + return IPC_ENOMEM; + } + + msg->cb = cb; + msg->userdata = userdata; + msg->class = interface_class; + + msg->vec[0].data = &msg->class; + msg->vec[0].len = 1; + + ret = IOS_IoctlvAsync(fd,USBV0_IOCTL_DEVICECLASSCHANGE,1,0,msg->vec,__usbv5_messageCB,msg); + IOS_Close(fd); + + if (ret<0) iosFree(hId, msg); + } + else if (interface_class != USB_CLASS_HID && ven_host) + ret = add_devicechange_cb(&ven_host->device_change_notify, cb, userdata); + + else if (interface_class==USB_CLASS_HID && hid_host) + ret = add_devicechange_cb(&hid_host->device_change_notify, cb, userdata); + + + return ret; +} + +s32 USB_GetDeviceList(usb_device_entry *descr_buffer,u8 num_descr,u8 interface_class,u8 *cnt_descr) +{ + int i; + u8 cntdevs=0; + + if (ven_host==NULL) { + s32 fd; + u32 *buf = (u32*)iosAlloc(hId, num_descr<<3); + if (buf==NULL) return IPC_ENOMEM; + + fd = IOS_Open(__oh0_path,IPC_OPEN_NONE); + if (fd<0) { + iosFree(hId, buf); + return fd; + } + + cntdevs = 0; + i = IOS_IoctlvFormat(hId,fd,USBV0_IOCTL_GETDEVLIST,"bb:dd",num_descr,interface_class,&cntdevs,sizeof(cntdevs),buf,(num_descr<<3)); + if (cnt_descr) *cnt_descr = cntdevs; + + while (cntdevs--) { + descr_buffer[cntdevs].device_id = 0; + descr_buffer[cntdevs].vid = (u16)(buf[cntdevs*2+1]>>16); + descr_buffer[cntdevs].pid = (u16)buf[cntdevs*2+1]; + } + + IOS_Close(fd); + iosFree(hId, buf); + return i; + } + + // for ven_host, we can only exclude usb_hid class devices + if (interface_class != USB_CLASS_HID && ven_host) { + i=0; + while (cntdevsattached_devices[i].device_id) { + descr_buffer[cntdevs++] = ven_host->attached_devices[i++]; + if (i>=32) break; + } + } + + if ((!interface_class || interface_class==USB_CLASS_HID) && hid_host) { + i=0; + while (cntdevsattached_devices[i].device_id) { + descr_buffer[cntdevs++] = hid_host->attached_devices[i++]; + if (i>32) break; + } + } + + if (cnt_descr) *cnt_descr = cntdevs; + + return IPC_OK; +} + +s32 USB_SetConfiguration(s32 fd, u8 configuration) +{ + return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_SETCONFIG, configuration, 0, 0, NULL, NULL, NULL); +} + +s32 USB_GetConfiguration(s32 fd, u8 *configuration) +{ + u8 *_configuration; + s32 retval; + + _configuration = iosAlloc(hId, 1); + if(_configuration == NULL) + return IPC_ENOMEM; + + retval = __usb_control_message(fd, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_GETCONFIG, 0, 0, 1, _configuration, NULL, NULL); + if(retval >= 0) + *configuration = *_configuration; + iosFree(hId, _configuration); + + return retval; +} + +s32 USB_SetAlternativeInterface(s32 fd, u8 interface, u8 alternateSetting) +{ + return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_INTERFACE), USB_REQ_SETINTERFACE, alternateSetting, interface, 0, NULL, NULL, NULL); +} + +static s32 USBV5_CancelEndpoint(s32 device_id, u8 endpoint) +{ + s32 ret; + s32 fd; + + if (__find_device_on_host(ven_host, device_id)>=0) + fd = ven_host->fd; + else if (__find_device_on_host(hid_host, device_id)>=0) + fd = hid_host->fd; + else + return IPC_ENOENT; + + s32 *buf = (s32*)iosAlloc(hId, 32); + if (buf==NULL) return IPC_ENOMEM; + + buf[0] = device_id; + buf[2] = endpoint; + ret = IOS_Ioctl(fd, USBV5_IOCTL_CANCELENDPOINT, buf, 32, NULL, 0); + iosFree(hId, buf); + + return ret; +} + +s32 USB_ClearHalt(s32 fd, u8 endpoint) +{ + if (fd>=0x20 || fd<-1) + return USBV5_CancelEndpoint(fd, endpoint); + return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_ENDPOINT), USB_REQ_CLEARFEATURE, USB_FEATURE_ENDPOINT_HALT, endpoint, 0, NULL, NULL, NULL); +} + +#endif /* defined(HW_RVL) */ + diff --git a/wii/libogc/libogc/usbgecko.c b/wii/libogc/libogc/usbgecko.c new file mode 100644 index 0000000000..c00630a207 --- /dev/null +++ b/wii/libogc/libogc/usbgecko.c @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbgecko.h" + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + + +static u32 usbgecko_inited = 0; +static lwpq_t wait_exi_queue[2]; + +static s32 __usbgecko_exi_unlock(s32 chan,s32 dev) +{ + LWP_ThreadBroadcast(wait_exi_queue[chan]); + return 1; +} + +static void __usbgecko_init() +{ + u32 i; + + for(i=0;i 0x7FFFF) + return 0; + + if(!EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)) ret |= 0x01; + if(!EXI_ImmEx(chn,&val,sizeof(u32),EXI_WRITE)) ret |= 0x02; + if(!EXI_ImmEx(chn,&val,sizeof(u32),EXI_WRITE)) ret |= 0x04; + if(!EXI_Deselect(chn)) ret |= 0x08; + + if(ret) return 0; + return 1; +} + +static __inline__ int __flashreadcommand(s32 chn, u32 flashaddress, u8 *flashdata) +{ + s32 ret = 0; + u32 val = 0xF0000000|(flashaddress<<9); + + if (flashaddress > 0x7FFFF) + return 0; + + if(!EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)) ret |= 0x01; + if(!EXI_ImmEx(chn,&val,sizeof(u32),EXI_WRITE)) ret |= 0x02; + if(!EXI_ImmEx(chn,&val,sizeof(u32),EXI_READ)) ret |= 0x04; + if(!EXI_Deselect(chn)) ret |= 0x08; + + if(ret) return 0; + *flashdata = val>>23; + return 1; +} + +static int __usb_sendbyte(s32 chn,char ch) +{ + s32 ret; + u16 val; + + val = (0xB000|_SHIFTL(ch,4,8)); + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0400)) ret = 0; + + return ret; +} + +static int __usb_recvbyte(s32 chn,char *ch) +{ + s32 ret; + u16 val; + + *ch = 0; + val = 0xA000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0800)) ret = 0; + else if(ret==1) *ch = (val&0xff); + + return ret; +} + +int __usb_checksend(s32 chn) +{ + s32 ret; + u16 val; + + val = 0xC000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0400)) ret = 0; + + return ret; +} + +int __usb_checkrecv(s32 chn) +{ + s32 ret; + u16 val; + + val = 0xD000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0400)) ret = 0; + + return ret; +} + +void usb_flush(s32 chn) +{ + char tmp; + + __usbgecko_exi_wait(chn); + while(__usb_recvbyte(chn,&tmp)); + EXI_Unlock(chn); +} + +int usb_isgeckoalive(s32 chn) +{ + u32 id = 0; + s32 ret; + u16 val; + + if (EXI_GetID(chn, EXI_DEVICE_0, &id) == 0) + return 0; + + if (id != 0) + return 0; + + __usbgecko_exi_wait(chn); + + val = 0x9000; + ret = __send_command(chn,&val); + if(ret==1 && !(val&0x0470)) ret = 0; + + EXI_Unlock(chn); + + return ret; +} + +int usb_recvbuffer_ex(s32 chn,void *buffer,int size, int retries) +{ + s32 ret; + s32 left = size; + char *ptr = (char*)buffer; + + __usbgecko_exi_wait(chn); + while(left>0) { + ret = __usb_recvbyte(chn,ptr); + if(ret==0) break; + + ptr++; + left--; + + if (retries >= 0) { + retries--; + if (retries == 0) + break; + } + } + EXI_Unlock(chn); + + return (size - left); +} + +int usb_recvbuffer(s32 chn,void *buffer,int size) { + return usb_recvbuffer_ex(chn, buffer, size, -1); +} + +int usb_sendbuffer_ex(s32 chn,const void *buffer,int size, int retries) +{ + s32 ret; + s32 left = size; + char *ptr = (char*)buffer; + + __usbgecko_exi_wait(chn); + while(left>0) { + ret = __usb_sendbyte(chn,*ptr); + if(ret==0) break; + + ptr++; + left--; + + if (retries >= 0) { + retries--; + if (retries == 0) + break; + } + } + EXI_Unlock(chn); + + return (size - left); +} + +int usb_sendbuffer(s32 chn,const void *buffer,int size) { + return usb_sendbuffer_ex(chn, buffer, size, -1); +} + +int usb_recvbuffer_safe_ex(s32 chn,void *buffer,int size, int retries) +{ + s32 ret; + s32 left = size; + char *ptr = (char*)buffer; + + __usbgecko_exi_wait(chn); + while(left>0) { + if(__usb_checkrecv(chn)) { + ret = __usb_recvbyte(chn,ptr); + if(ret==0) break; + + ptr++; + left--; + } + + if (retries >= 0) { + retries--; + if (retries == 0) + break; + } + } + EXI_Unlock(chn); + + return (size - left); +} + +int usb_recvbuffer_safe(s32 chn,void *buffer,int size) { + return usb_recvbuffer_safe_ex(chn, buffer, size, -1); +} + +int usb_sendbuffer_safe_ex(s32 chn,const void *buffer,int size, int retries) +{ + s32 ret; + s32 left = size; + char *ptr = (char*)buffer; + + __usbgecko_exi_wait(chn); + while(left>0) { + if(__usb_checksend(chn)) { + ret = __usb_sendbyte(chn,*ptr); + if(ret==0) break; + + ptr++; + left--; + } + + if (retries >= 0) { + retries--; + if (retries == 0) + break; + } + } + EXI_Unlock(chn); + + return (size - left); +} + +int usb_sendbuffer_safe(s32 chn,const void *buffer,int size) { + return usb_sendbuffer_safe_ex(chn, buffer, size, -1); +} + +static int __flashsoftwareid_entry(s32 chn) +{ + s32 ret=0; + + if (__flashwritecommand(chn, 0x5555, 0xAA) && __flashwritecommand(chn, 0x2AAA, 0x55) && + __flashwritecommand(chn, 0x5555, 0x90)) + ret = 1; + + return ret; +} + +static int __flashsoftwareid_exit(s32 chn) +{ + s32 ret=0; + + if (__flashwritecommand(chn, 0x5555, 0xAA) && __flashwritecommand(chn, 0x2AAA, 0x55) && + __flashwritecommand(chn, 0x5555, 0xF0)) + ret = 1; + + return ret; +} + +int usb_flashread(s32 chn, u32 offset, void *buffer, size_t length) +{ + s32 ret=1; + u8 *data = (u8*)buffer; + + __usbgecko_exi_wait(chn); + while (ret && length--) + ret = __flashreadcommand(chn, offset++, data++); + + EXI_Unlock(chn); + + return ret; +} + +int usb_flashwrite(s32 chn, u32 offset, const void *buffer, size_t length) +{ + s32 ret=1; + const u8 *data = (const u8*)buffer; + u8 verify; + + __usbgecko_exi_wait(chn); + while (ret && length--) + { + if (!__flashwritecommand(chn, 0x5555, 0xAA) || !__flashwritecommand(chn, 0x2AAA, 0x55) || + !__flashwritecommand(chn, 0x5555, 0xA0) || !__flashwritecommand(chn, offset, *data)) + ret = 0; + else + { + usleep(20); + if (!__flashreadcommand(chn, offset++, &verify) || verify != *data++) + ret = 0; + } + } + EXI_Unlock(chn); + + return ret; +} + +int usb_flashverify(s32 chn) +{ + u8 id[2]; + s32 ret=0; + + __usbgecko_exi_wait(chn); + + if (__flashsoftwareid_entry(chn) &&__flashreadcommand(chn, 0, id+0) && + __flashreadcommand(chn, 1, id+1) && id[0] == 0xBF && id[1] == 0xD7 && + __flashsoftwareid_exit(chn)) + ret = 1; + + EXI_Unlock(chn); + + return ret; +} diff --git a/wii/libogc/libogc/usbmouse.c b/wii/libogc/libogc/usbmouse.c new file mode 100644 index 0000000000..6ab1055d5c --- /dev/null +++ b/wii/libogc/libogc/usbmouse.c @@ -0,0 +1,407 @@ +/*------------------------------------------------------------- + +usbmouse.c -- USB mouse support + +Copyright (C) 2009 +Daryl Borth (Tantric) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MOUSE_THREAD_STACKSIZE (1024 * 4) +#define MOUSE_THREAD_PRIO 65 + +#define MOUSE_MAX_DATA 32 + +#define HEAP_SIZE 4096 +#define DEVLIST_MAXSIZE 8 + +typedef struct { + lwp_node node; + mouse_event event; +} _node; + +struct umouse { + bool connected; + bool has_wheel; + + s32 fd; + + u8 configuration; + u32 interface; + u32 altInterface; + + u8 ep; + u32 ep_size; +}; + +static lwp_queue _queue; + +static s32 hId = -1; +static bool _mouse_is_inited = false; +static lwp_t _mouse_thread = LWP_THREAD_NULL; +static bool _mouse_thread_running = false; +static bool _mouse_thread_quit = false; +static struct umouse *_mouse = NULL; +static s8 *_mousedata = NULL; +static sem_t _mousesema = LWP_SEM_NULL; + +static u8 _mouse_stack[MOUSE_THREAD_STACKSIZE] ATTRIBUTE_ALIGN(8); + +//Add an event to the event queue +static s32 _mouse_addEvent(const mouse_event *event) { + _node *n = malloc(sizeof(_node)); + n->event = *event; + + __lwp_queue_append(&_queue, (lwp_node*) n); + + return 1; +} + +// Event callback +static s32 _mouse_event_cb(s32 result, mouse_event *event) +{ + if (result>=3) + { + event->button = _mousedata[0]; + event->rx = _mousedata[1]; + event->ry = _mousedata[2]; + // this isn't defined in the HID mouse boot protocol, but it's a fairly safe bet + if (_mouse->has_wheel) { + // if more than 3 bytes were returned and the fourth byte is 1 or -1, assume it's wheel motion + // if it's outside this range, probably not a wheel + if (result < 4 || _mousedata[3] < -1 || _mousedata[3] > 1) { + _mouse->has_wheel = false; + event->rz = 0; + } + else + event->rz = _mousedata[3]; + } else + event->rz = 0; + } + else + _mouse->connected = false; + + if (_mousesema != LWP_SEM_NULL) + LWP_SemPost(_mousesema); + + return 0; +} + +//Callback when the mouse is disconnected +static s32 _disconnect(s32 retval, void *data) +{ + _mouse->connected = false; + if (_mousesema != LWP_SEM_NULL) + LWP_SemPost(_mousesema); + return 1; +} + +//Callback when a device is connected/disconnected (for notification when we're looking for a mouse) +static s32 _device_change(s32 retval, void *data) +{ + if (_mousesema != LWP_SEM_NULL) + LWP_SemPost(_mousesema); + return 1; +} + +//init the ioheap +static s32 USBMouse_Initialize(void) +{ + if (hId > 0) + return 0; + + hId = iosCreateHeap(HEAP_SIZE); + + if (hId < 0) + return IPC_ENOHEAP; + + return IPC_OK; +} + +//Close the device +static void USBMouse_Close(void) +{ + if (_mouse && _mouse->fd != -1) { + USB_CloseDevice(&_mouse->fd); + _mouse->fd = -1; + } +} + +//Search for a mouse connected to the wii usb port +//Thanks to Sven Peter usbstorage support +static s32 USBMouse_Open() +{ + usb_device_entry *buffer; + u8 device_count, i; + u16 vid, pid; + bool found = false; + u32 iConf, iInterface, iEp; + usb_devdesc udd; + usb_configurationdesc *ucd; + usb_interfacedesc *uid; + usb_endpointdesc *ued; + + buffer = iosAlloc(hId, DEVLIST_MAXSIZE * sizeof(usb_device_entry)); + if(buffer == NULL) + return -1; + + memset(buffer, 0, DEVLIST_MAXSIZE * sizeof(usb_device_entry)); + + if (USB_GetDeviceList(buffer, DEVLIST_MAXSIZE, USB_CLASS_HID, &device_count) < 0) + { + iosFree(hId,buffer); + return -2; + } + + for (i = 0; i < device_count; i++) + { + vid = buffer[i].vid; + pid = buffer[i].pid; + + if ((vid == 0) || (pid == 0)) + continue; + + s32 fd = 0; + if (USB_OpenDevice(buffer[i].device_id, vid, pid, &fd) < 0) + continue; + + if (USB_GetDescriptors(fd, &udd) < 0) { + USB_CloseDevice(&fd); + continue; + } + + for(iConf = 0; iConf < udd.bNumConfigurations; iConf++) + { + ucd = &udd.configurations[iConf]; + + for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) + { + uid = &ucd->interfaces[iInterface]; + + if ((uid->bInterfaceClass == USB_CLASS_HID) && + (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) && + (uid->bInterfaceProtocol== USB_PROTOCOL_MOUSE)) + { + for(iEp = 0; iEp < uid->bNumEndpoints; iEp++) + { + ued = &uid->endpoints[iEp]; + + if (ued->bmAttributes != USB_ENDPOINT_INTERRUPT) + continue; + + if (!(ued->bEndpointAddress & USB_ENDPOINT_IN)) + continue; + + if (ued->wMaxPacketSize > MOUSE_MAX_DATA) + continue; + + _mouse->fd = fd; + + _mouse->configuration = ucd->bConfigurationValue; + _mouse->interface = uid->bInterfaceNumber; + _mouse->altInterface = uid->bAlternateSetting; + + _mouse->ep = ued->bEndpointAddress; + _mouse->ep_size = ued->wMaxPacketSize; + + found = true; + + break; + } + } + + if (found) + break; + } + + if (found) + break; + } + + USB_FreeDescriptors(&udd); + + if (found) + break; + else + USB_CloseDevice(&fd); + } + + iosFree(hId,buffer); + + if (!found) + return -3; + + if (USB_DeviceRemovalNotifyAsync(_mouse->fd, &_disconnect, NULL) < 0) + { + USBMouse_Close(); + return -8; + } + + // set boot protocol + USB_WriteCtrlMsg(_mouse->fd, USB_REQTYPE_INTERFACE_SET, USB_REQ_SETPROTOCOL, 0, _mouse->interface, 0, NULL); + // assume there's a wheel until we know otherwise + _mouse->has_wheel = true; + _mouse->connected = true; + return 1; +} + +bool MOUSE_IsConnected(void) +{ + if (!_mouse) return false; + return _mouse->connected; +} + +static void * _mouse_thread_func(void *arg) +{ + mouse_event event; + memset(&event, 0, sizeof(event)); + + while (!_mouse_thread_quit) + { + // scan for new attached mice + if (!MOUSE_IsConnected()) + { + USBMouse_Close(); + if (USBMouse_Open() < 0) { + // wait for something to be inserted + USB_DeviceChangeNotifyAsync(USB_CLASS_HID, _device_change, NULL); + LWP_SemWait(_mousesema); + continue; + } + } + + if (USB_ReadIntrMsgAsync(_mouse->fd, _mouse->ep, _mouse->ep_size, _mousedata, (usbcallback)_mouse_event_cb, &event) < 0) + break; + LWP_SemWait(_mousesema); + _mouse_addEvent(&event); + memset(&event, 0, sizeof(event)); + } + return NULL; +} + +//Initialize USB and USB_MOUSE and the event queue +s32 MOUSE_Init(void) +{ + if(_mouse_is_inited) return 0; + + if (USB_Initialize() != IPC_OK) + return -1; + + if (USBMouse_Initialize() != IPC_OK) { + return -2; + } + + _mousedata = (s8*)iosAlloc(hId,MOUSE_MAX_DATA); + _mouse = (struct umouse *) malloc(sizeof(struct umouse)); + memset(_mouse, 0, sizeof(struct umouse)); + _mouse->fd = -1; + LWP_SemInit(&_mousesema, 0, 1); + + if (!_mouse_thread_running) + { + // start the mouse thread + _mouse_thread_quit = false; + memset(_mouse_stack, 0, MOUSE_THREAD_STACKSIZE); + + s32 res = LWP_CreateThread(&_mouse_thread, _mouse_thread_func, NULL, + _mouse_stack, MOUSE_THREAD_STACKSIZE, + MOUSE_THREAD_PRIO); + + if (res) + { + USBMouse_Close(); + MOUSE_FlushEvents(); + _mouse_thread_running = false; + return -6; + } + _mouse_thread_running = true; + } + + __lwp_queue_init_empty(&_queue); + _mouse_is_inited = true; + return 0; +} + +// Deinitialize USB_MOUSE and the event queue +s32 MOUSE_Deinit(void) +{ + if(!_mouse_is_inited) return 1; + + if (_mouse_thread_running) { + _mouse_thread_quit = true; + LWP_SemPost(_mousesema); + LWP_JoinThread(_mouse_thread, NULL); + _mouse_thread_running = false; + } + + USBMouse_Close(); + MOUSE_FlushEvents(); + if(_mousedata!=NULL) iosFree(hId,_mousedata); + free(_mouse); + if (_mousesema != LWP_SEM_NULL) { + LWP_SemDestroy(_mousesema); + _mousesema = LWP_SEM_NULL; + } + _mouse_is_inited = false; + return 1; +} + +//Get the first event of the event queue +s32 MOUSE_GetEvent(mouse_event *event) +{ + _node *n = (_node *) __lwp_queue_get(&_queue); + + if (!n) + return 0; + + if (event) + *event = n->event; + + free(n); + + return 1; +} + +//Flush all pending events +s32 MOUSE_FlushEvents(void) +{ + s32 res=0; + + while (MOUSE_GetEvent(NULL)) + res++; + + return res; +} + +#endif diff --git a/wii/libogc/libogc/usbstorage.c b/wii/libogc/libogc/usbstorage.c new file mode 100644 index 0000000000..d53effbcf6 --- /dev/null +++ b/wii/libogc/libogc/usbstorage.c @@ -0,0 +1,1008 @@ +/*------------------------------------------------------------- + +usbstorage.c -- Bulk-only USB mass storage support + +Copyright (C) 2008 +Sven Peter (svpe) +Copyright (C) 2009-2010 +tueidj, rodries, Tantric + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ +#if defined(HW_RVL) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "asm.h" +#include "processor.h" +#include "disc_io.h" +#include "lwp_watchdog.h" + +#define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f) + +#define HEAP_SIZE (18*1024) +#define TAG_START 0x0BADC0DE + +#define CBW_SIZE 31 +#define CBW_SIGNATURE 0x43425355 +#define CBW_IN (1 << 7) +#define CBW_OUT 0 + +#define CSW_SIZE 13 +#define CSW_SIGNATURE 0x53425355 + +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_INQUIRY 0x12 +#define SCSI_START_STOP 0x1B +#define SCSI_READ_CAPACITY 0x25 +#define SCSI_READ_10 0x28 +#define SCSI_WRITE_10 0x2A + +#define SCSI_SENSE_REPLY_SIZE 18 +#define SCSI_SENSE_NOT_READY 0x02 +#define SCSI_SENSE_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_HARDWARE_ERROR 0x04 + +#define USB_CLASS_MASS_STORAGE 0x08 +#define MASS_STORAGE_RBC_COMMANDS 0x01 +#define MASS_STORAGE_ATA_COMMANDS 0x02 +#define MASS_STORAGE_QIC_COMMANDS 0x03 +#define MASS_STORAGE_UFI_COMMANDS 0x04 +#define MASS_STORAGE_SFF8070_COMMANDS 0x05 +#define MASS_STORAGE_SCSI_COMMANDS 0x06 +#define MASS_STORAGE_BULK_ONLY 0x50 + +#define USBSTORAGE_GET_MAX_LUN 0xFE +#define USBSTORAGE_RESET 0xFF + +#define USB_ENDPOINT_BULK 0x02 + +#define USBSTORAGE_CYCLE_RETRIES 3 +#define USBSTORAGE_TIMEOUT 2 + +#define INVALID_LUN -2 + +#define MAX_TRANSFER_SIZE_V0 4096 +#define MAX_TRANSFER_SIZE_V5 (16*1024) + +#define DEVLIST_MAXSIZE 8 + +static heap_cntrl __heap; +static bool __inited = false; +static u64 usb_last_used = 0; +static lwpq_t __usbstorage_waitq = 0; +static u32 usbtimeout = USBSTORAGE_TIMEOUT; + +/* +The following is for implementing a DISC_INTERFACE +as used by libfat +*/ + +static usbstorage_handle __usbfd; +static u8 __lun = 0; +static bool __mounted = false; +static u16 __vid = 0; +static u16 __pid = 0; +static bool usb2_mode=true; + +static s32 __usbstorage_reset(usbstorage_handle *dev); +static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun); +s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun); + +/* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout + * but there's currently no other known way of doing this and it's in my humble + * opinion still better than having a function blocking forever while waiting + * for the USB data/IOS reply.. + */ + +static s32 __usb_blkmsg_cb(s32 retval, void *dummy) +{ + usbstorage_handle *dev = (usbstorage_handle *)dummy; + dev->retval = retval; + SYS_CancelAlarm(dev->alarm); + LWP_ThreadBroadcast(__usbstorage_waitq); + return 0; +} + +static s32 __usb_deviceremoved_cb(s32 retval,void *arg) +{ + __mounted = false; + return 0; +} + +static void __usb_timeouthandler(syswd_t alarm,void *cbarg) +{ + usbstorage_handle *dev = (usbstorage_handle*)cbarg; + dev->retval = USBSTORAGE_ETIMEDOUT; + LWP_ThreadBroadcast(__usbstorage_waitq); +} + +static void __usb_settimeout(usbstorage_handle *dev, u32 secs) +{ + struct timespec ts; + + ts.tv_sec = secs; + ts.tv_nsec = 0; + SYS_SetAlarm(dev->alarm,&ts,__usb_timeouthandler,dev); +} + +static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData, u32 timeout) +{ + s32 retval; + + dev->retval = USBSTORAGE_PROCESSING; + retval = USB_WriteBlkMsgAsync(dev->usb_fd, bEndpoint, wLength, rpData, __usb_blkmsg_cb, (void *)dev); + if(retval < 0) return retval; + + __usb_settimeout(dev, timeout); + + do { + retval = dev->retval; + if(retval!=USBSTORAGE_PROCESSING) break; + else LWP_ThreadSleep(__usbstorage_waitq); + } while(retval==USBSTORAGE_PROCESSING); + + if (retval<0) + USB_ClearHalt(dev->usb_fd, bEndpoint); + + return retval; +} + +static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData) +{ + s32 retval; + + dev->retval = USBSTORAGE_PROCESSING; + retval = USB_WriteCtrlMsgAsync(dev->usb_fd, bmRequestType, bmRequest, wValue, wIndex, wLength, rpData, __usb_blkmsg_cb, (void *)dev); + if(retval < 0) return retval; + + __usb_settimeout(dev, usbtimeout); + + do { + retval = dev->retval; + if(retval!=USBSTORAGE_PROCESSING) break; + else LWP_ThreadSleep(__usbstorage_waitq); + } while(retval==USBSTORAGE_PROCESSING); + + return retval; +} + +static u8 *arena_ptr=NULL; +static u8 *cbw_buffer=NULL; + +s32 USBStorage_Initialize() +{ + u32 level; + + if(__inited) + return IPC_OK; + + _CPU_ISR_Disable(level); + LWP_InitQueue(&__usbstorage_waitq); + if(!arena_ptr) { + arena_ptr = (u8*)ROUNDDOWN32(((u32)SYS_GetArena2Hi() - HEAP_SIZE)); + if((u32)arena_ptr < (u32)SYS_GetArena2Lo()) { + _CPU_ISR_Restore(level); + return IPC_ENOMEM; + } + SYS_SetArena2Hi(arena_ptr); + } + __lwp_heap_init(&__heap, arena_ptr, HEAP_SIZE, 32); + cbw_buffer=(u8*)__lwp_heap_allocate(&__heap, 32); + __inited = true; + _CPU_ISR_Restore(level); + return IPC_OK; +} + +static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen) +{ + s32 retval = USBSTORAGE_OK; + + if(cbLen == 0 || cbLen > 16) + return IPC_EINVAL; + + memset(cbw_buffer, 0, CBW_SIZE); + + __stwbrx(cbw_buffer, 0, CBW_SIGNATURE); + __stwbrx(cbw_buffer, 4, ++dev->tag); + __stwbrx(cbw_buffer, 8, len); + cbw_buffer[12] = flags; + cbw_buffer[13] = lun; + cbw_buffer[14] = (cbLen > 6 ? 10 : 6); + + memcpy(cbw_buffer + 15, cb, cbLen); + + if(dev->suspended == 1) + { + USB_ResumeDevice(dev->usb_fd); + dev->suspended = 0; + } + + retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)cbw_buffer, usbtimeout); + + if(retval == CBW_SIZE) return USBSTORAGE_OK; + else if(retval > 0) return USBSTORAGE_ESHORTWRITE; + + return retval; +} + +static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue, u32 timeout) +{ + s32 retval = USBSTORAGE_OK; + u32 signature, tag, _dataResidue, _status; + + memset(cbw_buffer, 0, CSW_SIZE); + + retval = __USB_BlkMsgTimeout(dev, dev->ep_in, CSW_SIZE, cbw_buffer, timeout); + if(retval > 0 && retval != CSW_SIZE) return USBSTORAGE_ESHORTREAD; + else if(retval < 0) return retval; + + signature = __lwbrx(cbw_buffer, 0); + tag = __lwbrx(cbw_buffer, 4); + _dataResidue = __lwbrx(cbw_buffer, 8); + _status = cbw_buffer[12]; + + if(signature != CSW_SIGNATURE) return USBSTORAGE_ESIGNATURE; + + if(dataResidue != NULL) + *dataResidue = _dataResidue; + if(status != NULL) + *status = _status; + + if(tag != dev->tag) return USBSTORAGE_ETAG; + + return USBSTORAGE_OK; +} + +static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue) +{ + s32 retval = USBSTORAGE_OK; + + u8 status=0; + u32 dataResidue = 0; + u16 max_size; + u8 ep = write ? dev->ep_out : dev->ep_in; + s8 retries = USBSTORAGE_CYCLE_RETRIES + 1; + + if(usb2_mode) + max_size=MAX_TRANSFER_SIZE_V5; + else + max_size=MAX_TRANSFER_SIZE_V0; + + LWP_MutexLock(dev->lock); + do + { + u8 *_buffer = buffer; + u32 _len = len; + retries--; + + if(retval == USBSTORAGE_ETIMEDOUT) + break; + + retval = __send_cbw(dev, lun, len, (write ? CBW_OUT:CBW_IN), cb, cbLen); + + while(_len > 0 && retval >= 0) + { + u32 thisLen = _len > max_size ? max_size : _len; + + if ((u32)_buffer&0x1F || !((u32)_buffer&0x10000000)) { + if (write) memcpy(dev->buffer, _buffer, thisLen); + retval = __USB_BlkMsgTimeout(dev, ep, thisLen, dev->buffer, usbtimeout); + if (!write && retval > 0) + memcpy(_buffer, dev->buffer, retval); + } else + retval = __USB_BlkMsgTimeout(dev, ep, thisLen, _buffer, usbtimeout); + + if (retval == thisLen) { + _len -= retval; + _buffer += retval; + } + else if (retval != USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_EDATARESIDUE; + } + + if (retval >= 0) + retval = __read_csw(dev, &status, &dataResidue, usbtimeout); + + if (retval < 0) { + if (__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_ETIMEDOUT; + } + } while (retval < 0 && retries > 0); + + LWP_MutexUnlock(dev->lock); + + if(_status != NULL) + *_status = status; + if(_dataResidue != NULL) + *_dataResidue = dataResidue; + + return retval; +} + +static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun) +{ + s32 retval; + u8 cmd[6]; + u8 sense[SCSI_SENSE_REPLY_SIZE]; + u8 status = 0; + + memset(cmd, 0, sizeof(cmd)); + cmd[0] = SCSI_TEST_UNIT_READY; + + retval = __cycle(dev, lun, NULL, 0, cmd, 1, 0, &status, NULL); + if (retval < 0) return retval; + + if (status) + { + cmd[0] = SCSI_REQUEST_SENSE; + cmd[1] = lun << 5; + cmd[4] = SCSI_SENSE_REPLY_SIZE; + memset(sense, 0, SCSI_SENSE_REPLY_SIZE); + retval = __cycle(dev, lun, sense, SCSI_SENSE_REPLY_SIZE, cmd, 6, 0, NULL, NULL); + if (retval>=0) { + switch (sense[2]&0xF) { + case SCSI_SENSE_NOT_READY: + return USBSTORAGE_EINIT; + case SCSI_SENSE_MEDIUM_ERROR: + case SCSI_SENSE_HARDWARE_ERROR: + return USBSTORAGE_ESENSE; + } + } + } + + return retval; +} + +static s32 __usbstorage_reset(usbstorage_handle *dev) +{ + u32 t = usbtimeout; + usbtimeout = 1; + s32 retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_RESET, 0, dev->interface, 0, NULL); + usbtimeout = t; + usleep(60*1000); + USB_ClearHalt(dev->usb_fd, dev->ep_in);usleep(10000); //from http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf + USB_ClearHalt(dev->usb_fd, dev->ep_out);usleep(10000); + return retval; +} + +s32 USBStorage_Open(usbstorage_handle *dev, s32 device_id, u16 vid, u16 pid) +{ + s32 retval = -1; + u8 conf = -1; + u8 *max_lun; + u32 iConf, iInterface, iEp; + usb_devdesc udd; + usb_configurationdesc *ucd; + usb_interfacedesc *uid; + usb_endpointdesc *ued; + + max_lun = __lwp_heap_allocate(&__heap, 1); + if (!max_lun) + return IPC_ENOMEM; + + memset(dev, 0, sizeof(*dev)); + dev->usb_fd = -1; + + dev->tag = TAG_START; + + if (LWP_MutexInit(&dev->lock, false) < 0) + goto free_and_return; + + if (SYS_CreateAlarm(&dev->alarm) < 0) + goto free_and_return; + + retval = USB_OpenDevice(device_id, vid, pid, &dev->usb_fd); + if (retval < 0) + goto free_and_return; + + retval = USB_GetDescriptors(dev->usb_fd, &udd); + if (retval < 0) + goto free_and_return; + + for (iConf = 0; iConf < udd.bNumConfigurations; iConf++) { + ucd = &udd.configurations[iConf]; + for (iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) { + uid = &ucd->interfaces[iInterface]; + if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE && /* + (uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS + || uid->bInterfaceSubClass == MASS_STORAGE_RBC_COMMANDS + || uid->bInterfaceSubClass == MASS_STORAGE_ATA_COMMANDS + || uid->bInterfaceSubClass == MASS_STORAGE_QIC_COMMANDS + || uid->bInterfaceSubClass == MASS_STORAGE_UFI_COMMANDS + || uid->bInterfaceSubClass == MASS_STORAGE_SFF8070_COMMANDS) &&*/ + uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY) + { + + if (uid->bNumEndpoints < 2) + continue; + + dev->ep_in = dev->ep_out = 0; + for (iEp = 0; iEp < uid->bNumEndpoints; iEp++) { + ued = &uid->endpoints[iEp]; + if (ued->bmAttributes != USB_ENDPOINT_BULK) + continue; + + if (ued->bEndpointAddress & USB_ENDPOINT_IN) { + dev->ep_in = ued->bEndpointAddress; + } + else { + dev->ep_out = ued->bEndpointAddress; + if(ued->wMaxPacketSize > 64 && (dev->usb_fd>=0x20 || dev->usb_fd<-1)) + usb2_mode=true; + else + usb2_mode=false; + } + } + + if (dev->ep_in != 0 && dev->ep_out != 0) { + dev->configuration = ucd->bConfigurationValue; + dev->interface = uid->bInterfaceNumber; + dev->altInterface = uid->bAlternateSetting; + goto found; + } + } + } + } + + USB_FreeDescriptors(&udd); + retval = USBSTORAGE_ENOINTERFACE; + goto free_and_return; + +found: + dev->bInterfaceSubClass = uid->bInterfaceSubClass; + + USB_FreeDescriptors(&udd); + + retval = USBSTORAGE_EINIT; + // some devices return an error, ignore it + USB_GetConfiguration(dev->usb_fd, &conf); + + if (conf != dev->configuration) USB_SetConfiguration(dev->usb_fd, dev->configuration); + if (dev->altInterface !=0) USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface); + + if(!usb2_mode) + retval = USBStorage_Reset(dev); + + dev->suspended = 0; + + LWP_MutexLock(dev->lock); + retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, 1, max_lun); + LWP_MutexUnlock(dev->lock); + + if (retval < 0) + dev->max_lun = 1; + else + dev->max_lun = *max_lun + 1; + + if (retval == USBSTORAGE_ETIMEDOUT) + goto free_and_return; + + retval = USBSTORAGE_OK; + dev->sector_size = (u32 *) calloc(dev->max_lun, sizeof(u32)); + if(!dev->sector_size) { + retval = IPC_ENOMEM; + goto free_and_return; + } + + /* taken from linux usbstorage module (drivers/usb/storage/transport.c) + * + * Some devices (i.e. Iomega Zip100) need this -- apparently + * the bulk pipes get STALLed when the GetMaxLUN request is + * processed. This is, in theory, harmless to all other devices + * (regardless of if they stall or not). + * + * 8/9/10: If anyone wants to actually use a Zip100, they can add this back. + * But for now, it seems to be breaking things more than it is helping. + */ + //USB_ClearHalt(dev->usb_fd, dev->ep_in); + //USB_ClearHalt(dev->usb_fd, dev->ep_out); + + if(!dev->buffer) + dev->buffer = __lwp_heap_allocate(&__heap, MAX_TRANSFER_SIZE_V5); + + if(!dev->buffer) { + retval = IPC_ENOMEM; + } else { + USB_DeviceRemovalNotifyAsync(dev->usb_fd,__usb_deviceremoved_cb,dev); + retval = USBSTORAGE_OK; + } + +free_and_return: + if (max_lun) + __lwp_heap_free(&__heap, max_lun); + + if (retval < 0) { + USBStorage_Close(dev); + return retval; + } + + return 0; +} + +s32 USBStorage_Close(usbstorage_handle *dev) +{ + __mounted = false; + __lun = 0; + __vid = 0; + __pid = 0; + + if (dev->usb_fd != -1) + USB_CloseDevice(&dev->usb_fd); + + LWP_MutexDestroy(dev->lock); + SYS_RemoveAlarm(dev->alarm); + + if(dev->sector_size) + free(dev->sector_size); + + if (dev->buffer) + __lwp_heap_free(&__heap, dev->buffer); + + memset(dev, 0, sizeof(*dev)); + dev->usb_fd = -1; + return 0; +} + +s32 USBStorage_Reset(usbstorage_handle *dev) +{ + s32 retval; + + LWP_MutexLock(dev->lock); + retval = __usbstorage_reset(dev); + LWP_MutexUnlock(dev->lock); + + return retval; +} + +s32 USBStorage_GetMaxLUN(usbstorage_handle *dev) +{ + return dev->max_lun; +} + +s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun) +{ + s32 retval; + u32 n_sectors; + + if(lun >= dev->max_lun) + return IPC_EINVAL; + + usleep(50); + retval = __usbstorage_clearerrors(dev, lun); + if (retval<0) + { + USBStorage_Reset(dev); + retval = __usbstorage_clearerrors(dev, lun); + } + + retval = USBStorage_Inquiry(dev, lun); + + retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], &n_sectors); + if(retval >= 0 && (dev->sector_size[lun]<512 || n_sectors==0)) + return INVALID_LUN; + + return retval; +} + +s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun) +{ + int n; + s32 retval; + u8 cmd[] = {SCSI_INQUIRY, lun << 5,0,0,36,0}; + u8 response[36]; + + for(n=0;n<2;n++) + { + memset(response,0,36); + + retval = __cycle(dev, lun, response, 36, cmd, 6, 0, NULL, NULL); + if(retval>=0) break; + } + + if(retval>=0) retval=*response & 31; + /* + if(retval>=0) + { + switch(retval) + { + // info from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type + case 5: // CDROM + case 7: // optical memory device (e.g., some optical disks) + __dvd_mounted = 1; + break; + default: + __dvd_mounted = 0; + break; + } + } + */ + return retval; +} + +s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors) +{ + s32 retval; + u8 cmd[10] = {SCSI_READ_CAPACITY, lun<<5}; + u8 response[8]; + + retval = __cycle(dev, lun, response, sizeof(response), cmd, sizeof(cmd), 0, NULL, NULL); + if(retval >= 0) + { + if(n_sectors != NULL) + memcpy(n_sectors, response, 4); + if(sector_size != NULL) + memcpy(sector_size, response + 4, 4); + retval = USBSTORAGE_OK; + } + + return retval; +} + +s32 USBStorage_IsDVD() +{ + u32 sectorsize, numSectors; + + if(!__mounted || __usbfd.sector_size[__lun] != 2048) + return 0; + + if(USBStorage_ReadCapacity(&__usbfd, __lun, §orsize, &numSectors) < 0) + return 0; + + if(sectorsize == 2048) + return 1; + return 0; +} + +/* lo_ej = load/eject, controls the tray +* start = start(1) or stop(0) the motor (or eject(0), load(1)) +* imm = return before the command has completed +* it might be a good idea to call this before STM_ShutdownToStandby() so the USB HDD doesn't stay on +*/ +s32 USBStorage_StartStop(usbstorage_handle *dev, u8 lun, u8 lo_ej, u8 start, u8 imm) +{ + u8 status = 0; + s32 retval = USBSTORAGE_OK; + u8 cmd[] = { + SCSI_START_STOP, + (lun << 5) | (imm&1), + 0, + 0, + ((lo_ej&1)<<1) | (start&1), + 0 + }; + + if(lun >= dev->max_lun) + return IPC_EINVAL; + + LWP_MutexLock(dev->lock); + + retval = __send_cbw(dev, lun, 0, CBW_IN, cmd, sizeof(cmd)); + + // if imm==0, wait up to 10secs for spinup to finish + if (retval >= 0) + retval = __read_csw(dev, &status, NULL, (imm ? USBSTORAGE_TIMEOUT : 10)); + + LWP_MutexUnlock(dev->lock); + + if(retval >=0 && status != 0) + retval = USBSTORAGE_ESTATUS; + + return retval; +} + +s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer) +{ + u8 status = 0; + s32 retval; + u8 cmd[] = { + SCSI_READ_10, + lun << 5, + sector >> 24, + sector >> 16, + sector >> 8, + sector, + 0, + n_sectors >> 8, + n_sectors, + 0 + }; + + if(lun >= dev->max_lun || dev->sector_size[lun] == 0) + return IPC_EINVAL; + + // more than 60s since last use - make sure drive is awake + if(ticks_to_secs(gettime() - usb_last_used) > 60) + { + usbtimeout = 10; + USBStorage_MountLUN(dev, lun); + } + + retval = __cycle(dev, lun, buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 0, &status, NULL); + if(retval > 0 && status != 0) + retval = USBSTORAGE_ESTATUS; + + usb_last_used = gettime(); + usbtimeout = USBSTORAGE_TIMEOUT; + + return retval; +} + +s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer) +{ + u8 status = 0; + s32 retval; + u8 cmd[] = { + SCSI_WRITE_10, + lun << 5, + sector >> 24, + sector >> 16, + sector >> 8, + sector, + 0, + n_sectors >> 8, + n_sectors, + 0 + }; + + if(lun >= dev->max_lun || dev->sector_size[lun] == 0) + return IPC_EINVAL; + + // more than 60s since last use - make sure drive is awake + if(ticks_to_secs(gettime() - usb_last_used) > 60) + { + usbtimeout = 10; + USBStorage_MountLUN(dev, lun); + } + + retval = __cycle(dev, lun, (u8 *)buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 1, &status, NULL); + if(retval > 0 && status != 0) + retval = USBSTORAGE_ESTATUS; + + usb_last_used = gettime(); + usbtimeout = USBSTORAGE_TIMEOUT; + + return retval; +} + +s32 USBStorage_Suspend(usbstorage_handle *dev) +{ + if(dev->suspended == 1) + return USBSTORAGE_OK; + + USB_SuspendDevice(dev->usb_fd); + dev->suspended = 1; + + return USBSTORAGE_OK; +} + +/* +The following is for implementing a DISC_INTERFACE +as used by libfat +*/ + +static bool __usbstorage_Startup(void) +{ + if(USB_Initialize() < 0 || USBStorage_Initialize() < 0) + return false; + + return true; +} + +static bool __usbstorage_IsInserted(void) +{ + usb_device_entry *buffer; + u8 device_count; + u8 i, j; + u16 vid, pid; + s32 maxLun; + s32 retval; + u32 sectorsize, numSectors; + + if(__mounted) + { + // device is not a USB DVD drive - always return true + if (__usbfd.sector_size[__lun] != 2048) + return true; + + // check if DVD is inserted + if (USBStorage_ReadCapacity(&__usbfd, __lun, §orsize, &numSectors) < 0) + return false; + else + return true; + } + + if(!__inited) + return false; + + buffer = (usb_device_entry*)__lwp_heap_allocate(&__heap, DEVLIST_MAXSIZE * sizeof(usb_device_entry)); + if (!buffer) + return false; + + memset(buffer, 0, DEVLIST_MAXSIZE * sizeof(usb_device_entry)); + + if (USB_GetDeviceList(buffer, DEVLIST_MAXSIZE, USB_CLASS_MASS_STORAGE, &device_count) < 0) + { + if (__vid != 0 || __pid != 0) + USBStorage_Close(&__usbfd); + + __lwp_heap_free(&__heap, buffer); + return false; + } + + usleep(100); + + if (__vid != 0 || __pid != 0) { + for(i = 0; i < device_count; i++) { + vid = buffer[i].vid; + pid = buffer[i].pid; + if(vid != 0 || pid != 0) { + if((vid == __vid) && (pid == __pid)) { + __mounted = true; + __lwp_heap_free(&__heap,buffer); + usleep(50); // I don't know why I have to wait but it's needed + return true; + } + } + } + USBStorage_Close(&__usbfd); // device changed or unplugged, return false the first time to notify to the client that he must unmount devices + __lwp_heap_free(&__heap,buffer); + return false; + } + for (i = 0; i < device_count; i++) { + vid = buffer[i].vid; + pid = buffer[i].pid; + if (vid == 0 || pid == 0) + continue; + + if (vid == 0x0b95 && pid == 0x7720) // USB LAN + continue; + + if (USBStorage_Open(&__usbfd, buffer[i].device_id, vid, pid) < 0) + continue; + + maxLun = USBStorage_GetMaxLUN(&__usbfd); + for (j = 0; j < maxLun; j++) { + retval = USBStorage_MountLUN(&__usbfd, j); + + if (retval == INVALID_LUN) + continue; + + if (retval < 0) + { + __usbstorage_reset(&__usbfd); + continue; + } + + __mounted = true; + __lun = j; + __vid = vid; + __pid = pid; + usb_last_used = gettime()-secs_to_ticks(100); + usleep(10000); + break; + } + + if (__mounted) + break; + + USBStorage_Close(&__usbfd); + } + __lwp_heap_free(&__heap, buffer); + + return __mounted; +} + +static bool __usbstorage_ReadSectors(u32 sector, u32 numSectors, void *buffer) +{ + s32 retval; + + if (!__mounted) + return false; + + retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer); + + return retval >= 0; +} + +static bool __usbstorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) +{ + s32 retval; + + if (!__mounted) + return false; + + retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer); + + return retval >= 0; +} + +static bool __usbstorage_ClearStatus(void) +{ + return true; +} + +static bool __usbstorage_Shutdown(void) +{ + if (__vid != 0 || __pid != 0) + USBStorage_Close(&__usbfd); + + return true; +} + +void USBStorage_Deinitialize() +{ + __usbstorage_Shutdown(); + LWP_CloseQueue(__usbstorage_waitq); + __inited = false; +} + +s32 USBStorage_ioctl(int request, ...) +{ + int retval = 0; + va_list ap; + + if(!__mounted) + return -1; + + va_start(ap, request); + + switch (request) + { + case B_RAW_DEVICE_COMMAND: + { + u8 write; + raw_device_command *rdc = va_arg(ap, raw_device_command *); + write = (rdc->flags == B_RAW_DEVICE_DATA_IN) ? 0 : 1; + retval = __cycle(&__usbfd, __lun, rdc->data, rdc->data_length, rdc->command, rdc->command_length, write, &rdc->scsi_status, NULL); + break; + } + + default: + retval = -1; + break; + } + + va_end(ap); + return retval; +} + +DISC_INTERFACE __io_usbstorage = { + DEVICE_TYPE_WII_USB, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP)&__usbstorage_Startup, + (FN_MEDIUM_ISINSERTED)&__usbstorage_IsInserted, + (FN_MEDIUM_READSECTORS)&__usbstorage_ReadSectors, + (FN_MEDIUM_WRITESECTORS)&__usbstorage_WriteSectors, + (FN_MEDIUM_CLEARSTATUS)&__usbstorage_ClearStatus, + (FN_MEDIUM_SHUTDOWN)&__usbstorage_Shutdown +}; + +#endif /* HW_RVL */ diff --git a/wii/libogc/libogc/video.c b/wii/libogc/libogc/video.c new file mode 100644 index 0000000000..9012530ea2 --- /dev/null +++ b/wii/libogc/libogc/video.c @@ -0,0 +1,2594 @@ +/*------------------------------------------------------------- + +video.c -- VIDEO subsystem + + Copyright (C) 2004 - 2008 + Michael Wiedenbauer (shagkur) + Dave Murphy (WinterMute) + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include "asm.h" +#include "processor.h" +#include "ogcsys.h" +#include "irq.h" +#include "exi.h" +#include "gx.h" +#include "si.h" +#include "lwp.h" +#include "system.h" +#include "video.h" +#include "video_types.h" + +#define VIDEO_MQ 1 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +#define VI_REGCHANGE(_reg) \ + ((u64)0x01<<(63-_reg)) + +typedef struct _horVer { + u16 dispPosX; + u16 dispPosY; + u16 dispSizeX; + u16 dispSizeY; + u16 adjustedDispPosX; + u16 adjustedDispPosY; + u16 adjustedDispSizeY; + u16 adjustedPanPosY; + u16 adjustedPanSizeY; + u16 fbSizeX; + u16 fbSizeY; + u16 panPosX; + u16 panPosY; + u16 panSizeX; + u16 panSizeY; + u32 fbMode; + u32 nonInter; + u32 tv; + u8 wordPerLine; + u8 std; + u8 wpl; + void *bufAddr; + u32 tfbb; + u32 bfbb; + u8 xof; + s32 black; + s32 threeD; + void *rbufAddr; + u32 rtfbb; + u32 rbfbb; + const struct _timing *timing; +} horVer; + +GXRModeObj TVNtsc240Ds = +{ + VI_TVMODE_NTSC_DS, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVNtsc240DsAa = +{ + VI_TVMODE_NTSC_DS, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVNtsc240Int = +{ + VI_TVMODE_NTSC_INT, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_TRUE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVNtsc240IntAa = +{ + VI_TVMODE_NTSC_INT, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_TRUE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVNtsc480Int = +{ + VI_TVMODE_NTSC_INT, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVNtsc480IntDf = +{ + VI_TVMODE_NTSC_INT, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } +}; + +GXRModeObj TVNtsc480IntAa = +{ + VI_TVMODE_NTSC_INT, // viDisplayMode + 640, // fbWidth + 242, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 4, // line n-1 + 8, // line n-1 + 12, // line n + 16, // line n + 12, // line n + 8, // line n+1 + 4 // line n+1 + } +}; + + +GXRModeObj TVNtsc480Prog = +{ + VI_TVMODE_NTSC_PROG, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVNtsc480ProgSoft = +{ + VI_TVMODE_NTSC_PROG, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } +}; + +GXRModeObj TVNtsc480ProgAa = +{ + VI_TVMODE_NTSC_PROG, // viDisplayMode + 640, // fbWidth + 242, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_NTSC - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 4, // line n-1 + 8, // line n-1 + 12, // line n + 16, // line n + 12, // line n + 8, // line n+1 + 4 // line n+1 + } +}; + +GXRModeObj TVMpal240Ds = +{ + VI_TVMODE_MPAL_DS, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_MPAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_MPAL - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVMpal240DsAa = +{ + VI_TVMODE_MPAL_DS, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_MPAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_MPAL - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVMpal480IntDf = +{ + VI_TVMODE_MPAL_INT, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_MPAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_MPAL - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } +}; + +GXRModeObj TVMpal480IntAa = +{ + VI_TVMODE_MPAL_INT, // viDisplayMode + 640, // fbWidth + 242, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_MPAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_MPAL - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 4, // line n-1 + 8, // line n-1 + 12, // line n + 16, // line n + 12, // line n + 8, // line n+1 + 4 // line n+1 + } +}; + +GXRModeObj TVMpal480Prog = +{ + VI_TVMODE_MPAL_PROG, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_MPAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_MPAL - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVPal264Ds = +{ + VI_TVMODE_PAL_DS, // viDisplayMode + 640, // fbWidth + 264, // efbHeight + 264, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 528)/2, // viYOrigin + 640, // viWidth + 528, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVPal264DsAa = +{ + VI_TVMODE_PAL_DS, // viDisplayMode + 640, // fbWidth + 264, // efbHeight + 264, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 528)/2, // viYOrigin + 640, // viWidth + 528, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVPal264Int = +{ + VI_TVMODE_PAL_INT, // viDisplayMode + 640, // fbWidth + 264, // efbHeight + 264, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 528)/2, // viYOrigin + 640, // viWidth + 528, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_TRUE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVPal264IntAa = +{ + VI_TVMODE_PAL_INT, // viDisplayMode + 640, // fbWidth + 264, // efbHeight + 264, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 528)/2, // viYOrigin + 640, // viWidth + 528, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_TRUE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVPal524IntAa = +{ + VI_TVMODE_PAL_INT, + 640, + 264, + 524, + (VI_MAX_WIDTH_PAL-640)/2, + (VI_MAX_HEIGHT_PAL-528)/2, + 640, + 524, + VI_XFBMODE_DF, + GX_FALSE, + GX_TRUE, + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 4, // line n-1 + 8, // line n-1 + 12, // line n + 16, // line n + 12, // line n + 8, // line n+1 + 4 // line n+1 + } +}; + +GXRModeObj TVPal528Int = +{ + VI_TVMODE_PAL_INT, // viDisplayMode + 640, // fbWidth + 528, // efbHeight + 528, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 528)/2, // viYOrigin + 640, // viWidth + 528, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVPal528IntDf = +{ + VI_TVMODE_PAL_INT, // viDisplayMode + 640, // fbWidth + 528, // efbHeight + 528, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 528)/2, // viYOrigin + 640, // viWidth + 528, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } +}; + +GXRModeObj TVPal576IntDfScale = +{ + VI_TVMODE_PAL_INT, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 576, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 576)/2, // viYOrigin + 640, // viWidth + 576, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } +}; + +GXRModeObj TVPal576ProgScale = +{ + VI_TVMODE_PAL_PROG, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 576, // xfbHeight + (VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_PAL - 576)/2, // viYOrigin + 640, // viWidth + 576, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz240Ds = +{ + VI_TVMODE_EURGB60_DS, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz240DsAa = +{ + VI_TVMODE_EURGB60_DS, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz240Int = +{ + VI_TVMODE_EURGB60_INT, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_TRUE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz240IntAa = +{ + VI_TVMODE_EURGB60_INT, // viDisplayMode + 640, // fbWidth + 240, // efbHeight + 240, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_TRUE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz480Int = +{ + VI_TVMODE_EURGB60_INT, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz480IntDf = +{ + VI_TVMODE_EURGB60_INT, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz480IntAa = +{ + VI_TVMODE_EURGB60_INT, // viDisplayMode + 640, // fbWidth + 242, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_DF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 4, // line n-1 + 8, // line n-1 + 12, // line n + 16, // line n + 12, // line n + 8, // line n+1 + 4 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz480Prog = +{ + VI_TVMODE_EURGB60_PROG, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz480ProgSoft = +{ + VI_TVMODE_EURGB60_PROG, // viDisplayMode + 640, // fbWidth + 480, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 4, // line n-1 + 8, // line n-1 + 12, // line n + 16, // line n + 12, // line n + 8, // line n+1 + 4 // line n+1 + } +}; + +GXRModeObj TVEurgb60Hz480ProgAa = +{ + VI_TVMODE_EURGB60_PROG, // viDisplayMode + 640, // fbWidth + 242, // efbHeight + 480, // xfbHeight + (VI_MAX_WIDTH_EURGB60 - 640)/2, // viXOrigin + (VI_MAX_HEIGHT_EURGB60 - 480)/2, // viYOrigin + 640, // viWidth + 480, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } +}; + + +static const u16 taps[26] = { + 0x01F0,0x01DC,0x01AE,0x0174,0x0129,0x00DB, + 0x008E,0x0046,0x000C,0x00E2,0x00CB,0x00C0, + 0x00C4,0x00CF,0x00DE,0x00EC,0x00FC,0x0008, + 0x000F,0x0013,0x0013,0x000F,0x000C,0x0008, + 0x0001,0x0000 +}; + +static const struct _timing { + u8 equ; + u16 acv; + u16 prbOdd,prbEven; + u16 psbOdd,psbEven; + u8 bs1,bs2,bs3,bs4; + u16 be1,be2,be3,be4; + u16 nhlines,hlw; + u8 hsy,hcs,hce,hbe640; + u16 hbs640; +} video_timing[] = { + { + 0x06,0x00F0, + 0x0018,0x0019,0x0003,0x0002, + 0x0C,0x0D,0x0C,0x0D, + 0x0208,0x0207,0x0208,0x0207, + 0x020D,0x01AD, + 0x40,0x47,0x69,0xA2, + 0x0175 + }, + { + 0x06,0x00F0, + 0x0018,0x0018,0x0004,0x0004, + 0x0C,0x0C,0x0C,0x0C, + 0x0208,0x0208,0x0208,0x0208, + 0x020E,0x01AD, + 0x40,0x47,0x69,0xA2, + 0x0175 + }, + { + 0x05,0x0120, + 0x0021,0x0022,0x0001,0x0000, + 0x0A,0x0B,0x0A,0x0B, + 0x026D,0x026C,0x026D,0x026C, + 0x0271,0x01B0, + 0x40,0x4B,0x6A,0xAC, + 0x017C + }, + { + 0x05,0x011F, + 0x0021,0x0021,0x0002,0x0002, + 0x0D,0x0B,0x0D,0x0B, + 0x026B,0x026D,0x026B,0x026D, + 0x0270,0x01B0, + 0x40,0x4B,0x6A,0xAC, + 0x017C + }, + { + 0x06,0x00F0, + 0x0018,0x0019,0x0003,0x0002, + 0x10,0x0F,0x0E,0x0D, + 0x0206,0x0205,0x0204,0x0207, + 0x020D,0x01AD, + 0x40,0x4E,0x70,0xA2, + 0x0175 + }, + { + 0x06,0x00F0, + 0x0018,0x0018,0x0004,0x0004, + 0x10,0x0E,0x10,0x0E, + 0x0206,0x0208,0x0206,0x0208, + 0x020E,0x01AD, + 0x40,0x4E,0x70,0xA2, + 0x0175 + }, + { + 0x0C,0x01E0, + 0x0030,0x0030,0x0006,0x0006, + 0x18,0x18,0x18,0x18, + 0x040E,0x040E,0x040E,0x040E, + 0x041A,0x01AD, + 0x40,0x47,0x69,0xA2, + 0x0175 + }, + { + 0x0A,0x0240, + 0x003E,0x003E,0x0006,0x0006, + 0x14,0x14,0x14,0x14, + 0x04D8,0x04D8,0x04D8,0x04D8, + 0x04E2,0x01B0, + 0x40,0x4B,0x6A,0xAC, + 0x017C + } +}; + +#if defined(HW_RVL) +static u32 vdacFlagRegion; +static u32 i2cIdentFirst = 0; +static u32 i2cIdentFlag = 1; +static u32 oldTvStatus = 0x03e7; +static u32 oldDtvStatus = 0x03e7; +static vu32* const _i2cReg = (u32*)0xCD800000; +#endif + +static u16 regs[60]; +static u16 shdw_regs[60]; +static u32 fbSet = 0; +static s16 displayOffsetH; +static s16 displayOffsetV; +static u32 currTvMode,changeMode; +static u32 shdw_changeMode,flushFlag; +static u64 changed,shdw_changed; +static vu32 retraceCount; +static const struct _timing *currTiming; +static lwpq_t video_queue; +static horVer HorVer; +static void *currentFb = NULL; +static void *nextFb = NULL; +static VIRetraceCallback preRetraceCB = NULL; +static VIRetraceCallback postRetraceCB = NULL; +static VIPositionCallback positionCB = NULL; + +static vu16* const _viReg = (u16*)0xCC002000; + +extern syssram* __SYS_LockSram(); +extern u32 __SYS_UnlockSram(u32 write); + +extern void __VIClearFramebuffer(void*,u32,u32); + +extern void udelay(int us); + +static __inline__ u32 cntlzd(u64 bit) +{ + u32 hi = (u32)(bit>>32); + u32 lo = (u32)(bit&-1); + u32 value = cntlzw(hi); + if(value>=32) value += cntlzw(lo); + + return value; +} + +static const struct _timing* __gettiming(u32 vimode) +{ + switch(vimode) { + case VI_TVMODE_NTSC_INT: + return &video_timing[0]; + break; + case VI_TVMODE_NTSC_DS: + return &video_timing[1]; + break; + case VI_TVMODE_PAL_INT: + return &video_timing[2]; + break; + case VI_TVMODE_PAL_DS: + return &video_timing[3]; + break; + case VI_TVMODE_EURGB60_INT: + return &video_timing[0]; + break; + case VI_TVMODE_EURGB60_DS: + return &video_timing[1]; + break; + case VI_TVMODE_MPAL_INT: + return &video_timing[4]; + break; + case VI_TVMODE_MPAL_DS: + return &video_timing[5]; + break; + case VI_TVMODE_NTSC_PROG: + return &video_timing[6]; + break; + case VI_TVMODE_PAL_PROG: + return &video_timing[7]; + break; + case VI_TVMODE_EURGB60_PROG: + return &video_timing[6]; + break; + case VI_TVMODE_MPAL_PROG: + return &video_timing[6]; + break; + default: + return NULL; + } +} + +#if defined(HW_RVL) +static inline void __viOpenI2C(u32 channel) +{ + u32 val = ((_i2cReg[49]&~0x8000)|0x4000); + val |= _SHIFTL(channel,15,1); + _i2cReg[49] = val; +} + +static inline u32 __viSetSCL(u32 channel) +{ + u32 val = (_i2cReg[48]&~0x4000); + val |= _SHIFTL(channel,14,1); + _i2cReg[48] = val; + return 1; +} +static inline u32 __viSetSDA(u32 channel) +{ + u32 val = (_i2cReg[48]&~0x8000); + val |= _SHIFTL(channel,15,1); + _i2cReg[48] = val; + return 1; +} + +static inline u32 __viGetSDA() +{ + return _SHIFTR(_i2cReg[50],15,1); +} + +static inline void __viCheckI2C() +{ + __viOpenI2C(0); + udelay(4); + + i2cIdentFlag = 0; + if(__viGetSDA()!=0) i2cIdentFlag = 1; +} + +static u32 __sendSlaveAddress(u8 addr) +{ + u32 i; + + __viSetSDA(i2cIdentFlag^1); + udelay(2); + + __viSetSCL(0); + for(i=0;i<8;i++) { + if(addr&0x80) __viSetSDA(i2cIdentFlag); + else __viSetSDA(i2cIdentFlag^1); + udelay(2); + + __viSetSCL(1); + udelay(2); + + __viSetSCL(0); + addr <<= 1; + } + + __viOpenI2C(0); + udelay(2); + + __viSetSCL(1); + udelay(2); + + if(i2cIdentFlag==1 && __viGetSDA()!=0) return 0; + + __viSetSDA(i2cIdentFlag^1); + __viOpenI2C(1); + __viSetSCL(0); + + return 1; +} +#endif + +static inline void __setInterruptRegs(const struct _timing *tm) +{ + u16 hlw; + + hlw = 0; + if(tm->nhlines%2) hlw = tm->hlw; + regs[24] = 0x1000|((tm->nhlines/2)+1); + regs[25] = hlw+1; + changed |= VI_REGCHANGE(24); + changed |= VI_REGCHANGE(25); +} + +static inline void __setPicConfig(u16 fbSizeX,u32 xfbMode,u16 panPosX,u16 panSizeX,u8 *wordPerLine,u8 *std,u8 *wpl,u8 *xof) +{ + *wordPerLine = (fbSizeX+15)/16; + *std = *wordPerLine; + if(xfbMode==VI_XFBMODE_DF) *std <<= 1; + + *xof = panPosX%16; + *wpl = (*xof+(panSizeX+15))/16; + regs[36] = (*wpl<<8)|*std; + changed |= VI_REGCHANGE(36); +} + +static inline void __setBBIntervalRegs(const struct _timing *tm) +{ + regs[10] = (tm->be3<<5)|tm->bs3; + regs[11] = (tm->be1<<5)|tm->bs1; + changed |= VI_REGCHANGE(10); + changed |= VI_REGCHANGE(11); + + regs[12] = (tm->be4<<5)|tm->bs4; + regs[13] = (tm->be2<<5)|tm->bs2; + changed |= VI_REGCHANGE(12); + changed |= VI_REGCHANGE(13); +} + +static void __setScalingRegs(u16 panSizeX,u16 dispSizeX,s32 threeD) +{ + if(threeD) panSizeX = _SHIFTL(panSizeX,1,16); + if(panSizeXbufAddr,horVer->panPosX,horVer->adjustedPanPosY,horVer->wordPerLine,horVer->fbMode,horVer->adjustedDispPosY,tfbb,bfbb); + if(horVer->threeD) __calcFbbs((u32)horVer->rbufAddr,horVer->panPosX,horVer->adjustedPanPosY,horVer->wordPerLine,horVer->fbMode,horVer->adjustedDispPosY,rtfbb,rbfbb); + + flag = 1; + if((*tfbb)<0x01000000 && (*bfbb)<0x01000000 + && (*rtfbb)<0x01000000 && (*rbfbb)<0x01000000) flag = 0; + + if(flag) { + *tfbb >>= 5; + *bfbb >>= 5; + *rtfbb >>= 5; + *rbfbb >>= 5; + } + + regs[14] = _SHIFTL(flag,12,1)|_SHIFTL(horVer->xof,8,4)|_SHIFTR(*tfbb,16,8); + regs[15] = *tfbb&0xffff; + changed |= VI_REGCHANGE(14); + changed |= VI_REGCHANGE(15); + + regs[18] = _SHIFTR(*bfbb,16,8); + regs[19] = *bfbb&0xffff; + changed |= VI_REGCHANGE(18); + changed |= VI_REGCHANGE(19); + + if(horVer->threeD) { + regs[16] = _SHIFTR(*rtfbb,16,8); + regs[17] = *rtfbb&0xffff; + changed |= VI_REGCHANGE(16); + changed |= VI_REGCHANGE(17); + + regs[20] = _SHIFTR(*rbfbb,16,8); + regs[21] = *rbfbb&0xffff; + changed |= VI_REGCHANGE(20); + changed |= VI_REGCHANGE(21); + } +} + +static inline void __setHorizontalRegs(const struct _timing *tm,u16 dispPosX,u16 dispSizeX) +{ + u32 val1,val2; + + regs[2] = (tm->hcs<<8)|tm->hce; + regs[3] = tm->hlw; + changed |= VI_REGCHANGE(2); + changed |= VI_REGCHANGE(3); + + val1 = (tm->hbe640+dispPosX-40)&0x01ff; + val2 = (tm->hbs640+dispPosX+40)-(720-dispSizeX); + regs[4] = (val1>>9)|(val2<<1); + regs[5] = (val1<<7)|tm->hsy; + changed |= VI_REGCHANGE(4); + changed |= VI_REGCHANGE(5); +} + +static inline void __setVerticalRegs(u16 dispPosY,u16 dispSizeY,u8 equ,u16 acv,u16 prbOdd,u16 prbEven,u16 psbOdd,u16 psbEven,s32 black) +{ + u16 tmp; + u32 div1,div2; + u32 psb,prb; + u32 psbodd,prbodd; + u32 psbeven,prbeven; + + div1 = 2; + div2 = 1; + if(equ>=10) { + div1 = 1; + div2 = 2; + } + + prb = div2*dispPosY; + psb = div2*(((acv*div1)-dispSizeY)-dispPosY); + if(dispPosY%2) { + prbodd = prbEven+prb; + psbodd = psbEven+psb; + prbeven = prbOdd+prb; + psbeven = psbOdd+psb; + } else { + prbodd = prbOdd+prb; + psbodd = psbOdd+psb; + prbeven = prbEven+prb; + psbeven = psbEven+psb; + } + + tmp = dispSizeY/div1; + if(black) { + prbodd += ((tmp<<1)-2); + prbeven += ((tmp<<1)-2); + psbodd += 2; + psbeven += 2; + tmp = 0; + } + + regs[0] = ((tmp<<4)&~0x0f)|equ; + changed |= VI_REGCHANGE(0); + + regs[6] = psbodd; + regs[7] = prbodd; + changed |= VI_REGCHANGE(6); + changed |= VI_REGCHANGE(7); + + regs[8] = psbeven; + regs[9] = prbeven; + changed |= VI_REGCHANGE(8); + changed |= VI_REGCHANGE(9); +} + +static inline void __adjustPosition(u16 acv) +{ + u32 fact,field; + s16 dispPosX,dispPosY; + s16 dispSizeY,maxDispSizeY; + + dispPosX = (HorVer.dispPosX+displayOffsetH); + if(dispPosX<=(720-HorVer.dispSizeX)) { + if(dispPosX>=0) HorVer.adjustedDispPosX = dispPosX; + else HorVer.adjustedDispPosX = 0; + } else HorVer.adjustedDispPosX = (720-HorVer.dispSizeX); + + fact = 1; + if(HorVer.fbMode==VI_XFBMODE_SF) fact = 2; + + field = HorVer.dispPosY&0x0001; + dispPosY = HorVer.dispPosY+displayOffsetV; + if(dispPosY>field) HorVer.adjustedDispPosY = dispPosY; + else HorVer.adjustedDispPosY = field; + + dispSizeY = HorVer.dispPosY+HorVer.dispSizeY+displayOffsetV; + maxDispSizeY = ((acv<<1)-field); + if(dispSizeY>maxDispSizeY) dispSizeY -= (acv<<1)-field; + else dispSizeY = 0; + + dispPosY = HorVer.dispPosY+displayOffsetV; + if(dispPosYmaxDispSizeY) dispSizeY -= maxDispSizeY; + else dispSizeY = 0; + + dispPosY = HorVer.dispPosY+displayOffsetV; + if(dispPosYdisplay_offsetH; + __SYS_UnlockSram(0); +#else + s8 offset; + if ( CONF_GetDisplayOffsetH(&offset) == 0 ) { + displayOffsetH = offset; + } else { + displayOffsetH = 0; + } +#endif + displayOffsetV = 0; +} + +static void __VIInit(u32 vimode) +{ + u32 cnt; + u32 vi_mode,interlace,progressive; + const struct _timing *cur_timing = NULL; + + vi_mode = ((vimode>>2)&0x07); + interlace = (vimode&0x01); + progressive = (vimode&0x02); + + cur_timing = __gettiming(vimode); + + //reset the interface + cnt = 0; + _viReg[1] = 0x02; + while(cnt<1000) cnt++; + _viReg[1] = 0x00; + + // now begin to setup the interface + _viReg[2] = ((cur_timing->hcs<<8)|cur_timing->hce); //set HCS & HCE + _viReg[3] = cur_timing->hlw; //set Half Line Width + + _viReg[4] = (cur_timing->hbs640<<1); //set HBS640 + _viReg[5] = ((cur_timing->hbe640<<7)|cur_timing->hsy); //set HBE640 & HSY + + _viReg[0] = cur_timing->equ; + + _viReg[6] = (cur_timing->psbOdd+2); //set PSB odd field + _viReg[7] = (cur_timing->prbOdd+((cur_timing->acv<<1)-2)); //set PRB odd field + + _viReg[8] = (cur_timing->psbEven+2); //set PSB even field + _viReg[9] = (cur_timing->prbEven+((cur_timing->acv<<1)-2)); //set PRB even field + + _viReg[10] = ((cur_timing->be3<<5)|cur_timing->bs3); //set BE3 & BS3 + _viReg[11] = ((cur_timing->be1<<5)|cur_timing->bs1); //set BE1 & BS1 + + _viReg[12] = ((cur_timing->be4<<5)|cur_timing->bs4); //set BE4 & BS4 + _viReg[13] = ((cur_timing->be2<<5)|cur_timing->bs2); //set BE2 & BS2 + + _viReg[24] = (0x1000|((cur_timing->nhlines/2)+1)); + _viReg[25] = (cur_timing->hlw+1); + + _viReg[26] = 0x1001; //set DI1 + _viReg[27] = 0x0001; //set DI1 + _viReg[36] = 0x2828; //set HSR + + if(vi_mode=VI_DEBUG_PAL) vi_mode = VI_NTSC; + if(progressive){ + _viReg[1] = ((vi_mode<<8)|0x0005); //set MODE & INT & enable + _viReg[54] = 0x0001; + } else { + _viReg[1] = ((vi_mode<<8)|(interlace<<2)|0x0001); + _viReg[54] = 0x0000; + } +} + +#if defined(HW_RVL) +static u32 __VISendI2CData(u8 addr,void *val,u32 len) +{ + u8 c; + s32 i,j; + u32 level,ret; + + if(i2cIdentFirst==0) { + __viCheckI2C(); + i2cIdentFirst = 1; + } + + _CPU_ISR_Disable(level); + + __viOpenI2C(1); + __viSetSCL(1); + + __viSetSDA(i2cIdentFlag); + udelay(4); + + ret = __sendSlaveAddress(addr); + if(ret==0) { + _CPU_ISR_Restore(level); + return 0; + } + + __viOpenI2C(1); + for(i=0;i> 8; + buf[2] = data & 0xFF; + __VISendI2CData(0xe0,buf,3); + udelay(2); +} + +static void __VIWriteI2CRegister32(u8 reg, u32 data) +{ + u8 buf[5]; + buf[0] = reg; + buf[1] = data >> 24; + buf[2] = (data >> 16) & 0xFF; + buf[3] = (data >> 8) & 0xFF; + buf[4] = data & 0xFF; + __VISendI2CData(0xe0,buf,5); + udelay(2); +} + +static void __VIWriteI2CRegisterBuf(u8 reg, int size, u8 *data) +{ + u8 buf[0x100]; + buf[0] = reg; + memcpy(&buf[1], data, size); + __VISendI2CData(0xe0,buf,size+1); + udelay(2); +} + +static void __VISetYUVSEL(u8 dtvstatus) +{ + if(currTvMode==VI_NTSC) vdacFlagRegion = 0x0000; + else if(currTvMode==VI_PAL || currTvMode==VI_EURGB60) vdacFlagRegion = 0x0002; + else if(currTvMode==VI_MPAL) vdacFlagRegion = 0x0001; + else vdacFlagRegion = 0x0000; + + __VIWriteI2CRegister8(0x01, _SHIFTL(dtvstatus,5,3)|(vdacFlagRegion&0x1f)); +} + +static void __VISetFilterEURGB60(u8 enable) +{ + __VIWriteI2CRegister8(0x6e, enable); +} + +static void __VISetupEncoder(void) +{ + u8 macrobuf[0x1a]; + + u8 gamma[0x21] = { + 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x60, + 0x80, 0xa0, 0xeb, 0x10, 0x00, 0x20, 0x00, 0x40, + 0x00, 0x60, 0x00, 0x80, 0x00, 0xa0, 0x00, 0xeb, + 0x00 + }; + + u8 dtv, tv; + + tv = VIDEO_GetCurrentTvMode(); + dtv = (_viReg[55]&0x01); + oldDtvStatus = dtv; + + // SetRevolutionModeSimple + + memset(macrobuf, 0, 0x1a); + + __VIWriteI2CRegister8(0x6a, 1); + __VIWriteI2CRegister8(0x65, 1); + __VISetYUVSEL(dtv); + __VIWriteI2CRegister8(0x00, 0); + __VIWriteI2CRegister16(0x71, 0x8e8e); + __VIWriteI2CRegister8(0x02, 7); + __VIWriteI2CRegister16(0x05, 0x0000); + __VIWriteI2CRegister16(0x08, 0x0000); + __VIWriteI2CRegister32(0x7A, 0x00000000); + + // Macrovision crap + __VIWriteI2CRegisterBuf(0x40, sizeof(macrobuf), macrobuf); + + // Sometimes 1 in RGB mode? (reg 1 == 3) + __VIWriteI2CRegister8(0x0A, 0); + + __VIWriteI2CRegister8(0x03, 1); + + __VIWriteI2CRegisterBuf(0x10, sizeof(gamma), gamma); + + __VIWriteI2CRegister8(0x04, 1); + + if(tv==VI_EURGB60) __VISetFilterEURGB60(1); + else __VISetFilterEURGB60(0); + oldTvStatus = tv; + +} +#endif + +static inline void __getCurrentDisplayPosition(u32 *px,u32 *py) +{ + u32 hpos = 0; + u32 vpos = 0; + u32 vpos_old; + + vpos = (_viReg[22]&0x7ff); + do { + vpos_old = vpos; + hpos = (_viReg[23]&0x7ff); + vpos = (_viReg[22]&0x7ff); + } while(vpos_old!=vpos); + *px = hpos; + *py = vpos; +} + +static inline u32 __getCurrentHalfLine() +{ + u32 vpos = 0; + u32 hpos = 0; + + __getCurrentDisplayPosition(&hpos,&vpos); + + hpos--; + vpos--; + vpos <<= 1; + + return vpos+(hpos/currTiming->hlw); +} + +static inline u32 __getCurrentFieldEvenOdd() +{ + u32 hline; + + hline = __getCurrentHalfLine(); + if(hlinenhlines) return 1; + + return 0; +} + +static inline u32 __VISetRegs() +{ + u32 val; + u64 mask; + + if(shdw_changeMode==1){ + if(!__getCurrentFieldEvenOdd()) return 0; + } + + while(shdw_changed) { + val = cntlzd(shdw_changed); + _viReg[val] = shdw_regs[val]; + mask = VI_REGCHANGE(val); + shdw_changed &= ~mask; + } + shdw_changeMode = 0; + currTiming = HorVer.timing; + currTvMode = HorVer.tv; + + currentFb = nextFb; + + return 1; +} + +static void __VIDisplayPositionToXY(s32 xpos,s32 ypos,s32 *px,s32 *py) +{ + u32 hpos,vpos; + u32 hline,val; + + hpos = (xpos-1); + vpos = (ypos-1); + hline = ((vpos<<1)+(hpos/currTiming->hlw)); + + *px = (s32)hpos; + if(HorVer.nonInter==0x0000) { + if(hlinenhlines) { + val = currTiming->prbOdd+(currTiming->equ*3); + if(hline>=val) { + val = (currTiming->nhlines-currTiming->psbOdd); + if(hlineequ*3))-currTiming->prbOdd)&~0x01); + } else + *py = -1; + } else + *py = -1; + } else { + hline -= currTiming->psbOdd; + val = (currTiming->prbEven+(currTiming->equ*3)); + if(hline>=val) { + val = (currTiming->nhlines-currTiming->psbEven); + if(hlineequ*3))-currTiming->prbEven)&~0x01)+1); + } else + *py = -1; + } else + *py = -1; + } + } else if(HorVer.nonInter==0x0001) { + if(hline>=currTiming->nhlines) hline -= currTiming->nhlines; + + val = (currTiming->prbOdd+(currTiming->equ*3)); + if(hline>=val) { + val = (currTiming->nhlines-currTiming->psbOdd); + if(hlineequ*3))-currTiming->prbOdd)&~0x01); + } else + *py = -1; + } else + *py = -1; + } else if(HorVer.nonInter==0x0002) { + if(hlinenhlines) { + val = currTiming->prbOdd+(currTiming->equ*3); + if(hline>=val) { + val = (currTiming->nhlines-currTiming->psbOdd); + if(hlineequ*3))-currTiming->prbOdd); + } else + *py = -1; + } else + *py = -1; + } else { + hline -= currTiming->psbOdd; + val = (currTiming->prbEven+(currTiming->equ*3)); + if(hline>=val) { + val = (currTiming->nhlines-currTiming->psbEven); + if(hlineequ*3))-currTiming->prbEven)&~0x01); + } else + *py = -1; + } else + *py = -1; + } + } +} + +static inline void __VIGetCurrentPosition(s32 *px,s32 *py) +{ + s32 xpos,ypos; + + __getCurrentDisplayPosition((u32*)&xpos,(u32*)&ypos); + __VIDisplayPositionToXY(xpos,ypos,px,py); +} + +static void __VIRetraceHandler(u32 nIrq,void *pCtx) +{ +#if defined(HW_RVL) + u8 dtv, tv; +#endif + u32 ret = 0; + u32 intr; + s32 xpos,ypos; + + intr = _viReg[24]; + if(intr&0x8000) { + _viReg[24] = intr&~0x8000; + ret |= 0x01; + } + + intr = _viReg[26]; + if(intr&0x8000) { + _viReg[26] = intr&~0x8000; + ret |= 0x02; + } + + intr = _viReg[28]; + if(intr&0x8000) { + _viReg[28] = intr&~0x8000; + ret |= 0x04; + } + + intr = _viReg[30]; + if(intr&0x8000) { + _viReg[30] = intr&~0x8000; + ret |= 0x08; + } + + intr = _viReg[30]; + if(ret&0x04 || ret&0x08) { + if(positionCB!=NULL) { + __VIGetCurrentPosition(&xpos,&ypos); + positionCB(xpos,ypos); + } + } + + retraceCount++; + if(preRetraceCB) + preRetraceCB(retraceCount); + + if(flushFlag) { + if(__VISetRegs()) { + flushFlag = 0; + SI_RefreshSamplingRate(); + } + } +#if defined(HW_RVL) + tv = VIDEO_GetCurrentTvMode(); + dtv = (_viReg[55]&0x01); + if(dtv!=oldDtvStatus || tv!=oldTvStatus) __VISetYUVSEL(dtv); + oldDtvStatus = dtv; + + if(tv!=oldTvStatus) { + if(tv==VI_EURGB60) __VISetFilterEURGB60(1); + else __VISetFilterEURGB60(0); + } + oldTvStatus = tv; +#endif + if(postRetraceCB) + postRetraceCB(retraceCount); + + LWP_ThreadBroadcast(video_queue); +} + +void* VIDEO_GetNextFramebuffer() +{ + return nextFb; +} + +void* VIDEO_GetCurrentFramebuffer() +{ + return currentFb; +} + +void VIDEO_Init() +{ + u32 level,vimode = 0; + + _CPU_ISR_Disable(level); + + if(!(_viReg[1]&0x0001)) + __VIInit(VI_TVMODE_NTSC_INT); + + retraceCount = 0; + changed = 0; + shdw_changed = 0; + shdw_changeMode = 0; + flushFlag = 0; + + _viReg[38] = ((taps[1]>>6)|(taps[2]<<4)); + _viReg[39] = (taps[0]|_SHIFTL(taps[1],10,6)); + _viReg[40] = ((taps[4]>>6)|(taps[5]<<4)); + _viReg[41] = (taps[3]|_SHIFTL(taps[4],10,6)); + _viReg[42] = ((taps[7]>>6)|(taps[8]<<4)); + _viReg[43] = (taps[6]|_SHIFTL(taps[7],10,6)); + _viReg[44] = (taps[11]|(taps[12]<<8)); + _viReg[45] = (taps[9]|(taps[10]<<8)); + _viReg[46] = (taps[15]|(taps[16]<<8)); + _viReg[47] = (taps[13]|(taps[14]<<8)); + _viReg[48] = (taps[19]|(taps[20]<<8)); + _viReg[49] = (taps[17]|(taps[18]<<8)); + _viReg[50] = (taps[23]|(taps[24]<<8)); + _viReg[51] = (taps[21]|(taps[22]<<8)); + _viReg[56] = 640; + + __importAdjustingValues(); + + HorVer.nonInter = _SHIFTR(_viReg[1],2,1); + HorVer.tv = _SHIFTR(_viReg[1],8,2); + + vimode = HorVer.nonInter; + if(HorVer.tv!=VI_DEBUG) vimode += (HorVer.tv<<2); + currTiming = __gettiming(vimode); + currTvMode = HorVer.tv; + + regs[1] = _viReg[1]; + HorVer.timing = currTiming; + HorVer.dispSizeX = 640; + HorVer.dispSizeY = currTiming->acv<<1; + HorVer.dispPosX = (VI_MAX_WIDTH_NTSC-HorVer.dispSizeX)/2; + HorVer.dispPosY = 0; + + __adjustPosition(currTiming->acv); + + HorVer.fbSizeX = 640; + HorVer.fbSizeY = currTiming->acv<<1; + HorVer.panPosX = 0; + HorVer.panPosY = 0; + HorVer.panSizeX = 640; + HorVer.panSizeY = currTiming->acv<<1; + HorVer.fbMode = VI_XFBMODE_SF; + HorVer.wordPerLine = 40; + HorVer.std = 40; + HorVer.wpl = 40; + HorVer.xof = 0; + HorVer.black = 1; + HorVer.threeD = 0; + HorVer.bfbb = 0; + HorVer.tfbb = 0; + HorVer.rbfbb = 0; + HorVer.rtfbb = 0; + + _viReg[24] &= ~0x8000; + _viReg[26] &= ~0x8000; + + preRetraceCB = NULL; + postRetraceCB = NULL; + + LWP_InitQueue(&video_queue); + + IRQ_Request(IRQ_PI_VI,__VIRetraceHandler,NULL); + __UnmaskIrq(IRQMASK(IRQ_PI_VI)); +#if defined(HW_RVL) + __VISetupEncoder(); +#endif + _CPU_ISR_Restore(level); +} + +void VIDEO_Configure(GXRModeObj *rmode) +{ + u16 dcr; + u32 nonint,vimode,level; + const struct _timing *curtiming; + _CPU_ISR_Disable(level); + nonint = (rmode->viTVMode&0x0003); + if(nonint!=HorVer.nonInter) { + changeMode = 1; + HorVer.nonInter = nonint; + } + HorVer.tv = _SHIFTR(rmode->viTVMode,2,3); + HorVer.dispPosX = rmode->viXOrigin; + HorVer.dispPosY = rmode->viYOrigin; + if(HorVer.nonInter==VI_NON_INTERLACE) HorVer.dispPosY = HorVer.dispPosY<<1; + + HorVer.dispSizeX = rmode->viWidth; + HorVer.fbSizeX = rmode->fbWidth; + HorVer.fbSizeY = rmode->xfbHeight; + HorVer.fbMode = rmode->xfbMode; + HorVer.panSizeX = HorVer.fbSizeX; + HorVer.panSizeY = HorVer.fbSizeY; + HorVer.panPosX = 0; + HorVer.panPosY = 0; + + if(HorVer.nonInter==VI_PROGRESSIVE || HorVer.nonInter==(VI_NON_INTERLACE|VI_PROGRESSIVE)) HorVer.dispSizeY = HorVer.panSizeY; + else if(HorVer.fbMode==VI_XFBMODE_SF) HorVer.dispSizeY = HorVer.panSizeY<<1; + else HorVer.dispSizeY = HorVer.panSizeY; + + if(HorVer.nonInter==(VI_NON_INTERLACE|VI_PROGRESSIVE)) HorVer.threeD = 1; + else HorVer.threeD = 0; + + vimode = VI_TVMODE(HorVer.tv,HorVer.nonInter); + curtiming = __gettiming(vimode); + HorVer.timing = curtiming; + + __adjustPosition(curtiming->acv); + __setInterruptRegs(curtiming); + + dcr = regs[1]&~0x030c; + dcr |= _SHIFTL(HorVer.threeD,3,1); + if(HorVer.nonInter==VI_PROGRESSIVE || HorVer.nonInter==(VI_NON_INTERLACE|VI_PROGRESSIVE)) dcr |= 0x0004; + else dcr |= _SHIFTL(HorVer.nonInter,2,1); + if(!(HorVer.tv==VI_EURGB60)) dcr |= _SHIFTL(HorVer.tv,8,2); + regs[1] = dcr; + changed |= VI_REGCHANGE(1); + + regs[54] &= ~0x0001; + if(HorVer.nonInter==VI_PROGRESSIVE || HorVer.nonInter==(VI_NON_INTERLACE|VI_PROGRESSIVE)) regs[54] |= 0x0001; + changed |= VI_REGCHANGE(54); + + __setScalingRegs(HorVer.panSizeX,HorVer.dispSizeX,HorVer.threeD); + __setHorizontalRegs(curtiming,HorVer.adjustedDispPosX,HorVer.dispSizeX); + __setBBIntervalRegs(curtiming); + __setPicConfig(HorVer.fbSizeX,HorVer.fbMode,HorVer.panPosX,HorVer.panSizeX,&HorVer.wordPerLine,&HorVer.std,&HorVer.wpl,&HorVer.xof); + + if(fbSet) __setFbbRegs(&HorVer,&HorVer.tfbb,&HorVer.bfbb,&HorVer.rtfbb,&HorVer.rbfbb); + + __setVerticalRegs(HorVer.adjustedDispPosY,HorVer.adjustedDispSizeY,curtiming->equ,curtiming->acv,curtiming->prbOdd,curtiming->prbEven,curtiming->psbOdd,curtiming->psbEven,HorVer.black); + _CPU_ISR_Restore(level); +} + +void VIDEO_WaitVSync(void) +{ + u32 level; + u32 retcnt; + + _CPU_ISR_Disable(level); + retcnt = retraceCount; + do { + LWP_ThreadSleep(video_queue); + } while(retraceCount==retcnt); + _CPU_ISR_Restore(level); +} + +void VIDEO_SetFramebuffer(void *fb) +{ + u32 level; + + _CPU_ISR_Disable(level); + fbSet = 1; + HorVer.bufAddr = fb; + __setFbbRegs(&HorVer,&HorVer.tfbb,&HorVer.bfbb,&HorVer.rtfbb,&HorVer.rbfbb); + _viReg[14] = regs[14]; + _viReg[15] = regs[15]; + + _viReg[18] = regs[18]; + _viReg[19] = regs[19]; + + if(HorVer.threeD) { + _viReg[16] = regs[16]; + _viReg[17] = regs[17]; + + _viReg[20] = regs[20]; + _viReg[21] = regs[21]; + } + _CPU_ISR_Restore(level); +} + +void VIDEO_SetNextFramebuffer(void *fb) +{ + u32 level; + _CPU_ISR_Disable(level); + fbSet = 1; + HorVer.bufAddr = fb; + __setFbbRegs(&HorVer,&HorVer.tfbb,&HorVer.bfbb,&HorVer.rtfbb,&HorVer.rbfbb); + _CPU_ISR_Restore(level); +} + +void VIDEO_SetNextRightFramebuffer(void *fb) +{ + u32 level; + + _CPU_ISR_Disable(level); + fbSet = 1; + HorVer.rbufAddr = fb; + __setFbbRegs(&HorVer,&HorVer.tfbb,&HorVer.bfbb,&HorVer.rtfbb,&HorVer.rbfbb); + _CPU_ISR_Restore(level); +} + +void VIDEO_Flush() +{ + u32 level; + u32 val; + u64 mask; + + _CPU_ISR_Disable(level); + shdw_changeMode |= changeMode; + changeMode = 0; + + shdw_changed |= changed; + while(changed) { + val = cntlzd(changed); + shdw_regs[val] = regs[val]; + mask = VI_REGCHANGE(val); + changed &= ~mask; + } + flushFlag = 1; + nextFb = HorVer.bufAddr; + _CPU_ISR_Restore(level); +} + +void VIDEO_SetBlack(bool black) +{ + u32 level; + const struct _timing *curtiming; + + _CPU_ISR_Disable(level); + HorVer.black = black; + curtiming = HorVer.timing; + __setVerticalRegs(HorVer.adjustedDispPosY,HorVer.dispSizeY,curtiming->equ,curtiming->acv,curtiming->prbOdd,curtiming->prbEven,curtiming->psbOdd,curtiming->psbEven,HorVer.black); + _CPU_ISR_Restore(level); +} + +u32 VIDEO_GetNextField() +{ + u32 level,nextfield; + + _CPU_ISR_Disable(level); + nextfield = __getCurrentFieldEvenOdd()^1; //we've to swap the result because it shows us only the current field,so we've the next field either even or odd + _CPU_ISR_Restore(level); + + return nextfield^(HorVer.adjustedDispPosY&0x0001); //if the YOrigin is at an odd position we've to swap it again, since the Fb registers are set swapped if this rule applies +} + +u32 VIDEO_GetCurrentTvMode() +{ + u32 mode; + u32 level; + u32 tv; + + _CPU_ISR_Disable(level); + mode = currTvMode; + + if(mode==VI_DEBUG) tv = VI_NTSC; + else if(mode==VI_EURGB60) tv = VI_EURGB60; + else if(mode==VI_MPAL) tv = VI_MPAL; + else if(mode==VI_NTSC) tv = VI_NTSC; + else tv = VI_PAL; + _CPU_ISR_Restore(level); + + return tv; +} + +GXRModeObj * VIDEO_GetPreferredMode(GXRModeObj *mode) +{ + +GXRModeObj *rmode = NULL; + +#if defined(HW_RVL) + u32 tvmode = CONF_GetVideo(); + if (CONF_GetProgressiveScan() > 0 && VIDEO_HaveComponentCable()) { + switch (tvmode) { + case CONF_VIDEO_NTSC: + rmode = &TVNtsc480Prog; + break; + case CONF_VIDEO_PAL: + if (CONF_GetEuRGB60() > 0) + rmode = &TVEurgb60Hz480Prog; + else rmode = &TVPal576ProgScale; + break; + case CONF_VIDEO_MPAL: + rmode = &TVMpal480Prog; + break; + default: + rmode = &TVNtsc480Prog; + } + } else { + switch (tvmode) { + case CONF_VIDEO_NTSC: + rmode = &TVNtsc480IntDf; + break; + case CONF_VIDEO_PAL: + if (CONF_GetEuRGB60() > 0) + rmode = &TVEurgb60Hz480IntDf; + else rmode = &TVPal576IntDfScale; + break; + case CONF_VIDEO_MPAL: + rmode = &TVMpal480IntDf; + break; + default: + rmode = &TVNtsc480IntDf; + } + } +#else + u32 tvmode = VIDEO_GetCurrentTvMode(); + if (VIDEO_HaveComponentCable()) { + switch (tvmode) { + case VI_NTSC: + rmode = &TVNtsc480Prog; + break; + case VI_PAL: + rmode = &TVPal576ProgScale; + break; + case VI_MPAL: + rmode = &TVMpal480Prog; + break; + case VI_EURGB60: + rmode = &TVEurgb60Hz480Prog; + break; + } + } else { + switch (tvmode) { + case VI_NTSC: + rmode = &TVNtsc480IntDf; + break; + case VI_PAL: + rmode = &TVPal576IntDfScale; + break; + case VI_MPAL: + rmode = &TVMpal480IntDf; + break; + case VI_EURGB60: + rmode = &TVEurgb60Hz480IntDf; + break; + } + } +#endif + + if ( NULL != mode ) { + memcpy( mode, rmode, sizeof(GXRModeObj)); + } else { + mode = rmode; + } + + return mode; + + +} + +u32 VIDEO_GetCurrentLine() +{ + u32 level,curr_hl = 0; + + _CPU_ISR_Disable(level); + curr_hl = __getCurrentHalfLine(); + _CPU_ISR_Restore(level); + + if(curr_hl>=currTiming->nhlines) curr_hl -=currTiming->nhlines; + curr_hl >>= 1; + + return curr_hl; +} + +VIRetraceCallback VIDEO_SetPreRetraceCallback(VIRetraceCallback callback) +{ + u32 level = 0; + VIRetraceCallback ret = preRetraceCB; + _CPU_ISR_Disable(level); + preRetraceCB = callback; + _CPU_ISR_Restore(level); + return ret; +} + +VIRetraceCallback VIDEO_SetPostRetraceCallback(VIRetraceCallback callback) +{ + u32 level = 0; + VIRetraceCallback ret = postRetraceCB; + _CPU_ISR_Disable(level); + postRetraceCB = callback; + _CPU_ISR_Restore(level); + return ret; +} + +u32 VIDEO_GetFrameBufferSize(GXRModeObj *rmode) { + u16 w, h; + + w = VIDEO_PadFramebufferWidth(rmode->fbWidth); + h = rmode->xfbHeight; + + if (rmode->aa) + h += 4; + + return w * h * VI_DISPLAY_PIX_SZ; +} + +void VIDEO_ClearFrameBuffer(GXRModeObj *rmode,void *fb,u32 color) +{ + __VIClearFramebuffer(fb, VIDEO_GetFrameBufferSize(rmode), color); +} + +u32 VIDEO_HaveComponentCable(void) +{ + return (_viReg[55]&0x01); +} diff --git a/wii/libogc/libogc/video_asm.S b/wii/libogc/libogc/video_asm.S new file mode 100644 index 0000000000..b8cd37329e --- /dev/null +++ b/wii/libogc/libogc/video_asm.S @@ -0,0 +1,106 @@ +/*------------------------------------------------------------- + +video_asm.S -- VIDEO subsystem assembler support + +Copyright (C) 2004 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + + +#include + + .globl __VIClearFramebuffer + //r3 = dst, r4 = length(bytes),r5 = color +__VIClearFramebuffer: + srwi. r0,r4,8 + beq 2f + mtctr r0 + subi r3,r3,4 +1: stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + stwu r5,4(r3) + bdnz 1b +2: blr diff --git a/wii/libogc/libogc/wiilaunch.c b/wii/libogc/libogc/wiilaunch.c new file mode 100644 index 0000000000..29072cb74d --- /dev/null +++ b/wii/libogc/libogc/wiilaunch.c @@ -0,0 +1,409 @@ +/*------------------------------------------------------------- + +wiilaunch.c -- Wii NAND title launching and argument passing + +Copyright (C) 2008 +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#if defined(HW_RVL) + +#include +#include +#include +#include +#include +#include "ipc.h" +#include "asm.h" +#include "processor.h" +#include "es.h" +#include "video.h" +#include "network.h" +#include "wiilaunch.h" + +static char __nandbootinfo[] ATTRIBUTE_ALIGN(32) = "/shared2/sys/NANDBOOTINFO"; +static char __stateflags[] ATTRIBUTE_ALIGN(32) = "/title/00000001/00000002/data/state.dat"; + +static int __initialized = 0; +static char args_set = 0; + +typedef struct { + u32 checksum; + u32 argsoff; + u8 unk1; + u8 unk2; + u8 apptype; + u8 titletype; + u32 launchcode; + u32 unknown[2]; + u64 launcher; + u8 argbuf[0x1000]; +} NANDBootInfo; + +typedef struct { + u32 checksum; + u8 flags; + u8 type; + u8 discstate; + u8 returnto; + u32 unknown[6]; +} StateFlags; + +#define TYPE_RETURN 3 +#define TYPE_NANDBOOT 4 +#define TYPE_SHUTDOWNSYSTEM 5 +#define RETURN_TO_MENU 0 +#define RETURN_TO_SETTINGS 1 +#define RETURN_TO_ARGS 2 + + +static NANDBootInfo nandboot ATTRIBUTE_ALIGN(32); + +static StateFlags stateflags ATTRIBUTE_ALIGN(32); + +static u32 __CalcChecksum(u32 *buf, int len) +{ + u32 sum = 0; + int i; + len = (len/4); + + for(i=1; i 0x1000) + return WII_E2BIG; + + argp = 0x1000 - argslen; + argvp = 0x1000 - buflen; + + memset(&nandboot.argbuf, 0, sizeof(nandboot.argbuf)); + + nandboot.argsoff = 0x1000 + argvp; + *((u32*)&nandboot.argbuf[argvp]) = argc; + argvp += 4; + + for(i=0; i 4) { + return WII_EINTERNAL; + } + res = ES_GetTicketViews(titleID, views, numviews); + if(res < 0) + return res; + + net_wc24cleanup(); + + if (args_set == 0) + { + memset(&nandboot,0,sizeof(NANDBootInfo)); + nandboot.apptype = 0x81; + if(titleID == 0x100000002LL) + nandboot.titletype = 4; + else + nandboot.titletype = 2; + if(ES_GetTitleID(&nandboot.launcher) < 0) + nandboot.launcher = 0x0000000100000002LL; + nandboot.checksum = __CalcChecksum((u32*)&nandboot,sizeof(NANDBootInfo)); + __WII_WriteNANDBootInfo(); + } + VIDEO_SetBlack(1); + VIDEO_Flush(); + + res = ES_LaunchTitle(titleID, &views[0]); + if(res < 0) + return res; + return WII_EINTERNAL; +} + +s32 WII_LaunchTitleWithArgs(u64 titleID, int launchcode, ...) +{ + char argv0[20]; + const char *argv[256]; + int argc = 1; + va_list args; + int ret = 0; + + if(!__initialized) + return WII_ENOTINIT; + + sprintf(argv0, "%016llx", titleID); + + argv[0] = argv0; + + va_start(args, launchcode); + + do { + argv[argc++] = va_arg(args, const char *); + } while(argv[argc - 1] != NULL); + + va_end(args); + + if(ES_GetTitleID(&nandboot.launcher) < 0) + nandboot.launcher = 0x100000002LL; + + if(titleID == 0x100000002LL) + nandboot.titletype = 4; + else + nandboot.titletype = 2; + nandboot.apptype = 0x81; + nandboot.launchcode = launchcode; + + stateflags.type = TYPE_RETURN; + stateflags.returnto = RETURN_TO_ARGS; + + __WII_SetArgs(argv); + + __WII_WriteStateFlags(); + __WII_WriteNANDBootInfo(); + + args_set = 1; + + ret = WII_LaunchTitle(titleID); + if(ret < 0) + args_set = 0; + + return ret; +} + +s32 WII_ReturnToMenu(void) +{ + if(!__initialized) + return WII_ENOTINIT; + stateflags.type = TYPE_RETURN; + stateflags.returnto = RETURN_TO_MENU; + __WII_WriteStateFlags(); + return WII_LaunchTitle(0x100000002LL); +} + +s32 WII_ReturnToSettings(void) +{ + if(!__initialized) + return WII_ENOTINIT; + stateflags.type = TYPE_RETURN; + stateflags.returnto = RETURN_TO_SETTINGS; + __WII_WriteStateFlags(); + return WII_LaunchTitle(0x100000002LL); +} + +s32 WII_ReturnToSettingsPage(const char *page) +{ + if(!__initialized) + return WII_ENOTINIT; + + return WII_LaunchTitleWithArgs(0x100000002LL, 1, page, NULL); +} + +s32 WII_OpenURL(const char *url) +{ + u32 tmdsize; + u64 tid = 0; + u64 *list; + u32 titlecount; + s32 ret; + u32 i; + + if(!__initialized) + return WII_ENOTINIT; + + ret = ES_GetNumTitles(&titlecount); + if(ret < 0) + return WII_EINTERNAL; + + list = memalign(32, titlecount * sizeof(u64) + 32); + + ret = ES_GetTitles(list, titlecount); + if(ret < 0) { + free(list); + return WII_EINTERNAL; + } + + for(i=0; i + + 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#if defined(HW_RVL) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SDIO_HEAPSIZE (5*1024) + +#define PAGE_SIZE512 512 + +#define SDIOHCR_RESPONSE 0x10 +#define SDIOHCR_HOSTCONTROL 0x28 +#define SDIOHCR_POWERCONTROL 0x29 +#define SDIOHCR_CLOCKCONTROL 0x2c +#define SDIOHCR_TIMEOUTCONTROL 0x2e +#define SDIOHCR_SOFTWARERESET 0x2f + +#define SDIOHCR_HOSTCONTROL_4BIT 0x02 + +#define SDIO_DEFAULT_TIMEOUT 0xe + +#define IOCTL_SDIO_WRITEHCREG 0x01 +#define IOCTL_SDIO_READHCREG 0x02 +#define IOCTL_SDIO_READCREG 0x03 +#define IOCTL_SDIO_RESETCARD 0x04 +#define IOCTL_SDIO_WRITECREG 0x05 +#define IOCTL_SDIO_SETCLK 0x06 +#define IOCTL_SDIO_SENDCMD 0x07 +#define IOCTL_SDIO_SETBUSWIDTH 0x08 +#define IOCTL_SDIO_READMCREG 0x09 +#define IOCTL_SDIO_WRITEMCREG 0x0A +#define IOCTL_SDIO_GETSTATUS 0x0B +#define IOCTL_SDIO_GETOCR 0x0C +#define IOCTL_SDIO_READDATA 0x0D +#define IOCTL_SDIO_WRITEDATA 0x0E + +#define SDIOCMD_TYPE_BC 1 +#define SDIOCMD_TYPE_BCR 2 +#define SDIOCMD_TYPE_AC 3 +#define SDIOCMD_TYPE_ADTC 4 + +#define SDIO_RESPONSE_NONE 0 +#define SDIO_RESPONSE_R1 1 +#define SDIO_RESPONSE_R1B 2 +#define SDIO_RESPOSNE_R2 3 +#define SDIO_RESPONSE_R3 4 +#define SDIO_RESPONSE_R4 5 +#define SDIO_RESPONSE_R5 6 +#define SDIO_RESPONSE_R6 7 + +#define SDIO_CMD_GOIDLE 0x00 +#define SDIO_CMD_ALL_SENDCID 0x02 +#define SDIO_CMD_SENDRCA 0x03 +#define SDIO_CMD_SELECT 0x07 +#define SDIO_CMD_DESELECT 0x07 +#define SDIO_CMD_SENDIFCOND 0x08 +#define SDIO_CMD_SENDCSD 0x09 +#define SDIO_CMD_SENDCID 0x0A +#define SDIO_CMD_SENDSTATUS 0x0D +#define SDIO_CMD_SETBLOCKLEN 0x10 +#define SDIO_CMD_READBLOCK 0x11 +#define SDIO_CMD_READMULTIBLOCK 0x12 +#define SDIO_CMD_WRITEBLOCK 0x18 +#define SDIO_CMD_WRITEMULTIBLOCK 0x19 +#define SDIO_CMD_APPCMD 0x37 + +#define SDIO_ACMD_SETBUSWIDTH 0x06 +#define SDIO_ACMD_SENDSCR 0x33 +#define SDIO_ACMD_SENDOPCOND 0x29 + +#define SDIO_STATUS_CARD_INSERTED 0x1 +#define SDIO_STATUS_CARD_INITIALIZED 0x10000 +#define SDIO_STATUS_CARD_SDHC 0x100000 + +#define READ_BL_LEN ((u8)(__sd0_csd[5]&0x0f)) +#define WRITE_BL_LEN ((u8)(((__sd0_csd[12]&0x03)<<2)|((__sd0_csd[13]>>6)&0x03))) + +static u8 *rw_buffer = NULL; + +struct _sdiorequest +{ + u32 cmd; + u32 cmd_type; + u32 rsp_type; + u32 arg; + u32 blk_cnt; + u32 blk_size; + void *dma_addr; + u32 isdma; + u32 pad0; +}; + +struct _sdioresponse +{ + u32 rsp_fields[3]; + u32 acmd12_response; +}; + +static s32 hId = -1; + +static s32 __sd0_fd = -1; +static u16 __sd0_rca = 0; +static s32 __sd0_initialized = 0; +static s32 __sd0_sdhc = 0; +//static u8 __sd0_csd[16]; +static u8 __sd0_cid[16]; + +static s32 __sdio_initialized = 0; + +static char _sd0_fs[] ATTRIBUTE_ALIGN(32) = "/dev/sdio/slot0"; + +static s32 __sdio_sendcommand(u32 cmd,u32 cmd_type,u32 rsp_type,u32 arg,u32 blk_cnt,u32 blk_size,void *buffer,void *reply,u32 rlen) +{ + s32 ret; + STACK_ALIGN(ioctlv,iovec,3,32); + STACK_ALIGN(struct _sdiorequest,request,1,32); + STACK_ALIGN(struct _sdioresponse,response,1,32); + + request->cmd = cmd; + request->cmd_type = cmd_type; + request->rsp_type = rsp_type; + request->arg = arg; + request->blk_cnt = blk_cnt; + request->blk_size = blk_size; + request->dma_addr = buffer; + request->isdma = ((buffer!=NULL)?1:0); + request->pad0 = 0; + + if(request->isdma || __sd0_sdhc == 1) { + iovec[0].data = request; + iovec[0].len = sizeof(struct _sdiorequest); + iovec[1].data = buffer; + iovec[1].len = (blk_size*blk_cnt); + iovec[2].data = response; + iovec[2].len = sizeof(struct _sdioresponse); + ret = IOS_Ioctlv(__sd0_fd,IOCTL_SDIO_SENDCMD,2,1,iovec); + } else + ret = IOS_Ioctl(__sd0_fd,IOCTL_SDIO_SENDCMD,request,sizeof(struct _sdiorequest),response,sizeof(struct _sdioresponse)); + + if(reply && !(rlen>16)) memcpy(reply,response,rlen); + +// printf(" cmd= %08x\n", cmd); + + return ret; +} + +static s32 __sdio_setclock(u32 set) +{ + s32 ret; + STACK_ALIGN(u32,clock,1,32); + + *clock = set; + ret = IOS_Ioctl(__sd0_fd,IOCTL_SDIO_SETCLK,clock,sizeof(u32),NULL,0); + + return ret; +} +static s32 __sdio_getstatus() +{ + s32 ret; + STACK_ALIGN(u32,status,1,32); + + ret = IOS_Ioctl(__sd0_fd,IOCTL_SDIO_GETSTATUS,NULL,0,status,sizeof(u32)); + if(ret<0) return ret; + + return *status; +} + +static s32 __sdio_resetcard() +{ + s32 ret; + STACK_ALIGN(u32,status,1,32); + + __sd0_rca = 0; + ret = IOS_Ioctl(__sd0_fd,IOCTL_SDIO_RESETCARD,NULL,0,status,sizeof(u32)); + if(ret<0) return ret; + + __sd0_rca = (u16)(*status>>16); + return (*status&0xffff); +} + +static s32 __sdio_gethcr(u8 reg, u8 size, u32 *val) +{ + s32 ret; + STACK_ALIGN(u32,hcr_value,1,32); + STACK_ALIGN(u32,hcr_query,6,32); + + if(val==NULL) return IPC_EINVAL; + + *hcr_value = 0; + *val = 0; + hcr_query[0] = reg; + hcr_query[1] = 0; + hcr_query[2] = 0; + hcr_query[3] = size; + hcr_query[4] = 0; + hcr_query[5] = 0; + ret = IOS_Ioctl(__sd0_fd,IOCTL_SDIO_READHCREG,(void*)hcr_query,24,hcr_value,sizeof(u32)); + *val = *hcr_value; + + + return ret; +} + +static s32 __sdio_sethcr(u8 reg, u8 size, u32 data) +{ + s32 ret; + STACK_ALIGN(u32,hcr_query,6,32); + + hcr_query[0] = reg; + hcr_query[1] = 0; + hcr_query[2] = 0; + hcr_query[3] = size; + hcr_query[4] = data; + hcr_query[5] = 0; + ret = IOS_Ioctl(__sd0_fd,IOCTL_SDIO_WRITEHCREG,(void*)hcr_query,24,NULL,0); + + + return ret; +} + +static s32 __sdio_waithcr(u8 reg, u8 size, u8 unset, u32 mask) +{ + u32 val; + s32 ret; + s32 tries = 10; + + while(tries-- > 0) + { + ret = __sdio_gethcr(reg, size, &val); + if(ret < 0) return ret; + if((unset && !(val & mask)) || (!unset && (val & mask))) return 0; + usleep(10000); + } + + return -1; +} + +static s32 __sdio_setbuswidth(u32 bus_width) +{ + s32 ret; + u32 hc_reg = 0; + + ret = __sdio_gethcr(SDIOHCR_HOSTCONTROL, 1, &hc_reg); + if(ret<0) return ret; + + hc_reg &= 0xff; + hc_reg &= ~SDIOHCR_HOSTCONTROL_4BIT; + if(bus_width==4) hc_reg |= SDIOHCR_HOSTCONTROL_4BIT; + + return __sdio_sethcr(SDIOHCR_HOSTCONTROL, 1, hc_reg); +} + +static s32 __sd0_getrca() +{ + s32 ret; + u32 rca; + + ret = __sdio_sendcommand(SDIO_CMD_SENDRCA,0,SDIO_RESPONSE_R5,0,0,0,NULL,&rca,sizeof(rca)); + if(ret<0) return ret; + + __sd0_rca = (u16)(rca>>16); + return (rca&0xffff); +} + +static s32 __sd0_select() +{ + s32 ret; + + ret = __sdio_sendcommand(SDIO_CMD_SELECT,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1B,(__sd0_rca<<16),0,0,NULL,NULL,0); + + return ret; +} + +static s32 __sd0_deselect() +{ + s32 ret; + + ret = __sdio_sendcommand(SDIO_CMD_DESELECT,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1B,0,0,0,NULL,NULL,0); + + return ret; +} + +static s32 __sd0_setblocklength(u32 blk_len) +{ + s32 ret; + + ret = __sdio_sendcommand(SDIO_CMD_SETBLOCKLEN,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,blk_len,0,0,NULL,NULL,0); + + return ret; +} + +static s32 __sd0_setbuswidth(u32 bus_width) +{ + u16 val; + s32 ret; + + val = 0x0000; + if(bus_width==4) val = 0x0002; + + ret = __sdio_sendcommand(SDIO_CMD_APPCMD,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,(__sd0_rca<<16),0,0,NULL,NULL,0); + if(ret<0) return ret; + + ret = __sdio_sendcommand(SDIO_ACMD_SETBUSWIDTH,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,val,0,0,NULL,NULL,0); + + return ret; +} + +static s32 __sd0_getcid() +{ + s32 ret; + + ret = __sdio_sendcommand(SDIO_CMD_ALL_SENDCID,0,SDIO_RESPOSNE_R2,(__sd0_rca<<16),0,0,NULL,__sd0_cid,16); + + return ret; +} + + +static bool __sd0_initio() +{ + s32 ret; + s32 tries; + u32 status; + struct _sdioresponse resp; + + __sdio_resetcard(); + status = __sdio_getstatus(); + + if(!(status & SDIO_STATUS_CARD_INSERTED)) + return false; + + if(!(status & SDIO_STATUS_CARD_INITIALIZED)) + { + // IOS doesn't like this card, so we need to convice it to accept it. + + // reopen the handle which makes IOS clean stuff up + IOS_Close(__sd0_fd); + __sd0_fd = IOS_Open(_sd0_fs,1); + + // reset the host controller + if(__sdio_sethcr(SDIOHCR_SOFTWARERESET, 1, 7) < 0) goto fail; + if(__sdio_waithcr(SDIOHCR_SOFTWARERESET, 1, 1, 7) < 0) goto fail; + + // initialize interrupts (sd_reset_card does this on success) + __sdio_sethcr(0x34, 4, 0x13f00c3); + __sdio_sethcr(0x38, 4, 0x13f00c3); + + // enable power + __sd0_sdhc = 1; + ret = __sdio_sethcr(SDIOHCR_POWERCONTROL, 1, 0xe); + if(ret < 0) goto fail; + ret = __sdio_sethcr(SDIOHCR_POWERCONTROL, 1, 0xf); + if(ret < 0) goto fail; + + // enable internal clock, wait until it gets stable and enable sd clock + ret = __sdio_sethcr(SDIOHCR_CLOCKCONTROL, 2, 0); + if(ret < 0) goto fail; + ret = __sdio_sethcr(SDIOHCR_CLOCKCONTROL, 2, 0x101); + if(ret < 0) goto fail; + ret = __sdio_waithcr(SDIOHCR_CLOCKCONTROL, 2, 0, 2); + if(ret < 0) goto fail; + ret = __sdio_sethcr(SDIOHCR_CLOCKCONTROL, 2, 0x107); + if(ret < 0) goto fail; + + // setup timeout + ret = __sdio_sethcr(SDIOHCR_TIMEOUTCONTROL, 1, SDIO_DEFAULT_TIMEOUT); + if(ret < 0) goto fail; + + // standard SDHC initialization process + ret = __sdio_sendcommand(SDIO_CMD_GOIDLE, 0, 0, 0, 0, 0, NULL, NULL, 0); + if(ret < 0) goto fail; + ret = __sdio_sendcommand(SDIO_CMD_SENDIFCOND, 0, SDIO_RESPONSE_R6, 0x1aa, 0, 0, NULL, &resp, sizeof(resp)); + if(ret < 0) goto fail; + if((resp.rsp_fields[0] & 0xff) != 0xaa) goto fail; + + tries = 10; + while(tries-- > 0) + { + ret = __sdio_sendcommand(SDIO_CMD_APPCMD, SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,0,0,0,NULL,NULL,0); + if(ret < 0) goto fail; + ret = __sdio_sendcommand(SDIO_ACMD_SENDOPCOND, 0, SDIO_RESPONSE_R3, 0x40300000, 0, 0, NULL, &resp, sizeof(resp)); + if(ret < 0) goto fail; + if(resp.rsp_fields[0] & (1 << 31)) break; + + usleep(10000); + } + if(tries < 0) goto fail; + + // FIXME: SDv2 cards which are not high-capacity won't work :/ + if(resp.rsp_fields[0] & (1 << 30)) + __sd0_sdhc = 1; + else + __sd0_sdhc = 0; + + ret = __sd0_getcid(); + if(ret < 0) goto fail; + ret = __sd0_getrca(); + if(ret < 0) goto fail; + } + else if(status&SDIO_STATUS_CARD_SDHC) + __sd0_sdhc = 1; + else + __sd0_sdhc = 0; + + ret = __sdio_setbuswidth(4); + if(ret<0) return false; + + ret = __sdio_setclock(1); + if(ret<0) return false; + + ret = __sd0_select(); + if(ret<0) return false; + + ret = __sd0_setblocklength(PAGE_SIZE512); + if(ret<0) { + ret = __sd0_deselect(); + return false; + } + + ret = __sd0_setbuswidth(4); + if(ret<0) { + ret = __sd0_deselect(); + return false; + } + __sd0_deselect(); + + __sd0_initialized = 1; + return true; + + fail: + __sdio_sethcr(SDIOHCR_SOFTWARERESET, 1, 7); + __sdio_waithcr(SDIOHCR_SOFTWARERESET, 1, 1, 7); + IOS_Close(__sd0_fd); + __sd0_fd = IOS_Open(_sd0_fs,1); + return false; +} + +bool sdio_Deinitialize() +{ + if(__sd0_fd>=0) + IOS_Close(__sd0_fd); + + __sd0_fd = -1; + __sdio_initialized = 0; + return true; +} + +bool sdio_Startup() +{ + if(__sdio_initialized==1) return true; + + if(hId<0) { + hId = iosCreateHeap(SDIO_HEAPSIZE); + if(hId<0) return false; + } + + if(rw_buffer == NULL) rw_buffer = iosAlloc(hId,(4*1024)); + if(rw_buffer == NULL) return false; + + __sd0_fd = IOS_Open(_sd0_fs,1); + + if(__sd0_fd<0) { + sdio_Deinitialize(); + return false; + } + + if(__sd0_initio()==false) { + sdio_Deinitialize(); + return false; + } + __sdio_initialized = 1; + return true; +} + + + +bool sdio_Shutdown() +{ + if(__sd0_initialized==0) return false; + + sdio_Deinitialize(); + + __sd0_initialized = 0; + return true; +} + +bool sdio_ReadSectors(sec_t sector, sec_t numSectors,void* buffer) +{ + s32 ret; + u8 *ptr; + sec_t blk_off; + + if(buffer==NULL) return false; + + ret = __sd0_select(); + if(ret<0) return false; + + if((u32)buffer & 0x1F) { + ptr = (u8*)buffer; + int secs_to_read; + while(numSectors>0) { + if(__sd0_sdhc == 0) blk_off = (sector*PAGE_SIZE512); + else blk_off = sector; + if(numSectors > 8)secs_to_read = 8; + else secs_to_read = numSectors; + ret = __sdio_sendcommand(SDIO_CMD_READMULTIBLOCK,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,blk_off,secs_to_read,PAGE_SIZE512,rw_buffer,NULL,0); + if(ret>=0) { + memcpy(ptr,rw_buffer,PAGE_SIZE512*secs_to_read); + ptr += PAGE_SIZE512*secs_to_read; + sector+=secs_to_read; + numSectors-=secs_to_read; + } else + break; + } + } else { + if(__sd0_sdhc == 0) sector *= PAGE_SIZE512; + ret = __sdio_sendcommand(SDIO_CMD_READMULTIBLOCK,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,sector,numSectors,PAGE_SIZE512,buffer,NULL,0); + } + + __sd0_deselect(); + + return (ret>=0); +} + +bool sdio_WriteSectors(sec_t sector, sec_t numSectors,const void* buffer) +{ + s32 ret; + u8 *ptr; + u32 blk_off; + + if(buffer==NULL) return false; + + ret = __sd0_select(); + if(ret<0) return false; + + if((u32)buffer & 0x1F) { + ptr = (u8*)buffer; + int secs_to_write; + while(numSectors>0) { + if(__sd0_sdhc == 0) blk_off = (sector*PAGE_SIZE512); + else blk_off = sector; + if(numSectors > 8)secs_to_write = 8; + else secs_to_write = numSectors; + memcpy(rw_buffer,ptr,PAGE_SIZE512*secs_to_write); + ret = __sdio_sendcommand(SDIO_CMD_WRITEMULTIBLOCK,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,blk_off,secs_to_write,PAGE_SIZE512,rw_buffer,NULL,0); + if(ret>=0) { + ptr += PAGE_SIZE512*secs_to_write; + sector+=secs_to_write; + numSectors-=secs_to_write; + } else + break; + } + } else { + if(__sd0_sdhc == 0) sector *= PAGE_SIZE512; + ret = __sdio_sendcommand(SDIO_CMD_WRITEMULTIBLOCK,SDIOCMD_TYPE_AC,SDIO_RESPONSE_R1,sector,numSectors,PAGE_SIZE512,(char *)buffer,NULL,0); + } + + __sd0_deselect(); + + return (ret>=0); +} + +bool sdio_ClearStatus() +{ + return true; +} + +bool sdio_IsInserted() +{ + return ((__sdio_getstatus() & SDIO_STATUS_CARD_INSERTED) == + SDIO_STATUS_CARD_INSERTED); +} + +bool sdio_IsInitialized() +{ + return ((__sdio_getstatus() & SDIO_STATUS_CARD_INITIALIZED) == + SDIO_STATUS_CARD_INITIALIZED); +} + +const DISC_INTERFACE __io_wiisd = { + DEVICE_TYPE_WII_SD, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_SD, + (FN_MEDIUM_STARTUP)&sdio_Startup, + (FN_MEDIUM_ISINSERTED)&sdio_IsInserted, + (FN_MEDIUM_READSECTORS)&sdio_ReadSectors, + (FN_MEDIUM_WRITESECTORS)&sdio_WriteSectors, + (FN_MEDIUM_CLEARSTATUS)&sdio_ClearStatus, + (FN_MEDIUM_SHUTDOWN)&sdio_Shutdown +}; + +#endif diff --git a/wii/libogc/libogc_license.txt b/wii/libogc/libogc_license.txt new file mode 100644 index 0000000000..a3dfd0581b --- /dev/null +++ b/wii/libogc/libogc_license.txt @@ -0,0 +1,20 @@ + Copyright (C) 2004 - 2009 + Michael Wiedenbauer (shagkur) + Dave Murphy (WinterMute) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source + distribution. diff --git a/wii/libogc/libs/cube/libbba.a b/wii/libogc/libs/cube/libbba.a new file mode 100644 index 0000000000..570c9a23f0 Binary files /dev/null and b/wii/libogc/libs/cube/libbba.a differ diff --git a/wii/libogc/libs/cube/libdb.a b/wii/libogc/libs/cube/libdb.a new file mode 100644 index 0000000000..4fa2e465e6 Binary files /dev/null and b/wii/libogc/libs/cube/libdb.a differ diff --git a/wii/libogc/libs/cube/libogc.a b/wii/libogc/libs/cube/libogc.a new file mode 100644 index 0000000000..debe55e6ed Binary files /dev/null and b/wii/libogc/libs/cube/libogc.a differ diff --git a/wii/libogc/libs/wii/libbte.a b/wii/libogc/libs/wii/libbte.a new file mode 100644 index 0000000000..191c62e51b Binary files /dev/null and b/wii/libogc/libs/wii/libbte.a differ diff --git a/wii/libogc/libs/wii/libdb.a b/wii/libogc/libs/wii/libdb.a new file mode 100644 index 0000000000..876deee6b8 Binary files /dev/null and b/wii/libogc/libs/wii/libdb.a differ diff --git a/wii/libogc/libs/wii/libogc.a b/wii/libogc/libs/wii/libogc.a new file mode 100644 index 0000000000..8d1fd55a9f Binary files /dev/null and b/wii/libogc/libs/wii/libogc.a differ diff --git a/wii/libogc/libs/wii/libwiikeyboard.a b/wii/libogc/libs/wii/libwiikeyboard.a new file mode 100644 index 0000000000..4a24f7cee4 Binary files /dev/null and b/wii/libogc/libs/wii/libwiikeyboard.a differ diff --git a/wii/libogc/libs/wii/libwiiuse.a b/wii/libogc/libs/wii/libwiiuse.a new file mode 100644 index 0000000000..60f39ba83a Binary files /dev/null and b/wii/libogc/libs/wii/libwiiuse.a differ diff --git a/wii/libogc/libwiikeyboard/keyboard.c b/wii/libogc/libwiikeyboard/keyboard.c new file mode 100644 index 0000000000..b7a67f5588 --- /dev/null +++ b/wii/libogc/libwiikeyboard/keyboard.c @@ -0,0 +1,664 @@ +/*------------------------------------------------------------- + +keyboard.c -- keyboard event system + +Copyright (C) 2008, 2009 +DAVY Guillaume davyg2@gmail.com +Brian Johnson brijohn@gmail.com +dhewg + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "wsksymvar.h" + +#define KBD_THREAD_STACKSIZE (1024 * 4) +#define KBD_THREAD_PRIO 64 +#define KBD_THREAD_UDELAY (1000 * 10) +#define KBD_THREAD_KBD_SCAN_INTERVAL (3 * 100) + +static lwp_queue _queue; +static lwp_t _kbd_thread = LWP_THREAD_NULL; +static lwp_t _kbd_buf_thread = LWP_THREAD_NULL; +static bool _kbd_thread_running = false; +static bool _kbd_thread_quit = false; + +keysym_t ksym_upcase(keysym_t); + +extern const struct wscons_keydesc ukbd_keydesctab[]; + +static struct wskbd_mapdata _ukbd_keymapdata = { + ukbd_keydesctab, + KB_NONE +}; + +struct nameint { + int value; + char *name; +}; + +static struct nameint kbdenc_tab[] = { + KB_ENCTAB +}; + +static struct nameint kbdvar_tab[] = { + KB_VARTAB +}; + +static int _sc_maplen = 0; /* number of entries in sc_map */ +static struct wscons_keymap *_sc_map = 0; /* current translation map */ + +static u16 _modifiers; + +static int _composelen; /* remaining entries in _composebuf */ +static keysym_t _composebuf[2]; + +typedef struct { + u8 keycode; + u16 symbol; +} _keyheld; + +#define MAXHELD 8 +static _keyheld _held[MAXHELD]; + +typedef struct { + lwp_node node; + keyboard_event event; +} _node; + +static keyPressCallback _readKey_cb = NULL; + +static u8 *_kbd_stack[KBD_THREAD_STACKSIZE] ATTRIBUTE_ALIGN(8); +static u8 *_kbd_buf_stack[KBD_THREAD_STACKSIZE] ATTRIBUTE_ALIGN(8); + +static kbd_t _get_keymap_by_name(const char *identifier) { + char name[64]; + u8 i, j; + kbd_t encoding, variant; + + kbd_t res = KB_NONE; + + if (!identifier || (strlen(identifier) < 2)) + return res; + + i = 0; + for (i = 0; ukbd_keydesctab[i].name != 0; ++i) { + if (ukbd_keydesctab[i].name & KB_HANDLEDBYWSKBD) + continue; + + encoding = KB_ENCODING(ukbd_keydesctab[i].name); + variant = KB_VARIANT(ukbd_keydesctab[i].name); + + name[0] = 0; + for (j = 0; j < sizeof(kbdenc_tab) / sizeof(struct nameint); ++j) + if (encoding == kbdenc_tab[j].value) { + strcpy(name, kbdenc_tab[j].name); + break; + } + + if (strlen(name) < 1) + continue; + + for (j = 0; j < sizeof(kbdvar_tab) / sizeof(struct nameint); ++j) + if (variant & kbdvar_tab[j].value) { + strcat(name, "-"); + strcat(name, kbdvar_tab[j].name); + } + + if (!strcmp(identifier, name)) { + res = ukbd_keydesctab[i].name; + break; + } + } + + return res; +} + +//Add an event to the event queue +static s32 _kbd_addEvent(const keyboard_event *event) { + _node *n = malloc(sizeof(_node)); + n->event = *event; + + __lwp_queue_append(&_queue, (lwp_node*) n); + + return 1; +} + +void update_modifier(u_int type, int toggle, int mask) { + if (toggle) { + if (type == KEYBOARD_PRESSED) + _modifiers ^= mask; + } else { + if (type == KEYBOARD_RELEASED) + _modifiers &= ~mask; + else + _modifiers |= mask; + } +} + +//Event callback, gets called when an event occurs in usbkeyboard +static void _kbd_event_cb(USBKeyboard_event kevent) +{ + keyboard_event event; + struct wscons_keymap kp; + keysym_t *group; + int gindex; + keysym_t ksym; + int i; + + switch (kevent.type) { + case USBKEYBOARD_DISCONNECTED: + event.type = KEYBOARD_DISCONNECTED; + event.modifiers = 0; + event.keycode = 0; + event.symbol = 0; + + _kbd_addEvent(&event); + + return; + + case USBKEYBOARD_PRESSED: + event.type = KEYBOARD_PRESSED; + break; + + case USBKEYBOARD_RELEASED: + event.type = KEYBOARD_RELEASED; + break; + + default: + return; + } + + event.keycode = kevent.keyCode; + + wskbd_get_mapentry(&_ukbd_keymapdata, event.keycode, &kp); + + /* Now update modifiers */ + switch (kp.group1[0]) { + case KS_Shift_L: + update_modifier(event.type, 0, MOD_SHIFT_L); + break; + + case KS_Shift_R: + update_modifier(event.type, 0, MOD_SHIFT_R); + break; + + case KS_Shift_Lock: + update_modifier(event.type, 1, MOD_SHIFTLOCK); + break; + + case KS_Caps_Lock: + update_modifier(event.type, 1, MOD_CAPSLOCK); + USBKeyboard_SetLed(USBKEYBOARD_LEDCAPS, + MOD_ONESET(_modifiers, MOD_CAPSLOCK)); + break; + + case KS_Control_L: + update_modifier(event.type, 0, MOD_CONTROL_L); + break; + + case KS_Control_R: + update_modifier(event.type, 0, MOD_CONTROL_R); + break; + + case KS_Alt_L: + update_modifier(event.type, 0, MOD_META_L); + break; + + case KS_Alt_R: + update_modifier(event.type, 0, MOD_META_R); + break; + + case KS_Mode_switch: + update_modifier(event.type, 0, MOD_MODESHIFT); + break; + + case KS_Mode_Lock: + update_modifier(event.type, 1, MOD_MODELOCK); + break; + + case KS_Num_Lock: + update_modifier(event.type, 1, MOD_NUMLOCK); + USBKeyboard_SetLed(USBKEYBOARD_LEDNUM, + MOD_ONESET(_modifiers, MOD_NUMLOCK)); + break; + + case KS_Hold_Screen: + update_modifier(event.type, 1, MOD_HOLDSCREEN); + USBKeyboard_SetLed(USBKEYBOARD_LEDSCROLL, + MOD_ONESET(_modifiers, MOD_HOLDSCREEN)); + break; + } + + /* Get the keysym */ + if (_modifiers & (MOD_MODESHIFT|MOD_MODELOCK) && + !MOD_ONESET(_modifiers, MOD_ANYCONTROL)) + group = &kp.group2[0]; + else + group = &kp.group1[0]; + + if ((_modifiers & MOD_NUMLOCK) && + KS_GROUP(group[1]) == KS_GROUP_Keypad) { + gindex = !MOD_ONESET(_modifiers, MOD_ANYSHIFT); + ksym = group[gindex]; + } else { + /* CAPS alone should only affect letter keys */ + if ((_modifiers & (MOD_CAPSLOCK | MOD_ANYSHIFT)) == + MOD_CAPSLOCK) { + gindex = 0; + ksym = ksym_upcase(group[0]); + } else { + gindex = MOD_ONESET(_modifiers, MOD_ANYSHIFT); + ksym = group[gindex]; + } + } + + /* Process compose sequence and dead accents */ + switch (KS_GROUP(ksym)) { + case KS_GROUP_Mod: + if (ksym == KS_Multi_key) { + update_modifier(KEYBOARD_PRESSED, 0, MOD_COMPOSE); + _composelen = 2; + } + break; + + case KS_GROUP_Dead: + if (event.type != KEYBOARD_PRESSED) + return; + + if (_composelen == 0) { + update_modifier(KEYBOARD_PRESSED, 0, MOD_COMPOSE); + _composelen = 1; + _composebuf[0] = ksym; + + return; + } + break; + } + + if ((event.type == KEYBOARD_PRESSED) && (_composelen > 0)) { + /* + * If the compose key also serves as AltGr (i.e. set to both + * KS_Multi_key and KS_Mode_switch), and would provide a valid, + * distinct combination as AltGr, leave compose mode. + */ + if (_composelen == 2 && group == &kp.group2[0]) { + if (kp.group1[gindex] != kp.group2[gindex]) + _composelen = 0; + } + + if (_composelen != 0) { + _composebuf[2 - _composelen] = ksym; + if (--_composelen == 0) { + ksym = wskbd_compose_value(_composebuf); + update_modifier(KEYBOARD_RELEASED, 0, MOD_COMPOSE); + } else { + return; + } + } + } + + // store up to MAXHELD pressed events to match the symbol for release + switch (KS_GROUP(ksym)) { + case KS_GROUP_Ascii: + case KS_GROUP_Keypad: + case KS_GROUP_Function: + if (event.type == KEYBOARD_PRESSED) { + for (i = 0; i < MAXHELD; ++i) { + if (_held[i].keycode == 0) { + _held[i].keycode = event.keycode; + _held[i].symbol = ksym; + + break; + } + } + } else { + for (i = 0; i < MAXHELD; ++i) { + if (_held[i].keycode == event.keycode) { + ksym = _held[i].symbol; + _held[i].keycode = 0; + _held[i].symbol = 0; + + break; + } + } + } + + break; + } + + event.symbol = ksym; + event.modifiers = _modifiers; + + _kbd_addEvent(&event); + + return; +} + +//This function call usb function to check if a new keyboard is connected +static s32 _kbd_scan_for_keyboard(void) +{ + s32 ret; + keyboard_event event; + + ret = USBKeyboard_Open(&_kbd_event_cb); + + if (ret < 0) + return ret; + + _modifiers = 0; + _composelen = 0; + memset(_held, 0, sizeof(_held)); + + USBKeyboard_SetLed(USBKEYBOARD_LEDNUM, true); + USBKeyboard_SetLed(USBKEYBOARD_LEDCAPS, true); + USBKeyboard_SetLed(USBKEYBOARD_LEDSCROLL, true); + usleep(200 * 1000); + USBKeyboard_SetLed(USBKEYBOARD_LEDNUM, false); + USBKeyboard_SetLed(USBKEYBOARD_LEDCAPS, false); + USBKeyboard_SetLed(USBKEYBOARD_LEDSCROLL, false); + + event.type = KEYBOARD_CONNECTED; + event.modifiers = 0; + event.keycode = 0; + + _kbd_addEvent(&event); + + return ret; +} + +static void * _kbd_thread_func(void *arg) { + u32 turns = 0; + + while (!_kbd_thread_quit) { + // scan for new attached keyboards + if ((turns % KBD_THREAD_KBD_SCAN_INTERVAL) == 0) { + if (!USBKeyboard_IsConnected()) + _kbd_scan_for_keyboard(); + + turns = 0; + } + turns++; + + USBKeyboard_Scan(); + usleep(KBD_THREAD_UDELAY); + } + + return NULL; +} + +struct { + vu8 head; + vu8 tail; + char buf[256]; +} _keyBuffer; + +static void * _kbd_buf_thread_func(void *arg) { + keyboard_event event; + while (!_kbd_thread_quit) { + if (((_keyBuffer.tail+1)&255) != _keyBuffer.head) { + if ( KEYBOARD_GetEvent(&event)) { + if (event.type == KEYBOARD_PRESSED) { + _keyBuffer.buf[_keyBuffer.tail] = event.symbol; + _keyBuffer.tail++; + } + } + } + usleep(KBD_THREAD_UDELAY); + } + return NULL; +} + +static ssize_t _keyboardRead(struct _reent *r, void *unused, char *ptr, size_t len) +{ + ssize_t count = len; + while ( count > 0 ) { + if (_keyBuffer.head != _keyBuffer.tail) { + char key = _keyBuffer.buf[_keyBuffer.head]; + *ptr++ = key; + if (_readKey_cb != NULL) _readKey_cb(key); + _keyBuffer.head++; + count--; + } + } + return len; +} + +static const devoptab_t std_in = +{ + "stdin", + 0, + NULL, + NULL, + NULL, + _keyboardRead, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +//Initialize USB and USB_KEYBOARD and the event queue +s32 KEYBOARD_Init(keyPressCallback keypress_cb) +{ + int fd; + struct stat st; + char keymap[64]; + size_t i; + + if (USB_Initialize() != IPC_OK) + return -1; + + if (USBKeyboard_Initialize() != IPC_OK) { + return -2; + } + + if (_ukbd_keymapdata.layout == KB_NONE) { + keymap[0] = 0; + fd = open("/wiikbd.map", O_RDONLY); + + if ((fd > 0) && !fstat(fd, &st)) { + if ((st.st_size > 0) && (st.st_size < 64) && + (st.st_size == read(fd, keymap, st.st_size))) { + keymap[63] = 0; + for (i = 0; i < 64; ++i) { + if ((keymap[i] != '-') && (isalpha((int)keymap[i]) == 0)) { + keymap[i] = 0; + break; + } + } + } + + close(fd); + } + + _ukbd_keymapdata.layout = _get_keymap_by_name(keymap); + } + + if (_ukbd_keymapdata.layout == KB_NONE) { + switch (CONF_GetLanguage()) { + case CONF_LANG_GERMAN: + _ukbd_keymapdata.layout = KB_DE; + break; + + case CONF_LANG_JAPANESE: + _ukbd_keymapdata.layout = KB_JP; + break; + + case CONF_LANG_FRENCH: + _ukbd_keymapdata.layout = KB_FR; + break; + + case CONF_LANG_SPANISH: + _ukbd_keymapdata.layout = KB_ES; + break; + + case CONF_LANG_ITALIAN: + _ukbd_keymapdata.layout = KB_IT; + break; + + case CONF_LANG_DUTCH: + _ukbd_keymapdata.layout = KB_NL; + break; + + case CONF_LANG_SIMP_CHINESE: + case CONF_LANG_TRAD_CHINESE: + case CONF_LANG_KOREAN: + default: + _ukbd_keymapdata.layout = KB_US; + break; + } + } + + if (wskbd_load_keymap(&_ukbd_keymapdata, &_sc_map, &_sc_maplen) < 0) { + _ukbd_keymapdata.layout = KB_NONE; + + return -4; + } + + __lwp_queue_init_empty(&_queue); + + if (!_kbd_thread_running) { + // start the keyboard thread + _kbd_thread_quit = false; + + memset(_kbd_stack, 0, KBD_THREAD_STACKSIZE); + + s32 res = LWP_CreateThread(&_kbd_thread, _kbd_thread_func, NULL, + _kbd_stack, KBD_THREAD_STACKSIZE, + KBD_THREAD_PRIO); + + if (res) { + USBKeyboard_Close(); + + return -6; + } + + if(keypress_cb) + { + _keyBuffer.head = 0; + _keyBuffer.tail = 0; + + res = LWP_CreateThread(&_kbd_buf_thread, _kbd_buf_thread_func, NULL, + _kbd_buf_stack, KBD_THREAD_STACKSIZE, + KBD_THREAD_PRIO); + if(res) { + _kbd_thread_quit = true; + + LWP_JoinThread(_kbd_thread, NULL); + + USBKeyboard_Close(); + KEYBOARD_FlushEvents(); + USBKeyboard_Deinitialize(); + _kbd_thread_running = false; + return -6; + } + + devoptab_list[STD_IN] = &std_in; + setvbuf(stdin, NULL , _IONBF, 0); + _readKey_cb = keypress_cb; + } + _kbd_thread_running = true; + } + return 0; +} + +//Deinitialize USB and USB_KEYBOARD and the event queue +s32 KEYBOARD_Deinit(void) +{ + if (_kbd_thread_running) { + _kbd_thread_quit = true; + + if(_kbd_thread != LWP_THREAD_NULL) + LWP_JoinThread(_kbd_thread, NULL); + if(_kbd_buf_thread != LWP_THREAD_NULL) + LWP_JoinThread(_kbd_buf_thread, NULL); + + _kbd_thread_running = false; + } + + USBKeyboard_Close(); + KEYBOARD_FlushEvents(); + USBKeyboard_Deinitialize(); + + if (_sc_map) { + free(_sc_map); + _sc_map = NULL; + _sc_maplen = 0; + } + + return 1; +} + +//Get the first event of the event queue +s32 KEYBOARD_GetEvent(keyboard_event *event) +{ + _node *n = (_node *) __lwp_queue_get(&_queue); + + if (!n) + return 0; + + *event = n->event; + + free(n); + + return 1; +} + +//Flush all pending events +s32 KEYBOARD_FlushEvents(void) +{ + s32 res; + _node *n; + + res = 0; + while (true) { + n = (_node *) __lwp_queue_get(&_queue); + + if (!n) + break; + + free(n); + res++; + } + + return res; +} + diff --git a/wii/libogc/libwiikeyboard/ukbdmap.c b/wii/libogc/libwiikeyboard/ukbdmap.c new file mode 100644 index 0000000000..133a7d791e --- /dev/null +++ b/wii/libogc/libwiikeyboard/ukbdmap.c @@ -0,0 +1,1132 @@ +/* + * THIS FILE IS AUTOMAGICALLY GENERATED. DO NOT EDIT. + * + * generated by: + * OpenBSD: makemap.awk,v 1.10 2009/01/11 16:54:53 miod Exp + * generated from: + */ + +/* + * PLEASE DO NOT FORGET TO REGEN + * sys/dev/usb/ukbdmap.c + * AFTER ANY CHANGES TO THIS FILE! + */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#include "wsksymvar.h" + +#define KC(n) KS_KEYCODE(n) + +static const keysym_t ukbd_keydesc_us[] = { +/* pos command normal shifted */ + KC(4), KS_a, + KC(5), KS_b, + KC(6), KS_c, + KC(7), KS_d, + KC(8), KS_e, + KC(9), KS_f, + KC(10), KS_g, + KC(11), KS_h, + KC(12), KS_i, + KC(13), KS_j, + KC(14), KS_k, + KC(15), KS_l, + KC(16), KS_m, + KC(17), KS_n, + KC(18), KS_o, + KC(19), KS_p, + KC(20), KS_q, + KC(21), KS_r, + KC(22), KS_s, + KC(23), KS_t, + KC(24), KS_u, + KC(25), KS_v, + KC(26), KS_w, + KC(27), KS_x, + KC(28), KS_y, + KC(29), KS_z, + KC(30), KS_1, KS_exclam, + KC(31), KS_2, KS_at, + KC(32), KS_3, KS_numbersign, + KC(33), KS_4, KS_dollar, + KC(34), KS_5, KS_percent, + KC(35), KS_6, KS_asciicircum, + KC(36), KS_7, KS_ampersand, + KC(37), KS_8, KS_asterisk, + KC(38), KS_9, KS_parenleft, + KC(39), KS_0, KS_parenright, + KC(40), KS_Return, + KC(41), KS_Cmd_Debugger,KS_Escape, + KC(42), KS_Cmd_ResetEmul,KS_BackSpace, + KC(43), KS_Tab, + KC(44), KS_space, + KC(45), KS_minus, KS_underscore, + KC(46), KS_equal, KS_plus, + KC(47), KS_bracketleft, KS_braceleft, + KC(48), KS_bracketright,KS_braceright, + KC(49), KS_backslash, KS_bar, + KC(50), KS_backslash, KS_bar, + KC(51), KS_semicolon, KS_colon, + KC(52), KS_apostrophe, KS_quotedbl, + KC(53), KS_grave, KS_asciitilde, + KC(54), KS_comma, KS_less, + KC(55), KS_period, KS_greater, + KC(56), KS_slash, KS_question, + KC(57), KS_Caps_Lock, + KC(58), KS_Cmd_Screen0, KS_f1, + KC(59), KS_Cmd_Screen1, KS_f2, + KC(60), KS_Cmd_Screen2, KS_f3, + KC(61), KS_Cmd_Screen3, KS_f4, + KC(62), KS_Cmd_Screen4, KS_f5, + KC(63), KS_Cmd_Screen5, KS_f6, + KC(64), KS_Cmd_Screen6, KS_f7, + KC(65), KS_Cmd_Screen7, KS_f8, + KC(66), KS_Cmd_Screen8, KS_f9, + KC(67), KS_Cmd_Screen9, KS_f10, + KC(68), KS_Cmd_Screen10,KS_f11, + KC(69), KS_Cmd_Screen11,KS_f12, + KC(70), KS_Print_Screen, + KC(71), KS_Hold_Screen, + KC(72), KS_Pause, /*Break*/ + KC(73), KS_Insert, + KC(74), KS_Home, + KC(75), KS_Cmd_ScrollBack,KS_Prior, + KC(76), KS_Cmd_ResetEmul,KS_Delete, + KC(77), KS_End, + KC(78), KS_Cmd_ScrollFwd,KS_Next, + KC(79), KS_Right, + KC(80), KS_Left, + KC(81), KS_Down, + KC(82), KS_Up, + KC(83), KS_Num_Lock, + KC(84), KS_KP_Divide, + KC(85), KS_KP_Multiply, + KC(86), KS_KP_Subtract, + KC(87), KS_KP_Add, + KC(88), KS_KP_Enter, + KC(89), KS_KP_End, KS_KP_1, + KC(90), KS_KP_Down, KS_KP_2, + KC(91), KS_KP_Next, KS_KP_3, + KC(92), KS_KP_Left, KS_KP_4, + KC(93), KS_KP_Begin, KS_KP_5, + KC(94), KS_KP_Right, KS_KP_6, + KC(95), KS_KP_Home, KS_KP_7, + KC(96), KS_KP_Up, KS_KP_8, + KC(97), KS_KP_Prior, KS_KP_9, + KC(98), KS_KP_Insert, KS_KP_0, + KC(99), KS_Cmd_KbdReset,KS_KP_Delete, + KC(101), KS_Menu, + KC(116), KS_Open, + KC(117), KS_Help, + KC(118), KS_Props, + KC(119), KS_Front, + KC(120), KS_Cmd, + KC(121), KS_Again, + KC(122), KS_Undo, + KC(123), KS_Cut, + KC(124), KS_Copy, + KC(125), KS_Paste, + KC(126), KS_Find, + KC(127), KS_AudioMute, + KC(128), KS_AudioRaise, + KC(129), KS_AudioLower, + KC(224), KS_Cmd1, KS_Control_L, + KC(225), KS_Shift_L, + KC(226), KS_Cmd2, KS_Alt_L, + KC(227), KS_Meta_L, + KC(228), KS_Cmd1, KS_Control_R, + KC(229), KS_Shift_R, + KC(230), KS_Cmd2, KS_Alt_R, KS_Multi_key, + KC(231), KS_Meta_R, +}; + +static const keysym_t ukbd_keydesc_de[] = { +/* pos normal shifted altgr shift-altgr */ + KC(16), KS_m, KS_M, KS_mu, + KC(20), KS_q, KS_Q, KS_at, + KC(28), KS_z, + KC(29), KS_y, + KC(31), KS_2, KS_quotedbl, KS_twosuperior, + KC(32), KS_3, KS_section, KS_threesuperior, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_slash, KS_braceleft, + KC(37), KS_8, KS_parenleft, KS_bracketleft, + KC(38), KS_9, KS_parenright, KS_bracketright, + KC(39), KS_0, KS_equal, KS_braceright, + KC(45), KS_ssharp, KS_question, KS_backslash, + KC(46), KS_dead_acute, KS_dead_grave, + KC(47), KS_udiaeresis, + KC(48), KS_plus, KS_asterisk, KS_dead_tilde, + KC(49), KS_numbersign, KS_apostrophe, + KC(50), KS_numbersign, KS_apostrophe, + KC(51), KS_odiaeresis, + KC(52), KS_adiaeresis, + KC(53), KS_dead_circumflex,KS_dead_abovering, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, KS_bar, KS_brokenbar, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_de_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(46), KS_apostrophe, KS_grave, + KC(48), KS_plus, KS_asterisk, KS_asciitilde, + KC(53), KS_asciicircum, KS_degree, +}; + +static const keysym_t ukbd_keydesc_dk[] = { +/* pos normal shifted altgr shift-altgr */ + KC(31), KS_2, KS_quotedbl, KS_at, + KC(32), KS_3, KS_numbersign, KS_sterling, + KC(33), KS_4, KS_currency, KS_dollar, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_slash, KS_braceleft, + KC(37), KS_8, KS_parenleft, KS_bracketleft, + KC(38), KS_9, KS_parenright, KS_bracketright, + KC(39), KS_0, KS_equal, KS_braceright, + KC(45), KS_plus, KS_question, + KC(46), KS_dead_acute, KS_dead_grave, KS_bar, + KC(47), KS_aring, + KC(48), KS_dead_diaeresis,KS_dead_circumflex,KS_dead_tilde, + KC(49), KS_apostrophe, KS_asterisk, + KC(50), KS_apostrophe, KS_asterisk, + KC(51), KS_ae, + KC(52), KS_oslash, + KC(53), KS_onehalf, KS_paragraph, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, KS_backslash, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_dk_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(46), KS_apostrophe, KS_grave, KS_bar, + KC(48), KS_diaeresis, KS_asciicircum, KS_asciitilde, +}; + +static const keysym_t ukbd_keydesc_sv[] = { +/* pos normal shifted altgr shift-altgr */ + KC(45), KS_plus, KS_question, KS_backslash, + KC(48), KS_dead_diaeresis,KS_dead_circumflex,KS_dead_tilde, + KC(51), KS_odiaeresis, + KC(52), KS_adiaeresis, + KC(53), KS_section, KS_onehalf, + KC(100), KS_less, KS_greater, KS_bar, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_sv_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(46), KS_apostrophe, KS_grave, KS_bar, + KC(48), KS_diaeresis, KS_asciicircum, KS_asciitilde, +}; + +static const keysym_t ukbd_keydesc_no[] = { +/* pos normal shifted altgr shift-altgr */ + KC(46), KS_backslash, KS_dead_grave, KS_dead_acute, + KC(48), KS_dead_diaeresis,KS_dead_circumflex,KS_dead_tilde, + KC(51), KS_oslash, + KC(52), KS_ae, + KC(53), KS_bar, KS_paragraph, + KC(100), KS_less, KS_greater, +}; + +static const keysym_t ukbd_keydesc_no_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(46), KS_backslash, KS_grave, KS_acute, + KC(48), KS_diaeresis, KS_asciicircum, KS_asciitilde, +}; + +static const keysym_t ukbd_keydesc_fr[] = { +/* pos normal shifted altgr shift-altgr */ + KC(4), KS_q, + KC(16), KS_comma, KS_question, + KC(20), KS_a, + KC(26), KS_z, + KC(29), KS_w, + KC(30), KS_ampersand, KS_1, + KC(31), KS_eacute, KS_2, KS_asciitilde, + KC(32), KS_quotedbl, KS_3, KS_numbersign, + KC(33), KS_apostrophe, KS_4, KS_braceleft, + KC(34), KS_parenleft, KS_5, KS_bracketleft, + KC(35), KS_minus, KS_6, KS_bar, + KC(36), KS_egrave, KS_7, KS_grave, + KC(37), KS_underscore, KS_8, KS_backslash, + KC(38), KS_ccedilla, KS_9, KS_asciicircum, + KC(39), KS_agrave, KS_0, KS_at, + KC(45), KS_parenright, KS_degree, KS_bracketright, + KC(46), KS_equal, KS_plus, KS_braceright, + KC(47), KS_dead_circumflex,KS_dead_diaeresis, + KC(48), KS_dollar, KS_sterling, KS_currency, + KC(49), KS_asterisk, KS_mu, + KC(50), KS_asterisk, KS_mu, + KC(51), KS_m, + KC(52), KS_ugrave, KS_percent, + KC(53), KS_twosuperior, + KC(54), KS_semicolon, KS_period, + KC(55), KS_colon, KS_slash, + KC(56), KS_exclam, KS_section, + KC(100), KS_less, KS_greater, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_fr_apple[] = { + KC(5), KS_b, KS_B, KS_ssharp, + KC(8), KS_e, KS_E, KS_ecircumflex, KS_Ecircumflex, + KC(11), KS_h, KS_H, KS_Igrave, KS_Icircumflex, + KC(12), KS_i, KS_I, KS_icircumflex, KS_idiaeresis, + KC(13), KS_j, KS_J, KS_Idiaeresis, KS_Iacute, + KC(14), KS_k, KS_K, KS_Egrave, KS_Ediaeresis, + KC(15), KS_l, KS_L, KS_voidSymbol, KS_bar, + KC(16), KS_comma, KS_question, KS_voidSymbol, KS_questiondown, + KC(17), KS_n, KS_N, KS_asciitilde, + KC(20), KS_a, KS_A, KS_ae, KS_AE, + KC(21), KS_r, KS_R, KS_registered, KS_comma, + KC(22), KS_s, KS_S, KS_Ograve, + KC(26), KS_z, KS_Z, KS_Acircumflex, KS_Aring, + KC(28), KS_y, KS_Y, KS_Uacute, + KC(31), KS_eacute, KS_2, KS_ediaeresis, + KC(32), KS_quotedbl, KS_3, + KC(33), KS_apostrophe, KS_4, + KC(34), KS_parenleft, KS_5, KS_braceleft, KS_bracketleft, + KC(35), KS_section, KS_6, + KC(36), KS_egrave, KS_7, KS_guillemotleft, + KS_guillemotright, + KC(37), KS_exclam, KS_8, + KC(38), KS_ccedilla, KS_9, KS_Ccedilla, KS_Aacute, + KC(37), KS_exclam, KS_8, KS_exclamdown, KS_Ucircumflex, + KC(39), KS_agrave, KS_0, KS_oslash, KS_Ooblique, + KC(45), KS_parenright, KS_degree, KS_braceright, KS_bracketright, + KC(46), KS_minus, KS_underscore, + KC(47), KS_dead_circumflex, KS_dead_diaeresis, + KS_ocircumflex, KS_Ocircumflex, + KC(48), KS_dollar, KS_asterisk, KS_cent, KS_yen, + KC(50), KS_grave, KS_sterling, KS_at, KS_numbersign, + KC(51), KS_m, KS_M, KS_mu, KS_Oacute, + KC(52), KS_ugrave, KS_percent, KS_Ugrave, + KC(53), KS_at, KS_numbersign, + KC(55), KS_colon, KS_slash, KS_voidSymbol, KS_backslash, + KC(56), KS_equal, KS_plus, + KC(103), KS_KP_Equal, + KC(231), KS_Mode_switch, KS_Multi_key, +}; + +/* + * fr-dvorak-be'po layout, simplified map, per http://www.clavier-dvorak.org/ + * (the complete map is still a moving target) + */ +static const keysym_t ukbd_keydesc_fr_dvorak_bepo[] = { + /* oe ligature */ + /* euro currency */ + KC(4), KS_a, KS_A, KS_ae, KS_AE, + KC(5), KS_k, KS_K, KS_asciitilde, + KC(6), KS_x, KS_X, KS_braceright, + KC(7), KS_i, KS_I, KS_dead_diaeresis, + KC(8), KS_p, KS_P, KS_ampersand, + KC(9), KS_e, KS_E, + KC(10), KS_comma, KS_semicolon, + KC(11), KS_c, + KC(12), KS_d, + KC(13), KS_t, + KC(14), KS_s, + KC(15), KS_r, + KC(16), KS_q, KS_Q, + KC(17), KS_apostrophe, KS_question, + KC(18), KS_l, + KC(19), KS_j, + KC(20), KS_b, KS_B, KS_bar, + KC(21), KS_o, KS_O, + KC(22), KS_u, KS_U, KS_ugrave, KS_Ugrave, + KC(23), KS_egrave, KS_Egrave, KS_dead_grave, + KC(24), KS_v, + KC(25), KS_period, KS_colon, /*ellipsis*/ + KC(26), KS_eacute, KS_Eacute, KS_dead_acute, + KC(27), KS_y, KS_Y, KS_braceleft, + KC(28), KS_dead_circumflex,KS_exclam, + KC(29), KS_agrave, KS_Agrave, KS_backslash, + KC(30), KS_quotedbl, KS_1, KS_hyphen, + KC(31), KS_guillemotleft,KS_2, KS_less, + KC(32), KS_guillemotright,KS_3, KS_greater, + KC(33), KS_parenleft, KS_4, KS_bracketleft, + KC(34), KS_parenright, KS_5, KS_bracketright, + KC(35), KS_at, KS_6, + KC(36), KS_plus, KS_7, + KC(37), KS_minus, KS_8, + KC(38), KS_slash, KS_9, + KC(39), KS_asterisk, KS_0, + KC(44), KS_space, KS_nobreakspace,KS_underscore, + KC(45), KS_equal, KS_asciicircum, + KC(46), KS_percent, KS_grave, + KC(47), KS_z, + KC(48), KS_w, + KC(49), KS_ccedilla, KS_Ccedilla, + KC(50), KS_ccedilla, KS_Ccedilla, + KC(51), KS_n, + KC(52), KS_m, + KC(53), KS_dollar, KS_numbersign, + KC(54), KS_g, KS_G, KS_mu, + KC(55), KS_h, + KC(56), KS_f, + KC(100), KS_egrave, KS_Egrave, KS_slash, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_it[] = { +/* pos normal shifted altgr shift-altgr */ + KC(31), KS_2, KS_quotedbl, KS_twosuperior, + KC(32), KS_3, KS_sterling, KS_threesuperior, + KC(34), KS_5, KS_percent, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_slash, + KC(37), KS_8, KS_parenleft, + KC(38), KS_9, KS_parenright, + KC(39), KS_0, KS_equal, + KC(45), KS_apostrophe, KS_question, + KC(46), KS_igrave, KS_asciicircum, + KC(47), KS_egrave, KS_eacute, KS_braceleft, KS_bracketleft, + KC(48), KS_plus, KS_asterisk, KS_braceright, KS_bracketright, + KC(49), KS_ugrave, KS_section, + KC(50), KS_ugrave, KS_section, + KC(51), KS_ograve, KS_Ccedilla, KS_at, + KC(52), KS_agrave, KS_degree, KS_numbersign, + KC(53), KS_backslash, KS_bar, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_uk[] = { +/* pos normal shifted altgr shift-altgr */ + KC(30), KS_1, KS_exclam, KS_plusminus, KS_exclamdown, + KC(31), KS_2, KS_quotedbl, KS_twosuperior, KS_cent, + KC(32), KS_3, KS_sterling, KS_threesuperior, + KC(33), KS_4, KS_dollar, KS_acute, KS_currency, + KC(34), KS_5, KS_percent, KS_mu, KS_yen, + KC(35), KS_6, KS_asciicircum, KS_paragraph, + KC(36), KS_7, KS_ampersand, KS_periodcentered,KS_brokenbar, + KC(37), KS_8, KS_asterisk, KS_cedilla, KS_ordfeminine, + KC(38), KS_9, KS_parenleft, KS_onesuperior, KS_diaeresis, + KC(39), KS_0, KS_parenright, KS_masculine, KS_copyright, + KC(45), KS_minus, KS_underscore, KS_hyphen, KS_ssharp, + KC(46), KS_equal, KS_plus, KS_onehalf, KS_guillemotleft, + KC(49), KS_numbersign, KS_asciitilde, KS_sterling, KS_thorn, + KC(50), KS_numbersign, KS_asciitilde, KS_sterling, KS_thorn, + KC(52), KS_apostrophe, KS_at, KS_section, KS_Agrave, + KC(53), KS_grave, KS_grave, KS_agrave, KS_agrave, + KC(100), KS_backslash, KS_bar, KS_Udiaeresis, +}; + +static const keysym_t ukbd_keydesc_jp[] = { +/* pos normal shifted altgr shift-altgr */ + KC(31), KS_2, KS_quotedbl, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_apostrophe, + KC(37), KS_8, KS_parenleft, + KC(38), KS_9, KS_parenright, + KC(39), KS_0, + KC(45), KS_minus, KS_equal, + KC(46), KS_asciicircum, KS_asciitilde, + KC(47), KS_at, KS_grave, + KC(48), KS_bracketleft, KS_braceleft, + KC(49), KS_bracketright,KS_braceright, + KC(50), KS_bracketright,KS_braceright, + KC(51), KS_semicolon, KS_plus, + KC(52), KS_colon, KS_asterisk, + KC(53), KS_Zenkaku_Hankaku,/*replacegrave/tilde*/ + KC(135), KS_Hiragana_Katakana, + KC(136), KS_backslash, KS_underscore, + KC(137), KS_Henkan, + KC(138), KS_Muhenkan, + KC(139), KS_backslash, KS_bar, +}; + +static const keysym_t ukbd_keydesc_es[] = { +/* pos normal shifted altgr shift-altgr */ + KC(30), KS_1, KS_exclam, KS_bar, + KC(31), KS_2, KS_quotedbl, KS_at, + KC(32), KS_3, KS_periodcentered,KS_numbersign, + KC(33), KS_4, KS_dollar, KS_asciitilde, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_slash, + KC(37), KS_8, KS_parenleft, + KC(38), KS_9, KS_parenright, + KC(39), KS_0, KS_equal, + KC(45), KS_apostrophe, KS_question, + KC(46), KS_exclamdown, KS_questiondown, + KC(47), KS_dead_grave, KS_dead_circumflex,KS_bracketleft, + KC(48), KS_plus, KS_asterisk, KS_bracketright, + KC(49), KS_ccedilla, KS_Ccedilla, KS_braceright, + KC(50), KS_ccedilla, KS_Ccedilla, KS_braceright, + KC(51), KS_ntilde, + KC(52), KS_dead_acute, KS_dead_diaeresis,KS_braceleft, + KC(53), KS_degree, KS_ordfeminine, KS_backslash, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_lt[] = { +/* pos normal shifted altgr shift-altgr */ + KC(8), KS_e, KS_E, KS_currency, + KC(9), KS_L7_scaron, KS_L7_Scaron, + KC(20), KS_L7_aogonek, KS_L7_Aogonek, + KC(26), KS_L7_zcaron, KS_L7_Zcaron, + KC(27), KS_L7_umacron, KS_L7_Umacron, + KC(30), KS_exclam, KS_1, KS_at, + KC(31), KS_minus, KS_2, KS_underscore, + KC(32), KS_slash, KS_3, KS_numbersign, + KC(33), KS_semicolon, KS_4, KS_dollar, + KC(34), KS_colon, KS_5, KS_paragraph, + KC(35), KS_comma, KS_6, KS_asciicircum, + KC(36), KS_period, KS_7, KS_ampersand, + KC(37), KS_equal, KS_8, KS_asterisk, + KC(38), KS_bracketleft, KS_9, KS_parenleft, + KC(39), KS_bracketright,KS_0, KS_parenright, + KC(44), KS_space, KS_space, KS_nobreakspace, + KC(45), KS_question, KS_plus, KS_apostrophe, + KC(46), KS_x, KS_X, KS_percent, + KC(47), KS_L7_iogonek, KS_L7_Iogonek, KS_braceleft, + KC(48), KS_w, KS_W, KS_braceright, + KC(49), KS_q, KS_Q, KS_bar, + KC(50), KS_q, KS_Q, KS_bar, + KC(51), KS_L7_uogonek, KS_L7_Uogonek, + KC(52), KS_L7_edot, KS_L7_Edot, KS_quotedbl, + KC(53), KS_grave, KS_asciitilde, + KC(54), KS_L7_ccaron, KS_L7_Ccaron, KS_L7_dbllow9quot, + KC(55), KS_f, KS_F, KS_L7_leftdblquot, + KC(56), KS_L7_eogonek, KS_L7_Eogonek, KS_backslash, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_be[] = { +/* pos normal shifted altgr shift-altgr */ + KC(4), KS_q, + KC(16), KS_comma, KS_question, + KC(20), KS_a, + KC(26), KS_z, + KC(29), KS_w, + KC(30), KS_ampersand, KS_1, KS_bar, + KC(31), KS_eacute, KS_2, KS_at, + KC(32), KS_quotedbl, KS_3, KS_numbersign, + KC(33), KS_apostrophe, KS_4, + KC(34), KS_parenleft, KS_5, + KC(35), KS_section, KS_6, KS_asciicircum, + KC(36), KS_egrave, KS_7, + KC(37), KS_exclam, KS_8, + KC(38), KS_ccedilla, KS_9, KS_braceleft, + KC(39), KS_agrave, KS_0, KS_braceright, + KC(45), KS_parenright, KS_degree, + KC(46), KS_minus, KS_underscore, + KC(47), KS_dead_circumflex,KS_dead_diaeresis,KS_bracketleft, + KC(48), KS_dollar, KS_asterisk, KS_bracketright, + KC(49), KS_mu, KS_sterling, KS_grave, + KC(50), KS_mu, KS_sterling, KS_grave, + KC(51), KS_m, + KC(52), KS_ugrave, KS_percent, KS_acute, + KC(53), KS_twosuperior, KS_threesuperior, + KC(54), KS_semicolon, KS_period, + KC(55), KS_colon, KS_slash, + KC(56), KS_equal, KS_plus, KS_asciitilde, + KC(100), KS_less, KS_greater, KS_backslash, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + + +static const keysym_t ukbd_keydesc_us_dvorak[] = { +/* pos command normal shifted */ + KC(5), KS_x, + KC(6), KS_j, + KC(7), KS_e, + KC(8), KS_period, KS_greater, + KC(9), KS_u, + KC(10), KS_i, + KC(11), KS_d, + KC(12), KS_c, + KC(13), KS_h, + KC(14), KS_t, + KC(15), KS_n, + KC(17), KS_b, + KC(18), KS_r, + KC(19), KS_l, + KC(20), KS_apostrophe, KS_quotedbl, + KC(21), KS_p, + KC(22), KS_o, + KC(23), KS_y, + KC(24), KS_g, + KC(25), KS_k, + KC(26), KS_comma, KS_less, + KC(27), KS_q, + KC(28), KS_f, + KC(29), KS_semicolon, KS_colon, + KC(45), KS_bracketleft, KS_braceleft, + KC(46), KS_bracketright,KS_braceright, + KC(47), KS_slash, KS_question, + KC(48), KS_equal, KS_plus, + KC(51), KS_s, + KC(52), KS_minus, KS_underscore, + KC(54), KS_w, + KC(55), KS_v, + KC(56), KS_z, +}; + +static const keysym_t ukbd_keydesc_swapctrlcaps[] = { +/* pos command normal shifted */ + KC(57), KS_Cmd1, KS_Control_L, + KC(224), KS_Caps_Lock, +}; + +static const keysym_t ukbd_keydesc_iopener[] = { +/* pos command normal shifted */ + KC(58), KS_Cmd_Debugger,KS_Escape, + KC(59), KS_Cmd_Screen0, KS_f1, + KC(60), KS_Cmd_Screen1, KS_f2, + KC(61), KS_Cmd_Screen2, KS_f3, + KC(62), KS_Cmd_Screen3, KS_f4, + KC(63), KS_Cmd_Screen4, KS_f5, + KC(64), KS_Cmd_Screen5, KS_f6, + KC(65), KS_Cmd_Screen6, KS_f7, + KC(66), KS_Cmd_Screen7, KS_f8, + KC(67), KS_Cmd_Screen8, KS_f9, + KC(68), KS_Cmd_Screen9, KS_f10, + KC(69), KS_f11, +}; + +static const keysym_t ukbd_keydesc_ru[] = { +/* pos normal shifted altgr shift-altgr */ + KC(4), KS_a, KS_A, KS_Cyrillic_ef, KS_Cyrillic_EF, + KC(5), KS_b, KS_B, KS_Cyrillic_i, KS_Cyrillic_I, + KC(6), KS_c, KS_C, KS_Cyrillic_es, KS_Cyrillic_ES, + KC(7), KS_d, KS_D, KS_Cyrillic_ve, KS_Cyrillic_VE, + KC(8), KS_e, KS_E, KS_Cyrillic_u, KS_Cyrillic_U, + KC(9), KS_f, KS_F, KS_Cyrillic_a, KS_Cyrillic_A, + KC(10), KS_g, KS_G, KS_Cyrillic_pe, KS_Cyrillic_PE, + KC(11), KS_h, KS_H, KS_Cyrillic_er, KS_Cyrillic_ER, + KC(12), KS_i, KS_I, KS_Cyrillic_sha,KS_Cyrillic_SHA, + KC(13), KS_j, KS_J, KS_Cyrillic_o, KS_Cyrillic_O, + KC(14), KS_k, KS_K, KS_Cyrillic_el, KS_Cyrillic_EL, + KC(15), KS_l, KS_L, KS_Cyrillic_de, KS_Cyrillic_DE, + KC(16), KS_m, KS_M, KS_Cyrillic_ssighn,KS_Cyrillic_SSIGHN, + KC(17), KS_n, KS_N, KS_Cyrillic_te, KS_Cyrillic_TE, + KC(18), KS_o, KS_O, KS_Cyrillic_scha,KS_Cyrillic_SCHA, + KC(19), KS_p, KS_P, KS_Cyrillic_ze, KS_Cyrillic_ZE, + KC(20), KS_q, KS_Q, KS_Cyrillic_ishort,KS_Cyrillic_ISHORT, + KC(21), KS_r, KS_R, KS_Cyrillic_ka, KS_Cyrillic_KA, + KC(22), KS_s, KS_S, KS_Cyrillic_yeru,KS_Cyrillic_YERU, + KC(23), KS_t, KS_T, KS_Cyrillic_ie, KS_Cyrillic_IE, + KC(24), KS_u, KS_U, KS_Cyrillic_ge, KS_Cyrillic_GE, + KC(25), KS_v, KS_V, KS_Cyrillic_em, KS_Cyrillic_EM, + KC(26), KS_w, KS_W, KS_Cyrillic_tse,KS_Cyrillic_TSE, + KC(27), KS_x, KS_X, KS_Cyrillic_che,KS_Cyrillic_CHE, + KC(28), KS_y, KS_Y, KS_Cyrillic_en, KS_Cyrillic_EN, + KC(29), KS_z, KS_Z, KS_Cyrillic_ya, KS_Cyrillic_YA, + KC(35), KS_6, KS_asciicircum, KS_6, KS_comma, + KC(36), KS_7, KS_ampersand, KS_7, KS_period, + KC(47), KS_bracketleft, KS_braceleft, KS_Cyrillic_ha, KS_Cyrillic_HA, + KC(48), KS_bracketright,KS_braceright, KS_Cyrillic_hsighn,KS_Cyrillic_HSIGHN, + KC(51), KS_semicolon, KS_colon, KS_Cyrillic_zhe,KS_Cyrillic_ZHE, + KC(52), KS_apostrophe, KS_quotedbl, KS_Cyrillic_e, KS_Cyrillic_E, + KC(54), KS_comma, KS_less, KS_Cyrillic_be, KS_Cyrillic_BE, + KC(55), KS_period, KS_greater, KS_Cyrillic_yu, KS_Cyrillic_YU, + KC(56), KS_slash, KS_question, KS_Cyrillic_yo, KS_Cyrillic_YO, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_ua[] = { +/* pos normal shifted altgr shift-altgr */ + KC(4), KS_a, KS_A, KS_Cyrillic_ef, KS_Cyrillic_EF, + KC(5), KS_b, KS_B, KS_Cyrillic_i, KS_Cyrillic_I, + KC(6), KS_c, KS_C, KS_Cyrillic_es, KS_Cyrillic_ES, + KC(7), KS_d, KS_D, KS_Cyrillic_ve, KS_Cyrillic_VE, + KC(8), KS_e, KS_E, KS_Cyrillic_u, KS_Cyrillic_U, + KC(9), KS_f, KS_F, KS_Cyrillic_a, KS_Cyrillic_A, + KC(10), KS_g, KS_G, KS_Cyrillic_pe, KS_Cyrillic_PE, + KC(11), KS_h, KS_H, KS_Cyrillic_er, KS_Cyrillic_ER, + KC(12), KS_i, KS_I, KS_Cyrillic_sha,KS_Cyrillic_SHA, + KC(13), KS_j, KS_J, KS_Cyrillic_o, KS_Cyrillic_O, + KC(14), KS_k, KS_K, KS_Cyrillic_el, KS_Cyrillic_EL, + KC(15), KS_l, KS_L, KS_Cyrillic_de, KS_Cyrillic_DE, + KC(16), KS_m, KS_M, KS_Cyrillic_ssighn,KS_Cyrillic_SSIGHN, + KC(17), KS_n, KS_N, KS_Cyrillic_te, KS_Cyrillic_TE, + KC(18), KS_o, KS_O, KS_Cyrillic_scha,KS_Cyrillic_SCHA, + KC(19), KS_p, KS_P, KS_Cyrillic_ze, KS_Cyrillic_ZE, + KC(20), KS_q, KS_Q, KS_Cyrillic_ishort,KS_Cyrillic_ISHORT, + KC(21), KS_r, KS_R, KS_Cyrillic_ka, KS_Cyrillic_KA, + KC(22), KS_s, KS_S, KS_Cyrillic_yeru,KS_Cyrillic_YERU, + KC(23), KS_t, KS_T, KS_Cyrillic_ie, KS_Cyrillic_IE, + KC(24), KS_u, KS_U, KS_Cyrillic_ge, KS_Cyrillic_GE, + KC(25), KS_v, KS_V, KS_Cyrillic_em, KS_Cyrillic_EM, + KC(26), KS_w, KS_W, KS_Cyrillic_tse,KS_Cyrillic_TSE, + KC(27), KS_x, KS_X, KS_Cyrillic_che,KS_Cyrillic_CHE, + KC(28), KS_y, KS_Y, KS_Cyrillic_en, KS_Cyrillic_EN, + KC(29), KS_z, KS_Z, KS_Cyrillic_ya, KS_Cyrillic_YA, + KC(35), KS_6, KS_asciicircum, KS_6, KS_comma, + KC(36), KS_7, KS_ampersand, KS_7, KS_period, + KC(45), KS_minus, KS_underscore, KS_Cyrillic_iukr,KS_Cyrillic_IUKR, + KC(46), KS_equal, KS_plus, KS_Cyrillic_yeukr,KS_Cyrillic_YEUKR, + KC(47), KS_bracketleft, KS_braceleft, KS_Cyrillic_ha, KS_Cyrillic_HA, + KC(48), KS_bracketright,KS_braceright, KS_Cyrillic_hsighn,KS_Cyrillic_HSIGHN, + KC(49), KS_backslash, KS_bar, KS_Cyrillic_yi, KS_Cyrillic_YI, + KC(50), KS_backslash, KS_bar, KS_Cyrillic_yi, KS_Cyrillic_YI, + KC(51), KS_semicolon, KS_colon, KS_Cyrillic_zhe,KS_Cyrillic_ZHE, + KC(52), KS_apostrophe, KS_quotedbl, KS_Cyrillic_e, KS_Cyrillic_E, + KC(53), KS_grave, KS_asciitilde, KS_Cyrillic_gheukr,KS_Cyrillic_GHEUKR, + KC(54), KS_comma, KS_less, KS_Cyrillic_be, KS_Cyrillic_BE, + KC(55), KS_period, KS_greater, KS_Cyrillic_yu, KS_Cyrillic_YU, + KC(56), KS_slash, KS_question, KS_Cyrillic_yo, KS_Cyrillic_YO, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_sg[] = { +/* pos normal shifted altgr shift-altgr */ + KC(8), KS_e, KS_E, KS_currency, + KC(28), KS_z, + KC(29), KS_y, + KC(30), KS_1, KS_plus, KS_bar, + KC(31), KS_2, KS_quotedbl, KS_at, + KC(32), KS_3, KS_asterisk, KS_numbersign, + KC(33), KS_4, KS_ccedilla, + KC(35), KS_6, KS_ampersand, KS_notsign, + KC(36), KS_7, KS_slash, KS_brokenbar, + KC(37), KS_8, KS_parenleft, KS_cent, + KC(38), KS_9, KS_parenright, + KC(39), KS_0, KS_equal, + KC(45), KS_apostrophe, KS_question, KS_dead_acute, + KC(46), KS_dead_circumflex,KS_dead_grave,KS_dead_tilde, + KC(47), KS_udiaeresis, KS_egrave, KS_bracketleft, + KC(48), KS_dead_diaeresis,KS_exclam, KS_bracketright, + KC(49), KS_dollar, KS_sterling, KS_braceright, + KC(50), KS_dollar, KS_sterling, KS_braceright, + KC(51), KS_odiaeresis, KS_eacute, + KC(52), KS_adiaeresis, KS_agrave, KS_braceleft, + KC(53), KS_section, KS_degree, KS_dead_abovering, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, KS_backslash, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_sg_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(45), KS_apostrophe, KS_question, KS_acute, + KC(46), KS_asciicircum, KS_grave, KS_asciitilde, + KC(48), KS_diaeresis, KS_exclam, KS_bracketright, +}; + +static const keysym_t ukbd_keydesc_sf[] = { +/* pos normal shifted altgr shift-altgr */ + KC(47), KS_egrave, KS_udiaeresis, KS_bracketleft, + KC(51), KS_eacute, KS_odiaeresis, + KC(52), KS_agrave, KS_adiaeresis, KS_braceleft, +}; + +static const keysym_t ukbd_keydesc_pt[] = { +/* pos normal shifted altgr shift-altgr */ + KC(31), KS_2, KS_quotedbl, KS_at, + KC(32), KS_3, KS_numbersign, KS_sterling, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_slash, KS_braceleft, + KC(37), KS_8, KS_parenleft, KS_bracketleft, + KC(38), KS_9, KS_parenright, KS_bracketright, + KC(39), KS_0, KS_equal, KS_braceright, + KC(45), KS_apostrophe, KS_question, + KC(46), KS_less, KS_greater, + KC(47), KS_plus, KS_asterisk, + KC(48), KS_dead_acute, KS_dead_grave, + KC(49), KS_dead_tilde, KS_dead_circumflex, + KC(50), KS_dead_tilde, KS_dead_circumflex, + KC(51), KS_ccedilla, KS_Ccedilla, + KC(52), KS_masculine, KS_ordfeminine, + KC(53), KS_backslash, KS_bar, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_pt_apple[] = { +/* pos normal shifted */ + KC(46), KS_plus, KS_asterisk, + KC(47), KS_masculine, KS_ordfeminine, + KC(50), KS_backslash, KS_bar, + KC(52), KS_dead_tilde, KS_dead_circumflex +}; + +static const keysym_t ukbd_keydesc_la[] = { +/* pos normal shifted altgr shift-altgr */ + KC(20), KS_q, KS_Q, KS_at, + KC(30), KS_1, KS_exclam, + KC(31), KS_2, KS_quotedbl, + KC(32), KS_3, KS_numbersign, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_slash, + KC(37), KS_8, KS_parenleft, + KC(38), KS_9, KS_parenright, + KC(39), KS_0, KS_equal, + KC(45), KS_apostrophe, KS_question, KS_backslash, + KC(46), KS_questiondown,KS_exclamdown, + KC(47), KS_dead_acute, KS_dead_diaeresis, + KC(48), KS_plus, KS_asterisk, KS_asciitilde, + KC(49), KS_braceright, KS_bracketright,KS_dead_grave, + KC(50), KS_braceright, KS_bracketright,KS_dead_grave, + KC(51), KS_ntilde, + KC(52), KS_braceleft, KS_bracketleft, KS_dead_circumflex, + KC(53), KS_bar, KS_degree, KS_notsign, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_br[] = { +/* pos normal shifted altgr shift-altgr */ + KC(30), KS_1, KS_exclam, KS_onesuperior, + KC(31), KS_2, KS_at, KS_twosuperior, + KC(32), KS_3, KS_numbersign, KS_threesuperior, + KC(33), KS_4, KS_dollar, KS_sterling, + KC(34), KS_5, KS_percent, KS_cent, + KC(35), KS_6, KS_dead_diaeresis,KS_notsign, + KC(46), KS_equal, KS_plus, KS_section, + KC(47), KS_dead_acute, KS_dead_grave, + KC(48), KS_bracketleft, KS_braceleft, KS_ordfeminine, + KC(49), KS_bracketright,KS_braceright, KS_masculine, + KC(50), KS_bracketright,KS_braceright, KS_masculine, + KC(51), KS_ccedilla, KS_Ccedilla, + KC(52), KS_dead_tilde, KS_dead_circumflex, + KC(53), KS_apostrophe, KS_quotedbl, + KC(56), KS_semicolon, KS_colon, + KC(99), KS_KP_Delete, KS_KP_Decimal, + KC(100), KS_backslash, KS_bar, + KC(136), KS_slash, KS_question, KS_degree, +}; + +static const keysym_t ukbd_keydesc_tr[] = { +/* pos normal shifted altgr shift-altgr */ + KC(12), KS_L5_idotless, KS_I, + KC(20), KS_q, KS_Q, KS_at, + KC(31), KS_2, KS_apostrophe, KS_sterling, + KC(32), KS_3, KS_asciicircum, KS_numbersign, + KC(33), KS_4, KS_plus, KS_dollar, + KC(34), KS_5, KS_percent, KS_onehalf, + KC(35), KS_6, KS_ampersand, + KC(36), KS_7, KS_slash, KS_braceleft, + KC(37), KS_8, KS_parenleft, KS_bracketleft, + KC(38), KS_9, KS_parenright, KS_bracketright, + KC(39), KS_0, KS_equal, KS_braceright, + KC(45), KS_asterisk, KS_question, KS_backslash, + KC(46), KS_minus, KS_underscore, + KC(47), KS_L5_gbreve, KS_L5_Gbreve, KS_dead_diaeresis, + KC(48), KS_udiaeresis, KS_Udiaeresis, KS_asciitilde, + KC(49), KS_comma, KS_semicolon, KS_dead_grave, + KC(50), KS_comma, KS_semicolon, KS_dead_grave, + KC(51), KS_L5_scedilla, KS_L5_Scedilla, KS_dead_acute, + KC(52), KS_i, KS_L5_Idotabove, + KC(53), KS_quotedbl, KS_eacute, + KC(54), KS_odiaeresis, KS_Odiaeresis, + KC(55), KS_ccedilla, KS_Ccedilla, + KC(56), KS_period, KS_colon, + KC(100), KS_less, KS_greater, KS_bar, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_tr_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(47), KS_L5_gbreve, KS_L5_Gbreve, + KC(49), KS_comma, KS_semicolon, KS_grave, + KC(50), KS_comma, KS_semicolon, KS_grave, + KC(51), KS_L5_scedilla, KS_L5_Scedilla, KS_apostrophe, +}; + +static const keysym_t ukbd_keydesc_pl[] = { +/* pos normal shifted altgr shift-altgr */ + KC(4), KS_a, KS_A, KS_L2_aogonek, KS_L2_Aogonek, + KC(6), KS_c, KS_C, KS_L2_cacute, KS_L2_Cacute, + KC(8), KS_e, KS_E, KS_L2_eogonek, KS_L2_Eogonek, + KC(15), KS_l, KS_L, KS_L2_lstroke, KS_L2_Lstroke, + KC(17), KS_n, KS_N, KS_L2_nacute, KS_L2_Nacute, + KC(18), KS_o, KS_O, KS_oacute, KS_Oacute, + KC(22), KS_s, KS_S, KS_L2_sacute, KS_L2_Sacute, + KC(27), KS_x, KS_X, KS_L2_zacute, KS_L2_Zacute, + KC(29), KS_z, KS_Z, KS_L2_zdotabove,KS_L2_Zdotabove, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_hu[] = { +/* pos normal shifted altgr shift-altgr */ + KC(5), KS_b, KS_B, KS_braceleft, + KC(6), KS_c, KS_C, KS_ampersand, + KC(9), KS_f, KS_F, KS_bracketleft, + KC(10), KS_g, KS_G, KS_bracketright, + KC(12), KS_i, KS_I, KS_iacute, + KC(13), KS_j, KS_J, KS_iacute, + KC(17), KS_n, KS_N, KS_braceright, + KC(20), KS_q, KS_Q, KS_backslash, + KC(25), KS_v, KS_V, KS_at, + KC(26), KS_w, KS_W,KS_bar, + KC(27), KS_x, KS_X, KS_numbersign, + KC(28), KS_z, KS_Z, + KC(29), KS_y, KS_Y, KS_greater, + KC(30), KS_1, KS_apostrophe, KS_asciitilde, + KC(31), KS_2, KS_quotedbl, + KC(32), KS_3, KS_plus, KS_asciicircum, + KC(33), KS_4, KS_exclam, + KC(34), KS_5, KS_percent, + KC(35), KS_6, KS_slash, + KC(36), KS_7, KS_equal,KS_grave, + KC(37), KS_8, KS_parenleft, + KC(38), KS_9, KS_parenright, KS_acute, + KC(39), KS_odiaeresis, KS_Odiaeresis, + KC(45), KS_udiaeresis, KS_Udiaeresis, + KC(46), KS_oacute, KS_Oacute, + KC(47), KS_odoubleacute,KS_Odoubleacute,KS_division, + KC(48), KS_uacute, KS_Uacute, KS_multiply, + KC(49), KS_udoubleacute,KS_Udoubleacute,KS_currency, + KC(50), KS_udoubleacute,KS_Udoubleacute,KS_currency, + KC(51), KS_eacute, KS_Eacute, KS_dollar, + KC(52), KS_aacute, KS_Aacute, KS_ssharp, + KC(53), KS_0, KS_section, + KC(54), KS_comma, KS_question, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, KS_asterisk, + KC(100), KS_iacute, KS_Iacute, KS_less, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_si[]= +{ +/* pos normal shifted altgr shift-altgr */ + KC(5), KS_b, KS_B, KS_braceleft, + KC(9), KS_f, KS_F, KS_bracketleft, + KC(10), KS_g, KS_G, KS_bracketright, + KC(14), KS_k, KS_K, KS_L2_lstroke, + KC(15), KS_l, KS_L, KS_L2_Lstroke, + KC(16), KS_m, KS_M, KS_section, + KC(17), KS_n, KS_N, KS_braceright, + KC(20), KS_q, KS_Q, KS_backslash, + KC(25), KS_v, KS_V, KS_at, + KC(26), KS_w, KS_W, KS_bar, + KC(28), KS_z, KS_Z, + KC(29), KS_y, KS_Y, + KC(30), KS_1, KS_exclam, KS_asciitilde, + KC(31), KS_2, KS_quotedbl, KS_L2_caron, + KC(32), KS_3, KS_numbersign, KS_asciicircum, + KC(33), KS_4, KS_dollar, KS_L2_breve, + KC(34), KS_5, KS_percent, KS_degree, + KC(35), KS_6, KS_ampersand, KS_L2_ogonek, + KC(36), KS_7, KS_slash, KS_grave, + KC(37), KS_8, KS_parenleft, KS_L2_dotabove, + KC(38), KS_9, KS_parenright, KS_acute, + KC(39), KS_0, KS_equal, KS_L2_dblacute, + KC(45), KS_apostrophe, KS_question, KS_diaeresis, + KC(46), KS_plus, KS_asterisk, KS_cedilla, + KC(47), KS_L2_scaron, KS_L2_Scaron, KS_division, + KC(48), KS_L2_dstroke, KS_L2_Dstroke, KS_multiply, + KC(49), KS_L2_zcaron, KS_L2_Zcaron, KS_currency, + KC(50), KS_L2_zcaron, KS_L2_Zcaron, KS_currency, + KC(51), KS_L2_ccaron, KS_L2_Ccaron, + KC(52), KS_L2_cacute, KS_L2_Cacute, KS_ssharp, + KC(53), KS_cedilla, KS_diaeresis, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, + KC(56), KS_minus, KS_underscore, + KC(100), KS_less, KS_greater, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_cf[] = { +/* pos normal shifted altgr shift-altgr */ + KC(16), KS_m, KS_M, KS_mu, + KC(18), KS_o, KS_O, KS_section, + KC(19), KS_p, KS_P, KS_paragraph, + KC(30), KS_1, KS_exclam, KS_plusminus, + KC(31), KS_2, KS_quotedbl, KS_at, + KC(32), KS_3, KS_slash, KS_sterling, + KC(33), KS_4, KS_dollar, KS_cent, + KC(34), KS_5, KS_percent, KS_diaeresis, + KC(35), KS_6, KS_question, KS_macron, + KC(36), KS_7, KS_ampersand, KS_brokenbar, + KC(37), KS_8, KS_asterisk, KS_twosuperior, + KC(38), KS_9, KS_parenleft, KS_threesuperior, + KC(39), KS_0, KS_parenright, KS_onequarter, + KC(45), KS_minus, KS_underscore, KS_onehalf, + KC(46), KS_equal, KS_plus, KS_threequarters, + KC(47), KS_dead_circumflex,KS_dead_circumflex,KS_bracketleft, + KC(48), KS_dead_cedilla,KS_dead_diaeresis,KS_bracketright, + KC(49), KS_less, KS_greater, KS_braceright, + KC(50), KS_less, KS_greater, KS_braceright, + KC(51), KS_semicolon, KS_colon, KS_asciitilde, + KC(52), KS_dead_grave, KS_dead_grave, KS_braceleft, + KC(53), KS_numbersign, KS_bar, KS_backslash, + KC(54), KS_comma, KS_apostrophe, KS_hyphen, + KC(55), KS_period, KS_period, + KC(56), KS_eacute, KS_Eacute, KS_dead_acute, + KC(100), KS_guillemotleft,KS_guillemotright,KS_degree, + KC(230), KS_Mode_switch,KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_cf_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(47), KS_asciicircum,KS_asciicircum,KS_bracketleft, + KC(48), KS_cedilla, KS_diaeresis, KS_bracketright, + KC(52), KS_grave, KS_grave, KS_braceleft, + KC(56), KS_eacute, KS_Eacute, KS_acute, +}; + +static const keysym_t ukbd_keydesc_lv[] = { +/* pos normal shifted altgr shift-altgr */ + KC(4), KS_a, KS_A, KS_L7_amacron, KS_L7_Amacron, + KC(6), KS_c, KS_C, KS_L7_ccaron, KS_L7_Ccaron, + KC(8), KS_e, KS_E, KS_L7_emacron, KS_L7_Emacron, + KC(10), KS_g, KS_G, KS_L7_gcedilla, KS_L7_Gcedilla, + KC(12), KS_i, KS_I, KS_L7_imacron, KS_L7_Imacron, + KC(14), KS_k, KS_K, KS_L7_kcedilla, KS_L7_Kcedilla, + KC(15), KS_l, KS_L, KS_L7_lcedilla, KS_L7_Lcedilla, + KC(17), KS_n, KS_N, KS_L7_ncedilla, KS_L7_Ncedilla, + KC(18), KS_o, KS_O, KS_L7_omacron, KS_L7_Omacron, + KC(22), KS_s, KS_S, KS_L7_scaron, KS_L7_Scaron, + KC(24), KS_u, KS_U, KS_L7_umacron, KS_L7_Umacron, + KC(29), KS_z, KS_Z, KS_L7_zcaron, KS_L7_Zcaron, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_nl[] = { +/* pos normal shifted altgr shift-altgr */ + KC(6), KS_c, KS_C, KS_cent, + KC(16), KS_m, KS_M, KS_mu, + KC(21), KS_r, KS_R, KS_paragraph, + KC(22), KS_s, KS_S, KS_ssharp, + KC(27), KS_x, KS_X, KS_guillemotright, + KC(29), KS_z, KS_Z, KS_guillemotleft, + KC(30), KS_1, KS_exclam, KS_onesuperior, + KC(31), KS_2, KS_quotedbl, KS_twosuperior, + KC(32), KS_3, KS_numbersign, KS_threesuperior, + KC(33), KS_4, KS_dollar, KS_onequarter, + KC(34), KS_5, KS_percent, KS_onehalf, + KC(35), KS_6, KS_ampersand, KS_threequarters, + KC(36), KS_7, KS_underscore, KS_sterling, + KC(37), KS_8, KS_parenleft, KS_braceleft, + KC(38), KS_9, KS_parenright, KS_braceright, + KC(39), KS_0, KS_apostrophe, + KC(45), KS_slash, KS_question, KS_backslash, + KC(46), KS_degree, KS_dead_tilde, KS_dead_cedilla, + KC(47), KS_dead_diaeresis,KS_dead_circumflex, + KC(48), KS_asterisk, KS_bar, + KC(49), KS_less, KS_greater, + KC(50), KS_less, KS_greater, + KC(51), KS_plus, KS_plusminus, + KC(52), KS_dead_acute, KS_dead_grave, + KC(53), KS_at, KS_section, KS_notsign, + KC(54), KS_comma, KS_semicolon, + KC(55), KS_period, KS_colon, KS_periodcentered, + KC(56), KS_minus, KS_equal, + KC(100), KS_bracketright,KS_bracketleft, KS_brokenbar, + KC(230), KS_Mode_switch, KS_Multi_key, +}; + +static const keysym_t ukbd_keydesc_nl_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(46), KS_degree, KS_asciitilde, KS_cedilla, + KC(47), KS_quotedbl, KS_asciicircum, + KC(52), KS_apostrophe, KS_grave, +}; + +#define KBD_MAP(name, base, map) \ + { name, base, sizeof(map)/sizeof(keysym_t), map } + +const struct wscons_keydesc ukbd_keydesctab[] = { + KBD_MAP(KB_US, 0, ukbd_keydesc_us), + KBD_MAP(KB_DE, KB_US, ukbd_keydesc_de), + KBD_MAP(KB_DE | KB_NODEAD, KB_DE, ukbd_keydesc_de_nodead), + KBD_MAP(KB_FR, KB_US, ukbd_keydesc_fr), + KBD_MAP(KB_FR | KB_APPLE, KB_FR, ukbd_keydesc_fr_apple), + KBD_MAP(KB_FR | KB_DVORAK, KB_US, ukbd_keydesc_fr_dvorak_bepo), + KBD_MAP(KB_DK, KB_US, ukbd_keydesc_dk), + KBD_MAP(KB_DK | KB_NODEAD, KB_DK, ukbd_keydesc_dk_nodead), + KBD_MAP(KB_IT, KB_US, ukbd_keydesc_it), + KBD_MAP(KB_UK, KB_US, ukbd_keydesc_uk), + KBD_MAP(KB_JP, KB_US, ukbd_keydesc_jp), + KBD_MAP(KB_SV, KB_DK, ukbd_keydesc_sv), + KBD_MAP(KB_SV | KB_NODEAD, KB_SV, ukbd_keydesc_sv_nodead), + KBD_MAP(KB_NO, KB_DK, ukbd_keydesc_no), + KBD_MAP(KB_NO | KB_NODEAD, KB_NO, ukbd_keydesc_no_nodead), + KBD_MAP(KB_US | KB_DVORAK, KB_US, ukbd_keydesc_us_dvorak), + KBD_MAP(KB_US | KB_SWAPCTRLCAPS, KB_US, ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_US | KB_IOPENER, KB_US, ukbd_keydesc_iopener), + KBD_MAP(KB_JP | KB_SWAPCTRLCAPS, KB_JP, ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_FR | KB_SWAPCTRLCAPS, KB_FR, ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_FR | KB_APPLE | KB_SWAPCTRLCAPS, KB_FR | KB_APPLE, + ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_FR | KB_DVORAK | KB_SWAPCTRLCAPS, KB_FR | KB_DVORAK, + ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_BE | KB_SWAPCTRLCAPS, KB_BE, ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_US | KB_DVORAK | KB_SWAPCTRLCAPS, KB_US | KB_DVORAK, + ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_US | KB_IOPENER | KB_SWAPCTRLCAPS, KB_US | KB_IOPENER, + ukbd_keydesc_swapctrlcaps), + KBD_MAP(KB_ES, KB_US, ukbd_keydesc_es), + KBD_MAP(KB_BE, KB_US, ukbd_keydesc_be), + KBD_MAP(KB_RU, KB_US, ukbd_keydesc_ru), + KBD_MAP(KB_UA, KB_US, ukbd_keydesc_ua), + KBD_MAP(KB_SG, KB_US, ukbd_keydesc_sg), + KBD_MAP(KB_SG | KB_NODEAD, KB_SG, ukbd_keydesc_sg_nodead), + KBD_MAP(KB_SF, KB_SG, ukbd_keydesc_sf), + KBD_MAP(KB_SF | KB_NODEAD, KB_SF, ukbd_keydesc_sg_nodead), + KBD_MAP(KB_PT, KB_US, ukbd_keydesc_pt), + KBD_MAP(KB_PT | KB_APPLE, KB_PT, ukbd_keydesc_pt_apple), + KBD_MAP(KB_LT, KB_US, ukbd_keydesc_lt), + KBD_MAP(KB_LA, KB_US, ukbd_keydesc_la), + KBD_MAP(KB_BR, KB_US, ukbd_keydesc_br), + KBD_MAP(KB_TR, KB_US, ukbd_keydesc_tr), + KBD_MAP(KB_TR | KB_NODEAD, KB_TR, ukbd_keydesc_tr_nodead), + KBD_MAP(KB_PL, KB_US, ukbd_keydesc_pl), + KBD_MAP(KB_HU, KB_US, ukbd_keydesc_hu), + KBD_MAP(KB_SI, KB_US, ukbd_keydesc_si), + KBD_MAP(KB_CF, KB_US, ukbd_keydesc_cf), + KBD_MAP(KB_CF | KB_NODEAD, KB_CF, ukbd_keydesc_cf_nodead), + KBD_MAP(KB_LV, KB_US, ukbd_keydesc_lv), + KBD_MAP(KB_NL, KB_US, ukbd_keydesc_nl), + KBD_MAP(KB_NL | KB_NODEAD, KB_NL, ukbd_keydesc_nl_nodead), + {0, 0, 0, 0} +}; + +#undef KBD_MAP +#undef KC diff --git a/wii/libogc/libwiikeyboard/usbkeyboard.c b/wii/libogc/libwiikeyboard/usbkeyboard.c new file mode 100644 index 0000000000..1b2d45a6e3 --- /dev/null +++ b/wii/libogc/libwiikeyboard/usbkeyboard.c @@ -0,0 +1,495 @@ +/*------------------------------------------------------------- + +usbkeyboard.c -- Usb keyboard support(boot protocol) + +Copyright (C) 2008, 2009 +DAVY Guillaume davyg2@gmail.com +dhewg + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#include +#include + +#include +#include + +#include + +#define HEAP_SIZE 4096 +#define DEVLIST_MAXSIZE 8 +#define KEY_ERROR 0x01 +#define MAXKEYCODE 6 + +#define USB_MOD_CTRL_L 0x01 +#define USB_MOD_SHIFT_L 0x02 +#define USB_MOD_ALT_L 0x04 +#define USB_MOD_META_L 0x08 +#define USB_MOD_CTRL_R 0x10 +#define USB_MOD_SHIFT_R 0x20 +#define USB_MOD_ALT_R 0x40 +#define USB_MOD_META_R 0x80 + +struct ukbd_data { + u16 modifiers; + u8 keycode[MAXKEYCODE]; +} ATTRIBUTE_PACKED; + +struct ukbd { + bool connected; + + s32 fd; + + struct ukbd_data sc_ndata; + struct ukbd_data sc_odata; + + u8 leds; + + eventcallback cb; + + u8 configuration; + u32 interface; + u32 altInterface; + + u8 ep; + u32 ep_size; +}; + +static s32 hId = -1; +static struct ukbd *_kbd = NULL; + +static u8 _ukbd_mod_map[][2] = { + { USB_MOD_CTRL_L, 224 }, + { USB_MOD_SHIFT_L, 225 }, + { USB_MOD_ALT_L, 226 }, + { USB_MOD_META_L, 227 }, + { USB_MOD_CTRL_R, 228 }, + { USB_MOD_SHIFT_R, 229 }, + { USB_MOD_ALT_R, 230 }, + { USB_MOD_META_R, 231 } +}; + +#define MODMAPSIZE (sizeof(_ukbd_mod_map)/sizeof(_ukbd_mod_map[0])) + +static void _submit(USBKeyboard_eventType type, u8 code) +{ + if (!_kbd->cb) + return; + + USBKeyboard_event ev; + ev.type = type; + ev.keyCode = code; + + _kbd->cb(ev); +} + +//Callback when the keyboard is disconnected +static s32 _disconnect(s32 retval, void *data) +{ + (void) data; + + _kbd->connected = false; + + _submit(USBKEYBOARD_DISCONNECTED, 0); + + return 1; +} + +//Get the protocol, 0=boot protocol and 1=report protocol +static s32 _get_protocol(void) +{ + s32 protocol; + u8 *buffer = 0; + + if(!_kbd || _kbd->fd==-1) return -1; + + buffer = iosAlloc(hId, 1); + + if (buffer == NULL) + return -1; + + USB_WriteCtrlMsg(_kbd->fd, USB_REQTYPE_INTERFACE_GET, USB_REQ_GETPROTOCOL, 0, _kbd->interface, 1, buffer); + + protocol = *buffer; + iosFree(hId, buffer); + + return protocol; +} + +//Modify the protocol, 0=boot protocol and 1=report protocol +static s32 _set_protocol(u8 protocol) +{ + if(!_kbd || _kbd->fd==-1) return -1; + return USB_WriteCtrlMsg(_kbd->fd, USB_REQTYPE_INTERFACE_SET, USB_REQ_SETPROTOCOL, protocol, _kbd->interface, 0, NULL); +} + +//Get an input report from interrupt pipe +static s32 _get_input_report(void) +{ + u8 *buffer = 0; + + if(!_kbd || _kbd->fd==-1) return -1; + buffer = iosAlloc(hId, 8); + + if (buffer == NULL) + return -1; + + s32 ret = USB_ReadIntrMsg(_kbd->fd, _kbd->ep, 8, buffer); + + memcpy(&_kbd->sc_ndata, buffer, 8); + iosFree(hId, buffer); + + _kbd->sc_ndata.modifiers = (_kbd->sc_ndata.modifiers << 8) | (_kbd->sc_ndata.modifiers >> 8); + + return ret; +} + +#if 0 +//Get an input report from control pipe +static s32 _get_output_report(u8 *leds) +{ + u8 *buffer = 0; + if(!_kbd || _kbd->fd==-1) return -1; + buffer = iosAlloc(hId, 1); + + if (buffer == NULL) + return -1; + + s32 ret = USB_WriteCtrlMsg(_kbd->fd, USB_REQTYPE_INTERFACE_GET, USB_REQ_GETREPORT, USB_REPTYPE_OUTPUT << 8, _kbd->interface, 1, buffer); + + memcpy(leds, buffer, 1); + iosFree(hId, buffer); + + return ret; +} +#endif + +//Set an input report to control pipe +static s32 _set_output_report(void) +{ + u8 *buffer = 0; + if(!_kbd || _kbd->fd==-1) return -1; + buffer = iosAlloc(hId, 1); + + if (buffer == NULL) + return -1; + + memcpy(buffer, &_kbd->leds, 1); + s32 ret = USB_WriteCtrlMsg(_kbd->fd, USB_REQTYPE_INTERFACE_SET, USB_REQ_SETREPORT, USB_REPTYPE_OUTPUT << 8, _kbd->interface, 1, buffer); + + iosFree(hId, buffer); + + return ret; +} + +//init the ioheap +s32 USBKeyboard_Initialize(void) +{ + if (hId > 0) + return 0; + + hId = iosCreateHeap(HEAP_SIZE); + + if (hId < 0) + return IPC_ENOHEAP; + + return IPC_OK; +} + +s32 USBKeyboard_Deinitialize(void) +{ + return IPC_OK; +} + +//Search for a keyboard connected to the wii usb port +//Thanks to Sven Peter usbstorage support +s32 USBKeyboard_Open(const eventcallback cb) +{ + usb_device_entry *buffer; + u8 device_count, i, conf; + u16 vid, pid; + bool found = false; + u32 iConf, iInterface, iEp; + usb_devdesc udd; + usb_configurationdesc *ucd; + usb_interfacedesc *uid; + usb_endpointdesc *ued; + + buffer = (usb_device_entry*)iosAlloc(hId, DEVLIST_MAXSIZE * sizeof(usb_device_entry)); + if(buffer == NULL) + return -1; + + memset(buffer, 0, DEVLIST_MAXSIZE * sizeof(usb_device_entry)); + + if (USB_GetDeviceList(buffer, DEVLIST_MAXSIZE, USB_CLASS_HID, &device_count) < 0) + { + iosFree(hId, buffer); + return -2; + } + + if (_kbd) { + if (_kbd->fd != -1) USB_CloseDevice(&_kbd->fd); + } else { + _kbd = (struct ukbd *) malloc(sizeof(struct ukbd)); + + if (!_kbd) + return -1; + } + + memset(_kbd, 0, sizeof(struct ukbd)); + _kbd->fd = -1; + + for (i = 0; i < device_count; i++) + { + vid = buffer[i].vid;; + pid = buffer[i].pid; + + if ((vid == 0) || (pid == 0)) + continue; + + s32 fd = 0; + if (USB_OpenDevice(buffer[i].device_id, vid, pid, &fd) < 0) + continue; + + if (USB_GetDescriptors(fd, &udd) < 0) { + USB_CloseDevice(&fd); + continue; + } + + for(iConf = 0; iConf < udd.bNumConfigurations; iConf++) + { + ucd = &udd.configurations[iConf]; + + for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) + { + uid = &ucd->interfaces[iInterface]; + + if ((uid->bInterfaceClass == USB_CLASS_HID) && + (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) && + (uid->bInterfaceProtocol== USB_PROTOCOL_KEYBOARD)) + { + for(iEp = 0; iEp < uid->bNumEndpoints; iEp++) + { + ued = &uid->endpoints[iEp]; + + if (ued->bmAttributes != USB_ENDPOINT_INTERRUPT) + continue; + + if (!(ued->bEndpointAddress & USB_ENDPOINT_IN)) + continue; + + _kbd->fd = fd; + _kbd->cb = cb; + + _kbd->configuration = ucd->bConfigurationValue; + _kbd->interface = uid->bInterfaceNumber; + _kbd->altInterface = uid->bAlternateSetting; + + _kbd->ep = ued->bEndpointAddress; + _kbd->ep_size = ued->wMaxPacketSize; + + found = true; + + break; + } + } + + if (found) + break; + } + + if (found) + break; + } + + USB_FreeDescriptors(&udd); + + if (found) + break; + else + USB_CloseDevice(&fd); + } + + iosFree(hId, buffer); + + if (!found) + return -3; + + if (USB_GetConfiguration(_kbd->fd, &conf) < 0) + { + USBKeyboard_Close(); + return -4; + } + + if (conf != _kbd->configuration && + USB_SetConfiguration(_kbd->fd, _kbd->configuration) < 0) + { + USBKeyboard_Close(); + return -5; + } + + if (_kbd->altInterface != 0 && + USB_SetAlternativeInterface(_kbd->fd, _kbd->interface, _kbd->altInterface) < 0) + { + USBKeyboard_Close(); + return -6; + } + + if (_get_protocol() != 0) + { + if (_set_protocol(0) < 0) + { + USBKeyboard_Close(); + return -6; + } + + if (_get_protocol() == 1) + { + USBKeyboard_Close(); + return -7; + } + } + + if (USB_DeviceRemovalNotifyAsync(_kbd->fd, &_disconnect, NULL) < 0) + { + USBKeyboard_Close(); + return -8; + } + + _kbd->connected = true; + + return 1; +} + +//Close the device +void USBKeyboard_Close(void) +{ + if (!_kbd) + return; + + if(_kbd->fd != -1) + USB_CloseDevice(&_kbd->fd); + + free(_kbd); + _kbd = NULL; + + return; +} + +bool USBKeyboard_IsConnected(void) { + if (!_kbd) + return false; + + return _kbd->connected; +} + +//Scan for key presses and generate events for the callback function +s32 USBKeyboard_Scan(void) +{ + int i, j, index; + + if (!_kbd) + return -1; + + if (_get_input_report() < 0) + return -2; + + if (_kbd->sc_ndata.keycode[0] == KEY_ERROR) + return 0; + + if (_kbd->sc_ndata.modifiers != _kbd->sc_odata.modifiers) { + for (i = 0; i < MODMAPSIZE; ++i) { + if ((_kbd->sc_odata.modifiers & _ukbd_mod_map[i][0]) + && !(_kbd->sc_ndata.modifiers & _ukbd_mod_map[i][0])) + _submit(USBKEYBOARD_RELEASED, _ukbd_mod_map[i][1]); + else if ((_kbd->sc_ndata.modifiers & _ukbd_mod_map[i][0]) + && !(_kbd->sc_odata.modifiers & _ukbd_mod_map[i][0])) + _submit(USBKEYBOARD_PRESSED, _ukbd_mod_map[i][1]); + } + } + + for (i = 0; i < MAXKEYCODE; i++) { + if (_kbd->sc_odata.keycode[i] > 3) { + index = -1; + + for (j = 0; j < MAXKEYCODE; j++) { + if (_kbd->sc_odata.keycode[i] == _kbd->sc_ndata.keycode[j]) { + index = j; + break; + } + } + + if (index == -1) + _submit(USBKEYBOARD_RELEASED, _kbd->sc_odata.keycode[i]); + } + + if (_kbd->sc_ndata.keycode[i] > 3) { + index = -1; + + for (j = 0; j < MAXKEYCODE; j++) { + if (_kbd->sc_ndata.keycode[i] == _kbd->sc_odata.keycode[j]) { + index = j; + break; + } + } + + if (index == -1) + _submit(USBKEYBOARD_PRESSED, _kbd->sc_ndata.keycode[i]); + } + } + + _kbd->sc_odata = _kbd->sc_ndata; + + return 0; +} + +//Turn on/off a led +s32 USBKeyboard_SetLed(const USBKeyboard_led led, bool on) +{ + if (!_kbd) + return -1; + + if (on) + _kbd->leds = _kbd->leds | (1 << led ); + else + _kbd->leds = _kbd->leds & (255 ^ (1 << led)); + + if (_set_output_report() < 0) + return -2; + + return 1; +} + +//Toggle a led +s32 USBKeyboard_ToggleLed(const USBKeyboard_led led) +{ + if (!_kbd) + return -1; + + _kbd->leds = _kbd->leds ^ (1 << led); + + if (_set_output_report() < 0) + return -2; + + return 1; +} + diff --git a/wii/libogc/libwiikeyboard/wskbdutil.c b/wii/libogc/libwiikeyboard/wskbdutil.c new file mode 100644 index 0000000000..8ed2495afc --- /dev/null +++ b/wii/libogc/libwiikeyboard/wskbdutil.c @@ -0,0 +1,492 @@ +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#include +#include +#include +#include +#include + +#include + +#include "wsksymvar.h" + +static struct compose_tab_s { + keysym_t elem[2]; + keysym_t result; +} compose_tab[] = { + { { KS_plus, KS_plus }, KS_numbersign }, + { { KS_a, KS_a }, KS_at }, + { { KS_parenleft, KS_parenleft }, KS_bracketleft }, + { { KS_slash, KS_slash }, KS_backslash }, + { { KS_parenright, KS_parenright }, KS_bracketright }, + { { KS_parenleft, KS_minus }, KS_braceleft }, + { { KS_slash, KS_minus }, KS_bar }, + { { KS_parenright, KS_minus }, KS_braceright }, + { { KS_exclam, KS_exclam }, KS_exclamdown }, + { { KS_c, KS_slash }, KS_cent }, + { { KS_l, KS_minus }, KS_sterling }, + { { KS_y, KS_minus }, KS_yen }, + { { KS_s, KS_o }, KS_section }, + { { KS_x, KS_o }, KS_currency }, + { { KS_c, KS_o }, KS_copyright }, + { { KS_less, KS_less }, KS_guillemotleft }, + { { KS_greater, KS_greater }, KS_guillemotright }, + { { KS_question, KS_question }, KS_questiondown }, + { { KS_dead_acute, KS_space }, KS_apostrophe }, + { { KS_dead_grave, KS_space }, KS_grave }, + { { KS_dead_tilde, KS_space }, KS_asciitilde }, + { { KS_dead_circumflex, KS_space }, KS_asciicircum }, + { { KS_dead_diaeresis, KS_space }, KS_quotedbl }, + { { KS_dead_cedilla, KS_space }, KS_comma }, + { { KS_dead_circumflex, KS_A }, KS_Acircumflex }, + { { KS_dead_diaeresis, KS_A }, KS_Adiaeresis }, + { { KS_dead_grave, KS_A }, KS_Agrave }, + { { KS_dead_abovering, KS_A }, KS_Aring }, + { { KS_dead_tilde, KS_A }, KS_Atilde }, + { { KS_dead_cedilla, KS_C }, KS_Ccedilla }, + { { KS_dead_acute, KS_E }, KS_Eacute }, + { { KS_dead_circumflex, KS_E }, KS_Ecircumflex }, + { { KS_dead_diaeresis, KS_E }, KS_Ediaeresis }, + { { KS_dead_grave, KS_E }, KS_Egrave }, + { { KS_dead_acute, KS_I }, KS_Iacute }, + { { KS_dead_circumflex, KS_I }, KS_Icircumflex }, + { { KS_dead_diaeresis, KS_I }, KS_Idiaeresis }, + { { KS_dead_grave, KS_I }, KS_Igrave }, + { { KS_dead_tilde, KS_N }, KS_Ntilde }, + { { KS_dead_acute, KS_O }, KS_Oacute }, + { { KS_dead_circumflex, KS_O }, KS_Ocircumflex }, + { { KS_dead_diaeresis, KS_O }, KS_Odiaeresis }, + { { KS_dead_grave, KS_O }, KS_Ograve }, + { { KS_dead_tilde, KS_O }, KS_Otilde }, + { { KS_dead_acute, KS_U }, KS_Uacute }, + { { KS_dead_circumflex, KS_U }, KS_Ucircumflex }, + { { KS_dead_diaeresis, KS_U }, KS_Udiaeresis }, + { { KS_dead_grave, KS_U }, KS_Ugrave }, + { { KS_dead_acute, KS_Y }, KS_Yacute }, + { { KS_dead_acute, KS_a }, KS_aacute }, + { { KS_dead_circumflex, KS_a }, KS_acircumflex }, + { { KS_dead_diaeresis, KS_a }, KS_adiaeresis }, + { { KS_dead_grave, KS_a }, KS_agrave }, + { { KS_dead_abovering, KS_a }, KS_aring }, + { { KS_dead_tilde, KS_a }, KS_atilde }, + { { KS_dead_cedilla, KS_c }, KS_ccedilla }, + { { KS_dead_acute, KS_e }, KS_eacute }, + { { KS_dead_circumflex, KS_e }, KS_ecircumflex }, + { { KS_dead_diaeresis, KS_e }, KS_ediaeresis }, + { { KS_dead_grave, KS_e }, KS_egrave }, + { { KS_dead_acute, KS_i }, KS_iacute }, + { { KS_dead_circumflex, KS_i }, KS_icircumflex }, + { { KS_dead_diaeresis, KS_i }, KS_idiaeresis }, + { { KS_dead_grave, KS_i }, KS_igrave }, + { { KS_dead_tilde, KS_n }, KS_ntilde }, + { { KS_dead_acute, KS_o }, KS_oacute }, + { { KS_dead_circumflex, KS_o }, KS_ocircumflex }, + { { KS_dead_diaeresis, KS_o }, KS_odiaeresis }, + { { KS_dead_grave, KS_o }, KS_ograve }, + { { KS_dead_tilde, KS_o }, KS_otilde }, + { { KS_dead_acute, KS_u }, KS_uacute }, + { { KS_dead_circumflex, KS_u }, KS_ucircumflex }, + { { KS_dead_diaeresis, KS_u }, KS_udiaeresis }, + { { KS_dead_grave, KS_u }, KS_ugrave }, + { { KS_dead_acute, KS_y }, KS_yacute }, + { { KS_dead_diaeresis, KS_y }, KS_ydiaeresis }, + { { KS_quotedbl, KS_A }, KS_Adiaeresis }, + { { KS_quotedbl, KS_E }, KS_Ediaeresis }, + { { KS_quotedbl, KS_I }, KS_Idiaeresis }, + { { KS_quotedbl, KS_O }, KS_Odiaeresis }, + { { KS_quotedbl, KS_U }, KS_Udiaeresis }, + { { KS_quotedbl, KS_a }, KS_adiaeresis }, + { { KS_quotedbl, KS_e }, KS_ediaeresis }, + { { KS_quotedbl, KS_i }, KS_idiaeresis }, + { { KS_quotedbl, KS_o }, KS_odiaeresis }, + { { KS_quotedbl, KS_u }, KS_udiaeresis }, + { { KS_quotedbl, KS_y }, KS_ydiaeresis }, + { { KS_acute, KS_A }, KS_Aacute }, + { { KS_asciicircum, KS_A }, KS_Acircumflex }, + { { KS_grave, KS_A }, KS_Agrave }, + { { KS_asterisk, KS_A }, KS_Aring }, + { { KS_asciitilde, KS_A }, KS_Atilde }, + { { KS_cedilla, KS_C }, KS_Ccedilla }, + { { KS_acute, KS_E }, KS_Eacute }, + { { KS_asciicircum, KS_E }, KS_Ecircumflex }, + { { KS_grave, KS_E }, KS_Egrave }, + { { KS_acute, KS_I }, KS_Iacute }, + { { KS_asciicircum, KS_I }, KS_Icircumflex }, + { { KS_grave, KS_I }, KS_Igrave }, + { { KS_asciitilde, KS_N }, KS_Ntilde }, + { { KS_acute, KS_O }, KS_Oacute }, + { { KS_asciicircum, KS_O }, KS_Ocircumflex }, + { { KS_grave, KS_O }, KS_Ograve }, + { { KS_asciitilde, KS_O }, KS_Otilde }, + { { KS_acute, KS_U }, KS_Uacute }, + { { KS_asciicircum, KS_U }, KS_Ucircumflex }, + { { KS_grave, KS_U }, KS_Ugrave }, + { { KS_acute, KS_Y }, KS_Yacute }, + { { KS_acute, KS_a }, KS_aacute }, + { { KS_asciicircum, KS_a }, KS_acircumflex }, + { { KS_grave, KS_a }, KS_agrave }, + { { KS_asterisk, KS_a }, KS_aring }, + { { KS_asciitilde, KS_a }, KS_atilde }, + { { KS_cedilla, KS_c }, KS_ccedilla }, + { { KS_acute, KS_e }, KS_eacute }, + { { KS_asciicircum, KS_e }, KS_ecircumflex }, + { { KS_grave, KS_e }, KS_egrave }, + { { KS_acute, KS_i }, KS_iacute }, + { { KS_asciicircum, KS_i }, KS_icircumflex }, + { { KS_grave, KS_i }, KS_igrave }, + { { KS_asciitilde, KS_n }, KS_ntilde }, + { { KS_acute, KS_o }, KS_oacute }, + { { KS_asciicircum, KS_o }, KS_ocircumflex }, + { { KS_grave, KS_o }, KS_ograve }, + { { KS_asciitilde, KS_o }, KS_otilde }, + { { KS_acute, KS_u }, KS_uacute }, + { { KS_asciicircum, KS_u }, KS_ucircumflex }, + { { KS_grave, KS_u }, KS_ugrave }, + { { KS_acute, KS_y }, KS_yacute } +}; + +#define COMPOSE_SIZE sizeof(compose_tab)/sizeof(compose_tab[0]) + +static int compose_tab_inorder = 0; + +inline int compose_tab_cmp(struct compose_tab_s *, + struct compose_tab_s *); +keysym_t ksym_upcase(keysym_t); +void fillmapentry(const keysym_t *, int, struct wscons_keymap *); + +inline int +compose_tab_cmp(i, j) + struct compose_tab_s *i, *j; +{ + if (i->elem[0] == j->elem[0]) + return(i->elem[1] - j->elem[1]); + else + return(i->elem[0] - j->elem[0]); +} + +keysym_t +wskbd_compose_value(compose_buf) + keysym_t *compose_buf; +{ + int i, j, r; + struct compose_tab_s v; + + if (! compose_tab_inorder) { + /* Insertion sort. */ + for (i = 1; i < COMPOSE_SIZE; i++) { + v = compose_tab[i]; + /* find correct slot, moving others up */ + for (j = i; --j >= 0 && compose_tab_cmp(& v, & compose_tab[j]) < 0; ) + compose_tab[j + 1] = compose_tab[j]; + compose_tab[j + 1] = v; + } + compose_tab_inorder = 1; + } + + for (j = 0, i = COMPOSE_SIZE; i != 0; i /= 2) { + if (compose_tab[j + i/2].elem[0] == compose_buf[0]) { + if (compose_tab[j + i/2].elem[1] == compose_buf[1]) + return(compose_tab[j + i/2].result); + r = compose_tab[j + i/2].elem[1] < compose_buf[1]; + } else + r = compose_tab[j + i/2].elem[0] < compose_buf[0]; + if (r) { + j += i/2 + 1; + i--; + } + } + + return(KS_voidSymbol); +} + +static const u_char latin1_to_upper[256] = { +/* 0 8 1 9 2 a 3 b 4 c 5 d 6 e 7 f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 4 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 4 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5 */ + 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 6 */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 6 */ + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 7 */ + 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* e */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* e */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0x00, /* f */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* f */ +}; + +keysym_t +ksym_upcase(ksym) + keysym_t ksym; +{ + if (ksym >= KS_f1 && ksym <= KS_f20) + return(KS_F1 - KS_f1 + ksym); + + if (KS_GROUP(ksym) == KS_GROUP_Ascii && ksym <= 0xff && + latin1_to_upper[ksym] != 0x00) + return(latin1_to_upper[ksym]); + + return(ksym); +} + +void +fillmapentry(kp, len, mapentry) + const keysym_t *kp; + int len; + struct wscons_keymap *mapentry; +{ + switch (len) { + case 0: + mapentry->group1[0] = KS_voidSymbol; + mapentry->group1[1] = KS_voidSymbol; + mapentry->group2[0] = KS_voidSymbol; + mapentry->group2[1] = KS_voidSymbol; + break; + + case 1: + mapentry->group1[0] = kp[0]; + mapentry->group1[1] = ksym_upcase(kp[0]); + mapentry->group2[0] = mapentry->group1[0]; + mapentry->group2[1] = mapentry->group1[1]; + break; + + case 2: + mapentry->group1[0] = kp[0]; + mapentry->group1[1] = kp[1]; + mapentry->group2[0] = mapentry->group1[0]; + mapentry->group2[1] = mapentry->group1[1]; + break; + + case 3: + mapentry->group1[0] = kp[0]; + mapentry->group1[1] = kp[1]; + mapentry->group2[0] = kp[2]; + mapentry->group2[1] = ksym_upcase(kp[2]); + break; + + case 4: + mapentry->group1[0] = kp[0]; + mapentry->group1[1] = kp[1]; + mapentry->group2[0] = kp[2]; + mapentry->group2[1] = kp[3]; + break; + + } +} + +void +wskbd_get_mapentry(mapdata, kc, mapentry) + const struct wskbd_mapdata *mapdata; + int kc; + struct wscons_keymap *mapentry; +{ + kbd_t cur; + const keysym_t *kp; + const struct wscons_keydesc *mp; + int l; + keysym_t ksg; + + mapentry->command = KS_voidSymbol; + mapentry->group1[0] = KS_voidSymbol; + mapentry->group1[1] = KS_voidSymbol; + mapentry->group2[0] = KS_voidSymbol; + mapentry->group2[1] = KS_voidSymbol; + + for (cur = mapdata->layout & ~KB_HANDLEDBYWSKBD; cur != 0; ) { + mp = mapdata->keydesc; + while (mp->map_size > 0) { + if (mp->name == cur) + break; + mp++; + } + + /* If map not found, return */ + if (mp->map_size <= 0) + return; + + for (kp = mp->map; kp < mp->map + mp->map_size; kp++) { + ksg = KS_GROUP(*kp); + if (ksg == KS_GROUP_Keycode && + KS_VALUE(*kp) == kc) { + /* First skip keycode and possible command */ + kp++; + if (KS_GROUP(*kp) == KS_GROUP_Command || + *kp == KS_Cmd || *kp == KS_Cmd1 || *kp == KS_Cmd2) + mapentry->command = *kp++; + + for (l = 0; kp + l < mp->map + mp->map_size; + l++) { + ksg = KS_GROUP(kp[l]); + if (ksg == KS_GROUP_Keycode) + break; + } + if (l > 4) { + fprintf(stderr, "wskbd_get_mapentry: %lu(%d): bad entry", + mp->name, *kp); + return; + } + fillmapentry(kp, l, mapentry); + return; + } + } + + cur = mp->base; + } +} + +void +wskbd_init_keymap(newlen, map, maplen) + int newlen; + struct wscons_keymap **map; + int *maplen; +{ + int i; + + if (newlen != *maplen) { + if (*maplen > 0) + free(*map); + *maplen = newlen; + *map = malloc(newlen*sizeof(struct wscons_keymap)); + } + + for (i = 0; i < *maplen; i++) { + (*map)[i].command = KS_voidSymbol; + (*map)[i].group1[0] = KS_voidSymbol; + (*map)[i].group1[1] = KS_voidSymbol; + (*map)[i].group2[0] = KS_voidSymbol; + (*map)[i].group2[1] = KS_voidSymbol; + } +} + +int +wskbd_load_keymap(mapdata, map, maplen) + const struct wskbd_mapdata *mapdata; + struct wscons_keymap **map; + int *maplen; +{ + int i, s, kc, stack_ptr; + const keysym_t *kp; + const struct wscons_keydesc *mp, *stack[10]; + kbd_t cur; + keysym_t ksg; + + for (cur = mapdata->layout & ~KB_HANDLEDBYWSKBD, stack_ptr = 0; + cur != 0; stack_ptr++) { + mp = mapdata->keydesc; + while (mp->map_size > 0) { + if (cur == 0 || mp->name == cur) { + break; + } + mp++; + } + + if (stack_ptr == sizeof(stack)/sizeof(stack[0])) { + fprintf(stderr, "wskbd_load_keymap: %lu: recursion too deep", + mapdata->layout); + return(EINVAL); + } + + if (mp->map_size <= 0) + return(EINVAL); + + stack[stack_ptr] = mp; + cur = mp->base; + } + + for (i = 0, s = stack_ptr - 1; s >= 0; s--) { + mp = stack[s]; + for (kp = mp->map; kp < mp->map + mp->map_size; kp++) { + ksg = KS_GROUP(*kp); + if (ksg == KS_GROUP_Keycode && KS_VALUE(*kp) > i) + i = KS_VALUE(*kp); + } + } + + wskbd_init_keymap(i + 1, map, maplen); + + for (s = stack_ptr - 1; s >= 0; s--) { + mp = stack[s]; + for (kp = mp->map; kp < mp->map + mp->map_size; ) { + ksg = KS_GROUP(*kp); + if (ksg != KS_GROUP_Keycode) { + fprintf(stderr, "wskbd_load_keymap: %lu(%d): bad entry", + mp->name, *kp); + return(EINVAL); + } + + kc = KS_VALUE(*kp); + kp++; + + if (KS_GROUP(*kp) == KS_GROUP_Command || + *kp == KS_Cmd || *kp == KS_Cmd1 || *kp == KS_Cmd2) { + (*map)[kc].command = *kp; + kp++; + } + + for (i = 0; kp + i < mp->map + mp->map_size; i++) { + ksg = KS_GROUP(kp[i]); + if (ksg == KS_GROUP_Keycode) + break; + } + + if (i > 4) { + fprintf(stderr, "wskbd_load_keymap: %lu(%d): bad entry", + mp->name, *kp); + return(EINVAL); + } + + fillmapentry(kp, i, &(*map)[kc]); + kp += i; + } + } + + return(0); +} diff --git a/wii/libogc/libwiikeyboard/wsksymvar.h b/wii/libogc/libwiikeyboard/wsksymvar.h new file mode 100644 index 0000000000..0bf10d3466 --- /dev/null +++ b/wii/libogc/libwiikeyboard/wsksymvar.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 _DEV_WSCONS_WSKSYMVAR_H_ +#define _DEV_WSCONS_WSKSYMVAR_H_ + +#include + +typedef u16 keysym_t; +typedef u32 kbd_t; + +struct wscons_keymap { + keysym_t command; + keysym_t group1[2]; + keysym_t group2[2]; +}; + +struct wscons_keydesc { + kbd_t name; /* name of this map */ + kbd_t base; /* map this one is based on */ + int map_size; /* size of map */ + const keysym_t *map; /* the map itself */ +}; + +struct wskbd_mapdata { + const struct wscons_keydesc *keydesc; + kbd_t layout; +}; + +/* layout variant bits ignored by mapping code */ +#define KB_HANDLEDBYWSKBD KB_METAESC + +/* + * Utility functions. + */ +void wskbd_get_mapentry(const struct wskbd_mapdata *, int, + struct wscons_keymap *); +void wskbd_init_keymap(int, struct wscons_keymap **, int *); +int wskbd_load_keymap(const struct wskbd_mapdata *, + struct wscons_keymap **, int *); +keysym_t wskbd_compose_value(keysym_t *); + +#endif /* !_DEV_WSCONS_WSKSYMVAR_H_ */ diff --git a/wii/libogc/lwbt/bt.h b/wii/libogc/lwbt/bt.h new file mode 100644 index 0000000000..d0ed63af8e --- /dev/null +++ b/wii/libogc/lwbt/bt.h @@ -0,0 +1,119 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * Header file for the uIP TCP/IP stack. + * \author Adam Dunkels + * + * The uIP TCP/IP stack header file contains definitions for a number + * of C macros that are used by uIP programs as well as internal uIP + * structures, TCP/IP header structures and function declarations. + * + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + +#ifndef __BT_H__ +#define __BT_H__ + +#include "btopt.h" +#include "btarch.h" + +#define ERR_OK 0 +#define ERR_MEM -1 +#define ERR_BUF -2 +#define ERR_ABRT -3 +#define ERR_RST -4 +#define ERR_CLSD -5 +#define ERR_CONN -6 +#define ERR_VAL -7 +#define ERR_ARG -8 +#define ERR_RTE -9 +#define ERR_USE -10 +#define ERR_IF -11 +#define ERR_PKTSIZE -17 + +#define PROTO_ICMP 1 +#define PROTO_TCP 6 +#define PROTO_UDP 17 + +/* Headezes. */ +#define IP_HLEN 20 /* Size of IP header */ +#define TRANSPORT_HLEN 20 + +#define UDP_HLEN 8 /* Size of UDP header */ +#define TCP_HLEN 20 /* Size of TCP header */ +#define IPUDP_HLEN 28 /* Size of IP + UDP header */ +#define IPTCP_HLEN 40 /* Size of IP + TCP header */ + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This macro is primarily used for converting constants from host + * byte order to network byte order. For converting variables to + * network byte order, use the htons() function instead. + * + * \hideinitializer + */ +#ifndef HTONS +# if BYTE_ORDER == BIG_ENDIAN +# define HTONS(n) (n) +# else /* BYTE_ORDER == BIG_ENDIAN */ +# define HTONS(n) ((((u16_t)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8)) +# endif /* BYTE_ORDER == BIG_ENDIAN */ +#endif /* HTONS */ + + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This function is primarily used for converting variables from host + * byte order to network byte order. For converting constants to + * network byte order, use the HTONS() macro instead. + */ +#ifndef htons +u16_t htons(u16_t val); +#endif /* htons */ + +/** @} */ + +#endif /* __UIP_H__ */ + + +/** @} */ + diff --git a/wii/libogc/lwbt/btarch.h b/wii/libogc/lwbt/btarch.h new file mode 100644 index 0000000000..7697f32b22 --- /dev/null +++ b/wii/libogc/lwbt/btarch.h @@ -0,0 +1,156 @@ +/** + * \defgroup uiparch Architecture specific uIP functions + * @{ + * + * The functions in the architecture specific module implement the IP + * check sum and 32-bit additions. + * + * The IP checksum calculation is the most computationally expensive + * operation in the TCP/IP stack and it therefore pays off to + * implement this in efficient assembler. The purpose of the uip-arch + * module is to let the checksum functions to be implemented in + * architecture specific assembler. + * + */ + +/** + * \file + * Declarations of architecture specific functions. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the lwBT stack. + * + * + */ + +#ifndef __BT_ARCH_H__ +#define __BT_ARCH_H__ + +#include "bt.h" +#include "asm.h" +#include "processor.h" + +#define MEM_ALIGNMENT 4 +#define MEM_ALIGN(mem) ((void*)(((u32_t)(mem)+MEM_ALIGNMENT-1)&~(u32_t)(MEM_ALIGNMENT-1))) +#define MEM_ALIGN_SIZE(size) (((size)+MEM_ALIGNMENT-1)&~(u32_t)(MEM_ALIGNMENT-1)) + + +#if BYTE_ORDER == BIG_ENDIAN + #ifndef htole16 + #define htole16 bswap16 + #endif + #ifndef htole32 + #define htole32 bswap32 + #endif + #ifndef htole64 + #define htole64 bswap64 + #endif + #ifndef le16toh + #define le16toh bswap16 + #endif + #ifndef le32toh + #define le32toh bswap32 + #endif + #ifndef le642toh + #define le64toh bswap64 + #endif + #ifndef htons + #define htons(x) (x) + #endif + #ifndef htonl + #define htonl(x) (x) + #endif + #ifndef ntohl + #define ntohl(x) (x) + #endif + #ifndef ntohs + #define ntohs(x) (x) + #endif +#else + #ifndef htole16 + #define htole16 + #endif + #ifndef htole32 + #define htole32 + #endif + #ifndef le16toh + #define le16toh + #endif + #ifndef le32toh + #define le32toh + #endif +#endif + +#if LIBC_MEMFUNCREPLACE +static __inline__ void __memcpy(void *dest,const void *src,s32_t len) +{ + u8_t *dest0 = (u8_t*)dest; + u8_t *src0 = (u8_t*)src; + + while(len--) { + *dest0++ = *src0++; + } +} + +static __inline__ void __memset(void *dest,s32_t c,s32_t len) +{ + u8_t *dest0 = (u8_t*)dest; + + while(len--) { + *dest0++ = (s8_t)c; + } +} + +#define MEMCPY __memcpy +#define MEMSET __memset +#else +#define MEMCPY memcpy +#define MEMSET memset +#endif + +#if LOGGING == 1 +#include +#define LOG(fmt, ...) fprintf(stderr, "[BTLOG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__) +#else +#define LOG(fmt, ...) +#endif /* LOGGING == 1 */ + +#if ERRORING == 1 +#include +#define ERROR(fmt,...) fprintf(stderr, "[BTERR] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__) +#else +#define ERROR(fmt, ...) +#endif /* ERRORING == 1 */ + +/** @} */ + +#endif /* __UIP_ARCH_H__ */ diff --git a/wii/libogc/lwbt/bte.c b/wii/libogc/lwbt/bte.c new file mode 100644 index 0000000000..f02bee003b --- /dev/null +++ b/wii/libogc/lwbt/bte.c @@ -0,0 +1,1361 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "bt.h" +#include "bte.h" +#include "hci.h" +#include "l2cap.h" +#include "btmemb.h" +#include "physbusif.h" + + +#define STACKSIZE 32768 +#define MQ_BOX_SIZE 256 + +/* Vendor specific OGF */ +#define HCI_VENDOR_OGF 0x3f + +/* Vendor specific OCF */ +#define HCI_VENDOR_PATCH_START_OCF 0x4f +#define HCI_VENDOR_PATCH_CONT_OCF 0x4c +#define HCI_VENDOR_PATCH_END_OCF 0x4f + +enum bte_state { + STATE_NOTREADY = -1, + STATE_READY = 0, + STATE_CONNECTING, + STATE_CONNECTED, + STATE_DISCONNECTING, + STATE_DISCONNECTED, + STATE_SENDING, + STATE_SENT, + STATE_RECEIVING, + STATE_RECEIVED, + STATE_FAILED +}; + +struct bt_state +{ + err_t last_err; + + syswd_t timer_svc; + lwpq_t hci_cmdq; + u8_t hci_cmddone; + u8_t hci_inited; + + u8_t num_maxdevs; + u8_t num_founddevs; + struct inquiry_info_ex *info; + + btecallback cb; + void *usrdata; +}; + +struct ctrl_req_t +{ + u8 err; + struct pbuf *p; + struct bte_pcb *pcb; + enum bte_state state; + s32 (*sent)(void *arg,struct bte_pcb *pcb,u8 err); + + struct ctrl_req_t *next; +}; + +static struct bt_state btstate; +static u8_t bte_patch0[184] = { + 0x70,0x99,0x08,0x00,0x88,0x43,0xd1,0x07,0x09,0x0c,0x08,0x43,0xa0,0x62,0x19,0x23, + 0xdb,0x01,0x33,0x80,0x7c,0xf7,0x88,0xf8,0x28,0x76,0x80,0xf7,0x17,0xff,0x43,0x78, + 0xeb,0x70,0x19,0x23,0xdb,0x01,0x33,0x87,0x7c,0xf7,0xbc,0xfb,0x0b,0x60,0xa3,0x7b, + 0x01,0x49,0x0b,0x60,0x90,0xf7,0x96,0xfb,0xd8,0x1d,0x08,0x00,0x00,0xf0,0x04,0xf8, + 0x00,0x23,0x79,0xf7,0xe3,0xfa,0x00,0x00,0x00,0xb5,0x00,0x23,0x11,0x49,0x0b,0x60, + 0x1d,0x21,0xc9,0x03,0x0b,0x60,0x7d,0x20,0x80,0x01,0x01,0x38,0xfd,0xd1,0x0e,0x4b, + 0x0e,0x4a,0x13,0x60,0x47,0x20,0x00,0x21,0x96,0xf7,0x96,0xff,0x46,0x20,0x00,0x21, + 0x96,0xf7,0x92,0xff,0x0a,0x4a,0x13,0x68,0x0a,0x48,0x03,0x40,0x13,0x60,0x0a,0x4a, + 0x13,0x68,0x0a,0x48,0x03,0x40,0x13,0x60,0x09,0x4a,0x13,0x68,0x09,0x48,0x03,0x40, + 0x13,0x60,0x00,0xbd,0x24,0x80,0x0e,0x00,0x81,0x03,0x0f,0xfe,0x5c,0x00,0x0f,0x00, + 0x60,0xfc,0x0e,0x00,0xfe,0xff,0x00,0x00,0xfc,0xfc,0x0e,0x00,0xff,0x9f,0x00,0x00, + 0x30,0xfc,0x0e,0x00,0x7f,0xff,0x00,0x00 +}; +static u8_t bte_patch1[92] = { + 0x07,0x20,0xbc,0x65,0x01,0x00,0x84,0x42,0x09,0xd2,0x84,0x42,0x09,0xd1,0x21,0x84, + 0x5a,0x00,0x00,0x83,0xf0,0x74,0xff,0x09,0x0c,0x08,0x43,0x22,0x00,0x61,0x00,0x00, + 0x83,0xf0,0x40,0xfc,0x00,0x00,0x00,0x00,0x23,0xcc,0x9f,0x01,0x00,0x6f,0xf0,0xe4, + 0xfc,0x03,0x28,0x7d,0xd1,0x24,0x3c,0x62,0x01,0x00,0x28,0x20,0x00,0xe0,0x60,0x8d, + 0x23,0x68,0x25,0x04,0x12,0x01,0x00,0x20,0x1c,0x20,0x1c,0x24,0xe0,0xb0,0x21,0x26, + 0x74,0x2f,0x00,0x00,0x86,0xf0,0x18,0xfd,0x21,0x4f,0x3b,0x60 +}; + +static u8 ppc_stack[STACKSIZE] ATTRIBUTE_ALIGN(8); + +err_t acl_wlp_completed(void *arg,struct bd_addr *bdaddr); +err_t link_key_not(void *arg,struct bd_addr *bdaddr,u8_t *key); +err_t pin_req(void *arg,struct bd_addr *bdaddr); +err_t l2cap_connected(void *arg,struct l2cap_pcb *l2cappcb,u16_t result,u16_t status); +err_t l2cap_accepted(void *arg,struct l2cap_pcb *l2cappcb,err_t err); +err_t acl_conn_complete(void *arg,struct bd_addr *bdaddr); +err_t l2cap_disconnect_cfm(void *arg, struct l2cap_pcb *pcb); +err_t l2cap_disconnected_ind(void *arg, struct l2cap_pcb *pcb, err_t err); + +err_t bte_input(void *arg,struct l2cap_pcb *pcb,struct pbuf *p,err_t err); +err_t bte_callback(void (*f)(void*),void *ctx); +err_t bte_hci_apply_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); +err_t bte_hci_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); +err_t bte_hci_initcore_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); +err_t bte_hci_initsub_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); +err_t bte_inquiry_complete(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result); +err_t bte_read_stored_link_key_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); +err_t bte_read_bd_addr_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); + + +MEMB(bte_pcbs,sizeof(struct bte_pcb),MEMP_NUM_BTE_PCB); +MEMB(bte_ctrl_reqs,sizeof(struct ctrl_req_t),MEMP_NUM_BTE_CTRLS); + +static void bte_reset_all() +{ + btmemb_init(&bte_pcbs); + btmemb_init(&bte_ctrl_reqs); + + if(btstate.info!=NULL) free(btstate.info); + + btstate.info = NULL; + btstate.hci_inited = 0; + btstate.hci_cmddone = 0; + btstate.num_founddevs = 0; + btstate.last_err = ERR_OK; +} + +static void bt_alarmhandler(syswd_t alarm,void *cbarg) +{ + __lwp_thread_dispatchdisable(); + SYS_SwitchFiber(0,0,0,0,(u32)l2cap_tmr,(u32)(&ppc_stack[STACKSIZE])); + __lwp_thread_dispatchunnest(); +} + +static inline s32 __bte_waitcmdfinish(struct bt_state *state) +{ + u32 level; + s32 ret; + + if(!state) return ERR_VAL; + + _CPU_ISR_Disable(level); + while(!state->hci_cmddone) + LWP_ThreadSleep(state->hci_cmdq); + ret = state->last_err; + _CPU_ISR_Restore(level); + + return ret; +} + +static inline s32 __bte_cmdfinish(struct bt_state *state,err_t err) +{ + u32 level; + + if(!state) return ERR_VAL; + + _CPU_ISR_Disable(level); + state->last_err = err; + state->hci_cmddone = 1; + if(state->cb!=NULL) + state->cb(err,state->usrdata); + else + LWP_ThreadSignal(state->hci_cmdq); + _CPU_ISR_Restore(level); + + return err; +} + +static inline s32 __bte_waitrequest(struct ctrl_req_t *req) +{ + s32 err; + u32 level; + + if(!req || !req->pcb) return ERR_VAL; + + _CPU_ISR_Disable(level); + while(req->state!=STATE_SENT + && req->state!=STATE_FAILED) + { + LWP_ThreadSleep(req->pcb->cmdq); + } + err = req->err; + _CPU_ISR_Restore(level); + + return err; +} + +static inline void __bte_close_ctrl_queue(struct bte_pcb *pcb) +{ + struct ctrl_req_t *req; + + while(pcb->ctrl_req_head!=NULL) { + req = pcb->ctrl_req_head; + req->err = ERR_CLSD; + req->state = STATE_DISCONNECTED; + if(req->sent!=NULL) { + req->sent(pcb->cbarg,pcb,ERR_CLSD); + btmemb_free(&bte_ctrl_reqs,req); + } else + LWP_ThreadSignal(pcb->cmdq); + + pcb->ctrl_req_head = req->next; + } + pcb->ctrl_req_tail = NULL; +} + +static s32 __bte_send_pending_request(struct bte_pcb *pcb) +{ + s32 err; + struct ctrl_req_t *req; + + if(pcb->ctrl_req_head==NULL) return ERR_OK; + if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; + + req = pcb->ctrl_req_head; + req->state = STATE_SENDING; + + err = l2ca_datawrite(pcb->ctl_pcb,req->p); + btpbuf_free(req->p); + + if(err!=ERR_OK) { + pcb->ctrl_req_head = req->next; + + req->err = err; + req->state = STATE_FAILED; + if(req->sent) { + req->sent(pcb->cbarg,pcb,err); + btmemb_free(&bte_ctrl_reqs,req); + } else + LWP_ThreadSignal(pcb->cmdq); + } + + return err; +} + +static s32 __bte_send_request(struct ctrl_req_t *req) +{ + s32 err; + u32 level; + + req->next = NULL; + req->err = ERR_VAL; + req->state = STATE_READY; + + _CPU_ISR_Disable(level); + if(req->pcb->ctrl_req_head==NULL) { + req->pcb->ctrl_req_head = req->pcb->ctrl_req_tail = req; + err = __bte_send_pending_request(req->pcb); + } else { + req->pcb->ctrl_req_tail->next = req; + req->pcb->ctrl_req_tail = req; + err = ERR_OK; + } + _CPU_ISR_Restore(level); + + return err; +} + +static err_t __bte_shutdown_finished(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + err_t err; + struct bt_state *state = (struct bt_state*)arg; + + if(state==NULL) return ERR_OK; + + state->hci_inited = 0; + hci_cmd_complete(NULL); + if(result==HCI_SUCCESS) + err = ERR_OK; + else + err = ERR_CONN; + + physbusif_close(); + return __bte_cmdfinish(state,err); +} + +static void bte_process_handshake(struct bte_pcb *pcb,u8_t param,void *buf,u16_t len) +{ + struct ctrl_req_t *req; + + LOG("bte_process_handshake(%p)\n",pcb); + + switch(param) { + case HIDP_HSHK_SUCCESSFULL: + req = pcb->ctrl_req_head; + pcb->ctrl_req_head = req->next; + + req->err = ERR_OK; + req->state = STATE_SENT; + if(req->sent) { + req->sent(pcb->cbarg,pcb,ERR_OK); + btmemb_free(&bte_ctrl_reqs,req); + } else + LWP_ThreadSignal(pcb->cmdq); + + __bte_send_pending_request(pcb); + break; + case HIDP_HSHK_NOTREADY: + case HIDP_HSHK_INV_REPORTID: + case HIDP_HSHK_NOTSUPPORTED: + case HIDP_HSHK_IVALIDPARAM: + case HIDP_HSHK_UNKNOWNERROR: + break; + case HIDP_HSHK_FATALERROR: + break; + default: + break; + } +} + +static void bte_process_data(struct bte_pcb *pcb,u8_t param,void *buf,u16_t len) +{ + LOG("bte_process_data(%p)\n",pcb); + switch(param) { + case HIDP_DATA_RTYPE_INPUT: + if(pcb->recv!=NULL) pcb->recv(pcb->cbarg,buf,len); + break; + case HIDP_DATA_RTYPE_OTHER: + case HIDP_DATA_RTYPE_OUPUT: + case HIDP_DATA_RTYPE_FEATURE: + break; + default: + break; + } +} + +static err_t bte_process_input(void *arg,struct l2cap_pcb *pcb,struct pbuf *p,err_t err) +{ + u8 *buf; + u16 len; + u8 hdr,type,param; + struct bte_pcb *bte = (struct bte_pcb*)arg; + + LOG("bte_process_input(%p,%p)\n",bte,p); + + if(bte->state==STATE_DISCONNECTING + || bte->state==STATE_DISCONNECTED) return ERR_CLSD; + + buf = p->payload; + len = p->tot_len; + + len--; + hdr = *buf++; + type = (hdr&HIDP_HDR_TRANS_MASK); + param = (hdr&HIDP_HDR_PARAM_MASK); + switch(type) { + case HIDP_TRANS_HANDSHAKE: + bte_process_handshake(bte,param,buf,len); + break; + case HIDP_TRANS_HIDCONTROL: + break; + case HIDP_TRANS_DATA: + bte_process_data(bte,param,buf,len); + break; + default: + break; + } + return ERR_OK; +} + +void BTE_Init() +{ + u32 level; + struct timespec tb; + + LOG("BTE_Init()\n"); + + memset(&btstate,0,sizeof(struct bt_state)); + + hci_init(); + l2cap_init(); + physbusif_init(); + + LWP_InitQueue(&btstate.hci_cmdq); + SYS_CreateAlarm(&btstate.timer_svc); + + _CPU_ISR_Disable(level); + bte_reset_all(); + hci_reset_all(); + l2cap_reset_all(); + physbusif_reset_all(); + + hci_wlp_complete(acl_wlp_completed); + hci_connection_complete(acl_conn_complete); + _CPU_ISR_Restore(level); + + tb.tv_sec = 1; + tb.tv_nsec = 0; + SYS_SetPeriodicAlarm(btstate.timer_svc,&tb,&tb,bt_alarmhandler, NULL); +} + +void BTE_Shutdown() +{ + u32 level; + + if(btstate.hci_inited==0) return; + + LOG("BTE_Shutdown()\n"); + + _CPU_ISR_Disable(level); + SYS_RemoveAlarm(btstate.timer_svc); + btstate.cb = NULL; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_cmd_complete(__bte_shutdown_finished); + hci_reset(); + __bte_waitcmdfinish(&btstate); + _CPU_ISR_Restore(level); + + physbusif_shutdown(); +} + +s32 BTE_InitCore(btecallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + btstate.cb = cb; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_cmd_complete(bte_hci_initcore_complete); + hci_reset(); + _CPU_ISR_Restore(level); + + return ERR_OK; +} + +s32 BTE_ApplyPatch(btecallback cb) +{ + u32 level; + u8 kick = 0; + + _CPU_ISR_Disable(level); + btstate.cb = cb; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_cmd_complete(bte_hci_apply_patch_complete); + hci_vendor_specific_command(HCI_VENDOR_PATCH_START_OCF,HCI_VENDOR_OGF,&kick,1); + _CPU_ISR_Restore(level); + + return ERR_OK; +} + +s32 BTE_InitSub(btecallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + btstate.cb = cb; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_cmd_complete(bte_hci_initsub_complete); + hci_write_inquiry_mode(0x01); + _CPU_ISR_Restore(level); + + return ERR_OK; +} + +s32 BTE_ReadStoredLinkKey(struct linkkey_info *keys,u8 max_cnt,btecallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + btstate.cb = cb; + btstate.usrdata = keys; + btstate.num_maxdevs = max_cnt; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_cmd_complete(bte_read_stored_link_key_complete); + hci_read_stored_link_key(); + _CPU_ISR_Restore(level); + + return ERR_OK; +} + +s32 BTE_ReadBdAddr(struct bd_addr *bdaddr, btecallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + btstate.cb = cb; + btstate.usrdata = bdaddr; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_cmd_complete(bte_read_bd_addr_complete); + hci_read_bd_addr(); + _CPU_ISR_Restore(level); + + return ERR_OK; +} + +void (*BTE_SetDisconnectCallback(void (*callback)(struct bd_addr *bdaddr,u8 reason)))(struct bd_addr *bdaddr,u8 reason) +{ + return l2cap_disconnect_bb(callback); +} + +struct bte_pcb* bte_new() +{ + struct bte_pcb *pcb; + + if((pcb=btmemb_alloc(&bte_pcbs))==NULL) return NULL; + + memset(pcb,0,sizeof(struct bte_pcb)); + + pcb->state = (u32)STATE_NOTREADY; + LWP_InitQueue(&(pcb->cmdq)); + + return pcb; +} + +s32 bte_registerdeviceasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) +{ + u32 level; + s32 err = ERR_OK; + struct l2cap_pcb *l2capcb = NULL; + + //printf("bte_registerdeviceasync()\n"); + _CPU_ISR_Disable(level); + pcb->err = ERR_USE; + pcb->data_pcb = NULL; + pcb->ctl_pcb = NULL; + pcb->conn_cfm = conn_cfm; + pcb->state = (u32)STATE_CONNECTING; + + bd_addr_set(&(pcb->bdaddr),bdaddr); + if((l2capcb=l2cap_new())==NULL) { + err = ERR_MEM; + goto error; + } + l2cap_arg(l2capcb,pcb); + + err = l2cap_connect_ind(l2capcb,bdaddr,HIDP_CONTROL_CHANNEL,l2cap_accepted); + if(err!=ERR_OK) { + l2cap_close(l2capcb); + err = ERR_CONN; + goto error; + } + + if((l2capcb=l2cap_new())==NULL) { + err = ERR_MEM; + goto error; + } + l2cap_arg(l2capcb,pcb); + + err = l2cap_connect_ind(l2capcb,bdaddr,HIDP_DATA_CHANNEL,l2cap_accepted); + if(err!=ERR_OK) { + l2cap_close(l2capcb); + err = ERR_CONN; + } + +error: + _CPU_ISR_Restore(level); + //printf("bte_registerdeviceasync(%02x)\n",err); + return err; +} + +s32 bte_inquiry(struct inquiry_info *info,u8 max_cnt,u8 flush) +{ + s32_t i; + u32 level,fnd; + err_t last_err; + struct inquiry_info_ex *pinfo; + + last_err = ERR_OK; + + _CPU_ISR_Disable(level); + if(btstate.num_founddevs==0 || flush==1) { + btstate.hci_cmddone = 0; + btstate.num_maxdevs = max_cnt; + hci_inquiry(0x009E8B33,0x03,max_cnt,bte_inquiry_complete); + last_err = __bte_waitcmdfinish(&btstate); + } + fnd = btstate.num_founddevs; + pinfo = btstate.info; + _CPU_ISR_Restore(level); + + if(last_err==ERR_OK) { + for(i=0;istate = (u32)STATE_DISCONNECTING; + if(pcb->data_pcb!=NULL ) + err = l2ca_disconnect_req(pcb->data_pcb,l2cap_disconnect_cfm); + else if(pcb->ctl_pcb!=NULL) + err = l2ca_disconnect_req(pcb->ctl_pcb,l2cap_disconnect_cfm); + _CPU_ISR_Restore(level); + + return err; +} + +/* +s32 bte_connect(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)) +{ + u32 level; + err_t err = ERR_OK; + + if(pcb==NULL) return ERR_VAL; + + if((pcb->l2capcb=l2cap_new())==NULL) return ERR_MEM; + + pcb->psm = psm; + pcb->recv = recv; + bd_addr_set(&(pcb->bdaddr),bdaddr); + + _CPU_ISR_Disable(level); + pcb->err = ERR_CONN; + l2cap_arg(pcb->l2capcb,pcb); + err = l2ca_connect_req(pcb->l2capcb,bdaddr,psm,HCI_ALLOW_ROLE_SWITCH,l2cap_connected); + if(err==ERR_OK) { + LWP_ThreadSleep(pcb->cmdq); + err = pcb->err; + } + _CPU_ISR_Restore(level); + + return err; +} + +s32 bte_connect_ex(struct bte_pcb *pcb,struct inquiry_info_ex *info,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)) +{ + err_t err; + + if((err=hci_reg_dev_info(&(info->bdaddr),info->cod,info->psrm,info->psm,info->co))!=ERR_OK) return err; + return bte_connect(pcb,&(info->bdaddr),psm,recv); +} + +s32 bte_listen(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm) +{ + s32 err; + u32 level; + struct l2cap_pcb *l2capcb = NULL; + + if(pcb==NULL) return ERR_VAL; + + if((l2capcb=l2cap_new())==NULL) return ERR_MEM; + pcb->l2capcb = NULL; + + pcb->psm = psm; + pcb->recv = NULL; + bd_addr_set(&(pcb->bdaddr),bdaddr); + + _CPU_ISR_Disable(level); + pcb->err = ERR_CONN; + l2cap_arg(l2capcb,pcb); + err = l2cap_connect_ind(l2capcb,psm,l2cap_accepted); + if(err!=ERR_OK) l2cap_close(l2capcb); + + _CPU_ISR_Restore(level); + return err; +} + +s32 bte_accept(struct bte_pcb *pcb,s32 (*recv)(void *arg,void *buffer,u16 len)) +{ + u32 level; + err_t err = ERR_OK; + + if(pcb==NULL) return ERR_VAL; + + _CPU_ISR_Disable(level); + pcb->recv = recv; + while(pcb->l2capcb==NULL) + LWP_ThreadSleep(pcb->cmdq); + err = pcb->err; + _CPU_ISR_Restore(level); + + return err; +} +*/ + +s32 bte_senddata(struct bte_pcb *pcb,void *message,u16 len) +{ + err_t err; + struct pbuf *p; + + if(pcb==NULL || message==NULL || len==0) return ERR_VAL; + if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; + + if((p=btpbuf_alloc(PBUF_RAW,(1 + len),PBUF_RAM))==NULL) { + ERROR("bte_senddata: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + ((u8*)p->payload)[0] = (HIDP_TRANS_DATA|HIDP_DATA_RTYPE_OUPUT); + memcpy(p->payload+1,message,len); + + err = l2ca_datawrite(pcb->data_pcb,p); + btpbuf_free(p); + + return err; +} + +s32 bte_sendmessageasync(struct bte_pcb *pcb,void *message,u16 len,s32 (*sent)(void *arg,struct bte_pcb *pcb,u8 err)) +{ + struct pbuf *p; + struct ctrl_req_t *req; + + //printf("bte_sendmessageasync()\n"); + + if(pcb==NULL || message==NULL || len==0) return ERR_VAL; + if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; + + if((req=btmemb_alloc(&bte_ctrl_reqs))==NULL) { + ERROR("bte_sendmessageasync: Could not allocate memory for request\n"); + return ERR_MEM; + } + + if((p=btpbuf_alloc(PBUF_RAW,(1 + len),PBUF_RAM))==NULL) { + ERROR("bte_sendmessageasync: Could not allocate memory for pbuf\n"); + btmemb_free(&bte_ctrl_reqs,req); + return ERR_MEM; + } + + ((u8*)p->payload)[0] = (HIDP_TRANS_SETREPORT|HIDP_DATA_RTYPE_OUPUT); + memcpy(p->payload+1,message,len); + + req->p = p; + req->pcb = pcb; + req->sent = sent; + return __bte_send_request(req); +} + +s32 bte_sendmessage(struct bte_pcb *pcb,void *message,u16 len) +{ + s32 err = ERR_VAL; + struct pbuf *p; + struct ctrl_req_t *req; + + //printf("bte_sendmessage()\n"); + + if(pcb==NULL || message==NULL || len==0) return ERR_VAL; + if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; + + if((req=btmemb_alloc(&bte_ctrl_reqs))==NULL) { + ERROR("bte_sendmessage: Could not allocate memory for request\n"); + return ERR_MEM; + } + + if((p=btpbuf_alloc(PBUF_RAW,(1 + len),PBUF_RAM))==NULL) { + ERROR("bte_sendmessage: Could not allocate memory for pbuf\n"); + btmemb_free(&bte_ctrl_reqs,req); + return ERR_MEM; + } + + ((u8*)p->payload)[0] = (HIDP_TRANS_SETREPORT|HIDP_DATA_RTYPE_OUPUT); + memcpy(p->payload+1,message,len); + + req->p = p; + req->pcb = pcb; + req->sent = NULL; + err = __bte_send_request(req); + if(err==ERR_OK) err = __bte_waitrequest(req); + + btmemb_free(&bte_ctrl_reqs,req); + return err; +} + +void bte_arg(struct bte_pcb *pcb,void *arg) +{ + u32 level; + _CPU_ISR_Disable(level); + pcb->cbarg = arg; + _CPU_ISR_Restore(level); +} + +void bte_received(struct bte_pcb *pcb, s32 (*recv)(void *arg,void *buffer,u16 len)) +{ + u32 level; + _CPU_ISR_Disable(level); + pcb->recv = recv; + _CPU_ISR_Restore(level); +} + +void bte_disconnected(struct bte_pcb *pcb,s32 (disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) +{ + u32 level; + _CPU_ISR_Disable(level); + pcb->disconn_cfm = disconn_cfm; + _CPU_ISR_Restore(level); +} + +err_t acl_wlp_completed(void *arg,struct bd_addr *bdaddr) +{ + //hci_sniff_mode(bdaddr,200,100,10,10); + return ERR_OK; +} + +err_t acl_conn_complete(void *arg,struct bd_addr *bdaddr) +{ + //printf("acl_conn_complete\n"); + //memcpy(&(btstate.acl_bdaddr),bdaddr,6); + + hci_write_link_policy_settings(bdaddr,0x0005); + return ERR_OK; +} + +err_t pin_req(void *arg,struct bd_addr *bdaddr) +{ + //printf("pin_req\n"); + return ERR_OK; +} + +err_t l2cap_disconnected_ind(void *arg, struct l2cap_pcb *pcb, err_t err) +{ + struct bte_pcb *bte = (struct bte_pcb*)arg; + + if(bte==NULL) return ERR_OK; + + bte->state = (u32)STATE_DISCONNECTING; + switch(l2cap_psm(pcb)) { + case HIDP_CONTROL_CHANNEL: + l2cap_close(bte->ctl_pcb); + bte->ctl_pcb = NULL; + break; + case HIDP_DATA_CHANNEL: + l2cap_close(bte->data_pcb); + bte->data_pcb = NULL; + break; + } + if(bte->data_pcb==NULL && bte->ctl_pcb==NULL) { + bte->err = ERR_OK; + bte->state = (u32)STATE_DISCONNECTED; + __bte_close_ctrl_queue(bte); + if(bte->disconn_cfm!=NULL) bte->disconn_cfm(bte->cbarg,bte,ERR_OK); + } + return ERR_OK; +} + +err_t l2cap_disconnect_cfm(void *arg, struct l2cap_pcb *pcb) +{ + struct bte_pcb *bte = (struct bte_pcb*)arg; + + if(bte==NULL) return ERR_OK; + + switch(l2cap_psm(pcb)) { + case HIDP_CONTROL_CHANNEL: + l2cap_close(bte->ctl_pcb); + bte->ctl_pcb = NULL; + if(bte->data_pcb!=NULL) + l2ca_disconnect_req(bte->data_pcb,l2cap_disconnect_cfm); + break; + case HIDP_DATA_CHANNEL: + l2cap_close(bte->data_pcb); + bte->data_pcb = NULL; + if(bte->ctl_pcb!=NULL) + l2ca_disconnect_req(bte->ctl_pcb,l2cap_disconnect_cfm); + break; + } + if(bte->data_pcb==NULL && bte->ctl_pcb==NULL) { + bte->err = ERR_OK; + bte->state = (u32)STATE_DISCONNECTED; + __bte_close_ctrl_queue(bte); + if(bte->disconn_cfm!=NULL) bte->disconn_cfm(bte->cbarg,bte,ERR_OK); + + hci_cmd_complete(NULL); + hci_disconnect(&(bte->bdaddr),HCI_OTHER_END_TERMINATED_CONN_USER_ENDED); + } + + return ERR_OK; +} + +err_t link_key_not(void *arg,struct bd_addr *bdaddr,u8_t *key) +{ + //printf("link_key_not\n"); + return hci_write_stored_link_key(bdaddr,key); +} + +/* +err_t l2cap_connected(void *arg,struct l2cap_pcb *l2cappcb,u16_t result,u16_t status) +{ + struct bte_pcb *btepcb = (struct bte_pcb*)arg; + + printf("l2cap_connected(%02x)\n",result); + if(result==L2CAP_CONN_SUCCESS) { + l2cap_recv(l2cappcb,bte_input); + l2cap_disconnect_ind(l2cappcb,l2cap_disconnected_ind); + btepcb->err = ERR_OK; + } else { + l2cap_close(l2cappcb); + btepcb->err = ERR_CONN; + } + + if(btepcb->conn_cfm) btepcb->conn_cfm(btepcb->cbarg,btepcb,btepcb->err); + LWP_ThreadSignal(btepcb->cmdq); + return ERR_OK; +} +*/ +err_t l2cap_accepted(void *arg,struct l2cap_pcb *l2cappcb,err_t err) +{ + struct bte_pcb *btepcb = (struct bte_pcb*)arg; + + //printf("l2cap_accepted(%02x)\n",err); + if(err==ERR_OK) { + l2cap_recv(l2cappcb,bte_process_input); + l2cap_disconnect_ind(l2cappcb,l2cap_disconnected_ind); + switch(l2cap_psm(l2cappcb)) { + case HIDP_CONTROL_CHANNEL: + btepcb->ctl_pcb = l2cappcb; + break; + case HIDP_DATA_CHANNEL: + btepcb->data_pcb = l2cappcb; + break; + } + if(btepcb->data_pcb && btepcb->ctl_pcb) { + btepcb->err = ERR_OK; + btepcb->state = (u32)STATE_CONNECTED; + if(btepcb->conn_cfm) btepcb->conn_cfm(btepcb->cbarg,btepcb,ERR_OK); + } + } else { + l2cap_close(l2cappcb); + btepcb->err = ERR_CONN; + btepcb->conn_cfm(btepcb->cbarg,btepcb,ERR_CONN); + } + + return ERR_OK; +} + +err_t bte_inquiry_complete(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result) +{ + u8_t i; + struct hci_inq_res *p; + struct bt_state *state = (struct bt_state*)arg; + + if(result==HCI_SUCCESS) { + if(ires!=NULL) { + + if(btstate.info!=NULL) free(btstate.info); + btstate.info = NULL; + btstate.num_maxdevs = 0; + btstate.num_founddevs = 0; + + p = ires; + while(p!=NULL) { + btstate.num_founddevs++; + p = p->next; + } + + p = ires; + btstate.info = (struct inquiry_info_ex*)malloc(sizeof(struct inquiry_info_ex)*btstate.num_founddevs); + for(i=0;ibdaddr)); + memcpy(btstate.info[i].cod,p->cod,3); + btstate.info[i].psrm = p->psrm; + btstate.info[i].psm = p->psm; + btstate.info[i].co = p->co; + + printf("bdaddr: %02x:%02x:%02x:%02x:%02x:%02x\n",p->bdaddr.addr[0],p->bdaddr.addr[1],p->bdaddr.addr[2],p->bdaddr.addr[3],p->bdaddr.addr[4],p->bdaddr.addr[5]); + printf("cod: %02x%02x%02x\n",p->cod[0],p->cod[1],p->cod[2]); + printf("psrm: %02x\n",p->psrm); + printf("psm: %02x\n",p->psm); + printf("co: %04x\n",p->co); + p = p->next; + } + __bte_cmdfinish(state,ERR_OK); + } else + hci_inquiry(0x009E8B33,0x03,btstate.num_maxdevs,bte_inquiry_complete); + } + return ERR_OK; +} + +err_t bte_read_stored_link_key_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + u8_t i = 0; + struct hci_link_key *p; + struct linkkey_info *keys; + struct bt_state *state = (struct bt_state*)arg; + + if(!pcb) return ERR_CONN; + + LOG("bte_read_stored_link_key_complete(%02x,%p)\n",result,pcb->keyres); + + if(state==NULL) return ERR_VAL; + if(!(ogf==HCI_HC_BB_OGF && ocf==HCI_R_STORED_LINK_KEY_OCF)) return __bte_cmdfinish(state,ERR_CONN); + + if(result==HCI_SUCCESS) { + keys = (struct linkkey_info*)state->usrdata; + if(pcb->keyres!=NULL && keys!=NULL) { + for(i=0,p=pcb->keyres;inum_maxdevs && p!=NULL;i++) { + bd_addr_set(&(keys[i].bdaddr),&(p->bdaddr)); + memcpy(keys[i].key,p->key,16); + + p = p->next; + } + } + LOG("bte_read_stored_link_key_complete(%02x,%p,%d)\n",result,pcb->keyres,i); + __bte_cmdfinish(state,i); + return ERR_OK; + } + + return __bte_cmdfinish(state,ERR_VAL); +} + +err_t bte_read_bd_addr_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + struct bd_addr *bdaddr; + struct bt_state *state = (struct bt_state*)arg; + + if(!pcb) return ERR_CONN; + + LOG("bte_read_bd_addr_complete(%02x,%p)\n", result, &pcb->bdaddr); + + if(state==NULL) return ERR_VAL; + + if(!(ogf==HCI_INFO_PARAM_OGF && ocf==HCI_R_BD_ADDR_OCF)) return __bte_cmdfinish(state,ERR_CONN); + + if(result == HCI_SUCCESS) { + bdaddr = (struct bd_addr *)state->usrdata; + if (bdaddr != NULL) { + bdaddr->addr[0] = pcb->bdaddr.addr[5]; + bdaddr->addr[1] = pcb->bdaddr.addr[4]; + bdaddr->addr[2] = pcb->bdaddr.addr[3]; + bdaddr->addr[3] = pcb->bdaddr.addr[2]; + bdaddr->addr[4] = pcb->bdaddr.addr[1]; + bdaddr->addr[5] = pcb->bdaddr.addr[0]; + } + LOG("bte_read_bd_addr_complete(%02x,%p,%d)\n",result,bdaddr,i); + __bte_cmdfinish(state,ERR_OK); + return ERR_OK; + } + + return __bte_cmdfinish(state,ERR_VAL); +} + +/* new init with patching */ +err_t bte_hci_initcore_complete2(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + err_t err = ERR_OK; + u8_t dev_cod[] = {0x04, 0x02,0x40}; + struct bt_state *state = (struct bt_state*)arg; + + LOG("bte_hci_initcore_complete2(%02x,%02x)\n",ogf,ocf); + switch(ogf) { + case HCI_HC_BB_OGF: + if(ocf==HCI_WRITE_INQUIRY_MODE) { + if(result==HCI_SUCCESS) { + hci_write_page_scan_type(0x01); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_PAGE_SCAN_TYPE) { + if(result==HCI_SUCCESS) { + hci_write_inquiry_scan_type(0x01); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_INQUIRY_SCAN_TYPE) { + if(result==HCI_SUCCESS) { + hci_write_cod(dev_cod); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_COD) { + if(result==HCI_SUCCESS) { + hci_write_page_timeout(0x2000); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_PAGE_TIMEOUT) { + if(result==HCI_SUCCESS) { + state->hci_inited = 1; + hci_cmd_complete(NULL); + return __bte_cmdfinish(state,ERR_OK); + } else + err = ERR_CONN; + } + break; + default: + LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); + err = ERR_CONN; + break; + } + + if(err!=ERR_OK) __bte_cmdfinish(state,err); + return err; +} + +err_t bte_hci_initcore_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + err_t err = ERR_OK; + u8_t dev_cod[] = {0x00, 0x1f,0x00}; + struct bt_state *state = (struct bt_state*)arg; + + LOG("bte_hci_initcore_complete(%02x,%02x)\n",ogf,ocf); + switch(ogf) { + case HCI_INFO_PARAM: + if(ocf==HCI_READ_BUFFER_SIZE) { + if(result==HCI_SUCCESS) { + hci_write_cod(dev_cod); + } else + err = ERR_CONN; + } else if(ocf==HCI_READ_LOCAL_VERSION) { + if(result==HCI_SUCCESS) { + hci_read_bd_addr(); + } else + err = ERR_CONN; + } else if(ocf==HCI_READ_BD_ADDR) { + if(result==HCI_SUCCESS) { + hci_read_local_features(); + } else + err = ERR_CONN; + } else if(ocf==HCI_READ_LOCAL_FEATURES) { + if(result==HCI_SUCCESS) { + hci_cmd_complete(bte_hci_initcore_complete2); + hci_write_inquiry_mode(0x01); + } else + err = ERR_CONN; + } + break; + case HCI_HC_BB_OGF: + if(ocf==HCI_RESET) { + if(result==HCI_SUCCESS) { + hci_read_buffer_size(); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_COD) { + if(result==HCI_SUCCESS) { + hci_write_local_name((u8_t*)"",1); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_LOCAL_NAME) { + if(result==HCI_SUCCESS) { + hci_write_pin_type(0x00); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_PIN_TYPE) { + if(result==HCI_SUCCESS) { + hci_host_buffer_size(); + } else + err = ERR_CONN; + } else if(ocf==HCI_HOST_BUF_SIZE) { + if(result==HCI_SUCCESS) { + hci_read_local_version(); + } else + err = ERR_CONN; + } + break; + default: + LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); + err = ERR_CONN; + break; + } + + if(err!=ERR_OK) __bte_cmdfinish(state,err); + return err; +} + +err_t bte_hci_apply_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + err_t err = ERR_OK; + struct bt_state *state = (struct bt_state*)arg; + + LOG("bte_hci_apply_patch_complete(%02x,%02x,%02x)\n",ogf,ocf,result); + switch(ogf) { + case HCI_VENDOR_OGF: + if(ocf==HCI_VENDOR_PATCH_START_OCF) { + if(result==HCI_SUCCESS) { + err = hci_vendor_specific_command(HCI_VENDOR_PATCH_CONT_OCF,HCI_VENDOR_OGF,bte_patch0,184); + } else + err = ERR_CONN; + } else if(ocf==HCI_VENDOR_PATCH_CONT_OCF) { + if(result==HCI_SUCCESS) { + hci_cmd_complete(bte_hci_patch_complete); + err = hci_vendor_specific_command(HCI_VENDOR_PATCH_END_OCF,HCI_VENDOR_OGF,bte_patch1,92); + } else + err = ERR_CONN; + } + break; + default: + LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); + err = ERR_CONN; + break; + } + + if(err!=ERR_OK) __bte_cmdfinish(state,err); + return err; +} + +err_t bte_hci_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + err_t err = ERR_OK; + u8_t dev_cod[] = {0x04, 0x02,0x40}; + struct bt_state *state = (struct bt_state*)arg; + + LOG("bte_hci_patch_complete(%02x,%02x,%02x)\n",ogf,ocf,result); + switch(ogf) { + case HCI_INFO_PARAM: + if(ocf==HCI_READ_BUFFER_SIZE) { + if(result==HCI_SUCCESS) { + hci_write_cod(dev_cod); + } else + err = ERR_CONN; + } else if(ocf==HCI_READ_LOCAL_VERSION) { + if(result==HCI_SUCCESS) { + hci_read_bd_addr(); + } else + err = ERR_CONN; + } else if(ocf==HCI_READ_BD_ADDR) { + if(result==HCI_SUCCESS) { + hci_read_local_features(); + } else + err = ERR_CONN; + } else if(ocf==HCI_READ_LOCAL_FEATURES) { + if(result==HCI_SUCCESS) { + hci_cmd_complete(NULL); + return __bte_cmdfinish(state,ERR_OK); + } else + err = ERR_CONN; + } + break; + case HCI_HC_BB_OGF: + if(ocf==HCI_RESET) { + if(result==HCI_SUCCESS) { + hci_read_buffer_size(); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_COD) { + if(result==HCI_SUCCESS) { + hci_write_local_name((u8_t*)"",1); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_LOCAL_NAME) { + if(result==HCI_SUCCESS) { + hci_write_pin_type(0x00); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_PIN_TYPE) { + if(result==HCI_SUCCESS) { + hci_host_buffer_size(); + } else + err = ERR_CONN; + } else if(ocf==HCI_HOST_BUF_SIZE) { + if(result==HCI_SUCCESS) { + hci_read_local_version(); + } else + err = ERR_CONN; + } + break; + case HCI_VENDOR_OGF: + if(ocf==HCI_VENDOR_PATCH_END_OCF) { + if(result==HCI_SUCCESS) { + err = hci_reset(); + } else + err = ERR_CONN; + } + break; + default: + LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); + err = ERR_CONN; + break; + } + + if(err!=ERR_OK) __bte_cmdfinish(state,err); + return err; +} + +err_t bte_hci_initsub_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + err_t err = ERR_OK; + u8_t dev_cod[] = {0x00, 0x04,0x48}; + struct bt_state *state = (struct bt_state*)arg; + + LOG("bte_hci_initsub_complete(%02x,%02x)\n",ogf,ocf); + switch(ogf) { + case HCI_HC_BB_OGF: + if(ocf==HCI_WRITE_INQUIRY_MODE) { + if(result==HCI_SUCCESS) { + hci_write_page_scan_type(0x01); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_PAGE_SCAN_TYPE) { + if(result==HCI_SUCCESS) { + hci_write_inquiry_scan_type(0x01); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_INQUIRY_SCAN_TYPE) { + if(result==HCI_SUCCESS) { + hci_write_cod(dev_cod); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_COD) { + if(result==HCI_SUCCESS) { + hci_write_page_timeout(0x8000); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_PAGE_TIMEOUT) { + if(result==HCI_SUCCESS) { + hci_write_local_name((u8_t*)"Wii",4); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_LOCAL_NAME) { + if(result==HCI_SUCCESS) { + hci_write_scan_enable(0x02); + } else + err = ERR_CONN; + } else if(ocf==HCI_WRITE_SCAN_ENABLE) { + if(result==HCI_SUCCESS) { + hci_cmd_complete(NULL); + return __bte_cmdfinish(state,ERR_OK); + } else + err = ERR_CONN; + } + break; + default: + LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); + err = ERR_CONN; + break; + + } + + if(err!=ERR_OK) __bte_cmdfinish(state,err); + return err; +} + diff --git a/wii/libogc/lwbt/btmemb.c b/wii/libogc/lwbt/btmemb.c new file mode 100644 index 0000000000..899a3359e5 --- /dev/null +++ b/wii/libogc/lwbt/btmemb.c @@ -0,0 +1,70 @@ +#include +#include + +#include "asm.h" +#include "processor.h" + +#include "bt.h" +#include "btmemb.h" + +void btmemb_init(struct memb_blks *blk) +{ + MEMSET(blk->mem,0,(MEM_ALIGN_SIZE(blk->size)+sizeof(u32))*blk->num); +} + +void* btmemb_alloc(struct memb_blks *blk) +{ + s32 i; + u32 *ptr; + u32 level; + void *p; + + _CPU_ISR_Disable(level); + ptr = (u32*)blk->mem; + for(i=0;inum;i++) { + if(*ptr==0) { + ++(*ptr); + p = (ptr+1); + _CPU_ISR_Restore(level); + return p; + } + ptr = (u32*)((u8*)ptr+(MEM_ALIGN_SIZE(blk->size)+sizeof(u32))); + } + _CPU_ISR_Restore(level); + return NULL; +} + +u8 btmemb_free(struct memb_blks *blk,void *ptr) +{ + u8 ref; + s32 i; + u32 level; + u32 *ptr2,*ptr1; + + _CPU_ISR_Disable(level); + ptr1 = ptr; + ptr2 = (u32*)blk->mem; + for(i=0;inum;i++) { + if(ptr2==(ptr1 - 1)) { + ref = --(*ptr2); + _CPU_ISR_Restore(level); + return ref; + } + ptr2 = (u32*)((u8*)ptr2+(MEM_ALIGN_SIZE(blk->size)+sizeof(u32))); + } + _CPU_ISR_Restore(level); + return -1; +} + +u8 btmemb_ref(struct memb_blks *blk,void *ptr) +{ + u8 ref; + u32 *pref; + u32 level; + + _CPU_ISR_Disable(level); + pref = ptr-sizeof(u32); + ref = ++(*pref); + _CPU_ISR_Restore(level); + return ref; +} diff --git a/wii/libogc/lwbt/btmemb.h b/wii/libogc/lwbt/btmemb.h new file mode 100644 index 0000000000..863456acda --- /dev/null +++ b/wii/libogc/lwbt/btmemb.h @@ -0,0 +1,21 @@ +#ifndef __BTMEMB_H__ +#define __BTMEMB_H__ + +#include + +#define MEMB(name,size,num) \ + static u8 memb_mem_##name[(MEM_ALIGN_SIZE(size)+sizeof(u32))*num]; \ + static struct memb_blks name = {size,num,memb_mem_##name} + +struct memb_blks { + u16 size; + u16 num; + u8 *mem; +}; + +void btmemb_init(struct memb_blks *blk); +void* btmemb_alloc(struct memb_blks *blk); +u8 btmemb_free(struct memb_blks *blk,void *ptr); +u8 btmemb_ref(struct memb_blks *blk,void *ptr); + +#endif diff --git a/wii/libogc/lwbt/btmemr.c b/wii/libogc/lwbt/btmemr.c new file mode 100644 index 0000000000..cd23473596 --- /dev/null +++ b/wii/libogc/lwbt/btmemr.c @@ -0,0 +1,166 @@ +#include +#include + +#include "asm.h" +#include "processor.h" + +#include "bt.h" +#include "btmemr.h" + +#define MIN_SIZE 12 +#define SIZEOF_STRUCT_MEM (sizeof(struct mem)+(((sizeof(struct mem)%MEM_ALIGNMENT)==0)?0:(4-(sizeof(struct mem)%MEM_ALIGNMENT)))) + +struct mem { + u32 next,prev; + u32 used; +}; + +static struct mem *ram_free; +static struct mem *ram_end; +static u8 ram_block[sizeof(struct mem)+MEM_SIZE+MEM_ALIGNMENT]; + +static void plug_holes(struct mem *rmem) +{ + struct mem *nmem; + struct mem *pmem; + + nmem = (struct mem*)&ram_block[rmem->next]; + if(rmem!=nmem && nmem->used==0 && (u8_t*)nmem!=(u8_t*)ram_end) { + if(ram_free==nmem) ram_free = rmem; + + rmem->next = nmem->next; + ((struct mem*)&ram_block[nmem->next])->prev = (u8_t*)rmem - ram_block; + } + + pmem = (struct mem*)&ram_block[rmem->prev]; + if(pmem!=rmem && pmem->used==0) { + if(ram_free==rmem) ram_free = pmem; + pmem->next = rmem->next; + ((struct mem*)&ram_block[rmem->next])->prev = (u8_t*)pmem - ram_block; + } +} + +void btmemr_init() +{ + u32 level; + struct mem *rmem; + + MEMSET(ram_block,0,MEM_SIZE); + + _CPU_ISR_Disable(level); + rmem = (struct mem*)ram_block; + rmem->next = MEM_SIZE; + rmem->prev = 0; + rmem->used = 0; + + ram_end = (struct mem*)&ram_block[MEM_SIZE]; + ram_end->used = 1; + ram_end->prev = MEM_SIZE; + ram_end->next = MEM_SIZE; + + ram_free = (struct mem*)ram_block; + _CPU_ISR_Restore(level); +} + +void* btmemr_malloc(u32 size) +{ + u32 level; + u32 ptr,ptr2; + struct mem *rmem,*rmem2; + + if(size==0) return NULL; + + if(size%MEM_ALIGNMENT) size += MEM_ALIGNMENT - ((size+SIZEOF_STRUCT_MEM)%SIZEOF_STRUCT_MEM); + if(size>MEM_SIZE) return NULL; + + _CPU_ISR_Disable(level); + for(ptr = (u8_t*)ram_free - ram_block;ptrnext) { + rmem = (struct mem*)&ram_block[ptr]; + if(!rmem->used && rmem->next - (ptr + SIZEOF_STRUCT_MEM)>=size + SIZEOF_STRUCT_MEM) { + ptr2 = ptr + SIZEOF_STRUCT_MEM + size; + rmem2 = (struct mem*)&ram_block[ptr2]; + + rmem2->prev = ptr; + rmem2->next = rmem->next; + rmem->next = ptr2; + if(rmem->next!=MEM_SIZE) ((struct mem*)&ram_block[rmem2->next])->prev = ptr2; + + rmem2->used = 0; + rmem->used = 1; + + if(rmem==ram_free) { + while(ram_free->used && ram_free!=ram_end) ram_free = (struct mem*)&ram_block[ram_free->next]; + } + + _CPU_ISR_Restore(level); + return (u8_t*)rmem+SIZEOF_STRUCT_MEM; + } + } + _CPU_ISR_Restore(level); + return NULL; +} + +void btmemr_free(void *ptr) +{ + u32 level; + struct mem *rmem; + + if(ptr==NULL) return; + if((u8_t*)ptr<(u8_t*)ram_block || (u8_t*)ptr>=(u8_t*)ram_end) return; + + _CPU_ISR_Disable(level); + rmem = (struct mem*)((u8_t*)ptr - SIZEOF_STRUCT_MEM); + rmem->used = 0; + + if(rmemMEM_SIZE) return NULL; + if((u8_t*)ptr<(u8_t*)ram_block || (u8_t*)ptr>=(u8_t*)ram_end) { + ERROR("memr_realloc: illegal memory.\n"); + return ptr; + } + + _CPU_ISR_Disable(level); + rmem = (struct mem*)((u8_t*)ptr - SIZEOF_STRUCT_MEM); + ptr1 = (u8_t*)rmem - ram_block; + size = rmem->next - ptr1 - SIZEOF_STRUCT_MEM; + + if(newsize+SIZEOF_STRUCT_MEM+MIN_SIZEused = 0; + rmem2->next = rmem->next; + rmem2->prev = ptr1; + rmem->next = ptr2; + if(rmem2->next!=MEM_SIZE) ((struct mem*)&ram_block[rmem2->next])->prev = ptr2; + + plug_holes(rmem2); + } + _CPU_ISR_Restore(level); + + return ptr; +} + +void* btmemr_reallocm(void *ptr,u32 newsize) +{ + void *nmem; + + nmem = btmemr_malloc(newsize); + if(nmem==NULL) return btmemr_realloc(ptr,newsize); + + MEMCPY(nmem,ptr,newsize); + btmemr_free(ptr); + + return nmem; +} diff --git a/wii/libogc/lwbt/btmemr.h b/wii/libogc/lwbt/btmemr.h new file mode 100644 index 0000000000..f9c71523ae --- /dev/null +++ b/wii/libogc/lwbt/btmemr.h @@ -0,0 +1,12 @@ +#ifndef __BTMEMR_H__ +#define __BTMEMR_H__ + +#include + +void btmemr_init(); +void* btmemr_malloc(u32 size); +void btmemr_free(void *ptr); +void* btmemr_realloc(void *ptr,u32 newsize); +void* btmemr_reallocm(void *ptr,u32 newsize); + +#endif diff --git a/wii/libogc/lwbt/btopt.h b/wii/libogc/lwbt/btopt.h new file mode 100644 index 0000000000..28485f10b1 --- /dev/null +++ b/wii/libogc/lwbt/btopt.h @@ -0,0 +1,352 @@ +/** + * \defgroup uipopt Configuration options for uIP + * @{ + * + * uIP is configured using the per-project configuration file + * "uipopt.h". This file contains all compile-time options for uIP and + * should be tweaked to match each specific project. The uIP + * distribution contains a documented example "uipopt.h" that can be + * copied and modified for each project. + */ + +/** + * \file + * Configuration options for uIP. + * \author Adam Dunkels + * + * This file is used for tweaking various configuration options for + * uIP. You should make a copy of this file into one of your project's + * directories instead of editing this example "uipopt.h" file that + * comes with the uIP distribution. + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * + */ + +#ifndef __BTOPT_H__ +#define __BTOPT_H__ + +#include +#include +#include + +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipopttypedef uIP type definitions + * @{ + */ + +/** + * The 8-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * char" works for most compilers. + */ +typedef u8 u8_t; + +/** + * The 8-bit signed data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * char" works for most compilers. + */ +typedef s8 s8_t; + +/** + * The 16-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef u16 u16_t; + +/** + * The 16-bit signed data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef s16 s16_t; + +/** + * The 32-bit signed data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef s32 s32_t; + +/** + * The 32-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef u32 u32_t; + +/** + * The 64-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef u64 u64_t; + +/** + * The 64-bit signed data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef s64 s64_t; + +/** + * The statistics data type. + * + * This datatype determines how high the statistics counters are able + * to count. + */ +typedef s8 err_t; + +/*------------------------------------------------------------------------------*/ + +/** + * \defgroup btopt general configuration options + * @{ + */ + +/** + * The size of the uIP packet buffer. + * + * The uIP packet buffer should not be smaller than 60 bytes, and does + * not need to be larger than 1500 bytes. Lower size results in lower + * TCP throughput, larger size results in higher TCP throughput. + * + * \hideinitializer + */ +#define MEM_SIZE (64*1024) + +#define PBUF_POOL_NUM (HCI_HOST_MAX_NUM_ACL*MAX_NUM_CLIENTS) +#define PBUF_POOL_BUFSIZE HCI_HOST_ACL_MAX_LEN + +#define PBUF_ROM_NUM 45 + + +/** + * Determines if statistics support should be compiled in. + * + * The statistics is useful for debugging and to show the user. + * + * \hideinitializer + */ +#define STATISTICS 0 + +/** + * Determines if logging of certain events should be compiled in. + * + * This is useful mostly for debugging. The function uip_log() + * must be implemented to suit the architecture of the project, if + * logging is turned on. + * + * \hideinitializer + */ +#define LOGGING 0 +#define ERRORING 0 + +/** + * Print out a uIP log message. + * + * This function must be implemented by the module that uses uIP, and + * is called by uIP whenever a log message is generated. + */ +void bt_log(const char *filename,int line_nb,char *msg); + +/** + * The link level header length. + * + * This is the offset into the uip_buf where the IP header can be + * found. For Ethernet, this should be set to 14. For SLIP, this + * should be set to 0. + * + * \hideinitializer + */ +#define LL_HLEN 16 + +#define TCPIP_HLEN 40 +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptcpu CPU architecture configuration + * @{ + * + * The CPU architecture configuration is where the endianess of the + * CPU on which uIP is to be run is specified. Most CPUs today are + * little endian, and the most notable exception are the Motorolas + * which are big endian. The BYTE_ORDER macro should be changed to + * reflect the CPU architecture on which uIP is to be run. + */ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 3412 +#endif /* LITTLE_ENDIAN */ +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 1234 +#endif /* BIGE_ENDIAN */ + +/** + * The byte order of the CPU architecture on which uIP is to be run. + * + * This option can be either BIG_ENDIAN (Motorola byte order) or + * LITTLE_ENDIAN (Intel byte order). + * + * \hideinitializer + */ +#ifndef BYTE_ORDER +#define BYTE_ORDER BIG_ENDIAN +#endif /* BYTE_ORDER */ + +/** @} */ +/*------------------------------------------------------------------------------*/ + +#define LIBC_MEMFUNCREPLACE 0 + +/* ---------- Memory options ---------- */ +#define MAX_NUM_CLIENTS 6 /* Maximum number of connected Bluetooth clients. No more than 6 */ +#define MAX_NUM_OPT_CLIENTS 10 /* Maximum number of possible Bluetooth clients we might listen to */ + +#define MEMB_NUM_HCI_PCB 1 /* Always set to one */ +#define MEMB_NUM_HCI_LINK MAX_NUM_CLIENTS /* One for DT + One per ACL connection */ +#define MEMB_NUM_HCI_INQ 256 /* One per max number of returned results from an inquiry */ +#define MEMB_NUM_HCI_LINK_KEY 256 /* One per max number of returned results from an read stored link key */ + +/* MEMP_NUM_L2CAP_PCB: the number of simulatenously active L2CAP + connections. */ +#define MEMB_NUM_L2CAP_PCB (2 + 2 * MAX_NUM_CLIENTS) /* One for a closing connection + one for DT + one per number of connected Bluetooth clients */ +/* MEMP_NUM_L2CAP_PCB_LISTEN: the number of listening L2CAP + connections. */ +#define MEMB_NUM_L2CAP_PCB_LISTEN (2 * MAX_NUM_OPT_CLIENTS) /* One per listening PSM */ +/* MEMP_NUM_L2CAP_SIG: the number of simultaneously unresponded + L2CAP signals */ +#define MEMB_NUM_L2CAP_SIG (2 * MAX_NUM_CLIENTS)/* Two per number of connected Bluetooth clients but min 2 */ +#define MEMB_NUM_L2CAP_SEG (2 + 2 * MAX_NUM_CLIENTS) /* One per number of L2CAP connections */ + +#define MEMB_NUM_SDP_PCB MAX_NUM_CLIENTS /* One per number of connected Bluetooth clients */ +#define MEMB_NUM_SDP_RECORD 1 /* One per registered service record */ + +#define MEMP_NUM_RFCOMM_PCB (2 + 2 * MAX_NUM_CLIENTS) /* Two for DT + Two per number of connected Bluetooth clients */ +#define MEMP_NUM_RFCOMM_PCB_LISTEN (2 * MAX_NUM_CLIENTS) /* Two per number of connected Bluetooth clients */ + +#define MEMP_NUM_HIDP_PCB (2 + 2 * MAX_NUM_CLIENTS) /* Two for DT + Two per number of connected Bluetooth clients */ +#define MEMP_NUM_HIDP_PCB_LISTEN (2 * MAX_NUM_CLIENTS) /* Two per number of connected Bluetooth clients */ + +#define MEMP_NUM_PPP_PCB (1 + MAX_NUM_CLIENTS) /* One for DT + One per number of connected Bluetooth clients */ +#define MEMP_NUM_PPP_REQ MAX_NUM_CLIENTS /* One per number of connected Bluetooth clients but min 1 */ + +#define MEMP_NUM_BTE_PCB (2 + 2 * MAX_NUM_CLIENTS) /* Two for DT + Two per number of connected Bluetooth clients */ +#define MEMP_NUM_BTE_PCB_LISTEN (2 * MAX_NUM_CLIENTS) /* Two per number of connected Bluetooth clients */ + +#define MEMP_NUM_BTE_CTRLS 256 + +/* ---------- HCI options ---------- */ +/* HCI: Defines if we have lower layers of the Bluetooth stack running on a separate host + controller */ +#define HCI 1 + +#if HCI +/* HCI_HOST_MAX_NUM_ACL: The maximum number of ACL packets that the host can buffer */ +#define HCI_HOST_MAX_NUM_ACL 20 //TODO: Should be equal to PBUF_POOL_SIZE/2??? */ +/* HCI_HOST_ACL_MAX_LEN: The maximum size of an ACL packet that the host can buffer */ +#define HCI_HOST_ACL_MAX_LEN 1691 /* Default: RFCOMM MFS + ACL header size, L2CAP header size, + RFCOMM header size and RFCOMM FCS size */ +/* HCI_PACKET_TYPE: The set of packet types which may be used on the connection. In order to + maximize packet throughput, it is recommended that RFCOMM should make use of the 3 and 5 + slot baseband packets.*/ +#define HCI_PACKET_TYPE 0xCC18 /* Default DM1, DH1, DM3, DH3, DM5, DH5 */ +/* HCI_ALLOW_ROLE_SWITCH: Tells the host controller whether to accept a Master/Slave switch + during establishment of a connection */ +#define HCI_ALLOW_ROLE_SWITCH 1 /* Default 1 */ +/* HCI_FLOW_QUEUEING: Control if a packet should be queued if the host controller is out of + bufferspace for outgoing packets. Only the first packet sent when out of credits will be + queued */ +#define HCI_FLOW_QUEUEING 0 /* Default: 0 */ + +#endif /* HCI */ + +/* ---------- L2CAP options ---------- */ +/* L2CAP_HCI: Option for including HCI to access the Bluetooth baseband capabilities */ +#define L2CAP_HCI 1 //TODO: NEEDED? +/* L2CAP_CFG_QOS: Control if a flow specification similar to RFC 1363 should be used */ +#define L2CAP_CFG_QOS 0 +/* L2CAP_MTU: Maximum transmission unit for L2CAP packet payload (min 48) */ +#define L2CAP_MTU (HIDD_N + 1)/* Default for this implementation is RFCOMM MFS + RFCOMM header size and + RFCOMM FCS size while the L2CAP default is 672 */ +/* L2CAP_OUT_FLUSHTO: For some networking protocols, such as many real-time protocols, guaranteed delivery + is undesirable. The flush time-out value SHALL be set to its default value 0xffff for a reliable L2CAP + channel, and MAY be set to other values if guaranteed delivery is not desired. (min 1) */ +#define L2CAP_OUT_FLUSHTO 0xFFFF /* Default: 0xFFFF. Infinite number of retransmissions (reliable channel) + The value of 1 implies no retransmissions at the Baseband level + should be performed since the minimum polling interval is 1.25 ms.*/ +/* L2CAP_RTX: The Responsive Timeout eXpired timer is used to terminate + the channel when the remote endpoint is unresponsive to signalling + requests (min 1s, max 60s) */ +#define L2CAP_RTX 60 +/* L2CAP_ERTX: The Extended Response Timeout eXpired timer is used in + place of the RTC timer when a L2CAP_ConnectRspPnd event is received + (min 60s, max 300s) */ +#define L2CAP_ERTX 300 +/* L2CAP_MAXRTX: Maximum number of Request retransmissions before + terminating the channel identified by the request. The decision + should be based on the flush timeout of the signalling link. If the + flush timeout is infinite, no retransmissions should be performed */ +#define L2CAP_MAXRTX 0 +/* L2CAP_CFG_TO: Amount of time spent arbitrating the channel parameters + before terminating the connection (max 120s) */ +#define L2CAP_CFG_TO 30 + +/* ---------- BTE options ---------- */ + +/* ---------- HIDD options ---------- */ +/* RFCOMM_N: Maximum frame size for RFCOMM segments (min 23, max 32767)*/ +#define HIDD_N 672 /* Default: Worst case byte stuffed PPP packet size + + non-compressed PPP header size and FCS size */ +/* RFCOMM_K: Initial amount of credits issued to the peer (min 0, max 7) */ +#define RFCOMM_K 0 +/* RFCOMM_TO: Acknowledgement timer (T1) and response timer for multiplexer control channel (T2). + T1 is the timeout for frames sent with the P/F bit set to 1 (SABM and DISC) and T2 is the timeout + for commands sent in UIH frames on DLCI 0 (min 10s, max 60s) */ +#define RFCOMM_TO 20 +/* RFCOMM_FLOW_QUEUEING: Control if a packet should be queued if a channel is out of credits for + outgoing packets. Only the first packet sent when out of credits will be queued */ +#define RFCOMM_FLOW_QUEUEING 0 /* Default: 0 */ + + +#endif /* __BTOPT_H__ */ diff --git a/wii/libogc/lwbt/btpbuf.c b/wii/libogc/lwbt/btpbuf.c new file mode 100644 index 0000000000..5afa2ce741 --- /dev/null +++ b/wii/libogc/lwbt/btpbuf.c @@ -0,0 +1,358 @@ +#include +#include + +#include "btmemb.h" +#include "btmemr.h" +#include "btpbuf.h" + +#if STATISTICS == 1 +#define STAT(s) +#else +#define STAT(s) +#endif /* STATISTICS == 1 */ + +MEMB(pool_pbufs,sizeof(struct pbuf)+PBUF_POOL_BUFSIZE,PBUF_POOL_NUM); +MEMB(rom_pbufs,sizeof(struct pbuf),PBUF_ROM_NUM); + +void btpbuf_init() +{ + btmemb_init(&pool_pbufs); + btmemb_init(&rom_pbufs); +} + +struct pbuf* btpbuf_alloc(pbuf_layer layer,u16_t len,pbuf_flag flag) +{ + u16_t offset; + s32_t rem_len; + struct pbuf *p,*q,*r; + + offset = 0; + switch(layer) { + case PBUF_TRANSPORT: + offset += TRANSPORT_HLEN; + case PBUF_LINK: + offset += LL_HLEN; + break; + case PBUF_RAW: + break; + default: + ERROR("btpbuf_alloc: bad pbuf layer.\n"); + return NULL; + } + + switch(flag) { + case PBUF_POOL: + p = btmemb_alloc(&pool_pbufs); + if(p==NULL) { + ERROR("btbtpbuf_alloc: couldn't allocate pbuf(p) from pool\n"); + return NULL; + } + + p->next = NULL; + p->payload = MEM_ALIGN((void*)((u8_t*)p+(sizeof(struct pbuf)+offset))); + p->tot_len = len; + p->len = (len>(PBUF_POOL_BUFSIZE-offset)?(PBUF_POOL_BUFSIZE-offset):len); + p->flags = PBUF_FLAG_POOL; + p->ref = 1; + + r = p; + rem_len = len - p->len; + while(rem_len>0) { + q = btmemb_alloc(&pool_pbufs); + if(q==NULL) { + ERROR("btpbuf_alloc: couldn't allocate pbuf(q) from pool\n"); + btpbuf_free(p); + return NULL; + } + + q->next = NULL; + r->next = q; + q->tot_len = rem_len; + q->len = (rem_len>PBUF_POOL_BUFSIZE?PBUF_POOL_BUFSIZE:rem_len); + q->payload = (void*)((u8_t*)q+sizeof(struct pbuf)); + q->flags = PBUF_FLAG_POOL; + q->ref = 1; + + rem_len -= q->len; + r = q; + } + break; + case PBUF_RAM: + p = btmemr_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf)+offset)+MEM_ALIGN_SIZE(len)); + if(p==NULL) { + ERROR("btpbuf_alloc: couldn't allocate pbuf from ram\n"); + return NULL; + } + p->payload = MEM_ALIGN((u8_t*)p+sizeof(struct pbuf)+offset); + p->len = p->tot_len = len; + p->next = NULL; + p->flags = PBUF_FLAG_RAM; + break; + case PBUF_ROM: + case PBUF_REF: + p = btmemb_alloc(&rom_pbufs); + if(p==NULL) { + ERROR("btpbuf_alloc: couldn't allocate pbuf from rom/ref\n"); + return NULL; + } + p->payload = NULL; + p->next = NULL; + p->len = p->tot_len = len; + p->flags = (flag==PBUF_ROM?PBUF_FLAG_ROM:PBUF_FLAG_REF); + break; + default: + ERROR("btpbuf_alloc: bad flag value.\n"); + return NULL; + } + + p->ref = 1; + return p; +} + +u8_t btpbuf_free(struct pbuf *p) +{ + u8_t cnt; + u32 level; + struct pbuf *q; + + if(p==NULL) return 0; + + cnt = 0; + + _CPU_ISR_Disable(level); + while(p!=NULL) { + p->ref--; + if(p->ref==0) { + q = p->next; + if(p->flags==PBUF_FLAG_POOL) { + btmemb_free(&pool_pbufs,p); + } else if(p->flags==PBUF_FLAG_ROM || p->flags==PBUF_FLAG_REF) { + btmemb_free(&rom_pbufs,p); + } else { + btmemr_free(p); + } + cnt++; + p = q; + } else + p = NULL; + } + _CPU_ISR_Restore(level); + + return cnt; +} + +void btpbuf_realloc(struct pbuf *p,u16_t new_len) +{ + u16_t rem_len; + s16_t grow; + struct pbuf *q; + + if(new_len>=p->tot_len) return; + + grow = new_len - p->tot_len; + rem_len = new_len; + q = p; + while(rem_len>q->len) { + rem_len -= q->len; + q->tot_len += grow; + q = q->next; + } + + if(q->flags==PBUF_FLAG_RAM && rem_len!=q->len) + btmemr_realloc(q,(u8_t*)q->payload-(u8_t*)q+rem_len); + + q->len = rem_len; + q->tot_len = q->len; + + if(q->next!=NULL) btpbuf_free(q->next); + q->next = NULL; +} + +u8_t btpbuf_header(struct pbuf *p,s16_t hdr_size_inc) +{ + void *payload; + + if(hdr_size_inc==0 || p==NULL) return 0; + + + payload = p->payload; + if(p->flags==PBUF_FLAG_POOL || p->flags==PBUF_FLAG_RAM) { + p->payload = (u8_t*)p->payload-hdr_size_inc; + if((u8_t*)p->payload<(u8_t*)p+sizeof(struct pbuf)) { + p->payload = payload; + return 1; + } + } else if(p->flags==PBUF_FLAG_ROM || p->flags==PBUF_FLAG_REF) { + if(hdr_size_inc<0 && hdr_size_inc-p->len<=0) p->payload = (u8_t*)p->payload-hdr_size_inc; + else return 1; + } + p->tot_len += hdr_size_inc; + p->len += hdr_size_inc; + + return 0; +} + +u8_t btpbuf_clen(struct pbuf *p) +{ + u8_t len; + + len = 0; + while(p!=NULL) { + len++; + p = p->next; + } + return len; +} + +void btpbuf_ref(struct pbuf *p) +{ + u32 level; + + if(p!=NULL) { + _CPU_ISR_Disable(level); + ++(p->ref); + _CPU_ISR_Restore(level); + } +} + +void btpbuf_cat(struct pbuf *h,struct pbuf *t) +{ + struct pbuf *p; + + if(h==NULL || t==NULL) return; + + for(p=h;p->next!=NULL;p=p->next) { + p->tot_len += t->tot_len; + } + p->tot_len += t->tot_len; + p->next = t; +} + +void btpbuf_queue(struct pbuf *p,struct pbuf *n) +{ + if(p==NULL || n==NULL || p==n) return; + + while(p->next!=NULL) p = p->next; + + p->next = n; + btpbuf_ref(n); +} + +struct pbuf* btpbuf_dequeue(struct pbuf *p) +{ + struct pbuf *q; + + if(p==NULL) return NULL; + + while(p->tot_len!=p->len) p = p->next; + + q = p->next; + p->next = NULL; + + return q; +} + +void btpbuf_chain(struct pbuf *h,struct pbuf *t) +{ + btpbuf_cat(h,t); + btpbuf_ref(t); +} + +struct pbuf* btpbuf_dechain(struct pbuf *p) +{ + struct pbuf *q; + u8_t tail_gone = 1; + + q = p->next; + if(q!=NULL) { + q->tot_len = p->tot_len - p->len; + p->next = NULL; + p->tot_len = p->len; + + tail_gone = btpbuf_free(q); + } + + return (tail_gone>0?NULL:q); +} + +struct pbuf* btpbuf_take(struct pbuf *p) +{ + struct pbuf *q , *prev, *head; + + prev = NULL; + head = p; + /* iterate through pbuf chain */ + do + { + /* pbuf is of type PBUF_REF? */ + if (p->flags == PBUF_FLAG_REF) { + LOG("pbuf_take: encountered PBUF_REF %p\n", (void *)p); + /* allocate a pbuf (w/ payload) fully in RAM */ + /* PBUF_POOL buffers are faster if we can use them */ + if (p->len <= PBUF_POOL_BUFSIZE) { + q = btpbuf_alloc(PBUF_RAW, p->len, PBUF_POOL); + if (q == NULL) { + LOG("pbuf_take: Could not allocate PBUF_POOL\n"); + } + } else { + /* no replacement pbuf yet */ + q = NULL; + LOG("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"); + } + /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */ + if (q == NULL) { + q = btpbuf_alloc(PBUF_RAW, p->len, PBUF_RAM); + if (q == NULL) { + LOG("pbuf_take: Could not allocate PBUF_RAM\n"); + } + } + /* replacement pbuf could be allocated? */ + if (q != NULL) + { + /* copy p to q */ + /* copy successor */ + q->next = p->next; + /* remove linkage from original pbuf */ + p->next = NULL; + /* remove linkage to original pbuf */ + if (prev != NULL) { + /* break chain and insert new pbuf instead */ + prev->next = q; + /* prev == NULL, so we replaced the head pbuf of the chain */ + } else { + head = q; + } + /* copy pbuf payload */ + memcpy(q->payload, p->payload, p->len); + q->tot_len = p->tot_len; + q->len = p->len; + /* in case p was the first pbuf, it is no longer refered to by + * our caller, as the caller MUST do p = pbuf_take(p); + * in case p was not the first pbuf, it is no longer refered to + * by prev. we can safely free the pbuf here. + * (note that we have set p->next to NULL already so that + * we will not free the rest of the chain by accident.) + */ + btpbuf_free(p); + /* do not copy ref, since someone else might be using the old buffer */ + LOG("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q); + p = q; + } else { + /* deallocate chain */ + btpbuf_free(head); + LOG("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p); + return NULL; + } + /* p->flags != PBUF_FLAG_REF */ + } else { + LOG("pbuf_take: skipping pbuf not of type PBUF_REF\n"); + } + /* remember this pbuf */ + prev = p; + /* proceed to next pbuf in original chain */ + p = p->next; + } while (p); + LOG("pbuf_take: end of chain reached.\n"); + + return head; +} diff --git a/wii/libogc/lwbt/btpbuf.h b/wii/libogc/lwbt/btpbuf.h new file mode 100644 index 0000000000..924b99c0cf --- /dev/null +++ b/wii/libogc/lwbt/btpbuf.h @@ -0,0 +1,49 @@ +#ifndef __BTPBUF_H__ +#define __BTPBUF_H__ + +#include "bt.h" + +/* Definitions for the pbuf flag field. These are NOT the flags that + * are passed to pbuf_alloc(). */ +#define PBUF_FLAG_RAM 0x00U /* Flags that pbuf data is stored in RAM */ +#define PBUF_FLAG_ROM 0x01U /* Flags that pbuf data is stored in ROM */ +#define PBUF_FLAG_POOL 0x02U /* Flags that the pbuf comes from the pbuf pool */ +#define PBUF_FLAG_REF 0x04U /* Flags thet the pbuf payload refers to RAM */ + +typedef enum { + PBUF_TRANSPORT, + PBUF_LINK, + PBUF_RAW +} pbuf_layer; + +typedef enum { + PBUF_POOL, + PBUF_RAM, + PBUF_ROM, + PBUF_REF +} pbuf_flag; + +struct pbuf { + struct pbuf *next; + void *payload; + u16_t tot_len; + u16_t len; + u16_t flags; + u16_t ref; +}; + +void btpbuf_init(); +struct pbuf* btpbuf_alloc(pbuf_layer layer,u16_t len,pbuf_flag flag); +u8_t btpbuf_free(struct pbuf *p); +void btpbuf_realloc(struct pbuf *p,u16_t new_len); +u8_t btpbuf_header(struct pbuf *p,s16_t hdr_size_inc); +void btpbuf_cat(struct pbuf *h,struct pbuf *t); +u8_t btpbuf_clen(struct pbuf *p); +void btpbuf_queue(struct pbuf *p,struct pbuf *n); +void btpbuf_ref(struct pbuf *p); +void btpbuf_chain(struct pbuf *h,struct pbuf *t); +struct pbuf* btpbuf_dequeue(struct pbuf *p); +struct pbuf* btpbuf_dechain(struct pbuf *p); +struct pbuf* btpbuf_take(struct pbuf *p); + +#endif diff --git a/wii/libogc/lwbt/hci.c b/wii/libogc/lwbt/hci.c new file mode 100644 index 0000000000..fa0a1e8378 --- /dev/null +++ b/wii/libogc/lwbt/hci.c @@ -0,0 +1,1772 @@ +/* + * Copyright (c) 2003 EISLAB, Lulea University of Technology. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwBT Bluetooth stack. + * + * Author: Conny Ohult + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* hci.c + * + * Implementation of the Host Controller Interface (HCI). A command interface to the + * baseband controller and link manager, and gives access to hardware status and + * control registers. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include + +#include "hci.h" +#include "l2cap.h" +#include "btmemr.h" +#include "btmemb.h" +#include "btpbuf.h" +#include "physbusif.h" + +struct hci_pcb *hci_dev = NULL; +struct hci_link *hci_active_links = NULL; +struct hci_link *hci_tmp_link = NULL; +struct hci_link_key *hci_tmp_key = NULL; + +MEMB(hci_pcbs,sizeof(struct hci_pcb),MEMB_NUM_HCI_PCB); +MEMB(hci_links,sizeof(struct hci_link),MEMB_NUM_HCI_LINK); +MEMB(hci_inq_results,sizeof(struct hci_inq_res),MEMB_NUM_HCI_INQ); +MEMB(hci_link_key_results,sizeof(struct hci_link_key),MEMB_NUM_HCI_LINK_KEY); + +err_t hci_init(void) +{ + btmemr_init(); + btpbuf_init(); + + btmemb_init(&hci_pcbs); + btmemb_init(&hci_links); + btmemb_init(&hci_inq_results); + btmemb_init(&hci_link_key_results); + + if((hci_dev=btmemb_alloc(&hci_pcbs))==NULL) { + ERROR("hci_init: Could not allocate memory for hci_dev\n"); + return ERR_MEM; + } + memset(hci_dev,0,sizeof(struct hci_pcb)); + + hci_active_links = NULL; + hci_tmp_link = NULL; + + return ERR_OK; +} + +struct hci_link* hci_new(void) +{ + struct hci_link *link; + + link = btmemb_alloc(&hci_links); + if(link==NULL) return NULL; + + memset(link,0,sizeof(struct hci_link)); + return link; +} + +struct hci_link* hci_get_link(struct bd_addr *bdaddr) +{ + struct hci_link *link; + + for(link=hci_active_links;link!=NULL;link=link->next) { + if(bd_addr_cmp(&(link->bdaddr),bdaddr)) break; + } + return link; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * hci_close(): + * + * Close the link control block. + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_close(struct hci_link *link) +{ + if(link->p != NULL) { + btpbuf_free(link->p); + } + + HCI_RMV(&(hci_active_links), link); + btmemb_free(&hci_links, link); + link = NULL; + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * hci_reset_all(): + * + * Closes all active link control blocks. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_reset_all(void) +{ + struct hci_link *link,*tlink; + struct hci_inq_res *ires,*tires; + struct hci_link_key *ikeys,*tikeys; + + for(link=hci_active_links;link!=NULL;) { + tlink = link->next; + hci_close(link); + link = tlink; + } + hci_active_links = NULL; + + for(ires=hci_dev->ires;ires!=NULL;) { + tires = ires->next; + btmemb_free(&hci_inq_results,ires); + ires = tires; + } + + for(ikeys=hci_dev->keyres;ikeys!=NULL;) { + tikeys = ikeys->next; + btmemb_free(&hci_inq_results,ikeys); + ikeys = tikeys; + } + btmemb_free(&hci_pcbs,hci_dev); + + hci_init(); +} + +void hci_arg(void *arg) +{ + hci_dev->cbarg = arg; +} + +void hci_cmd_complete(err_t (*cmd_complete)(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result)) +{ + hci_dev->cmd_complete = cmd_complete; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * hci_pin_req(): + * + * Used to specify the function that should be called when HCI has received a + * PIN code request event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_pin_req(err_t (* pin_req)(void *arg, struct bd_addr *bdaddr)) +{ + hci_dev->pin_req = pin_req; +} +/*-----------------------------------------------------------------------------------*/ +/* + * hci_link_key_req(): + * + * Used to specify the function that should be called when HCI has received a + * Link Key request event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_link_key_req(err_t (* link_key_req)(void *arg, struct bd_addr *bdaddr)) +{ + hci_dev->link_key_req = link_key_req; +} +/*-----------------------------------------------------------------------------------*/ +/* + * hci_link_key_not(): + * + * Used to specify the function that should be called when HCI has received a + * link key notification event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_link_key_not(err_t (* link_key_not)(void *arg, struct bd_addr *bdaddr, u8_t *key)) +{ + hci_dev->link_key_not = link_key_not; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * hci_connection_complete(): + * + * Used to specify the function that should be called when HCI has received a + * connection complete event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_connection_complete(err_t (* conn_complete)(void *arg, struct bd_addr *bdaddr)) +{ + hci_dev->conn_complete = conn_complete; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * hci_wlp_complete(): + * + * Used to specify the function that should be called when HCI has received a + * successful write link policy complete event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_wlp_complete(err_t (* wlp_complete)(void *arg, struct bd_addr *bdaddr)) +{ + hci_dev->wlp_complete = wlp_complete; +} + +void hci_conn_req(err_t (*conn_req)(void *arg,struct bd_addr *bdaddr,u8_t *cod,u8_t link_type)) +{ + hci_dev->conn_req = conn_req; +} + +err_t hci_reg_dev_info(struct bd_addr *bdaddr,u8_t *cod,u8_t psrm,u8_t psm,u16_t co) +{ + struct hci_inq_res *ires; + + if(hci_dev==NULL) return ERR_VAL; + + if((ires=btmemb_alloc(&hci_inq_results))!=NULL) { + bd_addr_set(&(ires->bdaddr),bdaddr); + memcpy(ires->cod,cod,3); + ires->psrm = psrm; + ires->psm = psm; + ires->co = co; + ires->next = NULL; + + HCI_REG(&(hci_dev->ires),ires); + return ERR_OK; + } + return ERR_MEM; +} + +struct pbuf* hci_cmd_ass(struct pbuf *p,u8_t ocf,u8_t ogf,u8_t len) +{ + ((u8_t*)p->payload)[0] = HCI_COMMAND_DATA_PACKET; /* cmd packet type */ + ((u8_t*)p->payload)[1] = (ocf&0xff); /* OCF & OGF */ + ((u8_t*)p->payload)[2] = ((ocf>>8)|(ogf<<2)); + ((u8_t*)p->payload)[3] = len-HCI_CMD_HDR_LEN-1; /* Param len = plen - cmd hdr - ptype */ + + if(hci_dev->num_cmd>0) hci_dev->num_cmd--; + return p; +} + +err_t hci_reset(void) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_RESET_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_reset: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_RESET_OCF,HCI_HC_BB_OGF,HCI_RESET_PLEN); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_read_buffer_size(void) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_BUF_SIZE_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_buffer_size: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_R_BUF_SIZE_OCF,HCI_INFO_PARAM_OGF,HCI_R_BUF_SIZE_PLEN); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_read_bd_addr(void) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_BD_ADDR_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_bd_addr: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_R_BD_ADDR_OCF,HCI_INFO_PARAM_OGF,HCI_R_BD_ADDR_PLEN); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_read_local_version(void) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_LOC_VERS_SIZE_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_local_version: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_R_LOC_VERSION_OCF,HCI_INFO_PARAM_OGF,HCI_R_LOC_VERS_SIZE_PLEN); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_read_local_features(void) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_LOC_FEAT_SIZE_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_local_features: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_R_LOC_FEATURES_OCF,HCI_INFO_PARAM_OGF,HCI_R_LOC_FEAT_SIZE_PLEN); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_read_stored_link_key() +{ + struct pbuf *p = NULL; + struct hci_link_key *tmpres; + + /* Free any previous link key result list */ + while(hci_dev->keyres != NULL) { + tmpres = hci_dev->keyres; + hci_dev->keyres = hci_dev->keyres->next; + btmemb_free(&hci_link_key_results,tmpres); + } + + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_STORED_LINK_KEY_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_stored_link_keys: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_R_STORED_LINK_KEY_OCF,HCI_HC_BB_OGF,HCI_R_STORED_LINK_KEY_PLEN); + + memcpy((void*)((u8_t*)p->payload + 4),hci_dev->bdaddr.addr,6); + ((u8_t*)p->payload)[10] = 1; + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_set_event_filter(u8_t filter_type,u8_t filter_cond_type,u8_t *cond) +{ + u32 cond_len = 0; + struct pbuf *p = NULL; + + switch(filter_type) { + case 0x00: + cond_len = 0x00; + break; + case 0x01: + switch(filter_cond_type) { + case 0x00: + cond_len = 0x00; + break; + case 0x01: + cond_len = 0x06; + break; + case 0x02: + cond_len = 0x06; + break; + default: + break; + } + break; + case 0x02: + switch(filter_cond_type) { + case 0x00: + cond_len = 0x01; + break; + case 0x01: + cond_len = 0x07; + break; + case 0x02: + cond_len = 0x07; + break; + default: + break; + } + break; + default: + break; + } + + if((p=btpbuf_alloc(PBUF_RAW,HCI_SET_EV_FILTER_PLEN+cond_len,PBUF_RAM))==NULL) { + ERROR("hci_set_event_filter: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_SET_EV_FILTER_OCF,HCI_HC_BB_OGF,HCI_SET_EV_FILTER_PLEN+cond_len); + ((u8_t*)p->payload)[4] = filter_type; + ((u8_t*)p->payload)[5] = filter_cond_type; + if(cond_len>0) memcpy(p->payload+6,cond,cond_len); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_write_page_timeout(u16_t timeout) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_PAGE_TIMEOUT_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_set_write_page_timeout: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_W_PAGE_TIMEOUT_OCF,HCI_HC_BB_OGF,HCI_W_PAGE_TIMEOUT_PLEN); + ((u16_t*)p->payload)[2] = htole16(timeout); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_write_scan_enable(u8_t scan_enable) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_SCAN_EN_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_set_write_page_timeout: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_W_SCAN_EN_OCF,HCI_HC_BB_OGF,HCI_W_SCAN_EN_PLEN); + ((u8_t*)p->payload)[4] = scan_enable; + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_inquiry(u32_t lap,u8_t inq_len,u8_t num_resp,err_t (*inq_complete)(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result)) +{ + struct pbuf *p = NULL; + struct hci_inq_res *tmpres; + + /* Free any previous inquiry result list */ + while(hci_dev->ires != NULL) { + tmpres = hci_dev->ires; + hci_dev->ires = hci_dev->ires->next; + btmemb_free(&hci_inq_results,tmpres); + } + + hci_dev->inq_complete = inq_complete; + if((p=btpbuf_alloc(PBUF_RAW,HCI_INQUIRY_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_inquiry: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_INQUIRY_OCF,HCI_LINK_CTRL_OGF,HCI_INQUIRY_PLEN); + ((u8_t*)p->payload)[4] = (lap&0xff); + ((u8_t*)p->payload)[5] = (lap>>8); + ((u8_t*)p->payload)[6] = (lap>>16); + + ((u8_t*)p->payload)[7] = inq_len; + ((u8_t*)p->payload)[8] = num_resp; + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_periodic_inquiry(u32_t lap,u16_t min_period,u16_t max_period,u8_t inq_len,u8_t num_resp,err_t (*inq_complete)(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result)) +{ + struct pbuf *p = NULL; + struct hci_inq_res *tmpres; + + /* Free any previous inquiry result list */ + while(hci_dev->ires != NULL) { + tmpres = hci_dev->ires; + hci_dev->ires = hci_dev->ires->next; + btmemb_free(&hci_inq_results,tmpres); + } + + hci_dev->inq_complete = inq_complete; + if((p=btpbuf_alloc(PBUF_RAW,HCI_PERIODIC_INQUIRY_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_periodic_inquiry: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_PERIODIC_INQUIRY_OCF,HCI_LINK_CTRL_OGF,HCI_PERIODIC_INQUIRY_PLEN); + + /* Assembling cmd prameters */ + ((u16_t*)p->payload)[2] = htole16(max_period); + ((u16_t*)p->payload)[3] = htole16(min_period); + ((u8_t*)p->payload)[8] = (lap&0xff); + ((u8_t*)p->payload)[9] = (lap>>8); + ((u8_t*)p->payload)[10] = (lap>>16); + + ((u8_t*)p->payload)[11] = inq_len; + ((u8_t*)p->payload)[12] = num_resp; + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_exit_periodic_inquiry() +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_EXIT_PERIODIC_INQUIRY_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_exit_periodic_inquiry: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_EXIT_PERIODIC_INQUIRY_OCF,HCI_LINK_CTRL_OGF,HCI_EXIT_PERIODIC_INQUIRY_PLEN); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_accecpt_conn_request(struct bd_addr *bdaddr,u8_t role) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_ACCEPT_CONN_REQ_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_exit_periodic_inquiry: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_ACCEPT_CONN_REQ_OCF,HCI_LINK_CTRL_OGF,HCI_ACCEPT_CONN_REQ_PLEN); + + /* Assembling cmd prameters */ + memcpy((void*)(((u8_t*)p->payload)+4),bdaddr,6); + ((u8_t*)p->payload)[10] = role; + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_set_event_mask(u64_t ev_mask) +{ + u64_t mask; + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_SET_EV_MASK_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_set_event_mask: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_SET_EV_MASK_OCF,HCI_HC_BB_OGF,HCI_SET_EV_MASK_PLEN); + + mask = htole64(ev_mask); + memcpy(((u8_t*)p->payload)+4,&mask,8); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_write_local_name(u8_t *name,u8_t len) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_LOCAL_NAME_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_write_local_name: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_W_LOCAL_NAME_OCF,HCI_HC_BB_OGF,HCI_W_LOCAL_NAME_PLEN); + /* Assembling cmd prameters */ + memcpy(((u8_t *)p->payload) + 4, name, len); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_write_pin_type(u8_t type) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_PIN_TYPE_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_write_local_name: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_W_PIN_TYPE_OCF,HCI_HC_BB_OGF,HCI_W_PIN_TYPE_PLEN); + /* Assembling cmd prameters */ + ((u8_t *)p->payload)[4] = type; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_read_remote_name(struct bd_addr *bdaddr) +{ + u16_t clock_offset; + struct pbuf *p = NULL; + struct hci_inq_res *ires; + u8_t page_scan_repetition_mode, page_scan_mode; + + for(ires=hci_dev->ires;ires!=NULL;ires=ires->next) { + if(bd_addr_cmp(&(ires->bdaddr),bdaddr)) { + page_scan_repetition_mode = ires->psrm; + page_scan_mode = ires->psm; + clock_offset = ires->co; + break; + } + } + + if(ires==NULL) { + page_scan_repetition_mode = 0x01; + page_scan_mode = 0x00; + clock_offset = 0x00; + } + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_REMOTE_NAME_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_remote_name: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_R_REMOTE_NAME_OCF,HCI_LINK_CTRL_OGF,HCI_R_REMOTE_NAME_PLEN); + /* Assembling cmd prameters */ + memcpy(((u8_t *)p->payload+4),bdaddr->addr,6); + ((u8_t*)p->payload)[10] = page_scan_repetition_mode; + ((u8_t*)p->payload)[11] = page_scan_mode; + ((u16_t*)p->payload)[6] = htole16(clock_offset); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; + +} + +err_t hci_write_inquiry_mode(u8_t mode) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_INQUIRY_MODE_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_write_inquiry_mode: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_W_INQUIRY_MODE_OCF,HCI_HC_BB_OGF,HCI_W_INQUIRY_MODE_PLEN); + /* Assembling cmd prameters */ + ((u8_t*)p->payload)[4] = mode; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_write_page_scan_type(u8_t type) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_PAGE_SCAN_TYPE_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_write_inquiry_mode: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_W_PAGE_SCAN_TYPE_OCF,HCI_HC_BB_OGF,HCI_W_PAGE_SCAN_TYPE_PLEN); + /* Assembling cmd prameters */ + ((u8_t*)p->payload)[4] = type; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_write_inquiry_scan_type(u8_t type) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_INQUIRY_SCAN_TYPE_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_write_inquiry_mode: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_W_INQUIRY_SCAN_TYPE_OCF,HCI_HC_BB_OGF,HCI_W_INQUIRY_SCAN_TYPE_PLEN); + /* Assembling cmd prameters */ + ((u8_t*)p->payload)[4] = type; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_vendor_specific_command(u8_t ocf,u8_t ogf,void *data,u8_t len) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_W_VENDOR_CMD_PLEN + len,PBUF_RAM))==NULL) { + ERROR("hci_vendor_specific_patch: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,ocf,ogf,HCI_W_VENDOR_CMD_PLEN + len); + /* Assembling cmd prameters */ + memcpy(((u8_t*)p->payload + 4),data,len); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* hci_sniff_mode(): + * + * Sets an ACL connection to low power Sniff mode. + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_sniff_mode(struct bd_addr *bdaddr, u16_t max_interval, u16_t min_interval, u16_t attempt, u16_t timeout) +{ + struct pbuf *p; + struct hci_link *link; + + /* Check if an ACL connection exists */ + link = hci_get_link(bdaddr); + + if(link == NULL) { + ERROR("hci_sniff_mode: ACL connection does not exist\n"); + return ERR_CONN; + } + + if((p = btpbuf_alloc(PBUF_TRANSPORT, HCI_SNIFF_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ + ERROR("hci_sniff_mode: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_SNIFF_MODE_OCF, HCI_LINK_POLICY_OGF, HCI_SNIFF_PLEN); + /* Assembling cmd prameters */ + ((u16_t *)p->payload)[2] = htole16(link->connhdl); + ((u16_t *)p->payload)[3] = htole16(max_interval); + ((u16_t *)p->payload)[4] = htole16(min_interval); + ((u16_t *)p->payload)[5] = htole16(attempt); + ((u16_t *)p->payload)[6] = htole16(timeout); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* hci_write_link_policy_settings(): + * + * Control the modes (park, sniff, hold) that an ACL connection can take. + * + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_write_link_policy_settings(struct bd_addr *bdaddr, u16_t link_policy) +{ + struct pbuf *p; + struct hci_link *link; + + /* Check if an ACL connection exists */ + link = hci_get_link(bdaddr); + + if(link == NULL) { + ERROR("hci_write_link_policy_settings: ACL connection does not exist\n"); + return ERR_CONN; + } + + if( (p = btpbuf_alloc(PBUF_TRANSPORT, HCI_W_LINK_POLICY_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ + ERROR("hci_write_link_policy_settings: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_W_LINK_POLICY_OCF, HCI_LINK_POLICY_OGF, HCI_W_LINK_POLICY_PLEN); + + /* Assembling cmd prameters */ + ((u16_t *)p->payload)[2] = htole16(link->connhdl); + ((u16_t *)p->payload)[3] = htole16(link_policy); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_pin_code_request_reply(): + * + * Used to reply to a PIN Code Request event from the Host Controller and specifies + * the PIN code to use for a connection. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_pin_code_request_reply(struct bd_addr *bdaddr, u8_t pinlen, u8_t *pincode) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_PIN_CODE_REQ_REP_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_pin_code_request_reply: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Reset buffer content just to make sure */ + memset((u8_t *)p->payload, 0, HCI_PIN_CODE_REQ_REP_PLEN); + + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_PIN_CODE_REQ_REP, HCI_LINK_CTRL_OGF, HCI_PIN_CODE_REQ_REP_PLEN); + /* Assembling cmd prameters */ + memcpy(((u8_t *)p->payload) + 4, bdaddr->addr, 6); + ((u8_t *)p->payload)[10] = pinlen; + memcpy(((u8_t *)p->payload) + 11, pincode, pinlen); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_link_key_req_reply(): + * + * Used to reply to a Link Key Code Request event from the Host Controller and specifies + * the Link Key to use for a connection. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_link_key_req_reply(struct bd_addr *bdaddr, unsigned char *link_key) +{ + struct pbuf *p; + if ((p = btpbuf_alloc(PBUF_RAW, HCI_LINK_KEY_REQ_REP_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_link_key_req_reply: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p, HCI_LINK_KEY_REQ_REP, HCI_LINK_CTRL_OGF, HCI_LINK_KEY_REQ_REP_PLEN); + //copy bdaddr to offset 0x4 + memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); + //copy Link Key (16 bytes long) to offset 10 (0xA) + memcpy(((u8_t *)p->payload)+10, link_key, 16); + //send command + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + + +/*-----------------------------------------------------------------------------------*/ +/* hci_pin_code_request_neg_reply(): + * + * Used to reply to a PIN Code Request event from the Host Controller when the Host + * cannot specify a PIN code to use for a connection. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_pin_code_request_neg_reply(struct bd_addr *bdaddr) +{ + struct pbuf *p; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_PIN_CODE_REQ_NEG_REP_PLEN,PBUF_RAM)) == NULL) { + ERROR("hci_pin_code_request_neg_reply: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p,HCI_PIN_CODE_REQ_NEG_REP,HCI_LINK_CTRL_OGF,HCI_PIN_CODE_REQ_NEG_REP_PLEN); + memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_link_key_req_neg_reply(): + * + * Used to reply to a Link Key Request event from the Host Controller when the Host + * cannot specify a Link Key to use for a connection. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_link_key_req_neg_reply(struct bd_addr *bdaddr) +{ + struct pbuf *p; + + if ((p = btpbuf_alloc(PBUF_RAW, HCI_LINK_KEY_REQ_REP_NEG_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_link_key_req_neg_repl: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + p = hci_cmd_ass(p, HCI_LINK_KEY_REQ_REP_NEG, HCI_LINK_CTRL_OGF, HCI_LINK_KEY_REQ_REP_NEG_PLEN); + memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); + + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_disconnect(): + * + * Used to terminate an existing connection. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_disconnect(struct bd_addr *bdaddr, u8_t reason) +{ + struct pbuf *p; + struct hci_link *link; + + link = hci_get_link(bdaddr); + + if(link == NULL) { + ERROR("hci_disconnect: Connection does not exist\n"); + return ERR_CONN; /* Connection does not exist */ + } + if((p = btpbuf_alloc(PBUF_RAW, HCI_DISCONN_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_disconnect: Could not allocate memory for pbuf\n"); + return ERR_MEM; /* Could not allocate memory for pbuf */ + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_DISCONN_OCF, HCI_LINK_CTRL_OGF, HCI_DISCONN_PLEN); + + /* Assembling cmd prameters */ + ((u16_t *)p->payload)[2] = htole16(link->connhdl); + ((u8_t *)p->payload)[6] = reason; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_reject_connection_request(): + * + * Used to decline a new incoming connection request. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_reject_connection_request(struct bd_addr *bdaddr, u8_t reason) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_REJECT_CONN_REQ_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_reject_connection_request: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_REJECT_CONN_REQ_OCF, HCI_LINK_CTRL_OGF, HCI_REJECT_CONN_REQ_PLEN); + /* Assembling cmd prameters */ + memcpy(((u8_t *)p->payload) + 4, bdaddr->addr, 6); + ((u8_t *)p->payload)[10] = reason; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_write_stored_link_key(): + * + * Writes a link key to be stored in the Bluetooth host controller. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_write_stored_link_key(struct bd_addr *bdaddr, u8_t *link) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_WRITE_STORED_LINK_KEY_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_write_stored_link_key: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_WRITE_STORED_LINK_KEY, HCI_HC_BB_OGF, HCI_WRITE_STORED_LINK_KEY_PLEN); + /* Assembling cmd prameters */ + ((u8_t *)p->payload)[4] = 0x01; + memcpy(((u8_t *)p->payload) + 5, bdaddr->addr, 6); + memcpy(((u8_t *)p->payload) + 11, link, 16); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_write_cod(): + * + * Write the value for the Class_of_Device parameter, which is used to indicate its + * capabilities to other devices. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_write_cod(u8_t *cod) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_W_COD_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_write_cod: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_W_COD_OCF, HCI_HC_BB_OGF, HCI_W_COD_PLEN); + /* Assembling cmd prameters */ + memcpy(((u8_t *)p->payload)+4, cod, 3); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +err_t hci_read_current_lap(void) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_R_CUR_IACLAP_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_read_current_lap: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_R_CUR_IACLAP_OCF, HCI_HC_BB_OGF, HCI_R_CUR_IACLAP_PLEN); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_set_hc_to_h_fc(): + * + * Used by the Host to turn flow control on or off in the direction from the Host + * Controller to the Host. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_set_hc_to_h_fc(void) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_SET_HC_TO_H_FC_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_set_hc_to_h_fc: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_SET_HC_TO_H_FC_OCF, HCI_HC_BB_OGF, HCI_SET_HC_TO_H_FC_PLEN); + /* Assembling cmd prameters */ + ((u8_t *)p->payload)[4] = 0x01; /* Flow control on for HCI ACL Data Packets and off for HCI + SCO Data Packets in direction from Host Controller to + Host */ + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_host_buffer_size(): + * + * Used by the Host to notify the Host Controller about the maximum size of the data + * portion of HCI ACL Data Packets sent from the Host Controller to the Host. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_host_buffer_size(void) +{ + struct pbuf *p; + if((p = btpbuf_alloc(PBUF_RAW, HCI_H_BUF_SIZE_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_host_buffer_size: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_H_BUF_SIZE_OCF, HCI_HC_BB_OGF, HCI_H_BUF_SIZE_PLEN); + ((u16_t *)p->payload)[2] = htole16(HCI_HOST_ACL_MAX_LEN); /* Host ACL data packet maximum length */ + ((u8_t *)p->payload)[6] = 255; /* Host SCO Data Packet Length */ + *((u16_t *)(((u8_t *)p->payload)+7)) = htole16(HCI_HOST_MAX_NUM_ACL); /* Host max total num ACL data packets */ + ((u16_t *)p->payload)[4] = htole16(1); /* Host Total Num SCO Data Packets */ + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + hci_dev->host_num_acl = HCI_HOST_MAX_NUM_ACL; + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_host_num_comp_packets(): + * + * Used by the Host to indicate to the Host Controller the number of HCI Data Packets + * that have been completed for each Connection Handle since the previous + * Host_Number_Of_Completed_Packets command was sent to the Host Controller. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_host_num_comp_packets(u16_t conhdl, u16_t num_complete) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_H_NUM_COMPL_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_host_num_comp_packets: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_H_NUM_COMPL_OCF, HCI_HC_BB_OGF, HCI_H_NUM_COMPL_PLEN); + ((u8_t*)p->payload)[4] = 1; + *(u16_t*)(p->payload+5) = htole16(conhdl); + *(u16_t*)(p->payload+7) = htole16(num_complete); /* Number of completed acl packets */ + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + hci_dev->host_num_acl += num_complete; + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* lp_pdu_maxsize(): + * + * Called by L2CAP to check the maxsize of the PDU. In this case it is the largest + * ACL packet that the Host Controller can buffer. + */ +/*-----------------------------------------------------------------------------------*/ +u16_t lp_pdu_maxsize() +{ + return hci_dev->acl_mtu; +} + +/*-----------------------------------------------------------------------------------*/ +/* lp_is_connected(): + * + * Called by L2CAP to check if an active ACL connection exists for the specified + * Bluetooth address. + */ +/*-----------------------------------------------------------------------------------*/ +u8_t lp_is_connected(struct bd_addr *bdaddr) +{ + struct hci_link *link; + + link = hci_get_link(bdaddr); + + if(link == NULL) { + return 0; + } + return 1; +} + +/*-----------------------------------------------------------------------------------*/ +/* lp_acl_write(): + * + * Called by L2CAP to send data to the Host Controller that will be transfered over + * the ACL link from there. + */ +/*-----------------------------------------------------------------------------------*/ +err_t lp_acl_write(struct bd_addr *bdaddr,struct pbuf *p,u16_t len,u8_t pb) +{ + u16_t connhdlpbbc; + struct hci_link *link; + struct hci_acl_hdr *aclhdr; + struct pbuf *q; + + link = hci_get_link(bdaddr); + if(link==NULL) { + ERROR("lp_acl_write: ACL connection does not exist\n"); + return ERR_CONN; + } + + if(hci_dev->acl_max_pkt==0) { + if(p != NULL) { + /* Packet can be queued? */ + if(link->p != NULL) { + LOG("lp_acl_write: Host buffer full. Dropped packet\n"); + return ERR_OK; /* Drop packet */ + } else { + /* Copy PBUF_REF referenced payloads into PBUF_RAM */ + p = btpbuf_take(p); + /* Remember pbuf to queue, if any */ + link->p = p; + link->len = len; + link->pb = pb; + /* Pbufs are queued, increase the reference count */ + btpbuf_ref(p); + LOG("lp_acl_write: Host queued packet %p\n", (void *)p); + } + } + } + + if((q=btpbuf_alloc(PBUF_RAW,HCI_ACL_HDR_LEN+1,PBUF_RAM))==NULL) { + ERROR("lp_acl_write: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + btpbuf_chain(q,p); + ((u8_t*)q->payload)[0] = HCI_ACL_DATA_PACKET; + + aclhdr = (void*)((u8_t*)q->payload+1); + //aclhdr->connhdl_pb_bc = CONNPBBC(link->connhdl,pb,0); + connhdlpbbc = link->connhdl; /* Received from connection complete event */ + connhdlpbbc |= (pb<<12); /* Packet boundary flag */ + connhdlpbbc &= 0x3FFF; /* Point-to-point */ + aclhdr->connhdl_pb_bc = htole16(connhdlpbbc); + aclhdr->len = htole16(len); + + physbusif_output(q,(q->len+len)); + --hci_dev->acl_max_pkt; + + p = btpbuf_dechain(q); + btpbuf_free(q); + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* lp_write_flush_timeout(): + * + * Called by L2CAP to set the flush timeout for the ACL link. + */ +/*-----------------------------------------------------------------------------------*/ +err_t lp_write_flush_timeout(struct bd_addr *bdaddr, u16_t flushto) +{ + struct hci_link *link; + struct pbuf *p; + + /* Check if an ACL connection exists */ + link = hci_get_link(bdaddr); + + if(link == NULL) { + ERROR("lp_write_flush_timeout: ACL connection does not exist\n"); + return ERR_CONN; + } + + if((p = btpbuf_alloc(PBUF_TRANSPORT, HCI_W_FLUSHTO_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ + ERROR("lp_write_flush_timeout: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_W_FLUSHTO, HCI_HC_BB_OGF, HCI_W_FLUSHTO_PLEN); + /* Assembling cmd prameters */ + ((u16_t *)p->payload)[2] = htole16(link->connhdl); + ((u16_t *)p->payload)[3] = htole16(flushto); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* lp_connect_req(): + * + * Called by L2CAP to cause the Link Manager to create a connection to the + * Bluetooth device with the BD_ADDR specified by the command parameters. + */ +/*-----------------------------------------------------------------------------------*/ +err_t lp_connect_req(struct bd_addr *bdaddr, u8_t allow_role_switch) +{ + u8_t page_scan_repetition_mode, page_scan_mode; + u16_t clock_offset; + struct pbuf *p; + struct hci_link *link = hci_new(); + struct hci_inq_res *inqres; + + if(link == NULL) { + ERROR("lp_connect_req: Could not allocate memory for link\n"); + return ERR_MEM; /* Could not allocate memory for link */ + } + + bd_addr_set(&(link->bdaddr), bdaddr); + HCI_REG(&(hci_active_links), link); + + + /* Check if module has been discovered in a recent inquiry */ + for(inqres = hci_dev->ires; inqres != NULL; inqres = inqres->next) { + if(bd_addr_cmp(&inqres->bdaddr, bdaddr)) { + page_scan_repetition_mode = inqres->psrm; + page_scan_mode = inqres->psm; + clock_offset = inqres->co; + break; + } + } + if(inqres == NULL) { + /* No information on parameters from an inquiry. Using default values */ + page_scan_repetition_mode = 0x01; /* Assuming worst case: time between + successive page scans starting + <= 2.56s */ + page_scan_mode = 0x00; /* Assumes the device uses mandatory scanning, most + devices use this. If no conn is established, try + again w this parm set to optional page scanning */ + clock_offset = 0x00; /* If the device was not found in a recent inquiry + this information is irrelevant */ + } + + if((p = btpbuf_alloc(PBUF_RAW, HCI_CREATE_CONN_PLEN, PBUF_RAM)) == NULL) { + ERROR("lp_connect_req: Could not allocate memory for pbuf\n"); + return ERR_MEM; /* Could not allocate memory for pbuf */ + } + + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_CREATE_CONN_OCF, HCI_LINK_CTRL_OGF, HCI_CREATE_CONN_PLEN); + /* Assembling cmd prameters */ + memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); + ((u16_t *)p->payload)[5] = htole16(hci_dev->pkt_type); + ((u8_t *)p->payload)[12] = page_scan_repetition_mode; + ((u8_t *)p->payload)[13] = page_scan_mode; + ((u16_t *)p->payload)[7] = htole16(clock_offset); + ((u8_t *)p->payload)[16] = allow_role_switch; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +static void hci_cc_info_param(u8_t ocf,struct pbuf *p) +{ + struct bd_addr *bdaddr; + + switch(ocf) { + case HCI_READ_LOCAL_VERSION: + if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { + hci_dev->info.hci_version = *((u8_t*)p->payload + 1); + hci_dev->info.hci_revision = le16toh(*(u16_t*)((u8_t*)p->payload + 2)); + hci_dev->info.lmp_version = *((u8_t*)p->payload + 4); + hci_dev->info.manufacturer = le16toh(*(u16_t*)((u8_t*)p->payload + 5)); + hci_dev->info.lmp_subversion = le16toh(*(u16_t*)((u8_t*)p->payload + 7)); + LOG("hci_cc_info_param(HCI_READ_LOCAL_VERSION): hci_version = %02x, hci_revision = %04x, lmp_version = %02x, manufacturer = %04x, lmp_suversion = %04x\n",hci_dev->info.hci_version,hci_dev->info.hci_revision,hci_dev->info.lmp_version,hci_dev->info.manufacturer,hci_dev->info.lmp_subversion); + } + break; + case HCI_READ_LOCAL_FEATURES: + if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { + memcpy(hci_dev->features,(void*)((u8_t*)p->payload+1),sizeof(hci_dev->features)); + + if(hci_dev->features[0]&LMP_3SLOT) + hci_dev->pkt_type |= (HCI_DM3|HCI_DH3); + if(hci_dev->features[0]&LMP_5SLOT) + hci_dev->pkt_type |= (HCI_DM5|HCI_DH5); + if(hci_dev->features[1]&LMP_HV2) + hci_dev->pkt_type |= HCI_HV2; + if(hci_dev->features[1]&LMP_HV3) + hci_dev->pkt_type |= HCI_HV3; + LOG("hci_cc_info_param(HCI_READ_LOCAL_FEATURES): %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",hci_dev->features[0],hci_dev->features[1],hci_dev->features[2],hci_dev->features[3], + hci_dev->features[4],hci_dev->features[5],hci_dev->features[6],hci_dev->features[7]); + } + break; + case HCI_READ_BUFFER_SIZE: + if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { + hci_dev->acl_mtu = le16toh(*(u16_t*)(((u8_t*)p->payload)+1)); + hci_dev->sco_mtu = *((u8_t*)p->payload+3); + hci_dev->acl_max_pkt = le16toh(*(u16_t*)(((u8_t*)p->payload)+4)); + hci_dev->sco_max_pkt = le16toh(*(u16_t*)(((u8_t*)p->payload)+5)); + LOG("hci_cc_info_param(HCI_READ_BUFFER_SIZE): acl_mt = %d, sco_mt = %d, acl_max_pkt = %d, sco_max_pkt = %d\n",hci_dev->acl_mtu,hci_dev->sco_mtu,hci_dev->acl_max_pkt,hci_dev->sco_max_pkt); + } + break; + case HCI_READ_BD_ADDR: + if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { + bdaddr = (void*)((u8_t*)p->payload+1); + LOG("hci_cc_info_param(HCI_READ_BD_ADDR): %02x:%02x:%02x:%02x:%02x:%02x",bdaddr->addr[0],bdaddr->addr[1],bdaddr->addr[2],bdaddr->addr[3],bdaddr->addr[4],bdaddr->addr[5]); + bd_addr_set(&(hci_dev->bdaddr),bdaddr); + } + break; + } +} + +static void hci_cc_host_ctrl(u8_t ocf,struct pbuf *p) +{ + u8_t *lap; + u8_t i,resp_off; + + //printf("hci_cc_host_ctrl(%02x)\n",ocf); + switch(ocf) { + case HCI_SET_HC_TO_H_FC: + if(((u8_t*)p->payload)[0]==HCI_SUCCESS) hci_dev->flow = 1; + break; + case HCI_READ_CUR_IACLAP: + if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { + for(i=0;i<((u8_t*)p->payload)[1];i++) { + resp_off = (i*3); + lap = (void*)(((u8_t*)p->payload)+(2+resp_off)); + printf("lap = 00%02x%02x%02x\n",lap[2],lap[1],lap[0]); + } + } + break; + } +} + +static void hci_cc_link_policy(u8_t ocf,struct pbuf *p) +{ + err_t ret; + struct hci_link *link; + + (void)ret; + + switch(ocf) { + case HCI_W_LINK_POLICY: + if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { + for(link=hci_active_links;link!=NULL;link=link->next) { + if(link->connhdl==le16toh(*((u16_t*)(((u8_t*)p->payload)+1)))) break; + } + if(link==NULL) { + LOG("hci_cc_link_policy: Connection does not exist\n"); + break; + } + HCI_EVENT_WLP_COMPLETE(hci_dev,&link->bdaddr,ret); + } else { + LOG("Unsuccessful HCI_W_LINK_POLICY.\n"); + } + break; + } +} + +static void hci_conn_request_evt(struct pbuf *p) +{ + u8_t *cod; + u8_t link_type; + err_t ret = ERR_OK; + struct bd_addr *bdaddr; + struct hci_link *link; + + LOG("hci_conn_request_evt()\n"); + bdaddr = (void*)((u8_t*)p->payload); + cod = (((u8_t*)p->payload)+6); + link_type = *(((u8_t*)p->payload)+9); + + HCI_EVENT_CONN_REQ(hci_dev,bdaddr,cod,link_type,ret); + if(ret==ERR_OK) { + link = hci_get_link(bdaddr); + if(link==NULL) { + if((link=hci_new())==NULL) { + ERROR("hci_conn_request_evt: Could not allocate memory for link. Disconnect\n"); + return; + } + + bd_addr_set(&(link->bdaddr),bdaddr); + HCI_REG(&(hci_active_links),link); + } + hci_accecpt_conn_request(bdaddr,0x00); + } else { + } +} + +static void hci_conn_complete_evt(struct pbuf *p) +{ + err_t ret; + struct bd_addr *bdaddr; + struct hci_link *link; + + (void)ret; + + bdaddr = (void*)(((u8_t*)p->payload)+3); + link = hci_get_link(bdaddr); + LOG("hci_conn_complete_evt(%p,%02x - %02x:%02x:%02x:%02x:%02x:%02x)\n",link,((u8_t*)p->payload)[0],bdaddr->addr[0],bdaddr->addr[1],bdaddr->addr[2],bdaddr->addr[3],bdaddr->addr[4],bdaddr->addr[5]); + switch(((u8_t*)p->payload)[0]) { + case HCI_SUCCESS: + if(link==NULL) { + if((link=hci_new())==NULL) { + ERROR("hci_conn_complete_evt: Could not allocate memory for link. Disconnect\n"); + hci_disconnect(bdaddr, HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES); + lp_disconnect_ind(bdaddr,HCI_CONN_TERMINATED_BY_LOCAL_HOST); + break; + } + bd_addr_set(&(link->bdaddr),bdaddr); + link->connhdl = le16toh(*((u16_t*)(((u8_t*)p->payload)+1))); + HCI_REG(&(hci_active_links),link); + HCI_EVENT_CONN_COMPLETE(hci_dev,bdaddr,ret); + lp_connect_ind(&(link->bdaddr)); + } else { + link->connhdl = le16toh(*((u16_t*)(((u8_t*)p->payload)+1))); + HCI_EVENT_CONN_COMPLETE(hci_dev,bdaddr,ret); + lp_connect_cfm(&(link->bdaddr),((u8_t*)p->payload)[10],ERR_OK); + } + break; + case HCI_PAGE_TIMEOUT: + break; + default: + if(link!=NULL) { + hci_close(link); + lp_connect_cfm(bdaddr,((u8_t*)p->payload)[10],ERR_CONN); + } + break; + } +} + +static void hci_inquiry_result_evt(struct pbuf *p) +{ + u8_t num_resp; + u32_t i,resp_off; + struct bd_addr *bdaddr; + struct hci_inq_res *ires; + + num_resp = ((u8_t*)p->payload)[0]; + //printf("hci_inquriy_result_evt(%d)\n",num_resp); + for(i=0;ipayload)+(1+resp_off)); + if((ires=btmemb_alloc(&hci_inq_results))!=NULL) { + bd_addr_set(&(ires->bdaddr),bdaddr); + ires->psrm = ((u8_t*)p->payload)[7+resp_off]; + ires->psm = ((u8_t*)p->payload)[8+resp_off]; + memcpy(ires->cod,((u8_t*)p->payload)+10+resp_off,3); + ires->co = le16toh(*((u16_t*)(((u8_t*)p->payload)+13+resp_off))); + ires->next = NULL; + + HCI_REG(&(hci_dev->ires),ires); + } else + ERROR("hci_inquriy_result_evt: Could not allocate memory for inquiry result\n"); + } + +} + +static void hci_return_link_key_evt(struct pbuf *p) +{ + u8_t num_keys; + u32_t i,resp_off; + struct bd_addr *bdaddr; + struct hci_link_key *keyres; + + num_keys = ((u8_t*)p->payload)[0]; + //printf("hci_return_link_key_evt(%d)\n",num_keys); + for(i=0;ipayload)+1+resp_off); + if((keyres=btmemb_alloc(&hci_link_key_results))!=NULL) { + bd_addr_set(&(keyres->bdaddr),bdaddr); + memcpy(keyres->key,((u8_t*)p->payload)+7+resp_off,16); + keyres->next = NULL; + + //printf("link key evt: %02x:%02x:%02x:%02x:%02x:%02x\n",bdaddr->addr[0],bdaddr->addr[1],bdaddr->addr[2],bdaddr->addr[3],bdaddr->addr[4],bdaddr->addr[5]); + HCI_REG(&(hci_dev->keyres),keyres); + } else + ERROR("hci_return_link_key_evt: Could not allocate memory for link key result\n"); + } + +} + +void hci_event_handler(struct pbuf *p) +{ + err_t ret; + u8_t i,resp_off; + u16_t ogf,ocf,opc; + u16_t connhdl; + struct pbuf *q; + struct hci_link *link; + struct bd_addr *bdaddr; + struct hci_evt_hdr *evthdr; + + (void)ret; + + evthdr = p->payload; + btpbuf_header(p,-HCI_EVENT_HDR_LEN); + + switch(evthdr->code) { + case HCI_INQUIRY_COMPLETE: + //printf("HCI_INQUIRY_COMPLETE\n"); + HCI_EVENT_INQ_COMPLETE(hci_dev,((u8_t*)p->payload)[0],ret); + break; + case HCI_INQUIRY_RESULT: + hci_inquiry_result_evt(p); + break; + case HCI_CONNECTION_COMPLETE: + hci_conn_complete_evt(p); + break; + case HCI_CONNECTION_REQUEST: + hci_conn_request_evt(p); + break; + case HCI_DISCONNECTION_COMPLETE: + switch(((u8_t*)p->payload)[0]) { + case HCI_SUCCESS: + for(link=hci_active_links;link!=NULL;link=link->next) { + if(link->connhdl==le16toh(*((u16_t*)(((u8_t*)p->payload)+1)))) break; + } + if(link!=NULL) { + lp_disconnect_ind(&(link->bdaddr),((u8_t*)p->payload)[3]); + hci_close(link); + } + break; + default: + return; + } + break; + case HCI_ENCRYPTION_CHANGE: + break; + case HCI_QOS_SETUP_COMPLETE: + break; + case HCI_COMMAND_COMPLETE: + hci_dev->num_cmd += ((u8_t*)p->payload)[0]; + btpbuf_header(p,-1); + + opc = le16toh(((u16_t*)p->payload)[0]); + ocf = (opc&0x03ff); + ogf = (opc>>10); + btpbuf_header(p,-2); + + switch(ogf) { + case HCI_INFO_PARAM: + hci_cc_info_param(ocf,p); + break; + case HCI_HOST_C_N_BB: + hci_cc_host_ctrl(ocf,p); + break; + case HCI_LINK_POLICY: + hci_cc_link_policy(ocf,p); + break; + } + HCI_EVENT_CMD_COMPLETE(hci_dev,ogf,ocf,((u8_t*)p->payload)[0],ret); + break; + case HCI_COMMAND_STATUS: + if(((u8_t*)p->payload)[0]!=HCI_SUCCESS) { + btpbuf_header(p,-2); + + opc = le16toh(((u16_t*)p->payload)[0]); + ocf = (opc&0x03ff); + ogf = (opc>>10); + btpbuf_header(p,-2); + + HCI_EVENT_CMD_COMPLETE(hci_dev,ogf,ocf,((u8_t*)p->payload)[0],ret); + btpbuf_header(p,4); + } + hci_dev->num_cmd += ((u8_t*)p->payload)[1]; + break; + case HCI_HARDWARE_ERROR: + //TODO: IS THIS FATAL?? + break; + case HCI_ROLE_CHANGE: + break; + case HCI_NBR_OF_COMPLETED_PACKETS: + for(i=0;i<((u8_t *)p->payload)[0];i++) { + resp_off = i*4; + hci_dev->acl_max_pkt += le16toh(*((u16_t *)(((u8_t *)p->payload) + 3 + resp_off))); + connhdl = le16toh(*((u16_t *)(((u8_t *)p->payload) + 1 + resp_off))); + + for(link = hci_active_links; link != NULL; link = link->next) { + if(link->connhdl == connhdl) break; + } + + q = link == NULL ? NULL : link->p; + /* Queued packet present? */ + if (q != NULL) { + /* NULL attached buffer immediately */ + link->p = NULL; + /* Send the queued packet */ + lp_acl_write(&link->bdaddr, q, link->len, link->pb); + /* Free the queued packet */ + btpbuf_free(q); + } + } + break; + case HCI_MODE_CHANGE: + printf("HCI_MODE_CHANGE\n"); + break; + case HCI_DATA_BUFFER_OVERFLOW: + //TODO: IS THIS FATAL???? + break; + case HCI_MAX_SLOTS_CHANGE: + break; + case HCI_RETURN_LINK_KEYS: + hci_return_link_key_evt(p); + break; + case HCI_PIN_CODE_REQUEST: + bdaddr = (void *)((u8_t *)p->payload); /* Get the Bluetooth address */ + HCI_EVENT_PIN_REQ(hci_dev, bdaddr, ret); /* Notify application. If event is not registered, + send a negative reply */ + break; + case HCI_LINK_KEY_REQUEST: + bdaddr = (void *)((u8_t *)p->payload); /* Get the Bluetooth address */ + HCI_EVENT_LINK_KEY_REQ(hci_dev, bdaddr, ret); + break; + case HCI_LINK_KEY_NOTIFICATION: + bdaddr = (void *)((u8_t *)p->payload); /* Get the Bluetooth address */ + + HCI_EVENT_LINK_KEY_NOT(hci_dev, bdaddr, ((u8_t *)p->payload) + 6, ret); /* Notify application.*/ + break; + default: + LOG("hci_event_input: Undefined event code 0x%x\n", evthdr->code); + break; + } +} + +void hci_acldata_handler(struct pbuf *p) +{ + struct hci_acl_hdr *aclhdr; + struct hci_link *link; + u16_t conhdl; + + aclhdr = p->payload; + btpbuf_header(p, -HCI_ACL_HDR_LEN); + + conhdl = le16toh(aclhdr->connhdl_pb_bc) & 0x0FFF; /* Get the connection handle from the first + 12 bits */ + if(hci_dev->flow) { + //TODO: XXX??? DO WE SAVE NUMACL PACKETS COMPLETED IN LINKS LIST?? SHOULD WE CALL + //hci_host_num_comp_packets from the main loop when no data has been received from the + //serial port??? + --hci_dev->host_num_acl; + if(hci_dev->host_num_acl == 0) { + hci_host_num_comp_packets(conhdl, HCI_HOST_MAX_NUM_ACL); + hci_dev->host_num_acl = HCI_HOST_MAX_NUM_ACL; + } + } + + for(link = hci_active_links; link != NULL; link = link->next) { + if(link->connhdl == conhdl) { + break; + } + } + + if(link != NULL) { + if(le16toh(aclhdr->len)) { + //LOG("hci_acl_input: Forward ACL packet to higher layer p->tot_len = %d\n", p->tot_len); + l2cap_input(p, &(link->bdaddr)); + } else { + btpbuf_free(p); /* If length of ACL packet is zero, we silently discard it */ + } + } else { + btpbuf_free(p); /* If no acitve ACL link was found, we silently discard the packet */ + } +} diff --git a/wii/libogc/lwbt/hci.h b/wii/libogc/lwbt/hci.h new file mode 100644 index 0000000000..3a3a98cf61 --- /dev/null +++ b/wii/libogc/lwbt/hci.h @@ -0,0 +1,482 @@ +#ifndef __HCI_H__ +#define __HCI_H__ + +#include "bt.h" +#include "bd_addr.h" + +/* HCI packet indicators */ +#define HCI_COMMAND_DATA_PACKET 0x01 +#define HCI_ACL_DATA_PACKET 0x02 +#define HCI_SCO_DATA_PACKET 0x03 +#define HCI_EVENT_PACKET 0x04 +#define HCI_VENDOR_PACKET 0xff + +/* HCI packet types */ +#define HCI_DM1 0x0008 +#define HCI_DM3 0x0400 +#define HCI_DM5 0x4000 +#define HCI_DH1 0x0010 +#define HCI_DH3 0x0800 +#define HCI_DH5 0x8000 + +#define HCI_HV1 0x0020 +#define HCI_HV2 0x0040 +#define HCI_HV3 0x0080 + +#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) +#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) + +#define HCI_EVENT_HDR_LEN 2 +#define HCI_ACL_HDR_LEN 4 +#define HCI_SCO_HDR_LEN 3 +#define HCI_CMD_HDR_LEN 3 + +/* LMP features */ +#define LMP_3SLOT 0x01 +#define LMP_5SLOT 0x02 +#define LMP_ENCRYPT 0x04 +#define LMP_SOFFSET 0x08 +#define LMP_TACCURACY 0x10 +#define LMP_RSWITCH 0x20 +#define LMP_HOLD 0x40 +#define LMP_SNIFF 0x80 + +#define LMP_PARK 0x01 +#define LMP_RSSI 0x02 +#define LMP_QUALITY 0x04 +#define LMP_SCO 0x08 +#define LMP_HV2 0x10 +#define LMP_HV3 0x20 +#define LMP_ULAW 0x40 +#define LMP_ALAW 0x80 + +#define LMP_CVSD 0x01 +#define LMP_PSCHEME 0x02 +#define LMP_PCONTROL 0x04 + +/* Opcode Group Field (OGF) values */ +#define HCI_LINK_CONTROL 0x01 /* Link Control Commands */ +#define HCI_LINK_POLICY 0x02 /* Link Policy Commands */ +#define HCI_HOST_C_N_BB 0x03 /* Host Controller & Baseband Commands */ +#define HCI_INFO_PARAM 0x04 /* Informational Parameters */ +#define HCI_STATUS_PARAM 0x05 /* Status Parameters */ +#define HCI_TESTING 0x06 /* Testing Commands */ + +/* Opcode Command Field (OCF) values */ + +/* Link control commands */ +#define HCI_INQUIRY 0x01 +#define HCI_PERIODIC_INQUIRY 0x03 +#define HCI_CREATE_CONNECTION 0x05 +#define HCI_REJECT_CONNECTION_REQUEST 0x0A +#define HCI_DISCONNECT 0x06 +#define HCI_PIN_CODE_REQ_REP 0x0D +#define HCI_PIN_CODE_REQ_NEG_REP 0x0E +#define HCI_LINK_KEY_REQ_REP 0x0B +#define HCI_LINK_KEY_REQ_REP_NEG 0x0C +#define HCI_SET_CONN_ENCRYPT 0x13 + +/* Link Policy commands */ +#define HCI_HOLD_MODE 0x01 +#define HCI_SNIFF_MODE 0x03 +#define HCI_EXIT_SNIFF_MODE 0x04 +#define HCI_PARK_MODE 0x05 +#define HCI_EXIT_PARK_MODE 0x06 +#define HCI_W_LINK_POLICY 0x0D + +/* Host-Controller and Baseband Commands */ +#define HCI_SET_EVENT_MASK 0x01 +#define HCI_RESET 0x03 +#define HCI_SET_EVENT_FILTER 0x05 +#define HCI_WRITE_STORED_LINK_KEY 0x11 +#define HCI_ROLE_CHANGE 0x12 +#define HCI_WRITE_LOCAL_NAME 0x13 + +#define HCI_WRITE_PAGE_TIMEOUT 0x18 +#define HCI_WRITE_SCAN_ENABLE 0x1A +#define HCI_WRITE_COD 0x24 +#define HCI_W_FLUSHTO 0x28 +#define HCI_SET_HC_TO_H_FC 0x31 +#define HCI_READ_CUR_IACLAP 0x39 +#define HCI_WRITE_PIN_TYPE 0x0A +#define HCI_R_STORED_LINK_KEY 0x0D +#define HCI_HOST_BUF_SIZE 0x33 +#define HCI_WRITE_INQUIRY_SCAN_TYPE 0x43 +#define HCI_WRITE_INQUIRY_MODE 0x45 +#define HCI_WRITE_PAGE_SCAN_TYPE 0x47 + +/* Informational Parameters */ +#define HCI_READ_LOCAL_VERSION 0x01 +#define HCI_READ_LOCAL_FEATURES 0x03 +#define HCI_READ_BUFFER_SIZE 0x05 +#define HCI_READ_BD_ADDR 0x09 + +/* Status Parameters */ +#define HCI_READ_FAILED_CONTACT_COUNTER 0x01 +#define HCI_RESET_FAILED_CONTACT_COUNTER 0x02 +#define HCI_GET_LINK_QUALITY 0x03 +#define HCI_READ_RSSI 0x05 + +/* Testing commands */ + +/* Possible event codes */ +#define HCI_INQUIRY_COMPLETE 0x01 +#define HCI_INQUIRY_RESULT 0x02 +#define HCI_CONNECTION_COMPLETE 0x03 +#define HCI_CONNECTION_REQUEST 0x04 +#define HCI_DISCONNECTION_COMPLETE 0x05 +#define HCI_ENCRYPTION_CHANGE 0x08 +#define HCI_QOS_SETUP_COMPLETE 0x0D +#define HCI_COMMAND_COMPLETE 0x0E +#define HCI_COMMAND_STATUS 0x0F +#define HCI_HARDWARE_ERROR 0x10 +#define HCI_ROLE_CHANGE 0x12 +#define HCI_NBR_OF_COMPLETED_PACKETS 0x13 +#define HCI_MODE_CHANGE 0x14 +#define HCI_RETURN_LINK_KEYS 0x15 +#define HCI_PIN_CODE_REQUEST 0x16 +#define HCI_LINK_KEY_REQUEST 0x17 +#define HCI_LINK_KEY_NOTIFICATION 0x18 +#define HCI_DATA_BUFFER_OVERFLOW 0x1A +#define HCI_MAX_SLOTS_CHANGE 0x1B + +/* Success code */ +#define HCI_SUCCESS 0x00 +/* Possible error codes */ +#define HCI_UNKNOWN_HCI_COMMAND 0x01 +#define HCI_NO_CONNECTION 0x02 +#define HCI_HW_FAILURE 0x03 +#define HCI_PAGE_TIMEOUT 0x04 +#define HCI_AUTHENTICATION_FAILURE 0x05 +#define HCI_KEY_MISSING 0x06 +#define HCI_MEMORY_FULL 0x07 +#define HCI_CONN_TIMEOUT 0x08 +#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09 +#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A +#define HCI_ACL_CONNECTION_EXISTS 0x0B +#define HCI_COMMAND_DISSALLOWED 0x0C +#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D +#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E +#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F +#define HCI_HOST_TIMEOUT 0x10 +#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11 +#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12 +#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13 +#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14 +#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15 +#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16 +#define HCI_REPETED_ATTEMPTS 0x17 +#define HCI_PAIRING_NOT_ALLOWED 0x18 +#define HCI_UNKNOWN_LMP_PDU 0x19 +#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A +#define HCI_SCO_OFFSET_REJECTED 0x1B +#define HCI_SCO_INTERVAL_REJECTED 0x1C +#define HCI_SCO_AIR_MODE_REJECTED 0x1D +#define HCI_INVALID_LMP_PARAMETERS 0x1E +#define HCI_UNSPECIFIED_ERROR 0x1F +#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20 +#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define HCI_LMP_RESPONSE_TIMEOUT 0x22 +#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23 +#define HCI_LMP_PDU_NOT_ALLOWED 0x24 +#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25 +#define HCI_UNIT_KEY_USED 0x26 +#define HCI_QOS_NOT_SUPPORTED 0x27 +#define HCI_INSTANT_PASSED 0x28 +#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29 + +/* Specification specific parameters */ +#define HCI_BD_ADDR_LEN 6 +#define HCI_LMP_FEATURES_LEN 8 +#define HCI_LINK_KEY_LEN 16 +#define HCI_LMP_FEAT_LEN 8 + +/* Command OGF */ +#define HCI_LINK_CTRL_OGF 0x01 /* Link ctrl cmds */ +#define HCI_LINK_POLICY_OGF 0x02 /* Link Policy Commands */ +#define HCI_HC_BB_OGF 0x03 /* Host controller and baseband commands */ +#define HCI_INFO_PARAM_OGF 0x04 /* Informal parameters */ + +/* Command OCF */ +#define HCI_INQUIRY_OCF 0x01 +#define HCI_SNIFF_MODE_OCF 0x03 +#define HCI_EXIT_SNIFF_MODE_OCF 0x04 +#define HCI_PARK_MODE_OCF 0x05 +#define HCI_EXIT_PARK_MODE_OCF 0x06 +#define HCI_PERIODIC_INQUIRY_OCF 0x03 +#define HCI_EXIT_PERIODIC_INQUIRY_OCF 0x04 +#define HCI_CREATE_CONN_OCF 0x05 +#define HCI_DISCONN_OCF 0x06 +#define HCI_W_LOCAL_NAME_OCF 0x13 +#define HCI_W_LINK_POLICY_OCF 0x0D +#define HCI_ACCEPT_CONN_REQ_OCF 0x09 +#define HCI_REJECT_CONN_REQ_OCF 0x0A +#define HCI_SET_EV_MASK_OCF 0x01 +#define HCI_RESET_OCF 0x03 +#define HCI_SET_EV_FILTER_OCF 0x05 +#define HCI_R_STORED_LINK_KEY_OCF 0x0D +#define HCI_W_PAGE_TIMEOUT_OCF 0x18 +#define HCI_W_SCAN_EN_OCF 0x1A +#define HCI_R_COD_OCF 0x23 +#define HCI_W_COD_OCF 0x24 +#define HCI_SET_HC_TO_H_FC_OCF 0x31 +#define HCI_H_BUF_SIZE_OCF 0x33 +#define HCI_H_NUM_COMPL_OCF 0x35 +#define HCI_R_CUR_IACLAP_OCF 0x39 +#define HCI_R_LOC_VERSION_OCF 0x01 +#define HCI_R_LOC_FEATURES_OCF 0x03 +#define HCI_R_BUF_SIZE_OCF 0x05 +#define HCI_R_BD_ADDR_OCF 0x09 +#define HCI_R_REMOTE_NAME_OCF 0x19 +#define HCI_W_PIN_TYPE_OCF 0x0A +#define HCI_W_INQUIRY_SCAN_TYPE_OCF 0x43 +#define HCI_W_INQUIRY_MODE_OCF 0x45 +#define HCI_W_PAGE_SCAN_TYPE_OCF 0x47 +#define HCI_W_PAGE_SCAN_TYPE_OCF 0x47 + +/* Command packet length (including ACL header)*/ +#define HCI_INQUIRY_PLEN 9 +#define HCI_PERIODIC_INQUIRY_PLEN 13 +#define HCI_EXIT_PERIODIC_INQUIRY_PLEN 4 +#define HCI_CREATE_CONN_PLEN 17 +#define HCI_DISCONN_PLEN 7 +#define HCI_REJECT_CONN_REQ_PLEN 11 +#define HCI_ACCEPT_CONN_REQ_PLEN 11 +#define HCI_PIN_CODE_REQ_REP_PLEN 27 +#define HCI_PIN_CODE_REQ_NEG_REP_PLEN 10 +#define HCI_LINK_KEY_REQ_REP_PLEN 26 +#define HCI_LINK_KEY_REQ_REP_NEG_PLEN 10 +#define HCI_SET_CONN_ENCRYPT_PLEN 7 +#define HCI_WRITE_STORED_LINK_KEY_PLEN 27 +#define HCI_SET_EV_MASK_PLEN 12 +#define HCI_SNIFF_PLEN 14 +#define HCI_W_LINK_POLICY_PLEN 8 +#define HCI_RESET_PLEN 4 +#define HCI_SET_EV_FILTER_PLEN 6 +#define HCI_W_PAGE_TIMEOUT_PLEN 6 +#define HCI_W_SCAN_EN_PLEN 5 +#define HCI_R_COD_PLEN 4 +#define HCI_W_COD_PLEN 7 +#define HCI_W_FLUSHTO_PLEN 8 +#define HCI_W_LOCAL_NAME_PLEN 252 +#define HCI_SET_HC_TO_H_FC_PLEN 5 +#define HCI_H_BUF_SIZE_PLEN 11 +#define HCI_H_NUM_COMPL_PLEN 9 +#define HCI_R_LOC_FEAT_SIZE_PLEN 4 +#define HCI_R_LOC_VERS_SIZE_PLEN 4 +#define HCI_R_BUF_SIZE_PLEN 4 +#define HCI_R_BD_ADDR_PLEN 4 +#define HCI_R_CUR_IACLAP_PLEN 4 +#define HCI_R_STORED_LINK_KEY_PLEN 11 +#define HCI_R_REMOTE_NAME_PLEN 14 +#define HCI_W_PIN_TYPE_PLEN 5 +#define HCI_W_INQUIRY_MODE_PLEN 5 +#define HCI_W_INQUIRY_SCAN_TYPE_PLEN 5 +#define HCI_W_PAGE_SCAN_TYPE_PLEN 5 +#define HCI_W_VENDOR_CMD_PLEN 4 + +struct hci_evt_hdr +{ + u8_t code; + u8_t len; +} ATTRIBUTE_PACKED; + +struct hci_acl_hdr +{ + u16_t connhdl_pb_bc; + u16_t len; +} ATTRIBUTE_PACKED; + +struct hci_inq_res +{ + struct hci_inq_res *next; + struct bd_addr bdaddr; + u8_t cod[3]; + u8_t psrm; + u8_t psm; + u16_t co; +}; + +struct hci_link_key +{ + struct bd_addr bdaddr; + u8_t key[16]; + + struct hci_link_key *next; +}; + +struct hci_link +{ + struct hci_link *next; + struct bd_addr bdaddr; + u16_t connhdl; + struct pbuf *p; + u16_t len; + u8_t pb; + u32_t link_mode; +}; + +struct hci_version_info +{ + u8_t hci_version; + u16_t hci_revision; + u8_t lmp_version; + u16_t manufacturer; + u16_t lmp_subversion; +}; + +struct hci_pcb +{ + void *cbarg; + s8_t num_cmd; + + u16_t acl_mtu; + u8_t sco_mtu; + u16_t acl_max_pkt; + u16_t sco_max_pkt; + + u32_t flags; + + u8_t flow; + u16_t host_num_acl; + + u16_t pkt_type; + u8_t features[8]; + + struct bd_addr bdaddr; + struct hci_version_info info; + + struct hci_inq_res *ires; + struct hci_link_key *keyres; + + err_t (*pin_req)(void *arg,struct bd_addr *bdaddr); + err_t (*link_key_req)(void *arg,struct bd_addr *bdaddr); + err_t (*cmd_complete)(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); + err_t (*link_key_not)(void *arg, struct bd_addr *bdaddr, u8_t *key); + err_t (*conn_complete)(void *arg,struct bd_addr *bdaddr); + err_t (*inq_complete)(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result); + err_t (*wlp_complete)(void *arg, struct bd_addr *bdaddr); + err_t (*conn_req)(void *arg,struct bd_addr *bdaddr,u8_t *cod,u8_t link_type); +}; + +err_t hci_init(void); +struct hci_link* hci_new(void); +void hci_reset_all(void); +void hci_event_handler(struct pbuf *p); +void hci_acldata_handler(struct pbuf *p); + +err_t hci_reset(); +err_t hci_read_bd_addr(void); +err_t hci_set_hc_to_h_fc(void); +err_t hci_read_buffer_size(void); +err_t hci_host_buffer_size(void); +err_t hci_read_current_lap(void); +err_t hci_write_cod(u8_t *cod); +err_t hci_close(struct hci_link *link); +err_t hci_write_inquiry_mode(u8_t mode); +err_t hci_write_page_scan_type(u8_t type); +err_t hci_write_inquiry_scan_type(u8_t type); +err_t hci_disconnect(struct bd_addr *bdaddr, u8_t reason); +err_t hci_reject_connection_request(struct bd_addr *bdaddr, u8_t reason); +err_t hci_pin_code_request_reply(struct bd_addr *bdaddr, u8_t pinlen, u8_t *pincode); +err_t hci_link_key_req_reply(struct bd_addr *bdaddr, u8_t *link_key); +err_t hci_write_stored_link_key(struct bd_addr *bdaddr, u8_t *link); +err_t hci_set_event_filter(u8_t filter_type,u8_t filter_cond_type,u8_t *cond); +err_t hci_write_page_timeout(u16_t timeout); +err_t hci_inquiry(u32_t lap,u8_t inq_len,u8_t num_resp,err_t (*inq_complete)(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result)); +err_t hci_pin_code_request_neg_reply(struct bd_addr *bdaddr); +err_t hci_link_key_req_neg_reply(struct bd_addr *bdaddr); +err_t hci_write_scan_enable(u8_t scan_enable); +err_t hci_host_num_comp_packets(u16_t conhdl, u16_t num_complete); +err_t hci_sniff_mode(struct bd_addr *bdaddr, u16_t max_interval, u16_t min_interval, u16_t attempt, u16_t timeout); +err_t hci_write_link_policy_settings(struct bd_addr *bdaddr, u16_t link_policy); +err_t hci_periodic_inquiry(u32_t lap,u16_t min_period,u16_t max_period,u8_t inq_len,u8_t num_resp,err_t (*inq_complete)(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result)); +err_t hci_exit_periodic_inquiry(); +err_t hci_accecpt_conn_request(struct bd_addr *bdaddr,u8_t role); +err_t hci_set_event_mask(u64_t ev_mask); +err_t hci_read_local_version(void); +err_t hci_read_local_features(void); +err_t hci_write_local_name(u8_t *name,u8_t len); +err_t hci_write_pin_type(u8_t type); +err_t hci_read_stored_link_key(); +err_t hci_read_remote_name(struct bd_addr *bdaddr); +err_t hci_vendor_specific_command(u8_t ocf,u8_t ogf,void *data,u8_t len); + +err_t hci_reg_dev_info(struct bd_addr *bdaddr,u8_t *cod,u8_t psrm,u8_t psm,u16_t co); + +void hci_arg(void *arg); +void hci_cmd_complete(err_t (*cmd_complete)(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result)); +void hci_connection_complete(err_t (* conn_complete)(void *arg, struct bd_addr *bdaddr)); +void hci_pin_req(err_t (* pin_req)(void *arg, struct bd_addr *bdaddr)); +void hci_link_key_req(err_t (* link_key_req)(void *arg, struct bd_addr *bdaddr)); +void hci_link_key_not(err_t (* link_key_not)(void *arg, struct bd_addr *bdaddr, u8_t *key)); +void hci_wlp_complete(err_t (* wlp_complete)(void *arg, struct bd_addr *bdaddr)); +void hci_conn_req(err_t (*conn_req)(void *arg,struct bd_addr *bdaddr,u8_t *cod,u8_t link_type)); + +u16_t lp_pdu_maxsize(); +u8_t lp_is_connected(struct bd_addr *bdaddr); +err_t lp_acl_write(struct bd_addr *bdaddr,struct pbuf *p,u16_t len,u8_t pb); +err_t lp_connect_req(struct bd_addr *bdaddr, u8_t allow_role_switch); +err_t lp_write_flush_timeout(struct bd_addr *bdaddr, u16_t flushto); + + +#define HCI_EVENT_PIN_REQ(pcb,bdaddr,ret) \ + if((pcb)->pin_req != NULL) { \ + (ret = (pcb)->pin_req((pcb)->cbarg,(bdaddr))); \ + } else { \ + ret = hci_pin_code_request_neg_reply(bdaddr); \ + } +#define HCI_EVENT_LINK_KEY_REQ(pcb,bdaddr,ret) \ + if((pcb)->link_key_req != NULL) { \ + (ret = (pcb)->link_key_req((pcb)->cbarg,(bdaddr))); \ + } else { \ + ret = hci_link_key_req_neg_reply(bdaddr); \ + } +#define HCI_EVENT_CONN_REQ(pcb,bdaddr,cod,linktype,ret) \ + if((pcb)->conn_req!=NULL) \ + (ret = (pcb)->conn_req((pcb)->cbarg,(bdaddr),(cod),(linktype))) +#define HCI_EVENT_LINK_KEY_NOT(pcb,bdaddr,key,ret) \ + if((pcb)->link_key_not != NULL) { \ + (ret = (pcb)->link_key_not((pcb)->cbarg,(bdaddr),(key))); \ + } +#define HCI_EVENT_INQ_COMPLETE(pcb,result,ret) \ + if((pcb)->inq_complete != NULL) \ + (ret = (pcb)->inq_complete((pcb)->cbarg,(pcb),(pcb)->ires,(result))) +#define HCI_EVENT_WLP_COMPLETE(pcb,bdaddr,ret) \ + if((pcb)->wlp_complete != NULL) \ + (ret = (pcb)->wlp_complete((pcb)->cbarg,(bdaddr))); +#define HCI_EVENT_CONN_COMPLETE(pcb,bdaddr,ret) \ + if((pcb)->conn_complete != NULL) \ + (ret = (pcb)->conn_complete((pcb)->cbarg,(bdaddr))); +#define HCI_EVENT_CMD_COMPLETE(pcb,ogf,ocf,result,ret) \ + if((pcb)->cmd_complete != NULL) \ + (ret = (pcb)->cmd_complete((pcb)->cbarg,(pcb),(ogf),(ocf),(result))) + +/* The HCI LINK lists. */ +extern struct hci_link *hci_active_links; /* List of all active HCI LINKs */ +extern struct hci_link *hci_tmp_link; /* Only used for temporary storage. */ +extern struct hci_link_key *hci_tmp_key; + +#define HCI_REG(links, nlink) do { \ + u32 level; \ + _CPU_ISR_Disable(level); \ + nlink->next = *links; \ + *links = nlink; \ + _CPU_ISR_Restore(level); \ + } while(0) +#define HCI_RMV(links, nlink) do { \ + u32 level; \ + _CPU_ISR_Disable(level);\ + if(*links == nlink) { \ + *links = (*links)->next; \ + } else for(hci_tmp_link = *links; hci_tmp_link != NULL; hci_tmp_link = hci_tmp_link->next) { \ + if(hci_tmp_link->next != NULL && hci_tmp_link->next == nlink) { \ + hci_tmp_link->next = nlink->next; \ + break; \ + } \ + } \ + nlink->next = NULL; \ + _CPU_ISR_Restore(level); \ + } while(0) + +#endif diff --git a/wii/libogc/lwbt/l2cap.c b/wii/libogc/lwbt/l2cap.c new file mode 100644 index 0000000000..0496834569 --- /dev/null +++ b/wii/libogc/lwbt/l2cap.c @@ -0,0 +1,1555 @@ +#include +#include +#include +#include +#include +#include + +#include "hci.h" +#include "l2cap.h" +#include "btmemb.h" +#include "btpbuf.h" + +/* Next Identifier to be sent */ +u8_t sigid_nxt; + +/* The L2CAP PCB lists. */ +struct l2cap_pcb_listen *l2cap_listen_pcbs = NULL; /* List of all L2CAP PCBs in CLOSED state + but awaiting an incoming conn req */ +struct l2cap_pcb *l2cap_active_pcbs; /* List of all L2CAP PCBs that are in a + state in which they accept or send + data */ +struct l2cap_pcb *l2cap_tmp_pcb = NULL; + +/* Temp signal */ +struct l2cap_sig *l2cap_tmp_sig = NULL; + +/* Global variable involved in input processing of l2cap data segements */ +struct l2cap_seg *l2cap_insegs = NULL; +struct l2cap_seg *l2cap_tmp_inseg = NULL; + +/* Global Baseband disconnect callback. */ +static void (*l2cap_disconnect_bb_cb)(struct bd_addr *bdaddr,u8_t reason) = NULL; + +/* Forward declarations */ +static u16_t l2cap_cid_alloc(void); + +MEMB(l2cap_pcbs,sizeof(struct l2cap_pcb),MEMB_NUM_L2CAP_PCB); +MEMB(l2cap_listenpcbs,sizeof(struct l2cap_pcb_listen),MEMB_NUM_L2CAP_PCB_LISTEN); +MEMB(l2cap_sigs,sizeof(struct l2cap_sig),MEMB_NUM_L2CAP_SIG); +MEMB(l2cap_segs,sizeof(struct l2cap_seg),MEMB_NUM_L2CAP_SEG); + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_init(): + * + * Initializes the L2CAP layer. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_init() +{ + btmemb_init(&l2cap_pcbs); + btmemb_init(&l2cap_listenpcbs); + btmemb_init(&l2cap_sigs); + btmemb_init(&l2cap_segs); + + /* Clear globals */ + l2cap_listen_pcbs = NULL; + l2cap_active_pcbs = NULL; + l2cap_tmp_pcb = NULL; + l2cap_tmp_sig = NULL; + l2cap_insegs = NULL; + l2cap_tmp_inseg = NULL; + l2cap_disconnect_bb_cb = NULL; + + /* Initialize the signal identifier (0x00 shall never be used) */ + sigid_nxt = 0x00; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_tmr(): + * + * Called every 1s and implements the retransmission timer that + * removes a channel if it has been waiting for a request enough + * time. It also includes a configuration timer. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_tmr() +{ + struct l2cap_sig *sig; + struct l2cap_pcb *pcb; + err_t ret; + + (void) ret; + + /* Step through all of the active pcbs */ + for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { + /* Step through any unresponded signals */ + for(sig = pcb->unrsp_sigs; sig != NULL; sig = sig->next) { + /* Check if channel is not reliable */ + if(pcb->cfg.outflushto < 0xFFFF) { + /* Check if rtx is active. Otherwise ertx is active */ + if(sig->rtx > 0) { + /* Adjust rtx timer */ + --sig->rtx; + /* Check if rtx has expired */ + if(sig->rtx == 0) { + if(sig->nrtx == 0) { + /* Move pcb to closed state */ + pcb->state = L2CAP_CLOSED; + /* Indicate disconnect to upper layer */ + LOG("l2cap_tmr: Max number of retransmissions (rtx) has expired\n"); + L2CA_ACTION_DISCONN_IND(pcb,ERR_OK,ret); + } else { + --sig->nrtx; + /* Indicate timeout to upper layer */ + L2CA_ACTION_TO_IND(pcb,ERR_OK,ret); + /* Retransmitt signal w timeout doubled */ + sig->rtx += sig->rtx; + ret = l2cap_rexmit_signal(pcb, sig); + } + } /* if */ + } else { + /* Adjust ertx timer */ + --sig->ertx; + /* Check if ertx has expired */ + if(sig->ertx == 0) { + if(sig->nrtx == 0) { + /* Move pcb to closed state */ + pcb->state = L2CAP_CLOSED; + /* Indicate disconnect to upper layer */ + LOG("l2cap_tmr: Max number of retransmissions (ertx) has expired\n"); + L2CA_ACTION_DISCONN_IND(pcb,ERR_OK,ret); + } else { + --sig->nrtx; + /* Indicate timeout to upper layer */ + L2CA_ACTION_TO_IND(pcb,ERR_OK,ret); + /* Disable ertx, activate rtx and retransmitt signal */ + sig->ertx = 0; + sig->rtx = L2CAP_RTX; + ret = l2cap_rexmit_signal(pcb, sig); + } + } /* if */ + } /* else */ + } /* if */ + } /* for */ + + /* Check configuration timer */ + if(pcb->state == L2CAP_CONFIG) { + /* Check if configuration timer is active */ + if(pcb->cfg.cfgto > 0) { + --pcb->cfg.cfgto; + //LOG("l2cap_tmr: Configuration timer = %d\n", pcb->cfg.cfgto); + /* Check if config timer has expired */ + if(pcb->cfg.cfgto == 0) { + /* Connection attempt failed. Disconnect */ + l2ca_disconnect_req(pcb, NULL); + /* Notify the application that the connection attempt failed */ + if(pcb->cfg.l2capcfg & L2CAP_CFG_IR) { + L2CA_ACTION_CONN_CFM(pcb, L2CAP_CONN_CFG_TO, 0x0000, ret); + } else { + L2CA_ACTION_CONN_IND(pcb, ERR_OK, ret); + } + pcb->cfg.cfgto = L2CAP_CFG_TO; /* Reset timer */ + } + } + } + } /* for */ +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_write(): + * + * Output L2CAP data to the lower layers. Segments the packet in to PDUs. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2cap_write(struct bd_addr *bdaddr, struct pbuf *p, u16_t len) +{ + u8_t pb = L2CAP_ACL_START; + u16_t maxsize; + u16_t outsize; + err_t ret = ERR_OK; + struct pbuf *q; + u16_t i = 0; + + /*u16_t i; + struct pbuf *q; + for(q = p; q != NULL; q = q->next) { + for(i = 0; i < q->len; ++i) { + LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_write: 0x%x\n", ((u8_t *)q->payload)[i])); + } + LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_write: *\n")); + } + */ + + maxsize = lp_pdu_maxsize(); + q = p; + + while(len && ret == ERR_OK) { + //LOG("l2cap_write: len %d maxsize %d p->len %d\n", len, maxsize, p->len); + if(len > maxsize) { + ret = lp_acl_write(bdaddr, q, maxsize, pb); + len -= maxsize; + outsize = maxsize; + //LOG("l2cap_write: Outsize before %d\n", outsize); + while(q->len < outsize) { + outsize -= q->len; + q = q->next; + } + //LOG("l2cap_write: Outsize after %d\n", outsize); + if(outsize) { + btpbuf_header(q, -outsize); + i += outsize; + } + pb = L2CAP_ACL_CONT; + LOG("l2cap_write: FRAG\n"); + } else { + ret = lp_acl_write(bdaddr, q, len, pb); + len = 0; + } + } + btpbuf_header(q, i); + LOG("l2cap_write: DONE\n"); + return ret; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_process_sig(): + * + * Parses the received message handles it. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_process_sig(struct pbuf *q, struct l2cap_hdr *l2caphdr, struct bd_addr *bdaddr) +{ + struct l2cap_sig_hdr *sighdr; + struct l2cap_sig *sig = NULL; + struct l2cap_pcb *pcb = NULL; + struct l2cap_pcb_listen *lpcb; + struct l2cap_cfgopt_hdr *opthdr; + u16_t result, status, flags, psm, dcid; + u16_t len; + u16_t siglen; + struct pbuf *p, *r = NULL, *s = NULL, *data; + err_t ret; + u8_t i; + u16_t rspstate = L2CAP_CFG_SUCCESS; + + (void)ret; + + if(q->len != q->tot_len) { + LOG("l2cap_process_sig: Fragmented packet received. Reassemble into one buffer\n"); + if((p = btpbuf_alloc(PBUF_RAW, q->tot_len, PBUF_RAM)) != NULL) { + i = 0; + for(r = q; r != NULL; r = r->next) { + memcpy(((u8_t *)p->payload) + i, r->payload, r->len); + i += r->len; + } + } else { + ERROR("l2cap_process_sig: Could not allocate buffer for fragmented packet\n"); + return; + } + } else { + p = q; + } + + len = l2caphdr->len; + + while(len > 0) { + /* Set up signal header */ + sighdr = p->payload; + btpbuf_header(p, -L2CAP_SIGHDR_LEN); + + /* Check if this is a response/reject signal, and if so, find the matching request */ + if(sighdr->code % 2) { /* if odd this is a resp/rej signal */ + LOG("l2cap_process_sig: Response/reject signal received id = %d code = %d\n", sighdr->id, sighdr->code); + for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { + for(sig = pcb->unrsp_sigs; sig != NULL; sig = sig->next) { + if(sig->sigid == sighdr->id) { + break; /* found */ + } + } + if(sig != NULL) { + break; + } + } + } else { + LOG("l2cap_process_sig: Request signal received id = %d code = %d\n", sighdr->id, sighdr->code); + } + + /* Reject packet if length exceeds MTU */ + if(l2caphdr->len > L2CAP_MTU) { + /* Alloc size of reason in cmd rej + MTU */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE+2, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(L2CAP_MTU_EXCEEDED); + ((u16_t *)data->payload)[1] = htole16(L2CAP_MTU); + + l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); + } + break; + } + + switch(sighdr->code) { + case L2CAP_CMD_REJ: + /* Remove signal from unresponded list and deallocate it */ + L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); + btpbuf_free(sig->p); + btmemb_free(&l2cap_sigs, sig); + LOG("l2cap_process_sig: Our command was rejected so we disconnect\n"); + l2ca_disconnect_req(pcb, NULL); + break; + case L2CAP_CONN_REQ: + psm = le16toh(((u16_t *)p->payload)[0]); + /* Search for a listening pcb */ + for(lpcb = l2cap_listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if(bd_addr_cmp(&(lpcb->bdaddr),bdaddr) && lpcb->psm == psm) { + /* Found a listening pcb with the correct PSM & BD Address */ + break; + } + } + + //printf("l2cap_process_sig(L2CAP_CONN_REQ): psm = %04x, lpcb = %p\n",psm,lpcb); + /* If no matching pcb was found, send a connection rsp neg (PSM) */ + if(lpcb == NULL) { + /* Alloc size of data in conn rsp signal */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CONN_RSP_SIZE, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(L2CAP_CONN_REF_PSM); + ((u16_t *)data->payload)[1] = 0; /* No further info available */ + ret = l2cap_signal(NULL, L2CAP_CONN_RSP, sighdr->id, bdaddr, data); + } + } else { + /* Initiate a new active pcb */ + pcb = l2cap_new(); + if(pcb == NULL) { + LOG("l2cap_process_sig: could not allocate PCB\n"); + /* Send a connection rsp neg (no resources available) and alloc size of data in conn rsp + signal */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CONN_RSP_SIZE, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(L2CAP_CONN_REF_RES); + ((u16_t *)data->payload)[1] = 0; /* No further info available */ + ret = l2cap_signal(NULL, L2CAP_CONN_RSP, sighdr->id, bdaddr, data); + } + } + bd_addr_set(&(pcb->remote_bdaddr),bdaddr); + + pcb->scid = l2cap_cid_alloc(); + pcb->dcid = le16toh(((u16_t *)p->payload)[1]); + pcb->psm = psm; + pcb->callback_arg = lpcb->callback_arg; + pcb->l2ca_connect_ind = lpcb->l2ca_connect_ind; + + pcb->state = L2CAP_CONFIG; + L2CAP_REG(&l2cap_active_pcbs, pcb); + + LOG("l2cap_process_sig: A connection request was received. Send a response\n"); + data = btpbuf_alloc(PBUF_RAW, L2CAP_CONN_RSP_SIZE, PBUF_RAM); + if(data == NULL) { + ERROR("l2cap_connect_rsp: Could not allocate memory for pbuf\n"); + break; + } + ((u16_t *)data->payload)[0] = htole16(pcb->scid); + ((u16_t *)data->payload)[1] = htole16(pcb->dcid); + ((u16_t *)data->payload)[2] = htole16(L2CAP_CONN_SUCCESS); + ((u16_t *)data->payload)[3] = 0x0000; /* No further information available */ + + /* Send the response */ + ret = l2cap_signal(pcb, L2CAP_CONN_RSP, sighdr->id, &(pcb->remote_bdaddr), data); + } + break; + case L2CAP_CONN_RSP: + if(pcb == NULL) { + /* A response without a matching request is silently discarded */ + break; + } + LOG("l2cap_process_sig: conn rsp, active pcb->state == W4_L2CAP_CONNECT_RSP\n"); + result = le16toh(((u16_t *)p->payload)[2]); + status = le16toh(((u16_t *)p->payload)[3]); + switch(result) { + case L2CAP_CONN_SUCCESS: + LOG("l2cap_process_sig: Conn_rsp_sucess, status %d\n", status); + LOG("l2cap_process_sig: conn rsp success, pcb->scid == %04x\n", ((u16_t *)p->payload)[1]); + + /* Set destination connection id */ + pcb->dcid = le16toh(((u16_t *)p->payload)[0]); + + /* Remove signal from unresponded list and deallocate it */ + L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); + btpbuf_free(sig->p); + btmemb_free(&l2cap_sigs, sig); + + /* Configure connection */ + pcb->state = L2CAP_CONFIG; + + /* If initiator send a configuration request */ + if(pcb->cfg.l2capcfg & L2CAP_CFG_IR) { + l2ca_config_req(pcb); + pcb->cfg.l2capcfg |= L2CAP_CFG_OUT_REQ; + } + break; + case L2CAP_CONN_PND: + LOG("l2cap_process_sig: Conn_rsp_pnd, status %d\n", status); + + /* Disable rtx and enable ertx */ + sig->rtx = 0; + sig->ertx = L2CAP_ERTX; + break; + default: + LOG("l2cap_process_sig: Conn_rsp_neg, result %d\n", result); + /* Remove signal from unresponded list and deallocate it */ + L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); + btpbuf_free(sig->p); + btmemb_free(&l2cap_sigs, sig); + + L2CA_ACTION_CONN_CFM(pcb,result,status,ret); + break; + } + break; + case L2CAP_CFG_REQ: + siglen = le16toh(sighdr->len); + dcid = le16toh(((u16_t *)p->payload)[0]); + flags = le16toh(((u16_t *)p->payload)[1]); + siglen -= 4; + btpbuf_header(p, -4); + + + LOG("l2cap_process_sig: Congfiguration request, flags = %d\n", flags); + + /* Find PCB with matching cid */ + for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { + //LOG("l2cap_process_sig: dcid = 0x%x, pcb->scid = 0x%x, pcb->dcid = 0x%x\n\n", dcid, pcb->scid, pcb->dcid); + if(pcb->scid == dcid) { + /* Matching cid found */ + break; + } + } + /* If no matching cid was found, send a cmd reject (Invalid cid) */ + if(pcb == NULL) { + LOG("l2cap_process_sig: Cfg req: no matching cid was found\n"); + /* Alloc size of reason in cmd rej + data (dcid + scid) */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE+4, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(L2CAP_INVALID_CID); + ((u16_t *)data->payload)[1] = htole16(dcid); /* Requested local cid */ + ((u16_t *)data->payload)[2] = htole16(L2CAP_NULL_CID); /* Remote cid not known */ + + ret = l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); + } + } else { /* Handle config request */ + LOG("l2cap_process_sig: Handle configuration request\n"); + pcb->ursp_id = sighdr->id; /* Set id of request to respond to */ + + /* Parse options and add to pcb */ + while(siglen > 0) { + LOG("l2cap_process_sig: Siglen = %d\n", siglen); + opthdr = p->payload; + /* Check if type of action bit indicates a non-hint. Hints are ignored */ + LOG("l2cap_process_sig: Type of action bit = %d\n", L2CAP_OPTH_TOA(opthdr)); + if(L2CAP_OPTH_TOA(opthdr) == 0) { + LOG("l2cap_process_sig: Type = %d\n", L2CAP_OPTH_TYPE(opthdr)); + LOG("l2cap_process_sig: Length = %d\n", opthdr->len); + switch(L2CAP_OPTH_TYPE(opthdr)) { + case L2CAP_CFG_MTU: + LOG("l2cap_process_sig: Out MTU = %d\n", le16toh(((u16_t *)p->payload)[1])); + pcb->cfg.outmtu = le16toh(((u16_t *)p->payload)[1]); + break; + case L2CAP_FLUSHTO: + LOG("l2cap_process_sig: In flush timeout = %d\n", ((u16_t *)p->payload)[1]); + pcb->cfg.influshto = le16toh(((u16_t *)p->payload)[1]); + break; + case L2CAP_QOS: + /* If service type is Best Effort or No Traffic the remainder fields will be ignored */ + if(((u8_t *)p->payload)[3] == L2CAP_QOS_GUARANTEED) { + /*LOG("l2cap_process_sig: This implementation does not support the guaranteed QOS service type"); + if(rspstate == L2CAP_CFG_SUCCESS) { + rspstate = L2CAP_CFG_UNACCEPT; + if(pcb->cfg.opt != NULL) { + btpbuf_free(pcb->cfg.opt); + pcb->cfg.opt = NULL; + } + }*/ + s = btpbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + opthdr->len, PBUF_RAM); + memcpy((u8_t *)s->payload, (u8_t *)p->payload, L2CAP_CFGOPTHDR_LEN + opthdr->len); + if(pcb->cfg.opt == NULL) { + pcb->cfg.opt = s; + } else { + btpbuf_chain(pcb->cfg.opt, s); + btpbuf_free(s); + } + } + break; + default: + if(rspstate != L2CAP_CFG_REJ) { + /* Unknown option. Add to unknown option type buffer */ + if(rspstate != L2CAP_CFG_UNKNOWN) { + rspstate = L2CAP_CFG_UNKNOWN; + if(pcb->cfg.opt != NULL) { + btpbuf_free(pcb->cfg.opt); + pcb->cfg.opt = NULL; + } + } + s = btpbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + opthdr->len, PBUF_RAM); + memcpy((u8_t *)s->payload, (u8_t *)p->payload, L2CAP_CFGOPTHDR_LEN + opthdr->len); + if(pcb->cfg.opt == NULL) { + pcb->cfg.opt = s; + } else { + btpbuf_chain(pcb->cfg.opt, s); + btpbuf_free(s); + } + } + break; + } /* switch */ + } /* if(L2CAP_OPTH_TOA(opthdr) == 0) */ + btpbuf_header(p, -(L2CAP_CFGOPTHDR_LEN + opthdr->len)); + siglen -= L2CAP_CFGOPTHDR_LEN + opthdr->len; + } /* while */ + + /* If continuation flag is set we don't send the final response just yet */ + if((flags & 0x0001) == 1) { + /* Send success result with no options until the full request has been received */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CFG_RSP_SIZE, PBUF_RAM)) == NULL) { + ERROR("l2cap_process_sig: Could not allocate memory for pbuf\n"); + break; + } + ((u16_t *)data->payload)[0] = htole16(pcb->dcid); + ((u16_t *)data->payload)[1] = 0; + ((u16_t *)data->payload)[2] = htole16(L2CAP_CFG_SUCCESS); + ret = l2cap_signal(pcb, L2CAP_CFG_RSP, pcb->ursp_id, &(pcb->remote_bdaddr), data); + break; + } + + /* Send a configure request for outgoing link if it hasnt been configured */ + if(!(pcb->cfg.l2capcfg & L2CAP_CFG_IR) && !(pcb->cfg.l2capcfg & L2CAP_CFG_OUT_REQ)) { + l2ca_config_req(pcb); + pcb->cfg.l2capcfg |= L2CAP_CFG_OUT_REQ; + } + + /* Send response to configuration request */ + LOG("l2cap_process_sig: Send response to configuration request\n"); + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CFG_RSP_SIZE, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(pcb->dcid); + ((u16_t *)data->payload)[1] = 0; /* Flags (No continuation) */ + ((u16_t *)data->payload)[2] = htole16(rspstate); /* Result */ + if(pcb->cfg.opt != NULL) { + LOG("l2cap_process_sig: pcb->cfg.opt->len = %d\n", pcb->cfg.opt->len); + btpbuf_chain(data, pcb->cfg.opt); /* Add option type buffer to data buffer */ + btpbuf_free(pcb->cfg.opt); + pcb->cfg.opt = NULL; + } + ret = l2cap_signal(pcb, L2CAP_CFG_RSP, pcb->ursp_id, &(pcb->remote_bdaddr), data); + } + + if(rspstate == L2CAP_CFG_SUCCESS) { + pcb->cfg.l2capcfg |= L2CAP_CFG_OUT_SUCCESS; + /* L2CAP connection established if a successful configuration response has been sent */ + if(pcb->cfg.l2capcfg & L2CAP_CFG_IN_SUCCESS) { + /* IPCP connection established, notify upper layer that connection is open */ + pcb->state = L2CAP_OPEN; + if(pcb->cfg.l2capcfg & L2CAP_CFG_IR) { + L2CA_ACTION_CONN_CFM(pcb, L2CAP_CONN_SUCCESS, 0x0000, ret); + } else { + L2CA_ACTION_CONN_IND(pcb, ERR_OK, ret); + } + } + } + } /* else */ + break; + case L2CAP_CFG_RSP: + if(pcb == NULL) { + /* A response without a matching request is silently discarded */ + LOG("l2cap_process_sig: discarded response without matching request\n"); + break; + } + + /* Remove signal from unresponded list and deallocate it */ + L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); + btpbuf_free(sig->p); + btmemb_free(&l2cap_sigs, sig); + + siglen = le16toh(sighdr->len); + //scid = le16toh(((u16_t *)p->payload)[0]); + flags = le16toh(((u16_t *)p->payload)[1]); + result = le16toh(((u16_t *)p->payload)[2]); + siglen -= 6; + btpbuf_header(p, -6); + + LOG("l2cap_process_sig: Outgoing configuration result == %d continuation flag == %d\n", result, flags); + + /* Handle config request */ + switch(result) { + case L2CAP_CFG_SUCCESS: + LOG("l2cap_process_sig: Successfull outgoing configuration\n"); + pcb->cfg.l2capcfg |= L2CAP_CFG_IN_SUCCESS; /* Local side of the connection + has been configured for outgoing data */ + pcb->cfg.cfgto = L2CAP_CFG_TO; /* Reset configuration timeout */ + + if(pcb->cfg.outflushto != L2CAP_CFG_DEFAULT_OUTFLUSHTO) { + lp_write_flush_timeout(&pcb->remote_bdaddr, pcb->cfg.outflushto); + } + + /* L2CAP connection established if a successful configuration response has been sent */ + if(pcb->cfg.l2capcfg & L2CAP_CFG_OUT_SUCCESS) { + pcb->state = L2CAP_OPEN; + if(pcb->cfg.l2capcfg & L2CAP_CFG_IR) { + L2CA_ACTION_CONN_CFM(pcb, L2CAP_CONN_SUCCESS, 0x0000, ret); + } else { + L2CA_ACTION_CONN_IND(pcb, ERR_OK, ret); + } + } + break; + case L2CAP_CFG_UNACCEPT: + /* Parse and add options to pcb */ + while(siglen > 0) { + opthdr = p->payload; + /* Check if type of action bit indicates a non-hint. Hints are ignored */ + if(L2CAP_OPTH_TOA(opthdr) == 0) { + switch(L2CAP_OPTH_TYPE(opthdr)) { + case L2CAP_CFG_MTU: + if(L2CAP_MTU > le16toh(((u16_t *)p->payload)[1])) { + pcb->cfg.outmtu = le16toh(((u16_t *)p->payload)[1]); + } else { + ERROR("l2cap_process_sig: Configuration of MTU failed\n"); + l2ca_disconnect_req(pcb, NULL); + return; + } + break; + case L2CAP_FLUSHTO: + pcb->cfg.influshto = le16toh(((u16_t *)p->payload)[1]); + break; + case L2CAP_QOS: + /* If service type Best Effort is not accepted we will close the connection */ + if(((u8_t *)p->payload)[3] != L2CAP_QOS_BEST_EFFORT) { + ERROR("l2cap_process_sig: Unsupported service type\n"); + l2ca_disconnect_req(pcb, NULL); + return; + } + break; + default: + /* Should not happen, skip option */ + break; + } /* switch */ + } /* if(L2CAP_OPTH_TOA(opthdr) == 0) */ + btpbuf_header(p, -(L2CAP_CFGOPTHDR_LEN + opthdr->len)); + siglen -= L2CAP_CFGOPTHDR_LEN + opthdr->len; + } /* while */ + + /* Send out a new configuration request if the continuation flag isn't set */ + if((flags & 0x0001) == 0) { + l2ca_config_req(pcb); + } + break; + case L2CAP_CFG_REJ: + /* Fallthrough */ + case L2CAP_CFG_UNKNOWN: + /* Fallthrough */ + default: + if((flags & 0x0001) == 0) { + LOG("l2cap_process_sig: Configuration failed\n"); + l2ca_disconnect_req(pcb, NULL); + return; + } + break; + } /* switch(result) */ + + /* If continuation flag is set we must send a NULL configuration request */ + if((flags & 0x0001) == 1) { + LOG("l2cap_process_sig: Continuation flag is set. Send empty (default) config request signal\n"); + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CFG_REQ_SIZE, PBUF_RAM)) == NULL) { + ERROR("l2cap_process_sig: Could not allocate memory for pbuf\n"); + return; + } + /* Assemble config request packet */ + ((u16_t *)data->payload)[0] = htole16(pcb->scid); + ((u16_t *)data->payload)[2] = 0; + l2cap_signal(pcb, L2CAP_CFG_REQ, 0, &(pcb->remote_bdaddr), data); + } + break; + case L2CAP_DISCONN_REQ: + siglen = le16toh(sighdr->len); + dcid = le16toh(((u16_t *)p->payload)[0]); + siglen = siglen - 2; + flags = le16toh(((u16_t *)p->payload)[1]); + siglen = siglen - 2; + btpbuf_header(p, -4); + + /* Find PCB with matching cid */ + for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->scid == dcid) { + /* Matching cid found */ + break; + } + } + /* If no matching cid was found, send a cmd reject (Invalid cid) */ + if(pcb == NULL) { + /* Alloc size of reason in cmd rej + data (dcid + scid) */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE+4, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(L2CAP_INVALID_CID); + ((u16_t *)data->payload)[1] = htole16(dcid); /* Requested local cid */ + ((u16_t *)data->payload)[2] = htole16(L2CAP_NULL_CID); /* Remote cid not known */ + + ret = l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); + } + } else { /* Handle disconnection request */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_DISCONN_RSP_SIZE, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(pcb->scid); + ((u16_t *)data->payload)[1] = htole16(pcb->dcid); + ret = l2cap_signal(pcb, L2CAP_DISCONN_RSP, sighdr->id, &(pcb->remote_bdaddr), data); + + /* Give upper layer indication */ + pcb->state = L2CAP_CLOSED; + LOG("l2cap_process_sig: Disconnection request\n"); + L2CA_ACTION_DISCONN_IND(pcb,ERR_OK,ret); + } + } + break; + case L2CAP_DISCONN_RSP: + if(pcb == NULL) { + /* A response without a matching request is silently discarded */ + break; + } + /* Remove signal from unresponded list and deallocate it */ + L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); + btpbuf_free(sig->p); + btmemb_free(&l2cap_sigs, sig); + + L2CA_ACTION_DISCONN_CFM(pcb,ret); /* NOTE: Application should + now close the connection */ + break; + case L2CAP_ECHO_REQ: + pcb->ursp_id = sighdr->id; + ret = l2cap_signal(pcb, L2CAP_ECHO_RSP, sighdr->id, &(pcb->remote_bdaddr), NULL); + break; + case L2CAP_ECHO_RSP: + if(pcb == NULL) { + /* A response without a matching request is silently discarded */ + break; + } + /* Remove signal from unresponded list and deallocate it */ + L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); + btpbuf_free(sig->p); + btmemb_free(&l2cap_sigs, sig); + + /* Remove temporary pcb from active list */ + L2CAP_RMV(&l2cap_active_pcbs, pcb); + L2CA_ACTION_PING_CFM(pcb,L2CAP_ECHO_RCVD,ret); + break; + default: + /* Alloc size of reason in cmd rej */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(L2CAP_CMD_NOT_UNDERSTOOD); + + ret = l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); + } + break; + } /* switch */ + len = len - (le16toh(sighdr->len) + L2CAP_SIGHDR_LEN); + btpbuf_header(p, -(le16toh(sighdr->len))); + } /* while */ +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_input(): + * + * Called by the lower layer. Reassembles the packet, parses the header and forward + * it to the upper layer or the signal handler. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_input(struct pbuf *p, struct bd_addr *bdaddr) +{ + struct l2cap_seg *inseg; + struct hci_acl_hdr *aclhdr; + struct pbuf *data; + err_t ret; + + (void)ret; + + btpbuf_header(p, HCI_ACL_HDR_LEN); + aclhdr = p->payload; + btpbuf_header(p, -HCI_ACL_HDR_LEN); + + btpbuf_realloc(p, aclhdr->len); + + for(inseg = l2cap_insegs; inseg != NULL; inseg = inseg->next) { + if(bd_addr_cmp(bdaddr, &(inseg->bdaddr))) { + break; + } + } + + aclhdr->connhdl_pb_bc = le16toh(aclhdr->connhdl_pb_bc); + aclhdr->len = le16toh(aclhdr->len); + /* Reassembly procedures */ + /* Check if continuing fragment or start of L2CAP packet */ + if(((aclhdr->connhdl_pb_bc >> 12) & 0x03)== L2CAP_ACL_CONT) { /* Continuing fragment */ + if(inseg == NULL) { + /* Discard packet */ + LOG("l2cap_input: Continuing fragment. Discard packet\n"); + btpbuf_free(p); + return; + } else if(inseg->p->tot_len + p->tot_len > inseg->len) { /* Check if length of + segment exceeds + l2cap header length */ + /* Discard packet */ + LOG("l2cap_input: Continuing fragment. Length exceeds L2CAP hdr length. Discard packet\n"); + btpbuf_free(inseg->p); + L2CAP_SEG_RMV(&(l2cap_insegs), inseg); + btmemb_free(&l2cap_segs, inseg); + + btpbuf_free(p); + return; + } + /* Add pbuf to segement */ + btpbuf_chain(inseg->p, p); + btpbuf_free(p); + + } else if(((aclhdr->connhdl_pb_bc >> 12) & 0x03) == L2CAP_ACL_START) { /* Start of L2CAP packet */ + //LOG("l2cap_input: Start of L2CAP packet p->len = %d, p->tot_len = %d\n", p->len, p->tot_len); + if(inseg != NULL) { /* Check if there are segments missing in a previous packet */ + /* Discard previous packet */ + LOG("l2cap_input: Start of L2CAP packet. Discard previous packet\n"); + btpbuf_free(inseg->p); + } else { + inseg = btmemb_alloc(&l2cap_segs); + bd_addr_set(&(inseg->bdaddr), bdaddr); + L2CAP_SEG_REG(&(l2cap_insegs), inseg); + } + inseg->p = p; + inseg->l2caphdr = p->payload; + inseg->l2caphdr->cid = le16toh(inseg->l2caphdr->cid); + inseg->l2caphdr->len = le16toh(inseg->l2caphdr->len); + + inseg->len = inseg->l2caphdr->len + L2CAP_HDR_LEN; + for(inseg->pcb = l2cap_active_pcbs; inseg->pcb != NULL; inseg->pcb = inseg->pcb->next) { + if(inseg->pcb->scid == inseg->l2caphdr->cid) { + break; /* found */ + } + } + } else { + /* Discard packet */ + LOG("l2cap_input: Discard packet\n"); + btpbuf_free(inseg->p); + L2CAP_SEG_RMV(&(l2cap_insegs), inseg); + btmemb_free(&l2cap_segs, inseg); + + btpbuf_free(p); + return; + } + if(inseg->p->tot_len < inseg->len) { + LOG("l2cap_input: Get continuing segments\n"); + return; /* Get continuing segments */ + } + + /* Handle packet */ + switch(inseg->l2caphdr->cid) { + case L2CAP_NULL_CID: + /* Illegal */ + LOG("l2cap_input: Illegal null cid\n"); + btpbuf_free(inseg->p); + break; + case L2CAP_SIG_CID: + btpbuf_header(inseg->p, -L2CAP_HDR_LEN); + l2cap_process_sig(inseg->p, inseg->l2caphdr, bdaddr); + btpbuf_free(inseg->p); + break; + case L2CAP_CONNLESS_CID: + /* Not needed by PAN, LAN access or DUN profiles */ + btpbuf_free(inseg->p); + break; + default: + if(inseg->l2caphdr->cid < 0x0040 || inseg->pcb == NULL) { + /* Reserved for specific L2CAP functions or channel does not exist */ + /* Alloc size of reason in cmd rej */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE+4, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(L2CAP_INVALID_CID); + ((u16_t *)data->payload)[1] = htole16(inseg->l2caphdr->cid); + ((u16_t *)data->payload)[2] = htole16(L2CAP_NULL_CID); + + ret = l2cap_signal(NULL, L2CAP_CMD_REJ, l2cap_next_sigid(), bdaddr, data); + } + btpbuf_free(inseg->p); + break; + } + + btpbuf_header(inseg->p, -L2CAP_HDR_LEN); + + /* Forward packet to higher layer */ + LOG("l2cap_input: Forward packet to higher layer\n"); + /* + LOG("l2cap_input: Remote BD address: 0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n", + inseg->pcb->remote_bdaddr.addr[5], + inseg->pcb->remote_bdaddr.addr[4], + inseg->pcb->remote_bdaddr.addr[3], + inseg->pcb->remote_bdaddr.addr[2], + inseg->pcb->remote_bdaddr.addr[1], + inseg->pcb->remote_bdaddr.addr[0])); + */ + L2CA_ACTION_RECV(inseg->pcb,inseg->p,ERR_OK,ret); + break; + } + + /* Remove input segment */ + L2CAP_SEG_RMV(&(l2cap_insegs), inseg); + btmemb_free(&l2cap_segs, inseg); +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_cid_alloc(): + * + * Allocates a channel identifier (CID). They are local names representing a logical + * channel endpoint on the device. + */ +/*-----------------------------------------------------------------------------------*/ +static u16_t l2cap_cid_alloc(void) +{ + u16_t cid; + struct l2cap_pcb *pcb; + + for (cid = L2CAP_MIN_CID; cid < L2CAP_MAX_CID; ++cid) { + for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->scid == cid) { + break; + } + } + if(pcb == NULL) { + return cid; + } + } + return 0; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_new(): + * + * Creates a new L2CAP protocol control block but doesn't place it on + * any of the L2CAP PCB lists. + */ +/*-----------------------------------------------------------------------------------*/ +struct l2cap_pcb* l2cap_new(void) +{ + struct l2cap_pcb *pcb; + + pcb = btmemb_alloc(&l2cap_pcbs); + if(pcb != NULL) { + memset(pcb, 0, sizeof(struct l2cap_pcb)); + pcb->state = L2CAP_CLOSED; + + /* Initialize configuration parameter options with default values */ + + /* Maximum Transmission Unit */ + pcb->cfg.inmtu = L2CAP_MTU; /* The MTU that this implementation support */ + pcb->cfg.outmtu = 672; /* Default MTU. Two Baseband DH5 packets minus the Baseband ACL headers and + L2CAP header. This can be set here since we will never send any signals + larger than the L2CAP sig MTU (48 bytes) before L2CAP has been configured + */ + + /* Flush Timeout */ + pcb->cfg.influshto = 0xFFFF; + pcb->cfg.outflushto = 0xFFFF; + + pcb->cfg.cfgto = L2CAP_CFG_TO; /* Maximum time before terminating a negotiation. + Cfg shall not last more than 120s */ + pcb->cfg.opt = NULL; + return pcb; + } + ERROR("l2cap_new: Could not allocate memory for pcb\n"); + return NULL; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_close(): + * + * Closes the L2CAP protocol control block. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2cap_close(struct l2cap_pcb *pcb) +{ + struct l2cap_sig *tmpsig; + + if(pcb->state == L2CAP_LISTEN) { + L2CAP_RMV((struct l2cap_pcb**)((void*)&(l2cap_listen_pcbs)), pcb); + btmemb_free(&l2cap_listenpcbs, pcb); + } else { + L2CAP_RMV(&(l2cap_active_pcbs), pcb); + /* Free any unresponded signals */ + while(pcb->unrsp_sigs != NULL) { + tmpsig = pcb->unrsp_sigs; + pcb->unrsp_sigs = pcb->unrsp_sigs->next; + btmemb_free(&l2cap_sigs, tmpsig); + } + + btmemb_free(&l2cap_pcbs, pcb); + } + pcb = NULL; + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_reset_all(): + * + * Closes all active and listening L2CAP protocol control blocks. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_reset_all(void) +{ + struct l2cap_pcb *pcb, *tpcb; + struct l2cap_pcb_listen *lpcb, *tlpcb; + struct l2cap_seg *seg, *tseg; + + for(pcb = l2cap_active_pcbs; pcb != NULL;) { + tpcb = pcb->next; + l2cap_close(pcb); + pcb = tpcb; + } + + for(lpcb = l2cap_listen_pcbs; lpcb != NULL;) { + tlpcb = lpcb->next; + l2cap_close((struct l2cap_pcb *)lpcb); + lpcb = tlpcb; + } + + for(seg = l2cap_insegs; seg != NULL;) { + tseg = seg->next; + L2CAP_SEG_RMV(&(l2cap_insegs), seg); + btmemb_free(&l2cap_segs, seg); + seg = tseg; + } + + l2cap_init(); +} + +/*-----------------------------------------------------------------------------------*/ +/* L2CAP to L2CAP signalling events + */ +/*-----------------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_signal(): + * + * Assembles the signalling packet and passes it to the lower layer. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2cap_signal(struct l2cap_pcb *pcb, u8_t code, u16_t ursp_id, struct bd_addr *remote_bdaddr, struct pbuf *data) +{ + struct l2cap_sig *sig; + struct l2cap_sig_hdr *sighdr; + struct l2cap_hdr *hdr; + err_t ret; + + /* Alloc a new signal */ + LOG("l2cap_signal: Allocate memory for l2cap_sig. Code = 0x%x\n", code); + if((sig = btmemb_alloc(&l2cap_sigs)) == NULL) { + ERROR("l2cap_signal: could not allocate memory for l2cap_sig\n"); + return ERR_MEM; + } + + /* Alloc a pbuf for signal */ + if((sig->p = btpbuf_alloc(PBUF_RAW, L2CAP_HDR_LEN+L2CAP_SIGHDR_LEN, PBUF_RAM)) == NULL) { + ERROR("l2cap_signal: could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Setup signal header and leave room for l2cap hdr */ + sighdr = (struct l2cap_sig_hdr *)(((u8_t *)sig->p->payload)+L2CAP_HDR_LEN); + + /* Chain data to signal and set length of signal data */ + if(data == NULL) { + sighdr->len = 0; + } else { + btpbuf_chain(sig->p, data); + btpbuf_free(data); + sighdr->len = htole16(data->tot_len); + } + + sighdr->code = code; + + if(sighdr->code % 2) { /* If odd this is a resp/rej signal */ + sig->sigid = ursp_id; /* Get id */ + LOG("l2cap_signal: Sending response/reject signal with id = %d code = %d\n", sig->sigid, sighdr->code); + } else { + sig->sigid = l2cap_next_sigid(); /* Alloc id */ + sig->rtx = L2CAP_RTX; /* Set Response Timeout Expired timer (in seconds) + should be at least as large as the BB flush timeout */ + sig->nrtx = L2CAP_MAXRTX; /* Set max number of retransmissions */ + LOG("l2cap_signal: Sending request signal with id = %d code = %d\n", sig->sigid, sighdr->code); + } + sighdr->id = sig->sigid; /* Set id */ + + /* Set up L2CAP hdr */ + hdr = sig->p->payload; + hdr->len = htole16((sig->p->tot_len - L2CAP_HDR_LEN)); + hdr->cid = htole16(L2CAP_SIG_CID); /* 0x0001 */ + + ret = l2cap_write(remote_bdaddr, sig->p, sig->p->tot_len); /* Send peer L2CAP signal */ + + /* Put signal on unresponded list if it's a request signal, else deallocate it */ + if(ret == ERR_OK && (sighdr->code % 2) == 0) { + LOG("l2cap_signal: Registering sent request signal with id = %d code = %d\n", sig->sigid, sighdr->code); + L2CAP_SIG_REG(&(pcb->unrsp_sigs), sig); + } else { + LOG("l2cap_signal: Deallocating sent response/reject signal with id = %d code = %d\n", sig->sigid, sighdr->code); + btpbuf_free(sig->p); + sig->p = NULL; + btmemb_free(&l2cap_sigs, sig); + } + + return ret; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_rexmit_signal(): + * + * Called by the l2cap timer. Retransmitts a signal. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2cap_rexmit_signal(struct l2cap_pcb *pcb, struct l2cap_sig *sig) +{ + err_t ret; + + /* Set up L2CAP hdr */ + ret = l2cap_write(&(pcb->remote_bdaddr), sig->p, sig->p->tot_len); /* Send peer L2CAP signal */ + + return ret; +} +/*-----------------------------------------------------------------------------------*/ +/* Upper-Layer to L2CAP signaling events + */ +/*-----------------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------------*/ +/* + * l2ca_connect_req(): + * + * Initiates the sending of a connect request message. Requests the creation of a + * channel representing a logicalconnection to a physical address. Input parameters + * are the target protocol(PSM) and remote devices 48-bit address (BD_ADDR). Also + * specify the function to be called when a confirm has been received. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2ca_connect_req(struct l2cap_pcb *pcb, struct bd_addr *bdaddr, u16_t psm, + u8_t role_switch, err_t (* l2ca_connect_cfm)(void *arg, struct l2cap_pcb *lpcb, + u16_t result, u16_t status)) +{ + err_t ret; + struct pbuf *data; + + if(bdaddr != NULL) { + bd_addr_set(&(pcb->remote_bdaddr),bdaddr); + } else { + return ERR_VAL; + } + + pcb->psm = psm; + pcb->l2ca_connect_cfm = l2ca_connect_cfm; + pcb->scid = l2cap_cid_alloc(); + + pcb->cfg.l2capcfg |= L2CAP_CFG_IR; /* We are the initiator of this connection */ + + if(!lp_is_connected(bdaddr)) { + ret = lp_connect_req(bdaddr, role_switch); /* Create ACL link w pcb state == CLOSED */ + } else { + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CONN_REQ_SIZE, PBUF_RAM)) == NULL) { + ERROR("l2cap_connect_req: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + ((u16_t *)data->payload)[0] = htole16(psm); + ((u16_t *)data->payload)[1] = htole16(pcb->scid); + ret = l2cap_signal(pcb, L2CAP_CONN_REQ, 0, &(pcb->remote_bdaddr), data); /* Send l2cap_conn_req signal */ + + pcb->state = W4_L2CAP_CONNECT_RSP; + } + + L2CAP_REG(&(l2cap_active_pcbs), pcb); + + return ret; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2ca_config_req(): + * + * Requests the initial configuration (or reconfiguration) of a channel to a new set + * of channel parameters. Input parameters are the local CID endpoint, new incoming + * receivable MTU (InMTU), new outgoing flow specification, and flush and link + * timeouts. Also specify the function to be called when a confirm has been received. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2ca_config_req(struct l2cap_pcb *pcb) +{ + struct pbuf *p, *q; + struct l2cap_cfgopt_hdr *opthdr; + err_t ret; + + switch(pcb->state) { + case L2CAP_OPEN: + LOG("l2cap_config_req: state = L2CAP_OPEN. Suspend transmission\n"); + /* Note: Application should have suspended data transmission, otherwise outgoing data will be + dropped */ + pcb->state = L2CAP_CONFIG; + /* Fallthrough */ + case L2CAP_CONFIG: + LOG("l2cap_config_req: state = L2CAP_CONFIG\n"); + + if((p = btpbuf_alloc(PBUF_RAW, L2CAP_CFG_REQ_SIZE, PBUF_RAM)) == NULL) { + ERROR("l2cap_config_req: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assemble config request packet. Only options that has to be changed will be + sent */ + ((u16_t *)p->payload)[0] = htole16(pcb->dcid); + /* In this implementation we do not send multiple cmds in one + signal packet. Therefore we will never send a config_req packet + that will cause the signal to be larger than the minimum L2CAP MTU + 48 bytes. Hence, this flag will always be cleared */ + ((u16_t *)p->payload)[1] = 0; + + /* Add MTU and out flush timeout to cfg packet if not default value. QoS (Best effort) is always + set to default and can be skipped */ + if(pcb->cfg.inmtu != L2CAP_CFG_DEFAULT_INMTU) { + if((q = btpbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + L2CAP_MTU_LEN, PBUF_RAM)) == NULL) { + ERROR("l2cap_config_req: Could not allocate memory for pbuf\n"); + btpbuf_free(p); + return ERR_MEM; + } + opthdr = q->payload; + opthdr->type = L2CAP_CFG_MTU; + opthdr->len = L2CAP_MTU_LEN; + ((u16_t *)q->payload)[1] = htole16(pcb->cfg.inmtu); + btpbuf_chain(p, q); + btpbuf_free(q); + } + + if(L2CAP_OUT_FLUSHTO != L2CAP_CFG_DEFAULT_OUTFLUSHTO) { + if((q = btpbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + L2CAP_FLUSHTO_LEN, PBUF_RAM)) == NULL) { + ERROR("l2cap_config_req: Could not allocate memory for pbuf\n"); + btpbuf_free(p); + return ERR_MEM; + } + opthdr = q->payload; + opthdr->type = L2CAP_FLUSHTO; + opthdr->len = L2CAP_FLUSHTO_LEN; + pcb->cfg.outflushto = L2CAP_OUT_FLUSHTO; + ((u16_t *)q->payload)[1] = htole16(pcb->cfg.outflushto); + btpbuf_chain(p, q); + btpbuf_free(q); + } + + /* Send config request signal */ + ret = l2cap_signal(pcb, L2CAP_CFG_REQ, 0, &(pcb->remote_bdaddr), p); + break; + default: + ERROR("l2cap_config_req: state = L2CAP_?. Invalid state\n"); + return ERR_CONN; /* Invalid state. Connection is not in OPEN or CONFIG state */ + } + return ret; +} +/*-----------------------------------------------------------------------------------*/ +/* + * l2ca_disconnect_req(): + * + * Requests the disconnection of the channel. Also specify the function to be called + * when a confirm is received + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2ca_disconnect_req(struct l2cap_pcb *pcb, err_t (* l2ca_disconnect_cfm)(void *arg, struct l2cap_pcb *pcb)) +{ + struct pbuf *data; + err_t ret; + + if(pcb->state == L2CAP_OPEN || pcb->state == L2CAP_CONFIG) { + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_DISCONN_REQ_SIZE, PBUF_RAM)) == NULL) { + ERROR("l2cap_disconnect_req: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + pcb->l2ca_disconnect_cfm = l2ca_disconnect_cfm; + + ((u16_t *)data->payload)[0] = htole16(pcb->dcid); + ((u16_t *)data->payload)[1] = htole16(pcb->scid); + + ret = l2cap_signal(pcb, L2CAP_DISCONN_REQ, 0, &(pcb->remote_bdaddr), data); + + if(ret == ERR_OK) { + pcb->state = W4_L2CAP_DISCONNECT_RSP; + } + } else { + return ERR_CONN; /* Signal not supported in this state */ + } + + return ret; +} +/*-----------------------------------------------------------------------------------*/ +/* + * l2ca_datawrite(): + * + * Transfers data across the channel. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2ca_datawrite(struct l2cap_pcb *pcb, struct pbuf *p) +{ + err_t ret; + struct l2cap_hdr *l2caphdr; + struct pbuf *q; + + if(pcb->state != L2CAP_OPEN) { + ERROR("l2cap_datawrite: State != L2CAP_OPEN. Dropping data\n"); + return ERR_CONN; + } + + /* Build L2CAP header */ + if((q = btpbuf_alloc(PBUF_RAW, L2CAP_HDR_LEN, PBUF_RAM)) == NULL) { + ERROR("l2cap_datawrite: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + btpbuf_chain(q, p); + + l2caphdr = q->payload; + l2caphdr->cid = htole16(pcb->dcid); + + /* If length of the data exceeds the OutMTU then only the first OutMTU bytes are sent */ + if(p->tot_len > pcb->cfg.outmtu) { + /* Send peer L2CAP data */ + l2caphdr->len = htole16(pcb->cfg.outmtu); + if((ret = l2cap_write(&(pcb->remote_bdaddr), q, pcb->cfg.outmtu + L2CAP_HDR_LEN)) == ERR_OK) { + //LOG("l2cap_datawrite: Length of data exceeds the OutMTU p->tot_len = %d\n", p->tot_len); + ret = ERR_BUF; /* Length of data exceeds the OutMTU */ + } + } else { + /* Send peer L2CAP data */ + l2caphdr->len = htole16(p->tot_len); + //LOG("l2cap_datawrite: q->tot_len = %d\n", q->tot_len); + ret = l2cap_write(&(pcb->remote_bdaddr), q, q->tot_len); + } + + /* Free L2CAP header. Higher layers will handle rest of packet */ + p = btpbuf_dechain(q); + btpbuf_free(q); + + return ret; +} +/*-----------------------------------------------------------------------------------*/ +/* + * l2ca_ping(): + * + * Sends an empty L2CAP echo request message. Also specify the function that should + * be called when a L2CAP echo reply has been received. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2ca_ping(struct bd_addr *bdaddr, struct l2cap_pcb *tpcb, + err_t (* l2ca_pong)(void *arg, struct l2cap_pcb *pcb, u8_t result)) +{ + err_t ret; + + if(!lp_is_connected(bdaddr)) { + return ERR_CONN; + } + + bd_addr_set(&(tpcb->remote_bdaddr), bdaddr); + tpcb->l2ca_pong = l2ca_pong; + + L2CAP_REG(&(l2cap_active_pcbs), tpcb); + + ret = l2cap_signal(tpcb, L2CAP_ECHO_REQ, 0, &(tpcb->remote_bdaddr), NULL); /* Send l2cap_echo_req signal */ + + return ret; +} +/*-----------------------------------------------------------------------------------*/ +/* Lower-Layer to L2CAP signaling events + */ +/*-----------------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------------*/ +/* + * lp_connect_cfm(): + * + * Confirms the request to establish a lower layer (Baseband) connection. + */ +/*-----------------------------------------------------------------------------------*/ +void lp_connect_cfm(struct bd_addr *bdaddr, u8_t encrypt_mode, err_t err) +{ + struct l2cap_pcb *pcb; + struct pbuf *data; + err_t ret; + + for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { + if(bd_addr_cmp(&(pcb->remote_bdaddr), bdaddr)) { + break; + } + } + if(pcb == NULL) { + /* Silently discard */ + LOG("lp_connect_cfm: Silently discard\n"); + } else { + if(err == ERR_OK) { + pcb->encrypt = encrypt_mode; + /* Send l2cap_conn_req signal if no error */ + if((data = btpbuf_alloc(PBUF_RAW, L2CAP_CONN_REQ_SIZE, PBUF_RAM)) != NULL) { + ((u16_t *)data->payload)[0] = htole16(pcb->psm); + ((u16_t *)data->payload)[1] = htole16(pcb->scid); + if((ret = l2cap_signal(pcb, L2CAP_CONN_REQ, 0, &(pcb->remote_bdaddr), data)) == ERR_OK) { + pcb->state = W4_L2CAP_CONNECT_RSP; + } else { + L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available? */ + } + //LOG("lp_connect_cfm: l2cap_conn_req signal sent. err = %d\nPSM = 0x%x\nscid = 0x%x\nencrypt mode = 0x%x\n", err, pcb->psm, pcb->scid, pcb->encrypt); + } else { + ERROR("lp_connect_cfm: No resources available\n"); + L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available */ + } + } else { + ERROR("lp_connect_cfm: Connection falied\n"); + L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available */ + } + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * lp_connect_ind(): + * + * Indicates the lower protocol has successfully established a connection. + */ +/*-----------------------------------------------------------------------------------*/ +void lp_connect_ind(struct bd_addr *bdaddr) +{ + LOG("lp_connect_ind\n"); +} +/*-----------------------------------------------------------------------------------*/ +/* + * lp_disconnect_ind(): + * + * Indicates the lower protocol (Baseband) has been shut down by LMP commands or a + * timeout event.. + */ +/*-----------------------------------------------------------------------------------*/ +void lp_disconnect_ind(struct bd_addr *bdaddr,u8_t reason) +{ + struct l2cap_pcb *pcb, *tpcb; + err_t ret; + + (void)ret; + + for(pcb = l2cap_active_pcbs; pcb != NULL;) { + tpcb = pcb->next; + LOG("lp_disconnect_ind: Find a pcb with a matching Bluetooth address\n"); + /* All PCBs with matching Bluetooth address have been disconnected */ + if(bd_addr_cmp(&(pcb->remote_bdaddr), bdaddr)) {// && pcb->state != L2CAP_CLOSED) { + pcb->state = L2CAP_CLOSED; + LOG("lp_disconnect_ind: Notify application\n"); + L2CA_ACTION_DISCONN_IND(pcb,ERR_OK,ret); + } + pcb = tpcb; + } + if(l2cap_disconnect_bb_cb) l2cap_disconnect_bb_cb(bdaddr,reason); +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_disconnect_bb(): + * + * Register a callback to obtain the disconnection reason from the baseband + */ +/*-----------------------------------------------------------------------------------*/ +void (*l2cap_disconnect_bb(void (*l2ca_disconnect_bb)(struct bd_addr *bdaddr,u8_t reason)))(struct bd_addr *bdaddr,u8_t reason) +{ + void (*oldcb)(struct bd_addr *bdaddr,u8_t reason) = NULL; + oldcb = l2cap_disconnect_bb_cb; + l2cap_disconnect_bb_cb = l2ca_disconnect_bb; + return oldcb; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_next_sigid(): + * + * Issues a signal identifier that helps matching a request with the reply. + */ +/*-----------------------------------------------------------------------------------*/ +u8_t l2cap_next_sigid(void) +{ + ++sigid_nxt; + if(sigid_nxt == 0) { + sigid_nxt = 1; + } + return sigid_nxt; +} +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_arg(): + * + * Used to specify the argument that should be passed callback functions. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_arg(struct l2cap_pcb *pcb, void *arg) +{ + pcb->callback_arg = arg; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_connect_ind(): + * + * Set the state of the connection to be LISTEN, which means that it is able to accept + * incoming connections. The protocol control block is reallocated in order to consume + * less memory. Setting the connection to LISTEN is an irreversible process. Also + * specify the function that should be called when the channel has received a + * connection request. + */ +/*-----------------------------------------------------------------------------------*/ +err_t l2cap_connect_ind(struct l2cap_pcb *npcb, struct bd_addr *bdaddr, u16_t psm,err_t (* l2ca_connect_ind)(void *arg, struct l2cap_pcb *pcb, err_t err)) +{ + struct l2cap_pcb_listen *lpcb; + + lpcb = btmemb_alloc(&l2cap_listenpcbs); + if(lpcb == NULL) { + ERROR("l2cap_connect_ind: Could not allocate memory for lpcb\n"); + return ERR_MEM; + } + + bd_addr_set(&(lpcb->bdaddr),bdaddr); + lpcb->psm = psm; + lpcb->l2ca_connect_ind = l2ca_connect_ind; + lpcb->state = L2CAP_LISTEN; + lpcb->callback_arg = npcb->callback_arg; + btmemb_free(&l2cap_pcbs, npcb); + L2CAP_REG(&(l2cap_listen_pcbs), lpcb); + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_disconnect_ind(): + * + * Used to specify the a function to be called when a disconnection request has been + * received from a remote device or the remote device has been disconnected because it + * has failed to respond to a signalling request. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_disconnect_ind(struct l2cap_pcb *pcb, err_t (* l2ca_disconnect_ind)(void *arg, struct l2cap_pcb *newpcb, err_t err)) +{ + pcb->l2ca_disconnect_ind = l2ca_disconnect_ind; +} +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_timeout_ind(): + * + * Used to specify the function to be called when RTX or ERTX timer has expired. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_timeout_ind(struct l2cap_pcb *pcb,err_t (* l2ca_timeout_ind)(void *arg, struct l2cap_pcb *newpcb, err_t err)) +{ + pcb->l2ca_timeout_ind = l2ca_timeout_ind; +} +/*-----------------------------------------------------------------------------------*/ +/* + * l2cap_recv(): + * + * Used to specify the function that should be called when a L2CAP connection receives + * data. + */ +/*-----------------------------------------------------------------------------------*/ +void l2cap_recv(struct l2cap_pcb *pcb, err_t (* l2ca_recv)(void *arg, struct l2cap_pcb *pcb, struct pbuf *p, err_t err)) +{ + pcb->l2ca_recv = l2ca_recv; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/wii/libogc/lwbt/l2cap.h b/wii/libogc/lwbt/l2cap.h new file mode 100644 index 0000000000..6ba450d7f1 --- /dev/null +++ b/wii/libogc/lwbt/l2cap.h @@ -0,0 +1,356 @@ +#ifndef __L2CAP_H__ +#define __L2CAP_H__ + +#include "bt.h" +#include "bd_addr.h" + +/* Protocol and service multiplexor */ +#define HIDP_PSM 0x0011 +#define INTR_PSM 0x0013 + +/* Packet header lengths */ +#define L2CAP_HDR_LEN 4 +#define L2CAP_SIGHDR_LEN 4 +#define L2CAP_CFGOPTHDR_LEN 2 + +/* Signals sizes */ +#define L2CAP_CONN_REQ_SIZE 4 +#define L2CAP_CONN_RSP_SIZE 8 +#define L2CAP_CFG_RSP_SIZE 6 +#define L2CAP_DISCONN_RSP_SIZE 4 + +#define L2CAP_CFG_REQ_SIZE 4 + +#define L2CAP_DISCONN_REQ_SIZE 4 +#define L2CAP_CMD_REJ_SIZE 2 + +/* Signal codes */ +#define L2CAP_CMD_REJ 0x01 +#define L2CAP_CONN_REQ 0x02 +#define L2CAP_CONN_RSP 0x03 +#define L2CAP_CFG_REQ 0x04 +#define L2CAP_CFG_RSP 0x05 +#define L2CAP_DISCONN_REQ 0x06 +#define L2CAP_DISCONN_RSP 0x07 +#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_INFO_REQ 0x0A +#define L2CAP_INFO_RSP 0x0B + +/* Permanent channel identifiers */ +#define L2CAP_NULL_CID 0x0000 +#define L2CAP_SIG_CID 0x0001 +#define L2CAP_CONNLESS_CID 0x0002 + +/* Channel identifiers values */ +#define L2CAP_MIN_CID 0x0040 +#define L2CAP_MAX_CID 0xFFFF + +/* Configuration types */ +#define L2CAP_CFG_MTU 0x01 +#define L2CAP_FLUSHTO 0x02 +#define L2CAP_QOS 0x03 + +/* Configuration types length */ +#define L2CAP_MTU_LEN 2 +#define L2CAP_FLUSHTO_LEN 2 +#define L2CAP_QOS_LEN 22 + +/* Configuration response types */ +#define L2CAP_CFG_SUCCESS 0x0000 +#define L2CAP_CFG_UNACCEPT 0x0001 +#define L2CAP_CFG_REJ 0x0002 +#define L2CAP_CFG_UNKNOWN 0x0003 +#define L2CAP_CFG_TIMEOUT 0xEEEE + +/* QoS types */ +#define L2CAP_QOS_NO_TRAFFIC 0x00 +#define L2CAP_QOS_BEST_EFFORT 0x01 +#define L2CAP_QOS_GUARANTEED 0x02 + +/* Command reject reasons */ +#define L2CAP_CMD_NOT_UNDERSTOOD 0x0000 +#define L2CAP_MTU_EXCEEDED 0x0001 +#define L2CAP_INVALID_CID 0x0002 + +/* Connection response results */ +#define L2CAP_CONN_SUCCESS 0x0000 +#define L2CAP_CONN_PND 0x0001 +#define L2CAP_CONN_REF_PSM 0x0002 +#define L2CAP_CONN_REF_SEC 0x0003 +#define L2CAP_CONN_REF_RES 0x0004 +#define L2CAP_CONN_CFG_TO 0x0005 /* Implementation specific result */ + +/* Echo response results */ +#define L2CAP_ECHO_RCVD 0x00 +#define L2CAP_ECHO_TO 0x01 + +/* L2CAP segmentation */ +#define L2CAP_ACL_START 0x02 +#define L2CAP_ACL_CONT 0x01 + +/* L2CAP config default parameters */ +#define L2CAP_CFG_DEFAULT_INMTU 672 /* Two Baseband DH5 packets (2*341=682) minus the Baseband ACL + headers (2*2=4) and L2CAP header (6) */ +#define L2CAP_CFG_DEFAULT_OUTFLUSHTO 0xFFFF + +/* L2CAP configuration parameter masks */ +#define L2CAP_CFG_IR 0x01 +#define L2CAP_CFG_IN_SUCCESS 0x02 +#define L2CAP_CFG_OUT_SUCCESS 0x04 +#define L2CAP_CFG_OUT_REQ 0x08 + +enum l2cap_state { + L2CAP_CLOSED, L2CAP_LISTEN, W4_L2CAP_CONNECT_RSP, W4_L2CA_CONNECT_RSP, L2CAP_CONFIG, + L2CAP_OPEN, W4_L2CAP_DISCONNECT_RSP, W4_L2CA_DISCONNECT_RSP +}; + +struct l2cap_hdr +{ + u16_t len; + u16_t cid; +} ATTRIBUTE_PACKED; + +struct l2cap_sig_hdr +{ + u8_t code; + u8_t id; + u16_t len; +} ATTRIBUTE_PACKED; + +struct l2cap_cfgopt_hdr +{ + u8_t type; + u8_t len; +} ATTRIBUTE_PACKED; + +/* This structure is used to represent L2CAP signals. */ +struct l2cap_sig { + struct l2cap_sig *next; /* for the linked list, used when putting signals + on a queue */ + struct pbuf *p; /* buffer containing data + L2CAP header */ + u16_t sigid; /* Identification */ + u16_t ertx; /* extended response timeout expired */ + u8_t rtx; /* response timeout expired */ + u8_t nrtx; /* number of retransmissions */ +}; + +struct l2cap_cfg +{ + u16_t inmtu; + u16_t outmtu; + u16_t influshto; + u16_t outflushto; + + struct pbuf *opt; + + u8_t cfgto; + u8_t l2capcfg; +}; + +struct l2cap_seg +{ + struct l2cap_seg *next; + struct bd_addr bdaddr; + struct pbuf *p; + u16_t len; + struct l2cap_hdr *l2caphdr; + struct l2cap_pcb *pcb; /* The L2CAP Protocol Control Block */ +}; + +struct l2cap_pcb { + struct l2cap_pcb *next; /* For the linked list */ + + enum l2cap_state state; /* L2CAP state */ + + void *callback_arg; + + u16_t scid; /* Source CID */ + u16_t dcid; /* Destination CID */ + + u16_t psm; /* Protocol/Service Multiplexer */ + + u16_t ursp_id; /* Signal id to respond to */ + u8_t encrypt; /* encryption mode */ + + struct l2cap_sig *unrsp_sigs; /* List of sent but unresponded signals */ + + struct bd_addr remote_bdaddr; + + struct l2cap_cfg cfg; /* Configuration parameters */ + + /* Upper layer to L2CAP confirmation functions */ + + /* Function to be called when a connection has been set up */ + err_t (* l2ca_connect_cfm)(void *arg, struct l2cap_pcb *pcb, u16_t result, u16_t status); + /* Function to be called when a connection has been closed */ + err_t (* l2ca_disconnect_cfm)(void *arg, struct l2cap_pcb *pcb); + /* Function to be called when a echo reply has been received */ + err_t (* l2ca_pong)(void *arg, struct l2cap_pcb *pcb, u8_t result); + + /* L2CAP to upper layer indication functions */ + + /* Function to be called when a connection indication event occurs */ + err_t (* l2ca_connect_ind)(void *arg, struct l2cap_pcb *pcb, err_t err); + /* Function to be called when a disconnection indication event occurs */ + err_t (* l2ca_disconnect_ind)(void *arg, struct l2cap_pcb *pcb, err_t err); + /* Function to be called when a timeout indication event occurs */ + err_t (* l2ca_timeout_ind)(void *arg, struct l2cap_pcb *newpcb, err_t err); + /* Function to be called when a L2CAP connection receives data */ + err_t (* l2ca_recv)(void *arg, struct l2cap_pcb *pcb, struct pbuf *p, err_t err); +}; + +struct l2cap_pcb_listen { + struct l2cap_pcb_listen *next; /* for the linked list */ + + enum l2cap_state state; /* L2CAP state */ + + void *callback_arg; + + u16_t psm; /* Protocol/Service Multiplexer */ + struct bd_addr bdaddr; /* Device Address */ + + /* Function to call when a connection request has been received + from a remote device. */ + err_t (* l2ca_connect_ind)(void *arg, struct l2cap_pcb *pcb, err_t err); +}; + +#define l2cap_psm(pcb) ((pcb)->psm) + +void l2cap_init(); +struct l2cap_pcb* l2cap_new(void); + +void lp_connect_ind(struct bd_addr *bdaddr); +void lp_connect_cfm(struct bd_addr *bdaddr, u8_t encrypt_mode, err_t err); +void lp_disconnect_ind(struct bd_addr *bdaddr,u8_t reason); + +err_t l2ca_config_req(struct l2cap_pcb *pcb); +err_t l2ca_disconnect_req(struct l2cap_pcb *pcb, err_t (* l2ca_disconnect_cfm)(void *arg, struct l2cap_pcb *pcb)); +err_t l2ca_datawrite(struct l2cap_pcb *pcb, struct pbuf *p); +err_t l2ca_ping(struct bd_addr *bdaddr, struct l2cap_pcb *tpcb,err_t (* l2ca_pong)(void *arg, struct l2cap_pcb *pcb, u8_t result)); +err_t l2ca_connect_req(struct l2cap_pcb *pcb, struct bd_addr *bdaddr, u16_t psm, u8_t role_switch, err_t (* l2ca_connect_cfm)(void *arg, struct l2cap_pcb *lpcb,u16_t result, u16_t status)); + +void l2cap_tmr(); +void l2cap_input(struct pbuf *p, struct bd_addr *bdaddr); +err_t l2cap_close(struct l2cap_pcb *pcb); +void l2cap_reset_all(void); +u8_t l2cap_next_sigid(void); +err_t l2cap_write(struct bd_addr *bdaddr, struct pbuf *p, u16_t len); +void l2cap_arg(struct l2cap_pcb *pcb, void *arg); +void l2cap_disconnect_ind(struct l2cap_pcb *pcb, err_t (* l2ca_disconnect_ind)(void *arg, struct l2cap_pcb *newpcb, err_t err)); +void l2cap_timeout_ind(struct l2cap_pcb *pcb,err_t (* l2ca_timeout_ind)(void *arg, struct l2cap_pcb *newpcb, err_t err)); +void l2cap_recv(struct l2cap_pcb *pcb, err_t (* l2ca_recv)(void *arg, struct l2cap_pcb *pcb, struct pbuf *p, err_t err)); +err_t l2cap_signal(struct l2cap_pcb *pcb, u8_t code, u16_t ursp_id, struct bd_addr *remote_bdaddr, struct pbuf *data); +void l2cap_process_sig(struct pbuf *q, struct l2cap_hdr *l2caphdr, struct bd_addr *bdaddr); + +err_t l2cap_rexmit_signal(struct l2cap_pcb *pcb, struct l2cap_sig *sig); +err_t l2cap_connect_ind(struct l2cap_pcb *npcb, struct bd_addr *bdaddr, u16_t psm,err_t (* l2ca_connect_ind)(void *arg, struct l2cap_pcb *pcb, err_t err)); + +void (*l2cap_disconnect_bb(void (*l2ca_disconnect_bb)(struct bd_addr *bdaddr,u8_t reason)))(struct bd_addr *bdaddr,u8_t reason); + +/* Internal functions and global variables */ +#define L2CA_ACTION_CONN_CFM(pcb,result,status,ret) if((pcb)->l2ca_connect_cfm != NULL) (ret = (pcb)->l2ca_connect_cfm((pcb)->callback_arg,(pcb),(result),(status))) +#define L2CA_ACTION_DISCONN_CFM(pcb,ret) if((pcb)->l2ca_disconnect_cfm != NULL) (ret = (pcb)->l2ca_disconnect_cfm((pcb)->callback_arg,(pcb))) +#define L2CA_ACTION_PING_CFM(pcb,result,ret) if((pcb)->l2ca_pong != NULL) (ret = (pcb)->l2ca_pong((pcb)->callback_arg,(pcb),(result))) + +#define L2CA_ACTION_CONN_IND(pcb,err,ret) if((pcb)->l2ca_connect_ind != NULL) (ret = (pcb)->l2ca_connect_ind((pcb)->callback_arg,(pcb),(err))) +#define L2CA_ACTION_DISCONN_IND(pcb,err,ret) \ + if((pcb)->l2ca_disconnect_ind != NULL) { \ + LOG("l2cap_disconnect_ind called\n"); \ + (ret = (pcb)->l2ca_disconnect_ind((pcb)->callback_arg,(pcb),(err))); \ + } else { \ + l2cap_close(pcb); \ + } +#define L2CA_ACTION_TO_IND(pcb,err,ret) if((pcb)->l2ca_timeout_ind != NULL) (ret = (pcb)->l2ca_timeout_ind((pcb)->callback_arg,(pcb),(err))) +#define L2CA_ACTION_RECV(pcb,p,err,ret) \ + if((pcb)->l2ca_recv != NULL) { \ + (ret = (pcb)->l2ca_recv((pcb)->callback_arg,(pcb),(p),(err))); \ + } else { \ + btpbuf_free(p); \ + } + +#define L2CAP_OPTH_TYPE(hdr) (((hdr)->type) & 0x7f) +#define L2CAP_OPTH_TOA(hdr) (((hdr)->type) >> 7) + +/* The L2CAP PCB lists. */ +extern struct l2cap_pcb_listen *l2cap_listen_pcbs; /* List of all L2CAP PCBs in CLOSED state + but awaing an incoming conn req. */ +extern struct l2cap_pcb *l2cap_active_pcbs; /* List of all L2CAP PCBs that has + established or is about to establish + an ACL link */ + +extern struct l2cap_pcb *l2cap_tmp_pcb; /* Only used for temporary storage. */ + +#define L2CAP_REG(pcbs, npcb) do { \ + u32 level; \ + _CPU_ISR_Disable(level); \ + npcb->next = *pcbs; \ + *pcbs = npcb; \ + _CPU_ISR_Restore(level); \ + } while(0) +#define L2CAP_RMV(pcbs, npcb) do { \ + u32 level; \ + _CPU_ISR_Disable(level); \ + if(*pcbs == npcb) { \ + *pcbs = (*pcbs)->next; \ + } else for(l2cap_tmp_pcb = *pcbs; l2cap_tmp_pcb != NULL; l2cap_tmp_pcb = l2cap_tmp_pcb->next) { \ + if(l2cap_tmp_pcb->next != NULL && l2cap_tmp_pcb->next == npcb) { \ + l2cap_tmp_pcb->next = npcb->next; \ + break; \ + } \ + } \ + npcb->next = NULL; \ + _CPU_ISR_Restore(level); \ + } while(0) + +/* The L2CAP SIG list macros */ +extern struct l2cap_sig *l2cap_tmp_sig; /* Only used for temporary storage. */ + +#define L2CAP_SIG_REG(ursp_sigs, nsig) do { \ + u32 level; \ + _CPU_ISR_Disable(level); \ + nsig->next = *ursp_sigs; \ + *ursp_sigs = nsig; \ + _CPU_ISR_Restore(level); \ + } while(0) +#define L2CAP_SIG_RMV(ursp_sigs, nsig) do { \ + u32 level; \ + _CPU_ISR_Disable(level); \ + if(*ursp_sigs == nsig) { \ + *ursp_sigs = (*ursp_sigs)->next; \ + } else for(l2cap_tmp_sig = *ursp_sigs; l2cap_tmp_sig != NULL; l2cap_tmp_sig = l2cap_tmp_sig->next) { \ + if(l2cap_tmp_sig->next != NULL && l2cap_tmp_sig->next == nsig) { \ + l2cap_tmp_sig->next = nsig->next; \ + break; \ + } \ + } \ + nsig->next = NULL; \ + _CPU_ISR_Restore(level); \ + } while(0) + +/* The L2CAP incoming segments list macros */ +extern struct l2cap_seg *l2cap_tmp_inseg; /* Only used for temporary storage. */ + +#define L2CAP_SEG_REG(segs, nseg) do { \ + u32 level; \ + _CPU_ISR_Disable(level); \ + nseg->next = *segs; \ + *segs = nseg; \ + _CPU_ISR_Restore(level); \ + } while(0) +#define L2CAP_SEG_RMV(segs, nseg) do { \ + u32 level; \ + _CPU_ISR_Disable(level); \ + if(*segs == nseg) { \ + *segs = (*segs)->next; \ + } else for(l2cap_tmp_inseg = *segs; l2cap_tmp_inseg != NULL; l2cap_tmp_inseg = l2cap_tmp_inseg->next) { \ + if(l2cap_tmp_inseg->next != NULL && l2cap_tmp_inseg->next == nseg) { \ + l2cap_tmp_inseg->next = nseg->next; \ + break; \ + } \ + } \ + nseg->next = NULL; \ + _CPU_ISR_Restore(level); \ + } while(0) + +#endif diff --git a/wii/libogc/lwbt/physbusif.c b/wii/libogc/lwbt/physbusif.c new file mode 100644 index 0000000000..669b6a6548 --- /dev/null +++ b/wii/libogc/lwbt/physbusif.c @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "hci.h" +#include "btmemb.h" +#include "physbusif.h" + +#define STACKSIZE 32768 + +#define NUM_ACL_BUFS 30 +#define NUM_CTRL_BUFS 45 + +#define ACL_BUF_SIZE 1800 +#define CTRL_BUF_SIZE 660 + +#define ROUNDUP32(v) (((u32)(v)+0x1f)&~0x1f) +#define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f) + +struct usbtxbuf +{ + u32 txsize; + void *rpData; +}; + +static u32 __ntd_ohci = 0; +static u32 __ntd_ohci_initflag = 0; +static u16 __ntd_vid = 0; +static u16 __ntd_pid = 0; +static u32 __ntd_vid_pid_specified = 0; +static s32 __ntd_usb_fd = -1; +static u32 __wait4hci = 1; +static struct _usb_p __usbdev; + +static struct memb_blks ctrlbufs; +static struct memb_blks aclbufs; + +static u8 __ppc_btstack1[STACKSIZE] ATTRIBUTE_ALIGN(8); +static u8 __ppc_btstack2[STACKSIZE] ATTRIBUTE_ALIGN(8); + +static s32 __issue_bulkread(); +static s32 __issue_intrread(); + +extern u32 __IPC_ClntInit(); + +static s32 __usb_closeCB(s32 result,void *usrdata) +{ + __usbdev.fd = -1; + return result; +} + +static s32 __writectrlmsgCB(s32 result,void *usrdata) +{ + if(usrdata!=NULL) btmemb_free(&ctrlbufs,usrdata); + return result; +} + +static s32 __writebulkmsgCB(s32 result,void *usrdata) +{ + if(usrdata!=NULL) btmemb_free(&aclbufs,usrdata); + return result; +} + +static s32 __readbulkdataCB(s32 result,void *usrdata) +{ + u8 *ptr; + u32 len; + struct pbuf *p,*q; + struct usbtxbuf *buf = (struct usbtxbuf*)usrdata; + + if(__usbdev.openstate!=0x0002) return 0; + + if(result>0) { + len = result; + p = btpbuf_alloc(PBUF_RAW,len,PBUF_POOL); + if(p!=NULL) { + ptr = buf->rpData; + for(q=p;q!=NULL && len>0;q=q->next) { + memcpy(q->payload,ptr,q->len); + ptr += q->len; + len -= q->len; + } + + SYS_SwitchFiber((u32)p,0,0,0,(u32)hci_acldata_handler,(u32)(&__ppc_btstack2[STACKSIZE])); + btpbuf_free(p); + } else + ERROR("__readbulkdataCB: Could not allocate memory for pbuf.\n"); + } + btmemb_free(&aclbufs,buf); + + return __issue_bulkread(); +} + +static s32 __readintrdataCB(s32 result,void *usrdata) +{ + u8 *ptr; + u32 len; + struct pbuf *p,*q; + struct usbtxbuf *buf = (struct usbtxbuf*)usrdata; + + if(__usbdev.openstate!=0x0002) return 0; + + if(result>0) { + len = result; + p = btpbuf_alloc(PBUF_RAW,len,PBUF_POOL); + if(p!=NULL) { + ptr = buf->rpData; + for(q=p;q!=NULL && len>0;q=q->next) { + memcpy(q->payload,ptr,q->len); + ptr += q->len; + len -= q->len; + } + + SYS_SwitchFiber((u32)p,0,0,0,(u32)hci_event_handler,(u32)(&__ppc_btstack1[STACKSIZE])); + btpbuf_free(p); + } else + ERROR("__readintrdataCB: Could not allocate memory for pbuf.\n"); + } + btmemb_free(&ctrlbufs,buf); + + return __issue_intrread(); +} + +static s32 __issue_intrread() +{ + s32 ret; + u32 len; + u8 *ptr; + struct usbtxbuf *buf; + + if(__usbdev.openstate!=0x0002) return IPC_OK; + + buf = (struct usbtxbuf*)btmemb_alloc(&ctrlbufs); + if(buf!=NULL) { + ptr = (u8*)((u32)buf + sizeof(struct usbtxbuf)); + buf->rpData = (void*)ROUNDUP32(ptr); + len = (ctrlbufs.size - ((u32)buf->rpData - (u32)buf)); + buf->txsize = ROUNDDOWN32(len); + ret = USB_ReadIntrMsgAsync(__usbdev.fd,__usbdev.hci_evt,buf->txsize,buf->rpData,__readintrdataCB,buf); + } else + ret = IPC_ENOMEM; + + return ret; +} + +static s32 __issue_bulkread() +{ + s32 ret; + u32 len; + u8 *ptr; + struct usbtxbuf *buf; + + if(__usbdev.openstate!=0x0002) return IPC_OK; + + buf = (struct usbtxbuf*)btmemb_alloc(&aclbufs); + if(buf!=NULL) { + ptr = (u8*)((u32)buf + sizeof(struct usbtxbuf)); + buf->rpData = (void*)ROUNDUP32(ptr); + len = (aclbufs.size - ((u32)buf->rpData - (u32)buf)); + buf->txsize = ROUNDDOWN32(len); + ret = USB_ReadBlkMsgAsync(__usbdev.fd,__usbdev.acl_in,buf->txsize,buf->rpData,__readbulkdataCB,buf); + } else + ret = IPC_ENOMEM; + + return ret; +} + +static s32 __initUsbIOBuffer(struct memb_blks *blk,u32 buf_size,u32 num_bufs) +{ + u32 len; + u8 *ptr = NULL; + + len = ((MEM_ALIGN_SIZE(buf_size)+sizeof(u32))*num_bufs); + ptr = (u8*)ROUNDDOWN32(((u32)SYS_GetArena2Hi() - len)); + if((u32)ptr<(u32)SYS_GetArena2Lo()) return -4; + + SYS_SetArena2Hi(ptr); + + blk->size = buf_size; + blk->num = num_bufs; + blk->mem = ptr; + + btmemb_init(blk); + return 0; +} + +static s32 __getDeviceId(u16 vid,u16 pid) +{ + s32 ret = 0; + + if(__ntd_ohci_initflag==0x0001) { + if(__ntd_ohci==0x0000) + ret = USB_OpenDevice(USB_OH0_DEVICE_ID,vid,pid,&__usbdev.fd); + else if(__ntd_ohci==0x0001) + ret = USB_OpenDevice(USB_OH1_DEVICE_ID,vid,pid,&__usbdev.fd); + } else + ret = USB_OpenDevice(USB_OH1_DEVICE_ID,vid,pid,&__usbdev.fd); + + //printf("__getDeviceId(%04x,%04x,%d)\n",vid,pid,__usbdev.fd); + if(ret==0) __ntd_usb_fd = __usbdev.fd; + return ret; +} + +static s32 __usb_register(pbcallback cb) +{ + s32 ret = 0; + + memset(&__usbdev,0,sizeof(struct _usb_p)); + __usbdev.openstate = 5; + + ret = __IPC_ClntInit(); + if(ret<0) return ret; + + ret = USB_Initialize(); + if(ret<0) return ret; + + __usbdev.fd = -1; + __usbdev.unregcb = cb; + if(__ntd_vid_pid_specified) { + __usbdev.vid = __ntd_vid; + __usbdev.pid = __ntd_pid; + } else { + __usbdev.vid = 0x057E; + __usbdev.pid = 0x0305; + } + + ret = __getDeviceId(__usbdev.vid,__usbdev.pid); + if(ret<0) return ret; + + __usbdev.acl_out = 0x02; + __usbdev.acl_in = 0x82; + __usbdev.hci_evt = 0x81; + __usbdev.hci_ctrl = 0x00; + + __initUsbIOBuffer(&ctrlbufs,CTRL_BUF_SIZE,NUM_CTRL_BUFS); + __initUsbIOBuffer(&aclbufs,ACL_BUF_SIZE,NUM_ACL_BUFS); + + __usbdev.openstate = 4; + __wait4hci = 1; + + return ret; +} + +static s32 __usb_open(pbcallback cb) +{ + if(__usbdev.openstate!=0x0004) return -1; + + __usbdev.closecb = cb; + __usbdev.openstate = 2; + + __issue_intrread(); + __issue_bulkread(); + + __wait4hci = 0; + return 0; +} + +void __ntd_set_ohci(u8 hci) +{ + if(hci==0x0000) { + __ntd_ohci = 0; + __ntd_ohci_initflag = 1; + } else if(hci==0x0001) { + __ntd_ohci = 1; + __ntd_ohci_initflag = 1; + } +} + +void __ntd_set_pid_vid(u16 vid,u16 pid) +{ + __ntd_vid = vid; + __ntd_pid = pid; + __ntd_vid_pid_specified = 1; +} + + +void physbusif_init() +{ + s32 ret; + + ret = __usb_register(NULL); + if(ret<0) return; + + __usb_open(NULL); +} + +void physbusif_close() +{ + if(__usbdev.openstate!=0x0002) return; + + __usbdev.openstate = 4; + __wait4hci = 1; +} + +void physbusif_shutdown() +{ + if(__usbdev.openstate!=0x0004) return; + USB_CloseDeviceAsync(&__usbdev.fd,__usb_closeCB,NULL); +} + +void physbusif_reset_all() +{ + return; +} + +void physbusif_output(struct pbuf *p,u16_t len) +{ + u32 pos; + u8 *ptr; + struct pbuf *q; + struct memb_blks *mblks; + struct usbtxbuf *blkbuf; + + if(__usbdev.openstate!=0x0002) return; + + if(((u8*)p->payload)[0]==HCI_COMMAND_DATA_PACKET) mblks = &ctrlbufs; + else if(((u8*)p->payload)[0]==HCI_ACL_DATA_PACKET) mblks = &aclbufs; + else return; + + blkbuf = btmemb_alloc(mblks); + if(blkbuf!=NULL) { + blkbuf->txsize = --len; + blkbuf->rpData = (void*)ROUNDUP32(((u32)blkbuf+sizeof(struct usbtxbuf))); + + ptr = blkbuf->rpData; + for(q=p,pos=1;q!=NULL && len>0;q=q->next,pos=0) { + memcpy(ptr,q->payload+pos,(q->len-pos)); + ptr += (q->len-pos); + len -= (q->len-pos); + } + + if(((u8*)p->payload)[0]==HCI_COMMAND_DATA_PACKET) { + USB_WriteCtrlMsgAsync(__usbdev.fd,0x20,0,0,0,blkbuf->txsize,blkbuf->rpData,__writectrlmsgCB,blkbuf); + } else if(((u8*)p->payload)[0]==HCI_ACL_DATA_PACKET) { + USB_WriteBlkMsgAsync(__usbdev.fd,__usbdev.acl_out,blkbuf->txsize,blkbuf->rpData,__writebulkmsgCB,blkbuf); + } + } +} diff --git a/wii/libogc/lwbt/physbusif.h b/wii/libogc/lwbt/physbusif.h new file mode 100644 index 0000000000..8565c5a690 --- /dev/null +++ b/wii/libogc/lwbt/physbusif.h @@ -0,0 +1,29 @@ +#ifndef __PHYSBUSIF_H__ +#define __PHYSBUSIF_H__ + +#include "btpbuf.h" + +typedef struct _usb_p usb_p; +typedef s32 (*pbcallback)(s32 state,s32 result,usb_p *usb); + +struct _usb_p +{ + s32 fd; + u8 acl_out; + u8 acl_in; + u8 hci_evt; + u8 hci_ctrl; + u32 vid; + u32 pid; + u8 openstate; + pbcallback closecb; + pbcallback unregcb; +}; + +void physbusif_init(); +void physbusif_close(); +void physbusif_shutdown(); +void physbusif_reset_all(); +void physbusif_output(struct pbuf *p,u16_t len); + +#endif diff --git a/wii/libogc/lwip/arch/gc/netif/gcif.c b/wii/libogc/lwip/arch/gc/netif/gcif.c new file mode 100644 index 0000000000..31cbb90257 --- /dev/null +++ b/wii/libogc/lwip/arch/gc/netif/gcif.c @@ -0,0 +1,1042 @@ +#include +#include "asm.h" +#include "processor.h" +#include "spinlock.h" +#include "irq.h" +#include "exi.h" +#include "cache.h" +#include "ogcsys.h" +#include "lwp.h" +#include "lwp_threads.h" +#include "lwp_watchdog.h" +#include "lwip/debug.h" +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "netif/etharp.h" + +#include "netif/gcif/gcif.h" + +//#define _BBA_DEBUG + +#define IFNAME0 'e' +#define IFNAME1 '0' + +#define GCIF_TX_TQ 8 +#define GCIF_EXI_TQ 9 + +#define BBA_MINPKTSIZE 60 + +#define BBA_CID 0x04020200 + +#define BBA_CMD_IRMASKALL 0x00 +#define BBA_CMD_IRMASKNONE 0xF8 + +#define BBA_NCRA 0x00 /* Network Control Register A, RW */ +#define BBA_NCRA_RESET (1<<0) /* RESET */ +#define BBA_NCRA_ST0 (1<<1) /* ST0, Start transmit command/status */ +#define BBA_NCRA_ST1 (1<<2) /* ST1, " */ +#define BBA_NCRA_SR (1<<3) /* SR, Start Receive */ + +#define BBA_NCRB 0x01 /* Network Control Register B, RW */ +#define BBA_NCRB_PR (1<<0) /* PR, Promiscuous Mode */ +#define BBA_NCRB_CA (1<<1) /* CA, Capture Effect Mode */ +#define BBA_NCRB_PM (1<<2) /* PM, Pass Multicast */ +#define BBA_NCRB_PB (1<<3) /* PB, Pass Bad Frame */ +#define BBA_NCRB_AB (1<<4) /* AB, Accept Broadcast */ +#define BBA_NCRB_HBD (1<<5) /* HBD, reserved */ +#define BBA_NCRB_RXINTC0 (1<<6) /* RXINTC, Receive Interrupt Counter */ +#define BBA_NCRB_RXINTC1 (1<<7) /* " */ +#define BBA_NCRB_1_PACKET_PER_INT (0<<6) /* 0 0 */ +#define BBA_NCRB_2_PACKETS_PER_INT (1<<6) /* 0 1 */ +#define BBA_NCRB_4_PACKETS_PER_INT (2<<6) /* 1 0 */ +#define BBA_NCRB_8_PACKETS_PER_INT (3<<6) /* 1 1 */ + +#define BBA_LTPS 0x04 /* Last Transmitted Packet Status, RO */ +#define BBA_LRPS 0x05 /* Last Received Packet Status, RO */ + +#define BBA_IMR 0x08 /* Interrupt Mask Register, RW, 00h */ +#define BBA_IMR_FRAGIM (1<<0) /* FRAGIM, Fragment Counter Int Mask */ +#define BBA_IMR_RIM (1<<1) /* RIM, Receive Interrupt Mask */ +#define BBA_IMR_TIM (1<<2) /* TIM, Transmit Interrupt Mask */ +#define BBA_IMR_REIM (1<<3) /* REIM, Receive Error Interrupt Mask */ +#define BBA_IMR_TEIM (1<<4) /* TEIM, Transmit Error Interrupt Mask */ +#define BBA_IMR_FIFOEIM (1<<5) /* FIFOEIM, FIFO Error Interrupt Mask */ +#define BBA_IMR_BUSEIM (1<<6) /* BUSEIM, BUS Error Interrupt Mask */ +#define BBA_IMR_RBFIM (1<<7) /* RBFIM, RX Buffer Full Interrupt Mask */ + +#define BBA_IR 0x09 /* Interrupt Register, RW, 00h */ +#define BBA_IR_FRAGI (1<<0) /* FRAGI, Fragment Counter Interrupt */ +#define BBA_IR_RI (1<<1) /* RI, Receive Interrupt */ +#define BBA_IR_TI (1<<2) /* TI, Transmit Interrupt */ +#define BBA_IR_REI (1<<3) /* REI, Receive Error Interrupt */ +#define BBA_IR_TEI (1<<4) /* TEI, Transmit Error Interrupt */ +#define BBA_IR_FIFOEI (1<<5) /* FIFOEI, FIFO Error Interrupt */ +#define BBA_IR_BUSEI (1<<6) /* BUSEI, BUS Error Interrupt */ +#define BBA_IR_RBFI (1<<7) /* RBFI, RX Buffer Full Interrupt */ + +#define BBA_BP 0x0a/*+0x0b*/ /* Boundary Page Pointer Register */ +#define BBA_TLBP 0x0c/*+0x0d*/ /* TX Low Boundary Page Pointer Register */ +#define BBA_TWP 0x0e/*+0x0f*/ /* Transmit Buffer Write Page Pointer Register */ +#define BBA_TRP 0x12/*+0x13*/ /* Transmit Buffer Read Page Pointer Register */ +#define BBA_RWP 0x16/*+0x17*/ /* Receive Buffer Write Page Pointer Register */ +#define BBA_RRP 0x18/*+0x19*/ /* Receive Buffer Read Page Pointer Register */ +#define BBA_RHBP 0x1a/*+0x1b*/ /* Receive High Boundary Page Pointer Register */ + +#define BBA_RXINTT 0x14/*+0x15*/ /* Receive Interrupt Timer Register */ + +#define BBA_NAFR_PAR0 0x20 /* Physical Address Register Byte 0 */ +#define BBA_NAFR_PAR1 0x21 /* Physical Address Register Byte 1 */ +#define BBA_NAFR_PAR2 0x22 /* Physical Address Register Byte 2 */ +#define BBA_NAFR_PAR3 0x23 /* Physical Address Register Byte 3 */ +#define BBA_NAFR_PAR4 0x24 /* Physical Address Register Byte 4 */ +#define BBA_NAFR_PAR5 0x25 /* Physical Address Register Byte 5 */ + +#define BBA_NWAYC 0x30 /* NWAY Configuration Register, RW, 84h */ +#define BBA_NWAYC_FD (1<<0) /* FD, Full Duplex Mode */ +#define BBA_NWAYC_PS100 (1<<1) /* PS100/10, Port Select 100/10 */ +#define BBA_NWAYC_ANE (1<<2) /* ANE, Autonegotiation Enable */ +#define BBA_NWAYC_ANS_RA (1<<3) /* ANS, Restart Autonegotiation */ +#define BBA_NWAYC_LTE (1<<7) /* LTE, Link Test Enable */ + +#define BBA_HALF_100 (BBA_NWAYC_PS100) +#define BBA_FULL_100 (BBA_NWAYC_PS100|BBA_NWAYC_FD) +#define BBA_HALF_10 (BBA_NWAYC_ANE) +#define BBA_FULL_10 (BBA_NWAYC_FD) + +#define BBA_NWAYS 0x31 +#define BBA_NWAYS_LS10 (1<<0) +#define BBA_NWAYS_LS100 (1<<1) +#define BBA_NWAYS_LPNWAY (1<<2) +#define BBA_NWAYS_ANCLPT (1<<3) +#define BBA_NWAYS_100TXF (1<<4) +#define BBA_NWAYS_100TXH (1<<5) +#define BBA_NWAYS_10TXF (1<<6) +#define BBA_NWAYS_10TXH (1<<7) + +#define BBA_GCA 0x32 /* GMAC Configuration A Register, RW, 00h */ +#define BBA_GCA_ARXERRB (1<<3) /* ARXERRB, Accept RX packet with error */ +#define BBA_GCA_TXFIFOCNTEN (1<<6) /* TX FIFO cnt enable */ + +#define BBA_MISC 0x3d /* MISC Control Register 1, RW, 3ch */ +#define BBA_MISC_BURSTDMA (1<<0) +#define BBA_MISC_DISLDMA (1<<1) + +#define BBA_TXFIFOCNT 0x3e/*0x3f*/ /* Transmit FIFO Counter Register */ +#define BBA_WRTXFIFOD 0x48/*-0x4b*/ /* Write TX FIFO Data Port Register */ + +#define BBA_MISC2 0x50 /* MISC Control Register 2, RW, 00h */ +#define BBA_MISC2_HBRLEN0 (1<<0) /* HBRLEN, Host Burst Read Length */ +#define BBA_MISC2_HBRLEN1 (1<<1) /* " */ +#define BBA_MISC2_RUNTSIZE (1<<2) /* " */ +#define BBA_MISC2_DREQBCTRL (1<<3) /* " */ +#define BBA_MISC2_RINTSEL (1<<4) /* " */ +#define BBA_MISC2_ITPSEL (3<<5) /* " */ +#define BBA_MISC2_AUTORCVR (1<<7) /* Auto RX Full Recovery */ + +#define BBA_RX_STATUS_BF (1<<0) +#define BBA_RX_STATUS_CRC (1<<1) +#define BBA_RX_STATUS_FAE (1<<2) +#define BBA_RX_STATUS_FO (1<<3) +#define BBA_RX_STATUS_RW (1<<4) +#define BBA_RX_STATUS_MF (1<<5) +#define BBA_RX_STATUS_RF (1<<6) +#define BBA_RX_STATUS_RERR (1<<7) + +#define BBA_TX_STATUS_CC0 (1<<0) +#define BBA_TX_STATUS_CC1 (1<<1) +#define BBA_TX_STATUS_CC2 (1<<2) +#define BBA_TX_STATUS_CC3 (1<<3) +#define BBA_TX_STATUS_CCMASK (0x0f) +#define BBA_TX_STATUS_CRSLOST (1<<4) +#define BBA_TX_STATUS_UF (1<<5) +#define BBA_TX_STATUS_OWC (1<<6) +#define BBA_TX_STATUS_OWN (1<<7) +#define BBA_TX_STATUS_TERR (1<<7) + +#define BBA_SI_ACTRL 0x5c +#define BBA_SI_STATUS 0x5d +#define BBA_SI_ACTRL2 0x60 + +#define BBA_INIT_TLBP 0x00 +#define BBA_INIT_BP 0x01 +#define BBA_INIT_RHBP 0x0f +#define BBA_INIT_RWP BBA_INIT_BP +#define BBA_INIT_RRP BBA_INIT_BP + +#define BBA_TX_MAX_PACKET_SIZE (1518) /* 14+1500+4 */ +#define BBA_RX_MAX_PACKET_SIZE (1536) /* 6 pages * 256 bytes */ + +#define BBA_NAPI_WEIGHT 16 + + +#define X(a,b) b,a +struct bba_descr { + u32 X(X(next_packet_ptr:12, packet_len:12), status:8); +} __attribute((packed)); + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + + +struct bba_priv { + u8 flag; + u8 revid; + u16 devid; + u8 acstart; + u8 linkstate; + lwpq_t tq_xmit; + err_t state; + struct eth_addr *ethaddr; + struct dev_stats { + u32 rx_errors,rx_overerrors,rx_crcerrors; + u32 rx_fifoerrors,rx_lengtherrors,rx_frameerrors; + u32 rx_bytes,rx_packets; + u32 tx_errors,tx_carriererrors,tx_fifoerrors; + u32 tx_windowerrors,tx_collisions; + } txrx_stats; +}; + +static lwpq_t wait_exi_queue; +static struct bba_descr cur_descr; +static struct netif *gc_netif = NULL; +static const struct eth_addr ethbroadcast = {{0xffU,0xffU,0xffU,0xffU,0xffU,0xffU}}; + +static err_t __bba_link_tx(struct netif *dev,struct pbuf *p); +static u32 __bba_rx_err(u8 status,struct bba_priv *priv); + +extern void udelay(int us); + +/* new functions */ +#define bba_select() EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_2,EXI_SPEED32MHZ) +#define bba_deselect() EXI_Deselect(EXI_CHANNEL_0) +#define bba_sync() EXI_Sync(EXI_CHANNEL_0) + +#define bba_in12(reg) ((bba_in8((reg))&0xff)|((bba_in8(((reg)+1))&0x0f)<<8)) +#define bba_out12(reg,val) do { \ + bba_out8((reg),((val)&0xff)); \ + bba_out8(((reg)+1),(((val)&0x0f00)>>8)); \ + } while(0) +#define bba_in16(reg) ((bba_in8((reg))&0xff)|((bba_in8(((reg)+1))&0xff)<<8)) +#define bba_out16(reg,val) do { \ + bba_out8((reg),((val)&0xff)); \ + bba_out8(((reg)+1),(((val)&0xff00)>>8)); \ + } while(0) + +static __inline__ void bba_cmd_insnosel(u32 reg,void *val,u32 len) +{ + u16 req; + req = reg<<8; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_READ); +} + +static __inline__ void bba_cmd_outsnosel(u32 reg,void *val,u32 len) +{ + u16 req; + req = (reg<<8)|0x4000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_WRITE); +} + +static __inline__ void bba_insnosel(u32 reg,void *val,u32 len) +{ + u32 req; + req = (reg<<8)|0x80000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_READ); +} + +static __inline__ void bba_outsnosel(u32 reg,void *val,u32 len) +{ + u32 req; + req = (reg<<8)|0xC0000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_WRITE); +} + +static __inline__ void bba_insregister(u32 reg) +{ + u32 req; + req = (reg<<8)|0x80000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); +} + +static __inline__ void bba_insdata(void *val,u32 len) +{ + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_READ); +} + +static __inline__ void bba_insdmadata(void *val,u32 len,s32 (*dmasubrcv)(s32 chn,s32 dev)) +{ + EXI_Dma(EXI_CHANNEL_0,val,len,EXI_READ,dmasubrcv); +} + +static void bba_insdata_fast(void *val,s32 len) +{ + u32 roundlen; + s32 missalign; + u8 *ptr = val; + + if(!val || len<=0) return; + + missalign = -((u32)val)&0x1f; + if((s32)(len-missalign)<32) { + bba_insdata(val,len); + return; + } + + if(missalign>0) { + bba_insdata(ptr,missalign); + len -= missalign; + ptr += missalign; + } + + roundlen = (len&~0x1f); + DCInvalidateRange(ptr,roundlen); + bba_insdmadata(ptr,roundlen,NULL); + bba_sync(); + + len -= roundlen; + ptr += roundlen; + if(len>0) bba_insdata(ptr,len); +} + +static __inline__ void bba_outsregister(u32 reg) +{ + u32 req; + req = (reg<<8)|0xC0000000; + EXI_Imm(EXI_CHANNEL_0,&req,sizeof(req),EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); +} + +static __inline__ void bba_outsdata(void *val,u32 len) +{ + EXI_ImmEx(EXI_CHANNEL_0,val,len,EXI_WRITE); +} + +static __inline__ void bba_outsdmadata(void *val,u32 len,s32 (*dmasubsnd)(s32 chn,s32 dev)) +{ + EXI_Dma(EXI_CHANNEL_0,val,len,EXI_WRITE,dmasubsnd); +} + +static void bba_outsdata_fast(void *val,s32 len) +{ + u32 roundlen; + s32 missalign; + u8 *ptr = val; + + if(!val || len<=0) return; + + missalign = -((u32)val)&0x1f; + if((s32)(len-missalign)<32) { + bba_outsdata(val,len); + return; + } + + if(missalign>0) { + bba_outsdata(ptr,missalign); + len -= missalign; + ptr += missalign; + } + + roundlen = (len&~0x1f); + DCStoreRange(ptr,roundlen); + bba_outsdmadata(ptr,roundlen,NULL); + bba_sync(); + + len -= roundlen; + ptr += roundlen; + if(len>0) bba_outsdata(ptr,len); +} + +static inline void bba_cmd_ins(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_cmd_insnosel(reg,val,len); + bba_deselect(); +} + +static inline void bba_cmd_outs(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_cmd_outsnosel(reg,val,len); + bba_deselect(); +} + +static inline u8 bba_cmd_in8(u32 reg) +{ + u8 val; + bba_cmd_ins(reg,&val,sizeof(val)); + return val; +} + +static inline u8 bba_cmd_in8_slow(u32 reg) +{ + u8 val; + bba_select(); + bba_cmd_insnosel(reg,&val,sizeof(val)); + udelay(200); //usleep doesn't work on this amount, decrementer is based on 10ms, wait is 200us + bba_deselect(); + return val; +} + +static inline void bba_cmd_out8(u32 reg,u8 val) +{ + bba_cmd_outs(reg,&val,sizeof(val)); +} + +static inline void bba_ins(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_insnosel(reg,val,len); + bba_deselect(); +} + + +static inline void bba_outs(u32 reg,void *val,u32 len) +{ + bba_select(); + bba_outsnosel(reg,val,len); + bba_deselect(); +} + +static inline u8 bba_in8(u32 reg) +{ + u8 val; + bba_ins(reg,&val,sizeof(val)); + return val; +} + +static inline void bba_out8(u32 reg,u8 val) +{ + bba_outs(reg,&val,sizeof(val)); +} + +static s32 __bba_exi_unlockcb(s32 chn,s32 dev) +{ + LWP_ThreadBroadcast(wait_exi_queue); + return 1; +} + +static __inline__ void __bba_exi_stop(struct bba_priv *priv) +{ + u32 level; + + _CPU_ISR_Disable(level); + while(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_2,__bba_exi_unlockcb)==0) { + LWIP_DEBUGF(NETIF_DEBUG|1,("__bba_exi_wait(exi locked)\n")); + LWP_ThreadSleep(wait_exi_queue); + } + _CPU_ISR_Restore(level); +} + +static __inline__ void __bba_exi_wake(struct bba_priv *priv) +{ + EXI_Unlock(EXI_CHANNEL_0); +} + +static __inline__ void __bba_tx_stop(struct bba_priv *priv) +{ + u32 level; + + _CPU_ISR_Disable(level); + while(priv->state==ERR_TXPENDING) { + LWIP_DEBUGF(NETIF_DEBUG,("__bba_tx_stop(pending tx)\n")); + LWP_ThreadSleep(priv->tq_xmit); + } + priv->state = ERR_TXPENDING; + _CPU_ISR_Restore(level); +} + +static __inline__ void __bba_tx_wake(struct bba_priv *priv) +{ + u32 level; + + _CPU_ISR_Disable(level); + if(priv->state==ERR_TXPENDING) { + priv->state = ERR_OK; + LWP_ThreadBroadcast(priv->tq_xmit); + } + _CPU_ISR_Restore(level); +} + +static __inline__ u8 __linkstate(struct bba_priv *priv) +{ + u8 nways = 0; + + nways = bba_in8(BBA_NWAYS); + priv->linkstate = nways; + if(nways&BBA_NWAYS_LS10 || nways&BBA_NWAYS_LS100) return nways; + return 0; +} + +static bool __bba_get_linkstateasync(struct bba_priv *priv) +{ + u32 ret,cnt,sec; + + for(cnt=0;cnt<10000;cnt++) { + udelay(500); + ret = __linkstate(priv); + + if(ret&0xf0 && ret&0x08) break; + } + + // only sleep for additional 2 seconds if linkstate is ok + if(cnt<10000) { + sec = 1; + if(!(ret&0x04)) sec = 2; + udelay(sec*TB_USPERSEC); + } + + return (cnt<10000); +} + +static u32 __bba_read_cid() +{ + u16 cmd = 0; + u32 cid = 0; + + bba_select(); + EXI_Imm(EXI_CHANNEL_0,&cmd,2,EXI_WRITE,NULL); + EXI_Sync(EXI_CHANNEL_0); + EXI_Imm(EXI_CHANNEL_0,&cid,4,EXI_READ,NULL); + EXI_Sync(EXI_CHANNEL_0); + bba_deselect(); + + return cid; +} + +static void __bba_reset() +{ + bba_out8(0x60,0x00); + udelay(10000); + bba_cmd_in8_slow(0x0F); + udelay(10000); + bba_out8(BBA_NCRA,BBA_NCRA_RESET); + udelay(100); + bba_out8(BBA_NCRA,0x00); + udelay(100); +} + +static void __bba_recv_init() +{ + bba_out8(BBA_NCRB,(BBA_NCRB_AB|BBA_NCRB_CA|BBA_NCRB_2_PACKETS_PER_INT)); + bba_out8(BBA_SI_ACTRL2,0x74); + bba_out8(BBA_RXINTT, 0x00); + bba_out8(BBA_RXINTT+1, 0x06); /* 0x0600 = 61us */ + + bba_out8(BBA_MISC2,BBA_MISC2_AUTORCVR); + + bba_out12(BBA_TLBP, BBA_INIT_TLBP); + bba_out12(BBA_BP,BBA_INIT_BP); + bba_out12(BBA_RHBP,BBA_INIT_RHBP); + bba_out12(BBA_RWP,BBA_INIT_RWP); + bba_out12(BBA_RRP,BBA_INIT_RRP); + + bba_out8(BBA_GCA,BBA_GCA_ARXERRB); + bba_out8(BBA_NCRA,BBA_NCRA_SR); +} + +static u32 __bba_tx_err(u8 status,struct bba_priv *priv) +{ + u32 last_errors = priv->txrx_stats.tx_errors; + + if(status&BBA_TX_STATUS_TERR) { + priv->txrx_stats.tx_errors++; + if(status&BBA_TX_STATUS_CCMASK) + priv->txrx_stats.tx_collisions += (status&BBA_TX_STATUS_CCMASK); + + if(status&BBA_TX_STATUS_CRSLOST) + priv->txrx_stats.tx_carriererrors++; + + if(status&BBA_TX_STATUS_UF) + priv->txrx_stats.tx_fifoerrors++; + + if(status&BBA_TX_STATUS_OWC) + priv->txrx_stats.tx_windowerrors++; + } + if(last_errors!=priv->txrx_stats.tx_errors) + LWIP_ERROR(("__bba_tx_err(%02x)\n",status)); + + return priv->txrx_stats.tx_errors; +} + +static u32 __bba_rx_err(u8 status,struct bba_priv *priv) +{ + u32 last_errors = priv->txrx_stats.tx_errors; + + if(status&0xff) { + priv->txrx_stats.rx_overerrors++; + priv->txrx_stats.rx_errors++; + } else { + if(status&BBA_RX_STATUS_RERR) { + priv->txrx_stats.rx_errors++; + if(status&BBA_RX_STATUS_BF) + priv->txrx_stats.rx_overerrors++; + + if(status&BBA_RX_STATUS_CRC) + priv->txrx_stats.rx_crcerrors++; + + if(status&BBA_RX_STATUS_FO) + priv->txrx_stats.rx_fifoerrors++; + + if(status&BBA_RX_STATUS_RW) + priv->txrx_stats.rx_lengtherrors++; + + if(status&BBA_RX_STATUS_RF) + priv->txrx_stats.rx_lengtherrors++; + + if(status&BBA_RX_STATUS_BF) + priv->txrx_stats.rx_overerrors++; + } + if(status&BBA_RX_STATUS_FAE) { + priv->txrx_stats.rx_errors++; + priv->txrx_stats.rx_frameerrors++; + } + } + if(last_errors!=priv->txrx_stats.rx_errors) + LWIP_ERROR(("__bba_rx_err(%02x)\n",status)); + + return priv->txrx_stats.rx_errors; +} + +void bba_process(struct pbuf *p,struct netif *dev) +{ + struct eth_hdr *ethhdr = NULL; + struct bba_priv *priv = (struct bba_priv*)dev->state; + const s32 hlen = sizeof(struct eth_hdr); + + if(p) { + ethhdr = p->payload; + switch(htons(ethhdr->type)) { + case ETHTYPE_IP: + LWIP_DEBUGF(NETIF_DEBUG,("bba_process: passing packet up to IP layer\n")); + + etharp_ip_input(dev,p); + pbuf_header(p,-(hlen)); + ip_input(p,dev); + break; + case ETHTYPE_ARP: + /* pass p to ARP module, get ARP reply or ARP queued packet */ + LWIP_DEBUGF(NETIF_DEBUG,("bba_process: passing packet up to ARP layer\n")); + etharp_arp_input(dev, priv->ethaddr, p); + break; + /* unsupported Ethernet packet type */ + default: + /* free pbuf */ + pbuf_free(p); + break; + } + } +} + +static err_t __bba_link_tx(struct netif *dev,struct pbuf *p) +{ + u8 tmpbuf[BBA_MINPKTSIZE]; + struct pbuf *tmp; + struct bba_priv *priv = (struct bba_priv*)dev->state; + + __bba_tx_stop(priv); + __bba_exi_stop(priv); + + if(p->tot_len>BBA_TX_MAX_PACKET_SIZE) { + LWIP_ERROR(("__bba_link_tx(%d,%p) pkt_size\n",p->tot_len,LWP_GetSelf())); + __bba_tx_wake(priv); + __bba_exi_wake(priv); + return ERR_PKTSIZE; + } + + if(!__linkstate(priv)) { + LWIP_ERROR(("__bba_link_tx(error link state)\n")); + __bba_tx_wake(priv); + __bba_exi_wake(priv); + return ERR_ABRT; + } + + LWIP_DEBUGF(NETIF_DEBUG,("__bba_link_tx(%d,%p)\n",p->tot_len,LWP_GetSelf())); + + bba_out12(BBA_TXFIFOCNT,p->tot_len); + + bba_select(); + bba_outsregister(BBA_WRTXFIFOD); + for(tmp=p;tmp!=NULL;tmp=tmp->next) { + bba_outsdata_fast(tmp->payload,tmp->len); + } + if(p->tot_lentot_len)); + bba_deselect(); + + bba_out8(BBA_NCRA,((bba_in8(BBA_NCRA)&~BBA_NCRA_ST0)|BBA_NCRA_ST1)); //&~BBA_NCRA_ST0 + __bba_exi_wake(priv); + return ERR_OK; +} + +static err_t __bba_start_tx(struct netif *dev,struct pbuf *p,struct ip_addr *ipaddr) +{ + LWIP_DEBUGF(NETIF_DEBUG,("__bba_start_tx(%p)\n",LWP_GetSelf())); + return etharp_output(dev,ipaddr,p); +} + +static err_t bba_start_rx(struct netif *dev,u32 budget) +{ + s32 size; + u16 top,pos,rrp,rwp; + u32 pkt_status,recvd; + struct pbuf *tmp,*p = NULL; + struct bba_priv *priv = (struct bba_priv*)dev->state; + + LWIP_DEBUGF(NETIF_DEBUG,("bba_start_rx()\n")); + + recvd = 0; + rwp = bba_in12(BBA_RWP); + rrp = bba_in12(BBA_RRP); + while(recvd(BBA_RX_MAX_PACKET_SIZE+4)) { + LWIP_DEBUGF(NETIF_DEBUG|2,("bba_start_rx(size>BBA_RX_MAX_PACKET_SIZE)\n")); + continue; + } + + if(pkt_status&(BBA_RX_STATUS_RERR|BBA_RX_STATUS_FAE)) { + LWIP_DEBUGF(NETIF_DEBUG|2,("bba_start_rx(pkt_status = 02x)\n",pkt_status)); + __bba_rx_err(pkt_status,priv); + rwp = bba_in12(BBA_RWP); + rrp = bba_in12(BBA_RRP); + continue; + } + + pos = ((rrp<<8)+4); + top = ((BBA_INIT_RHBP+1)<<8); + LWIP_DEBUGF(NETIF_DEBUG,("bba_start_rx(%04x,%d,%04x)\n",pos,size,top)); + + p = pbuf_alloc(PBUF_RAW,size,PBUF_POOL); + if(p) { + for(tmp=p;tmp!=NULL;tmp=tmp->next) { + size = tmp->len; + + bba_select(); + bba_insregister(pos); + if((pos+size)payload,size); + } else { + s32 chunk_size = (top-pos); + + size -= chunk_size; + pos = (BBA_INIT_RRP<<8); + bba_insdata_fast(tmp->payload,chunk_size); + bba_deselect(); + bba_select(); + bba_insregister(pos); + bba_insdata_fast(tmp->payload+chunk_size,size); + } + bba_deselect(); + pos += size; + } + dev->input(p,dev); + } else + break; + + recvd++; + bba_out12(BBA_RRP,(rrp=cur_descr.next_packet_ptr)); + rwp = bba_in12(BBA_RWP); + } + if(priv->flag&BBA_IR_RBFI) { + priv->flag &= ~BBA_IR_RBFI; + bba_out8(BBA_IMR,(bba_in8(BBA_IMR)|BBA_IMR_RBFIM)); + } + + LWIP_DEBUGF(NETIF_DEBUG,("bba_start_rx(rx interrupt close)\n")); + return ERR_OK; +} + +static inline void bba_interrupt(struct netif *dev) +{ + u8 ir,imr,status,lrps,ltps; + struct bba_priv *priv = (struct bba_priv*)dev->state; + + ir = bba_in8(BBA_IR); + imr = bba_in8(BBA_IMR); + status = ir&imr; + while(status) { + LWIP_DEBUGF(NETIF_DEBUG,("bba_interrupt(%02x)\n",status)); + bba_out8(BBA_IR,status); + if(status&BBA_IR_RBFI) { + bba_out8(BBA_IMR,(bba_in8(BBA_IMR)&~BBA_IMR_RBFIM)); + priv->flag |= BBA_IMR_RBFIM; + } + if(status&(BBA_IR_RI|BBA_IR_RBFI)) { + bba_start_rx(dev,0x20); + } + if(status&(BBA_IR_TI|BBA_IR_FIFOEI)) { + __bba_tx_wake(priv); + } + if(status&(BBA_IR_RBFI|BBA_IR_REI)) { + lrps = bba_in8(BBA_LRPS); + __bba_rx_err(lrps,priv); + } + if(status&BBA_IR_TEI) { + ltps = bba_in8(BBA_LTPS); + __bba_tx_err(ltps,priv); + __bba_tx_wake(priv); + } + if(status&BBA_IR_FRAGI) { + LWIP_DEBUGF(NETIF_DEBUG,("bba_interrupt(BBA_IR_FRAGI)\n")); + } + if(status&BBA_IR_FIFOEI) { + LWIP_DEBUGF(NETIF_DEBUG,("bba_interrupt(BBA_IR_FIFOEI)\n")); + } + if(status&BBA_IR_BUSEI) { + LWIP_DEBUGF(NETIF_DEBUG,("bba_interrupt(BBA_IR_BUSEI)\n")); + } + + ir = bba_in8(BBA_IR); + imr = bba_in8(BBA_IMR); + status = ir&imr; + } + LWIP_DEBUGF(NETIF_DEBUG,("bba_interrupt(exit)\n")); +} + +static err_t __bba_init(struct netif *dev) +{ + u8 nwayc; + struct bba_priv *priv = (struct bba_priv*)dev->state; + + if(!priv) return ERR_IF; + + LWIP_DEBUGF(NETIF_DEBUG,("initializing BBA...\n")); + bba_cmd_out8(0x02,BBA_CMD_IRMASKALL); + + __bba_reset(); + + priv->revid = bba_cmd_in8(0x01); + + bba_cmd_outs(0x04,&priv->devid,2); + bba_cmd_out8(0x05,priv->acstart); + + /* Assume you are being started by something which has fucked NWAY! + So reset to power on defaults for SIACTRL/SIACONN */ + bba_out8(0x58, 0x80); + bba_out8(0x59, 0x00); + bba_out8(0x5a, 0x03); + bba_out8(0x5b, 0x83); + bba_out8(0x5c, 0x32); + bba_out8(0x5d, 0xfe); + bba_out8(0x5e, 0x1f); + bba_out8(0x5f, 0x1f); + udelay(100); + + __bba_recv_init(); + + /* This doesn't set the speed anymore - it simple kicks off NWAY */ + nwayc = bba_in8(BBA_NWAYC)&0xc0; + bba_out8(BBA_NWAYC,nwayc); + udelay(100); + nwayc |= 0x04; + bba_out8(BBA_NWAYC,nwayc); + udelay(100); + nwayc |= 0x08; + bba_out8(BBA_NWAYC,nwayc); + udelay(100); + + bba_ins(BBA_NAFR_PAR0,priv->ethaddr->addr, 6); + LWIP_DEBUGF(NETIF_DEBUG,("MAC ADDRESS %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->ethaddr->addr[0], priv->ethaddr->addr[1], priv->ethaddr->addr[2], + priv->ethaddr->addr[3], priv->ethaddr->addr[4], priv->ethaddr->addr[5])); + + bba_out8(BBA_IR,0xFF); + bba_out8(BBA_IMR,0xFF&~BBA_IMR_FIFOEIM); + + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + + return ERR_OK; +} + +static err_t bba_init_one(struct netif *dev) +{ + struct bba_priv *priv = (struct bba_priv*)dev->state; + + if(!priv) return ERR_IF; + + priv->revid = 0xf0; + priv->devid = 0xD107; + priv->acstart = 0x4E; + + __bba_init(dev); + + return ERR_OK; +} + +static err_t bba_probe(struct netif *dev) +{ + u32 cid; + err_t ret; + + cid = __bba_read_cid(); + if(cid!=BBA_CID) return ERR_NODEV; + + ret = bba_init_one(dev); + return ret; +} + +static u32 bba_calc_response(struct bba_priv *priv,u32 val) +{ + u8 i0,i1,i2,i3; + u8 c0,c1,c2,c3; + u8 revid_0,revid_eth_0,revid_eth_1; + + revid_0 = priv->revid; + revid_eth_0 = _SHIFTR(priv->devid,8,8); + revid_eth_1 = _SHIFTR(priv->devid,0,8); + + i0 = _SHIFTR(val,24,8); + i1 = _SHIFTR(val,16,8); + i2 = _SHIFTR(val, 8,8); + i3 = _SHIFTR(val, 0,8); + + c0 = ((i0+i1*0xc1+0x18+revid_0)^(i3*i2+0x90))&0xff; + c1 = ((i1+i2+0x90)^(c0+i0-0xc1))&0xff; + c2 = ((i2+0xc8)^(c0+((revid_eth_0+revid_0*0x23)^0x19)))&0xff; + c3 = ((i0+0xc1)^(i3+((revid_eth_1+0xc8)^0x90)))&0xff; + + return ((c0<<24)|(c1<<16)|(c2<<8)|c3); +} + +static s32 bba_event_handler(s32 nChn,s32 nDev) +{ + u8 status; + struct bba_priv *priv = (struct bba_priv*)gc_netif->state; + + if(EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_2,bba_event_handler)==0) { + LWIP_DEBUGF(NETIF_DEBUG|1,("bba_event_handler(exi locked)\n")); + return 1; + } + + status = bba_cmd_in8(0x03); + bba_cmd_out8(0x02,BBA_CMD_IRMASKALL); + + LWIP_DEBUGF(NETIF_DEBUG,("bba_event_handler(status(%02x))\n",status)); + + if(status&0x80) { + LWIP_DEBUGF(NETIF_DEBUG,("bba_event_handler(bba_interrupt(%02x))\n",status)); + bba_interrupt(gc_netif); + bba_cmd_out8(0x03,0x80); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return 1; + } + if(status&0x40) { + LWIP_ERROR(("bba_event_handler(bba_reset(%02x))\n",status)); + __bba_init(gc_netif); + bba_cmd_out8(0x03, 0x40); + bba_cmd_out8(0x02, BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return 1; + } + if(status&0x20) { + LWIP_DEBUGF(NETIF_DEBUG,("bba_event_handler(unknown(%02x))\n",status)); + bba_cmd_out8(0x03, 0x20); + bba_cmd_out8(0x02, BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return 1; + } + if(status&0x10) { + u32 response,challange; + LWIP_DEBUGF(NETIF_DEBUG,("bba_event_handler(challange/response(%02x))\n",status)); + bba_cmd_out8(0x05,priv->acstart); + bba_cmd_ins(0x08,&challange,sizeof(challange)); + response = bba_calc_response(priv,challange); + bba_cmd_outs(0x09,&response,sizeof(response)); + + bba_cmd_out8(0x03, 0x10); + bba_cmd_out8(0x02, BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return 1; + } + if(status&0x08) { + LWIP_DEBUGF(NETIF_DEBUG,("bba_event_handler(challange/response status(%02x))\n",bba_cmd_in8(0x0b))); + bba_cmd_out8(0x03, 0x08); + bba_cmd_out8(0x02, BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return 1; + } + LWIP_ERROR(("GCIF - EXI - ?? %02x\n", status)); + bba_interrupt(gc_netif); + bba_cmd_out8(0x02,BBA_CMD_IRMASKNONE); + EXI_Unlock(EXI_CHANNEL_0); + return 1; +} + +err_t bba_init(struct netif *dev) +{ + err_t ret; + struct bba_priv *priv = (struct bba_priv*)dev->state; + + __bba_exi_stop(priv); + + LWIP_DEBUGF(NETIF_DEBUG, ("bba_init(call EXI_RegisterEXICallback())\n")); + EXI_RegisterEXICallback(EXI_CHANNEL_2,bba_event_handler); + + ret = bba_probe(dev); + if(ret!=ERR_OK) { + EXI_RegisterEXICallback(EXI_CHANNEL_2,NULL); + __bba_exi_wake(priv); + return ret; + } + + ret = __bba_get_linkstateasync(priv); + if(ret) { + dev->flags |= NETIF_FLAG_LINK_UP; + ret = ERR_OK; + } else { + EXI_RegisterEXICallback(EXI_CHANNEL_2,NULL); + ret = ERR_IF; + } + + __bba_exi_wake(priv); + return ret; +} + +dev_s bba_create(struct netif *dev) +{ + struct bba_priv *priv = NULL; + + LWIP_DEBUGF(NETIF_DEBUG, ("bba_create()\n")); + + priv = (struct bba_priv*)mem_malloc(sizeof(struct bba_priv)); + if(!priv) { + LWIP_ERROR(("bba_create: out of memory for bba_priv\n")); + return NULL; + } + memset(priv,0,sizeof(struct bba_priv)); + + LWP_InitQueue(&priv->tq_xmit); + LWP_InitQueue(&wait_exi_queue); + + dev->name[0] = IFNAME0; + dev->name[1] = IFNAME1; + dev->output = __bba_start_tx; + dev->linkoutput = __bba_link_tx; + dev->mtu = 1500; + dev->flags = NETIF_FLAG_BROADCAST; + dev->hwaddr_len = 6; + + priv->ethaddr = (struct eth_addr*)&(dev->hwaddr[0]); + priv->state = ERR_OK; + + gc_netif = dev; + return priv; +} diff --git a/wii/libogc/lwip/core/dhcp.c b/wii/libogc/lwip/core/dhcp.c new file mode 100644 index 0000000000..8cceeee34c --- /dev/null +++ b/wii/libogc/lwip/core/dhcp.c @@ -0,0 +1,1457 @@ +/** + * @file + * + * Dynamic Host Configuration Protocol client + */ + +/* + * + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. + * + * Author: Leon Woestenberg + * + * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform + * with RFC 2131 and RFC 2132. + * + * TODO: + * - Proper parsing of DHCP messages exploiting file/sname field overloading. + * - Add JavaDoc style documentation (API, internals). + * - Support for interfaces other than Ethernet (SLIP, PPP, ...) + * + * Please coordinate changes and requests with Leon Woestenberg + * + * + * Integration with your code: + * + * In lwip/dhcp.h + * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) + * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) + * + * Then have your application call dhcp_coarse_tmr() and + * dhcp_fine_tmr() on the defined intervals. + * + * dhcp_start(struct netif *netif); + * starts a DHCP client instance which configures the interface by + * obtaining an IP address lease and maintaining it. + * + * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) + * to remove the DHCP client. + * + */ + +#include + +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "netif/etharp.h" + +#include "lwip/sys.h" +#include "lwip/opt.h" +#include "lwip/dhcp.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */ + +/** global transaction identifier, must be + * unique for each DHCP request. We simply increment, starting + * with this value (easy to match with a packet analyzer) */ +static u32_t xid = 0xABCD0000; + +/** DHCP client state machine functions */ +static void dhcp_handle_ack(struct netif *netif); +static void dhcp_handle_nak(struct netif *netif); +static void dhcp_handle_offer(struct netif *netif); + +static err_t dhcp_discover(struct netif *netif); +static err_t dhcp_select(struct netif *netif); +static void dhcp_check(struct netif *netif); +static void dhcp_bind(struct netif *netif); +static err_t dhcp_decline(struct netif *netif); +static err_t dhcp_rebind(struct netif *netif); +static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); + +/** receive, unfold, parse and free incoming messages */ +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); +static err_t dhcp_unfold_reply(struct dhcp *dhcp); +static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type); +static u8_t dhcp_get_option_byte(u8_t *ptr); +//static u16_t dhcp_get_option_short(u8_t *ptr); +static u32_t dhcp_get_option_long(u8_t *ptr); +static void dhcp_free_reply(struct dhcp *dhcp); + +/** set the DHCP timers */ +static void dhcp_timeout(struct netif *netif); +static void dhcp_t1_timeout(struct netif *netif); +static void dhcp_t2_timeout(struct netif *netif); + +/** build outgoing messages */ +/** create a DHCP request, fill in common headers */ +static err_t dhcp_create_request(struct netif *netif); +/** free a DHCP request */ +static void dhcp_delete_request(struct netif *netif); +/** add a DHCP option (type, then length in bytes) */ +static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); +/** add option values */ +static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); +static void dhcp_option_short(struct dhcp *dhcp, u16_t value); +static void dhcp_option_long(struct dhcp *dhcp, u32_t value); +/** always add the DHCP options trailer to end and pad */ +static void dhcp_option_trailer(struct dhcp *dhcp); + +/** + * Back-off the DHCP client (because of a received NAK response). + * + * Back-off the DHCP client because of a received NAK. Receiving a + * NAK means the client asked for something non-sensible, for + * example when it tries to renew a lease obtained on another network. + * + * We back-off and will end up restarting a fresh DHCP negotiation later. + * + * @param state pointer to DHCP state structure + */ +static void dhcp_handle_nak(struct netif *netif) { + struct dhcp *dhcp = netif->dhcp; + u16_t msecs = 10 * 1000; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_handle_nak(): set request timeout %"U16_F" msecs\n", msecs)); + dhcp_set_state(dhcp, DHCP_BACKING_OFF); +} + +/** + * Checks if the offered IP address is already in use. + * + * It does so by sending an ARP request for the offered address and + * entering CHECKING state. If no ARP reply is received within a small + * interval, the address is assumed to be free for use by us. + */ +static void dhcp_check(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], + (s16_t)netif->name[1])); + /* create an ARP query for the offered IP address, expecting that no host + responds, as the IP address should not be in use. */ + result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); + if (result != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n")); + } + dhcp->tries++; + msecs = 500; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); + dhcp_set_state(dhcp, DHCP_CHECKING); +} + +/** + * Remember the configuration offered by a DHCP server. + * + * @param state pointer to DHCP state structure + */ +static void dhcp_handle_offer(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + /* obtain the server address */ + u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + if (option_ptr != NULL) + { + dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); + LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr)); + /* remember offered address */ + ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr); + LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); + + dhcp_select(netif); + } +} + +/** + * Select a DHCP server offer out of all offers. + * + * Simply select the first offer received. + * + * @param netif the netif under DHCP control + * @return lwIP specific error (see error.h) + */ +static err_t dhcp_select(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u32_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) + { + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_REQUEST); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, 576); + + /* MUST request the offered IP address */ + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); + dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); + dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); + dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); + + dhcp_option_trailer(dhcp); + /* shrink the pbuf to the actual content length */ + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* TODO: we really should bind to a specific local interface here + but we cannot specify an unconfigured netif as it is addressless */ + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + /* send broadcast to any DHCP server */ + udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + udp_send(dhcp->pcb, dhcp->p_out); + /* reconnect to any (or to server here?!) */ + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + dhcp_delete_request(netif); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_select: REQUESTING\n")); + dhcp_set_state(dhcp, DHCP_REQUESTING); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_select(): set request timeout %"U32_F" msecs\n", msecs)); + return result; +} + +/** + * The DHCP timer that checks for lease renewal/rebind timeouts. + * + */ +void dhcp_coarse_tmr() +{ + struct netif *netif = netif_list; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_coarse_tmr()\n")); + /* iterate through all network interfaces */ + while (netif != NULL) { + /* only act on DHCP configured interfaces */ + if (netif->dhcp != NULL) { + /* timer is active (non zero), and triggers (zeroes) now? */ + if (netif->dhcp->t2_timeout-- == 1) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); + /* this clients' rebind timeout triggered */ + dhcp_t2_timeout(netif); + /* timer is active (non zero), and triggers (zeroes) now */ + } else if (netif->dhcp->t1_timeout-- == 1) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); + /* this clients' renewal timeout triggered */ + dhcp_t1_timeout(netif); + } + } + /* proceed to next netif */ + netif = netif->next; + } +} + +/** + * DHCP transaction timeout handling + * + * A DHCP server is expected to respond within a short period of time. + * This timer checks whether an outstanding DHCP request is timed out. + * + */ +void dhcp_fine_tmr() +{ + struct netif *netif = netif_list; + /* loop through netif's */ + while (netif != NULL) { + /* only act on DHCP configured interfaces */ + if (netif->dhcp != NULL) { + /* timer is active (non zero), and is about to trigger now */ + if (netif->dhcp->request_timeout-- == 1) { + /* { netif->dhcp->request_timeout == 0 } */ + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); + /* this clients' request timeout triggered */ + dhcp_timeout(netif); + } + } + /* proceed to next network interface */ + netif = netif->next; + } +} + +/** + * A DHCP negotiation transaction, or ARP request, has timed out. + * + * The timer that was started with the DHCP or ARP request has + * timed out, indicating no response was received in time. + * + * @param netif the netif under DHCP control + * + */ +static void dhcp_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_timeout()\n")); + /* back-off period has passed, or server selection timed out */ + if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); + dhcp_discover(netif); + /* receiving the requested lease timed out */ + } else if (dhcp->state == DHCP_REQUESTING) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); + if (dhcp->tries <= 5) { + dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); + dhcp_release(netif); + dhcp_discover(netif); + } + /* received no ARP reply for the offered address (which is good) */ + } else if (dhcp->state == DHCP_CHECKING) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); + if (dhcp->tries <= 1) { + dhcp_check(netif); + /* no ARP replies on the offered address, + looks like the IP address is indeed free */ + } else { + /* bind the interface to the offered address */ + dhcp_bind(netif); + } + } + /* did not get response to renew request? */ + else if (dhcp->state == DHCP_RENEWING) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n")); + /* just retry renewal */ + /* note that the rebind timer will eventually time-out if renew does not work */ + dhcp_renew(netif); + /* did not get response to rebind request? */ + } else if (dhcp->state == DHCP_REBINDING) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n")); + if (dhcp->tries <= 8) { + dhcp_rebind(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n")); + dhcp_release(netif); + dhcp_discover(netif); + } + } +} + +/** + * The renewal period has timed out. + * + * @param netif the netif under DHCP control + */ +static void dhcp_t1_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n")); + if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { + /* just retry to renew - note that the rebind timer (t2) will + * eventually time-out if renew tries fail. */ + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n")); + dhcp_renew(netif); + } +} + +/** + * The rebind period has timed out. + * + */ +static void dhcp_t2_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout()\n")); + if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { + /* just retry to rebind */ + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout(): must rebind\n")); + dhcp_rebind(netif); + } +} + +/** + * + * @param netif the netif under DHCP control + */ +static void dhcp_handle_ack(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + u8_t *option_ptr; + /* clear options we might not get from the ACK */ + dhcp->offered_sn_mask.addr = 0; + dhcp->offered_gw_addr.addr = 0; + dhcp->offered_bc_addr.addr = 0; + + /* lease time given? */ + option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME); + if (option_ptr != NULL) { + /* remember offered lease time */ + dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2); + } + /* renewal period given? */ + option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1); + if (option_ptr != NULL) { + /* remember given renewal period */ + dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2); + } else { + /* calculate safe periods for renewal */ + dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; + } + + /* renewal period given? */ + option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2); + if (option_ptr != NULL) { + /* remember given rebind period */ + dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2); + } else { + /* calculate safe periods for rebinding */ + dhcp->offered_t2_rebind = dhcp->offered_t0_lease; + } + + /* (y)our internet address */ + ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr); + +/** + * Patch #1308 + * TODO: we must check if the file field is not overloaded by DHCP options! + */ +#if 0 + /* boot server address */ + ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr); + /* boot file name */ + if (dhcp->msg_in->file[0]) { + dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1); + strcpy(dhcp->boot_file_name, dhcp->msg_in->file); + } +#endif + + /* subnet mask */ + option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK); + /* subnet mask given? */ + if (option_ptr != NULL) { + dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2])); + } + + /* gateway router */ + option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER); + if (option_ptr != NULL) { + dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); + } + + /* broadcast address */ + option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST); + if (option_ptr != NULL) { + dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); + } + + /* DNS servers */ + option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER); + if (option_ptr != NULL) { + u8_t n; + dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]); + /* limit to at most DHCP_MAX_DNS DNS servers */ + if (dhcp->dns_count > DHCP_MAX_DNS) dhcp->dns_count = DHCP_MAX_DNS; + for (n = 0; n < dhcp->dns_count; n++) + { + dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2+(n<<2)])); + } + } +} + +/** + * Start DHCP negotiation for a network interface. + * + * If no DHCP client instance was attached to this interface, + * a new client is created first. If a DHCP client instance + * was already present, it restarts negotiation. + * + * @param netif The lwIP network interface + * @return lwIP error code + * - ERR_OK - No error + * - ERR_MEM - Out of memory + * + */ +err_t dhcp_start(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result = ERR_OK; + + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + netif->flags &= ~NETIF_FLAG_DHCP; + + /* no DHCP client attached yet? */ + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); + dhcp = mem_malloc(sizeof(struct dhcp)); + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); + return ERR_MEM; + } + /* store this dhcp client in the netif */ + netif->dhcp = dhcp; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp")); + /* already has DHCP client attached */ + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n")); + } + + /* clear data structure */ + memset(dhcp, 0, sizeof(struct dhcp)); + /* allocate UDP PCB */ + dhcp->pcb = udp_new(); + if (dhcp->pcb == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n")); + mem_free((void *)dhcp); + netif->dhcp = dhcp = NULL; + return ERR_MEM; + } + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); + /* (re)start the DHCP negotiation */ + result = dhcp_discover(netif); + if (result != ERR_OK) { + /* free resources allocated above */ + dhcp_stop(netif); + return ERR_MEM; + } + netif->flags |= NETIF_FLAG_DHCP; + return result; +} + +/** + * Inform a DHCP server of our manual configuration. + * + * This informs DHCP servers of our fixed IP address configuration + * by sending an INFORM message. It does not involve DHCP address + * configuration, it is just here to be nice to the network. + * + * @param netif The lwIP network interface + * + */ +void dhcp_inform(struct netif *netif) +{ + struct dhcp *dhcp; + err_t result = ERR_OK; + dhcp = mem_malloc(sizeof(struct dhcp)); + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n")); + return; + } + netif->dhcp = dhcp; + memset(dhcp, 0, sizeof(struct dhcp)); + + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): allocated dhcp\n")); + dhcp->pcb = udp_new(); + if (dhcp->pcb == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb")); + mem_free((void *)dhcp); + return; + } + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) { + + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_INFORM); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + /* TODO: use netif->mtu ?! */ + dhcp_option_short(dhcp, 576); + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_inform: INFORMING\n")); + udp_send(dhcp->pcb, dhcp->p_out); + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + dhcp_delete_request(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n")); + } + + if (dhcp != NULL) + { + if (dhcp->pcb != NULL) udp_remove(dhcp->pcb); + dhcp->pcb = NULL; + mem_free((void *)dhcp); + netif->dhcp = NULL; + } +} + +#if DHCP_DOES_ARP_CHECK +/** + * Match an ARP reply with the offered IP address. + * + * @param addr The IP address we received a reply from + * + */ +void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_arp_reply()\n")); + /* is a DHCP client doing an ARP check? */ + if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr)); + /* did a host respond with the address we + were offered by the DHCP server? */ + if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) { + /* we will not accept the offered address */ + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); + dhcp_decline(netif); + } + } +} + +/** + * Decline an offered lease. + * + * Tell the DHCP server we do not accept the offered address. + * One reason to decline the lease is when we find out the address + * is already in use by another host (through ARP). + */ +static err_t dhcp_decline(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result = ERR_OK; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_decline()\n")); + dhcp_set_state(dhcp, DHCP_BACKING_OFF); + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) + { + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_DECLINE); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, 576); + + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + + dhcp_option_trailer(dhcp); + /* resize pbuf to reflect true size of options */ + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + /* @todo: should we really connect here? we are performing sendto() */ + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + /* per section 4.4.4, broadcast DECLINE messages */ + udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + dhcp_delete_request(netif); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = 10*1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} +#endif + + +/** + * Start the DHCP process, discover a DHCP server. + * + */ +static err_t dhcp_discover(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result = ERR_OK; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_discover()\n")); + ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY); + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) + { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: making request\n")); + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_DISCOVER); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, 576); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); + dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); + dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); + dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); + + dhcp_option_trailer(dhcp); + + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: realloc()ing\n")); + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* set receive callback function with netif as user data */ + udp_recv(dhcp->pcb, dhcp_recv, netif); + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); + udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n")); + dhcp_delete_request(netif); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n")); + dhcp_set_state(dhcp, DHCP_SELECTING); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + + +/** + * Bind the interface to the offered IP address. + * + * @param netif network interface to bind to the offered address + */ +static void dhcp_bind(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + struct ip_addr sn_mask, gw_addr; + LWIP_ASSERT("dhcp_bind: netif != NULL", netif != NULL); + LWIP_ASSERT("dhcp_bind: dhcp != NULL", dhcp != NULL); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* temporary DHCP lease? */ + if (dhcp->offered_t1_renew != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); + dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); + } + /* set renewal period timer */ + if (dhcp->offered_t2_rebind != 0xffffffffUL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); + dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); + } + /* copy offered network mask */ + ip_addr_set(&sn_mask, &dhcp->offered_sn_mask); + + /* subnet mask not given? */ + /* TODO: this is not a valid check. what if the network mask is 0? */ + if (sn_mask.addr == 0) { + /* choose a safe subnet mask given the network class */ + u8_t first_octet = ip4_addr1(&sn_mask); + if (first_octet <= 127) sn_mask.addr = htonl(0xff000000); + else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00); + else sn_mask.addr = htonl(0xffff0000); + } + + ip_addr_set(&gw_addr, &dhcp->offered_gw_addr); + /* gateway address not given? */ + if (gw_addr.addr == 0) { + /* copy network address */ + gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr); + /* use first host address on network as gateway */ + gw_addr.addr |= htonl(0x00000001); + } + + LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); + netif_set_ipaddr(netif, &dhcp->offered_ip_addr); + LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr)); + netif_set_netmask(netif, &sn_mask); + LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr)); + netif_set_gw(netif, &gw_addr); + /* bring the interface up */ + netif_set_up(netif); + /* netif is now bound to DHCP leased address */ + dhcp_set_state(dhcp, DHCP_BOUND); +} + +/** + * Renew an existing DHCP lease at the involved DHCP server. + * + * @param netif network interface which must renew its lease + */ +err_t dhcp_renew(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n")); + dhcp_set_state(dhcp, DHCP_RENEWING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) { + + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_REQUEST); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + /* TODO: use netif->mtu in some way */ + dhcp_option_short(dhcp, 576); + +#if 0 + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); +#endif + +#if 0 + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); +#endif + /* append DHCP message trailer */ + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); + udp_send(dhcp->pcb, dhcp->p_out); + dhcp_delete_request(netif); + + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n")); + } + dhcp->tries++; + /* back-off on retries, but to a maximum of 20 seconds */ + msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Rebind with a DHCP server for an existing DHCP lease. + * + * @param netif network interface which must rebind with a DHCP server + */ +static err_t dhcp_rebind(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n")); + dhcp_set_state(dhcp, DHCP_REBINDING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) + { + + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_REQUEST); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, 576); + +#if 0 + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); +#endif + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* set remote IP association to any DHCP server */ + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + /* broadcast to server */ + udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + dhcp_delete_request(netif); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind: REBINDING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Release a DHCP lease. + * + * @param netif network interface which must release its lease + */ +err_t dhcp_release(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n")); + + /* idle DHCP client */ + dhcp_set_state(dhcp, DHCP_OFF); + /* clean old DHCP offer */ + dhcp->server_ip_addr.addr = 0; + dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0; + dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0; + dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; + dhcp->dns_count = 0; + + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_RELEASE); + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); + udp_send(dhcp->pcb, dhcp->p_out); + dhcp_delete_request(netif); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs)); + /* bring the interface down */ + netif_set_down(netif); + /* remove IP address from interface */ + netif_set_ipaddr(netif, IP_ADDR_ANY); + netif_set_gw(netif, IP_ADDR_ANY); + netif_set_netmask(netif, IP_ADDR_ANY); + + /* TODO: netif_down(netif); */ + return result; +} +/** + * Remove the DHCP client from the interface. + * + * @param netif The network interface to stop DHCP on + */ +void dhcp_stop(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_ASSERT("dhcp_stop: netif != NULL", netif != NULL); + + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n")); + /* netif is DHCP configured? */ + if (dhcp != NULL) + { + if (dhcp->pcb != NULL) + { + udp_remove(dhcp->pcb); + dhcp->pcb = NULL; + } + if (dhcp->p != NULL) + { + pbuf_free(dhcp->p); + dhcp->p = NULL; + } + /* free unfolded reply */ + dhcp_free_reply(dhcp); + mem_free((void *)dhcp); + netif->dhcp = NULL; + } +} + +/* + * Set the DHCP state of a DHCP client. + * + * If the state changed, reset the number of tries. + * + * TODO: we might also want to reset the timeout here? + */ +static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state) +{ + if (new_state != dhcp->state) + { + dhcp->state = new_state; + dhcp->tries = 0; + } +} + +/* + * Concatenate an option type and length field to the outgoing + * DHCP message. + * + */ +static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) +{ + LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = option_type; + dhcp->msg_out->options[dhcp->options_out_len++] = option_len; +} +/* + * Concatenate a single byte to the outgoing DHCP message. + * + */ +static void dhcp_option_byte(struct dhcp *dhcp, u8_t value) +{ + LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = value; +} +static void dhcp_option_short(struct dhcp *dhcp, u16_t value) +{ + LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8; + dhcp->msg_out->options[dhcp->options_out_len++] = value & 0x00ffU; +} +static void dhcp_option_long(struct dhcp *dhcp, u32_t value) +{ + LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24; + dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16; + dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8; + dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL); +} + +/** + * Extract the DHCP message and the DHCP options. + * + * Extract the DHCP message and the DHCP options, each into a contiguous + * piece of memory. As a DHCP message is variable sized by its options, + * and also allows overriding some fields for options, the easy approach + * is to first unfold the options into a conitguous piece of memory, and + * use that further on. + * + */ +static err_t dhcp_unfold_reply(struct dhcp *dhcp) +{ + struct pbuf *p = dhcp->p; + u8_t *ptr; + u16_t i; + u16_t j = 0; + LWIP_ASSERT("dhcp->p != NULL", dhcp->p != NULL); + /* free any left-overs from previous unfolds */ + dhcp_free_reply(dhcp); + /* options present? */ + if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) + { + dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); + dhcp->options_in = mem_malloc(dhcp->options_in_len); + if (dhcp->options_in == NULL) + { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n")); + return ERR_MEM; + } + } + dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); + if (dhcp->msg_in == NULL) + { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n")); + mem_free((void *)dhcp->options_in); + dhcp->options_in = NULL; + return ERR_MEM; + } + + ptr = (u8_t *)dhcp->msg_in; + /* proceed through struct dhcp_msg */ + for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++) + { + *ptr++ = ((u8_t *)p->payload)[j++]; + /* reached end of pbuf? */ + if (j == p->len) + { + /* proceed to next pbuf in chain */ + p = p->next; + j = 0; + } + } + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", i)); + if (dhcp->options_in != NULL) { + ptr = (u8_t *)dhcp->options_in; + /* proceed through options */ + for (i = 0; i < dhcp->options_in_len; i++) { + *ptr++ = ((u8_t *)p->payload)[j++]; + /* reached end of pbuf? */ + if (j == p->len) { + /* proceed to next pbuf in chain */ + p = p->next; + j = 0; + } + } + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", i)); + } + return ERR_OK; +} + +/** + * Free the incoming DHCP message including contiguous copy of + * its DHCP options. + * + */ +static void dhcp_free_reply(struct dhcp *dhcp) +{ + if (dhcp->msg_in != NULL) { + mem_free((void *)dhcp->msg_in); + dhcp->msg_in = NULL; + } + if (dhcp->options_in) { + mem_free((void *)dhcp->options_in); + dhcp->options_in = NULL; + dhcp->options_in_len = 0; + } + LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n")); +} + + +/** + * If an incoming DHCP message is in response to us, then trigger the state machine + */ +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +{ + struct netif *netif = (struct netif *)arg; + struct dhcp *dhcp = netif->dhcp; + struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; + u8_t *options_ptr; + u8_t msg_type; + u8_t i; + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, + (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff), + (u16_t)(ntohl(addr->addr) >> 8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port)); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); + /* prevent warnings about unused arguments */ + (void)pcb; (void)addr; (void)port; + dhcp->p = p; + /* TODO: check packet length before reading them */ + if (reply_msg->op != DHCP_BOOTREPLY) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); + pbuf_free(p); + dhcp->p = NULL; + return; + } + /* iterate through hardware address and match against DHCP message */ + for (i = 0; i < netif->hwaddr_len; i++) { + if (netif->hwaddr[i] != reply_msg->chaddr[i]) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", + (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); + pbuf_free(p); + dhcp->p = NULL; + return; + } + } + /* match transaction ID against what we expected */ + if (ntohl(reply_msg->xid) != dhcp->xid) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id mismatch\n")); + pbuf_free(p); + dhcp->p = NULL; + return; + } + /* option fields could be unfold? */ + if (dhcp_unfold_reply(dhcp) != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n")); + pbuf_free(p); + dhcp->p = NULL; + return; + } + + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); + /* obtain pointer to DHCP message type */ + options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE); + if (options_ptr == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); + pbuf_free(p); + dhcp->p = NULL; + return; + } + + /* read DHCP message type */ + msg_type = dhcp_get_option_byte(options_ptr + 2); + /* message type is DHCP ACK? */ + if (msg_type == DHCP_ACK) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n")); + /* in requesting state? */ + if (dhcp->state == DHCP_REQUESTING) { + dhcp_handle_ack(netif); + dhcp->request_timeout = 0; +#if DHCP_DOES_ARP_CHECK + /* check if the acknowledged lease address is already in use */ + dhcp_check(netif); +#else + /* bind interface to the acknowledged lease address */ + dhcp_bind(netif); +#endif + } + /* already bound to the given lease address? */ + else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { + dhcp->request_timeout = 0; + dhcp_bind(netif); + } + } + /* received a DHCP_NAK in appropriate state? */ + else if ((msg_type == DHCP_NAK) && + ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || + (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_NAK received\n")); + dhcp->request_timeout = 0; + dhcp_handle_nak(netif); + } + /* received a DHCP_OFFER in DHCP_SELECTING state? */ + else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n")); + dhcp->request_timeout = 0; + /* remember offered lease */ + dhcp_handle_offer(netif); + } + pbuf_free(p); + dhcp->p = NULL; +} + + +static err_t dhcp_create_request(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + u16_t i; + LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL); + LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL); + dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); + if (dhcp->p_out == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n")); + return ERR_MEM; + } + /* give unique transaction identifier to this request */ + dhcp->xid = xid++; + + dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; + + dhcp->msg_out->op = DHCP_BOOTREQUEST; + /* TODO: make link layer independent */ + dhcp->msg_out->htype = DHCP_HTYPE_ETH; + /* TODO: make link layer independent */ + dhcp->msg_out->hlen = DHCP_HLEN_ETH; + dhcp->msg_out->hops = 0; + dhcp->msg_out->xid = htonl(dhcp->xid); + dhcp->msg_out->secs = 0; + dhcp->msg_out->flags = 0; + dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr; + dhcp->msg_out->yiaddr.addr = 0; + dhcp->msg_out->siaddr.addr = 0; + dhcp->msg_out->giaddr.addr = 0; + for (i = 0; i < DHCP_CHADDR_LEN; i++) { + /* copy netif hardware address, pad with zeroes */ + dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/; + } + for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0; + for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0; + dhcp->msg_out->cookie = htonl(0x63825363UL); + dhcp->options_out_len = 0; + /* fill options field with an incrementing array (for debugging purposes) */ + for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i; + return ERR_OK; +} + +static void dhcp_delete_request(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); + LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); + pbuf_free(dhcp->p_out); + dhcp->p_out = NULL; + dhcp->msg_out = NULL; +} + +/** + * Add a DHCP message trailer + * + * Adds the END option to the DHCP message, and if + * necessary, up to three padding bytes. + */ + +static void dhcp_option_trailer(struct dhcp *dhcp) +{ + LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); + LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; + /* packet is too small, or not 4 byte aligned? */ + while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) { + /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */ + LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); + /* add a fill/padding byte */ + dhcp->msg_out->options[dhcp->options_out_len++] = 0; + } +} + +/** + * Find the offset of a DHCP option inside the DHCP message. + * + * @param client DHCP client + * @param option_type + * + * @return a byte offset into the UDP message where the option was found, or + * zero if the given option was not found. + */ +static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type) +{ + u8_t overload = DHCP_OVERLOAD_NONE; + + /* options available? */ + if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) { + /* start with options field */ + u8_t *options = (u8_t *)dhcp->options_in; + u16_t offset = 0; + /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ + while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) { + /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ + /* are the sname and/or file field overloaded with options? */ + if (options[offset] == DHCP_OPTION_OVERLOAD) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n")); + /* skip option type and length */ + offset += 2; + overload = options[offset++]; + } + /* requested option found */ + else if (options[offset] == option_type) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset)); + return &options[offset]; + /* skip option */ + } else { + LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset])); + /* skip option type */ + offset++; + /* skip option length, and then length bytes */ + offset += 1 + options[offset]; + } + } + /* is this an overloaded message? */ + if (overload != DHCP_OVERLOAD_NONE) { + u16_t field_len; + if (overload == DHCP_OVERLOAD_FILE) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n")); + options = (u8_t *)&dhcp->msg_in->file; + field_len = DHCP_FILE_LEN; + } else if (overload == DHCP_OVERLOAD_SNAME) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n")); + options = (u8_t *)&dhcp->msg_in->sname; + field_len = DHCP_SNAME_LEN; + /* TODO: check if else if () is necessary */ + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n")); + options = (u8_t *)&dhcp->msg_in->sname; + field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN; + } + offset = 0; + + /* at least 1 byte to read and no end marker */ + while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) { + if (options[offset] == option_type) { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%"U16_F"\n", offset)); + return &options[offset]; + /* skip option */ + } else { + LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\n", options[offset])); + /* skip option type */ + offset++; + offset += 1 + options[offset]; + } + } + } + } + return 0; +} + +/** + * Return the byte of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u8_t dhcp_get_option_byte(u8_t *ptr) +{ + LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr))); + return *ptr; +} + +/** + * Return the 16-bit value of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +#if 0 +static u16_t dhcp_get_option_short(u8_t *ptr) +{ + u16_t value; + value = *ptr++ << 8; + value |= *ptr; + LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value)); + return value; +} +#endif + +/** + * Return the 32-bit value of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u32_t dhcp_get_option_long(u8_t *ptr) +{ + u32_t value; + value = (u32_t)(*ptr++) << 24; + value |= (u32_t)(*ptr++) << 16; + value |= (u32_t)(*ptr++) << 8; + value |= (u32_t)(*ptr++); + LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value)); + return value; +} + +#endif /* LWIP_DHCP */ diff --git a/wii/libogc/lwip/core/inet.c b/wii/libogc/lwip/core/inet.c new file mode 100644 index 0000000000..33a353eb02 --- /dev/null +++ b/wii/libogc/lwip/core/inet.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +/* inet.c + * + * Functions common to all TCP/IP modules, such as the Internet checksum and the + * byte order functions. + * + */ + + +#include "lwip/opt.h" + +#include "lwip/arch.h" + +#include "lwip/def.h" +#include "lwip/inet.h" + +#include "lwip/sys.h" + +/* This is a reference implementation of the checksum algorithm, with the + * aim of being simple, correct and fully portable. Checksumming is the + * first thing you would want to optimize for your platform. You will + * need to port it to your architecture and in your sys_arch.h: + * + * #define LWIP_CHKSUM +*/ +#ifndef LWIP_CHKSUM +#define LWIP_CHKSUM lwip_standard_chksum + +/** + * lwip checksum + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum) + * + * @note accumulator size limits summable lenght to 64k + * @note host endianess is irrelevant (p3 RFC1071) + */ +static u16_t +lwip_standard_chksum(void *dataptr, u16_t len) +{ + u32_t acc; + u16_t src; + u8_t *octetptr; + + acc = 0; + /* dataptr may be at odd or even addresses */ + octetptr = (u8_t*)dataptr; + while (len > 1) + { + /* declare first octet as most significant + thus assume network order, ignoring host order */ + src = (*octetptr) << 8; + octetptr++; + /* declare second octet as least significant */ + src |= (*octetptr); + octetptr++; + acc += src; + len -= 2; + } + if (len > 0) + { + /* accumulate remaining octet */ + src = (*octetptr) << 8; + acc += src; + } + /* add deferred carry bits */ + acc = (acc >> 16) + (acc & 0x0000ffffUL); + if ((acc & 0xffff0000) != 0) { + acc = (acc >> 16) + (acc & 0x0000ffffUL); + } + /* This maybe a little confusing: reorder sum using htons() + instead of ntohs() since it has a little less call overhead. + The caller must invert bits for Internet sum ! */ + return htons((u16_t)acc); +} + +#endif + +#if 0 +/* + * Curt McDowell + * Broadcom Corp. + * csm@broadcom.com + * + * IP checksum two bytes at a time with support for + * unaligned buffer. + * Works for len up to and including 0x20000. + * by Curt McDowell, Broadcom Corp. 12/08/2005 + */ + +static u16_t +lwip_standard_chksum2(void *dataptr, int len) +{ + u8_t *pb = dataptr; + u16_t *ps, t = 0; + u32_t sum = 0; + int odd = ((u32_t)pb & 1); + + /* Get aligned to u16_t */ + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + /* Add the bulk of the data */ + ps = (u16_t *)pb; + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* Consume left-over byte, if any */ + if (len > 0) + ((u8_t *)&t)[0] = *(u8_t *)ps;; + + /* Add end bytes */ + sum += t; + + /* Fold 32-bit sum to 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + /* Swap if alignment was odd */ + if (odd) + sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8); + + return sum; +} + +/** + * An optimized checksum routine. Basically, it uses loop-unrolling on + * the checksum loop, treating the head and tail bytes specially, whereas + * the inner loop acts on 8 bytes at a time. + * + * @arg start of buffer to be checksummed. May be an odd byte address. + * @len number of bytes in the buffer to be checksummed. + * + * @todo First argument type conflicts with generic checksum routine. + * + * by Curt McDowell, Broadcom Corp. December 8th, 2005 + */ + +static u16_t +lwip_standard_chksum4(u8_t *pb, int len) +{ + u16_t *ps, t = 0; + u32_t *pl; + u32_t sum = 0, tmp; + /* starts at odd byte address? */ + int odd = ((u32_t)pb & 1); + + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + ps = (u16_t *)pb; + + if (((u32_t)ps & 3) && len > 1) { + sum += *ps++; + len -= 2; + } + + pl = (u32_t *)ps; + + while (len > 7) { + tmp = sum + *pl++; /* ping */ + if (tmp < sum) + tmp++; /* add back carry */ + + sum = tmp + *pl++; /* pong */ + if (sum < tmp) + sum++; /* add back carry */ + + len -= 8; + } + + /* make room in upper bits */ + sum = (sum >> 16) + (sum & 0xffff); + + ps = (u16_t *)pl; + + /* 16-bit aligned word remaining? */ + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* dangling tail byte remaining? */ + if (len > 0) /* include odd byte */ + ((u8_t *)&t)[0] = *(u8_t *)ps; + + sum += t; /* add end bytes */ + + while (sum >> 16) /* combine halves */ + sum = (sum >> 16) + (sum & 0xffff); + + if (odd) + sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8); + + return sum; +} +#endif + +/* inet_chksum_pseudo: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + */ + +u16_t +inet_chksum_pseudo(struct pbuf *p, + struct ip_addr *src, struct ip_addr *dest, + u8_t proto, u16_t proto_len) +{ + u32_t acc; + struct pbuf *q; + u8_t swapped; + + acc = 0; + swapped = 0; + /* iterate through all pbuf in chain */ + for(q = p; q != NULL; q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + acc += LWIP_CHKSUM(q->payload, q->len); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + while (acc >> 16) { + acc = (acc & 0xffffUL) + (acc >> 16); + } + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8); + } + acc += (src->addr & 0xffffUL); + acc += ((src->addr >> 16) & 0xffffUL); + acc += (dest->addr & 0xffffUL); + acc += ((dest->addr >> 16) & 0xffffUL); + acc += (u32_t)htons((u16_t)proto); + acc += (u32_t)htons(proto_len); + + while (acc >> 16) { + acc = (acc & 0xffffUL) + (acc >> 16); + } + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +/* inet_chksum: + * + * Calculates the Internet checksum over a portion of memory. Used primarely for IP + * and ICMP. + */ + +u16_t +inet_chksum(void *dataptr, u16_t len) +{ + u32_t acc; + + acc = LWIP_CHKSUM(dataptr, len); + while (acc >> 16) { + acc = (acc & 0xffff) + (acc >> 16); + } + return (u16_t)~(acc & 0xffff); +} + +u16_t +inet_chksum_pbuf(struct pbuf *p) +{ + u32_t acc; + struct pbuf *q; + u8_t swapped; + + acc = 0; + swapped = 0; + for(q = p; q != NULL; q = q->next) { + acc += LWIP_CHKSUM(q->payload, q->len); + while (acc >> 16) { + acc = (acc & 0xffffUL) + (acc >> 16); + } + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8); + } + } + + if (swapped) { + acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8); + } + return (u16_t)~(acc & 0xffffUL); +} + diff --git a/wii/libogc/lwip/core/inet6.c b/wii/libogc/lwip/core/inet6.c new file mode 100644 index 0000000000..c04915b73d --- /dev/null +++ b/wii/libogc/lwip/core/inet6.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +/* inet6.c + * + * Functions common to all TCP/IP modules, such as the Internet checksum and the + * byte order functions. + * + */ + + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/inet.h" + + + +/* chksum: + * + * Sums up all 16 bit words in a memory portion. Also includes any odd byte. + * This function is used by the other checksum functions. + * + * For now, this is not optimized. Must be optimized for the particular processor + * arcitecture on which it is to run. Preferebly coded in assembler. + */ + +static u32_t +chksum(void *dataptr, u16_t len) +{ + u16_t *sdataptr = dataptr; + u32_t acc; + + + for(acc = 0; len > 1; len -= 2) { + acc += *sdataptr++; + } + + /* add up any odd byte */ + if (len == 1) { + acc += htons((u16_t)(*(u8_t *)dataptr) << 8); + } + + return acc; + +} + +/* inet_chksum_pseudo: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + */ + +u16_t +inet_chksum_pseudo(struct pbuf *p, + struct ip_addr *src, struct ip_addr *dest, + u8_t proto, u32_t proto_len) +{ + u32_t acc; + struct pbuf *q; + u8_t swapped, i; + + acc = 0; + swapped = 0; + for(q = p; q != NULL; q = q->next) { + acc += chksum(q->payload, q->len); + while (acc >> 16) { + acc = (acc & 0xffff) + (acc >> 16); + } + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + } + } + + if (swapped) { + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + } + + for(i = 0; i < 8; i++) { + acc += ((u16_t *)src->addr)[i] & 0xffff; + acc += ((u16_t *)dest->addr)[i] & 0xffff; + while (acc >> 16) { + acc = (acc & 0xffff) + (acc >> 16); + } + } + acc += (u16_t)htons((u16_t)proto); + acc += ((u16_t *)&proto_len)[0] & 0xffff; + acc += ((u16_t *)&proto_len)[1] & 0xffff; + + while (acc >> 16) { + acc = (acc & 0xffff) + (acc >> 16); + } + return ~(acc & 0xffff); +} + +/* inet_chksum: + * + * Calculates the Internet checksum over a portion of memory. Used primarely for IP + * and ICMP. + */ + +u16_t +inet_chksum(void *dataptr, u16_t len) +{ + u32_t acc, sum; + + acc = chksum(dataptr, len); + sum = (acc & 0xffff) + (acc >> 16); + sum += (sum >> 16); + return ~(sum & 0xffff); +} + +u16_t +inet_chksum_pbuf(struct pbuf *p) +{ + u32_t acc; + struct pbuf *q; + u8_t swapped; + + acc = 0; + swapped = 0; + for(q = p; q != NULL; q = q->next) { + acc += chksum(q->payload, q->len); + while (acc >> 16) { + acc = (acc & 0xffff) + (acc >> 16); + } + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8); + } + } + + if (swapped) { + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + } + return ~(acc & 0xffff); +} + diff --git a/wii/libogc/lwip/core/ipv4/icmp.c b/wii/libogc/lwip/core/ipv4/icmp.c new file mode 100644 index 0000000000..02d467e43c --- /dev/null +++ b/wii/libogc/lwip/core/ipv4/icmp.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This + is not implemented. */ + +#include + +#include "lwip/opt.h" +#include "lwip/icmp.h" +#include "lwip/inet.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +void +icmp_input(struct pbuf *p, struct netif *inp) +{ + u8_t type; + u8_t code; + struct icmp_echo_hdr *iecho; + struct ip_hdr *iphdr; + struct ip_addr tmpaddr; + u16_t hlen; + + ICMP_STATS_INC(icmp.recv); + snmp_inc_icmpinmsgs(); + + + iphdr = p->payload; + hlen = IPH_HL(iphdr) * 4; + if (pbuf_header(p, -((s16_t)hlen)) || (p->tot_len < sizeof(u16_t)*2)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); + pbuf_free(p); + ICMP_STATS_INC(icmp.lenerr); + snmp_inc_icmpinerrors(); + return; + } + + type = *((u8_t *)p->payload); + code = *(((u8_t *)p->payload)+1); + (void)code; + switch (type) { + case ICMP_ECHO: + /* broadcast or multicast destination address? */ + if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); + ICMP_STATS_INC(icmp.err); + pbuf_free(p); + return; + } + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); + if (p->tot_len < sizeof(struct icmp_echo_hdr)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + pbuf_free(p); + ICMP_STATS_INC(icmp.lenerr); + snmp_inc_icmpinerrors(); + + return; + } + iecho = p->payload; + if (inet_chksum_pbuf(p) != 0) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); + pbuf_free(p); + ICMP_STATS_INC(icmp.chkerr); + snmp_inc_icmpinerrors(); + return; + } + tmpaddr.addr = iphdr->src.addr; + iphdr->src.addr = iphdr->dest.addr; + iphdr->dest.addr = tmpaddr.addr; + ICMPH_TYPE_SET(iecho, ICMP_ER); + /* adjust the checksum */ + if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { + iecho->chksum += htons(ICMP_ECHO << 8) + 1; + } else { + iecho->chksum += htons(ICMP_ECHO << 8); + } + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + snmp_inc_icmpoutmsgs(); + /* increase number of echo replies attempted to send */ + snmp_inc_icmpoutechoreps(); + + pbuf_header(p, hlen); + ip_output_if(p, &(iphdr->src), IP_HDRINCL, + IPH_TTL(iphdr), 0, IP_PROTO_ICMP, inp); + break; + default: + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", (s16_t)type, (s16_t)code)); + ICMP_STATS_INC(icmp.proterr); + ICMP_STATS_INC(icmp.drop); + } + pbuf_free(p); +} + +void +icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +{ + struct pbuf *q; + struct ip_hdr *iphdr; + struct icmp_dur_hdr *idur; + + q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); + /* ICMP header + IP header + 8 bytes of data */ + + iphdr = p->payload; + + idur = q->payload; + ICMPH_TYPE_SET(idur, ICMP_DUR); + ICMPH_CODE_SET(idur, t); + + memcpy((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8); + + /* calculate checksum */ + idur->chksum = 0; + idur->chksum = inet_chksum(idur, q->len); + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + snmp_inc_icmpoutmsgs(); + /* increase number of destination unreachable messages attempted to send */ + snmp_inc_icmpoutdestunreachs(); + + ip_output(q, NULL, &(iphdr->src), + ICMP_TTL, 0, IP_PROTO_ICMP); + pbuf_free(q); +} + +#if IP_FORWARD +void +icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +{ + struct pbuf *q; + struct ip_hdr *iphdr; + struct icmp_te_hdr *tehdr; + + q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); + + iphdr = p->payload; + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); + ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); + LWIP_DEBUGF(ICMP_DEBUG, (" to ")); + ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); + LWIP_DEBUGF(ICMP_DEBUG, ("\n")); + + tehdr = q->payload; + ICMPH_TYPE_SET(tehdr, ICMP_TE); + ICMPH_CODE_SET(tehdr, t); + + /* copy fields from original packet */ + memcpy((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8); + + /* calculate checksum */ + tehdr->chksum = 0; + tehdr->chksum = inet_chksum(tehdr, q->len); + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + snmp_inc_icmpoutmsgs(); + /* increase number of destination unreachable messages attempted to send */ + snmp_inc_icmpouttimeexcds(); + ip_output(q, NULL, &(iphdr->src), + ICMP_TTL, 0, IP_PROTO_ICMP); + pbuf_free(q); +} + +#endif /* IP_FORWARD */ + + + + + + + diff --git a/wii/libogc/lwip/core/ipv4/ip.c b/wii/libogc/lwip/core/ipv4/ip.c new file mode 100644 index 0000000000..4db68c8e86 --- /dev/null +++ b/wii/libogc/lwip/core/ipv4/ip.c @@ -0,0 +1,508 @@ +/* @file + * + * This is the IP layer implementation for incoming and outgoing IP traffic. + * + * @see ip_frag.c + * + */ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip.h" +#include "lwip/ip_frag.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include "lwip/stats.h" + +#include "arch/perf.h" + +#include "lwip/snmp.h" +#if LWIP_DHCP +# include "lwip/dhcp.h" +#endif /* LWIP_DHCP */ + + +/** + * Initializes the IP layer. + */ + +void +ip_init(void) +{ + /* no initializations as of yet */ +} + +/** + * Finds the appropriate network interface for a given IP address. It + * searches the list of network interfaces linearly. A match is found + * if the masked IP address of the network interface equals the masked + * IP address given to the function. + */ + +struct netif * +ip_route(struct ip_addr *dest) +{ + struct netif *netif; + + /* iterate through netifs */ + for(netif = netif_list; netif != NULL; netif = netif->next) { + /* network mask matches? */ + if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { + /* return netif on which to forward IP packet */ + return netif; + } + } + /* no matching netif found, use default netif */ + return netif_default; +} +#if IP_FORWARD + +/** + * Forwards an IP packet. It finds an appropriate route for the + * packet, decrements the TTL value of the packet, adjusts the + * checksum and outputs the packet on the appropriate interface. + */ + +static struct netif * +ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + PERF_START; + /* Find network interface where to forward this IP packet to. */ + netif = ip_route((struct ip_addr *)&(iphdr->dest)); + if (netif == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n", + iphdr->dest.addr)); + snmp_inc_ipnoroutes(); + return (struct netif *)NULL; + } + /* Do not forward packets onto the same network interface on which + * they arrived. */ + if (netif == inp) { + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); + snmp_inc_ipnoroutes(); + return (struct netif *)NULL; + } + + /* decrement TTL */ + IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); + /* send ICMP if TTL == 0 */ + if (IPH_TTL(iphdr) == 0) { + /* Don't send ICMP messages in response to ICMP messages */ + if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { + icmp_time_exceeded(p, ICMP_TE_TTL); + snmp_inc_icmpouttimeexcds(); + } + return (struct netif *)NULL; + } + + /* Incrementally update the IP checksum. */ + if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); + } else { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100)); + } + + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n", + iphdr->dest.addr)); + + IP_STATS_INC(ip.fw); + IP_STATS_INC(ip.xmit); + snmp_inc_ipforwdatagrams(); + + PERF_STOP("ip_forward"); + /* transmit pbuf on chosen interface */ + netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); + return netif; +} +#endif /* IP_FORWARD */ + +/** + * This function is called by the network interface device driver when + * an IP packet is received. The function does the basic checks of the + * IP header such as packet size being at least larger than the header + * size etc. If the packet was not destined for us, the packet is + * forwarded (using ip_forward). The IP checksum is always checked. + * + * Finally, the packet is sent to the upper layer protocol input function. + * + * + * + */ + +err_t +ip_input(struct pbuf *p, struct netif *inp) { + struct ip_hdr *iphdr; + struct netif *netif; + u16_t iphdrlen; + + IP_STATS_INC(ip.recv); + snmp_inc_ipinreceives(); + + /* identify the IP header */ + iphdr = p->payload; + if (IPH_V(iphdr) != 4) { + LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); + ip_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.err); + IP_STATS_INC(ip.drop); + snmp_inc_ipunknownprotos(); + return ERR_OK; + } + /* obtain IP header length in number of 32-bit words */ + iphdrlen = IPH_HL(iphdr); + /* calculate IP header length in bytes */ + iphdrlen *= 4; + + /* header length exceeds first pbuf length? */ + if (iphdrlen > p->len) { + LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet droppped.\n", + iphdrlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP_STATS_INC(ip.lenerr); + IP_STATS_INC(ip.drop); + snmp_inc_ipindiscards(); + return ERR_OK; + } + + /* verify checksum */ +#if CHECKSUM_CHECK_IP + if (inet_chksum(iphdr, iphdrlen) != 0) { + + LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen))); + ip_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.chkerr); + IP_STATS_INC(ip.drop); + snmp_inc_ipindiscards(); + return ERR_OK; + } +#endif + + /* Trim pbuf. This should have been done at the netif layer, + * but we'll do it anyway just to be sure that its done. */ + pbuf_realloc(p, ntohs(IPH_LEN(iphdr))); + + /* match packet against an interface, i.e. is this packet for us? */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + + LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", + iphdr->dest.addr, netif->ip_addr.addr, + iphdr->dest.addr & netif->netmask.addr, + netif->ip_addr.addr & netif->netmask.addr, + iphdr->dest.addr & ~(netif->netmask.addr))); + + /* interface is up and configured? */ + if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) + { + /* unicast to this interface address? */ + if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || + /* or broadcast on this interface network address? */ + ip_addr_isbroadcast(&(iphdr->dest), netif)) { + LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* break out of for loop */ + break; + } + } + } +#if LWIP_DHCP + /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed + * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. + * According to RFC 1542 section 3.1.1, referred by RFC 2131). + */ + if (netif == NULL) { + /* remote port is DHCP server? */ + if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { + LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", + ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest))); + if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) { + LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n")); + netif = inp; + } + } + } +#endif /* LWIP_DHCP */ + /* packet not for us? */ + if (netif == NULL) { + /* packet not for us, route or discard */ + LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n")); +#if IP_FORWARD + /* non-broadcast packet? */ + if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) { + /* try to forward IP packet on (other) interfaces */ + ip_forward(p, iphdr, inp); + } + else +#endif /* IP_FORWARD */ + { + snmp_inc_ipindiscards(); + } + pbuf_free(p); + return ERR_OK; + } + /* packet consists of multiple fragments? */ + if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { +#if IP_REASSEMBLY /* packet fragment reassembly code present? */ + LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", + ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); + /* reassemble the packet*/ + p = ip_reass(p); + /* packet not fully reassembled yet? */ + if (p == NULL) { + return ERR_OK; + } + iphdr = p->payload; +#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ + pbuf_free(p); + LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", + ntohs(IPH_OFFSET(iphdr)))); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + snmp_inc_ipunknownprotos(); + return ERR_OK; +#endif /* IP_REASSEMBLY */ + } + +#if IP_OPTIONS == 0 /* no support for IP options in the IP header? */ + if (iphdrlen > IP_HLEN) { + LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n")); + pbuf_free(p); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + snmp_inc_ipunknownprotos(); + return ERR_OK; + } +#endif /* IP_OPTIONS == 0 */ + + /* send to upper layers */ + LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); + ip_debug_print(p); + LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + +#if LWIP_RAW + /* raw input did not eat the packet? */ + if (raw_input(p, inp) == 0) { +#endif /* LWIP_RAW */ + + switch (IPH_PROTO(iphdr)) { +#if LWIP_UDP + case IP_PROTO_UDP: + case IP_PROTO_UDPLITE: + snmp_inc_ipindelivers(); + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case IP_PROTO_TCP: + snmp_inc_ipindelivers(); + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ + case IP_PROTO_ICMP: + snmp_inc_ipindelivers(); + icmp_input(p, inp); + break; + default: + /* send ICMP destination protocol unreachable unless is was a broadcast */ + if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && + !ip_addr_ismulticast(&(iphdr->dest))) { + p->payload = iphdr; + icmp_dest_unreach(p, ICMP_DUR_PROTO); + } + pbuf_free(p); + + LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); + + IP_STATS_INC(ip.proterr); + IP_STATS_INC(ip.drop); + snmp_inc_ipunknownprotos(); + } +#if LWIP_RAW + } /* LWIP_RAW */ +#endif + return ERR_OK; +} + +/** + * Sends an IP packet on a network interface. This function constructs + * the IP header and calculates the IP header checksum. If the source + * IP address is NULL, the IP address of the outgoing network + * interface is filled in as source address. + */ + +err_t +ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, + u8_t proto, struct netif *netif) +{ + struct ip_hdr *iphdr; + u16_t ip_id = 0; + + snmp_inc_ipoutrequests(); + + if (dest != IP_HDRINCL) { + if (pbuf_header(p, IP_HLEN)) { + LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n")); + + IP_STATS_INC(ip.err); + snmp_inc_ipoutdiscards(); + return ERR_BUF; + } + + iphdr = p->payload; + + IPH_TTL_SET(iphdr, ttl); + IPH_PROTO_SET(iphdr, proto); + + ip_addr_set(&(iphdr->dest), dest); + + IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos); + IPH_LEN_SET(iphdr, htons(p->tot_len)); + IPH_OFFSET_SET(iphdr, htons(IP_DF)); + IPH_ID_SET(iphdr, htons(ip_id)); + ++ip_id; + + if (ip_addr_isany(src)) { + ip_addr_set(&(iphdr->src), &(netif->ip_addr)); + } else { + ip_addr_set(&(iphdr->src), src); + } + + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); +#endif + } else { + iphdr = p->payload; + dest = &(iphdr->dest); + } + +#if IP_FRAG + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif->mtu && (p->tot_len > netif->mtu)) + return ip_frag(p,netif,dest); +#endif + + IP_STATS_INC(ip.xmit); + + LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); + ip_debug_print(p); + + LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); + + return netif->output(netif, p, dest); +} + +/** + * Simple interface to ip_output_if. It finds the outgoing network + * interface and calls upon ip_output_if to do the actual work. + */ + +err_t +ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto) +{ + struct netif *netif; + + if ((netif = ip_route(dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); + + IP_STATS_INC(ip.rterr); + snmp_inc_ipoutdiscards(); + return ERR_RTE; + } + + return ip_output_if(p, src, dest, ttl, tos, proto, netif); +} + +#if IP_DEBUG +void +ip_debug_print(struct pbuf *p) +{ + struct ip_hdr *iphdr = p->payload; + u8_t *payload; + + payload = (u8_t *)iphdr + IP_HLEN; + + LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", + IPH_V(iphdr), + IPH_HL(iphdr), + IPH_TOS(iphdr), + ntohs(IPH_LEN(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", + ntohs(IPH_ID(iphdr)), + ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, + ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, + ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, + ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", + IPH_TTL(iphdr), + IPH_PROTO(iphdr), + ntohs(IPH_CHKSUM(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", + ip4_addr1(&iphdr->src), + ip4_addr2(&iphdr->src), + ip4_addr3(&iphdr->src), + ip4_addr4(&iphdr->src))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", + ip4_addr1(&iphdr->dest), + ip4_addr2(&iphdr->dest), + ip4_addr3(&iphdr->dest), + ip4_addr4(&iphdr->dest))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ + + + + + + diff --git a/wii/libogc/lwip/core/ipv4/ip_addr.c b/wii/libogc/lwip/core/ipv4/ip_addr.c new file mode 100644 index 0000000000..2af526e9f3 --- /dev/null +++ b/wii/libogc/lwip/core/ipv4/ip_addr.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/ip_addr.h" +#include "lwip/inet.h" +#include "lwip/netif.h" + +/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ +const struct ip_addr ip_addr_any = { 0x00000000UL }; +const struct ip_addr ip_addr_broadcast = { 0xffffffffUL }; + +/* Determine if an address is a broadcast address on a network interface + * + * @param addr address to be checked + * @param netif the network interface against which the address is checked + * @return returns non-zero if the address is a broadcast address + * + */ + +u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif) +{ + /* all ones (broadcast) or all zeroes (old skool broadcast) */ + if ((addr->addr == ip_addr_broadcast.addr) || + (addr->addr == ip_addr_any.addr)) + return 1; + /* no broadcast support on this network interface? */ + else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) + /* the given address cannot be a broadcast address + * nor can we check against any broadcast addresses */ + return 0; + /* address matches network interface address exactly? => no broadcast */ + else if (addr->addr == netif->ip_addr.addr) + return 0; + /* on the same (sub) network... */ + else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask)) + /* ...and host identifier bits are all ones? =>... */ + && ((addr->addr & ~netif->netmask.addr) == + (ip_addr_broadcast.addr & ~netif->netmask.addr))) + /* => network broadcast address */ + return 1; + else + return 0; +} diff --git a/wii/libogc/lwip/core/ipv4/ip_frag.c b/wii/libogc/lwip/core/ipv4/ip_frag.c new file mode 100644 index 0000000000..5a57138ce3 --- /dev/null +++ b/wii/libogc/lwip/core/ipv4/ip_frag.c @@ -0,0 +1,366 @@ +/* @file + * + * This is the IP packet segmentation and reassembly implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * original reassembly code by Adam Dunkels + * + */ + +#include + +#include "lwip/opt.h" +/* #include "lwip/sys.h" */ +#include "lwip/ip.h" +#include "lwip/ip_frag.h" +#include "lwip/netif.h" +#include "lwip/stats.h" + + +/* + * Copy len bytes from offset in pbuf to buffer + * + * helper used by both ip_reass and ip_frag + */ +static struct pbuf * +copy_from_pbuf(struct pbuf *p, u16_t * offset, + u8_t * buffer, u16_t len) +{ + u16_t l; + + p->payload = (u8_t *)p->payload + *offset; + p->len -= *offset; + while (len) { + l = len < p->len ? len : p->len; + memcpy(buffer, p->payload, l); + buffer += l; + len -= l; + if (len) + p = p->next; + else + *offset = l; + } + return p; +} + +#define IP_REASS_BUFSIZE 5760 +#define IP_REASS_MAXAGE 30 +#define IP_REASS_TMO 1000 + +static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE]; +static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1]; +static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f, + 0x0f, 0x07, 0x03, 0x01 +}; +static u16_t ip_reasslen; +static u8_t ip_reassflags; +#define IP_REASS_FLAG_LASTFRAG 0x01 + +static u8_t ip_reasstmr; + +/** + * Reassembly timer base function + * for both NO_SYS == 0 and 1 (!). + * + * Should be called every 1000 msec. + */ +void +ip_reass_tmr(void) +{ + if (ip_reasstmr > 0) { + ip_reasstmr--; + } +} + +/** + * Reassembles incoming IP fragments into an IP datagram. + * + * @param p points to a pbuf chain of the fragment + * @return NULL if reassembly is incomplete, ? otherwise + */ +struct pbuf * +ip_reass(struct pbuf *p) +{ + struct pbuf *q; + struct ip_hdr *fraghdr, *iphdr; + u16_t offset, len; + u16_t i; + + IPFRAG_STATS_INC(ip_frag.recv); + + iphdr = (struct ip_hdr *) ip_reassbuf; + fraghdr = (struct ip_hdr *) p->payload; + /* If ip_reasstmr is zero, no packet is present in the buffer, so we + write the IP header of the fragment into the reassembly + buffer. The timer is updated with the maximum age. */ + if (ip_reasstmr == 0) { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n")); + memcpy(iphdr, fraghdr, IP_HLEN); + ip_reasstmr = IP_REASS_MAXAGE; + ip_reassflags = 0; + /* Clear the bitmap. */ + memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap)); + } + + /* Check if the incoming fragment matches the one currently present + in the reasembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if (ip_addr_cmp(&iphdr->src, &fraghdr->src) && + ip_addr_cmp(&iphdr->dest, &fraghdr->dest) && + IPH_ID(iphdr) == IPH_ID(fraghdr)) { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", + ntohs(IPH_ID(fraghdr)))); + IPFRAG_STATS_INC(ip_frag.cachehit); + /* Find out the offset in the reassembly buffer where we should + copy the fragment. */ + len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; + offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; + + /* If the offset or the offset + fragment length overflows the + reassembly buffer, we discard the entire packet. */ + if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) { + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset, + offset + len, IP_REASS_BUFSIZE)); + ip_reasstmr = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset, + IP_HLEN + offset, IP_HLEN + offset + len)); + i = IPH_HL(fraghdr) * 4; + copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len); + + /* Update the bitmap. */ + if (offset / (8 * 8) == (offset + len) / (8 * 8)) { + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: updating single byte in bitmap.\n")); + /* If the two endpoints are in the same byte, we only update that byte. */ + LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)", + offset / (8 * 8) < sizeof(ip_reassbitmap)); + ip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8) & 7] & + ~bitmap_bits[((offset + len) / 8) & 7]; + } else { + /* If the two endpoints are in different bytes, we update the + bytes in the endpoints and fill the stuff inbetween with + 0xff. */ + LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)", + offset / (8 * 8) < sizeof(ip_reassbitmap)); + ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7]; + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\n", + 1 + offset / (8 * 8), (offset + len) / (8 * 8))); + for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { + ip_reassbitmap[i] = 0xff; + } + LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)", + (offset + len) / (8 * 8) < sizeof(ip_reassbitmap)); + ip_reassbitmap[(offset + len) / (8 * 8)] |= + ~bitmap_bits[((offset + len) / 8) & 7]; + } + + /* If this fragment has the More Fragments flag set to zero, we + know that this is the last fragment, so we can calculate the + size of the entire packet. We also set the + IP_REASS_FLAG_LASTFRAG flag to indicate that we have received + the final fragment. */ + + if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) { + ip_reassflags |= IP_REASS_FLAG_LASTFRAG; + ip_reasslen = offset + len; + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: last fragment seen, total len %"S16_F"\n", + ip_reasslen)); + } + + /* Finally, we check if we have a full packet in the buffer. We do + this by checking if we have the last fragment and if all bits + in the bitmap are set. */ + if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) { + /* Check all bytes up to and including all but the last byte in + the bitmap. */ + LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)", + ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)); + for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) { + if (ip_reassbitmap[i] != 0xff) { + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\n", + i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i])); + goto nullreturn; + } + } + /* Check the last byte in the bitmap. It should contain just the + right amount of bits. */ + LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)", + ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)); + if (ip_reassbitmap[ip_reasslen / (8 * 8)] != + (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) { + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\n", + ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7], + ip_reassbitmap[ip_reasslen / (8 * 8)])); + goto nullreturn; + } + + /* Pretend to be a "normal" (i.e., not fragmented) IP packet + from now on. */ + ip_reasslen += IP_HLEN; + + IPH_LEN_SET(iphdr, htons(ip_reasslen)); + IPH_OFFSET_SET(iphdr, 0); + IPH_CHKSUM_SET(iphdr, 0); + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + + /* If we have come this far, we have a full packet in the + buffer, so we allocate a pbuf and copy the packet into it. We + also reset the timer. */ + ip_reasstmr = 0; + pbuf_free(p); + p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL); + if (p != NULL) { + i = 0; + for (q = p; q != NULL; q = q->next) { + /* Copy enough bytes to fill this pbuf in the chain. The + available data in the pbuf is given by the q->len variable. */ + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n", + (void *)&ip_reassbuf[i], i, q->payload, + q->len > ip_reasslen - i ? ip_reasslen - i : q->len)); + memcpy(q->payload, &ip_reassbuf[i], + q->len > ip_reasslen - i ? ip_reasslen - i : q->len); + i += q->len; + } + IPFRAG_STATS_INC(ip_frag.fw); + } else { + IPFRAG_STATS_INC(ip_frag.memerr); + } + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p)); + return p; + } + } + +nullreturn: + IPFRAG_STATS_INC(ip_frag.drop); + pbuf_free(p); + return NULL; +} + +#define MAX_MTU 1500 +static u8_t buf[MEM_ALIGN_SIZE(MAX_MTU)]; + +/** + * Fragment an IP datagram if too large for the netif. + * + * Chop the datagram in MTU sized chunks and send them in order + * by using a fixed size static memory buffer (PBUF_ROM) + */ +err_t +ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) +{ + struct pbuf *rambuf; + struct pbuf *header; + struct ip_hdr *iphdr; + u16_t nfb = 0; + u16_t left, cop; + u16_t mtu = netif->mtu; + u16_t ofo, omf; + u16_t last; + u16_t poff = IP_HLEN; + u16_t tmp; + + /* Get a RAM based MTU sized pbuf */ + rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); + if (rambuf == NULL) { + return ERR_MEM; + } + rambuf->tot_len = rambuf->len = mtu; + rambuf->payload = MEM_ALIGN((void *)buf); + + /* Copy the IP header in it */ + iphdr = rambuf->payload; + memcpy(iphdr, p->payload, IP_HLEN); + + /* Save original offset */ + tmp = ntohs(IPH_OFFSET(iphdr)); + ofo = tmp & IP_OFFMASK; + omf = tmp & IP_MF; + + left = p->tot_len - IP_HLEN; + + while (left) { + last = (left <= mtu - IP_HLEN); + + /* Set new offset and MF flag */ + ofo += nfb; + tmp = omf | (IP_OFFMASK & (ofo)); + if (!last) + tmp = tmp | IP_MF; + IPH_OFFSET_SET(iphdr, htons(tmp)); + + /* Fill this fragment */ + nfb = (mtu - IP_HLEN) / 8; + cop = last ? left : nfb * 8; + + p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop); + + /* Correct header */ + IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); + IPH_CHKSUM_SET(iphdr, 0); + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + + if (last) + pbuf_realloc(rambuf, left + IP_HLEN); + /* This part is ugly: we alloc a RAM based pbuf for + * the link level header for each chunk and then + * free it.A PBUF_ROM style pbuf for which pbuf_header + * worked would make things simpler. + */ + header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); + if (header != NULL) { + pbuf_chain(header, rambuf); + netif->output(netif, header, dest); + IPFRAG_STATS_INC(ip_frag.xmit); + pbuf_free(header); + } else { + pbuf_free(rambuf); + return ERR_MEM; + } + left -= cop; + } + pbuf_free(rambuf); + return ERR_OK; +} diff --git a/wii/libogc/lwip/core/mem.c b/wii/libogc/lwip/core/mem.c new file mode 100644 index 0000000000..ffe3f57c39 --- /dev/null +++ b/wii/libogc/lwip/core/mem.c @@ -0,0 +1,310 @@ +/** @file + * + * Dynamic memory manager + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include + +#include "lwip/arch.h" +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" + +#include "lwip/sys.h" + +#include "lwip/stats.h" + +struct mem { + mem_size_t next, prev; +#if MEM_ALIGNMENT == 1 + u8_t used; +#elif MEM_ALIGNMENT == 2 + u16_t used; +#elif MEM_ALIGNMENT == 4 + u32_t used; +#elif MEM_ALIGNMENT == 8 + u64_t used; +#else +#error "unhandled MEM_ALIGNMENT size" +#endif /* MEM_ALIGNMENT */ +}; + +static struct mem *ram_end; +static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT]; + +#define MIN_SIZE 12 +#if 0 /* this one does not align correctly for some, resulting in crashes */ +#define SIZEOF_STRUCT_MEM (unsigned int)MEM_ALIGN_SIZE(sizeof(struct mem)) +#else +#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \ + (((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \ + (4 - (sizeof(struct mem) % MEM_ALIGNMENT)))) +#endif + +static struct mem *lfree; /* pointer to the lowest free block */ + +static sys_sem mem_sem; + +static void +plug_holes(struct mem *mem) +{ + struct mem *nmem; + struct mem *pmem; + + LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); + LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); + LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); + + /* plug hole forward */ + LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE); + + nmem = (struct mem *)&ram[mem->next]; + if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { + if (lfree == nmem) { + lfree = mem; + } + mem->next = nmem->next; + ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram; + } + + /* plug hole backward */ + pmem = (struct mem *)&ram[mem->prev]; + if (pmem != mem && pmem->used == 0) { + if (lfree == mem) { + lfree = pmem; + } + pmem->next = mem->next; + ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram; + } + +} +void +mem_init(void) +{ + struct mem *mem; + + memset(ram, 0, MEM_SIZE); + mem = (struct mem *)ram; + mem->next = MEM_SIZE; + mem->prev = 0; + mem->used = 0; + ram_end = (struct mem *)&ram[MEM_SIZE]; + ram_end->used = 1; + ram_end->next = MEM_SIZE; + ram_end->prev = MEM_SIZE; + + LWP_SemInit(&mem_sem,1,1); + + lfree = (struct mem *)ram; + +#if MEM_STATS + lwip_stats.mem.avail = MEM_SIZE; +#endif /* MEM_STATS */ +} +void +mem_free(void *rmem) +{ + struct mem *mem; + + if (rmem == NULL) { + LWIP_DEBUGF(MEM_DEBUG | DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n")); + return; + } + + LWP_SemWait(mem_sem); + + LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && + (u8_t *)rmem < (u8_t *)ram_end); + + if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n")); +#if MEM_STATS + ++lwip_stats.mem.err; +#endif /* MEM_STATS */ + LWP_SemPost(mem_sem); + return; + } + mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + + LWIP_ASSERT("mem_free: mem->used", mem->used); + + mem->used = 0; + + if (mem < lfree) { + lfree = mem; + } + +#if MEM_STATS + lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram); + +#endif /* MEM_STATS */ + plug_holes(mem); + LWP_SemPost(mem_sem); +} +void * +mem_reallocm(void *rmem, mem_size_t newsize) +{ + void *nmem; + nmem = mem_malloc(newsize); + if (nmem == NULL) { + return mem_realloc(rmem, newsize); + } + memcpy(nmem, rmem, newsize); + mem_free(rmem); + return nmem; +} + +void * +mem_realloc(void *rmem, mem_size_t newsize) +{ + mem_size_t size; + mem_size_t ptr, ptr2; + struct mem *mem, *mem2; + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + if ((newsize % MEM_ALIGNMENT) != 0) { + newsize += MEM_ALIGNMENT - ((newsize + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT); + } + + if (newsize > MEM_SIZE) { + return NULL; + } + + LWP_SemWait(mem_sem); + + LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram && + (u8_t *)rmem < (u8_t *)ram_end); + + if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n")); + return rmem; + } + mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + + ptr = (u8_t *)mem - ram; + + size = mem->next - ptr - SIZEOF_STRUCT_MEM; +#if MEM_STATS + lwip_stats.mem.used -= (size - newsize); +#endif /* MEM_STATS */ + + if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) { + ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; + mem2 = (struct mem *)&ram[ptr2]; + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + mem->next = ptr2; + if (mem2->next != MEM_SIZE) { + ((struct mem *)&ram[mem2->next])->prev = ptr2; + } + + plug_holes(mem2); + } + LWP_SemPost(mem_sem); + return rmem; +} +void * +mem_malloc(mem_size_t size) +{ + mem_size_t ptr, ptr2; + struct mem *mem, *mem2; + + if (size == 0) { + return NULL; + } + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + if ((size % MEM_ALIGNMENT) != 0) { + size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT); + } + + if (size > MEM_SIZE) { + return NULL; + } + + LWP_SemWait(mem_sem); + + for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) { + mem = (struct mem *)&ram[ptr]; + if (!mem->used && + mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) { + ptr2 = ptr + SIZEOF_STRUCT_MEM + size; + mem2 = (struct mem *)&ram[ptr2]; + + mem2->prev = ptr; + mem2->next = mem->next; + mem->next = ptr2; + if (mem2->next != MEM_SIZE) { + ((struct mem *)&ram[mem2->next])->prev = ptr2; + } + + mem2->used = 0; + mem->used = 1; +#if MEM_STATS + lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM); + /* if (lwip_stats.mem.max < lwip_stats.mem.used) { + lwip_stats.mem.max = lwip_stats.mem.used; + } */ + if (lwip_stats.mem.max < ptr2) { + lwip_stats.mem.max = ptr2; + } +#endif /* MEM_STATS */ + + if (mem == lfree) { + /* Find next free block after mem */ + while (lfree->used && lfree != ram_end) { + lfree = (struct mem *)&ram[lfree->next]; + } + LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used); + } + LWP_SemPost(mem_sem); + LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", + (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); + LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", + (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); + return (u8_t *)mem + SIZEOF_STRUCT_MEM; + } + } + LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); +#if MEM_STATS + ++lwip_stats.mem.err; +#endif /* MEM_STATS */ + LWP_SemPost(mem_sem); + return NULL; +} diff --git a/wii/libogc/lwip/core/memp.c b/wii/libogc/lwip/core/memp.c new file mode 100644 index 0000000000..3f5ca97727 --- /dev/null +++ b/wii/libogc/lwip/core/memp.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/memp.h" + +#include "lwip/pbuf.h" +#include "lwip/udp.h" +#include "lwip/raw.h" +#include "lwip/tcp.h" +#include "lwip/api.h" +#include "lwip/api_msg.h" +#include "lwip/tcpip.h" + +#include "lwip/sys.h" +#include "lwip/stats.h" + +struct memp { + struct memp *next; +}; + + + +static struct memp *memp_tab[MEMP_MAX]; + +static const u16_t memp_sizes[MEMP_MAX] = { + sizeof(struct pbuf), + sizeof(struct raw_pcb), + sizeof(struct udp_pcb), + sizeof(struct tcp_pcb), + sizeof(struct tcp_pcb_listen), + sizeof(struct tcp_seg), + sizeof(struct netbuf), + sizeof(struct netconn), + sizeof(struct api_msg), + sizeof(struct net_msg), + sizeof(struct sys_timeout) +}; + +static const u16_t memp_num[MEMP_MAX] = { + MEMP_NUM_PBUF, + MEMP_NUM_RAW_PCB, + MEMP_NUM_UDP_PCB, + MEMP_NUM_TCP_PCB, + MEMP_NUM_TCP_PCB_LISTEN, + MEMP_NUM_TCP_SEG, + MEMP_NUM_NETBUF, + MEMP_NUM_NETCONN, + MEMP_NUM_API_MSG, + MEMP_NUM_TCPIP_MSG, + MEMP_NUM_SYS_TIMEOUT +}; + +static u8_t memp_memory[(MEMP_NUM_PBUF * + MEM_ALIGN_SIZE(sizeof(struct pbuf) + + sizeof(struct memp)) + + MEMP_NUM_RAW_PCB * + MEM_ALIGN_SIZE(sizeof(struct raw_pcb) + + sizeof(struct memp)) + + MEMP_NUM_UDP_PCB * + MEM_ALIGN_SIZE(sizeof(struct udp_pcb) + + sizeof(struct memp)) + + MEMP_NUM_TCP_PCB * + MEM_ALIGN_SIZE(sizeof(struct tcp_pcb) + + sizeof(struct memp)) + + MEMP_NUM_TCP_PCB_LISTEN * + MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen) + + sizeof(struct memp)) + + MEMP_NUM_TCP_SEG * + MEM_ALIGN_SIZE(sizeof(struct tcp_seg) + + sizeof(struct memp)) + + MEMP_NUM_NETBUF * + MEM_ALIGN_SIZE(sizeof(struct netbuf) + + sizeof(struct memp)) + + MEMP_NUM_NETCONN * + MEM_ALIGN_SIZE(sizeof(struct netconn) + + sizeof(struct memp)) + + MEMP_NUM_API_MSG * + MEM_ALIGN_SIZE(sizeof(struct api_msg) + + sizeof(struct memp)) + + MEMP_NUM_TCPIP_MSG * + MEM_ALIGN_SIZE(sizeof(struct net_msg) + + sizeof(struct memp)) + + MEMP_NUM_SYS_TIMEOUT * + MEM_ALIGN_SIZE(sizeof(struct sys_timeout) + + sizeof(struct memp)))]; + + +#if !SYS_LIGHTWEIGHT_PROT +static sys_sem mutex; +#endif + +#if MEMP_SANITY_CHECK +static int +memp_sanity(void) +{ + s16_t i, c; + struct memp *m, *n; + + for(i = 0; i < MEMP_MAX; i++) { + for(m = memp_tab[i]; m != NULL; m = m->next) { + c = 1; + for(n = memp_tab[i]; n != NULL; n = n->next) { + if (n == m) { + --c; + } + if (c < 0) return 0; /* LW was: abort(); */ + } + } + } + return 1; +} +#endif /* MEMP_SANITY_CHECK*/ + +void +memp_init(void) +{ + struct memp *m, *memp; + u16_t i, j; + u16_t size; + +#if MEMP_STATS + for(i = 0; i < MEMP_MAX; ++i) { + lwip_stats.memp[i].used = lwip_stats.memp[i].max = + lwip_stats.memp[i].err = 0; + lwip_stats.memp[i].avail = memp_num[i]; + } +#endif /* MEMP_STATS */ + + memp = (struct memp *)&memp_memory[0]; + for(i = 0; i < MEMP_MAX; ++i) { + size = MEM_ALIGN_SIZE(memp_sizes[i] + sizeof(struct memp)); + if (memp_num[i] > 0) { + memp_tab[i] = memp; + m = memp; + + for(j = 0; j < memp_num[i]; ++j) { + m->next = (struct memp *)MEM_ALIGN((u8_t *)m + size); + memp = m; + m = m->next; + } + memp->next = NULL; + memp = m; + } else { + memp_tab[i] = NULL; + } + } + +#if !SYS_LIGHTWEIGHT_PROT + LWP_SemInit(&mutex,1,1); +#endif + + +} + +void * +memp_malloc(memp_t type) +{ + struct memp *memp; + void *mem; +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_DECL_PROTECT(old_level); +#endif + + LWIP_ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX); + +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_PROTECT(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ + LWP_SemWait(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ + + memp = memp_tab[type]; + if (memp != NULL) { + memp_tab[type] = memp->next; + memp->next = NULL; +#if MEMP_STATS + ++lwip_stats.memp[type].used; + if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) { + lwip_stats.memp[type].max = lwip_stats.memp[type].used; + } +#endif /* MEMP_STATS */ +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_UNPROTECT(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ + LWP_SemPost(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ + LWIP_ASSERT("memp_malloc: memp properly aligned", + ((mem_ptr_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0); + + mem = MEM_ALIGN((u8_t *)memp + sizeof(struct memp)); + return mem; + } else { + LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %"S16_F"\n", type)); +#if MEMP_STATS + ++lwip_stats.memp[type].err; +#endif /* MEMP_STATS */ +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_UNPROTECT(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ + LWP_SemPost(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ + return NULL; + } +} + +void +memp_free(memp_t type, void *mem) +{ + struct memp *memp; +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_DECL_PROTECT(old_level); +#endif /* SYS_LIGHTWEIGHT_PROT */ + + if (mem == NULL) { + return; + } + memp = (struct memp *)((u8_t *)mem - sizeof(struct memp)); + +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_PROTECT(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ + LWP_SemWait(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#if MEMP_STATS + lwip_stats.memp[type].used--; +#endif /* MEMP_STATS */ + + memp->next = memp_tab[type]; + memp_tab[type] = memp; + +#if MEMP_SANITY_CHECK + LWIP_ASSERT("memp sanity", memp_sanity()); +#endif + +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_UNPROTECT(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ + LWP_SemPost(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ +} + diff --git a/wii/libogc/lwip/core/netif.c b/wii/libogc/lwip/core/netif.c new file mode 100644 index 0000000000..3525089b2f --- /dev/null +++ b/wii/libogc/lwip/core/netif.c @@ -0,0 +1,288 @@ +/** + * @file + * + * lwIP network interface abstraction + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/tcp.h" + +struct netif *netif_list = NULL; +struct netif *netif_default = NULL; + +/** + * Add a network interface to the list of lwIP netifs. + * + * @param netif a pre-allocated netif structure + * @param ipaddr IP address for the new netif + * @param netmask network mask for the new netif + * @param gw default gateway IP address for the new netif + * @param state opaque data passed to the new netif + * @param init callback function that initializes the interface + * @param input callback function that is called to pass + * ingress packets up in the protocol layer stack. + * + * @return netif, or NULL if failed. + */ +struct netif * +netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, + struct ip_addr *gw, + void *state, + err_t (* init)(struct netif *netif), + err_t (* input)(struct pbuf *p, struct netif *netif)) +{ + static s16_t netifnum = 0; + +#if LWIP_DHCP + /* netif not under DHCP control by default */ + netif->dhcp = NULL; +#endif + /* remember netif specific state information data */ + netif->state = state; + netif->num = netifnum++; + netif->input = input; + + netif_set_addr(netif, ipaddr, netmask, gw); + + /* call user specified initialization function for netif */ + if (init(netif) != ERR_OK) { + return NULL; + } + + /* add this netif to the list */ + netif->next = netif_list; + netif_list = netif; + LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", + netif->name[0], netif->name[1])); + ip_addr_debug_print(NETIF_DEBUG, ipaddr); + LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); + ip_addr_debug_print(NETIF_DEBUG, netmask); + LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); + ip_addr_debug_print(NETIF_DEBUG, gw); + LWIP_DEBUGF(NETIF_DEBUG, ("\n")); + return netif; +} + +void +netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask, + struct ip_addr *gw) +{ + netif_set_ipaddr(netif, ipaddr); + netif_set_netmask(netif, netmask); + netif_set_gw(netif, gw); +} + +void netif_remove(struct netif * netif) +{ + if ( netif == NULL ) return; + + /* is it the first netif? */ + if (netif_list == netif) { + netif_list = netif->next; + } + else { + /* look for netif further down the list */ + struct netif * tmpNetif; + for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { + if (tmpNetif->next == netif) { + tmpNetif->next = netif->next; + break; + } + } + if (tmpNetif == NULL) + return; /* we didn't find any netif today */ + } + /* this netif is default? */ + if (netif_default == netif) + /* reset default netif */ + netif_default = NULL; + LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); +} + +struct netif * +netif_find(char *name) +{ + struct netif *netif; + u8_t num; + + if (name == NULL) { + return NULL; + } + + num = name[2] - '0'; + + for(netif = netif_list; netif != NULL; netif = netif->next) { + if (num == netif->num && + name[0] == netif->name[0] && + name[1] == netif->name[1]) { + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); + return netif; + } + } + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); + return NULL; +} + +void +netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) +{ + /* TODO: Handling of obsolete pcbs */ + /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ +#if LWIP_TCP + struct tcp_pcb *pcb; + struct tcp_pcb_listen *lpcb; + + /* address is actually being changed? */ + if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) + { + /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ + LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n")); + pcb = tcp_active_pcbs; + while (pcb != NULL) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { + /* this connection must be aborted */ + struct tcp_pcb *next = pcb->next; + LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); + tcp_abort(pcb); + pcb = next; + } else { + pcb = pcb->next; + } + } + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr))) { + /* The PCB is listening to the old ipaddr and + * is set to listen to the new one instead */ + ip_addr_set(&(lpcb->local_ip), ipaddr); + } + } + } +#endif + ip_addr_set(&(netif->ip_addr), ipaddr); +#if 0 /* only allowed for Ethernet interfaces TODO: how can we check? */ + /** For Ethernet network interfaces, we would like to send a + * "gratuitous ARP"; this is an ARP packet sent by a node in order + * to spontaneously cause other nodes to update an entry in their + * ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6. + */ + etharp_query(netif, ipaddr, NULL); +#endif + LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1(&netif->ip_addr), + ip4_addr2(&netif->ip_addr), + ip4_addr3(&netif->ip_addr), + ip4_addr4(&netif->ip_addr))); +} + +void +netif_set_gw(struct netif *netif, struct ip_addr *gw) +{ + ip_addr_set(&(netif->gw), gw); + LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1(&netif->gw), + ip4_addr2(&netif->gw), + ip4_addr3(&netif->gw), + ip4_addr4(&netif->gw))); +} + +void +netif_set_netmask(struct netif *netif, struct ip_addr *netmask) +{ + ip_addr_set(&(netif->netmask), netmask); + LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1(&netif->netmask), + ip4_addr2(&netif->netmask), + ip4_addr3(&netif->netmask), + ip4_addr4(&netif->netmask))); +} + +void +netif_set_default(struct netif *netif) +{ + netif_default = netif; + LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", + netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); +} + +/** + * Bring an interface up, available for processing + * traffic. + * + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + * + * @see dhcp_start() + */ +void netif_set_up(struct netif *netif) +{ + netif->flags |= NETIF_FLAG_UP; +} + +/** + * Ask if an interface is up + */ +u8_t netif_is_up(struct netif *netif) +{ + return (netif->flags & NETIF_FLAG_UP)?1:0; +} + +/** + * Bring an interface down, disabling any traffic processing. + * + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + * + * @see dhcp_start() + */ +void netif_set_down(struct netif *netif) +{ + netif->flags &= ~NETIF_FLAG_UP; +} + +void +netif_init(void) +{ + netif_list = netif_default = NULL; +} + diff --git a/wii/libogc/lwip/core/pbuf.c b/wii/libogc/lwip/core/pbuf.c new file mode 100644 index 0000000000..471e6efb7a --- /dev/null +++ b/wii/libogc/lwip/core/pbuf.c @@ -0,0 +1,957 @@ +/** + * @file + * Packet buffer management + * + * Packets are built from the pbuf data structure. It supports dynamic + * memory allocation for packet contents or can reference externally + * managed packet contents both in RAM and ROM. Quick allocation for + * incoming packets is provided through pools with fixed sized pbufs. + * + * A packet may span over multiple pbufs, chained as a singly linked + * list. This is called a "pbuf chain". + * + * Multiple packets may be queued, also using this singly linked list. + * This is called a "packet queue". + * + * So, a packet queue consists of one or more pbuf chains, each of + * which consist of one or more pbufs. Currently, queues are only + * supported in a limited section of lwIP, this is the etharp queueing + * code. Outside of this section no packet queues are supported yet. + * + * The differences between a pbuf chain and a packet queue are very + * precise but subtle. + * + * The last pbuf of a packet has a ->tot_len field that equals the + * ->len field. It can be found by traversing the list. If the last + * pbuf of a packet has a ->next field other than NULL, more packets + * are on the queue. + * + * Therefore, looping through a pbuf of a single packet, has an + * loop end condition (tot_len == p->len), NOT (next == NULL). + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include + +#include "lwip/opt.h" +#include "lwip/stats.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "arch/perf.h" + +static u8_t pbuf_pool_memory[MEM_ALIGNMENT - 1 + PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf))]; + +#if !SYS_LIGHTWEIGHT_PROT +static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock; +static sys_sem pbuf_pool_free_sem; +#endif + +static struct pbuf *pbuf_pool = NULL; + +/** + * Initializes the pbuf module. + * + * A large part of memory is allocated for holding the pool of pbufs. + * The size of the individual pbufs in the pool is given by the size + * parameter, and the number of pbufs in the pool by the num parameter. + * + * After the memory has been allocated, the pbufs are set up. The + * ->next pointer in each pbuf is set up to point to the next pbuf in + * the pool. + * + */ +void +pbuf_init(void) +{ + struct pbuf *p, *q = NULL; + u16_t i; + + pbuf_pool = (struct pbuf *)MEM_ALIGN(pbuf_pool_memory); + +#if PBUF_STATS + lwip_stats.pbuf.avail = PBUF_POOL_SIZE; +#endif /* PBUF_STATS */ + + /* Set up ->next pointers to link the pbufs of the pool together */ + p = pbuf_pool; + + for(i = 0; i < PBUF_POOL_SIZE; ++i) { + p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf)); + p->len = p->tot_len = PBUF_POOL_BUFSIZE; + p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf))); + p->flags = PBUF_FLAG_POOL; + q = p; + p = p->next; + } + + /* The ->next pointer of last pbuf is NULL to indicate that there + are no more pbufs in the pool */ + q->next = NULL; + +#if !SYS_LIGHTWEIGHT_PROT + pbuf_pool_alloc_lock = 0; + pbuf_pool_free_lock = 0; + LWP_SemInit(&pbuf_pool_free_sem,1,1); +#endif +} + +/** + * @internal only called from pbuf_alloc() + */ +static struct pbuf * +pbuf_pool_alloc(void) +{ + struct pbuf *p = NULL; + + SYS_ARCH_DECL_PROTECT(old_level); + SYS_ARCH_PROTECT(old_level); + +#if !SYS_LIGHTWEIGHT_PROT + /* Next, check the actual pbuf pool, but if the pool is locked, we + pretend to be out of buffers and return NULL. */ + if (pbuf_pool_free_lock) { +#if PBUF_STATS + ++lwip_stats.pbuf.alloc_locked; +#endif /* PBUF_STATS */ + return NULL; + } + pbuf_pool_alloc_lock = 1; + if (!pbuf_pool_free_lock) { +#endif /* SYS_LIGHTWEIGHT_PROT */ + p = pbuf_pool; + if (p) { + pbuf_pool = p->next; + } +#if !SYS_LIGHTWEIGHT_PROT +#if PBUF_STATS + } else { + ++lwip_stats.pbuf.alloc_locked; +#endif /* PBUF_STATS */ + } + pbuf_pool_alloc_lock = 0; +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#if PBUF_STATS + if (p != NULL) { + ++lwip_stats.pbuf.used; + if (lwip_stats.pbuf.used > lwip_stats.pbuf.max) { + lwip_stats.pbuf.max = lwip_stats.pbuf.used; + } + } +#endif /* PBUF_STATS */ + + SYS_ARCH_UNPROTECT(old_level); + return p; +} + + +/** + * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param flag this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_RAM: buffer memory for pbuf is allocated as one large + * chunk. This includes protocol headers as well. + * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for + * protocol headers. Additional headers must be prepended + * by allocating another pbuf and chain in to the front of + * the ROM pbuf. It is assumed that the memory used is really + * similar to ROM in that it is immutable and will not be + * changed. Memory which is dynamic should generally not + * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: no buffer memory is allocated for the pbuf, even for + * protocol headers. It is assumed that the pbuf is only + * being used in a single thread. If the pbuf gets queued, + * then pbuf_take should be called to copy the buffer. + * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from + * the pbuf pool that is allocated during pbuf_init(). + * + * @return the allocated pbuf. If multiple pbufs where allocated, this + * is the first pbuf of a pbuf chain. + */ +struct pbuf * +pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag) +{ + struct pbuf *p, *q, *r; + u16_t offset; + s32_t rem_len; /* remaining length */ + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length)); + + /* determine header offset */ + offset = 0; + switch (l) { + case PBUF_TRANSPORT: + /* add room for transport (often TCP) layer header */ + offset += PBUF_TRANSPORT_HLEN; + /* FALLTHROUGH */ + case PBUF_IP: + /* add room for IP layer header */ + offset += PBUF_IP_HLEN; + /* FALLTHROUGH */ + case PBUF_LINK: + /* add room for link layer header */ + offset += PBUF_LINK_HLEN; + break; + case PBUF_RAW: + break; + default: + LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); + return NULL; + } + + switch (flag) { + case PBUF_POOL: + /* allocate head of pbuf chain into p */ + p = pbuf_pool_alloc(); + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); + if (p == NULL) { +#if PBUF_STATS + ++lwip_stats.pbuf.err; +#endif /* PBUF_STATS */ + return NULL; + } + p->next = NULL; + + /* make the payload pointer point 'offset' bytes into pbuf data memory */ + p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); + LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + /* the total length of the pbuf chain is the requested size */ + p->tot_len = length; + /* set the length of the first pbuf in the chain */ + p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length; + /* set reference count (needed here in case we fail) */ + p->ref = 1; + + /* now allocate the tail of the pbuf chain */ + + /* remember first pbuf for linkage in next iteration */ + r = p; + /* remaining length to be allocated */ + rem_len = length - p->len; + /* any remaining pbufs to be allocated? */ + while (rem_len > 0) { + q = pbuf_pool_alloc(); + if (q == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n")); +#if PBUF_STATS + ++lwip_stats.pbuf.err; +#endif /* PBUF_STATS */ + /* free chain so far allocated */ + pbuf_free(p); + /* bail out unsuccesfully */ + return NULL; + } + q->next = NULL; + /* make previous pbuf point to this pbuf */ + r->next = q; + /* set total length of this pbuf and next in chain */ + q->tot_len = rem_len; + /* this pbuf length is pool size, unless smaller sized tail */ + q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len; + q->payload = (void *)((u8_t *)q + sizeof(struct pbuf)); + LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", + ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); + q->ref = 1; + /* calculate remaining length to be allocated */ + rem_len -= q->len; + /* remember this pbuf for linkage in next iteration */ + r = q; + } + /* end of chain */ + /*r->next = NULL;*/ + + break; + case PBUF_RAM: + /* If pbuf is to be allocated in RAM, allocate memory for it. */ + p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length)); + if (p == NULL) { + return NULL; + } + /* Set up internal structure of the pbuf. */ + p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset)); + p->len = p->tot_len = length; + p->next = NULL; + p->flags = PBUF_FLAG_RAM; + + LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + break; + /* pbuf references existing (non-volatile static constant) ROM payload? */ + case PBUF_ROM: + /* pbuf references existing (externally allocated) RAM payload? */ + case PBUF_REF: + /* only allocate memory for the pbuf structure */ + p = memp_malloc(MEMP_PBUF); + if (p == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", flag == PBUF_ROM?"ROM":"REF")); + return NULL; + } + /* caller must set this field properly, afterwards */ + p->payload = NULL; + p->len = p->tot_len = length; + p->next = NULL; + p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF); + break; + default: + LWIP_ASSERT("pbuf_alloc: erroneous flag", 0); + return NULL; + } + /* set reference count */ + p->ref = 1; + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); + return p; +} + + +#if PBUF_STATS +#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0) +#else /* PBUF_STATS */ +#define DEC_PBUF_STATS +#endif /* PBUF_STATS */ + +#define PBUF_POOL_FAST_FREE(p) do { \ + p->next = pbuf_pool; \ + pbuf_pool = p; \ + DEC_PBUF_STATS; \ + } while (0) + +#if SYS_LIGHTWEIGHT_PROT +#define PBUF_POOL_FREE(p) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + PBUF_POOL_FAST_FREE(p); \ + SYS_ARCH_UNPROTECT(old_level); \ + } while (0) +#else /* SYS_LIGHTWEIGHT_PROT */ +#define PBUF_POOL_FREE(p) do { \ + LWP_SemWait(pbuf_pool_free_sem); \ + PBUF_POOL_FAST_FREE(p); \ + LWP_SemPost(pbuf_pool_free_sem); \ + } while (0) +#endif /* SYS_LIGHTWEIGHT_PROT */ + +/** + * Shrink a pbuf chain to a desired length. + * + * @param p pbuf to shrink. + * @param new_len desired new length of pbuf chain + * + * Depending on the desired length, the first few pbufs in a chain might + * be skipped and left unchanged. The new last pbuf in the chain will be + * resized, and any remaining pbufs will be freed. + * + * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. + * @note May not be called on a packet queue. + * + * @bug Cannot grow the size of a pbuf (chain) (yet). + */ +void +pbuf_realloc(struct pbuf *p, u16_t new_len) +{ + struct pbuf *q; + u16_t rem_len; /* remaining length */ + s16_t grow; + + LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL || + p->flags == PBUF_FLAG_ROM || + p->flags == PBUF_FLAG_RAM || + p->flags == PBUF_FLAG_REF); + + /* desired length larger than current length? */ + if (new_len >= p->tot_len) { + /* enlarging not yet supported */ + return; + } + + /* the pbuf chain grows by (new_len - p->tot_len) bytes + * (which may be negative in case of shrinking) */ + grow = new_len - p->tot_len; + + /* first, step over any pbufs that should remain in the chain */ + rem_len = new_len; + q = p; + /* should this pbuf be kept? */ + while (rem_len > q->len) { + /* decrease remaining length by pbuf length */ + rem_len -= q->len; + /* decrease total length indicator */ + q->tot_len += grow; + /* proceed to next pbuf in chain */ + q = q->next; + } + /* we have now reached the new last pbuf (in q) */ + /* rem_len == desired length for pbuf q */ + + /* shrink allocated memory for PBUF_RAM */ + /* (other types merely adjust their length fields */ + if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) { + /* reallocate and adjust the length of the pbuf that will be split */ + mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len); + } + /* adjust length fields for new last pbuf */ + q->len = rem_len; + q->tot_len = q->len; + + /* any remaining pbufs in chain? */ + if (q->next != NULL) { + /* free remaining pbufs in chain */ + pbuf_free(q->next); + } + /* q is last packet in chain */ + q->next = NULL; + +} + +/** + * Adjusts the payload pointer to hide or reveal headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * (dis)appears in the pbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param hdr_size_inc Number of bytes to increment header size which + * increases the size of the pbuf. New space is on the front. + * (Using a negative value decreases the header size.) + * If hdr_size_inc is 0, this function does nothing and returns succesful. + * + * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so + * the call will fail. A check is made that the increase in header size does + * not move the payload pointer in front of the start of the buffer. + * @return non-zero on failure, zero on success. + * + */ +u8_t +pbuf_header(struct pbuf *p, s16_t header_size_increment) +{ + void *payload; + + LWIP_ASSERT("p != NULL", p != NULL); + if ((header_size_increment == 0) || (p == NULL)) return 0; + + /* remember current payload pointer */ + payload = p->payload; + + /* pbuf types containing payloads? */ + if (p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_POOL) { + /* set new payload pointer */ + p->payload = (u8_t *)p->payload - header_size_increment; + /* boundary check fails? */ + if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) { + LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", + (void *)p->payload, + (void *)(p + 1)));\ + /* restore old payload pointer */ + p->payload = payload; + /* bail out unsuccesfully */ + return 1; + } + /* pbuf types refering to external payloads? */ + } else if (p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_ROM) { + /* hide a header in the payload? */ + if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) { + /* increase payload pointer */ + p->payload = (u8_t *)p->payload - header_size_increment; + } else { + /* cannot expand payload to front (yet!) + * bail out unsuccesfully */ + return 1; + } + } + /* modify pbuf length fields */ + p->len += header_size_increment; + p->tot_len += header_size_increment; + + LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n", + (void *)payload, (void *)p->payload, header_size_increment)); + + return 0; +} + +/** + * Dereference a pbuf chain or queue and deallocate any no-longer-used + * pbufs at the head of this chain or queue. + * + * Decrements the pbuf reference count. If it reaches zero, the pbuf is + * deallocated. + * + * For a pbuf chain, this is repeated for each pbuf in the chain, + * up to the first pbuf which has a non-zero reference count after + * decrementing. So, when all reference counts are one, the whole + * chain is free'd. + * + * @param pbuf The pbuf (chain) to be dereferenced. + * + * @return the number of pbufs that were de-allocated + * from the head of the chain. + * + * @note MUST NOT be called on a packet queue (Not verified to work yet). + * @note the reference counter of a pbuf equals the number of pointers + * that refer to the pbuf (or into the pbuf). + * + * @internal examples: + * + * Assuming existing chains a->b->c with the following reference + * counts, calling pbuf_free(a) results in: + * + * 1->2->3 becomes ...1->3 + * 3->3->3 becomes 2->3->3 + * 1->1->2 becomes ......1 + * 2->1->1 becomes 1->1->1 + * 1->1->1 becomes ....... + * + */ +u8_t +pbuf_free(struct pbuf *p) +{ + struct pbuf *q; + u8_t count; + SYS_ARCH_DECL_PROTECT(old_level); + + LWIP_ASSERT("p != NULL", p != NULL); + /* if assertions are disabled, proceed with debug output */ + if (p == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); + return 0; + } + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p)); + + PERF_START; + + LWIP_ASSERT("pbuf_free: sane flags", + p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM || + p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL); + + count = 0; + /* Since decrementing ref cannot be guaranteed to be a single machine operation + * we must protect it. Also, the later test of ref must be protected. + */ + SYS_ARCH_PROTECT(old_level); + /* de-allocate all consecutive pbufs from the head of the chain that + * obtain a zero reference count after decrementing*/ + while (p != NULL) { + /* all pbufs in a chain are referenced at least once */ + LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); + /* decrease reference count (number of pointers to pbuf) */ + p->ref--; + /* this pbuf is no longer referenced to? */ + if (p->ref == 0) { + /* remember next pbuf in chain for next iteration */ + q = p->next; + LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p)); + /* is this a pbuf from the pool? */ + if (p->flags == PBUF_FLAG_POOL) { + p->len = p->tot_len = PBUF_POOL_BUFSIZE; + p->payload = (void *)((u8_t *)p + sizeof(struct pbuf)); + PBUF_POOL_FREE(p); + /* is this a ROM or RAM referencing pbuf? */ + } else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) { + memp_free(MEMP_PBUF, p); + /* p->flags == PBUF_FLAG_RAM */ + } else { + mem_free(p); + } + count++; + /* proceed to next pbuf */ + p = q; + /* p->ref > 0, this pbuf is still referenced to */ + /* (and so the remaining pbufs in chain as well) */ + } else { + LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)p->ref)); + /* stop walking through the chain */ + p = NULL; + } + } + SYS_ARCH_UNPROTECT(old_level); + PERF_STOP("pbuf_free"); + /* return number of de-allocated pbufs */ + return count; +} + +/** + * Count number of pbufs in a chain + * + * @param p first pbuf of chain + * @return the number of pbufs in a chain + */ + +u8_t +pbuf_clen(struct pbuf *p) +{ + u8_t len; + + len = 0; + while (p != NULL) { + ++len; + p = p->next; + } + return len; +} + +/** + * Increment the reference count of the pbuf. + * + * @param p pbuf to increase reference counter of + * + */ +void +pbuf_ref(struct pbuf *p) +{ + SYS_ARCH_DECL_PROTECT(old_level); + /* pbuf given? */ + if (p != NULL) { + SYS_ARCH_PROTECT(old_level); + ++(p->ref); + SYS_ARCH_UNPROTECT(old_level); + } +} + +/** + * Concatenate two pbufs (each may be a pbuf chain) and take over + * the caller's reference of the tail pbuf. + * + * @note The caller MAY NOT reference the tail pbuf afterwards. + * Use pbuf_chain() for that purpose. + * + * @see pbuf_chain() + */ + +void +pbuf_cat(struct pbuf *h, struct pbuf *t) +{ + struct pbuf *p; + + LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL); + LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL); + if ((h == NULL) || (t == NULL)) return; + + /* proceed to last pbuf of chain */ + for (p = h; p->next != NULL; p = p->next) { + /* add total length of second chain to all totals of first chain */ + p->tot_len += t->tot_len; + } + /* { p is last pbuf of first h chain, p->next == NULL } */ + LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); + LWIP_ASSERT("p->next == NULL", p->next == NULL); + /* add total length of second chain to last pbuf total of first chain */ + p->tot_len += t->tot_len; + /* chain last pbuf of head (p) with first of tail (t) */ + p->next = t; + /* p->next now references t, but the caller will drop its reference to t, + * so netto there is no change to the reference count of t. + */ +} + +/** + * Chain two pbufs (or pbuf chains) together. + * + * The caller MUST call pbuf_free(t) once it has stopped + * using it. Use pbuf_cat() instead if you no longer use t. + * + * @param h head pbuf (chain) + * @param t tail pbuf (chain) + * @note The pbufs MUST belong to the same packet. + * @note MAY NOT be called on a packet queue. + * + * The ->tot_len fields of all pbufs of the head chain are adjusted. + * The ->next field of the last pbuf of the head chain is adjusted. + * The ->ref field of the first pbuf of the tail chain is adjusted. + * + */ +void +pbuf_chain(struct pbuf *h, struct pbuf *t) +{ + pbuf_cat(h, t); + /* t is now referenced by h */ + pbuf_ref(t); + LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); +} + +/* For packet queueing. Note that queued packets MUST be dequeued first + * using pbuf_dequeue() before calling other pbuf_() functions. */ +#if ARP_QUEUEING +/** + * Add a packet to the end of a queue. + * + * @param q pointer to first packet on the queue + * @param n packet to be queued + * + * Both packets MUST be given, and must be different. + */ +void +pbuf_queue(struct pbuf *p, struct pbuf *n) +{ +#if PBUF_DEBUG /* remember head of queue */ + struct pbuf *q = p; +#endif + /* programmer stupidity checks */ + LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL); + LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL); + LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n); + if ((p == NULL) || (n == NULL) || (p == n)){ + LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n")); + return; + } + + /* iterate through all packets on queue */ + while (p->next != NULL) { +/* be very picky about pbuf chain correctness */ +#if PBUF_DEBUG + /* iterate through all pbufs in packet */ + while (p->tot_len != p->len) { + /* make sure invariant condition holds */ + LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len); + /* make sure each packet is complete */ + LWIP_ASSERT("p->next != NULL", p->next != NULL); + p = p->next; + /* { p->tot_len == p->len => p is last pbuf of a packet } */ + } + /* { p is last pbuf of a packet } */ + /* proceed to next packet on queue */ +#endif + /* proceed to next pbuf */ + if (p->next != NULL) p = p->next; + } + /* { p->tot_len == p->len and p->next == NULL } ==> + * { p is last pbuf of last packet on queue } */ + /* chain last pbuf of queue with n */ + p->next = n; + /* n is now referenced to by the (packet p in the) queue */ + pbuf_ref(n); +#if PBUF_DEBUG + LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, + ("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n", + (void *)n, (void *)p, (void *)q)); +#endif +} + +/** + * Remove a packet from the head of a queue. + * + * The caller MUST reference the remainder of the queue (as returned). The + * caller MUST NOT call pbuf_ref() as it implicitly takes over the reference + * from p. + * + * @param p pointer to first packet on the queue which will be dequeued. + * @return first packet on the remaining queue (NULL if no further packets). + * + */ +struct pbuf * +pbuf_dequeue(struct pbuf *p) +{ + struct pbuf *q; + LWIP_ASSERT("p != NULL", p != NULL); + + /* iterate through all pbufs in packet p */ + while (p->tot_len != p->len) { + /* make sure invariant condition holds */ + LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len); + /* make sure each packet is complete */ + LWIP_ASSERT("p->next != NULL", p->next != NULL); + p = p->next; + } + /* { p->tot_len == p->len } => p is the last pbuf of the first packet */ + /* remember next packet on queue in q */ + q = p->next; + /* dequeue packet p from queue */ + p->next = NULL; + /* any next packet on queue? */ + if (q != NULL) { + /* although q is no longer referenced by p, it MUST be referenced by + * the caller, who is maintaining this packet queue. So, we do not call + * pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */ + LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q)); + } else { + LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n")); + } + return q; +} +#endif + +/** + * + * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs. + * + * Used to queue packets on behalf of the lwIP stack, such as + * ARP based queueing. + * + * Go through a pbuf chain and replace any PBUF_REF buffers + * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of + * the referenced data. + * + * @note You MUST explicitly use p = pbuf_take(p); + * The pbuf you give as argument, may have been replaced + * by a (differently located) copy through pbuf_take()! + * + * @note Any replaced pbufs will be freed through pbuf_free(). + * This may deallocate them if they become no longer referenced. + * + * @param p Head of pbuf chain to process + * + * @return Pointer to head of pbuf chain + */ +struct pbuf * +pbuf_take(struct pbuf *p) +{ + struct pbuf *q , *prev, *head; + LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL); + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p)); + + prev = NULL; + head = p; + /* iterate through pbuf chain */ + do + { + /* pbuf is of type PBUF_REF? */ + if (p->flags == PBUF_FLAG_REF) { + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p)); + /* allocate a pbuf (w/ payload) fully in RAM */ + /* PBUF_POOL buffers are faster if we can use them */ + if (p->len <= PBUF_POOL_BUFSIZE) { + q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL); + if (q == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n")); + } + } else { + /* no replacement pbuf yet */ + q = NULL; + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n")); + } + /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */ + if (q == NULL) { + q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM); + if (q == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n")); + } + } + /* replacement pbuf could be allocated? */ + if (q != NULL) + { + /* copy p to q */ + /* copy successor */ + q->next = p->next; + /* remove linkage from original pbuf */ + p->next = NULL; + /* remove linkage to original pbuf */ + if (prev != NULL) { + /* prev->next == p at this point */ + LWIP_ASSERT("prev->next == p", prev->next == p); + /* break chain and insert new pbuf instead */ + prev->next = q; + /* prev == NULL, so we replaced the head pbuf of the chain */ + } else { + head = q; + } + /* copy pbuf payload */ + memcpy(q->payload, p->payload, p->len); + q->tot_len = p->tot_len; + q->len = p->len; + /* in case p was the first pbuf, it is no longer refered to by + * our caller, as the caller MUST do p = pbuf_take(p); + * in case p was not the first pbuf, it is no longer refered to + * by prev. we can safely free the pbuf here. + * (note that we have set p->next to NULL already so that + * we will not free the rest of the chain by accident.) + */ + pbuf_free(p); + /* do not copy ref, since someone else might be using the old buffer */ + LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q)); + p = q; + } else { + /* deallocate chain */ + pbuf_free(head); + LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p)); + return NULL; + } + /* p->flags != PBUF_FLAG_REF */ + } else { + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n")); + } + /* remember this pbuf */ + prev = p; + /* proceed to next pbuf in original chain */ + p = p->next; + } while (p); + LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n")); + + return head; +} + +/** + * Dechains the first pbuf from its succeeding pbufs in the chain. + * + * Makes p->tot_len field equal to p->len. + * @param p pbuf to dechain + * @return remainder of the pbuf chain, or NULL if it was de-allocated. + * @note May not be called on a packet queue. + */ +struct pbuf * +pbuf_dechain(struct pbuf *p) +{ + struct pbuf *q; + u8_t tail_gone = 1; + /* tail */ + q = p->next; + /* pbuf has successor in chain? */ + if (q != NULL) { + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); + /* enforce invariant if assertion is disabled */ + q->tot_len = p->tot_len - p->len; + /* decouple pbuf from remainder */ + p->next = NULL; + /* total length of pbuf p is its own length only */ + p->tot_len = p->len; + /* q is no longer referenced by p, free it */ + LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); + tail_gone = pbuf_free(q); + if (tail_gone > 0) { + LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, + ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); + } + /* return remaining tail or NULL if deallocated */ + } + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); + return (tail_gone > 0? NULL: q); +} diff --git a/wii/libogc/lwip/core/raw.c b/wii/libogc/lwip/core/raw.c new file mode 100644 index 0000000000..30199804dc --- /dev/null +++ b/wii/libogc/lwip/core/raw.c @@ -0,0 +1,326 @@ +/** + * @file + * + * Implementation of raw protocol PCBs for low-level handling of + * different types of protocols besides (or overriding) those + * already available in lwIP. + * + */ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/raw.h" + +#include "lwip/stats.h" + +#include "arch/perf.h" +#include "lwip/snmp.h" + +#if LWIP_RAW + +/** The list of RAW PCBs */ +static struct raw_pcb *raw_pcbs = NULL; + +void +raw_init(void) +{ + raw_pcbs = NULL; +} + +/** + * Determine if in incoming IP packet is covered by a RAW PCB + * and if so, pass it to a user-provided receive callback function. + * + * Given an incoming IP datagram (as a chain of pbufs) this function + * finds a corresponding RAW PCB and calls the corresponding receive + * callback function. + * + * @param pbuf pbuf to be demultiplexed to a RAW PCB. + * @param netif network interface on which the datagram was received. + * @Return - 1 if the packet has been eaten by a RAW PCB receive + * callback function. The caller MAY NOT not reference the + * packet any longer, and MAY NOT call pbuf_free(). + * @return - 0 if packet is not eaten (pbuf is still referenced by the + * caller). + * + */ +u8_t +raw_input(struct pbuf *p, struct netif *inp) +{ + struct raw_pcb *pcb; + struct ip_hdr *iphdr; + s16_t proto; + u8_t eaten = 0; + + iphdr = p->payload; + proto = IPH_PROTO(iphdr); + + pcb = raw_pcbs; + /* loop through all raw pcbs until the packet is eaten by one */ + /* this allows multiple pcbs to match against the packet by design */ + while ((eaten == 0) && (pcb != NULL)) { + if (pcb->protocol == proto) { + /* receive callback function available? */ + if (pcb->recv != NULL) { + /* the receive callback function did not eat the packet? */ + if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) + { + /* receive function ate the packet */ + p = NULL; + eaten = 1; + } + } + /* no receive callback function was set for this raw PCB */ + /* drop the packet */ + } + pcb = pcb->next; + } + return eaten; +} + +/** + * Bind a RAW PCB. + * + * @param pcb RAW PCB to be bound with a local address ipaddr. + * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to + * bind to all local interfaces. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_USE. The specified IP address is already bound to by + * another RAW PCB. + * + * @see raw_disconnect() + */ +err_t +raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr) +{ + ip_addr_set(&pcb->local_ip, ipaddr); + return ERR_OK; +} + +/** + * Connect an RAW PCB. This function is required by upper layers + * of lwip. Using the raw api you could use raw_sendto() instead + * + * This will associate the RAW PCB with the remote address. + * + * @param pcb RAW PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * + * @return lwIP error code + * + * @see raw_disconnect() and raw_sendto() + */ +err_t +raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr) +{ + ip_addr_set(&pcb->remote_ip, ipaddr); + return ERR_OK; +} + + +/** + * Set the callback function for received packets that match the + * raw PCB's protocol and binding. + * + * The callback function MUST either + * - eat the packet by calling pbuf_free() and returning non-zero. The + * packet will not be passed to other raw PCBs or other protocol layers. + * - not free the packet, and return zero. The packet will be matched + * against further PCBs and/or forwarded to another protocol layers. + * + * @return non-zero if the packet was free()d, zero if the packet remains + * available for others. + */ +void +raw_recv(struct raw_pcb *pcb, + u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p, + struct ip_addr *addr), + void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} + +/** + * Send the raw IP packet to the given address. Note that actually you cannot + * modify the IP headers (this is inconsistent with the receive callback where + * you actually get the IP headers), you can only specify the IP payload here. + * It requires some more changes in lwIP. (there will be a raw_send() function + * then.) + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * @param ipaddr the destination address of the IP packet + * + */ +err_t +raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) +{ + err_t err; + struct netif *netif; + struct ip_addr *src_ip; + struct pbuf *q; /* q will be sent down the stack */ + + LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_sendto\n")); + + /* not enough space to add an IP header to first pbuf in given p chain? */ + if (pbuf_header(p, IP_HLEN)) { + /* allocate header in new pbuf */ + q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_sendto: could not allocate header\n")); + return ERR_MEM; + } + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* first pbuf q equals given pbuf */ + q = p; + pbuf_header(q, -IP_HLEN); + } + + if ((netif = ip_route(ipaddr)) == NULL) { + LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr)); +#if RAW_STATS + /* ++lwip_stats.raw.rterr;*/ +#endif /* RAW_STATS */ + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } + + if (ip_addr_isany(&pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = &(netif->ip_addr); + } else { + /* use RAW PCB local IP address as source address */ + src_ip = &(pcb->local_ip); + } + + err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); + + /* did we chain a header earlier? */ + if (q != p) { + /* free the header */ + pbuf_free(q); + } + return err; +} + +/** + * Send the raw IP packet to the address given by raw_connect() + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * @param ipaddr the destination address of the IP packet + * + */ +err_t +raw_send(struct raw_pcb *pcb, struct pbuf *p) +{ + return raw_sendto(pcb, p, &pcb->remote_ip); +} + +/** + * Remove an RAW PCB. + * + * @param pcb RAW PCB to be removed. The PCB is removed from the list of + * RAW PCB's and the data structure is freed from memory. + * + * @see raw_new() + */ +void +raw_remove(struct raw_pcb *pcb) +{ + struct raw_pcb *pcb2; + /* pcb to be removed is first in list? */ + if (raw_pcbs == pcb) { + /* make list start at 2nd pcb */ + raw_pcbs = raw_pcbs->next; + /* pcb not 1st in list */ + } else for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in raw_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + } + } + memp_free(MEMP_RAW_PCB, pcb); +} + +/** + * Create a RAW PCB. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) + * + * @see raw_remove() + */ +struct raw_pcb * +raw_new(u16_t proto) { + struct raw_pcb *pcb; + + LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_new\n")); + + pcb = memp_malloc(MEMP_RAW_PCB); + /* could allocate RAW PCB? */ + if (pcb != NULL) { + /* initialize PCB to all zeroes */ + memset(pcb, 0, sizeof(struct raw_pcb)); + pcb->protocol = proto; + pcb->ttl = RAW_TTL; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } + return pcb; +} + +#endif /* LWIP_RAW */ diff --git a/wii/libogc/lwip/core/stats.c b/wii/libogc/lwip/core/stats.c new file mode 100644 index 0000000000..c94623f7a8 --- /dev/null +++ b/wii/libogc/lwip/core/stats.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include + +#include "lwip/opt.h" + +#include "lwip/def.h" + +#include "lwip/stats.h" +#include "lwip/mem.h" + + +#if LWIP_STATS +struct stats_ lwip_stats; + +void +stats_init(void) +{ + memset(&lwip_stats, 0, sizeof(struct stats_)); +} +#if LWIP_STATS_DISPLAY +void +stats_display_proto(struct stats_proto *proto, char *name) +{ + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); + LWIP_PLATFORM_DIAG(("xmit: %"S16_F"\n\t", proto->xmit)); + LWIP_PLATFORM_DIAG(("rexmit: %"S16_F"\n\t", proto->rexmit)); + LWIP_PLATFORM_DIAG(("recv: %"S16_F"\n\t", proto->recv)); + LWIP_PLATFORM_DIAG(("fw: %"S16_F"\n\t", proto->fw)); + LWIP_PLATFORM_DIAG(("drop: %"S16_F"\n\t", proto->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"S16_F"\n\t", proto->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"S16_F"\n\t", proto->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"S16_F"\n\t", proto->memerr)); + LWIP_PLATFORM_DIAG(("rterr: %"S16_F"\n\t", proto->rterr)); + LWIP_PLATFORM_DIAG(("proterr: %"S16_F"\n\t", proto->proterr)); + LWIP_PLATFORM_DIAG(("opterr: %"S16_F"\n\t", proto->opterr)); + LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", proto->err)); + LWIP_PLATFORM_DIAG(("cachehit: %"S16_F"\n", proto->cachehit)); +} + +void +stats_display_pbuf(struct stats_pbuf *pbuf) +{ + LWIP_PLATFORM_DIAG(("\nPBUF\n\t")); + LWIP_PLATFORM_DIAG(("avail: %"S16_F"\n\t", pbuf->avail)); + LWIP_PLATFORM_DIAG(("used: %"S16_F"\n\t", pbuf->used)); + LWIP_PLATFORM_DIAG(("max: %"S16_F"\n\t", pbuf->max)); + LWIP_PLATFORM_DIAG(("err: %"S16_F"\n\t", pbuf->err)); + LWIP_PLATFORM_DIAG(("alloc_locked: %"S16_F"\n\t", pbuf->alloc_locked)); + LWIP_PLATFORM_DIAG(("refresh_locked: %"S16_F"\n", pbuf->refresh_locked)); +} + +void +stats_display_mem(struct stats_mem *mem, char *name) +{ + LWIP_PLATFORM_DIAG(("\n MEM %s\n\t", name)); + LWIP_PLATFORM_DIAG(("avail: %"S16_F"\n\t", mem->avail)); + LWIP_PLATFORM_DIAG(("used: %"S16_F"\n\t", mem->used)); + LWIP_PLATFORM_DIAG(("max: %"S16_F"\n\t", mem->max)); + LWIP_PLATFORM_DIAG(("err: %"S16_F"\n", mem->err)); + +} + +void +stats_display(void) +{ + s16_t i; + char * memp_names[] = {"PBUF", "RAW_PCB", "UDP_PCB", "TCP_PCB", "TCP_PCB_LISTEN", + "TCP_SEG", "NETBUF", "NETCONN", "API_MSG", "TCP_MSG", "TIMEOUT"}; + stats_display_proto(&lwip_stats.link, "LINK"); + stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG"); + stats_display_proto(&lwip_stats.ip, "IP"); + stats_display_proto(&lwip_stats.icmp, "ICMP"); + stats_display_proto(&lwip_stats.udp, "UDP"); + stats_display_proto(&lwip_stats.tcp, "TCP"); + stats_display_pbuf(&lwip_stats.pbuf); + stats_display_mem(&lwip_stats.mem, "HEAP"); + for (i = 0; i < MEMP_MAX; i++) { + stats_display_mem(&lwip_stats.memp[i], memp_names[i]); + } + +} +#endif /* LWIP_STATS_DISPLAY */ +#endif /* LWIP_STATS */ + diff --git a/wii/libogc/lwip/core/sys.c b/wii/libogc/lwip/core/sys.c new file mode 100644 index 0000000000..a7dbf34dab --- /dev/null +++ b/wii/libogc/lwip/core/sys.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/sys.h" +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/memp.h" + +#if (NO_SYS == 0) + +struct sswt_cb +{ + s16_t timeflag; + sys_sem_t *psem; +}; + + + +void +sys_mbox_fetch(sys_mbox_t mbox, void **msg) +{ + u32_t time; + struct sys_timeouts *timeouts; + struct sys_timeout *tmptimeout; + sys_timeout_handler h; + void *arg; + + + again: + timeouts = sys_arch_timeouts(); + + if (!timeouts || !timeouts->next) { + sys_arch_mbox_fetch(mbox, msg, 0); + } else { + if (timeouts->next->time > 0) { + time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time); + } else { + time = SYS_ARCH_TIMEOUT; + } + + if (time == SYS_ARCH_TIMEOUT) { + /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message + could be fetched. We should now call the timeout handler and + deallocate the memory allocated for the timeout. */ + tmptimeout = timeouts->next; + timeouts->next = tmptimeout->next; + h = tmptimeout->h; + arg = tmptimeout->arg; + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (h != NULL) { + LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void *)h, (void *)arg)); + h(arg); + } + + /* We try again to fetch a message from the mbox. */ + goto again; + } else { + /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout + occured. The time variable is set to the number of + milliseconds we waited for the message. */ + if (time <= timeouts->next->time) { + timeouts->next->time -= time; + } else { + timeouts->next->time = 0; + } + } + + } +} + +void +sys_sem_wait(sys_sem_t sem) +{ + u32_t time; + struct sys_timeouts *timeouts; + struct sys_timeout *tmptimeout; + sys_timeout_handler h; + void *arg; + + /* while (sys_arch_sem_wait(sem, 1000) == 0); + return;*/ + + again: + + timeouts = sys_arch_timeouts(); + + if (!timeouts || !timeouts->next) { + sys_arch_sem_wait(sem, 0); + } else { + if (timeouts->next->time > 0) { + time = sys_arch_sem_wait(sem, timeouts->next->time); + } else { + time = SYS_ARCH_TIMEOUT; + } + + if (time == SYS_ARCH_TIMEOUT) { + /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message + could be fetched. We should now call the timeout handler and + deallocate the memory allocated for the timeout. */ + tmptimeout = timeouts->next; + timeouts->next = tmptimeout->next; + h = tmptimeout->h; + arg = tmptimeout->arg; + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (h != NULL) { + LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void *)h, (void *)arg)); + h(arg); + } + + + /* We try again to fetch a message from the mbox. */ + goto again; + } else { + /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout + occured. The time variable is set to the number of + milliseconds we waited for the message. */ + if (time <= timeouts->next->time) { + timeouts->next->time -= time; + } else { + timeouts->next->time = 0; + } + } + + } +} + +void +sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ + struct sys_timeouts *timeouts; + struct sys_timeout *timeout, *t; + + timeout = memp_malloc(MEMP_SYS_TIMEOUT); + if (timeout == NULL) { + return; + } + timeout->next = NULL; + timeout->h = h; + timeout->arg = arg; + timeout->time = msecs; + + timeouts = sys_arch_timeouts(); + + LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n", + (void *)timeout, msecs, (void *)h, (void *)arg)); + + LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL); + + if (timeouts->next == NULL) { + timeouts->next = timeout; + return; + } + + if (timeouts->next->time > msecs) { + timeouts->next->time -= msecs; + timeout->next = timeouts->next; + timeouts->next = timeout; + } else { + for(t = timeouts->next; t != NULL; t = t->next) { + timeout->time -= t->time; + if (t->next == NULL || t->next->time > timeout->time) { + if (t->next != NULL) { + t->next->time -= timeout->time; + } + timeout->next = t->next; + t->next = timeout; + break; + } + } + } + +} + +/* Go through timeout list (for this task only) and remove the first matching entry, + even though the timeout has not triggered yet. +*/ + +void +sys_untimeout(sys_timeout_handler h, void *arg) +{ + struct sys_timeouts *timeouts; + struct sys_timeout *prev_t, *t; + + timeouts = sys_arch_timeouts(); + + if (timeouts->next == NULL) + return; + + for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) + { + if ((t->h == h) && (t->arg == arg)) + { + /* We have a match */ + /* Unlink from previous in list */ + if (prev_t == NULL) + timeouts->next = t->next; + else + prev_t->next = t->next; + /* If not the last one, add time of this one back to next */ + if (t->next != NULL) + t->next->time += t->time; + memp_free(MEMP_SYS_TIMEOUT, t); + return; + } + } + return; +} + + + + + +static void +sswt_handler(void *arg) +{ + struct sswt_cb *sswt_cb = (struct sswt_cb *) arg; + + /* Timeout. Set flag to TRUE and signal semaphore */ + sswt_cb->timeflag = 1; + sys_sem_signal(*(sswt_cb->psem)); +} + +/* Wait for a semaphore with timeout (specified in ms) */ +/* timeout = 0: wait forever */ +/* Returns 0 on timeout. 1 otherwise */ + +int +sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout) +{ + struct sswt_cb sswt_cb; + + sswt_cb.psem = &sem; + sswt_cb.timeflag = 0; + + /* If timeout is zero, then just wait forever */ + if (timeout > 0) + /* Create a timer and pass it the address of our flag */ + sys_timeout(timeout, sswt_handler, &sswt_cb); + sys_sem_wait(sem); + /* Was it a timeout? */ + if (sswt_cb.timeflag) + { + /* timeout */ + return 0; + } else { + /* Not a timeout. Remove timeout entry */ + sys_untimeout(sswt_handler, &sswt_cb); + return 1; + } + +} + + +void +sys_msleep(u32_t ms) +{ + sys_sem_t delaysem = sys_sem_new(0); + + sys_sem_wait_timeout(delaysem, ms); + + sys_sem_free(delaysem); +} + + +#endif /* NO_SYS */ diff --git a/wii/libogc/lwip/core/tcp.c b/wii/libogc/lwip/core/tcp.c new file mode 100644 index 0000000000..41a9edb4e5 --- /dev/null +++ b/wii/libogc/lwip/core/tcp.c @@ -0,0 +1,1171 @@ +/** + * @file + * + * Transmission Control Protocol for IP + * + * This file contains common functions for the TCP implementation, such as functinos + * for manipulating the data structures and the TCP timer functions. TCP functions + * related to input and output is found in tcp_in.c and tcp_out.c respectively. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" + +#include "lwip/tcp.h" +#if LWIP_TCP + +/* Incremented every coarse grained timer shot + (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */ +u32_t tcp_ticks; +const u8_t tcp_backoff[13] = + { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; + +/* The TCP PCB lists. */ + +/** List of all TCP PCBs in LISTEN state */ +union tcp_listen_pcbs_t tcp_listen_pcbs; +/** List of all TCP PCBs that are in a state in which + * they accept or send data. */ +struct tcp_pcb *tcp_active_pcbs; +/** List of all TCP PCBs in TIME-WAIT state */ +struct tcp_pcb *tcp_tw_pcbs; + +struct tcp_pcb *tcp_tmp_pcb; + +static u8_t tcp_timer; +static u16_t tcp_new_port(void); + +/** + * Initializes the TCP layer. + */ +void +tcp_init(void) +{ + /* Clear globals. */ + tcp_listen_pcbs.listen_pcbs = NULL; + tcp_active_pcbs = NULL; + tcp_tw_pcbs = NULL; + tcp_tmp_pcb = NULL; + + /* initialize timer */ + tcp_ticks = 0; + tcp_timer = 0; + +} + +/** + * Called periodically to dispatch TCP timers. + * + */ +void +tcp_tmr(void) +{ + /* Call tcp_fasttmr() every 250 ms */ + tcp_fasttmr(); + + if (++tcp_timer & 1) { + /* Call tcp_tmr() every 500 ms, i.e., every other timer + tcp_tmr() is called. */ + tcp_slowtmr(); + } +} + +/** + * Closes the connection held by the PCB. + * + */ +err_t +tcp_close(struct tcp_pcb *pcb) +{ + err_t err; + +#if TCP_DEBUG + LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in state ")); + tcp_debug_print_state(pcb->state); + LWIP_DEBUGF(TCP_DEBUG, ("\n")); +#endif /* TCP_DEBUG */ + switch (pcb->state) { + case CLOSED: + /* Closing a pcb in the CLOSED state might seem erroneous, + * however, it is in this state once allocated and as yet unused + * and the user needs some way to free it should the need arise. + * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) + * or for a pcb that has been used and then entered the CLOSED state + * is erroneous, but this should never happen as the pcb has in those cases + * been freed, and so any remaining handles are bogus. */ + err = ERR_OK; + memp_free(MEMP_TCP_PCB, pcb); + pcb = NULL; + break; + case LISTEN: + err = ERR_OK; + tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb); + memp_free(MEMP_TCP_PCB_LISTEN, pcb); + pcb = NULL; + break; + case SYN_SENT: + err = ERR_OK; + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + pcb = NULL; + break; + case SYN_RCVD: + case ESTABLISHED: + err = tcp_send_ctrl(pcb, TCP_FIN); + if (err == ERR_OK) { + pcb->state = FIN_WAIT_1; + } + break; + case CLOSE_WAIT: + err = tcp_send_ctrl(pcb, TCP_FIN); + if (err == ERR_OK) { + pcb->state = LAST_ACK; + } + break; + default: + /* Has already been closed, do nothing. */ + err = ERR_OK; + pcb = NULL; + break; + } + + if (pcb != NULL && err == ERR_OK) { + err = tcp_output(pcb); + } + return err; +} + +/** + * Aborts a connection by sending a RST to the remote host and deletes + * the local protocol control block. This is done when a connection is + * killed because of shortage of memory. + * + */ +void +tcp_abort(struct tcp_pcb *pcb) +{ + u32_t seqno, ackno; + u16_t remote_port, local_port; + struct ip_addr remote_ip, local_ip; +#if LWIP_CALLBACK_API + void (* errf)(void *arg, err_t err); +#endif /* LWIP_CALLBACK_API */ + void *errf_arg; + + + /* Figure out on which TCP PCB list we are, and remove us. If we + are in an active state, call the receive function associated with + the PCB with a NULL argument, and send an RST to the remote end. */ + if (pcb->state == TIME_WAIT) { + tcp_pcb_remove(&tcp_tw_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + seqno = pcb->snd_nxt; + ackno = pcb->rcv_nxt; + ip_addr_set(&local_ip, &(pcb->local_ip)); + ip_addr_set(&remote_ip, &(pcb->remote_ip)); + local_port = pcb->local_port; + remote_port = pcb->remote_port; +#if LWIP_CALLBACK_API + errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + errf_arg = pcb->callback_arg; + tcp_pcb_remove(&tcp_active_pcbs, pcb); + if (pcb->unacked != NULL) { + tcp_segs_free(pcb->unacked); + } + if (pcb->unsent != NULL) { + tcp_segs_free(pcb->unsent); + } +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + tcp_segs_free(pcb->ooseq); + } +#endif /* TCP_QUEUE_OOSEQ */ + memp_free(MEMP_TCP_PCB, pcb); + TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n")); + tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); + } +} + +/** + * Binds the connection to a local portnumber and IP address. If the + * IP address is not given (i.e., ipaddr == NULL), the IP address of + * the outgoing network interface is used instead. + * + */ + +err_t +tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct tcp_pcb *cpcb; + + if (port == 0) { + port = tcp_new_port(); + } + /* Check if the address already is in use. */ + for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; + cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->local_port == port) { + if (ip_addr_isany(&(cpcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { + return ERR_USE; + } + } + } + for(cpcb = tcp_active_pcbs; + cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->local_port == port) { + if (ip_addr_isany(&(cpcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { + return ERR_USE; + } + } + } + + if (!ip_addr_isany(ipaddr)) { + pcb->local_ip = *ipaddr; + } + pcb->local_port = port; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); + return ERR_OK; +} +#if LWIP_CALLBACK_API +static err_t +tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) +{ + (void)arg; + (void)pcb; + (void)err; + + return ERR_ABRT; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * + */ +struct tcp_pcb * +tcp_listen(struct tcp_pcb *pcb) +{ + struct tcp_pcb_listen *lpcb; + + /* already listening? */ + if (pcb->state == LISTEN) { + return pcb; + } + lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN); + if (lpcb == NULL) { + return NULL; + } + lpcb->callback_arg = pcb->callback_arg; + lpcb->local_port = pcb->local_port; + lpcb->state = LISTEN; + lpcb->so_options = pcb->so_options; + lpcb->so_options |= SOF_ACCEPTCONN; + lpcb->ttl = pcb->ttl; + lpcb->tos = pcb->tos; + ip_addr_set(&lpcb->local_ip, &pcb->local_ip); + memp_free(MEMP_TCP_PCB, pcb); +#if LWIP_CALLBACK_API + lpcb->accept = tcp_accept_null; +#endif /* LWIP_CALLBACK_API */ + TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb); + return (struct tcp_pcb *)lpcb; +} + +/** + * This function should be called by the application when it has + * processed the data. The purpose is to advertise a larger window + * when the data has been processed. + * + */ +void +tcp_recved(struct tcp_pcb *pcb, u16_t len) +{ + if ((u32_t)pcb->rcv_wnd + len > TCP_WND) { + pcb->rcv_wnd = TCP_WND; + } else { + pcb->rcv_wnd += len; + } + if (!(pcb->flags & TF_ACK_DELAY) && + !(pcb->flags & TF_ACK_NOW)) { + /* + * We send an ACK here (if one is not already pending, hence + * the above tests) as tcp_recved() implies that the application + * has processed some data, and so we can open the receiver's + * window to allow more to be transmitted. This could result in + * two ACKs being sent for each received packet in some limited cases + * (where the application is only receiving data, and is slow to + * process it) but it is necessary to guarantee that the sender can + * continue to transmit. + */ + tcp_ack(pcb); + } + else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) { + /* If we can send a window update such that there is a full + * segment available in the window, do so now. This is sort of + * nagle-like in its goals, and tries to hit a compromise between + * sending acks each time the window is updated, and only sending + * window updates when a timer expires. The "threshold" used + * above (currently TCP_WND/2) can be tuned to be more or less + * aggressive */ + tcp_ack_now(pcb); + } + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", + len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); +} + +/** + * A nastly hack featuring 'goto' statements that allocates a + * new TCP local port. + */ +static u16_t +tcp_new_port(void) +{ + struct tcp_pcb *pcb; +#ifndef TCP_LOCAL_PORT_RANGE_START +#define TCP_LOCAL_PORT_RANGE_START 4096 +#define TCP_LOCAL_PORT_RANGE_END 0x7fff +#endif + static u16_t port = TCP_LOCAL_PORT_RANGE_START; + + again: + if (++port > TCP_LOCAL_PORT_RANGE_END) { + port = TCP_LOCAL_PORT_RANGE_START; + } + + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == port) { + goto again; + } + } + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == port) { + goto again; + } + } + for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == port) { + goto again; + } + } + return port; +} + +/** + * Connects to another host. The function given as the "connected" + * argument will be called when the connection has been established. + * + */ +err_t +tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, + err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) +{ + u32_t optdata; + err_t ret; + u32_t iss; + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); + if (ipaddr != NULL) { + pcb->remote_ip = *ipaddr; + } else { + return ERR_VAL; + } + pcb->remote_port = port; + if (pcb->local_port == 0) { + pcb->local_port = tcp_new_port(); + } + iss = tcp_next_iss(); + pcb->rcv_nxt = 0; + pcb->snd_nxt = iss; + pcb->lastack = iss - 1; + pcb->snd_lbb = iss - 1; + pcb->rcv_wnd = TCP_WND; + pcb->snd_wnd = TCP_WND; + pcb->mss = TCP_MSS; + pcb->cwnd = 1; + pcb->ssthresh = pcb->mss * 10; + pcb->state = SYN_SENT; +#if LWIP_CALLBACK_API + pcb->connected = connected; +#endif /* LWIP_CALLBACK_API */ + TCP_REG(&tcp_active_pcbs, pcb); + + /* Build an MSS option */ + optdata = htonl(((u32_t)2 << 24) | + ((u32_t)4 << 16) | + (((u32_t)pcb->mss / 256) << 8) | + (pcb->mss & 255)); + + ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4); + if (ret == ERR_OK) { + tcp_output(pcb); + } + return ret; +} + +/** + * Called every 500 ms and implements the retransmission timer and the timer that + * removes PCBs that have been in TIME-WAIT for enough time. It also increments + * various timers such as the inactivity timer in each PCB. + */ +void +tcp_slowtmr(void) +{ + struct tcp_pcb *pcb, *pcb2, *prev; + u32_t eff_wnd; + u8_t pcb_remove; /* flag if a PCB should be removed */ + err_t err; + + err = ERR_OK; + + ++tcp_ticks; + + /* Steps through all of the active PCBs. */ + prev = NULL; + pcb = tcp_active_pcbs; + if (pcb == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); + } + while (pcb != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); + + pcb_remove = 0; + + if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); + } + else if (pcb->nrtx == TCP_MAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); + } else { + ++pcb->rtime; + if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { + + /* Time for a retransmission. */ + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_F"\n", + pcb->rtime, pcb->rto)); + + /* Double retransmission time-out unless we are trying to + * connect to somebody (i.e., we are in SYN_SENT). */ + if (pcb->state != SYN_SENT) { + pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; + } + /* Reduce congestion window and ssthresh. */ + eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); + pcb->ssthresh = eff_wnd >> 1; + if (pcb->ssthresh < pcb->mss) { + pcb->ssthresh = pcb->mss * 2; + } + pcb->cwnd = pcb->mss; + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n", + pcb->cwnd, pcb->ssthresh)); + + /* The following needs to be called AFTER cwnd is set to one mss - STJ */ + tcp_rexmit_rto(pcb); + } + } + /* Check if this PCB has stayed too long in FIN-WAIT-2 */ + if (pcb->state == FIN_WAIT_2) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); + } + } + + /* Check if KEEPALIVE should be sent */ + if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { + if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", + ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), + ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + + tcp_abort(pcb); + } + else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) { + tcp_keepalive(pcb); + pcb->keep_cnt++; + } + } + + /* If this PCB has queued out of sequence data, but has been + inactive for too long, will drop the data (it will eventually + be retransmitted). */ +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL && + (u32_t)tcp_ticks - pcb->tmr >= + pcb->rto * TCP_OOSEQ_TIMEOUT) { + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); + } +#endif /* TCP_QUEUE_OOSEQ */ + + /* Check if this PCB has stayed too long in SYN-RCVD */ + if (pcb->state == SYN_RCVD) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); + } + } + + /* Check if this PCB has stayed too long in LAST-ACK */ + if (pcb->state == LAST_ACK) { + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); + } + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_active_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); + tcp_active_pcbs = pcb->next; + } + + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); + + pcb2 = pcb->next; + memp_free(MEMP_TCP_PCB, pcb); + pcb = pcb2; + } else { + + /* We check if we should poll the connection. */ + ++pcb->polltmr; + if (pcb->polltmr >= pcb->pollinterval) { + pcb->polltmr = 0; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); + TCP_EVENT_POLL(pcb, err); + if (err == ERR_OK) { + tcp_output(pcb); + } + } + + prev = pcb; + pcb = pcb->next; + } + } + + + /* Steps through all of the TIME-WAIT PCBs. */ + prev = NULL; + pcb = tcp_tw_pcbs; + while (pcb != NULL) { + LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + pcb_remove = 0; + + /* Check if this PCB has stayed long enough in TIME-WAIT */ + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + + + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_tw_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); + tcp_tw_pcbs = pcb->next; + } + pcb2 = pcb->next; + memp_free(MEMP_TCP_PCB, pcb); + pcb = pcb2; + } else { + prev = pcb; + pcb = pcb->next; + } + } +} + +/** + * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs. + */ +void +tcp_fasttmr(void) +{ + struct tcp_pcb *pcb; + + /* send delayed ACKs */ + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->flags & TF_ACK_DELAY) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); + tcp_ack_now(pcb); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + } +} + +/** + * Deallocates a list of TCP segments (tcp_seg structures). + * + */ +u8_t +tcp_segs_free(struct tcp_seg *seg) +{ + u8_t count = 0; + struct tcp_seg *next; + while (seg != NULL) { + next = seg->next; + count += tcp_seg_free(seg); + seg = next; + } + return count; +} + +/** + * Frees a TCP segment. + * + */ +u8_t +tcp_seg_free(struct tcp_seg *seg) +{ + u8_t count = 0; + + if (seg != NULL) { + if (seg->p != NULL) { + count = pbuf_free(seg->p); +#if TCP_DEBUG + seg->p = NULL; +#endif /* TCP_DEBUG */ + } + memp_free(MEMP_TCP_SEG, seg); + } + return count; +} + +/** + * Sets the priority of a connection. + * + */ +void +tcp_setprio(struct tcp_pcb *pcb, u8_t prio) +{ + pcb->prio = prio; +} +#if TCP_QUEUE_OOSEQ + +/** + * Returns a copy of the given TCP segment. + * + */ +struct tcp_seg * +tcp_seg_copy(struct tcp_seg *seg) +{ + struct tcp_seg *cseg; + + cseg = memp_malloc(MEMP_TCP_SEG); + if (cseg == NULL) { + return NULL; + } + memcpy((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); + pbuf_ref(cseg->p); + return cseg; +} +#endif + +#if LWIP_CALLBACK_API +static err_t +tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + arg = arg; + if (p != NULL) { + pbuf_free(p); + } else if (err == ERR_OK) { + return tcp_close(pcb); + } + return ERR_OK; +} +#endif /* LWIP_CALLBACK_API */ + +static void +tcp_kill_prio(u8_t prio) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + u8_t mprio; + + + mprio = TCP_PRIO_MAX; + + /* We kill the oldest active connection that has lower priority than + prio. */ + inactivity = 0; + inactive = NULL; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->prio <= prio && + pcb->prio <= mprio && + (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + mprio = pcb->prio; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + + +static void +tcp_kill_timewait(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + inactivity = 0; + inactive = NULL; + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + + + +struct tcp_pcb * +tcp_alloc(u8_t prio) +{ + struct tcp_pcb *pcb; + u32_t iss; + + pcb = memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing oldest connection in TIME-WAIT. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); + tcp_kill_timewait(); + pcb = memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + tcp_kill_prio(prio); + pcb = memp_malloc(MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + memset(pcb, 0, sizeof(struct tcp_pcb)); + pcb->prio = TCP_PRIO_NORMAL; + pcb->snd_buf = TCP_SND_BUF; + pcb->snd_queuelen = 0; + pcb->rcv_wnd = TCP_WND; + pcb->tos = 0; + pcb->ttl = TCP_TTL; + pcb->mss = TCP_MSS; + pcb->rto = 3000 / TCP_SLOW_INTERVAL; + pcb->sa = 0; + pcb->sv = 3000 / TCP_SLOW_INTERVAL; + pcb->rtime = 0; + pcb->cwnd = 1; + iss = tcp_next_iss(); + pcb->snd_wl2 = iss; + pcb->snd_nxt = iss; + pcb->snd_max = iss; + pcb->lastack = iss; + pcb->snd_lbb = iss; + pcb->tmr = tcp_ticks; + + pcb->polltmr = 0; + +#if LWIP_CALLBACK_API + pcb->recv = tcp_recv_null; +#endif /* LWIP_CALLBACK_API */ + + /* Init KEEPALIVE timer */ + pcb->keepalive = TCP_KEEPDEFAULT; + pcb->keep_cnt = 0; + } + return pcb; +} + +/** + * Creates a new TCP protocol control block but doesn't place it on + * any of the TCP PCB lists. + * + * @internal: Maybe there should be a idle TCP PCB list where these + * PCBs are put on. We can then implement port reservation using + * tcp_bind(). Currently, we lack this (BSD socket type of) feature. + */ + +struct tcp_pcb * +tcp_new(void) +{ + return tcp_alloc(TCP_PRIO_NORMAL); +} + +/* + * tcp_arg(): + * + * Used to specify the argument that should be passed callback + * functions. + * + */ + +void +tcp_arg(struct tcp_pcb *pcb, void *arg) +{ + pcb->callback_arg = arg; +} +#if LWIP_CALLBACK_API + +/** + * Used to specify the function that should be called when a TCP + * connection receives data. + * + */ +void +tcp_recv(struct tcp_pcb *pcb, + err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) +{ + pcb->recv = recv; +} + +/** + * Used to specify the function that should be called when TCP data + * has been successfully delivered to the remote host. + * + */ + +void +tcp_sent(struct tcp_pcb *pcb, + err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) +{ + pcb->sent = sent; +} + +/** + * Used to specify the function that should be called when a fatal error + * has occured on the connection. + * + */ +void +tcp_err(struct tcp_pcb *pcb, + void (* errf)(void *arg, err_t err)) +{ + pcb->errf = errf; +} + +/** + * Used for specifying the function that should be called when a + * LISTENing connection has been connected to another host. + * + */ +void +tcp_accept(struct tcp_pcb *pcb, + err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) +{ + ((struct tcp_pcb_listen *)pcb)->accept = accept; +} +#endif /* LWIP_CALLBACK_API */ + + +/** + * Used to specify the function that should be called periodically + * from TCP. The interval is specified in terms of the TCP coarse + * timer interval, which is called twice a second. + * + */ +void +tcp_poll(struct tcp_pcb *pcb, + err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) +{ +#if LWIP_CALLBACK_API + pcb->poll = poll; +#endif /* LWIP_CALLBACK_API */ + pcb->pollinterval = interval; +} + +/** + * Purges a TCP PCB. Removes any buffered data and frees the buffer memory. + * + */ +void +tcp_pcb_purge(struct tcp_pcb *pcb) +{ + if (pcb->state != CLOSED && + pcb->state != TIME_WAIT && + pcb->state != LISTEN) { + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); + + if (pcb->unsent != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); + } + if (pcb->unacked != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); + } +#if TCP_QUEUE_OOSEQ /* LW */ + if (pcb->ooseq != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); + } + + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; +#endif /* TCP_QUEUE_OOSEQ */ + tcp_segs_free(pcb->unsent); + tcp_segs_free(pcb->unacked); + pcb->unacked = pcb->unsent = NULL; + } +} + +/** + * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. + * + */ +void +tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) +{ + TCP_RMV(pcblist, pcb); + + tcp_pcb_purge(pcb); + + /* if there is an outstanding delayed ACKs, send it */ + if (pcb->state != TIME_WAIT && + pcb->state != LISTEN && + pcb->flags & TF_ACK_DELAY) { + pcb->flags |= TF_ACK_NOW; + tcp_output(pcb); + } + pcb->state = CLOSED; + + LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); +} + +/** + * Calculates a new initial sequence number for new connections. + * + */ +u32_t +tcp_next_iss(void) +{ + static u32_t iss = 6510; + + iss += tcp_ticks; /* XXX */ + return iss; +} + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void +tcp_debug_print(struct tcp_hdr *tcphdr) +{ + LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + ntohs(tcphdr->src), ntohs(tcphdr->dest))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", + ntohl(tcphdr->seqno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", + ntohl(tcphdr->ackno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", + TCPH_HDRLEN(tcphdr), + TCPH_FLAGS(tcphdr) >> 5 & 1, + TCPH_FLAGS(tcphdr) >> 4 & 1, + TCPH_FLAGS(tcphdr) >> 3 & 1, + TCPH_FLAGS(tcphdr) >> 2 & 1, + TCPH_FLAGS(tcphdr) >> 1 & 1, + TCPH_FLAGS(tcphdr) & 1, + ntohs(tcphdr->wnd))); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", + ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +} + +void +tcp_debug_print_state(enum tcp_state s) +{ + LWIP_DEBUGF(TCP_DEBUG, ("State: ")); + switch (s) { + case CLOSED: + LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n")); + break; + case LISTEN: + LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n")); + break; + case SYN_SENT: + LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n")); + break; + case SYN_RCVD: + LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n")); + break; + case ESTABLISHED: + LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n")); + break; + case FIN_WAIT_1: + LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n")); + break; + case FIN_WAIT_2: + LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n")); + break; + case CLOSE_WAIT: + LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n")); + break; + case CLOSING: + LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n")); + break; + case LAST_ACK: + LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n")); + break; + case TIME_WAIT: + LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n")); + break; + } +} + +void +tcp_debug_print_flags(u8_t flags) +{ + if (flags & TCP_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); + } + if (flags & TCP_SYN) { + LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); + } + if (flags & TCP_RST) { + LWIP_DEBUGF(TCP_DEBUG, ("RST ")); + } + if (flags & TCP_PSH) { + LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); + } + if (flags & TCP_ACK) { + LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); + } + if (flags & TCP_URG) { + LWIP_DEBUGF(TCP_DEBUG, ("URG ")); + } + if (flags & TCP_ECE) { + LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); + } + if (flags & TCP_CWR) { + LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); + } +} + +void +tcp_debug_print_pcbs(void) +{ + struct tcp_pcb *pcb; + LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); + for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } +} + +s16_t +tcp_pcbs_sane(void) +{ + struct tcp_pcb *pcb; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + } + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + } + return 1; +} +#endif /* TCP_DEBUG */ +#endif /* LWIP_TCP */ + + + + + + + + + + diff --git a/wii/libogc/lwip/core/tcp_in.c b/wii/libogc/lwip/core/tcp_in.c new file mode 100644 index 0000000000..212f9c4db6 --- /dev/null +++ b/wii/libogc/lwip/core/tcp_in.c @@ -0,0 +1,1199 @@ +/** + * @file + * + * Transmission Control Protocol, incoming traffic + * + * The input processing functions of TCP. + * + * These functions are generally called in the order (ip_input() ->) tcp_input() -> + * tcp_process() -> tcp_receive() (-> application). + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/def.h" +#include "lwip/opt.h" + +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/mem.h" +#include "lwip/memp.h" + +#include "lwip/inet.h" +#include "lwip/tcp.h" + +#include "lwip/stats.h" + +#include "arch/perf.h" +#if LWIP_TCP +/* These variables are global to all functions involved in the input + processing of TCP segments. They are set by the tcp_input() + function. */ +static struct tcp_seg inseg; +static struct tcp_hdr *tcphdr; +static struct ip_hdr *iphdr; +static u32_t seqno, ackno; +static u8_t flags; +static u16_t tcplen; + +static u8_t recv_flags; +static struct pbuf *recv_data; + +struct tcp_pcb *tcp_input_pcb; + +/* Forward declarations. */ +static err_t tcp_process(struct tcp_pcb *pcb); +static void tcp_receive(struct tcp_pcb *pcb); +static void tcp_parseopt(struct tcp_pcb *pcb); + +static err_t tcp_listen_input(struct tcp_pcb_listen *pcb); +static err_t tcp_timewait_input(struct tcp_pcb *pcb); + + +/* tcp_input: + * + * The initial input processing of TCP. It verifies the TCP header, demultiplexes + * the segment between the PCBs and passes it on to tcp_process(), which implements + * the TCP finite state machine. This function is called by the IP layer (in + * ip_input()). + */ + +void +tcp_input(struct pbuf *p, struct netif *inp) +{ + struct tcp_pcb *pcb, *prev; + struct tcp_pcb_listen *lpcb; + u8_t hdrlen; + err_t err; + + PERF_START; + + TCP_STATS_INC(tcp.recv); + + iphdr = p->payload; + tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); + +#if TCP_INPUT_DEBUG + tcp_debug_print(tcphdr); +#endif + + /* remove header from payload */ + if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) { + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); + TCP_STATS_INC(tcp.lenerr); + TCP_STATS_INC(tcp.drop); + pbuf_free(p); + return; + } + + /* Don't even process incoming broadcasts/multicasts. */ + if (ip_addr_isbroadcast(&(iphdr->dest), inp) || + ip_addr_ismulticast(&(iphdr->dest))) { + pbuf_free(p); + return; + } + +#if CHECKSUM_CHECK_TCP + /* Verify TCP checksum. */ + if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_TCP, p->tot_len) != 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", + inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), + IP_PROTO_TCP, p->tot_len))); +#if TCP_DEBUG + tcp_debug_print(tcphdr); +#endif /* TCP_DEBUG */ + TCP_STATS_INC(tcp.chkerr); + TCP_STATS_INC(tcp.drop); + + pbuf_free(p); + return; + } +#endif + + /* Move the payload pointer in the pbuf so that it points to the + TCP data instead of the TCP header. */ + hdrlen = TCPH_HDRLEN(tcphdr); + pbuf_header(p, -(hdrlen * 4)); + + /* Convert fields in TCP header to host byte order. */ + tcphdr->src = ntohs(tcphdr->src); + tcphdr->dest = ntohs(tcphdr->dest); + seqno = tcphdr->seqno = ntohl(tcphdr->seqno); + ackno = tcphdr->ackno = ntohl(tcphdr->ackno); + tcphdr->wnd = ntohs(tcphdr->wnd); + + flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS; + tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0); + + /* Demultiplex an incoming segment. First, we check if it is destined + for an active connection. */ + prev = NULL; + + + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); + if (prev != NULL) { + prev->next = pcb->next; + pcb->next = tcp_active_pcbs; + tcp_active_pcbs = pcb; + } + LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); + break; + } + prev = pcb; + } + + if (pcb == NULL) { + /* If it did not go to an active connection, we check the connections + in the TIME-WAIT state. */ + + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + /* We don't really care enough to move this PCB to the front + of the list since we are not very likely to receive that + many segments for connections in TIME-WAIT. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); + tcp_timewait_input(pcb); + pbuf_free(p); + return; + } + } + + /* Finally, if we still did not get a match, we check all PCBs that + are LISTENing for incoming connections. */ + prev = NULL; + for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if ((ip_addr_isany(&(lpcb->local_ip)) || + ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) && + lpcb->local_port == tcphdr->dest) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + if (prev != NULL) { + ((struct tcp_pcb_listen *)prev)->next = lpcb->next; + /* our successor is the remainder of the listening list */ + lpcb->next = tcp_listen_pcbs.listen_pcbs; + /* put this listening pcb at the head of the listening list */ + tcp_listen_pcbs.listen_pcbs = lpcb; + } + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); + tcp_listen_input(lpcb); + pbuf_free(p); + return; + } + prev = (struct tcp_pcb *)lpcb; + } + } + +#if TCP_INPUT_DEBUG + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); +#endif /* TCP_INPUT_DEBUG */ + + + if (pcb != NULL) { + /* The incoming segment belongs to a connection. */ +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + + /* Set up a tcp_seg structure. */ + inseg.next = NULL; + inseg.len = p->tot_len; + inseg.dataptr = p->payload; + inseg.p = p; + inseg.tcphdr = tcphdr; + + recv_data = NULL; + recv_flags = 0; + + tcp_input_pcb = pcb; + err = tcp_process(pcb); + tcp_input_pcb = NULL; + /* A return value of ERR_ABRT means that tcp_abort() was called + and that the pcb has been freed. If so, we don't do anything. */ + if (err != ERR_ABRT) { + if (recv_flags & TF_RESET) { + /* TF_RESET means that the connection was reset by the other + end. We then call the error callback to inform the + application that the connection is dead before we + deallocate the PCB. */ + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else if (recv_flags & TF_CLOSED) { + /* The connection has been closed and we will deallocate the + PCB. */ + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + err = ERR_OK; + /* If the application has registered a "sent" function to be + called when new send buffer space is available, we call it + now. */ + if (pcb->acked > 0) { + TCP_EVENT_SENT(pcb, pcb->acked, err); + } + + if (recv_data != NULL) { + /* Notify application that data has been received. */ + TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + } + + /* If a FIN segment was received, we call the callback + function with a NULL buffer to indicate EOF. */ + if (recv_flags & TF_GOT_FIN) { + TCP_EVENT_RECV(pcb, NULL, ERR_OK, err); + } + /* If there were no errors, we try to send something out. */ + if (err == ERR_OK) { + tcp_output(pcb); + } + } + } + + + /* We deallocate the incoming pbuf. If it was buffered by the + application, the application should have called pbuf_ref() to + increase the reference counter in the pbuf. If so, the buffer + isn't actually deallocated by the call to pbuf_free(), only the + reference count is decreased. */ + if (inseg.p != NULL) pbuf_free(inseg.p); +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + + } else { + + /* If no matching PCB was found, send a TCP RST (reset) to the + sender. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); + if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { + TCP_STATS_INC(tcp.proterr); + TCP_STATS_INC(tcp.drop); + tcp_rst(ackno, seqno + tcplen, + &(iphdr->dest), &(iphdr->src), + tcphdr->dest, tcphdr->src); + } + pbuf_free(p); + } + + LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); + PERF_STOP("tcp_input"); +} + +/* tcp_listen_input(): + * + * Called by tcp_input() when a segment arrives for a listening + * connection. + */ + +static err_t +tcp_listen_input(struct tcp_pcb_listen *pcb) +{ + struct tcp_pcb *npcb; + u32_t optdata; + + /* In the LISTEN state, we check for incoming SYN segments, + creates a new PCB, and responds with a SYN|ACK. */ + if (flags & TCP_ACK) { + /* For incoming segments with the ACK flag set, respond with a + RST. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); + tcp_rst(ackno + 1, seqno + tcplen, + &(iphdr->dest), &(iphdr->src), + tcphdr->dest, tcphdr->src); + } else if (flags & TCP_SYN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); + npcb = tcp_alloc(pcb->prio); + /* If a new PCB could not be created (probably due to lack of memory), + we don't do anything, but rely on the sender will retransmit the + SYN at a time when we have more memory available. */ + if (npcb == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + /* Set up the new PCB. */ + ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); + npcb->local_port = pcb->local_port; + ip_addr_set(&(npcb->remote_ip), &(iphdr->src)); + npcb->remote_port = tcphdr->src; + npcb->state = SYN_RCVD; + npcb->rcv_nxt = seqno + 1; + npcb->snd_wnd = tcphdr->wnd; + npcb->ssthresh = npcb->snd_wnd; + npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ + npcb->callback_arg = pcb->callback_arg; +#if LWIP_CALLBACK_API + npcb->accept = pcb->accept; +#endif /* LWIP_CALLBACK_API */ + /* inherit socket options */ + npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); + /* Register the new PCB so that we can begin receiving segments + for it. */ + TCP_REG(&tcp_active_pcbs, npcb); + + /* Parse any options in the SYN. */ + tcp_parseopt(npcb); + + /* Build an MSS option. */ + optdata = htonl(((u32_t)2 << 24) | + ((u32_t)4 << 16) | + (((u32_t)npcb->mss / 256) << 8) | + (npcb->mss & 255)); + /* Send a SYN|ACK together with the MSS option. */ + tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4); + return tcp_output(npcb); + } + return ERR_OK; +} + +/* tcp_timewait_input(): + * + * Called by tcp_input() when a segment arrives for a connection in + * TIME_WAIT. + */ + +static err_t +tcp_timewait_input(struct tcp_pcb *pcb) +{ + if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) { + pcb->rcv_nxt = seqno + tcplen; + } + if (tcplen > 0) { + tcp_ack_now(pcb); + } + return tcp_output(pcb); +} + +/* tcp_process + * + * Implements the TCP state machine. Called by tcp_input. In some + * states tcp_receive() is called to receive data. The tcp_seg + * argument will be freed by the caller (tcp_input()) unless the + * recv_data pointer in the pcb is set. + */ + +static err_t +tcp_process(struct tcp_pcb *pcb) +{ + struct tcp_seg *rseg; + u8_t acceptable = 0; + err_t err; + + + err = ERR_OK; + + /* Process incoming RST segments. */ + if (flags & TCP_RST) { + /* First, determine if the reset is acceptable. */ + if (pcb->state == SYN_SENT) { + if (ackno == pcb->snd_nxt) { + acceptable = 1; + } + } else { + /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) && + TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) { + */ + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { + acceptable = 1; + } + } + + if (acceptable) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); + LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); + recv_flags = TF_RESET; + pcb->flags &= ~TF_ACK_DELAY; + return ERR_RST; + } else { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + return ERR_OK; + } + } + + /* Update the PCB (in)activity timer. */ + pcb->tmr = tcp_ticks; + pcb->keep_cnt = 0; + + /* Do different things depending on the TCP state. */ + switch (pcb->state) { + case SYN_SENT: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, + pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); + /* received SYN ACK with expected sequence number? */ + if ((flags & TCP_ACK) && (flags & TCP_SYN) + && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { + pcb->snd_buf++; + pcb->rcv_nxt = seqno + 1; + pcb->lastack = ackno; + pcb->snd_wnd = tcphdr->wnd; + pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ + pcb->state = ESTABLISHED; + pcb->cwnd = pcb->mss; + --pcb->snd_queuelen; + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + rseg = pcb->unacked; + pcb->unacked = rseg->next; + tcp_seg_free(rseg); + + /* Parse any options in the SYNACK. */ + tcp_parseopt(pcb); + + /* Call the user specified function to call when sucessfully + * connected. */ + TCP_EVENT_CONNECTED(pcb, ERR_OK, err); + tcp_ack(pcb); + } + /* received ACK? possibly a half-open connection */ + else if (flags & TCP_ACK) { + /* send a RST to bring the other side in a non-synchronized state. */ + tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + tcphdr->dest, tcphdr->src); + } + break; + case SYN_RCVD: + if (flags & TCP_ACK && + !(flags & TCP_RST)) { + /* expected ACK number? */ + if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { + pcb->state = ESTABLISHED; + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +#if LWIP_CALLBACK_API + LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); +#endif + /* Call the accept function. */ + TCP_EVENT_ACCEPT(pcb, ERR_OK, err); + if (err != ERR_OK) { + /* If the accept function returns with an error, we abort + * the connection. */ + tcp_abort(pcb); + return ERR_ABRT; + } + /* If there was any data contained within this ACK, + * we'd better pass it on to the application as well. */ + tcp_receive(pcb); + pcb->cwnd = pcb->mss; + } + /* incorrect ACK number */ + else { + /* send RST */ + tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + tcphdr->dest, tcphdr->src); + } + } + break; + case CLOSE_WAIT: + /* FALLTHROUGH */ + case ESTABLISHED: + tcp_receive(pcb); + if (flags & TCP_FIN) { + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + break; + case FIN_WAIT_1: + tcp_receive(pcb); + if (flags & TCP_FIN) { + if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + LWIP_DEBUGF(TCP_DEBUG, + ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } else { + tcp_ack_now(pcb); + pcb->state = CLOSING; + } + } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + pcb->state = FIN_WAIT_2; + } + break; + case FIN_WAIT_2: + tcp_receive(pcb); + if (flags & TCP_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case CLOSING: + tcp_receive(pcb); + if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case LAST_ACK: + tcp_receive(pcb); + if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + pcb->state = CLOSED; + recv_flags = TF_CLOSED; + } + break; + default: + break; + } + return ERR_OK; +} + +/* tcp_receive: + * + * Called by tcp_process. Checks if the given segment is an ACK for outstanding + * data, and if so frees the memory of the buffered data. Next, is places the + * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment + * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until + * i it has been removed from the buffer. + * + * If the incoming segment constitutes an ACK for a segment that was used for RTT + * estimation, the RTT is estimated here as well. + */ + +static void +tcp_receive(struct tcp_pcb *pcb) +{ + struct tcp_seg *next; +#if TCP_QUEUE_OOSEQ + struct tcp_seg *prev, *cseg; +#endif + struct pbuf *p; + s32_t off; + s16_t m; + u32_t right_wnd_edge; + u16_t new_tot_len; + + + if (flags & TCP_ACK) { + right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1; + + /* Update window. */ + if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || + (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || + (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { + pcb->snd_wnd = tcphdr->wnd; + pcb->snd_wl1 = seqno; + pcb->snd_wl2 = ackno; + LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U32_F"\n", pcb->snd_wnd)); +#if TCP_WND_DEBUG + } else { + if (pcb->snd_wnd != tcphdr->wnd) { + LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", + pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); + } +#endif /* TCP_WND_DEBUG */ + } + + + if (pcb->lastack == ackno) { + pcb->acked = 0; + + if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){ + ++pcb->dupacks; + if (pcb->dupacks >= 3 && pcb->unacked != NULL) { + if (!(pcb->flags & TF_INFR)) { + /* This is fast retransmit. Retransmit the first unacked segment. */ + LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n", + (u16_t)pcb->dupacks, pcb->lastack, + ntohl(pcb->unacked->tcphdr->seqno))); + tcp_rexmit(pcb); + /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */ + /*pcb->ssthresh = LWIP_MAX((pcb->snd_max - + pcb->lastack) / 2, + 2 * pcb->mss);*/ + /* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */ + if(pcb->cwnd > pcb->snd_wnd) + pcb->ssthresh = pcb->snd_wnd / 2; + else + pcb->ssthresh = pcb->cwnd / 2; + + pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; + pcb->flags |= TF_INFR; + } else { + /* Inflate the congestion window, but not if it means that + the value overflows. */ + if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + } + } + } else { + LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n", + pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge)); + } + } else + /*if (TCP_SEQ_LT(pcb->lastack, ackno) && + TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */ + if(TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){ + /* We come here when the ACK acknowledges new data. */ + + /* Reset the "IN Fast Retransmit" flag, since we are no longer + in fast retransmit. Also reset the congestion window to the + slow start threshold. */ + if (pcb->flags & TF_INFR) { + pcb->flags &= ~TF_INFR; + pcb->cwnd = pcb->ssthresh; + } + + /* Reset the number of retransmissions. */ + pcb->nrtx = 0; + + /* Reset the retransmission time-out. */ + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + /* Update the send buffer space. */ + pcb->acked = ackno - pcb->lastack; + + pcb->snd_buf += pcb->acked; + + /* Reset the fast retransmit variables. */ + pcb->dupacks = 0; + pcb->lastack = ackno; + + /* Update the congestion control variables (cwnd and + ssthresh). */ + if (pcb->state >= ESTABLISHED) { + if (pcb->cwnd < pcb->ssthresh) { + if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd)); + } else { + u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); + if (new_cwnd > pcb->cwnd) { + pcb->cwnd = new_cwnd; + } + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd)); + } + } + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", + ackno, + pcb->unacked != NULL? + ntohl(pcb->unacked->tcphdr->seqno): 0, + pcb->unacked != NULL? + ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); + + /* Remove segment from the unacknowledged list if the incoming + ACK acknowlegdes them. */ + while (pcb->unacked != NULL && + TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked), ackno)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", + ntohl(pcb->unacked->tcphdr->seqno), + ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked))); + + next = pcb->unacked; + pcb->unacked = pcb->unacked->next; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); + pcb->snd_queuelen -= pbuf_clen(next->p); + tcp_seg_free(next); + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } + } + pcb->polltmr = 0; + } + + /* We go through the ->unsent list to see if any of the segments + on the list are acknowledged by the ACK. This may seem + strange since an "unsent" segment shouldn't be acked. The + rationale is that lwIP puts all outstanding segments on the + ->unsent list after a retransmission, so these segments may + in fact have been sent once. */ + while (pcb->unsent != NULL && + /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) && + TCP_SEQ_LEQ(ackno, pcb->snd_max)*/ + TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max) + ) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", + ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent))); + + next = pcb->unsent; + pcb->unsent = pcb->unsent->next; + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); + pcb->snd_queuelen -= pbuf_clen(next->p); + tcp_seg_free(next); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_receive: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + if (pcb->unsent != NULL) { + pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno); + } + } + /* End of ACK for new data processing. */ + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", + pcb->rttest, pcb->rtseq, ackno)); + + /* RTT estimation calculations. This is done by checking if the + incoming segment acknowledges the segment we use to take a + round-trip time measurement. */ + if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { + m = tcp_ticks - pcb->rttest; + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", + m, m * TCP_SLOW_INTERVAL)); + + /* This is taken directly from VJs original code in his paper */ + m = m - (pcb->sa >> 3); + pcb->sa += m; + if (m < 0) { + m = -m; + } + m = m - (pcb->sv >> 2); + pcb->sv += m; + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" miliseconds)\n", + pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); + + pcb->rttest = 0; + } + } + + /* If the incoming segment contains data, we must process it + further. */ + if (tcplen > 0) { + /* This code basically does three things: + + +) If the incoming segment contains data that is the next + in-sequence data, this data is passed to the application. This + might involve trimming the first edge of the data. The rcv_nxt + variable and the advertised window are adjusted. + + +) If the incoming segment has data that is above the next + sequence number expected (->rcv_nxt), the segment is placed on + the ->ooseq queue. This is done by finding the appropriate + place in the ->ooseq queue (which is ordered by sequence + number) and trim the segment in both ends if needed. An + immediate ACK is sent to indicate that we received an + out-of-sequence segment. + + +) Finally, we check if the first segment on the ->ooseq queue + now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If + rcv_nxt > ooseq->seqno, we must trim the first edge of the + segment on ->ooseq before we adjust rcv_nxt. The data in the + segments that are now on sequence are chained onto the + incoming segment so that we only need to call the application + once. + */ + + /* First, we check if we must trim the first edge. We have to do + this if the sequence number of the incoming segment is less + than rcv_nxt, and the sequence number plus the length of the + segment is larger than rcv_nxt. */ + /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ + if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ + if(TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno+1, seqno+tcplen-1)){ + /* Trimming the first edge is done by pushing the payload + pointer in the pbuf downwards. This is somewhat tricky since + we do not want to discard the full contents of the pbuf up to + the new starting point of the data since we have to keep the + TCP header which is present in the first pbuf in the chain. + + What is done is really quite a nasty hack: the first pbuf in + the pbuf chain is pointed to by inseg.p. Since we need to be + able to deallocate the whole pbuf, we cannot change this + inseg.p pointer to point to any of the later pbufs in the + chain. Instead, we point the ->payload pointer in the first + pbuf to data in one of the later pbufs. We also set the + inseg.data pointer to point to the right place. This way, the + ->p pointer will still point to the first pbuf, but the + ->p->payload pointer will point to data in another pbuf. + + After we are done with adjusting the pbuf pointers we must + adjust the ->data pointer in the seg and the segment + length.*/ + + off = pcb->rcv_nxt - seqno; + p = inseg.p; + if (inseg.p->len < off) { + new_tot_len = inseg.p->tot_len - off; + while (p->len < off) { + off -= p->len; + /* KJM following line changed (with addition of new_tot_len var) + to fix bug #9076 + inseg.p->tot_len -= p->len; */ + p->tot_len = new_tot_len; + p->len = 0; + p = p->next; + } + pbuf_header(p, -off); + } else { + pbuf_header(inseg.p, -off); + } + /* KJM following line changed to use p->payload rather than inseg->p->payload + to fix bug #9076 */ + inseg.dataptr = p->payload; + inseg.len -= pcb->rcv_nxt - seqno; + inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; + } + else{ + if(TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ + /* the whole segment is < rcv_nxt */ + /* must be a duplicate of a packet that has already been correctly handled */ + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); + tcp_ack_now(pcb); + } + } + + /* The sequence number must be within the window (above rcv_nxt + and below rcv_nxt + rcv_wnd) in order to be further + processed. */ + /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) && + TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ + if(TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){ + if (pcb->rcv_nxt == seqno) { + /* The incoming segment is the next in sequence. We check if + we have to trim the end of the segment and update rcv_nxt + and pass the data to the application. */ +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL && + TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) { + /* We have to trim the second edge of the incoming + segment. */ + inseg.len = pcb->ooseq->tcphdr->seqno - seqno; + pbuf_realloc(inseg.p, inseg.len); + } +#endif /* TCP_QUEUE_OOSEQ */ + + tcplen = TCP_TCPLEN(&inseg); + + /* First received FIN will be ACKed +1, on any successive (duplicate) + * FINs we are already in CLOSE_WAIT and have already done +1. + */ + if (pcb->state != CLOSE_WAIT) { + pcb->rcv_nxt += tcplen; + } + + /* Update the receiver's (our) window. */ + if (pcb->rcv_wnd < tcplen) { + pcb->rcv_wnd = 0; + } else { + pcb->rcv_wnd -= tcplen; + } + + /* If there is data in the segment, we make preparations to + pass this up to the application. The ->recv_data variable + is used for holding the pbuf that goes to the + application. The code for reassembling out-of-sequence data + chains its data on this pbuf as well. + + If the segment was a FIN, we set the TF_GOT_FIN flag that will + be used to indicate to the application that the remote side has + closed its end of the connection. */ + if (inseg.p->tot_len > 0) { + recv_data = inseg.p; + /* Since this pbuf now is the responsibility of the + application, we delete our reference to it so that we won't + (mistakingly) deallocate it. */ + inseg.p = NULL; + } + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); + recv_flags = TF_GOT_FIN; + } + +#if TCP_QUEUE_OOSEQ + /* We now check if we have segments on the ->ooseq queue that + is now in sequence. */ + while (pcb->ooseq != NULL && + pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { + + cseg = pcb->ooseq; + seqno = pcb->ooseq->tcphdr->seqno; + + pcb->rcv_nxt += TCP_TCPLEN(cseg); + if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) { + pcb->rcv_wnd = 0; + } else { + pcb->rcv_wnd -= TCP_TCPLEN(cseg); + } + if (cseg->p->tot_len > 0) { + /* Chain this pbuf onto the pbuf that we will pass to + the application. */ + if (recv_data) { + pbuf_cat(recv_data, cseg->p); + } else { + recv_data = cseg->p; + } + cseg->p = NULL; + } + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); + recv_flags = TF_GOT_FIN; + } + + + pcb->ooseq = cseg->next; + tcp_seg_free(cseg); + } +#endif /* TCP_QUEUE_OOSEQ */ + + + /* Acknowledge the segment(s). */ + tcp_ack(pcb); + + } else { + /* We get here if the incoming segment is out-of-sequence. */ + tcp_ack_now(pcb); +#if TCP_QUEUE_OOSEQ + /* We queue the segment on the ->ooseq queue. */ + if (pcb->ooseq == NULL) { + pcb->ooseq = tcp_seg_copy(&inseg); + } else { + /* If the queue is not empty, we walk through the queue and + try to find a place where the sequence number of the + incoming segment is between the sequence numbers of the + previous and the next segment on the ->ooseq queue. That is + the place where we put the incoming segment. If needed, we + trim the second edges of the previous and the incoming + segment so that it will fit into the sequence. + + If the incoming segment has the same sequence number as a + segment on the ->ooseq queue, we discard the segment that + contains less data. */ + + prev = NULL; + for(next = pcb->ooseq; next != NULL; next = next->next) { + if (seqno == next->tcphdr->seqno) { + /* The sequence number of the incoming segment is the + same as the sequence number of the segment on + ->ooseq. We check the lengths to see which one to + discard. */ + if (inseg.len > next->len) { + /* The incoming segment is larger than the old + segment. We replace the old segment with the new + one. */ + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + cseg->next = next->next; + if (prev != NULL) { + prev->next = cseg; + } else { + pcb->ooseq = cseg; + } + } + break; + } else { + /* Either the lenghts are the same or the incoming + segment was smaller than the old one; in either + case, we ditch the incoming segment. */ + break; + } + } else { + if (prev == NULL) { + if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { + /* The sequence number of the incoming segment is lower + than the sequence number of the first segment on the + queue. We put the incoming segment first on the + queue. */ + + if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + inseg.len = next->tcphdr->seqno - seqno; + pbuf_realloc(inseg.p, inseg.len); + } + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + cseg->next = next; + pcb->ooseq = cseg; + } + break; + } + } else + /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && + TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ + if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){ + /* The sequence number of the incoming segment is in + between the sequence numbers of the previous and + the next segment on ->ooseq. We trim and insert the + incoming segment and trim the previous segment, if + needed. */ + if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + inseg.len = next->tcphdr->seqno - seqno; + pbuf_realloc(inseg.p, inseg.len); + } + + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + cseg->next = next; + prev->next = cseg; + if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { + /* We need to trim the prev segment. */ + prev->len = seqno - prev->tcphdr->seqno; + pbuf_realloc(prev->p, prev->len); + } + } + break; + } + /* If the "next" segment is the last segment on the + ooseq queue, we add the incoming segment to the end + of the list. */ + if (next->next == NULL && + TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { + next->next = tcp_seg_copy(&inseg); + if (next->next != NULL) { + if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { + /* We need to trim the last segment. */ + next->len = seqno - next->tcphdr->seqno; + pbuf_realloc(next->p, next->len); + } + } + break; + } + } + prev = next; + } + } +#endif /* TCP_QUEUE_OOSEQ */ + + } + } else { + /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || + TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ + if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ + tcp_ack_now(pcb); + } + } + } else { + /* Segments with length 0 is taken care of here. Segments that + fall out of the window are ACKed. */ + /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || + TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ + if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ + tcp_ack_now(pcb); + } + } +} + +/* + * tcp_parseopt: + * + * Parses the options contained in the incoming segment. (Code taken + * from uIP with only small changes.) + * + */ + +static void +tcp_parseopt(struct tcp_pcb *pcb) +{ + u8_t c; + u8_t *opts, opt; + u16_t mss; + + opts = (u8_t *)tcphdr + TCP_HLEN; + + /* Parse the TCP MSS option, if present. */ + if(TCPH_HDRLEN(tcphdr) > 0x5) { + for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) { + opt = opts[c]; + if (opt == 0x00) { + /* End of options. */ + break; + } else if (opt == 0x01) { + ++c; + /* NOP option. */ + } else if (opt == 0x02 && + opts[c + 1] == 0x04) { + /* An MSS option with the right option length. */ + mss = (opts[c + 2] << 8) | opts[c + 3]; + pcb->mss = mss > TCP_MSS? TCP_MSS: mss; + + /* And we are done processing options. */ + break; + } else { + if (opts[c + 1] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + /* All other options have a length field, so that we easily + can skip past them. */ + c += opts[c + 1]; + } + } + } +} +#endif /* LWIP_TCP */ + + diff --git a/wii/libogc/lwip/core/tcp_out.c b/wii/libogc/lwip/core/tcp_out.c new file mode 100644 index 0000000000..edfdd8e7b4 --- /dev/null +++ b/wii/libogc/lwip/core/tcp_out.c @@ -0,0 +1,721 @@ +/** + * @file + * + * Transmission Control Protocol, outgoing traffic + * + * The output functions of TCP. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include + +#include "lwip/def.h" +#include "lwip/opt.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/stats.h" + +#if LWIP_TCP + +/* Forward declarations.*/ +static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); + +err_t +tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) +{ + /* no data, no length, flags, copy=1, no optdata, no optdatalen */ + return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0); +} + +/** + * Write data for sending (but does not send it immediately). + * + * It waits in the expectation of more data being sent soon (as + * it can send them more efficiently by combining them together). + * To prompt the system to send data now, call tcp_output() after + * calling tcp_write(). + * + * @arg pcb Protocol control block of the TCP connection to enqueue data for. + * + * @see tcp_write() + */ + +err_t +tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy) +{ + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%"U16_F", copy=%"U16_F")\n", (void *)pcb, + arg, len, (u16_t)copy)); + /* connection is in valid state for data transmission? */ + if (pcb->state == ESTABLISHED || + pcb->state == CLOSE_WAIT || + pcb->state == SYN_SENT || + pcb->state == SYN_RCVD) { + if (len > 0) { + return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0); + } + return ERR_OK; + } else { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n")); + return ERR_CONN; + } +} + +/** + * Enqueue either data or TCP options (but not both) for tranmission + * + * + * + * @arg pcb Protocol control block for the TCP connection to enqueue data for. + * @arg arg Pointer to the data to be enqueued for sending. + * @arg len Data length in bytes + * @arg flags + * @arg copy 1 if data must be copied, 0 if data is non-volatile and can be + * referenced. + * @arg optdata + * @arg optlen + */ +err_t +tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, + u8_t flags, u8_t copy, + u8_t *optdata, u8_t optlen) +{ + struct pbuf *p; + struct tcp_seg *seg, *useg, *queue; + u32_t left, seqno; + u16_t seglen; + void *ptr; + u16_t queuelen; + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", copy=%"U16_F")\n", + (void *)pcb, arg, len, (u16_t)flags, (u16_t)copy)); + LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)", + len == 0 || optlen == 0); + LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)", + arg == NULL || optdata == NULL); + /* fail on too much data */ + if (len > pcb->snd_buf) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf)); + return ERR_MEM; + } + left = len; + ptr = arg; + + /* seqno will be the sequence number of the first segment enqueued + * by the call to this function. */ + seqno = pcb->snd_lbb; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + + /* If total number of pbufs on the unsent/unacked queues exceeds the + * configured maximum, return an error */ + queuelen = pcb->snd_queuelen; + if (queuelen >= TCP_SND_QUEUELEN) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + if (queuelen != 0) { + LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty", + pcb->unacked != NULL || pcb->unsent != NULL); + } else { + LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty", + pcb->unacked == NULL && pcb->unsent == NULL); + } + + /* First, break up the data into segments and tuck them together in + * the local "queue" variable. */ + useg = queue = seg = NULL; + seglen = 0; + while (queue == NULL || left > 0) { + + /* The segment length should be the MSS if the data to be enqueued + * is larger than the MSS. */ + seglen = left > pcb->mss? pcb->mss: left; + + /* Allocate memory for tcp_seg, and fill in fields. */ + seg = memp_malloc(MEMP_TCP_SEG); + if (seg == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n")); + goto memerr; + } + seg->next = NULL; + seg->p = NULL; + + /* first segment of to-be-queued data? */ + if (queue == NULL) { + queue = seg; + } + /* subsequent segments of to-be-queued data */ + else { + /* Attach the segment to the end of the queued segments */ + LWIP_ASSERT("useg != NULL", useg != NULL); + useg->next = seg; + } + /* remember last segment of to-be-queued data for next iteration */ + useg = seg; + + /* If copy is set, memory should be allocated + * and data copied into pbuf, otherwise data comes from + * ROM or other static memory, and need not be copied. If + * optdata is != NULL, we have options instead of data. */ + + /* options? */ + if (optdata != NULL) { + if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + goto memerr; + } + ++queuelen; + seg->dataptr = seg->p->payload; + } + /* copy from volatile memory? */ + else if (copy) { + if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); + goto memerr; + } + ++queuelen; + if (arg != NULL) { + memcpy(seg->p->payload, ptr, seglen); + } + seg->dataptr = seg->p->payload; + } + /* do not copy data */ + else { + /* First, allocate a pbuf for holding the data. + * since the referenced data is available at least until it is sent out on the + * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM + * instead of PBUF_REF here. + */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } + ++queuelen; + /* reference the non-volatile payload data */ + p->payload = ptr; + seg->dataptr = ptr; + + /* Second, allocate a pbuf for the headers. */ + if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) { + /* If allocation fails, we have to deallocate the data pbuf as + * well. */ + pbuf_free(p); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n")); + goto memerr; + } + ++queuelen; + + /* Concatenate the headers and data pbufs together. */ + pbuf_cat(seg->p/*header*/, p/*data*/); + p = NULL; + } + + /* Now that there are more segments queued, we check again if the + length of the queue exceeds the configured maximum. */ + if (queuelen > TCP_SND_QUEUELEN) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); + goto memerr; + } + + seg->len = seglen; + + /* build TCP header */ + if (pbuf_header(seg->p, TCP_HLEN)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n")); + TCP_STATS_INC(tcp.err); + goto memerr; + } + seg->tcphdr = seg->p->payload; + seg->tcphdr->src = htons(pcb->local_port); + seg->tcphdr->dest = htons(pcb->remote_port); + seg->tcphdr->seqno = htonl(seqno); + seg->tcphdr->urgp = 0; + TCPH_FLAGS_SET(seg->tcphdr, flags); + /* don't fill in tcphdr->ackno and tcphdr->wnd until later */ + + /* Copy the options into the header, if they are present. */ + if (optdata == NULL) { + TCPH_HDRLEN_SET(seg->tcphdr, 5); + } + else { + TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4)); + /* Copy options into data portion of segment. + Options can thus only be sent in non data carrying + segments such as SYN|ACK. */ + memcpy(seg->dataptr, optdata, optlen); + } + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", + ntohl(seg->tcphdr->seqno), + ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), + (u16_t)flags)); + + left -= seglen; + seqno += seglen; + ptr = (void *)((u8_t *)ptr + seglen); + } + + /* Now that the data to be enqueued has been broken up into TCP + segments in the queue variable, we add them to the end of the + pcb->unsent queue. */ + if (pcb->unsent == NULL) { + useg = NULL; + } + else { + for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); + } + /* { useg is last segment on the unsent queue, NULL if list is empty } */ + + /* If there is room in the last pbuf on the unsent queue, + chain the first pbuf on the queue together with that. */ + if (useg != NULL && + TCP_TCPLEN(useg) != 0 && + !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && + !(flags & (TCP_SYN | TCP_FIN)) && + /* fit within max seg size */ + useg->len + queue->len <= pcb->mss) { + /* Remove TCP header from first segment of our to-be-queued list */ + pbuf_header(queue->p, -TCP_HLEN); + pbuf_cat(useg->p, queue->p); + useg->len += queue->len; + useg->next = queue->next; + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len)); + if (seg == queue) { + seg = NULL; + } + memp_free(MEMP_TCP_SEG, queue); + } + else { + /* empty list */ + if (useg == NULL) { + /* initialize list with this segment */ + pcb->unsent = queue; + } + /* enqueue segment */ + else { + useg->next = queue; + } + } + if ((flags & TCP_SYN) || (flags & TCP_FIN)) { + ++len; + } + pcb->snd_lbb += len; + + pcb->snd_buf -= len; + + /* update number of segments on the queues */ + pcb->snd_queuelen = queuelen; + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_enqueue: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + /* Set the PSH flag in the last segment that we enqueued, but only + if the segment has data (indicated by seglen > 0). */ + if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) { + TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); + } + + return ERR_OK; +memerr: + TCP_STATS_INC(tcp.memerr); + + if (queue != NULL) { + tcp_segs_free(queue); + } + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } + LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); + return ERR_MEM; +} + +/* find out what we can send and send it */ +err_t +tcp_output(struct tcp_pcb *pcb) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + struct tcp_seg *seg, *useg; + u32_t wnd; +#if TCP_CWND_DEBUG + s16_t i = 0; +#endif /* TCP_CWND_DEBUG */ + + /* First, check if we are invoked by the TCP input processing + code. If so, we do not output anything. Instead, we rely on the + input processing code to call us when input processing is done + with. */ + if (tcp_input_pcb == pcb) { + return ERR_OK; + } + + wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); + + seg = pcb->unsent; + + /* useg should point to last segment on unacked queue */ + useg = pcb->unacked; + if (useg != NULL) { + for (; useg->next != NULL; useg = useg->next); + } + + /* If the TF_ACK_NOW flag is set and no data will be sent (either + * because the ->unsent queue is empty or because the window does + * not allow it), construct an empty ACK segment and send it. + * + * If data is to be sent, we will just piggyback the ACK (see below). + */ + if (pcb->flags & TF_ACK_NOW && + (seg == NULL || + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); + return ERR_BUF; + } + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); + /* remove ACK flags from the PCB, as we send an empty ACK now */ + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + + tcphdr = p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dest = htons(pcb->remote_port); + tcphdr->seqno = htonl(pcb->snd_nxt); + tcphdr->ackno = htonl(pcb->rcv_nxt); + TCPH_FLAGS_SET(tcphdr, TCP_ACK); + tcphdr->wnd = htons(pcb->rcv_wnd); + tcphdr->urgp = 0; + TCPH_HDRLEN_SET(tcphdr, 5); + + tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP + tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), + IP_PROTO_TCP, p->tot_len); +#endif + ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, + IP_PROTO_TCP); + pbuf_free(p); + + return ERR_OK; + } + +#if TCP_OUTPUT_DEBUG + if (seg == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent)); + } +#endif /* TCP_OUTPUT_DEBUG */ +#if TCP_CWND_DEBUG + if (seg == NULL) { + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", seg == NULL, ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + pcb->lastack)); + } else { + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, + ntohl(seg->tcphdr->seqno), pcb->lastack)); + } +#endif /* TCP_CWND_DEBUG */ + /* data available and window allows it to be sent? */ + while (seg != NULL && + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { +#if TCP_CWND_DEBUG + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + ntohl(seg->tcphdr->seqno) + seg->len - + pcb->lastack, + ntohl(seg->tcphdr->seqno), pcb->lastack, i)); + ++i; +#endif /* TCP_CWND_DEBUG */ + + pcb->unsent = seg->next; + + if (pcb->state != SYN_SENT) { + TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + + tcp_output_segment(seg, pcb); + pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); + if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) { + pcb->snd_max = pcb->snd_nxt; + } + /* put segment on unacknowledged list if length > 0 */ + if (TCP_TCPLEN(seg) > 0) { + seg->next = NULL; + /* unacked list is empty? */ + if (pcb->unacked == NULL) { + pcb->unacked = seg; + useg = seg; + /* unacked list is not empty? */ + } else { + /* In the case of fast retransmit, the packet should not go to the tail + * of the unacked queue, but rather at the head. We need to check for + * this case. -STJ Jul 27, 2004 */ + if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){ + /* add segment to head of unacked list */ + seg->next = pcb->unacked; + pcb->unacked = seg; + } else { + /* add segment to tail of unacked list */ + useg->next = seg; + useg = useg->next; + } + } + /* do not queue empty segments on the unacked list */ + } else { + tcp_seg_free(seg); + } + seg = pcb->unsent; + } + return ERR_OK; +} + +/** + * Actually send a TCP segment over IP + */ +static void +tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) +{ + u16_t len; + struct netif *netif; + + /* The TCP header has already been constructed, but the ackno and + wnd fields remain. */ + seg->tcphdr->ackno = htonl(pcb->rcv_nxt); + + /* silly window avoidance */ + if (pcb->rcv_wnd < pcb->mss) { + seg->tcphdr->wnd = 0; + } else { + /* advertise our receive window size in this TCP segment */ + seg->tcphdr->wnd = htons(pcb->rcv_wnd); + } + + /* If we don't have a local IP address, we get one by + calling ip_route(). */ + if (ip_addr_isany(&(pcb->local_ip))) { + netif = ip_route(&(pcb->remote_ip)); + if (netif == NULL) { + return; + } + ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); + } + + pcb->rtime = 0; + + if (pcb->rttest == 0) { + pcb->rttest = tcp_ticks; + pcb->rtseq = ntohl(seg->tcphdr->seqno); + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); + } + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", + htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + + seg->len)); + + len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); + + seg->p->len -= len; + seg->p->tot_len -= len; + + seg->p->payload = seg->tcphdr; + + seg->tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP + seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, + &(pcb->local_ip), + &(pcb->remote_ip), + IP_PROTO_TCP, seg->p->tot_len); +#endif + TCP_STATS_INC(tcp.xmit); + + ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, + IP_PROTO_TCP); +} + +void +tcp_rst(u32_t seqno, u32_t ackno, + struct ip_addr *local_ip, struct ip_addr *remote_ip, + u16_t local_port, u16_t remote_port) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); + return; + } + + tcphdr = p->payload; + tcphdr->src = htons(local_port); + tcphdr->dest = htons(remote_port); + tcphdr->seqno = htonl(seqno); + tcphdr->ackno = htonl(ackno); + TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK); + tcphdr->wnd = htons(TCP_WND); + tcphdr->urgp = 0; + TCPH_HDRLEN_SET(tcphdr, 5); + + tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP + tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, + IP_PROTO_TCP, p->tot_len); +#endif + TCP_STATS_INC(tcp.xmit); + /* Send output with hardcoded TTL since we have no access to the pcb */ + ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); + pbuf_free(p); + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); +} + +/* requeue all unacked segments for retransmission */ +void +tcp_rexmit_rto(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + + if (pcb->unacked == NULL) { + return; + } + + /* Move all unacked segments to the head of the unsent queue */ + for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); + /* concatenate unsent queue after unacked queue */ + seg->next = pcb->unsent; + /* unsent queue is the concatenated queue (of unacked, unsent) */ + pcb->unsent = pcb->unacked; + /* unacked queue is now empty */ + pcb->unacked = NULL; + + pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); + /* increment number of retransmissions */ + ++pcb->nrtx; + + /* Don't take any RTT measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission */ + tcp_output(pcb); +} + +void +tcp_rexmit(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + + if (pcb->unacked == NULL) { + return; + } + + /* Move the first unacked segment to the unsent queue */ + seg = pcb->unacked->next; + pcb->unacked->next = pcb->unsent; + pcb->unsent = pcb->unacked; + pcb->unacked = seg; + + pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); + + ++pcb->nrtx; + + /* Don't take any rtt measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission. */ + tcp_output(pcb); + +} + + +void +tcp_keepalive(struct tcp_pcb *pcb) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), + ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt)); + + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); + + if(p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n")); + return; + } + + tcphdr = p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dest = htons(pcb->remote_port); + tcphdr->seqno = htonl(pcb->snd_nxt - 1); + tcphdr->ackno = htonl(pcb->rcv_nxt); + tcphdr->wnd = htons(pcb->rcv_wnd); + tcphdr->urgp = 0; + TCPH_HDRLEN_SET(tcphdr, 5); + + tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP + tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len); +#endif + TCP_STATS_INC(tcp.xmit); + + /* Send output to IP */ + ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); + + pbuf_free(p); + + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt)); +} + +#endif /* LWIP_TCP */ + + + + + + + + + diff --git a/wii/libogc/lwip/core/udp.c b/wii/libogc/lwip/core/udp.c new file mode 100644 index 0000000000..d1e0eacacd --- /dev/null +++ b/wii/libogc/lwip/core/udp.c @@ -0,0 +1,655 @@ +/** + * @file + * User Datagram Protocol module + * + */ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +/* udp.c + * + * The code for the User Datagram Protocol UDP. + * + */ + +#include + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "lwip/icmp.h" + +#include "lwip/stats.h" + +#include "arch/perf.h" +#include "lwip/snmp.h" + +/* The list of UDP PCBs */ +#if LWIP_UDP +/* was static, but we may want to access this from a socket layer */ +struct udp_pcb *udp_pcbs = NULL; + +static struct udp_pcb *pcb_cache = NULL; + +void +udp_init(void) +{ + udp_pcbs = pcb_cache = NULL; +} + +/** + * Process an incoming UDP datagram. + * + * Given an incoming UDP datagram (as a chain of pbufs) this function + * finds a corresponding UDP PCB and + * + * @param pbuf pbuf to be demultiplexed to a UDP PCB. + * @param netif network interface on which the datagram was received. + * + */ +void +udp_input(struct pbuf *p, struct netif *inp) +{ + struct udp_hdr *udphdr; + struct udp_pcb *pcb; + struct udp_pcb *uncon_pcb; + struct ip_hdr *iphdr; + u16_t src, dest; + u8_t local_match; + + PERF_START; + + UDP_STATS_INC(udp.recv); + + iphdr = p->payload; + + if (pbuf_header(p, -((s16_t)(UDP_HLEN + IPH_HL(iphdr) * 4)))) { + /* drop short packets */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); + UDP_STATS_INC(udp.lenerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + + udphdr = (struct udp_hdr *)((u8_t *)p->payload - UDP_HLEN); + + LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); + + src = ntohs(udphdr->src); + dest = ntohs(udphdr->dest); + + udp_debug_print(udphdr); + + /* print the UDP source and destination */ + LWIP_DEBUGF(UDP_DEBUG, ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", + ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest), + ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), + ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), + ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src))); + + local_match = 0; + uncon_pcb = NULL; + /* Iterate through the UDP pcb list for a matching pcb */ + for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + /* print the PCB local and remote address */ + LWIP_DEBUGF(UDP_DEBUG, ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", + ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), + ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, + ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), + ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port)); + + /* compare PCB local addr+port to UDP destination addr+port */ + if ((pcb->local_port == dest) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { + local_match = 1; + if ((uncon_pcb == NULL) && + ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { + /* the first unconnected matching PCB */ + uncon_pcb = pcb; + } + } + /* compare PCB remote addr+port to UDP source addr+port */ + if ((local_match != 0) && + (pcb->remote_port == src) && + (ip_addr_isany(&pcb->remote_ip) || + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) { + /* the first fully matching PCB */ + break; + } + } + /* no fully matching pcb found? then look for an unconnected pcb */ + if (pcb == NULL) { + pcb = uncon_pcb; + } + + /* Check checksum if this is a match or if it was directed at us. */ + if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) + { + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: calculating checksum\n")); + pbuf_header(p, UDP_HLEN); +#ifdef IPv6 + if (iphdr->nexthdr == IP_PROTO_UDPLITE) { +#else + if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { +#endif /* IPv4 */ + /* Do the UDP Lite checksum */ +#if CHECKSUM_CHECK_UDP + if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) { + LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } +#endif + } else { +#if CHECKSUM_CHECK_UDP + if (udphdr->chksum != 0) { + if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_UDP, p->tot_len) != 0) { + LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP datagram discarded due to failing checksum\n")); + + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + } +#endif + } + pbuf_header(p, -UDP_HLEN); + if (pcb != NULL) { + snmp_inc_udpindatagrams(); + /* callback */ + if (pcb->recv != NULL) + { + pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); + } + } else { + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n")); + + /* No match was found, send ICMP destination port unreachable unless + destination address was broadcast/multicast. */ + + if (!ip_addr_isbroadcast(&iphdr->dest, inp) && + !ip_addr_ismulticast(&iphdr->dest)) { + + /* adjust pbuf pointer */ + p->payload = iphdr; + icmp_dest_unreach(p, ICMP_DUR_PORT); + } + UDP_STATS_INC(udp.proterr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpnoports(); + pbuf_free(p); + } + } else { + pbuf_free(p); + } + end: + + PERF_STOP("udp_input"); +} + +/** + * Send data to a specified address using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param pbuf chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * + * If the PCB already has a remote address association, it will + * be restored after the data is sent. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_MEM. Out of memory. + * - ERR_RTE. Could not find route to destination address. + * + * @see udp_disconnect() udp_send() + */ +err_t +udp_sendto(struct udp_pcb *pcb, struct pbuf *p, + struct ip_addr *dst_ip, u16_t dst_port) +{ + err_t err; + /* temporary space for current PCB remote address */ + struct ip_addr pcb_remote_ip; + u16_t pcb_remote_port; + /* remember current remote peer address of PCB */ + pcb_remote_ip.addr = pcb->remote_ip.addr; + pcb_remote_port = pcb->remote_port; + /* copy packet destination address to PCB remote peer address */ + pcb->remote_ip.addr = dst_ip->addr; + pcb->remote_port = dst_port; + /* send to the packet destination address */ + err = udp_send(pcb, p); + /* restore PCB remote peer address */ + pcb->remote_ip.addr = pcb_remote_ip.addr; + pcb->remote_port = pcb_remote_port; + return err; +} + +/** + * Send data using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param pbuf chain of pbuf's to be sent. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_MEM. Out of memory. + * - ERR_RTE. Could not find route to destination address. + * + * @see udp_disconnect() udp_sendto() + */ +err_t +udp_send(struct udp_pcb *pcb, struct pbuf *p) +{ + struct udp_hdr *udphdr; + struct netif *netif; + struct ip_addr *src_ip; + err_t err; + struct pbuf *q; /* q will be sent down the stack */ + + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_send\n")); + + /* if the PCB is not yet bound to a port, bind it here */ + if (pcb->local_port == 0) { + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n")); + err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: forced port bind failed\n")); + return err; + } + } + /* find the outgoing network interface for this packet */ + netif = ip_route(&(pcb->remote_ip)); + /* no outgoing network interface could be found? */ + if (netif == NULL) { + LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", pcb->remote_ip.addr)); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } + + /* not enough space to add an UDP header to first pbuf in given p chain? */ + if (pbuf_header(p, UDP_HLEN)) { + /* allocate header in a seperate new pbuf */ + q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: could not allocate header\n")); + return ERR_MEM; + } + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + /* adding a header within p succeeded */ + } else { + /* first pbuf q equals given pbuf */ + q = p; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); + } + /* { q now represents the packet to be sent } */ + udphdr = q->payload; + udphdr->src = htons(pcb->local_port); + udphdr->dest = htons(pcb->remote_port); + /* in UDP, 0 checksum means 'no checksum' */ + udphdr->chksum = 0x0000; + + /* PCB local address is IP_ANY_ADDR? */ + if (ip_addr_isany(&pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = &(netif->ip_addr); + } else { + /* use UDP PCB local IP address as source address */ + src_ip = &(pcb->local_ip); + } + + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); + + /* UDP Lite protocol? */ + if (pcb->flags & UDP_FLAGS_UDPLITE) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); + /* set UDP message length in UDP header */ + udphdr->len = htons(pcb->chksum_len); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip), + IP_PROTO_UDP, pcb->chksum_len); + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; +#else + udphdr->chksum = 0x0000; +#endif + /* output to IP */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); + err = ip_output_if (q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); + /* UDP */ + } else { + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); + udphdr->len = htons(q->tot_len); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len); + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; + } +#else + udphdr->chksum = 0x0000; +#endif + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); + /* output to IP */ + err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); + } + /* TODO: must this be increased even if error occured? */ + snmp_inc_udpoutdatagrams(); + + /* did we chain a seperate header pbuf earlier? */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); q = NULL; + /* { p is still referenced by the caller, and will live on } */ + } + + UDP_STATS_INC(udp.xmit); + return err; +} + +/** + * Bind an UDP PCB. + * + * @param pcb UDP PCB to be bound with a local address ipaddr and port. + * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to + * bind to all local interfaces. + * @param port local UDP port to bind with. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_USE. The specified ipaddr and port are already bound to by + * another UDP PCB. + * + * @see udp_disconnect() + */ +err_t +udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + u8_t rebind; + + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = ")); + ip_addr_debug_print(UDP_DEBUG, ipaddr); + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %"U16_F")\n", port)); + + rebind = 0; + /* Check for double bind and rebind of the same pcb */ + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + /* is this UDP PCB already on active list? */ + if (pcb == ipcb) { + /* pcb may occur at most once in active list */ + LWIP_ASSERT("rebind == 0", rebind == 0); + /* pcb already in list, just rebind */ + rebind = 1; + } + +/* this code does not allow upper layer to share a UDP port for + listening to broadcast or multicast traffic (See SO_REUSE_ADDR and + SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR + combine with implementation of UDP PCB flags. Leon Woestenberg. */ +#ifdef LWIP_UDP_TODO + /* port matches that of PCB in list? */ + else if ((ipcb->local_port == port) && + /* IP address matches, or one is IP_ADDR_ANY? */ + (ip_addr_isany(&(ipcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { + /* other PCB already binds to this local IP and port */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); + return ERR_USE; + } +#endif + + } + + ip_addr_set(&pcb->local_ip, ipaddr); + /* no port specified? */ + if (port == 0) { +#ifndef UDP_LOCAL_PORT_RANGE_START +#define UDP_LOCAL_PORT_RANGE_START 4096 +#define UDP_LOCAL_PORT_RANGE_END 0x7fff +#endif + port = UDP_LOCAL_PORT_RANGE_START; + ipcb = udp_pcbs; + while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) { + if (ipcb->local_port == port) { + port++; + ipcb = udp_pcbs; + } else + ipcb = ipcb->next; + } + if (ipcb != NULL) { + /* no more ports available in local range */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); + return ERR_USE; + } + } + pcb->local_port = port; + /* pcb not active yet? */ + if (rebind == 0) { + /* place the PCB on the active list if not already there */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE, ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", + (u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff), + (u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff), + (u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff), + (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port)); + return ERR_OK; +} +/** + * Connect an UDP PCB. + * + * This will associate the UDP PCB with the remote address. + * + * @param pcb UDP PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * @param port remote UDP port to connect with. + * + * @return lwIP error code + * + * @see udp_disconnect() + */ +err_t +udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + + if (pcb->local_port == 0) { + err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) + return err; + } + + ip_addr_set(&pcb->remote_ip, ipaddr); + pcb->remote_port = port; + pcb->flags |= UDP_FLAGS_CONNECTED; +/** TODO: this functionality belongs in upper layers */ +#ifdef LWIP_UDP_TODO + /* Nail down local IP for netconn_addr()/getsockname() */ + if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) { + struct netif *netif; + + if ((netif = ip_route(&(pcb->remote_ip))) == NULL) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr)); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } + /** TODO: this will bind the udp pcb locally, to the interface which + is used to route output packets to the remote address. However, we + might want to accept incoming packets on any interface! */ + pcb->local_ip = netif->ip_addr; + } else if (ip_addr_isany(&pcb->remote_ip)) { + pcb->local_ip.addr = 0; + } +#endif + LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE, ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", + (u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff), + (u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff), + (u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff), + (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port)); + + /* Insert UDP PCB into the list of active UDP PCBs. */ + for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + if (pcb == ipcb) { + /* already on the list, just return */ + return ERR_OK; + } + } + /* PCB not yet on the list, add PCB now */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + return ERR_OK; +} + +void +udp_disconnect(struct udp_pcb *pcb) +{ + /* reset remote address association */ + ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY); + pcb->remote_port = 0; + /* mark PCB as unconnected */ + pcb->flags &= ~UDP_FLAGS_CONNECTED; +} + +void +udp_recv(struct udp_pcb *pcb, + void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, + struct ip_addr *addr, u16_t port), + void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} +/** + * Remove an UDP PCB. + * + * @param pcb UDP PCB to be removed. The PCB is removed from the list of + * UDP PCB's and the data structure is freed from memory. + * + * @see udp_new() + */ +void +udp_remove(struct udp_pcb *pcb) +{ + struct udp_pcb *pcb2; + /* pcb to be removed is first in list? */ + if (udp_pcbs == pcb) { + /* make list start at 2nd pcb */ + udp_pcbs = udp_pcbs->next; + /* pcb not 1st in list */ + } else for(pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in udp_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + } + } + memp_free(MEMP_UDP_PCB, pcb); +} +/** + * Create a UDP PCB. + * + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * +udp_new(void) { + struct udp_pcb *pcb; + pcb = memp_malloc(MEMP_UDP_PCB); + /* could allocate UDP PCB? */ + if (pcb != NULL) { + /* initialize PCB to all zeroes */ + memset(pcb, 0, sizeof(struct udp_pcb)); + pcb->ttl = UDP_TTL; + } + + + return pcb; +} + +#if UDP_DEBUG +void +udp_debug_print(struct udp_hdr *udphdr) +{ + LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + ntohs(udphdr->src), ntohs(udphdr->dest))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", + ntohs(udphdr->len), ntohs(udphdr->chksum))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* UDP_DEBUG */ + +#endif /* LWIP_UDP */ + + + + + + + + + diff --git a/wii/libogc/lwip/netif/etharp.c b/wii/libogc/lwip/netif/etharp.c new file mode 100644 index 0000000000..4d4ebdbe15 --- /dev/null +++ b/wii/libogc/lwip/netif/etharp.c @@ -0,0 +1,831 @@ +/** + * @file + * Address Resolution Protocol module for IP over Ethernet + * + * Functionally, ARP is divided into two parts. The first maps an IP address + * to a physical address when sending a packet, and the second part answers + * requests from other machines for our physical address. + * + * This implementation complies with RFC 826 (Ethernet ARP). It supports + * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 + * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon + * address change. + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/ip.h" +#include "lwip/stats.h" + +/* ARP needs to inform DHCP of any ARP replies? */ +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) +# include "lwip/dhcp.h" +#endif + +/** the time an ARP entry stays valid after its last update, + * (240 * 5) seconds = 20 minutes. + */ +#define ARP_MAXAGE 240 +/** the time an ARP entry stays pending after first request, + * (2 * 5) seconds = 10 seconds. + * + * @internal Keep this number at least 2, otherwise it might + * run out instantly if the timeout occurs directly after a request. + */ +#define ARP_MAXPENDING 2 + +#define HWTYPE_ETHERNET 1 + +/** ARP message types */ +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8) +#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff) + +#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8)) +#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8)) + +enum etharp_state { + ETHARP_STATE_EMPTY, + ETHARP_STATE_PENDING, + ETHARP_STATE_STABLE, + /** @internal transitional state used in etharp_tmr() for convenience*/ + ETHARP_STATE_EXPIRED +}; + +struct etharp_entry { +#if ARP_QUEUEING + /** + * Pointer to queue of pending outgoing packets on this ARP entry. + */ + struct pbuf *p; +#endif + struct ip_addr ipaddr; + struct eth_addr ethaddr; + enum etharp_state state; + u8_t ctime; +}; + +static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static struct etharp_entry arp_table[ARP_TABLE_SIZE]; + +/** + * Try hard to create a new entry - we want the IP address to appear in + * the cache (even if this means removing an active entry or so). */ +#define ETHARP_TRY_HARD 1 + +static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags); +static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); +/** + * Initializes ARP module. + */ +void +etharp_init(void) +{ + u8_t i; + /* clear ARP entries */ + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + arp_table[i].state = ETHARP_STATE_EMPTY; +#if ARP_QUEUEING + arp_table[i].p = NULL; +#endif + arp_table[i].ctime = 0; + } +} + +/** + * Clears expired entries in the ARP table. + * + * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds), + * in order to expire entries in the ARP table. + */ +void +etharp_tmr(void) +{ + u8_t i; + + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); + /* remove expired entries from the ARP table */ + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + arp_table[i].ctime++; + /* stable entry? */ + if ((arp_table[i].state == ETHARP_STATE_STABLE) && + /* entry has become old? */ + (arp_table[i].ctime >= ARP_MAXAGE)) { + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %"U16_F".\n", (u16_t)i)); + arp_table[i].state = ETHARP_STATE_EXPIRED; + /* pending entry? */ + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* entry unresolved/pending for too long? */ + if (arp_table[i].ctime >= ARP_MAXPENDING) { + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i)); + arp_table[i].state = ETHARP_STATE_EXPIRED; +#if ARP_QUEUEING + } else if (arp_table[i].p != NULL) { + /* resend an ARP query here */ +#endif + } + } + /* clean up entries that have just been expired */ + if (arp_table[i].state == ETHARP_STATE_EXPIRED) { +#if ARP_QUEUEING + /* and empty packet queue */ + if (arp_table[i].p != NULL) { + /* remove all queued packets */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].p))); + pbuf_free(arp_table[i].p); + arp_table[i].p = NULL; + } +#endif + /* recycle entry for re-use */ + arp_table[i].state = ETHARP_STATE_EMPTY; + } + } +} + +/** + * Search the ARP table for a matching or new entry. + * + * If an IP address is given, return a pending or stable ARP entry that matches + * the address. If no match is found, create a new entry with this address set, + * but in state ETHARP_EMPTY. The caller must check and possibly change the + * state of the returned entry. + * + * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. + * + * In all cases, attempt to create new entries from an empty entry. If no + * empty entries are available and ETHARP_TRY_HARD flag is set, recycle + * old entries. Heuristic choose the least important entry for recycling. + * + * @param ipaddr IP address to find in ARP cache, or to add if not found. + * @param flags + * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of + * active (stable or pending) entries. + * + * @return The ARP entry index that matched or is created, ERR_MEM if no + * entry is found or could be recycled. + */ +static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags) +{ + s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; + s8_t empty = ARP_TABLE_SIZE; + u8_t i = 0, age_pending = 0, age_stable = 0; +#if ARP_QUEUEING + /* oldest entry with packets on queue */ + s8_t old_queue = ARP_TABLE_SIZE; + /* its age */ + u8_t age_queue = 0; +#endif + + /** + * a) do a search through the cache, remember candidates + * b) select candidate entry + * c) create new entry + */ + + /* a) in a single search sweep, do all of this + * 1) remember the first empty entry (if any) + * 2) remember the oldest stable entry (if any) + * 3) remember the oldest pending entry without queued packets (if any) + * 4) remember the oldest pending entry with queued packets (if any) + * 5) search for a matching IP entry, either pending or stable + * until 5 matches, or all entries are searched for. + */ + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + /* no empty entry found yet and now we do find one? */ + if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) { + LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); + /* remember first empty entry */ + empty = i; + } + /* pending entry? */ + else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* if given, does IP address match IP address in ARP entry? */ + if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i)); + /* found exact IP address match, simply bail out */ + return i; +#if ARP_QUEUEING + /* pending with queued packets? */ + } else if (arp_table[i].p != NULL) { + if (arp_table[i].ctime >= age_queue) { + old_queue = i; + age_queue = arp_table[i].ctime; + } +#endif + /* pending without queued packets? */ + } else { + if (arp_table[i].ctime >= age_pending) { + old_pending = i; + age_pending = arp_table[i].ctime; + } + } + } + /* stable entry? */ + else if (arp_table[i].state == ETHARP_STATE_STABLE) { + /* if given, does IP address match IP address in ARP entry? */ + if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i)); + /* found exact IP address match, simply bail out */ + return i; + /* remember entry with oldest stable entry in oldest, its age in maxtime */ + } else if (arp_table[i].ctime >= age_stable) { + old_stable = i; + age_stable = arp_table[i].ctime; + } + } + } + /* { we have no match } => try to create a new entry */ + + /* no empty entry found and not allowed to recycle? */ + if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0)) + { + return (s8_t)ERR_MEM; + } + + /* b) choose the least destructive entry to recycle: + * 1) empty entry + * 2) oldest stable entry + * 3) oldest pending entry without queued packets + * 4) oldest pending entry without queued packets + * + * { ETHARP_TRY_HARD is set at this point } + */ + + /* 1) empty entry available? */ + if (empty < ARP_TABLE_SIZE) { + i = empty; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); + } + /* 2) found recyclable stable entry? */ + else if (old_stable < ARP_TABLE_SIZE) { + /* recycle oldest stable*/ + i = old_stable; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); +#if ARP_QUEUEING + /* no queued packets should exist on stable entries */ + LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL); +#endif + /* 3) found recyclable pending entry without queued packets? */ + } else if (old_pending < ARP_TABLE_SIZE) { + /* recycle oldest pending */ + i = old_pending; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); +#if ARP_QUEUEING + /* 4) found recyclable pending entry with queued packets? */ + } else if (old_queue < ARP_TABLE_SIZE) { + /* recycle oldest pending */ + i = old_queue; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].p))); + pbuf_free(arp_table[i].p); + arp_table[i].p = NULL; +#endif + /* no empty or recyclable entries found */ + } else { + return (s8_t)ERR_MEM; + } + + /* { empty or recyclable entry found } */ + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + + /* recycle entry (no-op for an already empty entry) */ + arp_table[i].state = ETHARP_STATE_EMPTY; + + /* IP address given? */ + if (ipaddr != NULL) { + /* set IP address */ + ip_addr_set(&arp_table[i].ipaddr, ipaddr); + } + arp_table[i].ctime = 0; + return (err_t)i; +} + +/** + * Update (or insert) a IP/MAC address pair in the ARP cache. + * + * If a pending entry is resolved, any queued packets will be sent + * at this point. + * + * @param ipaddr IP address of the inserted ARP entry. + * @param ethaddr Ethernet address of the inserted ARP entry. + * @param flags Defines behaviour: + * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified, + * only existing ARP entries will be updated. + * + * @return + * - ERR_OK Succesfully updated ARP cache. + * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set. + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + * @see pbuf_free() + */ +static err_t +update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) +{ + s8_t i, k; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n")); + LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0); + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), + ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], + ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); + /* non-unicast address? */ + if (ip_addr_isany(ipaddr) || + ip_addr_isbroadcast(ipaddr, netif) || + ip_addr_ismulticast(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + /* find or create ARP entry */ + i = find_entry(ipaddr, flags); + /* bail out if no entry could be found */ + if (i < 0) return (err_t)i; + + /* mark it stable */ + arp_table[i].state = ETHARP_STATE_STABLE; + + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); + /* update address */ + for (k = 0; k < netif->hwaddr_len; ++k) { + arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; + } + /* reset time stamp */ + arp_table[i].ctime = 0; +/* this is where we will send out queued packets! */ +#if ARP_QUEUEING + while (arp_table[i].p != NULL) { + /* get the first packet on the queue */ + struct pbuf *p = arp_table[i].p; + /* Ethernet header */ + struct eth_hdr *ethhdr = p->payload; + /* remember (and reference) remainder of queue */ + /* note: this will also terminate the p pbuf chain */ + arp_table[i].p = pbuf_dequeue(p); + /* fill-in Ethernet header */ + for (k = 0; k < netif->hwaddr_len; ++k) { + ethhdr->dest.addr[k] = ethaddr->addr[k]; + ethhdr->src.addr[k] = netif->hwaddr[k]; + } + ethhdr->type = htons(ETHTYPE_IP); + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p)); + /* send the queued IP packet */ + netif->linkoutput(netif, p); + /* free the queued IP packet */ + pbuf_free(p); + } +#endif + return ERR_OK; +} + +/** + * Updates the ARP table using the given IP packet. + * + * Uses the incoming IP packet's source address to update the + * ARP cache for the local network. The function does not alter + * or free the packet. This function must be called before the + * packet p is passed to the IP layer. + * + * @param netif The lwIP network interface on which the IP packet pbuf arrived. + * @param pbuf The IP packet that arrived on netif. + * + * @return NULL + * + * @see pbuf_free() + */ +void +etharp_ip_input(struct netif *netif, struct pbuf *p) +{ + struct ethip_hdr *hdr; + LWIP_ASSERT("netif != NULL", netif != NULL); + /* Only insert an entry if the source IP address of the + incoming IP packet comes from a host on the local network. */ + hdr = p->payload; + /* source is not on the local network? */ + if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { + /* do nothing */ + return; + } + + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); + /* update ARP table */ + /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk + * back soon (for example, if the destination IP address is ours. */ + update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0); +} + + +/** + * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache + * send out queued IP packets. Updates cache with snooped address pairs. + * + * Should be called for incoming ARP packets. The pbuf in the argument + * is freed by this function. + * + * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * @param pbuf The ARP packet that arrived on netif. Is freed by this function. + * @param ethaddr Ethernet address of netif. + * + * @return NULL + * + * @see pbuf_free() + */ +void +etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) +{ + struct etharp_hdr *hdr; + /* these are aligned properly, whereas the ARP header fields might not be */ + struct ip_addr sipaddr, dipaddr; + u8_t i; + u8_t for_us; + + LWIP_ASSERT("netif != NULL", netif != NULL); + + /* drop short ARP packets */ + if (p->tot_len < sizeof(struct etharp_hdr)) { + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, sizeof(struct etharp_hdr))); + pbuf_free(p); + return; + } + + hdr = p->payload; + + /* get aligned copies of addresses */ + *(struct ip_addr2 *)((void*)&sipaddr) = hdr->sipaddr; + *(struct ip_addr2 *)((void*)&dipaddr) = hdr->dipaddr; + + /* this interface is not configured? */ + if (netif->ip_addr.addr == 0) { + for_us = 0; + } else { + /* ARP packet directed to us? */ + for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr)); + } + + /* ARP message directed to us? */ + if (for_us) { + /* add IP address in ARP cache; assume requester wants to talk to us. + * can result in directly sending the queued packets for this host. */ + update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD); + /* ARP message not directed to us? */ + } else { + /* update the source IP address in the cache, if present */ + update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0); + } + + /* now act on the message itself */ + switch (htons(hdr->opcode)) { + /* ARP request? */ + case ARP_REQUEST: + /* ARP request. If it asked for our address, we send out a + * reply. In any case, we time-stamp any existing ARP entry, + * and possiby send out an IP packet that was queued on it. */ + + LWIP_DEBUGF (ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); + /* ARP request for our address? */ + if (for_us) { + + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); + /* re-use pbuf to send ARP reply */ + hdr->opcode = htons(ARP_REPLY); + + hdr->dipaddr = hdr->sipaddr; + hdr->sipaddr = *(struct ip_addr2 *)((void*)&netif->ip_addr); + + for(i = 0; i < netif->hwaddr_len; ++i) { + hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; + hdr->shwaddr.addr[i] = ethaddr->addr[i]; + hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i]; + hdr->ethhdr.src.addr[i] = ethaddr->addr[i]; + } + + hdr->hwtype = htons(HWTYPE_ETHERNET); + ARPH_HWLEN_SET(hdr, netif->hwaddr_len); + + hdr->proto = htons(ETHTYPE_IP); + ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); + + hdr->ethhdr.type = htons(ETHTYPE_ARP); + /* return ARP reply */ + netif->linkoutput(netif, p); + /* we are not configured? */ + } else if (netif->ip_addr.addr == 0) { + /* { for_us == 0 and netif->ip_addr.addr == 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); + /* request was not directed to us */ + } else { + /* { for_us == 0 and netif->ip_addr.addr != 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); + } + break; + case ARP_REPLY: + /* ARP reply. We already updated the ARP cache earlier. */ + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) + /* DHCP wants to know about ARP replies from any host with an + * IP address also offered to us by the DHCP server. We do not + * want to take a duplicate IP address on a single network. + * @todo How should we handle redundant (fail-over) interfaces? + * */ + dhcp_arp_reply(netif, &sipaddr); +#endif + break; + default: + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); + break; + } + /* free ARP packet */ + pbuf_free(p); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing packet. + * + * For IP multicast and broadcast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, the packet is submitted to etharp_query(). In + * case the IP address is outside the local network, the IP address of + * the gateway is used. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param ipaddr The IP address of the packet destination. + * @param pbuf The pbuf(s) containing the IP packet to be sent. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or netif->linkoutput(). + */ +err_t +etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) +{ + struct eth_addr *dest, *srcaddr, mcastaddr; + struct eth_hdr *ethhdr; + u8_t i; + + /* make room for Ethernet header - should not fail */ + if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { + /* bail out */ + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n")); + LINK_STATS_INC(link.lenerr); + return ERR_BUF; + } + + /* assume unresolved Ethernet address */ + dest = NULL; + /* Determine on destination hardware address. Broadcasts and multicasts + * are special, other IP addresses are looked up in the ARP table. */ + + /* broadcast destination IP address? */ + if (ip_addr_isbroadcast(ipaddr, netif)) { + /* broadcast on Ethernet also */ + dest = (struct eth_addr *)ðbroadcast; + /* multicast destination IP address? */ + } else if (ip_addr_ismulticast(ipaddr)) { + /* Hash IP multicast address to MAC address.*/ + mcastaddr.addr[0] = 0x01; + mcastaddr.addr[1] = 0x00; + mcastaddr.addr[2] = 0x5e; + mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; + mcastaddr.addr[4] = ip4_addr3(ipaddr); + mcastaddr.addr[5] = ip4_addr4(ipaddr); + /* destination Ethernet address is multicast */ + dest = &mcastaddr; + /* unicast destination IP address? */ + } else { + /* outside local network? */ + if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { + /* interface has default gateway? */ + if (netif->gw.addr != 0) { + /* send to hardware address of default gateway IP address */ + ipaddr = &(netif->gw); + /* no default gateway available */ + } else { + /* no route to destination error (default gateway missing) */ + return ERR_RTE; + } + } + /* queue on destination Ethernet address belonging to ipaddr */ + return etharp_query(netif, ipaddr, q); + } + + /* continuation for multicast/broadcast destinations */ + /* obtain source Ethernet address of the given interface */ + srcaddr = (struct eth_addr *)netif->hwaddr; + ethhdr = q->payload; + for (i = 0; i < netif->hwaddr_len; i++) { + ethhdr->dest.addr[i] = dest->addr[i]; + ethhdr->src.addr[i] = srcaddr->addr[i]; + } + ethhdr->type = htons(ETHTYPE_IP); + /* send packet directly on the link */ + return netif->linkoutput(netif, q); +} + +/** + * Send an ARP request for the given IP address and/or queue a packet. + * + * If the IP address was not yet in the cache, a pending ARP cache entry + * is added and an ARP request is sent for the given address. The packet + * is queued on this entry. + * + * If the IP address was already pending in the cache, a new ARP request + * is sent for the given address. The packet is queued on this entry. + * + * If the IP address was already stable in the cache, and a packet is + * given, it is directly sent and no ARP request is sent out. + * + * If the IP address was already stable in the cache, and no packet is + * given, an ARP request is sent out. + * + * @param netif The lwIP network interface on which ipaddr + * must be queried for. + * @param ipaddr The IP address to be resolved. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. + * q is not freed by this function. + * + * @return + * - ERR_BUF Could not make room for Ethernet header. + * - ERR_MEM Hardware address unknown, and no more ARP entries available + * to query for address or queue the packet. + * - ERR_MEM Could not queue packet due to memory shortage. + * - ERR_RTE No route to destination (no gateway to external networks). + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + */ +err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) +{ + struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; + err_t result = ERR_MEM; + s8_t i; /* ARP entry index */ + u8_t k; /* Ethernet address octet index */ + + /* non-unicast address? */ + if (ip_addr_isbroadcast(ipaddr, netif) || + ip_addr_ismulticast(ipaddr) || + ip_addr_isany(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + + /* find entry in ARP cache, ask to create entry if queueing packet */ + i = find_entry(ipaddr, ETHARP_TRY_HARD); + + /* could not find or create entry? */ + if (i < 0) + { + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n")); + if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n")); + return (err_t)i; + } + + /* mark a fresh entry as pending (we just sent a request) */ + if (arp_table[i].state == ETHARP_STATE_EMPTY) { + arp_table[i].state = ETHARP_STATE_PENDING; + } + + /* { i is either a STABLE or (new or existing) PENDING entry } */ + LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", + ((arp_table[i].state == ETHARP_STATE_PENDING) || + (arp_table[i].state == ETHARP_STATE_STABLE))); + + /* do we have a pending entry? or an implicit query request? */ + if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { + /* try to resolve it; send out ARP request */ + result = etharp_request(netif, ipaddr); + } + + /* packet given? */ + if (q != NULL) { + /* stable entry? */ + if (arp_table[i].state == ETHARP_STATE_STABLE) { + /* we have a valid IP->Ethernet address mapping, + * fill in the Ethernet header for the outgoing packet */ + struct eth_hdr *ethhdr = q->payload; + for(k = 0; k < netif->hwaddr_len; k++) { + ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k]; + ethhdr->src.addr[k] = srcaddr->addr[k]; + } + ethhdr->type = htons(ETHTYPE_IP); + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q)); + /* send the packet */ + result = netif->linkoutput(netif, q); + /* pending entry? (either just created or already pending */ + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { +#if ARP_QUEUEING /* queue the given q packet */ + struct pbuf *p; + /* copy any PBUF_REF referenced payloads into PBUF_RAM */ + /* (the caller of lwIP assumes the referenced payload can be + * freed after it returns from the lwIP call that brought us here) */ + p = pbuf_take(q); + /* packet could be taken over? */ + if (p != NULL) { + /* queue packet ... */ + if (arp_table[i].p == NULL) { + /* ... in the empty queue */ + pbuf_ref(p); + arp_table[i].p = p; +#if 0 /* multi-packet-queueing disabled, see bug #11400 */ + } else { + /* ... at tail of non-empty queue */ + pbuf_queue(arp_table[i].p, p); +#endif + } + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + result = ERR_OK; + } else { + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + /* { result == ERR_MEM } through initialization */ + } +#else /* ARP_QUEUEING == 0 */ + /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */ + /* { result == ERR_MEM } through initialization */ + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q)); +#endif + } + } + return result; +} + +err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr) +{ + struct pbuf *p; + struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; + err_t result = ERR_OK; + u8_t k; /* ARP entry index */ + + /* allocate a pbuf for the outgoing ARP request packet */ + p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); + /* could allocate a pbuf for an ARP request? */ + if (p != NULL) { + struct etharp_hdr *hdr = p->payload; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n")); + hdr->opcode = htons(ARP_REQUEST); + for (k = 0; k < netif->hwaddr_len; k++) + { + hdr->shwaddr.addr[k] = srcaddr->addr[k]; + /* the hardware address is what we ask for, in + * a request it is a don't-care value, we use zeroes */ + hdr->dhwaddr.addr[k] = 0x00; + } + hdr->dipaddr = *(struct ip_addr2 *)ipaddr; + hdr->sipaddr = *(struct ip_addr2 *)((void*)&netif->ip_addr); + + hdr->hwtype = htons(HWTYPE_ETHERNET); + ARPH_HWLEN_SET(hdr, netif->hwaddr_len); + + hdr->proto = htons(ETHTYPE_IP); + ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); + for (k = 0; k < netif->hwaddr_len; ++k) + { + /* broadcast to all network interfaces on the local network */ + hdr->ethhdr.dest.addr[k] = 0xff; + hdr->ethhdr.src.addr[k] = srcaddr->addr[k]; + } + hdr->ethhdr.type = htons(ETHTYPE_ARP); + /* send ARP query */ + result = netif->linkoutput(netif, p); + /* free ARP query packet */ + pbuf_free(p); + p = NULL; + /* could not allocate pbuf for ARP request */ + } else { + result = ERR_MEM; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n")); + } + return result; +} diff --git a/wii/libogc/lwip/netif/loopif.c b/wii/libogc/lwip/netif/loopif.c new file mode 100644 index 0000000000..d37e3e8ce9 --- /dev/null +++ b/wii/libogc/lwip/netif/loopif.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include +#include "lwp_watchdog.h" +#include "lwip/opt.h" + +#if LWIP_HAVE_LOOPIF + +#include "netif/loopif.h" +#include "lwip/mem.h" + +#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP) +#include "netif/tcpdump.h" +#endif /* LWIP_DEBUG && LWIP_TCPDUMP */ + +#include "lwip/tcp.h" +#include "lwip/ip.h" + +#include "lwp_watchdog.h" + +#define LOOP_TIMER_ID 0x00070045 + +static u64 loopif_ticks; +static wd_cntrl loopif_tmr_cntrl; + +extern unsigned int timespec_to_interval(const struct timespec *); + +static void +loopif_input( void * arg ) +{ + struct netif *netif = (struct netif*)(((void**)arg)[0]); + struct pbuf *r = (struct pbuf*)(((void**)arg)[1]); + + mem_free(arg); + netif->input(r,netif); +} + +static err_t +loopif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + struct pbuf *q, *r; + char *ptr; + void **arg; + +#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP) + tcpdump(p); +#endif /* LWIP_DEBUG && LWIP_TCPDUMP */ + + r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (r != NULL) { + ptr = r->payload; + + for(q = p; q != NULL; q = q->next) { + memcpy(ptr, q->payload, q->len); + ptr += q->len; + } + + arg = mem_malloc( sizeof( void *[2])); + if( NULL == arg ) { + return ERR_MEM; + } + + arg[0] = netif; + arg[1] = r; + /** + * workaround (patch #1779) to try to prevent bug #2595: + * When connecting to "localhost" with the loopif interface, + * tcp_output doesn't get the opportunity to finnish sending the + * segment before tcp_process gets it, resulting in tcp_process + * referencing pcb->unacked-> which still is NULL. + * + * TODO: Is there still a race condition here? Leon + */ + __lwp_wd_initialize(&loopif_tmr_cntrl,loopif_input,LOOP_TIMER_ID,arg); + __lwp_wd_insert_ticks(&loopif_tmr_cntrl,loopif_ticks); + + return ERR_OK; + } + return ERR_MEM; +} + +err_t +loopif_init(struct netif *netif) +{ + struct timespec tb; + + netif->name[0] = 'l'; + netif->name[1] = 'o'; +#if 0 /** TODO: I think this should be enabled, or not? Leon */ + netif->input = loopif_input; +#endif + netif->output = loopif_output; + + tb.tv_sec = 0; + tb.tv_nsec = 10*TB_NSPERMS; + loopif_ticks = __lwp_wd_calc_ticks(&tb); + + return ERR_OK; +} + +#endif /* LWIP_HAVE_LOOPIF */ + + + + + + + diff --git a/wii/libogc/lwip/netif/skeleton/ethernetif.c b/wii/libogc/lwip/netif/skeleton/ethernetif.c new file mode 100644 index 0000000000..7cd04ece5e --- /dev/null +++ b/wii/libogc/lwip/netif/skeleton/ethernetif.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + +#include "netif/etharp.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +struct ethernetif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ +}; + +static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; + +/* Forward declarations. */ +static void ethernetif_input(struct netif *netif); +static err_t ethernetif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr); + + +static void +low_level_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + ethernetif = netif->state; + + /* set MAC hardware address length */ + netif->hwaddr_len = 6; + + /* set MAC hardware address */ + netif->hwaddr[0] = ; + ... + netif->hwaddr[5] = ; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* broadcast capability */ + netif->flags = NETIF_FLAG_BROADCAST; + + /* Do whatever else is needed to initialize interface. */ +} + +/* + * low_level_output(): + * + * Should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + */ + + +static err_t +low_level_output(struct ethernetif *ethernetif, struct pbuf *p) +{ + struct pbuf *q; + + initiate transfer(); + + for(q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + send data from(q->payload, q->len); + } + + signal that packet should be sent(); + +#ifdef LINK_STATS + lwip_stats.link.xmit++; +#endif /* LINK_STATS */ + + return ERR_OK; +} + +/* + * low_level_input(): + * + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + */ + +static struct pbuf * +low_level_input(struct ethernetif *ethernetif) +{ + struct pbuf *p, *q; + u16_t len; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len = ; + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + + if (p != NULL) { + /* We iterate over the pbuf chain until we have read the entire + packet into the pbuf. */ + for(q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + available data in the pbuf is given by the q->len + variable. */ + read data into(q->payload, q->len); + } + acknowledge that packet has been read(); +#ifdef LINK_STATS + lwip_stats.link.recv++; +#endif /* LINK_STATS */ + } else { + drop packet(); +#ifdef LINK_STATS + lwip_stats.link.memerr++; + lwip_stats.link.drop++; +#endif /* LINK_STATS */ + } + + return p; +} + +/* + * ethernetif_output(): + * + * This function is called by the TCP/IP stack when an IP packet + * should be sent. It calls the function called low_level_output() to + * do the actual transmission of the packet. + * + */ + +static err_t +ethernetif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + struct ethernetif *ethernetif; + struct pbuf *q; + struct eth_hdr *ethhdr; + struct eth_addr *dest, mcastaddr; + struct ip_addr *queryaddr; + err_t err; + u8_t i; + + ethernetif = netif->state; + + /* resolve the link destination hardware address */ + p = etharp_output(netif, ipaddr, p); + + /* network hardware address obtained? */ + if (p == NULL) + { + /* we cannot tell if the packet was sent: the packet could */ + /* have been queued on an ARP entry that was already pending. */ + return ERR_OK; + } + + /* send out the packet */ + return low_level_output(ethernetif, p); + +} + +/* + * ethernetif_input(): + * + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. + * + */ + +static void +ethernetif_input(struct netif *netif) +{ + struct ethernetif *ethernetif; + struct eth_hdr *ethhdr; + struct pbuf *p, *q; + + ethernetif = netif->state; + + p = low_level_input(ethernetif); + + if (p != NULL) + return; + +#ifdef LINK_STATS + lwip_stats.link.recv++; +#endif /* LINK_STATS */ + + ethhdr = p->payload; + q = NULL; + + switch (htons(ethhdr->type)) { + case ETHTYPE_IP: + q = etharp_ip_input(netif, p); + pbuf_header(p, -14); + netif->input(p, netif); + break; + + case ETHTYPE_ARP: + q = etharp_arp_input(netif, ethernetif->ethaddr, p); + break; + default: + pbuf_free(p); + p = NULL; + break; + } + if (q != NULL) { + low_level_output(ethernetif, q); + pbuf_free(q); + q = NULL; + } +} + +static void +arp_timer(void *arg) +{ + etharp_tmr(); + sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +} + +/* + * ethernetif_init(): + * + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + */ + +void +ethernetif_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + ethernetif = mem_malloc(sizeof(struct ethernetif)); + + if (ethernetif == NULL) + { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); + return ERR_MEM; + } + + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + netif->output = ethernetif_output; + netif->linkoutput = low_level_output; + + ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); + + low_level_init(netif); + + etharp_init(); + + sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +} + diff --git a/wii/libogc/lwip/netif/skeleton/slipif.c b/wii/libogc/lwip/netif/skeleton/slipif.c new file mode 100644 index 0000000000..776c13f7a6 --- /dev/null +++ b/wii/libogc/lwip/netif/skeleton/slipif.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is built upon the file: src/arch/rtxc/netif/sioslip.c + * + * Author: Magnus Ivarsson + */ + +/* + * This is an arch independent SLIP netif. The specific serial hooks must be provided + * by another file.They are sio_open, sio_recv and sio_send + */ + +#include "netif/slipif.h" +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "lwip/sio.h" + +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + +#define MAX_SIZE 1500 + +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + */ +err_t +slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +{ + struct pbuf *q; + int i; + u8_t c; + + /* Send pbuf out on the serial I/O device. */ + sio_send(SLIP_END, netif->state); + + for(q = p; q != NULL; q = q->next) { + for(i = 0; i < q->len; i++) { + c = ((u8_t *)q->payload)[i]; + switch (c) { + case SLIP_END: + sio_send(SLIP_ESC, netif->state); + sio_send(SLIP_ESC_END, netif->state); + break; + case SLIP_ESC: + sio_send(SLIP_ESC, netif->state); + sio_send(SLIP_ESC_ESC, netif->state); + break; + default: + sio_send(c, netif->state); + break; + } + } + } + sio_send(SLIP_END, netif->state); + return 0; +} + +/** + * Handle the incoming SLIP stream character by character + * + * Poll the serial layer by calling sio_recv() + * + * @return The IP packet when SLIP_END is received + */ +static struct pbuf * +slipif_input( struct netif * netif ) +{ + u8_t c; + struct pbuf *p, *q; + int recved; + int i; + + q = p = NULL; + recved = i = 0; + c = 0; + + while (1) { + c = sio_recv(netif->state); + switch (c) { + case SLIP_END: + if (recved > 0) { + /* Received whole packet. */ + pbuf_realloc(q, recved); + + LINK_STATS_INC(link.recv); + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n")); + return q; + } + break; + + case SLIP_ESC: + c = sio_recv(netif->state); + switch (c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + } + /* FALLTHROUGH */ + + default: + if (p == NULL) { + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); + p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL); + + if (p == NULL) { + LINK_STATS_INC(link.drop); + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); + } + + if (q != NULL) { + pbuf_cat(q, p); + } else { + q = p; + } + } + if (p != NULL && recved < MAX_SIZE) { + ((u8_t *)p->payload)[i] = c; + recved++; + i++; + if (i >= p->len) { + i = 0; + p = NULL; + } + } + break; + } + + } + return NULL; +} + +/** + * The SLIP input thread + * + * Feed the IP layer with incoming packets + */ +static void +slipif_loop(void *nf) +{ + struct pbuf *p; + struct netif *netif = (struct netif *)nf; + + while (1) { + p = slipif_input(netif); + netif->input(p, netif); + } +} + +/** + * SLIP netif initialization + * + * Call the arch specific sio_open and remember + * the opened device in the state field of the netif. + */ +err_t +slipif_init(struct netif *netif) +{ + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%x\n", (int)netif->num)); + + netif->name[0] = 's'; + netif->name[1] = 'l'; + netif->output = slipif_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_POINTTOPOINT; + + netif->state = sio_open(netif->num); + if (!netif->state) + return ERR_IF; + + sys_thread_new(slipif_loop, netif, SLIPIF_THREAD_PRIO); + return ERR_OK; +} diff --git a/wii/libogc/lwip/netio.c b/wii/libogc/lwip/netio.c new file mode 100644 index 0000000000..45de58a928 --- /dev/null +++ b/wii/libogc/lwip/netio.c @@ -0,0 +1,103 @@ +#if 0 +#include +#include +#include +#include +#undef errno +extern int errno; + +#include +#include "lwip/ip_addr.h" +#include "network.h" +int netio_open(struct _reent *r, void *fileStruct, const char *path,int flags,int mode); +int netio_close(struct _reent *r,void *fd); +int netio_write(struct _reent *r,void *fd,const char *ptr,size_t len); +int netio_read(struct _reent *r,void *fd,char *ptr,size_t len); + +//--------------------------------------------------------------------------------- +const devoptab_t dotab_stdnet = { +//--------------------------------------------------------------------------------- + "stdnet", // device name + 0, // size of file structure + netio_open, // device open + netio_close, // device close + netio_write, // device write + netio_read, // device read + NULL, // device seek + NULL, // device fstat + NULL, // device stat + NULL, // device link + NULL, // device unlink + NULL, // device chdir + NULL, // device rename + NULL, // device mkdir + 0, // dirStateSize + NULL, // device diropen_r + NULL, // device dirreset_r + NULL, // device dirnext_r + NULL, // device dirclose_r + NULL // device statvfs_r +}; + +int netio_open(struct _reent *r, void *fileStruct, const char *path,int flags,int mode) +{ + char *cport = NULL; + int optval = 1,nport = -1,udp_sock = INVALID_SOCKET; + struct sockaddr_in name; + socklen_t namelen = sizeof(struct sockaddr); + + if(net_init()==SOCKET_ERROR) return -1; + + udp_sock = net_socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if(udp_sock==INVALID_SOCKET) return -1; + + cport = strchr(path,':'); + if(cport) { + *cport++ = '\0'; + nport = atoi(cport); + } + if(nport==-1) nport = 7; //try to connect to the well known port 7 + + name.sin_addr.s_addr = inet_addr(path); + name.sin_port = htons(nport); + name.sin_family = AF_INET; + if(net_connect(udp_sock,(struct sockaddr*)&name,namelen)==-1) { + net_close(udp_sock); + return -1; + } + net_setsockopt(udp_sock,IPPROTO_TCP,TCP_NODELAY,&optval,sizeof(optval)); + + return udp_sock; +} + +int netio_close(struct _reent *r,void *fd) +{ + if(fd<0) return -1; + + net_close(fd); + + return 0; +} + +int netio_write(struct _reent *r,void *fd,const char *ptr,size_t len) +{ + int ret; + + if(fd<0) return -1; + + ret = net_write(fd,(void*)ptr,len); + + return ret; +} + +int netio_read(struct _reent *r,void *fd,char *ptr,size_t len) +{ + int ret; + + if(fd<0) return -1; + + ret = net_read(fd,ptr,len); + + return ret; +} +#endif diff --git a/wii/libogc/lwip/network.c b/wii/libogc/lwip/network.c new file mode 100644 index 0000000000..cabc4d1720 --- /dev/null +++ b/wii/libogc/lwip/network.c @@ -0,0 +1,2248 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "network.h" + +//#define _NET_DEBUG +#define ARP_TIMER_ID 0x00070041 +#define TCP_TIMER_ID 0x00070042 +#define DHCPCOARSE_TIMER_ID 0x00070043 +#define DHCPFINE_TIMER_ID 0x00070044 + +#define STACKSIZE 32768 +#define MQBOX_SIZE 256 +#define NUM_SOCKETS MEMP_NUM_NETCONN + +struct netsocket { + struct netconn *conn; + struct netbuf *lastdata; + u16 lastoffset,rcvevt,sendevt,flags; + s32 err; +}; + +struct netselect_cb { + struct netselect_cb *next; + fd_set *readset; + fd_set *writeset; + fd_set *exceptset; + u32 signaled; + mutex_t cond_lck; + cond_t cond; +}; + +typedef void (*apimsg_decode)(struct apimsg_msg *); + +static u32 g_netinitiated = 0; +static u32 tcpiplayer_inited = 0; +static u64 net_tcp_ticks = 0; +static u64 net_dhcpcoarse_ticks = 0; +static u64 net_dhcpfine_ticks = 0; +static u64 net_arp_ticks = 0; +static wd_cntrl arp_time_cntrl; +static wd_cntrl tcp_timer_cntrl; +static wd_cntrl dhcp_coarsetimer_cntrl; +static wd_cntrl dhcp_finetimer_cntrl; + +static struct netif g_hNetIF; +static struct netif g_hLoopIF; +static struct netsocket sockets[NUM_SOCKETS]; +static struct netselect_cb *selectcb_list = NULL; + +static sys_sem netsocket_sem; +static sys_sem sockselect_sem; +static sys_mbox netthread_mbox; + +static sys_thread hnet_thread; +static u8 netthread_stack[STACKSIZE]; + +static u32 tcp_timer_active = 0; + +static struct netbuf* netbuf_new(); +static void netbuf_delete(struct netbuf *); +static void netbuf_copypartial(struct netbuf *,void *,u32,u32); +static void netbuf_ref(struct netbuf *,const void *,u32); + +static struct netconn* netconn_new_with_callback(enum netconn_type,void (*)(struct netconn *,enum netconn_evt,u32)); +static struct netconn* netconn_new_with_proto_and_callback(enum netconn_type,u16,void (*)(struct netconn *,enum netconn_evt,u32)); +static err_t netconn_delete(struct netconn *); +static struct netconn* netconn_accept(struct netconn* ); +static err_t netconn_peer(struct netconn *,struct ip_addr *,u16 *); +static err_t netconn_bind(struct netconn *,struct ip_addr *,u16); +static err_t netconn_listen(struct netconn *); +static struct netbuf* netconn_recv(struct netconn *); +static err_t netconn_send(struct netconn *,struct netbuf *); +static err_t netconn_write(struct netconn *,const void *,u32,u8); +static err_t netconn_connect(struct netconn *,struct ip_addr *,u16); +static err_t netconn_disconnect(struct netconn *); + +static void do_newconn(struct apimsg_msg *); +static void do_delconn(struct apimsg_msg *); +static void do_bind(struct apimsg_msg *); +static void do_listen(struct apimsg_msg *); +static void do_connect(struct apimsg_msg *); +static void do_disconnect(struct apimsg_msg *); +static void do_accept(struct apimsg_msg *); +static void do_send(struct apimsg_msg *); +static void do_recv(struct apimsg_msg *); +static void do_write(struct apimsg_msg *); +static void do_close(struct apimsg_msg *); + +static apimsg_decode decode[APIMSG_MAX] = { + do_newconn, + do_delconn, + do_bind, + do_connect, + do_disconnect, + do_listen, + do_accept, + do_send, + do_recv, + do_write, + do_close +}; + +static void apimsg_post(struct api_msg *); + +static err_t net_input(struct pbuf *,struct netif *); +static void net_apimsg(struct api_msg *); +static err_t net_callback(void (*)(void *),void *); +static void* net_thread(void *); + +static void tmr_callback(void *arg) +{ + void (*functor)() = (void(*)())arg; + if(functor) functor(); +} + +/* low level stuff */ +static void __dhcpcoarse_timer(void *arg) +{ + __lwp_thread_dispatchdisable(); + net_callback(tmr_callback,(void*)dhcp_coarse_tmr); + __lwp_wd_insert_ticks(&dhcp_coarsetimer_cntrl,net_dhcpcoarse_ticks); + __lwp_thread_dispatchunnest(); +} + +static void __dhcpfine_timer(void *arg) +{ + __lwp_thread_dispatchdisable(); + net_callback(tmr_callback,(void*)dhcp_fine_tmr); + __lwp_wd_insert_ticks(&dhcp_finetimer_cntrl,net_dhcpfine_ticks); + __lwp_thread_dispatchunnest(); +} + +static void __tcp_timer(void *arg) +{ +#ifdef _NET_DEBUG + printf("__tcp_timer(%d,%p,%p)\n",tcp_timer_active,tcp_active_pcbs,tcp_tw_pcbs); +#endif + __lwp_thread_dispatchdisable(); + net_callback(tmr_callback,(void*)tcp_tmr); + if (tcp_active_pcbs || tcp_tw_pcbs) { + __lwp_wd_insert_ticks(&tcp_timer_cntrl,net_tcp_ticks); + } else + tcp_timer_active = 0; + __lwp_thread_dispatchunnest(); +} + +static void __arp_timer(void *arg) +{ + __lwp_thread_dispatchdisable(); + net_callback(tmr_callback,(void*)etharp_tmr); + __lwp_wd_insert_ticks(&arp_time_cntrl,net_arp_ticks); + __lwp_thread_dispatchunnest(); +} + +void tcp_timer_needed(void) +{ +#ifdef _NET_DEBUG + printf("tcp_timer_needed()\n"); +#endif + if(!tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { + tcp_timer_active = 1; + __lwp_wd_insert_ticks(&tcp_timer_cntrl,net_tcp_ticks); + } +} + +/* netbuf part */ +static __inline__ u16 netbuf_len(struct netbuf *buf) +{ + return ((buf && buf->p)?buf->p->tot_len:0); +} + +static __inline__ struct ip_addr* netbuf_fromaddr(struct netbuf *buf) +{ + return (buf?buf->fromaddr:NULL); +} + +static __inline__ u16 netbuf_fromport(struct netbuf *buf) +{ + return (buf?buf->fromport:0); +} + +static void netbuf_copypartial(struct netbuf *buf,void *dataptr,u32 len,u32 offset) +{ + struct pbuf *p; + u16 i,left; + + left = 0; + if(buf==NULL || dataptr==NULL) return; + + for(p=buf->p;leftnext) { + if(offset!=0 && offset>=p->len) + offset -= p->len; + else { + for(i=offset;ilen;i++) { + ((u8*)dataptr)[left] = ((u8*)p->payload)[i]; + if(++left>=len) return; + } + offset = 0; + } + } +} + +static struct netbuf* netbuf_new() +{ + struct netbuf *buf = NULL; + + buf = memp_malloc(MEMP_NETBUF); + if(buf) { + buf->p = NULL; + buf->ptr = NULL; + } + return buf; +} + +static void netbuf_delete(struct netbuf *buf) +{ + if(buf!=NULL) { + if(buf->p!=NULL) pbuf_free(buf->p); + memp_free(MEMP_NETBUF,buf); + } +} + +static void netbuf_ref(struct netbuf *buf, const void *dataptr,u32 size) +{ + if(buf->p!=NULL) pbuf_free(buf->p); + buf->p = pbuf_alloc(PBUF_TRANSPORT,0,PBUF_REF); + buf->p->payload = (void*)dataptr; + buf->p->len = buf->p->tot_len = size; + buf->ptr = buf->p; +} + +/* netconn part */ +static inline enum netconn_type netconn_type(struct netconn *conn) +{ + return conn->type; +} + +static struct netconn* netconn_new_with_callback(enum netconn_type t,void (*cb)(struct netconn*,enum netconn_evt,u32)) +{ + return netconn_new_with_proto_and_callback(t,0,cb); +} + +static struct netconn* netconn_new_with_proto_and_callback(enum netconn_type t,u16 proto,void (*cb)(struct netconn *,enum netconn_evt,u32)) +{ + u32 dummy = 0; + struct netconn *conn; + struct api_msg *msg; + + conn = memp_malloc(MEMP_NETCONN); + if(!conn) return NULL; + + conn->err = ERR_OK; + conn->type = t; + conn->pcb.tcp = NULL; + + if(MQ_Init(&conn->mbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) { + memp_free(MEMP_NETCONN,conn); + return NULL; + } + if(LWP_SemInit(&conn->sem,0,1)==-1) { + MQ_Close(conn->mbox); + memp_free(MEMP_NETCONN,conn); + return NULL; + } + + conn->acceptmbox = SYS_MBOX_NULL; + conn->recvmbox = SYS_MBOX_NULL; + conn->state = NETCONN_NONE; + conn->socket = 0; + conn->callback = cb; + conn->recvavail = 0; + + msg = memp_malloc(MEMP_API_MSG); + if(!msg) { + MQ_Close(conn->mbox); + memp_free(MEMP_NETCONN,conn); + return NULL; + } + + msg->type = APIMSG_NEWCONN; + msg->msg.msg.bc.port = proto; + msg->msg.conn = conn; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + + if(conn->err!=ERR_OK) { + MQ_Close(conn->mbox); + memp_free(MEMP_NETCONN,conn); + return NULL; + } + return conn; +} + +static err_t netconn_delete(struct netconn *conn) +{ + u32 dummy = 0; + struct api_msg *msg; + sys_mbox mbox; + void *mem; + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_delete(%p)\n", conn)); + + if(!conn) return ERR_OK; + + msg = memp_malloc(MEMP_API_MSG); + if(!msg) return ERR_MEM; + + msg->type = APIMSG_DELCONN; + msg->msg.conn = conn; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + + mbox = conn->recvmbox; + conn->recvmbox = SYS_MBOX_NULL; + if(mbox!=SYS_MBOX_NULL) { + while(MQ_Receive(mbox,(mqmsg_t)&mem,MQ_MSG_NOBLOCK)==TRUE) { + if(mem!=NULL) { + if(conn->type==NETCONN_TCP) + pbuf_free((struct pbuf*)mem); + else + netbuf_delete((struct netbuf*)mem); + } + } + MQ_Close(mbox); + } + + mbox = conn->acceptmbox; + conn->acceptmbox = SYS_MBOX_NULL; + if(mbox!=SYS_MBOX_NULL) { + while(MQ_Receive(mbox,(mqmsg_t)&mem,MQ_MSG_NOBLOCK)==TRUE) { + if(mem!=NULL) netconn_delete((struct netconn*)mem); + } + MQ_Close(mbox); + } + + MQ_Close(conn->mbox); + conn->mbox = SYS_MBOX_NULL; + + LWP_SemDestroy(conn->sem); + conn->sem = SYS_SEM_NULL; + + memp_free(MEMP_NETCONN,conn); + return ERR_OK; +} + +static struct netconn* netconn_accept(struct netconn* conn) +{ + struct netconn *newconn; + + if(conn==NULL) return NULL; + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_accept(%p)\n", conn)); + MQ_Receive(conn->acceptmbox,(mqmsg_t)&newconn,MQ_MSG_BLOCK); + if(conn->callback) + (*conn->callback)(conn,NETCONN_EVTRCVMINUS,0); + + return newconn; +} + +static err_t netconn_peer(struct netconn *conn,struct ip_addr *addr,u16 *port) +{ + switch(conn->type) { + case NETCONN_RAW: + return ERR_CONN; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + if(conn->pcb.udp==NULL || ((conn->pcb.udp->flags&UDP_FLAGS_CONNECTED)==0)) + return ERR_CONN; + *addr = conn->pcb.udp->remote_ip; + *port = conn->pcb.udp->remote_port; + break; + case NETCONN_TCP: + if(conn->pcb.tcp==NULL) + return ERR_CONN; + *addr = conn->pcb.tcp->remote_ip; + *port = conn->pcb.tcp->remote_port; + break; + } + return (conn->err = ERR_OK); +} + +static err_t netconn_bind(struct netconn *conn,struct ip_addr *addr,u16 port) +{ + u32 dummy = 0; + struct api_msg *msg; + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_bind(%p)\n", conn)); + + if(conn==NULL) return ERR_VAL; + if(conn->type!=NETCONN_TCP && conn->recvmbox==SYS_MBOX_NULL) { + if(MQ_Init(&conn->recvmbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) return ERR_MEM; + } + + if((msg=memp_malloc(MEMP_API_MSG))==NULL) + return (conn->err = ERR_MEM); + + msg->type = APIMSG_BIND; + msg->msg.conn = conn; + msg->msg.msg.bc.ipaddr = addr; + msg->msg.msg.bc.port = port; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + return conn->err; +} + +static err_t netconn_listen(struct netconn *conn) +{ + u32 dummy = 0; + struct api_msg *msg; + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_listen(%p)\n", conn)); + + if(conn==NULL) return -1; + if(conn->acceptmbox==SYS_MBOX_NULL) { + if(MQ_Init(&conn->acceptmbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) return ERR_MEM; + } + + if((msg=memp_malloc(MEMP_API_MSG))==NULL) return (conn->err = ERR_MEM); + msg->type = APIMSG_LISTEN; + msg->msg.conn = conn; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + return conn->err; +} + +static struct netbuf* netconn_recv(struct netconn *conn) +{ + u32 dummy = 0; + struct api_msg *msg; + struct netbuf *buf; + struct pbuf *p; + u16 len; + + if(conn==NULL) return NULL; + if(conn->recvmbox==SYS_MBOX_NULL) { + conn->err = ERR_CONN; + return NULL; + } + if(conn->err!=ERR_OK) return NULL; + + if(conn->type==NETCONN_TCP) { + if(conn->pcb.tcp->state==LISTEN) { + conn->err = ERR_CONN; + return NULL; + } + + buf = memp_malloc(MEMP_NETBUF); + if(buf==NULL) { + conn->err = ERR_MEM; + return NULL; + } + + MQ_Receive(conn->recvmbox,(mqmsg_t)&p,MQ_MSG_BLOCK); + if(p!=NULL) { + len = p->tot_len; + conn->recvavail -= len; + } else + len = 0; + + if(conn->callback) + (*conn->callback)(conn,NETCONN_EVTRCVMINUS,len); + + if(p==NULL) { + memp_free(MEMP_NETBUF,buf); + MQ_Close(conn->recvmbox); + conn->recvmbox = SYS_MBOX_NULL; + return NULL; + } + + buf->p = p; + buf->ptr = p; + buf->fromport = 0; + buf->fromaddr = NULL; + + if((msg=memp_malloc(MEMP_API_MSG))==NULL) { + conn->err = ERR_MEM; + return buf; + } + + msg->type = APIMSG_RECV; + msg->msg.conn = conn; + if(buf!=NULL) + msg->msg.msg.len = len; + else + msg->msg.msg.len = 1; + + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + } else { + MQ_Receive(conn->recvmbox,(mqmsg_t)&buf,MQ_MSG_BLOCK); + conn->recvavail -= buf->p->tot_len; + if(conn->callback) + (*conn->callback)(conn,NETCONN_EVTRCVMINUS,buf->p->tot_len); + } + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err)); + return buf; +} + +static err_t netconn_send(struct netconn *conn,struct netbuf *buf) +{ + u32 dummy = 0; + struct api_msg *msg; + + if(conn==NULL) return ERR_VAL; + if(conn->err!=ERR_OK) return conn->err; + if((msg=memp_malloc(MEMP_API_MSG))==NULL) return (conn->err = ERR_MEM); + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len)); + msg->type = APIMSG_SEND; + msg->msg.conn = conn; + msg->msg.msg.p = buf->p; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + return conn->err; +} + +static err_t netconn_write(struct netconn *conn,const void *dataptr,u32 size,u8 copy) +{ + u32 dummy = 0; + struct api_msg *msg; + u16 len,snd_buf; + + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write(%d)\n",conn->err)); + + if(conn==NULL) return ERR_VAL; + if(conn->err!=ERR_OK) return conn->err; + + if((msg=memp_malloc(MEMP_API_MSG))==NULL) return (conn->err = ERR_MEM); + + msg->type = APIMSG_WRITE; + msg->msg.conn = conn; + conn->state = NETCONN_WRITE; + while(conn->err==ERR_OK && size>0) { + msg->msg.msg.w.dataptr = (void*)dataptr; + msg->msg.msg.w.copy = copy; + if(conn->type==NETCONN_TCP) { + while((snd_buf=tcp_sndbuf(conn->pcb.tcp))==0) { + LWIP_DEBUGF(API_LIB_DEBUG,("netconn_write: tcp_sndbuf = 0,err = %d\n", conn->err)); + LWP_SemWait(conn->sem); + if(conn->err!=ERR_OK) goto ret; + } + if(size>snd_buf) + len = snd_buf; + else + len = size; + } else + len = size; + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy)); + msg->msg.msg.w.len = len; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + if(conn->err==ERR_OK) { + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: %d bytes written\n",len)); + dataptr = (void*)((char*)dataptr+len); + size -= len; + } else if(conn->err==ERR_MEM) { + LWIP_DEBUGF(API_LIB_DEBUG,("netconn_write: mem err\n")); + conn->err = ERR_OK; + LWP_SemWait(conn->sem); + } else { + LWIP_DEBUGF(API_LIB_DEBUG,("netconn_write: err = %d\n", conn->err)); + break; + } + } +ret: + memp_free(MEMP_API_MSG,msg); + conn->state = NETCONN_NONE; + + return conn->err; +} + +static err_t netconn_connect(struct netconn *conn,struct ip_addr *addr,u16 port) +{ + u32 dummy = 0; + struct api_msg *msg; + + if(conn==NULL) return -1; + if(conn->recvmbox==SYS_MBOX_NULL) { + if(MQ_Init(&conn->recvmbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) return ERR_MEM; + } + + if((msg=memp_malloc(MEMP_API_MSG))==NULL) return ERR_MEM; + + msg->type = APIMSG_CONNECT; + msg->msg.conn = conn; + msg->msg.msg.bc.ipaddr = addr; + msg->msg.msg.bc.port = port; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + return conn->err; +} + +static err_t netconn_disconnect(struct netconn *conn) +{ + u32 dummy = 0; + struct api_msg *msg; + + if(conn==NULL) return ERR_VAL; + if((msg=memp_malloc(MEMP_API_MSG))==NULL) return ERR_MEM; + + msg->type = APIMSG_DISCONNECT; + msg->msg.conn = conn; + apimsg_post(msg); + MQ_Receive(conn->mbox,(mqmsg_t)&dummy,MQ_MSG_BLOCK); + memp_free(MEMP_API_MSG,msg); + return conn->err; +} + +/* api msg part */ +static u8_t recv_raw(void *arg,struct raw_pcb *pcb,struct pbuf *p,struct ip_addr *addr) +{ + struct netbuf *buf; + struct netconn *conn = (struct netconn*)arg; + + if(!conn) return 0; + + if(conn->recvmbox!=SYS_MBOX_NULL) { + if((buf=memp_malloc(MEMP_NETBUF))==NULL) return 0; + + pbuf_ref(p); + buf->p = p; + buf->ptr = p; + buf->fromaddr = addr; + buf->fromport = pcb->protocol; + + conn->recvavail += p->tot_len; + if(conn->callback) + (*conn->callback)(conn,NETCONN_EVTRCVPLUS,p->tot_len); + MQ_Send(conn->recvmbox,buf,MQ_MSG_BLOCK); + } + return 0; +} + +static void recv_udp(void *arg,struct udp_pcb *pcb,struct pbuf *p,struct ip_addr *addr,u16 port) +{ + struct netbuf *buf; + struct netconn *conn = (struct netconn*)arg; + + if(!conn) { + pbuf_free(p); + return; + } + + if(conn->recvmbox!=SYS_MBOX_NULL) { + buf = memp_malloc(MEMP_NETBUF); + if(!buf) { + pbuf_free(p); + return; + } + buf->p = p; + buf->ptr = p; + buf->fromaddr = addr; + buf->fromport = port; + + conn->recvavail += p->tot_len; + if(conn->callback) + (*conn->callback)(conn,NETCONN_EVTRCVPLUS,p->tot_len); + + MQ_Send(conn->recvmbox,buf,MQ_MSG_BLOCK); + } +} + +static err_t recv_tcp(void *arg,struct tcp_pcb *pcb,struct pbuf *p,err_t err) +{ + u16 len; + struct netconn *conn = (struct netconn*)arg; + + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: recv_tcp(%p,%p,%p,%d)\n",arg,pcb,p,err)); + + if(conn==NULL) { + pbuf_free(p); + return ERR_VAL; + } + + if(conn->recvmbox!=SYS_MBOX_NULL) { + conn->err = err; + if(p!=NULL) { + len = p->tot_len; + conn->recvavail += len; + } else len = 0; + + if(conn->callback) + (*conn->callback)(conn,NETCONN_EVTRCVPLUS,len); + + MQ_Send(conn->recvmbox,p,MQ_MSG_BLOCK); + } + return ERR_OK; +} + +static void err_tcp(void *arg,err_t err) +{ + u32 dummy = 0; + struct netconn *conn = (struct netconn*)arg; + + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: err_tcp: %d\n",err)); + if(conn) { + conn->err = err; + conn->pcb.tcp = NULL; + if(conn->recvmbox!=SYS_MBOX_NULL) { + if(conn->callback) (*conn->callback)(conn,NETCONN_EVTRCVPLUS,0); + MQ_Send(conn->recvmbox,&dummy,MQ_MSG_BLOCK); + } + if(conn->mbox!=SYS_MBOX_NULL) { + MQ_Send(conn->mbox,&dummy,MQ_MSG_BLOCK); + } + if(conn->acceptmbox!=SYS_MBOX_NULL) { + if(conn->callback) (*conn->callback)(conn,NETCONN_EVTRCVPLUS,0); + MQ_Send(conn->acceptmbox,&dummy,MQ_MSG_BLOCK); + } + if(conn->sem!=SYS_SEM_NULL) { + LWP_SemPost(conn->sem); + } + } +} + +static err_t poll_tcp(void *arg,struct tcp_pcb *pcb) +{ + struct netconn *conn = (struct netconn*)arg; + + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: poll_tcp\n")); + if(conn && conn->sem!=SYS_SEM_NULL && (conn->state==NETCONN_WRITE || conn->state==NETCONN_CLOSE)) + LWP_SemPost(conn->sem); + + return ERR_OK; +} + +static err_t sent_tcp(void *arg,struct tcp_pcb *pcb,u16 len) +{ + struct netconn *conn = (struct netconn*)arg; + + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: sent_tcp: sent %d bytes\n",len)); + if(conn && conn->sem!=SYS_SEM_NULL) + LWP_SemPost(conn->sem); + + if(conn && conn->callback) { + if(tcp_sndbuf(conn->pcb.tcp)>TCP_SNDLOWAT) + (*conn->callback)(conn,NETCONN_EVTSENDPLUS,len); + } + return ERR_OK; +} + +static void setuptcp(struct netconn *conn) +{ + struct tcp_pcb *pcb = conn->pcb.tcp; + + tcp_arg(pcb,conn); + tcp_recv(pcb,recv_tcp); + tcp_sent(pcb,sent_tcp); + tcp_poll(pcb,poll_tcp,4); + tcp_err(pcb,err_tcp); +} + +static err_t accept_func(void *arg,struct tcp_pcb *newpcb,err_t err) +{ + sys_mbox mbox; + struct netconn *newconn,*conn = (struct netconn*)arg; + + LWIP_DEBUGF(API_LIB_DEBUG, ("accept_func: %p %p %d\n",arg,newpcb,err)); + + mbox = conn->acceptmbox; + newconn = memp_malloc(MEMP_NETCONN); + if(newconn==NULL) return ERR_MEM; + + if(MQ_Init(&newconn->recvmbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) { + memp_free(MEMP_NETCONN,newconn); + return ERR_MEM; + } + + if(MQ_Init(&newconn->mbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) { + MQ_Close(newconn->recvmbox); + memp_free(MEMP_NETCONN,newconn); + return ERR_MEM; + } + + if(LWP_SemInit(&newconn->sem,0,1)==-1) { + MQ_Close(newconn->recvmbox); + MQ_Close(newconn->mbox); + memp_free(MEMP_NETCONN,newconn); + return ERR_MEM; + } + + newconn->type = NETCONN_TCP; + newconn->pcb.tcp = newpcb; + setuptcp(newconn); + + newconn->acceptmbox = SYS_MBOX_NULL; + newconn->err = err; + + if(conn->callback) { + (*conn->callback)(conn,NETCONN_EVTRCVPLUS,0); + } + newconn->callback = conn->callback; + newconn->socket = -1; + newconn->recvavail = 0; + + MQ_Send(mbox,newconn,MQ_MSG_BLOCK); + return ERR_OK; +} + +static void do_newconn(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + if(msg->conn->pcb.tcp) { + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); + return; + } + + msg->conn->err = ERR_OK; + switch(msg->conn->type) { + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.bc.port); + raw_recv(msg->conn->pcb.raw,recv_raw,msg->conn); + break; + case NETCONN_UDPLITE: + msg->conn->pcb.udp = udp_new(); + if(!msg->conn->pcb.udp) { + msg->conn->err = ERR_MEM; + break; + } + udp_setflags(msg->conn->pcb.udp,UDP_FLAGS_UDPLITE); + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_UDPNOCHKSUM: + msg->conn->pcb.udp = udp_new(); + if(!msg->conn->pcb.udp) { + msg->conn->err = ERR_MEM; + break; + } + udp_setflags(msg->conn->pcb.udp,UDP_FLAGS_NOCHKSUM); + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new(); + if(!msg->conn->pcb.udp) { + msg->conn->err = ERR_MEM; + break; + } + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + if(!msg->conn->pcb.tcp) { + msg->conn->err = ERR_MEM; + break; + } + setuptcp(msg->conn); + break; + default: + break; + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void do_delconn(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + if(msg->conn->pcb.tcp) { + switch(msg->conn->type) { + case NETCONN_RAW: + raw_remove(msg->conn->pcb.raw); + break; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + msg->conn->pcb.udp->recv_arg = NULL; + udp_remove(msg->conn->pcb.udp); + break; + case NETCONN_TCP: + if(msg->conn->pcb.tcp->state==LISTEN) { + tcp_arg(msg->conn->pcb.tcp,NULL); + tcp_accept(msg->conn->pcb.tcp,NULL); + tcp_close(msg->conn->pcb.tcp); + } else { + tcp_arg(msg->conn->pcb.tcp,NULL); + tcp_sent(msg->conn->pcb.tcp,NULL); + tcp_recv(msg->conn->pcb.tcp,NULL); + tcp_poll(msg->conn->pcb.tcp,NULL,0); + tcp_err(msg->conn->pcb.tcp,NULL); + if(tcp_close(msg->conn->pcb.tcp)!=ERR_OK) + tcp_abort(msg->conn->pcb.tcp); + } + break; + default: + break; + } + } + if(msg->conn->callback) { + (*msg->conn->callback)(msg->conn,NETCONN_EVTRCVPLUS,0); + (*msg->conn->callback)(msg->conn,NETCONN_EVTSENDPLUS,0); + } + if(msg->conn->mbox!=SYS_MBOX_NULL) + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void do_bind(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + if(msg->conn->pcb.tcp==NULL) { + switch(msg->conn->type) { + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.bc.port); + raw_recv(msg->conn->pcb.raw,recv_raw,msg->conn); + break; + case NETCONN_UDPLITE: + msg->conn->pcb.udp = udp_new(); + udp_setflags(msg->conn->pcb.udp,UDP_FLAGS_UDPLITE); + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_UDPNOCHKSUM: + msg->conn->pcb.udp = udp_new(); + udp_setflags(msg->conn->pcb.udp,UDP_FLAGS_NOCHKSUM); + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new(); + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + setuptcp(msg->conn); + break; + default: + break; + } + } + switch(msg->conn->type) { + case NETCONN_RAW: + msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr); + break; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + msg->conn->err = udp_bind(msg->conn->pcb.udp,msg->msg.bc.ipaddr,msg->msg.bc.port); + break; + case NETCONN_TCP: + msg->conn->err = tcp_bind(msg->conn->pcb.tcp,msg->msg.bc.ipaddr,msg->msg.bc.port); + break; + default: + break; + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static err_t do_connected(void *arg,struct tcp_pcb *pcb,err_t err) +{ + u32 dummy = 0; + struct netconn *conn = (struct netconn*)arg; + + if(!conn) return ERR_VAL; + + conn->err = err; + if(conn->type==NETCONN_TCP && err==ERR_OK) setuptcp(conn); + + MQ_Send(conn->mbox,&dummy,MQ_MSG_BLOCK); + return ERR_OK; +} + +static void do_connect(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + if(!msg->conn->pcb.tcp) { + switch(msg->conn->type) { + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.bc.port); + raw_recv(msg->conn->pcb.raw,recv_raw,msg->conn); + break; + case NETCONN_UDPLITE: + msg->conn->pcb.udp = udp_new(); + if(!msg->conn->pcb.udp) { + msg->conn->err = ERR_MEM; + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); + return; + } + udp_setflags(msg->conn->pcb.udp,UDP_FLAGS_UDPLITE); + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_UDPNOCHKSUM: + msg->conn->pcb.udp = udp_new(); + if(!msg->conn->pcb.udp) { + msg->conn->err = ERR_MEM; + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); + return; + } + udp_setflags(msg->conn->pcb.udp,UDP_FLAGS_NOCHKSUM); + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new(); + if(!msg->conn->pcb.udp) { + msg->conn->err = ERR_MEM; + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); + return; + } + udp_recv(msg->conn->pcb.udp,recv_udp,msg->conn); + break; + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + if(!msg->conn->pcb.tcp) { + msg->conn->err = ERR_MEM; + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); + return; + } + break; + default: + break; + } + } + switch(msg->conn->type) { + case NETCONN_RAW: + raw_connect(msg->conn->pcb.raw,msg->msg.bc.ipaddr); + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); + break; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + udp_connect(msg->conn->pcb.udp,msg->msg.bc.ipaddr,msg->msg.bc.port); + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); + break; + case NETCONN_TCP: + setuptcp(msg->conn); + tcp_connect(msg->conn->pcb.tcp,msg->msg.bc.ipaddr,msg->msg.bc.port,do_connected); + break; + default: + break; + } +} + +static void do_disconnect(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + switch(msg->conn->type) { + case NETCONN_RAW: + break; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + udp_disconnect(msg->conn->pcb.udp); + break; + case NETCONN_TCP: + break; + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void do_listen(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + if(msg->conn->pcb.tcp!=NULL) { + switch(msg->conn->type) { + case NETCONN_RAW: + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n")); + break; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n")); + break; + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_listen(msg->conn->pcb.tcp); + if(msg->conn->pcb.tcp==NULL) + msg->conn->err = ERR_MEM; + else { + if(msg->conn->acceptmbox==SYS_MBOX_NULL) { + if(MQ_Init(&msg->conn->acceptmbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) { + msg->conn->err = ERR_MEM; + break; + } + } + tcp_arg(msg->conn->pcb.tcp,msg->conn); + tcp_accept(msg->conn->pcb.tcp,accept_func); + } + break; + default: + break; + } + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void do_accept(struct apimsg_msg *msg) +{ + if(msg->conn->pcb.tcp) { + switch(msg->conn->type) { + case NETCONN_RAW: + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n")); + break; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept UDP: cannot accept for UDP.\n")); + break; + case NETCONN_TCP: + break; + } + } +} + +static void do_send(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + if(msg->conn->pcb.tcp) { + switch(msg->conn->type) { + case NETCONN_RAW: + raw_send(msg->conn->pcb.raw,msg->msg.p); + break; + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + udp_send(msg->conn->pcb.udp,msg->msg.p); + break; + case NETCONN_TCP: + break; + } + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void do_recv(struct apimsg_msg *msg) +{ + u32 dummy = 0; + + if(msg->conn->pcb.tcp && msg->conn->type==NETCONN_TCP) { + tcp_recved(msg->conn->pcb.tcp,msg->msg.len); + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void do_write(struct apimsg_msg *msg) +{ + err_t err; + u32 dummy = 0; + + if(msg->conn->pcb.tcp) { + switch(msg->conn->type) { + case NETCONN_RAW: + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + msg->conn->err = ERR_VAL; + break; + case NETCONN_TCP: + err = tcp_write(msg->conn->pcb.tcp,msg->msg.w.dataptr,msg->msg.w.len,msg->msg.w.copy); + if(err==ERR_OK && (!msg->conn->pcb.tcp->unacked || (msg->conn->pcb.tcp->flags&TF_NODELAY) + || msg->conn->pcb.tcp->snd_queuelen>1)) { + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: TCP write: tcp_output.\n")); + tcp_output(msg->conn->pcb.tcp); + } + msg->conn->err = err; + if(msg->conn->callback) { + if(err==ERR_OK) { + if(tcp_sndbuf(msg->conn->pcb.tcp)<=TCP_SNDLOWAT) + (*msg->conn->callback)(msg->conn,NETCONN_EVTSENDMINUS,msg->msg.w.len); + } + } + break; + default: + break; + } + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void do_close(struct apimsg_msg *msg) +{ + u32 dummy = 0; + err_t err = ERR_OK; + + if(msg->conn->pcb.tcp) { + switch(msg->conn->type) { + case NETCONN_RAW: + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + break; + case NETCONN_TCP: + if(msg->conn->pcb.tcp->state==LISTEN) + err = tcp_close(msg->conn->pcb.tcp); + else if(msg->conn->pcb.tcp->state==CLOSE_WAIT) + err = tcp_output(msg->conn->pcb.tcp); + msg->conn->err = err; + break; + default: + break; + } + } + MQ_Send(msg->conn->mbox,&dummy,MQ_MSG_BLOCK); +} + +static void apimsg_input(struct api_msg *msg) +{ + decode[msg->type](&(msg->msg)); +} + +static void apimsg_post(struct api_msg *msg) +{ + net_apimsg(msg); +} + +/* tcpip thread part */ +static err_t net_input(struct pbuf *p,struct netif *inp) +{ + struct net_msg *msg = memp_malloc(MEMP_TCPIP_MSG); + + LWIP_DEBUGF(TCPIP_DEBUG, ("net_input: %p %p\n", p,inp)); + + if(msg==NULL) { + LWIP_ERROR(("net_input: msg out of memory.\n")); + pbuf_free(p); + return ERR_MEM; + } + + msg->type = NETMSG_INPUT; + msg->msg.inp.p = p; + msg->msg.inp.net = inp; + MQ_Send(netthread_mbox,msg,MQ_MSG_BLOCK); + return ERR_OK; +} + +static void net_apimsg(struct api_msg *apimsg) +{ + struct net_msg *msg = memp_malloc(MEMP_TCPIP_MSG); + + LWIP_DEBUGF(TCPIP_DEBUG, ("net_apimsg: %p\n",apimsg)); + if(msg==NULL) { + LWIP_ERROR(("net_apimsg: msg out of memory.\n")); + memp_free(MEMP_API_MSG,apimsg); + return; + } + + msg->type = NETMSG_API; + msg->msg.apimsg = apimsg; + MQ_Send(netthread_mbox,msg,MQ_MSG_BLOCK); +} + +static err_t net_callback(void (*f)(void *),void *ctx) +{ + struct net_msg *msg = memp_malloc(MEMP_TCPIP_MSG); + + LWIP_DEBUGF(TCPIP_DEBUG, ("net_callback: %p(%p)\n", f,ctx)); + + if(msg==NULL) { + LWIP_ERROR(("net_apimsg: msg out of memory.\n")); + return ERR_MEM; + } + + msg->type = NETMSG_CALLBACK; + msg->msg.cb.f = f; + msg->msg.cb.ctx = ctx; + MQ_Send(netthread_mbox,msg,MQ_MSG_BLOCK); + return ERR_OK; +} + +static void* net_thread(void *arg) +{ + struct net_msg *msg; + struct timespec tb; + sys_sem sem = (sys_sem)arg; + + etharp_init(); + ip_init(); + udp_init(); + tcp_init(); + + + tb.tv_sec = ARP_TMR_INTERVAL/TB_MSPERSEC; + tb.tv_nsec = 0; + net_arp_ticks = __lwp_wd_calc_ticks(&tb); + __lwp_wd_initialize(&arp_time_cntrl,__arp_timer,ARP_TIMER_ID,NULL); + __lwp_wd_insert_ticks(&arp_time_cntrl,net_arp_ticks); + + tb.tv_sec = 0; + tb.tv_nsec = TCP_TMR_INTERVAL*TB_NSPERMS; + net_tcp_ticks = __lwp_wd_calc_ticks(&tb); + __lwp_wd_initialize(&tcp_timer_cntrl,__tcp_timer,TCP_TIMER_ID,NULL); + + LWP_SemPost(sem); + + LWIP_DEBUGF(TCPIP_DEBUG, ("net_thread(%p)\n",arg)); + + while(1) { + MQ_Receive(netthread_mbox,(mqmsg_t)&msg,MQ_MSG_BLOCK); + switch(msg->type) { + case NETMSG_API: + LWIP_DEBUGF(TCPIP_DEBUG, ("net_thread: API message %p\n", (void *)msg)); + apimsg_input(msg->msg.apimsg); + break; + case NETMSG_INPUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("net_thread: IP packet %p\n", (void *)msg)); + bba_process(msg->msg.inp.p,msg->msg.inp.net); + break; + case NETMSG_CALLBACK: + LWIP_DEBUGF(TCPIP_DEBUG, ("net_thread: CALLBACK %p\n", (void *)msg)); + msg->msg.cb.f(msg->msg.cb.ctx); + break; + default: + break; + } + memp_free(MEMP_TCPIP_MSG,msg); + } + return NULL; +} + +/* sockets part */ +static s32 alloc_socket(struct netconn *conn) +{ + s32 i; + + LWP_SemWait(netsocket_sem); + + for(i=0;iNUM_SOCKETS) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); + return NULL; + } + sock = &sockets[s]; + if(!sock->conn) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): no active\n", s)); + return NULL; + } + + return sock; +} + +static void evt_callback(struct netconn *conn,enum netconn_evt evt,u32 len) +{ + s32 s; + struct netsocket *sock; + struct netselect_cb *scb; + + if(conn) { + s = conn->socket; + if(s<0) { + if(evt==NETCONN_EVTRCVPLUS) + conn->socket--; + return; + } + sock = get_socket(s); + if(!sock) return; + } else + return; + + LWP_SemWait(sockselect_sem); + switch(evt) { + case NETCONN_EVTRCVPLUS: + sock->rcvevt++; + break; + case NETCONN_EVTRCVMINUS: + sock->rcvevt--; + break; + case NETCONN_EVTSENDPLUS: + sock->sendevt = 1; + break; + case NETCONN_EVTSENDMINUS: + sock->sendevt = 0; + break; + } + LWP_SemPost(sockselect_sem); + + while(1) { + LWP_SemWait(sockselect_sem); + for(scb = selectcb_list;scb;scb = scb->next) { + if(scb->signaled==0) { + if(scb->readset && FD_ISSET(s,scb->readset)) + if(sock->rcvevt) break; + if(scb->writeset && FD_ISSET(s,scb->writeset)) + if(sock->sendevt) break; + } + } + if(scb) { + scb->signaled = 1; + LWP_SemPost(sockselect_sem); + LWP_MutexLock(scb->cond_lck); + LWP_CondSignal(scb->cond); + LWP_MutexUnlock(scb->cond_lck); + } else { + LWP_SemPost(sockselect_sem); + break; + } + } + +} + +extern const devoptab_t dotab_stdnet; + +s32 if_configex(struct in_addr *local_ip,struct in_addr *netmask,struct in_addr *gateway,bool use_dhcp, int max_retries) +{ + s32 ret = 0; + struct ip_addr loc_ip, mask, gw; + struct netif *pnet; + struct timespec tb; + dev_s hbba = NULL; + + if(g_netinitiated) return 0; + g_netinitiated = 1; + +// AddDevice(&dotab_stdnet); +#ifdef STATS + stats_init(); +#endif /* STATS */ + + sys_init(); + mem_init(); + memp_init(); + pbuf_init(); + netif_init(); + + // init tcpip thread message box + if(MQ_Init(&netthread_mbox,MQBOX_SIZE)!=MQ_ERROR_SUCCESSFUL) return -1; + + // create & setup interface + loc_ip.addr = 0; + mask.addr = 0; + gw.addr = 0; + + + if(use_dhcp==FALSE) { + if( !gateway || gateway->s_addr==0 + || !local_ip || local_ip->s_addr==0 + || !netmask || netmask->s_addr==0 ) return -EINVAL; + loc_ip.addr = local_ip->s_addr; + mask.addr = netmask->s_addr; + gw.addr = gateway->s_addr; + } + hbba = bba_create(&g_hNetIF); + pnet = netif_add(&g_hNetIF,&loc_ip, &mask, &gw, hbba, bba_init, net_input); + if(pnet) { + netif_set_up(pnet); + netif_set_default(pnet); +#if (LWIP_DHCP) + if(use_dhcp==TRUE) { + //setup coarse timer + tb.tv_sec = DHCP_COARSE_TIMER_SECS; + tb.tv_nsec = 0; + net_dhcpcoarse_ticks = __lwp_wd_calc_ticks(&tb); + __lwp_wd_initialize(&dhcp_coarsetimer_cntrl, __dhcpcoarse_timer, DHCPCOARSE_TIMER_ID, NULL); + __lwp_wd_insert_ticks(&dhcp_coarsetimer_cntrl, net_dhcpcoarse_ticks); + + //setup fine timer + tb.tv_sec = 0; + tb.tv_nsec = DHCP_FINE_TIMER_MSECS * TB_NSPERMS; + net_dhcpfine_ticks = __lwp_wd_calc_ticks(&tb); + __lwp_wd_initialize(&dhcp_finetimer_cntrl, __dhcpfine_timer, DHCPFINE_TIMER_ID, NULL); + __lwp_wd_insert_ticks(&dhcp_finetimer_cntrl, net_dhcpfine_ticks); + + //now start dhcp client + dhcp_start(pnet); + } +#endif + } else + return -ENXIO; + + // setup loopinterface + IP4_ADDR(&loc_ip, 127, 0, 0, 1); + IP4_ADDR(&mask, 255, 0, 0, 0); + IP4_ADDR(&gw, 127, 0, 0, 1); + pnet = netif_add(&g_hLoopIF, &loc_ip, &mask, &gw, NULL, loopif_init, net_input); + + //last and least start the tcpip layer + ret = net_init(); + + if ( ret == 0 && use_dhcp == TRUE ) { + + int retries = max_retries; + // wait for dhcp to bind + while ( g_hNetIF.dhcp->state != DHCP_BOUND && retries > 0 ) { + retries--; + usleep(500000); + } + + if ( retries > 0 ) { + //copy back network addresses + if ( local_ip != NULL ) local_ip->s_addr = g_hNetIF.ip_addr.addr; + if ( gateway != NULL ) gateway->s_addr = g_hNetIF.gw.addr; + if ( netmask != NULL ) netmask->s_addr = g_hNetIF.netmask.addr; + } else { + ret = -ETIMEDOUT; + } + } + + return ret; +} + +s32 if_config(char *local_ip, char *netmask, char *gateway,bool use_dhcp, int max_retries) +{ + s32 ret = 0; + struct in_addr loc_ip, mask, gw; + + loc_ip.s_addr = 0; + mask.s_addr = 0; + gw.s_addr = 0; + + if ( local_ip != NULL ) loc_ip.s_addr = inet_addr(local_ip); + if ( netmask != NULL ) mask.s_addr = inet_addr(netmask); + if ( gateway != NULL ) gw.s_addr = inet_addr(gateway); + + ret = if_configex( &loc_ip, &mask, &gw, use_dhcp, max_retries); + + if (ret<0) return ret; + + if ( use_dhcp == TRUE ) { + //copy back network addresses + if ( local_ip != NULL ) strcpy(local_ip, inet_ntoa( loc_ip )); + if ( netmask != NULL ) strcpy(netmask, inet_ntoa( mask)); + if ( gateway != NULL ) strcpy(gateway, inet_ntoa( gw )); + } + return ret; +} + + +s32 net_init() +{ + sys_sem sem; + + if(tcpiplayer_inited) return 1; + + if(LWP_SemInit(&netsocket_sem,1,1)==-1) return -1; + if(LWP_SemInit(&sockselect_sem,1,1)==-1) { + LWP_SemDestroy(netsocket_sem); + return -1; + } + if(LWP_SemInit(&sem,0,1)==-1) { + LWP_SemDestroy(netsocket_sem); + LWP_SemDestroy(sockselect_sem); + return -1; + } + + if(LWP_CreateThread(&hnet_thread,net_thread,(void*)sem,netthread_stack,STACKSIZE,220)==-1) { + LWP_SemDestroy(netsocket_sem); + LWP_SemDestroy(sockselect_sem); + LWP_SemDestroy(sem); + return -1; + } + LWP_SemWait(sem); + LWP_SemDestroy(sem); + + tcpiplayer_inited = 1; + + return 0; +} + +s32 net_shutdown(s32 s,u32 how) +{ + return -1; +} + +s32 net_fcntl(s32 s, u32 cmd, u32 flags) +{ + return -1; +} + +s32 net_socket(u32 domain,u32 type,u32 protocol) +{ + s32 i; + struct netconn *conn; + + switch(type) { + case SOCK_RAW: + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_socket(SOCK_RAW)\n")); + conn = netconn_new_with_proto_and_callback(NETCONN_RAW,protocol,evt_callback); + break; + case SOCK_DGRAM: + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_socket(SOCK_DGRAM)\n")); + conn = netconn_new_with_callback(NETCONN_UDP,evt_callback); + break; + case SOCK_STREAM: + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_socket(SOCK_STREAM)\n")); + conn = netconn_new_with_callback(NETCONN_TCP,evt_callback); + break; + default: + return -1; + } + if(!conn) return -1; + + i = alloc_socket(conn); + if(i==-1) { + netconn_delete(conn); + return -1; + } + + conn->socket = i; + return i; +} + +s32 net_accept(s32 s,struct sockaddr *addr,socklen_t *addrlen) +{ + struct netsocket *sock; + struct netconn *newconn; + struct ip_addr naddr = {0}; + u16 port = 0; + s32 newsock; + struct sockaddr_in sin; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_accept(%d)\n", s)); + + sock = get_socket(s); + if(!sock) return -ENOTSOCK; + + newconn = netconn_accept(sock->conn); + netconn_peer(newconn,&naddr,&port); + + memset(&sin,0,sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = naddr.addr; + + if(*addrlen>sizeof(sin)) + *addrlen = sizeof(sin); + memcpy(addr,&sin,*addrlen); + + newsock = alloc_socket(newconn); + if(newsock==-1) { + netconn_delete(newconn); + return -1; + } + + newconn->callback = evt_callback; + sock = get_socket(newsock); + + LWP_SemWait(netsocket_sem); + sock->rcvevt += -1 - newconn->socket; + newconn->socket = newsock; + LWP_SemPost(netsocket_sem); + + return newsock; +} + +s32 net_bind(s32 s,struct sockaddr *name,socklen_t namelen) +{ + struct netsocket *sock; + struct ip_addr loc_addr; + u16 loc_port; + err_t err; + + sock = get_socket(s); + if(!sock) return -ENOTSOCK; + + loc_addr.addr = ((struct sockaddr_in*)name)->sin_addr.s_addr; + loc_port = ((struct sockaddr_in*)name)->sin_port; + + err = netconn_bind(sock->conn,&loc_addr,ntohs(loc_port)); + if(err!=ERR_OK) return -1; + + return 0; +} + +s32 net_listen(s32 s,u32 backlog) +{ + struct netsocket *sock; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_listen(%d, backlog=%d)\n", s, backlog)); + sock = get_socket(s); + if(!sock) return -ENOTSOCK; + + err = netconn_listen(sock->conn); + if(err!=ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_listen(%d) failed, err=%d\n", s, err)); + return -1; + } + return 0; +} + +s32 net_recvfrom(s32 s,void *mem,s32 len,u32 flags,struct sockaddr *from,socklen_t *fromlen) +{ + struct netsocket *sock; + struct netbuf *buf; + u16 buflen,copylen; + struct ip_addr *addr; + u16 port; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags)); + if(mem==NULL || len<=0) return -EINVAL; + + sock = get_socket(s); + if(!sock) return -ENOTSOCK; + + if(sock->lastdata) + buf = sock->lastdata; + else { + if(((flags&MSG_DONTWAIT) || (sock->flags&O_NONBLOCK)) && !sock->rcvevt) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_recvfrom(%d): returning EWOULDBLOCK\n", s)); + return -EAGAIN; + } + buf = netconn_recv(sock->conn); + if(!buf) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_recvfrom(%d): buf == NULL!\n", s)); + return 0; + } + } + + buflen = netbuf_len(buf); + buflen -= sock->lastoffset; + if(buflen<=0) + return 0; + if(len>buflen) + copylen = buflen; + else + copylen = len; + + netbuf_copypartial(buf,mem,copylen,sock->lastoffset); + + if(from && fromlen) { + struct sockaddr_in sin; + + addr = netbuf_fromaddr(buf); + port = netbuf_fromport(buf); + + memset(&sin,0,sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = addr->addr; + + if(*fromlen>sizeof(sin)) + *fromlen = sizeof(sin); + + memcpy(from,&sin,*fromlen); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_recvfrom(%d): addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen)); + } + if(netconn_type(sock->conn)==NETCONN_TCP && (buflen-copylen)>0) { + sock->lastdata = buf; + sock->lastoffset += copylen; + } else { + sock->lastdata = NULL; + sock->lastoffset = 0; + netbuf_delete(buf); + } + return copylen; +} + +s32 net_read(s32 s,void *mem,s32 len) +{ + return net_recvfrom(s,mem,len,0,NULL,NULL); +} + +s32 net_recv(s32 s,void *mem,s32 len,u32 flags) +{ + return net_recvfrom(s,mem,len,flags,NULL,NULL); +} + +s32 net_sendto(s32 s,const void *data,s32 len,u32 flags,struct sockaddr *to,socklen_t tolen) +{ + struct netsocket *sock; + struct ip_addr remote_addr, addr; + u16_t remote_port, port = 0; + s32 ret,connected; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_sendto(%d, data=%p, size=%d, flags=0x%x)\n", s, data, len, flags)); + if(data==NULL || len<=0) return -EINVAL; + + sock = get_socket(s); + if (!sock) return -ENOTSOCK; + + /* get the peer if currently connected */ + connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK); + + remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; + remote_port = ((struct sockaddr_in *)to)->sin_port; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, len, flags)); + ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port))); + + netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); + + ret = net_send(s, data, len, flags); + + /* reset the remote address and port number + of the connection */ + if (connected) + netconn_connect(sock->conn, &addr, port); + else + netconn_disconnect(sock->conn); + return ret; +} + +s32 net_send(s32 s,const void *data,s32 len,u32 flags) +{ + struct netsocket *sock; + struct netbuf *buf; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, len, flags)); + if(data==NULL || len<=0) return -EINVAL; + + sock = get_socket(s); + if(!sock) return -ENOTSOCK; + + switch(netconn_type(sock->conn)) { + case NETCONN_RAW: + case NETCONN_UDP: + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + buf = netbuf_new(); + if(!buf) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_send(%d) ENOBUFS\n", s)); + return -ENOBUFS; + } + netbuf_ref(buf,data,len); + err = netconn_send(sock->conn,buf); + netbuf_delete(buf); + break; + case NETCONN_TCP: + err = netconn_write(sock->conn,data,len,NETCONN_COPY); + break; + default: + err = ERR_ARG; + break; + } + if(err!=ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_send(%d) err=%d\n", s, err)); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_send(%d) ok size=%d\n", s, len)); + return len; +} + +s32 net_write(s32 s,const void *data,s32 size) +{ + return net_send(s,data,size,0); +} + +s32 net_connect(s32 s,struct sockaddr *name,socklen_t namelen) +{ + struct netsocket *sock; + err_t err; + + sock = get_socket(s); + if(!sock) return -ENOTSOCK; + + if(((struct sockaddr_in*)name)->sin_family==AF_UNSPEC) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_connect(%d, AF_UNSPEC)\n", s)); + err = netconn_disconnect(sock->conn); + } else { + struct ip_addr remote_addr; + u16 remote_port; + + remote_addr.addr = ((struct sockaddr_in*)name)->sin_addr.s_addr; + remote_port = ((struct sockaddr_in*)name)->sin_port; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_connect(%d, addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port))); + + err = netconn_connect(sock->conn,&remote_addr,ntohs(remote_port)); + } + if(err!=ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_connect(%d) failed, err=%d\n", s, err)); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_connect(%d) succeeded\n", s)); + return -EISCONN; +} + +s32 net_close(s32 s) +{ + struct netsocket *sock; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_close(%d)\n", s)); + + LWP_SemWait(netsocket_sem); + + sock = get_socket(s); + if(!sock) { + LWP_SemPost(netsocket_sem); + return -ENOTSOCK; + } + + netconn_delete(sock->conn); + if(sock->lastdata) netbuf_delete(sock->lastdata); + + sock->lastdata = NULL; + sock->lastoffset = 0; + sock->conn = NULL; + + LWP_SemPost(netsocket_sem); + return 0; +} + +static s32 net_selscan(s32 maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset) +{ + s32 i,nready = 0; + fd_set lreadset,lwriteset,lexceptset; + struct netsocket *sock; + + FD_ZERO(&lreadset); + FD_ZERO(&lwriteset); + FD_ZERO(&lexceptset); + + for(i=0;ilastdata || sock->rcvevt)) { + FD_SET(i,&lreadset); + nready++; + } + } + if(FD_ISSET(i,writeset)) { + sock = get_socket(i); + if(sock && sock->sendevt) { + FD_SET(i,&lwriteset); + nready++; + } + } + } + *readset = lreadset; + *writeset = lwriteset; + FD_ZERO(exceptset); + + return nready; +} + +s32 net_select(s32 maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,struct timeval *timeout) +{ + s32 i,nready; + fd_set lreadset,lwriteset,lexceptset; + struct timespec tb,*p_tb; + struct netselect_cb sel_cb; + struct netselect_cb *psel_cb; + + sel_cb.next = NULL; + sel_cb.readset = readset; + sel_cb.writeset = writeset; + sel_cb.exceptset = exceptset; + sel_cb.signaled = 0; + + LWP_SemWait(sockselect_sem); + + if(readset) + lreadset = *readset; + else + FD_ZERO(&lreadset); + + if(writeset) + lwriteset = *writeset; + else + FD_ZERO(&lwriteset); + + if(exceptset) + lexceptset = *exceptset; + else + FD_ZERO(&lexceptset); + + nready = net_selscan(maxfdp1,&lreadset,&lwriteset,&lexceptset); + if(!nready) { + if(timeout && timeout->tv_sec==0 && timeout->tv_usec==0) { + LWP_SemPost(sockselect_sem); + if(readset) + FD_ZERO(readset); + if(writeset) + FD_ZERO(writeset); + if(exceptset) + FD_ZERO(exceptset); + return 0; + } + + LWP_MutexInit(&sel_cb.cond_lck,FALSE); + LWP_CondInit(&sel_cb.cond); + sel_cb.next = selectcb_list; + selectcb_list = &sel_cb; + + LWP_SemPost(sockselect_sem); + if(timeout==NULL) + p_tb = NULL; + else { + tb.tv_sec = timeout->tv_sec; + tb.tv_nsec = (timeout->tv_usec+500)*TB_NSPERUS; + p_tb = &tb; + } + + LWP_MutexLock(sel_cb.cond_lck); + i = LWP_CondTimedWait(sel_cb.cond,sel_cb.cond_lck,p_tb); + LWP_MutexUnlock(sel_cb.cond_lck); + + LWP_SemWait(sockselect_sem); + if(selectcb_list==&sel_cb) + selectcb_list = sel_cb.next; + else { + for(psel_cb = selectcb_list;psel_cb;psel_cb = psel_cb->next) { + if(psel_cb->next==&sel_cb) { + psel_cb->next = sel_cb.next; + break; + } + } + } + LWP_CondDestroy(sel_cb.cond); + LWP_MutexDestroy(sel_cb.cond_lck); + + LWP_SemPost(sockselect_sem); + + if(i==ETIMEDOUT) { + if(readset) + FD_ZERO(readset); + if(writeset) + FD_ZERO(writeset); + if(exceptset) + FD_ZERO(exceptset); + return 0; + } + + if(readset) + lreadset = *readset; + else + FD_ZERO(&lreadset); + + if(writeset) + lwriteset = *writeset; + else + FD_ZERO(&lwriteset); + + if(exceptset) + lexceptset = *exceptset; + else + FD_ZERO(&lexceptset); + + nready = net_selscan(maxfdp1,&lreadset,&lwriteset,&lexceptset); + } else + LWP_SemPost(sockselect_sem); + + if(readset) + *readset = lreadset; + if(writeset) + *writeset = lwriteset; + if(exceptset) + *exceptset = lexceptset; + + return nready; +} + +s32 net_setsockopt(s32 s,u32 level,u32 optname,const void *optval,socklen_t optlen) +{ + s32 err = 0; + struct netsocket *sock; + + sock = get_socket(s); + if(sock==NULL) return -ENOTSOCK; + if(optval==NULL) return -EINVAL; + + switch(level) { + case SOL_SOCKET: + { + switch(optname) { + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_REUSEADDR: + case SO_REUSEPORT: + if(optlenconn->type!=NETCONN_TCP) return 0; + + switch(optname) { + case TCP_NODELAY: + case TCP_KEEPALIVE: + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); + err = ENOPROTOOPT; + } + } + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname)); + err = ENOPROTOOPT; + } + if(err!=0) return -1; + + switch(level) { + case SOL_SOCKET: + { + switch(optname) { + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_REUSEADDR: + case SO_REUSEPORT: + if(*(u32*)optval) + sock->conn->pcb.tcp->so_options |= optname; + else + sock->conn->pcb.tcp->so_options &= ~optname; + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(u32*)optval?"on":"off"))); + break; + } + } + break; + + case IPPROTO_IP: + { + switch(optname) { + case IP_TTL: + sock->conn->pcb.tcp->ttl = (u8)(*(u32*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl)); + break; + case IP_TOS: + sock->conn->pcb.tcp->tos = (u8)(*(u32*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos)); + break; + } + } + break; + + case IPPROTO_TCP: + { + switch(optname) { + case TCP_NODELAY: + if(*(u32*)optval) + sock->conn->pcb.tcp->flags |= TF_NODELAY; + else + sock->conn->pcb.tcp->flags &= ~TF_NODELAY; + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(u32*)optval)?"on":"off") ); + break; + case TCP_KEEPALIVE: + sock->conn->pcb.tcp->keepalive = (u32)(*(u32*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %u\n", s, sock->conn->pcb.tcp->keepalive)); + break; + } + } + } + return err?-1:0; +} + +s32 net_ioctl(s32 s, u32 cmd, void *argp) +{ + struct netsocket *sock = get_socket(s); + + if(!sock) return -ENOTSOCK; + + switch (cmd) { + case FIONREAD: + if(!argp) return -EINVAL; + + *((u16_t*)argp) = sock->conn->recvavail; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16*)argp))); + return 0; + + case FIONBIO: + if(argp && *(u32*)argp) + sock->flags |= O_NONBLOCK; + else + sock->flags &= ~O_NONBLOCK; + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags&O_NONBLOCK))); + return 0; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("net_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); + return -EINVAL; + } +} diff --git a/wii/libogc/wiiuse/classic.c b/wii/libogc/wiiuse/classic.c new file mode 100644 index 0000000000..671522c21c --- /dev/null +++ b/wii/libogc/wiiuse/classic.c @@ -0,0 +1,225 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/classic.c,v 1.7 2008-11-14 13:34:57 shagkur Exp $ + * + */ + +/** + * @file + * @brief Classic controller expansion device. + */ + +#include +#include +#include +#include + +#ifdef WIN32 + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "classic.h" +#include "io.h" + +static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now); + +/** + * @brief Handle the handshake data from the classic controller. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * @return Returns 1 if handshake was successful, 0 if not. + */ +int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, ubyte* data, uword len) { + //int i; + int offset = 0; + + cc->btns = 0; + cc->btns_held = 0; + cc->btns_released = 0; + + /* decrypt data */ + /* + for (i = 0; i < len; ++i) + data[i] = (data[i] ^ 0x17) + 0x17; + */ + + /* is this a wiiu pro? */ + if (len > 223 && data[223] == 0x20) { + cc->ljs.max.x = cc->ljs.max.y = 0xFF; + cc->ljs.min.x = cc->ljs.min.y = 0; + cc->ljs.center.x = cc->ljs.center.y = 0x80; + + cc->rjs = cc->ljs; + + cc->type = 2; + } + else { + if (data[offset] == 0xFF) { + /* + * Sometimes the data returned here is not correct. + * This might happen because the wiimote is lagging + * behind our initialization sequence. + * To fix this just request the handshake again. + * + * Other times it's just the first 16 bytes are 0xFF, + * but since the next 16 bytes are the same, just use + * those. + */ + if (data[offset + 16] == 0xFF) { + /* get the calibration data again */ + WIIUSE_DEBUG("Classic controller handshake appears invalid, trying again."); + wiiuse_read_data(wm, data, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN, wiiuse_handshake_expansion); + } else + offset += 16; + } + + if (len > 218 && data[218]) + cc->type = 1; /* classic controller pro (no analog triggers) */ + else + cc->type = 0; /* original classic controller (analog triggers) */ + + /* joystick stuff */ + cc->ljs.max.x = data[0 + offset] / 4 == 0 ? 64 : data[0 + offset] / 4; + cc->ljs.min.x = data[1 + offset] / 4; + cc->ljs.center.x = data[2 + offset] / 4 == 0 ? 32 : data[2 + offset] / 4; + cc->ljs.max.y = data[3 + offset] / 4 == 0 ? 64 : data[3 + offset] / 4; + cc->ljs.min.y = data[4 + offset] / 4; + cc->ljs.center.y = data[5 + offset] / 4 == 0 ? 32 : data[5 + offset] / 4; + + cc->rjs.max.x = data[6 + offset] / 8 == 0 ? 32 : data[6 + offset] / 8; + cc->rjs.min.x = data[7 + offset] / 8; + cc->rjs.center.x = data[8 + offset] / 8 == 0 ? 16 : data[8 + offset] / 8; + cc->rjs.max.y = data[9 + offset] / 8 == 0 ? 32 : data[9 + offset] / 8; + cc->rjs.min.y = data[10 + offset] / 8; + cc->rjs.center.y = data[11 + offset] / 8 == 0 ? 16 : data[11 + offset] / 8; + } + /* handshake done */ + wm->event = WIIUSE_CLASSIC_CTRL_INSERTED; + wm->exp.type = EXP_CLASSIC; + + #ifdef WIN32 + wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; + #endif + + return 1; +} + + +/** + * @brief The classic controller disconnected. + * + * @param cc A pointer to a classic_ctrl_t structure. + */ +void classic_ctrl_disconnected(struct classic_ctrl_t* cc) +{ + memset(cc, 0, sizeof(struct classic_ctrl_t)); +} + + + +/** + * @brief Handle classic controller event. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message specified in the event packet. + */ +void classic_ctrl_event(struct classic_ctrl_t* cc, ubyte* msg) { + //int i; + + /* decrypt data */ + /* + for (i = 0; i < 6; ++i) + msg[i] = (msg[i] ^ 0x17) + 0x17; + */ + if (cc->type==2) { + classic_ctrl_pressed_buttons(cc, BIG_ENDIAN_SHORT(*(short*)(msg + 8))); + + /* 12-bit little endian values adjusted to 8-bit */ + cc->ljs.pos.x = (msg[0] >> 4) | (msg[1] << 4); + cc->rjs.pos.x = (msg[2] >> 4) | (msg[3] << 4); + cc->ljs.pos.y = (msg[4] >> 4) | (msg[5] << 4); + cc->rjs.pos.y = (msg[6] >> 4) | (msg[7] << 4); + + cc->ls_raw = cc->btns & CLASSIC_CTRL_BUTTON_FULL_L ? 0x1F : 0; + cc->rs_raw = cc->btns & CLASSIC_CTRL_BUTTON_FULL_R ? 0x1F : 0; + } + else { + classic_ctrl_pressed_buttons(cc, BIG_ENDIAN_SHORT(*(short*)(msg + 4))); + + /* left/right buttons */ + cc->ls_raw = (((msg[2] & 0x60) >> 2) | ((msg[3] & 0xE0) >> 5)); + cc->rs_raw = (msg[3] & 0x1F); + + /* + * TODO - LR range hardcoded from 0x00 to 0x1F. + * This is probably in the calibration somewhere. + */ +#ifndef GEKKO + cc->r_shoulder = ((float)r / 0x1F); + cc->l_shoulder = ((float)l / 0x1F); +#endif + /* calculate joystick orientation */ + cc->ljs.pos.x = (msg[0] & 0x3F); + cc->ljs.pos.y = (msg[1] & 0x3F); + cc->rjs.pos.x = ((msg[0] & 0xC0) >> 3) | ((msg[1] & 0xC0) >> 5) | ((msg[2] & 0x80) >> 7); + cc->rjs.pos.y = (msg[2] & 0x1F); + } + +#ifndef GEKKO + calc_joystick_state(&cc->ljs, cc->ljs.pos.x, cc->ljs.pos.y); + calc_joystick_state(&cc->rjs, cc->rjs.pos.x, cc->rjs.pos.y); +#endif +} + + +/** + * @brief Find what buttons are pressed. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message byte specified in the event packet. + */ +static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & CLASSIC_CTRL_BUTTON_ALL; + + /* preserve old btns pressed */ + cc->btns_last = cc->btns; + + /* pressed now & were pressed, then held */ + cc->btns_held = (now & cc->btns); + + /* were pressed or were held & not pressed now, then released */ + cc->btns_released = ((cc->btns | cc->btns_held) & ~now); + + /* buttons pressed now */ + cc->btns = now; +} diff --git a/wii/libogc/wiiuse/classic.h b/wii/libogc/wiiuse/classic.h new file mode 100644 index 0000000000..2e741efca5 --- /dev/null +++ b/wii/libogc/wiiuse/classic.h @@ -0,0 +1,56 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/classic.h,v 1.1 2008-05-08 09:42:14 shagkur Exp $ + * + */ + +/** + * @file + * @brief Classic controller expansion device. + */ + +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef CLASSIC_H_INCLUDED +#define CLASSIC_H_INCLUDED + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, ubyte* data, uword len); + +void classic_ctrl_disconnected(struct classic_ctrl_t* cc); + +void classic_ctrl_event(struct classic_ctrl_t* cc, ubyte* msg); + +#ifdef __cplusplus +} +#endif + +#endif // CLASSIC_H_INCLUDED diff --git a/wii/libogc/wiiuse/definitions.h b/wii/libogc/wiiuse/definitions.h new file mode 100644 index 0000000000..04dc5be6d8 --- /dev/null +++ b/wii/libogc/wiiuse/definitions.h @@ -0,0 +1,55 @@ +#ifndef __DEFINITIONS_H__ +#define __DEFINITIONS_H__ + +#include "os.h" + +#define WIIMOTE_PI 3.14159265f + +//#define WITH_WIIUSE_DEBUG + +/* Error output macros */ +#define WIIUSE_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__) + +/* Warning output macros */ +#define WIIUSE_WARNING(fmt, ...) fprintf(stderr, "[WARNING] " fmt "\n", ##__VA_ARGS__) + +/* Information output macros */ +#define WIIUSE_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__) + +#ifdef WITH_WIIUSE_DEBUG + #ifdef WIN32 + #define WIIUSE_DEBUG(fmt, ...) do { \ + char* file = __FILE__; \ + int i = strlen(file) - 1; \ + for (; i && (file[i] != '\\'); --i); \ + fprintf(stderr, "[DEBUG] %s:%i: " fmt "\n", file+i+1, __LINE__, ##__VA_ARGS__); \ + } while (0) + #else + #define WIIUSE_DEBUG(fmt, ...) fprintf(stderr, "[DEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__) + #endif +#else + #define WIIUSE_DEBUG(fmt, ...) +#endif + +#if 1 +#define WII_DEBUG(fmt, ...) do { \ + printf("[WDEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__); \ + usleep(3000000); \ + } while (0) +#else + #define WII_DEBUG(fmt, ...) +#endif + + +/* Convert between radians and degrees */ +#define RAD_TO_DEGREE(r) ((r * 180.0f) / WIIMOTE_PI) +#define DEGREE_TO_RAD(d) (d * (WIIMOTE_PI / 180.0f)) + +/* Convert to big endian */ +#define BIG_ENDIAN_LONG(i) (htonl(i)) +#define BIG_ENDIAN_SHORT(i) (htons(i)) + +#define absf(x) ((x >= 0) ? (x) : (x * -1.0f)) +#define diff_f(x, y) ((x >= y) ? (absf(x - y)) : (absf(y - x))) + +#endif diff --git a/wii/libogc/wiiuse/dynamics.c b/wii/libogc/wiiuse/dynamics.c new file mode 100644 index 0000000000..b30539e97b --- /dev/null +++ b/wii/libogc/wiiuse/dynamics.c @@ -0,0 +1,240 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/dynamics.c,v 1.2 2008-11-14 13:34:57 shagkur Exp $ + * + */ + +/** + * @file + * @brief Handles the dynamics of the wiimote. + * + * The file includes functions that handle the dynamics + * of the wiimote. Such dynamics include orientation and + * motion sensing. + */ + +#include +#include +#include + +#ifdef WIN32 + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "ir.h" +#include "dynamics.h" + +/** + * @brief Calculate the roll, pitch, yaw. + * + * @param ac An accelerometer (accel_t) structure. + * @param accel [in] Pointer to a vec3w_t structure that holds the raw acceleration data. + * @param orient [out] Pointer to a orient_t structure that will hold the orientation data. + * @param rorient [out] Pointer to a orient_t structure that will hold the non-smoothed orientation data. + * @param smooth If smoothing should be performed on the angles calculated. 1 to enable, 0 to disable. + * + * Given the raw acceleration data from the accelerometer struct, calculate + * the orientation of the device and set it in the \a orient parameter. + */ +void calculate_orientation(struct accel_t* ac, struct vec3w_t* accel, struct orient_t* orient, int smooth) { + float xg, yg, zg; + float x, y, z; + + /* + * roll - use atan(z / x) [ ranges from -180 to 180 ] + * pitch - use atan(z / y) [ ranges from -180 to 180 ] + * yaw - impossible to tell without IR + */ + + /* yaw - set to 0, IR will take care of it if it's enabled */ + orient->yaw = 0.0f; + + /* find out how much it has to move to be 1g */ + xg = (float)ac->cal_g.x; + yg = (float)ac->cal_g.y; + zg = (float)ac->cal_g.z; + + /* find out how much it actually moved and normalize to +/- 1g */ + x = ((float)accel->x - (float)ac->cal_zero.x) / xg; + y = ((float)accel->y - (float)ac->cal_zero.y) / yg; + z = ((float)accel->z - (float)ac->cal_zero.z) / zg; + + /* make sure x,y,z are between -1 and 1 for the tan functions */ + if (x < -1.0f) x = -1.0f; + else if (x > 1.0f) x = 1.0f; + if (y < -1.0f) y = -1.0f; + else if (y > 1.0f) y = 1.0f; + if (z < -1.0f) z = -1.0f; + else if (z > 1.0f) z = 1.0f; + + /* if it is over 1g then it is probably accelerating and not reliable */ + if (abs(accel->x - ac->cal_zero.x) <= (ac->cal_g.x+10)) { + /* roll */ + x = RAD_TO_DEGREE(atan2f(x, z)); + if(isfinite(x)) { + orient->roll = x; + orient->a_roll = x; + } + } + + if (abs(accel->y - ac->cal_zero.y) <= (ac->cal_g.y+10)) { + /* pitch */ + y = RAD_TO_DEGREE(atan2f(y, z)); + if(isfinite(y)) { + orient->pitch = y; + orient->a_pitch = y; + } + } + + /* smooth the angles if enabled */ + if (smooth) { + apply_smoothing(ac, orient, SMOOTH_ROLL); + apply_smoothing(ac, orient, SMOOTH_PITCH); + } +} + + +/** + * @brief Calculate the gravity forces on each axis. + * + * @param ac An accelerometer (accel_t) structure. + * @param accel [in] Pointer to a vec3w_t structure that holds the raw acceleration data. + * @param gforce [out] Pointer to a gforce_t structure that will hold the gravity force data. + */ +void calculate_gforce(struct accel_t* ac, struct vec3w_t* accel, struct gforce_t* gforce) { + float xg, yg, zg; + + /* find out how much it has to move to be 1g */ + xg = (float)ac->cal_g.x; + yg = (float)ac->cal_g.y; + zg = (float)ac->cal_g.z; + + /* find out how much it actually moved and normalize to +/- 1g */ + gforce->x = ((float)accel->x - (float)ac->cal_zero.x) / xg; + gforce->y = ((float)accel->y - (float)ac->cal_zero.y) / yg; + gforce->z = ((float)accel->z - (float)ac->cal_zero.z) / zg; +} + +static float applyCalibration(float inval,float minval, float maxval,float centerval) +{ + float ret; + /* We don't use the exact ranges but the ranges +1 in case we get bad calibration + * data - avoid div0 */ + + if (inval == centerval) + ret = 0; + else if (inval < centerval) + ret = (inval - centerval) / (centerval - minval + 1); + else + ret = (inval - centerval) / (maxval - centerval + 1); + return ret; +} + +/** + * @brief Calculate the angle and magnitude of a joystick. + * + * @param js [out] Pointer to a joystick_t structure. + * @param x The raw x-axis value. + * @param y The raw y-axis value. + */ +void calc_joystick_state(struct joystick_t* js, float x, float y) { + float rx, ry; + + /* + * Since the joystick center may not be exactly: + * (min + max) / 2 + * Then the range from the min to the center and the center to the max + * may be different. + * Because of this, depending on if the current x or y value is greater + * or less than the assoicated axis center value, it needs to be interpolated + * between the center and the minimum or maxmimum rather than between + * the minimum and maximum. + * + * So we have something like this: + * (x min) [-1] ---------*------ [0] (x center) [0] -------- [1] (x max) + * Where the * is the current x value. + * The range is therefore -1 to 1, 0 being the exact center rather than + * the middle of min and max. + */ + if (x == js->center.x) + rx = 0; + else if (x >= js->center.x) + rx = ((float)(x - js->center.x) / (float)(js->max.x - js->center.x)); + else + rx = ((float)(x - js->min.x) / (float)(js->center.x - js->min.x)) - 1.0f; + + if (y == js->center.y) + ry = 0; + else if (y >= js->center.y) + ry = ((float)(y - js->center.y) / (float)(js->max.y - js->center.y)); + else + ry = ((float)(y - js->min.y) / (float)(js->center.y - js->min.y)) - 1.0f; + + /* calculate the joystick angle and magnitude */ + js->ang = RAD_TO_DEGREE(atan2f(rx, ry)); + js->mag = hypotf(rx, ry); +} + + +void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type) { + switch (type) { + case SMOOTH_ROLL: + { + /* it's possible last iteration was nan or inf, so set it to 0 if that happened */ + if (isnan(ac->st_roll) || isinf(ac->st_roll)) + ac->st_roll = 0.0f; + + /* + * If the sign changes (which will happen if going from -180 to 180) + * or from (-1 to 1) then don't smooth, just use the new angle. + */ + if (((ac->st_roll < 0) && (orient->roll > 0)) || ((ac->st_roll > 0) && (orient->roll < 0))) { + ac->st_roll = orient->roll; + } else { + orient->roll = ac->st_roll + (ac->st_alpha * (orient->a_roll - ac->st_roll)); + ac->st_roll = orient->roll; + } + + return; + } + + case SMOOTH_PITCH: + { + if (isnan(ac->st_pitch) || isinf(ac->st_pitch)) + ac->st_pitch = 0.0f; + + if (((ac->st_pitch < 0) && (orient->pitch > 0)) || ((ac->st_pitch > 0) && (orient->pitch < 0))) { + ac->st_pitch = orient->pitch; + } else { + orient->pitch = ac->st_pitch + (ac->st_alpha * (orient->a_pitch - ac->st_pitch)); + ac->st_pitch = orient->pitch; + } + + return; + } + } +} diff --git a/wii/libogc/wiiuse/dynamics.h b/wii/libogc/wiiuse/dynamics.h new file mode 100644 index 0000000000..7d6f1ae642 --- /dev/null +++ b/wii/libogc/wiiuse/dynamics.h @@ -0,0 +1,59 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/dynamics.h,v 1.2 2008-11-14 13:34:57 shagkur Exp $ + * + */ + +/** + * @file + * @brief Handles the dynamics of the wiimote. + * + * The file includes functions that handle the dynamics + * of the wiimote. Such dynamics include orientation and + * motion sensing. + */ + +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef DYNAMICS_H_INCLUDED +#define DYNAMICS_H_INCLUDED + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void calculate_orientation(struct accel_t* ac, struct vec3w_t* accel, struct orient_t* orient, int smooth); +void calculate_gforce(struct accel_t* ac, struct vec3w_t* accel, struct gforce_t* gforce); +void calc_joystick_state(struct joystick_t* js, float x, float y); +void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type); + +#ifdef __cplusplus +} +#endif + +#endif // DYNAMICS_H_INCLUDED diff --git a/wii/libogc/wiiuse/events.c b/wii/libogc/wiiuse/events.c new file mode 100644 index 0000000000..4c435af2ee --- /dev/null +++ b/wii/libogc/wiiuse/events.c @@ -0,0 +1,336 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#include + +#ifndef WIN32 + #include + #include + #include +#else + #include +#endif + +#include +#include +#include +#include + +#include "dynamics.h" +#include "definitions.h" +#include "wiiuse_internal.h" +#include "events.h" +#include "nunchuk.h" +#include "classic.h" +#include "motion_plus.h" +#include "ir.h" +#include "io.h" + + +static void event_data_read(struct wiimote_t *wm,ubyte *msg) +{ + ubyte err; + ubyte len; + uword offset; + struct op_t *op; + struct cmd_blk_t *cmd = wm->cmd_head; + + wiiuse_pressed_buttons(wm,msg); + + if(!cmd) return; + if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_READ_DATA)) return; + + //printf("event_data_read(%p)\n",cmd); + + err = msg[2]&0x0f; + op = (struct op_t*)cmd->data; + if(err) { + wm->cmd_head = cmd->next; + + cmd->state = CMD_DONE; + if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,(op->readdata.size - op->wait)); + + __lwp_queue_append(&wm->cmdq,&cmd->node); + wiiuse_send_next_command(wm); + return; + } + + len = ((msg[2]&0xf0)>>4)+1; + offset = BIG_ENDIAN_SHORT(*(uword*)(msg+3)); + + //printf("addr: %08x\noffset: %d\nlen: %d\n",req->addr,offset,len); + + op->readdata.addr = (op->readdata.addr&0xffff); + op->wait -= len; + if(op->wait>=op->readdata.size) op->wait = 0; + + memcpy((op->buffer+offset-op->readdata.addr),(msg+5),len); + if(!op->wait) { + wm->cmd_head = cmd->next; + + wm->event = WIIUSE_READ_DATA; + cmd->state = CMD_DONE; + if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,op->readdata.size); + + __lwp_queue_append(&wm->cmdq,&cmd->node); + wiiuse_send_next_command(wm); + } +} + +static void event_ack(struct wiimote_t *wm,ubyte *msg) +{ + struct cmd_blk_t *cmd = wm->cmd_head; + + wiiuse_pressed_buttons(wm,msg); + + if(!cmd || cmd->state!=CMD_SENT || cmd->data[0]==WM_CMD_READ_DATA || cmd->data[0]==WM_CMD_CTRL_STATUS || cmd->data[0]!=msg[2] || msg[3]) { + //WIIUSE_WARNING("Unsolicited event ack: report %02x status %02x", msg[2], msg[3]); + return; + } + + //WIIUSE_DEBUG("Received ack for command %02x %02x", cmd->data[0], cmd->data[1]); + + wm->cmd_head = cmd->next; + + wm->event = WIIUSE_ACK; + cmd->state = CMD_DONE; + if(cmd->cb) cmd->cb(wm,NULL,0); + + __lwp_queue_append(&wm->cmdq,&cmd->node); + wiiuse_send_next_command(wm); +} + +static void event_status(struct wiimote_t *wm,ubyte *msg) +{ + int ir = 0; + int attachment = 0; +#ifdef HAVE_WIIUSE_SPEAKER + int speaker = 0; +#endif + //int led[4]= {0}; + struct cmd_blk_t *cmd = wm->cmd_head; + + wiiuse_pressed_buttons(wm,msg); + + wm->event = WIIUSE_STATUS; + //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_1) led[0] = 1; + //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_2) led[1] = 1; + //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_3) led[2] = 1; + //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_4) led[3] = 1; + + if((msg[2]&WM_CTRL_STATUS_BYTE1_ATTACHMENT)==WM_CTRL_STATUS_BYTE1_ATTACHMENT) attachment = 1; +#ifdef HAVE_WIIUSE_SPEAKER + if((msg[2]&WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED)==WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) speaker = 1; +#endif + if((msg[2]&WM_CTRL_STATUS_BYTE1_IR_ENABLED)==WM_CTRL_STATUS_BYTE1_IR_ENABLED) ir = 1; + + wm->battery_level = msg[5]; + + if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR_INIT)) { + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT); + wiiuse_set_ir(wm, 1); + goto done; + } + if(ir && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_IR); + else if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); + +#ifdef HAVE_WIIUSE_SPEAKER + if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER_INIT)) { + WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER_INIT); + wiiuse_set_speaker(wm,1); + goto done; + } + if(speaker && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_SPEAKER); + else if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER); +#endif + + if(attachment) { + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_FAILED) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE)) { + wiiuse_handshake_expansion_start(wm); + goto done; + } + } else { + WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_FAILED); + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) { + wiiuse_disable_expansion(wm); + goto done; + } + } + wiiuse_set_report_type(wm,NULL); + +done: + if(!cmd) return; + if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_CTRL_STATUS)) return; + + wm->cmd_head = cmd->next; + + cmd->state = CMD_DONE; + if(cmd->cb!=NULL) cmd->cb(wm,msg,6); + + __lwp_queue_append(&wm->cmdq,&cmd->node); + wiiuse_send_next_command(wm); +} + +static void handle_expansion(struct wiimote_t *wm,ubyte *msg) +{ + switch (wm->exp.type) { + case EXP_NUNCHUK: + nunchuk_event(&wm->exp.nunchuk, msg); + break; + case EXP_CLASSIC: + classic_ctrl_event(&wm->exp.classic, msg); + break; + case EXP_MOTION_PLUS: + motion_plus_event(&wm->exp.mp, msg); + break; + default: + break; + } +} + +/** + * @brief Called on a cycle where no significant change occurs. + * + * @param wm Pointer to a wiimote_t structure. + */ +void idle_cycle(struct wiimote_t* wm) +{ + /* + * Smooth the angles. + * + * This is done to make sure that on every cycle the orientation + * angles are smoothed. Normally when an event occurs the angles + * are updated and smoothed, but if no packet comes in then the + * angles remain the same. This means the angle wiiuse reports + * is still an old value. Smoothing needs to be applied in this + * case in order for the angle it reports to converge to the true + * angle of the device. + */ + //printf("idle_cycle()\n");/// + if (WIIUSE_USING_ACC(wm) && WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)) { + apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_ROLL); + apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_PITCH); + } +} + +void parse_event(struct wiimote_t *wm) +{ + ubyte event; + ubyte *msg; + + event = wm->event_buf[0]; + msg = wm->event_buf+1; + //printf("parse_event(%02x,%p)\n",event,msg); + switch(event) { + case WM_RPT_CTRL_STATUS: + event_status(wm,msg); + return; + case WM_RPT_READ: + event_data_read(wm,msg); + return; + case WM_RPT_ACK: + event_ack(wm,msg); + return; + case WM_RPT_BTN: + wiiuse_pressed_buttons(wm,msg); + break; + case WM_RPT_BTN_ACC: + wiiuse_pressed_buttons(wm,msg); + + wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); + wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); + wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); +#ifndef GEKKO + /* calculate the remote orientation */ + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + + /* calculate the gforces on each axis */ + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); +#endif + break; + case WM_RPT_BTN_ACC_IR: + wiiuse_pressed_buttons(wm,msg); + + wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); + wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); + wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); +#ifndef GEKKO + /* calculate the remote orientation */ + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + + /* calculate the gforces on each axis */ + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); +#endif + calculate_extended_ir(wm, msg+5); + break; + case WM_RPT_BTN_EXP: + wiiuse_pressed_buttons(wm,msg); + handle_expansion(wm,msg+2); + break; + case WM_RPT_BTN_ACC_EXP: + /* button - motion - expansion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); + wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); + wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); +#ifndef GEKKO + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); +#endif + handle_expansion(wm, msg+5); + break; + case WM_RPT_BTN_IR_EXP: + wiiuse_pressed_buttons(wm,msg); + calculate_basic_ir(wm, msg+2); + handle_expansion(wm,msg+12); + break; + case WM_RPT_BTN_ACC_IR_EXP: + /* button - motion - ir - expansion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); + wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); + wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); +#ifndef GEKKO + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); +#endif + /* ir */ + calculate_basic_ir(wm, msg+5); + + handle_expansion(wm, msg+15); + break; + default: + WIIUSE_WARNING("Unknown event, can not handle it [Code 0x%x].", event); + return; + } + + /* was there an event? */ + wm->event = WIIUSE_EVENT; +} + +/** + * @brief Find what buttons are pressed. + * + * @param wm Pointer to a wiimote_t structure. + * @param msg The message specified in the event packet. + */ +void wiiuse_pressed_buttons(struct wiimote_t* wm, ubyte* msg) { + short now; + + /* convert to big endian */ + now = BIG_ENDIAN_SHORT(*(short*)msg) & WIIMOTE_BUTTON_ALL; + + /* preserve old btns pressed */ + wm->btns_last = wm->btns; + + /* pressed now & were pressed, then held */ + wm->btns_held = (now & wm->btns); + + /* were pressed or were held & not pressed now, then released */ + wm->btns_released = ((wm->btns | wm->btns_held) & ~now); + + /* buttons pressed now */ + wm->btns = now; +} diff --git a/wii/libogc/wiiuse/events.h b/wii/libogc/wiiuse/events.h new file mode 100644 index 0000000000..a7de3380bd --- /dev/null +++ b/wii/libogc/wiiuse/events.h @@ -0,0 +1,17 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void wiiuse_pressed_buttons(struct wiimote_t* wm, ubyte* msg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/wiiuse/io.c b/wii/libogc/wiiuse/io.c new file mode 100644 index 0000000000..c062afd14f --- /dev/null +++ b/wii/libogc/wiiuse/io.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "nunchuk.h" +#include "classic.h" +#include "motion_plus.h" +#include "io.h" + +void wiiuse_handshake(struct wiimote_t *wm,ubyte *data,uword len) +{ + ubyte *buf = NULL; + struct accel_t *accel = &wm->accel_calib; + + //printf("wiiuse_handshake(%d,%p,%d)\n",wm->handshake_state,data,len); + + switch(wm->handshake_state) { + case 0: + wm->handshake_state++; + + wiiuse_set_leds(wm,WIIMOTE_LED_NONE,NULL); + wiiuse_status(wm,wiiuse_handshake); + return; + + case 1: + wm->handshake_state++; + buf = __lwp_wkspace_allocate(sizeof(ubyte)*8); + + if (len > 2 && data[2]&WM_CTRL_STATUS_BYTE1_ATTACHMENT) { + wiiuse_read_data(wm,buf,WM_EXP_ID,6,wiiuse_handshake); + return; + + case 2: + if (BIG_ENDIAN_LONG(*(int*)(&data[2])) == EXP_ID_CODE_CLASSIC_WIIU_PRO) { + memset(data, 0, 8); + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_WIIU_PRO); + break; + } + buf = data; + } + + wm->handshake_state++; + wiiuse_read_data(wm,buf,WM_MEM_OFFSET_CALIBRATION,7,wiiuse_handshake); + return; + } + + accel->cal_zero.x = ((data[0]<<2)|((data[3]>>4)&3)); + accel->cal_zero.y = ((data[1]<<2)|((data[3]>>2)&3)); + accel->cal_zero.z = ((data[2]<<2)|(data[3]&3)); + + accel->cal_g.x = (((data[4]<<2)|((data[7]>>4)&3)) - accel->cal_zero.x); + accel->cal_g.y = (((data[5]<<2)|((data[7]>>2)&3)) - accel->cal_zero.y); + accel->cal_g.z = (((data[6]<<2)|(data[7]&3)) - accel->cal_zero.z); + __lwp_wkspace_free(data); + + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE); + + wm->event = WIIUSE_CONNECT; + wiiuse_status(wm,NULL); +} + +void wiiuse_handshake_expansion_start(struct wiimote_t *wm) +{ + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP) || WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_FAILED) || WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE)) + return; + + wm->expansion_state = 0; + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE); + wiiuse_handshake_expansion(wm, NULL, 0); +} + +void wiiuse_handshake_expansion(struct wiimote_t *wm,ubyte *data,uword len) +{ + int id; + ubyte val; + ubyte *buf = NULL; + + switch(wm->expansion_state) { + /* These two initialization writes disable the encryption */ + case 0: + wm->expansion_state = 1; + val = 0x55; + wiiuse_write_data(wm,WM_EXP_MEM_ENABLE1,&val,1,wiiuse_handshake_expansion); + break; + case 1: + wm->expansion_state = 2; + val = 0x00; + wiiuse_write_data(wm,WM_EXP_MEM_ENABLE2,&val,1,wiiuse_handshake_expansion); + break; + case 2: + wm->expansion_state = 3; + buf = __lwp_wkspace_allocate(sizeof(ubyte)*EXP_HANDSHAKE_LEN); + wiiuse_read_data(wm,buf,WM_EXP_MEM_CALIBR,EXP_HANDSHAKE_LEN,wiiuse_handshake_expansion); + break; + case 3: + if(!data || !len) return; + id = BIG_ENDIAN_LONG(*(int*)(&data[220])); + + switch(id) { + case EXP_ID_CODE_NUNCHUK: + if(!nunchuk_handshake(wm,&wm->exp.nunchuk,data,len)) return; + break; + case EXP_ID_CODE_CLASSIC_CONTROLLER: + case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING: + case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING2: + case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING3: + case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC: + case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC2: + case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC3: + case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC4: + case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC5: + case EXP_ID_CODE_CLASSIC_WIIU_PRO: + if(!classic_ctrl_handshake(wm,&wm->exp.classic,data,len)) return; + break; + default: + if(!classic_ctrl_handshake(wm,&wm->exp.classic,data,len)) return; + /*WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_HANDSHAKE); + WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP_FAILED); + __lwp_wkspace_free(data); + wiiuse_status(wm,NULL); + return;*/ + } + __lwp_wkspace_free(data); + + WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_HANDSHAKE); + WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP); + wiiuse_set_ir_mode(wm); + wiiuse_status(wm,NULL); + break; + } +} + +void wiiuse_disable_expansion(struct wiimote_t *wm) +{ + if(!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) return; + + /* tell the associated module the expansion was removed */ + switch(wm->exp.type) { + case EXP_NUNCHUK: + nunchuk_disconnected(&wm->exp.nunchuk); + wm->event = WIIUSE_NUNCHUK_REMOVED; + break; + case EXP_CLASSIC: + classic_ctrl_disconnected(&wm->exp.classic); + wm->event = WIIUSE_CLASSIC_CTRL_REMOVED; + break; + case EXP_MOTION_PLUS: + motion_plus_disconnected(&wm->exp.mp); + wm->event = WIIUSE_MOTION_PLUS_REMOVED; + break; + + default: + break; + } + + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP); + wm->exp.type = EXP_NONE; + + wiiuse_set_ir_mode(wm); + wiiuse_status(wm,NULL); +} diff --git a/wii/libogc/wiiuse/io.h b/wii/libogc/wiiuse/io.h new file mode 100644 index 0000000000..738ceea137 --- /dev/null +++ b/wii/libogc/wiiuse/io.h @@ -0,0 +1,26 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef __IO_H__ +#define __IO_H__ + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void wiiuse_handshake(struct wiimote_t* wm,ubyte *data,uword len); +void wiiuse_handshake_expansion_start(struct wiimote_t *wm); +void wiiuse_handshake_expansion(struct wiimote_t *wm,ubyte *data,uword len); +void wiiuse_disable_expansion(struct wiimote_t *wm); + +int wiiuse_io_read(struct wiimote_t* wm); +int wiiuse_io_write(struct wiimote_t* wm, ubyte* buf, int len); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/wii/libogc/wiiuse/io_wii.c b/wii/libogc/wiiuse/io_wii.c new file mode 100644 index 0000000000..63e4b7b56a --- /dev/null +++ b/wii/libogc/wiiuse/io_wii.c @@ -0,0 +1,181 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifdef GEKKO + +#include +#include +#include +#include + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "events.h" +#include "io.h" +#include "lwp_wkspace.h" + +#define MAX_COMMANDS 0x100 +#define MAX_WIIMOTES 5 + +static vu32* const _ipcReg = (u32*)0xCD000000; +static u8 *__queue_buffer[MAX_WIIMOTES] = { 0, 0, 0, 0, 0 }; + +extern void parse_event(struct wiimote_t *wm); +extern void idle_cycle(struct wiimote_t* wm); +extern void hexdump(void *d, int len); + +static __inline__ u32 ACR_ReadReg(u32 reg) +{ + return _ipcReg[reg>>2]; +} + +static __inline__ void ACR_WriteReg(u32 reg,u32 val) +{ + _ipcReg[reg>>2] = val; +} + +static s32 __wiiuse_disconnected(void *arg,struct bte_pcb *pcb,u8 err) +{ + struct wiimote_listen_t *wml = (struct wiimote_listen_t*)arg; + struct wiimote_t *wm = wml->wm; + + if(!wm) return ERR_OK; + + //printf("wiimote disconnected\n"); + WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR|WIIMOTE_STATE_IR_INIT)); +#ifdef HAVE_WIIUSE_SPEAKER + WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_SPEAKER|WIIMOTE_STATE_SPEAKER_INIT)); +#endif + WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_EXP|WIIMOTE_STATE_EXP_HANDSHAKE|WIIMOTE_STATE_EXP_FAILED)); + WIIMOTE_DISABLE_STATE(wm,(WIIMOTE_STATE_CONNECTED|WIIMOTE_STATE_HANDSHAKE|WIIMOTE_STATE_HANDSHAKE_COMPLETE)); + + while(wm->cmd_head) { + __lwp_queue_append(&wm->cmdq,&wm->cmd_head->node); + wm->cmd_head = wm->cmd_head->next; + } + wm->cmd_tail = NULL; + + if(wm->event_cb) wm->event_cb(wm,WIIUSE_DISCONNECT); + + wml->wm = NULL; + return ERR_OK; +} + +static s32 __wiiuse_receive(void *arg,void *buffer,u16 len) +{ + struct wiimote_listen_t *wml = (struct wiimote_listen_t*)arg; + struct wiimote_t *wm = wml->wm; + + if(!wm || !buffer || len==0) return ERR_OK; + + //printf("__wiiuse_receive[%02x]\n",*(char*)buffer); + wm->event = WIIUSE_NONE; + + memcpy(wm->event_buf,buffer,len); + memset(&(wm->event_buf[len]),0,(MAX_PAYLOAD - len)); + parse_event(wm); + + if(wm->event!=WIIUSE_NONE) { + if(wm->event_cb) wm->event_cb(wm,wm->event); + } + + return ERR_OK; +} + +static s32 __wiiuse_connected(void *arg,struct bte_pcb *pcb,u8 err) +{ + struct wiimote_listen_t *wml = (struct wiimote_listen_t*)arg; + struct wiimote_t *wm; + + wm = wml->assign_cb(&wml->bdaddr); + + if(!wm) { + bte_disconnect(wml->sock); + return ERR_OK; + } + + wml->wm = wm; + + wm->sock = wml->sock; + wm->bdaddr = wml->bdaddr; + + //printf("__wiiuse_connected()\n"); + WIIMOTE_ENABLE_STATE(wm,(WIIMOTE_STATE_CONNECTED|WIIMOTE_STATE_HANDSHAKE)); + + wm->handshake_state = 0; + wiiuse_handshake(wm,NULL,0); + + return ERR_OK; +} + +void __wiiuse_sensorbar_enable(int enable) +{ + u32 val; + u32 level; + + level = IRQ_Disable(); + val = (ACR_ReadReg(0xc0)&~0x100); + if(enable) val |= 0x100; + ACR_WriteReg(0xc0,val); + IRQ_Restore(level); +} + +int wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr)) +{ + s32 err; + + if(!wml || !bdaddr || !assign_cb) return 0; + + wml->wm = NULL; + wml->bdaddr = *bdaddr; + wml->sock = bte_new(); + wml->assign_cb = assign_cb; + if(wml->sock==NULL) return 0; + + bte_arg(wml->sock,wml); + bte_received(wml->sock,__wiiuse_receive); + bte_disconnected(wml->sock,__wiiuse_disconnected); + + err = bte_registerdeviceasync(wml->sock,bdaddr,__wiiuse_connected); + if(err==ERR_OK) return 1; + + return 0; +} + +void wiiuse_disconnect(struct wiimote_t *wm) +{ + if(wm==NULL || wm->sock==NULL) return; + + WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_CONNECTED); + bte_disconnect(wm->sock); +} + +void wiiuse_sensorbar_enable(int enable) +{ + __wiiuse_sensorbar_enable(enable); +} + + +void wiiuse_init_cmd_queue(struct wiimote_t *wm) +{ + u32 size; + + if (!__queue_buffer[wm->unid]) { + size = (MAX_COMMANDS*sizeof(struct cmd_blk_t)); + __queue_buffer[wm->unid] = __lwp_heap_allocate(&__wkspace_heap,size); + if(!__queue_buffer[wm->unid]) return; + } + + __lwp_queue_initialize(&wm->cmdq,__queue_buffer[wm->unid],MAX_COMMANDS,sizeof(struct cmd_blk_t)); +} + +int wiiuse_io_write(struct wiimote_t *wm,ubyte *buf,int len) +{ + if(wm->sock) { + return bte_senddata(wm->sock,buf,len); + } + + return ERR_CONN; +} + +#endif diff --git a/wii/libogc/wiiuse/ir.c b/wii/libogc/wiiuse/ir.c new file mode 100644 index 0000000000..f118ea6e58 --- /dev/null +++ b/wii/libogc/wiiuse/ir.c @@ -0,0 +1,837 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#include +#include +#include + +#ifndef WIN32 + #include +#endif +#ifdef GEKKO + #include +#endif +#include "definitions.h" +#include "wiiuse_internal.h" +#include "ir.h" + +static int ir_correct_for_bounds(float* x, float* y, enum aspect_t aspect, int offset_x, int offset_y); +static void ir_convert_to_vres(float* x, float* y, enum aspect_t aspect, unsigned int vx, unsigned int vy); + +/** + * @brief Get the IR sensitivity settings. + * + * @param wm Pointer to a wiimote_t structure. + * @param block1 [out] Pointer to where block1 will be set. + * @param block2 [out] Pointer to where block2 will be set. + * + * @return Returns the sensitivity level. + */ +static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2) { + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL1)) { + *block1 = WM_IR_BLOCK1_LEVEL1; + *block2 = WM_IR_BLOCK2_LEVEL1; + return 1; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL2)) { + *block1 = WM_IR_BLOCK1_LEVEL2; + *block2 = WM_IR_BLOCK2_LEVEL2; + return 2; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL3)) { + *block1 = WM_IR_BLOCK1_LEVEL3; + *block2 = WM_IR_BLOCK2_LEVEL3; + return 3; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL4)) { + *block1 = WM_IR_BLOCK1_LEVEL4; + *block2 = WM_IR_BLOCK2_LEVEL4; + return 4; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL5)) { + *block1 = WM_IR_BLOCK1_LEVEL5; + *block2 = WM_IR_BLOCK2_LEVEL5; + return 5; + } + + *block1 = NULL; + *block2 = NULL; + return 0; +} + +static void rotate_dots(struct fdot_t* in, struct fdot_t *out, int count, float ang) { + float s, c; + int i; + + if (ang == 0) { + for (i = 0; i < count; ++i) { + out[i].x = in[i].x; + out[i].y = in[i].y; + } + return; + } + + s = sin(DEGREE_TO_RAD(ang)); + c = cos(DEGREE_TO_RAD(ang)); + + /* + * [ cos(theta) -sin(theta) ][ ir->rx ] + * [ sin(theta) cos(theta) ][ ir->ry ] + */ + + for (i = 0; i < count; ++i) { + out[i].x = (c * in[i].x) + (-s * in[i].y); + out[i].y = (s * in[i].x) + (c * in[i].y); + } +} + +/** + * @brief Correct for the IR bounding box. + * + * @param x [out] The current X, it will be updated if valid. + * @param y [out] The current Y, it will be updated if valid. + * @param aspect Aspect ratio of the screen. + * @param offset_x The X offset of the bounding box. + * @param offset_y The Y offset of the bounding box. + * + * @return Returns 1 if the point is valid and was updated. + * + * Nintendo was smart with this bit. They sacrifice a little + * precision for a big increase in usability. + */ +static int ir_correct_for_bounds(float* x, float* y, enum aspect_t aspect, int offset_x, int offset_y) { + float x0, y0; + int xs, ys; + + if (aspect == WIIUSE_ASPECT_16_9) { + xs = WM_ASPECT_16_9_X; + ys = WM_ASPECT_16_9_Y; + } else { + xs = WM_ASPECT_4_3_X; + ys = WM_ASPECT_4_3_Y; + } + + x0 = ((1024 - xs) / 2) + offset_x; + y0 = ((768 - ys) / 2) + offset_y; + + if ((*x >= x0) + && (*x <= (x0 + xs)) + && (*y >= y0) + && (*y <= (y0 + ys))) + { + *x -= offset_x; + *y -= offset_y; + + return 1; + } + + return 0; +} + + +/** + * @brief Interpolate the point to the user defined virtual screen resolution. + */ +static void ir_convert_to_vres(float* x, float* y, enum aspect_t aspect, unsigned int vx, unsigned int vy) { + int xs, ys; + + if (aspect == WIIUSE_ASPECT_16_9) { + xs = WM_ASPECT_16_9_X; + ys = WM_ASPECT_16_9_Y; + } else { + xs = WM_ASPECT_4_3_X; + ys = WM_ASPECT_4_3_Y; + } + + *x -= ((1024-xs)/2); + *y -= ((768-ys)/2); + + *x = (*x / (float)xs) * vx; + *y = (*y / (float)ys) * vy; +} + +void wiiuse_set_ir_mode(struct wiimote_t *wm) +{ + ubyte buf = 0x00; + + if(!wm) return; + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) return; + + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) buf = WM_IR_TYPE_BASIC; + else buf = WM_IR_TYPE_EXTENDED; + wiiuse_write_data(wm,WM_REG_IR_MODENUM, &buf, 1, NULL); +} + +void wiiuse_set_ir(struct wiimote_t *wm,int status) +{ + ubyte buf = 0x00; + int ir_level = 0; + char* block1 = NULL; + char* block2 = NULL; + + if(!wm) return; + + /* + * Wait for the handshake to finish first. + * When it handshake finishes and sees that + * IR is enabled, it will call this function + * again to actually enable IR. + */ + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { + WIIUSE_DEBUG("Tried to enable IR, will wait until handshake finishes.\n"); + if(status) + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_INIT); + else + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT); + return; + } + + /* + * Check to make sure a sensitivity setting is selected. + */ + ir_level = get_ir_sens(wm, &block1, &block2); + if (!ir_level) { + WIIUSE_ERROR("No IR sensitivity setting selected."); + return; + } + + if (status) { + /* if already enabled then stop */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { + wiiuse_status(wm,NULL); + return; + } + } else { + /* if already disabled then stop */ + if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { + wiiuse_status(wm,NULL); + return; + } + } + + buf = (status ? 0x04 : 0x00); + wiiuse_sendcmd(wm,WM_CMD_IR,&buf,1,NULL); + wiiuse_sendcmd(wm,WM_CMD_IR_2,&buf,1,NULL); + + if (!status) { + WIIUSE_DEBUG("Disabled IR cameras for wiimote id %i.", wm->unid); + wiiuse_status(wm,NULL); + return; + } + + /* enable IR, set sensitivity */ + buf = 0x08; + wiiuse_write_data(wm,WM_REG_IR,&buf,1,NULL); + + wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (ubyte*)block1, 9, NULL); + wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (ubyte*)block2, 2, NULL); + + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) buf = WM_IR_TYPE_BASIC; + else buf = WM_IR_TYPE_EXTENDED; + wiiuse_write_data(wm,WM_REG_IR_MODENUM, &buf, 1, NULL); + + wiiuse_status(wm,NULL); + return; +} + +/** + * @brief Set the virtual screen resolution for IR tracking. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + */ +void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y) { + if (!wm) return; + + wm->ir.vres[0] = (x-1); + wm->ir.vres[1] = (y-1); +} + +/** + * @brief Set the XY position for the IR cursor. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos) { + if (!wm) return; + + wm->ir.pos = pos; + + switch (pos) { + + case WIIUSE_IR_ABOVE: + wm->ir.offset[0] = 0; + + if (wm->ir.aspect == WIIUSE_ASPECT_16_9) + wm->ir.offset[1] = WM_ASPECT_16_9_Y/2 - 70; + else if (wm->ir.aspect == WIIUSE_ASPECT_4_3) + wm->ir.offset[1] = WM_ASPECT_4_3_Y/2 - 100; + + return; + + case WIIUSE_IR_BELOW: + wm->ir.offset[0] = 0; + + if (wm->ir.aspect == WIIUSE_ASPECT_16_9) + wm->ir.offset[1] = -WM_ASPECT_16_9_Y/2 + 70; + else if (wm->ir.aspect == WIIUSE_ASPECT_4_3) + wm->ir.offset[1] = -WM_ASPECT_4_3_Y/2 + 100; + + return; + + default: + return; + }; +} + +/** + * @brief Set the aspect ratio of the TV/monitor. + * + * @param wm Pointer to a wiimote_t structure. + * @param aspect Either WIIUSE_ASPECT_16_9 or WIIUSE_ASPECT_4_3 + */ +void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect) { + if (!wm) return; + + wm->ir.aspect = aspect; + + if (aspect == WIIUSE_ASPECT_4_3) { + wm->ir.vres[0] = WM_ASPECT_4_3_X; + wm->ir.vres[1] = WM_ASPECT_4_3_Y; + } else { + wm->ir.vres[0] = WM_ASPECT_16_9_X; + wm->ir.vres[1] = WM_ASPECT_16_9_Y; + } + + /* reset the position offsets */ + wiiuse_set_ir_position(wm, wm->ir.pos); +} + + +/** + * @brief Set the IR sensitivity. + * + * @param wm Pointer to a wiimote_t structure. + * @param level 1-5, same as Wii system sensitivity setting. + * + * If the level is < 1, then level will be set to 1. + * If the level is > 5, then level will be set to 5. + */ +void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level) { + char* block1 = NULL; + char* block2 = NULL; + + if (!wm) return; + + if (level > 5) level = 5; + if (level < 1) level = 1; + + WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR_SENS_LVL1 | + WIIMOTE_STATE_IR_SENS_LVL2 | + WIIMOTE_STATE_IR_SENS_LVL3 | + WIIMOTE_STATE_IR_SENS_LVL4 | + WIIMOTE_STATE_IR_SENS_LVL5)); + + switch (level) { + case 1: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL1); + break; + case 2: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL2); + break; + case 3: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL3); + break; + case 4: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL4); + break; + case 5: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL5); + break; + default: + return; + } + + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) return; + + /* set the new sensitivity */ + get_ir_sens(wm, &block1, &block2); + + wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (ubyte*)block1, 9,NULL); + wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (ubyte*)block2, 2,NULL); + + WIIUSE_DEBUG("Set IR sensitivity to level %i (unid %i)", level, wm->unid); +} + + +/** + * @brief Calculate the data from the IR spots. Basic IR mode. + * + * @param wm Pointer to a wiimote_t structure. + * @param data Data returned by the wiimote for the IR spots. + */ +void calculate_basic_ir(struct wiimote_t* wm, ubyte* data) { + struct ir_dot_t* dot = wm->ir.dot; + int i; + + dot[0].rx = 1023 - (data[0] | ((data[2] & 0x30) << 4)); + dot[0].ry = data[1] | ((data[2] & 0xC0) << 2); + + dot[1].rx = 1023 - (data[3] | ((data[2] & 0x03) << 8)); + dot[1].ry = data[4] | ((data[2] & 0x0C) << 6); + + dot[2].rx = 1023 - (data[5] | ((data[7] & 0x30) << 4)); + dot[2].ry = data[6] | ((data[7] & 0xC0) << 2); + + dot[3].rx = 1023 - (data[8] | ((data[7] & 0x03) << 8)); + dot[3].ry = data[9] | ((data[7] & 0x0C) << 6); + + /* set each IR spot to visible if spot is in range */ + for (i = 0; i < 4; ++i) { + dot[i].rx = BIG_ENDIAN_SHORT(dot[i].rx); + dot[i].ry = BIG_ENDIAN_SHORT(dot[i].ry); + + if (dot[i].ry == 1023) + dot[i].visible = 0; + else { + dot[i].visible = 1; + dot[i].size = 0; /* since we don't know the size, set it as 0 */ + } + } +#ifndef GEKKO + interpret_ir_data(&wm->ir,&wm->orient,WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC)); +#endif +} + +/** + * @brief Calculate the data from the IR spots. Extended IR mode. + * + * @param wm Pointer to a wiimote_t structure. + * @param data Data returned by the wiimote for the IR spots. + */ +void calculate_extended_ir(struct wiimote_t* wm, ubyte* data) { + struct ir_dot_t* dot = wm->ir.dot; + int i; + + for (i = 0; i < 4; ++i) { + dot[i].rx = 1023 - (data[3*i] | ((data[(3*i)+2] & 0x30) << 4)); + dot[i].ry = data[(3*i)+1] | ((data[(3*i)+2] & 0xC0) << 2); + + dot[i].size = data[(3*i)+2]; + + dot[i].rx = BIG_ENDIAN_SHORT(dot[i].rx); + dot[i].ry = BIG_ENDIAN_SHORT(dot[i].ry); + + dot[i].size = dot[i].size&0x0f; + + /* if in range set to visible */ + if (dot[i].ry == 1023) + dot[i].visible = 0; + else + dot[i].visible = 1; + } +#ifndef GEKKO + interpret_ir_data(&wm->ir,&wm->orient,WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC)); +#endif +} + +enum { + IR_STATE_DEAD = 0, + IR_STATE_GOOD, + IR_STATE_SINGLE, + IR_STATE_LOST, +}; + +// half-height of the IR sensor if half-width is 1 +#define HEIGHT (384.0f / 512.0f) +// maximum sensor bar slope (tan(35 degrees)) +#define MAX_SB_SLOPE 0.7f +// minimum sensor bar width in view, relative to half of the IR sensor area +#define MIN_SB_WIDTH 0.1f +// reject "sensor bars" that happen to have a dot towards the middle +#define SB_MIDDOT_REJECT 0.05f + +// physical dimensions +// cm center to center of emitters +#define SB_WIDTH 19.5f +// half-width in cm of emitters +#define SB_DOT_WIDTH 2.25f +// half-height in cm of emitters (with some tolerance) +#define SB_DOT_HEIGHT 1.0f + +#define SB_DOT_WIDTH_RATIO (SB_DOT_WIDTH / SB_WIDTH) +#define SB_DOT_HEIGHT_RATIO (SB_DOT_HEIGHT / SB_WIDTH) + +// dots further out than these coords are allowed to not be picked up +// otherwise assume something's wrong +//#define SB_OFF_SCREEN_X 0.8f +//#define SB_OFF_SCREEN_Y (0.8f * HEIGHT) + +// disable, may be doing more harm than good due to sensor pickup glitches +#define SB_OFF_SCREEN_X 0.0f +#define SB_OFF_SCREEN_Y 0.0f + +// if a point is closer than this to one of the previous SB points +// when it reappears, consider it the same instead of trying to guess +// which one of the two it is +#define SB_SINGLE_NOGUESS_DISTANCE (100.0 * 100.0) + +// width of the sensor bar in pixels at one meter from the Wiimote +#define SB_Z_COEFFICIENT 256.0f + +// distance in meters from the center of the FOV to the left or right edge, +// when the wiimote is at one meter +#define WIIMOTE_FOV_COEFFICIENT 0.39f + +#define SQUARED(x) ((x)*(x)) +#define WMAX(x,y) ((x>y)?(x):(y)) +#define WMIN(x,y) ((xroll); + + /* count visible dots and populate dots structure */ + /* dots[] is in -1..1 units for width */ + ir->num_dots = 0; + for (i = 0; i < 4; i++) { + if (ir->dot[i].visible) { + dots[ir->num_dots].x = (ir->dot[i].rx - 512.0f) / 512.0f; + dots[ir->num_dots].y = (ir->dot[i].ry - 384.0f) / 512.0f; + WIIUSE_DEBUG("IR: dot %d at (%d,%d) (%.03f,%.03f)\n",ir->num_dots,ir->dot[i].rx,ir->dot[i].ry,dots[ir->num_dots].x,dots[ir->num_dots].y); + ir->num_dots++; + } + } + + WIIUSE_DEBUG("IR: found %d dots\n",ir->num_dots); + + // nothing to track + if(ir->num_dots == 0) { + if(ir->state != IR_STATE_DEAD) + ir->state = IR_STATE_LOST; + ir->ax = 0; + ir->ay = 0; + ir->distance = 0.0f; + ir->raw_valid = 0; + return; + } + + /* ==== Find the Sensor Bar ==== */ + + // first rotate according to accelerometer orientation + rotate_dots(dots, acc_dots, ir->num_dots, orient->roll); + if(ir->num_dots > 1) { + WIIUSE_DEBUG("IR: locating sensor bar candidates\n"); + + // iterate through all dot pairs + for(first=0; first < (ir->num_dots-1); first++) { + for(second=(first+1); second < ir->num_dots; second++) { + WIIUSE_DEBUG("IR: trying dots %d and %d\n",first,second); + // order the dots leftmost first into cand + // storing both the raw dots and the accel-rotated dots + if(acc_dots[first].x > acc_dots[second].x) { + cand.dots[0] = dots[second]; + cand.dots[1] = dots[first]; + cand.acc_dots[0] = acc_dots[second]; + cand.acc_dots[1] = acc_dots[first]; + } else { + cand.dots[0] = dots[first]; + cand.dots[1] = dots[second]; + cand.acc_dots[0] = acc_dots[first]; + cand.acc_dots[1] = acc_dots[second]; + } + difference.x = cand.acc_dots[1].x - cand.acc_dots[0].x; + difference.y = cand.acc_dots[1].y - cand.acc_dots[0].y; + + // check angle + if(fabsf(difference.y / difference.x) > MAX_SB_SLOPE) + continue; + WIIUSE_DEBUG("IR: passed angle check\n"); + // rotate to the true sensor bar angle + cand.off_angle = -RAD_TO_DEGREE(atan2(difference.y, difference.x)); + cand.angle = cand.off_angle + orient->roll; + rotate_dots(cand.dots, cand.rot_dots, 2, cand.angle); + WIIUSE_DEBUG("IR: off_angle: %.02f, angle: %.02f\n", cand.off_angle, cand.angle); + // recalculate x distance - y should be zero now, so ignore it + difference.x = cand.rot_dots[1].x - cand.rot_dots[0].x; + + // check distance + if(difference.x < MIN_SB_WIDTH) + continue; + // middle dot check. If there's another source somewhere in the + // middle of this candidate, then this can't be a sensor bar + + for(i=0; inum_dots; i++) { + float wadj, hadj; + struct fdot_t tdot; + if(i==first || i==second) continue; + hadj = SB_DOT_HEIGHT_RATIO * difference.x; + wadj = SB_DOT_WIDTH_RATIO * difference.x; + rotate_dots(&dots[i], &tdot, 1, cand.angle); + if( ((cand.rot_dots[0].x + wadj) < tdot.x) && + ((cand.rot_dots[1].x - wadj) > tdot.x) && + ((cand.rot_dots[0].y + hadj) > tdot.y) && + ((cand.rot_dots[0].y - hadj) < tdot.y)) + break; + } + // failed middle dot check + if(i < ir->num_dots) continue; + WIIUSE_DEBUG("IR: passed middle dot check\n"); + + cand.score = 1 / (cand.rot_dots[1].x - cand.rot_dots[0].x); + + // we have a candidate, store it + WIIUSE_DEBUG("IR: new candidate %d\n",num_candidates); + candidates[num_candidates++] = cand; + } + } + } + + if(num_candidates == 0) { + int closest = -1; + int closest_to = 0; + float best = 999.0f; + float d; + float dx[2]; + struct sb_t sbx[2]; + // no sensor bar candidates, try to work with a lone dot + WIIUSE_DEBUG("IR: no candidates\n"); + switch(ir->state) { + case IR_STATE_DEAD: + WIIUSE_DEBUG("IR: we're dead\n"); + // we've never seen a sensor bar before, so we're screwed + ir->ax = 0.0f; + ir->ay = 0.0f; + ir->distance = 0.0f; + ir->raw_valid = 0; + return; + case IR_STATE_GOOD: + case IR_STATE_SINGLE: + case IR_STATE_LOST: + WIIUSE_DEBUG("IR: trying to keep track of single dot\n"); + // try to find the dot closest to the previous sensor bar position + for(i=0; inum_dots; i++) { + WIIUSE_DEBUG("IR: checking dot %d (%.02f, %.02f)\n",i, acc_dots[i].x,acc_dots[i].y); + for(j=0; j<2; j++) { + WIIUSE_DEBUG(" to dot %d (%.02f, %.02f)\n",j, ir->sensorbar.acc_dots[j].x,ir->sensorbar.acc_dots[j].y); + d = SQUARED(acc_dots[i].x - ir->sensorbar.acc_dots[j].x); + d += SQUARED(acc_dots[i].y - ir->sensorbar.acc_dots[j].y); + if(d < best) { + best = d; + closest_to = j; + closest = i; + } + } + } + WIIUSE_DEBUG("IR: closest dot is %d to %d\n",closest,closest_to); + if(ir->state != IR_STATE_LOST || best < SB_SINGLE_NOGUESS_DISTANCE) { + // now work out where the other dot would be, in the acc frame + sb.acc_dots[closest_to] = acc_dots[closest]; + sb.acc_dots[closest_to^1].x = ir->sensorbar.acc_dots[closest_to^1].x - ir->sensorbar.acc_dots[closest_to].x + acc_dots[closest].x; + sb.acc_dots[closest_to^1].y = ir->sensorbar.acc_dots[closest_to^1].y - ir->sensorbar.acc_dots[closest_to].y + acc_dots[closest].y; + // get the raw frame + rotate_dots(sb.acc_dots, sb.dots, 2, -orient->roll); + if((fabsf(sb.dots[closest_to^1].x) < SB_OFF_SCREEN_X) && (fabsf(sb.dots[closest_to^1].y) < SB_OFF_SCREEN_Y)) { + // this dot should be visible but isn't, since the candidate section failed. + // fall through and try to pick out the sensor bar without previous information + WIIUSE_DEBUG("IR: dot falls on screen, falling through\n"); + } else { + // calculate the rotated dots frame + // angle tends to drift, so recalculate + sb.off_angle = -RAD_TO_DEGREE(atan2(sb.acc_dots[1].y - sb.acc_dots[0].y, sb.acc_dots[1].x - sb.acc_dots[0].x)); + sb.angle = ir->sensorbar.off_angle + orient->roll; + rotate_dots(sb.acc_dots, sb.rot_dots, 2, ir->sensorbar.off_angle); + WIIUSE_DEBUG("IR: kept track of single dot\n"); + break; + } + } else { + WIIUSE_DEBUG("IR: lost the dot and new one is too far away\n"); + } + // try to find the dot closest to the sensor edge + WIIUSE_DEBUG("IR: trying to find best dot\n"); + for(i=0; inum_dots; i++) { + d = WMIN(1.0f - fabsf(dots[i].x), HEIGHT - fabsf(dots[i].y)); + if(d < best) { + best = d; + closest = i; + } + } + WIIUSE_DEBUG("IR: best dot: %d\n",closest); + // now try it as both places in the sensor bar + // and pick the one that places the other dot furthest off-screen + for(i=0; i<2; i++) { + sbx[i].acc_dots[i] = acc_dots[closest]; + sbx[i].acc_dots[i^1].x = ir->sensorbar.acc_dots[i^1].x - ir->sensorbar.acc_dots[i].x + acc_dots[closest].x; + sbx[i].acc_dots[i^1].y = ir->sensorbar.acc_dots[i^1].y - ir->sensorbar.acc_dots[i].y + acc_dots[closest].y; + rotate_dots(sbx[i].acc_dots, sbx[i].dots, 2, -orient->roll); + dx[i] = WMAX(fabsf(sbx[i].dots[i^1].x),fabsf(sbx[i].dots[i^1].y / HEIGHT)); + } + if(dx[0] > dx[1]) { + WIIUSE_DEBUG("IR: dot is LEFT: %.02f > %.02f\n",dx[0],dx[1]); + sb = sbx[0]; + } else { + WIIUSE_DEBUG("IR: dot is RIGHT: %.02f < %.02f\n",dx[0],dx[1]); + sb = sbx[1]; + } + // angle tends to drift, so recalculate + sb.off_angle = -RAD_TO_DEGREE(atan2(sb.acc_dots[1].y - sb.acc_dots[0].y, sb.acc_dots[1].x - sb.acc_dots[0].x)); + sb.angle = ir->sensorbar.off_angle + orient->roll; + rotate_dots(sb.acc_dots, sb.rot_dots, 2, ir->sensorbar.off_angle); + WIIUSE_DEBUG("IR: found new dot to track\n"); + break; + } + sb.score = 0; + ir->state = IR_STATE_SINGLE; + } else { + int bestidx = 0; + float best = 0.0f; + WIIUSE_DEBUG("IR: finding best candidate\n"); + // look for the best candidate + // for now, the formula is simple: pick the one with the smallest distance + for(i=0; i best) { + bestidx = i; + best = candidates[i].score; + } + } + WIIUSE_DEBUG("IR: best candidate: %d\n",bestidx); + sb = candidates[bestidx]; + ir->state = IR_STATE_GOOD; + } + + ir->raw_valid = 1; + ir->ax = ((sb.rot_dots[0].x + sb.rot_dots[1].x) / 2) * 512.0 + 512.0; + ir->ay = ((sb.rot_dots[0].y + sb.rot_dots[1].y) / 2) * 512.0 + 384.0; + ir->sensorbar = sb; + ir->distance = (sb.rot_dots[1].x - sb.rot_dots[0].x) * 512.0; + +} + +#define SMOOTH_IR_RADIUS 8.0f +#define SMOOTH_IR_SPEED 0.25f +#define SMOOTH_IR_DEADZONE 2.5f + +/** + * @brief Smooth the IR pointer position + * + * @param ir Pointer to an ir_t structure. + */ +void apply_ir_smoothing(struct ir_t *ir) { + f32 dx, dy, d, theta; + + WIIUSE_DEBUG("Smooth: OK (%.02f, %.02f) LAST (%.02f, %.02f) ", ir->ax, ir->ay, ir->sx, ir->sy); + dx = ir->ax - ir->sx; + dy = ir->ay - ir->sy; + d = sqrtf(dx*dx + dy*dy); + if (d > SMOOTH_IR_DEADZONE) { + if (d < SMOOTH_IR_RADIUS) { + WIIUSE_DEBUG("INSIDE\n"); + ir->sx += dx * SMOOTH_IR_SPEED; + ir->sy += dy * SMOOTH_IR_SPEED; + } else { + WIIUSE_DEBUG("OUTSIDE\n"); + theta = atan2f(dy, dx); + ir->sx = ir->ax - cosf(theta) * SMOOTH_IR_RADIUS; + ir->sy = ir->ay - sinf(theta) * SMOOTH_IR_RADIUS; + } + } else { + WIIUSE_DEBUG("DEADZONE\n"); + } +} + +// max number of errors before cooked data drops out +#define ERROR_MAX_COUNT 8 +// max number of glitches before cooked data updates +#define GLITCH_MAX_COUNT 5 +// squared delta over which we consider something a glitch +#define GLITCH_DIST (150.0f * 150.0f) + +/** + * @brief Interpret IR data into more user friendly variables. + * + * @param ir Pointer to an ir_t structure. + * @param orient Pointer to an orient_t structure. + */ +void interpret_ir_data(struct ir_t* ir, struct orient_t *orient) { + + float x,y; + float d; + + find_sensorbar(ir, orient); + + if(ir->raw_valid) { + ir->angle = ir->sensorbar.angle; + ir->z = SB_Z_COEFFICIENT / ir->distance; + orient->yaw = calc_yaw(ir); + if(ir->error_cnt >= ERROR_MAX_COUNT) { + ir->sx = ir->ax; + ir->sy = ir->ay; + ir->glitch_cnt = 0; + } else { + d = SQUARED(ir->ax - ir->sx) + SQUARED(ir->ay - ir->sy); + if(d > GLITCH_DIST) { + if(ir->glitch_cnt > GLITCH_MAX_COUNT) { + apply_ir_smoothing(ir); + ir->glitch_cnt = 0; + } else { + ir->glitch_cnt++; + } + } else { + ir->glitch_cnt = 0; + apply_ir_smoothing(ir); + } + } + ir->smooth_valid = 1; + ir->error_cnt = 0; + } else { + if(ir->error_cnt >= ERROR_MAX_COUNT) { + ir->smooth_valid = 0; + } else { + ir->smooth_valid = 1; + ir->error_cnt++; + } + } + if(ir->smooth_valid) { + x = ir->sx; + y = ir->sy; + if (ir_correct_for_bounds(&x, &y, ir->aspect, ir->offset[0], ir->offset[1])) { + ir_convert_to_vres(&x, &y, ir->aspect, ir->vres[0], ir->vres[1]); + ir->x = x; + ir->y = y; + ir->valid = 1; + } else { + ir->valid = 0; + } + } else { + ir->valid = 0; + } +} + +/** + * @brief Calculate yaw given the IR data. + * + * @param ir IR data structure. + */ +float calc_yaw(struct ir_t* ir) { + float x; + + x = ir->ax - 512; + x *= WIIMOTE_FOV_COEFFICIENT / 512.0; + + return RAD_TO_DEGREE( atanf(x) ); +} + diff --git a/wii/libogc/wiiuse/ir.h b/wii/libogc/wiiuse/ir.h new file mode 100644 index 0000000000..0ac683b8d1 --- /dev/null +++ b/wii/libogc/wiiuse/ir.h @@ -0,0 +1,25 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef __IR_H__ +#define __IR_H__ + +#include "wiiuse_internal.h" + +#define WII_VRES_X 560 +#define WII_VRES_Y 340 + +#ifdef __cplusplus +extern "C" { +#endif + +void calculate_basic_ir(struct wiimote_t* wm, ubyte* data); +void calculate_extended_ir(struct wiimote_t* wm, ubyte* data); +float calc_yaw(struct ir_t* ir); +void interpret_ir_data(struct ir_t* ir, struct orient_t *orient); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/wiiuse/license_libogc.txt b/wii/libogc/wiiuse/license_libogc.txt new file mode 100644 index 0000000000..a149fce1ce --- /dev/null +++ b/wii/libogc/wiiuse/license_libogc.txt @@ -0,0 +1,641 @@ +This license is valid ONLY for libogc and what this license +defines as a "covered work" or a "combined work" with libogc. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an officialder +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 18. Exceptions + + Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give +you permission to link this library with independent modules to produce +an executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from or +based on this library. If you modify this library, you may extend this +exception to your version of the library, but you are not obligated to +do so. If you do not wish to do so, delete this exception statement from +your version. + diff --git a/wii/libogc/wiiuse/motion_plus.c b/wii/libogc/wiiuse/motion_plus.c new file mode 100644 index 0000000000..8d37d7063f --- /dev/null +++ b/wii/libogc/wiiuse/motion_plus.c @@ -0,0 +1,95 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#include +#include +#include +#include + +#ifdef WIN32 + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "io.h" + +void wiiuse_motion_plus_check(struct wiimote_t *wm,ubyte *data,uword len) +{ + u32 val; + if(data == NULL) + { + wiiuse_read_data(wm, wm->motion_plus_id, WM_EXP_ID, 6, wiiuse_motion_plus_check); + } + else + { + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE); + val = (data[3] << 16) | (data[2] << 24) | (data[4] << 8) | data[5]; + if(val == EXP_ID_CODE_MOTION_PLUS) + { + /* handshake done */ + wm->event = WIIUSE_MOTION_PLUS_ACTIVATED; + wm->exp.type = EXP_MOTION_PLUS; + + WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP); + wiiuse_set_ir_mode(wm); + } + } +} + +static void wiiuse_set_motion_plus_clear2(struct wiimote_t *wm,ubyte *data,uword len) +{ + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE); + wiiuse_set_ir_mode(wm); + wiiuse_status(wm,NULL); +} + +static void wiiuse_set_motion_plus_clear1(struct wiimote_t *wm,ubyte *data,uword len) +{ + ubyte val = 0x00; + wiiuse_write_data(wm,WM_EXP_MEM_ENABLE1,&val,1,wiiuse_set_motion_plus_clear2); +} + + +void wiiuse_set_motion_plus(struct wiimote_t *wm, int status) +{ + ubyte val; + + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE)) + return; + + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE); + if(status) + { + val = 0x04; + wiiuse_write_data(wm,WM_EXP_MOTION_PLUS_ENABLE,&val,1,wiiuse_motion_plus_check); + } + else + { + wiiuse_disable_expansion(wm); + val = 0x55; + wiiuse_write_data(wm,WM_EXP_MEM_ENABLE1,&val,1,wiiuse_set_motion_plus_clear1); + } +} + +void motion_plus_disconnected(struct motion_plus_t* mp) +{ + WIIUSE_DEBUG("Motion plus disconnected"); + memset(mp, 0, sizeof(struct motion_plus_t)); +} + +void motion_plus_event(struct motion_plus_t* mp, ubyte* msg) +{ + mp->rx = ((msg[5] & 0xFC) << 6) | msg[2]; // Pitch + mp->ry = ((msg[4] & 0xFC) << 6) | msg[1]; // Roll + mp->rz = ((msg[3] & 0xFC) << 6) | msg[0]; // Yaw + + mp->ext = msg[4] & 0x1; + mp->status = (msg[3] & 0x3) | ((msg[4] & 0x2) << 1); // roll, yaw, pitch +} diff --git a/wii/libogc/wiiuse/motion_plus.h b/wii/libogc/wiiuse/motion_plus.h new file mode 100644 index 0000000000..628d9c6492 --- /dev/null +++ b/wii/libogc/wiiuse/motion_plus.h @@ -0,0 +1,26 @@ +/** + * @file + * @brief Motion plus extension + */ + +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef MOTION_PLUS_H_INCLUDED +#define MOTION_PLUS_H_INCLUDED + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void motion_plus_disconnected(struct motion_plus_t* mp); + +void motion_plus_event(struct motion_plus_t* mp, ubyte* msg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/wiiuse/nunchuk.c b/wii/libogc/wiiuse/nunchuk.c new file mode 100644 index 0000000000..468db73a31 --- /dev/null +++ b/wii/libogc/wiiuse/nunchuk.c @@ -0,0 +1,157 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#include +#include +#include +#include + +#include "dynamics.h" +#include "definitions.h" +#include "wiiuse_internal.h" +#include "nunchuk.h" +#include "io.h" + +/** + * @brief Find what buttons are pressed. + * + * @param nc Pointer to a nunchuk_t structure. + * @param msg The message byte specified in the event packet. + */ +static void nunchuk_pressed_buttons(struct nunchuk_t* nc, ubyte now) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & NUNCHUK_BUTTON_ALL; + + /* preserve old btns pressed */ + nc->btns_last = nc->btns; + + /* pressed now & were pressed, then held */ + nc->btns_held = (now & nc->btns); + + /* were pressed or were held & not pressed now, then released */ + nc->btns_released = ((nc->btns | nc->btns_held) & ~now); + + /* buttons pressed now */ + nc->btns = now; +} + +int nunchuk_handshake(struct wiimote_t *wm,struct nunchuk_t *nc,ubyte *data,uword len) +{ + //int i; + int offset = 0; + + nc->btns = 0; + nc->btns_held = 0; + nc->btns_released = 0; + nc->flags = &wm->flags; + nc->accel_calib = wm->accel_calib; + + //for(i=0;iaccel_calib.cal_zero.x = (data[offset + 0]<<2)|((data[offset + 3]>>4)&3); + nc->accel_calib.cal_zero.y = (data[offset + 1]<<2)|((data[offset + 3]>>2)&3); + nc->accel_calib.cal_zero.z = (data[offset + 2]<<2)|(data[offset + 3]&3); + nc->accel_calib.cal_g.x = (data[offset + 4]<<2)|((data[offset + 7]>>4)&3); + nc->accel_calib.cal_g.y = (data[offset + 5]<<2)|((data[offset + 7]>>2)&3); + nc->accel_calib.cal_g.z = (data[offset + 6]<<2)|(data[offset + 7]&3); + nc->js.max.x = data[offset + 8]; + nc->js.min.x = data[offset + 9]; + nc->js.center.x = data[offset + 10]; + nc->js.max.y = data[offset + 11]; + nc->js.min.y = data[offset + 12]; + nc->js.center.y = data[offset + 13]; + + // set to defaults (averages from 5 nunchuks) if calibration data is invalid + if(nc->accel_calib.cal_zero.x == 0) + nc->accel_calib.cal_zero.x = 499; + if(nc->accel_calib.cal_zero.y == 0) + nc->accel_calib.cal_zero.y = 509; + if(nc->accel_calib.cal_zero.z == 0) + nc->accel_calib.cal_zero.z = 507; + if(nc->accel_calib.cal_g.x == 0) + nc->accel_calib.cal_g.x = 703; + if(nc->accel_calib.cal_g.y == 0) + nc->accel_calib.cal_g.y = 709; + if(nc->accel_calib.cal_g.z == 0) + nc->accel_calib.cal_g.z = 709; + if(nc->js.max.x == 0) + nc->js.max.x = 223; + if(nc->js.min.x == 0) + nc->js.min.x = 27; + if(nc->js.center.x == 0) + nc->js.center.x = 126; + if(nc->js.max.y == 0) + nc->js.max.y = 222; + if(nc->js.min.y == 0) + nc->js.min.y = 30; + if(nc->js.center.y == 0) + nc->js.center.y = 131; + + wm->event = WIIUSE_NUNCHUK_INSERTED; + wm->exp.type = EXP_NUNCHUK; + + return 1; +} + +/** + * @brief The nunchuk disconnected. + * + * @param nc A pointer to a nunchuk_t structure. + */ +void nunchuk_disconnected(struct nunchuk_t* nc) +{ + //printf("nunchuk_disconnected()\n"); + memset(nc, 0, sizeof(struct nunchuk_t)); +} + +/** + * @brief Handle nunchuk event. + * + * @param nc A pointer to a nunchuk_t structure. + * @param msg The message specified in the event packet. + */ +void nunchuk_event(struct nunchuk_t* nc, ubyte* msg) { + //int i; + + /* decrypt data */ + /* + for (i = 0; i < 6; ++i) + msg[i] = (msg[i] ^ 0x17) + 0x17; + */ + /* get button states */ + nunchuk_pressed_buttons(nc, msg[5]); + + nc->js.pos.x = msg[0]; + nc->js.pos.y = msg[1]; + + /* extend min and max values to physical range of motion */ + if (nc->js.center.x) { + if (nc->js.min.x > nc->js.pos.x) nc->js.min.x = nc->js.pos.x; + if (nc->js.max.x < nc->js.pos.x) nc->js.max.x = nc->js.pos.x; + } + if (nc->js.center.y) { + if (nc->js.min.y > nc->js.pos.y) nc->js.min.y = nc->js.pos.y; + if (nc->js.max.y < nc->js.pos.y) nc->js.max.y = nc->js.pos.y; + } + +#ifndef GEKKO + /* calculate joystick state */ + calc_joystick_state(&nc->js, nc->js.pos.x, nc->js.pos.y); +#endif + /* calculate orientation */ + nc->accel.x = (msg[2]<<2) + ((msg[5]>>2)&3); + nc->accel.y = (msg[3]<<2) + ((msg[5]>>4)&3); + nc->accel.z = (msg[4]<<2) + ((msg[5]>>6)&3); +#ifndef GEKKO + calculate_orientation(&nc->accel_calib, &nc->accel, &nc->orient, NUNCHUK_IS_FLAG_SET(nc, WIIUSE_SMOOTHING)); + calculate_gforce(&nc->accel_calib, &nc->accel, &nc->gforce); +#endif +} + diff --git a/wii/libogc/wiiuse/nunchuk.h b/wii/libogc/wiiuse/nunchuk.h new file mode 100644 index 0000000000..7545aa7b6e --- /dev/null +++ b/wii/libogc/wiiuse/nunchuk.h @@ -0,0 +1,21 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef __NUNCHUK_H__ +#define __NUNCHUK_H__ + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, ubyte* data, uword len); +void nunchuk_disconnected(struct nunchuk_t* nc); +void nunchuk_event(struct nunchuk_t* nc, ubyte* msg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/wiiuse/os.h b/wii/libogc/wiiuse/os.h new file mode 100644 index 0000000000..16571047cd --- /dev/null +++ b/wii/libogc/wiiuse/os.h @@ -0,0 +1,31 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef __OS_H__ +#define __OS_H__ + +#ifdef WIN32 + /* windows */ + #define isnan(x) _isnan(x) + #define isinf(x) !_finite(x) + + /* disable warnings I don't care about */ + #pragma warning(disable:4244) /* possible loss of data conversion */ + #pragma warning(disable:4273) /* inconsistent dll linkage */ + #pragma warning(disable:4217) +#else + /* nix/gekko */ + #ifdef GEKKO + #include + #include + #include + #include "network.h" + #include + #include + #include + #include + #else + #endif +#endif + +#endif diff --git a/wii/libogc/wiiuse/speaker.c b/wii/libogc/wiiuse/speaker.c new file mode 100644 index 0000000000..43ca994275 --- /dev/null +++ b/wii/libogc/wiiuse/speaker.c @@ -0,0 +1,145 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#include +#include +#include +#include + +#ifndef WIN32 +#include +#endif +#ifdef GEKKO +#include +#endif +#include "definitions.h" +#include "wiiuse_internal.h" +#include "speaker.h" + +#define WENCMIN(a,b) ((a)>(b)?(b):(a)) +#define ABS(x) ((s32)(x)>0?(s32)(x):-((s32)(x))) + +static const int yamaha_indexscale[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 230, 230, 230, 230, 307, 409, 512, 614 +}; + +static const int yamaha_difflookup[] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1, -3, -5, -7, -9, -11, -13, -15 +}; + +static ubyte __wiiuse_speaker_vol = 0x40; +static ubyte __wiiuse_speaker_defconf[7] = { 0x00,0x00,0xD0,0x07,0x40,0x0C,0x0E }; + +static __inline__ short wenc_clip_short(int a) +{ + if((a+32768)&~65535) return (a>>31)^32767; + else return a; +} + +static __inline__ int wenc_clip(int a,int amin,int amax) +{ + if(aamax) return amax; + else return a; +} + +ubyte wencdata(WENCStatus *info,short sample) +{ + int nibble,delta; + + if(!info->step) { + info->predictor = 0; + info->step = 127; + } + + delta = sample - info->predictor; + nibble = WENCMIN(7,(ABS(delta)*4)/info->step) + ((delta<0)*8); + + info->predictor += ((info->step*yamaha_difflookup[nibble])/8); + info->predictor = wenc_clip_short(info->predictor); + info->step = (info->step*yamaha_indexscale[nibble])>>8; + info->step = wenc_clip(info->step,127,24576); + + return nibble; +} + +void wiiuse_set_speaker(struct wiimote_t *wm,int status) +{ + ubyte conf[7]; + ubyte buf = 0x00; + + if(!wm) return; + + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { + WIIUSE_DEBUG("Tried to enable speaker, will wait until handshake finishes.\n"); + if(status) + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_SPEAKER_INIT); + else + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_SPEAKER_INIT); + return; + } + + if(status) { + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) { + wiiuse_status(wm,NULL); + return; + } + } else { + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) { + wiiuse_status(wm,NULL); + return; + } + } + + + buf = 0x04; + wiiuse_sendcmd(wm,WM_CMD_SPEAKER_MUTE,&buf,1,NULL); + + if (!status) { + WIIUSE_DEBUG("Disabled speaker for wiimote id %i.", wm->unid); + + buf = 0x01; + wiiuse_write_data(wm,WM_REG_SPEAKER_REG1,&buf,1,NULL); + + buf = 0x00; + wiiuse_write_data(wm,WM_REG_SPEAKER_REG3,&buf,1,NULL); + + buf = 0x00; + wiiuse_sendcmd(wm,WM_CMD_SPEAKER_ENABLE,&buf,1,NULL); + + wiiuse_status(wm,NULL); + return; + } + + memcpy(conf,__wiiuse_speaker_defconf,7); + + buf = 0x04; + wiiuse_sendcmd(wm,WM_CMD_SPEAKER_ENABLE,&buf,1,NULL); + + buf = 0x01; + wiiuse_write_data(wm,WM_REG_SPEAKER_REG3,&buf,1,NULL); + + buf = 0x08; + wiiuse_write_data(wm,WM_REG_SPEAKER_REG1,&buf,1,NULL); + + conf[2] = 0xd0; + conf[3] = 0x07; + conf[4] = __wiiuse_speaker_vol; + wiiuse_write_data(wm,WM_REG_SPEAKER_BLOCK,conf,7,NULL); + + buf = 0x01; + wiiuse_write_data(wm,WM_REG_SPEAKER_REG2,&buf,1,NULL); + + buf = 0x00; + wiiuse_sendcmd(wm,WM_CMD_SPEAKER_MUTE,&buf,1,NULL); + + wiiuse_status(wm,NULL); + return; +} + +void set_speakervol(struct wiimote_t *wm,ubyte vol) +{ + __wiiuse_speaker_vol = vol; +} diff --git a/wii/libogc/wiiuse/speaker.h b/wii/libogc/wiiuse/speaker.h new file mode 100644 index 0000000000..b7b9229126 --- /dev/null +++ b/wii/libogc/wiiuse/speaker.h @@ -0,0 +1,33 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef __SPEAKER_H__ +#define __SPEAKER_H__ + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _wencstatus +{ + s32 predictor; + s16 step_index; + s32 step; + s32 prev_sample; + s16 sample1; + s16 sample2; + s32 coeff1; + s32 coeff2; + s32 idelta; +} WENCStatus; + +u8 wencdata(WENCStatus *info,s16 sample); +void set_speakervol(struct wiimote_t *wm,ubyte vol); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wii/libogc/wiiuse/wiiuse.c b/wii/libogc/wiiuse/wiiuse.c new file mode 100644 index 0000000000..73e813063a --- /dev/null +++ b/wii/libogc/wiiuse/wiiuse.c @@ -0,0 +1,337 @@ +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#include +#include +#include + +#ifndef WIN32 + #include +#else + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "io.h" + +static struct wiimote_t** __wm = NULL; + +void wiiuse_send_next_command(struct wiimote_t *wm) +{ + struct cmd_blk_t *cmd = wm->cmd_head; + + if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return; + + if(!cmd) return; + if(cmd->state!=CMD_READY) return; + + cmd->state = CMD_SENT; +#ifdef HAVE_WIIUSE_RUMBLE + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_RUMBLE)) cmd->data[1] |= 0x01; +#endif + + //WIIUSE_DEBUG("Sending command: %02x %02x", cmd->data[0], cmd->data[1]); + wiiuse_io_write(wm,cmd->data,cmd->len); +} + +static inline void __wiiuse_push_command(struct wiimote_t *wm,struct cmd_blk_t *cmd) +{ + uint level; + + if(!wm || !cmd) return; + + cmd->next = NULL; + cmd->state = CMD_READY; + + _CPU_ISR_Disable(level); + if(wm->cmd_head==NULL) { + wm->cmd_head = wm->cmd_tail = cmd; + wiiuse_send_next_command(wm); + } else { + wm->cmd_tail->next = cmd; + wm->cmd_tail = cmd; + } + _CPU_ISR_Restore(level); +} + +#ifndef GEKKO +struct wiimote_t** wiiuse_init(int wiimotes) { +#else +extern void __wiiuse_sensorbar_enable(int enable); +struct wiimote_t** wiiuse_init(int wiimotes, wii_event_cb event_cb) { +#endif + int i = 0; + + if (!wiimotes) + return NULL; + + if (!__wm) { + __wm = __lwp_heap_allocate(&__wkspace_heap, sizeof(struct wiimote_t*) * wiimotes); + if(!__wm) return NULL; + memset(__wm, 0, sizeof(struct wiimote_t*) * wiimotes); + } + + for (i = 0; i < wiimotes; ++i) { + if(!__wm[i]) + __wm[i] = __lwp_heap_allocate(&__wkspace_heap, sizeof(struct wiimote_t)); + + memset(__wm[i], 0, sizeof(struct wiimote_t)); + __wm[i]->unid = i; + + #if defined(WIN32) + __wm[i]->dev_handle = 0; + __wm[i]->stack = WIIUSE_STACK_UNKNOWN; + __wm[i]->normal_timeout = WIIMOTE_DEFAULT_TIMEOUT; + __wm[i]->exp_timeout = WIIMOTE_EXP_TIMEOUT; + __wm[i]->timeout = __wm[i]->normal_timeout; + #elif defined(GEKKO) + __wm[i]->sock = NULL; + __wm[i]->bdaddr = *BD_ADDR_ANY; + __wm[i]->event_cb = event_cb; + wiiuse_init_cmd_queue(__wm[i]); + #elif defined(unix) + __wm[i]->bdaddr = *BDADDR_ANY; + __wm[i]->out_sock = -1; + __wm[i]->in_sock = -1; + #endif + + __wm[i]->state = WIIMOTE_INIT_STATES; + __wm[i]->flags = WIIUSE_INIT_FLAGS; + + __wm[i]->event = WIIUSE_NONE; + + __wm[i]->exp.type = EXP_NONE; + + wiiuse_set_aspect_ratio(__wm[i], WIIUSE_ASPECT_4_3); + wiiuse_set_ir_position(__wm[i], WIIUSE_IR_ABOVE); + + __wm[i]->accel_calib.st_alpha = WIIUSE_DEFAULT_SMOOTH_ALPHA; + } + + return __wm; +} + +/** + * @brief Set flags for the specified wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param enable Flags to enable. + * @param disable Flags to disable. + * + * @return The flags set after 'enable' and 'disable' have been applied. + * + * The values 'enable' and 'disable' may be any flags OR'ed together. + * Flags are defined in wiiuse.h. + */ +int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable) { + if (!wm) return 0; + + /* remove mutually exclusive flags */ + enable &= ~disable; + disable &= ~enable; + + wm->flags |= enable; + wm->flags &= ~disable; + + return wm->flags; +} + +/** + * @brief Set if the wiimote should report motion sensing. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + * + * Since reporting motion sensing sends a lot of data, + * the wiimote saves power by not transmitting it + * by default. + */ +void wiiuse_motion_sensing(struct wiimote_t* wm, int status) +{ + if (status) { + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_ACC)) return; + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_ACC); + } else { + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_ACC)) return; + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC); + } + + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) return; + + wiiuse_status(wm,NULL); +} + +/** + * @brief Toggle the state of the rumble. + * + * @param wm Pointer to a wiimote_t structure. + */ +#ifdef HAVE_WIIUSE_RUMBLE +void wiiuse_toggle_rumble(struct wiimote_t* wm) +{ + if (!wm) return; + + WIIMOTE_TOGGLE_STATE(wm, WIIMOTE_STATE_RUMBLE); + if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) return; + + wiiuse_set_leds(wm,wm->leds,NULL); +} + +/** + * @brief Enable or disable the rumble. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + */ +void wiiuse_rumble(struct wiimote_t* wm, int status) +{ + if (status && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_RUMBLE)) return; + else if(!status && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_RUMBLE)) return; + wiiuse_toggle_rumble(wm); +} +#endif + +void wiiuse_set_leds(struct wiimote_t *wm,int leds,cmd_blk_cb cb) +{ + ubyte buf; + + if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return; + + wm->leds = (leds&0xf0); + + buf = wm->leds; + wiiuse_sendcmd(wm,WM_CMD_LED,&buf,1,cb); +} + +int wiiuse_set_report_type(struct wiimote_t *wm,cmd_blk_cb cb) +{ + ubyte buf[2]; + int motion,ir,exp; + + if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; + + buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_CONTINUOUS) ? 0x04 : 0x00); /* set to 0x04 for continuous reporting */ + buf[1] = 0x00; + + motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC) || WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR); + exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP); + ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR); + + if (motion && ir && exp) buf[1] = WM_RPT_BTN_ACC_IR_EXP; + else if (motion && exp) buf[1] = WM_RPT_BTN_ACC_EXP; + else if (motion && ir) buf[1] = WM_RPT_BTN_ACC_IR; + else if (ir && exp) buf[1] = WM_RPT_BTN_IR_EXP; + else if (ir) buf[1] = WM_RPT_BTN_ACC_IR; + else if (exp) buf[1] = WM_RPT_BTN_EXP; + else if (motion) buf[1] = WM_RPT_BTN_ACC; + else buf[1] = WM_RPT_BTN; + + //WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]); + + wiiuse_sendcmd(wm,WM_CMD_REPORT_TYPE,buf,2,cb); + return buf[1]; +} + +void wiiuse_status(struct wiimote_t *wm,cmd_blk_cb cb) +{ + ubyte buf; + + if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return; + + buf = 0x00; + wiiuse_sendcmd(wm,WM_CMD_CTRL_STATUS,&buf,1,cb); +} + +int wiiuse_read_data(struct wiimote_t *wm,ubyte *buffer,uint addr,uword len,cmd_blk_cb cb) +{ + struct op_t *op; + struct cmd_blk_t *cmd; + + if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; + if(!buffer || !len) return 0; + + cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq); + if(!cmd) return 0; + + cmd->cb = cb; + cmd->len = 7; + + op = (struct op_t*)cmd->data; + op->cmd = WM_CMD_READ_DATA; + op->buffer = buffer; + op->wait = len; + op->readdata.addr = BIG_ENDIAN_LONG(addr); + op->readdata.size = BIG_ENDIAN_SHORT(len); + __wiiuse_push_command(wm,cmd); + + return 1; +} + +int wiiuse_write_data(struct wiimote_t *wm,uint addr,ubyte *data,ubyte len,cmd_blk_cb cb) +{ + struct op_t *op; + struct cmd_blk_t *cmd; + + if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; + if(!data || !len) return 0; + + cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq); + if(!cmd) return 0; + + cmd->cb = cb; + cmd->len = 22; + + op = (struct op_t*)cmd->data; + op->cmd = WM_CMD_WRITE_DATA; + op->buffer = NULL; + op->wait = 0; + op->writedata.addr = BIG_ENDIAN_LONG(addr); + op->writedata.size = (len&0x0f); + memcpy(op->writedata.data,data,len); + memset(op->writedata.data+len,0,(16 - len)); + __wiiuse_push_command(wm,cmd); + + return 1; +} + +int wiiuse_write_streamdata(struct wiimote_t *wm,ubyte *data,ubyte len,cmd_blk_cb cb) +{ + struct cmd_blk_t *cmd; + + if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; + if(!data || !len || len>20) return 0; + + cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq); + if(!cmd) return 0; + + cmd->cb = cb; + cmd->len = 22; + cmd->data[0] = WM_CMD_STREAM_DATA; + cmd->data[1] = (len<<3); + memcpy(cmd->data+2,data,len); + __wiiuse_push_command(wm,cmd); + + return 1; +} + +int wiiuse_sendcmd(struct wiimote_t *wm,ubyte report_type,ubyte *msg,int len,cmd_blk_cb cb) +{ + struct cmd_blk_t *cmd; + + cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq); + if(!cmd) return 0; + + cmd->cb = cb; + cmd->len = (1+len); + + cmd->data[0] = report_type; + memcpy(cmd->data+1,msg,len); + if(report_type!=WM_CMD_READ_DATA && report_type!=WM_CMD_CTRL_STATUS) + cmd->data[1] |= 0x02; + + //WIIUSE_DEBUG("Pushing command: %02x %02x", cmd->data[0], cmd->data[1]); + __wiiuse_push_command(wm,cmd); + + return 1; +} diff --git a/wii/libogc/wiiuse/wiiuse_internal.h b/wii/libogc/wiiuse/wiiuse_internal.h new file mode 100644 index 0000000000..c95171e9de --- /dev/null +++ b/wii/libogc/wiiuse/wiiuse_internal.h @@ -0,0 +1,280 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/wiiuse_internal.h,v 1.8 2008-12-10 16:16:40 shagkur Exp $ + * + */ + +/** + * @file + * @brief General internal wiiuse stuff. + * + * Since Wiiuse is a library, wiiuse.h is a duplicate + * of the API header. + * + * The code that would normally go in that file, but + * which is not needed by third party developers, + * is put here. + * + * So wiiuse_internal.h is included by other files + * internally, wiiuse.h is included only here. + */ + +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#ifndef WIIUSE_INTERNAL_H_INCLUDED +#define WIIUSE_INTERNAL_H_INCLUDED + +#if defined(__linux__) + #include /* htons() */ + #include +#endif + +#include "definitions.h" + +/* wiiuse version */ +#define WIIUSE_VERSION "0.12" + +/******************** + * + * Wiimote internal codes + * + ********************/ + +/* Communication channels */ +#define WM_OUTPUT_CHANNEL 0x11 +#define WM_INPUT_CHANNEL 0x13 + +#define WM_SET_REPORT 0x50 +#define WM_DATA 0xA0 + +/* commands */ +#define WM_CMD_RUMBLE 0x10 +#define WM_CMD_LED 0x11 +#define WM_CMD_REPORT_TYPE 0x12 +#define WM_CMD_IR 0x13 +#define WM_CMD_SPEAKER_ENABLE 0x14 +#define WM_CMD_CTRL_STATUS 0x15 +#define WM_CMD_WRITE_DATA 0x16 +#define WM_CMD_READ_DATA 0x17 +#define WM_CMD_STREAM_DATA 0x18 +#define WM_CMD_SPEAKER_MUTE 0x19 +#define WM_CMD_IR_2 0x1A + +/* input report ids */ +#define WM_RPT_CTRL_STATUS 0x20 +#define WM_RPT_READ 0x21 +#define WM_RPT_ACK 0x22 +#define WM_RPT_BTN 0x30 +#define WM_RPT_BTN_ACC 0x31 +#define WM_RPT_BTN_ACC_IR 0x33 +#define WM_RPT_BTN_EXP 0x34 +#define WM_RPT_BTN_ACC_EXP 0x35 +#define WM_RPT_BTN_IR_EXP 0x36 +#define WM_RPT_BTN_ACC_IR_EXP 0x37 + +#define WM_BT_INPUT 0x01 +#define WM_BT_OUTPUT 0x02 + +/* Identify the wiimote device by its class */ +#define WM_DEV_CLASS_0 0x04 +#define WM_DEV_CLASS_1 0x25 +#define WM_DEV_CLASS_2 0x00 +#define WM_VENDOR_ID 0x057E +#define WM_PRODUCT_ID 0x0306 + +/* controller status stuff */ +#define WM_MAX_BATTERY_CODE 0xC8 + +/* offsets in wiimote memory */ +#define WM_MEM_OFFSET_CALIBRATION 0x16 +#define WM_EXP_MEM_BASE 0x04A40000 +#define WM_EXP_MEM_ENABLE1 0x04A400F0 +#define WM_EXP_MEM_ENABLE2 0x04A400FB +#define WM_EXP_MEM_KEY 0x04A40040 +#define WM_EXP_MEM_CALIBR 0x04A40020 +#define WM_EXP_MOTION_PLUS_ENABLE 0x04A600FE +#define WM_EXP_ID 0x04A400FA + +#define WM_REG_IR 0x04B00030 +#define WM_REG_IR_BLOCK1 0x04B00000 +#define WM_REG_IR_BLOCK2 0x04B0001A +#define WM_REG_IR_MODENUM 0x04B00033 + +#define WM_REG_SPEAKER_REG1 0x04A20001 +#define WM_REG_SPEAKER_REG2 0x04A20008 +#define WM_REG_SPEAKER_REG3 0x04A20009 +#define WM_REG_SPEAKER_BLOCK 0x04A20001 + +/* ir block data */ +#define WM_IR_BLOCK1_LEVEL1 "\x02\x00\x00\x71\x01\x00\x64\x00\xfe" +#define WM_IR_BLOCK2_LEVEL1 "\xfd\x05" +#define WM_IR_BLOCK1_LEVEL2 "\x02\x00\x00\x71\x01\x00\x96\x00\xb4" +#define WM_IR_BLOCK2_LEVEL2 "\xb3\x04" +#define WM_IR_BLOCK1_LEVEL3 "\x02\x00\x00\x71\x01\x00\xaa\x00\x64" +#define WM_IR_BLOCK2_LEVEL3 "\x63\x03" +#define WM_IR_BLOCK1_LEVEL4 "\x02\x00\x00\x71\x01\x00\xc8\x00\x36" +#define WM_IR_BLOCK2_LEVEL4 "\x35\x03" +#define WM_IR_BLOCK1_LEVEL5 "\x07\x00\x00\x71\x01\x00\x72\x00\x20" +#define WM_IR_BLOCK2_LEVEL5 "\x1f\x03" + +#define WM_IR_TYPE_BASIC 0x01 +#define WM_IR_TYPE_EXTENDED 0x03 +#define WM_IR_TYPE_FULL 0x05 + +/* controller status flags for the first message byte */ +/* bit 1 is unknown */ +#define WM_CTRL_STATUS_BYTE1_ATTACHMENT 0x02 +#define WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED 0x04 +#define WM_CTRL_STATUS_BYTE1_IR_ENABLED 0x08 +#define WM_CTRL_STATUS_BYTE1_LED_1 0x10 +#define WM_CTRL_STATUS_BYTE1_LED_2 0x20 +#define WM_CTRL_STATUS_BYTE1_LED_3 0x40 +#define WM_CTRL_STATUS_BYTE1_LED_4 0x80 + +/* aspect ratio */ +#define WM_ASPECT_16_9_X 660 +#define WM_ASPECT_16_9_Y 370 +#define WM_ASPECT_4_3_X 560 +#define WM_ASPECT_4_3_Y 420 + + +/** + * Expansion stuff + */ + +/* encrypted expansion id codes (located at 0x04A400FC) */ +#define EXP_ID_CODE_NUNCHUK 0xa4200000 +#define EXP_ID_CODE_CLASSIC_CONTROLLER 0xa4200101 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING 0x90908f00 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING2 0x9e9f9c00 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING3 0x908f8f00 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC 0xa5a2a300 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC2 0x98999900 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC3 0xa0a1a000 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC4 0x8d8d8e00 +#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC5 0x93949400 +#define EXP_ID_CODE_CLASSIC_WIIU_PRO 0xa4200120 +//#define EXP_ID_CODE_GUITAR 0xa4200103 +//#define EXP_ID_CODE_WIIBOARD 0xa4200402 +#define EXP_ID_CODE_MOTION_PLUS 0xa4200405 + +#define EXP_HANDSHAKE_LEN 224 + +/******************** + * + * End Wiimote internal codes + * + ********************/ + +/* wiimote state flags - (some duplicated in wiiuse.h)*/ +#define WIIMOTE_STATE_DEV_FOUND 0x00001 +//#define WIIMOTE_STATE_DEV_REGISTER 0x00002 +#define WIIMOTE_STATE_HANDSHAKE 0x00004 /* actual connection exists but no handshake yet */ +#define WIIMOTE_STATE_HANDSHAKE_COMPLETE 0x00008 /* actual connection exists but no handshake yet */ +#define WIIMOTE_STATE_CONNECTED 0x00010 +#define WIIMOTE_STATE_EXP_HANDSHAKE 0x00020 /* actual connection exists but no handshake yet */ +#define WIIMOTE_STATE_EXP_FAILED 0x00040 /* actual connection exists but no handshake yet */ +#define WIIMOTE_STATE_RUMBLE 0x00080 +#define WIIMOTE_STATE_ACC 0x00100 +#define WIIMOTE_STATE_EXP 0x00200 +#define WIIMOTE_STATE_IR 0x00400 +#define WIIMOTE_STATE_SPEAKER 0x00800 +#define WIIMOTE_STATE_IR_SENS_LVL1 0x01000 +#define WIIMOTE_STATE_IR_SENS_LVL2 0x02000 +#define WIIMOTE_STATE_IR_SENS_LVL3 0x04000 +#define WIIMOTE_STATE_IR_SENS_LVL4 0x08000 +#define WIIMOTE_STATE_IR_SENS_LVL5 0x10000 +#define WIIMOTE_STATE_IR_INIT 0x20000 +#define WIIMOTE_STATE_SPEAKER_INIT 0x40000 +#define WIIMOTE_STATE_WIIU_PRO 0x80000 + +#define WIIMOTE_INIT_STATES (WIIMOTE_STATE_IR_SENS_LVL3) + +/* macro to manage states */ +#define WIIMOTE_IS_SET(wm, s) ((wm->state & (s)) == (s)) +#define WIIMOTE_ENABLE_STATE(wm, s) (wm->state |= (s)) +#define WIIMOTE_DISABLE_STATE(wm, s) (wm->state &= ~(s)) +#define WIIMOTE_TOGGLE_STATE(wm, s) ((wm->state & (s)) ? WIIMOTE_DISABLE_STATE(wm, s) : WIIMOTE_ENABLE_STATE(wm, s)) + +#define WIIMOTE_IS_FLAG_SET(wm, s) ((wm->flags & (s)) == (s)) +#define WIIMOTE_ENABLE_FLAG(wm, s) (wm->flags |= (s)) +#define WIIMOTE_DISABLE_FLAG(wm, s) (wm->flags &= ~(s)) +#define WIIMOTE_TOGGLE_FLAG(wm, s) ((wm->flags & (s)) ? WIIMOTE_DISABLE_FLAG(wm, s) : WIIMOTE_ENABLE_FLAG(wm, s)) + +#define NUNCHUK_IS_FLAG_SET(wm, s) ((*(wm->flags) & (s)) == (s)) + +/* misc macros */ +#define WIIMOTE_ID(wm) (wm->unid) +#define WIIMOTE_IS_CONNECTED(wm) (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_CONNECTED)) + +/* + * Smooth tilt calculations are computed with the + * exponential moving average formula: + * St = St_last + (alpha * (tilt - St_last)) + * alpha is between 0 and 1 + */ +#define WIIUSE_DEFAULT_SMOOTH_ALPHA 0.3f + +#define SMOOTH_ROLL 0x01 +#define SMOOTH_PITCH 0x02 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct op_t +{ + ubyte cmd; + union { + struct { + uint addr; + uword size; + } readdata; + struct { + uint addr; + ubyte size; + ubyte data[16]; + } writedata; + ubyte __data[MAX_PAYLOAD]; + }; + + void *buffer; + int wait; +} __attribute__((packed)); + +/* not part of the api */ +void wiiuse_init_cmd_queue(struct wiimote_t *wm); +void wiiuse_send_next_command(struct wiimote_t *wm); +int wiiuse_set_report_type(struct wiimote_t* wm,cmd_blk_cb cb); +int wiiuse_sendcmd(struct wiimote_t *wm,ubyte report_type,ubyte *msg,int len,cmd_blk_cb cb); + +#ifdef __cplusplus +} +#endif + +#endif /* WIIUSE_INTERNAL_H_INCLUDED */ diff --git a/wii/libogc/wiiuse/wpad.c b/wii/libogc/wiiuse/wpad.c new file mode 100644 index 0000000000..8e80da0de3 --- /dev/null +++ b/wii/libogc/wiiuse/wpad.c @@ -0,0 +1,1106 @@ +/*------------------------------------------------------------- + +wpad.c -- Wiimote Application Programmers Interface + +Copyright (C) 2008 +Michael Wiedenbauer (shagkur) +Dave Murphy (WinterMute) +Hector Martin (marcan) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +/* This source as presented is a modified version of original wiiuse for use + * with RetroArch, and must not be confused with the original software. */ + +#include +#include +#include +#include +#include + +#include "os.h" +#include "conf.h" +#include "ir.h" + +#ifdef HAVE_WIIUSE_SPEAKER +#include "speaker.h" +#endif + +#include "dynamics.h" +#include "wiiuse_internal.h" +#include "wiiuse/wpad.h" +#include "lwp_threads.h" +#include "ogcsys.h" + +#define MAX_STREAMDATA_LEN 20 +#define EVENTQUEUE_LENGTH 16 + +#define DISCONNECT_BATTERY_DIED 0x14 +#define DISCONNECT_POWER_OFF 0x15 + +struct _wpad_thresh{ + s32 btns; + s32 ir; + s32 js; + s32 acc; + s32 mp; +}; + +struct _wpad_cb { + wiimote *wm; + s32 data_fmt; + s32 queue_head; + s32 queue_tail; + s32 queue_full; + u32 queue_length; + u32 dropped_events; + s32 idle_time; + s32 speaker_enabled; + struct _wpad_thresh thresh; + +#ifdef HAVE_WIIUSE_SPEAKER + void *sound_data; + u32 sound_len; + u32 sound_off; + syswd_t sound_alarm; +#endif + + WPADData lstate; +#ifdef HAVE_WIIUSE_QUEUE_EXT + WPADData *queue_ext; +#endif + WPADData queue_int[EVENTQUEUE_LENGTH]; +}; + +static syswd_t __wpad_timer; +static vu32 __wpads_inited = 0; +static vs32 __wpads_ponded = 0; +static u32 __wpad_idletimeout = 300; +static vu32 __wpads_active = 0; +static vu32 __wpads_used = 0; +static wiimote **__wpads = NULL; +static wiimote_listen __wpads_listen[CONF_PAD_MAX_REGISTERED]; +static WPADData wpaddata[WPAD_MAX_WIIMOTES]; +static struct _wpad_cb __wpdcb[WPAD_MAX_WIIMOTES]; +static conf_pads __wpad_devs; +static struct linkkey_info __wpad_keys[WPAD_MAX_WIIMOTES]; + +static s32 __wpad_onreset(s32 final); +static s32 __wpad_disconnect(struct _wpad_cb *wpdcb); +static void __wpad_eventCB(struct wiimote_t *wm,s32 event); + +static void __wpad_def_powcb(s32 chan); +static WPADShutdownCallback __wpad_batcb = NULL; +static WPADShutdownCallback __wpad_powcb = __wpad_def_powcb; + +extern void __wiiuse_sensorbar_enable(int enable); +extern void __SYS_DoPowerCB(void); + +static sys_resetinfo __wpad_resetinfo = { + {}, + __wpad_onreset, + 127 +}; + +static s32 __wpad_onreset(s32 final) +{ + //printf("__wpad_onreset(%d)\n",final); + if(final==FALSE) { + WPAD_Shutdown(); + } + return 1; +} + +static void __wpad_def_powcb(s32 chan) +{ + __SYS_DoPowerCB(); +} + +static void __wpad_timeouthandler(syswd_t alarm,void *cbarg) +{ + s32 i; + struct wiimote_t *wm = NULL; + struct _wpad_cb *wpdcb = NULL; + + if(!__wpads_active) return; + + ++_thread_dispatch_disable_level; + for(i=0;iwm; + if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) { + wpdcb->idle_time++; + if(wpdcb->idle_time>=__wpad_idletimeout) { + wpdcb->idle_time = 0; + wiiuse_disconnect(wm); + } + } + } + --_thread_dispatch_disable_level; +} + +#ifdef HAVE_WIIUSE_SPEAKER +static void __wpad_sounddata_alarmhandler(syswd_t alarm,void *cbarg) +{ + u8 *snd_data; + u32 snd_off; + struct wiimote_t *wm; + struct _wpad_cb *wpdcb = (struct _wpad_cb*)cbarg; + + if(!wpdcb) return; + + if(wpdcb->sound_off>=wpdcb->sound_len) { + wpdcb->sound_data = NULL; + wpdcb->sound_len = 0; + wpdcb->sound_off = 0; + SYS_CancelAlarm(wpdcb->sound_alarm); + return; + } + + wm = wpdcb->wm; + snd_data = wpdcb->sound_data; + snd_off = wpdcb->sound_off; + wpdcb->sound_off += MAX_STREAMDATA_LEN; + wiiuse_write_streamdata(wm,(snd_data+snd_off),MAX_STREAMDATA_LEN,NULL); +} +#endif + +static void __wpad_setfmt(s32 chan) +{ + switch(__wpdcb[chan].data_fmt) { + case WPAD_FMT_BTNS: + wiiuse_set_flags(__wpads[chan], 0, WIIUSE_CONTINUOUS); + wiiuse_motion_sensing(__wpads[chan],0); + wiiuse_set_ir(__wpads[chan],0); + break; + case WPAD_FMT_BTNS_ACC: + wiiuse_set_flags(__wpads[chan], WIIUSE_CONTINUOUS, 0); + wiiuse_motion_sensing(__wpads[chan],1); + wiiuse_set_ir(__wpads[chan],0); + break; + case WPAD_FMT_BTNS_ACC_IR: + wiiuse_set_flags(__wpads[chan], WIIUSE_CONTINUOUS, 0); + wiiuse_motion_sensing(__wpads[chan],1); + wiiuse_set_ir(__wpads[chan],1); + break; + default: + break; + } +} + +wiimote *__wpad_assign_slot(struct bd_addr *pad_addr) +{ + u32 i, level; + struct bd_addr bdaddr; + //printf("WPAD Assigning slot (active: 0x%02x)\n", __wpads_used); + _CPU_ISR_Disable(level); + + // Try preassigned slots + for(i=0; iwm; + if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) { + wiiuse_disconnect(wm); + } + + return 0; +} + +static void __wpad_calc_data(WPADData *data,WPADData *lstate,struct accel_t *accel_calib,u32 smoothed) +{ + if(data->err!=WPAD_ERR_NONE) return; + + data->orient = lstate->orient; + + data->ir.state = lstate->ir.state; + data->ir.sensorbar = lstate->ir.sensorbar; + data->ir.x = lstate->ir.x; + data->ir.y = lstate->ir.y; + data->ir.sx = lstate->ir.sx; + data->ir.sy = lstate->ir.sy; + data->ir.ax = lstate->ir.ax; + data->ir.ay = lstate->ir.ay; + data->ir.distance = lstate->ir.distance; + data->ir.z = lstate->ir.z; + data->ir.angle = lstate->ir.angle; + data->ir.error_cnt = lstate->ir.error_cnt; + data->ir.glitch_cnt = lstate->ir.glitch_cnt; + + if(data->data_present & WPAD_DATA_ACCEL) { + calculate_orientation(accel_calib, &data->accel, &data->orient, smoothed); + calculate_gforce(accel_calib, &data->accel, &data->gforce); + } + if(data->data_present & WPAD_DATA_IR) { + interpret_ir_data(&data->ir,&data->orient); + } + if(data->data_present & WPAD_DATA_EXPANSION) { + switch(data->exp.type) { + case EXP_NUNCHUK: + { + struct nunchuk_t *nc = &data->exp.nunchuk; + + nc->orient = lstate->exp.nunchuk.orient; + calc_joystick_state(&nc->js,nc->js.pos.x,nc->js.pos.y); + calculate_orientation(&nc->accel_calib,&nc->accel,&nc->orient,smoothed); + calculate_gforce(&nc->accel_calib,&nc->accel,&nc->gforce); + data->btns_h |= (data->exp.nunchuk.btns<<16); + } + break; + + case EXP_CLASSIC: + { + struct classic_ctrl_t *cc = &data->exp.classic; + + cc->r_shoulder = ((f32)cc->rs_raw/0x1F); + cc->l_shoulder = ((f32)cc->ls_raw/0x1F); + calc_joystick_state(&cc->ljs, cc->ljs.pos.x, cc->ljs.pos.y); + calc_joystick_state(&cc->rjs, cc->rjs.pos.x, cc->rjs.pos.y); + data->btns_h |= (data->exp.classic.btns<<16); + } + break; + default: + break; + } + } + *lstate = *data; +} + +static void __save_state(struct wiimote_t* wm) { + /* wiimote */ + wm->lstate.btns = wm->btns; + wm->lstate.accel = wm->accel; + + /* ir */ + wm->lstate.ir = wm->ir; + + /* expansion */ + switch (wm->exp.type) { + case EXP_NUNCHUK: + wm->lstate.exp.nunchuk = wm->exp.nunchuk; + break; + case EXP_CLASSIC: + wm->lstate.exp.classic = wm->exp.classic; + break; + case EXP_MOTION_PLUS: + wm->lstate.exp.mp = wm->exp.mp; + break; + } +} + +#define ABS(x) ((s32)(x)>0?(s32)(x):-((s32)(x))) + +#define STATE_CHECK(thresh, a, b) \ + if(((thresh) > WPAD_THRESH_IGNORE) && (ABS((a)-(b)) > (thresh))) \ + state_changed = 1; + +#define STATE_CHECK_SIMPLE(thresh, a, b) \ + if(((thresh) > WPAD_THRESH_IGNORE) && ((a) != (b))) \ + state_changed = 1; + +static u32 __wpad_read_expansion(struct wiimote_t *wm,WPADData *data, struct _wpad_thresh *thresh) +{ + int state_changed = 0; + switch(data->exp.type) { + case EXP_NUNCHUK: + data->exp.nunchuk = wm->exp.nunchuk; + STATE_CHECK_SIMPLE(thresh->btns, wm->exp.nunchuk.btns, wm->lstate.exp.nunchuk.btns); + STATE_CHECK(thresh->acc, wm->exp.nunchuk.accel.x, wm->lstate.exp.nunchuk.accel.x); + STATE_CHECK(thresh->acc, wm->exp.nunchuk.accel.y, wm->lstate.exp.nunchuk.accel.y); + STATE_CHECK(thresh->acc, wm->exp.nunchuk.accel.z, wm->lstate.exp.nunchuk.accel.z); + STATE_CHECK(thresh->js, wm->exp.nunchuk.js.pos.x, wm->lstate.exp.nunchuk.js.pos.x); + STATE_CHECK(thresh->js, wm->exp.nunchuk.js.pos.y, wm->lstate.exp.nunchuk.js.pos.y); + break; + case EXP_CLASSIC: + data->exp.classic = wm->exp.classic; + STATE_CHECK_SIMPLE(thresh->btns, wm->exp.classic.btns, wm->lstate.exp.classic.btns); + STATE_CHECK(thresh->js, wm->exp.classic.rs_raw, wm->lstate.exp.classic.rs_raw); + STATE_CHECK(thresh->js, wm->exp.classic.ls_raw, wm->lstate.exp.classic.ls_raw); + STATE_CHECK(thresh->js, wm->exp.classic.ljs.pos.x, wm->lstate.exp.classic.ljs.pos.x); + STATE_CHECK(thresh->js, wm->exp.classic.ljs.pos.y, wm->lstate.exp.classic.ljs.pos.y); + STATE_CHECK(thresh->js, wm->exp.classic.rjs.pos.x, wm->lstate.exp.classic.rjs.pos.x); + STATE_CHECK(thresh->js, wm->exp.classic.rjs.pos.y, wm->lstate.exp.classic.rjs.pos.y); + break; + case EXP_MOTION_PLUS: + data->exp.mp = wm->exp.mp; + STATE_CHECK(thresh->mp,wm->exp.mp.rx,wm->lstate.exp.mp.rx); + STATE_CHECK(thresh->mp,wm->exp.mp.ry,wm->lstate.exp.mp.ry); + STATE_CHECK(thresh->mp,wm->exp.mp.rz,wm->lstate.exp.mp.rz); + break; + } + return state_changed; +} + +static void __wpad_read_wiimote(struct wiimote_t *wm, WPADData *data, s32 *idle_time, struct _wpad_thresh *thresh) +{ + int i; + int state_changed = 0; + data->err = WPAD_ERR_TRANSFER; + data->data_present = 0; + data->battery_level = wm->battery_level; + data->exp.type = wm->exp.type; + if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) { + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { + switch(wm->event_buf[0]) { + case WM_RPT_BTN: + case WM_RPT_BTN_ACC: + case WM_RPT_BTN_ACC_IR: + case WM_RPT_BTN_EXP: + case WM_RPT_BTN_ACC_EXP: + case WM_RPT_BTN_IR_EXP: + case WM_RPT_BTN_ACC_IR_EXP: + data->btns_h = (wm->btns&0xffff); + data->data_present |= WPAD_DATA_BUTTONS; + STATE_CHECK_SIMPLE(thresh->btns, wm->btns, wm->lstate.btns); + } + switch(wm->event_buf[0]) { + case WM_RPT_BTN_ACC: + case WM_RPT_BTN_ACC_IR: + case WM_RPT_BTN_ACC_EXP: + case WM_RPT_BTN_ACC_IR_EXP: + data->accel = wm->accel; + data->data_present |= WPAD_DATA_ACCEL; + STATE_CHECK(thresh->acc, wm->accel.x, wm->lstate.accel.x); + STATE_CHECK(thresh->acc, wm->accel.y, wm->lstate.accel.y); + STATE_CHECK(thresh->acc, wm->accel.z, wm->lstate.accel.z); + } + switch(wm->event_buf[0]) { + //IR requires acceleration + //case WM_RPT_BTN_IR_EXP: + case WM_RPT_BTN_ACC_IR: + case WM_RPT_BTN_ACC_IR_EXP: + data->ir = wm->ir; + data->data_present |= WPAD_DATA_IR; + for(i=0; iir, wm->ir.dot[i].visible, wm->lstate.ir.dot[i].visible); + STATE_CHECK(thresh->ir, wm->ir.dot[i].rx, wm->lstate.ir.dot[i].rx); + STATE_CHECK(thresh->ir, wm->ir.dot[i].ry, wm->lstate.ir.dot[i].ry); + } + } + switch(wm->event_buf[0]) { + case WM_RPT_BTN_EXP: + case WM_RPT_BTN_ACC_EXP: + case WM_RPT_BTN_IR_EXP: + case WM_RPT_BTN_ACC_IR_EXP: + state_changed |= __wpad_read_expansion(wm,data,thresh); + data->data_present |= WPAD_DATA_EXPANSION; + } + data->err = WPAD_ERR_NONE; + if(state_changed) { + *idle_time = 0; + __save_state(wm); + } + } else + data->err = WPAD_ERR_NOT_READY; + } else + data->err = WPAD_ERR_NO_CONTROLLER; +} + +static void __wpad_eventCB(struct wiimote_t *wm,s32 event) +{ + s32 chan; + u32 maxbufs; + WPADData *wpadd = NULL; + struct _wpad_cb *wpdcb = NULL; + + switch(event) { + case WIIUSE_EVENT: + chan = wm->unid; + wpdcb = &__wpdcb[chan]; + +#ifdef HAVE_WIIUSE_QUEUE_EXT + if(wpdcb->queue_ext!=NULL) { + maxbufs = wpdcb->queue_length; + wpadd = &(wpdcb->queue_ext[wpdcb->queue_tail]); + } + else +#endif + { + maxbufs = EVENTQUEUE_LENGTH; + wpadd = &(wpdcb->queue_int[wpdcb->queue_tail]); + } + if(wpdcb->queue_full == maxbufs) { + wpdcb->queue_head++; + wpdcb->queue_head %= maxbufs; + wpdcb->dropped_events++; + } else { + wpdcb->queue_full++; + } + + __wpad_read_wiimote(wm, wpadd, &wpdcb->idle_time, &wpdcb->thresh); + + wpdcb->queue_tail++; + wpdcb->queue_tail %= maxbufs; + + break; + case WIIUSE_STATUS: + break; + case WIIUSE_CONNECT: + chan = wm->unid; + wpdcb = &__wpdcb[chan]; + wpdcb->wm = wm; + wpdcb->queue_head = 0; + wpdcb->queue_tail = 0; + wpdcb->queue_full = 0; + wpdcb->idle_time = 0; + memset(&wpdcb->lstate,0,sizeof(WPADData)); + memset(&wpaddata[chan],0,sizeof(WPADData)); + memset(wpdcb->queue_int,0,(sizeof(WPADData)*EVENTQUEUE_LENGTH)); + wiiuse_set_ir_position(wm,(CONF_GetSensorBarPosition()^1)); + wiiuse_set_ir_sensitivity(wm,CONF_GetIRSensitivity()); + wiiuse_set_leds(wm,(WIIMOTE_LED_1<<(chan%WPAD_BALANCE_BOARD)),NULL); +#ifdef HAVE_WIIUSE_SPEAKER + wiiuse_set_speaker(wm,wpdcb->speaker_enabled); +#endif + __wpad_setfmt(chan); + __wpads_active |= (0x01<unid; + wpdcb = &__wpdcb[chan]; + wpdcb->wm = wm; + wpdcb->queue_head = 0; + wpdcb->queue_tail = 0; + wpdcb->queue_full = 0; + wpdcb->queue_length = 0; +#ifdef HAVE_WIIUSE_QUEUE_EXT + wpdcb->queue_ext = NULL; +#endif + wpdcb->idle_time = -1; + memset(&wpdcb->lstate,0,sizeof(WPADData)); + memset(&wpaddata[chan],0,sizeof(WPADData)); + memset(wpdcb->queue_int,0,(sizeof(WPADData)*EVENTQUEUE_LENGTH)); + __wpads_active &= ~(0x01< CONF_PAD_MAX_REGISTERED) { + WPAD_Shutdown(); + _CPU_ISR_Restore(level); + return WPAD_ERR_BADCONF; + } + + __wpads = wiiuse_init(WPAD_MAX_WIIMOTES,__wpad_eventCB); + if(__wpads==NULL) { + WPAD_Shutdown(); + _CPU_ISR_Restore(level); + return WPAD_ERR_UNKNOWN; + } + + __wiiuse_sensorbar_enable(1); + + BTE_Init(); + BTE_SetDisconnectCallback(__wpad_disconnectCB); + BTE_InitCore(__initcore_finished); + + if (SYS_CreateAlarm(&__wpad_timer) < 0) + { + WPAD_Shutdown(); + _CPU_ISR_Restore(level); + return WPAD_ERR_UNKNOWN; + } + + SYS_RegisterResetFunc(&__wpad_resetinfo); + + tb.tv_sec = 1; + tb.tv_nsec = 0; + SYS_SetPeriodicAlarm(__wpad_timer,&tb,&tb,__wpad_timeouthandler,NULL); + __wpads_inited = WPAD_STATE_ENABLING; + } + _CPU_ISR_Restore(level); + return WPAD_ERR_NONE; +} + +s32 WPAD_ReadEvent(s32 chan, WPADData *data) +{ + u32 level; + u32 maxbufs,smoothed = 0; + struct accel_t *accel_calib = NULL; + struct _wpad_cb *wpdcb = NULL; + WPADData *lstate = NULL,*wpadd = NULL; + + //if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + if(__wpads[chan] && WIIMOTE_IS_SET(__wpads[chan],WIIMOTE_STATE_CONNECTED)) { + if(WIIMOTE_IS_SET(__wpads[chan],WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { + wpdcb = &__wpdcb[chan]; +#ifdef HAVE_WIIUSE_QUEUE_EXT + if(wpdcb->queue_ext!=NULL) { + maxbufs = wpdcb->queue_length; + wpadd = wpdcb->queue_ext; + } + else +#endif + { + maxbufs = EVENTQUEUE_LENGTH; + wpadd = wpdcb->queue_int; + } + if(wpdcb->queue_full == 0) { + _CPU_ISR_Restore(level); + return WPAD_ERR_QUEUE_EMPTY; + } + if(data) + *data = wpadd[wpdcb->queue_head]; + wpdcb->queue_head++; + wpdcb->queue_head %= maxbufs; + wpdcb->queue_full--; + lstate = &wpdcb->lstate; + accel_calib = &__wpads[chan]->accel_calib; + smoothed = WIIMOTE_IS_FLAG_SET(__wpads[chan], WIIUSE_SMOOTHING); + } else { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + } else { + _CPU_ISR_Restore(level); + return WPAD_ERR_NO_CONTROLLER; + } + + _CPU_ISR_Restore(level); + if(data) + __wpad_calc_data(data,lstate,accel_calib,smoothed); + return 0; +} + +static s32 pad_readpending_temp(s32 chan) +{ + s32 count = 0; + s32 ret; + + while(1) + { + ret = WPAD_ReadEvent(chan, &wpaddata[chan]); + if(ret < WPAD_ERR_NONE) + break; + count++; + } + if(ret == WPAD_ERR_QUEUE_EMPTY) return count; + return ret; +} + +s32 WPAD_ReadPending(s32 chan, WPADDataCallback datacb) +{ + u32 i; + s32 count = 0; + s32 ret; + + for(i= WPAD_CHAN_0; i < WPAD_MAX_WIIMOTES; i++) + if((ret = pad_readpending_temp(i)) >= WPAD_ERR_NONE) + count += ret; + return count; +} + +s32 WPAD_SetMotionPlus(s32 chan, u8 enable) +{ + u32 level; + s32 ret; + int i; + + if(chan == WPAD_CHAN_ALL) { + for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + if(__wpads[chan]!=NULL) { + wiiuse_set_motion_plus(__wpads[chan], enable); + } + _CPU_ISR_Restore(level); + return WPAD_ERR_NONE; +} + +s32 WPAD_SetVRes(s32 chan,u32 xres,u32 yres) +{ + u32 level; + s32 ret; + int i; + + if(chan == WPAD_CHAN_ALL) { + for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + if(__wpads[chan]!=NULL) + wiiuse_set_ir_vres(__wpads[chan],xres,yres); + + _CPU_ISR_Restore(level); + return WPAD_ERR_NONE; +} + +s32 WPAD_GetStatus() +{ + s32 ret; + u32 level; + + _CPU_ISR_Disable(level); + ret = __wpads_inited; + _CPU_ISR_Restore(level); + + return ret; +} + +s32 WPAD_Probe(s32 chan,u32 *type) +{ + s32 ret; + u32 level,dev; + wiimote *wm = NULL; + + //if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + wm = __wpads[chan]; + if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) { + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { + dev = WPAD_EXP_NONE; + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) { + switch(wm->exp.type) { + case WPAD_EXP_NUNCHUK: + case WPAD_EXP_CLASSIC: + dev = wm->exp.type; + break; + } + } + if(type!=NULL) *type = dev; + ret = WPAD_ERR_NONE; + } else + ret = WPAD_ERR_NOT_READY; + } else + ret = WPAD_ERR_NO_CONTROLLER; + _CPU_ISR_Restore(level); + + return ret; +} + +#ifdef HAVE_WIIUSE_QUEUE_EXT +s32 WPAD_SetEventBufs(s32 chan, WPADData *bufs, u32 cnt) +{ + u32 level; + struct _wpad_cb *wpdcb = NULL; + + if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + wpdcb = &__wpdcb[chan]; + wpdcb->queue_head = 0; + wpdcb->queue_tail = 0; + wpdcb->queue_full = 0; + wpdcb->queue_length = cnt; + wpdcb->queue_ext = bufs; + _CPU_ISR_Restore(level); + return WPAD_ERR_NONE; +} +#endif + +void WPAD_SetPowerButtonCallback(WPADShutdownCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + if(cb) + __wpad_powcb = cb; + else + __wpad_powcb = __wpad_def_powcb; + _CPU_ISR_Restore(level); +} + +void WPAD_SetBatteryDeadCallback(WPADShutdownCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + __wpad_batcb = cb; + _CPU_ISR_Restore(level); +} + +s32 WPAD_Disconnect(s32 chan) +{ + u32 level, cnt = 0; + struct _wpad_cb *wpdcb = NULL; + + if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + wpdcb = &__wpdcb[chan]; + __wpad_disconnect(wpdcb); + + _CPU_ISR_Restore(level); + + while(__wpads_active&(0x01< 3000) break; + } + + return WPAD_ERR_NONE; +} + +void WPAD_Shutdown() +{ + s32 i; + u32 level; + u32 cnt = 0; + struct _wpad_cb *wpdcb = NULL; + + _CPU_ISR_Disable(level); + + __wpads_inited = WPAD_STATE_DISABLED; + SYS_RemoveAlarm(__wpad_timer); + for(i=0;isound_alarm); +#endif + __wpad_disconnect(wpdcb); + } + + __wiiuse_sensorbar_enable(0); + _CPU_ISR_Restore(level); + + while(__wpads_active) { + usleep(50); + if(++cnt > 3000) break; + } + + BTE_Shutdown(); +} + +void WPAD_SetIdleTimeout(u32 seconds) +{ + u32 level; + + _CPU_ISR_Disable(level); + __wpad_idletimeout = seconds; + _CPU_ISR_Restore(level); +} + +#ifdef HAVE_WIIUSE_RUMBLE +s32 WPAD_Rumble(s32 chan, int status) +{ + int i; + s32 ret; + u32 level; + + if(chan == WPAD_CHAN_ALL) { + for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + if(__wpads[chan]!=NULL) + wiiuse_rumble(__wpads[chan],status); + + _CPU_ISR_Restore(level); + return WPAD_ERR_NONE; +} +#endif + +#ifdef HAVE_WIIUSE_SPEAKER +s32 WPAD_ControlSpeaker(s32 chan,s32 enable) +{ + int i; + s32 ret; + u32 level; + + if(chan == WPAD_CHAN_ALL) { + for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + if(__wpads[chan]!=NULL) { + __wpdcb[chan].speaker_enabled = enable; + wiiuse_set_speaker(__wpads[chan],enable); + } + + _CPU_ISR_Restore(level); + return WPAD_ERR_NONE; +} + +s32 WPAD_IsSpeakerEnabled(s32 chan) +{ + s32 ret; + u32 level; + wiimote *wm = NULL; + + if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + + _CPU_ISR_Disable(level); + if(__wpads_inited==WPAD_STATE_DISABLED) { + _CPU_ISR_Restore(level); + return WPAD_ERR_NOT_READY; + } + + wm = __wpads[chan]; + ret = WPAD_ERR_NOT_READY; + if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) { + if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE) + && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) ret = WPAD_ERR_NONE; + } + + _CPU_ISR_Restore(level); + return ret; +} + +void WPAD_EncodeData(WPADEncStatus *info,u32 flag,const s16 *pcmSamples,s32 numSamples,u8 *encData) +{ + int n; + short *samples = (short*)pcmSamples; + WENCStatus *status = (WENCStatus*)info; + + if(!(flag&WPAD_ENC_CONT)) status->step = 0; + + n = (numSamples+1)/2; + for(;n>0;n--) { + int nibble; + nibble = (wencdata(status,samples[0]))<<4; + nibble |= (wencdata(status,samples[1])); + *encData++ = nibble; + samples += 2; + } +} +#endif + +WPADData *WPAD_Data(int chan) +{ + //if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return NULL; + return &wpaddata[chan]; +} + +u8 WPAD_BatteryLevel(int chan) +{ + //if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return 0; + return wpaddata[chan].battery_level; +} + +void WPAD_IR(int chan, struct ir_t *ir) +{ + //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || ir==NULL ) return; + *ir = wpaddata[chan].ir; +} + +void WPAD_Orientation(int chan, struct orient_t *orient) +{ + //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || orient==NULL ) return; + *orient = wpaddata[chan].orient; +} + +void WPAD_GForce(int chan, struct gforce_t *gforce) +{ + //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || gforce==NULL ) return; + *gforce = wpaddata[chan].gforce; +} + +void WPAD_Accel(int chan, struct vec3w_t *accel) +{ + //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || accel==NULL ) return; + *accel = wpaddata[chan].accel; +} diff --git a/wiiu/link_elf.ld b/wiiu/link_elf.ld index 9c68424a8d..5dfdf95e80 100644 --- a/wiiu/link_elf.ld +++ b/wiiu/link_elf.ld @@ -73,6 +73,8 @@ SECTIONS .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } + PROVIDE (__code_start = .); + .text : { *(.text) @@ -89,6 +91,7 @@ SECTIONS . = ALIGN(32); /* REQUIRED. LD is flaky without it. */ } = 0 + PROVIDE (__code_end = .); PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); diff --git a/wiiu/link_rpl.ld b/wiiu/link_rpl.ld index 2deb7293ff..93f5c1f647 100644 --- a/wiiu/link_rpl.ld +++ b/wiiu/link_rpl.ld @@ -20,6 +20,7 @@ PHDRS { SECTIONS { . = ORIGIN(code); + PROVIDE(__code_start = .); .syscall ALIGN(32) : { *(.syscall) } : hdr_text @@ -53,6 +54,8 @@ SECTIONS { } : hdr_text + PROVIDE(__code_end = .); + /* Standard data sections */ . = ORIGIN(data); diff --git a/wiiu/system/exception.h b/wiiu/system/exception.h deleted file mode 100644 index 9d7226cd15..0000000000 --- a/wiiu/system/exception.h +++ /dev/null @@ -1,53 +0,0 @@ -/* source: https://github.com/QuarkTheAwesome/URetro */ - -#include - -#ifndef __EXCEPTION_H__ -#define __EXCEPTION_H__ - -void exception_disassembly_helper(char *fmt, int addr,int opcode, char* s) -{ - char* *store = (char**)0x1ab5d140; - char *buffer = (char *)store[0]; - if (addr == ((int*)store)[1]) { - store[0] += __os_snprintf(buffer,512,"> 0x%08X 0x%08X %s\n", addr,opcode,s); - } else { - store[0] += __os_snprintf(buffer,512," 0x%08X 0x%08X %s\n", addr,opcode,s); - } - -} -unsigned char exception_handler(void* contextIn) { - - //Temporary hacky fix, please ignore me. - - OSDynLoadModule coreinit_handle; - OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle); - void (*DisassemblePPCRange)(void *start, void *end, void *printf_func, int *find_symbol_func, int flags); - OSDynLoad_FindExport(coreinit_handle, 0, "DisassemblePPCRange", (void**)&DisassemblePPCRange); - - int* context = (int*)contextIn; - - char buf2[512]; - int* store = (int*)0x1AB5D140; - store[0] = (int)buf2; - store[1] = (int)context[38]; - - - DisassemblePPCRange((void*)context[38]-0x18, (void*)context[38]+0x4, (void*)exception_disassembly_helper, 0, 0); - char buf[2048]; - __os_snprintf(buf, 2048, "SP:%08X LR:%08X PC:%08X CR:%08X CTR:%08X\nXER:%08X SR0:%08X SR1:%08X EX0:%08X EX1:%08X\nr0:%08X r2:%08X r3:%08X r4:%08X r5:%08X\nr6:%08X r7:%08X r8:%08X r9:%08X r10:%08X\nr11:%08X r12:%08X r13:%08X r14:%08X r15:%08X\nr16:%08X r17:%08X r18:%08X r19:%08X r20:%08X\nr21:%08X r22:%08X r23:%08X r24:%08X r25:%08X\nr26:%08X r27:%08X r28:%08X r29:%08X r30:%08X\nr31:%08X\n%s", context[3], context[35], context[38], context[34], context[36], context[37], context[38], context[39], context[40], context[41], context[2], context[4], context[5], context[6], context[7], context[8], context[9], context[10], context[11], context[12], context[13], context[14], context[15], context[16], context[17], context[18], context[19], context[20], context[21], context[22], context[23], context[24], context[25], context[26], context[27], context[28], context[29], context[30], context[31], context[32], context[33], buf2); - void net_print_exp(const char* str); - void log_deinit(void); - net_print_exp(buf); - log_deinit(); - OSFatal(buf); - - return 0; -} -void InstallExceptionHandler() { - OSSetExceptionCallback(OS_EXCEPTION_TYPE_DSI, (OSExceptionCallbackFn)&exception_handler); - OSSetExceptionCallback(OS_EXCEPTION_TYPE_ISI, (OSExceptionCallbackFn)&exception_handler); - OSSetExceptionCallback(OS_EXCEPTION_TYPE_PROGRAM, (OSExceptionCallbackFn)&exception_handler); -} - -#endif //__EXCEPTION_H__ diff --git a/wiiu/system/exception_handler.c b/wiiu/system/exception_handler.c index 2a20b600ff..0bc1b443b4 100644 --- a/wiiu/system/exception_handler.c +++ b/wiiu/system/exception_handler.c @@ -1,50 +1,40 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2017 Ash Logan (QuarkTheAwesome) + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +//TODO: Program exceptions don't seem to work. Good thing they almost never happen. + #include +#include +#include #include -#include "exception_handler.h" #include "wiiu_dbg.h" +#include "exception_handler.h" -#define OS_EXCEPTION_MODE_GLOBAL_ALL_CORES 4 +/* Settings */ +#define NUM_STACK_TRACE_LINES 5 -#define OS_EXCEPTION_DSI 2 -#define OS_EXCEPTION_ISI 3 -#define OS_EXCEPTION_PROGRAM 6 +/* Externals + From the linker scripts. +*/ +extern unsigned int __code_start; +#define TEXT_START (unsigned int)&__code_start +extern unsigned int __code_end; +#define TEXT_END (unsigned int)&__code_end -/* Exceptions */ -typedef struct OSContext_ -{ - /* OSContext identifier */ - uint32_t tag1; - uint32_t tag2; - - /* GPRs */ - uint32_t gpr[32]; - - /* Special registers */ - uint32_t cr; - uint32_t lr; - uint32_t ctr; - uint32_t xer; - - /* Initial PC and MSR */ - uint32_t srr0; - uint32_t srr1; - - /* Only valid during DSI exception */ - uint32_t exception_specific0; - uint32_t exception_specific1; - - /* There is actually a lot more here but we don't need the rest*/ -} OSContext_; - -#define CPU_STACK_TRACE_DEPTH 10 -#define __stringify(rn) #rn - -#define mfspr(_rn) \ -({ register uint32_t _rval = 0; \ - asm volatile("mfspr %0," __stringify(_rn) \ - : "=r" (_rval));\ - _rval; \ -}) +void test_os_exceptions(void); +void exception_print_symbol(unsigned int addr); typedef struct _framerec { @@ -52,157 +42,228 @@ typedef struct _framerec void* lr; } frame_rec, *frame_rec_t; -static const char* exception_names[] = -{ - "DSI", - "ISI", - "PROGRAM" -}; +/* Fill in a few gaps in thread.h + Dimok calls these exception_specific0 and 1; + though we may as well name them by their function. +*/ +#define dsisr __unknown[0] +#define dar __unknown[1] -static const char exception_print_formats[18][45] = -{ - "Exception type %s occurred!\n", // 0 - "GPR00 %08X GPR08 %08X GPR16 %08X GPR24 %08X\n", // 1 - "GPR01 %08X GPR09 %08X GPR17 %08X GPR25 %08X\n", // 2 - "GPR02 %08X GPR10 %08X GPR18 %08X GPR26 %08X\n", // 3 - "GPR03 %08X GPR11 %08X GPR19 %08X GPR27 %08X\n", // 4 - "GPR04 %08X GPR12 %08X GPR20 %08X GPR28 %08X\n", // 5 - "GPR05 %08X GPR13 %08X GPR21 %08X GPR29 %08X\n", // 6 - "GPR06 %08X GPR14 %08X GPR22 %08X GPR30 %08X\n", // 7 - "GPR07 %08X GPR15 %08X GPR23 %08X GPR31 %08X\n", // 8 - "LR %08X SRR0 %08x SRR1 %08x\n", // 9 - "DAR %08X DSISR %08X\n", // 10 - "STACK DUMP:", // 11 - " --> ", // 12 - " -->\n", // 13 - "\n", // 14 - "%p", // 15 - "\nCODE DUMP:\n", // 16 - "%p: %08X %08X %08X %08X\n", // 17 -}; -void net_print_exp(const char* str); -void wiiu_log_deinit(void); +/* Some bitmasks for determining DSI causes. + Taken from the PowerPC Programming Environments Manual (32-bit). +*/ +//Set if the EA is unmapped. +#define DSISR_TRANSLATION_MISS 0x40000000 +//Set if the memory accessed is protected. +#define DSISR_TRANSLATION_PROT 0x8000000 +//Set if certain instructions are used on uncached memory (see manual) +#define DSISR_BAD_CACHING 0x4000000 +//Set if the offending operation is a write, clear for a read. +#define DSISR_WRITE_ATTEMPTED 0x2000000 +//Set if the memory accessed is a DABR match +#define DSISR_DABR_MATCH 0x400000 +/* ISI cause bitmasks, same source */ +#define SRR1_ISI_TRANSLATION_MISS 0x40000000 +#define SRR1_ISI_TRANSLATION_PROT 0x8000000 +/* PROG cause bitmasks, guess where from */ +//Set on floating-point exceptions +#define SRR1_PROG_IEEE_FLOAT 0x100000 +//Set on an malformed instruction (can't decode) +#define SRR1_PROG_BAD_INSTR 0x80000 +//Set on a privileged instruction executing in userspace +#define SRR1_PROG_PRIV_INSTR 0x40000 +//Set on a trap instruction +#define SRR1_PROG_TRAP 0x20000 +//Clear if srr0 points to the address that caused the exception (yes, really) +#define SRR1_PROG_SRR0_INACCURATE 0x10000 -static unsigned char exception_cb(void* c, unsigned char exception_type) -{ - char gdb_buf[512]; - char* gdb_buf_ptr = gdb_buf; - char buf[4096]; - int pos = 0; +#define buf_add(...) pos += sprintf(exception_msgbuf + pos, __VA_ARGS__) +size_t pos = 0; +char* exception_msgbuf; - OSContext_ *context = (OSContext_*) c; - /* - * This part is mostly from libogc. Thanks to the devs over there. - */ - pos += sprintf(buf + pos, exception_print_formats[0], exception_names[exception_type]); - pos += sprintf(buf + pos, exception_print_formats[1], context->gpr[0], context->gpr[8], context->gpr[16], - context->gpr[24]); - pos += sprintf(buf + pos, exception_print_formats[2], context->gpr[1], context->gpr[9], context->gpr[17], - context->gpr[25]); - pos += sprintf(buf + pos, exception_print_formats[3], context->gpr[2], context->gpr[10], context->gpr[18], - context->gpr[26]); - pos += sprintf(buf + pos, exception_print_formats[4], context->gpr[3], context->gpr[11], context->gpr[19], - context->gpr[27]); - pos += sprintf(buf + pos, exception_print_formats[5], context->gpr[4], context->gpr[12], context->gpr[20], - context->gpr[28]); - pos += sprintf(buf + pos, exception_print_formats[6], context->gpr[5], context->gpr[13], context->gpr[21], - context->gpr[29]); - pos += sprintf(buf + pos, exception_print_formats[7], context->gpr[6], context->gpr[14], context->gpr[22], - context->gpr[30]); - pos += sprintf(buf + pos, exception_print_formats[8], context->gpr[7], context->gpr[15], context->gpr[23], - context->gpr[31]); - pos += sprintf(buf + pos, exception_print_formats[9], context->lr, context->srr0, context->srr1); +void __attribute__((__noreturn__)) exception_cb(OSContext* ctx, OSExceptionType type) { + if (!exception_msgbuf || !OSEffectiveToPhysical(exception_msgbuf)) { + /* No message buffer available, fall back onto MEM1 */ + exception_msgbuf = (char*)0xF4000000; + } - //if(exception_type == OS_EXCEPTION_DSI) { - pos += sprintf(buf + pos, exception_print_formats[10], context->exception_specific1, - context->exception_specific0); // this freezes - //} +/* First up, the pretty header that tells you wtf just happened */ + if (type == OS_EXCEPTION_TYPE_DSI) { + /* Exception type and offending instruction location + Also initializes exception_msgbuf, use buf_add from now on */ + buf_add("DSI: Instr at %08X", ctx->srr0); + /* Was this a read or a write? */ + if (ctx->dsisr & DSISR_WRITE_ATTEMPTED) { + buf_add(" bad write to"); + } else { + buf_add(" bad read from"); + } + /* So why was it bad? + Other causes (DABR) don't have a message to go with them. */ + if (ctx->dsisr & DSISR_TRANSLATION_MISS) { + buf_add(" unmapped memory at"); + } else if (ctx->dsisr & DSISR_TRANSLATION_PROT) { + buf_add(" protected memory at"); + } else if (ctx->dsisr & DSISR_BAD_CACHING) { + buf_add(" uncached memory at"); + } + buf_add(" %08X\n", ctx->dar); + } else if (type == OS_EXCEPTION_TYPE_ISI) { + buf_add("ISI: Bad execute of"); + if (ctx->srr1 & SRR1_ISI_TRANSLATION_PROT) { + buf_add(" protected memory at"); + } else if (ctx->srr1 & SRR1_ISI_TRANSLATION_MISS) { + buf_add(" unmapped memory at"); + } + buf_add(" %08X\n", ctx->srr0); + } else if (type == OS_EXCEPTION_TYPE_PROGRAM) { + buf_add("PROG:"); + if (ctx->srr1 & SRR1_PROG_BAD_INSTR) { + buf_add(" Malformed instruction at"); + } else if (ctx->srr1 & SRR1_PROG_PRIV_INSTR) { + buf_add(" Privileged instruction in userspace at"); + } else if (ctx->srr1 & SRR1_PROG_IEEE_FLOAT) { + buf_add(" Floating-point exception at"); + } else if (ctx->srr1 & SRR1_PROG_TRAP) { + buf_add(" Trap conditions met at"); + } else { + buf_add(" Out-of-spec error (!) at"); + } + if (ctx->srr1 & SRR1_PROG_SRR0_INACCURATE) { + buf_add("%08X-ish\n", ctx->srr0); + } else { + buf_add("%08X\n", ctx->srr0); + } + } - void* pc = (void*)context->srr0; - void* lr = (void*)context->lr; - void* r1 = (void*)context->gpr[1]; - register uint32_t i = 0; - register frame_rec_t l, p = (frame_rec_t)lr; +/* Add register dump + There's space for two more regs at the end of the last line... + Any ideas for what to put there? */ + buf_add( \ + "r0 %08X r1 %08X r2 %08X r3 %08X r4 %08X\n" \ + "r5 %08X r6 %08X r7 %08X r8 %08X r9 %08X\n" \ + "r10 %08X r11 %08X r12 %08X r13 %08X r14 %08X\n" \ + "r15 %08X r16 %08X r17 %08X r18 %08X r19 %08X\n" \ + "r20 %08X r21 %08X r22 %08X r23 %08X r24 %08X\n" \ + "r25 %08X r26 %08X r27 %08X r28 %08X r29 %08X\n" \ + "r30 %08X r31 %08X lr %08X sr1 %08X dsi %08X\n" \ + "ctr %08X cr %08X xer %08X\n",\ + ctx->gpr[0], ctx->gpr[1], ctx->gpr[2], ctx->gpr[3], ctx->gpr[4], \ + ctx->gpr[5], ctx->gpr[6], ctx->gpr[7], ctx->gpr[8], ctx->gpr[9], \ + ctx->gpr[10], ctx->gpr[11], ctx->gpr[12], ctx->gpr[13], ctx->gpr[14], \ + ctx->gpr[15], ctx->gpr[16], ctx->gpr[17], ctx->gpr[18], ctx->gpr[19], \ + ctx->gpr[20], ctx->gpr[21], ctx->gpr[22], ctx->gpr[23], ctx->gpr[24], \ + ctx->gpr[25], ctx->gpr[26], ctx->gpr[27], ctx->gpr[28], ctx->gpr[29], \ + ctx->gpr[30], ctx->gpr[31], ctx->lr, ctx->srr1, ctx->dsisr, \ + ctx->ctr, ctx->cr, ctx->xer \ + ); - l = p; - p = r1; +/* Stack trace! + First, let's print the PC... */ + exception_print_symbol(ctx->srr0); - if (!p) - asm volatile("mr %0,%%r1" : "=r"(p)); + if (ctx->gpr[1]) { + /* Then the addresses off the stack. + Code borrowed from Dimok's exception handler. */ + frame_rec_t p = (frame_rec_t)ctx->gpr[1]; + if ((unsigned int)p->lr != ctx->lr) { + exception_print_symbol(ctx->lr); + } + for (int i = 0; i < NUM_STACK_TRACE_LINES && p->up; p = p->up, i++) { + exception_print_symbol((unsigned int)p->lr); + } + } else { + buf_add("Stack pointer invalid. Could not trace further.\n"); + } - pos += sprintf(buf + pos, exception_print_formats[11]); - - for (i = 0; i < CPU_STACK_TRACE_DEPTH - 1 && p->up; p = p->up, i++) - { - if (i % 4) - pos += sprintf(buf + pos, exception_print_formats[12]); - else - { - if (i > 0) - pos += sprintf(buf + pos, exception_print_formats[13]); - else - pos += sprintf(buf + pos, exception_print_formats[14]); - } - - switch (i) - { - case 0: - if (pc) - { - pos += sprintf(buf + pos, exception_print_formats[15], pc); - gdb_buf_ptr += __os_snprintf(gdb_buf_ptr, &gdb_buf[sizeof(gdb_buf)] - gdb_buf_ptr, "info line *0x%08X\n", pc); - - } - - break; - - case 1: - if (!l) - l = (frame_rec_t)mfspr(8); - - pos += sprintf(buf + pos, exception_print_formats[15], (void*)l); - gdb_buf_ptr += __os_snprintf(gdb_buf_ptr, &gdb_buf[sizeof(gdb_buf)] - gdb_buf_ptr, "info line *0x%08X\n", l); - break; - - default: - pos += sprintf(buf + pos, exception_print_formats[15], (void*)(p->up->lr)); - gdb_buf_ptr += __os_snprintf(gdb_buf_ptr, &gdb_buf[sizeof(gdb_buf)] - gdb_buf_ptr, "info line *0x%08X\n", p->up->lr); - break; - } - } - - //if(exception_type == OS_EXCEPTION_DSI) { - uint32_t* pAdd = (uint32_t*)context->srr0; - pos += sprintf(buf + pos, exception_print_formats[16]); - - // TODO by Dimok: this was actually be 3 instead of 2 lines in libogc .... but there is just no more space anymore on the screen - for (i = 0; i < 8; i += 4) - pos += sprintf(buf + pos, exception_print_formats[17], &(pAdd[i]), pAdd[i], pAdd[i + 1], pAdd[i + 2], pAdd[i + 3]); - - //} - net_print_exp(gdb_buf); -// net_print_exp(buf); - wiiu_log_deinit(); - OSFatal(buf); - return 1; + OSFatal(exception_msgbuf); + for (;;) {} } -static unsigned char dsi_exception_cb(void* context) -{ - return exception_cb(context, 0); +BOOL __attribute__((__noreturn__)) exception_dsi_cb(OSContext* ctx) { + exception_cb(ctx, OS_EXCEPTION_TYPE_DSI); } -static unsigned char isi_exception_cb(void* context) -{ - return exception_cb(context, 1); +BOOL __attribute__((__noreturn__)) exception_isi_cb(OSContext* ctx) { + exception_cb(ctx, OS_EXCEPTION_TYPE_ISI); } -static unsigned char program_exception_cb(void* context) -{ - return exception_cb(context, 2); +BOOL __attribute__((__noreturn__)) exception_prog_cb(OSContext* ctx) { + exception_cb(ctx, OS_EXCEPTION_TYPE_PROGRAM); } -void setup_os_exceptions(void) -{ - OSSetExceptionCallback(OS_EXCEPTION_DSI, (OSExceptionCallbackFn)&dsi_exception_cb); - OSSetExceptionCallback(OS_EXCEPTION_ISI, (OSExceptionCallbackFn)&isi_exception_cb); - OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, (OSExceptionCallbackFn)&program_exception_cb); +void exception_print_symbol(unsigned int addr) { +/* Check if addr is within this RPX's .text */ + if (addr >= TEXT_START && addr < TEXT_END) { + char symbolName[64]; + OSGetSymbolName(addr, symbolName, 63); + + buf_add("%08X(%08X):%s\n", addr, addr - TEXT_START, symbolName); + } +/* Check if addr is within the system library area... */ + else if ((addr >= 0x01000000 && addr < 0x01800000) || +/* Or the rest of the app executable area. + I would have used whatever method JGeckoU uses to determine + the real lowest address, but *someone* didn't make it open-source :/ */ + (addr >= 0x01800000 && addr < 0x1000000)) { + char symbolName[64]; + OSGetSymbolName(addr, symbolName, 63); + /* Extract RPL name and try and find its base address */ + char* seperator = strchr(symbolName, '|'); + if (seperator) { + /* Isolate library name; should end with .rpl + (our main RPX was caught by another test case above) */ + *seperator = '\0'; + /* Try for a base address */ + void* libAddr; + OSDynLoad_Acquire(symbolName, &libAddr); + *seperator = '|'; + /* We got one! */ + if (libAddr) { + buf_add("%08X(%08X):%s\n", addr, addr - (unsigned int)libAddr, symbolName); + OSDynLoad_Release(libAddr); + return; + } + } + /* Ah well. We can still print the basics. */ + buf_add("%08X( ):%s\n", addr, symbolName); + } +/* Check if addr is in the HBL range + TODO there's no real reason we couldn't find the symbol here, + it's just laziness and arguably uneccesary bloat */ + else if (addr >= 0x00800000 && addr < 0x01000000) { + buf_add("%08X(%08X):\n", addr, addr - 0x00800000); + } +/* If all else fails, just say "unknown" */ + else { + buf_add("%08X( ):\n", addr); + } +} + +/* void setup_os_exceptions(void) + Install and initialize the exception handler. +*/ +void setup_os_exceptions(void) { + exception_msgbuf = malloc(4096); + OSSetExceptionCallback(OS_EXCEPTION_TYPE_DSI, exception_dsi_cb); + OSSetExceptionCallback(OS_EXCEPTION_TYPE_ISI, exception_isi_cb); + OSSetExceptionCallback(OS_EXCEPTION_TYPE_PROGRAM, exception_prog_cb); + test_os_exceptions(); +} + +/* void test_os_exceptions(void) + Used for debugging. Insert code here to induce a crash. +*/ +void test_os_exceptions(void) { + //Write to 0x00000000; causes DSI + /*__asm__ volatile ( + "li %r3, 0 \n" \ + "stw %r3, 0(%r3) \n" + ); + DCFlushRange((void*)0, 4);*/ + //Malformed instruction, causes PROG. Doesn't seem to work. + /*__asm__ volatile ( + ".int 0xDEADC0DE" + );*/ + //Jump to 0; causes ISI + /*void (*testFunc)() = (void(*)())0; + testFunc();*/ } diff --git a/wiiu/system/exception_handler.h b/wiiu/system/exception_handler.h index 7626f92877..2d04f2a32e 100644 --- a/wiiu/system/exception_handler.h +++ b/wiiu/system/exception_handler.h @@ -1,14 +1,29 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2017 Ash Logan (QuarkTheAwesome) + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + #ifndef __EXCEPTION_HANDLER_H_ #define __EXCEPTION_HANDLER_H_ #ifdef __cplusplus extern "C" { -#endif +#endif //__cplusplus void setup_os_exceptions(void); #ifdef __cplusplus } -#endif +#endif //__cplusplus -#endif +#endif //__EXCEPTION_HANDLER_H_ diff --git a/wiiu/system/imports.h b/wiiu/system/imports.h index 0014e7e552..866382c1de 100644 --- a/wiiu/system/imports.h +++ b/wiiu/system/imports.h @@ -31,6 +31,12 @@ IMPORT(OSGetSystemTick); IMPORT(OSGetSymbolName); IMPORT(OSGetSharedData); IMPORT(OSEffectiveToPhysical); +IMPORT(OSInitSemaphore); +IMPORT(OSInitSemaphoreEx); +IMPORT(OSGetSemaphoreCount); +IMPORT(OSSignalSemaphore); +IMPORT(OSWaitSemaphore); +IMPORT(OSTryWaitSemaphore); IMPORT(exit); IMPORT(_Exit); @@ -219,6 +225,7 @@ IMPORT_BEGIN(vpad); IMPORT(VPADRead); IMPORT(VPADInit); +IMPORT(VPADGetTPCalibratedPoint); IMPORT_END();