pax_global_header00006660000000000000000000000064127107466230014522gustar00rootroot0000000000000052 comment=a6659ee7955b5472999cafc8cadaa42e2846f903 ajtcl-16.04/000077500000000000000000000000001271074662300126315ustar00rootroot00000000000000ajtcl-16.04/.gitignore000066400000000000000000000007621271074662300146260ustar00rootroot00000000000000TAGS LinuxTAGS tags cscope.out whitespace.db .sconsign.dblite .sconf_temp/ config.log *.pdb .*.swp .cproject *.ncb *.log *.suo *.aps *.user *.obj *.lib *.exe *.sln *.o *.d *.elf *.map *.os *.ilk *.dep *.creds *.a html/ build/ dist/ ajlite.nvram .whitespace.db *.pyc *.exp samples/basic/eventaction_service samples/network/net_bus samples/secure/SecureClientECDHE samples/secure/SecureServiceECDHE test/base64 test/certificate test/codisco test/ctrdrbg test/nvramdump test/sessionslite test/sigtest ajtcl-16.04/Doxyfile000066400000000000000000002071741271074662300143520ustar00rootroot00000000000000# Doxyfile 1.7.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "AllJoyn™ Thin Client API Reference" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = "Version 16.04.00" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST = YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ./inc/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is adviced to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the # mathjax.org site, so you can quickly see the result without installing # MathJax, but it is strongly recommended to install a local copy of MathJax # before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called Helvetica to the output # directory and reference it in all dot files that doxygen generates. # When you want a differently looking font you can specify the font name # using DOT_FONTNAME. You need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES ajtcl-16.04/Makefile000066400000000000000000000304041271074662300142720ustar00rootroot00000000000000# Copyright AllSeen Alliance. All rights reserved. # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # This makefile is meant to be used solely for building WSL-enabled applications. # It is intended to be invoked from IDEs that do not support building using SCons. # All paths in this file are relative to the makefile location # # Some care has to be taken when passing string values into the makefile from the command-line. # An extra level of backslash escaping required to get a string presented to the compiler's preprocessor. # For example, passing the string "bar" to use as a character string initializer in a .c file: # const char foo_var[] = FOO_VAR; # # Is passed on the command line: # make target FOO_VAR=\\\"bar\\\" # # Which results in compiler arguments such as: # -DFOO_VAR=\"bar\" # # settings that can be defined: # AJ_CONFIGURE_WIFI_UPON_START: (boolean) should wifi network connections be started when the AllJoyn # application starts, 1 means yes, 0 or undef means no # example: AJ_CONFIGURE_WIFI_UPON_START=1 # WIFI_DEVICE_NAME: (quoted string) the hostname to assign to your device when connecting to the network # example: WIFI_DEVICE_NAME=\\\"WSLNode001\\\" # WIFI_SCAN: (boolean) should a scan of access points be performed when the device starts up, # 1 means yes, 0 or undef means no # example: WIFI_SCAN=1 # WIFI_SSID: (quoted string) the SSID of the network to connect to # example: WIFI_SSID=\\\"AP_SSID01\\\" # WIFI_PASSPHRASE: (quoted string) the passphrase used to connect to WIFI_SSID # example: WIFI_PASSPHRASE=\\\"PassPhrase\\\" # SOFTAP_SSID: (quoted string) the SSID to use when the device is put into Access Point mode # example: SOFTAP_SSID=\\\"SoftAP_SSID01\\\" # SOFTAP_PASSPHRASE: (quoted string) the passphrase needed by clients to connect to SOFTAP_SSID # example: SOFTAP_PASSPHRASE=\\\"My_PassPhrase\\\" ALLJOYN_DEFINES = # Check which options are defined on the command-line ifneq ($(AJ_DEBUG_RESTRICT), ) ALLJOYN_DEFINES += -DAJ_DEBUG_RESTRICT=${AJ_DEBUG_RESTRICT} endif ifneq ($(AJ_CONFIGURE_WIFI_UPON_START), ) ALLJOYN_DEFINES += -DAJ_CONFIGURE_WIFI_UPON_START=${AJ_CONFIGURE_WIFI_UPON_START} endif ifneq ($(WIFI_DEVICE_NAME),) ALLJOYN_DEFINES += -DWIFI_DEVICE_NAME=${WIFI_DEVICE_NAME} endif ifneq ($(WIFI_SCAN),) ALLJOYN_DEFINES += -DWIFI_SCAN=${WIFI_SCAN} endif ifneq ($(WIFI_SSID),) ALLJOYN_DEFINES += -DWIFI_SSID=${WIFI_SSID} endif ifneq ($(WIFI_PASSPHRASE),) ALLJOYN_DEFINES += -DWIFI_PASSPHRASE=${WIFI_PASSPHRASE} endif ifneq ($(SOFTAP_SSID),) ALLJOYN_DEFINES += -DSOFTAP_SSID=${SOFTAP_SSID} endif ifneq ($(SOFTAP_PASSPHRASE),) ALLJOYN_DEFINES += -DSOFTAP_PASSPHRASE=${SOFTAP_PASSPHRASE} endif DEFINES = -D__SAM3X8E__ \ -DARM_MATH_CM3=true \ -DBOARD=ARDUINO_DUE_X \ -Dprintf=iprintf DEFINES += $(ALLJOYN_DEFINES) RELEASE_DEFINES = -DNDEBUG \ # Linker flags LDFLAGS = -mthumb \ -Wl,-Map=$@.map \ -Wl,--start-group \ -larm_cortexM3l_math \ -lm \ -Wl,--end-group \ -L"$(ATMEL_DIR)/thirdparty/CMSIS/Lib/GCC" \ -Wl,--gc-sections \ -mcpu=cortex-m3 \ -Wl,--entry=Reset_Handler \ -Wl,--cref \ -mthumb \ -T$(ATMEL_DIR)/sam/utils/linker_scripts/sam3x/sam3x8/gcc/flash.ld RELEASE_LDFLAGS = \ -Os \ # Include Paths INCLUDES = -I. \ -Iconfig \ -I$(FREE_RTOS_DIR)/Source/include \ -I$(FREE_RTOS_DIR)/Source/portable/GCC/ARM_CM3 \ -I$(ATMEL_DIR)/common/boards \ -I$(ATMEL_DIR)/common/services/clock \ -I$(ATMEL_DIR)/common/services/clock/sam3x \ -I$(ATMEL_DIR)/common/services/gpio \ -I$(ATMEL_DIR)/common/services/ioport \ -I$(ATMEL_DIR)/common/services/freertos/sam \ -I$(ATMEL_DIR)/common/services/serial/sam_uart \ -I$(ATMEL_DIR)/common/services/serial \ -I$(ATMEL_DIR)/common/services/spi \ -I$(ATMEL_DIR)/common/services/sam_spi \ -I$(ATMEL_DIR)/common/services/spi/sam_spi/module_config \ -I$(ATMEL_DIR)/common/utils \ -I$(ATMEL_DIR)/common/utils/stdio/stdio_serial \ -I$(ATMEL_DIR)/common/drivers/nvm \ -I$(ATMEL_DIR)/common/drivers/nvm/sam/module_config \ -I$(ATMEL_DIR)/sam/boards \ -I$(ATMEL_DIR)/sam/boards/arduino_due_x \ -I$(ATMEL_DIR)/sam/drivers/dmac \ -I$(ATMEL_DIR)/sam/drivers/pio \ -I$(ATMEL_DIR)/sam/drivers/pmc \ -I$(ATMEL_DIR)/sam/drivers/pdc \ -I$(ATMEL_DIR)/sam/drivers/uart \ -I$(ATMEL_DIR)/sam/drivers/usart \ -I$(ATMEL_DIR)/sam/drivers/spi \ -I$(ATMEL_DIR)/sam/drivers/efc \ -I$(ATMEL_DIR)/sam/drivers/trng \ -I$(ATMEL_DIR)/sam/utils \ -I$(ATMEL_DIR)/sam/utils/cmsis/sam3x/include \ -I$(ATMEL_DIR)/sam/utils/cmsis/sam3x/source/templates \ -I$(ATMEL_DIR)/sam/utils/cmsis/sam3x/include/component \ -I$(ATMEL_DIR)/sam/utils/header_files \ -I$(ATMEL_DIR)/sam/utils/preprocessor \ -I$(ATMEL_DIR)/sam/services/flash_efc \ -I$(ATMEL_DIR)/thirdparty/CMSIS/Include \ -I$(ATMEL_DIR)/thirdparty/CMSIS/Lib/GCC \ -I$(ATMEL_DIR)/sam/boards/arduino_due_x/board_config \ -I$(ATMEL_DIR)/common/services/clock/sam3x/module_config \ -I$(ATMEL_DIR)/config \ -I$(ATMEL_DIR)/common/services/clock/sam3x \ -Iinc \ -IRTOS \ -IRTOS/FreeRTOS \ -Ibsp \ -Ibsp/due \ -Ibsp/due/config \ -Imalloc \ -Iexternal\sha2 \ -Icrypto \ -Icrypto/ecc \ -IWSL # Compiler flags FLAGS = -mthumb \ -fdata-sections \ -ffunction-sections \ -mlong-calls \ -g3 \ -Wall \ -mcpu=cortex-m3 \ -c \ -pipe \ -fno-strict-aliasing \ -Wpointer-arith \ -std=gnu99 \ -Wchar-subscripts \ -Wcomment \ -Wformat=2 \ -Wimplicit-int \ -Wmain \ -Wparentheses \ -Wsequence-point \ -Wreturn-type \ -Wswitch \ -Wtrigraphs \ -Wunused \ -Wuninitialized \ -Wfloat-equal \ -Wundef \ -Wshadow \ -Wbad-function-cast \ -Wwrite-strings \ -Wsign-compare \ -Waggregate-return \ -Wformat \ -Wno-deprecated-declarations \ -Wno-unknown-pragmas \ -Wpacked \ -Wunreachable-code \ -Wcast-align \ --param max-inline-insns-single=500 \ -MD \ -MP \ -MF $(@:%.o=%.d) COMPILER = arm-none-eabi-gcc.exe SOURCE_FILES := $(FREE_RTOS_DIR)/Source/croutine.c \ $(FREE_RTOS_DIR)/Source/list.c \ $(FREE_RTOS_DIR)/Source/queue.c \ $(FREE_RTOS_DIR)/Source/tasks.c \ $(FREE_RTOS_DIR)/Source/timers.c \ $(FREE_RTOS_DIR)/Source/portable/MemMang/heap_3.c \ $(FREE_RTOS_DIR)/Source/portable/GCC/ARM_CM3/port.c \ $(ATMEL_DIR)/common/services/clock/sam3x/sysclk.c \ $(ATMEL_DIR)/common/services/spi/sam_spi/spi_master.c \ $(ATMEL_DIR)/common/services/freertos/sam/freertos_peripheral_control.c \ $(ATMEL_DIR)/common/services/freertos/sam/freertos_usart_serial.c \ $(ATMEL_DIR)/common/utils/interrupt/interrupt_sam_nvic.c \ $(ATMEL_DIR)/common/utils/stdio/read.c \ $(ATMEL_DIR)/common/utils/stdio/write.c \ $(ATMEL_DIR)/common/drivers/nvm/sam/sam_nvm.c \ $(ATMEL_DIR)/sam/boards/arduino_due_x/init.c \ $(ATMEL_DIR)/sam/boards/arduino_due_x/led.c \ $(ATMEL_DIR)/sam/drivers/dmac/dmac.c \ $(ATMEL_DIR)/sam/drivers/pdc/pdc.c \ $(ATMEL_DIR)/sam/drivers/pio/pio.c \ $(ATMEL_DIR)/sam/drivers/pio/pio_handler.c \ $(ATMEL_DIR)/sam/drivers/pmc/pmc.c \ $(ATMEL_DIR)/sam/drivers/pmc/sleep.c \ $(ATMEL_DIR)/sam/drivers/uart/uart.c \ $(ATMEL_DIR)/sam/drivers/usart/usart.c \ $(ATMEL_DIR)/sam/drivers/spi/spi.c \ $(ATMEL_DIR)/sam/drivers/efc/efc.c \ $(ATMEL_DIR)/sam/drivers/trng/trng.c \ $(ATMEL_DIR)/sam/utils/cmsis/sam3x/source/templates/exceptions.c \ $(ATMEL_DIR)/sam/utils/cmsis/sam3x/source/templates/system_sam3x.c \ $(ATMEL_DIR)/sam/utils/cmsis/sam3x/source/templates/gcc/startup_sam3x.c \ $(ATMEL_DIR)/sam/services/flash_efc/flash_efc.c \ $(ATMEL_DIR)/sam/utils/syscalls/gcc/syscalls.c \ crypto/aj_sw_crypto.c \ crypto/ecc/aj_crypto_ecc.c \ crypto/ecc/aj_crypto_sha2.c \ src/aj_about.c \ src/aj_bufio.c \ src/aj_bus.c \ src/aj_connect.c \ src/aj_cert.c \ src/aj_crc16.c \ src/aj_creds.c \ src/aj_crypto.c \ src/aj_debug.c \ src/aj_disco.c \ src/aj_guid.c \ src/aj_helper.c \ src/aj_init.c \ src/aj_introspect.c \ src/aj_keyauthentication.c \ src/aj_keyexchange.c \ src/aj_link_timeout.c \ src/aj_msg.c \ src/aj_nvram.c \ src/aj_peer.c \ src/aj_serial.c \ src/aj_serial_rx.c \ src/aj_serial_tx.c \ src/aj_std.c \ src/aj_util.c \ malloc/aj_malloc.c \ external/sha2/sha2.c \ WSL/aj_buf.c \ WSL/aj_wsl_htc.c \ WSL/aj_wsl_net.c \ WSL/aj_wsl_spi_mbox.c \ WSL/aj_wsl_unmarshal.c \ WSL/aj_wsl_wmi.c \ WSL/aj_wsl_marshal.c \ WSL/aj_wsl_tasks.c \ RTOS/main.c \ RTOS/aj_net.c \ RTOS/aj_wifi_ctrl.c \ RTOS/Alljoyn.c \ RTOS/FreeRTOS/aj_target_rtos.c \ bsp/due/aj_spi.c \ bsp/due/aj_trng.c \ bsp/due/aj_target_platform.c TEST_FILES = test/aestest.c TEST_FILES += test/mutter.c TEST_FILES += test/svclite.c TEST_FILES += test/nvramtest.c TEST_FILES += test/clientlite.c TEST_FILES += test/sessionslite.c SAMPLE_FILES = samples/basic/basic_client.c SAMPLE_FILES += samples/basic/basic_service.c SAMPLE_FILES += samples/basic/nameChange_client.c SAMPLE_FILES += samples/basic/signalConsumer_client.c SAMPLE_FILES += samples/basic/signal_service.c SAMPLE_FILES += samples/secure/SecureClient.c OBJECTS = $(SOURCE_FILES:.c=.o) TEST_OBJECTS = $(TEST_FILES:.c=.o) SAMPLE_OBJECTS = $(SAMPLE_FILES:.c=.o) DFILES = $(SOURCE_FILES:.c=.d) EXECUTABLES = $(TEST_FILES:.c=.elf) test: $(TEST_FILES) $(TEST_OBJECTS) $(OBJECTS) sample: $(SAMPLE_FILES) $(SAMPLE_OBJECTS) $(OBJECTS) Release: release #release: FLAGS += -O3 release: DEFINES += -DNDEBUG release: all Debug: debug #debug: FLAGS += -g3 debug: all # All the test elf's are linked here. Add more by using the same format as the others # $(COMPILER) -o .elf $(OBJECTS) .o $(LDFLAGS) all: test \ sample \ due_mutter \ due_svclite \ due_nvram_test \ due_clientlite \ due_sessionslite \ due_basic_client \ due_basic_service \ due_aestest: $(COMPILER) -o due_aestest.elf $(OBJECTS) test/aestest.o $(LDFLAGS) due_mutter: $(COMPILER) -o due_mutter.elf $(OBJECTS) test/mutter.o $(LDFLAGS) due_svclite: $(COMPILER) -o due_svclite.elf $(OBJECTS) test/svclite.o $(LDFLAGS) due_nvram_test: $(COMPILER) -o due_nvram_test.elf $(OBJECTS) test/nvramtest.o $(LDFLAGS) due_clientlite: $(COMPILER) -o due_clientlite.elf $(OBJECTS) test/clientlite.o $(LDFLAGS) due_sessionslite: $(COMPILER) -o due_sessionslite.elf $(OBJECTS) test/sessionslite.o $(LDFLAGS) due_samplesecureclient: $(COMPILER) -o due_samplesecureclient.elf $(OBJECTS) samples/secure/secureclient.o $(LDFLAGS) due_samplesecureservice: $(COMPILER) -o due_samplesecureservice.elf $(OBJECTS) samples/secure/secureservice.o $(LDFLAGS) due_basic_client: $(COMPILER) -o due_basic_client.elf $(OBJECTS) samples/basic/basic_client.o $(LDFLAGS) due_basic_service: $(COMPILER) -o due_basic_service.elf $(OBJECTS) samples/basic/basic_service.o $(LDFLAGS) due_nameChange_client: $(COMPILER) -o due_nameChange_client.elf $(OBJECTS) samples/basic/nameChange_client.o $(LDFLAGS) due_signalConsumer_client: $(COMPILER) -o due_signalConsumer_client.elf $(OBJECTS) samples/basic/signalConsumer_client.o $(LDFLAGS) due_signal_service: $(COMPILER) -o due_signal_service.elf $(OBJECTS) samples/basic/signal_service.o $(LDFLAGS) %.o : %.c $(COMPILER) $(DEFINES) $(INCLUDES) $(FLAGS) -o $@ $< clean: cmd /C del /S *.elf cmd /C for /r %i in (*.o, *.d, *.map) do del %i clean_c: cmd /C del /S *.o cmd /C del /S *.d cd test; cmd /C del /S *.o cd test; cmd /C del /S *.d cd ajtcl; cmd /C del /S *.o cd ajtcl; cmd /C del /S *.d ajtcl-16.04/README.md000066400000000000000000000025231271074662300141120ustar00rootroot00000000000000Notice of Export Control Law ============================ Cryptographic software is subject to the US government export control and economic sanctions laws (“US export lawsâ€) including the US Department of Commerce Bureau of Industry and Security’s (“BISâ€) Export Administration Regulations (“EARâ€, 15 CFR 730 et seq., http://www.bis.doc.gov/). You may also be subject to US export laws, including the requirements of license exception TSU in accordance with part 740.13(e) of the EAR. Software and/or technical data subject to the US export laws may not be directly or indirectly exported, reexported, transferred, or released (“exportedâ€) to US embargoed or sanctioned destinations currently including Cuba, Iran, North Korea, Sudan, or Syria, but any amendments to this list shall apply. In addition, software and/or technical data may not be exported to any entity barred by the US government from participating in export activities. Denied persons or entities include those listed on BIS’s Denied Persons and Entities Lists, and the US Department of Treasury’s Office of Foreign Assets Control’s Specially Designated Nationals List. The country in which you are currently located may have restrictions on the import, possession, use of encryption software. You are responsible for compliance with the laws where You are located. ajtcl-16.04/ReleaseNotes.txt000066400000000000000000000100721271074662300157630ustar00rootroot00000000000000AllJoyn Thin Core Version 16.04 Release Notes ============================================== Fully Validated Platforms ------------------------- * Linux Ubuntu 14.04 LTS (64 bit) See the release review page for other platforms that have not been fully verified, but may work: https://wiki.allseenalliance.org/core/core_16.04_release_review#regression_test Features added in Version 16.04 ------------------------------- * New password-based authentication mechanism ECDHE_SPEKE (ASACORE-2055) * Security 2.0 continues to be a Developer Preview Feature (ASACORE-1393) * Support for multiple Security 2.0 Manifests for a single app (ASACORE-2710) * Each Security 2.0 Manifest must be signed (ASACORE-2750) Issues Addressed in Version 16.04 --------------------------------- ASACORE-2177 Introspection in Thin Library doesn't work for app objects that use the root path '/' ASACORE-2394 Security unit tests require bbservice. Run "bbservice -n org.alljoyn.svclite" at the same time for SecurityTest.Test_ECDHE_NULL and SecurityTest.Test_ECDHE_PS ASACORE-2546 Identity and Membership certificates must have an AKI to be installed For a complete list of fixed issues: https://jira.allseenalliance.org/issues/?jql=project%20%3D%20ASACORE%20AND%20issuetype%20%3D%20Bug%20AND%20status%20in%20%28Closed%2C%20Resolved%29%20AND%20resolution%20%3D%20Fixed%20AND%20fixVersion%20in%20%2816.04%29%20AND%20component%20%3D%20%22Thin%20Core%20Library%22%20ORDER%20BY%20key%20ASC Known Issues in Version 16.04 ----------------------------- ASACORE-2053 AJ_NVRAM_Read can read beyond the item's capacity ASACORE-2589 When introspecting object path /org/alljoyn/Bus/Security, the introspection xml returned by TCL and SCL differ. ASACORE-2623 Access to secure bus object fails after RN disconnect/reconnect For a complete list of open issues: https://jira.allseenalliance.org/issues/?jql=project%20%3D%20%22Core%20SW%22%20AND%20%28component%20in%20%28%22Thin%20Core%20Library%22%2C%20SCONS%29%20OR%20component%20is%20EMPTY%29%20AND%20%28status%20%3D%20closed%20AND%20resolution%20%3D%20Postponed%20OR%20status%20not%20in%20%28closed%2C%20resolved%29%20AND%20issuetype%20%3D%20Bug%29%20ORDER%20BY%20Severity%20DESC%2C%20priority%20DESC%2C%20id%20ASC Compatibility ------------- Starting in Version 16.04 * The AJ_Connect() API has been removed (was DEPRECATED since 14.02) More details on these changes can be found on the release plan page: https://wiki.allseenalliance.org/core/core_16.04_release_plan#compatibility_with_previous_releases For details of previous releases/release families please see the release notes: 15.09: https://git.allseenalliance.org/cgit/core/ajtcl.git/tree/ReleaseNotes.txt?h=RB15.09 15.04: https://git.allseenalliance.org/cgit/core/ajtcl.git/tree/ReleaseNotes.txt?h=RB15.04 14.12: https://git.allseenalliance.org/cgit/core/ajtcl.git/tree/ReleaseNotes.txt?h=RB14.12 14.06: https://git.allseenalliance.org/cgit/core/ajtcl.git/tree/ReleaseNotes.txt?h=RB14.06 Change history -------------- 16.04 - Bug fixes, ECDHE_SPEKE 15.09a - Bug fixes: ASACORE-2554, ASACORE-2560, ASACORE-2580, ASACORE-2582, ASACORE-2593, ASACORE-2596, ASACORE-2612, ASACORE-2619, ASACORE-2622, ASACORE-2630, ASACORE-2631 15.09 - Bug fixes, Security2.0 feature, Productization of TC <-> RN ARDP/UDP feature, reorganization of code and build, support for asynchronous method replies 15.04b - Critical bug fixes: ASACORE-2045, ASACORE-2247, ASACORE-2248, ASACORE-2294, ASACORE-2299, ASACORE-2332, ASACORE-2365 15.04a - Critical bug fixes: ASACORE-1948, ASACORE-1949, ASACORE-1952, ASACORE-2008 15.04 - Bug fixes, new features listed above. 14.12 - Bug fixes, major improvements to address scalability, new features listed above. 14.06a - Critical bug fixes: ASACORE-800, ASACORE-805, ASACORE-908, ASACORE-912, ASACORE-924 and ASACORE-943. 14.06 - Bug fixes, scalability and stability support, several features listed in release notes: https://git.allseenalliance.org/cgit/core/ajtcl.git/tree/ReleaseNotes.txt?id=v14.06 ajtcl-16.04/SConscript.target.arduino000066400000000000000000000040321271074662300175670ustar00rootroot00000000000000Import('env') # Arduino does not build binaries; just sets up for inclusion in Arduino IDE env['build'] = False arduinoLibDir = '#dist/arduino_due/libraries/AllJoyn/' # Install the .c files as .cpp files for the Arduino IDE to consume. srcs = [ Glob('src/*.c'), Glob('src/target/$TARG/*.c'), Glob('src/crypto/*.c'), Glob('external/sha2/*.c') ] env.InstallAs([ File(arduinoLibDir + f.name.replace('.c' , '.cpp')) for f in srcs ], srcs) # Install the related header files as well. hdrs = [ Glob('inc/ajtcl/*.h'), Glob('src/*.h'), Glob('src/target/$TARG/*.h'), Glob('src/crypto/*.h'), Glob('external/sha2/*.h') ] env.Install(arduinoLibDir + 'ajtcl', hdrs) # Install the Arduino specific examples into their source env.Install(Dir(arduinoLibDir).abspath, Dir('src/target/arduino/examples/')) # Install the generic .c sample and test programs from the sample and # test directories into their destination while changing the # extension. # Install the test programs tests = [ 'svclite', 'clientlite', 'siglite', 'bastress2', 'mutter', 'sessions', 'aestest' ] for test in tests: tdir = arduinoLibDir + 'tests/AJ_' + test env.Install(tdir, 'src/target/arduino/tests/AJ_' + test + '/AJ_' + test + '.ino') env.InstallAs(tdir + '/' + test + '.cpp', 'test/' + test + '.c') # Install basic samples basicsamples = [ 'basic_service', 'basic_client', 'signal_service', 'signalConsumer_client' ] for sample in basicsamples: sdir = arduinoLibDir + 'samples/AJ_' + sample env.Install(sdir, 'src/target/arduino/samples/AJ_' + sample + '/AJ_' + sample + '.ino') env.InstallAs(sdir + '/' + sample + '.cpp', 'samples/basic/' + sample + '.c') # Install secure samples securesamples = [ 'SecureClient', 'SecureService' ] for sample in securesamples: sdir = arduinoLibDir + 'samples/AJ_' + sample env.Install(sdir, 'src/target/arduino/samples/AJ_' + sample + '/AJ_' + sample + '.ino') env.InstallAs(sdir + '/' + sample + '.cpp', 'samples/secure/' + sample + '.c') ajtcl-16.04/SConscript.target.darwin000066400000000000000000000042201271074662300174110ustar00rootroot00000000000000import os Import('env') # Target specific SCons command line variables vars = Variables() vars.Add(BoolVariable('FORCE32', 'Force building 32 bit on 64 bit architecture', os.environ.get('AJ_FORCE32', False))) vars.Add(BoolVariable('NO_AUTH', "Compile in authentication mechanism's to the code base", os.environ.get('AJ_NO_AUTH', False))) vars.Update(env) Help(vars.GenerateHelpText(env)) # Platform libraries env.Append(LIBS = ['pthread']) # Cross compile setup if os.environ.has_key('CROSS_PREFIX'): cc = env['CC'] cxx = env['CXX'] ar = env['AR'] ranlib = env['RANLIB'] env.Replace(CC = os.environ['CROSS_PREFIX'] + cc) env.Replace(CXX = os.environ['CROSS_PREFIX'] + cxx) env.Replace(LINK = os.environ['CROSS_PREFIX'] + cc) env.Replace(AR = os.environ['CROSS_PREFIX'] + ar) env.Replace(RANLIB = os.environ['CROSS_PREFIX'] + ranlib) env['ENV']['STAGING_DIR'] = os.environ.get('STAGING_DIR', '') if os.environ.has_key('CROSS_PATH'): env['ENV']['PATH'] = ':'.join([ os.environ['CROSS_PATH'], env['ENV']['PATH'] ] ) if os.environ.has_key('CROSS_CFLAGS'): env.Append(CFLAGS=os.environ['CROSS_CFLAGS'].split()) if os.environ.has_key('CROSS_LINKFLAGS'): env.Append(LINKFLAGS=os.environ['CROSS_LINKFLAGS'].split()) # Compiler flags env.Append(CFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing', '-Wall', '-Waggregate-return', '-Wbad-function-cast', '-Wcast-align', '-Wfloat-equal', '-Wformat=2', '-Wno-deprecated-declarations', '-Wno-unknown-pragmas', '-Wpacked', '-Wpointer-arith', '-Wshadow', '-Wundef', '-Wwrite-strings' ]) if env['FORCE32']: env.Append(CFLAGS = '-m32') env.Append(LINKFLAGS = '-m32') env.Append(CPPDEFINES = [ 'AJ_MAIN' ]) if env['NO_AUTH']: env.Append(CPPDEFINES = [ 'TEST_DISABLE_SECURITY' ]) # Debug/Release Variants if env['VARIANT'] == 'debug': env.Append(CFLAGS = '-g') else: env.Append(CFLAGS = '-Os') #env['build_shared'] = True #env['connectivity_options'] = [ 'tcp', 'ardp' ] # Large Memory Platform env.Append(CPPDEFINES = ['AJ_NVRAM_SIZE=64000']) env.Append(CPPDEFINES = ['AJ_NUM_REPLY_CONTEXTS=8']) ajtcl-16.04/SConscript.target.freertos-due000066400000000000000000000147531271074662300205450ustar00rootroot00000000000000import os Import('env') # Target specific SCons command line variables vars = Variables() vars.Add(BoolVariable('AJWSL', 'Compile driver for the QCA4004 for a specific platform', os.environ.get('AJ_AJWSL', True))) vars.Add(PathVariable('ATMEL_DIR', 'Directory for ATMEL source code', os.environ.get('AJ_ATMEL_DIR'), PathVariable.PathIsDir)) vars.Add(PathVariable('FREE_RTOS_DIR', 'Directory to FreeRTOS source code', os.environ.get('AJ_FREE_RTOS_DIR'), PathVariable.PathIsDir)) vars.Add(PathVariable('ARM_TOOLCHAIN_DIR', 'Path to the GNU ARM toolchain bin folder', os.environ.get('AJ_ARM_TOOLCHAIN_DIR'), PathVariable.PathIsDir)) vars.Update(env) Help(vars.GenerateHelpText(env)) # Disable building unit tests env['build_unit_tests'] = False # Update environment if env.has_key('ARM_TOOLCHAIN_DIR'): env['ENV']['PATH'] = ';'.join([ env['ENV']['PATH'], env['ARM_TOOLCHAIN_DIR'] ]) # Cross compile setup cross_prefix = 'arm-none-eabi-' env.Replace(CC = cross_prefix + 'gcc') env.Replace(CXX = cross_prefix + 'g++') env.Replace(LINK = cross_prefix + 'gcc') env.Replace(AR = cross_prefix + 'ar') env.Replace(RANLIB = cross_prefix + 'ranlib') env.Replace(CCCOM = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES') env.Replace(CPPDEFPREFIX = '-D') env.Replace(OBJSUFFIX = '.o') env.Replace(INCPREFIX = '-I') env.Replace(LIBPREFIX = 'lib') env.Replace(LIBSUFFIX = '.a') env.Replace(PROGPREFIX = '') env.Replace(PROGSUFFIX = '.elf') env.Replace(LIBDIRPREFIX = '-L') env.Replace(LIBDIRSUFFIX = '') env.Replace(LIBLINKPREFIX = '-l') env.Replace(LIBLINKSUFFIX = '') env.Replace(LINKCOM = '$LINK $PRELINKFLAGS $LINKSCRIPT $LIBPATHS -o $TARGET $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $LINKFLAGS') env.Replace(LINKFLAGS = '') env.Replace(CCFLAGS = '') env.Replace(ARFLAGS = 'rc') env.Replace(ARCOM = '$AR $ARFLAGS $TARGET $SOURCES') # This was done because scons creates a link file to feed into the linker # and arm-none-eabi removes '\' when interpreting a linker file. This # prevents scons from creating a link file and just feeding the command line # options directly to the compiler/linker env['MAXLINELENGTH'] = 10000 # Platform libraries env.Append(LIBS = ['c']) # Compiler flags env.Append(CFLAGS = [ '-std=gnu99', '-pipe', '-mcpu=cortex-m3', '-mthumb', '-mlong-calls', '-fdata-sections', '-ffunction-sections', '-fno-strict-aliasing', '-Wall', '-Waggregate-return', '-Wbad-function-cast', '-Wcast-align', '-Wfloat-equal', '-Wformat=2', '-Wno-deprecated-declarations', '-Wno-unknown-pragmas', '-Wpacked', '-Wpointer-arith', '-Wshadow', '-Wundef', '-Wformat-security', '-Werror=format-security', '-Wwrite-strings' ]) # Pre-processor directives env.Append(CPPDEFINES = { '__SAM3X8E__': None, 'ARM_MATH_CM3': 'true', 'BOARD': 'ARDUINO_DUE_X', 'printf': 'iprintf', '_FORTIFY_SOURCE': '1' }) # Linker flags env.Append(LINKFLAGS = [ '-mcpu=cortex-m3', '-mthumb', '-Wl,--gc-sections', '-Wl,-Map,${TARGET.base}.map', '-Wl,--entry=Reset_Handler', ]) env.Replace(LINKSCRIPT = '-T$ATMEL_DIR/sam/utils/linker_scripts/sam3x/sam3x8/gcc/flash.ld') # Path to libajtcl.a and standard C libraries env.Append(LIBPATH = ['$ATMEL_DIR/thirdparty/CMSIS/Lib/GCC']) # Add in extra non standard include files env.Install('#dist/include/ajtcl', Glob('src/wsl/*.h')) env.Install('#dist/include/ajtcl', Glob('src/target/freertos-due/*.h')) env.Install('#dist/include/ajtcl', Glob('src/freertos/*.h')) env.Install('#dist/include/ajtcl', Glob('src/bsp/*.h')) # The Atmel software pack requires that you provide "conf_uart_serial.h" as a # configurable header file. Install that file to '#dist/include' where it will # be found via the normal -I flags test SCons files use. env.Install('#dist/include', Glob('src/target/freertos-due/atmel/conf_uart_serial.h')) # ATMEL include paths env.Append(CPPPATH = Dir([ 'src/bsp', env['FREE_RTOS_DIR'] + '/Source/include', env['FREE_RTOS_DIR'] + '/Source/portable/GCC/ARM_CM3', env['ATMEL_DIR'] + '/common/boards', env['ATMEL_DIR'] + '/common/services/clock', env['ATMEL_DIR'] + '/common/services/clock/sam3x', env['ATMEL_DIR'] + '/common/services/gpio', env['ATMEL_DIR'] + '/common/services/ioport', env['ATMEL_DIR'] + '/common/services/freertos/sam', env['ATMEL_DIR'] + '/common/services/serial/sam_uart', env['ATMEL_DIR'] + '/common/services/serial', env['ATMEL_DIR'] + '/common/services/spi', env['ATMEL_DIR'] + '/common/services/sam_spi', env['ATMEL_DIR'] + '/common/services/spi/sam_spi/module_config', env['ATMEL_DIR'] + '/common/utils', env['ATMEL_DIR'] + '/common/utils/stdio/stdio_serial', env['ATMEL_DIR'] + '/common/drivers/nvm', env['ATMEL_DIR'] + '/common/nvm/sam/module_config', env['ATMEL_DIR'] + '/sam/boards', env['ATMEL_DIR'] + '/sam/boards/arduino_due_x', env['ATMEL_DIR'] + '/sam/drivers/pio', env['ATMEL_DIR'] + '/sam/drivers/pmc', env['ATMEL_DIR'] + '/sam/drivers/tc', env['ATMEL_DIR'] + '/sam/drivers/trng', env['ATMEL_DIR'] + '/sam/drivers/pdc', env['ATMEL_DIR'] + '/sam/drivers/uart', env['ATMEL_DIR'] + '/sam/drivers/usart', env['ATMEL_DIR'] + '/sam/drivers/spi', env['ATMEL_DIR'] + '/sam/drivers/efc', env['ATMEL_DIR'] + '/sam/drivers/dmac', env['ATMEL_DIR'] + '/sam/drivers/rstc', env['ATMEL_DIR'] + '/sam/utils', env['ATMEL_DIR'] + '/sam/utils/cmsis/sam3x/include', env['ATMEL_DIR'] + '/sam/utils/cmsis/sam3x/source/templates', env['ATMEL_DIR'] + '/sam/utils/cmsis/sam3x/include/component', env['ATMEL_DIR'] + '/sam/utils/header_files', env['ATMEL_DIR'] + '/sam/utils/preprocessor', env['ATMEL_DIR'] + '/sam/services/flash_efc', env['ATMEL_DIR'] + '/thirdparty/CMSIS/Include', env['ATMEL_DIR'] + '/thirdparty/CMSIS/Lib/GCC', env['ATMEL_DIR'] + '/sam/boards/arduino_due_x/board_config', env['ATMEL_DIR'] + '/config', env['ATMEL_DIR'] + '/common/services/clock/sam3x/module_config', env['ATMEL_DIR'] + '/common/services/clock/sam3x', env['ATMEL_DIR'] + '/thirdparty/freertos/freertos-7.3.0/module_config' ])) # Debug/Release Variants if env['VARIANT'] == 'debug': env.Append(CFLAGS = '-g3') else: env.Append(CFLAGS = '-Os') env.Append(LINKFLAGS = '-s') env['build_shared'] = False #env['connectivity_options'] = [ 'tcp', 'ardp' ] ajtcl-16.04/SConscript.target.freertos-stm32000066400000000000000000000115301271074662300207260ustar00rootroot00000000000000import os Import('env') # Target specific SCons command line variables vars = Variables() vars.Add(BoolVariable('AJWSL', 'Compile driver for the QCA4004 for a specific platform', os.environ.get('AJ_AJWSL', True))) vars.Add(PathVariable('STM_SRC_DIR', 'Path to the source code for the STM32 microcontroller', os.environ.get('AJ_STM_SRC_DIR'), PathVariable.PathIsDir)) vars.Add(PathVariable('ARM_TOOLCHAIN_DIR', 'Path to the ARM Toolchain', os.environ.get('AJ_ARM_TOOLCHAIN_DIR'), PathVariable.PathIsDir)) vars.Add(PathVariable('FREE_RTOS_DIR', 'Directory to FreeRTOS source code', os.environ.get('AJ_FREE_RTOS_DIR'), PathVariable.PathIsDir)) vars.Update(env) Help(vars.GenerateHelpText(env)) # Disable building unit tests env['build_unit_tests'] = False # Update environment if env.has_key('ARM_TOOLCHAIN_DIR'): env['ENV']['PATH'] = ';'.join([ env['ENV']['PATH'], env['ARM_TOOLCHAIN_DIR'] ]) # Cross compile setup cross_prefix = 'arm-none-eabi-' env.Replace(CC = cross_prefix + 'gcc') env.Replace(CXX = cross_prefix + 'g++') env.Replace(LINK = cross_prefix + 'gcc') env.Replace(AR = cross_prefix + 'ar') env.Replace(RANLIB = cross_prefix + 'ranlib') env.Replace(CCCOM = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES') env.Replace(CPPDEFPREFIX = '-D') env.Replace(OBJSUFFIX = '.o') env.Replace(INCPREFIX = '-I') env.Replace(LIBDIRPREFIX = '-L') env.Replace(LIBPREFIX = 'lib') env.Replace(LIBSUFFIX = '.a') env.Replace(PROGPREFIX = '') env.Replace(PROGSUFFIX = '.elf') env.Replace(LIBDIRSUFFIX = '') env.Replace(LIBLINKPREFIX = '-l') env.Replace(LIBLINKSUFFIX = '') env.Replace(LINKCOM = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS') env.Replace(LINKFLAGS = '') env.Replace(CCFLAGS = '') env.Replace(ARFLAGS = 'rc') env.Replace(ARCOM = '$AR $ARFLAGS $TARGET $SOURCES') env.Replace(ASCOM = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES') # This was done because scons creates a link file to feed into the linker # and arm-none-eabi removes '\' when interpreting a linker file. This # prevents scons from creating a link file and just feeding the command line # options directly to the compiler/linker env['MAXLINELENGTH'] = 10000 # Compiler flags env.Append(CFLAGS = [ '-std=gnu99', '-pipe', '-mcpu=cortex-m3', '-mthumb', '-mlong-calls', '-fdata-sections', '-ffunction-sections', '-fno-strict-aliasing', '-Wall', '-Waggregate-return', '-Wbad-function-cast', '-Wcast-align', '-Wfloat-equal', '-Wformat=2', '-Wno-deprecated-declarations', '-Wno-unknown-pragmas', '-Wpacked', '-Wpointer-arith', '-Wshadow', '-Wundef', '-Wformat-security', '-Werror=format-security', '-Wwrite-strings' ]) env.Append(CPPDEFINES = { 'STM32F407xx' : None, 'USE_STDPERIPH_DRIVER' : None, 'HAL_UART_MODULE_ENABLED' : None, 'HAL_RCC_MODULE_ENABLED' : None, 'HAL_GPIO_MODULE_ENABLED' : None, 'HAL_USART_MODULE_ENABLED': None, 'HAL_FLASH_MODULE_ENABLED': None, '_FORTIFY_SOURCE': '1' }) # Linker flags env.Append(LINKFLAGS = [ '-mthumb', '-Wl,--start-group', '-lm', '-lc', '-Wl,--end-group', '-Wl,--gc-sections', '-Wl,-Map,${TARGET.base}.map', '-mcpu=cortex-m3', '-T' + env['STM_SRC_DIR'] + 'Project/Peripheral_Examples/SysTick/TrueSTUDIO/SysTick/stm32_flash.ld', '-Wl,--entry=Reset_Handler' ]) # Add in extra non standard include files env.Install('#dist/include/ajtcl', Glob('src/wsl/*.h')) env.Install('#dist/include/ajtcl', Glob('src/target/freertos-stm32/*.h')) env.Install('#dist/include/ajtcl', Glob('src/freertos/*.h')) env.Install('#dist/include/ajtcl', Glob('src/bsp/*.h')) # The STM32 software pack requires that you provide "stm32f4xx_conf.h" as a # configurable header file. Install that file to '#dist/include' where it will # be found via the normal -I flags test SCons files use. env.Install('#dist/include', Glob('src/target/freertos-stm32/stm32/*.h')) env.Append(CPPPATH = Dir(['src/bsp'])) env.Append(CPPPATH = Dir([env['FREE_RTOS_DIR'] + '/Source/include', env['FREE_RTOS_DIR'] + '/Source/portable/GCC/ARM_CM3', env['STM_SRC_DIR'] + 'Utilities/STM32F4-Discovery', env['STM_SRC_DIR'] + 'Libraries/CMSIS/ST/STM32F4xx/Include', env['STM_SRC_DIR'] + 'Libraries/CMSIS/Include', env['STM_SRC_DIR'] + 'Libraries/STM32F4xx_StdPeriph_Driver/inc'])) # Debug/Release Variants if env['VARIANT'] == 'debug': env.Append(CFLAGS = '-g3') else: env.Append(CFLAGS = '-Os') env.Append(LINKFLAGS = '-s') env['build_shared'] = False #env['connectivity_options'] = [ 'tcp', 'ardp' ] ajtcl-16.04/SConscript.target.linux000066400000000000000000000043621271074662300172730ustar00rootroot00000000000000import os Import('env') # Target specific SCons command line variables vars = Variables() vars.Add(BoolVariable('FORCE32', 'Force building 32 bit on 64 bit architecture', os.environ.get('AJ_FORCE32', False))) vars.Add(BoolVariable('NO_AUTH', "Compile in authentication mechanism's to the code base", os.environ.get('AJ_NO_AUTH', False))) vars.Update(env) Help(vars.GenerateHelpText(env)) # Platform libraries env.Append(LIBS = ['rt', 'pthread']) # Cross compile setup if os.environ.has_key('CROSS_PREFIX'): cc = env['CC'] cxx = env['CXX'] ar = env['AR'] ranlib = env['RANLIB'] env.Replace(CC = os.environ['CROSS_PREFIX'] + cc) env.Replace(CXX = os.environ['CROSS_PREFIX'] + cxx) env.Replace(LINK = os.environ['CROSS_PREFIX'] + cc) env.Replace(AR = os.environ['CROSS_PREFIX'] + ar) env.Replace(RANLIB = os.environ['CROSS_PREFIX'] + ranlib) env['ENV']['STAGING_DIR'] = os.environ.get('STAGING_DIR', '') if os.environ.has_key('CROSS_PATH'): env['ENV']['PATH'] = ':'.join([ os.environ['CROSS_PATH'], env['ENV']['PATH'] ] ) if os.environ.has_key('CROSS_CFLAGS'): env.Append(CFLAGS=os.environ['CROSS_CFLAGS'].split()) if os.environ.has_key('CROSS_LINKFLAGS'): env.Append(LINKFLAGS=os.environ['CROSS_LINKFLAGS'].split()) # Compiler flags env.Append(CFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing', '-Wall', '-Waggregate-return', '-Wbad-function-cast', '-Wcast-align', '-Wfloat-equal', '-Wformat=2', '-Wno-deprecated-declarations', '-Wno-unknown-pragmas', '-Wpacked', '-Wpointer-arith', '-Wshadow', '-Wundef', '-Wformat-security', '-Werror=format-security', '-Wwrite-strings' ]) if env['FORCE32']: env.Append(CFLAGS = '-m32') env.Append(LINKFLAGS = '-m32') env.Append(CPPDEFINES = [ 'AJ_MAIN' ]) if env['NO_AUTH']: env.Append(CPPDEFINES = [ 'TEST_DISABLE_SECURITY' ]) # Debug/Release Variants if env['VARIANT'] == 'debug': env.Append(CFLAGS = '-g') else: env.Append(CFLAGS = '-Os') env.Append(LINKFLAGS = '-s') env['build_shared'] = True env['connectivity_options'] = [ 'tcp', 'ardp' ] # Large Memory Platform env.Append(CPPDEFINES = ['AJ_NVRAM_SIZE=64000']) env.Append(CPPDEFINES = ['AJ_NUM_REPLY_CONTEXTS=8']) ajtcl-16.04/SConscript.target.mbedrtos-frdm000066400000000000000000000260561271074662300207050ustar00rootroot00000000000000import os Import('env') # Target specific SCons command line variables vars = Variables() vars.Add(PathVariable('MBED_DIR', 'Path to the mbed source code repository', os.environ.get('AJ_MBED_DIR'), PathVariable)) vars.Add(PathVariable('ARM_TOOLCHAIN_DIR', 'Path to the GNU ARM toolchain bin folder', os.environ.get('AJ_ARM_TOOLCHAIN_DIR'), PathVariable.PathIsDir)) vars.Update(env) Help(vars.GenerateHelpText(env)) # Disable building unit tests env['build_unit_tests'] = False # Update environment if env.has_key('ARM_TOOLCHAIN_DIR'): env['ENV']['PATH'] = ';'.join([ env['ENV']['PATH'], env['ARM_TOOLCHAIN_DIR'] ]) # Cross compile setup cross_prefix = 'arm-none-eabi-' env.Replace(CC = cross_prefix + 'gcc') env.Replace(CXX = cross_prefix + 'g++') env.Replace(LINK = cross_prefix + 'gcc') env.Replace(AR = cross_prefix + 'ar') env.Replace(RANLIB = cross_prefix + 'ranlib') env.Replace(CCCOM = '$CC $CFLAGS $CCFLAGS $_CCCOMCOM -o $TARGET $SOURCES') env.Replace(CXXCOM = '$CXX $CFLAGS $CCFLAGS $CXXFLAGS $_CCCOMCOM -o $TARGET $SOURCES') env.Replace(CPPDEFPREFIX = '-D') env.Replace(OBJSUFFIX = '.o') env.Replace(INCPREFIX = '-I') env.Replace(LIBPREFIX = 'lib') env.Replace(LIBSUFFIX = '.a') env.Replace(PROGPREFIX = '') env.Replace(PROGSUFFIX = '.elf') env.Replace(LIBDIRPREFIX = '-L') env.Replace(LIBDIRSUFFIX = '') env.Replace(LIBLINKPREFIX = '-l') env.Replace(LIBLINKSUFFIX = '') env.Replace(LINKCOM = '$LINK $PRELINKFLAGS $LINKSCRIPT $LIBPATHS -o $TARGET $__RPATH $SOURCES $system_objects $_LIBDIRFLAGS $_LIBFLAGS $LINKFLAGS') env.Replace(CCFLAGS = '') env.Replace(CXXFLAGS = '') env.Replace(CPPFLAGS = '') env.Replace(ASFLAGS = '') env.Replace(ASPPCOM = '$AS') env.Replace(ARFLAGS = 'rc') env.Replace(ARCOM = '$AR $ARFLAGS $TARGET $SOURCES') env.Replace(ASCOM = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES') # This was done because scons creates a link file to feed into the linker # and arm-none-eabi removes '\' when interpreting a linker file. This # prevents scons from creating a link file and just feeding the command line # options directly to the compiler/linker env['MAXLINELENGTH'] = 10000 # Compiler flags env.Append(CXXFLAGS = ['-std=gnu++98', '-fno-rtti']) env.Append(CCFLAGS = ['-mcpu=cortex-m4', '-mthumb', '-mfpu=fpv4-sp-d16', '-c', '-g', '-fno-common', '-fmessage-length=0', '-Wall', '-fno-exceptions', '-ffunction-sections', '-Wformat-security', '-Werror=format-security', '-fdata-sections']) env.Append(PRELINKFLAGS = ['-mcpu=cortex-m4', '-mthumb', '-Wl,--gc-sections', '--specs=nano.specs', '-u', '_printf_float', '-u', '_scanf_float']) env.Append(LINKSCRIPT = ['-T' + env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/K64FN1M0xxx12.ld']) env.Append(LIBPATHS = ['-L' + env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM']) env.Replace(LINKFLAGS = ['-Wl,-Map,${TARGET.base}.map']) env.Prepend(_LIBFLAGS = ['-Wl,-start-group']) env.Append(_LIBFLAGS = ['-Wl,-end-group']) env.Append(LIBS = ['mbed', 'stdc++', 'gcc', 'm', 'c']) # Pre-processor directives env.Append(CPPDEFINES = {'TARGET_K64F' : None, 'TARGET_M4' : None, 'TARGET_Freescale' : None, 'TARGET_KPSDK_MCUS': None, 'TARGET_KPSDK_CODE': None, 'TARGET_MCU_K64F' : None, 'TARGET_FRDM' : None, 'TOOLCHAIN_GCC_ARM': None, 'TOOLCHAIN_GCC' : None, '__CORTEX_M4' : None, 'ARM_MATH_CM4' : None, '__FPU_PRESENT' : '1', 'MBED_BUILD_TIMESTAMP': '0.0', '__MBED__' : '1', 'CPU_MK64FN1M0VMD12': None, 'FSL_RTOS_MBED' : None, 'TARGET_FF_ARDUINO': None, '__CORTEX_M4' : None, 'FSL_RTOS_MBED' : None, '_FORTIFY_SOURCE' : '1' }) # Linker flags env.Append(LINKFLAGS = [ '-mcpu=cortex-m3', '-mthumb', '-Wl,--gc-sections', '-Wl,-Map,${TARGET.base}.map', '-Wl,--entry=Reset_Handler', ]) env.Append(CPPPATH = [env['MBED_DIR'] + '/mbed-rtos', env['MBED_DIR'] + '/mbed-rtos/rtx', env['MBED_DIR'] + '/mbed-rtos/rtx/TARGET_M4', env['MBED_DIR'] + '/mbed-rtos/rtx/TARGET_M4/TOOLCHAIN_GCC', env['MBED_DIR'] + '/mbed-rtos/rtos', env['MBED_DIR'] + '/SDFileSystem', env['MBED_DIR'] + '/FATFileSystem', env['MBED_DIR'] + '/FATFileSystem/ChaN', env['MBED_DIR'] + '/mbed', env['MBED_DIR'] + '/mbed/TARGET_K64F', env['MBED_DIR'] + '/mbed/TARGET_K64F_Freescale', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/can', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/edma', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/sdhc', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/pit', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/flextimer', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/smc', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/uart', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/pmc', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/mcg', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/port', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/wdog', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/adc', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/osc', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/enet', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/i2c', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/gpio', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/rtc', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/dmamux', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/sim', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/sai', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/dspi', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/utilities', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/drivers', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/drivers/pit', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/drivers/clock', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/drivers/clock/src', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/drivers/enet', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/drivers/interrupt', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/common', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/common/phyksz8081', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_MCU_K64F', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_MCU_K64F/device', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_MCU_K64F/device/MK64F12', env['MBED_DIR'] + '/mbed/TARGET_K64F/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_MCU_K64F/TARGET_FRDM', env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM']) # Pre-compiled object files for the K64F env['system_objects'] = [env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/startup_MK64F12.o', env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/cmsis_nvic.o', env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/system_MK64F12.o', env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/mbed_overrides.o', env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/board.o', env['MBED_DIR'] + '/mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/retarget.o'] env.Install('#dist/include/ajtcl', Glob('src/target/mbedrtos-frdm/*.h')) env.Install('#dist/include/ajtcl', Glob('src/mbedrtos/*.h')) env.Install('#dist/include/ajtcl', Glob('src/wsl/*.h')) env.Install('#dist/include/ajtcl', Glob('src/bsp/*.h')) # Debug/Release Variants if env['VARIANT'] == 'debug': env.Append(CFLAGS = '-g3') else: env.Append(CFLAGS = '-Os') env.Append(LINKFLAGS = '-s') env['build_shared'] = False #env['connectivity_options'] = [ 'tcp', 'ardp' ] ajtcl-16.04/SConscript.target.win32000066400000000000000000000035531271074662300170770ustar00rootroot00000000000000import os import platform Import('env') default_target_os = 'win7' allowed_target_oss = ('win7', 'win10') # Target specific SCons command line variables default_msvc_version = os.environ.get('AJ_MSVC_VERSION', '12.0') supported_msvc_versions = [ '8.0', '9.0', '10.0', '11.0', '11.0Exp', '12.0', '12.0Exp', '14.0', '14.0Exp' ] vars = Variables() vars.Add(EnumVariable('OS', 'Target OS', default_target_os, allowed_values = allowed_target_oss)) vars.Add(EnumVariable('MSVC_VERSION', 'MSVC compiler version - Windows', default_msvc_version, allowed_values = supported_msvc_versions)) vars.Add(BoolVariable('NO_AUTH', "Compile in authentication mechanism's to the code base", os.environ.get('AJ_NO_AUTH', False))) vars.Update(env) Help(vars.GenerateHelpText(env)) # Platform libraries env.Append(LIBS = ['advapi32']) # Compiler flags env.Append(CFLAGS = ['/J', '/W3', '/nologo']) env.Append(CPPDEFINES = ['_CRT_SECURE_NO_WARNINGS', 'AJ_MAIN']) if env['NO_AUTH']: env.Append(CPPDEFINES = ['TEST_DISABLE_SECURITY']) # Debug/Release Variants if env['VARIANT'] == 'debug': env.Append(CFLAGS = ['/Zi', '/Od', '/MDd']) env.Append(CPPDEFINES = ['_DEBUG']) env.Append(LINKFLAGS = ['/debug']) else: env.Append(CFLAGS = ['/Gy', '/O1', '/GF', '/MD']) env.Append(LINKFLAGS = ['/opt:ref', '/NODEFAULTLIB:libcmt.lib']) env['connectivity_options'] = ['tcp', 'ardp'] # Support running on Win7 and newer Windows versions. env.Append(CPPDEFINES = [('_WIN32_WINNT', '_WIN32_WINNT_WIN7')]) # This is needed in order to build with Scons and Visual Studio multiple targets # in parallel using the -j option. See alljoyn\build_core\conf\windows\SConscript. env['CCPDBFLAGS'] = '/Z7' env['PDB'] = '${TARGET.base}.pdb' env.Append(LINKFLAGS=['/PDB:${TARGET.base}.pdb']) # Large Memory Platform env.Append(CPPDEFINES = ['AJ_NVRAM_SIZE=64000']) env.Append(CPPDEFINES = ['AJ_NUM_REPLY_CONTEXTS=8']) ajtcl-16.04/SConstruct000066400000000000000000000232621271074662300146700ustar00rootroot00000000000000import os import platform import re ####################################################### # Custom Configure functions ####################################################### def CheckCommand(context, cmd): context.Message('Checking for %s command...' % cmd) r = WhereIs(cmd) context.Result(r is not None) return r def CheckAJLib(context, ajlib, ajheader, sconsvarname, ajdistpath): prog = "#include <%s>\nint main(void) { return 0; }" % ajheader context.Message('Checking for AllJoyn library %s...' % ajlib) prevLIBS = context.env['LIBS'] prevLIBPATH = context.env.get('LIBPATH', []) prevCPPPATH = context.env.get('CPPPATH', []) # Check if library is in standard system locations context.env.Append(LIBS = ajlib) defpath = '' # default path is a system directory if not context.TryLink(prog, '.c'): # Check if library is in project default location context.env.Append(LIBPATH = ajdistpath + '/lib', CPPPATH = ajdistpath + '/include') if context.TryLink(prog, '.c'): defpath = ajdistpath # default path is the dist directory # Remove project default location from LIBPATH and CPPPATH context.env.Replace(LIBPATH = prevLIBPATH, CPPPATH = prevCPPPATH) vars = Variables() vars.Add(PathVariable(sconsvarname, 'Path to %s dist directory' % ajlib, os.environ.get('AJ_%s' % sconsvarname, defpath), lambda k, v, e : v == '' or PathVariable.PathIsDir(k, v, e))) vars.Update(context.env) Help(vars.GenerateHelpText(context.env)) # Get the actual library path to use ('' == system path, may be same as ajdistpath) libpath = env.get(sconsvarname, '') if libpath is not '': libpath = str(context.env.Dir(libpath)) # Add the user specified (or ajdistpath) to LIBPATH and CPPPATH context.env.Append(LIBPATH = libpath + '/lib', CPPPATH = libpath + '/include') # The real test for the library r = context.TryLink(prog, '.c') if not r: context.env.Replace(LIBS = prevLIBS, LIBPATH = prevLIBPATH, CPPPATH = prevCPPPATH) context.Result(r) return r ####################################################### # Default target platform ####################################################### if platform.system() == 'Linux': default_target = 'linux' elif platform.system() == 'Windows': default_target = 'win32' elif platform.system() == 'Darwin': default_target = 'darwin' ####################################################### # Build variables ####################################################### debug_restrict_options = ( '0', 'AJ_DEBUG_OFF', '1', 'AJ_DEBUG_ERROR', '2', 'AJ_DEBUG_WARN', '3', 'AJ_DEBUG_INFO', '4', 'AJ_DEBUG_DUMP', '5', 'AJ_DEBUG_ALL' ) target_options = [ t.split('.')[-1] for t in os.listdir('.') if re.match('^SConscript\.target\.[-_0-9A-Za-z]+$', t) ] vars = Variables() vars.Add(BoolVariable('V', 'Build verbosity', False)) vars.Add(EnumVariable('TARG', 'Target platform variant', os.environ.get('AJ_TARG', default_target), allowed_values = target_options)) vars.Add(EnumVariable('VARIANT', 'Build variant', os.environ.get('AJ_VARIANT', 'debug'), allowed_values = ('debug', 'release'))) vars.Add(EnumVariable('DEBUG_RESTRICT', 'Set compiled in debug level', os.environ.get('AJ_DEBUG_RESTRICT'), allowed_values = debug_restrict_options)) vars.Add('CC', 'C Compiler override') vars.Add('CXX', 'C++ Compiler override') vars.Add(EnumVariable('NDEBUG', 'Override NDEBUG default for release variant', 'defined', allowed_values=('defined', 'undefined'))) if platform.system() != 'Windows': env = Environment(variables = vars) else: if platform.machine() != 'AMD64': target_arch = 'x86' else: environment_force32 = os.environ.get('AJ_FORCE32', False) vars.Add(BoolVariable('FORCE32', 'Force building 32 bit on 64 bit architecture', environment_force32)) if environment_force32: default_force32 = 'true' else: default_force32 = 'false' force32 = ARGUMENTS.get('FORCE32', default_force32) force32 = force32.lower() if force32 == 'true' or force32 == 'yes' or force32 == '1': target_arch = 'x86' else: target_arch = 'x86_64' # Target CPU architecture must be specified here for Windows - otherwise platform.machine() is always used as the target! env = Environment(variables = vars, TARGET_ARCH=target_arch) Export('env') Help(vars.GenerateHelpText(env)) ####################################################### # Setup non-verbose output ####################################################### if not env['V']: env.Replace( CCCOMSTR = '\t[CC] $SOURCE', SHCCCOMSTR = '\t[CC-SH] $SOURCE', CXXCOMSTR = '\t[CXX] $SOURCE', SHCXXCOMSTR = '\t[CXX-SH] $SOURCE', LINKCOMSTR = '\t[LINK] $TARGET', SHLINKCOMSTR = '\t[LINK-SH] $TARGET', JAVACCOMSTR = '\t[JAVAC] $SOURCE', JARCOMSTR = '\t[JAR] $TARGET', ARCOMSTR = '\t[AR] $TARGET', ASCOMSTR = '\t[AS] $TARGET', RANLIBCOMSTR = '\t[RANLIB] $TARGET', INSTALLSTR = '\t[INSTALL] $TARGET', WSCOMSTR = '\t[WS] $WS' ) ####################################################### # Load target setup ####################################################### env['build'] = True env['build_shared'] = False env['build_unit_tests'] = True env['connectivity_options'] = [ 'tcp' ] env.SConscript('SConscript.target.$TARG') vars = Variables() vars.Add('CONNECTIVITY', 'Connectivity mechanism to connect to a routing node (any of ' + ', '.join(env['connectivity_options']) + ')', os.environ.get('AJ_CONNECTIVITY', ' '.join(env['connectivity_options']))) vars.Update(env) Help(vars.GenerateHelpText(env)) env['connectivity'] = [ opt.upper() for opt in env['connectivity_options'] if opt in env['CONNECTIVITY'].lower() ] if len(env['connectivity']) == 0 and not GetOption('help'): print '*** Must enable at least one of %s' % ', '.join(env['connectivity_options']) Exit(1) ####################################################### # Build Configuration ####################################################### config = Configure(env, custom_tests = { 'CheckCommand' : CheckCommand, 'CheckAJLib' : CheckAJLib }) found_ws = config.CheckCommand('uncrustify') env = config.Finish() ####################################################### # Compilation defines ####################################################### if env.has_key('DEBUG_RESTRICT'): env.Append(CPPDEFINES = { 'AJ_DEBUG_RESTRICT' : env['DEBUG_RESTRICT'] }) if env['VARIANT'] == 'release' and env['NDEBUG'] == 'defined': env.Append(CPPDEFINES = [ 'NDEBUG' ]) env.Append(CPPDEFINES = [ 'AJ_' + conn for conn in env['connectivity'] ]) ####################################################### # Include path ####################################################### env.Append(CPPPATH = [ '#dist/include' ]) ####################################################### # Process commandline defines ####################################################### env.Append(CPPDEFINES = [ v for k, v in ARGLIST if k.lower() == 'define' ]) ####################################################### # Install header files ####################################################### env.Install('#dist/include/ajtcl', env.Glob('inc/*.h')) env.Install('#dist/include/ajtcl', env.Glob('src/target/$TARG/aj_target.h')) # Need to force a dpendency here because SCons can't follow nested # #include dependencies otherwise env.Depends('#build/$VARIANT', '#dist/include') # Install service headers env.Install('#dist/include/ajtcl/services', env.Glob('services/common/inc/*.h')) env.Install('#dist/include/ajtcl/services', env.Glob('services/config/inc/*.h')) ####################################################### # Build the various parts ####################################################### if env['build']: env.SConscript('src/SConscript', variant_dir='#build/$VARIANT/src', duplicate = 0) env.SConscript('samples/SConscript', variant_dir='#build/$VARIANT/samples', duplicate = 0) env.SConscript('test/SConscript', variant_dir='#build/$VARIANT/test', duplicate = 0) env.SConscript('unit_test/SConscript', variant_dir='#build/$VARIANT/unit_test', duplicate = 0) # Build ConfigService env.SConscript('services/common/src/SConscript.config', variant_dir='#build/$VARIANT/services/common/config/src', duplicate = 0) env.SConscript('services/config/src/SConscript', variant_dir='#build/$VARIANT/services/config/src', duplicate = 0) env.SConscript('services/config/samples/SConscript', variant_dir='#build/$VARIANT/services/config/samples', duplicate = 0) ####################################################### # Run the whitespace checker ####################################################### # Set the location of the uncrustify config file if found_ws: import sys sys.path.append(os.getcwd() + '/tools') import whitespace def wsbuild(target, source, env): return whitespace.main([ env['WS'], os.getcwd() + '/tools/ajuncrustify.cfg' ]) vars = Variables() vars.Add(EnumVariable('WS', 'Whitespace Policy Checker', os.environ.get('AJ_WS', 'off'), allowed_values = ('check', 'detail', 'fix', 'off'))) vars.Update(config.env) Help(vars.GenerateHelpText(config.env)) if env.get('WS', 'off') != 'off': env.Command('#ws_ajtcl', '#dist', Action(wsbuild, '$WSCOMSTR')) ajtcl-16.04/footer.html000066400000000000000000000024201271074662300150130ustar00rootroot00000000000000
$projectname $projectnumber ($datetime)
Copyright AllSeen Alliance, Inc. All Rights Reserved.
AllSeen, AllSeen Alliance, and AllJoyn are trademarks of the AllSeen Alliance, Inc in the United States and other jurisdictions.
THIS DOCUMENT AND ALL INFORMATION CONTAIN HEREIN ARE PROVIDED ON AN "AS-IS" BASIS WITHOUT WARRANTY OF ANY KIND.
MAY CONTAIN U.S. AND INTERNATIONAL EXPORT CONTROLLED INFORMATION
ajtcl-16.04/inc/000077500000000000000000000000001271074662300134025ustar00rootroot00000000000000ajtcl-16.04/inc/aj_about.h000066400000000000000000000407661271074662300153540ustar00rootroot00000000000000#ifndef _AJ_ABOUT_H #define _AJ_ABOUT_H /** * @file aj_about.h * @defgroup aj_about Bus Attachment * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* String defines used for About fields */ #define AJ_APP_ID_STR "AppId" #define AJ_DEFAULT_LANGUAGE_STR "DefaultLanguage" #define AJ_DEVICE_NAME_STR "DeviceName" #define AJ_DEVICE_ID_STR "DeviceId" #define AJ_APP_NAME_STR "AppName" #define AJ_MANUFACTURER_STR "Manufacturer" #define AJ_MODEL_NUMBER_STR "ModelNumber" #define AJ_SUPPORTED_LANGUAGES_STR "SupportedLanguages" #define AJ_DESCRIPTION_STR "Description" #define AJ_DATE_OF_MANUFACTURE_STR "DateOfManufacture" #define AJ_SOFTWARE_VERSION_STR "SoftwareVersion" #define AJ_AJSOFTWARE_VERSION_STR "AJSoftwareVersion" #define AJ_HARDWARE_VERSION_STR "HardwareVersion" #define AJ_SUPPORT_URL_STR "SupportUrl" /** * Prototype for a function provided by the property store for getting ANNOUNCE * and ABOUT properties. If the language tag given is not supported, use the * best matching language according to RFC 4647 section 3.4. This algorithm * requires that the "supported" languages be the least specific they can * (e.g., "en" in order to match both "en" and "en-US" if requested), and the * "requested" language be the most specific it can (e.g., "en-US" in * order to match either "en-US" or "en" if supported). * * @param reply The message to marshal the property values into. The getter can also figure out * from the msgId in the reply message if the reply is for ANNOUNCE or ABOUT. * * @param language The requested language to use to return the string properties. If this is NULL the default * language will be used. * * @return Return AJ_OK if the properties were succesfully marshaled into the reply. * */ typedef AJ_Status (*AJ_AboutPropGetter)(AJ_Message* reply, const char* language); /** * Called by the property store to register the about property getter. Functionality will be limited * if there is not property store. * * @param propGetter The property getter function being registered. */ void AJ_AboutRegisterPropStoreGetter(AJ_AboutPropGetter propGetter); /** * Initialize About and send the initial announcement. * * @param bus The bus attachment * @param boundPort Session port the application has bound */ AJ_Status AJ_AboutInit(AJ_BusAttachment* bus, uint16_t boundPort); /** * Emit an announcement if one has been scheduled. * * @param bus The bus attachment context. */ AJ_Status AJ_AboutAnnounce(AJ_BusAttachment* bus); /** * Cancel an about announcement * * @param bus The bus attachment context * * @return AJ_OK if canceled successfully */ AJ_Status AJ_AboutUnannounce(AJ_BusAttachment* bus); /** * Checks whether the icon has been set * * @return TRUE if the icon struct in the About data has been filled; FALSE otherwise */ uint8_t AJ_AboutHasIcon(); /** * Set a device icon to be returned by About * * @param icon Pointer to the icon data blob. This pointer must remain live until the next time this * function is called. Can be NULL if there is not icon data. * @param size The size of the icon data blob. * @param mime The mime type for the icon * @param url Optional URL for an icon */ void AJ_AboutSetIcon(const uint8_t* icon, uint16_t size, const char* mimeType, const char* url); /** * Handle a GET_PROP method call * * @param msg The GET_PROP message * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_WRITE if there was a write failure */ AJ_Status AJ_AboutHandleGetProp(AJ_Message* msg); /** * Handle a GET_ABOUT_DATA method call * * @param msg The GET_ABOUT_DATA message * @param reply The GET_ABOUT_DATA reply message * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_WRITE if there was a write failure */ AJ_Status AJ_AboutHandleGetAboutData(AJ_Message* msg, AJ_Message* reply); /** * Handle a GET_ABOUT_OBJECT_DESCRIPTION method call * * @param msg The GET_ABOUT_OBJECT_DESCRIPTION message * @param reply The GET_ABOUT_OBJECT_DESCRIPTION reply message * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_WRITE if there was a write failure */ AJ_Status AJ_AboutHandleGetObjectDescription(AJ_Message* msg, AJ_Message* reply); /** * Handle a GET_PROP method call * * @param msg The GET_PROP message * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_WRITE if there was a write failure */ AJ_Status AJ_AboutIconHandleGetProp(AJ_Message* msg); /** * Handle a GET_ABOUT_ICON_GET_URL method call * * @param msg The GET_ABOUT_ICON_GET_URL message * @param reply The GET_ABOUT_ICON_GET_URL reply message * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_WRITE if there was a write failure */ AJ_Status AJ_AboutIconHandleGetURL(AJ_Message* msg, AJ_Message* reply); /** * Handle a GET_ABOUT_ICON_GET_CONTENT method call * * @param msg The GET_ABOUT_ICON_GET_CONTENT message * @param reply The GET_ABOUT_ICON_GET_CONTENT reply message * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_WRITE if there was a write failure */ AJ_Status AJ_AboutIconHandleGetContent(AJ_Message* msg, AJ_Message* reply); /** * Function called by the application and other services when there are changes that warrant sending * of a new announcement. The announce condition is cleared after all AJ_AboutAnnounce() is called. */ void AJ_AboutSetShouldAnnounce(); /** * Sets the announce flag on a list of objects * * @param objList The object list to set. */ void AJ_AboutSetAnnounceObjects(AJ_Object* objList); #ifdef ANNOUNCE_BASED_DISCOVERY /** * Type for received object description * * This structure is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ typedef struct _AJ_AboutObjectDescription { const char* path; /**< the object path in an Announcement's ObjectDescription */ const char* interfaces[AJ_MAX_NUM_OF_INTERFACES]; /**< array of interface names in an Announcement's ObjectDescription */ uint8_t interfacesCount; /**< number of interface names in an Announcement's ObjectDescription */ } AJ_AboutObjectDescription; /** * Unmarshal an Announcement message ObjectDescription section. * * @param announcement The received Announcement message. * @param objDescs[out] An array of AJ_AboutObjectDescriptions that points at the Announcement message. * @param objDescsCount[out] The number of AJ_AboutObjectDescriptions in the objDescs array. * * @return Return AJ_Status * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ AJ_Status AJ_AboutUnmarshalObjectDescriptions(AJ_Message* announcement, AJ_AboutObjectDescription* objDescs, uint16_t* objDescsCount); /** * About found peer function prototype for indicating an Annoucement from a peer with matching interfaces was received. * * @param version The org.alljoyn.About interface version * @param port The application session port that is used by About * @param peerName The peer bus unique name * @param objPath The object path of the queried interface or "/" otherwise * * @return continueProcessing TRUE to continue processing the Announcement properties. * * Important: functions which implement this prototype MUST copy the input strings * (i.e. peerName and objPath) if they need to use it later! * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ typedef uint8_t (*AJ_AboutPeerDescriptionMatched)(uint16_t version, uint16_t port, const char* peerName, const char* objPath); /** * About peer's object description prototype for retrieving an Annoucement object description. * * @param peerName The peer bus unique name * @param aboutObjectDescription The object description * * Important: functions which implement this prototype MUST copy the input strings * (i.e. peerName and objPath) if they need to use it later! * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ typedef void (*AJ_AboutHandleObjectDescription)(const char* peerName, const AJ_AboutObjectDescription* aboutObjectDescription); /** * About peer's mandatory properties function prototype for retrieving an Annoucement mandatory properties. * * @param peerName The peer bus unique name * @param appId The string value of the peer's AppId * @param appName The string value of the peer's AppName * @param deviceId The string value of the peer's DeviceId * @param deviceName The string value of the peer's DeviceName * @param manufacturer The string value of the peer's Manufacturer * @param modelNumber The string value of the peer's ModelNumber * @param defaultLanguage The string value of the peer's DefaultLanguage * * Important: functions which implement this prototype MUST copy the input strings * (e.g. appId, deviceName etc.) if they need to use it later! * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ typedef void (*AJ_AboutHandleMandatoryProps)(const char* peerName, const char* appId, const char* appName, const char* deviceId, const char* deviceName, const char* manufacturer, const char* modelNumber, const char* defaultLanguage); /** * About peer's optional property function prototype for retrieving an Annoucement optional property. * * @param peerName The peer bus unique name * @param key The optional property key name * @param sig The optional property value signature * @param value The optional property value variant AJ_Arg of a basic type! * * Important: functions which implement this prototype MUST copy the input key * and unmarshal as variant the value if they need to use it later! * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ typedef void (*AJ_AboutHandleOptionalProperty)(const char* peerName, const char* key, const char* sig, const AJ_Arg* value); /** * About peer isRelevant function prototype for indicating the peer is relevant for engagement. * * @param peerName The peer bus name * * @return relevant TRUE to indicate the Announcement is from a relevant peer. * * Important: functions which implement this prototype MUST copy the input strings * (i.e. peerName and objPath) if they need to use it later! * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ typedef uint8_t (*AJ_AboutPeerIsRelevant)(const char* peerName); /** * Type for a peer Announcement filter criterion * * This structure is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ typedef struct _AJ_AboutPeerDescription { const char** implementsInterfaces; /**< interface names to resolve in peer Announcement */ uint16_t numberInterfaces; /**< number of interface names */ AJ_AboutPeerDescriptionMatched handleMatch; /**< handleMatched called when a peer with a matching description is found. The callee returns whether to continue to process this description */ AJ_AboutPeerIsRelevant handleIsRelevant; /**< handleIsRelevant called when the Announcement message was unmarshalled entirely. The callee returns whether the peer is relevant for enagement */ AJ_AboutHandleObjectDescription handleObjectDescription; /**< handleObjectDescription called when an object description is found. */ AJ_AboutHandleMandatoryProps handleMandatoryProps; /**< handleMandatoryProps called when mandatory props are found. */ AJ_AboutHandleOptionalProperty handleOptionalProperty; /**< handleOptionalProperty called when an optional property is found. This may be called prior to handleMandatoryProps */ } AJ_AboutPeerDescription; /** * Register Announce signal handlers matching each provided peer description. * * @param peerDescs An array of peer description structs. * @param peerDescsCount The number of AJ_AboutPeerDescriptions in the peerDescs array. * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ void AJ_AboutRegisterAnnounceHandlers(AJ_AboutPeerDescription* peerDescs, uint16_t peerDescsCount); /** * Unmarshal an Announcement message AboutData section. * * @param announcement The received Announcement message. * @param onMandatoryProps A callback function to return the unmarshalled mandatory properties. * @param onOptionalProperty A callback function to return each unmarshalled optional property. * * @return Return AJ_Status * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ AJ_Status AJ_AboutUnmarshalProps(AJ_Message* announcement, AJ_AboutHandleMandatoryProps onMandatoryProps, AJ_AboutHandleOptionalProperty onOptionalProperty); /** * Unmarshal the AppId variant from an Announcement message AboutData section. * * @param announcement The received Announcement message. * @param appIdBuf[out] A buffer to store the AppId string value. * @param appIdBufLen The length of the appIdBuf. * * @return Return AJ_Status * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ AJ_Status AJ_AboutUnmarshalAppIdFromVariant(AJ_Message* announcement, char* appIdBuf, size_t appIdBufLen); /** * Handle an ANNOUNCE signal * * @param announcement The received Announcement message. * @param version[out] The org.alljoyn.About interface version in the Announcenment * @param port[out] The application session port in the Annoucnement * @param peerName[out] The peer bus unique name of the Announcement sender (supply array of size AJ_MAX_NAME_SIZE+1) * @param handled[out] One of the registered Announce handlers indicated this peer is relevant for engagement * * @return Return AJ_Status * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ AJ_Status AJ_AboutHandleAnnounce(AJ_Message* announcement, uint16_t* version, uint16_t* port, char* peerName, uint8_t* relevant); #endif #ifdef __cplusplus } #endif /** End of insert */ /** * @} */ #endif ajtcl-16.04/inc/aj_ardp.h000066400000000000000000000156321271074662300151620ustar00rootroot00000000000000/** * @file ArdpProtocol is an implementation of the Reliable Datagram Protocol * (RDP) adapted to AllJoyn. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef _ALLJOYN_ARDP_PROTOCOL_H #define _ALLJOYN_ARDP_PROTOCOL_H #ifdef AJ_ARDP #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include /** * @brief Per-protocol-instance (global) configuration variables. */ #define UDP_CONNECT_TIMEOUT 1000 /**< How long before we expect a connection to complete */ #define UDP_CONNECT_RETRIES 10 /**< How many times do we retry a connection before giving up */ #define UDP_INITIAL_DATA_TIMEOUT 1000 /**< Initial value for how long do we wait before retrying sending data */ #define UDP_TOTAL_DATA_RETRY_TIMEOUT 30000 /**< Initial total amount of time to try and send data before giving up */ #define UDP_MIN_DATA_RETRIES 5 /**< Minimum number of times to try and send data before giving up */ #define UDP_LINK_TIMEOUT 30000 /**< How long before we decide a link is down (with no responses to keepalive probes */ #define UDP_KEEPALIVE_RETRIES 5 /**< How many times do we try to probe on an idle link before terminating the connection */ #define UDP_FAST_RETRANSMIT_ACK_COUNTER 1 /**< How many duplicate acknowledgements to we need to trigger a data retransmission */ #define UDP_DELAYED_ACK_TIMEOUT 100 /**< How long do we wait until acknowledging received segments */ #define UDP_DISCONNECT_TIMEOUT 1000 /**< How long can disconnect block the program waiting for TX queue to drain */ #define UDP_MINIMUM_TIMEOUT 100 /**< The minimum amount of time between calls to ARDP_Recv, should not be greater than any of the timeout values above */ #define UDP_SEGBMAX 1472 /**< Maximum size of an ARDP segment (quantum of reliable transmission) */ #define UDP_SEGMAX ((AJ_TX_DATA_SIZE + UDP_SEGBMAX - 1) / UDP_SEGBMAX + 1) /**< Maximum number of ARDP segments in-flight (bandwidth-delay product sizing) */ /* Protocol specific values */ #define UDP_HEADER_SIZE 8 #define ARDP_HEADER_SIZE 36 #define ARDP_TTL_INFINITE 0 /* * SEGMAX and SEGBMAX on both send and receive sides are indicated by SYN header in Connection request: * the acceptor cannot modify these parameters, only reject in case the request cannot be accommodated. * No EACKs: only acknowledge segments received in sequence. */ #define ARDP_FLAG_SIMPLE_MODE 2 struct _AJ_IOBuffer; /* * ARDP connection request. Connect begins the SYN, * SYN-ACK, ACK three-way handshake. * * Returns error code: * AJ_OK - all is good, connection transitioned to SYN_SENT state; * fail error code otherwise */ AJ_Status AJ_ARDP_Connect(uint8_t* data, uint16_t dataLen, void* context, AJ_NetSocket* netSock); /* * Disconnect is used to actively close the connection. * forced (IN) - if set to TRUE, the connection should be torn down regardless * of whether there are pending data retransmits. Otherwise, the * callee should check the value of returned error code. */ void AJ_ARDP_Disconnect(uint8_t forced); /* * StartMsgSend informs the ARDP protocol that next chunk of data to be sent * is a beginning of anew message with a specified TTL. * Returns error code: * AJ_OK - all is good * AJ_ERR_ARDP_TTL_EXPIRED - Discard this message. TTL is less than 1/2 estimated roundtrip time. * AJ_ERR_ARDP_INVALID_CONNECTION - Connection does not exist (effectively connection record is NULL) */ AJ_Status AJ_ARDP_StartMsgSend(uint32_t ttl); /** * AJ_ARDP_Send will attempt to send the data in buf. It will attempt to send the message, waiting for * backpressure to clear if necessary. It can potentially block for as long as is necessary * for the backpressure to be cleared. * * returns: * AJ_OK - if we sent successfully * AJ_ERR_WRITE - if we were unable to send. */ AJ_Status AJ_ARDP_Send(struct _AJ_IOBuffer* buf); /* * ARDP_Recv: data are being read, buffered, and timers are checked. * rxBuf - (IN) app buffer to be filled * len - (IN) the number of bytes the app wants * timeout - (IN) the longest time period we can spend here * Returns error code: * AJ_OK; * AJ_ERR_ARDP_RECV_EXPIRED; * AJ_ERR_ARDP_REMOTE_DISCONNECT; * AJ_ERR_TIMEOUT; * AJ_ERR_INTERRUPTED; * AJ_ERR_READ; * AJ_ERR_PROBE_TIMEOUT * */ AJ_Status AJ_ARDP_Recv(struct _AJ_IOBuffer* rxBuf, uint32_t len, uint32_t timeout); /** * A pointer to the function used by ARDP to receive from a socket * * @param context - (IN) The context pointer * @param buf - (OUT) A pointer to the underlying data that was received * @param recved - (OUT) The number of bytes received into buf * @param timeout - (IN) The timeout * * @return error code * AJ_OK if data was recived * AJ_ERR_TIMEOUT if no data was received by msec * AJ_ERR_INTERRUPTED if the receive operation was interrupted by AJ_Net_Interrupt * AJ_ERR_READ if an error has occured */ typedef AJ_Status (*ReceiveFunction)(void* context, uint8_t** buf, uint32_t* recved, uint32_t timeout); /** * A pointer to the function used by ARDP to send raw data to a socket * * @param context - (IN) The context pointer * @param buf - (IN) A pointer to the buffer to send * @param recved - (IN) The number of bytes to send * @param timeout - (OUT) The number of bytes actually sent * @param confirm - (IN) The indicator whether MSG_CONFIRM flag should be set * * @return error code * AJ_OK if data was sent * AJ_ERR_READ if an error has occured */ typedef AJ_Status (*SendFunction)(void* context, uint8_t* buf, size_t len, size_t* sent, uint8_t confirm); void AJ_ARDP_InitFunctions(ReceiveFunction recv, SendFunction send); #ifdef __cplusplus } #endif #endif // AJ_ARDP #endif // _ALLJOYN_ARDP_PROTOCOL_H ajtcl-16.04/inc/aj_auth_listener.h000066400000000000000000000046461271074662300171050ustar00rootroot00000000000000#ifndef _AJ_AUTH_LISTENER_H #define _AJ_AUTH_LISTENER_H /** * @file aj_auth_listener.h * @defgroup aj_auth_listener Authentication Listener * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* * Command for auth listener callback */ #define AJ_CRED_PRV_KEY 0x0001 /**< private key */ #define AJ_CRED_PUB_KEY 0x0002 /**< public key */ #define AJ_CRED_CERT_CHAIN 0x0003 /**< certificate chain */ #define AJ_CRED_PASSWORD 0x0004 /**< password */ #define AJ_CRED_REQUEST 0 #define AJ_CRED_RESPONSE 1 /* The key exchange is in the 16 MSB */ #define AUTH_KEYX_ECDHE 0x00400000 /* The key authentication suite is in the 16 LSB */ #define AUTH_SUITE_ECDHE_NULL (AUTH_KEYX_ECDHE | 0x0001) #define AUTH_SUITE_ECDHE_PSK (AUTH_KEYX_ECDHE | 0x0002) #define AUTH_SUITE_ECDHE_ECDSA (AUTH_KEYX_ECDHE | 0x0004) #define AUTH_SUITE_ECDHE_SPEKE (AUTH_KEYX_ECDHE | 0x0008) #define AJ_AUTH_SUITES_NUM 4 /**< Number of supported authentication suites */ /* * Type for a Credential entry for the auth listener callback */ typedef struct _AJ_Credential { uint8_t direction; /**< request or response */ uint32_t expiration; /**< auth listener to set key expiration value */ uint8_t* data; /**< data to or from the auth listener */ size_t len; /**< length of data */ } AJ_Credential; #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_authentication.h000066400000000000000000000173361271074662300172560ustar00rootroot00000000000000#ifndef _AJ_AUTHENTICATION_H #define _AJ_AUTHENTICATION_H /** * @file aj_authentication.h * @defgroup aj_authentication Implementation of Authentication mechanisms * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* The key exchange is in the 16 MSB */ #define AUTH_KEYX_ECDHE 0x00400000 /* The key authentication suite is in the 16 LSB */ #define AUTH_SUITE_ECDHE_NULL (AUTH_KEYX_ECDHE | 0x0001) #define AUTH_SUITE_ECDHE_PSK (AUTH_KEYX_ECDHE | 0x0002) #define AUTH_SUITE_ECDHE_ECDSA (AUTH_KEYX_ECDHE | 0x0004) #define AUTH_SUITE_ECDHE_SPEKE (AUTH_KEYX_ECDHE | 0x0008) #define AJ_AUTH_SUITES_NUM 4 /**< Number of supported authentication suites */ #define AUTH_CLIENT 0 #define AUTH_SERVER 1 #define HASH_MSG_UNMARSHALED ((uint8_t)0) #define HASH_MSG_MARSHALED ((uint8_t)1) /* * We now define two versions of conversation hash: one that only hashes * things inside KeyExchanger, used in authentication versions 3 and below, and * the entire authentication conversation, used starting with version 4. These * constants are used internally for calls to UpdateHash to indicate which * version of the conversation hash a particular call pertains to. * * To stay consistent with the authentication version numbers, these are called * V1 and V4. */ #define CONVERSATION_V1 ((uint32_t)0x0000) #define CONVERSATION_V4 ((uint32_t)0x0004) /* The authentication conversation version is stored in the upper 16 * bits of the version value, and the keygen version is stored in the * lower 16 bits */ #define AJ_UNPACK_AUTH_VERSION(v) ((v) >> 16) #define AJ_UNPACK_KEYGEN_VERSION(v) ((v) & 0xFFFF) typedef struct _KeyExchangeContext { AJ_ECCPublicKey pub; AJ_ECCPrivateKey prv; } KeyExchangeContext; /** * Size of buffer provided for the PSK when using the V1 callback. */ #define PSK_V1_CALLBACK_BUFFER_SIZE ((size_t)128) /** * Context for PSK authentication * Memory is allocated and copied, and is cleared and freed by AJ_ClearAuthContext */ typedef struct _PSKContext { uint8_t* hint; /**< PSK hint */ size_t hintSize; /**< Size of PSK hint */ uint8_t* key; /**< PSK */ size_t keySize; /**< Size of PSK */ } PSKContext; typedef struct _ECDSAContext { AJ_ECCPublicKey* key; /**< Array of public keys (subject + issuers) */ size_t num; /**< Number of public keys */ uint8_t thumbprint[AJ_SHA256_DIGEST_LENGTH]; /**< Identity certificate SHA-256 thumbprint */ size_t thumbprintSize; /**< Thumbprint size (should always be 0 or AJ_SHA256_DIGEST_LENGTH) */ } ECDSAContext; /** * Context for EC-SPEKE authentication * The local GUID is read from the keystore, so we need to keep it in memory, * while the remote GUID is already in memory during authentication. */ typedef struct _SPEKEContext { AJ_GUID localGUID; /**< Our GUID */ const AJ_GUID* remoteGUID; /**< Our peer's GUID */ } SPEKEContext; /** * The KeyAuthenticationContext will hold the suite-specific context, * depending on AJ_AuthenticationContext.suite. */ typedef struct _KeyAuthenticationContext { PSKContext psk; /**< Context for PSK authentication */ ECDSAContext ecdsa; /**< Context for ECDSA authentication */ SPEKEContext speke; /**< Context for EC-SPEKE authentication */ } KeyAuthenticationContext; /** * Authentication context */ typedef struct _AJ_AuthenticationContext { AJ_BusAttachment* bus; /**< Bus attachement - required for auth callbacks */ uint8_t role; /**< Role (client or server) */ uint32_t suite; /**< Authentication suite */ uint32_t version; /**< Protocol version */ AJ_SHA256_Context* hash; /**< Running hash of exchanged messages */ KeyExchangeContext kectx; /**< Context for key exchange step */ KeyAuthenticationContext kactx; /**< Context for key authentication step */ uint8_t mastersecret[AJ_MASTER_SECRET_LEN]; /**< Master secret */ uint32_t expiration; /**< Master secret expiration */ uint16_t slot; /**< NVRAM slot of membership certificate */ uint8_t code; /**< Send Membership code (NONE, MORE, LAST) */ uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; /**< Conversation digest */ uint8_t sensitiveMode; /**< Conversation digest tracing sensitive mode */ } AJ_AuthenticationContext; /** * Marshal a key exchange message * * @param ctx The authentication context * @param msg The outgoing message * * @return * - AJ_OK on success * - An error status otherwise */ AJ_Status AJ_KeyExchangeMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg); /** * Unmarshal a key exchange message * * @param ctx The authentication context * @param msg The incoming message * * @return * - AJ_OK on success * - An error status otherwise */ AJ_Status AJ_KeyExchangeUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg); /** * Marshal a key authentication message * * @param ctx The authentication context * @param msg The outgoing message * * @return * - AJ_OK on success * - An error status otherwise */ AJ_Status AJ_KeyAuthenticationMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg); /** * Unmarshal a key authentication message * * @param ctx The authentication context * @param msg The incoming message * * @return * - AJ_OK on success * - An error status otherwise */ AJ_Status AJ_KeyAuthenticationUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg); /** * Check if an authentication suite is available * * @param bus The bus attachment * @param suite The authentication suite to check * @param version The authentication protocol version * * @return Return true or false */ uint8_t AJ_IsSuiteEnabled(AJ_BusAttachment* bus, uint32_t suite, uint32_t version); /** * Enable an authentication suite * * @param bus The bus attachment * @param suite The authentication suite to enable */ void AJ_EnableSuite(AJ_BusAttachment* bus, uint32_t suite); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_authorisation.h000066400000000000000000000351751271074662300171310ustar00rootroot00000000000000#ifndef _AJ_AUTHORISATION_H #define _AJ_AUTHORISATION_H /** * @file aj_authorisation.h * @defgroup aj_authorisation Authorisation Support * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define AJ_ACCESS_INCOMING 0x1 #define AJ_ACCESS_OUTGOING 0x2 #define AJ_MEMBER_TYPE_ANY 0 #define AJ_MEMBER_TYPE_METHOD 1 #define AJ_MEMBER_TYPE_SIGNAL 2 #define AJ_MEMBER_TYPE_PROPERTY 3 #define AJ_ACTION_PROVIDE 0x1 #define AJ_ACTION_OBSERVE 0x2 #define AJ_ACTION_MODIFY 0x4 typedef struct _AJ_PermissionMember { const char* mbr; /**< Member name */ uint8_t type; /**< Member type (METHOD, SIGNAL, etc.) */ uint8_t action; /**< Action (PROVIDE, OBSERVE, etc.) */ struct _AJ_PermissionMember* next; } AJ_PermissionMember; typedef struct _AJ_PermissionRule { const char* obj; /**< Object name */ const char* ifn; /**< Interface name */ AJ_PermissionMember* members; /**< Members */ struct _AJ_PermissionRule* next; } AJ_PermissionRule; typedef struct _AJ_Manifest { uint32_t version; /**< Version */ AJ_PermissionRule* rules; /**< Rules */ const char* thumbprintAlgorithmOid;/**< Thumbprint algorithm OID */ uint8_t* thumbprint; /**< Identity certificate thumbprint */ uint32_t thumbprintSize; /**< Length of identity certificate thumbprint */ const char* signatureAlgorithmOid; /**< Signature algorithm OID */ uint8_t* signature; /**< Signature */ uint32_t signatureSize; /**< Length of signature */ uint16_t serializedSize; /**< Size of serialized form */ } AJ_Manifest; typedef struct _AJ_ManifestArray { AJ_Manifest* manifest; /**< Manifests */ struct _AJ_ManifestArray* next; } AJ_ManifestArray; #define AJ_PEER_TYPE_ALL 0 #define AJ_PEER_TYPE_ANY_TRUSTED 1 #define AJ_PEER_TYPE_FROM_CA 2 #define AJ_PEER_TYPE_WITH_PUBLIC_KEY 3 #define AJ_PEER_TYPE_WITH_MEMBERSHIP 4 typedef struct _AJ_PermissionPeer { uint8_t type; /**< Peer type */ DER_Element kid; /**< Key identifier (optional) */ AJ_ECCPublicKey pub; /**< ECC public key (optional) */ DER_Element group; /**< Group identifier (optional) */ struct _AJ_PermissionPeer* next; } AJ_PermissionPeer; typedef struct _AJ_PermissionACL { AJ_PermissionPeer* peers; /**< Peers */ AJ_PermissionRule* rules; /**< Rules */ struct _AJ_PermissionACL* next; } AJ_PermissionACL; typedef struct _AJ_Policy { uint16_t specification; /**< Specification version */ uint32_t version; /**< Policy version */ AJ_PermissionACL* acls; /**< ACLs */ } AJ_Policy; /** * Register objects on the access control list * * @param list The object list * @param l The std, app, prx identifier * * @return * - AJ_OK on success * - AJ_ERR_RESOURCES if memory not available */ AJ_Status AJ_AuthorisationRegister(const AJ_Object* list, uint8_t l); /** * Cleanup access control memory */ void AJ_AuthorisationClose(void); /** * Set the manifest template, called by the application * * @param manifest The manifest */ void AJ_ManifestTemplateSet(AJ_PermissionRule* manifest); /** * Marshal the manifest template, set from the application * * @param msg The outgoing message * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_ManifestTemplateMarshal(AJ_Message* msg); /** * Calculate manifest digest * * @param manifest The marshalled manifest message body * @param digest The output digest * * @return * - AJ_OK on success * - AJ_ERR_RESOURCES or AJ_ERR_SECURITY if the digest failed */ AJ_Status AJ_ManifestDigest(AJ_CredField * manifest, uint8_t digest[AJ_SHA256_DIGEST_LENGTH]); /** * Marshal a manifest record. The signature field can optionally be omitted for the purposes * of computing the manifest's digest. * * @param manifest The manifest * @param msg The outgoing message * @param useForDigest TRUE to exclude the signature field for purposes of computing a digest * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_ManifestMarshal(AJ_Manifest* manifest, AJ_Message* msg, uint8_t useForDigest); /** * Unmarshal a manifest record * * @param manifest The manifest * @param msg The incoming message * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_ManifestUnmarshal(AJ_Manifest** manifest, AJ_Message* msg); /** * Marshal a manifest array * * @param manifest The manifest array * @param msg The outgoing message * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_ManifestArrayMarshal(AJ_ManifestArray* manifests, AJ_Message* msg); /** * Unmarshal a manifest array * * @param manifests The manifest array * @param msg The incoming message * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_ManifestArrayUnmarshal(AJ_ManifestArray** manifests, AJ_Message* msg); /** * Marshal a policy record * * @param policy The policy * @param msg The outgoing message * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_PolicyMarshal(const AJ_Policy* policy, AJ_Message* msg); /** * Unmarshal a policy record * * @param policy The policy * @param msg The incoming message * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_PolicyUnmarshal(AJ_Policy** policy, AJ_Message* msg); /** * Free manifest memory * * @param manifest The manifest object */ void AJ_ManifestFree(AJ_Manifest* manifest); /** * Free manifest array memory * * @param manifests The manifest array */ void AJ_ManifestArrayFree(AJ_ManifestArray* manifests); /** * Free policy memory * * @param policy The policy object */ void AJ_PolicyFree(AJ_Policy* policy); /** * Marshal the default policy * * @param field The local buffer. * @param ca The CA peer * @param admin The Admin group peer * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_MarshalDefaultPolicy(AJ_CredField* field, AJ_PermissionPeer* peer_ca, AJ_PermissionPeer* peer_admin); /** * Apply the manifest access rules * * @param manifest The manifest object * @param name The peer's name * @param ctx The authentication context * * @return * - AJ_OK on success * - AJ_ERR_ACCESS if the named peer is not found * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_ManifestApply(AJ_Manifest* manifest, const char* name, AJ_AuthenticationContext* ctx); /** * Validate and apply an array of manifests * * @param manifests The array of manifests * @param name The peer's name * @param ctx The authentication context * */ void AJ_ManifestArrayApply(AJ_ManifestArray* manifests, const char* name, AJ_AuthenticationContext* ctx); /** * Apply the policy access rules * * @param ctx The authentication context * @param name The peer's name * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_PolicyApply(AJ_AuthenticationContext* ctx, const char* name); /** * Apply the policy access rules for a group membership * * @param root The membership certificate chain * @param issuer The root certificate authority * @param group The membership group * @param name The peer's name * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_MembershipApply(X509CertificateChain* root, AJ_ECCPublicKey* issuer, DER_Element* group, const char* name); /** * Get the policy version * * @param version The output policy version * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_PolicyVersion(uint32_t* version); /** * Search for the intermediate issuers amongst the stored authorities * * @param root The certificate chain * * @return * - AJ_OK on success * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_PolicyFindAuthority(const X509CertificateChain* root); /** * Attempt to verify certificate using stored authorities * * @param cert The certificate * @param pub The output public key * * @return * - AJ_OK on success * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_PolicyVerifyCertificate(const X509Certificate* cert, AJ_ECCPublicKey* pub); /** * Access control check for message * * @param msg The message * @param name The peer's name * @param direction The message direction (incoming/outgoing) * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_ACCESS on all failures */ AJ_Status AJ_AccessControlCheckMessage(const AJ_Message* msg, const char* name, uint8_t direction); /** * Access control check for a property * * @param msg The message * @param id The property id * @param name The peer's name * @param direction The message direction (incoming/outgoing) * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_ACCESS on all failures */ AJ_Status AJ_AccessControlCheckProperty(const AJ_Message* msg, uint32_t id, const char* name, uint8_t direction); /** * Reset access control list for a peer * * @param name The peer's name * * @return * - AJ_OK on success * - AJ_ERR_INVALID otherwise */ AJ_Status AJ_AccessControlReset(const char* name); /** * Marshal a manifest to a local buffer. * * @param manifest The input manifest. * @param field The local buffer. * @param useForDigest TRUE to exclude the signature field for purposes of computing a digest * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_ManifestToBuffer(AJ_Manifest* manifest, AJ_CredField* field, uint8_t useForDigest); /** * Unmarshal a manifest from a local buffer. * * @param manifest The output manifest. * @param field The local buffer. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_ManifestFromBuffer(AJ_Manifest** manifest, AJ_CredField* field); /** * Marshal a manifest array to a local buffer. * * @param manifests The input manifest array. * @param field The local buffer. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_ManifestArrayToBuffer(AJ_ManifestArray* manifest, AJ_CredField* field); /** * Unmarshal a manifest array from a local buffer. * * @param manifests The output manifest array. * @param field The local buffer. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_ManifestArrayFromBuffer(AJ_ManifestArray** manifest, AJ_CredField* field); /** * Marshal a policy to a local buffer. * * @param policy The input policy. * @param field The local buffer. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_PolicyToBuffer(AJ_Policy* policy, AJ_CredField* field); /** * Unmarshal a policy from a local buffer. * * @param policy The output policy. * @param field The local buffer. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_PolicyFromBuffer(AJ_Policy** policy, AJ_CredField* field); /** * Checks if name is a substring of a description, * also allows wildcard matching. * * @param name The name of access control element * @param desc The description (object, interface, member) * @param type The description type (SIGNAL, METHOD, PROPERTY) * * @return Return uint8_t * - 1 on success * - 0 on failure */ uint8_t AJ_CommonPath(const char* name, const char* desc, uint8_t type); /* * Load policy into memory */ AJ_Status AJ_PolicyLoad(void); /* * Unload policy from memory */ void AJ_PolicyUnload(void); /** * Determine if a manifest has been signed by looking for the presence of the thumbprint and * signature fields. This does not verify the cryptographic signature, as that requires access * to the public key of the signer which may not be available. Instead, this allows rejecting * unsigned manifests which can never be valid. * * @param manifest The manifest to check * * @return Return uint8_t * - TRUE if fields have been set that indicate signature * - FALSE otherwise */ uint8_t AJ_ManifestHasSignature(const AJ_Manifest* manifest); /** * Filter out any unsigned manifests from an array. * * @param manifests Pointer to a pointer to linked list. Because the first element might be filtered, * this might be changed. */ void AJ_ManifestArrayFilterUnsigned(AJ_ManifestArray** manifests); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_bufio.h000066400000000000000000000110341271074662300153300ustar00rootroot00000000000000#ifndef _AJ_BUFIO_H #define _AJ_BUFIO_H /** * @file aj_bufio.h * @defgroup aj_bufio Buffer Input/Output * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /* * Forward declaration */ struct _AJ_IOBuffer; /** * Function pointer type for an abstracted transmit function */ typedef AJ_Status (*AJ_TxFunc)(struct _AJ_IOBuffer* buf); /** * Function pointer type for an abstracted receive function * * @param buf The buffer to read into * @param len The requested number of bytes to read. More or fewer bytes may actually be read into * the buffer. * @param timeout A timeout in milliseconds after which the read will return with an error status if * there is not data to read. * * @return * - AJ_OK if some data was read * - AJ_ERR_TIMEOUT if the read timedout * - AJ_ERR_RESOURCES if there isn't enough room in the buffer to read len bytes. The buffer * will contain the bytes actually read so this is not a fatal error. * - AJ_ERR_READ the read failed irrecoverably * - AJ_ERR_LINK_DEAD the network link is dead */ typedef AJ_Status (*AJ_RxFunc)(struct _AJ_IOBuffer* buf, uint32_t len, uint32_t timeout); #define AJ_IO_BUF_RX 1 /**< I/O direction is receive */ #define AJ_IO_BUF_TX 2 /**< I/O direction is send */ #define AJ_IO_BUF_AJ 1 /**< send/receive data to/from AJ */ #define AJ_IO_BUF_MDNS 2 /**< send/receive data to/from mDNS */ /** * A type for managing a receive or transmit buffer */ typedef struct _AJ_IOBuffer { uint8_t direction; /**< I/O buffer is either a Tx buffer or an Rx buffer */ uint8_t flags; /**< ports to send to or receive on */ uint16_t bufSize; /**< Size of the data buffer */ uint8_t* bufStart; /**< Start for the data buffer */ uint8_t* readPtr; /**< Current position in buf for reading data */ uint8_t* writePtr; /**< Current position in buf for writing data */ /* * Function pointer to send or recv function */ union { AJ_TxFunc send; AJ_RxFunc recv; }; void* context; /**< Abstracted context for managing I/O */ } AJ_IOBuffer; /** * How much data is available to read from the buffer */ #define AJ_IO_BUF_AVAIL(iobuf) (uint32_t)(((iobuf)->writePtr - (iobuf)->readPtr)) /** * How much space is available to write to the buffer */ #define AJ_IO_BUF_SPACE(iobuf) ((uint32_t)((iobuf)->bufSize - ((iobuf)->writePtr - (iobuf)->bufStart))) /** * How much data has been consumed from the buffer */ #define AJ_IO_BUF_CONSUMED(iobuf) (uint32_t)(((iobuf)->readPtr - (iobuf)->bufStart)) /** * Reset and IO buffer */ #define AJ_IO_BUF_RESET(iobuf) \ do { \ (iobuf)->readPtr = (iobuf)->bufStart; \ (iobuf)->writePtr = (iobuf)->bufStart; \ (iobuf)->flags = 0; \ } while (0) /** * Initialize an I/O Buffer. * * @param ioBuf The I/O buffer to initialize * @param buffer The data buffer to use * @param bufLen The size of the data buffer * @param direction Indicates if the buffer is being used for sending or receiving data * @param context Abstracted context for managing I/O */ void AJ_IOBufInit(AJ_IOBuffer* ioBuf, uint8_t* buffer, uint32_t bufLen, uint8_t direction, void* context); /** * Move any unconsumed data to the start of the buffer. * * @param ioBuf An RX I/O buf that may contain unconsumed data * @param preserve Data (if any) at front of buffer that must be preserved */ void AJ_IOBufRebase(AJ_IOBuffer* ioBuf, size_t preserve); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_bus.h000066400000000000000000000643531271074662300150310ustar00rootroot00000000000000#ifndef _AJ_BUS_H #define _AJ_BUS_H /** * @file aj_bus.h * @defgroup aj_bus Bus Attachment * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Forward declarations */ typedef struct _AJ_Message AJ_Message; typedef struct _AJ_Arg AJ_Arg; /** * Callback function prototype for requesting a password or pincode from an application. * * @param buffer The buffer to receive the password. * @param bufLen The size of the buffer * * @return Returns the length of the password. If the length is zero this will be * treated as a rejected password request. */ typedef uint32_t (*AJ_AuthPwdFunc)(uint8_t* buffer, uint32_t bufLen); /** * Callback function prototype for authentication listener * * @param authmechanism The authentication mechanism used * @param command The listener command * @param creds The credentials * * @return Returns true if authorized; false otherwise. */ typedef AJ_Status (*AJ_AuthListenerFunc)(uint32_t authmechanism, uint32_t command, AJ_Credential* creds); /** * Callback function prototype for handling a factory reset request * * @return * - AJ_OK if the application was able to reset its own state * - An error status otherwise */ typedef AJ_Status (*AJ_FactoryResetFunc)(); /** * Callback function prototype for handling a local policy change notification */ typedef void (*AJ_PolicyChangedFunc)(); /** * Callback function prototype for handling security management start notification */ typedef void (*AJ_StartManagementFunc)(); /** * Callback function prototype for handling security management end notification */ typedef void (*AJ_EndManagementFunc)(); #define AJ_MAX_NAME_SIZE 20 /**< Maximum length for a bus unique name */ /** * Session description. * * This is a linked list, maintained within AJ_BusAttachment. There are actually * three kinds of sessions here: * - truly ongoing sessions (sessionId != 0) * - bound session ports (sessionId == 0 && host == TRUE) * - pending JoinSession calls (sessionId == 0 && host == FALSE) * * Note: we only keep track of the bus name at the other end of the session if * we're dealing with a point-to-point session. It's not too hard to extend * this to a list of other participants for a multipoint session, but we don't * have a good use case for this at the moment, so we don't want to waste * memory on this. */ typedef struct __AJ_Session { int host; /**< Are we hosting this session? */ int multipoint; /**< Is this a multipoint session? */ uint32_t sessionId; /**< The session id */ char* otherParticipant; /**< Other end of the session, in case of a point-to-point session */ uint16_t sessionPort; /**< session port */ uint32_t joinCallSerial; /**< call serial for pending JoinSession call */ struct __AJ_Session* next; /**< Next element in the linked list */ } AJ_Session; /** * Type for a bus attachment */ typedef struct _AJ_BusAttachment { uint16_t aboutPort; /**< The port to use in announcements */ char uniqueName[AJ_MAX_NAME_SIZE + 1]; /**< The unique name returned by the hello message */ AJ_NetSocket sock; /**< Abstracts a network socket */ uint32_t serial; /**< Next outgoing message serial number */ AJ_AuthPwdFunc pwdCallback; /**< Callback for obtaining passwords */ AJ_AuthListenerFunc authListenerCallback; /**< Callback for obtaining passwords */ uint32_t suites[AJ_AUTH_SUITES_NUM]; /**< Supported cipher suites */ uint8_t isAuthenticated; /**< Has authentication already occured? */ uint32_t aboutSerial; /**< Serial number for About announcement */ uint8_t isProbeRequired; /**< Are probe requests required for the live transport? */ uint8_t managementStarted; /**< Did the Security Manager call the StartManagement method? */ AJ_FactoryResetFunc factoryResetCallback; /**< Callback for handling a factory reset request */ AJ_PolicyChangedFunc policyChangedCallback; /**< Callback for handling a local policy change notification */ AJ_Session* sessions; /**< Linked list describing all ongoing sessions this bus attachment is involved in */ AJ_StartManagementFunc startManagementCallback; /**< Callback for the start of a security management session */ AJ_EndManagementFunc endManagementCallback; /**< Callback for the end of a security management session */ } AJ_BusAttachment; /** * Get the unique name for the bus * * @return The unique name or NULL if the bus is not connected. */ const char* AJ_GetUniqueName(AJ_BusAttachment* bus); #define AJ_NAME_REQ_ALLOW_REPLACEMENT 0x01 /**< Allow others to take ownership of this name */ #define AJ_NAME_REQ_REPLACE_EXISTING 0x02 /**< Attempt to take ownership of name if already taken */ #define AJ_NAME_REQ_DO_NOT_QUEUE 0x04 /**< Fail if name cannot be immediately obtained */ /** * Make a method call to request a well known name * * @param bus The bus attachment * @param name The name being requested * @param flags An XOR of the name request flags * * @return * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusRequestName(AJ_BusAttachment* bus, const char* name, uint32_t flags); #define AJ_TRANSPORT_NONE 0x0000 /**< no transports */ #define AJ_TRANSPORT_LOCAL 0x0001 /**< Local (same device) transport */ #define AJ_TRANSPORT_TCP 0x0004 /**< TCP/IP transport */ #define AJ_TRANSPORT_UDP 0x0100 /**< UDP/IP transport */ #define AJ_TRANSPORT_EXPERIMENTAL 0x8000 /**< Placeholder for an experimental transport */ #define AJ_TRANSPORT_IP (AJ_TRANSPORT_TCP | AJ_TRANSPORT_UDP) /**< Any IP-based transport */ #define AJ_TRANSPORT_ANY (AJ_TRANSPORT_LOCAL | AJ_TRANSPORT_IP) /**< ANY non-experimental transport */ #define AJ_TRANSPORT_BLUETOOTH (attempted_use_of_deprecated_definition = 0x0002) /**< Bluetooth transport */ #define AJ_TRANSPORT_WLAN (attempted_use_of_deprecated_definition = 0x0004) /**< Wireless local-area network transport */ #define AJ_TRANSPORT_WWAN (attempted_use_of_deprecated_definition = 0x0008) /**< Wireless wide-area network transport */ #define AJ_TRANSPORT_LAN (attempted_use_of_deprecated_definition = 0x0010) /**< Wired local-area network transport */ /** * Make a method call to release a previously requested well known name. * * @param bus The bus attachment * @param name The name being released * * @return * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusReleaseName(AJ_BusAttachment* bus, const char* name); #define AJ_BUS_START_ADVERTISING 0 /**< start advertising */ #define AJ_BUS_STOP_ADVERTISING 1 /**< stop advertising */ /** * Make a method call to start or stop advertising a name * * @param bus The bus attachment * @param name The name to be advertised * @param transportMask Restricts the transports the advertisement will be stopped/started on. * @param op Either AJ_BUS_START_ADVERTISING or AJ_BUS_STOP_ADVERTISING * @param flags Flags to pass into AJ_MarshalMsg * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusAdvertiseName(AJ_BusAttachment* bus, const char* name, uint16_t transportMask, uint8_t op, uint8_t flags); #define AJ_BUS_START_FINDING 0 /**< Start finding advertised name */ #define AJ_BUS_STOP_FINDING 1 /**< Stop finding advertised name */ #define AJ_FIND_NAME_STARTED 0x1 /**< Started to find the name as requested */ #define AJ_FIND_NAME_ALREADY 0x2 /**< Was already finding the requested name */ #define AJ_FIND_NAME_FAILURE 0x3 /**< Attempt to find the name failed */ /** * Register interest in a well-known name prefix for the purpose of discovery. * * @param bus The bus attachment * @param namePrefix Well-known name prefix that application is interested in receiving * FoundAdvertisedName notifications about. * @param op Either AJ_BUS_START_FINDING or AJ_BUS_STOP_FINDING * @param flags Flags being passed in * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusFindAdvertisedName(AJ_BusAttachment* bus, const char* namePrefix, uint8_t op); /** * Register interest in a well-known name prefix for the purpose of discovery. * * @param bus The bus attachment * @param namePrefix Well-known name prefix that application is interested in receiving * @param transport Transports by which for well-known name discovery * FoundAdvertisedName notifications about. * @param op Either AJ_BUS_START_FINDING or AJ_BUS_STOP_FINDING * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusFindAdvertisedNameByTransport(AJ_BusAttachment* bus, const char* namePrefix, uint16_t transport, uint8_t op); #define AJ_SESSION_PROXIMITY_ANY 0xFF /**< No proximity restrictions */ #define AJ_SESSION_PROXIMITY_PHYSICAL 0x01 /**< Limit to services that are physically proximal */ #define AJ_SESSION_PROXIMITY_NETWORK 0x02 /**< Allow services that are on the same subnet */ #define AJ_SESSION_TRAFFIC_MESSAGES 0x01 /**< Session carries message traffic */ #define AJ_SESSION_TRAFFIC_RAW_UNRELIABLE 0x02 /**< Not supported by this implementation */ #define AJ_SESSION_TRAFFIC_RAW_RELIABLE 0x04 /**< Not supported by this implementation */ #define AJ_SESSION_PORT_ANY 0x00 /**< Use a daemon assigned ephemeral session port */ /** * Type for describing session options */ typedef struct _AJ_SessionOpts { uint8_t traffic; /**< traffic type */ uint8_t proximity; /**< proximity */ uint16_t transports; /**< allowed transports */ uint32_t isMultipoint; /**< multi-point session capable */ } AJ_SessionOpts; /** * Make a method call to bind a session port. * * @param bus The bus attachment * @param port The port to bind, if AJ_SESSION_PORT_ANY is passed in, the daemon * will assign an ephemeral session port * @param opts Options for establishing a session, if NULL defaults are used. * @param flags Flags to pass into AJ_MarshalMsg * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusBindSessionPort(AJ_BusAttachment* bus, uint16_t port, const AJ_SessionOpts* opts, uint8_t flags); /** * Possible response codes for AJ_BusBindSessionPort */ #define AJ_BINDSESSIONPORT_REPLY_SUCCESS 1 /**< BindSessionPort reply: Success */ #define AJ_BINDSESSIONPORT_REPLY_ALREADY_EXISTS 2 /**< BindSessionPort reply: SessionPort already exists */ #define AJ_BINDSESSIONPORT_REPLY_FAILED 3 /**< BindSessionPort reply: Failed */ #define AJ_BINDSESSIONPORT_REPLY_INVALID_OPTS 4 /**< BindSessionPort reply: Invalid SessionOpts */ /** * Make a method call to unbind a session port. * * @param bus The bus attachment * @param port The port the session is associated with * @param flags The flags associated with binding a port * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusUnbindSession(AJ_BusAttachment* bus, uint16_t port); /** * Make a method call to cancel a sessionless signal * * @param bus The bus attachment * @param serialNum The serial number of the signal to cancel * * @return * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusCancelSessionless(AJ_BusAttachment* bus, uint32_t serialNum); /** * Possible response codes for AJ_BusCancelSessionless */ #define AJ_CANCELSESSIONLESS_REPLY_SUCCESS 1 /**< Cancel Sessionless: reply success */ #define AJ_CANCELSESSIONLESS_REPLY_NO_SUCH_MSG 2 /**< Cancel Sessionless: no such msg */ #define AJ_CANCELSESSIONLESS_REPLY_NOT_ALLOWED 3 /**< Cancel Sessionless: not allowed */ #define AJ_CANCELSESSIONLESS_REPLY_FAILED 4 /**< Cancel Sessionless: reply failed */ /** * Send a reply to an accept session method call * * @param msg The AcceptSession method call * @param accept TRUE to accept the session, FALSE to reject it. * * @return Return AJ_Status * - AJ_OK if the message was succesfully delivered * - AJ_ERR_MARSHAL if the message arguments were incompletely marshaled */ AJ_EXPORT AJ_Status AJ_BusReplyAcceptSession(AJ_Message* msg, uint32_t accept); /** * Make a method call join a session. * * @param bus The bus attachment * @param sessionHost Bus name of attachment that is hosting the session to be joined. * @param port The session port to join * @param opts Options for establishing a session, if NULL defaults are used. * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusJoinSession(AJ_BusAttachment* bus, const char* sessionHost, uint16_t port, const AJ_SessionOpts* opts); /** * Make a method call join a session. * * @param bus The bus attachment * @param sessionId The Id of the session joined * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusLeaveSession(AJ_BusAttachment* bus, uint32_t sessionId); #define AJ_BUS_SIGNAL_ALLOW 0 /**< Allow signals */ #define AJ_BUS_SIGNAL_DENY 1 /**< Deny signals */ /** * Add a SIGNAL match rule. A rule must be added for every non-session signal that the application * is interested in receiving. * * @param bus The bus attachment * @param ruleString Match rule to be added/removed * @param rule Either AJ_BUS_SIGNAL_ALLOW or AJ_BUS_SIGNAL_DENY * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusSetSignalRule(AJ_BusAttachment* bus, const char* ruleString, uint8_t rule); /** * Add a SIGNAL match rule. A rule must be added for every non-session signal that the application * is interested in receiving. * * @param bus The bus attachment * @param ruleString Match rule to be added/removed * @param rule Either AJ_BUS_SIGNAL_ALLOW or AJ_BUS_SIGNAL_DENY * @param flags Flags associated with the new rule * @param[out] serialNum The serial number of the method call * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_Status AJ_BusSetSignalRuleSerial(AJ_BusAttachment* bus, const char* ruleString, uint8_t rule, uint8_t flags, uint32_t* serialNum); /** * Add a SIGNAL match rule. A rule must be added for every non-session signal that the application * is interested in receiving. * * @param bus The bus attachment * @param signalName The name of the signal. * @param interfaceName The name of the interface. * @param rule Either AJ_BUS_SIGNAL_ALLOW or AJ_BUS_SIGNAL_DENY * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusAddSignalRule(AJ_BusAttachment* bus, const char* signalName, const char* interfaceName, uint8_t rule); /** * Add a SIGNAL match rule. A rule must be added for every non-session signal that the application * is interested in receiving. * * @param bus The bus attachment * @param ruleString Match rule to be added/removed * @param rule Either AJ_BUS_SIGNAL_ALLOW or AJ_BUS_SIGNAL_DENY * @param flags Flags associated with the new rule * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusSetSignalRuleFlags(AJ_BusAttachment* bus, const char* ruleString, uint8_t rule, uint8_t flags); #define AJ_SETLINKTIMEOUT_SUCCESS 1 /**< SetLinkTimeout reply: Success */ #define AJ_SETLINKTIMEOUT_NO_DEST_SUPPORT 2 /**< SetLinkTimeout reply: Destination endpoint does not support link monitoring */ #define AJ_SETLINKTIMEOUT_NO_SESSION 3 /**< SetLinkTimeout reply: Session with given id does not exist */ #define AJ_SETLINKTIMEOUT_FAILED 4 /**< SetLinkTimeout reply: Failed */ /** * Set a link timeout on a session. This will ensure that a session lost signal is reported by the * daemon within the specified timeout period if the session peer unexpectedly leaves the bus, for * example because the peer moved out of range. The application may want to handle to reply to * this method call to determine if the request succeeded. * * @param bus The bus attachment * @param sessionId The session id for the session to set the timeout on. * @param linkTimeout The link timeout value to set specified in milliseconds * * @return Return AJ_Status * - AJ_OK if the link timwout request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusSetLinkTimeout(AJ_BusAttachment* bus, uint32_t sessionId, uint32_t linkTimeout); /* * Use to remove a member from the session * * @param bus The bus attachment your on * @param sessionId The session ID for the session your removing the member from * @param member The unique ID of the member you wish to remove from the session * * @return Return AJ_Status * - AJ_OK if the member was removed successfully * - An error if not removed */ AJ_EXPORT AJ_Status AJ_BusRemoveSessionMember(AJ_BusAttachment* bus, uint32_t sessionId, const char* member); /* * Is the bus name reachable? * * @param bus The bus attachment * @param name The unique or well-known name of the object to ping * @param timeout Timeout (in milliseconds) to wait for a reply * * @return Return AJ_Status * - AJ_OK if ping was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_BusPing(AJ_BusAttachment* bus, const char* name, uint32_t timeout); #define AJ_PING_SUCCESS 1 /**< Ping reply: Success */ #define AJ_PING_FAILED 2 /**< Ping reply: Failed */ #define AJ_PING_TIMEOUT 3 /**< Ping reply: Timed out */ /** * Invoke a built-in handler for standard bus messages. Signals passed to this function that are * not bus messages are silently ignored. Method calls passed to this function that are not * recognized bus messages are rejected with an error response. * * Method calls that currently have built-in handlers are: * * - AJ_BUS_METHOD_PING * - AJ_BUS_METHOD_GET_MACHINE_ID * - AJ_BUS_METHOD_INTROSPECT * - AJ_BUS_METHOD_EXCHANGE_GUIDS * - AJ_BUS_METHOD_GEN_SESSION_KEY * - AJ_BUS_METHOD_EXCHANGE_GROUP_KEYS * - AJ_BUS_METHOD_AUTH_CHALLENGE * * @param msg The message to handle * * @return Return AJ_Status * - AJ_OK if the message was handled or ingored */ AJ_EXPORT AJ_Status AJ_BusHandleBusMessage(AJ_Message* msg); /** * Set a callback for returning passwords for peer authentication. Authentication is not enabled * until a password callback function has been set. * * @param bus The bus attachment struct * @param pwdCallback The password callback function. */ AJ_EXPORT void AJ_BusSetPasswordCallback(AJ_BusAttachment* bus, AJ_AuthPwdFunc pwdCallback); /** * Set a callback for auth listener * until a password callback function has been set. * * @param bus The bus attachment struct * @param authListenerCallback The auth listener callback function. */ AJ_EXPORT void AJ_BusSetAuthListenerCallback(AJ_BusAttachment* bus, AJ_AuthListenerFunc authListenerCallback); /** * Set a callback for handling requests to factory reset any application state. * * @param bus The bus attachment struct * @param factoryResetCallback The factory reset callback function. */ AJ_EXPORT void AJ_BusSetFactoryResetCallback(AJ_BusAttachment* bus, AJ_FactoryResetFunc factoryResetCallback); /** * Set a callback for handling security policy change notifications. * * @param bus The bus attachment struct * @param policyChangedCallback The policy changed callback function. */ AJ_EXPORT void AJ_BusSetPolicyChangedCallback(AJ_BusAttachment* bus, AJ_PolicyChangedFunc policyChangedCallback); /** * Callback function prototype for the function called when an authentication completes or fails. * * @param context The context provided when AJ_PeerAuthenticate() was called. * @param status A status code indicating if the authentication was succesful * - AJ_OK indicates the authentication succeeded * - AJ_ERR_SECURITY indicates the authentication failed * - AJ_ERR_TIMEOUT indciates the authentication timed-out */ typedef void (*AJ_BusAuthPeerCallback)(const void* context, AJ_Status status); /** * Initiate a secure connection to a remote peer authenticating if necessary. * * @param bus The bus attachment * @param peerBusName The bus name of the remote peer to secure. * @param callback A function to be called when the authentication completes * @param cbContext A caller provided context to pass to the callback function * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_Status AJ_BusAuthenticatePeer(AJ_BusAttachment* bus, const char* peerBusName, AJ_BusAuthPeerCallback callback, void* cbContext); /** * Callback function prototype for a callback function to GET a property. All this function has to * do is marshal the property value. * * @param replyMsg The GET_PROPERTY or GET_ALL_PROPERTIES reply message * @param propId The property identifier * @param context The caller provided context that was passed into AJ_BusPropGet() * * @return Return AJ_Status * - AJ_OK if the property was read and marshaled * - An error status if the property could not be returned for any reason. */ typedef AJ_Status (*AJ_BusPropGetCallback)(AJ_Message* replyMsg, uint32_t propId, void* context); /** * Helper function that provides all the boilerplate for responding to a GET_PROPERTY. All the * application has to do is marshal the property value. * * @param msg An unmarshalled GET_PROPERTY message * @param callback The function called to request the application to marshal the property value. * @param context A caller provided context that is passed into the callback function * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_BusPropGet(AJ_Message* msg, AJ_BusPropGetCallback callback, void* context); /** * Helper function that provides all the boilerplate for responding to a GET_ALL_PROPERTIES. All the * application has to do is marshal each of the property values. * * @param msg An unmarshalled GET_ALL_PROPERTIES message * @param callback The function called to request the application to marshal the property value. * @param context A caller provided context that is passed into the callback function * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_BusPropGetAll(AJ_Message* msg, AJ_BusPropGetCallback callback, void* context); /** * Callback function prototype for a callback function to SET an application property. All this * function has to do is unmarshal the property value. * * @param replyMsg The SET_PROPERTY reply message * @param propId The property identifier * @param context The caller provided context that was passed into AJ_BusPropSet() * * @return Return AJ_Status * - AJ_OK if the property was unmarshaled * - An error status if the property could not be set for any reason. */ typedef AJ_Status (*AJ_BusPropSetCallback)(AJ_Message* replyMsg, uint32_t propId, void* context); /** * Helper function that provides all the boilerplate for responding to a SET_PROPERTY. All the * application has to do is unmarshal the property value. * * @param msg An unmarshalled SET_PROPERTY message * @param callback The function called to request the application to marshal the property value. * @param context A caller provided context that is passed into the callback function * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_BusPropSet(AJ_Message* msg, AJ_BusPropSetCallback callback, void* context); /** * Function to specify which authentication suites are available. * * @param bus The bus attachment struct * @param suites The authentication suites to enable * @param numsuites The number of authentication suites * * @return Return AJ_Status */ AJ_Status AJ_BusEnableSecurity(AJ_BusAttachment* bus, const uint32_t* suites, size_t numsuites); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_bus_priv.h000066400000000000000000000057421271074662300160660ustar00rootroot00000000000000#ifndef _AJ_BUS_PRIV_H #define _AJ_BUS_PRIV_H /** * @file aj_bus_priv.h * @defgroup aj_bus_priv Non-public Bus Attachment APIs * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #ifdef __cplusplus extern "C" { #endif /** * Do session bookkeeping when a hosted session is joined * * @param msg The AJ_SIGNAL_SESSION_JOINED message * * @return - AJ_OK if all went well * - AJ_ERR_SIGNATURE if the message was the signature was missing or incorrect. */ AJ_EXPORT AJ_Status AJ_BusHandleSessionJoined(AJ_Message* msg); /** * Do session bookkeeping when a session is lost * * @param msg The AJ_SIGNAL_SESSION_LOST message * * @return - AJ_OK if all went well * - AJ_ERR_SIGNATURE if the message was the signature was missing or incorrect. */ AJ_EXPORT AJ_Status AJ_BusHandleSessionLost(AJ_Message* msg); /** * Do session bookkeeping when a session is lost * * @param msg The AJ_SIGNAL_SESSION_LOST_WITH_REASON message * * @return - AJ_OK if all went well * - AJ_ERR_SIGNATURE if the message was the signature was missing or incorrect. */ AJ_EXPORT AJ_Status AJ_BusHandleSessionLostWithReason(AJ_Message* msg); /** * Do session bookkeeping when a JoinSession reply comes in * * @param msg The AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION) message * * @return - AJ_OK if all went well * - AJ_ERR_SIGNATURE if the message was the signature was missing or incorrect. */ AJ_EXPORT AJ_Status AJ_BusHandleJoinSessionReply(AJ_Message* msg); /** * Look up an ongoing session by session id. * * @param bus The AJ_BusAttachment * @param sessionId The session id of the session to look up * * @return pointer to the AJ_Session or NULL if not found */ AJ_EXPORT AJ_Session* AJ_BusGetOngoingSession(AJ_BusAttachment* bus, uint32_t sessionId); /** * Clean up the sessions list in the bus attachment - to be called during AJ_BusAttachment cleanup * * @param bus The AJ_BusAttachment */ AJ_EXPORT void AJ_BusRemoveAllSessions(AJ_BusAttachment* bus); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_cert.h000066400000000000000000000237101271074662300151650ustar00rootroot00000000000000#ifndef _AJ_CERT_H #define _AJ_CERT_H /** * @file aj_cert.h * @defgroup aj_cert Certificate Utilities * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif extern const uint8_t OID_SIG_ECDSA_SHA256[8]; extern const uint8_t OID_KEY_ECC[7]; extern const uint8_t OID_CRV_PRIME256V1[8]; extern const uint8_t OID_DN_OU[3]; extern const uint8_t OID_DN_CN[3]; extern const uint8_t OID_BASIC_CONSTRAINTS[3]; extern const uint8_t OID_SKI[3]; extern const uint8_t OID_AKI[3]; extern const uint8_t OID_SUB_ALTNAME[3]; extern const uint8_t OID_HASH_SHA256[9]; extern const uint8_t OID_CUSTOM_EKU_IDENTITY[10]; extern const uint8_t OID_CUSTOM_DIGEST[10]; extern const uint8_t OID_CUSTOM_GROUP[10]; extern const uint8_t OID_CUSTOM_ALIAS[10]; extern const uint8_t OID_CUSTOM_EKU_MEMBERSHIP[10]; /** * Structure for a DER encoded element. */ typedef struct _DER_Element { size_t size; uint8_t* data; } DER_Element; /** * Decode one element from a DER encoded blob. * * @param der The input DER encoded blob. * @param tag The expected element type. * @param out The output decoded element. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_INVALID on all failures */ AJ_Status AJ_ASN1DecodeElement(DER_Element* der, uint8_t tag, DER_Element* out); /** * Decode many elements from a DER encoded blob. * This is a non-recursive decoder. * Only a depth of one may be decoded in one call. * * @param der The input DER encoded blob. * @param tags The expected element types. * @param len The number of types to decode. * @param ... The output decoded elements. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_INVALID on all failures */ AJ_Status AJ_ASN1DecodeElements(DER_Element* der, const uint8_t* tags, size_t len, ...); #define CERT_FMT_X509_DER 0 typedef struct _X509Validity { uint64_t from; uint64_t to; } X509Validity; typedef struct _X509DistinguishedName { DER_Element ou; /**< Organizational Unit name */ DER_Element cn; /**< Common name */ } X509DistinguishedName; typedef struct _X509Extensions { uint32_t ca; /**< Certificate authority */ uint32_t type; /**< Certificate type in AllJoyn ecosystem */ DER_Element ski; /**< Subject Key Identifier */ DER_Element aki; /**< Authority Key Identifier */ DER_Element alias; /**< Alias (subject alt name) */ DER_Element group; /**< Group (subject alt name) */ DER_Element digest; /**< Associated digest */ } X509Extensions; typedef struct _X509TbsCertificate { DER_Element serial; /**< The serial number */ X509DistinguishedName issuer; /**< The issuer's identity */ X509Validity validity; /**< The validity period */ X509DistinguishedName subject; /**< The subject's identity */ AJ_ECCPublicKey publickey; /**< The subject's public key */ X509Extensions extensions; /**< The certificate extensions */ } X509TbsCertificate; /** * Structure for X.509 certificate. * Only useful for NISTP256 ECDSA signed certificates at the moment. * Can be modified to handle other types in the future. */ typedef struct _X509Certificate { DER_Element der; /**< Certificate DER encoding */ DER_Element raw; /**< The raw tbs section */ X509TbsCertificate tbs; /**< The TBS section of the certificate */ AJ_ECCSignature signature; /**< The certificate signature */ } X509Certificate; /** * Certificate chain: linked list of certificates * These are always root..end entity order. */ typedef struct _X509CertificateChain { X509Certificate certificate; /**< The certificate */ struct _X509CertificateChain* next; /**< Linked list pointer */ } X509CertificateChain; /** * Decode a PEM encoded private key * * @param key The output decoded key. * @param pem The input PEM. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_INVALID on all failures */ AJ_Status AJ_DecodePrivateKeyPEM(AJ_ECCPrivateKey* key, const char* pem); /** * Decode a ASN.1 DER encoded X.509 certificate. * * @param certificate The output decoded certificate. * @param der The input encoded DER blob. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_INVALID on all failures */ AJ_Status AJ_X509DecodeCertificateDER(X509Certificate* certificate, DER_Element* der); /** * Decode a PEM encoded X.509 certificate. * * @param certificate The output decoded certificate. * @param pem The input PEM. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_RESOURCES on failure */ AJ_Status AJ_X509DecodeCertificatePEM(X509Certificate* certificate, const char* pem); /** * Decode a PEM encoded X.509 certificate chain. * The order of certificates is important. * PEM strings are stored as end entity...root order. * This decodes to a linked list that is root...end entity order. * * On success, caller must later free the chain with a call * to AJ_X509FreeDecodedCertificateChain. * * @param pem The input PEM. * * @return Return chain on success, NULL on failure */ X509CertificateChain* AJ_X509DecodeCertificateChainPEM(const char* pem); /** * Free the memory allocated to an X509CertificateChain* as returned * by AJ_X509DecodeCertificateChainPEM. * * @param root Root of the certificate chain. If this is NULL, this function does nothing. */ void AJ_X509FreeDecodedCertificateChain(X509CertificateChain* root); /** * Verify a self-signed X.509 certificate. * * @param certificate The input certificate. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_X509SelfVerify(const X509Certificate* certificate); /** * Verify a signed X.509 certificate. * * @param certificate The input certificate. * @param key The verification key. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_X509Verify(const X509Certificate* certificate, const AJ_ECCPublicKey* key); /** * Verify a chain of X.509 certificates. * Root certificate is first. * * @param chain The input certificate chain. * @param key The verification key of the root. If this is NULL, don't verify the root. * @param type The expected certificate type (EKU). If this is 0, don't verify the type. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_X509VerifyChain(const X509CertificateChain* root, const AJ_ECCPublicKey* key, uint32_t type); /** * Free memory associated with X.509 chain. * * @param root The input certificate chain. */ void AJ_X509ChainFree(X509CertificateChain* root); /** * Marshal a X.509 certificate chain. * * @param chain The input certificate chain. * @param msg The message. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_X509ChainMarshal(X509CertificateChain* root, AJ_Message* msg); /** * Unmarshal a X.509 certificate chain. * * @param chain The output certificate chain. * @param msg The message. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_X509ChainUnmarshal(X509CertificateChain** root, AJ_Message* msg); /** * Marshal a X.509 certificate chain to a local buffer. * * @param chain The input certificate chain. * @param field The local buffer. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_X509ChainToBuffer(X509CertificateChain* root, AJ_CredField* field); /** * Unmarshal a X.509 certificate chain from a local buffer. * * @param chain The output certificate chain. * @param field The local buffer. * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on failure */ AJ_Status AJ_X509ChainFromBuffer(X509CertificateChain** root, AJ_CredField* field); /** * Return a reference to the leaf certificate in a chain. * * @param root The certificate chain. * * @return Return the head of the reversed linked list. */ X509Certificate* AJ_X509LeafCertificate(X509CertificateChain* root); /** * Reverse the certificate chain linked list. * The order for certificates in memory is root first. * The wire protocol expects leaf certificate first. * * @param root The certificate chain. * * @return Return the head of the reversed linked list. */ X509CertificateChain* AJ_X509ReverseChain(X509CertificateChain* root); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_config.h000066400000000000000000000135311271074662300154750ustar00rootroot00000000000000#ifndef _AJ_CONFIG_H #define _AJ_CONFIG_H /** * @file aj_config.h * @defgroup aj_config Configuration * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /* Debug options */ #define _AJ_AUTH_DEBUG 0 //Enable for authentication debugging #ifndef AJ_DEBUG_RESTRICT #define AJ_DEBUG_RESTRICT AJ_DEBUG_WARN //Debug output level (aj_debug.h) #endif #define AJ_DUMP_MSG_RAW 0 //set to see raw msg bytes #define AJ_DUMP_BYTE_SIZE 16 //aj_debug.c /* Network options */ #define AJ_CONNECT_LOCALHOST 0 //Enable to bypass discovery and connect locally #define AJ_MAX_TIMERS 4 //maximum number of timers (aj_helper.c) #define AJ_ROUTING_NODE_BLACKLIST_SIZE 16 //maximum number of blacklisted routing nodes #define AJ_ROUTING_NODE_RESPONSELIST_SIZE 3 //maximum number of routing node responses to track #define AJ_TX_DATA_SIZE 5000 //minimum size of network transmit buffer #define AJ_RX_DATA_SIZE 5000 //minimum size of network receive buffer /* Auth options */ #define AJ_NONCE_LEN 28 //Length of the nonce. #define AJ_VERIFIER_LEN 12 //Length of the verifier string #define AJ_PINX_MASTER_SECRET_LEN 24 //Length of the master secret PINX #define AJ_MASTER_SECRET_LEN 48 //Length of the master secret - RFC 5246 #define AJ_SESSION_KEY_LEN 16 //Length of the session key (for AES128-CCM) #define AJ_ADHOC_LEN 16 //AD-HOC maximal passcode length (aj_auth.h) #define AJ_NAME_MAP_GUID_SIZE 4 //aj_guid.c #define AJ_MAX_CREDS 40 //Max number of credentials that can store credentials (aj_creds.h) #define AJ_LOCAL_GUID_NV_ID AJ_NVRAM_ID_CREDS_BEGIN #define AJ_CREDS_NV_ID_BEGIN (AJ_LOCAL_GUID_NV_ID + 1) #define AJ_CREDS_NV_ID_END (AJ_CREDS_NV_ID_BEGIN + AJ_MAX_CREDS) /* Timeouts */ #define AJ_UNMARSHAL_TIMEOUT (100 * 1000) //unmarshal timeout (aj_helper.c + aj_msg.c) #define AJ_CONNECT_TIMEOUT (60 * 1000) //connection timeout (aj_helper.c) #define AJ_SELECTION_TIMEOUT (5 * 1000) //selection timeout (aj_helper.c) #define AJ_CONNECT_PAUSE (10 * 1000) //how long to pause between failed connects (aj_helper.c) #define AJ_DEFAULT_REPLY_TIMEOUT (1000 * 20) //reply timeout (aj_introspect.c) #define AJ_MIN_BUS_LINK_TIMEOUT (40) //min link timeout for the bus (aj_link_timeout.c) #define AJ_BUS_LINK_PING_TIMEOUT (5 * 1000) //time period in which probe requests sb acked (aj_link_timeout.c) #define AJ_MAX_LINK_PING_PACKETS (3) //max number of outstanding probe requests (aj_link_timeout.c) #define AJ_METHOD_TIMEOUT (1000 * 3) //timeout for method calls (aj_bus.c) #define AJ_MAX_AUTH_TIME (5 * 60 * 1000ul) //max time for incomplete authentication (aj_peer.c) #define AJ_AUTH_CALL_TIMEOUT (2 * 60 * 1000ul) //long timeout for method calls w/ user input (aj_peer.c) #define AJ_CALL_TIMEOUT (1000ul * 10) //default timout for method calls (aj_peer.c) #define AJ_UDP_CONNECT_TIMEOUT 5000 //UDP connection timeout (aj_connect.c) /* Message identification related */ #if !defined(AJ_NUM_REPLY_CONTEXTS) #define AJ_NUM_REPLY_CONTEXTS (3) //number of concurrent method calls (aj_introspect.c) #endif #if !(defined(AJ_MAX_OBJECT_LISTS)) #define AJ_MAX_OBJECT_LISTS (9) //maximum number of object lists (aj_introspect.c) #endif /* Crypto */ #define AJ_CCM_TRACE 0 //Enables fine-grained tracing for debugging new implementations. #define _SO_REUSEPORT 0 //Linux target /* About client Announcement buffer */ #define AJ_MAX_NUM_OF_OBJ_DESC (32) //number of object descriptions in an Announcement payload (aj_about.c) #define AJ_MAX_NUM_OF_INTERFACES (16) //number of interfaces per object description in an Annoucement payload (aj_about.c) /* String defines */ #define AJ_PASSCODE_STR "Passcode" #define AJ_REALM_NAME_STR "RealmName" #define AJ_MAX_LENGTH_STR "MaxLength" /* Below sets the actual #define's based on values above */ #if _AJ_AUTH_DEBUG #define AUTH_DEBUG #endif #if _SO_REUSEPORT #define SO_REUSEPORT #endif #if HOST_IS_LITTLE_ENDIAN #define HOST_ENDIANESS AJ_LITTLE_ENDIAN #elif HOST_IS_BIG_ENDIAN #define HOST_ENDIANESS AJ_BIG_ENDIAN #endif #ifdef __cplusplus } #endif /** * @} */ #endif //AJ_CONFIG_H ajtcl-16.04/inc/aj_connect.h000066400000000000000000000115331271074662300156610ustar00rootroot00000000000000#ifndef _AJ_CONNECT_H #define _AJ_CONNECT_H /** * @file aj_connect.h * @defgroup aj_connect Bus Connection Management * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Set the minimum acceptable routing node protocol version. * * @param min Minimum acceptable protocol version */ void AJ_SetMinProtoVersion(uint8_t min); /** * Set the amount of time to wait for routing node responses. * * @param selection time for selecting routing node responses */ void AJ_SetSelectionTimeout(uint32_t selection); /** * Get the RN selection timeout * * @return Current selection timeout */ uint32_t AJ_GetSelectionTimeout(void); /** * Get the minimum acceptable routing node protocol version. * * @return Minimum acceptable protocol version */ uint8_t AJ_GetMinProtoVersion(); /** * Get the routing nodes protocol version * * @return The routing nodes protocol version * 0 if not connected to a routing node */ AJ_EXPORT uint8_t AJ_GetRoutingProtoVersion(void); /** * Authenticate with the daemon * * @param bus The bus attachment to authenticate * * @return Return AJ_Status */ AJ_Status AJ_Authenticate(AJ_BusAttachment* bus); #ifdef AJ_ARDP /** * Establish an ARDP-based AllJoyn UDP connection. * * @param bus The bus attachment to connect. * @param context The context that will be used to send and receive data * @param service The connection information * @param netSock The netSock * * @return * - AJ_OK if the connection was succesfully established * - AJ_ERR_TIMEOUT if the connection attempt timed out */ AJ_EXPORT AJ_Status AJ_ARDP_UDP_Connect(AJ_BusAttachment* bus, void* context, const AJ_Service* service, AJ_NetSocket* netSock); #endif /** * Find a daemon, connect to it and then authenticate. * * @param bus The bus attachment to connect. * @param serviceName Name of a specific service to connect to, NULL for the default name. * @param timeout How long to spend attempting to connect * * @return * - AJ_OK if the connection was succesfully established * - AJ_ERR_TIMEOUT if the connection attempt timed out */ AJ_EXPORT AJ_Status AJ_FindBusAndConnect(AJ_BusAttachment* bus, const char* serviceName, uint32_t timeout); /** * Terminate an AllJoyn connection * * @param bus The bus attachment to disconnect. */ AJ_EXPORT void AJ_Disconnect(AJ_BusAttachment* bus); /** * @deprecated * Bus authentication password function prototype for requesting a * password (to authenticate with the daemon) from the application. * * @param buffer The buffer to receive the password * @param bufLen The size of the buffer * * @return Returns the length of the password. If the length is zero, * this will be treated as a rejected password request. */ typedef uint32_t (*BusAuthPwdFunc)(uint8_t* buffer, uint32_t bufLen); /** * @deprecated * Set the callback for the application to provide a password for authentication to the daemon bus * * @param callback The callback provided by the application */ AJ_EXPORT void SetBusAuthPwdCallback(BusAuthPwdFunc callback); /** * Check whether we have already attempted to connect to the routing node * specified by service. * * @param service The service info struct * * @return TRUE if blacklisted */ uint8_t AJ_IsRoutingNodeBlacklisted(AJ_Service* service); void AJ_AddRoutingNodeToResponseList(AJ_Service* service); AJ_Status AJ_SelectRoutingNodeFromResponseList(AJ_Service* service); uint8_t AJ_GetRoutingNodeResponseListSize(); /** * Clear the list of blacklisted routing nodes. */ void AJ_InitRoutingNodeBlacklist(); void AJ_InitRoutingNodeResponselist(); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_conversationhash.h000066400000000000000000000132021271074662300176010ustar00rootroot00000000000000#ifndef _AJ_CONVERSATIONHASH_H #define _AJ_CONVERSATIONHASH_H /** * @file aj_conversationhash.h * @defgroup aj_conversationhash Implementation of conversation hash mechanism * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Initialize/reset a conversation hash * * @param ctx The authentication context * * @return * - AJ_OK on success * - An error status otherwise */ AJ_Status AJ_ConversationHash_Initialize(AJ_AuthenticationContext* ctx); /** * Determine whether the conversation hash is initialized * * @param ctx The authentication context * * @return * - The value 1 if initialized * - The value 0 if not initialized */ uint8_t AJ_ConversationHash_IsInitialized(AJ_AuthenticationContext* ctx); /** * Update the conversation hash with a uint8_t * * @param ctx The authentication context * @param conversationVersion The minimum authentication version which applies to this update * @param byte The byte to hash * */ void AJ_ConversationHash_Update_UInt8(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, uint8_t byte); /** * Update the conversation hash with a byte array * * @param ctx The authentication context * @param conversationVersion The minimum authentication version which applies to this update * @param buf The input array to hash * @param bufSize The size of buf * */ void AJ_ConversationHash_Update_UInt8Array(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, const uint8_t* buf, size_t bufSize); /** * Update the conversation hash with a string. This function does not assume a null-terminated * string; it will hash exactly the number of characters indicated by strSize. * * @param ctx The authentication context * @param conversationVersion The minimum authentication version which applies to this update * @param str The string content to hash * @param strSize The length of the string * */ void AJ_ConversationHash_Update_String(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, const char* str, size_t strSize); /** * Update the conversation hash with a message. If the message has been created locally with calls to AJ_Marshal* * functions, this function must be called BEFORE AJ_DeliverMsg or AJ_DeliverMsgPartial is called on it. * * If isMarshaledMessage is HASH_MSG_UNMARSHALED, the message will be reset to the beginning as a consequence * of calling this function. Any subsequent argument unmarshaling calls will start at the beginning of the message. * It is therefore recommended to call this function before or after all argument unmarshaling. * * @param ctx The authentication context * @param conversationVersion The minimum authentication version which applies to this update * @param msg The pointer to a message that was unmarshaled by an earlier call to AJ_UnmarshalMsg * or created by calls to AJ_Marshal* * @param isMarshaledMessage HASH_MSG_MARSHALED if msg was created locally through AJ_Marshal* calls, * or HASH_MSG_UNMARSHALED if received through a call to AJ_UnmarshalMsg * */ void AJ_ConversationHash_Update_Message(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, AJ_Message* msg, uint8_t isMarshaledMessage); /** * Get the conversation hash * * @param ctx The authentication context * * @return * - AJ_OK on success * - An error status otherwise */ AJ_Status AJ_ConversationHash_GetDigest(AJ_AuthenticationContext* ctx); /** * Reset the conversation hash * * @param ctx The authentication context * * @return * - AJ_OK on success * - An error status otherwise */ AJ_Status AJ_ConversationHash_Reset(AJ_AuthenticationContext* ctx); /** * Enable or disable "sensitive mode," where byte arrays that get hashed aren't * logged verbatim. When enabled, calling AJ_ConversationHash_Update_UInt8Array, * AJ_ConversationHash_Update_String, or AJ_ConversationHash_Update_Message will * log the size of the data, but then log that secret data was hashed without * showing the data. * * Other conversation hash functions, including AJ_ConversationHash_Update_UInt8, are * unaffected by this setting. * @param ctx The authentication context * @param mode TRUE to enable sensitive mode; FALSE to disable */ void AJ_ConversationHash_SetSensitiveMode(AJ_AuthenticationContext* ctx, uint8_t mode); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_crc16.h000066400000000000000000000036301271074662300151450ustar00rootroot00000000000000#ifndef _AJ_CRC16_H #define _AJ_CRC16_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #ifdef __cplusplus extern "C" { #endif /** * Computes a 16-bit CRC on a buffer. The caller provides the context for the running CRC. * * @param buffer buffer over which to compute the CRC * @param bufLen length of the buffer in bytes * @param runningCrc On input the current CRC, on output the updated CRC. */ void AJ_CRC16_Compute(const uint8_t* buffer, uint16_t bufLen, uint16_t* runningCrc); /** * This function completes the CRC computation by rearranging the CRC bits and bytes * into the correct order. * * @param crc computed crc as calculated by AJ_CRC16_Compute() * @param crcBlock pointer to a 2-byte buffer where the resulting CRC will be stored */ void AJ_CRC16_Complete(uint16_t crc, uint8_t* crcBlock); #ifdef __cplusplus } #endif #endif /* _AJ_CRC16_H */ ajtcl-16.04/inc/aj_creds.h000066400000000000000000000226651271074662300153400ustar00rootroot00000000000000#ifndef _AJ_CREDS_H #define _AJ_CREDS_H /** * @file aj_creds.h * @defgroup aj_creds Credentials Management * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Type low byte is basic type */ #define AJ_CRED_TYPE_GENERIC 0x0001 /**< generic type */ #define AJ_CRED_TYPE_AES 0x0002 /**< AES type */ #define AJ_CRED_TYPE_PRIVATE 0x0003 /**< private key type */ #define AJ_CRED_TYPE_PEM 0x0004 /**< PEM encoded type */ #define AJ_CRED_TYPE_PUBLIC 0x0005 /**< public key type */ #define AJ_CRED_TYPE_CERTIFICATE 0x0006 /**< Certificate type */ #define AJ_CRED_TYPE_MANIFESTS 0x0007 /**< manifests type */ #define AJ_CRED_TYPE_POLICY 0x0008 /**< policy type */ #define AJ_CRED_TYPE_CONFIG 0x0009 /**< config type */ /** * Type high byte is basic type (low byte) context specific */ #define AJ_GENERIC_MASTER_SECRET 0x0000 /**< Peer master secret */ #define AJ_GENERIC_ECDSA_THUMBPRINT 0x0100 /**< Identity certificate thumbprint from ECDSA authentication */ #define AJ_GENERIC_ECDSA_KEYS 0x0200 /**< Public keys from ECDSA authentication */ #define AJ_ECC_SIG 0x0000 /**< ECC key for communication */ #define AJ_CERTIFICATE_OEM_X509 0x0000 /**< Manufacturer certificate */ #define AJ_CERTIFICATE_IDN_X509 0x0100 /**< AllJoyn identity certificate */ #define AJ_CERTIFICATE_MBR_X509 0x0200 /**< AllJoyn membership certificate */ #define AJ_CERTIFICATE_UNR_X509 (AJ_CERTIFICATE_IDN_X509 | AJ_CERTIFICATE_MBR_X509) /**< Unrestricted AllJoyn certificate */ #define AJ_CERTIFICATE_INV_X509 0x0400 /**< Invalid certificate (EKUs present but no AllJoyn EKUs) */ #define AJ_POLICY_DEFAULT 0x0000 /**< Default policy */ #define AJ_POLICY_INSTALLED 0x0100 /**< Installed policy */ #define AJ_CONFIG_CLAIMSTATE 0x0000 /**< Claim state */ #define AJ_CONFIG_ADMIN_GROUP 0x0100 /**< Admin group identifier */ /** * Credential storage structures */ typedef struct _AJ_CredField { uint16_t size; /**< Field size */ uint8_t* data; /**< Field data */ } AJ_CredField; /** * Read the credential from an NVRAM slot * * @param type Credential type * @param id Credential id * @param expiration Credential expiration * @param data Credential data * @param slot NVRAM slot * * @return * - AJ_OK if the credential is found * - AJ_ERR_FAILURE otherwise */ AJ_Status AJ_CredentialRead(uint16_t* type, AJ_CredField* id, uint32_t* expiration, AJ_CredField* data, uint16_t slot); /** * Set the credential for a (type, id) pair * * @param type Credential type * @param id Credential id * @param expiration Credential expiration * @param data Credential data * * @return * - AJ_OK if the credential is found * - AJ_ERR_FAILURE otherwise */ AJ_Status AJ_CredentialSet(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_CredField* data); /** * Get the credential for a (type, id) pair * * @param type Credential type * @param id Credential id * @param expiration Credential expiration * @param data Credential data * * @return * - AJ_OK if the credential is found * - AJ_ERR_UNKNOWN otherwise */ AJ_Status AJ_CredentialGet(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_CredField* data); /** * Get the credential for a (type, id) pair starting from a given slot * * @param type Credential type * @param id Credential id * @param expiration Credential expiration * @param data Credential data * @param slot NVRAM slot to start searching from * * @return * - AJ_OK if the credential is found * - AJ_ERR_UNKNOWN otherwise */ AJ_Status AJ_CredentialGetNext(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_CredField* data, uint16_t* slot); /** * Get the GUID for this peer * If this is the first time the GUID has been requested this function, * it will generate the GUID and store it in NVRAM * * @param guid Pointer to a buffer that has enough space to store the local GUID * * @return - AJ_OK on success * - AJ_ERR_FAILURE on failure */ AJ_Status AJ_GetLocalGUID(AJ_GUID* guid); /** * Set the credential for a peer * * @param type The credential type * @param guid The peer's GUID * @param expiration The credential expiration * @param secret The credential secret * @param size The credential secret size * * @return * - AJ_OK if the credentials were written * - AJ_ERR_RESOURCES if there is no space to write the credentials */ AJ_Status AJ_CredentialSetPeer(uint16_t type, const AJ_GUID* guid, uint32_t expiration, const uint8_t* secret, uint16_t size); /** * Get the credential for a peer * * @param type The credential type * @param guid The input GUID for the remote peer * @param expiration The credential expiration * @param data The credential data * * @return * - AJ_OK if the credentials for the specific remote peer exist and are copied into the buffer * - AJ_ERR_FAILURE otherwise */ AJ_Status AJ_CredentialGetPeer(uint16_t type, const AJ_GUID* guid, uint32_t* expiration, AJ_CredField* data); /** * Set the credential for an ECC public key * * @param type The credential type * @param id The credential id * @param expiration The credential expiration * @param pub The ECC public key * * @return * - AJ_OK on success * - AJ_ERR_FAILURE otherwise */ AJ_Status AJ_CredentialSetECCPublicKey(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_ECCPublicKey* pub); /** * Get the credential for an ECC public key * * @param type The credential type * @param id The credential id * @param expiration The credential expiration * @param pub The ECC public key * * @return * - AJ_OK on success * - AJ_ERR_FAILURE otherwise */ AJ_Status AJ_CredentialGetECCPublicKey(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_ECCPublicKey* pub); /** * Set the credential for an ECC private key * * @param type The credential type * @param id The credential id * @param expiration The credential expiration * @param prv The ECC private key * * @return * - AJ_OK on success * - AJ_ERR_FAILURE otherwise */ AJ_Status AJ_CredentialSetECCPrivateKey(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_ECCPrivateKey* prv); /** * Get the credential for an ECC private key * * @param type The credential type * @param id The credential id * @param expiration The credential expiration * @param prv The ECC private key * * @return * - AJ_OK on success * - AJ_ERR_FAILURE otherwise */ AJ_Status AJ_CredentialGetECCPrivateKey(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_ECCPrivateKey* prv); /** * Delete a credential from a specified slot in NVRAM * * @param type Credential type * @param slot NVRAM slot * * @return * - AJ_OK if the credentials were deleted */ AJ_Status AJ_CredentialDeleteSlot(uint16_t type, uint16_t slot); /** * Delete a credential from NVRAM * * @param type Credential type * @param id Credential id * * @return * - AJ_OK if the credentials were deleted */ AJ_Status AJ_CredentialDelete(uint16_t type, const AJ_CredField* id); /** * Delete a peer credential from NVRAM * * @param type The credential type */ void AJ_CredentialDeletePeer(const AJ_GUID* guid); /** * Clears credentials * * @param type The type of credentials to clear (0 for all). * * @return * - AJ_OK if all credentials have been deleted */ AJ_Status AJ_ClearCredentials(uint16_t type); /** * Free the memory allocation for this credential field * * @param field Pointer to a credential field * */ void AJ_CredFieldFree(AJ_CredField* field); /** * Checks a credential's expiry * * @param expiration The credential expiration * * @return * - AJ_OK if the credential has not expired * - AJ_ERR_KEY_EXPIRED if the credential has expired * - AJ_ERR_INVALID if not clock is available */ AJ_Status AJ_CredentialExpired(uint32_t expiration); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_crypto.h000066400000000000000000000113521271074662300155470ustar00rootroot00000000000000#ifndef _AJ_CRYPTO_H #define _AJ_CRYPTO_H /** * @file aj_crypto.h * @defgroup aj_crypto Cryptographic Support * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /** * Implements AES-CCM (Counter with CBC-MAC) encryption as described in RFC 3610. The message in * encrypted in place. * * @param key The AES-128 encryption key * @param msg The buffer containing the entire message that is to be encrypted, The buffer must * have room at the end to append an authentication tag of length tagLen. * @param msgLen The length of the entire message * @param hdrLen The length of the header portion that will be authenticated but not encrypted * @param tagLen The length of the authentication tag to be appended to the message * @param nonce The nonce * @param nLen The length of the nonce * * @return * - AJ_OK if the CCM context is initialized * - AJ_ERR_RESOURCES if the resources required are not available. */ AJ_Status AJ_Encrypt_CCM(const uint8_t* key, uint8_t* msg, uint32_t msgLen, uint32_t hdrLen, uint8_t tagLen, const uint8_t* nonce, uint32_t nLen); /** * Implements AES-CCM (Counter with CBC-MAC) decryption as described in RFC 3610. The message in * decrypted in place. * * @param key The AES-128 encryption key * @param msg The buffer containing the entire message to be decrypted. * @param msgLen The length of the entire message, excluding the tag. * @param hdrLen The length of the header portion that will be authenticated but not encrypted * @param tagLen The length of the authentication tag to be appended to the message * @param nonce The nonce * @param nLen The length of the nonce * * @return * - AJ_OK if the CCM context is initialized * - AJ_ERR_RESOURCES if the resources required are not available. */ AJ_Status AJ_Decrypt_CCM(const uint8_t* key, uint8_t* msg, uint32_t msgLen, uint32_t hdrLen, uint8_t tagLen, const uint8_t* nonce, uint32_t nLen); /** * Return a string of randomly generated bytes. * * @param rand Pointer to a buffer to return the random data * @param size The number of random bytes to return. */ void AJ_RandBytes(uint8_t* rand, uint32_t size); /** * Return a random hexadecimal string of the requested length * * @param rand Pointer to a buffer to return the random data * @param bufLen The length of the buffer. The buffer must be at * least (len * 2) + 1 bytes. * @param len The length of the hexadecimal string * * @return Return AJ_Status * - AJ_OK if the string was converted * - AJ_ERR_RESOURCES if the hexLen is too small to fit the converted string. */ AJ_Status AJ_RandHex(char* rand, uint32_t bufLen, uint32_t len); /** * Enable AES allocating any resources required * * @param key The key in case this is required */ void AJ_AES_Enable(const uint8_t* key); /** * Disable AES freeing any resources that were allocated */ void AJ_AES_Disable(void); /** * Compare two buffers in constant time. For any two inputs buf1 and buf2, and * fixed count, the function will use the same number of cycles. * * @param buf1 The first buffer to compare. * @param buf2 The second buffer to compare. * @param count The number of bytes to compare. * * @return 0 if the first count bytes of buf1 and buf2 are equal, nonzero otherwise. * */ int AJ_Crypto_Compare(const void* buf1, const void* buf2, size_t count); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_crypto_aes_priv.h000066400000000000000000000044761271074662300174500ustar00rootroot00000000000000#ifndef _AJ_CRYPTO_AES_PRIV_H #define _AJ_CRYPTO_AES_PRIV_H /** * @file aj_crypto_aes_priv.h * @defgroup Private functions for low-level AES implementation * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /** * AES counter mode encryption/decryption. Note that in CTR mode encrytion is its own inverse. * * @param key The AES encryption key * @param in The data to encrypt * @param out The encrypted data * @param len The length of the input data, must be multiple of 16 * @param ctr Pointer to a 16 byte counter block */ void AJ_AES_CTR_128(const uint8_t* key, const uint8_t* in, uint8_t* out, uint32_t len, uint8_t* ctr); /** * AES CCM mode encryption * * @param key The AES encryption key * @param in The data to encrypt * @param out The encrypted data * @param len The length of the input data, must be multiple of 16 * @param iv Pointer to a 16 byte initialization vector */ void AJ_AES_CBC_128_ENCRYPT(const uint8_t* key, const uint8_t* in, uint8_t* out, uint32_t len, uint8_t* iv); /** * Encrypt a single 16 byte block using AES in ECB mode * * @param key The AES encryption key * @param in The data to encrypt * @param out The encrypted data */ void AJ_AES_ECB_128_ENCRYPT(const uint8_t* key, const uint8_t* in, uint8_t* out); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_crypto_drbg.h000066400000000000000000000053601271074662300165470ustar00rootroot00000000000000#ifndef _AJ_CRYPTO_DRBG_H #define _AJ_CRYPTO_DRBG_H /** * @file aj_crypto_drbg.h * @defgroup aj_crypto Cryptographic Random Number Generator * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /** * AES-128 CTR DRBG constants */ #define OUTLEN 16 #define KEYLEN 16 #define SEEDLEN OUTLEN + KEYLEN /** * Context for AES-128 CTR DRBG */ typedef struct _CTR_DRBG_CTX { uint8_t df; /**< Use DF or not */ uint8_t v[OUTLEN]; /**< Internal working state */ uint8_t k[KEYLEN]; /**< Key working state */ uint32_t c; /**< Reseed counter */ } CTR_DRBG_CTX; /** * AES-128 CTR DRBG instantiate function * This takes a seed value: entropy || nonce || personalization * * @param ctx The context * @param seed Input seed material * @param size Input seed material size * @param df Use DF or not */ void AES_CTR_DRBG_Instantiate(CTR_DRBG_CTX* ctx, uint8_t* seed, size_t size, uint8_t df); /** * AES-128 CTR DRBG reseed function * This takes a seed value: entropy || additional * * @param ctx The context * @param seed Input seed material * @param size Input seed material size */ void AES_CTR_DRBG_Reseed(CTR_DRBG_CTX* ctx, uint8_t* seed, size_t size); /** * AES-128 CTR DRBG generate function * This implementation does not take additional input * * @param ctx The context * @param rand Output rand material * @param size Required output rand material size * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY if reseed required */ AJ_Status AES_CTR_DRBG_Generate(CTR_DRBG_CTX* ctx, uint8_t* rand, size_t size); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_crypto_ec_p256.h000066400000000000000000000157731271074662300170050ustar00rootroot00000000000000#ifndef AJ_CRYPTO_EC_P256_H #define AJ_CRYPTO_EC_P256_H /** * @file aj_crypto_ec_p256.h Implementation of curve arithmetic for ECC. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #ifdef __cplusplus extern "C" { #endif /* * The algorithms used here to implement elliptic curve arithmetic are described in detail in * * Joppe W. Bos and Craig Costello and Patrick Longa and Michael Naehrig * "Selecting elliptic curves for cryptography: an efficiency and security analysis", * Journal of Cryptographic Engineering, 2015, http://eprint.iacr.org/2014/130 * * and parts of this implementation are based on the associated implementation "MSR Elliptic Curve Cryptography Library", * available at http://research.microsoft.com/en-us/projects/nums/default.aspx. * * The above referenced paper gives a proof that the scalar multiplication algorithm implemented * here is exception-less, and has constant-time execution. */ /* These point types/formats are for the ECC/math implementation only, not the wider * AJ library. */ /* Point representation in Jacobian coordinates (X:Y:Z) such that x = X/Z^2, y = Y/Z^3.*/ typedef struct { digit256_t X; digit256_t Y; digit256_t Z; } ecpoint_jacobian_t; /* Point representation in affine coordinates (x,y). */ typedef struct { digit256_t x; digit256_t y; } ecpoint_t; /* Point representation in Chudnovsky coordinates (X:Y:Z:Z^2:Z^3) (used for precomputed points).*/ typedef struct { digit256_t X; digit256_t Y; digit256_t Z; digit256_t Z2; digit256_t Z3; } ecpoint_chudnovsky_t; /* An identifier for the curve. This field may be serialized, so numbers should be re-used * for different curves between releases. */ typedef enum { NISTP256r1 = 1 } curveid_t; /* Structure to hold curve related data. */ typedef struct { curveid_t curveid; /* Curve ID */ size_t rbits; /* Bitlength of the order of the curve (sub)group */ size_t pbits; /* Bitlength of the prime */ digit_t* prime; /* Prime */ digit_t* a; /* Curve parameter a */ digit_t* b; /* Curve parameter b */ digit_t* order; /* Prime order of the curve (sub)group */ ecpoint_t generator; digit_t* Rprime; /* (2^W)^2 mod r, where r is the order and W is it's bitlength */ digit_t* rprime; /* -(r^-1) mod 2^W */ } ec_t; /* Functions */ /** * Get the curve data for the curve specified by curveid. * * @param[out] curve The structure to get the curve data. * @param[in] curveid The ID of the curve. * * @return AJ_OK if the curve was initialized correctly. * * @remarks * If ec_getcurve succeeds, callers must call ec_freecurve to free memory * allocated by ec_getcurve. */ AJ_Status ec_getcurve(ec_t* curve, curveid_t curveid); /** * Free a curve initialized by ec_getcurve. * * @param[in,out] curve The curve to be freed. If NULL, no action is taken. * */ void ec_freecurve(ec_t* curve); /** * Get the generator (basepoint) associated with the curve, in affine (x,y) representation. * * @param[out] P The point that will be set to the generator. * @param[in] curve The curve. */ void ec_get_generator(ecpoint_t* P, ec_t* curve); /** * Test whether the affine point P = (x,y) is the point at infinity (0,0). * * @param[in] P The affine point to test. * @param[in] curve The curve associated with P. * * @return B_TRUE if P is the point at infinity, B_FALSE otherwise. */ boolean_t ec_is_infinity(const ecpoint_t* P, ec_t* curve); /** * Test whether the Jacboian point P = (X:Y:Z) is the point at infinity (0:Y:0). * * @param[in] P The affine point to test. * @param[in] curve The curve associated with P. * * @return B_TRUE if P is the point at infinity, B_FALSE otherwise. */ boolean_t ec_is_infinity_jacobian(const ecpoint_jacobian_t* P, ec_t* curve); /** * Convert a Jacobian point Q = (X:Y:Z) to an affine point P = (X/Z:Y/Z). * * @param[in] Q An affine point to be converted. * @param[out] P The Jacobian representation of P. * @param[in] curve The curve that P and Q lie on. */ void ec_toaffine(ecpoint_jacobian_t* Q, ecpoint_t* P, ec_t* curve); /** * Convert an affine point Q = (x,y) to a Jacobian point P = (X:Y:1), where X=x, Y=y. * * @param[in] Q An affine point to be converted. * @param[out] P The Jacobian representation of P. * @param[in] curve The curve that P and Q lie on. */ void ec_affine_tojacobian(const ecpoint_t* Q, ecpoint_jacobian_t* P); /** * Compute the scalar multiplication k*P. * * @param[in] P The point to be multiplied. * @param[in] k The scalar * @param[out] Q The output point Q = k*P * @param[in] curve The curve P is on. * * @return AJ_OK if succcessful */ AJ_Status ec_scalarmul(const ecpoint_t* P, digit256_t k, ecpoint_t* Q, ec_t* curve); /** * Check that a point is valid. * Ensure that the x and y coordinates are in [0, p], that (x,y) is a point on * the curve, and that it is not the point at infinity. * * @param[in] P The point to validated * @param[in] curve The curve P should be on. * * @return B_TRUE if P is valid, B_FALSE otherwise. */ boolean_t ecpoint_validation(const ecpoint_t* P, ec_t* curve); /** * Adds two affine points. * * @param[in,out] P The first point to be added, and to hold the result, i.e., P += Q. * @param[in] Q The second point to be added. * @param[in] curve The curve that P and Q lie on. */ void ec_add(ecpoint_t* P, const ecpoint_t* Q, ec_t* curve); /* These are internal to the ECC code -- defined here for testing. */ void ec_double_jacobian(ecpoint_jacobian_t* P); void ec_add_jacobian(ecpoint_jacobian_t* Q, ecpoint_jacobian_t* P, ec_t* curve); AJ_Status ec_REDP1(const uint8_t* pi, size_t len, ecpoint_t* Q, ec_t* curve); AJ_Status ec_REDP2(const uint8_t* pi, const ecpoint_t* Q1, const ecpoint_t* Q2, ecpoint_t* R, ec_t* curve); void ec_get_REDP_basepoints(ecpoint_t* Q1, ecpoint_t* Q2, curveid_t curveid); #ifdef __cplusplus } #endif #endif /* AJ_CRYPTO_EC_P256_H */ajtcl-16.04/inc/aj_crypto_ecc.h000066400000000000000000000136641271074662300163710ustar00rootroot00000000000000#ifndef _AJ_CRYPTO_ECC_H #define _AJ_CRYPTO_ECC_H /** * @file aj_crypto_ecc.h * @defgroup aj_crypto Cryptographic Support * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #ifdef __cplusplus extern "C" { #endif typedef enum {B_FALSE, B_TRUE} boolean_t; /** * ECC type sizes */ #define KEY_ECC_SZ (8 * sizeof (uint32_t)) #define KEY_ECC_PRV_SZ KEY_ECC_SZ #define KEY_ECC_PUB_SZ (2 * KEY_ECC_SZ) #define KEY_ECC_SIG_SZ (2 * KEY_ECC_SZ) /* Size of affine_point_t */ #define KEY_ECC_OLD_SZ (19 * sizeof (uint32_t)) /** * Key and curve types for AJ_ECC key types */ #define KEY_ALG_ECDSA_SHA256 0 #define KEY_ALG_ECSPEKE 1 #define KEY_CRV_NISTP256 0 typedef struct _AJ_ECCPublicKey { uint8_t alg; /**< Algorithm */ uint8_t crv; /**< Elliptic curve */ uint8_t x[KEY_ECC_SZ]; uint8_t y[KEY_ECC_SZ]; } AJ_ECCPublicKey; typedef struct _AJ_ECCPrivateKey { uint8_t alg; /**< Algorithm */ uint8_t crv; /**< Elliptic curve */ uint8_t x[KEY_ECC_SZ]; } AJ_ECCPrivateKey; typedef AJ_ECCPrivateKey AJ_ECCSecret; typedef struct _AJ_ECCSignature { uint8_t alg; /**< Algorithm */ uint8_t crv; /**< Elliptic curve */ uint8_t r[KEY_ECC_SZ]; uint8_t s[KEY_ECC_SZ]; } AJ_ECCSignature; /** * Generates an ECC key pair. * * @param pub The output public key * @param prv The output private key * * @return - AJ_OK if the key pair is successfully generated. * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_GenerateECCKeyPair(AJ_ECCPublicKey* pub, AJ_ECCPrivateKey* prv); /** * Generates the Diffie-Hellman share secret. * * @param pub The peer's public key * @param prv The private key * @param sec The output share secret * * @return - AJ_OK if the share secret is successfully generated. * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_GenerateShareSecret(AJ_ECCPublicKey* pub, AJ_ECCPrivateKey* prv, AJ_ECCSecret* sec); /** * Sign a digest using the DSA key * @param digest The digest to sign * @param prv The signing private key * @param sig The output signature * @return - AJ_OK if the signing process succeeds * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_ECDSASignDigest(const uint8_t* digest, const AJ_ECCPrivateKey* prv, AJ_ECCSignature* sig); /** * Sign a buffer using the DSA key * @param buf The buffer to sign * @param len The buffer len * @param prv The signing private key * @param sig The output signature * @return - AJ_OK if the signing process succeeds * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_ECDSASign(const uint8_t* buf, uint16_t len, const AJ_ECCPrivateKey* prv, AJ_ECCSignature* sig); /** * Verify DSA signature of a digest * @param digest The digest to sign * @param sig The signature * @param pub The signing public key * @return - AJ_OK if the signature verification succeeds * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_ECDSAVerifyDigest(const uint8_t* digest, const AJ_ECCSignature* sig, const AJ_ECCPublicKey* pub); /** * Verify DSA signature of a buffer * @param buf The buffer to sign * @param len The buffer len * @param sig The signature * @param pub The signing public key * @return - AJ_OK if the signature verification succeeds * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_ECDSAVerify(const uint8_t* buf, uint16_t len, const AJ_ECCSignature* sig, const AJ_ECCPublicKey* pub); /** * Old encoding of native public key. * * @param pub The ECC public key * @param[out] b8 Big endian byte array * */ void AJ_BigEndianDecodePublicKey(AJ_ECCPublicKey* pu, uint8_t* b8); /** * Old decoding of native public key. * * @param[out] pub The ECC public key * @param b8 Big endian byte array * */ void AJ_BigEndianEncodePublicKey(AJ_ECCPublicKey* pub, uint8_t* b8); /** * Generates the Diffie-Hellman share secret using old encoding. * * @param pub The peer's public key * @param prv The private key * @param sec The output share secret * * @return - AJ_OK if the share secret is successfully generated. * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_GenerateShareSecretOld(AJ_ECCPublicKey* pub, AJ_ECCPrivateKey* prv, AJ_ECCPublicKey* sec); /** * Generates an ephemeral key pair for EC-SPEKE. * * @param[in] pw Password and additional data to use during key generation * @param[in] pwLen The byte length of pw * @param[in] clientGUID The client's GUID * @param[in] serviceGUID The service's GUID * @param[out] publicKey The output public key * @param[out] privateKey The output private key * * @return - AJ_OK if the key pair is successfully generated. * - AJ_ERR_SECURITY otherwise */ AJ_Status AJ_GenerateSPEKEKeyPair(const uint8_t* pw, size_t pwLen, const AJ_GUID* clientGUID, const AJ_GUID* serviceGUID, AJ_ECCPublicKey* publicKey, AJ_ECCPrivateKey* privateKey); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_crypto_fp.h000066400000000000000000000213211271074662300162310ustar00rootroot00000000000000#ifndef FIELD_256_H #define FIELD_256_H /** * @file aj_crypto_fp.h Header file for field arithmetic for ECC. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #ifdef __cplusplus extern "C" { #endif #ifndef UNREFERENCED_PARAMETER #define UNREFERENCED_PARAMETER(P) ((void)(P)) #endif /* Digit types for multiprecision integers.*/ #define digit_t uint64_t #define digit_tc const uint64_t #define sdigit_t int64_t /* Number of bits in the large integer radix, i.e., digits are from the set {0, ..., 2^(RADIX_BITS) - 1}. */ #define RADIX_BITS (64) /* The zero digit_t. */ #define DIGIT_ZERO ((digit_t) 0) /* Convert a bitlength to the number of digit_t's required to represent it. */ #define NBITS_TO_NDIGITS(x) (((x) + RADIX_BITS - 1) / (RADIX_BITS)) /* Number of temps required by field arithmetic functions */ #define P256_TEMPS (2 * P256_DIGITS) /* Number of digits required to represent a field element. */ #define P256_DIGITS ((256 + RADIX_BITS - 1) / RADIX_BITS) /* Swap two values of the same type. */ #define SWAP(a, b) { \ (a) = (a) ^ (b); \ (b) = (a) ^ (b); \ (a) = (a) ^ (b); \ } /* Multiprecision type to represent 256-bit field elements */ typedef digit_t digit256_t[P256_DIGITS]; typedef const digit256_t digit256_tc; /** * Add two field elements (modular addition). * * @param[in] addend1 The first addend. * @param[in] paddend1 The second addend. * @param[out] sum The sum addend1 + paddend1 (mod p256). * */ void fpadd_p256( digit256_tc addend1, digit256_tc paddend1, digit256_t sum); /** * Set a field element to the value zero. * * @param[in,out] a The value to be zeroed. * * @remarks * This function uses a platform-specific secure zero function, * to ensure it will not be optimized away. */ void fpzero_p256(digit256_t a); /** * Test whether a field element is zero. * * @param[in] a The field element to test. * * @return 1 if a is zero, and 0 if a is nonzero. */ digit_t fpiszero_p256(digit256_t a); /** * Get the value P256, the prime that defines the field. * * @param[out] a The field element that will be set to P256. * */ void fpgetprime_p256(digit256_t a); /** * Test whether a 256-bit value is a valid element of the field defiend * by the prime P256. * * @param[in] a The field element to test. * * @return TRUE if a is in [0, P256-1], and FALSE otherwise. */ boolean_t fpvalidate_p256(digit256_tc a); /** * Test whether a 256-bit value is in [0, modulus-1]. * * @param[in] a The 256-bit value to test. * * @return TRUE if a is in [0, modulus-1], and FALSE otherwise. */ boolean_t validate_256(digit256_tc a, digit256_tc modulus); /** * Test whether a digit is zero, in constant time. * * @param[in] x the digit to test. * * @return 1 if x == 0, 0 otherwise. */ digit_t is_digit_zero_ct(digit_t x); /** * Test whether a digit is nonzero, in constant time, fully typed as digit_t. * * @param[in] x the digit to test. * * @return 1 if x != 0, 0 otherwise. */ digit_t is_digit_nonzero_ct(digit_t x); /** * Field subtraction (modular subtraction). * * @param[in] minuend The field element to subtract from. * @param[in] subtrahend The field element to subtract. * @param[out] difference The output difference, minuend - subtrahend (mod p256). */ void fpsub_p256( digit256_tc minuend, digit256_tc subtrahend, digit256_t difference); /** * Negate a field element. * * @param[in,out] a The field element to be negated. * * @return If a is less than or equal to modulus returns "1" (TRUE), else returns "0" (FALSE). */ boolean_t fpneg_p256( digit256_t a); /** * Divide a field element by two. * * @param[in] numerator The numerator in the division. * @param[out] quotient The quotient: numerator/2 (mod p256). * @param[in,out] temps Temporary space for use by this function, must have digit length P256_TEMPS. * */ void fpdiv2_p256( digit256_tc numerator, digit256_t quotient, digit_t* temps); /** * Modular multiplication. * * @param[in] multiplier The multiplier. * @param[in] multiplicand The multiplicand. * @param[out] product The product multiplier*multiplicand (mod p256). * @param[in,out] temps Temporary space for use by this function, must have digit length P256_TEMPS. * */ void fpmul_p256( digit256_tc multiplier, digit256_tc multiplicand, digit256_t product, digit_t* temps); /** * Modular squarring. * * @param[in] multiplier The value to be squarred. * @param[out] product The square mutiplier*multiplier (mod p256). * @param[in,out] temps Temporary space for use by this function, must have digit length P256_TEMPS. * */ void fpsqr_p256( digit256_tc multiplier, digit256_t product, digit_t* temps); /** * Copy one field element to another. * * @param[in] src The source field element. * @param[out] dst The destination field element. */ void fpcopy_p256(digit256_tc src, digit256_t dst); /** * Check whether two field elements are equal. * * @param[in] a The first field element to compare. * @param[in] b The second field element to compare. * * @return TRUE if the element two elements are equal, FALSE otherwise. * * @remarks * Note that all inputs must be fully reduced mod p256, e.g., p+1 and 1 will not be considered equal. * This should not be an issue since all outputs of this implementation are fully reduced. */ boolean_t fpequal_p256(digit256_tc a, digit256_tc b); /** * Compute the multiplicative inverse of a field element. * * @param[in] a The element to be inverted. * @param[out] inv The output result 1/a (mod p256). * @param[in,out] temps Temporary space for use by this function, must have digit length P256_TEMPS. * */ void fpinv_p256( digit256_tc a, digit256_t inv, digit_t* temps); /** * Set a field element to a single digit value. * * @param[in] dig0 The value to assign. * @param[out] a The field element to be assigned. * * @remarks For example, fpset_p256((digit_t)1, a) sets a to the value 1. */ void fpset_p256(digit_t dig0, digit256_t a); /** * Swaps the byte order of the digits in a field element. The order of digits * is not changed. * i.e., fpdigitswap_p256(a) does a[i] = ByteSwap(a[i]) * * @param[in,out] a The field element to have it's digits swapped */ void fpdigitswap_p256(digit256_t a); /** * Create a field element x from a byte string. * Input buffer must have length sizeof(digit256_t) * Inputs larger than P256 will be reduced mod P256. * * @param[in] bytes The byte array to import. * @param[out] x The field element to create. * @param[in,out] temps Temporary space for use by this function, must have digit length P256_TEMPS. * @param[in] is_bigendian TRUE if bytes has big endian byte ordering, or FALSE if little endian ordering. * */ void fpimport_p256(const uint8_t* bytes, digit256_t x, digit_t* temps, boolean_t is_bigendian); /** * Test whether a field element is a square. * * @param[in] a The element to test. * @param[in,out] temps Temporary space for use by this function, must have digit length P256_TEMPS. * * @return * TRUE if the element is a square mod P256, FALSE otherwise. * */ boolean_t fpissquare_p256(digit256_tc a, digit_t* temps); /** * Compute the square root of a field element (known to be a square). * * @param[in] a The element to compute the square root of. * @param[out] sqrt The output result sqrt(a) (mod p256). * @param[in,out] temps Temporary space for use by this function, must have digit length P256_TEMPS. * * @remarks * If a is not a square, the returned value is incorrect. See * fpissquare_p256 to test whether a is a square. */ void fpsqrt_p256(digit256_tc a, digit256_t sqrt, digit_t* temps); #ifdef __cplusplus } #endif #endif /* FIELD_P256_H */ ajtcl-16.04/inc/aj_crypto_sha2.h000066400000000000000000000061571271074662300164730ustar00rootroot00000000000000#ifndef _AJ_CRYPTO_SHA2_H #define _AJ_CRYPTO_SHA2_H /** * @file aj_crypto_sha2.h * @defgroup aj_crypto SHA-256 Cryptographic Support * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif #define AJ_SHA256_DIGEST_LENGTH (32) typedef struct AJ_SHA256_Context AJ_SHA256_Context; /*** SHA-256/384/512 Function Prototypes ******************************/ /** * Initialize the hash context. Calls to this function must be * matched with a call to AJ_SHA256_Final() to ensure that resources * are released. * * @return Pointer to context. NULL if init failed. */ AJ_SHA256_Context* AJ_SHA256_Init(void); /** * Update the digest using the specific bytes * @param context the hash context * @param buf the bytes to digest * @param bufSize the number of bytes to digest */ void AJ_SHA256_Update(AJ_SHA256_Context* context, const uint8_t* buf, size_t bufSize); /** * Retrieve the digest but keep the hash active for further updates. * @param context the hash context * @param digest the buffer to hold the digest. Must be of size AJ_SHA256_DIGEST_LENGTH * @return AJ_OK if successful, otherwise error. */ AJ_Status AJ_SHA256_GetDigest(AJ_SHA256_Context* context, uint8_t* digest); /** * Finish the hash calculation and free resources. * @param context the hash context * @param digest - the buffer to hold the digest. * Must be NULL or of size AJ_SHA256_DIGEST_LENGTH. * If the value is NULL, resources are freed but the digest * is not calculated. * @return AJ_OK if successful, otherwise error. */ AJ_Status AJ_SHA256_Final(AJ_SHA256_Context* context, uint8_t* digest); /** * Random function * @param inputs array holding secret, label, seed * @param lengths array holding the lengths of the inputs * @param count the size of the input array * @param out the buffer holding the random value * @param outLen the buffer size * @return AJ_OK if succeeds; otherwise error */ AJ_Status AJ_Crypto_PRF_SHA256(const uint8_t** inputs, const uint8_t* lengths, uint32_t count, uint8_t* out, uint32_t outLen); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_debug.h000066400000000000000000000330471271074662300153220ustar00rootroot00000000000000#ifndef _AJ_DEBUG_H #define _AJ_DEBUG_H /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * @file aj_debug.h * This file contains the debug logging support for the Thin Client. * * @defgroup aj_debug Debug Logging * * @brief The debug logging module provides structured support for what is * sometimes called "printf debugging" or "debug tracing." As in most such * facilities, support for different levels of verbosity is provided. Since a * Thin Client program can be run on different devices with very different * capabilities, the debug logging module allows for convenient and verbose * debug logging on off-target (desktop-like) platforms; and it provides the * ability to constrain debug logging in on-target (embedded system) platforms. * Because debug logging needs to work in both desktop and embedded environments * there are a few more "knobs" than one might expect. The next sections * describe how to quickly enable debug output and then continues to explain how * to configure debug logging in more detail on platforms of different * capabilities. * * @section aj_debug_qs Quick Start * * To enable all debug logging from all modules, open inc/aj_debug.h in your * favorite editor and change the definition of @c AJ_DEBUG_RESTRICT to: * * @code * #define AJ_DEBUG_RESTRICT AJ_DEBUG_ALL * @endcode * * Open src/aj_debug.c in your favorite editor and set the initial value of the * verbosity setting @c AJ_DbgLevel to: * * @code * AJ_DebugLevel AJ_DbgLevel = AJ_DEBUG_ALL; * @endcode * * If you want to enable logging from all modules, change the initial value of * @c dbgALL in src/aj_debug.c to: * * @code * uint8_t dbgALL = 1; * @endcode * * After the changes are made, do a debug build (NDEBUG must be set to false to * allow any logging above the warning level). Debug logging will now be * enabled for all modules. When a Thin Client program is run, the system will * begin logging debug messages to the device console formatted as: * * @code * seconds.milliseconds filename:line-number message * @endcode * * If you find the logging from all modules to be too verbose, you can enable * logging from specific modules. In this case, leave @c dbgALL set to zero and * enable logging for each module individually. For a module named @c MODULE * change the initial value of the variable @c dbgMODULE in src/aj_MODULE.c to * nonzero. For example, to enable logging in the CONNECT module, change the * variable @c dbgCONNECT in src/aj_connect.c to: * * @code * uint8_t dbgCONNECT = 1; * @endcode * * @note Setting @c dbgALL or @c dbgCONNECT may be done by changing the variable * in memory using a debugger at runtime instead of by hardcoding as shown here. * * @section aj_debug_env Enabling Debug Logging Using Environment Variables * * On targets that support it (for example Linux or Windows), debug logging may * also enabled using environment variables. Instead of setting a memory variable * named as @c dbgMODULE one can set a corresponding environment variable named as * @c ER_DEBUG_MODULE. If one wanted to enable debug logging in the CONNECT module * as done in the @ref aj_debug_qs section, one would set the environment variable * for the CONNECT module: * * @code * export ER_DEBUG_CONNECT=1 * @endcode * * @note There is an environment variable corresponding to the @c dbgALL memory * variable. to enable logging on @c ALL modules, simply set the @c * ER_DEBUG_ALL environment variable. * * @section aj_debug_ver Changing Verbosity of Debug Logging * * Often, the amount of debug logging printed can be quite large. To minimize * the amount of "debug spew" it is possible to control the verbosity of the * debug output. This is done by changing the value of the memory variable @c * AJ_DbgLevel. * * There are several different levels of verbosity: @par * @ref AJ_DEBUG_OFF @par * @ref AJ_DEBUG_ERROR @par * @ref AJ_DEBUG_WARN @par * @ref AJ_DEBUG_INFO @par * @ref AJ_DEBUG_DUMP @par * @ref AJ_DEBUG_ALL @par * * To use this feature, set the variable @c AJ_DbgLevel either by hardcoding in * src/aj_debug.c or by setting the memory variable using a debugger. Think of * this value as enabling messages of the specified verbosity and lesser. For * example, in order to enable error, warning and informational messages, go to * src/aj_debug.c and set the initial value of @c AJ_DbgLevel to: * * @code * AJ_DebugLevel AJ_DbgLevel = AJ_DEBUG_INFO; * @endcode * * @note Again, one can set AJ_DbgLevel in the debugger to dynamically control the * verbosity of logging at runtime. * * @section aj_debug_com Restricting Compilation of Debug Logging * * It is possible that some target environments are restricted to such a degree that * it is not possible to store all of the strings required for the various log * statements in memory. To accommodate such environments a @c RESTRICT mechanism * is provided. This restriction mechanism is controlled by the definition of * @c AJ_DEBUG_RESTRICT in the inc/aj_debug.h header file. * * The same verbosity levels are used in the @c RESTRICT mechanism as were shown * in the @ref aj_debug_ver section, but the meaning is different. Think of the * definition of AJ_DEBUG_RESTRICT as meaning, restrict messages of levels * greater than the specified level from even being compiled into the code. The * default value of AJ_DEBUG_RESTRICT is given as AJ_DEBUG_WARN so by default * only error and warning messages will be logged. Messages of AJ_DEBUG_INFO * level and greater are not compiled into the code by default. In the @ref * aj_debug_qs section, AJ_DEBUG_RESTRICT was set to AJ_DEBUG_ALL to allow all * messages to be compiled into the code so they could be logged. * * Typically, if one is running on a platform that has enough memory to * accommodate all of the log messages one would change AJ_DEBUG_RESTRICT to * AJ_DEBUG_ALL and simply leave it along. The usefulness of this definition is * when the target cannot accommodate all of the strings. In that case, it may * be useful to relax the restriction on a per-module basis to enable subsets of * logging when required. To accomplish this, one would leave AJ_DEBUG_RESTRICT * set to AJ_DEBUG_INFO in inc/aj_debug.h and add the following code to the * source file of the module where logging was to be enabled before inclusion of * aj_debug.h: * * @code * #define AJ_DEBUG_RESTRICT AJ_DEBUG_ALL * @endcode * * @{ */ #include #include #ifdef __cplusplus extern "C" { #endif /** * Always print a message in a fashion similar to other conditional log outputs. * Do not include time stamp, file and line number. * * @param msg A format string and arguments */ #define AJ_AlwaysPrintf(msg) \ do { \ AJ_Printf msg; \ } while (0) #ifndef NDEBUG /** * Dump message name and content. if body is true, dump raw data * * @param tag tag name of message * @param msg message header * @param body if true, dump raw data */ void _AJ_DumpMsg(const char* tag, AJ_Message* msg, uint8_t body); /** * Dump raw (byte) data in a convenient format. * * @param tag tag name of message * @param data start address to dump * @param len length to dump */ void _AJ_DumpBytes(const char* tag, const uint8_t* data, uint32_t len); /* * Threshold level for debug output. When used with AJ_DbgLevel the setting * controls which debug messages are actually printed. These values are also * used in the AJ_DEBUG_RESTRICT mechanism to control which log messages are * actually compiled into the code. */ #define AJ_DEBUG_OFF 0 /**< Suppresses all debug output */ #define AJ_DEBUG_ERROR 1 /**< Indicates a log message conveying an error condition */ #define AJ_DEBUG_WARN 2 /**< Indicates a log message corresponding to a warning */ #define AJ_DEBUG_INFO 3 /**< Indicates a log message with general information */ #define AJ_DEBUG_DUMP 4 /**< Indicates a message with a detailed, possibly byte-by-byte dump */ #define AJ_DEBUG_ALL 5 /**< A placeholder level above other levels */ /** * Type definition for a value used to control the debug level (verbosity) * threshold. */ typedef uint32_t AJ_DebugLevel; /** * We allow the verbosity of debug output to be controlled programmatically using * predefined AJ_DEBUG_* threshold levels. The macro AJ_DEBUG_RESTRICT is used * in the sense of restricting (not compiling in) messages with verbosity levels * greater than the given level. * * By default, all messages of all verbosity at info level and above are not * compiled into the code (by defining AJ_DEBUG_RESTRICT to be AJ_DEBUG_WARN). */ #ifndef AJ_DEBUG_RESTRICT #define AJ_DEBUG_RESTRICT AJ_DEBUG_WARN #endif /** * Set this value to control the debug output threshold level. The default is AJ_DEBUG_ERROR */ AJ_EXPORT extern AJ_DebugLevel AJ_DbgLevel; AJ_EXPORT extern uint8_t dbgALL; extern int _AJ_DbgEnabled(const char* module); /** * Internal debug printf function. Don't call this directly, use the AJ_*Printf() macros. * * @param level The level associated with this debug print * @param file File name for file calling this function * @param line Line number for line this function was called from */ AJ_EXPORT int _AJ_DbgHeader(AJ_DebugLevel level, const char* file, int line); #define QUOTE(x) # x #define STR(x) QUOTE(x) #define CONCAT(x, y) x ## y #define MKVAR(x, y) CONCAT(x, y) /** * Print a message in a fashion similar to other conditional log outputs and * include time stamp, file and line number (unless NDEBUG is defined). * When NDEBUG is defined, the behavior is identical to AJ_AlwaysPrintf. * This macro is intended for use in test application code where the timing of * events needs to be recorded in an optimized build (release mode) even when * other debug prints have been suppressed. * * @param msg A format string and arguments */ #define AJ_AlwaysHdrPrintf(msg) \ do { \ _AJ_DbgHeader(AJ_DEBUG_OFF, __FILE__, __LINE__); \ AJ_Printf msg; \ } while (0) #if AJ_DEBUG_RESTRICT >= AJ_DEBUG_ERROR /** * Print an error message. Error messages may be suppressed by AJ_DEBUG_RESTRICT * * @param msg A format string and arguments */ #define AJ_ErrPrintf(msg) \ do { \ if (_AJ_DbgHeader(AJ_DEBUG_ERROR, __FILE__, __LINE__)) { AJ_Printf msg; } \ } while (0) #else #define AJ_ErrPrintf(_msg) #endif #if AJ_DEBUG_RESTRICT >= AJ_DEBUG_WARN /** * Print a warning message. Warnings may be suppressed by AJ_DEBUG_RESTRICT * * @param msg A format string and arguments */ #define AJ_WarnPrintf(msg) \ do { \ if (_AJ_DbgHeader(AJ_DEBUG_WARN, __FILE__, __LINE__)) { AJ_Printf msg; } \ } while (0) #else #define AJ_WarnPrintf(_msg) #endif #if AJ_DEBUG_RESTRICT >= AJ_DEBUG_INFO /** * Print an informational message. Informational messages may be suppressed by * AJ_DEBUG_RESTRICT or by the module selection (global memory value or shell * environment variable) mechanism. * * @param msg A format string and arguments */ #define AJ_InfoPrintf(msg) \ do { \ if (dbgALL || MKVAR(dbg, AJ_MODULE) || _AJ_DbgEnabled(STR(AJ_MODULE))) { \ if (_AJ_DbgHeader(AJ_DEBUG_INFO, __FILE__, __LINE__)) { AJ_Printf msg; } \ } \ } while (0) #else #define AJ_InfoPrintf(_msg) #endif #if AJ_DEBUG_RESTRICT >= AJ_DEBUG_DUMP /** * Dump the bytes in a buffer in a human readable way. Byte dumps messages may * be suppressed by AJ_DEBUG_RESTRICT or by the module selection (global memory * value or shell environment variable) mechanism. * * @param msg A format string * and arguments */ #define AJ_DumpBytes(tag, data, len) \ do { \ if (MKVAR(dbg, AJ_MODULE) || _AJ_DbgEnabled(STR(AJ_MODULE))) { _AJ_DumpBytes(tag, data, len); } \ } while (0) #else #define AJ_DumpBytes(tag, data, len) #endif #if AJ_DEBUG_RESTRICT >= AJ_DEBUG_DUMP /** * Print a human readable summary of a message. Message dumps messages may be * suppressed by AJ_DEBUG_RESTRICT or by the module selection (global memory * value or shell environment variable) mechanism. * * @param msg A format string and arguments */ #define AJ_DumpMsg(tag, msg, body) \ do { \ if (MKVAR(dbg, AJ_MODULE) || _AJ_DbgEnabled(STR(AJ_MODULE))) { _AJ_DumpMsg(tag, msg, body); } \ } while (0) #else #define AJ_DumpMsg(tag, msg, body) #endif #else #define AJ_DumpMsg(tag, msg, body) #define AJ_DumpBytes(tag, data, len) #define AJ_ErrPrintf(_msg) #define AJ_WarnPrintf(_msg) #define AJ_InfoPrintf(_msg) #define AJ_AlwaysHdrPrintf AJ_AlwaysPrintf #endif /** * Utility function that converts numerical status to a readable string * * @param status A status code */ AJ_EXPORT const char* AJ_StatusText(AJ_Status status); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_disco.h000066400000000000000000000045501271074662300153320ustar00rootroot00000000000000#ifndef _AJ_DISCO_H #define _AJ_DISCO_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /** * Information about the remote service */ typedef struct _AJ_Service { uint8_t addrTypes; /**< address type */ uint16_t transportMask; /**< restricts the transports the advertisement */ uint16_t ipv4port; /**< port number of ipv4 */ uint16_t ipv6port; /**< port number of ipv6 */ uint32_t ipv4; /**< ipv4 address */ uint16_t priority; /**< priority */ uint32_t pv; /**< protocol version */ uint32_t ipv6[4]; /**< ipv6 address */ uint16_t ipv4portUdp; /**< port number of ipv4 */ uint16_t ipv6portUdp; /**< port number of ipv6 */ uint32_t ipv4Udp; /**< ipv4 address */ uint32_t ipv6Udp[4]; /**< ipv6 address */ } AJ_Service; /** * Discover a remote service * * @param prefix The service name prefix * @param service Information about the service that was found * @param timeout How long to wait to discover the service * @param selectionTimeout How long to wait to receive router responses * * @return Return AJ_Status */ AJ_Status AJ_Discover(const char* prefix, AJ_Service* service, uint32_t timeout, uint32_t selectionTimeout); #ifdef __cplusplus } #endif #endif ajtcl-16.04/inc/aj_guid.h000066400000000000000000000206361271074662300151640ustar00rootroot00000000000000#ifndef _AJ_GUID_H #define _AJ_GUID_H /** * @file aj_guid.h * @defgroup aj_guid Globally Unique Identifier Support * @{ * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Type for a GUID */ #define AJ_GUID_LEN 16 typedef struct _AJ_GUID { uint8_t val[AJ_GUID_LEN]; /**< string for a GUID */ } AJ_GUID; /** * Type for tracking serial numbers */ typedef struct _AJ_SerialNum { uint32_t serial; /**< base serial number */ uint64_t offset; /**< offset (from base) of allowed message */ } AJ_SerialNum; /** * Return a pointer to an ASCII string representation of a GUID * * @param guid The guid to convert * @param buffer The buffer to store the string * @param bufLen The size of the buffer. * * * @return Return AJ_Status * - AJ_OK if the GUID was converted * - AJ_ERR_RESOURCES if the buffer was not big enough */ AJ_Status AJ_GUID_ToString(const AJ_GUID* guid, char* buffer, uint32_t bufLen); /** * Unpacks a string into a GUID * * @param guid Pointer to a GUID structure * @param str A hex string representation of the GUID * * @return Return AJ_Status * - AJ_OK if the conversion was succsessful * - An error status otherwise */ AJ_Status AJ_GUID_FromString(AJ_GUID* guid, const char* str); /** * Clears names from the GUID map */ void AJ_GUID_ClearNameMap(void); /** * Adds a unique name to the GUID map. * * This also adds a match rule for the name owner changed signal to * detect when the name mapping can be deleted. * * @param bus The bus attachment * @param guid The GUID to add * @param uniqueName A unique name that maps to the GUID * @param serviceName A service name that maps to the GUID * * @return Return AJ_Status * - AJ_OK if the mapping was added * - AJ_ERR_RESOURCES if there is no room to the mapping */ AJ_Status AJ_GUID_AddNameMapping(AJ_BusAttachment* bus, const AJ_GUID* guid, const char* uniqueName, const char* serviceName); #define AJ_ROLE_KEY_UNDEFINED 0 /**< Indicates the session key role is undefined (only applies for group keys) */ #define AJ_ROLE_KEY_INITIATOR 1 /**< Indicates the session key was initiated by this peer */ #define AJ_ROLE_KEY_RESPONDER 2 /**< Indicates the session key was initiated by the remote peer */ /** * Delete a name mapping from the GUID map. * * This is called when a name owner changed signal is received * indicating that the unique name has gone away. * * @param bus The bus attachment * @param uniqueName The unique name that went away */ void AJ_GUID_DeleteNameMapping(AJ_BusAttachment* bus, const char* uniqueName); /** * Looks up the GUID for a name * * @param name The unique or well-known name to lookup * * @return Return A pointer to a GUID or NULL, if there is no mapping. */ const AJ_GUID* AJ_GUID_Find(const char* name); /** * Sets a session key for an entry in the GUID map * * @param uniqueName The unique name for a remote peer * @param key The 16 byte session key to add * @param role Indicates which peer initiated the session key * @param authVersion Indicates the authentication version associated with this key * * @return Return AJ_Status * - AJ_OK if the key was added * - AJ_ERR_NO_MATCH if there is no entry to the peer */ AJ_Status AJ_SetSessionKey(const char* uniqueName, const uint8_t* key, uint8_t role, uint32_t authVersion); /** * Sets a group key for an entry in the GUID map * * @param uniqueName The unique name for a remote peer * @param key The 16 byte session key to add * * @return Return AJ_Status * - AJ_OK if the key was added * - AJ_ERR_NO_MATCH if there is no entry to the peer */ AJ_Status AJ_SetGroupKey(const char* uniqueName, const uint8_t* key); /** * Gets a session key for an entry from the GUID map * * @param name The unique or well-known name for a remote peer * @param key Buffer to receive the 16 byte session key * @param role Indicates which peer initiated the session key * @param authVersion Indicates the authentication version associated with this key * * @return Return AJ_Status * - AJ_OK if the key was obtained * - AJ_ERR_NO_MATCH if there is no entry to the peer */ AJ_Status AJ_GetSessionKey(const char* name, uint8_t* key, uint8_t* role, uint32_t* authVersion); /** * Gets the peer index in the name map, used for access control list * * @param name The unique or well-known name for a remote peer * @param peer The peer index * * @return Return AJ_Status * - AJ_OK if the index was obtained * - AJ_ERR_NO_MATCH if there is no entry to the peer */ AJ_Status AJ_GetPeerIndex(const char* name, uint32_t* peer); /** * Gets serial numbers for an entry from the GUID map * * @param name The unique or well-known name for a remote peer * @param incoming The incoming serial numbers * * @return Return AJ_Status * - AJ_OK if the information was obtained * - AJ_ERR_NO_MATCH if there is no entry to the peer */ AJ_Status AJ_GetSerialNumbers(const char* name, AJ_SerialNum** incoming); /** * Gets unique name for an entry from the GUID map * * @param name The well-known name for a remote peer. Unique names are ok too. * @param unique Unique name corresponding to the requested name * * @return Return AJ_Status * - AJ_OK if the information was obtained * - AJ_ERR_NO_MATCH if there is no entry to the peer */ AJ_Status AJ_GetRemoteUniqueName(const char* name, const char** unique); /** * Gets a group key for an entry from the GUID map * * @param name The unique or well-known name for a remote peer or NULL to get the local group key. * @param key Buffer to receive the 16 byte group key * * @return Return AJ_Status * - AJ_OK if the key was obtained * - AJ_ERR_NO_MATCH if there is no entry to the peer */ AJ_Status AJ_GetGroupKey(const char* name, uint8_t* key); /** * Handle an add match reply message * * @param msg The add match reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_GUID_HandleAddMatchReply(AJ_Message* msg); /** * Handle a remove match reply message * * @param msg The remove match reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_GUID_HandleRemoveMatchReply(AJ_Message* msg); /** * Handle a name has owner reply message * * @param msg The name has owner reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_GUID_HandleNameHasOwnerReply(AJ_Message* msg); /** * Handle a name owner changed message * * @param msg The name owner changed message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_GUID_HandleNameOwnerChanged(AJ_Message* msg); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_helper.h000066400000000000000000000314431271074662300155110ustar00rootroot00000000000000#ifndef _AJ_HELPER_H #define _AJ_HELPER_H /** * @file aj_helper.h * @defgroup aj_helper Helper Functions * @{ * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #ifdef __cplusplus extern "C" { #endif #define AJ_JOINSESSION_REPLY_SUCCESS 1 /**< JoinSession reply: Success */ #define AJ_JOINSESSION_REPLY_NO_SESSION 2 /**< JoinSession reply: Session with given name does not exist */ #define AJ_JOINSESSION_REPLY_UNREACHABLE 3 /**< JoinSession reply: Failed to find suitable transport */ #define AJ_JOINSESSION_REPLY_CONNECT_FAILED 4 /**< JoinSession reply: Connect to advertised address */ #define AJ_JOINSESSION_REPLY_REJECTED 5 /**< JoinSession reply: The session creator rejected the join req */ #define AJ_JOINSESSION_REPLY_BAD_SESSION_OPTS 6 /**< JoinSession reply: Failed due to session option incompatibilities */ #define AJ_JOINSESSION_REPLY_ALREADY_JOINED 7 /**< JoinSession reply: Caller has already joined this session */ #define AJ_JOINSESSION_REPLY_FAILED 10 /**< JoinSession reply: Failed for unknown reason */ /** * Callback function prototype for a callback function to handle a method or signal * * @param msg The message received * @param reply The method reply (NULL if msg is a signal or method reply) * * @return Return AJ_Status * - AJ_OK if the message was correctly decoded (and a reply sent in the case of a method call) * - An error status if something went wrong decoding the message */ typedef AJ_Status (*MessageHandler)(AJ_Message* msg, AJ_Message* reply); /** * Callback function prototype for a callback function to handle new sessions * * @param msg The message received * * @return Return uint8_t * - TRUE if the service should allow the session * - FALSE if the service should *NOT* allow the session */ typedef uint8_t (*AcceptSessionHandler)(AJ_Message* msg); /** * Callback function prototype to indicate when the Daemon connection status changes * * @param connected TRUE if connected, FALSE if disconnected */ typedef void (*ConnectionHandler)(uint8_t connected); /** * Type to describe a mapping of message id to message handler. */ typedef struct { uint32_t msgid; MessageHandler handler; } MessageHandlerEntry; /** * Type to describe a mapping of property get/set message id * to get/set handler with context pointer */ typedef struct { uint32_t msgid; AJ_BusPropGetCallback callback; void* context; } PropHandlerEntry; /** * Type to describe the AllJoyn service configuration */ typedef struct { const char* daemonName; /**< Name of a specific daemon service to connect to, NULL for the default name. */ uint32_t connect_timeout; /**< How long to spend attempting to connect to the bus */ uint8_t connected; /**< Whether the bus attachment is already connected to the daemon bus */ uint16_t session_port; /**< The port to bind */ const char* service_name; /**< The name being requested */ uint32_t flags; /**< An OR of the name request flags */ const AJ_SessionOpts* opts; /**< The session option setting. */ AJ_AuthPwdFunc password_callback; /**< The auth password callback */ uint32_t link_timeout; /**< The daemon connection's link timeout */ AcceptSessionHandler acceptor; /**< The AcceptSession callback */ ConnectionHandler connection_handler; /**< A callback for when the daemon connection status changes */ const MessageHandlerEntry* message_handlers; /**< An array of message handlers */ const PropHandlerEntry* prop_handlers; /**< An array of property get/set handlers */ AJ_FactoryResetFunc factory_reset_callback; /**< The factory reset callback */ AJ_PolicyChangedFunc policy_changed_callback; /**< The policy changed callback */ } AllJoynConfiguration; /** * Helper function that connects to a bus initializes an AllJoyn service. * * @param bus The bus attachment * @param config The AllJoyn configuration object * * @return AJ_OK if service was successfully run to completion. */ AJ_Status AJ_RunAllJoynService(AJ_BusAttachment* bus, AllJoynConfiguration* config); /** * Callback function prototype for a timer function callback * * @param context The context pointer passed in to AJ_SetTimer */ typedef void (*TimeoutHandler)(void* context); /** * Start a timer * * @param relative_time The time (relative to now) when the timer should first go off * @param handler The callback to execute after milliseconds * @param context The context pointer that will be passed into the handler * @param repeat If nonzero, repeat this timer every msec * * @return The id of the new timer, which can be used to cancel it later * 0 if timer was not set. */ uint32_t AJ_SetTimer(uint32_t relative_time, TimeoutHandler handler, void* context, uint32_t repeat); /** * Cancel the timer specified * * @param id The id of the timer to cancel (returned by AJ_SetTimer) */ void AJ_CancelTimer(uint32_t id); /** * Helper function that connects to a bus initializes an AllJoyn service. * * @param bus The bus attachment * @param daemonName Name of a specific daemon service to connect to, NULL for the default name. * @param timeout How long to spend attempting to connect to the bus * @param connected Whether the bus attachment is already connected to the daemon bus * @param port The port to bind * @param name The name being requested * @param flags An OR of the name request flags * @param opts The session option setting. * * @return AJ_OK if service was successfully started. */ AJ_EXPORT AJ_Status AJ_StartService(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, uint16_t port, const char* name, uint32_t flags, const AJ_SessionOpts* opts); /** * @deprecated * Initializes an AllJoyn client and connect to a service. Note that this function is deprecated * and AJ_StartClientByName() should be used instead. * * @param bus The bus attachment * @param daemonName Name of a specific daemon service to connect to, NULL for the default name. * @param timeout How long to spend attempting to find a remote service to connect to. * @param connected Whether the bus attachment is already connected to the daemon bus. * @param name The name of the service to connect to. * @param port The service port to connect to. * @param[out] sessionId The session id returned if the connection was successful * @param opts The session option setting. * * @return AJ_OK if connection was successfully established */ AJ_EXPORT AJ_Status AJ_StartClient(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const char* name, uint16_t port, uint32_t* sessionId, const AJ_SessionOpts* opts); /** * Initializes an AllJoyn client and connect to a service * * @param bus The bus attachment * @param daemonName Name of a specific daemon service to connect to, NULL for the default name. * @param timeout How long to spend attempting to find a remote service to connect to. * @param connected Whether the bus attachment is already connected to the daemon bus. * @param name The name of the service to connect to. * @param port The service port to connect to. * @param[out] sessionId The session id returned if the connection was successful * @param opts The session option setting. * @param[out] fullName This buffer passed in will be filled with the full service name if the connection * was successful. The buffer should be of size AJ_MAX_SERVICE_NAME_SIZE or buffer overflow may occur. * * @return AJ_OK if connection was successfully established */ AJ_EXPORT AJ_Status AJ_StartClientByName(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const char* name, uint16_t port, uint32_t* sessionId, const AJ_SessionOpts* opts, char* fullName); /** * Initialize an AllJoyn client, discover service by interface name, and connect. * * @param bus The bus attachment * @param daemonName Name of a specific daemon service to connect to, NULL for the default name. * @param timeout How long to spend attempting to find a remote service to connect to. * @param connected Whether the bus attachment is already connected to the daemon bus. * @param interfaces Find a service that implements these interface(s) (NULL-terminated list of names) * @param[out] sessionId The session id if the connection was successful * @param[out] uniqueName The unique name of the service if the connection was successful (supply array of size AJ_MAX_NAME_SIZE+1) * @param opts The session option setting. * * @return AJ_OK if connection was successfully established */ AJ_EXPORT AJ_Status AJ_StartClientByInterface(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const char** interfaces, uint32_t* sessionId, char* uniqueName, const AJ_SessionOpts* opts); #ifdef ANNOUNCE_BASED_DISCOVERY /** * Initialize an AllJoyn client, discover service by peer description, and connect. * * @param bus The bus attachment * @param daemonName Name of a specific daemon service to connect to, NULL for the default name. * @param timeout How long to spend attempting to find a remote service to connect to. * @param connected Whether the bus attachment is already connected to the daemon bus. * @param peerDesc Find a peer that matched the description i.e. that implements thes interface(s) and register match callbacks * @param port The service port to connect to. If value is 0 use the About port in the Announcement. * @param[out] sessionId The session id if the connection was successful * @param[out] uniqueName The unique name of the service if the connection was successful (supply array of size AJ_MAX_NAME_SIZE+1) * @param opts The session option setting. * * @return AJ_OK if connection was successfully established * * This function is experimental, and as such has not been fully tested. * Please help make it more solid by contributing fixes if you find issues. */ AJ_EXPORT AJ_Status AJ_StartClientByPeerDescription(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const AJ_AboutPeerDescription* peerDesc, uint16_t port, uint32_t* sessionId, char* uniqueName, const AJ_SessionOpts* opts); #endif #ifdef __cplusplus } #endif /** * @} */ #endif /* _AJ_HELPER_H */ ajtcl-16.04/inc/aj_init.h000066400000000000000000000025211271074662300151700ustar00rootroot00000000000000#ifndef _AJ_INIT_H #define _AJ_INIT_H /** * @file aj_init.h * @defgroup aj_init Initialization * @{ * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #ifdef __cplusplus extern "C" { #endif /** * Initialization for AllJoyn. This function should be called before calling any * other AllJoyn APIs. */ AJ_EXPORT void AJ_Initialize(void); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_introspect.h000066400000000000000000000622121271074662300164220ustar00rootroot00000000000000#ifndef _AJ_INTROSPECT_H #define _AJ_INTROSPECT_H /** * @file aj_introspect.h * @defgroup aj_introspect Introspection Support * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Support for introspection */ /** * An interface description is a NULL terminated array of strings. The first string is the interface * name. The subsequent strings are a compact representation of the members of the interface. In * this representation special characters encode information about the members, whitespace is * significant. * * If the first character of the interface name is a '$' character this indicates that the interface * is secure and only authenticated peers can make method calls and received signals defined in the * interface. If the first character of the interface name is a '#' character this indicates that * security is not applicable to this interface even if the interface is implemented by an otherwise * secure object. The '$' and '#' characters are merely signifiers and are not part of the interface * name. * * The first character of a member string identifies the type of member: * * A '?' character indicates the member is a METHOD * A '!' character indicates the member is a SIGNAL * A '@' character indicates the member is a PROPERTY * * The type character is a signifier, it is not part of the member name. Characters following the * member type character up to the end of the string or to the first space character comprise the * member names. If the member is a METHOD or SIGNAL the remaining characters encode the argument * names, direction (IN or OUT) and the argument type as a standard AllJoyn signature string. For * SIGNALS for correctness the direction should be specified as OUT but it really doesn't matter as * the direction is ignored. * * Arguments are separated by a single space character. Argument names are optional and if present are * all characters between the space character and the directions character. All characters after the * direction character up to the next space or the end of the string are the argument type. The * argument direction is specified as follows: * * A '>' character indicates the argument is an OUT parameter. * A '<' character indicates the argument is an IN parameter. * * If the member is a PROPERTY the member name is terminated by an access rights character which is * immediately followed by the property type signature. The access rights for a property are * READ_ONLY, WRITE_ONLY and READ_WRITE. The access rights are specified as follows: * * A '>' character indicates the argument is READ_ONLY (i.e. an OUT parameter) * A '<' character indicates the argument is WRITE_ONLY (i.e. an IN parameter) * A '=' character indicates the argument is READ/WRITE * @code static const char* const ExampleInterface[] = { "org.alljoyn.example", // The interface name "?StringPing inStr", // A method called StringPing with an IN arg and OUT arg of type string "?Hello", // A method call with no arguments "?Add i", // A method call that takes two integers and returns an integer. The args are not named "!ListChanged >a{ys}", // A signal that returns a dictionary "@TimeNow>(yyy)", // A READ_ONLY property that returns a struct with three 8 bit integers "@Counter=u", // A READ/WRITE property "@SecretKey> 4) - 2) #define SIGNAL MEMBER_TYPE('!') /* ((0x21 >> 4) - 2) == 0 */ #define METHOD MEMBER_TYPE('?') /* ((0x3F >> 4) - 2) == 1 */ #define PROPERTY MEMBER_TYPE('@') /* ((0x40 >> 4) - 2) == 2 */ #define WRITE_ONLY '<' /* 0x3C */ #define READ_WRITE '=' /* 0x3D */ #define READ_ONLY '>' /* 0x3E */ #define SECURE_TRUE '$' /* Security is required for an interface that start with a '$' character */ #define SECURE_OFF '#' /* Security is OFF, i.e. never required for an interface that starts with a '#' character */ #define SESSIONLESS '&' /* Only to be used with a signal member types, indicates that the signal will not require a session and is a sessionless signal */ /** * Enmeration type for characterizing interface members */ typedef enum { AJ_INVALID_MEMBER = 0, /**< Invalid member */ AJ_SIGNAL_MEMBER = '!', /**< Member is a signal */ AJ_METHOD_MEMBER = '?', /**< Member is a method call */ AJ_PROPERTY_MEMBER = '@' /**< Member is a property */ } AJ_MemberType; /** * Type for an interface description - NULL terminated array of strings. */ typedef const char* const* AJ_InterfaceDescription; /* * AJ_DESCRIPTION_ID(BusObject base ID, Interface index, Member index, Arg index) * Interface, Member, and Arg indexes starts at 1 and represent the readible index in a list. * [ a, b, ... ] a would be index 1, b 2, etc. */ #define AJ_DESCRIPTION_ID(o, i, m, a) ((((uint32_t)(o)) << 24) | (((uint32_t)(i)) << 16) | (((uint32_t)(m)) << 8) | (a)) /* Helper macros for reuse of the message and property Ids from the AJ_ENCODE_*_ID macros: */ /* * AJ_DESC_ID_FROM_MSG_ID(msgId, argIdx) * msgId Id of the method or the signal member * argIdx starts at 1 as in (a) in AJ_DESCRIPTION_ID. argIdx 0 indicate the interface member itself (i.e. method or signal) instead of the member's arguments. */ #define AJ_DESC_ID_FROM_MSG_ID(msgId, argIdx) (((uint32_t)(((uint32_t)(msgId) & 0xFFFFFF) + 0x101) << 8) | argIdx) /* * AJ_DESC_ID_FROM_PROP_ID(propId) * propId Id of the property member */ #define AJ_DESC_ID_FROM_PROP_ID(propId) ((uint32_t)(((uint32_t)(propId) & 0xFFFFFF) + 0x101) << 8) /* * AJ_DESC_ID_FROM_OBJ_INDEX(objIdx) * objIdx index of the object in its registered object list */ #define AJ_DESC_ID_FROM_OBJ_INDEX(objIdx) (((uint32_t)(objIdx) & 0xFF) << 24) /* * AJ_DESC_ID_FROM_INTERFACE_INDEX(objIdx, ifaceIdx) * objIdx index of the object in its registered object list * ifaceIdx index of the interface in the object description for this object index. */ #define AJ_DESC_ID_FROM_INTERFACE_INDEX(objIdx, ifaceIdx) (AJ_DESC_ID_FROM_OBJ_INDEX(objIdx) | (((uint32_t)(ifaceIdx) & 0xFF) + 0x1)) << 16)) /* end of helper macros */ /** * Function pointer type for an abstracted Description lookup function * * @param descId The encoded id that represents the request description value * @param lang The language that is being asked for */ typedef const char* (*AJ_DescriptionLookupFunc)(uint32_t descId, const char* lang); #define AJ_OBJ_FLAG_SECURE 0x01 /**< If set this bit indicates that an object is secure */ #define AJ_OBJ_FLAG_HIDDEN 0x02 /**< If set this bit indicates this is object is not announced */ #define AJ_OBJ_FLAG_DISABLED 0x04 /**< If set this bit indicates that method calls cannot be made to the object at this time */ #define AJ_OBJ_FLAG_ANNOUNCED 0x08 /**< If set this bit indicates this object is announced by ABOUT */ #define AJ_OBJ_FLAG_IS_PROXY 0x10 /**< If set this bit indicates this object is a proxy object */ #define AJ_OBJ_FLAG_DESCRIBED 0x20 /**< If set this bit indicates this object has descriptions and is announced by ABOUT with 'org.allseen.Introspectable' interface added to the announcement */ #define AJ_OBJ_FLAGS_ALL_INCLUDE_MASK 0xFF /**< The include filter mask for the object iterator indicating ALL objects */ /** * Type for an AllJoyn object description */ typedef struct _AJ_Object { const char* path; /**< object path */ const AJ_InterfaceDescription* interfaces; /**< interface descriptor */ uint8_t flags; /**< flags for the object */ void* context; /**< an application provided context pointer for this object */ } AJ_Object; /** * The root object */ extern const AJ_Object AJ_ROOT_OBJECT; /* * When a message unmarshalled the message is validated by matching it against a list of object * tables that fully describe the message. If the message matches the unmarshal code sets the msgId * field in the AJ_Message struct. Rather than using a series of string comparisons, application code * can simply use this msgId to identify the message. There are three predefined object tables and * applications and services are free to add additional tables. The maximum number of table is 127 * because the most signifant bit in the msgId is reserved to distinguish between method calls and * their corresponding replies. * * Of the three predefined tables the first is reserved for bus management messages. The second is * for objects implemented by the application. The third is for proxy (remote) objects the * application interacts with. * * The same message identifiers are also used by the marshalling code to populate the message header * with the appropriate strings for the object path, interface name, member, and signature. This * relieves the application developer from having to explicitly set these values in the message. */ #define AJ_BUS_ID_FLAG 0x00 /**< Identifies that a message belongs to the set of builtin bus object messages */ #define AJ_APP_ID_FLAG 0x01 /**< Identifies that a message belongs to the set of objects implemented by the application */ #define AJ_PRX_ID_FLAG 0x02 /**< Identifies that a message belongs to the set of objects implemented by remote peers */ /* * This flag AJ_REP_ID_FLAG is set in the msgId filed to indentify that a message is a reply to a * method call. Because the object description describes the out (call) and in (reply) arguments the * same entry in the object table is used for both method calls and replies but since they are * handled differently this flags is set by the unmarshaller to indicate whether the specific * message is the call or reply. */ #define AJ_REP_ID_FLAG 0x80 /**< Indicates a message is a reply message */ /* * Macros to encode a message or property id from object table index, object path, interface, and member indices. */ #define AJ_ENCODE_MESSAGE_ID(o, p, i, m) (((uint32_t)(o) << 24) | (((uint32_t)(p)) << 16) | (((uint32_t)(i)) << 8) | (m)) /**< Encode a message id */ #define AJ_ENCODE_PROPERTY_ID(o, p, i, m) (((uint32_t)(o) << 24) | (((uint32_t)(p)) << 16) | (((uint32_t)(i)) << 8) | (m)) /**< Encode a property id */ /* * Macros for encoding the standard bus and applications messages */ #define AJ_BUS_MESSAGE_ID(p, i, m) AJ_ENCODE_MESSAGE_ID(AJ_BUS_ID_FLAG, p, i, m) /**< Encode a message id from bus object */ #define AJ_APP_MESSAGE_ID(p, i, m) AJ_ENCODE_MESSAGE_ID(AJ_APP_ID_FLAG, p, i, m) /**< Encode a message id from application object */ #define AJ_PRX_MESSAGE_ID(p, i, m) AJ_ENCODE_MESSAGE_ID(AJ_PRX_ID_FLAG, p, i, m) /**< Encode a message id from proxy object */ /* * Macros for encoding the standard bus and application properties */ #define AJ_BUS_PROPERTY_ID(p, i, m) AJ_ENCODE_PROPERTY_ID(AJ_BUS_ID_FLAG, p, i, m) /**< Encode a property id from bus object */ #define AJ_APP_PROPERTY_ID(p, i, m) AJ_ENCODE_PROPERTY_ID(AJ_APP_ID_FLAG, p, i, m) /**< Encode a property id from application object */ #define AJ_PRX_PROPERTY_ID(p, i, m) AJ_ENCODE_PROPERTY_ID(AJ_PRX_ID_FLAG, p, i, m) /**< Encode a property id from proxy object */ /** * Macro to generate the reply message identifier from method call message. This is the message * identifier in the reply context. */ #define AJ_REPLY_ID(id) ((id) | (uint32_t)(AJ_REP_ID_FLAG << 24)) /** * Register an object list with a specific index. This overrides any existing object list * registered at the specified index. * * @param objList A NULL terminated array of object info structs. * @param index The index for the object list to register. * * @return - AJ_OK if the object list was succesfully registered * - AJ_ERR_RANGE if the index is outside the allowed range * - AJ_ERR_DISALLOWED if the index is a predefined object index */ AJ_EXPORT AJ_Status AJ_RegisterObjectList(const AJ_Object* objList, uint8_t index); /** * Add all currently registered object list to the access control list. * * @return - AJ_OK on success * - AJ_ERR_RESOURCES otherwise */ AJ_EXPORT AJ_Status AJ_RegisterObjectsACL(); /** * Register an object list with a specific index providing also a lookup function for the descriptions of objects in the list. * This overrides any existing object list and lookup function registered at the specified index. * * @param objList A NULL terminated array of object info structs. * @param index The index for the object list to register. * @param descLookup A lookup function for the descriptions of the describable items namely the objects, interfaces, members and arguments. * * @return - AJ_OK if the object list was succesfully registered * - AJ_ERR_RANGE if the index is outside the allowed range * - AJ_ERR_DISALLOWED if the index is a predefined object index */ AJ_EXPORT AJ_Status AJ_RegisterObjectListWithDescriptions(const AJ_Object* objList, uint8_t index, AJ_DescriptionLookupFunc descLookup); /** * Register a local array of languages that will allow for a description to be supplied. * * @param languages The NULL-terminated list of languages that are supported for descriptions. */ AJ_EXPORT void AJ_RegisterDescriptionLanguages(const char* const* languages); /** * Register the local objects and the remote objects for this application. Local objects have * methods that remote applications can call, have properties that a remote application can GET or * SET or define signals that the local application can emit. Proxy objects describe the remote * objects that have methods that this object can call and signals * that remote objects emit that this application can receive. * * @param localObjects A NULL terminated array of object info structs. * @param proxyObjects A NULL terminated array of object info structs. */ AJ_EXPORT void AJ_RegisterObjects(const AJ_Object* localObjects, const AJ_Object* proxyObjects); /** * Object iterator type - treat as opaque */ typedef struct { uint8_t fin; uint8_t fex; uint8_t l; uint16_t n; } AJ_ObjectIterator; /** * Initialize announce object iterator. * * @param iter Struct for maintaining object iterator state * @param inFlags Object flags included in the iteration (logical AND with the object flags) * @param exFlags Object flags excluded from the iteration (logical AND with the object flags) * * * @return Returns the first iterated object. Call AJ_NextAnnounceObject to return successive * objects. */ AJ_EXPORT const AJ_Object* AJ_InitObjectIterator(AJ_ObjectIterator* iter, uint8_t inFlags, uint8_t exFlags); /** * Returns the next iterated object */ AJ_EXPORT const AJ_Object* AJ_NextObject(AJ_ObjectIterator* iter); /** * This function checks that a message ifrom a remote peer is valid and correct and returns the * message id for that message. * * For method calls this function checks that the object is one of the registered objects, checks * that the interface and method are implemented by the object and checks that the signature is * correct. * * For signals this function checks that the interface is a known interface, the signal name is * defined for that interface, and the signature is correct. * * For method replies and error message this function matches the serial number of the response to * the serial number in the list of reply contexts. If the reply matches the signature is checked. * * If everything is correct the the message identifier is set in the message struct * * @param msg The message to identify * * @return Return AJ_Status */ AJ_Status AJ_IdentifyMessage(AJ_Message* msg); /** * This function unmarshals the first two arguments of a property SET or GET message, identifies * which property the method is accessing and returns the id for the property. * * @param msg The property GET or SET message to identify * @param propId Returns the id for the identified property * @param sig Pointer to string to return the signature * * @return Return AJ_Status * - ER_OK if the property was identified * - AJ_ERR_NO_MATCH if there is no matching property * - AJ_ERR_DISALLOWED if the property exists but has access rights do not permit the requested GET or SET operation. */ AJ_EXPORT AJ_Status AJ_UnmarshalPropertyArgs(AJ_Message* msg, uint32_t* propId, const char** sig); /** * This function marshals the first two arguments of a property SET or GET message. * * @param msg The property GET or SET message to be initialized * @param propId The the id for the specified property * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalPropertyArgs(AJ_Message* msg, uint32_t propId); /** * This function marshals ALL the properties arguments (names and values) of a given interface of a property GET_ALL message. * * If everything is correct the reply message contains the marshalled response with the ALL the properties * defined for the given interface of the object associated with the request. Otherwise, an error reply * message is marshalled with the last error status. * * @param replyMsg The message to marshal the reply into. Assumes the message header is already set by a previous call to AJ_MarshalReplyMsg(). * @param iface The interface name (obtained from the request) whose properties are to be marshalled. * @param callback The function called to request the application to marshal each property value. * @param context A caller provided context that is passed into the callback function. * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalAllPropertiesArgs(AJ_Message* replyMsg, const char* iface, AJ_BusPropGetCallback callback, void* context); /** * Get the introspection data * * @param msg The introspection request method call * @param reply The reply to the introspection request * * @return Return AJ_Status */ AJ_Status AJ_GetIntrospectionData(const AJ_Message* msg, AJ_Message* reply); /** * @deprecated - use AJ_GetIntrospectionData() instead * Handle an introspection request * * @param msg The introspection request method call * @param reply The reply to the introspection request * @param languageTag The language that descriptions should be returned in if supported, else default lang used * * @return Return AJ_Status */ AJ_Status AJ_HandleIntrospectRequest(const AJ_Message* msg, AJ_Message* reply, const char* languageTag); /** * Handle a request to get the supported description languages * * @param msg The get description languages method call * @param reply The reply to the get description languages request * */ AJ_Status AJ_HandleGetDescriptionLanguages(const AJ_Message* msg, AJ_Message* reply); /** * Internal function for initializing a message from information obtained via the message id. * * @param msg The message to initialize * @param msgId The message id * @param msgType The type of the message * * @return Return AJ_Status */ AJ_Status AJ_InitMessageFromMsgId(AJ_Message* msg, uint32_t msgId, uint8_t msgType, uint8_t* secure); /** * Set or update the object path on a proxy object entry. This function makes is used for making * method calls to remote objects when the object path is not known until runtime. Note the proxy * object table cannot be declared as const in this case. * * @param proxyObjects Pointer to the proxy object table (for validation purposes) * @param msgId The message identifier for the methods * @param objPath The object path to set. This value must remain valid while the method is * being marshaled. * * @return - AJ_OK if the object path was sucessfully set. * - AJ_ERR_OBJECT_PATH if the object path is NULL or invalid. * - AJ_ERR_NO_MATCH if the message id does not identify a proxy object method call. */ AJ_EXPORT AJ_Status AJ_SetProxyObjectPath(AJ_Object* proxyObjects, uint32_t msgId, const char* objPath); /** * Internal function to allocate a reply context for a method call message. Reply contexts are used * to associate method replies with method calls. Depending on avaiable system resources the number * of reply contexts may be very limited, in some cases only one reply context. * * @param msg A method call message that needs a reply context * @param timeout The time to wait for a reply (0 to use the internal default) * * @return Return AJ_Status * - AJ_OK if the reply context was allocated * - AJ_ERR_RESOURCES if the reply context could not be allocated */ AJ_Status AJ_AllocReplyContext(AJ_Message* msg, uint32_t timeout); /** * Internal function to release all reply contexts. Called when disconnecting from the bus. */ void AJ_ReleaseReplyContexts(void); /** * Internal function to check for timed out method calls. Returns TRUE and sets some information in * the message struct to identify the timed-out call if there was one. This function is called by * AJ_UnmarshalMessage() when there are no messages to unmarshal. * * @param msg A message structure to initialize if there was a timed-out method call. * * @return Returns TRUE if there was a timed-out method call, FALSE otherwise. */ uint8_t AJ_TimedOutMethodCall(AJ_Message* msg); /** * Internal function called to release a reply context in the case that a message could not be marshaled. * * @param msg The message that a reply context might have been allocated for. */ void AJ_ReleaseReplyContext(AJ_Message* msg); /** * Recursively set and/or clear the object flags on an application object and all the children of * the object. This function can be called to disable, hide, or secure and entire object tree. Note * that to use this funcion the application object list must not be declared as const. * * To disable an application object and all of its children recursively * @code * AJ_SetObjectFlags("/foo/bar", AJ_OBJ_FLAG_DISABLED, 0); * @endcode * * To enable an application object and all of its children recursively but leave them hidden * @code * AJ_SetObjectFlags("/foo/bar", AJ_OBJ_FLAG_HIDDEN, AJ_OBJ_FLAG_DISABLED); * @endcode * * @param objPath The object path for the parent object to set the flags on * @param setFlags The flags to set OR'd together * @param clearFlags The flags to clear OR'd together * * @return Return AJ_Status * - ER_OK if the flags were set * - AJ_ERR_NO_MATCH if there are no matching objects */ AJ_EXPORT AJ_Status AJ_SetObjectFlags(const char* objPath, uint8_t setFlags, uint8_t clearFlags); /** * Returns the member type for a given message or property Id. Returns 0 if the * identifier is not a message or property identifier. * * @param identifier The identifier to characterize. * @param member If not NULL returns the member string * @param isSecure If not NULL returns TRUE if the member is secure either because the interface * is secure or the object instance is secure. * * @return One of the AJ_MemberType enumeration values. */ AJ_EXPORT AJ_MemberType AJ_GetMemberType(uint32_t identifier, const char** member, uint8_t* isSecure); /** * Debugging aid that prints out the XML for an object table * * @param objs A NULL terminated array of object info structs. */ #ifdef NDEBUG #define AJ_PrintXML(objs) #else AJ_EXPORT void AJ_PrintXML(const AJ_Object* objs); #endif /** * Debugging aid that prints out the XML for an object table * * @param objs A NULL terminated array of object info structs. * @param languageTag The language that descriptions should be returned in if supported, else default lang used */ #ifdef NDEBUG #define AJ_PrintXMLWithDescriptions(...) #else AJ_EXPORT void AJ_PrintXMLWithDescriptions(const AJ_Object* objs, const char* languageTag); #endif /** * Hook for unit testing marshal/unmarshal */ #ifndef NDEBUG typedef AJ_Status (*AJ_MutterHook)(AJ_Message* msg, uint32_t msgId, uint8_t msgType); #endif #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_link_timeout.h000066400000000000000000000064321271074662300167350ustar00rootroot00000000000000#ifndef _AJ_LINK_TIMEOUT_H #define _AJ_LINK_TIMEOUT_H /** * @file aj_link_timeout.h * @defgroup aj_link_timeout Daemon Connection Keepalive Support * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /** * Enable link timeout for the connection between the application and the daemon bus. If there are * no link activities during that period, at most 3 probe packets are sent to the daemon bus with * an interval of 5 seconds. If none of the probe packets are acknowledged by the daemon bus due * to any resons (eg., WIFI is off), AJ_BusLinkStateProc will return AJ_ERR_LINK_TIMEOUT * so that the application has to re-connect to the daemon bus. * * @param bus The bus attachment to which the app is connected to * @param timeout The time unit is second. The minimum value is 40. * * @return Return AJ_Status * - AJ_OK if the bus link timeout is set successfully * - AJ_ERR_FAILURE if timeout is 0 */ AJ_EXPORT AJ_Status AJ_SetBusLinkTimeout(AJ_BusAttachment* bus, uint32_t timeout); /** * Call to notify that the bus link is currently active. This is implicitly implied upon receiving packets from the bus. */ AJ_EXPORT void AJ_NotifyLinkActive(); /** * Call to do the work of bus link maintainance. * * @return Return AJ_Status * - AJ_ERR_LINK_TIMEOUT if the bus link is considered as dead. The application has to re-connect to the daemon bus. * - AJ_OK otherwise */ AJ_EXPORT AJ_Status AJ_BusLinkStateProc(AJ_BusAttachment* bus); /** * Set the idle timeouts from the Routing node to the TCL. * * @param bus The bus attachment to which the app is connected to * @param idleTo Requested Idle Timeout for the link. i.e. time after which the Routing node * must send a DBus ping to Leaf node in case of inactivity. * Use 0 to leave unchanged. * @param probeTo Requested Probe timeout. The time from the Routing node sending the DBus * ping to the expected response. * Use 0 to leave unchanged. * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_EXPORT AJ_Status AJ_SetIdleTimeouts(AJ_BusAttachment* bus, uint32_t idleTo, uint32_t probeTo); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_msg.h000066400000000000000000000741761271074662300150320ustar00rootroot00000000000000#ifndef _AJ_MSG_H #define _AJ_MSG_H /** * @file aj_msg.h * @defgroup aj_msg Message Marshaling and Unmarshaling * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* * Message argument types */ #define AJ_ARG_INVALID '\0' /**< AllJoyn invalid type */ #define AJ_ARG_ARRAY 'a' /**< AllJoyn array container type */ #define AJ_ARG_BOOLEAN 'b' /**< AllJoyn boolean basic type */ #define AJ_ARG_DOUBLE 'd' /**< AllJoyn IEEE 754 double basic type */ #define AJ_ARG_SIGNATURE 'g' /**< AllJoyn signature basic type */ #define AJ_ARG_HANDLE 'h' /**< AllJoyn socket handle basic type */ #define AJ_ARG_INT32 'i' /**< AllJoyn 32-bit signed integer basic type */ #define AJ_ARG_INT16 'n' /**< AllJoyn 16-bit signed integer basic type */ #define AJ_ARG_OBJ_PATH 'o' /**< AllJoyn Name of an AllJoyn object instance basic type */ #define AJ_ARG_UINT16 'q' /**< AllJoyn 16-bit unsigned integer basic type */ #define AJ_ARG_STRING 's' /**< AllJoyn UTF-8 NULL terminated string basic type */ #define AJ_ARG_UINT64 't' /**< AllJoyn 64-bit unsigned integer basic type */ #define AJ_ARG_UINT32 'u' /**< AllJoyn 32-bit unsigned integer basic type */ #define AJ_ARG_VARIANT 'v' /**< AllJoyn variant container type */ #define AJ_ARG_INT64 'x' /**< AllJoyn 64-bit signed integer basic type */ #define AJ_ARG_BYTE 'y' /**< AllJoyn 8-bit unsigned integer basic type */ #define AJ_ARG_STRUCT '(' /**< AllJoyn struct container type */ #define AJ_ARG_DICT_ENTRY '{' /**< AllJoyn dictionary or map container type - an array of key-value pairs */ /* * Message argument flags */ #define AJ_ARRAY_FLAG 0x01 /**< Indicates an argument is an array */ /* * Endianess flag. This is the first byte of a message */ #define AJ_LITTLE_ENDIAN 'l' /**< Indicates the bus is little-endian */ #define AJ_BIG_ENDIAN 'B' /**< Indicates the bus is big-endian */ /* * Set the native endianness */ #if HOST_IS_BIG_ENDIAN #define AJ_NATIVE_ENDIAN AJ_BIG_ENDIAN #else #define AJ_NATIVE_ENDIAN AJ_LITTLE_ENDIAN #endif /* * Message flags are or'd together */ #define AJ_NO_FLAGS 0x00 /**< No message flags */ #define AJ_FLAG_NO_REPLY_EXPECTED 0x01 /**< Not expecting a reply */ #define AJ_FLAG_AUTO_START 0x02 /**< Auto start the service */ #define AJ_FLAG_ALLOW_REMOTE_MSG 0x04 /**< Allow messeages from remote hosts */ #define AJ_FLAG_SESSIONLESS 0x10 /**< Sessionless message */ #define AJ_FLAG_GLOBAL_BROADCAST 0x20 /**< Global (bus-to-bus) broadcast */ #define AJ_FLAG_COMPRESSED 0x40 /**< Header is compressed */ #define AJ_FLAG_ENCRYPTED 0x80 /**< Body is encrypted */ #define ALLJOYN_FLAG_SESSIONLESS 0x10 /**< Deprecated: Use AJ_FLAG_SESSIONLESS instead */ /* * Wire protocol version number */ #define AJ_MAJOR_PROTOCOL_VERSION 1 /**< AllJoyn protocol version */ /* * Message types */ #define AJ_MSG_INVALID 0 /**< Invalid message type */ #define AJ_MSG_METHOD_CALL 1 /**< Method call message type */ #define AJ_MSG_METHOD_RET 2 /**< Method return message type */ #define AJ_MSG_ERROR 3 /**< Error message type */ #define AJ_MSG_SIGNAL 4 /**< Signal message type */ /* * Header field types */ #define AJ_HDR_INVALID 0x00 /**< Invalid header field type */ #define AJ_HDR_OBJ_PATH 0x01 /**< Object path header field type */ #define AJ_HDR_INTERFACE 0x02 /**< Message interface header field type */ #define AJ_HDR_MEMBER 0x03 /**< Member (message/signal) name header field type */ #define AJ_HDR_ERROR_NAME 0x04 /**< Error name header field type */ #define AJ_HDR_REPLY_SERIAL 0x05 /**< Reply serial number header field type */ #define AJ_HDR_DESTINATION 0x06 /**< Message destination header field type */ #define AJ_HDR_SENDER 0x07 /**< Sender well-known name header field type */ #define AJ_HDR_SIGNATURE 0x08 /**< Message signature header field type */ #define AJ_HDR_HANDLES 0x09 /**< Number of file/socket handles that accompany the message */ #define AJ_HDR_TIMESTAMP 0x10 /**< Time stamp header field type (AllJoyn specific headers start at 0x10. Time stamp header field type) */ #define AJ_HDR_TIME_TO_LIVE 0x11 /**< Messages time-to-live header field type */ #define AJ_HDR_COMPRESSION_TOKEN 0x12 /**< Messages compression token header field type */ #define AJ_HDR_SESSION_ID 0x13 /**< Session id header field type */ /** * Maximum string length of a service (including null terminator) */ #define AJ_MAX_SERVICE_NAME_SIZE 256 /** * Type for a message argument */ struct _AJ_Arg { uint8_t typeId; /**< the argument type */ uint8_t flags; /**< non-zero if the value is a variant - values > 1 indicate variant-of-variant etc. */ uint16_t len; /**< length of a string or array in bytes */ /* * Union of the various argument values. */ union { uint8_t* v_byte; /**< byte type field value in the message */ int16_t* v_int16; /**< int16 type field value in the message */ uint16_t* v_uint16; /**< uint16 type field value in the message */ uint32_t* v_bool; /**< boolean type field value in the message */ uint32_t* v_uint32; /**< uint32 type field value in the message */ int32_t* v_int32; /**< int32 type field value in the message */ int64_t* v_int64; /**< int64 type field value in the message */ uint64_t* v_uint64; /**< uint64 type field value in the message */ double* v_double; /**< double type field value in the message */ const char* v_string; /**< string(char *) type field value in the message */ const char* v_objPath; /**< objPath(char *) type field value in the message */ const char* v_signature; /**< signature(char *) type field value in the message */ const void* v_data; /**< data(void *) type field value in the message */ } val; /**< union of the field value in the message */ const char* sigPtr; /**< pointer to the signature */ struct _AJ_Arg* container; /**< container argument */ }; /** * AllJoyn Message Header */ typedef struct _AJ_MsgHeader { char endianess; /**< The endianness of this message */ uint8_t msgType; /**< Indicates if the message is method call, signal, etc. */ uint8_t flags; /**< Flag bits */ uint8_t majorVersion; /**< Major version of this message */ uint32_t bodyLen; /**< Length of the body data */ uint32_t serialNum; /**< serial of this message */ uint32_t headerLen; /**< Length of the header data */ } AJ_MsgHeader; /** * AllJoyn Message */ struct _AJ_Message { uint32_t msgId; /**< Identifies the message to the application */ AJ_MsgHeader* hdr; /**< The message header */ union { const char* objPath; /**< The nul terminated object path string or NULL */ uint32_t replySerial; /**< The reply serial number */ }; union { const char* member; /**< The nul terminated member name string or NULL */ const char* error; /**< The nul terminated error name string or NULL */ }; const char* iface; /**< The nul terminated interface string or NULL */ const char* sender; /**< The nul terminated sender string or NULL */ const char* destination; /**< The nul terminated destination string or NULL */ const char* signature; /**< The nul terminated signature string or NULL */ uint32_t sessionId; /**< Session id */ uint32_t timestamp; /**< Timestamp */ uint32_t ttl; /**< Time to live */ /* * Private message state - the application should not touch this data */ uint8_t sigOffset; /**< Offset to current position in the signature */ uint8_t varOffset; /**< For variant marshalling/unmarshalling - Offset to start of variant signature */ uint16_t bodyBytes; /**< Running count of the number body bytes written */ AJ_BusAttachment* bus; /**< Bus attachment for this message */ struct _AJ_Arg* outer; /**< Container arg current being marshaled */ uint32_t timeout; /**< Remaining time to wait for all bytes of this message */ uint32_t authVersion; /**< Authentication version used */ uint8_t expired; /**< For indicating whether the Rx message has expired */ AJ_MsgHeader raw; /**< The raw original message header (before endian swaps) */ }; /** * Reply context for deferred (asynchronous) method replies. */ typedef struct _AJ_MsgReplyContext { AJ_BusAttachment* bus; /**< Bus attachment */ uint32_t serialNum; /**< Serial number from the method call */ uint32_t msgId; /**< Message id from the method call */ uint32_t sessionId; /**< Session id from the method call */ uint8_t flags; /**< Flags from the method call */ char sender[AJ_MAX_NAME_SIZE + 1]; /**< Sender field from the method call */ } AJ_MsgReplyContext; /** * Unmarshals a message returning a message structure. Note that if a message is received but is not * recognized this function will return an uninitialized msg with msgId == 0. The application must * be prepared to handle this case. * * @param bus The bus attachment * @param msg Pointer to a structure to receive the unmarshalled message * @param timeout How long to wait for a message * * @return * - AJ_OK if a message header was succesfully unmarshaled. Note that the message may have * been consumed or rejected internally in which case the msgId will be zero. * - AJ_ERR_UNMARSHAL if the message was badly formed * - AJ_ERR_RESOURCES if the message header is too big to unmarshal into the attached buffer * - AJ_ERR_TIMEOUT if there was no message to unmarshal within the timeout period * - AJ_ERR_READ if there was a read failure */ AJ_EXPORT AJ_Status AJ_UnmarshalMsg(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t timeout); /** * Unmarshals the next argument from a message or next element in a container (array, struct, * dictionary entry, or variant). * * @param msg A pointer to a message that was unmarshaled by an earlier call to AJ_UnmarshalMsg * @param arg Pointer to unmarshal the argument * * @return * - AJ_OK if the argument was succesfully unmarshaled. * - AJ_ERR_UNMARSHAL if the arg was badly formed * - AJ_ERR_READ if there was a read failure * - AJ_ERR_NO_MORE when there is no more to unmarshal (typically for array and container elements) */ AJ_EXPORT AJ_Status AJ_UnmarshalArg(AJ_Message* msg, AJ_Arg* arg); /** * Unmarshals and discard the next argument from a message or next element in a container (array, * struct, dictionary entry). Variants must be skipped atomically, that is AJ_UnmarshalVariant() * should not be called. * * @param msg A pointer to a message that was unmarshaled by an earlier call to AJ_UnmarshalMsg * * @return * - AJ_OK if the argument was succesfully skipped. * - AJ_ERR_UNMARSHAL if the arg was badly formed * - AJ_ERR_READ if there was a read failure */ AJ_EXPORT AJ_Status AJ_SkipArg(AJ_Message* msg); /** * Attempts to reset the state of message so the arguments can be unmarshaled again. All of the * arguments must have been unmarshaled, a restriction to ensure that endianness conversions * are correct. This function allows a message handler to inspect the message arguments and * decide whether to handle it or not. For example a service handler might need to check if it * is supposed to accept a session joiner by inspecting the session port. * * @param msg A pointer to a message that was unmarshaled by an earlier call to AJ_UnmarshalMsg * * @return * - AJ_OK if the message arguments were succesfully reset * - AJ_ERR_UNMARSHAL if the arguments could not be reset */ AJ_EXPORT AJ_Status AJ_ResetArgs(AJ_Message* msg); /** * Unmamarshals one or arguments of basic types such as integers, strings. * * @param msg A pointer to a message that was unmarshaled by an earlier call to AJ_UnmarshalMsg * @param signature The signature of the argument list to unmarshal. * @param ... Pointers to values of the correct sizeo and type per the signature. * * @return * - AJ_OK if the arguments were succesfully unmarshaled. * - AJ_ERR_UNMARSHAL if the arg was badly formed * - AJ_ERR_READ if there was a read failure * - AJ_ERR_UNEXPECTED if any of the argument types in the signature is not a basic type */ AJ_EXPORT AJ_Status AJ_UnmarshalArgs(AJ_Message* msg, const char* signature, ...); /** * Unmarshals data from a message as raw bytes. * * The main use of this function is for unmarshalling message payloads that exceed the size of the * network transmit buffer. Note that the data pointer returned is only valid until the next call to * AJ_UnmarshalRaw() so must be consumed or buffered by the application. * * @param msg A pointer to the message currently being marshaled * @param data Returns a pointer to the unmarshalled data * @param len The number of bytes to unmarshal * @param actual Returns the actual number of bytes unmarshaled * * @return * - AJ_OK if the data was succesfully unmarshaled. * - AJ_ERR_READ if there was a read failure * - AJ_ERR_UNMARSHAL if there is no more data to unmarshal * - AJ_ERR_SIGNATURE of an invalid type was found in the message */ AJ_EXPORT AJ_Status AJ_UnmarshalRaw(AJ_Message* msg, const void** data, size_t len, size_t* actual); /** * Begin unmarshalling a container argument. * * @param msg A pointer to a message that was unmarshaled by an earlier call to AJ_UnmarshalMsg * @param arg Returns the unmarshaled container argument * @param typeId The expected type of the container (for checking purposes) * * @return Return AJ_Status * - AJ_OK if the container was succesfully unmarshaled. * - AJ_ERR_UNMARSHAL if the arg was badly formed * - AJ_ERR_READ if there was a read failure * - AJ_ERR_NO_MORE when there is no more to unmarshal (typically for array and container elements) */ AJ_EXPORT AJ_Status AJ_UnmarshalContainer(AJ_Message* msg, AJ_Arg* arg, uint8_t typeId); /** * Finish unmarshalling a container argument * * @param msg A pointer to a message that was unmarshaled by an earlier call to AJ_UnmarshalMsg * @param arg The container argument currently being unmarshaled * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_UnmarshalCloseContainer(AJ_Message* msg, AJ_Arg* arg); /** * Prepare to unmarshal a variant. The next argument unmarshalled is expected to be variant. * * @param msg A pointer to the message currently being marshaled * @param sig Returns the signature for the variant * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_UnmarshalVariant(AJ_Message* msg, const char** sig); /** * Closes an ummarshalled message when it is no longer needed. This releases resources and makes the * bus available for unmarshalling another message. After a message has been closed unmarshaled * values are no longer valid so this function should not be called until the message and its * arguments are no longer needed. * * @param msg The message to close. * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_CloseMsg(AJ_Message* msg); /** * Like AJ_CloseMsg(), this function closes an ummarshalled method call and release resources but * returns a reply context that can be used later to generate a reply message. This allows an * application to defer replying to a method call to a later time while still receiving other * messages. * * @param msg The message to close. * @param replyCtx A structure allocated by the caller to hold information needed to generate a * reply message. * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_CloseMsgAndSaveReplyContext(AJ_Message* msg, AJ_MsgReplyContext* replyCtx); /** * Type for a session identifier */ typedef uint32_t AJ_SessionId; /** * Marshal a METHOD_CALL message. * * @param bus The bus attachment * @param msg Pointer to a message structure * @param msgId The message identifier for this message * @param destination Bus address of the destination for this message * @param sessionId The session this message is for. * @param flags A logical OR of the applicable message flags * @param timeout Time in milliseconds to allow for a reply to the message before reporting * a timeout error message is reported to the application. * * @return * - AJ_OK if a message header was succesfully marshaled * - AJ_ERR_RESOURCES if the message is too big to marshal into the message buffer * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_MarshalMethodCall(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t msgId, const char* destination, AJ_SessionId sessionId, uint8_t flags, uint32_t timeout); /** * Marshal a SIGNAL message. * * @param bus The bus attachment * @param msg Pointer to a message structure * @param msgId The message identifier for this message * @param destination Bus address of the destination for this message * @param sessionId The session this message is for. * @param flags A logical OR of the applicable message flags * @param ttl Time to live for this signal in milliseconds. This parameter should be set to 0 * for a signal with no ttl. * * @return * - AJ_OK if a message header was succesfully marshaled * - AJ_ERR_RESOURCES if the message is too big to marshal into the message buffer * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_MarshalSignal(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t msgId, const char* destination, AJ_SessionId sessionId, uint8_t flags, uint32_t ttl); /** * Initialize and marshal a message that is a reply to a method call. * * @param methodCall The method call message that was received * @param reply The reply to be initialized * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalReplyMsg(const AJ_Message* methodCall, AJ_Message* reply); /** * Initialize and marshal a message that is an error response to a method call. * * @param methodCall The method call message that was received * @param reply The reply to be initialized * @param error The error name to use in the response. * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalErrorMsg(const AJ_Message* methodCall, AJ_Message* reply, const char* error); /** * Initialize and marshal a message that is an error response to a method call. * * @param methodCall The method call message that was received * @param reply The reply to be initialized * @param error The error name to use in the response. * @param info A text string that provides additional information about the error. Can be * NULL in which case this is equivalent to calling AJ_MarshalErrorMsg(). * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalErrorMsgWithInfo(const AJ_Message* methodCall, AJ_Message* reply, const char* error, const char* info); /** * Marshal a message that is an error response to a method call. This is a wrapper function around * AJ_MarshalErrorMsg() that chooses an appropriate error message depending on the AJ_Status value * passed in. * * @param methodCall The method call message that was received * @param reply The reply to be initialized * @param status The status code for the error * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalStatusMsg(const AJ_Message* methodCall, AJ_Message* reply, AJ_Status status); /** * Use a saved reply context to initialize and marshal a message that is a reply to a method call. * * This function clears the reply context before returning. * * @param replyCtx The saved context for generating a reply to the method call * @param reply The reply message to be initialized * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalReplyMsgAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply); /** * Use a saved reply context to initialize and marshal a message that is an error response to a method call. * * This function clears the reply context before returning. * * @param replyCtx The saved context for generating a reply to the method call * @param reply The reply message to be initialized * @param error The error name to use in the response. * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalErrorMsgAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply, const char* error); /** * Use a saved reply context to initialize and marshal a message that is an error response to a method call. * * This function clears the reply context before returning. * * @param replyCtx The saved context for generating a reply to the method call * @param reply The reply to be initialized * @param error The error name to use in the response. * @param info A text string that provides additional information about the error. Can be * NULL in which case this is equivalent to calling AJ_MarshalErrorFromReplyContext(). * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalErrorMsgWithInfoAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply, const char* error, const char* info); /** * Use a saved reply context to initialize and marshal a message that is an error response to a * method call. This is a wrapper function around AJ_MarshalErrorMsgAsync() that chooses an * appropriate error message depending on the AJ_Status value passed in. * * This function clears the reply context before returning. * * @param replyCtx The saved context for generating a reply to the method call * @param reply The reply to be initialized * @param status The status code for the error * * @return Return AJ_Status */ AJ_EXPORT AJ_Status AJ_MarshalStatusMsgAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply, AJ_Status status); /** * Delivers a marshalled message to the network. * * @param msg The message to deliver. * * @return * - AJ_OK if the message was succesfully delivered * - AJ_ERR_MARSHAL if the message arguments were incompletely marshaled * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_DeliverMsg(AJ_Message* msg); /** * This function does partial delivery of a marshalled message. This allow an application to send * messages that are larger (much larger) than the transmit buffer. The remaining data must be * custom marshaled by the application using AJ_MarshalRaw(). After all the remaining data has been * marshaled the applicatiom must call AJ_DeliverMsg() to complete the delivery of the message to * the network. * * * @param msg The message to deliver. * @param bytesRemaining The bytes yet to be marshaled. This cannot be zero. * * @return * - AJ_OK if the message partial delivery was successful * - AJ_ERR_SIGNATURE if there are no arguments left to marshal * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_DeliverMsgPartial(AJ_Message* msg, uint32_t bytesRemaining); /** * Marshals one or arguments of basic types such as integers, strings, etc. Container types * (structs and arrays) must use AJ_MarshalContainer() * * @param msg A pointer to a message currently being marshaled. * @param signature The signature of the argument list to marshal. * @param ... Values of the correct size and type per the signature * * @return * - AJ_OK if the arguments were succesfully marshaled. * - AJ_ERR_RESOURCES if the arguments are too big to marshal into the message buffer * - AJ_ERR_WRITE if there was a write failure * - AJ_ERR_UNEXPECTED if any of the argument types in the signature is not a basic type */ AJ_EXPORT AJ_Status AJ_MarshalArgs(AJ_Message* msg, const char* signature, ...); /** * Initializes a non-container argument of any of the following types: * * - Scalar values (boolean, bytes, signed and unsigned integer of various sizes, and doubles) * - Various string types * - Arrays of scalar values * * @param arg The argument to initialize * @param typeId The type or element type if the array flag is set * @param flags Indicates if the argument is an array. Valid values are AJ_ARRAY_FLAG and 0 * @param val The value to set, a string pointer or an address * @param len The length of the value if flags is AJ_ARRAY_FLAG or 0 otherwise * * @return Returns the address of the initialized arg. */ AJ_EXPORT AJ_Arg* AJ_InitArg(AJ_Arg* arg, uint8_t typeId, uint8_t flags, const void* val, size_t len); /** * Marshals a single argument. * * @param msg A pointer to a message that has marshaled by an earlier call to AJ_MarshalMsg * @param arg The argument to marshal * * @return * - AJ_OK if the argument was succesfully marshaled. * - AJ_ERR_RESOURCES if the arg is too big to marshal into the message buffer * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_MarshalArg(AJ_Message* msg, AJ_Arg* arg); /** * Marshals data for a message as raw bytes. The application is responsible for correctly composing * the data according to the wire protocol specification including any padding that may be required * as required by the alignment rules. * * The main use of this function is for marshalling message payloads that exceed the size of the * network transmit buffer. Before calling this function the application will typically call * AJ_DeliverMsgPartial() to establish the total length of the message in the message header. * * The simple uses cases are marshaling of long strings and arrays of bytes or integers. * In these two cases the application must marshal a 32 bit length then then marshal the data. * * Note that strings must be NUL terminated but NUL is not included in the length. * * @param msg A pointer to the message currently being marshaled * @param data The data to marshal * @param len The length of the data * * @return * - AJ_OK if the data was succesfully marshaled. * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_MarshalRaw(AJ_Message* msg, const void* data, size_t len); /** * Begin marshalling a container argument. * * @param msg A pointer to the message currently being marshaled * @param arg The container argument to marshal * @param typeId The type of container begin marshaled. * * @return Return AJ_Status * - AJ_OK if the argument was succesfully marshaled. * - AJ_ERR_RESOURCES if the arg is too big to marshal into the message buffer * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_MarshalContainer(AJ_Message* msg, AJ_Arg* arg, uint8_t typeId); /** * Finish marshalling a container argument * * @param msg A pointer to the message currently being marshaled * @param arg The container argument being marshalled * * @return Return AJ_Status * - AJ_OK if the signature is correct * - AJ_ERR_SIGNATURE if the signature is not correctly closed */ AJ_EXPORT AJ_Status AJ_MarshalCloseContainer(AJ_Message* msg, AJ_Arg* arg); /** * Prepare to marshal a variant. The next argument marshalled will be marshalled as a variant. * * @param msg A pointer to the message currently being marshaled * @param sig The signature for the variant * * @return Return AJ_Status * - AJ_OK if the argument was succesfully marshaled. * - AJ_ERR_RESOURCES if the arg is too big to marshal into the message buffer * - AJ_ERR_WRITE if there was a write failure */ AJ_EXPORT AJ_Status AJ_MarshalVariant(AJ_Message* msg, const char* sig); /** * Create a message for local marshal or unmarshal * * @param bus A dummy bus attachment * @param hdr The message header * @param msg The message * @param sig The message signature * @param data The buffer for the message body * @param size The buffer size */ void AJ_LocalMsg(AJ_BusAttachment* bus, AJ_MsgHeader* hdr, AJ_Message* msg, const char* sig, uint8_t* data, size_t size); /** * Checks an incoming method or signal for a valid serial number. * * @param prev Previous serial number struct for sending peer. * @param curr Current serial number. * * @return Return AJ_Status * - AJ_OK if serial number is valid. * - AJ_ERR_INVALID if serial number is invalid. */ AJ_Status AJ_CheckIncomingSerial(AJ_SerialNum* prev, uint32_t curr); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_msg_priv.h000066400000000000000000000111601271074662300160520ustar00rootroot00000000000000#ifndef _AJ_MSG_PRIV_H #define _AJ_MSG_PRIV_H /** * @file aj_msg_priv.h * @defgroup aj_msg_priv Non-public Message Marshaling and Unmarshaling APIs * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #ifdef __cplusplus extern "C" { #endif /* * Get the amount of header padding needed for a given header length. */ #define HEADERPAD(headerLength) ((8 - (headerLength))& 7) /** * Returns the signature of the next arg to be unmarshalled. * * @param msg A pointer to the message currently being unmarshaled * * @return Pointer to the signature of the next arg to unmarshal. */ AJ_EXPORT const char* AJ_NextArgSig(AJ_Message* msg); /** * Check if the type ID is a container type (array, struct, dictionay entry). * * @param typeId The type or element type if the array flag is set * * @return Indication if the type is a container or not. * - TRUE (1) iff the type is a container. * - FLASE (0) iff the type is not a container. */ AJ_EXPORT int AJ_IsContainerType(char typeId); /** * Check if the type ID is a scalar type (boolean, byte, int16, int32, int64, uint16, uint32, uint64, double). * * @param typeId The type or element type if the array flag is set * * @return Indication if the type is a scalar or not. * - TRUE (1) iff the type is a scalar. * - FLASE (0) iff the type is not a scalar. */ AJ_EXPORT int AJ_IsScalarType(char typeId); /** * Check if the type ID is a string type (string, object path, signature). * * @param typeId The type or element type if the array flag is set * * @return Indication if the type is a string or not. * - TRUE (1) iff the type is a string. * - FLASE (0) iff the type is not a string. */ AJ_EXPORT int AJ_IsStringType(char typeId); /** * Check if the type ID is a basic type (string or scalar). * * @param typeId The type or element type if the array flag is set * * @return Indication if the type is a basic type or not. * - TRUE (1) iff the type is a basic type. * - FLASE (0) iff the type is not a basic type. */ AJ_EXPORT int AJ_IsBasicType(char typeId); /** * For scalar types, get the size of that type. For non-scalar types, get the alignment. * * @param typeId The type or element type if the array flag is set * * @return Size (or alignment) of the type. */ AJ_EXPORT size_t AJ_GetTypeSize(char typeId); /** * Lookup the message identifier and set the msgId on the message. * * @param msg The message already initialized with object, interface, and member fields * @param secure Returns boolen indicating if the object or interface was marked secure * * @return - AJ_OK if the message was found * - AJ_ERR_SIGNATURE if the message was found but the signature was missing or incorrect. * The message identified is still set. * - AJ_ERR_NO_MATCH if the message could not be identified */ AJ_EXPORT AJ_Status AJ_LookupMessageId(AJ_Message* msg, uint8_t* secure); /** * Lookup a property identifier and get the property signature * * @param msg A property Get or Set method call or reply message * @param iface The interface the property is defined on * @param prop The property name * @param propId Returns the property identifier * @param sig Returns the property type signature * @param secure Returns boolen indicating if the property is on an object or interface marked secure * * @return - AJ_OK if the message was found * - AJ_ERR_NO_MATCH if the property could not be identified */ AJ_EXPORT AJ_Status AJ_IdentifyProperty(AJ_Message* msg, const char* iface, const char* prop, uint32_t* propId, const char** sig, uint8_t* secure); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_net.h000066400000000000000000000053531271074662300150210ustar00rootroot00000000000000#ifndef _AJ_NET_H #define _AJ_NET_H /** * @file aj_net.h * @defgroup aj_net Network Send and Receive * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #ifdef __cplusplus extern "C" { #endif #define AJ_ADDR_UDP4 0x01 /**< UDP ip4 address */ #define AJ_ADDR_UDP6 0x02 /**< UDP ip6 address */ #define AJ_ADDR_TCP4 0x04 /**< TCP ip4 address */ #define AJ_ADDR_TCP6 0x08 /**< TCP ip6 address */ struct _AJ_Service; struct _AJ_BusAttachment; /** * Abstracts a network socket */ typedef struct _AJ_NetSocket { AJ_IOBuffer tx; /**< transmit network socket */ AJ_IOBuffer rx; /**< receive network socket */ } AJ_NetSocket; /** * Connect to bus at an IPV4 or IPV6 address, either UDP or TCP * * @return Return AJ_Status */ AJ_Status AJ_Net_Connect(struct _AJ_BusAttachment* bus, const struct _AJ_Service* service); /** * Disconnect from the bus */ void AJ_Net_Disconnect(AJ_NetSocket* netSock); /** * Send from an I/O buffer * * @return Return AJ_Status */ AJ_Status AJ_Net_Send(AJ_IOBuffer* txBuf); /** * Send into an I/O buffer * * @return Return AJ_Status */ AJ_Status AJ_Net_Recv(AJ_IOBuffer* rxBuf, uint32_t len, uint32_t timeout); /** * Abstracts discovery sockets */ typedef struct _AJ_MCastSocket { AJ_IOBuffer tx; AJ_IOBuffer rx; } AJ_MCastSocket; /** * Enable multicast (for discovery) * * @return Return AJ_Status */ AJ_Status AJ_Net_MCastUp(AJ_MCastSocket* mcastSock); /** * Disable multicast (for discovery) */ void AJ_Net_MCastDown(AJ_MCastSocket* mcastSock); /** * Function that signals AJ_Net_Recv() to bail out early if it * is blocking on select. */ void AJ_Net_Interrupt(void); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_nvram.h000066400000000000000000000160441271074662300153550ustar00rootroot00000000000000#ifndef _AJ_NVRAM_H_ #define _AJ_NVRAM_H_ /** * @file aj_nvram.h * @defgroup aj_nvram Non-Volatile RAM Management * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif #define AJ_NVRAM_ID_CREDS_BEGIN 0x0001 /**< First NVRAM ID reserved for AllJoyn credentials management */ #define AJ_NVRAM_ID_CREDS_MAX 0x0FFF /**< Last NVRAM ID reserved for AllJoyn credentials management */ #define AJ_NVRAM_ID_SERVICES_BEGIN 0x1000 /**< First NVRAM ID reserved for AllJoyn services */ #define AJ_NVRAM_ID_SERVICES_MAX 0x1FFF /**< Last NVRAM ID reserved for AllJoyn services */ #define AJ_NVRAM_ID_FRAMEWORK_BEGIN 0x2000 /**< First NVRAM ID reserved for AllJoyn framework */ #define AJ_NVRAM_ID_FRAMEWORK_MAX 0x2FFF /**< Last NVRAM ID reserved for AllJoyn framework */ #define AJ_NVRAM_ID_ALLJOYNJS_BEGIN 0x3000 /**< First NVRAM ID reserved for AllJoyn AllJoyn.js */ #define AJ_NVRAM_ID_ALLJOYNJS_MAX 0x3FFF /**< Last NVRAM ID reserved for AllJoyn AllJoyn.js */ #define AJ_NVRAM_ID_RESERVED_BEGIN 0x4000 /**< First NVRAM ID reserved for AllJoyn future use*/ #define AJ_NVRAM_ID_RESERVED_MAX 0x7FFF /**< Last NVRAM ID reserved for AllJoyn future use*/ #define AJ_NVRAM_ID_APPS_BEGIN 0x8000 /**< First NVRAM ID available for application use */ #define AJ_NVRAM_ID_APPS_MAX 0xFFFE /**< Last NVRAM ID available for application use */ #define AJ_NV_DATASET_MODE_READ 'r' /**< Data set is in read mode */ #define AJ_NV_DATASET_MODE_WRITE 'w' /**< Data set is in write mode */ #ifndef AJ_NVRAM_SIZE #define AJ_NVRAM_SIZE (4096) #endif /** * AllJoyn NVRAM dataset handle. Applications should treat this an opaque data structure. The values * of the fields are implementation specific so cannot be relied on to have the same meaning across * different implementations. */ typedef struct _AJ_NV_DATASET { uint8_t mode; /**< The access mode (read or write) of a data set */ uint16_t curPos; /**< The current read/write offset of a data set */ uint16_t capacity; /**< The capacity of the data set established by AJ_NVRAM_Open() */ uint16_t id; /**< The unique id of a data set */ uint8_t* inode; /**< Pointer or offset to a location of the data set in the NVRAM */ void* internal; /**< Implementation-specific state */ } AJ_NV_DATASET; /** * Initialize NVRAM */ void AJ_NVRAM_Init(); /* * Get the number of bytes currently used in the NVRAM memory block * * @return Number of bytes used */ uint32_t AJ_NVRAM_GetSize(void); /* * Get the number of bytes unallocated in the NVRAM memory block * * @return Number of free bytes remaining */ uint32_t AJ_NVRAM_GetSizeRemaining(void); /** * Completely clear NVRAM */ void AJ_NVRAM_Clear(); /** * Open a data set * * @param id A unique id for a data set. The value must not be 0. * @param mode C string containing a data set access mode. It can be: * "r" : read: Open data set for input operations. The data set must exist. * "w" : write: Create an empty data set for output operations. If a data set with the same id already exists, its contents are discarded. * @param capacity The reserved space size for the data set. Only used for "w" access mode. * * @return A handle that specifies the data set. NULL if the open operation fails. */ AJ_NV_DATASET* AJ_NVRAM_Open(uint16_t id, const char* mode, uint16_t capacity); /** * Write to the data set specified by a handle * * @param ptr Pointer to a block of memory with a size of at least size bytes to be written to NVRAM. * @param size Size, in bytes, to be written. * @param handle Pointer to an AJ_NV_DATASET object that specifies a data set. * * @return The number of byte of data written to the data set or -1 if the write failed. */ size_t AJ_NVRAM_Write(const void* ptr, uint16_t size, AJ_NV_DATASET* handle); /** * Read from the data set specified by a handle * * @param ptr Pointer to a block of memory with a size of at least size bytes to be read from NVRAM. * @param size Size, in bytes, to be read. * @param handle Pointer to an AJ_NV_DATASET object that specifies a data set. * * @return The number of bytes of data read from the data set, or -1 if the read failed. */ size_t AJ_NVRAM_Read(void* ptr, uint16_t size, AJ_NV_DATASET* handle); /** * Returns a pointer to data at the current read position of an NVRAM data set. This function may * not be supported by all implementations. If this function returns NULL the caller will have to * allocate a buffer and use AJ_NVRAM_Read() to load the data set into memory. * * Note: the caller cannot assume that the pointer value returned will remain valid after the data * set is closed. * * @param handle Pointer to an AJ_NV_DATASET object that has been opened for reading. * * @return A pointer to the requested data or NULL if this function is not supported by the * implementation or the data set was not opened for reading. */ const void* AJ_NVRAM_Peek(AJ_NV_DATASET* handle); /** * Close the data set and release the handle * * @param handle Pointer to an AJ_NV_DATASET object that specifies a data set. * * @return AJ_ERR_INVALID if the handle is invalid, otherwise AJ_OK. */ AJ_Status AJ_NVRAM_Close(AJ_NV_DATASET* handle); /** * Check if a data set with a unique id exists * * @param id A unique ID for a data set. A valid id must not be 0. * * @return 1 if a data set with the specified id exists * 0 if not. */ uint8_t AJ_NVRAM_Exist(uint16_t id); /** * Securely delete (overwrite) a data set specified by the id * * @param id A unique id for a data set. * * @return AJ_OK if the data set is deleted successfully * AJ_ERR_FAILURE if the data set does not exist. */ AJ_Status AJ_NVRAM_SecureDelete(uint16_t id); /** * Delete a data set specified by the id * * @param id A unique id for a data set. * * @return AJ_OK if the data set is deleted successfully * AJ_ERR_FAILURE if the data set does not exist. */ AJ_Status AJ_NVRAM_Delete(uint16_t id); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_peer.h000066400000000000000000000216041271074662300151630ustar00rootroot00000000000000#ifndef _AJ_PEER_H #define _AJ_PEER_H /** * @file aj_peer.h * @defgroup aj_peer Implementation of org.alljoyn.Bus.Peer Object * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Handle an exchange guids message * * @param msg The exchange guids message * @param reply The guids reply message * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_RESOURCES if the arguments are too big to marshal into the message buffer * - AJ_ERR_WRITE if there was a write failure * - AJ_ERR_UNEXPECTED if any of the argument types in the signature is not a basic type */ AJ_Status AJ_PeerHandleExchangeGUIDs(AJ_Message* msg, AJ_Message* reply); /** * Handle an exchange guids reply message * * @param msg The exchange guids reply * * @return Return AJ_Status * - AJ_OK if successfully handled * - AJ_ERR_UNMARSHAL if the message was badly formed * - AJ_ERR_RESOURCES if the message header is too big to unmarshal into the attached buffer * - AJ_ERR_TIMEOUT if there was no message to unmarshal within the timeout period * - AJ_ERR_READ if there was a read failure */ AJ_Status AJ_PeerHandleExchangeGUIDsReply(AJ_Message* msg); /** * Handle a gen session key message * * @param msg The gen session key message * @param reply The gen session key reply message * * @return Return AJ_Status */ AJ_Status AJ_PeerHandleGenSessionKey(AJ_Message* msg, AJ_Message* reply); /** * Handle a gen session key reply message * * @param msg The gen session key reply message * * @return Return AJ_Status */ AJ_Status AJ_PeerHandleGenSessionKeyReply(AJ_Message* msg); /** * Handle an exchange group keys message * * @param msg The exchange group keys message * @param reply The group keys reply message * * @return Return AJ_Status */ AJ_Status AJ_PeerHandleExchangeGroupKeys(AJ_Message* msg, AJ_Message* reply); /** * Handle an exchange group keys reply message * * @param msg The exchange group keys reply message * * @return Return AJ_Status */ AJ_Status AJ_PeerHandleExchangeGroupKeysReply(AJ_Message* msg); /** * Callback function prototype for the function called when an authentication completes or fails. * * @param context The context provided when AJ_PeerAuthenticate() was called. * @param status A status code indicating if the authentication was succesful * - AJ_OK indicates the authentication succeeded * - AJ_ERR_SECURITY indicates the authentication failed * - AJ_ERR_TIMEOUT indciates the authentication timed-out */ typedef void (*AJ_PeerAuthenticateCallback)(const void* context, AJ_Status status); /** * Initiate a secure connection to a remote peer authenticating if necessary. * * @param bus The bus attachment * @param peerName The bus name of the remote peer to secure. * @param callback A function to be called when the authentication completes * @param cbContext A caller provided context to pass to the callback function * * @return Return AJ_Status * - AJ_OK if the request was sent * - An error status otherwise */ AJ_Status AJ_PeerAuthenticate(AJ_BusAttachment* bus, const char* peerName, AJ_PeerAuthenticateCallback callback, void* cbContext); /** * Handle an exchange suites message * * @param msg The exchange suites message * @param reply The exchange suites reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleExchangeSuites(AJ_Message* msg, AJ_Message* reply); /** * Handle an exchange suites reply message * * @param msg The exchange suites reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleExchangeSuitesReply(AJ_Message* msg); /** * Handle a key exchange message * * @param msg The key exchange message * @param reply The key exchange reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleKeyExchange(AJ_Message* msg, AJ_Message* reply); /** * Handle a key exchange reply message * * @param msg The key exchange reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleKeyExchangeReply(AJ_Message* msg); /** * Handle a key authentication message * * @param msg The key authentication message * @param reply The key authentication reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleKeyAuthentication(AJ_Message* msg, AJ_Message* reply); /** * Handle a key authentication reply message * * @param msg The key authentication reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleKeyAuthenticationReply(AJ_Message* msg); /** * Handle a send manifests message * * @param msg The send manifests message * @param reply The send manifests reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleSendManifests(AJ_Message* msg, AJ_Message* reply); /** * Handle a send manifests reply * * @param msg The send manifests reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleSendManifestsReply(AJ_Message* msg); /** * Handle a send memberships message, an array of guild memberships * * @param msg The send memberships message * @param reply The send memberships reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleSendMemberships(AJ_Message* msg, AJ_Message* reply); /** * Handle a send memberships reply * * @param msg The send memberships reply message * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerHandleSendMembershipsReply(AJ_Message* msg); /** * Request manifests be sent to peer * * @param msg The message being sent or received * @param outgoing TRUE if msg is an outgoing message, FALSE if not * * @return Return AJ_Status * - AJ_OK if successful * - AJ_ERR_RESOURCES if resource error or authentication in progress * - AJ_ERR_SECURITY if generic security violation */ AJ_Status AJ_PeerSendManifests(AJ_Message* msg, uint8_t outgoing); /** * Clear the authentication handshake context */ void AJ_ClearAuthContext(); /** * Clear the flag that determines if we've sent manifests to the peer */ void AJ_ClearSentManifests(); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_security.h000066400000000000000000000223771271074662300161070ustar00rootroot00000000000000#ifndef _AJ_SECURITY_H #define _AJ_SECURITY_H /** * @file aj_security.h * @defgroup aj_security Implementation of org.alljoyn.Bus.Security.* * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define AJ_SECURE_MGMT_PORT 101 #define APP_STATE_NOT_CLAIMABLE 0x0000 #define APP_STATE_CLAIMABLE 0x0001 #define APP_STATE_CLAIMED 0x0002 #define APP_STATE_NEED_UPDATE 0x0003 /* Authentication mechanisms supported for claiming. */ #define CLAIM_CAPABILITY_ECDHE_NULL 0x0001 #define CLAIM_CAPABILITY_ECDHE_PSK 0x0002 #define CLAIM_CAPABILITY_ECDHE_ECDSA 0x0004 #define CLAIM_CAPABILITY_ECDHE_SPEKE 0x0008 /* * Indicates whether the security manager or application generated the * pre-shared key or password used during claim. */ #define CLAIM_PSK_SECURITY_MANAGER 0x0001 #define CLAIM_PSK_APPLICATION 0x0002 typedef struct _AJ_CertificateId { DER_Element serial; /**< Certificate serial number */ DER_Element aki; /**< Certificate issuer aki */ AJ_ECCPublicKey pub; /**< Certificate issuer public key */ } AJ_CertificateId; /** * Set the application claim configuration * * @param bus Bus attachment * @param state Claim state * @param capabilities Claim capabilities * @param info Claim capabilities info * */ void AJ_SecuritySetClaimConfig(AJ_BusAttachment* bus, uint16_t state, uint16_t capabilities, uint16_t info); /** * Get the application claim configuration * * @param state Claim state * @param capabilities Claim capabilities * @param info Claim capabilities info * */ void AJ_SecurityGetClaimConfig(uint16_t* state, uint16_t* capabilities, uint16_t* info); /** * Initialistion for security module * Generates key pair if not found * Binds to the permission management port * * @param bus The bus attachment * * @return * - AJ_OK on success * - AJ_ERR_RESOURCES on failure */ AJ_Status AJ_SecurityInit(AJ_BusAttachment* bus); /** * Closes security module * Unbinds the permission management port * * @param bus The bus attachment * */ void AJ_SecurityClose(AJ_BusAttachment* bus); /** * Send application state signal * * @param bus The bus attachment * * @return * - AJ_OK on success */ AJ_Status AJ_ApplicationStateSignal(AJ_BusAttachment* bus); /** * Get security application property * * @param msg The message * * @return * - AJ_OK on success */ AJ_Status AJ_SecurityGetProperty(AJ_Message* msg); /** * Handle a claim message * * @param msg The claim message * @param reply The claim reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityClaimMethod(AJ_Message* msg, AJ_Message* reply); /** * Handle a reset message * Bus method handler for a MANAGED_RESET method call * * @param msg The reset message * @param reply The reset reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityResetMethod(AJ_Message* msg, AJ_Message* reply); /** * Perform a security reset * Function called by the application to initiate a security reset * * @param bus The bus attachment * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityReset(AJ_BusAttachment* bus); /** * Handle an update identity message * * @param msg The update identity message * @param reply The update identity reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityUpdateIdentityMethod(AJ_Message* msg, AJ_Message* reply); /** * Handle an update policy message * * @param msg The update policy message * @param reply The update policy reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityUpdatePolicyMethod(AJ_Message* msg, AJ_Message* reply); /** * Handle a reset policy message * * @param msg The reset policy message * @param reply The reset policy reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityResetPolicyMethod(AJ_Message* msg, AJ_Message* reply); /** * Handle an install membership message * * @param msg The install membership message * @param reply The install membership reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityInstallMembershipMethod(AJ_Message* msg, AJ_Message* reply); /** * Handle a remove membership message * * @param msg The remove membership message * @param reply The remove membership reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityRemoveMembershipMethod(AJ_Message* msg, AJ_Message* reply); /** * Handle a start management message * Bus method handler for a MANAGED_START_MANAGEMENT method call * * @param msg The start management message * @param reply The start management reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityStartManagementMethod(AJ_Message* msg, AJ_Message* reply); /** * Call application's start management callback, as a result of a MANAGED_START_MANAGEMENT method call * * @param bus The bus attachment * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_MANAGEMENT_ALREADY_STARTED on failure */ AJ_Status AJ_SecurityStartManagement(AJ_BusAttachment* bus); /** * Handle a end management message * Bus method handler for a MANAGED_END_MANAGEMENT method call * * @param msg The end management message * @param reply The end management reply message * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_SECURITY on all failures */ AJ_Status AJ_SecurityEndManagementMethod(AJ_Message* msg, AJ_Message* reply); /** * Call application's end management callback, as a result of a MANAGED_END_MANAGEMENT method call * * @param bus The bus attachment * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_MANAGEMENT_NOT_STARTED on failure */ AJ_Status AJ_SecurityEndManagement(AJ_BusAttachment* bus); /** * Handle an install manifests message * Bus method handler for a MANAGED_INSTALL_MANIFESTS method call * * @param msg The install manifests message * @param reply The install manifests reply * * @return Return AJ_Status * - AJ_OK if at least one manifest is accepted and installed * - AJ_ERR_SECURITY_DIGEST_MISMATCH if no manifests are accepted */ AJ_Status AJ_SecurityInstallManifestsMethod(AJ_Message* msg, AJ_Message* reply); /** * Unmarshal an ECCPublicKey object * * @param msg The message * @param pub The ECCPublicKey object * @param kid The key identifier (optional) * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_INVALID on all failures */ AJ_Status AJ_UnmarshalECCPublicKey(AJ_Message* msg, AJ_ECCPublicKey* pub, DER_Element* kid); /** * Unmarshal a certificate chain field and generate the id * * @param chain The certificate chain * @param id The certificate id * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_INVALID on all failures */ AJ_Status AJ_GetCertificateId(X509CertificateChain* chain, AJ_CertificateId* id); /** * Callback for the bind session port call. * * @param bus The bus attachment * * @return Return AJ_Status * - AJ_OK on success * - AJ_ERR_INVALID on all failures */ AJ_Status AJ_SecurityBound(AJ_BusAttachment* bus); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_serial.h000066400000000000000000000152761271074662300155170ustar00rootroot00000000000000#ifndef _AJ_SERIAL_H #define _AJ_SERIAL_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_SERIAL_CONNECTION #include #include #ifdef __cplusplus extern "C" { #endif /* * SLIP encapsulation characters as defined in (the ancient) RFC 1055 */ #define BOUNDARY_BYTE 0xC0 #define BOUNDARY_SUBSTITUTE 0xDC #define ESCAPE_BYTE 0xDB #define ESCAPE_SUBSTITUTE 0xDD /* * maximum and minimum window sizes */ #define MIN_WINDOW_SIZE 1 #define MAX_WINDOW_SIZE 4 /** * Packet header is four bytes. */ #define AJ_SERIAL_HDR_LEN 4 #define AJ_SERIAL_DATA 0 /**< Indicates a data packet */ #define AJ_SERIAL_UDATA 1 /**< Indicates an ack packet */ #define AJ_SERIAL_CTRL 14 /**< Indicates an Link control packet */ #define AJ_SERIAL_ACK 15 /**< Indicates an ack packet */ #define AJ_CRC_LEN 2 #define AJ_BOUNDARY_BYTES 2 #define SLIPPED_LEN(packetsize) (((packetsize) + AJ_SERIAL_HDR_LEN + AJ_CRC_LEN) * 2 + AJ_BOUNDARY_BYTES) /** * This is big enough to hold the control payloads stored in unreliable packets */ #define AJ_LINK_PACKET_PAYLOAD 32 /** * packets that carry transport control information */ #define CNTRL_PACKET(t) \ (((t) == AJ_SERIAL_ACK) || ((t) == AJ_SERIAL_CTRL)) /** * Reliable packets are ACKed; unreliable packets are not. */ #define RELIABLE_PACKET(t) \ ((t) == AJ_SERIAL_DATA) /** * Data packets can only be sent and received when the link is active. */ typedef enum { AJ_LINK_UNINITIALIZED, AJ_LINK_INITIALIZED, AJ_LINK_ACTIVE, AJ_LINK_DYING, AJ_LINK_DEAD } AJ_LinkState; /** * link parameter structure */ typedef struct _AJ_LinkParameters { uint8_t protoVersion; /**< Protocol version*/ AJ_LinkState linkState; /**< State of the link */ uint8_t maxWindowSize; /**< Window size configuration parameter */ uint8_t windowSize; /**< Negotiated window size */ uint16_t packetSize; /**< Packet size configuration parameter */ uint32_t bitRate; /**< Bit rate of the underlying serial link */ uint32_t txResendTimeout; /**< how long to wait for an acknowledgement before resending a packet */ uint32_t txAckTimeout; /**< how long to wait after a packet has been received before sending a ACK packet */ } AJ_LinkParameters; /** * Struct used for transferring buffers to and from the Rx/Tx interrupts. */ typedef struct __AJ_SlippedBuffer { uint8_t* buffer; uint16_t allocatedLen; uint16_t actualLen; struct __AJ_SlippedBuffer volatile* next; } AJ_SlippedBuffer; /** * Function pointer type for an abstracted serial transmit function * * @param buf The buffer to be transmitted * @param len The number of bytes to write */ typedef void (*AJ_SerialTxFunc)(uint8_t* buf, uint32_t len); /** * global function pointer for serial transmit funciton */ extern AJ_SerialTxFunc g_AJ_TX; void ClearSlippedBuffer(volatile AJ_SlippedBuffer* buf); extern volatile int dataReceived; extern volatile int dataSent; /** * global variable for link parameters */ extern AJ_LinkParameters AJ_SerialLinkParams; /** * Determine relative ordering of two sequence numbers. Sequence numbers are * modulo 8 so 0 > 7. * * This is used to test for ACKs and to detect gaps in the sequence of received * packets. */ #define SEQ_GT(s1, s2) (((7 + (s1) - (s2)) & 7) < AJ_SerialLinkParams.windowSize) /** * CRC Computation. The CRC computation must be initialized to the following value. */ #define AJ_SERIAL_CRC_INIT 0xFFFF /* * Handle a link control packet. */ void AJ_SerialLinkPacket(uint8_t* buffer, uint16_t len); /** * Function prototype for function called when the serial transport is open for business. */ typedef void (AJ_SerialInitialized)(); /** * This function initializes the serial transport layer. * * @param ttyName string used to choose the correct tty * @param bitRate configure the UART to this speed * @param windowSize Window size for acks and packet retransmission * @param enableCRC If TRUE enable CRC checks on data packets * @param packetSize Packet size with which the serial transport layer is initialized */ AJ_Status AJ_SerialInit(const char* ttyName, uint32_t bitRate, uint8_t windowSize, uint16_t packetSize); /** * This function calls AJ_SerialInit with the appropriate parameters. * Its implementation is target-dependent. */ AJ_Status AJ_Serial_Up(); /** * This function shuts down the serial transport layer. * */ void AJ_SerialShutdown(void); /** * Send a data buffer over the serial transport. This function blocks until the data has been queued * or sent. * * @param buffer The buffer containing the data to be sent * @param len The length of the data in the buffer * * @return - AJ_OK if the data was succesfully queued or sent. */ AJ_Status AJ_SerialSend(uint8_t* buffer, uint16_t len); /** * Receive data from the serial transport. This function blocks until the request data has been * read into the buffer. * * @param buffer The buffer containing the data to be sent * @param len The length of the buffer * @param timeout The amount of time to wait for data to arrive * @param recv The amount of data received * * @return - AJ_OK if data was succesfully received. */ AJ_Status AJ_SerialRecv(uint8_t* buffer, uint16_t len, uint32_t timeout, uint16_t* recv); /** * This function disconnects the serial transport layer. * */ void AJ_SerialDisconnect(void); #ifdef __cplusplus } #endif #endif /* AJ_SERIAL_CONNECTION */ #endif /* _AJ_SERIAL_H */ ajtcl-16.04/inc/aj_serial_rx.h000066400000000000000000000032121271074662300162130ustar00rootroot00000000000000#ifndef _AJ_SERIAL_RX_H #define _AJ_SERIAL_RX_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_SERIAL_CONNECTION #include #include #include #ifdef __cplusplus extern "C" { #endif /** * This function initializes the receive path */ AJ_Status AJ_SerialRX_Init(void); /** * This function shuts down the receive path */ void AJ_SerialRX_Shutdown(void); /** * This function resets the receive path */ AJ_Status AJ_SerialRX_Reset(void); /** * Process the buffers read by the Receive callback - called by the StateMachine. */ void AJ_ProcessRxBufferList(); #ifdef __cplusplus } #endif #endif /* AJ_SERIAL_CONNECTION */ #endif /* _AJ_SERIAL_RX_H */ ajtcl-16.04/inc/aj_serial_tx.h000066400000000000000000000060171271074662300162230ustar00rootroot00000000000000#ifndef _AJ_SERIAL_TX_H #define _AJ_SERIAL_TX_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_SERIAL_CONNECTION #include #include #include #ifdef __cplusplus extern "C" { #endif /** * This function initializes the serial transport layer. */ AJ_Status AJ_SerialTX_Init(void); /** * This function resets the transmit side of the H:5 transport. */ AJ_Status AJ_SerialTX_Reset(void); /** * This function shuts down the serial transport layer. */ void AJ_SerialTX_Shutdown(void); /** * This function adds a control packet that contains H:5 control information (link control or ACK) * to the transmit queue. This function assumes that the packet is statically allocated or is NULL. */ void AJ_SerialTX_EnqueueCtrl(const uint8_t* packet, uint16_t pktLen, uint8_t type); /** * This function adds a packet that contains Bluetooth data, HCI command, * ACL data, or SCO data to the transmit queue. */ void AJ_SerialTX_EnqueuePkt(uint8_t type, uint16_t header, uint16_t length); /** * This function is called by the receive layer when a data packet or an explicit ACK * has been received. The ACK value is one greater (modulo 8) than the seq number of the * last packet successfully received. */ void AJ_SerialTX_ReceivedAck(uint8_t ack); /** * This function is called from the receive side with the sequence number of * the last packet received. */ void AJ_SerialTX_ReceivedSeq(uint8_t seq); /** * This function is called from the state machine to resend any data packets * that have not yet been acked. */ void ResendPackets(); /** * This function is called from the state machine to ack a data packet recieved * in case this end doesnt have data to send. */ void SendAck(); /** * There is space available in the transmit queue handled by the transmit callback, * queue up packets if there are any. */ void AJ_FillTxBufferList(); #ifdef __cplusplus } #endif #endif /* AJ_SERIAL_CONNECTION */ #endif /* _AJ_SERIAL_TX_H */ ajtcl-16.04/inc/aj_serio.h000066400000000000000000000110171271074662300153460ustar00rootroot00000000000000#ifndef _AJ_SERIO_H #define _AJ_SERIO_H /** * @file aj_serio.h * @defgroup aj_serio Serial Input/Output * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif #define AJ_SERIO_RX 1 /**< The receive direction (from the wire) of the serial I/O subsystem */ #define AJ_SERIO_TX 2 /**< The transmit direction (to the wire) of the serial I/O subsystem */ /** * A type for managing serial port configuration */ typedef struct _AJ_SerIOConfig { uint32_t bitrate; /**< bitrate of the port */ uint8_t bits; /**< The number of data bits */ uint8_t stopBits; /**< The number of stop bits */ uint8_t parity; /**< Zero disables parity checking, one means odd and two means even parity */ void* config; /**< Abstracted context for device/platform specific configuration items */ } AJ_SerIOConfig; /** * @brief Enable or disable the Serial I/O Subsystem to send or receive frames * * The serial I/O subsystem will not begin sending or receiving data until it * is explicitly told to. This allows for orderly bring-up and shutdown of the * system. * * @param direction Provide AJ_SERIO_RX for the receiver section, AJ_SERIO_TX for the transmitter. * @param enable Provide true to enable the section, false to disable. * * @return * - AJ_OK If the serial operation completed successfully */ AJ_Status AJ_SerialIOEnable(uint32_t direction, uint8_t enable); /** * @brief Shutdown the Serial I/O Subsystem * * Disable the serial I/O subsystem and return all buffers to the client with * an appropriated error code. An implied disable of the transmit and receive * side is done during shutdown. */ AJ_Status AJ_SerialIOShutdown(void); /** * Function pointer type for an abstracted receive callback function * * @param buf The buffer that has a new frame read into it * @param len The number of bytes actually read */ typedef void (*AJ_SerIORxCompleteFunc)(uint8_t* buf, uint16_t len); /** * Function pointer type for an abstracted transmit callback function * * @param buf The buffer that has had its bytes transmitted out * @param len The number of bytes actually written */ typedef void (*AJ_SerIOTxCompleteFunc)(uint8_t* buf, uint16_t len); /** * Function pointer type for an abstracted serial transmit function * * @param buf The buffer to be transmitted * @param len The number of bytes to write */ typedef void (*AJ_SerialTxFunc)(uint8_t* buf, uint32_t len); /** * @brief Initialize the Serial I/O Subsystem * * Given a serial IO config structure as a guide, initialize the serial I/O * subsystem. Not all combinations of bitrate, data bits and stopbits will be * legal. Limitations due to the configurability apply. * * @param config The configuration to use. NULL implies use a default setting. * @param rx_cb The function to call when a complete SLIP frame is received * @param tx_cb The function to call when a frame has been completely transmitted * * @return * - AJ_OK if the serial subsystem was successfully initialized * - AJ_ERR_UNEXPECTED if one of the parameters is not supported */ AJ_Status AJ_SerialIOInit(AJ_SerIOConfig* config); void AJ_SetRxCB(AJ_SerIORxCompleteFunc rx_cb); void AJ_SetTxCB(AJ_SerIOTxCompleteFunc tx_cb); void AJ_SetTxSerialTransmit(AJ_SerialTxFunc tx_func); void AJ_RX(uint8_t* buf, uint32_t len); void AJ_PauseRX(); void AJ_ResumeRX(); void AJ_TX(uint8_t* buf, uint32_t len); void AJ_PauseTX(); void AJ_ResumeTX(); #ifdef __cplusplus } #endif /** * @} */ #endif /* _AJ_SERIO_H */ ajtcl-16.04/inc/aj_status.h000066400000000000000000000132041271074662300155500ustar00rootroot00000000000000#ifndef _AJ_STATUS_H #define _AJ_STATUS_H /** * @file aj_status.h * @defgroup aj_status AllJoyn Status (Return) Codes * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Status codes */ typedef enum { AJ_OK = 0, /**< Success status */ AJ_ERR_NULL = 1, /**< Unexpected NULL pointer */ AJ_ERR_UNEXPECTED = 2, /**< An operation was unexpected at this time */ AJ_ERR_INVALID = 3, /**< A value was invalid */ AJ_ERR_IO_BUFFER = 4, /**< An I/O buffer was invalid or in the wrong state */ AJ_ERR_READ = 5, /**< An error while reading data from the network */ AJ_ERR_WRITE = 6, /**< An error while writing data to the network */ AJ_ERR_TIMEOUT = 7, /**< A timeout occurred */ AJ_ERR_MARSHAL = 8, /**< Marshaling failed due to badly constructed message argument */ AJ_ERR_UNMARSHAL = 9, /**< Unmarshaling failed due to a corrupt or invalid message */ AJ_ERR_END_OF_DATA = 10, /**< Not enough data */ AJ_ERR_RESOURCES = 11, /**< Insufficient memory to perform the operation */ AJ_ERR_NO_MORE = 12, /**< Attempt to unmarshal off the end of an array */ AJ_ERR_SECURITY = 13, /**< Authentication or decryption failed */ AJ_ERR_CONNECT = 14, /**< Network connect failed */ AJ_ERR_UNKNOWN = 15, /**< A unknown value */ AJ_ERR_NO_MATCH = 16, /**< Something didn't match */ AJ_ERR_SIGNATURE = 17, /**< Signature is not what was expected */ AJ_ERR_DISALLOWED = 18, /**< An operation was not allowed */ AJ_ERR_FAILURE = 19, /**< A failure has occurred */ AJ_ERR_RESTART = 20, /**< The OEM event loop must restart */ AJ_ERR_LINK_TIMEOUT = 21, /**< The bus link is inactive too long */ AJ_ERR_DRIVER = 22, /**< An error communicating with a lower-layer driver */ AJ_ERR_OBJECT_PATH = 23, /**< Object path was not specified */ AJ_ERR_BUSY = 24, /**< An operation failed and should be retried later */ AJ_ERR_DHCP = 25, /**< A DHCP operation has failed */ AJ_ERR_ACCESS = 26, /**< The operation specified is not allowed */ AJ_ERR_SESSION_LOST = 27, /**< The session was lost */ AJ_ERR_LINK_DEAD = 28, /**< The network link is now dead */ AJ_ERR_HDR_CORRUPT = 29, /**< The message header was corrupt */ AJ_ERR_RESTART_APP = 30, /**< The application must cleanup and restart */ AJ_ERR_INTERRUPTED = 31, /**< An I/O operation (READ) was interrupted */ AJ_ERR_REJECTED = 32, /**< The connection was rejected */ AJ_ERR_RANGE = 33, /**< Value provided was out of range */ AJ_ERR_ACCESS_ROUTING_NODE = 34, /**< Access defined by routing node */ AJ_ERR_KEY_EXPIRED = 35, /**< The key has expired */ AJ_ERR_SPI_NO_SPACE = 36, /**< Out of space error */ AJ_ERR_SPI_READ = 37, /**< Read error */ AJ_ERR_SPI_WRITE = 38, /**< Write error */ AJ_ERR_OLD_VERSION = 39, /**< Router you connected to is old and unsupported */ AJ_ERR_NVRAM_READ = 40, /**< Error while reading from NVRAM */ AJ_ERR_NVRAM_WRITE = 41, /**< Error while writing to NVRAM */ AJ_ERR_WOULD_BLOCK = 42, /**< Last operation would block */ AJ_ERR_ARDP_DISCONNECTED = 43, /**< Local ARDP disconnect */ AJ_ERR_ARDP_DISCONNECTING = 44, /**< ARDP waiting for Send queue to drain before complete disconnect */ AJ_ERR_ARDP_REMOTE_CONNECTION_RESET = 45, /**< Remote ARDP disconnect */ AJ_ERR_ARDP_PROBE_TIMEOUT = 46, /**< ARDP connection timeout */ AJ_ERR_ARDP_BACKPRESSURE = 47, /**< The Send queue is full */ AJ_ERR_ARDP_SEND_EXPIRED = 48, /**< The outgoing message has expired */ AJ_ERR_ARDP_RECV_EXPIRED = 49, /**< The incoming message has expired */ AJ_ERR_ARDP_VERSION_NOT_SUPPORTED = 50, /**< Error to indicate ARDP protocol mismatch */ AJ_ERR_SECURITY_DIGEST_MISMATCH = 51, /**< Security error for digest mismatch */ AJ_ERR_SECURITY_INVALID_CERTIFICATE = 52, /**< Security error for invalid certificate */ AJ_ERR_SECURITY_DUPLICATE_CERTIFICATE = 53, /**< Security error for duplicate certificate */ AJ_ERR_SECURITY_POLICY_NOT_NEWER = 54, /**< Security error for invalid policy update */ AJ_ERR_SECURITY_CERTIFICATE_NOT_FOUND = 55, /**< Security error for certificate not found */ AJ_ERR_MANAGEMENT_ALREADY_STARTED = 56, /**< Starting security management when it has been started already */ AJ_ERR_MANAGEMENT_NOT_STARTED = 57, /**< Stopping security management when it has not been started yet */ /* * REMINDER: Update AJ_StatusText in aj_debug.c if adding a new status code. */ AJ_STATUS_LAST = 58 /**< The last error status code */ } AJ_Status; /** * @} */ #endif ajtcl-16.04/inc/aj_std.h000066400000000000000000000346271271074662300150330ustar00rootroot00000000000000#ifndef _AJ_STD_H #define _AJ_STD_H /** * @file aj_std.h * @defgroup aj_std AllJoyn Standard Object Definitions * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include /** * Identifiers for standard methods and signals. These are the values returned by * AJ_IdentifyMessage() for correctly formed method and signal messages. * * The first value is the index into the object array. * The second value is the index into the interfaces array for the object. * The third value is the index into the members array of the interface. */ /* * Members of the /org/freedesktop/DBus interface org.freedesktop.DBus */ #define AJ_METHOD_HELLO AJ_BUS_MESSAGE_ID(0, 0, 0) /**< method for hello */ #define AJ_SIGNAL_NAME_OWNER_CHANGED AJ_BUS_MESSAGE_ID(0, 0, 1) /**< signal for name owner changed */ #define AJ_SIGNAL_NAME_ACQUIRED AJ_BUS_MESSAGE_ID(0, 0, 2) /**< signal for name acquired */ #define AJ_SIGNAL_NAME_LOST AJ_BUS_MESSAGE_ID(0, 0, 3) /**< signal for name lost */ #define AJ_METHOD_REQUEST_NAME AJ_BUS_MESSAGE_ID(0, 0, 4) /**< method for request name */ #define AJ_METHOD_ADD_MATCH AJ_BUS_MESSAGE_ID(0, 0, 5) /**< method for add match */ #define AJ_METHOD_REMOVE_MATCH AJ_BUS_MESSAGE_ID(0, 0, 6) /**< method for remove match */ #define AJ_METHOD_RELEASE_NAME AJ_BUS_MESSAGE_ID(0, 0, 7) /**< method for release name */ #define AJ_METHOD_NAME_HAS_OWNER AJ_BUS_MESSAGE_ID(0, 0, 8) /**< method for name has owner */ /* * Members of /org/alljoyn/Bus interface org.alljoyn.Bus */ #define AJ_SIGNAL_SESSION_LOST AJ_BUS_MESSAGE_ID(1, 0, 0) /**< signal for session lost */ #define AJ_SIGNAL_FOUND_ADV_NAME AJ_BUS_MESSAGE_ID(1, 0, 1) /**< signal for found advertising name */ #define AJ_SIGNAL_LOST_ADV_NAME AJ_BUS_MESSAGE_ID(1, 0, 2) /**< signal for lost advertising name */ #define AJ_SIGNAL_MP_SESSION_CHANGED AJ_BUS_MESSAGE_ID(1, 0, 3) /**< signal for mp session changed */ #define AJ_METHOD_ADVERTISE_NAME AJ_BUS_MESSAGE_ID(1, 0, 4) /**< method for advertise name */ #define AJ_METHOD_CANCEL_ADVERTISE AJ_BUS_MESSAGE_ID(1, 0, 5) /**< method for cancel advertise */ #define AJ_METHOD_FIND_NAME AJ_BUS_MESSAGE_ID(1, 0, 6) /**< method for find name */ #define AJ_METHOD_CANCEL_FIND_NAME AJ_BUS_MESSAGE_ID(1, 0, 7) /**< method for cancel find name */ #define AJ_METHOD_BIND_SESSION_PORT AJ_BUS_MESSAGE_ID(1, 0, 8) /**< method for bind session port */ #define AJ_METHOD_UNBIND_SESSION AJ_BUS_MESSAGE_ID(1, 0, 9) /**< method for unbind session */ #define AJ_METHOD_JOIN_SESSION AJ_BUS_MESSAGE_ID(1, 0, 10) /**< method for join session */ #define AJ_METHOD_LEAVE_SESSION AJ_BUS_MESSAGE_ID(1, 0, 11) /**< method for leave session */ #define AJ_METHOD_CANCEL_SESSIONLESS AJ_BUS_MESSAGE_ID(1, 0, 12) /**< method for cancel sessionless */ #define AJ_METHOD_FIND_NAME_BY_TRANSPORT AJ_BUS_MESSAGE_ID(1, 0, 13) /**< method for find name by specific transports */ #define AJ_METHOD_CANCEL_FIND_NAME_BY_TRANSPORT AJ_BUS_MESSAGE_ID(1, 0, 14) /**< method for cancel find name by specific transports */ #define AJ_METHOD_SET_LINK_TIMEOUT AJ_BUS_MESSAGE_ID(1, 0, 15) /**< method for setting the link timeout for a session */ #define AJ_METHOD_REMOVE_SESSION_MEMBER AJ_BUS_MESSAGE_ID(1, 0, 16) /**< method for removing a member in a session */ #define AJ_SIGNAL_SESSION_LOST_WITH_REASON AJ_BUS_MESSAGE_ID(1, 0, 17) /**< signal for session lost with a reason */ #define AJ_METHOD_BUS_PING AJ_BUS_MESSAGE_ID(1, 0, 18) /**< method for ping */ #define AJ_METHOD_BUS_SET_IDLE_TIMEOUTS AJ_BUS_MESSAGE_ID(1, 0, 19) /**< method for set idle timeouts */ #define AJ_METHOD_BUS_SIMPLE_HELLO AJ_BUS_MESSAGE_ID(1, 0, 20) /**< Simple Hello, similar to BusHello */ /* * Members of /org/alljoyn/Bus/Peer interface org.alljoyn.Bus.Peer.Session */ #define AJ_METHOD_ACCEPT_SESSION AJ_BUS_MESSAGE_ID(2, 0, 0) /**< method for accept session */ #define AJ_SIGNAL_SESSION_JOINED AJ_BUS_MESSAGE_ID(2, 0, 1) /**< signal for session joined */ /* * Members of /org/alljoyn/Bus/Peer interface org.alljoyn.Bus.Peer.Authentication */ #define AJ_PEER_AUTHENTICATION_IFN AJ_BUS_MESSAGE_ID(2, 1, 0) /**< Id for Peer.Authentication interface */ #define AJ_METHOD_EXCHANGE_GUIDS AJ_BUS_MESSAGE_ID(2, 1, 0) /**< method for exchange guids */ #define AJ_METHOD_GEN_SESSION_KEY AJ_BUS_MESSAGE_ID(2, 1, 1) /**< method for generate session key */ #define AJ_METHOD_EXCHANGE_GROUP_KEYS AJ_BUS_MESSAGE_ID(2, 1, 2) /**< method for exchange group keys */ #define AJ_METHOD_AUTH_CHALLENGE AJ_BUS_MESSAGE_ID(2, 1, 3) /**< method for auth challenge */ #define AJ_METHOD_EXCHANGE_SUITES AJ_BUS_MESSAGE_ID(2, 1, 4) /**< method for exchange suites */ #define AJ_METHOD_KEY_EXCHANGE AJ_BUS_MESSAGE_ID(2, 1, 5) /**< method for key exchange */ #define AJ_METHOD_KEY_AUTHENTICATION AJ_BUS_MESSAGE_ID(2, 1, 6) /**< method for authenticating key exchange */ #define AJ_METHOD_SEND_MANIFESTS AJ_BUS_MESSAGE_ID(2, 1, 7) /**< method for exchanging manifests */ #define AJ_METHOD_SEND_MEMBERSHIPS AJ_BUS_MESSAGE_ID(2, 1, 8) /**< method for exchanging membership certificates */ /* * Members of interface org.freedesktop.DBus.Introspectable * * Note - If you use this message id explicitly to construct a method call it will always introspect * the root object. */ #define AJ_METHOD_INTROSPECT AJ_BUS_MESSAGE_ID(3, 0, 0) /**< method for introspect */ /* * Members of the interface org.freedesktop.DBus.Peer */ #define AJ_METHOD_PING AJ_BUS_MESSAGE_ID(3, 1, 0) /**< method for ping */ #define AJ_METHOD_GET_MACHINE_ID AJ_BUS_MESSAGE_ID(3, 1, 1) /**< method for get machine id */ /* * Members of the interface org.allseen.Introspectable */ #define AJ_METHOD_GET_DESCRIPTION_LANG AJ_BUS_MESSAGE_ID(3, 2, 0) /**< method for get description langauges */ #define AJ_METHOD_INTROSPECT_WITH_DESC AJ_BUS_MESSAGE_ID(3, 2, 1) /**< method for introspect with descriptions */ /* * Members of /org/alljoyn/Daemon interface org.alljoyn.Daemon */ #define AJ_SIGNAL_PROBE_REQ AJ_BUS_MESSAGE_ID(4, 0, 0) /**< signal for link probe request */ #define AJ_SIGNAL_PROBE_ACK AJ_BUS_MESSAGE_ID(4, 0, 1) /**< signal for link probe acknowledgement */ /* * Members of interface org.alljoyn.About */ #define AJ_METHOD_ABOUT_GET_PROP AJ_BUS_MESSAGE_ID(5, 0, AJ_PROP_GET) #define AJ_METHOD_ABOUT_SET_PROP AJ_BUS_MESSAGE_ID(5, 0, AJ_PROP_SET) #define AJ_PROPERTY_ABOUT_VERSION AJ_BUS_PROPERTY_ID(5, 1, 0) #define AJ_METHOD_ABOUT_GET_ABOUT_DATA AJ_BUS_MESSAGE_ID(5, 1, 1) #define AJ_METHOD_ABOUT_GET_OBJECT_DESCRIPTION AJ_BUS_MESSAGE_ID(5, 1, 2) #define AJ_SIGNAL_ABOUT_ANNOUNCE AJ_BUS_MESSAGE_ID(5, 1, 3) /* * Members of interface org.alljoyn.AboutIcon */ #define AJ_METHOD_ABOUT_ICON_GET_PROP AJ_BUS_MESSAGE_ID(6, 0, AJ_PROP_GET) #define AJ_METHOD_ABOUT_ICON_SET_PROP AJ_BUS_MESSAGE_ID(6, 0, AJ_PROP_SET) #define AJ_PROPERTY_ABOUT_ICON_VERSION_PROP AJ_BUS_PROPERTY_ID(6, 1, 0) #define AJ_PROPERTY_ABOUT_ICON_MIMETYPE_PROP AJ_BUS_PROPERTY_ID(6, 1, 1) #define AJ_PROPERTY_ABOUT_ICON_SIZE_PROP AJ_BUS_PROPERTY_ID(6, 1, 2) #define AJ_METHOD_ABOUT_ICON_GET_URL AJ_BUS_MESSAGE_ID(6, 1, 3) #define AJ_METHOD_ABOUT_ICON_GET_CONTENT AJ_BUS_MESSAGE_ID(6, 1, 4) #define AJ_METHOD_SECURITY_GET_PROP AJ_BUS_MESSAGE_ID(7, 0, AJ_PROP_GET) #define AJ_METHOD_SECURITY_SET_PROP AJ_BUS_MESSAGE_ID(7, 0, AJ_PROP_SET) /* * Members of interface org.alljoyn.Bus.Application */ #define AJ_PROPERTY_APPLICATION_VERSION AJ_BUS_MESSAGE_ID(7, 1, 0) #define AJ_SIGNAL_APPLICATION_STATE AJ_BUS_MESSAGE_ID(7, 1, 1) /* * Members of interface org.alljoyn.Bus.Security.Application */ #define AJ_PROPERTY_SEC_VERSION AJ_BUS_MESSAGE_ID(7, 2, 0) #define AJ_PROPERTY_SEC_APPLICATION_STATE AJ_BUS_MESSAGE_ID(7, 2, 1) #define AJ_PROPERTY_SEC_MANIFEST_DIGEST AJ_BUS_MESSAGE_ID(7, 2, 2) #define AJ_PROPERTY_SEC_ECC_PUBLICKEY AJ_BUS_MESSAGE_ID(7, 2, 3) #define AJ_PROPERTY_SEC_MANUFACTURER_CERTIFICATE AJ_BUS_MESSAGE_ID(7, 2, 4) #define AJ_PROPERTY_SEC_MANIFEST_TEMPLATE AJ_BUS_MESSAGE_ID(7, 2, 5) #define AJ_PROPERTY_SEC_CLAIM_CAPABILITIES AJ_BUS_MESSAGE_ID(7, 2, 6) #define AJ_PROPERTY_SEC_CLAIM_CAPABILITIES_INFO AJ_BUS_MESSAGE_ID(7, 2, 7) /* * Members of interface org.alljoyn.Bus.Security.ClaimableApplication */ #define AJ_PROPERTY_CLAIMABLE_VERSION AJ_BUS_MESSAGE_ID(7, 3, 0) #define AJ_METHOD_CLAIMABLE_CLAIM AJ_BUS_MESSAGE_ID(7, 3, 1) /* * Members of interface org.alljoyn.Bus.Security.ManagedApplication */ #define AJ_PROPERTY_MANAGED_VERSION AJ_BUS_MESSAGE_ID(7, 4, 0) #define AJ_PROPERTY_MANAGED_IDENTITY AJ_BUS_MESSAGE_ID(7, 4, 1) #define AJ_PROPERTY_MANAGED_MANIFESTS AJ_BUS_MESSAGE_ID(7, 4, 2) #define AJ_PROPERTY_MANAGED_IDENTITY_CERT_ID AJ_BUS_MESSAGE_ID(7, 4, 3) #define AJ_PROPERTY_MANAGED_POLICY_VERSION AJ_BUS_MESSAGE_ID(7, 4, 4) #define AJ_PROPERTY_MANAGED_POLICY AJ_BUS_MESSAGE_ID(7, 4, 5) #define AJ_PROPERTY_MANAGED_DEFAULT_POLICY AJ_BUS_MESSAGE_ID(7, 4, 6) #define AJ_PROPERTY_MANAGED_MEMBERSHIP_SUMMARY AJ_BUS_MESSAGE_ID(7, 4, 7) #define AJ_METHOD_MANAGED_RESET AJ_BUS_MESSAGE_ID(7, 4, 8) #define AJ_METHOD_MANAGED_UPDATE_IDENTITY AJ_BUS_MESSAGE_ID(7, 4, 9) #define AJ_METHOD_MANAGED_UPDATE_POLICY AJ_BUS_MESSAGE_ID(7, 4, 10) #define AJ_METHOD_MANAGED_RESET_POLICY AJ_BUS_MESSAGE_ID(7, 4, 11) #define AJ_METHOD_MANAGED_INSTALL_MEMBERSHIP AJ_BUS_MESSAGE_ID(7, 4, 12) #define AJ_METHOD_MANAGED_REMOVE_MEMBERSHIP AJ_BUS_MESSAGE_ID(7, 4, 13) #define AJ_METHOD_MANAGED_START_MANAGEMENT AJ_BUS_MESSAGE_ID(7, 4, 14) #define AJ_METHOD_MANAGED_END_MANAGEMENT AJ_BUS_MESSAGE_ID(7, 4, 15) #define AJ_METHOD_MANAGED_INSTALL_MANIFESTS AJ_BUS_MESSAGE_ID(7, 4, 16) /** * Message identifier that indicates a message was invalid. */ #define AJ_INVALID_MSG_ID (0xFFFFFFFF) /** * Message identifier that indicates a property was invalid. */ #define AJ_INVALID_PROP_ID (0xFFFFFFFF) /** * DBus well-known bus name */ extern const char AJ_DBusDestination[21]; /** * AllJoyn well-known bus name */ extern const char AJ_BusDestination[16]; /* * Error message strings */ extern const char AJ_ErrSecurityViolation[34]; /**< Error security violation string */ extern const char AJ_ErrPermissionDenied[48]; /**< Error permission denied string */ extern const char AJ_ErrDigestMismatch[46]; /**< Error digest mismatch string */ extern const char AJ_ErrInvalidCertificate[50]; /**< Error invalid certificate string */ extern const char AJ_ErrDuplicateCertificate[52]; /**< Error duplicate certificate string */ extern const char AJ_ErrCertificateNotFound[51]; /**< Error certificate not found string */ extern const char AJ_ErrPolicyNotNewer[46]; /**< Error invalid policy string */ extern const char AJ_ErrTimeout[24]; /**< Error timeout string */ extern const char AJ_ErrRejected[25]; /**< Error rejected string */ extern const char AJ_ErrResources[26]; /**< Error resource string */ extern const char AJ_ErrServiceUnknown[42]; /**< Error service unknown string */ extern const char AJ_ErrUpdateNotAllowed[35]; /**< Error update not allowed string */ extern const char AJ_ErrInvalidValue[31]; /**< Error invalid value string */ extern const char AJ_ErrFeatureNotAvailable[38]; /**< Error feature not available string */ extern const char AJ_ErrMaxSizeExceeded[34]; /**< Error max size exceeded string */ extern const char AJ_ErrLanguageNotSuppored[39]; /**< Error language not supported string */ extern const char AJ_ErrMethodNotAllowed[35]; /**< Error method not allowed string */ /** * The properties interface. This interface must be included in the property lists of all local and * proxy objects that have properties. */ extern const char* const AJ_PropertiesIface[6]; /** * The DBUS Peer interface name */ extern const char DBusPeerInterface[27]; /** * The AllJoyn Peer Authentication interface name */ extern const char PeerAuthInterface[36]; /* * Constants for the various property method indices in the properties interface */ #define AJ_PROP_GET 0 /**< index for property method get */ #define AJ_PROP_SET 1 /**< index for property method set */ #define AJ_PROP_GET_ALL 2 /**< index for property method get_all */ #define AJ_PROP_CHANGED 3 /**< index for properties changed signal */ /** * The introspection interface. */ extern const char* const AJ_IntrospectionIface[3]; /** * The AllSeen introspection interface name */ extern const char AllSeenIntrospectableInterface[28]; /** * The AllSeen introspection interface with the additional descriptions */ extern const char* const AJ_AllSeenIntrospectionIface[4]; /** * The standard objects that implement AllJoyn core functionality */ extern const AJ_Object AJ_StandardObjects[9]; /** * @} */ #endif ajtcl-16.04/inc/aj_util.h000066400000000000000000000236271271074662300152140ustar00rootroot00000000000000#ifndef _AJ_UTIL_H #define _AJ_UTIL_H /** * @file aj_util.h * @defgroup aj_util Utility Functions * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif /** * Structure for holding a time */ typedef struct _AJ_Time { uint16_t milliseconds; /**< The number of milliseconds in the time */ uint32_t seconds; /**< The number of seconds in the time */ } AJ_Time; /** * Get the current alljoyn version found in aj_version.h. * Format is: * ".. Tag " * * @return A string containing the alljoyn version */ AJ_EXPORT const char* AJ_GetVersion(); /** * Get the time elapsed in milliseconds since this function was called with the same timer. * Call AJ_InitTimer() to initialize the timer before calling this function. * * @param timer Tracks relative time. * @param cumulative If TRUE the elapsed time returned is cumulative, otherwise it is relative to * the time the function was last called. * * @return The elapsed time in milliseconds. */ AJ_EXPORT uint32_t AJ_GetElapsedTime(AJ_Time* timer, uint8_t cumulative); /** * Gets the time for the debug statement. * * @param timer the time for the debug statement. * * @return AJ_OK if the time has been set. An error indicates that the time has not been set and the default debug time should be used. */ AJ_EXPORT AJ_Status _AJ_GetDebugTime(AJ_Time* timer); /** * Initialize a timer * * @param timer The timer to initialize */ AJ_EXPORT void AJ_InitTimer(AJ_Time* timer); AJ_EXPORT int32_t AJ_GetTimeDifference(AJ_Time* timerA, AJ_Time* timerB); AJ_EXPORT void AJ_TimeAddOffset(AJ_Time* timerA, uint32_t msec); AJ_EXPORT int8_t AJ_CompareTime(AJ_Time timerA, AJ_Time timerB); AJ_EXPORT uint64_t AJ_DecodeTime(char* der, const char* fmt); /** * Indicates a future time so a periodic event won't happen */ #define AJ_TIMER_FOREVER -1 /** * Pause the current thread for a number of milliseconds */ AJ_EXPORT void AJ_Sleep(uint32_t time); /** * Allocate memory. This function should only be used for allocation of short term buffers that * might otherwise be allocated on the stack. */ AJ_EXPORT void* AJ_Malloc(size_t size); /** * Reallocate a previously allocated memory block to a new size */ AJ_EXPORT void* AJ_Realloc(void* ptr, size_t size); /** * Free memory previously allocated by AJ_Malloc() */ AJ_EXPORT void AJ_Free(void* mem); /** * Zero-fill memory and assure it will not be optimized away */ AJ_EXPORT void AJ_MemZeroSecure(void* s, size_t n); /** * Macro for getting the size of an array variable */ #define ArraySize(a) (sizeof(a) / sizeof(a[0])) /** * Find position of first instance of any character in a given string in a string. * * @param str The string to search * @param chars The characters to search for * * @return The position of the first instance of the character in the string or -1 if the character * does not appear in the string. * */ int32_t AJ_StringFindFirstOf(const char* str, const char* chars); /** * Convert a raw byte string to NUL terminated ascii hex string. It is permitted for raw and hex to * point to the same memory location. * * @param raw The bytes to convert * @param rawLen The number of bytes to convert * @param hex The buffer to receive the converted hex data * @param hexLen The length of the hex buffer * @param lower TRUE for lower-case, FALSE for upper-case * * @return * - AJ_OK if the string was converted * - AJ_ERR_RESOURCES if the hexLen is too small to fit the converted string. */ AJ_Status AJ_RawToHex(const uint8_t* raw, size_t rawLen, char* hex, size_t hexLen, uint8_t lower); /** * Convert a NUL terminated ascii hex string to raw bytes. It is permitted for raw and hex buffer to * point to the same memory location. * * @param hex The buffer containing the ASCII hex string * @param hexLen Length of the hex data to decode or zero to decode entire string. * @param raw The bytes to convert * @param rawLen The number of bytes to convert * * @return * - AJ_OK if the string was converted. * - AJ_ERR_RESOURCES if the rawLen is too small to fit the converted string. * - AJ_ERR_UNEXPECTED if the string is not a hexidecimal string. */ AJ_Status AJ_HexToRaw(const char* hex, size_t hexLen, uint8_t* raw, size_t rawLen); /** * get a line of input from the the file pointer (most likely stdin). * This will capture the the num-1 characters or till a newline character is * entered. * * @param[out] str a pointer to a character array that will hold the user input * @param[in] num the size of the character array 'str' * @param[in] fp the file pointer the sting will be read from. (most likely stdin) * * @return returns the same string as 'str' if there has been a read error a null * pointer will be returned and 'str' will remain unchanged. */ char* AJ_GetLine(char* str, size_t num, void* fp); /** * Prepare to read input from stdin */ uint8_t AJ_StartReadFromStdIn(); /** * Stop reading input from stdin */ uint8_t AJ_StopReadFromStdIn(); /** * get a line of input from stdin. * This will capture the the num-1 characters or till a newline character is * entered. * * @param[out] buf a character array that will hold the user input * @param[in] num the size of the character array 'str' * * @return returns the same string as 'buf' if there has been a read error a null * pointer will be returned and 'buf' will remain unchanged. */ char* AJ_GetCmdLine(char* buf, size_t num); /** * Encodes raw bytes to base 64 * * @param raw The raw bytes to encode * @param rawlen The length of the raw bytes to encode * @param pem The base64 encoded string * @param pemlen The size of the input buffer * * @return AJ_OK on success, AJ_ERR_RESOURCES if input buffer too short */ AJ_Status AJ_RawToB64(const uint8_t* raw, size_t rawlen, char* pem, size_t pemlen); /** * Decodes base64 to raw bytes * * @param pem The base64 encoded string * @param pemlen The length of the encoded string * @param raw The decoded raw bytes * @param rawlen The size of the input buffer * * @return AJ_OK on success, AJ_ERR_RESOURCES if input buffer too short */ AJ_Status AJ_B64ToRaw(const char* pem, size_t pemlen, uint8_t* raw, size_t rawlen); uint16_t AJ_ByteSwap16(uint16_t x); uint32_t AJ_ByteSwap32(uint32_t x); uint64_t AJ_ByteSwap64(uint64_t x); /** * Convert integer to decimal string representation * * @param val The integer to convert * @param buf The input buffer where converted string is stored * @param buflen The size of the input buffer * * @return AJ_OK on success, AJ_ERR_RESOURCES if input buffer too short */ AJ_Status AJ_IntToString(int32_t val, char* buf, size_t buflen); /** * Convert AF_INET address to dotted decimal string representation * * @param val The address to convert * @param buf The input buffer where converted string is stored * @param buflen The size of the input buffer * * @return AJ_OK on success, AJ_ERR_RESOURCES if input buffer too short */ AJ_Status AJ_InetToString(uint32_t addr, char* buf, size_t buflen); /* * Convert unsigned 16-bit int array to network order (big endian) bytes. * * @param u16 Unsigned 16-bit array * @param len Length of 16-bit array * @param u8 Unsigned 8-bit array * */ void HostU16ToBigEndianU8(uint16_t* u16, size_t len, uint8_t* u8); /** * Convert unsigned 16-bit int array to little endian bytes. * * @param u16 Unsigned 16-bit array * @param len Length of 16-bit array * @param u8 Unsigned 8-bit array * */ void HostU16ToLittleEndianU8(uint16_t* u16, size_t len, uint8_t* u8); /** * Convert unsigned 32-bit int array to little endian bytes. * * @param u32 Unsigned 32-bit array * @param len Length of 32-bit array * @param u8 Unsigned 8-bit array * */ void HostU32ToLittleEndianU8(uint32_t* u32, size_t len, uint8_t* u8); /** * Convert unsigned 64-bit int array to network order (big endian) bytes. * * @param u64 Unsigned 64-bit array * @param len Length of 64-bit array * @param u8 Unsigned 8-bit array * */ void HostU64ToBigEndianU8(uint64_t* u64, size_t len, uint8_t* u8); /** * Convert unsigned 64-bit int array to little endian bytes. * * @param u64 Unsigned 64-bit array * @param len Length of 64-bit array * @param u8 Unsigned 8-bit array * */ void HostU64ToLittleEndianU8(uint64_t* u64, size_t len, uint8_t* u8); /** * Convert unsigned 32-bit int array to network order (big endian) bytes. * * @param u32 Unsigned 32-bit array * @param len Length of 32-bit array * @param u8 Unsigned 8-bit array * */ void HostU32ToBigEndianU8(uint32_t* u32, size_t len, uint8_t* u8); /** * Convert network order (big endian) bytes to unsigned 32-bit int array. * * @param u8 Unsigned 8-bit array * @param u32 Unsigned 32-bit array * @param len Length of 32-bit array * */ void BigEndianU8ToHostU32(uint8_t* u8, uint32_t* u32, size_t len); #ifdef __cplusplus } #endif /** * @} */ #endif ajtcl-16.04/inc/aj_version.h000066400000000000000000000042441271074662300157160ustar00rootroot00000000000000#ifndef _AJ_VERSION_H #define _AJ_VERSION_H /** * @file aj_version.h * @defgroup aj_version Current AllJoyn Thin Client Version * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_RELEASE_YEAR 16 /**< release year */ #define AJ_MAJOR_VERSION AJ_RELEASE_YEAR /**< deprecated */ #define AJ_RELEASE_MONTH 4 /**< release month */ #define AJ_MINOR_VERSION AJ_RELEASE_MONTH /**< deprecated */ #define AJ_FEATURE_VERSION 0 /**< feature version */ #define AJ_RELEASE_VERSION AJ_FEATURE_VERSION /**< deprecated */ #define AJ_BUGFIX_VERSION 0 /**< bugfix version (0=first, 0x61==a, 0x62==b, etc.) */ #define AJ_RELEASE_YEAR_STR 16 /**< release year string (two digits) */ #define AJ_RELEASE_MONTH_STR 04 /**< release month string (two digits) */ #define AJ_FEATURE_VERSION_STR 00 /**< feature version string (00, 01, 02, ...) */ #define AJ_BUGFIX_VERSION_STR "" /**< bugfix version string (blank, a, b, ...) */ #define AJ_RELEASE_TAG "v16.04.00" #define AJ_VERSION (((AJ_RELEASE_YEAR) << 24) | ((AJ_RELEASE_MONTH) << 16) | ((AJ_FEATURE_VERSION) << 8) | (AJ_BUGFIX_VERSION)) /**< macro to generate the version from major, minor, release, bugfix */ /** * @} */ #endif ajtcl-16.04/inc/aj_wifi_ctrl.h000066400000000000000000000126631271074662300162170ustar00rootroot00000000000000#ifndef _AJ_WIFI_CTRL_H #define _AJ_WIFI_CTRL_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #ifdef __cplusplus extern "C" { #endif typedef enum { AJ_WIFI_IDLE, AJ_WIFI_CONNECTING, /**< Connecting to an AP */ AJ_WIFI_CONNECT_OK, /**< Connected to an AP */ AJ_WIFI_SOFT_AP_INIT, /**< Initialized Soft AP */ AJ_WIFI_SOFT_AP_UP, /**< Soft AP is up and ready for stations to connect */ AJ_WIFI_STATION_OK, /**< Station has connected to Soft AP */ AJ_WIFI_CONNECT_FAILED, /**< Connneciton to an AP failed */ AJ_WIFI_AUTH_FAILED, /**< Authentication failure while connecting to AP */ AJ_WIFI_DISCONNECTING /**< Currently disconnecting */ } AJ_WiFiConnectState; /** * Enumeration of WiFi security types. These values are returned in an AllJoyn message so the * integer mappings must not be changed. */ typedef enum { AJ_WIFI_SECURITY_NONE = 0x00, /**< No security, network is open */ AJ_WIFI_SECURITY_WEP = 0x01, /**< WiFi WEP security */ AJ_WIFI_SECURITY_WPA = 0x02, /**< WiFi WPA Security */ AJ_WIFI_SECURITY_WPA2 = 0x03 /**< WiFi WPA2 Security */ } AJ_WiFiSecurityType; /** * Enumeration of WiFi cipher types. */ typedef enum { AJ_WIFI_CIPHER_NONE = 0x00, /**< No cipher specified */ AJ_WIFI_CIPHER_TKIP = 0x01, /**< Legacy TKIP cipher */ AJ_WIFI_CIPHER_CCMP = 0x02, /**< CCMP cipher */ AJ_WIFI_CIPHER_WEP = 0x03 /**< WEP cipher */ } AJ_WiFiCipherType; /** * Get the current connection state */ AJ_WiFiConnectState AJ_GetWifiConnectState(void); /** * Connect to a WiFi access point * * @param ssid NUL terminated string with the name of the ssid to connect to * @param secType The type of WiFi security to use. * @param cipherType The cipher type to use. * @param passphrase The WiFi security passphrase if security is not AJ_WIFI_SECURITY_NONE. * */ AJ_Status AJ_ConnectWiFi(const char* ssid, AJ_WiFiSecurityType secType, AJ_WiFiCipherType cipherType, const char* passphrase); /** * Print the boards firmware version */ AJ_Status AJ_PrintFWVersion(); /** * Disconnect from the current WiFi access point */ AJ_Status AJ_DisconnectWiFi(void); /** * Enable soft-AP mode * * @param ssid The SSID for the AP * @param hidden If TRUE the SSID is not broadcast * @param passphrase The passphrase if secType != AJ_WIFI_SECURITY_NONE * @param timeout Return AJ_ERR_TIMEOUT if nobody connects within msec. 0 means wait forever. */ AJ_Status AJ_EnableSoftAP(const char* ssid, uint8_t hidden, const char* passphrase, uint32_t timeout); /* * Put the wifi radio to sleep for a while * * @param msec Number of milliseconds to sleep radio */ AJ_Status AJ_SuspendWifi(uint32_t msec); /** * Function prototype for receiving scan results * * @param context The caller's context passed in to AJ_WiFiScan() * @param ssid NUL terminated string containing the SSID of a WiFi AP * @param bssid The MAC address of the WiFi AP * @param rssi The receive signal strength indication * @param secType The security type for the WiFi AP * @param cipherType The cipher type used in conjunction with the security type * */ typedef void (*AJ_WiFiScanResult)(void* context, const char* ssid, const uint8_t bssid[6], uint8_t rssi, AJ_WiFiSecurityType secType, AJ_WiFiCipherType cipherType); /** * Scan for WiFi access points. Will callback for each AP found with the acccess points sorted in * descending RSSI. This function returns when the scan is complete. * * @param context A caller-provided context to pass into the callback function * @param callback A function to be called for each WiFi AP found during the scan. * @param maxAPs The maximum number of APs to return via the callback function. * * @return AJ_OK if the scan completed succesfully. */ AJ_Status AJ_WiFiScan(void* context, AJ_WiFiScanResult callback, uint8_t maxAPs); /** * Reset the WiFi driver */ AJ_Status AJ_ResetWiFi(void); /** * Get an IP address from DHCP and return it * * @return Return AJ_Status */ AJ_Status AJ_AcquireIPAddress(uint32_t* ip, uint32_t* mask, uint32_t* gateway, int32_t timeout); /** * Return the current IP * * @return Return AJ_Status */ AJ_Status AJ_GetIPAddress(uint32_t* ip, uint32_t* mask, uint32_t* gateway); /** * Set the system's IP address * * @return Return AJ_Status */ AJ_Status AJ_SetIPAddress(uint32_t ip, uint32_t mask, uint32_t gateway); #ifdef __cplusplus } #endif #endif ajtcl-16.04/inc/alljoyn.h000066400000000000000000000027301271074662300152250ustar00rootroot00000000000000#ifndef _ALLJOYN_H #define _ALLJOYN_H /** * @file alljoyn.h * @defgroup alljoyn Conveniently Include AllJoyn Headers * @{ */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include /** * @} */ #endif ajtcl-16.04/samples/000077500000000000000000000000001271074662300142755ustar00rootroot00000000000000ajtcl-16.04/samples/SConscript000066400000000000000000000010571271074662300163120ustar00rootroot00000000000000Import('env') sample_env = env.Clone() sample_env.Append(LIBPATH = "#dist/lib") sample_env.Prepend(LIBS = "ajtcl") Export('sample_env') # Add/remove projects from build # Only build the following samples for the TARG operating system. # The samples/examples for target platforms are handled by # the target specific directory (viz. target/arduino). if sample_env['TARG'] in [ 'win32', 'linux', 'darwin' ]: sample_env.SConscript(['basic/SConscript']) sample_env.SConscript(['secure/SConscript']) sample_env.SConscript(['network/SConscript']) ajtcl-16.04/samples/basic/000077500000000000000000000000001271074662300153565ustar00rootroot00000000000000ajtcl-16.04/samples/basic/.gitignore000066400000000000000000000001221271074662300173410ustar00rootroot00000000000000basic_client basic_service nameChange_client signalConsumer_client signal_service ajtcl-16.04/samples/basic/SConscript000066400000000000000000000007401271074662300173710ustar00rootroot00000000000000Import('sample_env') progs = [ sample_env.Program('basic_service', ['basic_service.c']), sample_env.Program('basic_client', ['basic_client.c']), sample_env.Program('signal_service', ['signal_service.c']), sample_env.Program('nameChange_client', ['nameChange_client.c']), sample_env.Program('signalConsumer_client', ['signalConsumer_client.c']), sample_env.Program('eventaction_service', ['eventaction_service.c']) ] sample_env.Install("#dist/bin", progs) ajtcl-16.04/samples/basic/basic_client.c000066400000000000000000000163511271074662300201470ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE BASIC_CLIENT #include #include #include #include static const char ServiceName[] = "org.alljoyn.Bus.sample"; static const char ServicePath[] = "/sample"; static const uint16_t ServicePort = 25; /* * Buffer to hold the full service name. This buffer must be big enough to hold * a possible 255 characters plus a null terminator (256 bytes) */ static char fullServiceName[AJ_MAX_SERVICE_NAME_SIZE]; uint8_t dbgBASIC_CLIENT = 0; /** * The interface name followed by the method signatures. * * See also .\inc\aj_introspect.h */ static const char* const sampleInterface[] = { "org.alljoyn.Bus.sample", /* The first entry is the interface name. */ "?Dummy foos", /* Method at index 2. */ NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription sampleInterfaces[] = { sampleInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, sampleInterfaces }, { NULL } }; /* * The value of the arguments are the indices of the object path in AppObjects (above), * interface in sampleInterfaces (above), and member indices in the interface. * The 'cat' index is 2. The reason for this is as follows: The first entry in sampleInterface * is the interface name. This makes the first index (index 0 of the methods) the second string in * sampleInterface[]. The two dummy entries are indices 0 and 1. The index of the method we * implement for basic_client, 'cat', is 2 which is the fourth string in the array of strings * sampleInterface[]. * * See also .\inc\aj_introspect.h */ #define BASIC_CLIENT_CAT AJ_PRX_MESSAGE_ID(0, 0, 2) #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (100 * 10) void MakeMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_CAT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "ss", "Hello ", "World!"); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("MakeMethodCall() resulted in a status of 0x%04x.\n", status)); } int AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint8_t done = FALSE; uint32_t sessionId = 0; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(NULL, AppObjects); while (!done) { AJ_Message msg; if (!connected) { status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServiceName, ServicePort, &sessionId, NULL, fullServiceName); if (status == AJ_OK) { AJ_InfoPrintf(("StartClient returned %d, sessionId=%u.\n", status, sessionId)); connected = TRUE; MakeMethodCall(&bus, sessionId); } else { AJ_InfoPrintf(("StartClient returned 0x%04x.\n", status)); break; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_REPLY_ID(BASIC_CLIENT_CAT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%s'.\n", fullServiceName, "cat", ServicePath, arg.val.v_string)); done = TRUE; } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ MakeMethodCall(&bus, sessionId); } } else { const char* info = ""; if (AJ_UnmarshalArgs(&msg, "s", &info) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%s)\n", msg.error, info)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } done = TRUE; } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* A session was lost so return error to force a disconnect. */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u\n", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_SESSION_LOST)) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); exit(0); } } AJ_AlwaysPrintf(("Basic client exiting with status %d.\n", status)); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/basic/basic_service.c000066400000000000000000000147321271074662300203320ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE BASIC_SERVICE #include #include #include #define CONNECT_ATTEMPTS 10 static const char ServiceName[] = "org.alljoyn.Bus.sample"; static const char ServicePath[] = "/sample"; static const uint16_t ServicePort = 25; uint8_t dbgBASIC_SERVICE = 0; /** * The interface name followed by the method signatures. * * See also .\inc\aj_introspect.h */ static const char* const sampleInterface[] = { "org.alljoyn.Bus.sample", /* The first entry is the interface name. */ "?Dummy foos", /* Method at index 1. */ NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription sampleInterfaces[] = { sampleInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, sampleInterfaces }, { NULL } }; /* * The value of the arguments are the indices of the * object path in AppObjects (above), interface in sampleInterfaces (above), and * member indices in the interface. * The 'cat' index is 1 because the first entry in sampleInterface is the interface name. * This makes the first index (index 0 of the methods) the second string in * sampleInterface[] which, for illustration purposes is a dummy entry. * The index of the method we implement for basic_service, 'cat', is 1 which is the third string * in the array of strings sampleInterface[]. * * See also .\inc\aj_introspect.h */ #define BASIC_SERVICE_CAT AJ_APP_MESSAGE_ID(0, 0, 1) /* * Use async version of API for reply */ static uint8_t asyncForm = TRUE; static AJ_Status AppHandleCat(AJ_Message* msg) { const char* string0; const char* string1; char buffer[256]; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "ss", &string0, &string1); /* We have the arguments. Now do the concatenation. */ strncpy(buffer, string0, ArraySize(buffer)); buffer[ArraySize(buffer) - 1] = '\0'; strncat(buffer, string1, ArraySize(buffer) - strlen(buffer) - 1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_STRING, 0, buffer, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } /* All times are expressed in milliseconds. */ #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define SLEEP_TIME (1000 * 2) int AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; /* One time initialization before calling any other AllJoyn APIs. */ AJ_Initialize(); /* This is for debug purposes and is optional. */ AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned %d, session_id=%u\n", status, sessionId)); connected = TRUE; } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } break; case BASIC_SERVICE_CAT: status = AppHandleCat(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u\n", id, reason)); } break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); connected = FALSE; /* Sleep a little while before trying to reconnect. */ AJ_Sleep(SLEEP_TIME); } } AJ_AlwaysPrintf(("Basic service exiting with status %d.\n", status)); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/basic/eventaction_service.c000066400000000000000000000331121271074662300215610ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE EVENTACTION_SERVICE #include #include #include #include #include #define CONNECT_ATTEMPTS 10 static const char ServiceName[] = "example.alljoyn.Bus.eventaction.sample"; static const char ServicePath[] = "/eventaction"; static const uint16_t ServicePort = 50; static char buffer[60]; uint8_t dbgEVENTACTION_SERVICE = 0; /** * The interface name followed by the method signatures. * * See also .\inc\aj_introspect.h */ static const char* const sampleInterface[] = { "example.alljoyn.Bus.eventaction.sample", /* The first entry is the interface name. */ "?dummyMethod foos", /* Method at index 1. */ "!someSignal name>s", "!&someSessionlessSignal", /* & indicates that a signal is designated as sessionless so the introspection will describe it as such */ NULL }; static const char* const objDesc[] = { "Sample object description", "ES: Sample object description" }; static const char* const intfDesc[] = { "Sample interface", "ES: Sample interface" }; static const char* const joinDesc[] = { "Join two strings and return the result", "ES: Join two strings and return the result" }; static const char* const joinInArg1Desc[] = { "First part of string", "ES: First part of string" }; static const char* const joinInArg2Desc[] = { "Second part of string", "ES: Second part of string" }; static const char* const joinOutArgDesc[] = { "Return result", "ES: Return result" }; static const char* const someSignalArgDesc[] = { "EN: %s", "ES: %s" }; static const char* const someSessionlessSignalDesc[] = { "An example sessionless signal", "ES: An example sessionless signal" }; /* * AJ_DESCRIPTION_ID(BusObject base ID, Interface index, Member index, Arg index) * Interface, Member, and Arg indexes starts at 1 and represent the readible index in a list. * [ a, b, ... ] a would be index 1, b 2, etc. */ #define SAMPLE_OBJECT_ID 0 #define SAMPLE_OBJECT_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 0, 0, 0) #define SAMPLE_INTERFACE_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 1, 0, 0) #define SAMPLE_JOIN_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 1, 2, 0) #define SAMPLE_JOIN_ARG_INSTR1_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 1, 2, 1) #define SAMPLE_JOIN_ARG_INSTR2_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 1, 2, 2) #define SAMPLE_JOIN_ARG_OUTSTR_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 1, 2, 3) #define SAMPLE_SOMESIGNAL_ARG_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 1, 3, 1) #define SAMPLE_SOMESESSIONLESSSIGNAL_DESC AJ_DESCRIPTION_ID(SAMPLE_OBJECT_ID, 1, 4, 0) static const char* const languages[] = { "en", "es", NULL }; static const char* MyTranslator(uint32_t descId, const char* lang) { uint8_t langIndex; /* Compute the location of lang in our languages array */ langIndex = 0; while (lang && languages[langIndex] != NULL) { if (strlen(lang) > 0 && strcmp(lang, languages[langIndex]) == 0) { break; } ++langIndex; } /* If all languages in list did not match, then set index to 0 (default) language */ if (languages[langIndex] == NULL) { langIndex = 0; } /* Return correct lang string for descId */ switch (descId) { case SAMPLE_OBJECT_DESC: return objDesc[langIndex]; case SAMPLE_INTERFACE_DESC: return intfDesc[langIndex]; case SAMPLE_JOIN_DESC: return joinDesc[langIndex]; case SAMPLE_JOIN_ARG_INSTR1_DESC: return joinInArg1Desc[langIndex]; case SAMPLE_JOIN_ARG_INSTR2_DESC: return joinInArg2Desc[langIndex]; case SAMPLE_JOIN_ARG_OUTSTR_DESC: return joinOutArgDesc[langIndex]; case SAMPLE_SOMESIGNAL_ARG_DESC: sprintf(buffer, someSignalArgDesc[langIndex], "Some replacement value"); return buffer; case SAMPLE_SOMESESSIONLESSSIGNAL_DESC: return someSessionlessSignalDesc[langIndex]; } /* No description set so return NULL */ return NULL; } static AJ_Status MyAboutPropGetter(AJ_Message* reply, const char* language) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_GUID guid; char guidStr[16 * 2 + 1]; uint8_t appId[16]; guidStr[16 * 2] = '\0'; if ((language != NULL) && (0 != strcmp(language, languages[0])) && (0 != strcmp(language, languages[1])) && (0 != strcmp(language, ""))) { /* the language supplied was not supported */ return AJ_ERR_NO_MATCH; } status = AJ_GetLocalGUID(&guid); if (status != AJ_OK) { return status; } AJ_GUID_ToString(&guid, guidStr, sizeof(guidStr)); status = AJ_HexToRaw(guidStr, 0, appId, 16); if (status != AJ_OK) { return status; } status = AJ_MarshalContainer(reply, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_APP_ID_STR, "ay", appId, 16); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_APP_NAME_STR, "s", "eventaction_service"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_ID_STR, "s", guidStr); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_NAME_STR, "s", "Tester"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MANUFACTURER_STR, "s", "QCE"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MODEL_NUMBER_STR, "s", "1.0"); } //SupportedLanguages if (status == AJ_OK) { AJ_Arg dict; AJ_Arg languageListArray; status = AJ_MarshalContainer(reply, &dict, AJ_ARG_DICT_ENTRY); if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", AJ_SUPPORTED_LANGUAGES_STR); } if (status == AJ_OK) { status = AJ_MarshalVariant(reply, "as"); } if (status == AJ_OK) { status = AJ_MarshalContainer(reply, &languageListArray, AJ_ARG_ARRAY); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", languages[0]); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", languages[1]); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &languageListArray); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &dict); } } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DESCRIPTION_STR, "s", "eventaction_service test app"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEFAULT_LANGUAGE_STR, "s", languages[0]); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_SOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_AJSOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &array); } return status; } /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription sampleInterfaces[] = { sampleInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, sampleInterfaces, AJ_OBJ_FLAG_DESCRIBED, NULL }, { NULL } }; /* * The value of the arguments are the indices of the * object path in AppObjects (above), interface in sampleInterfaces (above), and * member indices in the interface. * The 'cat' index is 1 because the first entry in sampleInterface is the interface name. * This makes the first index (index 0 of the methods) the second string in * sampleInterface[] which, for illustration purposes is a dummy entry. * The index of the method we implement for basic_service, 'cat', is 1 which is the third string * in the array of strings sampleInterface[]. * * See also .\inc\aj_introspect.h */ #define EVENTACTION_SERVICE_CAT AJ_APP_MESSAGE_ID(0, 0, 1) static AJ_Status AppHandleCat(AJ_Message* msg) { const char* string0; const char* string1; char tmpBuffer[256]; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "ss", &string0, &string1); AJ_MarshalReplyMsg(msg, &reply); /* We have the arguments. Now do the concatenation. */ strncpy(tmpBuffer, string0, ArraySize(tmpBuffer)); tmpBuffer[ArraySize(tmpBuffer) - 1] = '\0'; strncat(tmpBuffer, string1, ArraySize(tmpBuffer) - strlen(tmpBuffer) - 1); AJ_InitArg(&replyArg, AJ_ARG_STRING, 0, tmpBuffer, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } /* All times are expressed in milliseconds. */ #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define SLEEP_TIME (1000 * 2) int AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; /* One time initialization before calling any other AllJoyn APIs. */ AJ_Initialize(); /* Set the languages and a lookup function so that we can print out the default descriptions in the AJ_PrintXML call */ AJ_RegisterDescriptionLanguages(languages); AJ_RegisterObjectListWithDescriptions(AppObjects, 1, MyTranslator); AJ_AboutRegisterPropStoreGetter(MyAboutPropGetter); /* This is for debug purposes and is optional. */ AJ_AlwaysPrintf(("XML with no Descriptions\n")); AJ_PrintXML(AppObjects); AJ_AlwaysPrintf(("XML with Descriptions using language: %s\n", languages[0])); AJ_PrintXMLWithDescriptions(AppObjects, languages[0]); AJ_AlwaysPrintf(("XML with Descriptions using language: %s\n", languages[1])); AJ_PrintXMLWithDescriptions(AppObjects, languages[1]); AJ_AlwaysPrintf(("XML with empty language\n")); AJ_PrintXMLWithDescriptions(AppObjects, ""); AJ_AlwaysPrintf(("XML with unsupported language (fr)\n")); AJ_PrintXMLWithDescriptions(AppObjects, "fr"); AJ_AlwaysPrintf(("XML with sublanguage (EN-US)\n")); AJ_PrintXMLWithDescriptions(AppObjects, "EN-US"); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned %d, session_id=%u\n", status, sessionId)); connected = TRUE; } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_AlwaysPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } break; case EVENTACTION_SERVICE_CAT: status = AppHandleCat(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u\n", id, reason)); } break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); connected = FALSE; /* Sleep a little while before trying to reconnect. */ AJ_Sleep(SLEEP_TIME); } } AJ_AlwaysPrintf(("Basic service exiting with status %d.\n", status)); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/basic/nameChange_client.c000066400000000000000000000151761271074662300211200ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE NAME_CHANGE #include #include #include #include uint8_t dbgNAME_CHANGE = 0; /** * Static constants. */ static const char InterfaceName[] = "org.alljoyn.Bus.signal_sample"; static const char ServiceName[] = "org.alljoyn.Bus.signal_sample"; static const char ServicePath[] = "/"; static const uint16_t ServicePort = 25; /* * Buffer to hold the full service name. This buffer must be big enough to hold * a possible 255 characters plus a null terminator (256 bytes) */ static char fullServiceName[AJ_MAX_SERVICE_NAME_SIZE]; /** * The interface name followed by the method signatures. * This sample changes a property in the signal_service sample. * * See also .\inc\aj_introspect.h */ static const char* const sampleInterface[] = { InterfaceName, /* The first entry is the interface name. */ "@name=s", /* Property at index 0. */ NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription sampleInterfaces[] = { sampleInterface, AJ_PropertiesIface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, sampleInterfaces }, { NULL } }; /* * The value of the arguments are the indices of the object path in AppObjects (above), * interface in sampleInterfaces (above), and member indices in the interface. * The 'name' index is 0 because the first entry in sampleInterface is the interface name. * * Encode the property id from the object path, interface, and member indices. * * See also .\inc\aj_introspect.h */ #define PRX_SET_NAME AJ_PRX_PROPERTY_ID(0, 0, 0) #define PRX_SET_PROP AJ_PRX_MESSAGE_ID(0, 1, AJ_PROP_SET) #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (100 * 10) AJ_Status SendNewName(AJ_BusAttachment* bus, uint32_t sessionId, char*newName) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, PRX_SET_PROP, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalPropertyArgs(&msg, PRX_SET_NAME); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", newName); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } } return status; } int main(int argc, char*argv[]) { AJ_Status status = AJ_ERR_INVALID; if (argc > 1) { AJ_BusAttachment bus; uint8_t connected = FALSE; uint8_t done = FALSE; uint32_t sessionId = 0; char*newName = argv[1]; status = AJ_OK; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(NULL, AppObjects); while (!done) { AJ_Message msg; if (!connected) { status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServiceName, ServicePort, &sessionId, NULL, fullServiceName); if (status == AJ_OK) { AJ_InfoPrintf(("StartClient returned %d, sessionId=%u.\n", status, sessionId)); connected = TRUE; SendNewName(&bus, sessionId, newName); } else { AJ_InfoPrintf(("StartClient returned 0x%04x.\n", status)); break; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_REPLY_ID(PRX_SET_PROP): done = TRUE; AJ_AlwaysPrintf(("Name on the interface '%s' at service '%s' was set to '%s'.\n", InterfaceName, fullServiceName, newName)); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* Force a disconnect. */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_SESSION_LOST) || (status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); exit(0); } } } else { AJ_ErrPrintf(("Error. New name not given: nameChange_client [new name].\n")); } AJ_AlwaysPrintf(("nameChange_Client exiting with status 0x%04x.\n", status)); return status; } ajtcl-16.04/samples/basic/signalConsumer_client.c000066400000000000000000000230331271074662300220520ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SIGNAL_CONSUMER #include #include #include #include uint8_t dbgSIGNAL_CONSUMER = 0; /** * Static constants. */ static const char InterfaceName[] = "org.alljoyn.Bus.signal_sample"; static const char ServiceName[] = "org.alljoyn.Bus.signal_sample"; static const char ServicePath[] = "/"; static const uint16_t ServicePort = 25; /* * Buffer to hold the full service name. This buffer must be big enough to hold * a possible 255 characters plus a null terminator (256 bytes) */ static char fullServiceName[AJ_MAX_SERVICE_NAME_SIZE]; /** * The interface name followed by the method signatures. * This sample receives a signal of a property change in the sample signal_service. * * See also .\inc\aj_introspect.h */ static const char* const sampleInterface[] = { InterfaceName, /* The first entry is the interface name. */ "!nameChanged newName>s", /* Signal at index 0 with an output string of the new name. */ NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription sampleInterfaces[] = { sampleInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, sampleInterfaces }, { NULL } }; /* * The value of the arguments are the indices of the object path in AppObjects (above), * interface in sampleInterfaces (above), and member indices in the interface. * The 'name' index is 0 because the first entry in sampleInterface is the interface name. * * Encode the property id from the object path, interface, and member indices. * * See also .\inc\aj_introspect.h */ #define NAMECHANGE_SIGNAL AJ_PRX_MESSAGE_ID(0, 0, 0) #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (100 * 10) AJ_Status ReceiveNewName(AJ_Message*msg) { AJ_Arg arg; AJ_Status status = AJ_UnmarshalArg(msg, &arg); if (status == AJ_OK) { AJ_AlwaysPrintf(("--==## signalConsumer: Name Changed signal Received ##==--\n")); AJ_AlwaysPrintf(("\tNew name: '%s'.\n", arg.val.v_string)); } return status; } int AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint8_t done = FALSE; uint32_t sessionId = 0; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(NULL, AppObjects); while (!done) { AJ_Message msg; if (!connected) { status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServiceName, ServicePort, &sessionId, NULL, fullServiceName); if (status == AJ_OK) { AJ_InfoPrintf(("StartClient returned %d, sessionId=%u.\n", status, sessionId)); connected = TRUE; status = AJ_BusAddSignalRule(&bus, "nameChanged", InterfaceName, AJ_BUS_SIGNAL_ALLOW); } else { AJ_InfoPrintf(("StartClient returned 0x%04x.\n", status)); break; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } switch (status) { case AJ_OK: /* * The contents of the message are meaningful, only when * the message was unmarshaled successfully. */ switch (msg.msgId) { case NAMECHANGE_SIGNAL: ReceiveNewName(&msg); break; case AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION): AJ_InfoPrintf(("JoinSession SUCCESS (Session id=%d).\n", sessionId)); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* Force a disconnect. */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } break; case AJ_ERR_NULL: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Unexpected NULL pointer'.\n")); break; case AJ_ERR_UNEXPECTED: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'An operation was unexpected at this time'.\n")); break; case AJ_ERR_INVALID: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'A value was invalid'.\n")); break; case AJ_ERR_IO_BUFFER: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'An I/O buffer was invalid or in the wrong state'.\n")); break; case AJ_ERR_READ: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'An error while reading data from the network'.\n")); break; case AJ_ERR_WRITE: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'An error while writing data to the network'.\n")); break; case AJ_ERR_TIMEOUT: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'A timeout occurred'.\n")); break; case AJ_ERR_MARSHAL: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Marshaling failed due to badly constructed message argument'.\n")); break; case AJ_ERR_UNMARSHAL: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Unmarshaling failed due to a corrupt or invalid message'.\n")); break; case AJ_ERR_END_OF_DATA: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'No enough data'.\n")); break; case AJ_ERR_RESOURCES: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Insufficient memory to perform the operation'.\n")); break; case AJ_ERR_NO_MORE: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Attempt to unmarshal off the end of an array'.\n")); break; case AJ_ERR_SECURITY: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Authentication or decryption failed'.\n")); break; case AJ_ERR_CONNECT: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Network connect failed'.\n")); break; case AJ_ERR_UNKNOWN: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'A unknown value'.\n")); break; case AJ_ERR_NO_MATCH: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Something didn't match'.\n")); break; case AJ_ERR_SIGNATURE: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'Signature is not what was expected'.\n")); break; case AJ_ERR_DISALLOWED: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'An operations was not allowed'.\n")); break; case AJ_ERR_FAILURE: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'A failure has occured'.\n")); break; case AJ_ERR_RESTART: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'The OEM event loop must restart'.\n")); break; case AJ_ERR_LINK_TIMEOUT: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'The bus link is inactive too long'.\n")); break; case AJ_ERR_DRIVER: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned 'An error communicating with a lower-layer driver'.\n")); break; case AJ_ERR_SESSION_LOST: AJ_ErrPrintf(("The session was lost\n")); break; default: AJ_ErrPrintf(("AJ_UnmarshalMsg() returned '%s'.\n", AJ_StatusText(status))); break; } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if (status == AJ_ERR_SESSION_LOST) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); exit(0); } } AJ_AlwaysPrintf(("signalConsumer_Client exiting with status 0x%04x.\n", status)); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/basic/signal_service.c000066400000000000000000000174651271074662300205340ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SIGNAL_SERVICE #include #include #include #include uint8_t dbgSIGNAL_SERVICE = 0; /** * Statics. */ static AJ_BusAttachment busAttachment; static char propertyName[128] = "Default name"; /** * Static constants. */ static const size_t propertyNameSize = sizeof(propertyName) / sizeof(propertyName[0]); static const int ConnectAttempts = 10; static const char InterfaceName[] = "org.alljoyn.Bus.signal_sample"; static const char ServiceName[] = "org.alljoyn.Bus.signal_sample"; static const char ServicePath[] = "/"; static const uint16_t ServicePort = 25; /** * The interface name followed by the method signatures. * * See also .\inc\aj_introspect.h */ static const char* const sampleInterface[] = { InterfaceName, /* The first entry is the interface name. */ "!nameChanged newName>s", /* Signal at index 0 with an output string of the new name. */ "@name=s", /* Read/write property of the name. */ NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription sampleInterfaces[] = { AJ_PropertiesIface, /* This must be included for any interface that has properties. */ sampleInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, sampleInterfaces }, { NULL } }; /* * The value of the arguments are the indices of the * object path in AppObjects (above), interface in sampleInterfaces (above), and * member indices in the interface. * The 'nameChanged' index is 0 because the first entry in sampleInterface is the interface name. * This makes the first index (index 0 of the methods) the second string in * sampleInterface[]. * * See also .\inc\aj_introspect.h */ #define BASIC_SIGNAL_SERVICE_SIGNAL AJ_APP_MESSAGE_ID(0, 1, 0) #define BASIC_SIGNAL_SERVICE_GET_NAME AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_GET) #define BASIC_SIGNAL_SERVICE_SET_NAME AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_SET) /* * Property identifiers for the properies this application implements * Encode a property id from the object path, interface, and member indices. */ #define BASIC_SIGNAL_SERVICE_NAME_ID AJ_APP_PROPERTY_ID(0, 1, 1) static AJ_Status SendSignal() { AJ_Message msg; AJ_AlwaysPrintf(("Emitting Name Changed Signal. New value for property 'name' is '%s'.\n", propertyName)); /* For the signal to transmit outside of the current process the session ID must be 0. */ AJ_MarshalSignal(&busAttachment, &msg, BASIC_SIGNAL_SERVICE_SIGNAL, NULL, 0, AJ_FLAG_GLOBAL_BROADCAST, 0); AJ_MarshalArgs(&msg, "s", propertyName); return AJ_DeliverMsg(&msg); } static AJ_Status GetName(AJ_Message* replyMsg, uint32_t propId, void* context) { AJ_Status status = AJ_ERR_UNEXPECTED; if (propId == BASIC_SIGNAL_SERVICE_NAME_ID) { status = AJ_MarshalArgs(replyMsg, "s", propertyName); } return status; } static AJ_Status SetName(AJ_Message* replyMsg, uint32_t propId, void* context) { AJ_Status status = AJ_ERR_UNEXPECTED; if (propId == BASIC_SIGNAL_SERVICE_NAME_ID) { char*string; AJ_UnmarshalArgs(replyMsg, "s", &string); strncpy(propertyName, string, propertyNameSize); propertyName[propertyNameSize - 1] = '\0'; AJ_AlwaysPrintf(("Set 'name' property was called changing name to '%s'.\n", propertyName)); status = AJ_OK; } return status; } /* All times are expressed in milliseconds. */ #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define SLEEP_TIME (1000 * 2) int AJ_Main(void) { AJ_Status status = AJ_OK; uint8_t connected = FALSE; /* One time initialization before calling any other AllJoyn APIs. */ AJ_Initialize(); /* This is for debug purposes and is optional. */ AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&busAttachment, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned %d\n", status)); connected = TRUE; } status = AJ_UnmarshalMsg(&busAttachment, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; uint32_t sessionId; AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session. Port=%u, session_id=%u joiner='%s'.\n", port, sessionId, joiner)); } break; case BASIC_SIGNAL_SERVICE_GET_NAME: status = AJ_BusPropGet(&msg, GetName, NULL); break; case BASIC_SIGNAL_SERVICE_SET_NAME: status = AJ_BusPropSet(&msg, SetName, NULL); if (AJ_OK == status) { status = SendSignal(); AJ_InfoPrintf(("SendSignal reports status 0x%04x.\n", status)); } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&busAttachment); connected = FALSE; /* Sleep a little while before trying to reconnect. */ AJ_Sleep(SLEEP_TIME); } } AJ_AlwaysPrintf(("Basic service exiting with status 0x%04x.\n", status)); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/network/000077500000000000000000000000001271074662300157665ustar00rootroot00000000000000ajtcl-16.04/samples/network/NetworkAndBus.c000066400000000000000000000151661271074662300206710ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE NETBUSSAMPLE #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NDEBUG AJ_EXPORT uint8_t dbgNETBUSSAMPLE = 0; #endif static const char* const testInterface[] = { "org.alljoyn.alljoyn_test", "?my_ping inStrs", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { testInterface, NULL }; static const AJ_Object AppObjects[] = { { "/org/alljoyn/alljoyn_test", testInterfaces }, { NULL } }; static const char serviceName[] = "org.alljoyn.BusNode"; static AJ_Status ConnectToBus(AJ_BusAttachment* bus) { AJ_Status status; AJ_Service service; uint32_t timeout = 5000; #ifdef AJ_SERIAL_CONNECTION AJ_Time start, now; AJ_InitTimer(&start); #endif AJ_InfoPrintf(("ConnectToBus(): bus=0x%p, serviceName=\"%s\", timeout=%d.\n", bus, serviceName, timeout)); /* * Clear the bus struct */ memset(bus, 0, sizeof(AJ_BusAttachment)); /* * Clear stale name->GUID mappings */ AJ_GUID_ClearNameMap(); /* * First we need to discover a routing node. This is done with the function AJ_Discover. * It will store the connection information in the AJ_Service struct. */ #if AJ_CONNECT_LOCALHOST service.ipv4port = 9955; #if HOST_IS_LITTLE_ENDIAN service.ipv4 = 0x0100007F; // 127.0.0.1 #endif #if HOST_IS_BIG_ENDIAN service.ipv4 = 0x7f000001; // 127.0.0.1 #endif service.addrTypes = AJ_ADDR_TCP4; #elif defined ARDUINO service.ipv4port = 9955; service.ipv4 = 0x6501A8C0; // 192.168.1.101 service.addrTypes = AJ_ADDR_TCP4; status = AJ_Discover(serviceName, &service, timeout, AJ_SELECTION_TIMEOUT); if (status != AJ_OK) { AJ_InfoPrintf(("ConnectToBus(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #elif defined AJ_SERIAL_CONNECTION // don't bother with discovery, we are connected to a daemon. // however, take this opportunity to bring up the serial connection status = AJ_Serial_Up(); if (status != AJ_OK) { AJ_InfoPrintf(("ConnectToBus(): AJ_Serial_Up status=%s\n", AJ_StatusText(status))); } #else status = AJ_Discover(serviceName, &service, timeout, AJ_SELECTION_TIMEOUT); if (status != AJ_OK) { AJ_InfoPrintf(("ConnectToBus(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #endif /* * Now that we have discovered a routing node, we can connect to it. This is done with AJ_Net_Connect. */ status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { // or retry discovery to find another node that will accept our connection AJ_InfoPrintf(("ConnectToBus(): AJ_Net_Connect status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #ifdef AJ_SERIAL_CONNECTION // run the state machine for long enough to (hopefully) do the SLAP handshake do { AJ_StateMachine(); AJ_InitTimer(&now); } while (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE && AJ_GetTimeDifference(&now, &start) < timeout); if (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE) { AJ_InfoPrintf(("Failed to establish active SLAP connection in %u msec\n", timeout)); AJ_SerialShutdown(); return AJ_ERR_TIMEOUT; } #endif /* * We are connected to a routing node! We still need to authenticate with it * before it will route our messages. */ status = AJ_Authenticate(bus); ExitConnect: if (status != AJ_OK) { AJ_InfoPrintf(("ConnectToBus(): status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); } return status; } static const char ssid[] = "AllJoyn"; static const char passphrase[] = "ajajajaj"; static const AJ_WiFiSecurityType secType = AJ_WIFI_SECURITY_WPA2; int AJ_Main(void) { #ifdef AJ_CONFIGURE_WIFI_UPON_START # error This sample cannot be built with AJ_CONFIGURE_WIFI_UPON_START defined #endif // dhcp_attempts applies to systems in need of network connections #if !(defined(ARDUINO) || defined(__linux) || defined(_WIN32) || defined(__MACH__)) int32_t dhcp_attempts = 5; #endif AJ_Status status = AJ_OK; AJ_BusAttachment bus; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); // Windows, Linux and Arduino are already connected to the network when we get to this point. #if !(defined(ARDUINO) || defined(__linux) || defined(_WIN32) || defined(__MACH__)) #define AJ_DHCP_TIMEOUT 10000 // Step 1: connect to a WIFI network. // This will also attempt to acquire an IP from DHCP status = AJ_ConnectWiFi(ssid, secType, AJ_WIFI_CIPHER_CCMP, passphrase); // if DHCP timed out, try it again for up to five attempts while (status == AJ_ERR_TIMEOUT && --dhcp_attempts) { uint32_t ip, mask, gw; status = AJ_AcquireIPAddress(&ip, &mask, &gw, AJ_DHCP_TIMEOUT); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_Net_Up(): AJ_AcquireIPAddress Failed\n")); } } if (status != AJ_OK) { printf("Unable to connect to wifi and acquire IP\n"); return status; } #endif //Now we need to find a daemon, connect to it and authenticate // see the ConnectToBus for an explanation. status = ConnectToBus(&bus); AJ_Sleep(10000); AJ_Disconnect(&bus); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/network/SConscript000066400000000000000000000002001271074662300177700ustar00rootroot00000000000000Import('sample_env') progs = [ sample_env.Program('net_bus', ['NetworkAndBus.c']) ] sample_env.Install("#dist/bin", progs) ajtcl-16.04/samples/secure/000077500000000000000000000000001271074662300155635ustar00rootroot00000000000000ajtcl-16.04/samples/secure/.gitignore000066400000000000000000000000331271074662300175470ustar00rootroot00000000000000SecureClient SecureService ajtcl-16.04/samples/secure/SConscript000066400000000000000000000005201271074662300175720ustar00rootroot00000000000000Import('sample_env') progs = [ sample_env.Program('SecureClient', ['SecureClient.c']), sample_env.Program('SecureService', ['SecureService.c']), sample_env.Program('SecureClientECDHE', ['SecureClientECDHE.c']), sample_env.Program('SecureServiceECDHE', ['SecureServiceECDHE.c']) ] sample_env.Install("#dist/bin", progs) ajtcl-16.04/samples/secure/SecureClient.c000066400000000000000000000224511271074662300203200ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SECURE_CLIENT #include #include #include #include #include #include uint8_t dbgSECURE_CLIENT = 0; static const char ServiceName[] = "org.alljoyn.bus.samples.secure"; static const char InterfaceName[] = "org.alljoyn.bus.samples.secure.SecureInterface"; static const char ServicePath[] = "/SecureService"; static const uint16_t ServicePort = 42; /* * Buffer to hold the full service name. This buffer must be big enough to hold * a possible 255 characters plus a null terminator (256 bytes) */ static char fullServiceName[AJ_MAX_SERVICE_NAME_SIZE]; static const char* const secureInterface[] = { "$org.alljoyn.bus.samples.secure.SecureInterface", "?Ping inStrs", NULL }; static const AJ_InterfaceDescription secureInterfaces[] = { secureInterface, NULL }; /** * Objects implemented by the application */ static const AJ_Object ProxyObjects[] = { { ServicePath, secureInterfaces }, { NULL } }; #define PRX_PING AJ_PRX_MESSAGE_ID(0, 0, 0) /* * Let the application do some work */ static void AppDoWork() { } #ifndef AJ_NO_CONSOLE /* If there is a console to read/write from/to. */ /* * get a line of input from the file pointer (most likely stdin). * This will capture the the num-1 characters or till a newline character is * entered. * * @param[out] str a pointer to a character array that will hold the user input * @param[in] num the size of the character array 'str' * @param[in] fp the file pointer the sting will be read from. (most likely stdin) * * @return returns the length of the string received from the file. */ uint32_t get_line(char*str, int num, FILE*fp) { uint32_t stringLength = 0; char*p = fgets(str, num, fp); // fgets will capture the '\n' character if the string entered is shorter than // num. Remove the '\n' from the end of the line and replace it with nul '\0'. if (p != NULL) { stringLength = (uint32_t)strlen(str) - 1; if (str[stringLength] == '\n') { str[stringLength] = '\0'; } } return stringLength; } #endif /** * Callback function prototype for requesting a password or pincode from an application. * * @param buffer The buffer to receive the password. * @param bufLen The size of the buffer * * @return Returns the length of the password. If the length is zero this will be * treated as a rejected password request. */ static uint32_t PasswordCallback(uint8_t* buffer, uint32_t bufLen) { char inputBuffer[16]; const uint32_t bufSize = sizeof(inputBuffer) / sizeof(inputBuffer[0]); uint32_t maxCopyLength; #ifdef AJ_NO_CONSOLE /* If there is no console to read/write from/to. */ const char password[] = "107734"; /* Upside down this can be read as 'hELLO!'. */ maxCopyLength = sizeof(password) - 1; if (maxCopyLength > bufSize) { maxCopyLength = bufSize; } memcpy(inputBuffer, password, maxCopyLength); #else /* Take input from stdin and send it. */ AJ_AlwaysPrintf(("Please enter one time password : ")); /* Use 'bufSize - 1' to allow for '\0' termination. */ maxCopyLength = get_line(inputBuffer, bufSize - 1, stdin); #endif if (maxCopyLength > bufLen) { maxCopyLength = bufLen; } /* Always terminated with a '\0' for following AJ_Printf(). */ inputBuffer[maxCopyLength] = '\0'; memcpy(buffer, inputBuffer, maxCopyLength); AJ_AlwaysPrintf(("Responding with password of '%s' length %u.\n", inputBuffer, maxCopyLength)); return maxCopyLength; } #define CONNECT_TIMEOUT (1000 * 200) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (100 * 10) static char pingString[] = "Client AllJoyn Lite says Hello AllJoyn!"; AJ_Status SendPing(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; AJ_AlwaysPrintf(("Sending ping request '%s'.\n", pingString)); status = AJ_MarshalMethodCall(bus, &msg, PRX_PING, fullServiceName, sessionId, AJ_FLAG_ENCRYPTED, METHOD_TIMEOUT); if (AJ_OK == status) { status = AJ_MarshalArgs(&msg, "s", pingString); } else { AJ_InfoPrintf(("In SendPing() AJ_MarshalMethodCall() status = %d.\n", status)); } if (AJ_OK == status) { status = AJ_DeliverMsg(&msg); } else { AJ_InfoPrintf(("In SendPing() AJ_MarshalArgs() status = %d.\n", status)); } if (AJ_OK != status) { AJ_InfoPrintf(("In SendPing() AJ_DeliverMsg() status = %d.\n", status)); } return status; } void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } static uint32_t authenticate = TRUE; int AJ_Main(void) { int done = FALSE; AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; AJ_Status authStatus = AJ_ERR_NULL; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(ProxyObjects); AJ_RegisterObjects(NULL, ProxyObjects); while (!done) { AJ_Message msg; if (!connected) { status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServiceName, ServicePort, &sessionId, NULL, fullServiceName); if (status == AJ_OK) { AJ_InfoPrintf(("StartClient returned %d, sessionId=%u\n", status, sessionId)); connected = TRUE; if (authenticate) { AJ_BusSetPasswordCallback(&bus, PasswordCallback); authStatus = AJ_BusAuthenticatePeer(&bus, fullServiceName, AuthCallback, &authStatus); } else { authStatus = AJ_OK; } } else { AJ_InfoPrintf(("StartClient returned %d\n", status)); break; } } if (authStatus != AJ_ERR_NULL) { if (authStatus != AJ_OK) { AJ_Disconnect(&bus); break; } authStatus = AJ_ERR_NULL; SendPing(&bus, sessionId); } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { AppDoWork(); continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_REPLY_ID(PRX_PING): { AJ_Arg arg; if (AJ_OK == AJ_UnmarshalArg(&msg, &arg)) { AJ_AlwaysPrintf(("%s.Ping (path=%s) returned \"%s\".\n", InterfaceName, ServicePath, arg.val.v_string)); if (strcmp(arg.val.v_string, pingString) == 0) { AJ_InfoPrintf(("Ping was successful.\n")); } else { AJ_InfoPrintf(("Ping returned different string.\n")); } } else { AJ_ErrPrintf(("Bad ping response.\n")); } done = TRUE; } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * Force a disconnect */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); exit(0); } } AJ_AlwaysPrintf(("SecureClient EXIT %d.\n", status)); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/secure/SecureClientECDHE.c000066400000000000000000000442251271074662300210540ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SECURE_CLIENT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * If MAIN_ALLOW_ARGS is defined, the user must specify the auth suite to use. * If it's not defined, all auth suites are enabled, and AllJoyn negotiates * one to use, and in the event of failure, tries multiple auth suites until * one succeeds. */ #define MAIN_ALLOW_ARGS uint8_t dbgSECURE_CLIENT = 0; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; static const char ServiceName[] = "org.alljoyn.bus.samples.secure"; static const char InterfaceName[] = "org.alljoyn.bus.samples.secure.SecureInterface"; static const char ServicePath[] = "/SecureService"; static const uint16_t ServicePort = 42; /* * Buffer to hold the full service name. This buffer must be big enough to hold * a possible 255 characters plus a null terminator (256 bytes) */ static char fullServiceName[AJ_MAX_SERVICE_NAME_SIZE]; static const char* const secureInterface[] = { "$org.alljoyn.bus.samples.secure.SecureInterface", "?Ping inStrs", NULL }; static const AJ_InterfaceDescription secureInterfaces[] = { secureInterface, NULL }; /** * Objects implemented by the application */ static const AJ_Object ProxyObjects[] = { { ServicePath, secureInterfaces }, { NULL } }; static AJ_PermissionMember members[] = { { "*", AJ_MEMBER_TYPE_ANY, AJ_ACTION_MODIFY | AJ_ACTION_OBSERVE, NULL } }; static AJ_PermissionRule rules[] = { { ServicePath, InterfaceName, members, NULL } }; #define PRX_PING AJ_PRX_MESSAGE_ID(0, 0, 0) /* * Let the application do some work */ static void AppDoWork() { } /* * get a line of input from the file pointer (most likely stdin). * This will capture the the num-1 characters or till a newline character is * entered. * * @param[out] str a pointer to a character array that will hold the user input * @param[in] num the size of the character array 'str' * @param[in] fp the file pointer the sting will be read from. (most likely stdin) * * @return returns the length of the string received from the file. */ uint32_t get_line(char* str, int num, FILE* fp) { uint32_t stringLength = 0; char* p = fgets(str, num, fp); // fgets will capture the '\n' character if the string entered is shorter than // num. Remove the '\n' from the end of the line and replace it with nul '\0'. if (p != NULL) { stringLength = (uint32_t)strlen(str) - 1; if (str[stringLength] == '\n') { str[stringLength] = '\0'; } } return stringLength; } #define CONNECT_TIMEOUT (1000 * 200) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (100 * 10) static char pingString[] = "Client AllJoyn Lite says Hello AllJoyn!"; AJ_Status SendPing(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; AJ_Printf("Sending ping request '%s'.\n", pingString); status = AJ_MarshalMethodCall(bus, &msg, PRX_PING, fullServiceName, sessionId, AJ_FLAG_ENCRYPTED, METHOD_TIMEOUT); if (AJ_OK == status) { status = AJ_MarshalArgs(&msg, "s", pingString); } else { AJ_InfoPrintf(("In SendPing() AJ_MarshalMethodCall() status = %d.\n", status)); } if (AJ_OK == status) { status = AJ_DeliverMsg(&msg); } else { AJ_InfoPrintf(("In SendPing() AJ_MarshalArgs() status = %d.\n", status)); } if (AJ_OK != status) { AJ_InfoPrintf(("In SendPing() AJ_DeliverMsg() status = %d.\n", status)); } return status; } // Copied from alljoyn/alljoyn_core/unit_test/AuthListenerECDHETest.cc with // newlines removed static const char pem_prv[] = { "-----BEGIN EC PRIVATE KEY-----" "MDECAQEEIMtCXTgmP+mWy/R3r+xhRVz28c7Mg/3/rFozWEngZIEmoAoGCCqGSM49AwEH" "-----END EC PRIVATE KEY-----" }; static const char pem_x509[] = { "-----BEGIN CERTIFICATE-----" "MIIBRDCB66ADAgECAgIwMjAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANjbjEwHhcN" "MTYwMzE3MjIxNjI4WhcNMTYwMzE4MDEwMzA4WjAOMQwwCgYDVQQDDANjbjIwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAASLzhwhsTFYITWYFWjxzsCjeWmmPpBYyphL" "B9JjxhGf8hO8jIHyYzVGbwFLo8yxdLi/1aAfygdZAQg4yrgktY7LozkwNzAJBgNV" "HRMEAjAAMBUGA1UdJQQOMAwGCisGAQQBgt58AQEwEwYDVR0jBAwwCqAIT3aVgSWQ" "cxQwCgYIKoZIzj0EAwIDSAAwRQIgQbIJ8XFFQegKmGlVrrAEDfOajRo6AlR/eDHa" "s/9gPH4CIQDxTdT7JSsskcSlfv3iPj4QEQMAyBCoClDTxtB76y3O8g==" "-----END CERTIFICATE-----" "-----BEGIN CERTIFICATE-----" "MIIBMjCB2aADAgECAgIwMTAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANjbjEwHhcN" "MTYwMzE3MjIxNjI4WhcNMTYwMzE4MDEwMzA4WjAOMQwwCgYDVQQDDANjbjEwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAARN2kDX85eo+La+shs813nyoF4s6zEBDBop" "37Od5JjxyjznaqjZAja35ArHFiyIiW6MHIsOe/Lh1eH+DobTdmjioycwJTAMBgNV" "HRMEBTADAQH/MBUGA1UdJQQOMAwGCisGAQQBgt58AQEwCgYIKoZIzj0EAwIDSAAw" "RQIgC+/FJEGmD72oTE8mr+nb+LCS9rbvdzHiGgeFw1fiKYYCIQDEwvNzqtcgoaFK" "AWcekk3QYgDKwrwJVmwbxuHT8etlxw==" "-----END CERTIFICATE-----" }; // Security 1.0 certificates without EKUs static const char pem_prv_noekus[] = { "-----BEGIN EC PRIVATE KEY-----" "MDECAQEEINAmL3v0wNo5EfMqzB/GiVturVDGGefg9bPY/rZ5cM1GoAoGCCqGSM49" "AwEH" "-----END EC PRIVATE KEY-----" }; static const char pem_x509_noekus[] = { "-----BEGIN CERTIFICATE-----" "MIIBajCCARCgAwIBAgIUYB6roPAvFLNLCDrHmQB+pD8LjbkwCgYIKoZIzj0EAwIw" "NTEzMDEGA1UEAwwqQWxsSm95biBFQ0RIRSBTYW1wbGUgQ2VydGlmaWNhdGUgQXV0" "aG9yaXR5MB4XDTE1MDUwNzIyMTY0NVoXDTIwMDUwNTIyMTY0NVowJjEkMCIGA1UE" "AwwbQWxsSm95biBFQ0RIRSBTYW1wbGUgQ2xpZW50MFkwEwYHKoZIzj0CAQYIKoZI" "zj0DAQcDQgAEzE6Fox8LU/Cbi9+KI+6wQsFA8RhOv44JxTa1PY13xQGgzL0h+KKq" "DrHleThtYqL8rFXFtuDMtYo1T/lOMIcz86MNMAswCQYDVR0TBAIwADAKBggqhkjO" "PQQDAgNIADBFAiEA3KmONKSK9ebMUnBxDTYZMilW1QNqyR04KB3TUuI1MvcCIDTZ" "MzxxFqMIDDaGUzqd4g1t/W9h+G+alwj3KemLkD3T" "-----END CERTIFICATE-----" "" "-----BEGIN CERTIFICATE-----" "MIIBezCCASKgAwIBAgIUDrFhHE80+zbEUOCNTxw219Nd1qwwCgYIKoZIzj0EAwIw" "NTEzMDEGA1UEAwwqQWxsSm95biBFQ0RIRSBTYW1wbGUgQ2VydGlmaWNhdGUgQXV0" "aG9yaXR5MB4XDTE1MDUwNzIyMTYzNloXDTI1MDUwNDIyMTYzNlowNTEzMDEGA1UE" "AwwqQWxsSm95biBFQ0RIRSBTYW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MFkw" "EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6AsCTTviTBWX0Jw2e8Cs8DhwxfRd37Yp" "IH5ALzBqwUN2sfG1odcthe6GKdE/9oVfy12SXOL3X2bi3yg1XFoWnaMQMA4wDAYD" "VR0TBAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiASuD0OrpDM8ziC5GzMbZWKNE/X" "eboedc0p6YsAZmry2AIgR23cKM4cKkc2bgUDbETNbDcOcwm+EWaK9E4CkOO/tBc=" "-----END CERTIFICATE-----" }; static const char psk_hint[] = ""; static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; static const char ecspeke_password[] = "1234"; static X509CertificateChain* chain = NULL; static uint8_t noekus = FALSE; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential*cred) { AJ_Status status = AJ_ERR_INVALID; X509CertificateChain* node; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_SPEKE: switch (command) { case AJ_CRED_PASSWORD: cred->data = (uint8_t*)ecspeke_password; cred->len = strlen(ecspeke_password); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_ECDSA: switch (command) { case AJ_CRED_PRV_KEY: AJ_ASSERT(sizeof (AJ_ECCPrivateKey) == cred->len); status = AJ_DecodePrivateKeyPEM((AJ_ECCPrivateKey*) cred->data, noekus ? pem_prv_noekus : pem_prv); cred->expiration = keyexpiration; break; case AJ_CRED_CERT_CHAIN: switch (cred->direction) { case AJ_CRED_REQUEST: // Free previous certificate chain AJ_X509FreeDecodedCertificateChain(chain); chain = AJ_X509DecodeCertificateChainPEM(noekus ? pem_x509_noekus : pem_x509); if (NULL == chain) { return AJ_ERR_INVALID; } cred->data = (uint8_t*) chain; cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_RESPONSE: node = (X509CertificateChain*) cred->data; status = AJ_X509VerifyChain(node, NULL, AJ_CERTIFICATE_IDN_X509); while (node) { AJ_DumpBytes("CERTIFICATE", node->certificate.der.data, node->certificate.der.size); node = node->next; } break; } break; } break; default: break; } return status; } void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } #ifdef MAIN_ALLOWS_ARGS int AJ_Main(int ac, char** av) #else int AJ_Main(void) #endif { int done = FALSE; AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; AJ_Status authStatus = AJ_ERR_NULL; uint16_t state; uint16_t capabilities; uint16_t info; uint32_t suites[16]; size_t numsuites = 0; uint8_t clearkeys = FALSE; #ifdef MAIN_ALLOWS_ARGS ac--; av++; /* * Enable authentication mechanism by command line */ while (ac) { if (0 == strncmp(*av, "-noekus", 7)) { noekus = TRUE; ac--; av++; } else if (0 == strncmp(*av, "-e", 2)) { if (0 == strncmp(*av, "-ek", 3)) { clearkeys = TRUE; } ac--; av++; if (!ac) { AJ_Printf("-e(k) requires an auth mechanism.\n"); return 1; } while (ac) { if (0 == strncmp(*av, "ECDHE_ECDSA", 11)) { suites[numsuites++] = AUTH_SUITE_ECDHE_ECDSA; } else if (0 == strncmp(*av, "ECDHE_PSK", 9)) { suites[numsuites++] = AUTH_SUITE_ECDHE_PSK; } else if (0 == strncmp(*av, "ECDHE_NULL", 10)) { suites[numsuites++] = AUTH_SUITE_ECDHE_NULL; } else if (0 == strncmp(*av, "ECDHE_SPEKE", 11)) { suites[numsuites++] = AUTH_SUITE_ECDHE_SPEKE; } ac--; av++; } } else { AJ_Printf("SecureClientECDHE [-noekus] [-e|-ek] \n" "-noekus\n" " For ECDHE_ECDSA, present a Security 1.0-style certificate chain without EKUs\n" " For all other auth suites, this option has no effect.\n" "-e \n" " Specify one or more encryption suites to use: ECDHE_ECDSA, ECDHE_PSK, or ECDHE_NULL\n" " Encryption suites should be listed in desired order of attempting, separated by spaces.\n" "-ek \n" " Same as -e, except that any existing authentication keys are cleared. This \n" " will ensure a new key exchange occurs.\n" "-e or -ek must be the last option on the command line.\n"); return AJ_ERR_NULL; } } #else /* * Allow all authentication mechanisms */ AJ_AlwaysPrintf(("Ignoring command line arguments: enabling all auth suites, not clearing the keystore and using EKUs in certificates.\n")); clearkeys = FALSE; noekus = FALSE; suites[numsuites++] = AUTH_SUITE_ECDHE_ECDSA; suites[numsuites++] = AUTH_SUITE_ECDHE_PSK; suites[numsuites++] = AUTH_SUITE_ECDHE_NULL; suites[numsuites++] = AUTH_SUITE_ECDHE_SPEKE; #endif /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(ProxyObjects); AJ_RegisterObjects(NULL, ProxyObjects); while (!done) { AJ_Message msg; if (!connected) { status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServiceName, ServicePort, &sessionId, NULL, fullServiceName); if (status == AJ_OK) { AJ_InfoPrintf(("StartClient returned %d, sessionId=%u\n", status, sessionId)); AJ_Printf("StartClient returned %d, sessionId=%u\n", status, sessionId); connected = TRUE; AJ_BusEnableSecurity(&bus, suites, numsuites); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); if (clearkeys) { status = AJ_ClearCredentials(AJ_CRED_TYPE_GENERIC); if (AJ_OK != status) { AJ_Printf("AJ_ClearCredentials returned %d\n", status); break; } } AJ_ManifestTemplateSet(rules); AJ_SecurityGetClaimConfig(&state, &capabilities, &info); /* Set app claimable if not already claimed */ if (APP_STATE_CLAIMED != state) { AJ_SecuritySetClaimConfig(&bus, APP_STATE_CLAIMABLE, CLAIM_CAPABILITY_ECDHE_PSK, 0); } status = AJ_BusAuthenticatePeer(&bus, fullServiceName, AuthCallback, &authStatus); if (status != AJ_OK) { AJ_Printf("AJ_BusAuthenticatePeer returned %d\n", status); break; } } else { AJ_InfoPrintf(("StartClient returned %d\n", status)); AJ_Printf("StartClient returned %d\n", status); break; } } if (authStatus != AJ_ERR_NULL) { if (authStatus != AJ_OK) { AJ_Disconnect(&bus); break; } authStatus = AJ_ERR_NULL; status = SendPing(&bus, sessionId); if (status != AJ_OK) { AJ_Printf("SendPing returned %d\n", status); continue; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { AppDoWork(); continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_REPLY_ID(PRX_PING): { AJ_Arg arg; if (AJ_OK == AJ_UnmarshalArg(&msg, &arg)) { AJ_Printf("%s.Ping (path=%s) returned \"%s\".\n", InterfaceName, ServicePath, arg.val.v_string); if (strcmp(arg.val.v_string, pingString) == 0) { AJ_InfoPrintf(("Ping was successful.\n")); } else { AJ_InfoPrintf(("Ping returned different string.\n")); } } else { AJ_ErrPrintf(("Bad ping response.\n")); } done = TRUE; } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * Force a disconnect */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_Printf("AllJoyn disconnect.\n"); AJ_Disconnect(&bus); break; } } AJ_Printf("SecureClient EXIT %d.\n", status); // Clean up certificate chain AJ_X509FreeDecodedCertificateChain(chain); return status; } #ifdef AJ_MAIN #ifdef MAIN_ALLOWS_ARGS int main(int ac, char** av) { return AJ_Main(ac, av); } #else int main(void) { return AJ_Main(); } #endif #endif ajtcl-16.04/samples/secure/SecureService.c000066400000000000000000000172621271074662300205060ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SECURE_SERVICE #include #include #include #include #include uint8_t dbgSECURE_SERVICE = 0; #define CONNECT_ATTEMPTS 10 static const char ServiceName[] = "org.alljoyn.bus.samples.secure"; static const char ServicePath[] = "/SecureService"; static const uint16_t ServicePort = 42; /** * The interface name followed by the method signatures. * * See also .\inc\aj_introspect.h */ static const char* const secureInterface[] = { "$org.alljoyn.bus.samples.secure.SecureInterface", "?Ping inStrs", /* Method at index 0. */ NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription secureInterfaces[] = { secureInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, secureInterfaces }, { NULL } }; /* * The value of the arguments are the indices of the * object path in AppObjects (above), interface in sampleInterfaces (above), and * member indices in the interface. * The 'ping' index is 0 because the first entry in sampleInterface is the interface name. * This makes the first index (index 0 of the methods) the second string in * secureInterfaces[]. * * See also .\inc\aj_introspect.h */ #define BASIC_SERVICE_PING AJ_APP_MESSAGE_ID(0, 0, 0) static AJ_Status AppHandlePing(AJ_Message* msg) { AJ_Status status; AJ_Message reply; AJ_Arg arg; status = AJ_UnmarshalArg(msg, &arg); if (AJ_OK == status) { if (arg.typeId == AJ_ARG_STRING) { AJ_AlwaysPrintf(("Received ping request '%s'.\n", arg.val.v_string)); } else { AJ_AlwaysPrintf(("Unexpected arg type '%d' in ping request.\n", arg.typeId)); } status = AJ_MarshalReplyMsg(msg, &reply); if (AJ_OK == status) { /* * Just return the arg we received */ status = AJ_MarshalArg(&reply, &arg); if (AJ_OK == status) { status = AJ_DeliverMsg(&reply); } } } return status; } static char pinStr[16]; static uint32_t pinLength = 0; static void PasswordGenerate() { #ifdef AJ_NO_CONSOLE /* If there is no console to read/write from/to. */ const char password[] = "107734"; /* Upside down this can be read as 'hELLO!'. */ const int maxPinSize = sizeof(pinStr) / sizeof(pinStr[0]) - 1; pinLength = sizeof(password) - 1; if (pinLength > maxPinSize) { pinLength = maxPinSize; } memcpy(pinStr, password, pinLength); pinStr[pinLength] = '\0'; #else int pin; /* seed the random number */ srand((unsigned int) time(NULL)); pin = 1000 * (rand() % 1000) + (rand() % 1000); sprintf(pinStr, "%06d", pin); AJ_AlwaysPrintf(("One Time Password : '%s'.\n", pinStr)); pinLength = (uint32_t)strlen(pinStr); #endif } static uint32_t PasswordCallback(uint8_t* buffer, uint32_t bufLen) { if (pinLength > bufLen) { pinLength = bufLen; } /* Always terminated with a '\0' for following AJ_Printf(). */ pinStr[pinLength] = '\0'; memcpy(buffer, pinStr, pinLength); AJ_AlwaysPrintf(("Need password of '%s' length %u.\n", pinStr, pinLength)); return pinLength; } static uint32_t FactoryResetCallback() { /* Delete any application-specific state here, and return * a failure if we cannot. In this sample, there is nothing * to delete, so we can just return success. */ return AJ_OK; } /* All times are expressed in milliseconds. */ #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define SLEEP_TIME (1000 * 2) int AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; /* One time initialization before calling any other AllJoyn APIs. */ AJ_Initialize(); /* This is for debug purposes and is optional. */ AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned %d, session_id=%u\n", status, sessionId)); connected = TRUE; PasswordGenerate(); AJ_BusSetPasswordCallback(&bus, PasswordCallback); AJ_BusSetFactoryResetCallback(&bus, FactoryResetCallback); } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } break; case BASIC_SERVICE_PING: status = AppHandlePing(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* Force a disconnect. */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); connected = FALSE; /* Sleep a little while before trying to reconnect. */ AJ_Sleep(SLEEP_TIME); } } return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/samples/secure/SecureServiceECDHE.c000066400000000000000000000274101271074662300212330ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SECURE_SERVICE #include #include #include #include #include #include #include #include #include #include #include #include #include #include uint8_t dbgSECURE_SERVICE = 1; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; #define CONNECT_ATTEMPTS 10 static const char ServiceName[] = "org.alljoyn.bus.samples.secure"; static const char InterfaceName[] = "org.alljoyn.bus.samples.secure.SecureInterface"; static const char ServicePath[] = "/SecureService"; static const uint16_t ServicePort = 42; /** * The interface name followed by the method signatures. * * See also .\inc\aj_introspect.h */ static const char* const secureInterface[] = { "$org.alljoyn.bus.samples.secure.SecureInterface", "?Ping inStrs", /* Method at index 0. */ NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription secureInterfaces[] = { secureInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, secureInterfaces }, { NULL } }; static AJ_PermissionMember members[] = { { "*", AJ_MEMBER_TYPE_ANY, AJ_ACTION_PROVIDE | AJ_ACTION_OBSERVE, NULL } }; static AJ_PermissionRule rules[] = { { ServicePath, InterfaceName, members, NULL } }; /* * The value of the arguments are the indices of the * object path in AppObjects (above), interface in sampleInterfaces (above), and * member indices in the interface. * The 'ping' index is 0 because the first entry in sampleInterface is the interface name. * This makes the first index (index 0 of the methods) the second string in * secureInterfaces[]. * * See also .\inc\aj_introspect.h */ #define BASIC_SERVICE_PING AJ_APP_MESSAGE_ID(0, 0, 0) static AJ_Status AppHandlePing(AJ_Message* msg) { AJ_Status status; AJ_Message reply; AJ_Arg arg; status = AJ_UnmarshalArg(msg, &arg); if (AJ_OK == status) { if (arg.typeId == AJ_ARG_STRING) { AJ_Printf("Received ping request '%s'.\n", arg.val.v_string); } else { AJ_Printf("Unexpected arg type '%d' in ping request.\n", arg.typeId); } status = AJ_MarshalReplyMsg(msg, &reply); if (AJ_OK == status) { /* * Just return the arg we received */ status = AJ_MarshalArg(&reply, &arg); if (AJ_OK == status) { status = AJ_DeliverMsg(&reply); } } } return status; } // Copied from alljoyn/alljoyn_core/unit_test/AuthListenerECDHETest.cc with // newlines removed static const char pem_prv[] = { "-----BEGIN EC PRIVATE KEY-----" "MDECAQEEICCRJMbxSiWUqj4Zs7jFQRXDJdBRPWX6fIVqE1BaXd08oAoGCCqGSM49" "AwEH" "-----END EC PRIVATE KEY-----" }; static const char pem_x509[] = { "-----BEGIN CERTIFICATE-----" "MIIBuDCCAV2gAwIBAgIHMTAxMDEwMTAKBggqhkjOPQQDAjBCMRUwEwYDVQQLDAxv" "cmdhbml6YXRpb24xKTAnBgNVBAMMIDgxM2FkZDFmMWNiOTljZTk2ZmY5MTVmNTVk" "MzQ4MjA2MB4XDTE1MDcyMjIxMDYxNFoXDTE2MDcyMTIxMDYxNFowQjEVMBMGA1UE" "CwwMb3JnYW5pemF0aW9uMSkwJwYDVQQDDCAzOWIxZGNmMjBmZDJlNTNiZGYzMDU3" "NzMzMjBlY2RjMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGJ/9F4xHn3Klw7z" "6LREmHJgzu8yJ4i09b4EWX6a5MgUpQoGKJcjWgYGWb86bzbciMCFpmKzfZ42Hg+k" "BJs2ZWajPjA8MAwGA1UdEwQFMAMBAf8wFQYDVR0lBA4wDAYKKwYBBAGC3nwBATAV" "BgNVHSMEDjAMoAoECELxjRK/fVhaMAoGCCqGSM49BAMCA0kAMEYCIQDixoulcO7S" "df6Iz6lvt2CDy0sjt/bfuYVW3GeMLNK1LAIhALNklms9SP8ZmTkhCKdpC+/fuwn0" "+7RX8CMop11eWCih" "-----END CERTIFICATE-----" }; static const char psk_hint[] = ""; static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; static const char ecspeke_password[] = "1234"; static X509CertificateChain* chain = NULL; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential*cred) { AJ_Status status = AJ_ERR_INVALID; X509CertificateChain* node; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_SPEKE: switch (command) { case AJ_CRED_PASSWORD: cred->data = (uint8_t*)ecspeke_password; cred->len = strlen(ecspeke_password); cred->expiration = keyexpiration; status = AJ_OK; break; } break; /* * The ECDHE_PSK auth mechanism is deprecated as of 16.04 and ECDHE_SPEKE * should be used instead. */ case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_ECDSA: switch (command) { case AJ_CRED_PRV_KEY: AJ_ASSERT(sizeof (AJ_ECCPrivateKey) == cred->len); status = AJ_DecodePrivateKeyPEM((AJ_ECCPrivateKey*) cred->data, pem_prv); cred->expiration = keyexpiration; break; case AJ_CRED_CERT_CHAIN: switch (cred->direction) { case AJ_CRED_REQUEST: // Free previous certificate chain AJ_X509FreeDecodedCertificateChain(chain); chain = AJ_X509DecodeCertificateChainPEM(pem_x509); if (NULL == chain) { return AJ_ERR_INVALID; } cred->data = (uint8_t*) chain; cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_RESPONSE: node = (X509CertificateChain*) cred->data; status = AJ_X509VerifyChain(node, NULL, AJ_CERTIFICATE_IDN_X509); while (node) { AJ_DumpBytes("CERTIFICATE", node->certificate.der.data, node->certificate.der.size); node = node->next; } break; } break; } break; default: break; } return status; } static const uint32_t suites[4] = { AUTH_SUITE_ECDHE_ECDSA, AUTH_SUITE_ECDHE_SPEKE, AUTH_SUITE_ECDHE_PSK, AUTH_SUITE_ECDHE_NULL }; static const size_t numsuites = 4; /* All times are expressed in milliseconds. */ #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define SLEEP_TIME (1000 * 2) int AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; uint16_t state; uint16_t capabilities; uint16_t info; /* One time initialization before calling any other AllJoyn APIs. */ AJ_Initialize(); /* This is for debug purposes and is optional. */ AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned %d, session_id=%u\n", status, sessionId)); connected = TRUE; AJ_BusEnableSecurity(&bus, suites, numsuites); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); AJ_ManifestTemplateSet(rules); AJ_SecurityGetClaimConfig(&state, &capabilities, &info); /* Set app claimable if not already claimed */ if (APP_STATE_CLAIMED != state) { AJ_SecuritySetClaimConfig(&bus, APP_STATE_CLAIMABLE, CLAIM_CAPABILITY_ECDHE_PSK, 0); } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); if (port == ServicePort) { status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } else { status = AJ_ResetArgs(&msg); if (AJ_OK != status) { break; } status = AJ_BusHandleBusMessage(&msg); } } break; case BASIC_SERVICE_PING: status = AppHandlePing(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* Force a disconnect. */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE)) { AJ_Printf("AllJoyn disconnect.\n"); AJ_Disconnect(&bus); connected = FALSE; /* Sleep a little while before trying to reconnect. */ AJ_Sleep(SLEEP_TIME); } } AJ_Printf("Secure service exiting with status 0x%04x.\n", status); // Clean up certificate chain AJ_X509FreeDecodedCertificateChain(chain); return status; } #ifdef AJ_MAIN int main(void) { return AJ_Main(); } #endif ajtcl-16.04/services/000077500000000000000000000000001271074662300144545ustar00rootroot00000000000000ajtcl-16.04/services/common/000077500000000000000000000000001271074662300157445ustar00rootroot00000000000000ajtcl-16.04/services/common/inc/000077500000000000000000000000001271074662300165155ustar00rootroot00000000000000ajtcl-16.04/services/common/inc/PropertyStore.h000066400000000000000000000142531271074662300215340ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef _PROPERTY_STORE_H_ #define _PROPERTY_STORE_H_ #include /** @defgroup PropertyStore property store * * @{ */ /** * Field indices */ #define AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX ((int8_t)(-1)) /**< error field index */ /** * Enum that is used for the Field indices of mandatory and optional fields */ typedef enum _AJSVC_PropertyStoreFieldIndices { //Start of keys AJSVC_PROPERTY_STORE_DEVICE_ID = 0, AJSVC_PROPERTY_STORE_APP_ID, AJSVC_PROPERTY_STORE_DEVICE_NAME, #ifndef CONFIG_SERVICE AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS, //End of runtime keys AJSVC_PROPERTY_STORE_DEFAULT_LANGUAGE = AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS, AJSVC_PROPERTY_STORE_APP_NAME, #else AJSVC_PROPERTY_STORE_DEFAULT_LANGUAGE, AJSVC_PROPERTY_STORE_PASSCODE, AJSVC_PROPERTY_STORE_REALM_NAME, #if defined(CUSTOM_CONFIG_USER_VALUES_INDICES) CUSTOM_CONFIG_USER_VALUES_INDICES #endif AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS, //End of runtime keys AJSVC_PROPERTY_STORE_APP_NAME = AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS, #endif AJSVC_PROPERTY_STORE_DESCRIPTION, AJSVC_PROPERTY_STORE_MANUFACTURER, AJSVC_PROPERTY_STORE_MODEL_NUMBER, AJSVC_PROPERTY_STORE_DATE_OF_MANUFACTURE, AJSVC_PROPERTY_STORE_SOFTWARE_VERSION, AJSVC_PROPERTY_STORE_AJ_SOFTWARE_VERSION, #ifdef CONFIG_SERVICE AJSVC_PROPERTY_STORE_MAX_LENGTH, #endif AJSVC_PROPERTY_STORE_NUMBER_OF_MANDATORY_KEYS, //End of mandatory keys AJSVC_PROPERTY_STORE_HARDWARE_VERSION = AJSVC_PROPERTY_STORE_NUMBER_OF_MANDATORY_KEYS, AJSVC_PROPERTY_STORE_SUPPORT_URL, AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS, //End of About keys } AJSVC_PropertyStoreFieldIndices; /** * Get maximum value length for given key. * @param fieldIndex * @return aj_status */ uint8_t AJSVC_PropertyStore_GetMaxValueLength(int8_t fieldIndex); /** * Language indices */ #define AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX ((int8_t)(-1)) /**< error language index */ #define AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX 0 /**< no language index */ /** * Bitfield that defines the category to filter the properties */ typedef struct _AJSVC_PropertyStoreCategoryFilter { uint8_t bit0About : 1; /**< about */ uint8_t bit1Config : 1; /**< config */ uint8_t bit2Announce : 1; /**< announce */ } AJSVC_PropertyStoreCategoryFilter; /** * Read all properties that match filter for given a language. * @param reply * @param filter * @param langIndex * @return aj_status */ AJ_Status AJSVC_PropertyStore_ReadAll(AJ_Message* reply, AJSVC_PropertyStoreCategoryFilter filter, int8_t langIndex); /** * Update given property with value for given language. * @param key * @param langIndex * @param value * @return aj_status */ AJ_Status AJSVC_PropertyStore_Update(const char* key, int8_t langIndex, const char* value); /** * Reset given property back to default for given language. * @param key * @param langIndex * @return aj_status */ AJ_Status AJSVC_PropertyStore_Reset(const char* key, int8_t langIndex); /** * Reset all properties back to defaults. * @return aj_status */ AJ_Status AJSVC_PropertyStore_ResetAll(); /** * get field name for given field index * @param fieldIndex * @return fieldName */ const char* AJSVC_PropertyStore_GetFieldName(int8_t fieldIndex); /** * Get field index for given field name. * @param fieldName * @return fieldIndex */ int8_t AJSVC_PropertyStore_GetFieldIndex(const char* fieldName); /** * Get value for given field index for given language index. * @param fieldIndex * @param langIndex * @return value */ const char* AJSVC_PropertyStore_GetValueForLang(int8_t fieldIndex, int8_t langIndex); /** * Get value for field index for default language. * @param fieldIndex * @return value */ const char* AJSVC_PropertyStore_GetValue(int8_t fieldIndex); /** * Set value for given field index for given language index. * @param fieldIndex * @param langIndex * @param value * @return success */ uint8_t AJSVC_PropertyStore_SetValueForLang(int8_t fieldIndex, int8_t langIndex, const char* value); /** * Set value for given field index for the default language. * @param fieldIndex * @param value * @return success */ uint8_t AJSVC_PropertyStore_SetValue(int8_t fieldIndex, const char* value); /** * Get default language index among all languages indexes. * @return langIndex */ int8_t AJSVC_PropertyStore_GetCurrentDefaultLanguageIndex(); /** * Get language name for given language index. * @param langIndex * @return languageName */ const char* AJSVC_PropertyStore_GetLanguageName(int8_t langIndex); /** * Get the language index for the given language name. * @param language * @return langIndex */ int8_t AJSVC_PropertyStore_GetLanguageIndex(const char* const language); /** * The number of supported languages * @return numberOfLanguages */ uint8_t AJSVC_PropertyStore_GetNumberOfLanguages(); /** * Load all persisted values. * @return aj_status */ AJ_Status AJSVC_PropertyStore_LoadAll(); /** * Save all persisted values. * @return aj_status */ AJ_Status AJSVC_PropertyStore_SaveAll(); /** @} */ //End of group 'PropertyStore' #endif /* _PROPERTY_STORE_H_ */ ajtcl-16.04/services/common/inc/PropertyStoreOEMProvisioning.h000066400000000000000000000072141271074662300245030ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef _PROPERTYSTOREOEMPROVISIONING_H_ #define _PROPERTYSTOREOEMPROVISIONING_H_ /** @defgroup PropertyStoreOEMProvisioning * * @{ */ #include #include #include #include /** * Device manufacture name */ extern const char* deviceManufactureName; /** * Device product name */ extern const char* deviceProductName; #define LANG_VALUE_LENGTH 7 #define KEY_VALUE_LENGTH 10 #define MACHINE_ID_LENGTH (UUID_LENGTH * 2) #define DEVICE_NAME_VALUE_LENGTH 32 #define PASSWORD_VALUE_LENGTH (AJ_ADHOC_LEN * 2) extern const char* const* propertyStoreDefaultLanguages; // A NULL termminated list of language strings /** * A convenience macro for the number of languages */ #define AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES (AJSVC_PropertyStore_GetNumberOfLanguages()) // The number of language strings calculated upon PropertyStore initialization /** * property structure */ typedef struct _PropertyStoreEntry { const char* keyName; // The property key name as shown in About and Config documentation // msb=public/private; bit number 3 - initialise once; bit number 2 - multi-language value; bit number 1 - announce; bit number 0 - read/write uint8_t mode0Write : 1; uint8_t mode1Announce : 1; uint8_t mode2MultiLng : 1; uint8_t mode3Init : 1; uint8_t mode4 : 1; uint8_t mode5 : 1; uint8_t mode6 : 1; uint8_t mode7Public : 1; } PropertyStoreEntry; /** * properties array variable with property definitions */ extern const PropertyStoreEntry propertyStoreProperties[AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS]; /** * properties array variable with default values */ extern const char** propertyStoreDefaultValues[AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS]; // Array of Array of size 1 or AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES constant buffers depending on whether the property is multilingual /** * properties container for runtime values */ typedef struct _PropertyStoreRuntimeEntry { char** value; // An array of size 1 or AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES mutable buffers depending on whether the property is multilingual uint8_t size; // The size of the value buffer(s) } PropertyStoreConfigEntry; /** * properties runtime array variable with runtime values of dynamically initialized and configurable properties */ extern PropertyStoreConfigEntry propertyStoreRuntimeValues[AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS]; #define AJ_PROPERTIES_NV_ID_END (AJ_PROPERTIES_NV_ID_BEGIN + (int)AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS * (int)AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES - 1) AJ_Status PropertyStore_Init(); /** @} */ #endif //_PROPERTYSTOREOEMPROVISIONING_H_ ajtcl-16.04/services/common/inc/ServicesCommon.h000066400000000000000000000136171271074662300216320ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef _SERVICES_COMMON_H_ #define _SERVICES_COMMON_H_ #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG extern uint8_t dbgAJSVC; #endif /** * Function prototype for return callback when a method call is completed. */ typedef void (*AJSVC_MethodCallCompleted)(AJ_Status status, void* context); /** * Service Status is an enum that signals whether a call was handled * or not handled within an AJSVC_MessageProcessor function */ typedef enum _AJSVC_ServiceStatus { AJSVC_SERVICE_STATUS_HANDLED, //!< SERVICE_STATUS_HANDLED AJSVC_SERVICE_STATUS_NOT_HANDLED, //!< SERVICE_STATUS_NOT_HANDLED } AJSVC_ServiceStatus; /** * Function used to process request messages. * @param busAttachment * @param msg * @param msgStatus * @return serviceStatus */ typedef AJSVC_ServiceStatus (*AJSVC_MessageProcessor)(AJ_BusAttachment* busAttachment, AJ_Message* msg, AJ_Status* msgStatus); /** * UpdateNotAllowed Error Message for services */ #define AJSVC_ERROR_UPDATE_NOT_ALLOWED AJ_ErrUpdateNotAllowed /** * InvalidValue Error Message for services */ #define AJSVC_ERROR_INVALID_VALUE AJ_ErrInvalidValue /** * FeatureNotAvailable Error Message for services */ #define AJSVC_ERROR_FEATURE_NOT_AVAILABLE AJ_ErrFeatureNotAvailable /** * MazSizeExceeded Error Message for services */ #define AJSVC_ERROR_MAX_SIZE_EXCEEDED AJ_ErrMaxSizeExceeded /** * LanguageNotSupported Error Message for services */ #define AJSVC_ERROR_LANGUAGE_NOT_SUPPORTED AJ_ErrLanguageNotSuppored /** * returns the language index for the given language name possibly creating an error reply message if erred * @param msg * @param reply * @param language * @param langIndex * @return success */ uint8_t AJSVC_IsLanguageSupported(AJ_Message* msg, AJ_Message* reply, const char* language, int8_t* langIndex); /** * Signature of the AppId field */ #define APP_ID_SIGNATURE "ay" /** * Length of UUID that is used for the AppId field */ #define UUID_LENGTH 16 /** * Marshals the appId Hex string as a variant into the provided message. * @param msg the message to marshal the appId into * @param appId the application id to marshal * @return status */ AJ_Status AJSVC_MarshalAppIdAsVariant(AJ_Message* msg, const char* appId); /** * Marshals the appId Hex string into the provided message. * @param msg the message to marshal the appId into * @param appId the application id to marshal * @return status */ AJ_Status AJSVC_MarshalAppId(AJ_Message* msg, const char* appId); /** * Unmarshals the appId from a variant in the provided message. * @param msg the message to unmarshal the appId from * @param buf the buffer where the application id is unmarshalled into * @param bufLen the size of the provided buffer. Should be UUID_LENGTH * 2 + 1. * @return status */ AJ_Status AJSVC_UnmarshalAppIdFromVariant(AJ_Message* msg, char* buf, size_t bufLen); /** * Unmarshals the appId from the provided message. * @param msg the message to unmarshal the appId from * @param buf the buffer where the application id is unmarshalled into * @param bufLen the size of the provided buffer. Should be UUID_LENGTH * 2 + 1. * @return status */ AJ_Status AJSVC_UnmarshalAppId(AJ_Message* msg, char* buf, size_t bufLen); // The following is the static registration of all services' bus objects /* * For each service: * 1) Define pre objects - the amount of objects registered before the service * 2) If service is included: * i) include service header file(s) * If service is NOT included: * i) define the default number of appobjects and number of objects * ii) define the default announce objects */ /* * ObjectsList definitions for ALL the services */ /* * ObjectsList index for Config Service objects */ #define AJCFG_OBJECT_LIST_INDEX 3 /* * ObjectsList index for Onboarding Service objects */ #define AJOBS_OBJECT_LIST_INDEX 4 /* * ObjectsList index for Notification Service objects */ #define AJNS_OBJECT_LIST_INDEX 5 /* * ObjectsList index for ControlPanel Service objects */ #define AJCPS_OBJECT_LIST_INDEX 6 /* * ObjectsList index for Time Service objects */ #define AJTS_OBJECT_LIST_INDEX 7 /* * ObjectsList index for Application objects */ #define AJAPP_OBJECTS_LIST_INDEX 8 #if AJAPP_OBJECTS_LIST_INDEX >= AJ_MAX_OBJECT_LISTS #error AJ_MAX_OBJECT_LISTS in aj_config.h too small #endif /** * The NVRAM starting id for the PropertyStore */ #define AJ_PROPERTIES_NV_ID_BEGIN (AJ_NVRAM_ID_SERVICES_BEGIN) /** * The NVRAM maximum id for the PropertyStore */ #define AJ_PROPERTIES_NV_ID_MAX (AJ_PROPERTIES_NV_ID_BEGIN + 999) /** * The NVRAM starting id for the Onboarding Service */ #define AJ_OBS_NV_ID_BEGIN (AJ_PROPERTIES_NV_ID_MAX + 1) #endif /* _SERVICES_COMMON_H_ */ ajtcl-16.04/services/common/inc/ServicesHandlers.h000066400000000000000000000063121271074662300221340ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef _SERVICES_HANDLERS_H_ #define _SERVICES_HANDLERS_H_ #include #include /** * Establish connection to named Routing Node * @param busAttachment * @param routingNodeName * @param connectTimeout * @param connectPause * @param busLinkTimeout * @param isConnected - state of connection to Routing Node after connect is performed * @return ajStatus - status of last request to Routing Node */ AJ_Status AJSVC_RoutingNodeConnect(AJ_BusAttachment* busAttachment, const char* routingNodeName, uint32_t connectTimeout, uint32_t connectPause, uint32_t busLinkTimeout, uint8_t* isConnected); /** * Functions to call after the Routing Node is Connected * @param busAttachment * @return ajStatus - status of last request to Routing Node */ AJ_Status AJSVC_ConnectedHandler(AJ_BusAttachment* busAttachment); /** * Process an incoming message and dispatch handling to relevant services * @param busAttachment * @param msg * @param status * @return servicestatus - shows if the message was processed or not */ AJSVC_ServiceStatus AJSVC_MessageProcessorAndDispatcher(AJ_BusAttachment* busAttachment, AJ_Message* msg, AJ_Status* status); /** * Session request accept/reject function for service targetted session * @param port * @param sessionId * @param joiner */ uint8_t AJSVC_CheckSessionAccepted(uint16_t port, uint32_t sessionId, char* joiner); /** * Shutdown services. Should be called on bus disconnect * @param busAttachment * @return ajStatus - status of last request to Routing Node */ AJ_Status AJSVC_DisconnectHandler(AJ_BusAttachment* busAttachment); /** * Disconnect from Routing Node * @param busAttachment * @param disconnectWiFi * @param preDisconnectPause - a small pause before disconnect to allow for outgoing message to be dispatched * @param postDisconnectPause - a small pause after disconnect to allow for system to stablize * @param isConnected - state of connection to Rounting Node after disconnect is performed * @return ajStatus - status of last request to Routing Node */ AJ_Status AJSVC_RoutingNodeDisconnect(AJ_BusAttachment* busAttachment, uint8_t disconnectWiFi, uint32_t preDisconnectPause, uint32_t postDisconnectPause, uint8_t* isConnected); #endif /* _SERVICES_HANDLERS_H_ */ ajtcl-16.04/services/common/src/000077500000000000000000000000001271074662300165335ustar00rootroot00000000000000ajtcl-16.04/services/common/src/PropertyStore.c000066400000000000000000000615711271074662300215520ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h. * The corresponding flag dbgAJSVCAPP is defined in the containing sample app. */ #define AJ_MODULE AJSVCAPP #include #include #include #include #include #include #ifdef ONBOARDING_SERVICE #include #endif #include #include #include #include #ifndef NDEBUG extern AJ_EXPORT uint8_t dbgAJSVCAPP; #endif const PropertyStoreEntry propertyStoreProperties[AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS] = { // { "Key Name ", W, A, M, I .. . . ., P }, { AJ_DEVICE_ID_STR, 0, 1, 0, 1, 0, 0, 0, 1 }, { AJ_APP_ID_STR, 0, 1, 0, 1, 0, 0, 0, 1 }, #ifndef CONFIG_SERVICE { AJ_DEVICE_NAME_STR, 0, 1, 1, 1, 0, 0, 0, 1 }, // Add other runtime keys above this line { AJ_DEFAULT_LANGUAGE_STR, 0, 1, 0, 0, 0, 0, 0, 1 }, #else { AJ_DEVICE_NAME_STR, 1, 1, 1, 1, 0, 0, 0, 1 }, { AJ_DEFAULT_LANGUAGE_STR, 1, 1, 0, 0, 0, 0, 0, 1 }, { AJ_PASSCODE_STR, 1, 0, 0, 0, 0, 0, 0, 0 }, { AJ_REALM_NAME_STR, 1, 0, 0, 0, 0, 0, 0, 0 }, // Add other runtime keys above this line #endif { AJ_APP_NAME_STR, 0, 1, 0, 0, 0, 0, 0, 1 }, { AJ_DESCRIPTION_STR, 0, 0, 1, 0, 0, 0, 0, 1 }, { AJ_MANUFACTURER_STR, 0, 1, 1, 0, 0, 0, 0, 1 }, { AJ_MODEL_NUMBER_STR, 0, 1, 0, 0, 0, 0, 0, 1 }, { AJ_DATE_OF_MANUFACTURE_STR, 0, 0, 0, 0, 0, 0, 0, 1 }, { AJ_SOFTWARE_VERSION_STR, 0, 0, 0, 0, 0, 0, 0, 1 }, { AJ_AJSOFTWARE_VERSION_STR, 0, 0, 0, 0, 0, 0, 0, 1 }, #ifdef CONFIG_SERVICE { AJ_MAX_LENGTH_STR, 0, 1, 0, 0, 0, 0, 0, 1 }, #endif // Add other mandatory about keys above this line { AJ_HARDWARE_VERSION_STR, 0, 0, 0, 0, 0, 0, 0, 1 }, { AJ_SUPPORT_URL_STR, 0, 0, 1, 0, 0, 0, 0, 1 }, // Add other optional about keys above this line }; static const char* defaultLanguagesKeyName = { AJ_SUPPORTED_LANGUAGES_STR }; static uint8_t numberOfLanguages = 0; uint8_t AJSVC_PropertyStore_GetNumberOfLanguages() { return numberOfLanguages; } uint8_t AJSVC_PropertyStore_GetMaxValueLength(int8_t fieldIndex) { switch (fieldIndex) { case AJSVC_PROPERTY_STORE_DEVICE_NAME: return DEVICE_NAME_VALUE_LENGTH; case AJSVC_PROPERTY_STORE_DEFAULT_LANGUAGE: return LANG_VALUE_LENGTH; #ifdef CONFIG_SERVICE case AJSVC_PROPERTY_STORE_PASSCODE: return PASSWORD_VALUE_LENGTH; #endif default: return KEY_VALUE_LENGTH; } } const char* AJSVC_PropertyStore_GetFieldName(int8_t fieldIndex) { if (fieldIndex <= AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX || fieldIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS) { return "N/A"; } return propertyStoreProperties[fieldIndex].keyName; } int8_t AJSVC_PropertyStore_GetFieldIndex(const char* fieldName) { int8_t fieldIndex; for (fieldIndex = 0; fieldIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS; fieldIndex++) { if (!strcmp(propertyStoreProperties[fieldIndex].keyName, fieldName)) { return fieldIndex; } } return AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX; } static int8_t GetLanguageIndexForProperty(int8_t langIndex, int8_t fieldIndex) { if (propertyStoreProperties[fieldIndex].mode2MultiLng) { return langIndex; } return AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX; } const char* AJSVC_PropertyStore_GetValueForLang(int8_t fieldIndex, int8_t langIndex) { if (fieldIndex <= AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX || fieldIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS) { return NULL; } langIndex = GetLanguageIndexForProperty(langIndex, fieldIndex); if (langIndex <= AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX || langIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES) { return NULL; } if (fieldIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS && (propertyStoreProperties[fieldIndex].mode0Write || propertyStoreProperties[fieldIndex].mode3Init) && propertyStoreRuntimeValues[fieldIndex].value != NULL && (propertyStoreRuntimeValues[fieldIndex].value[langIndex]) != NULL && (propertyStoreRuntimeValues[fieldIndex].value[langIndex])[0] != '\0') { AJ_InfoPrintf(("Has key [%s] runtime Value [%s]\n", propertyStoreProperties[fieldIndex].keyName, propertyStoreRuntimeValues[fieldIndex].value[langIndex])); return propertyStoreRuntimeValues[fieldIndex].value[langIndex]; } else if (propertyStoreDefaultValues[fieldIndex] != NULL && (propertyStoreDefaultValues[fieldIndex])[langIndex] != NULL) { AJ_InfoPrintf(("Has key [%s] default Value [%s]\n", propertyStoreProperties[fieldIndex].keyName, (propertyStoreDefaultValues[fieldIndex])[langIndex])); return (propertyStoreDefaultValues[fieldIndex])[langIndex]; } return NULL; } const char* AJSVC_PropertyStore_GetValue(int8_t fieldIndex) { return AJSVC_PropertyStore_GetValueForLang(fieldIndex, AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX); } const char* AJSVC_PropertyStore_GetLanguageName(int8_t langIndex) { if (langIndex <= AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX || langIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES) { return "N/A"; } return propertyStoreDefaultLanguages[langIndex]; } int8_t AJSVC_PropertyStore_GetLanguageIndex(const char* const language) { int8_t langIndex; const char* search = language; if (search != NULL) { if (search[0] == '\0') { // Check for empty language, if yes then search for current default language index search = AJSVC_PropertyStore_GetValue(AJSVC_PROPERTY_STORE_DEFAULT_LANGUAGE); if (search == NULL) { return AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX; } } for (langIndex = 0; langIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES; langIndex++) { if (!strcmp(search, propertyStoreDefaultLanguages[langIndex])) { return langIndex; } } } return AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX; } uint8_t AJSVC_PropertyStore_SetValueForLang(int8_t fieldIndex, int8_t langIndex, const char* value) { size_t var_size; if (fieldIndex <= AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX || fieldIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS) { return FALSE; } langIndex = GetLanguageIndexForProperty(langIndex, fieldIndex); if (langIndex <= AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX || langIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES) { return FALSE; } AJ_InfoPrintf(("Set key [%s] defaultValue [%s]\n", propertyStoreProperties[fieldIndex].keyName, value)); var_size = propertyStoreRuntimeValues[fieldIndex].size; //Check that the field we are trying to write into is not actually the same value. //On Darwin this will fail per the strncpy function definition if (propertyStoreRuntimeValues[fieldIndex].value[langIndex] != value) { strncpy(propertyStoreRuntimeValues[fieldIndex].value[langIndex], value, var_size - 1); (propertyStoreRuntimeValues[fieldIndex].value[langIndex])[var_size - 1] = '\0'; } return TRUE; } uint8_t AJSVC_PropertyStore_SetValue(int8_t fieldIndex, const char* value) { return AJSVC_PropertyStore_SetValueForLang(fieldIndex, AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX, value); } int8_t AJSVC_PropertyStore_GetCurrentDefaultLanguageIndex() { const char* currentDefaultLanguage = AJSVC_PropertyStore_GetValue(AJSVC_PROPERTY_STORE_DEFAULT_LANGUAGE); int8_t currentDefaultLanguageIndex = AJSVC_PropertyStore_GetLanguageIndex(currentDefaultLanguage); if (currentDefaultLanguageIndex == AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX) { currentDefaultLanguageIndex = AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX; AJ_WarnPrintf(("Failed to find default language %s defaulting to %s", (currentDefaultLanguage != NULL ? currentDefaultLanguage : "NULL"), propertyStoreDefaultLanguages[AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX])); } return currentDefaultLanguageIndex; } #ifdef CONFIG_SERVICE static void ClearPropertiesInRAM() { int8_t fieldIndex; int8_t langIndex; char* buf; for (fieldIndex = 0; fieldIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS; fieldIndex++) { if (propertyStoreRuntimeValues[fieldIndex].value) { for (langIndex = 0; langIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES; langIndex++) { if (propertyStoreProperties[fieldIndex].mode2MultiLng || langIndex == AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX) { buf = propertyStoreRuntimeValues[fieldIndex].value[langIndex]; if (buf) { memset(buf, 0, propertyStoreRuntimeValues[fieldIndex].size); } } } } } } #endif static void InitMandatoryPropertiesInRAM() { char* machineIdValue = propertyStoreRuntimeValues[AJSVC_PROPERTY_STORE_APP_ID].value[AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX]; const char* currentAppIdValue = AJSVC_PropertyStore_GetValue(AJSVC_PROPERTY_STORE_APP_ID); const char* currentDeviceIdValue = AJSVC_PropertyStore_GetValue(AJSVC_PROPERTY_STORE_DEVICE_ID); const char* currentDeviceNameValue; int8_t langIndex; size_t serialIdLen = 0; size_t machineIdLen = 0; AJ_GUID theAJ_GUID; AJ_Status status; char deviceName[DEVICE_NAME_VALUE_LENGTH + 1] = { 0 }; if (currentAppIdValue == NULL || currentAppIdValue[0] == '\0') { status = AJ_GetLocalGUID(&theAJ_GUID); if (status == AJ_OK) { AJ_GUID_ToString(&theAJ_GUID, machineIdValue, propertyStoreRuntimeValues[AJSVC_PROPERTY_STORE_APP_ID].size); } } if (currentDeviceIdValue == NULL || currentDeviceIdValue[0] == '\0') { AJSVC_PropertyStore_SetValue(AJSVC_PROPERTY_STORE_DEVICE_ID, machineIdValue); } for (langIndex = 0; langIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES; langIndex++) { currentDeviceNameValue = AJSVC_PropertyStore_GetValueForLang(AJSVC_PROPERTY_STORE_DEVICE_NAME, langIndex); if (currentDeviceNameValue == NULL || currentDeviceNameValue[0] == '\0') { if (deviceName[0] == '\0') { #ifdef ONBOARDING_SERVICE serialIdLen = AJOBS_DEVICE_SERIAL_ID_LEN; #else serialIdLen = 7; #endif machineIdLen = strlen(machineIdValue); #ifdef _WIN32 _snprintf(deviceName, DEVICE_NAME_VALUE_LENGTH + 1, "%s %s %s", deviceManufactureName, deviceProductName, &machineIdValue[machineIdLen - min(serialIdLen, machineIdLen)]); #else snprintf(deviceName, DEVICE_NAME_VALUE_LENGTH + 1, "%s %s %s", deviceManufactureName, deviceProductName, &machineIdValue[machineIdLen - min(serialIdLen, machineIdLen)]); #endif } AJSVC_PropertyStore_SetValueForLang(AJSVC_PROPERTY_STORE_DEVICE_NAME, langIndex, deviceName); } } } /* * This function is registered with About and handles property store read requests */ static AJ_Status AboutPropGetter(AJ_Message* msg, const char* language) { AJ_Status status = AJ_ERR_INVALID; int8_t langIndex; AJSVC_PropertyStoreCategoryFilter filter; memset(&filter, 0, sizeof(AJSVC_PropertyStoreCategoryFilter)); if (msg->msgId == AJ_SIGNAL_ABOUT_ANNOUNCE) { filter.bit2Announce = TRUE; langIndex = AJSVC_PropertyStore_GetLanguageIndex(language); status = AJ_OK; } else if (msg->msgId == AJ_REPLY_ID(AJ_METHOD_ABOUT_GET_ABOUT_DATA)) { filter.bit0About = TRUE; langIndex = AJSVC_PropertyStore_GetLanguageIndex(language); status = (langIndex == AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX) ? AJ_ERR_UNKNOWN : AJ_OK; } if (status == AJ_OK) { status = AJSVC_PropertyStore_ReadAll(msg, filter, langIndex); } return status; } AJ_Status PropertyStore_Init() { AJ_Status status = AJ_OK; const char* const* supportedLanguage = propertyStoreDefaultLanguages; numberOfLanguages = 0; while (*(supportedLanguage++) != NULL) { numberOfLanguages++; } #ifdef CONFIG_SERVICE status = AJSVC_PropertyStore_LoadAll(); #endif InitMandatoryPropertiesInRAM(); /* * About needs to get values from the property store */ AJ_AboutRegisterPropStoreGetter(AboutPropGetter); return status; } #ifdef CONFIG_SERVICE static AJ_Status PropertyStore_ReadConfig(uint16_t index, void* ptr, uint16_t size) { AJ_Status status = AJ_OK; uint16_t sizeRead = 0; AJ_NV_DATASET* nvramHandle = AJ_NVRAM_Open(index, "r", 0); if (nvramHandle != NULL) { sizeRead = AJ_NVRAM_Read(ptr, size, nvramHandle); status = AJ_NVRAM_Close(nvramHandle); if (sizeRead != size) { status = AJ_ERR_NVRAM_READ; } } return status; } static AJ_Status PropertyStore_WriteConfig(uint16_t index, void* ptr, uint16_t size, char* mode) { AJ_Status status = AJ_OK; uint16_t sizeWritten = 0; AJ_NV_DATASET* nvramHandle = AJ_NVRAM_Open(index, mode, size); if (nvramHandle != NULL) { sizeWritten = AJ_NVRAM_Write(ptr, size, nvramHandle); status = AJ_NVRAM_Close(nvramHandle); if (sizeWritten != size) { status = AJ_ERR_NVRAM_WRITE; } } return status; } AJ_Status AJSVC_PropertyStore_LoadAll() { AJ_Status status = AJ_OK; int8_t langIndex; int8_t fieldIndex; void* buf = NULL; uint16_t size = 0; uint16_t entry; for (langIndex = 0; langIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES; langIndex++) { for (fieldIndex = 0; fieldIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS; fieldIndex++) { if (propertyStoreRuntimeValues[fieldIndex].value == NULL || !propertyStoreProperties[fieldIndex].mode0Write || (langIndex != AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX && !propertyStoreProperties[fieldIndex].mode2MultiLng)) { continue; } buf = propertyStoreRuntimeValues[fieldIndex].value[langIndex]; if (buf) { size = propertyStoreRuntimeValues[fieldIndex].size; entry = (int)fieldIndex + (int)langIndex * (int)AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS; status = PropertyStore_ReadConfig(AJ_PROPERTIES_NV_ID_BEGIN + entry, buf, size); AJ_InfoPrintf(("nvram read fieldIndex=%d [%s] langIndex=%d [%s] entry=%d val=%s size=%u status=%s\n", (int)fieldIndex, propertyStoreProperties[fieldIndex].keyName, (int)langIndex, propertyStoreDefaultLanguages[langIndex], (int)entry, propertyStoreRuntimeValues[fieldIndex].value[langIndex], (int)size, AJ_StatusText(status))); } } } return status; } AJ_Status AJSVC_PropertyStore_SaveAll() { AJ_Status status = AJ_OK; int8_t langIndex; int8_t fieldIndex; void* buf = NULL; uint16_t size = 0; uint16_t entry; for (langIndex = 0; langIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES; langIndex++) { for (fieldIndex = 0; fieldIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS; fieldIndex++) { if (propertyStoreRuntimeValues[fieldIndex].value == NULL || !propertyStoreProperties[fieldIndex].mode0Write || (langIndex != AJSVC_PROPERTY_STORE_NO_LANGUAGE_INDEX && !propertyStoreProperties[fieldIndex].mode2MultiLng)) { continue; } buf = propertyStoreRuntimeValues[fieldIndex].value[langIndex]; if (buf) { size = propertyStoreRuntimeValues[fieldIndex].size; entry = (int)fieldIndex + (int)langIndex * (int)AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS; status = PropertyStore_WriteConfig(AJ_PROPERTIES_NV_ID_BEGIN + entry, buf, size, "w"); AJ_InfoPrintf(("nvram write fieldIndex=%d [%s] langIndex=%d [%s] entry=%d val=%s size=%u status=%s\n", (int)fieldIndex, propertyStoreProperties[fieldIndex].keyName, (int)langIndex, propertyStoreDefaultLanguages[langIndex], (int)entry, propertyStoreRuntimeValues[fieldIndex].value[langIndex], (int)size, AJ_StatusText(status))); } } } AJ_AboutSetShouldAnnounce(); // Set flag for sending an updated Announcement return status; } static uint8_t UpdateFieldInRAM(int8_t fieldIndex, int8_t langIndex, const char* fieldValue) { uint8_t ret = FALSE; if (propertyStoreProperties[fieldIndex].mode0Write && propertyStoreProperties[fieldIndex].mode7Public) { ret = AJSVC_PropertyStore_SetValueForLang(fieldIndex, langIndex, fieldValue); } else { AJ_ErrPrintf(("UpdateFieldInRAM ERROR - field %s has read only attribute or is private\n", propertyStoreProperties[fieldIndex].keyName)); } return ret; } static uint8_t DeleteFieldFromRAM(AJSVC_PropertyStoreFieldIndices fieldIndex, int8_t langIndex) { return UpdateFieldInRAM(fieldIndex, langIndex, ""); } #endif AJ_Status AJSVC_PropertyStore_ReadAll(AJ_Message* msg, AJSVC_PropertyStoreCategoryFilter filter, int8_t langIndex) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_Arg array2; AJ_Arg dict; const char* value; uint8_t index; const char* ajVersion; int8_t fieldIndex; AJ_InfoPrintf(("PropertyStore_ReadAll()\n")); status = AJ_MarshalContainer(msg, &array, AJ_ARG_ARRAY); if (status != AJ_OK) { return status; } for (fieldIndex = 0; fieldIndex < AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS; fieldIndex++) { #ifdef CONFIG_SERVICE if (propertyStoreProperties[fieldIndex].mode7Public && (filter.bit0About || (filter.bit1Config && propertyStoreProperties[fieldIndex].mode0Write) || (filter.bit2Announce && propertyStoreProperties[fieldIndex].mode1Announce))) { #else if (propertyStoreProperties[fieldIndex].mode7Public && (filter.bit0About || (filter.bit2Announce && propertyStoreProperties[fieldIndex].mode1Announce))) { #endif value = AJSVC_PropertyStore_GetValueForLang(fieldIndex, langIndex); if (value == NULL && (int8_t)fieldIndex >= (int8_t)AJSVC_PROPERTY_STORE_NUMBER_OF_MANDATORY_KEYS) { // Non existing values are skipped! AJ_WarnPrintf(("PropertyStore_ReadAll - Failed to get value for field=(name=%s, index=%d) and language=(name=%s, index=%d), skipping.\n", AJSVC_PropertyStore_GetFieldName(fieldIndex), (int)fieldIndex, AJSVC_PropertyStore_GetLanguageName(langIndex), (int)langIndex)); } else { if (fieldIndex == AJSVC_PROPERTY_STORE_APP_ID) { if (value == NULL) { AJ_ErrPrintf(("PropertyStore_ReadAll - Failed to get value for mandatory field=(name=%s, index=%d) and language=(name=%s, index=%d), aborting.\n", AJSVC_PropertyStore_GetFieldName(fieldIndex), (int)fieldIndex, AJSVC_PropertyStore_GetLanguageName(langIndex), (int)langIndex)); return AJ_ERR_NULL; } status = AJ_MarshalContainer(msg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { return status; } status = AJ_MarshalArgs(msg, "s", propertyStoreProperties[fieldIndex].keyName); if (status != AJ_OK) { return status; } status = AJSVC_MarshalAppIdAsVariant(msg, value); if (status != AJ_OK) { return status; } status = AJ_MarshalCloseContainer(msg, &dict); if (status != AJ_OK) { return status; } #ifdef CONFIG_SERVICE } else if (fieldIndex == AJSVC_PROPERTY_STORE_MAX_LENGTH) { status = AJ_MarshalArgs(msg, "{sv}", propertyStoreProperties[fieldIndex].keyName, "q", DEVICE_NAME_VALUE_LENGTH); if (status != AJ_OK) { return status; } AJ_InfoPrintf(("Has key [%s] runtime Value [%d]\n", propertyStoreProperties[AJSVC_PROPERTY_STORE_MAX_LENGTH].keyName, DEVICE_NAME_VALUE_LENGTH)); #endif } else if (fieldIndex == AJSVC_PROPERTY_STORE_AJ_SOFTWARE_VERSION) { ajVersion = AJ_GetVersion(); if (ajVersion == NULL) { AJ_ErrPrintf(("PropertyStore_ReadAll - Failed to get value for mandatory field=(name=%s, index=%d) and language=(name=%s, index=%d), aborting.\n", AJSVC_PropertyStore_GetFieldName(fieldIndex), (int)fieldIndex, AJSVC_PropertyStore_GetLanguageName(langIndex), (int)langIndex)); return AJ_ERR_NULL; } status = AJ_MarshalArgs(msg, "{sv}", propertyStoreProperties[fieldIndex].keyName, "s", ajVersion); if (status != AJ_OK) { return status; } AJ_InfoPrintf(("Has key [%s] runtime Value [%s]\n", propertyStoreProperties[AJSVC_PROPERTY_STORE_AJ_SOFTWARE_VERSION].keyName, ajVersion)); } else { if (value == NULL) { AJ_ErrPrintf(("PropertyStore_ReadAll - Failed to get value for mandatory field=(name=%s, index=%d) and language=(name=%s, index=%d), aborting.\n", AJSVC_PropertyStore_GetFieldName(fieldIndex), (int)fieldIndex, AJSVC_PropertyStore_GetLanguageName(langIndex), (int)langIndex)); return AJ_ERR_NULL; } status = AJ_MarshalArgs(msg, "{sv}", propertyStoreProperties[fieldIndex].keyName, "s", value); if (status != AJ_OK) { return status; } } } } } if (filter.bit0About) { // Add supported languages status = AJ_MarshalContainer(msg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { return status; } status = AJ_MarshalArgs(msg, "s", defaultLanguagesKeyName); if (status != AJ_OK) { return status; } status = AJ_MarshalVariant(msg, "as"); if (status != AJ_OK) { return status; } status = AJ_MarshalContainer(msg, &array2, AJ_ARG_ARRAY); if (status != AJ_OK) { return status; } for (index = 0; index < AJSVC_PROPERTY_STORE_NUMBER_OF_LANGUAGES; index++) { status = AJ_MarshalArgs(msg, "s", propertyStoreDefaultLanguages[index]); if (status != AJ_OK) { return status; } } status = AJ_MarshalCloseContainer(msg, &array2); if (status != AJ_OK) { return status; } status = AJ_MarshalCloseContainer(msg, &dict); if (status != AJ_OK) { return status; } } status = AJ_MarshalCloseContainer(msg, &array); if (status != AJ_OK) { return status; } return status; } #ifdef CONFIG_SERVICE AJ_Status AJSVC_PropertyStore_Update(const char* key, int8_t langIndex, const char* value) { int8_t fieldIndex = AJSVC_PropertyStore_GetFieldIndex(key); if (fieldIndex <= AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX || fieldIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS) { return AJ_ERR_INVALID; } if (!UpdateFieldInRAM(fieldIndex, langIndex, value)) { return AJ_ERR_FAILURE; } return AJ_OK; } AJ_Status AJSVC_PropertyStore_Reset(const char* key, int8_t langIndex) { int8_t fieldIndex = AJSVC_PropertyStore_GetFieldIndex(key); if (fieldIndex <= AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX || fieldIndex >= AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS) { return AJ_ERR_INVALID; } if (!DeleteFieldFromRAM(fieldIndex, langIndex)) { return AJ_ERR_FAILURE; } InitMandatoryPropertiesInRAM(); return AJ_OK; } AJ_Status AJSVC_PropertyStore_ResetAll() { ClearPropertiesInRAM(); InitMandatoryPropertiesInRAM(); return AJSVC_PropertyStore_SaveAll(); } #endif ajtcl-16.04/services/common/src/SConscript.config000066400000000000000000000003021271074662300220040ustar00rootroot00000000000000import os Import('env') common_env = env.Clone() common_env.Append(CPPDEFINES = { 'CONFIG_SERVICE': '1' }) srcs = [] srcs.extend(common_env.Glob('*.c')) objs = common_env.Object(srcs) ajtcl-16.04/services/common/src/ServicesCommon.c000066400000000000000000000107221271074662300216350ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h. * The corresponding flag dbgAJSVC is defined in ServicesCommon.h and implemented * below. */ #define AJ_MODULE AJSVC #include #include #include #include #ifdef ONBOARDING_SERVICE #include #endif #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG #ifndef ER_DEBUG_AJSVCALL #define ER_DEBUG_AJSVCALL 0 #endif #ifndef ER_DEBUG_AJSVC #define ER_DEBUG_AJSVC 0 #endif uint8_t dbgAJSVC = ER_DEBUG_AJSVC || ER_DEBUG_AJSVCALL; #endif uint8_t AJSVC_IsLanguageSupported(AJ_Message* msg, AJ_Message* reply, const char* language, int8_t* langIndex) { uint8_t supported = TRUE; int8_t foundLangIndex = AJSVC_PropertyStore_GetLanguageIndex(language); if (foundLangIndex == AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX) { AJ_MarshalErrorMsg(msg, reply, AJSVC_ERROR_LANGUAGE_NOT_SUPPORTED); supported = FALSE; } if (langIndex != NULL) { *langIndex = foundLangIndex; } return supported; } AJ_Status AJSVC_MarshalAppIdAsVariant(AJ_Message* msg, const char* appId) { AJ_Status status; uint8_t binAppId[UUID_LENGTH]; uint32_t sz = strlen(appId); if (sz > UUID_LENGTH * 2) { // Crop application id that is too long sz = UUID_LENGTH * 2; } status = AJ_HexToRaw(appId, sz, binAppId, UUID_LENGTH); if (status != AJ_OK) { return status; } status = AJ_MarshalArgs(msg, "v", APP_ID_SIGNATURE, binAppId, sz / 2); return status; } AJ_Status AJSVC_MarshalAppId(AJ_Message* msg, const char* appId) { AJ_Status status; uint8_t binAppId[UUID_LENGTH]; uint32_t sz = strlen(appId); if (sz > UUID_LENGTH * 2) { // Crop application id that is too long sz = UUID_LENGTH * 2; } status = AJ_HexToRaw(appId, sz, binAppId, UUID_LENGTH); if (status != AJ_OK) { return status; } status = AJ_MarshalArgs(msg, APP_ID_SIGNATURE, binAppId, sz / 2); return status; } AJ_Status AJSVC_UnmarshalAppIdFromVariant(AJ_Message* msg, char* buf, size_t bufLen) { AJ_Status status; uint8_t* appId; size_t appIdLen; if (bufLen < (UUID_LENGTH * 2 + 1)) { AJ_ErrPrintf(("UnmarshalAppId: Insufficient buffer size! Should be at least %u but got %u\n", UUID_LENGTH * 2 + 1, (uint32_t)bufLen)); return AJ_ERR_RESOURCES; } status = AJ_UnmarshalArgs(msg, "v", APP_ID_SIGNATURE, &appId, &appIdLen); if (status != AJ_OK) { return status; } status = AJ_RawToHex((const uint8_t*)appId, appIdLen, buf, ((appIdLen > UUID_LENGTH) ? UUID_LENGTH : appIdLen) * 2 + 1, FALSE); return status; } AJ_Status AJSVC_UnmarshalAppId(AJ_Message* msg, char* buf, size_t bufLen) { AJ_Status status; uint8_t* appId; size_t appIdLen; if (bufLen < (UUID_LENGTH * 2 + 1)) { AJ_ErrPrintf(("UnmarshalAppId: Insufficient buffer size! Should be at least %u but got %u\n", UUID_LENGTH * 2 + 1, (uint32_t)bufLen)); return AJ_ERR_RESOURCES; } status = AJ_UnmarshalArgs(msg, APP_ID_SIGNATURE, &appId, &appIdLen); if (status != AJ_OK) { return status; } status = AJ_RawToHex((const uint8_t*)appId, appIdLen, buf, ((appIdLen > UUID_LENGTH) ? UUID_LENGTH : appIdLen) * 2 + 1, FALSE); return status; } ajtcl-16.04/services/common/src/ServicesHandlers.c000066400000000000000000000317261271074662300221540ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h. * The corresponding flag dbgAJSVC is defined in ServicesCommon.h and implemented * in ServicesCommon.c. */ #define AJ_MODULE AJSVC #include #include #include #include #include #ifdef CONFIG_SERVICE #include #endif #ifdef ONBOARDING_SERVICE #include #include #endif #ifdef NOTIFICATION_SERVICE_CONSUMER #include #endif #ifdef NOTIFICATION_SERVICE_PRODUCER #include #endif #ifdef CONTROLPANEL_SERVICE #include #endif #ifdef TIME_SERVICE_SERVER #include #endif #ifdef TIME_SERVICE_CLIENT #include #endif #include #include AJ_Status AJSVC_RoutingNodeConnect(AJ_BusAttachment* busAttachment, const char* routingNodeName, uint32_t connectTimeout, uint32_t connectPause, uint32_t busLinkTimeout, uint8_t* isConnected) { AJ_Status status = AJ_OK; const char* busUniqueName; while (TRUE) { #ifdef ONBOARDING_SERVICE status = AJOBS_EstablishWiFi(); if (status != AJ_OK) { AJ_ErrPrintf(("Failed to establish WiFi connectivity with status=%s\n", AJ_StatusText(status))); AJ_Sleep(connectPause); if (isConnected != NULL) { *isConnected = FALSE; } return status; } #endif AJ_InfoPrintf(("Attempting to connect to bus '%s'\n", routingNodeName)); status = AJ_FindBusAndConnect(busAttachment, routingNodeName, connectTimeout); if (status != AJ_OK) { AJ_ErrPrintf(("Failed attempt to connect to bus, sleeping for %d seconds\n", connectPause / 1000)); AJ_Sleep(connectPause); #ifdef ONBOARDING_SERVICE if (status == AJ_ERR_DHCP || status == AJ_ERR_TIMEOUT) { status = AJOBS_SwitchToRetry(); if (status != AJ_OK) { AJ_ErrPrintf(("Failed to switch to Retry mode status=%s\n", AJ_StatusText(status))); } } #endif continue; } busUniqueName = AJ_GetUniqueName(busAttachment); if (busUniqueName == NULL) { AJ_ErrPrintf(("Failed to GetUniqueName() from newly connected bus, retrying\n")); continue; } AJ_InfoPrintf(("Connected to Routing Node with BusUniqueName=%s\n", busUniqueName)); break; } /* Configure timeout for the link to the Routing Node bus */ AJ_SetBusLinkTimeout(busAttachment, busLinkTimeout); if (isConnected != NULL) { *isConnected = TRUE; } return status; } AJ_Status AJSVC_ConnectedHandler(AJ_BusAttachment* busAttachment) { AJ_Status status = AJ_OK; #ifdef CONFIG_SERVICE status = AJCFG_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } #endif #ifdef ONBOARDING_SERVICE status = AJOBS_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } #endif #ifdef NOTIFICATION_SERVICE_PRODUCER status = AJNS_Producer_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } #endif #ifdef CONTROLPANEL_SERVICE status = AJCPS_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } #endif #ifdef NOTIFICATION_SERVICE_CONSUMER status = AJNS_Consumer_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } #endif #ifdef TIME_SERVICE_SERVER status = AJTS_Server_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } #endif #ifdef TIME_SERVICE_CLIENT status = AJTS_Client_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } #endif return status; ErrorExit: AJ_ErrPrintf(("Service ConnectedHandler returned an error %s\n", (AJ_StatusText(status)))); return status; } uint8_t AJSVC_CheckSessionAccepted(uint16_t port, uint32_t sessionId, char* joiner) { uint8_t session_accepted = FALSE; #ifdef NOTIFICATION_SERVICE_PRODUCER session_accepted |= AJNS_Producer_CheckSessionAccepted(port, sessionId, joiner); #endif #ifdef CONTROLPANEL_SERVICE session_accepted |= AJCPS_CheckSessionAccepted(port, sessionId, joiner); #endif #ifdef TIME_SERVICE_SERVER session_accepted |= AJTS_CheckSessionAccepted(port, sessionId, joiner); #endif return session_accepted; } static AJSVC_ServiceStatus SessionJoinedHandler(AJ_BusAttachment* busAttachment, uint32_t sessionId, uint32_t replySerialNum) { AJSVC_ServiceStatus serviceStatus = AJSVC_SERVICE_STATUS_NOT_HANDLED; #ifdef NOTIFICATION_SERVICE_CONSUMER if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJNS_Consumer_SessionJoinedHandler(busAttachment, sessionId, replySerialNum); } #endif #ifdef TIME_SERVICE_CLIENT if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJTS_Client_SessionJoinedHandler(busAttachment, sessionId, replySerialNum); } #endif return serviceStatus; } static AJSVC_ServiceStatus SessionRejectedHandler(AJ_BusAttachment* busAttachment, uint32_t sessionId, uint32_t replySerialNum, uint32_t replyCode) { AJSVC_ServiceStatus serviceStatus = AJSVC_SERVICE_STATUS_NOT_HANDLED; #ifdef NOTIFICATION_SERVICE_CONSUMER if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJNS_Consumer_SessionRejectedHandler(busAttachment, replySerialNum, replyCode); } #endif #ifdef TIME_SERVICE_CLIENT if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJTS_Client_SessionRejectedHandler(busAttachment, replySerialNum, replyCode); } #endif return serviceStatus; } static AJSVC_ServiceStatus SessionLostHandler(AJ_BusAttachment* busAttachment, uint32_t sessionId, uint32_t reason) { AJSVC_ServiceStatus serviceStatus = AJSVC_SERVICE_STATUS_NOT_HANDLED; #ifdef NOTIFICATION_SERVICE_CONSUMER if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJNS_Consumer_SessionLostHandler(busAttachment, sessionId, reason); } #endif #ifdef TIME_SERVICE_CLIENT if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJTS_Client_SessionLostHandler(busAttachment, sessionId, reason); } #endif return serviceStatus; } AJSVC_ServiceStatus AJSVC_MessageProcessorAndDispatcher(AJ_BusAttachment* busAttachment, AJ_Message* msg, AJ_Status* status) { AJSVC_ServiceStatus serviceStatus = AJSVC_SERVICE_STATUS_NOT_HANDLED; if (msg->msgId == AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION)) { // Process all incoming replies to join a session and pass session state change to all services uint32_t replyCode = 0; uint32_t sessionId = 0; uint8_t sessionJoined = FALSE; uint32_t joinSessionReplySerialNum = msg->replySerial; if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("JoinSessionReply: AJ_METHOD_JOIN_SESSION: AJ_ERR_FAILURE\n")); *status = AJ_ERR_FAILURE; } else { *status = AJ_UnmarshalArgs(msg, "uu", &replyCode, &sessionId); if (*status != AJ_OK) { AJ_ErrPrintf(("JoinSessionReply: failed to unmarshal\n")); } else { if (replyCode == AJ_JOINSESSION_REPLY_SUCCESS) { AJ_InfoPrintf(("JoinSessionReply: AJ_JOINSESSION_REPLY_SUCCESS with sessionId=%u and replySerial=%u\n", sessionId, joinSessionReplySerialNum)); sessionJoined = TRUE; } else { AJ_ErrPrintf(("JoinSessionReply: AJ_ERR_FAILURE\n")); *status = AJ_ERR_FAILURE; } } } if (sessionJoined) { serviceStatus = SessionJoinedHandler(busAttachment, sessionId, joinSessionReplySerialNum); } else { serviceStatus = SessionRejectedHandler(busAttachment, sessionId, joinSessionReplySerialNum, replyCode); } if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { AJ_ResetArgs(msg); } } else if (msg->msgId == AJ_SIGNAL_SESSION_LOST || msg->msgId == AJ_SIGNAL_SESSION_LOST_WITH_REASON) { // Process all incoming LeaveSession replies and lost session signals and pass session state change to all services uint32_t sessionId = 0; uint32_t reason = 0; if (msg->msgId == AJ_SIGNAL_SESSION_LOST_WITH_REASON) { *status = AJ_UnmarshalArgs(msg, "uu", &sessionId, &reason); } else { *status = AJ_UnmarshalArgs(msg, "u", &sessionId); } if (*status != AJ_OK) { AJ_ErrPrintf(("JoinSessionReply: failed to marshal\n")); } else { AJ_InfoPrintf(("Session lost: sessionId = %u, reason = %u\n", sessionId, reason)); serviceStatus = SessionLostHandler(busAttachment, sessionId, reason); if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { AJ_ResetArgs(msg); } } } else { #ifdef CONFIG_SERVICE if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJCFG_MessageProcessor(busAttachment, msg, status); } #endif #ifdef ONBOARDING_SERVICE if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJOBS_MessageProcessor(busAttachment, msg, status); } #endif #ifdef NOTIFICATION_SERVICE_PRODUCER if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJNS_Producer_MessageProcessor(busAttachment, msg, status); } #endif #ifdef NOTIFICATION_SERVICE_CONSUMER if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJNS_Consumer_MessageProcessor(busAttachment, msg, status); } #endif #ifdef CONTROLPANEL_SERVICE if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJCPS_MessageProcessor(busAttachment, msg, status); } #endif #ifdef TIME_SERVICE_SERVER if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJTS_Server_MessageProcessor(busAttachment, msg, status); } #endif #ifdef TIME_SERVICE_CLIENT if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJTS_Client_MessageProcessor(busAttachment, msg, status); } #endif } return serviceStatus; } AJ_Status AJSVC_DisconnectHandler(AJ_BusAttachment* busAttachment) { AJ_Status status = AJ_OK; #ifdef CONFIG_SERVICE AJCFG_DisconnectHandler(busAttachment); #endif #ifdef ONBOARDING_SERVICE AJOBS_DisconnectHandler(busAttachment); #endif #ifdef NOTIFICATION_SERVICE_CONSUMER AJNS_Consumer_DisconnectHandler(busAttachment); #endif #ifdef NOTIFICATION_SERVICE_PRODUCER AJNS_Producer_DisconnectHandler(busAttachment); #endif #ifdef CONTROLPANEL_SERVICE AJCPS_DisconnectHandler(busAttachment); #endif #ifdef TIME_SERVICE_SERVER AJTS_Server_DisconnectHandler(busAttachment); #endif #ifdef TIME_SERVICE_CLIENT AJTS_Client_DisconnectHandler(busAttachment); #endif return status; } AJ_Status AJSVC_RoutingNodeDisconnect(AJ_BusAttachment* busAttachment, uint8_t disconnectWiFi, uint32_t preDisconnectPause, uint32_t postDisconnectPause, uint8_t* isConnected) { AJ_Status status = AJ_OK; AJ_ErrPrintf(("AllJoyn disconnect\n")); AJ_Sleep(preDisconnectPause); // Sleep a little to let any pending requests to Routing Node to be sent AJ_Disconnect(busAttachment); #ifdef ONBOARDING_SERVICE if (disconnectWiFi) { status = AJOBS_DisconnectWiFi(); } #endif AJ_Sleep(postDisconnectPause); // Sleep a little while before trying to reconnect if (isConnected != NULL) { *isConnected = FALSE; } return status; } ajtcl-16.04/services/config/000077500000000000000000000000001271074662300157215ustar00rootroot00000000000000ajtcl-16.04/services/config/inc/000077500000000000000000000000001271074662300164725ustar00rootroot00000000000000ajtcl-16.04/services/config/inc/ConfigService.h000066400000000000000000000057361271074662300214040ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef _CONFIGSERVICE_H_ #define _CONFIGSERVICE_H_ /** @defgroup ConfigService Config Service Framework * * @{ */ #include #include /** * Following definitions are read by the application. */ /** * Actions to perform when factory reset is requested. * Performed by the application. * @return status */ typedef AJ_Status (*AJCFG_FactoryReset)(void); /** * Actions to perform when a device restart is requested. * Performed by the application. * @return aj_status */ typedef AJ_Status (*AJCFG_Restart)(void); /** * Actions to perform when a new device passcode is set. * Performed by the application. * @param routerRealm * @param newPasscode * @param newPasscodeLen * @return aj_status */ typedef AJ_Status (*AJCFG_SetPasscode)(const char* routerRealm, const uint8_t* newPasscode, uint8_t newPasscodeLen); /** * Check whether the given value is valid for the given key. * @param key * @param value * @return isValid */ typedef uint8_t (*AJCFG_IsValueValid)(const char* key, const char* value); /** * Config Service API */ /** * Start Config service framework passing callbacks. * @param factoryReset * @param restart * @param setPasscode * @param isValueValid * @return aj_status */ AJ_Status AJCFG_Start(AJCFG_FactoryReset factoryReset, AJCFG_Restart restart, AJCFG_SetPasscode setPasscode, AJCFG_IsValueValid isValueValid); /** * Called when Routing Node is connected. * @param busAttachment * @return aj_status */ AJ_Status AJCFG_ConnectedHandler(AJ_BusAttachment* busAttachment); /** * Called when a new incoming message requires processing. * @param busAttachment * @param msg * @param msgStatus * @return aj_status */ AJSVC_ServiceStatus AJCFG_MessageProcessor(AJ_BusAttachment* busAttachment, AJ_Message* msg, AJ_Status* msgStatus); /** * Called just before the Routing Node disconnects. * @param busAttachment * @return aj_status */ AJ_Status AJCFG_DisconnectHandler(AJ_BusAttachment* busAttachment); /** @} */ #endif // _CONFIGSERVICE_H_ ajtcl-16.04/services/config/samples/000077500000000000000000000000001271074662300173655ustar00rootroot00000000000000ajtcl-16.04/services/config/samples/AllJoynLogo.h000066400000000000000000000112321271074662300217260ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef _ALLJOYNLOGO_H #define _ALLJOYNLOGO_H static const uint8_t AJ_LogoMimeType[] = "image/png"; static const uint8_t AJ_LogoData[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x04, 0x03, 0x00, 0x00, 0x00, 0xec, 0x11, 0x95, 0x82, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x50, 0x4c, 0x54, 0x45, 0x21, 0x1e, 0x1e, 0x21, 0x1e, 0x1e, 0x21, 0x1e, 0x1e, 0x21, 0x1e, 0x1e, 0xff, 0xff, 0xff, 0xb3, 0x89, 0xa3, 0xd8, 0x00, 0x00, 0x00, 0x04, 0x74, 0x52, 0x4e, 0x53, 0x02, 0x65, 0xfd, 0xa0, 0x20, 0x42, 0x9b, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x04, 0x8f, 0x68, 0xd9, 0x51, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x5f, 0x00, 0xa8, 0xb5, 0x68, 0xf3, 0x00, 0x00, 0x00, 0xfb, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x75, 0xd4, 0x8b, 0xad, 0xc3, 0x20, 0x0c, 0x05, 0x50, 0x13, 0x16, 0x48, 0x33, 0x01, 0x98, 0x05, 0x50, 0xde, 0xfe, 0xbb, 0x3d, 0x08, 0x18, 0x5f, 0xf3, 0xb1, 0x5a, 0x05, 0xe5, 0x20, 0x30, 0xc6, 0x2d, 0x91, 0x86, 0xfb, 0xd1, 0x21, 0xd2, 0x15, 0xf7, 0xc0, 0xa1, 0x7e, 0x36, 0xf1, 0x72, 0x2e, 0xdf, 0x7b, 0x85, 0x87, 0x99, 0xe8, 0xe2, 0x95, 0xca, 0xbb, 0xb2, 0x89, 0xe3, 0xea, 0x33, 0x7c, 0x7b, 0x94, 0x47, 0x32, 0x50, 0xe7, 0xb2, 0xcc, 0x30, 0xc4, 0x22, 0xbe, 0x0e, 0xe2, 0x04, 0x61, 0x1e, 0xb6, 0xb4, 0x58, 0x92, 0x6a, 0xe3, 0x8c, 0xc0, 0x9a, 0x8a, 0x4c, 0xf3, 0x6d, 0x1c, 0x21, 0x17, 0x48, 0x47, 0x17, 0xa0, 0x55, 0xf0, 0x64, 0x46, 0xd2, 0x51, 0xb4, 0xc8, 0xb3, 0x64, 0xb2, 0x67, 0x50, 0xb1, 0x25, 0x04, 0x81, 0x82, 0x38, 0x2b, 0x78, 0x97, 0x56, 0xe6, 0x1b, 0xd9, 0x17, 0xde, 0xa3, 0xd8, 0xc6, 0x40, 0xb1, 0x97, 0xff, 0x82, 0xf4, 0x0d, 0x92, 0x6e, 0xa4, 0xbd, 0xd1, 0xd6, 0x8f, 0x63, 0xb9, 0x2e, 0x61, 0x9c, 0x23, 0xca, 0x72, 0x5d, 0xa0, 0x5e, 0x19, 0x5e, 0xf5, 0xc7, 0xcb, 0x7a, 0x9b, 0x43, 0x82, 0x5e, 0x79, 0x27, 0x91, 0x7b, 0xdc, 0x8a, 0x14, 0xe6, 0xe9, 0x32, 0x7a, 0x61, 0xd0, 0xd5, 0x24, 0x8e, 0xb6, 0x60, 0x69, 0x16, 0xd7, 0x24, 0x10, 0x4f, 0x51, 0xde, 0x7c, 0xb2, 0x40, 0xa1, 0xeb, 0x3b, 0xfa, 0xb3, 0x0a, 0xff, 0x41, 0xb3, 0x4c, 0x81, 0xdd, 0x6b, 0x22, 0x6b, 0xd5, 0xb7, 0x40, 0x9b, 0xdc, 0x68, 0x4f, 0xf8, 0xaf, 0xe0, 0x4f, 0x60, 0xc8, 0xfe, 0x82, 0x31, 0x41, 0xa2, 0x03, 0xdd, 0x74, 0xa0, 0x4c, 0x9b, 0x98, 0xbb, 0xd8, 0xd0, 0x01, 0xc8, 0x99, 0x7c, 0xff, 0x01, 0x5f, 0x41, 0x49, 0x2e, 0xb7, 0x6d, 0x6b, 0x80, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x35, 0x2d, 0x30, 0x38, 0x2d, 0x32, 0x31, 0x54, 0x31, 0x30, 0x3a, 0x30, 0x38, 0x3a, 0x31, 0x33, 0x2d, 0x30, 0x37, 0x3a, 0x30, 0x30, 0x7a, 0x11, 0xd4, 0xf9, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x35, 0x2d, 0x30, 0x38, 0x2d, 0x32, 0x31, 0x54, 0x31, 0x30, 0x3a, 0x30, 0x37, 0x3a, 0x34, 0x30, 0x2d, 0x30, 0x37, 0x3a, 0x30, 0x30, 0x83, 0x4f, 0x23, 0x31, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; #define AJ_LogoSize sizeof(AJ_LogoData) static const char AJ_LogoURL[] = "https://www.allseenalliance.org/"; #endif ajtcl-16.04/services/config/samples/ConfigSample.c000066400000000000000000000413041271074662300221020ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h. * The corresponding flag dbgAJSVCAPP is defined in the containing sample app. */ #define AJ_MODULE AJSVCAPP #include #include #include #include #include #include #include #include #include #include #include #include "AllJoynLogo.h" /* * Logger definition */ #ifndef NDEBUG #ifndef ER_DEBUG_AJSVCAPP #define ER_DEBUG_AJSVCAPP 0 #endif AJ_EXPORT uint8_t dbgAJSVCAPP = ER_DEBUG_AJSVCAPP; #endif /* * Define timeout/pause values. Values are in milli seconds. * The following may be tuned according to platform requirements such as battery usage. */ #define AJAPP_BUS_LINK_TIMEOUT 60 #define AJAPP_CONNECT_TIMEOUT (1000 * 60 * 10) // Override AJ_CONNECT_TIMEOUT to wait longer for a successful connection to a Routing Node #define AJAPP_CONNECT_PAUSE (1000 * 2) // Override AJ_CONNECT_PAUSE to be more responsive #define AJAPP_SLEEP_TIME (1000 * 2) // A little pause to let things settle #define AJAPP_UNMARSHAL_TIMEOUT (1000 * 1) // Override AJ_UNMARSHAL_TIMEOUT to be more responsive /** * Application wide globals */ #define ROUTING_NODE_NAME "org.alljoyn.BusNode" static uint8_t isBusConnected = FALSE; static AJ_BusAttachment busAttachment; #define AJ_ABOUT_SERVICE_PORT 900 /** * Application wide callbacks */ static uint32_t PasswordCallback(uint8_t* buffer, uint32_t bufLen) { AJ_Status status = AJ_OK; const char* hexPassword = AJSVC_PropertyStore_GetValue(AJSVC_PROPERTY_STORE_PASSCODE); size_t hexPasswordLen; uint32_t len = 0; if (hexPassword == NULL) { AJ_ErrPrintf(("Password is NULL!\n")); return len; } AJ_InfoPrintf(("Configured password=%s\n", hexPassword)); hexPasswordLen = strlen(hexPassword); len = hexPasswordLen / 2; status = AJ_HexToRaw(hexPassword, hexPasswordLen, buffer, bufLen); if (status == AJ_ERR_RESOURCES) { len = 0; } return len; } /** * Application handlers */ typedef enum { INIT_START = 0, INIT_SERVICES = INIT_START, INIT_SERVICES_PORT, INIT_ABOUT, INIT_CHECK_ANNOUNCE, INIT_FINISHED = INIT_CHECK_ANNOUNCE } enum_init_state_t; static enum_init_state_t currentServicesInitializationState = INIT_START; static enum_init_state_t nextServicesInitializationState = INIT_START; static AJ_Status AJApp_ConnectedHandler(AJ_BusAttachment* busAttachment) { AJ_Status status = AJ_OK; if (AJ_GetUniqueName(busAttachment)) { if (currentServicesInitializationState == nextServicesInitializationState) { switch (currentServicesInitializationState) { case INIT_SERVICES: status = AJSVC_ConnectedHandler(busAttachment); if (status != AJ_OK) { goto ErrorExit; } currentServicesInitializationState = nextServicesInitializationState = INIT_SERVICES_PORT; break; case INIT_SERVICES_PORT: status = AJ_BusBindSessionPort(busAttachment, AJ_ABOUT_SERVICE_PORT, NULL, 0); if (status != AJ_OK) { goto ErrorExit; } nextServicesInitializationState = INIT_ABOUT; break; case INIT_ABOUT: status = AJ_AboutInit(busAttachment, AJ_ABOUT_SERVICE_PORT); if (status != AJ_OK) { goto ErrorExit; } currentServicesInitializationState = nextServicesInitializationState = INIT_CHECK_ANNOUNCE; break; case INIT_CHECK_ANNOUNCE: status = AJ_AboutAnnounce(busAttachment); if (status != AJ_OK) { goto ErrorExit; } break; default: break; } } } return status; ErrorExit: AJ_ErrPrintf(("Application ConnectedHandler returned an error %s\n", (AJ_StatusText(status)))); return status; } static AJSVC_ServiceStatus AJApp_MessageProcessor(AJ_BusAttachment* busAttachment, AJ_Message* msg, AJ_Status* status) { AJSVC_ServiceStatus serviceStatus = AJSVC_SERVICE_STATUS_HANDLED; uint16_t port; char* joiner; uint32_t sessionId = 0; uint8_t session_accepted = FALSE; if (msg->msgId == AJ_METHOD_ACCEPT_SESSION) { // Process all incoming request to join a session and pass request for acceptance by all services *status = AJ_UnmarshalArgs(msg, "qus", &port, &sessionId, &joiner); if (*status != AJ_OK) { return serviceStatus; } session_accepted |= (port == AJ_ABOUT_SERVICE_PORT); session_accepted |= AJSVC_CheckSessionAccepted(port, sessionId, joiner); *status = AJ_BusReplyAcceptSession(msg, session_accepted); AJ_AlwaysPrintf(("%s session session_id=%u joiner=%s for port %u\n", (session_accepted ? "Accepted" : "Rejected"), sessionId, joiner, port)); } else { switch (currentServicesInitializationState) { case INIT_SERVICES_PORT: if (msg->msgId == AJ_REPLY_ID(AJ_METHOD_BIND_SESSION_PORT)) { currentServicesInitializationState = nextServicesInitializationState; } break; default: serviceStatus = AJSVC_MessageProcessorAndDispatcher(busAttachment, msg, status); break; } } return serviceStatus; } static AJ_Status AJApp_DisconnectHandler(AJ_BusAttachment* busAttachment, uint8_t restart) { AJ_Status status = AJ_OK; if (restart) { AJ_BusUnbindSession(busAttachment, AJ_ABOUT_SERVICE_PORT); } AJ_AboutSetShouldAnnounce(); currentServicesInitializationState = nextServicesInitializationState = INIT_START; return status; } /** * Services Provisioning */ const char* deviceManufactureName = "COMPANY"; const char* deviceProductName = "GENERIC BOARD"; /** * Config supported PropertyStore provisioning */ static const char DEFAULT_LANGUAGE[] = "en"; static const char* DEFAULT_LANGUAGES[] = { DEFAULT_LANGUAGE }; static const char SUPPORTED_LANG2[] = "de-AT"; static const char* SUPPORTED_LANGUAGES[] = { DEFAULT_LANGUAGE, SUPPORTED_LANG2, NULL }; const char* const* propertyStoreDefaultLanguages = SUPPORTED_LANGUAGES; /** * property array of structure with defaults */ static const char DEFAULT_DEVICE_NAME_LANG1[] = { "Company A - \"Generic Board\"" }; static const char DEFAULT_DEVICE_NAME_LANG2[] = { "Firma A - \"Generic Board\"" }; static const char* DEFAULT_DEVICE_NAMES[] = { DEFAULT_DEVICE_NAME_LANG1, DEFAULT_DEVICE_NAME_LANG2 }; static const char* DEFAULT_PASSCODES[] = { "303030303030" }; // HEX encoded { '0', '0', '0', '0', '0', '0' } static const char* DEFAULT_APP_NAMES[] = { "Configuree" }; static const char DEFAULT_DESCRIPTION_LANG1[] = "My First IOE device"; static const char DEFAULT_DESCRIPTION_LANG2[] = "Mein erstes IOE Geraet"; static const char* DEFAULT_DESCRIPTIONS[] = { DEFAULT_DESCRIPTION_LANG1, DEFAULT_DESCRIPTION_LANG2 }; static const char DEFAULT_MANUFACTURER_LANG1[] = "Company A(EN)"; static const char DEFAULT_MANUFACTURER_LANG2[] = "Firma A(DE-AT)"; static const char* DEFAULT_MANUFACTURERS[] = { DEFAULT_MANUFACTURER_LANG1, DEFAULT_MANUFACTURER_LANG2 }; static const char* DEFAULT_DEVICE_MODELS[] = { "0.0.1" }; static const char* DEFAULT_DATE_OF_MANUFACTURES[] = { "2014-05-01" }; static const char* DEFAULT_SOFTWARE_VERSIONS[] = { "0.0.1" }; static const char* DEFAULT_HARDWARE_VERSIONS[] = { "0.0.1" }; static const char DEFAULT_SUPPORT_URL_LANG1[] = "http://www.company_a.com"; static const char DEFAULT_SUPPORT_URL_LANG2[] = "http://www.company_a.com/de-AT"; static const char* DEFAULT_SUPPORT_URLS[] = { DEFAULT_SUPPORT_URL_LANG1, DEFAULT_SUPPORT_URL_LANG2 }; const char** propertyStoreDefaultValues[AJSVC_PROPERTY_STORE_NUMBER_OF_KEYS] = { // "Default Values per language", "Key Name" NULL, /*DeviceId*/ NULL, /*AppId*/ DEFAULT_DEVICE_NAMES, /*DeviceName*/ DEFAULT_LANGUAGES, /*DefaultLanguage*/ DEFAULT_PASSCODES, /*Passcode*/ NULL, /*RealmName*/ // Add other runtime keys above this line DEFAULT_APP_NAMES, /*AppName*/ DEFAULT_DESCRIPTIONS, /*Description*/ DEFAULT_MANUFACTURERS, /*Manufacturer*/ DEFAULT_DEVICE_MODELS, /*ModelNumber*/ DEFAULT_DATE_OF_MANUFACTURES, /*DateOfManufacture*/ DEFAULT_SOFTWARE_VERSIONS, /*SoftwareVersion*/ NULL, /*AJSoftwareVersion*/ NULL, /*MaxLength*/ // Add other mandatory about keys above this line DEFAULT_HARDWARE_VERSIONS, /*HardwareVersion*/ DEFAULT_SUPPORT_URLS, /*SupportUrl*/ // Add other optional about keys above this line }; /** * properties array of runtime values' buffers */ static char machineIdVar[MACHINE_ID_LENGTH + 1] = { 0 }; static char* machineIdVars[] = { machineIdVar }; static char deviceNameVarLang1[DEVICE_NAME_VALUE_LENGTH + 1] = { 0 }; static char deviceNameVarLang2[DEVICE_NAME_VALUE_LENGTH + 1] = { 0 }; static char* deviceNameVars[] = { deviceNameVarLang1, deviceNameVarLang2 }; static char defaultLanguageVar[LANG_VALUE_LENGTH + 1] = { 0 }; static char* defaultLanguageVars[] = { defaultLanguageVar }; static char passcodeVar[PASSWORD_VALUE_LENGTH + 1] = { 0 }; static char* passcodeVars[] = { passcodeVar }; static char realmNameVar[KEY_VALUE_LENGTH + 1] = { 0 }; static char* realmNameVars[] = { realmNameVar }; PropertyStoreConfigEntry propertyStoreRuntimeValues[AJSVC_PROPERTY_STORE_NUMBER_OF_RUNTIME_KEYS] = { // {"Buffers for Values per language", "Buffer Size"}, "Key Name" { machineIdVars, MACHINE_ID_LENGTH + 1 }, /*DeviceId*/ { machineIdVars, MACHINE_ID_LENGTH + 1 }, /*AppId*/ { deviceNameVars, DEVICE_NAME_VALUE_LENGTH + 1 }, /*DeviceName*/ { defaultLanguageVars, LANG_VALUE_LENGTH + 1 }, /*AppName*/ { passcodeVars, PASSWORD_VALUE_LENGTH + 1 }, /*Description*/ { realmNameVars, KEY_VALUE_LENGTH + 1 }, /*Manufacturer*/ // Add other runtime keys above this line }; /** * AboutIcon Provisioning */ const char* aboutIconMimetype = AJ_LogoMimeType; const uint8_t* aboutIconContent = AJ_LogoData; const size_t aboutIconContentSize = AJ_LogoSize; const char* aboutIconUrl = AJ_LogoURL; /* * Config Provisioning */ static AJ_Status FactoryReset() { AJ_Status status = AJ_OK; AJ_InfoPrintf(("GOT FACTORY RESET\n")); status = AJSVC_PropertyStore_ResetAll(); if (status != AJ_OK) { return status; } AJ_ClearCredentials(0); return AJ_ERR_RESTART_APP; // Force disconnect of AJ and services and reconnection of WiFi on restart of app } static AJ_Status Restart() { AJ_InfoPrintf(("GOT RESTART REQUEST\n")); AJ_AboutSetShouldAnnounce(); // Set flag for sending an updated Announcement return AJ_ERR_RESTART_APP; // Force disconnect of AJ and services and reconnection of WiFi on restart of app } static AJ_Status SetPasscode(const char* daemonRealm, const uint8_t* newPasscode, uint8_t newPasscodeLen) { AJ_Status status = AJ_OK; char newStringPasscode[PASSWORD_VALUE_LENGTH + 1]; status = AJ_RawToHex(newPasscode, newPasscodeLen, newStringPasscode, sizeof(newStringPasscode), FALSE); if (status != AJ_OK) { return status; } if (AJSVC_PropertyStore_SetValue(AJSVC_PROPERTY_STORE_REALM_NAME, daemonRealm) && AJSVC_PropertyStore_SetValue(AJSVC_PROPERTY_STORE_PASSCODE, newStringPasscode)) { status = AJSVC_PropertyStore_SaveAll(); if (status != AJ_OK) { return status; } AJ_ClearCredentials(AJ_CRED_TYPE_GENERIC); status = AJ_ERR_READ; //Force disconnect of AJ and services to refresh current sessions } else { status = AJSVC_PropertyStore_LoadAll(); if (status != AJ_OK) { return status; } } return status; } static uint8_t IsValueValid(const char* key, const char* value) { return TRUE; } static AJ_Status Config_Init() { AJ_Status status = AJCFG_Start(&FactoryReset, &Restart, &SetPasscode, &IsValueValid); return status; } /** * The AllJoyn Message Loop */ int AJ_Main(void) { AJ_Status status = AJ_OK; uint8_t isUnmarshalingSuccessful = FALSE; AJSVC_ServiceStatus serviceStatus; AJ_Message msg; uint8_t forcedDisconnnect = FALSE; uint8_t rebootRequired = FALSE; AJ_Initialize(); AJ_AboutSetIcon(aboutIconContent, aboutIconContentSize, aboutIconMimetype, aboutIconUrl); status = PropertyStore_Init(); if (status != AJ_OK) { goto Exit; } status = Config_Init(); if (status != AJ_OK) { goto Exit; } while (TRUE) { status = AJ_OK; serviceStatus = AJSVC_SERVICE_STATUS_NOT_HANDLED; if (!isBusConnected) { status = AJSVC_RoutingNodeConnect(&busAttachment, ROUTING_NODE_NAME, AJAPP_CONNECT_TIMEOUT, AJAPP_CONNECT_PAUSE, AJAPP_BUS_LINK_TIMEOUT, &isBusConnected); if (!isBusConnected) { // Failed to connect to Routing Node. continue; // Retry establishing connection to Routing Node. } /* Setup password based authentication listener for secured peer to peer connections */ AJ_BusSetPasswordCallback(&busAttachment, PasswordCallback); } status = AJApp_ConnectedHandler(&busAttachment); if (status == AJ_OK) { status = AJ_UnmarshalMsg(&busAttachment, &msg, AJAPP_UNMARSHAL_TIMEOUT); isUnmarshalingSuccessful = (status == AJ_OK); if (status == AJ_ERR_TIMEOUT) { if (AJ_ERR_LINK_TIMEOUT == AJ_BusLinkStateProc(&busAttachment)) { status = AJ_ERR_READ; // something's not right. force disconnect } } if (isUnmarshalingSuccessful) { if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { serviceStatus = AJApp_MessageProcessor(&busAttachment, &msg, &status); } if (serviceStatus == AJSVC_SERVICE_STATUS_NOT_HANDLED) { //Pass to the built-in bus message handlers status = AJ_BusHandleBusMessage(&msg); } AJ_NotifyLinkActive(); } //Unmarshaled messages must be closed to free resources AJ_CloseMsg(&msg); } if (status == AJ_ERR_READ || status == AJ_ERR_WRITE || status == AJ_ERR_RESTART || status == AJ_ERR_RESTART_APP) { if (isBusConnected) { forcedDisconnnect = (status != AJ_ERR_READ); rebootRequired = (status == AJ_ERR_RESTART_APP); AJApp_DisconnectHandler(&busAttachment, forcedDisconnnect); AJSVC_RoutingNodeDisconnect(&busAttachment, forcedDisconnnect, AJAPP_SLEEP_TIME, AJAPP_SLEEP_TIME, &isBusConnected); if (rebootRequired) { AJ_Reboot(); } } } } // while (TRUE) return 0; Exit: return (1); } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/services/config/samples/SConscript000066400000000000000000000011761271074662300214040ustar00rootroot00000000000000import os Import('env') config_env = env.Clone() config_env.Append(CPPDEFINES = { 'AJ_MAIN': None, 'AJ_NUM_REPLY_CONTEXTS': '8', 'AJ_MAX_OBJECT_LISTS': '9', 'ANNOUNCE_BASED_DISCOVERY': '1', 'CONFIG_SERVICE': '1' }) config_env.Append(LIBPATH = '#dist/lib') config_env.Prepend(LIBS = ['ajtcl_services_config']) config_env.Prepend(LIBS = ['ajtcl']) common_objs = config_env.Glob('../../common/config/src/*' + env['OBJSUFFIX']) config_objs = config_env.Object(config_env.Glob('*.c')) config_progs = config_env.Program('ConfigSample', common_objs + config_objs) config_env.Install('#dist/bin/services', config_progs) ajtcl-16.04/services/config/src/000077500000000000000000000000001271074662300165105ustar00rootroot00000000000000ajtcl-16.04/services/config/src/ConfigService.c000066400000000000000000000403351271074662300214070ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h. * The corresponding flag dbgAJCFG is declared below. */ #define AJ_MODULE AJCFG #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG #ifndef ER_DEBUG_AJSVCALL #define ER_DEBUG_AJSVCALL 0 #endif #ifndef ER_DEBUG_AJCFG #define ER_DEBUG_AJCFG 0 #endif uint8_t dbgAJCFG = ER_DEBUG_AJCFG || ER_DEBUG_AJSVCALL; #endif /** * Published Config BusObjects and Interfaces. */ static const char* const AJSVC_ConfigInterface[] = { "$org.alljoyn.Config", "@Version>q", "?FactoryReset", "?Restart", "?GetConfigurations a{sv}", "?UpdateConfigurations bus); if (status != AJ_OK) { return status; } if (AppFactoryReset) { status = (AppFactoryReset)(); } return status; } AJ_Status AJCFG_RestartHandler(AJ_Message* msg) { AJ_Status status = AJ_OK; if (AppRestart) { status = (AppRestart)(); } return status; } AJ_Status AJCFG_GetConfigurationsHandler(AJ_Message* msg) { AJ_Status status = AJ_OK; AJ_Message reply; char* language; int8_t langIndex = AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX; AJSVC_PropertyStoreCategoryFilter filter; AJ_InfoPrintf(("Handling GetConfigurations request\n")); memset(&filter, 0, sizeof(AJSVC_PropertyStoreCategoryFilter)); filter.bit1Config = TRUE; status = AJ_UnmarshalArgs(msg, "s", &language); if (status != AJ_OK) { return status; } if (AJSVC_IsLanguageSupported(msg, &reply, language, &langIndex)) { status = AJ_MarshalReplyMsg(msg, &reply); if (status != AJ_OK) { return status; } status = AJSVC_PropertyStore_ReadAll(&reply, filter, langIndex); if (status != AJ_OK) { return status; } } status = AJ_DeliverMsg(&reply); if (status != AJ_OK) { return status; } return status; } static uint8_t IsValueValid(AJ_Message* msg, AJ_Message* reply, const char* key, const char* value) { if (strcmp(AJSVC_PropertyStore_GetFieldName(AJSVC_PROPERTY_STORE_DEFAULT_LANGUAGE), key) == 0) { // Check that if language was updated that it is supported if (strlen(value) > 0) { // that it is not empty return AJSVC_IsLanguageSupported(msg, reply, value, NULL); } else { AJ_MarshalErrorMsg(msg, reply, AJSVC_ERROR_LANGUAGE_NOT_SUPPORTED); } } else if (strcmp(AJSVC_PropertyStore_GetFieldName(AJSVC_PROPERTY_STORE_DEVICE_NAME), key) == 0) { // Check that if device name was updated if (strlen(value) <= AJSVC_PropertyStore_GetMaxValueLength(AJSVC_PROPERTY_STORE_DEVICE_NAME)) { // that it does not exceed maximum length if (strlen(value) > 0) { // that it is not empty return TRUE; } else { AJ_MarshalErrorMsg(msg, reply, AJSVC_ERROR_INVALID_VALUE); } } else { AJ_MarshalErrorMsg(msg, reply, AJSVC_ERROR_MAX_SIZE_EXCEEDED); } } else if (AJSVC_PropertyStore_GetFieldIndex(key) == AJSVC_PROPERTY_STORE_ERROR_FIELD_INDEX) { // Check that the key exists AJ_MarshalErrorMsg(msg, reply, AJSVC_ERROR_INVALID_VALUE); } else { if (AppIsValueValid == NULL || (AppIsValueValid)(key, value)) { return TRUE; } AJ_MarshalErrorMsg(msg, reply, AJSVC_ERROR_INVALID_VALUE); } return FALSE; } AJ_Status AJCFG_UpdateConfigurationsHandler(AJ_Message* msg) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_Arg dict; AJ_Message reply; char* key; char* sig; char* value; char* language; int8_t langIndex = AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX; uint8_t numOfUpdatedItems = 0; uint8_t errorReply = FALSE; AJ_InfoPrintf(("Handling UpdateConfigurations request\n")); status = AJ_UnmarshalArgs(msg, "s", &language); if (status != AJ_OK) { goto Exit; } AJ_InfoPrintf(("Lang=%s\n", language)); errorReply = !AJSVC_IsLanguageSupported(msg, &reply, language, &langIndex); if (!errorReply) { status = AJ_UnmarshalContainer(msg, &array, AJ_ARG_ARRAY); if (status != AJ_OK) { goto Exit; } while (1) { status = AJ_UnmarshalContainer(msg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(msg, "s", &key); if (status != AJ_OK) { break; } status = AJ_UnmarshalVariant(msg, (const char**)&sig); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(msg, sig, &value); if (status != AJ_OK) { break; } AJ_InfoPrintf(("key=%s value=%s\n", key, value)); if (IsValueValid(msg, &reply, key, value)) { status = AJSVC_PropertyStore_Update(key, langIndex, value); if (status == AJ_OK) { numOfUpdatedItems++; } else if (status == AJ_ERR_INVALID) { if (!errorReply) { AJ_MarshalErrorMsg(msg, &reply, AJSVC_ERROR_INVALID_VALUE); errorReply = TRUE; } } else if (status == AJ_ERR_FAILURE) { if (!errorReply) { AJ_MarshalErrorMsg(msg, &reply, AJSVC_ERROR_UPDATE_NOT_ALLOWED); errorReply = TRUE; } } } else { errorReply = TRUE; } status = AJ_UnmarshalCloseContainer(msg, &dict); if (status != AJ_OK) { break; } } if (status != AJ_OK && status != AJ_ERR_NO_MORE) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &array); if (status != AJ_OK) { goto Exit; } } if (!errorReply) { status = AJ_MarshalReplyMsg(msg, &reply); if (status != AJ_OK) { goto Exit; } } status = AJ_DeliverMsg(&reply); if (status != AJ_OK) { goto Exit; } Exit: if (numOfUpdatedItems) { if (errorReply) { AJSVC_PropertyStore_LoadAll(); // Discard partial successful updates } else { AJSVC_PropertyStore_SaveAll(); AJ_AboutSetShouldAnnounce(); } } return status; } AJ_Status AJCFG_ResetConfigurationsHandler(AJ_Message* msg) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_Message reply; char* key; char* language; int8_t langIndex = AJSVC_PROPERTY_STORE_ERROR_LANGUAGE_INDEX; uint8_t numOfDeletedItems = 0; uint8_t errorReply = FALSE; AJ_InfoPrintf(("Handling ResetConfigurations request\n")); status = AJ_UnmarshalArgs(msg, "s", &language); if (status != AJ_OK) { goto Exit; } AJ_InfoPrintf(("Lang=%s\n", language)); errorReply = !AJSVC_IsLanguageSupported(msg, &reply, language, &langIndex); if (!errorReply) { status = AJ_UnmarshalContainer(msg, &array, AJ_ARG_ARRAY); if (status != AJ_OK) { goto Exit; } while (1) { status = AJ_UnmarshalArgs(msg, "s", &key); if (status != AJ_OK) { break; } AJ_InfoPrintf(("Key=%s\n", key)); status = AJSVC_PropertyStore_Reset(key, langIndex); if (status == AJ_OK) { numOfDeletedItems++; } else if (status == AJ_ERR_INVALID) { if (!errorReply) { AJ_MarshalErrorMsg(msg, &reply, AJSVC_ERROR_INVALID_VALUE); errorReply = TRUE; } } else if (status == AJ_ERR_FAILURE) { if (!errorReply) { AJ_MarshalErrorMsg(msg, &reply, AJSVC_ERROR_UPDATE_NOT_ALLOWED); errorReply = TRUE; } } } if (status != AJ_OK && status != AJ_ERR_NO_MORE) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &array); if (status != AJ_OK) { goto Exit; } } if (!errorReply) { status = AJ_MarshalReplyMsg(msg, &reply); if (status != AJ_OK) { goto Exit; } } status = AJ_DeliverMsg(&reply); if (status != AJ_OK) { goto Exit; } Exit: if (numOfDeletedItems) { if (errorReply) { AJSVC_PropertyStore_LoadAll(); // Discard partial successful deletions } else { AJSVC_PropertyStore_SaveAll(); AJ_AboutSetShouldAnnounce(); } } return status; } AJ_Status AJCFG_SetPasscodeHandler(AJ_Message* msg) { AJ_Status status = AJ_OK; char* daemonRealm; AJ_Arg newPasscode; AJ_Message reply; uint8_t forceRoutingNodeDisconnect = FALSE; uint8_t errorReply = FALSE; AJ_InfoPrintf(("Handling SetPasscode request\n")); status = AJ_UnmarshalArgs(msg, "s", &daemonRealm); if (status != AJ_OK) { return status; } AJ_InfoPrintf(("Realm=%s\n", daemonRealm)); status = AJ_UnmarshalArg(msg, &newPasscode); if (status != AJ_OK) { return status; } AJ_InfoPrintf(("Passcode=%d bytes long\n", newPasscode.len)); if (newPasscode.len > 0) { // Check passcode is not empty if (AppSetPasscode) { status = (AppSetPasscode)(daemonRealm, (const uint8_t*)newPasscode.val.v_string, (uint8_t)newPasscode.len); if (status == AJ_ERR_RESOURCES) { // Check passcode is too long to persist status = AJ_MarshalErrorMsg(msg, &reply, AJSVC_ERROR_MAX_SIZE_EXCEEDED); if (status != AJ_OK) { return status; } errorReply = TRUE; } forceRoutingNodeDisconnect = (status == AJ_ERR_READ); } } else { AJ_ErrPrintf(("Error - newPasscode cannot be empty!\n")); status = AJ_MarshalErrorMsg(msg, &reply, AJSVC_ERROR_INVALID_VALUE); if (status != AJ_OK) { return status; } errorReply = TRUE; } if (!errorReply) { status = AJ_MarshalReplyMsg(msg, &reply); if (status != AJ_OK) { return status; } } status = AJ_DeliverMsg(&reply); if (forceRoutingNodeDisconnect) { return AJ_ERR_READ; } return status; } AJ_Status AJCFG_ConnectedHandler(AJ_BusAttachment* busAttachment) { return AJ_OK; } AJSVC_ServiceStatus AJCFG_MessageProcessor(AJ_BusAttachment* bus, AJ_Message* msg, AJ_Status* msgStatus) { AJSVC_ServiceStatus serviceStatus = AJSVC_SERVICE_STATUS_HANDLED; switch (msg->msgId) { case CONFIG_GET_PROP: *msgStatus = AJ_BusPropGet(msg, AJCFG_PropGetHandler, NULL); break; case CONFIG_SET_PROP: *msgStatus = AJ_BusPropSet(msg, AJCFG_PropSetHandler, NULL); break; case CONFIG_FACTORY_RESET: *msgStatus = AJCFG_FactoryResetHandler(msg); break; case CONFIG_RESTART: *msgStatus = AJCFG_RestartHandler(msg); break; case CONFIG_GET_CONFIG_CONFIGURATIONS: *msgStatus = AJCFG_GetConfigurationsHandler(msg); break; case CONFIG_RESET_CONFIGURATIONS: *msgStatus = AJCFG_ResetConfigurationsHandler(msg); break; case CONFIG_UPDATE_CONFIGURATIONS: *msgStatus = AJCFG_UpdateConfigurationsHandler(msg); break; case CONFIG_SET_PASSCODE: *msgStatus = AJCFG_SetPasscodeHandler(msg); break; default: serviceStatus = AJSVC_SERVICE_STATUS_NOT_HANDLED; break; } return serviceStatus; } AJ_Status AJCFG_DisconnectHandler(AJ_BusAttachment* busAttachment) { return AJ_OK; } ajtcl-16.04/services/config/src/SConscript000066400000000000000000000012431271074662300205220ustar00rootroot00000000000000import os Import('env') config_env = env.Clone() config_env.Append(CPPDEFINES = { 'CONFIG_SERVICE': '1' }) config_srcs = [] config_srcs.extend(config_env.Glob('*.c')) config_objs = config_env.Object(config_srcs) #####config_lib = config_env.Library("ajtcl_services_config", config_objs + config_env.Glob('../../common/config/src/*.o')) config_lib = config_env.Library("ajtcl_services_config", config_objs) config_env.Install("#dist/lib", config_lib) if config_env['build_shared']: config_objs = config_env.SharedObject(config_srcs) config_lib = config_env.SharedLibrary("ajtcl_services_config", config_objs) config_env.Install("#dist/lib", config_lib) ajtcl-16.04/src/000077500000000000000000000000001271074662300134205ustar00rootroot00000000000000ajtcl-16.04/src/SConscript000066400000000000000000000032561271074662300154400ustar00rootroot00000000000000import os Import('env') src_env = env.Clone() src_env['srcs'] = [] # Default common optional components to off (enabled according target platform) src_env['crypto'] = False src_env['external_sha2'] = False src_env['malloc'] = False src_env['freertos'] = False src_env['mbedrtos'] = False src_env['wsl'] = False src_env['system_objects'] = False src_env['nvram'] = False Export ('src_env') # Get the core sources src_env['srcs'] += Glob('*.c') # Get the target sources src_env.SConscript('target/$TARG/SConscript') # Get sources for any optional components if src_env['nvram']: src_env['srcs'] += Glob('nvram/*.c') if src_env['crypto']: src_env['srcs'] += Glob('crypto/*.c') if src_env['external_sha2']: src_env['srcs'] += Glob('external/sha2/*.c') src_env.Append(CPPPATH = [ 'external/sha2' ]) if src_env['malloc']: src_env.Append(CPPPATH = 'malloc') src_env['srcs'] += Glob('malloc/*.c') if src_env['freertos']: src_env.Append(CPPPATH = Dir(['freertos'])) src_env['srcs'] += Glob('freertos/*.c') if src_env['mbedrtos']: src_env.Append(CPPPATH = Dir(['mbedrtos'])) src_env['srcs'] += Glob('mbedrtos/*.cpp') src_env['srcs'] += Glob('mbedrtos/*.c') if src_env['wsl']: src_env.Append(CPPPATH = Dir(['target/$TARG'])) src_env.Append(CPPPATH = Dir(['bsp'])) src_env['srcs'] += Glob('wsl/*.c') src_env.Append(CPPPATH = Dir(['.'])) # Compile sources and create libraries objs = src_env.StaticObject(src_env['srcs']) lib = src_env.Library("ajtcl", objs) src_env.Install('#dist/lib', lib) if src_env['build_shared']: objs = src_env.SharedObject(src_env['srcs']) lib = src_env.SharedLibrary("ajtcl", objs) src_env.Install('#dist/lib', lib) ajtcl-16.04/src/aj_about.c000066400000000000000000000553251271074662300153620ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE ABOUT #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgABOUT = 0; #endif #define ABOUT_VERSION (1) #define ABOUT_ICON_VERSION (1) /* * Registered by the Property Store implementation */ static AJ_AboutPropGetter PropStoreGetter = NULL; /* * About icon registration */ static struct { uint16_t size; const uint8_t* data; const char* mime; const char* URL; uint8_t isSet; } icon; /* * Checked to see if announcements have been requested */ static uint8_t doAnnounce = TRUE; void AJ_AboutRegisterPropStoreGetter(AJ_AboutPropGetter propGetter) { PropStoreGetter = propGetter; } /* * Default about properties if there is no property store getter registered */ static AJ_Status MarshalDefaultProps(AJ_Message* msg) { AJ_Status status; AJ_Arg array; status = AJ_MarshalContainer(msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { status = AJ_MarshalCloseContainer(msg, &array); } return status; } AJ_Status AJ_AboutInit(AJ_BusAttachment* bus, uint16_t boundPort) { bus->aboutPort = boundPort; doAnnounce = TRUE; return AJ_AboutAnnounce(bus); } uint8_t AJ_AboutHasIcon() { return icon.isSet; } void AJ_AboutSetIcon(const uint8_t* data, uint16_t size, const char* mime, const char* url) { icon.data = data; icon.size = data ? size : 0; icon.mime = mime; icon.URL = url; icon.isSet = TRUE; } /* * Handles a property GET request so marshals the property value to return */ static AJ_Status AboutGetProp(AJ_Message* replyMsg, uint32_t propId, void* context) { if (propId == AJ_PROPERTY_ABOUT_VERSION) { return AJ_MarshalArgs(replyMsg, "q", (uint16_t)ABOUT_VERSION); } else { return AJ_ERR_UNEXPECTED; } } AJ_Status AJ_AboutHandleGetProp(AJ_Message* msg) { return AJ_BusPropGet(msg, AboutGetProp, NULL); } AJ_Status AJ_AboutHandleGetAboutData(AJ_Message* msg, AJ_Message* reply) { AJ_Status status = AJ_OK; const char* language; status = AJ_UnmarshalArgs(msg, "s", &language); if (status == AJ_OK) { AJ_MarshalReplyMsg(msg, reply); if (PropStoreGetter) { status = PropStoreGetter(reply, language); } else { status = AJ_ERR_NO_MATCH; } if (status != AJ_OK) { status = MarshalDefaultProps(reply); } } return status; } static AJ_Status MarshalObjectDescriptions(AJ_Message* msg) { AJ_Status status; AJ_Arg objList; AJ_ObjectIterator iter; const AJ_Object* obj; status = AJ_MarshalContainer(msg, &objList, AJ_ARG_ARRAY); if (status != AJ_OK) { goto ErrorExit; } /* * Announce objects that are flagged for announcement and not hidden */ for (obj = AJ_InitObjectIterator(&iter, AJ_OBJ_FLAG_ANNOUNCED | AJ_OBJ_FLAG_DESCRIBED, AJ_OBJ_FLAG_HIDDEN); obj != NULL; obj = AJ_NextObject(&iter)) { size_t i; AJ_Arg structure; AJ_Arg ifcList; const char* iface; status = AJ_MarshalContainer(msg, &structure, AJ_ARG_STRUCT); if (status != AJ_OK) { goto ErrorExit; } AJ_InfoPrintf(("Announcing object %s\n", obj->path)); status = AJ_MarshalArgs(msg, "o", obj->path); if (status != AJ_OK) { goto ErrorExit; } status = AJ_MarshalContainer(msg, &ifcList, AJ_ARG_ARRAY); if (status != AJ_OK) { goto ErrorExit; } /* * Add the AllSeenIntrospectableInterface if this object is flagged as being described */ if (obj->flags & AJ_OBJ_FLAG_DESCRIBED) { iface = AllSeenIntrospectableInterface; /* * Don't need the $ or # that indicate the interface is secure or not */ if (*iface == '$' || *iface == '#') { ++iface; } AJ_InfoPrintf((" %s\n", iface)); status = AJ_MarshalArgs(msg, "s", iface); if (status != AJ_OK) { goto ErrorExit; } } for (i = 0; obj->interfaces[i]; ++i) { if (obj->interfaces[i] != AJ_PropertiesIface) { iface = obj->interfaces[i][0]; if (iface) { /* * Don't need the $ or # that indicate the interface is secure or not */ if (*iface == '$' || *iface == '#') { ++iface; } AJ_InfoPrintf((" %s\n", iface)); status = AJ_MarshalArgs(msg, "s", iface); if (status != AJ_OK) { goto ErrorExit; } } } } status = AJ_MarshalCloseContainer(msg, &ifcList); if (status != AJ_OK) { goto ErrorExit; } status = AJ_MarshalCloseContainer(msg, &structure); if (status != AJ_OK) { goto ErrorExit; } } return AJ_MarshalCloseContainer(msg, &objList); ErrorExit: return status; } AJ_Status AJ_AboutAnnounce(AJ_BusAttachment* bus) { AJ_Status status = AJ_OK; AJ_Message announcement; if (!doAnnounce) { return status; } doAnnounce = FALSE; if (!bus->aboutPort) { AJ_InfoPrintf(("AJ_AboutAnnounce - nothing to announce\n")); return status; } AJ_InfoPrintf(("AJ_AboutAnnounce - announcing port=%d\n", bus->aboutPort)); status = AJ_MarshalSignal(bus, &announcement, AJ_SIGNAL_ABOUT_ANNOUNCE, NULL, 0, AJ_FLAG_SESSIONLESS, 0); if (status != AJ_OK) { goto ErrorExit; } status = AJ_MarshalArgs(&announcement, "q", (uint16_t)ABOUT_VERSION); if (status != AJ_OK) { goto ErrorExit; } status = AJ_MarshalArgs(&announcement, "q", bus->aboutPort); if (status != AJ_OK) { goto ErrorExit; } status = MarshalObjectDescriptions(&announcement); if (status != AJ_OK) { goto ErrorExit; } if (PropStoreGetter) { status = PropStoreGetter(&announcement, ""); } else { status = MarshalDefaultProps(&announcement); } if (status != AJ_OK) { goto ErrorExit; } bus->aboutSerial = announcement.hdr->serialNum; return AJ_DeliverMsg(&announcement); ErrorExit: return status; } AJ_Status AJ_AboutUnannounce(AJ_BusAttachment* bus) { AJ_Status status; if (bus->aboutSerial != 0) { status = AJ_BusCancelSessionless(bus, bus->aboutSerial); bus->aboutSerial = 0; return status; } else { AJ_ErrPrintf(("AJ_AboutUnannounce(): No about announcement to cancel\n")); return AJ_ERR_DISALLOWED; } } AJ_Status AJ_AboutHandleGetObjectDescription(AJ_Message* msg, AJ_Message* reply) { AJ_Status status = AJ_MarshalReplyMsg(msg, reply); if (status == AJ_OK) { return MarshalObjectDescriptions(reply); } else { return status; } } static AJ_Status AboutIconGetProp(AJ_Message* replyMsg, uint32_t propId, void* context) { AJ_Status status = AJ_ERR_UNEXPECTED; if (propId == AJ_PROPERTY_ABOUT_ICON_VERSION_PROP) { status = AJ_MarshalArgs(replyMsg, "q", (uint16_t)ABOUT_ICON_VERSION); } else if (propId == AJ_PROPERTY_ABOUT_ICON_MIMETYPE_PROP) { status = AJ_MarshalArgs(replyMsg, "s", icon.mime ? icon.mime : ""); } else if (propId == AJ_PROPERTY_ABOUT_ICON_SIZE_PROP) { status = AJ_MarshalArgs(replyMsg, "u", (uint32_t)icon.size); } return status; } AJ_Status AJ_AboutIconHandleGetProp(AJ_Message* msg) { return AJ_BusPropGet(msg, AboutIconGetProp, NULL); } AJ_Status AJ_AboutIconHandleGetURL(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; status = AJ_MarshalReplyMsg(msg, reply); if (status != AJ_OK) { goto ErrorExit; } return AJ_MarshalArgs(reply, "s", icon.URL ? icon.URL : ""); ErrorExit: return status; } AJ_Status AJ_AboutIconHandleGetContent(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; uint32_t u = (uint32_t)icon.size; status = AJ_MarshalReplyMsg(msg, reply); if (status != AJ_OK) { goto ErrorExit; } status = AJ_DeliverMsgPartial(reply, u + 4); if (status != AJ_OK) { goto ErrorExit; } status = AJ_MarshalRaw(reply, &u, 4); if (status != AJ_OK) { goto ErrorExit; } return AJ_MarshalRaw(reply, icon.data, u); ErrorExit: return status; } void AJ_AboutSetShouldAnnounce() { doAnnounce = TRUE; } void AJ_AboutSetAnnounceObjects(AJ_Object* objList) { if (objList) { while (objList->path) { objList->flags |= AJ_OBJ_FLAG_ANNOUNCED; ++objList; } } } #ifdef ANNOUNCE_BASED_DISCOVERY static const AJ_AboutPeerDescription* peerList = NULL; static uint16_t peerListLength = 0; void AJ_AboutRegisterAnnounceHandlers(AJ_AboutPeerDescription* peerDescs, uint16_t peerDescCount) { peerList = peerDescs; peerListLength = peerDescCount; } /** * It is assumed that the AJ_Message *msg supplied to this function is in memory while using objDescs. objDescs is merely pointing to entries in the messgae buffer in msg. */ AJ_Status AJ_AboutUnmarshalObjectDescriptions(AJ_Message* msg, AJ_AboutObjectDescription* objDescs, uint16_t* objDescsCount) { AJ_Status status = AJ_OK; AJ_Arg objList; status = AJ_UnmarshalContainer(msg, &objList, AJ_ARG_ARRAY); if (status != AJ_OK) { goto ErrorExit; } /* * Announce object that a flagged for announcement and not hidden */ while (status == AJ_OK) { AJ_Arg structure; AJ_Arg ifcList; uint16_t count = 0; status = AJ_UnmarshalContainer(msg, &structure, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(msg, "o", &objDescs[*objDescsCount].path); if (status != AJ_OK) { goto ErrorExit; } status = AJ_UnmarshalContainer(msg, &ifcList, AJ_ARG_ARRAY); if (status != AJ_OK) { goto ErrorExit; } while (status == AJ_OK) { status = AJ_UnmarshalArgs(msg, "s", &objDescs[*objDescsCount].interfaces[count]); count++; if (count >= AJ_MAX_NUM_OF_INTERFACES) { AJ_ErrPrintf(("Maximum Predefined number of interfaces (%d) exceeded\n", AJ_MAX_NUM_OF_INTERFACES)); status = AJ_ERR_RESOURCES; goto ErrorExit; } } if ((status != AJ_ERR_NO_MORE) && (status != AJ_OK)) { goto ErrorExit; } objDescs[*objDescsCount].interfacesCount = count - 1; status = AJ_UnmarshalCloseContainer(msg, &ifcList); if (status != AJ_OK) { goto ErrorExit; } status = AJ_UnmarshalCloseContainer(msg, &structure); (*objDescsCount)++; if (*objDescsCount >= AJ_MAX_NUM_OF_OBJ_DESC) { AJ_ErrPrintf(("Maximum Predefined number of object descriptions (%d) exceeded\n", AJ_MAX_NUM_OF_OBJ_DESC)); status = AJ_ERR_RESOURCES; goto ErrorExit; } } if (status == AJ_ERR_NO_MORE) { return AJ_UnmarshalCloseContainer(msg, &objList); } ErrorExit: return status; } #define UUID_LENGTH 16 #define APP_ID_SIGNATURE "ay" AJ_Status AJ_AboutUnmarshalAppIdFromVariant(AJ_Message* msg, char* buf, size_t bufLen) { AJ_Status status; uint8_t* appId; size_t appIdLen; if (bufLen < (UUID_LENGTH * 2 + 1)) { AJ_ErrPrintf(("UnmarshalAppId: Insufficient buffer size! Should be at least %u but got %u\n", UUID_LENGTH * 2 + 1, (uint32_t)bufLen)); return AJ_ERR_RESOURCES; } status = AJ_UnmarshalArgs(msg, "v", APP_ID_SIGNATURE, &appId, &appIdLen); if (status != AJ_OK) { return status; } status = AJ_RawToHex((const uint8_t*)appId, appIdLen, buf, ((appIdLen > UUID_LENGTH) ? UUID_LENGTH : appIdLen) * 2 + 1, FALSE); return status; } AJ_Status AJ_AboutUnmarshalProps(AJ_Message* msg, AJ_AboutHandleMandatoryProps onMandatoryProperties, AJ_AboutHandleOptionalProperty onOptionalProperty) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_Arg dict; char* key; const char* peerName = msg->sender; char appId[UUID_LENGTH * 2 + 1]; const char* appName = NULL; const char* deviceId = NULL; const char* deviceName = NULL; const char* manufacturer = NULL; const char* modelNumber = NULL; const char* defaultLanguage = NULL; appId[0] = '\0'; status = AJ_UnmarshalContainer(msg, &array, AJ_ARG_ARRAY); while (status == AJ_OK) { status = AJ_UnmarshalContainer(msg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(msg, "s", &key); if (status != AJ_OK) { break; } if (!strcmp(key, AJ_APP_ID_STR)) { status = AJ_AboutUnmarshalAppIdFromVariant(msg, appId, sizeof(appId)); } else if (!strcmp(key, AJ_APP_NAME_STR)) { status = AJ_UnmarshalArgs(msg, "v", "s", &appName); } else if (!strcmp(key, AJ_DEVICE_ID_STR)) { status = AJ_UnmarshalArgs(msg, "v", "s", &deviceId); } else if (!strcmp(key, AJ_DEVICE_NAME_STR)) { status = AJ_UnmarshalArgs(msg, "v", "s", &deviceName); } else if (!strcmp(key, AJ_MANUFACTURER_STR)) { status = AJ_UnmarshalArgs(msg, "v", "s", &manufacturer); } else if (!strcmp(key, AJ_MODEL_NUMBER_STR)) { status = AJ_UnmarshalArgs(msg, "v", "s", &modelNumber); } else if (!strcmp(key, AJ_DEFAULT_LANGUAGE_STR)) { status = AJ_UnmarshalArgs(msg, "v", "s", &defaultLanguage); } else { if (onOptionalProperty == NULL) { status = AJ_SkipArg(msg); } else { const char* vsig; AJ_Arg value; status = AJ_UnmarshalVariant(msg, &vsig); if (status != AJ_OK) { break; } status = AJ_UnmarshalArg(msg, &value); if (status != AJ_OK) { break; } onOptionalProperty(peerName, key, vsig, &value); } } if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(msg, &dict); } if (status == AJ_ERR_NO_MORE) { AJ_InfoPrintf(("About Data:\nAppId:'%s'\nAppName:'%s'\nDeviceId:'%s'\nDeviceName:'%s'\nManufacturer:'%s'\nModelNumber'%s'\nDefaultLanguage:'%s'\n", (appId[0] == '\0' ? "N/A" : appId), ((appName == NULL || appName[0] == '\0') ? "N/A" : appName), ((deviceId == NULL || deviceId[0] == '\0') ? "N/A" : deviceId), ((deviceName == NULL || deviceName[0] == '\0') ? "N/A" : deviceName), ((manufacturer == NULL || manufacturer[0] == '\0') ? "N/A" : manufacturer), ((modelNumber == NULL || modelNumber[0] == '\0') ? "N/A" : modelNumber), ((defaultLanguage == NULL || defaultLanguage[0] == '\0') ? "N/A" : defaultLanguage))); status = AJ_UnmarshalCloseContainer(msg, &array); if ((status == AJ_OK) && (onMandatoryProperties != NULL)) { onMandatoryProperties(peerName, appId, appName, deviceId, deviceName, manufacturer, modelNumber, defaultLanguage); } } return status; } static void handleMandatoryProps(const char* peerName, const char* appId, const char* appName, const char* deviceId, const char* deviceName, const char* manufacturer, const char* modelNumber, const char* defaultLanguage) { uint16_t i; if ((peerList != NULL) && (peerListLength > 0)) { for (i = 0; i < peerListLength; i++) { if (peerList[i].handleMandatoryProps != NULL) { peerList[i].handleMandatoryProps(peerName, appId, appName, deviceId, deviceName, manufacturer, modelNumber, defaultLanguage); } } } } static void handleOptionalProp(const char* peerName, const char* key, const char* sig, const AJ_Arg* value) { uint16_t i; if ((peerList != NULL) && (peerListLength > 0)) { for (i = 0; i < peerListLength; i++) { if (peerList[i].handleOptionalProperty != NULL) { peerList[i].handleOptionalProperty(peerName, key, sig, value); } } } } AJ_Status AJ_AboutHandleAnnounce(AJ_Message* announcement, uint16_t* outAboutVersion, uint16_t* outAboutPort, char* peerName, uint8_t* outRelevant) { AJ_Status status = AJ_OK; const char* objPath = "/"; uint16_t peerListCount = 0; AJ_AboutObjectDescription objDescs[AJ_MAX_NUM_OF_OBJ_DESC]; uint16_t objDescsCount = 0; uint16_t aboutVersion = 0; uint16_t aboutPort = 0; uint8_t relevant = FALSE; /** * Extract basic information from Announcement message */ status = AJ_UnmarshalArgs(announcement, "qq", &aboutVersion, &aboutPort); if (status != AJ_OK) { return status; } if (outAboutVersion != NULL) { *outAboutVersion = aboutVersion; } if (outAboutPort != NULL) { *outAboutPort = aboutPort; } if (outRelevant != NULL) { *outRelevant = relevant; } if (peerName != NULL) { strncpy(peerName, announcement->sender, AJ_MAX_NAME_SIZE); peerName[AJ_MAX_NAME_SIZE] = '\0'; } /** * If there are no registered peer descriptions to match then skip all processing of Announce message and return basic information */ if ((peerList == NULL) || (peerListLength == 0)) { return status; } /** * Unmarshal the object description section i.e. the objects with their paths and published interface names */ status = AJ_AboutUnmarshalObjectDescriptions(announcement, objDescs, &objDescsCount); if (status != AJ_OK) { return status; } /** * Match object descriptions against registered peer descriptions looking for implemented interfaces */ for (peerListCount = 0; peerListCount < peerListLength; peerListCount++) { const AJ_AboutPeerDescription* peerDesc = &peerList[peerListCount]; const char** ifaceNames = peerDesc->implementsInterfaces; if (ifaceNames != NULL) { uint8_t count; uint8_t found = 0; /** * Loop through peer interfaces */ for (count = 0; count < peerDesc->numberInterfaces; count++) { uint16_t i; /** * Loop through the object descriptions */ for (i = 0; i != objDescsCount; i++) { uint16_t j; AJ_AboutObjectDescription* currObjDesc = &objDescs[i]; if (peerDesc->handleObjectDescription != NULL) { peerDesc->handleObjectDescription(announcement->sender, currObjDesc); } /** * Loop through the interfaces */ for (j = 0; j != currObjDesc->interfacesCount; j++) { if (strcmp(currObjDesc->interfaces[j], ifaceNames[count]) == 0) { objPath = currObjDesc->path; found++; } } /** * Check if the current object contains ALL the interfaces and fire handle on the match */ if ((found == peerDesc->numberInterfaces) && (peerDesc->handleMatch != NULL)) { if (peerDesc->handleMatch(aboutVersion, aboutPort, announcement->sender, objPath) == FALSE) { goto NextPeerDescription; } found = 0; } } } /** * Check if ALL the interfaces where found on peer and fire handle on the match */ if ((found == peerDesc->numberInterfaces) && (peerDesc->handleMatch != NULL)) { /** * If peer description includes multiple interfaces on different objects or no interfaces return the root object path */ if (peerDesc->numberInterfaces != 1) { objPath = "/"; } peerDesc->handleMatch(aboutVersion, aboutPort, announcement->sender, objPath); } } else { /** * If no interface names criteria registered simply call the registered peer found handler with root object path. * The handler will be able to perform introspection using the given peerName if required. */ if (peerDesc->handleMatch != NULL) { peerDesc->handleMatch(aboutVersion, aboutPort, announcement->sender, objPath); } } NextPeerDescription: continue; } /** * Unmarshal the metadata section i.e. the property list */ status = AJ_AboutUnmarshalProps(announcement, handleMandatoryProps, handleOptionalProp); for (peerListCount = 0; peerListCount < peerListLength; peerListCount++) { const AJ_AboutPeerDescription* peerDesc = &peerList[peerListCount]; relevant |= peerDesc->handleIsRelevant(announcement->sender); } if (outRelevant != NULL) { *outRelevant = relevant; } return status; } #endif ajtcl-16.04/src/aj_ardp.c000066400000000000000000001432511271074662300151720ustar00rootroot00000000000000/** * @file ArdpProtocol is an implementation of the Reliable Datagram Protocol * (RDP) adapted to AllJoyn. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_ARDP #ifdef __cplusplus extern "C" { #endif #define AJ_MODULE ARDP #include #include #include #include #include #include #ifndef NDEBUG uint8_t dbgARDP = 0; #endif #define UDP_MTU 1472 #define ARDP_SYN_HEADER_SIZE 28 /* Maximum data payload in one ARDP segment */ #define ARDP_MAX_DLEN (UDP_SEGBMAX - (UDP_HEADER_SIZE + ARDP_HEADER_SIZE)) #define ARDP_FLAG_SYN 0x01 /**< Control flag. Request to open a connection. Must be separate segment. */ #define ARDP_FLAG_ACK 0x02 /**< Control flag. Acknowledge a segment. May accompany message */ #define ARDP_FLAG_EACK 0x04 /**< Control flag. Non-cumulative (extended) acknowledgement */ #define ARDP_FLAG_RST 0x08 /**< Control flag. Reset this connection. Must be separate segment. */ #define ARDP_FLAG_NUL 0x10 /**< Control flag. Null (zero-length) segment. Must have zero data length */ #define ARDP_FLAG_VER 0x40 /**< Control flag. Bits 6-7 of flags byte. Current version is (1) */ #define ARDP_FLAG_SDM 0x0001 /**< Sequenced delivery mode option. Indicates in-order sequence delivery is in force. */ #define ARDP_VERSION_BITS 0xC0 /* Bits 6-7 of FLAGS byte in ARDP segment header*/ /* Reserved TTL value to indicate that data associated with the message has expired */ #define ARDP_TTL_EXPIRED 0xffffffff /* Maximum allowed TTL value */ #define ARDP_TTL_MAX (ARDP_TTL_EXPIRED - 1) /* Maximum number of accumulated unacknowledged RCV segments */ #define ARDP_MAX_ACK_PENDING 2 /* Flag indicating that the buffer is occupied */ #define ARDP_BUFFER_IN_USE 0x01 /* Flag indicating that the buffer is delivered to the upper layer */ #define ARDP_BUFFER_DELIVERED 0x02 /* Minimum Roundtrip Time */ #define ARDP_MIN_RTO 100 /* Maximum Roundtrip Time */ #define ARDP_MAX_RTO 64000 /* Minimum Delayed ACK Timeout */ #define ARDP_MIN_DELAYED_ACK_TIMEOUT 10 /* ARDP backpressure relief retry interval */ #define ARDP_BACKPRESSURE_INTERVAL 100 /* ARDP backpressure relief maximum number of retries */ #define ARDP_MAX_BACKPRESSURE_RETRIES ((UDP_LINK_TIMEOUT) / (ARDP_BACKPRESSURE_INTERVAL)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define ABS(a) ((a) >= 0 ? (a) : -(a)) /* Marshal/Unmarshal ARDP header offsets */ #define FLAGS_OFFSET 0 #define HLEN_OFFSET 1 #define SRC_OFFSET 2 #define DST_OFFSET 4 #define DLEN_OFFSET 6 #define SEQ_OFFSET 8 #define ACK_OFFSET 12 #define TTL_OFFSET 16 #define LCS_OFFSET 20 #define ACKNXT_OFFSET 24 #define SOM_OFFSET 28 #define FCNT_OFFSET 32 #define RSRV_OFFSET 34 /* Additional Marshal/Unmarshal ARDP SYN header offsets */ #define SEGMAX_OFFSET 16 #define SEGBMAX_OFFSET 18 #define DACKT_OFFSET 20 #define OPTIONS_OFFSET 24 #define SYN_RSRV_OFFSET 26 /* Structure encapsulating timer to to handle timeouts */ struct ArdpTimer { AJ_Time tStart; uint32_t delta; uint32_t retry; }; typedef struct AJ_ARDP_RCV_BUFFER { uint32_t seq; /* Sequence number */ uint8_t data[UDP_SEGBMAX - ARDP_HEADER_SIZE]; /* Data payload */ struct AJ_ARDP_RCV_BUFFER* next; /* Pointer to the next buffer */ uint32_t som; /* Sequence number of first segment in fragmented message */ uint16_t dataLen; /* Data payload size */ uint16_t fcnt; /* Number of segments comprising fragmented message, doubles as "in use" indicator */ } ArdpRBuf; /* Structure encapsulating the information about segments on SEND side */ typedef struct AJ_ARDP_SEND_BUF { uint32_t data[UDP_SEGBMAX >> 2]; AJ_Time tStart; struct ArdpTimer timer; /* Data retransmit timer */ struct AJ_ARDP_SEND_BUF* next; uint16_t dataLen; uint8_t retransmits; uint8_t inFlight; } ArdpSBuf; /** * Structure encapsulating the send-related quantities. The stuff we manage on * the local side of the connection and which we may send to THEM. */ struct ArdpSnd { uint32_t NXT; /* The sequence number of the next segment that is to be sent */ uint32_t UNA; /* The sequence number of the oldest unacknowledged segment */ uint32_t ISS; /* The initial send sequence number. The number that was sent in the SYN segment */ uint32_t LCS; /* Sequence number of last consumed segment (we get this form them) */ uint32_t DACKT; /* Delayed ACK timeout from the other side */ uint32_t SEGMAX; /* The maximum number of unacknowledged segments that can be sent */ ArdpSBuf buf[UDP_SEGMAX]; /* Array holding in-flight sent buffers. */ uint32_t msgTTL; /* TTL associated with the most recent outbound message */ uint32_t msgLenTotal; /* Length of the most recent outbound message */ uint32_t msgLenSent; /* Cumulative length of all the segments that has been sent so far for the most recent outbound message */ uint32_t msgSOM; /* Sequence number of the first segment in the most recent outbound message */ uint8_t pending; /* Number of unacknowledged sent buffers */ uint8_t newMsg; /* Indicates that the next call to ARDP_Send() will carry new AllJoyn message */ }; /** * Structure encapsulating the receive-related quantities. The stuff managed on * the remote/foreign side, copies of which we may get from THEM. */ struct ArdpRcv { uint32_t CUR; /* The sequence number of the last segment received correctly and in sequence */ uint32_t LCS; /* LCS - Last "in-order" consumed segment.*/ ArdpRBuf buf[UDP_SEGMAX]; /* Array holding received buffers not consumed by the app */ uint8_t pending; /* Number of unacknowledged received buffers */ }; /** * Information encapsulating the various interesting tidbits we get from the * other side when we receive a datagram. Some of the names are chosen so that they * are similar to the quantities found in RFC-908 when used. */ struct ArdpSeg { uint32_t SEQ; /* The sequence number in the segment currently being processed. */ uint32_t ACK; /* The acknowledgement number in the segment currently being processed. */ uint32_t LCS; /* The last "in-sequence" consumed segment */ uint32_t ACKNXT; /* The first valid SND segment, TTL accounting */ uint32_t SOM; /* Start sequence number for fragmented message */ uint32_t TTL; /* Time-to-live */ uint16_t FCNT; /* Number of fragments comprising a message */ uint16_t DLEN; /* The length of the data that came in with the current segment. */ uint8_t FLG; /* The flags in the header of the segment currently being processed. */ uint8_t HLEN; /* The header length */ }; /** * The states through which our main state machine transitions. */ typedef enum { CLOSED = 0, /* No connection exists and no connection record available */ SYN_SENT, /* Entered after processing an active open request. SYN is sent and ARDP waits here for ACK of open request. */ OPEN, /* Successful echange of state information happened,. Data may be sent and received. */ CLOSE_WAIT /* Disconnecting. Waiting for the outbound data to be ACKed */ } ArdpState; /** * The format of a SYN segment on the wire. */ struct AJ_ARDP_Syn_Hdr { uint8_t flags; /* See Control flag definitions above */ uint8_t hlen; /* Length of the header in units of two octets (number of uint16_t) */ uint16_t src; /* Used to distinguish between multiple connections on the local side. */ uint16_t dst; /* Used to distinguish between multiple connections on the foreign side. */ uint16_t dlen; /* The length of the data in the current segment. Does not include the header size. */ uint32_t seq; /* The sequence number of the current segment. */ uint32_t ack; /* The number of the segment that the sender of this segment last received correctly and in sequence. */ uint16_t segmax; /* The maximum number of outstanding segments the other side can send without acknowledgement. */ uint16_t segbmax; /* The maximum segment size we are willing to receive. (the RBUF.MAX specified by the user calling open). */ uint32_t dackt; /* Receiver's delayed ACK timeout. Used in TTL estimate prior to sending a message. */ uint16_t options; /* Options for the connection. Always Sequenced Delivery Mode (SDM). */ }; /** * A connection record describing each "connection." This acts as a containter * to hold all of the interesting information about a reliable link between * hosts. */ struct ArdpConnection { AJ_NetSocket* netSock; /* I/O Buffer management socket */ ArdpState state; /* The current sate of the connection */ struct ArdpSnd snd; /* Send-side related state information */ struct ArdpRcv rcv; /* Receive-side related state information */ struct ArdpTimer connectTimer; /* Connect/Disconnect timer */ struct ArdpTimer probeTimer; /* Probe (link timeout) timer */ struct ArdpTimer ackTimer; /* Delayed ACK timer */ struct ArdpTimer persistTimer; /* Persist (frozen window) timer */ void* context; /* Platform independent UDP socket equivalent */ uint16_t local; /* ARDP local port for this connection */ uint16_t foreign; /* ARDP foreign port for this connection */ uint32_t rttMean; /* Smoothed RTT value */ uint32_t rttMeanVar; /* RTT variance */ uint32_t backoff; /* Backoff factor accounting for retransmits on connection, resets to 1 when receive "good ack" */ uint32_t rttMeanUnit; /* Smoothed RTT value per UDP MTU */ uint8_t rttInit; /* Flag indicating that the first RTT was measured and SRTT calculation applies */ uint8_t confirm; /* Flag to indicate that progress happened, do not send ARP re-probe */ }; static struct ArdpConnection* conn = NULL; /* * Important!!! All our numbers are within window size, the calculation below will hold. * If necessary, can add check that delta between the numbers does not exceed half-range. */ #define SEQ32_LT(a, b) ((int32_t)((uint32_t)(a) - (uint32_t)(b)) < 0) #define SEQ32_LET(a, b) (((int32_t)((uint32_t)(a) - (uint32_t)(b)) < 0) || ((a) == (b))) /** * Inside window calculation. * Returns TRUE if p is in range [beg, beg+sz) * This function properly accounts for possible wrap-around in [beg, beg+sz) region. */ #define IN_RANGE(tp, beg, sz, p) ((((tp) ((beg) + (sz)) > (beg)) && ((p) >= (beg)) && ((p) < (tp) ((beg) + (sz)))) || \ (((tp) ((beg) + (sz)) < (beg)) && !(((p) < (beg)) && (p) >= (tp) ((beg) + (sz))))) /* Housekeeping for data (inside ARDP rBuf) that have been received and potentially not consumed */ static struct { uint8_t* readBuf; /* Pointer to current unconsumed data */ uint16_t dataLen; /* How many bytes are left to read */ ArdpRBuf* rxContext; /* Pointer to ARDP rBuf from where the data are being currently consumed */ } UDP_Recv_State; static ReceiveFunction recvFunction; static SendFunction sendFunction; /************** * End of definitions */ void AJ_ARDP_InitFunctions(ReceiveFunction rcvFunc, SendFunction sndFunc) { recvFunction = rcvFunc; sendFunction = sndFunc; } static AJ_Status InitConnection() { uint32_t rand32; uint32_t i; conn = (struct ArdpConnection*) AJ_Malloc(sizeof(struct ArdpConnection)); if (conn == NULL) { return AJ_ERR_RESOURCES; } memset(conn, 0, sizeof(struct ArdpConnection)); AJ_RandBytes((uint8_t*) &rand32, sizeof(uint32_t)); conn->local = (rand32 % 65534) + 1; /* Allocate an "ephemeral" source port */ /* Initialize the sender side of the connection */ AJ_RandBytes((uint8_t*) &conn->snd.ISS, sizeof(conn->snd.ISS)); conn->snd.NXT = conn->snd.ISS + 1; /* The sequence number of the next segment to be sent over this connection */ conn->snd.UNA = conn->snd.ISS; /* The oldest unacknowledged segment is the ISS */ conn->snd.LCS = conn->snd.ISS; /* The most recently consumed segment (we keep this in sync with the other side) */ for (i = 0; i < UDP_SEGMAX; i++) { conn->snd.buf[i].next = &conn->snd.buf[(i + 1) % UDP_SEGMAX]; } for (i = 0; i < UDP_SEGMAX; i++) { conn->rcv.buf[i].next = &conn->rcv.buf[(i + 1) % UDP_SEGMAX]; } conn->rttInit = FALSE; conn->rttMean = UDP_INITIAL_DATA_TIMEOUT; conn->rttMeanUnit = UDP_INITIAL_DATA_TIMEOUT; conn->rttMeanVar = 0; conn->backoff = 0; return AJ_OK; } static void MarshalHeader(uint32_t* buf32, uint8_t flags, uint16_t dlen, uint32_t ttl, uint32_t som, uint16_t fcnt) { uint8_t* txbuf = (uint8_t*) (buf32); *(txbuf + FLAGS_OFFSET) = flags; *(txbuf + HLEN_OFFSET) = (uint8_t)(ARDP_HEADER_SIZE >> 1); *((uint16_t*) (txbuf + SRC_OFFSET)) = htons(conn->local); *((uint16_t*) (txbuf + DST_OFFSET)) = htons(conn->foreign); *((uint16_t*) (txbuf + DLEN_OFFSET)) = htons(dlen); *((uint32_t*) (txbuf + SEQ_OFFSET)) = htonl(conn->snd.NXT); *((uint32_t*) (txbuf + ACK_OFFSET)) = htonl(conn->rcv.CUR); *((uint32_t*) (txbuf + TTL_OFFSET)) = htonl(ttl); *((uint32_t*) (txbuf + LCS_OFFSET)) = htonl(conn->rcv.LCS); *((uint32_t*) (txbuf + ACKNXT_OFFSET)) = htonl(conn->snd.UNA); *((uint32_t*) (txbuf + SOM_OFFSET)) = htonl(som); *((uint16_t*) (txbuf + FCNT_OFFSET)) = htons(fcnt); *((uint16_t*) (txbuf + RSRV_OFFSET)) = 0; } static AJ_Status SendHeader(uint8_t flags) { uint32_t buf32[ARDP_HEADER_SIZE >> 2]; size_t sent; AJ_Status status; AJ_InfoPrintf(("SendHeader(flags=0x%02x, seq=%u, ack=%u, lcs=%u)\n", flags, conn->snd.NXT, conn->rcv.CUR, conn->rcv.LCS)); /* Marshal the header structure into a byte buffer */ MarshalHeader(buf32, flags, 0, ARDP_TTL_INFINITE, 0, 0); AJ_InfoPrintf(("SendHeader: cancel ackTimer\n")); conn->ackTimer.retry = 0; conn->rcv.pending = 0; status = (*sendFunction)(conn->context, (uint8_t*) &buf32, ARDP_HEADER_SIZE, &sent, conn->confirm); if (status == AJ_OK) { conn->confirm = FALSE; } return status; } static AJ_Status SendSyn(uint16_t dataLen) { size_t sent; uint8_t* txbuf = (uint8_t*) &(conn->snd.buf[0].data[0]); /* Marshal SYN header */ *(txbuf + FLAGS_OFFSET) = ARDP_FLAG_SYN | ARDP_FLAG_VER; *(txbuf + HLEN_OFFSET) = ARDP_SYN_HEADER_SIZE >> 1; *((uint16_t*) (txbuf + SRC_OFFSET)) = htons(conn->local); *((uint16_t*) (txbuf + DST_OFFSET)) = 0; /* optional, can be removed to reduce code size */ *((uint16_t*) (txbuf + DLEN_OFFSET)) = htons(dataLen); *((uint32_t*) (txbuf + SEQ_OFFSET)) = htonl(conn->snd.ISS); *((uint32_t*) (txbuf + ACK_OFFSET)) = 0; /* optional , can be removed to reduce code size*/ *((uint16_t*) (txbuf + SEGMAX_OFFSET)) = htons(UDP_SEGMAX); *((uint16_t*) (txbuf + SEGBMAX_OFFSET)) = htons(UDP_SEGBMAX); *((uint32_t*) (txbuf + DACKT_OFFSET)) = htonl(UDP_DELAYED_ACK_TIMEOUT); *((uint16_t*) (txbuf + OPTIONS_OFFSET)) = htons(ARDP_FLAG_SIMPLE_MODE | ARDP_FLAG_SDM); *((uint16_t*) (txbuf + SYN_RSRV_OFFSET)) = 0; return (*sendFunction)(conn->context, (uint8_t*) &conn->snd.buf[0].data[0], ARDP_SYN_HEADER_SIZE + dataLen, &sent, FALSE); } static uint8_t IsDataRetransmitScheduled() { if (((conn->snd.UNA + 1) != conn->snd.NXT) && (conn->snd.UNA != conn->snd.NXT)) { return TRUE; } return FALSE; } static void InitTimer(struct ArdpTimer* timer, uint32_t delta, uint8_t retry) { AJ_InitTimer(&timer->tStart); timer->delta = delta; timer->retry = retry; } static AJ_Status ConnectTimerHandler() { AJ_Status status; AJ_InfoPrintf(("ConnectTimerHandler: retries left %d\n", conn->connectTimer.retry)); if (conn->connectTimer.retry > 1) { size_t sent; uint16_t len = conn->snd.buf[0].dataLen + ARDP_SYN_HEADER_SIZE; AJ_InfoPrintf(("ConnectTimerHandler: send %d bytes\n", len)); status = (*sendFunction)(conn->context, (uint8_t*) conn->snd.buf[0].data, len, &sent, FALSE); if (status == AJ_ERR_WOULD_BLOCK) { status = AJ_OK; } conn->connectTimer.retry--; } else { status = AJ_ERR_TIMEOUT; } if (status != AJ_OK) { conn->state = CLOSED; conn->connectTimer.retry = 0; AJ_ErrPrintf(("ConnectTimerHandler(): %s\n", AJ_StatusText(status))); AJ_Free(conn); conn = NULL; return AJ_ERR_CONNECT; } else { return AJ_OK; } } static uint32_t GetDataTimeout() { uint32_t timeout = UDP_TOTAL_DATA_RETRY_TIMEOUT; if (conn->rttInit) { timeout = MAX(timeout, (UDP_SEGMAX * UDP_SEGBMAX * (conn->rttMean >> 1)) / UDP_MTU); } return timeout; } static uint32_t GetRTO() { /* RTO = (rttMean + (4 * rttMeanVar)) << backoff */ uint32_t ms = (MAX((uint32_t)ARDP_MIN_RTO, conn->rttMean + (4 * conn->rttMeanVar))) << conn->backoff; AJ_InfoPrintf(("GetRTO(): rto=%u RTO = %u)\n", ms, MIN(ms, (uint32_t)ARDP_MAX_RTO))); return MIN(MAX(ms, conn->snd.DACKT), (uint32_t)ARDP_MAX_RTO); } static AJ_Status DataTimerHandler(ArdpSBuf* sBuf) { AJ_Status status; struct ArdpTimer* timer = &sBuf->timer; uint32_t msElapsed = AJ_GetElapsedTime(&sBuf->tStart, FALSE); uint32_t timeout = GetDataTimeout(); ArdpSBuf* startBuf = sBuf; sBuf->retransmits++; do { #ifndef NDEBUG uint32_t seq = ntohl(*(uint32_t*)((uint8_t*)sBuf->data + SEQ_OFFSET)); #endif if ((msElapsed >= timeout) && (timer->retry > UDP_MIN_DATA_RETRIES)) { AJ_ErrPrintf(("DataTimerHandler(): hit timeout for %u\n", seq)); status = AJ_ERR_TIMEOUT; } else { size_t sent; uint8_t* txbuf = (uint8_t*) sBuf->data; uint16_t len = sBuf->dataLen + ARDP_HEADER_SIZE; /* Currently, we do not check TTL for in-flight SND packets */ *((uint32_t*) (txbuf + ACK_OFFSET)) = htonl(conn->rcv.CUR); *((uint32_t*) (txbuf + LCS_OFFSET)) = htonl(conn->rcv.LCS); *((uint32_t*) (txbuf + ACKNXT_OFFSET)) = htonl(conn->snd.UNA); AJ_InfoPrintf(("DataTimerHandler: send %d bytes (seq %u, ack %u)\n", len, seq, conn->rcv.CUR)); status = (*sendFunction)(conn->context, (uint8_t*) sBuf->data, len, &sent, conn->confirm); AJ_InitTimer(&sBuf->timer.tStart); if (status == AJ_OK) { conn->backoff = MAX(conn->backoff, timer->retry); if (conn->rttInit) { timer->delta = GetRTO(); } else { timer->delta = MIN(UDP_INITIAL_DATA_TIMEOUT << conn->backoff, (uint32_t)ARDP_MAX_RTO); } AJ_InfoPrintf(("DataTimerHandler: backoff %u, delta %u\n", conn->backoff, timer->delta)); timer->retry++; AJ_InfoPrintf(("DataTimerHandler: cancel ackTimer\n")); conn->ackTimer.retry = 0; conn->rcv.pending = 0; conn->confirm = FALSE; } else { AJ_ErrPrintf(("DataTimerHandler():Write to Socket went bad")); } } sBuf = sBuf->next; } while (status == AJ_OK && (sBuf->timer.retry != 0) && (sBuf != startBuf)); /* Here "retry" check equates checking for "in flight" */ return status; } static AJ_Status CheckDataTimers() { uint32_t idx; /* Check data retransmit timer */ idx = conn->snd.UNA % UDP_SEGMAX; if (conn->snd.buf[idx].timer.retry != 0 && AJ_GetElapsedTime(&conn->snd.buf[idx].timer.tStart, TRUE) >= conn->snd.buf[idx].timer.delta) { AJ_InfoPrintf(("CheckDataTimers: Fire data timer\n")); return DataTimerHandler(&conn->snd.buf[idx]); } return AJ_OK; } static AJ_Status CheckTimers() { AJ_Status status = AJ_OK; uint32_t delta; /* * Check connection timer. This timer is alive only when the connection is being established. * No other timers should be active on the connection. */ if (conn->connectTimer.retry != 0) { if (AJ_GetElapsedTime(&conn->connectTimer.tStart, TRUE) >= conn->connectTimer.delta) { AJ_InfoPrintf(("CheckTimers: Fire connection timer\n")); return ConnectTimerHandler(); } return AJ_OK; } /* Check probe timer, it's always turned on */ delta = AJ_GetElapsedTime(&conn->probeTimer.tStart, TRUE); if (delta >= conn->probeTimer.delta) { if (conn->probeTimer.retry == 0) { AJ_ErrPrintf(("CheckTimers: link timeout\n")); return AJ_ERR_ARDP_PROBE_TIMEOUT; } AJ_InfoPrintf(("CheckTimers: Fire probe timer\n")); status = SendHeader(ARDP_FLAG_ACK | ARDP_FLAG_VER | ARDP_FLAG_NUL); AJ_InitTimer(&conn->probeTimer.tStart); conn->probeTimer.retry--; if (IsDataRetransmitScheduled() == FALSE) { conn->rttInit = FALSE; } } status = CheckDataTimers(); /* Check delayed ACK timer */ delta = AJ_GetElapsedTime(&conn->ackTimer.tStart, TRUE); if ((conn->ackTimer.retry != 0) && ((delta >= conn->ackTimer.delta) || (conn->rcv.pending >= ARDP_MAX_ACK_PENDING))) { AJ_InfoPrintf(("CheckTimers: Fire ACK timer (elapsed %u vs %u)\n", delta, conn->ackTimer.delta)); status = SendHeader(ARDP_FLAG_ACK | ARDP_FLAG_VER); } return status; } static AJ_Status UnmarshalSynSegment(uint8_t* buf, struct ArdpSeg* seg) { uint16_t segmax; uint16_t segbmax; conn->foreign = ntohs(*((uint16_t*)(buf + SRC_OFFSET))); /* The source ARDP port */ conn->snd.DACKT = ntohl(*((uint32_t*)(buf + DACKT_OFFSET))); /* Delayed ACK timeout from the other side. */ segmax = ntohs(*((uint16_t*)(buf + SEGMAX_OFFSET))); /* Max number of unacknowledged packets other side can buffer */ segbmax = ntohs(*((uint16_t*)(buf + SEGBMAX_OFFSET))); /* Max size segment the other side can handle */ if ((segmax < UDP_SEGMAX) || (segbmax < UDP_SEGBMAX)) { AJ_WarnPrintf(("UnmarshalSynSegment: unacceptable segmax=%d, segbmax=%d\n", segmax, segbmax)); return AJ_ERR_RANGE; } conn->snd.SEGMAX = segmax; AJ_InfoPrintf(("UnmarshalSynSegment: segmax=%d, segbmax=%d\n", segmax, segbmax)); conn->rcv.CUR = seg->SEQ; conn->rcv.LCS = seg->SEQ; return AJ_OK; } static AJ_Status RecvValidateSegment(uint8_t* rxbuf, uint16_t len, struct ArdpSeg* seg) { uint16_t hdrSz; AJ_InfoPrintf(("Receive: rxbuf=%p, len=%u)\n", rxbuf, len)); seg->FLG = rxbuf[FLAGS_OFFSET]; /* The flags of the current segment */ seg->HLEN = rxbuf[HLEN_OFFSET]; /* The header len */ if (seg->FLG & ARDP_FLAG_RST) { /* This is a disconnect from the remote, no checks are needed */ AJ_WarnPrintf(("Receive: Remote disconnect RST\n")); AJ_Free(conn); conn = NULL; return AJ_ERR_ARDP_REMOTE_CONNECTION_RESET; } seg->DLEN = ntohs(*((uint16_t*)(rxbuf + DLEN_OFFSET))); /* The data payload size */ hdrSz = (seg->FLG & ARDP_FLAG_SYN) ? ARDP_SYN_HEADER_SIZE : ARDP_HEADER_SIZE; /* Perform length validation checks */ if (((seg->HLEN * 2) < hdrSz) || (len < hdrSz) || (seg->DLEN + (seg->HLEN * 2)) != len) { AJ_ErrPrintf(("Receive: length check failed len = %u, seg->hlen = %u, seg->dlen = %u\n", len, (seg->HLEN * 2), seg->DLEN)); return AJ_ERR_INVALID; } seg->SEQ = ntohl(*((uint32_t*)(rxbuf + SEQ_OFFSET))); /* The send sequence of the current segment */ seg->ACK = ntohl(*((uint32_t*)(rxbuf + ACK_OFFSET))); /* The cumulative acknowledgement number to our sends */ if (seg->FLG & ARDP_FLAG_SYN) { return AJ_OK; } seg->LCS = ntohl(*((uint32_t*)(rxbuf + LCS_OFFSET))); /* The last consumed segment on receiver side (them) */ seg->ACKNXT = ntohl(*((uint32_t*)(rxbuf + ACKNXT_OFFSET))); /* The first valid segment sender wants to be acknowledged */ AJ_InfoPrintf(("Receive() seq = %u, ack = %u, lcs = %u, acknxt = %u\n", seg->SEQ, seg->ACK, seg->LCS, seg->ACKNXT)); seg->TTL = ntohl(*((uint32_t*)(rxbuf + TTL_OFFSET))); /* TTL associated with this segment */ seg->SOM = ntohl(*((uint32_t*)(rxbuf + SOM_OFFSET))); /* Sequence number of the first fragment in message */ seg->FCNT = ntohs(*((uint16_t*)(rxbuf + FCNT_OFFSET))); /* Number of segments comprising fragmented message */ /* Perform sequence validation checks */ if (SEQ32_LT(conn->snd.NXT, seg->ACK)) { AJ_ErrPrintf(("Receive: ack %u ahead of SND>NXT %u\n", seg->ACK, conn->snd.NXT)); return AJ_ERR_INVALID; } if (SEQ32_LT(seg->ACK, seg->LCS)) { AJ_ErrPrintf(("Receive: lcs %u and ack %u out of order\n", seg->LCS, seg->ACK)); return AJ_ERR_INVALID; } /* * SEQ and ACKNXT must fall within receive window. */ if ((SEQ32_LT(seg->SEQ, seg->ACKNXT)) || ((seg->DLEN != 0) && ((seg->SEQ - seg->ACKNXT) >= UDP_SEGMAX))) { AJ_ErrPrintf(("Receive: incorrect sequence numbers seg->seq = %u, seg->acknxt = %u\n", seg->SEQ, seg->ACKNXT)); return AJ_ERR_INVALID; } /* Additional checks for invalid payload values */ if (seg->DLEN != 0) { if ((seg->FCNT == 0) || ((seg->SEQ - seg->SOM) >= seg->FCNT)) { AJ_ErrPrintf(("Receive: incorrect data segment seq = %u, som = %u, fcnt = %u\n", seg->SEQ, seg->SOM, seg->FCNT)); return AJ_ERR_INVALID; } } return AJ_OK; } /* * error = measuredRTT - meanRTT * new meanRTT = 7/8 * meanRTT + 1/8 * error * if (measuredRTT >= (meanRTT - meanVAR)) * new meanVar = 3/4 * meanVar + 1/4 * |error| * else * new meanVar = 31/32 * meanVar + 1/32 * |error| * * Since ARDP segments can have varying length, maintain additional * mean RTT calculation of UDP MTU unit that will be used in message TTL estimate. */ static void AdjustRTT(ArdpSBuf* sBuf) { uint16_t units = (sBuf->dataLen + ARDP_HEADER_SIZE + UDP_MTU - 1) / UDP_MTU; uint32_t rtt = AJ_GetElapsedTime(&sBuf->timer.tStart, TRUE); uint32_t rttUnit = rtt / units; int32_t err; if (!conn->rttInit) { conn->rttMean = rtt; conn->rttMeanVar = rtt >> 1; conn->rttInit = TRUE; } err = rtt - conn->rttMean; AJ_InfoPrintf(("AdjustRtt: mean = %u, var =%u, rtt = %u, error = %d\n", conn->rttMean, conn->rttMeanVar, rtt, err)); conn->rttMean = (7 * conn->rttMean + rtt) >> 3; if ((rtt + conn->rttMeanVar) >= conn->rttMean) { conn->rttMeanVar = (conn->rttMeanVar * 3 + ABS(err)) >> 2; } else { conn->rttMeanVar = (conn->rttMeanVar * 31 + ABS(err)) >> 5; } conn->rttMeanUnit = (7 * conn->rttMeanUnit + rttUnit) >> 3; conn->backoff = 0; AJ_InfoPrintf(("AdjustRtt: New mean = %u, var =%u\n", conn->rttMean, conn->rttMeanVar)); } static void UpdateSndSegments(uint32_t ack) { uint16_t idx = ack % UDP_SEGMAX; ArdpSBuf* sBuf = &conn->snd.buf[idx]; uint32_t i; /* Nothing to clean up */ if (conn->snd.pending == 0) { return; } /* * Count only "good" roundrips to ajust RTT values. */ if ((sBuf->retransmits == 0) && (sBuf->timer.retry != 0)) { AdjustRTT(sBuf); } sBuf = &conn->snd.buf[0]; /* Cycle through all the buffers */ for (i = 0; i < UDP_SEGMAX; i++) { uint32_t seq = ntohl(*(uint32_t*)((uint8_t*)(sBuf->data) + SEQ_OFFSET)); if (SEQ32_LET(seq, ack) && (sBuf->inFlight != 0)) { /* If the remote acknowledged the segment, stop retransmit attempts. */ AJ_InfoPrintf(("UpdateSndSegments(): cancel retransmit for %u\n", seq)); sBuf->timer.retry = 0; sBuf->dataLen = 0; sBuf->inFlight = 0; sBuf->retransmits = 0; conn->snd.pending--; } if (conn->snd.pending == 0) { break; } sBuf = sBuf->next; } } static void FlushExpiredRcvMessages(uint32_t seq, uint32_t ackNXT) { uint32_t idx = conn->rcv.CUR % UDP_SEGMAX; ArdpRBuf* rBuf = &conn->rcv.buf[idx]; AJ_InfoPrintf(("FlushExpiredRcvMessages: seq = %u, expected %u got %u\n", seq, conn->rcv.CUR + 1, ackNXT)); while (SEQ32_LT(conn->rcv.CUR + 1, ackNXT)) { rBuf->fcnt = 0; rBuf->dataLen = 0; rBuf = rBuf->next; conn->rcv.CUR++; } /* * If the next rBuf contains valid data, update internal ARDP Rx context * to point to the payload. Otherwise, there are no pending received data, * reset Rx context to NULL. */ if (rBuf->dataLen != 0) { UDP_Recv_State.readBuf = rBuf->data; UDP_Recv_State.dataLen = rBuf->dataLen; UDP_Recv_State.rxContext = (void*) rBuf; } else { UDP_Recv_State.rxContext = NULL; } } static void AddRcvBuffer(struct ArdpSeg* seg, uint8_t* rxBuf, uint16_t dataOffset) { uint32_t idx = seg->SEQ % UDP_SEGMAX; AJ_InfoPrintf(("AddRcvBuffer: seq=%u\n", seg->SEQ)); AJ_ASSERT(conn->rcv.buf[idx].fcnt == 0); conn->rcv.buf[idx].seq = seg->SEQ; conn->rcv.buf[idx].som = seg->SOM; conn->rcv.buf[idx].fcnt = seg->FCNT; conn->rcv.buf[idx].dataLen = seg->DLEN; memcpy(conn->rcv.buf[idx].data, rxBuf + dataOffset, seg->DLEN); if (UDP_Recv_State.rxContext == NULL) { UDP_Recv_State.readBuf = conn->rcv.buf[idx].data; UDP_Recv_State.dataLen = seg->DLEN; UDP_Recv_State.rxContext = (void*) &conn->rcv.buf[idx]; } } static AJ_Status ArdpMachine(struct ArdpSeg* seg, uint8_t* rxBuf, uint16_t len) { AJ_Status status = AJ_OK; AJ_InfoPrintf(("ArdpMachine(seg=%p, buf=%p, len=%d)\n", seg, rxBuf, len)); switch (conn->state) { case SYN_SENT: { AJ_InfoPrintf(("ArdpMachine(): conn->state = SYN_SENT\n")); if (seg->FLG & ARDP_FLAG_SYN) { AJ_InfoPrintf(("ArdpMachine(): SYN_SENT: SYN received\n")); status = UnmarshalSynSegment(rxBuf, seg); if (status == AJ_OK) { if ((seg->FLG & ARDP_VERSION_BITS) != ARDP_FLAG_VER) { AJ_WarnPrintf(("ArdpMachine(): SYN_SENT: Unsupported protocol version 0x%x\n", seg->FLG & ARDP_VERSION_BITS)); status = AJ_ERR_ARDP_VERSION_NOT_SUPPORTED; } else if (!(seg->FLG & ARDP_FLAG_ACK) || (seg->ACK != conn->snd.ISS)) { AJ_WarnPrintf(("ArdpMachine(): SYN_SENT: does not ACK ISS\n")); status = AJ_ERR_INVALID; } else { AJ_InfoPrintf(("ArdpMachine(): SYN_SENT: SYN | ACK received. state -> OPEN\n")); conn->snd.UNA = seg->ACK + 1; conn->state = OPEN; conn->snd.buf[0].timer.retry = 0; conn->snd.buf[0].dataLen = 0; conn->snd.buf[0].inFlight = 0; /* Initialize and kick off link timeout timer */ InitTimer(&conn->probeTimer, UDP_LINK_TIMEOUT / UDP_KEEPALIVE_RETRIES, UDP_KEEPALIVE_RETRIES); conn->confirm = TRUE; /* * */ status = SendHeader(ARDP_FLAG_ACK | ARDP_FLAG_VER); if (status == AJ_OK) { AddRcvBuffer(seg, rxBuf, ARDP_SYN_HEADER_SIZE); } } } /* Stop connect retry timer */ conn->connectTimer.retry = 0; } break; } case CLOSE_WAIT: case OPEN: { AJ_InfoPrintf(("ArdpMachine(): conn->state = %s\n", (conn->state == CLOSE_WAIT) ? "CLOSE_WAIT" : "OPEN")); if (seg->FLG & ARDP_FLAG_SYN) { /* Ignore */ return AJ_OK; } if (seg->FLG & ARDP_FLAG_ACK) { AJ_InfoPrintf(("ArdpMachine(): Got ACK %u LCS %u ACKNXT %u\n", seg->ACK, seg->LCS, seg->ACKNXT)); if (IN_RANGE(uint32_t, conn->snd.UNA, ((conn->snd.NXT - conn->snd.UNA) + 1), seg->ACK) == TRUE) { conn->snd.UNA = seg->ACK + 1; UpdateSndSegments(seg->ACK); } conn->snd.LCS = seg->LCS; if (conn->state == CLOSE_WAIT) { if (conn->snd.pending != 0) { return AJ_ERR_ARDP_DISCONNECTING; } else { return AJ_ERR_ARDP_DISCONNECTED; } } conn->confirm = TRUE; } AJ_InfoPrintf(("ArdpMachine(): OPEN: seq = %u, we are waiting for %u, they wait for %u\n", seg->SEQ, conn->rcv.CUR + 1, seg->ACKNXT)); if (SEQ32_LT(conn->rcv.CUR + 1, seg->ACKNXT)) { AJ_InfoPrintf(("ArdpMachine(): OPEN: seq = %u, expected %u got %u\n", seg->SEQ, conn->rcv.CUR + 1, seg->ACKNXT)); FlushExpiredRcvMessages(seg->SEQ, seg->ACKNXT); status = AJ_ERR_ARDP_RECV_EXPIRED; } /* If we got NUL segment, send ACK without delay */ if (seg->FLG & ARDP_FLAG_NUL) { SendHeader(ARDP_FLAG_ACK | ARDP_FLAG_VER); } else if (seg->DLEN) { if (conn->ackTimer.retry == 0) { InitTimer(&conn->ackTimer, UDP_DELAYED_ACK_TIMEOUT, 1); } conn->rcv.pending++; /* Update with new data */ if (SEQ32_LET((conn->rcv.CUR + 1), seg->SEQ)) { AddRcvBuffer(seg, rxBuf, ARDP_HEADER_SIZE); conn->rcv.CUR = seg->SEQ; AJ_InfoPrintf(("ArdpMachine(): OPEN: received data with seq %u, som %u, fcnt %u\n", seg->SEQ, seg->SOM, seg->FCNT)); } else { AJ_InfoPrintf(("ArdpMachine(): OPEN: duplicate data with seq %u (cur=%u)\n", seg->SEQ, conn->rcv.CUR)); } } InitTimer(&conn->probeTimer, UDP_LINK_TIMEOUT / UDP_KEEPALIVE_RETRIES, UDP_KEEPALIVE_RETRIES); break; } default: status = AJ_ERR_DISALLOWED; AJ_ASSERT(0 && "ArdpMachine(): unexpected conn->state %d"); break; } AJ_InfoPrintf(("ArdpMachine(): %s(0x%x)\n", AJ_StatusText(status), status)); return status; } static AJ_Status ARDP_Recv(uint8_t* rxBuf, uint16_t len) { AJ_Status status = AJ_OK; struct ArdpSeg seg; memset(&seg, 0, sizeof(struct ArdpSeg)); status = RecvValidateSegment(rxBuf, len, &seg); if (status == AJ_OK) { status = ArdpMachine(&seg, rxBuf, len); } if (status != AJ_OK && status != AJ_ERR_ARDP_RECV_EXPIRED) { AJ_ErrPrintf(("ARDP_Recv(): returned %s (0x%x)\n", AJ_StatusText(status), status)); } return status; } static void RecvReady(void* rxContext) { ArdpRBuf* rBuf = (ArdpRBuf*) rxContext; AJ_InfoPrintf(("RecvReady: buf=%p, seq=%u, lcs=%u\n", rBuf, rBuf->seq, conn->rcv.LCS)); rBuf->fcnt = 0; rBuf->dataLen = 0; conn->rcv.LCS = rBuf->seq; if (conn->ackTimer.retry == 0) { InitTimer(&conn->ackTimer, 0, 1); } } AJ_Status AJ_ARDP_StartMsgSend(uint32_t ttl) { if (conn == NULL) { return AJ_ERR_DISALLOWED; } AJ_InfoPrintf(("ARDP_StartMsgSend: ttl=%d\n", ttl)); if (conn->snd.msgLenSent != 0) { AJ_ASSERT(conn->snd.newMsg == FALSE); } conn->snd.newMsg = TRUE; conn->snd.msgTTL = ttl; conn->snd.msgLenSent = 0; return AJ_OK; } /* * Send is a synchronous send. The data being sent are buffered at the protocol * level. * Returns error code: * AJ_OK - all is good * AJ_ERR_ARDP_TTL_EXPIRED - Discard the message that is currently being marshalled. * AJ_ERR_ARDP_BACKPRESSURE - Send window does not allow immediate transmission. * AJ_ERR_DISALLOWED - Connection does not exist (efffectively connection record is NULL) * */ static AJ_Status ARDP_Send(uint8_t* txBuf, uint16_t len) { uint16_t pending; ArdpSBuf* sBuf; uint32_t ttl; uint16_t fcnt; uint16_t offset; AJ_Status status; AJ_InfoPrintf(("ARDP_Send: buf=%p, len=%d ((nxt %u, lcs %u))\n", txBuf, len, conn->snd.NXT, conn->snd.LCS)); if ((conn == NULL) || ((conn->state != OPEN))) { return AJ_ERR_DISALLOWED; } status = CheckDataTimers(); if (status != AJ_OK) { return status; } pending = (conn->snd.NXT - conn->snd.LCS) - 1; sBuf = &(conn->snd.buf[conn->snd.NXT % UDP_SEGMAX]); AJ_ASSERT(conn->snd.pending <= UDP_SEGMAX); if (conn->snd.pending == UDP_SEGMAX) { AJ_InfoPrintf(("ARDP_Send: backpressure, all (%u) SND buffers are in flight\n", conn->snd.pending)); return AJ_ERR_ARDP_BACKPRESSURE; } AJ_ASSERT(sBuf->inFlight == 0); ttl = conn->snd.msgTTL; offset = sBuf->dataLen; /* If this is the start of a new message, extract the total message length */ if (conn->snd.newMsg == TRUE) { AJ_MsgHeader* hdr = (AJ_MsgHeader*) txBuf; conn->snd.msgLenTotal = sizeof(AJ_MsgHeader) + ((hdr->headerLen + 7) & 0xFFFFFFF8) + hdr->bodyLen; AJ_InfoPrintf(("ARDP_Send: new message len = %u\n", conn->snd.msgLenTotal)); conn->snd.newMsg = FALSE; conn->snd.msgSOM = conn->snd.NXT; } /* * Check whether there is enough local buffer space to fit the data. * Also, check if the remote side can currently accept these data. */ if (((len + offset) > (ARDP_MAX_DLEN * (UDP_SEGMAX - conn->snd.pending))) || ((len + offset) > (ARDP_MAX_DLEN * (conn->snd.SEGMAX - pending)))) { AJ_InfoPrintf(("ARDP_Send: backpressure, cannot send %u (%u + %u): local send pending %u, remote consume pending %u\n", len + offset, len, offset, conn->snd.pending, pending)); return AJ_ERR_ARDP_BACKPRESSURE; } AJ_ASSERT(conn->snd.msgLenTotal > 0); if (conn->rttInit && (ttl != ARDP_TTL_INFINITE)) { uint32_t expireThreshold = (conn->rttMeanUnit * (conn->snd.msgLenTotal + UDP_MTU - 1) / UDP_MTU) >> 1; if ((ttl < (ARDP_TTL_MAX - conn->snd.DACKT)) && ((ttl + conn->snd.DACKT) <= expireThreshold)) { return AJ_ERR_ARDP_SEND_EXPIRED; } /* If we passed the above "expire" test only due to factoring in DACKT, do not adjust ttl */ if (ttl > expireThreshold) { ttl = ttl - expireThreshold; } } fcnt = (conn->snd.msgLenTotal + ARDP_MAX_DLEN - 1) / ARDP_MAX_DLEN; AJ_ASSERT(fcnt > 0); do { uint16_t dataLen; size_t sent; uint32_t timeout; /* Check whether the current buffer is not in a process of being populated with fragmented data */ dataLen = (len <= (ARDP_MAX_DLEN - offset)) ? offset + len : ARDP_MAX_DLEN; memcpy(((uint8_t*) sBuf->data) + offset + ARDP_HEADER_SIZE, txBuf, dataLen - offset); sBuf->dataLen = dataLen; AJ_ASSERT(sBuf->inFlight == 0); AJ_InfoPrintf(("ARDP_Send(): len %u, dataLen %u, offset %u\n", len, dataLen, offset)); /* * Check if the segment is not filled to full capacity and is not the last segment. If so, we need * to wait for more data to pack in. Do not send, do not update counters. * Note: Soft check (instead of checking len == 0): a precaution for avoiding infinite loop in case we miscalculated. */ if ((dataLen < ARDP_MAX_DLEN) && dataLen != (conn->snd.msgLenTotal - conn->snd.msgLenSent)) { AJ_InfoPrintf(("ARDP_Send(): queued %d bytes\n", dataLen)); break; } sBuf->inFlight = 1; conn->snd.msgLenSent += dataLen; MarshalHeader(sBuf->data, ARDP_FLAG_ACK | ARDP_FLAG_VER, dataLen, ttl, conn->snd.msgSOM, fcnt); AJ_InfoPrintf(("ARDP_Send(): send %d bytes (seq %u, ack %u, lcs %u)\n", ARDP_HEADER_SIZE + dataLen, conn->snd.NXT, conn->rcv.CUR, conn->rcv.LCS)); status = (*sendFunction)(conn->context, (uint8_t*) sBuf->data, ARDP_HEADER_SIZE + dataLen, &sent, conn->confirm); if (status != AJ_OK) { AJ_ErrPrintf(("ARDP_Send(): %s\n", AJ_StatusText(status))); return status; } AJ_InfoPrintf(("ArdpSend(): cancel ackTimer\n")); conn->ackTimer.retry = 0; conn->rcv.pending = 0; conn->confirm = FALSE; len -= (dataLen - offset); conn->snd.NXT++; conn->snd.pending++; if (conn->rttInit) { timeout = GetRTO(); } else { timeout = UDP_INITIAL_DATA_TIMEOUT; } AJ_InitTimer(&sBuf->tStart); InitTimer(&sBuf->timer, timeout, 1); sBuf = sBuf->next; txBuf += (dataLen - offset); offset = 0; } while (len != 0); return AJ_OK; } AJ_Status AJ_ARDP_Connect(uint8_t* data, uint16_t dataLen, void* context, AJ_NetSocket* netSock) { AJ_Status status; memset(&UDP_Recv_State, 0, sizeof(UDP_Recv_State)); status = InitConnection(); if (status != AJ_OK) { return status; } AJ_ASSERT(dataLen < (UDP_SEGBMAX - ARDP_SYN_HEADER_SIZE)); memcpy(((uint8_t*) conn->snd.buf[0].data) + ARDP_SYN_HEADER_SIZE, data, dataLen); conn->snd.buf[0].dataLen = dataLen; conn->snd.buf[0].inFlight = 1; conn->context = context; conn->netSock = netSock; status = SendSyn(dataLen); if (status != AJ_OK) { AJ_Free(conn); } else { InitTimer(&conn->connectTimer, UDP_CONNECT_TIMEOUT, UDP_CONNECT_RETRIES); conn->state = SYN_SENT; } return status; } void AJ_ARDP_Disconnect(uint8_t forced) { AJ_WarnPrintf(("ARDP Disconnect Request (local)\n")); if (conn == NULL) { return; } if ((forced == FALSE) && (conn->snd.pending != 0)) { AJ_InfoPrintf(("ARDP_Disconnect: wait for tx queue to drain\n")); conn->state = CLOSE_WAIT; /* Block here to give data retransmits a chance to go through */ AJ_ARDP_Recv(&conn->netSock->rx, 0, UDP_DISCONNECT_TIMEOUT); /* * If, while we are waiting, the remote disconnected, the connection is torn down at this point. * Nothing to do, just return. */ if (conn == NULL) { return; } } AJ_WarnPrintf(("ARDP_Disconnect: Send RST\n")); SendHeader(ARDP_FLAG_RST | ARDP_FLAG_ACK | ARDP_FLAG_VER); AJ_Free(conn); conn = NULL; } AJ_Status AJ_ARDP_Send(AJ_IOBuffer* buf) { size_t tx = AJ_IO_BUF_AVAIL(buf); AJ_Status status = AJ_OK; uint32_t retry = 0; AJ_InfoPrintf(("AJ_ARDP_Send(buf=0x%p)\n", buf)); if (conn == NULL) { return AJ_ERR_DISALLOWED; } AJ_ASSERT(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { status = ARDP_Send(buf->readPtr, tx); /* We essentially block until the backpressure is releived */ if (status == AJ_ERR_ARDP_BACKPRESSURE) { do { AJ_InfoPrintf(("AJ_ARDP_Send: dealing with backpressure\n")); if (++retry >= ARDP_MAX_BACKPRESSURE_RETRIES) { return AJ_ERR_WRITE; } /* * If we can't make room in the send window within a certain amount of time, * assume that the connection has failed. */ status = AJ_ARDP_Recv(&conn->netSock->rx, 0, ARDP_BACKPRESSURE_INTERVAL); if (status != AJ_OK && status != AJ_ERR_TIMEOUT) { /* Something has gone wrong */ AJ_ErrPrintf(("AJ_ARDP_Send: (*recvFunction) returns %s\n", AJ_StatusText(status))); return AJ_ERR_WRITE; } status = ARDP_Send(buf->readPtr, tx); /* Loop while backpressure continues */ } while (status == AJ_ERR_ARDP_BACKPRESSURE); } else if (status != AJ_OK) { /* Something other than backpressure */ return AJ_ERR_WRITE; } if ((status == AJ_OK) || (status == AJ_ERR_ARDP_RECV_EXPIRED)) { buf->readPtr += tx; } } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_ARDP_Send(): status=AJ_OK\n")); return status; } static void UpdateReadBuffer(AJ_IOBuffer* rxBuf, uint32_t len) { AJ_InfoPrintf(("UpdateRead: rxBuf %p, len %u\n", rxBuf, len)); while ((UDP_Recv_State.rxContext != NULL) && (UDP_Recv_State.readBuf != NULL) && (len != 0)) { ArdpRBuf* rBuf = UDP_Recv_State.rxContext; size_t rx = AJ_IO_BUF_SPACE(rxBuf); uint32_t consumed; /* How much buffer space is available */ rx = min(rx, len); /* How much we can consume from the current rBuf */ consumed = min(rx, UDP_Recv_State.dataLen); memcpy(rxBuf->writePtr, UDP_Recv_State.readBuf, consumed); /* Advance the write pointer */ rxBuf->writePtr += consumed; len -= consumed; if (consumed == UDP_Recv_State.dataLen) { /* * We are done with the current rBuf. Release and potentially * move on to next rBuf. */ AJ_InfoPrintf(("UpdateRead: ready\n")); RecvReady(rBuf); /* Advance to the next rBuf */ if (rBuf->next->dataLen) { AJ_InfoPrintf(("UpdateRead: Start reading from next RCV\n")); UDP_Recv_State.readBuf = rBuf->next->data; UDP_Recv_State.dataLen = rBuf->next->dataLen; UDP_Recv_State.rxContext = rBuf->next; } else { AJ_InfoPrintf(("UpdateRead: Nothing in next RCV\n")); memset(&UDP_Recv_State, 0, sizeof(UDP_Recv_State)); } } else { /* No more space to write data. Update the internal read state and return */ UDP_Recv_State.readBuf += rx; UDP_Recv_State.dataLen -= rx; return; } } } AJ_Status AJ_ARDP_Recv(AJ_IOBuffer* rxBuf, uint32_t len, uint32_t timeout) { AJ_Status status = AJ_ERR_TIMEOUT; AJ_Status localStatus; uint32_t timeout2 = min(timeout, UDP_MINIMUM_TIMEOUT); AJ_Time now, end; AJ_InfoPrintf(("AJ_ARDP_Recv(rxBuf=%p, len=%u, timeout=%u)\n", rxBuf, len, timeout)); if (conn == NULL) { return AJ_ERR_READ; } AJ_InitTimer(&end); AJ_TimeAddOffset(&end, timeout); if ((len != 0) && (UDP_Recv_State.rxContext != NULL)) { timeout2 = 0; } do { uint32_t received = 0; uint8_t* buf = NULL; status = (*recvFunction)(rxBuf->context, &buf, &received, timeout2); localStatus = CheckTimers(); if (localStatus == AJ_ERR_CONNECT) { return AJ_ERR_CONNECT; } else if (localStatus != AJ_OK) { AJ_InfoPrintf(("AJ_ARDP_Recv CheckTimers status %s\n", AJ_StatusText(localStatus))); return AJ_ERR_READ; } switch (status) { case AJ_ERR_TIMEOUT: AJ_InfoPrintf(("AJ_ARDP_Recv status %s, len = %u, rxContext = %p\n", AJ_StatusText(status), len, UDP_Recv_State.rxContext)); if ((len != 0) && (UDP_Recv_State.rxContext != NULL)) { status = AJ_OK; AJ_InitTimer(&conn->probeTimer.tStart); goto UPDATE_READ; } break; case AJ_OK: status = ARDP_Recv(buf, received); if (status == AJ_OK) { goto UPDATE_READ; } else if (status == AJ_ERR_ARDP_RECV_EXPIRED) { AJ_InfoPrintf(("AJ_ARDP_Recv: Expired message, LCS %u\n", conn->rcv.LCS)); conn->rcv.LCS = conn->rcv.CUR; if (conn->ackTimer.retry == 0) { InitTimer(&conn->ackTimer, ARDP_MIN_DELAYED_ACK_TIMEOUT, 1); } return status; } else if (status == AJ_ERR_ARDP_DISCONNECTING) { /* We are waiting for either TX queue to drain or timeout */ break; } else if ((status != AJ_ERR_ARDP_REMOTE_CONNECTION_RESET) && (conn->state != CLOSE_WAIT)) { AJ_WarnPrintf(("AJ_ARDP_Recv: received bad data, disconnecting\n")); AJ_ARDP_Disconnect(TRUE); } status = AJ_ERR_READ; /* Fall through */ case AJ_ERR_INTERRUPTED: case AJ_ERR_READ: return status; default: AJ_WarnPrintf(("AJ_ARDP_Recv: Invalid\n")); AJ_ASSERT(!"this shouldn't happen!"); return AJ_ERR_READ; } AJ_InitTimer(&now); } while (AJ_CompareTime(now, end) < 0); UPDATE_READ: if ((len != 0) && (UDP_Recv_State.rxContext != NULL)) { UpdateReadBuffer(rxBuf, len); // can't possibly time out if data was recved! return AJ_OK; } AJ_InfoPrintf(("AJ_ARDP_Recv exit with %s\n", AJ_StatusText(status))); return AJ_ERR_TIMEOUT; } #ifdef __cplusplus } #endif #endif // AJ_ARDP ajtcl-16.04/src/aj_authentication.c000066400000000000000000001140341271074662300172600ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE AUTHENTICATION #include #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgAUTHENTICATION = 0; #endif #define SIG_FMT 0 #define AUTH_VERIFIER_LEN AJ_SHA256_DIGEST_LENGTH static AJ_Status ComputeMasterSecret(AJ_AuthenticationContext* ctx, uint8_t* pms, size_t len) { const uint8_t* data[2]; uint8_t lens[2]; AJ_ASSERT(len <= UINT8_MAX); AJ_InfoPrintf(("ComputeMasterSecret(ctx=%p, pms=%p, len=%u)\n", ctx, pms, (uint32_t)len)); data[0] = pms; lens[0] = (uint8_t) len; data[1] = (uint8_t*) "master secret"; lens[1] = 13; return AJ_Crypto_PRF_SHA256(data, lens, ArraySize(data), ctx->mastersecret, AJ_MASTER_SECRET_LEN); } static AJ_Status ComputeVerifier(AJ_AuthenticationContext* ctx, const char* label, uint8_t* buffer, size_t bufferlen) { const uint8_t* data[3]; uint8_t lens[3]; AJ_ASSERT(bufferlen <= UINT32_MAX); data[0] = ctx->mastersecret; lens[0] = AJ_MASTER_SECRET_LEN; data[1] = (uint8_t*) label; lens[1] = (uint8_t) strlen(label); data[2] = ctx->digest; lens[2] = (uint8_t) sizeof (ctx->digest); return AJ_Crypto_PRF_SHA256(data, lens, ArraySize(data), buffer, (uint32_t) bufferlen); } static AJ_Status ComputePSKVerifier(AJ_AuthenticationContext* ctx, const char* label, uint8_t* buffer, size_t bufferlen) { const uint8_t* data[5]; uint8_t lens[5]; /* Use the old method for < CONVERSATION_V4. */ if (AJ_UNPACK_AUTH_VERSION(ctx->version) < CONVERSATION_V4) { return ComputeVerifier(ctx, label, buffer, bufferlen); } data[0] = ctx->mastersecret; lens[0] = AJ_MASTER_SECRET_LEN; data[1] = (uint8_t*)label; lens[1] = (uint8_t)strlen(label); data[2] = ctx->digest; lens[2] = sizeof(ctx->digest); data[3] = ctx->kactx.psk.hint; AJ_ASSERT(ctx->kactx.psk.hintSize <= 0xFF); lens[3] = (uint8_t)ctx->kactx.psk.hintSize; data[4] = ctx->kactx.psk.key; AJ_ASSERT(ctx->kactx.psk.keySize <= 0xFF); lens[4] = (uint8_t)ctx->kactx.psk.keySize; AJ_ASSERT(bufferlen <= 0xFFFFFFFF); return AJ_Crypto_PRF_SHA256(data, lens, ArraySize(data), buffer, (uint32_t)bufferlen); } static AJ_Status ECDHEMarshalV1(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; uint8_t buf[1 + KEY_ECC_OLD_SZ]; AJ_InfoPrintf(("ECDHEMarshalV1(ctx=%p, msg=%p)\n", ctx, msg)); // Encode the public key buf[0] = KEY_CRV_NISTP256; AJ_BigEndianEncodePublicKey(&ctx->kectx.pub, &buf[1]); // Marshal the encoded key status = AJ_MarshalArgs(msg, "v", "ay", buf, sizeof (buf)); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, buf, sizeof (buf)); return status; } static AJ_Status ECDHEMarshalV3(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_InfoPrintf(("ECDHEMarshalV3(ctx=%p, msg=%p)\n", ctx, msg)); // Marshal the encoded key status = AJ_MarshalArgs(msg, "v", "(yay)", ctx->kectx.pub.crv, ctx->kectx.pub.x, KEY_ECC_PUB_SZ); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, &ctx->kectx.pub.crv, sizeof (ctx->kectx.pub.crv)); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, ctx->kectx.pub.x, KEY_ECC_PUB_SZ); return status; } static AJ_Status ECDHEMarshalV4(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_InfoPrintf(("ECDHEMarshalV4(ctx=%p, msg=%p)\n", ctx, msg)); // Marshal the encoded key status = AJ_MarshalArgs(msg, "v", "(yyayay)", ctx->kectx.pub.alg, ctx->kectx.pub.crv, ctx->kectx.pub.x, KEY_ECC_SZ, ctx->kectx.pub.y, KEY_ECC_SZ); return status; } static AJ_Status ECDHEMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_Credential cred = { 0 }; AJ_InfoPrintf(("ECDHEMarshal(ctx=%p, msg=%p)\n", ctx, msg)); // Generate key pair if client if (AUTH_CLIENT == ctx->role) { if (ctx->suite == AUTH_SUITE_ECDHE_SPEKE) { /* EC-SPEKE keygen depends on the password, use the callback */ if (ctx->bus->authListenerCallback == NULL) { AJ_InfoPrintf(("Authentication failure: Missing callback for ECDHE_SPEKE\n")); return AJ_ERR_INVALID; } status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_SPEKE, AJ_CRED_PASSWORD, &cred); if (status != AJ_OK) { AJ_InfoPrintf(("Authentication failure: callback failed for ECDHE_SPEKE\n")); return status; } if (cred.expiration) { ctx->expiration = cred.expiration; } status = AJ_GenerateSPEKEKeyPair(cred.data, cred.len, &ctx->kactx.speke.localGUID, ctx->kactx.speke.remoteGUID, &ctx->kectx.pub, &ctx->kectx.prv); } else { /* The other ECDH suites use traditional key generation */ status = AJ_GenerateECCKeyPair(&ctx->kectx.pub, &ctx->kectx.prv); } if (AJ_OK != status) { AJ_InfoPrintf(("ECDHEMarshal(ctx=%p, msg=%p): Key generation failed\n", ctx, msg)); return status; } } switch (AJ_UNPACK_AUTH_VERSION(ctx->version)) { case 1: case 2: status = ECDHEMarshalV1(ctx, msg); break; case 3: status = ECDHEMarshalV3(ctx, msg); break; case 4: status = ECDHEMarshalV4(ctx, msg); break; default: status = AJ_ERR_INVALID; break; } return status; } static AJ_Status ECDHEUnmarshalV1(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; uint8_t* data; size_t size; AJ_ECCPublicKey pub; AJ_ECCPublicKey secret; AJ_InfoPrintf(("ECDHEUnmarshalV1(ctx=%p, msg=%p)\n", ctx, msg)); // Unmarshal the encoded key status = AJ_UnmarshalArgs(msg, "v", "ay", &data, &size); if (AJ_OK != status) { AJ_InfoPrintf(("ECDHEUnmarshalV1(ctx=%p, msg=%p): Unmarshal error\n", ctx, msg)); return status; } if ((1 + KEY_ECC_OLD_SZ) != size) { AJ_InfoPrintf(("ECDHEUnmarshalV1(ctx=%p, msg=%p): Invalid key material\n", ctx, msg)); return AJ_ERR_SECURITY; } if (KEY_CRV_NISTP256 != data[0]) { AJ_InfoPrintf(("ECDHEUnmarshalV1(ctx=%p, msg=%p): Invalid curve\n", ctx, msg)); return AJ_ERR_SECURITY; } // Decode the public key AJ_BigEndianDecodePublicKey(&pub, &data[1]); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, data, size); // Generate shared secret status = AJ_GenerateShareSecretOld(&pub, &ctx->kectx.prv, &secret); if (AJ_OK != status) { AJ_InfoPrintf(("ECDHEUnmarshalV1(ctx=%p, msg=%p): Generate secret error\n", ctx, msg)); return status; } // Encode the shared secret size = KEY_ECC_OLD_SZ; data = (uint8_t*) AJ_Malloc(size); if (NULL == data) { return AJ_ERR_RESOURCES; } AJ_BigEndianEncodePublicKey(&secret, data); status = ComputeMasterSecret(ctx, data, size); AJ_Free(data); return status; } static AJ_Status GenerateShareSecret(AJ_AuthenticationContext* ctx, AJ_ECCPublicKey* pub, AJ_ECCPrivateKey* prv) { AJ_Status status; AJ_ECCSecret sec; AJ_SHA256_Context* sha; uint8_t* data; size_t size; // Generate shared secret status = AJ_GenerateShareSecret(pub, prv, &sec); if (AJ_OK != status) { return status; } size = AJ_SHA256_DIGEST_LENGTH; data = (uint8_t*) AJ_Malloc(size); if (NULL == data) { return AJ_ERR_RESOURCES; } sha = AJ_SHA256_Init(); if (!sha) { status = AJ_ERR_RESOURCES; goto Exit; } AJ_SHA256_Update(sha, sec.x, KEY_ECC_SZ); status = AJ_SHA256_Final(sha, data); if (AJ_OK != status) { goto Exit; } status = ComputeMasterSecret(ctx, data, size); Exit: AJ_Free(data); return status; } static AJ_Status ECDHEUnmarshalV3(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; uint8_t* data; size_t size; AJ_ECCPublicKey pub; AJ_InfoPrintf(("ECDHEUnmarshalV3(ctx=%p, msg=%p)\n", ctx, msg)); // Unmarshal the encoded key status = AJ_UnmarshalArgs(msg, "v", "(yay)", &pub.crv, &data, &size); if (AJ_OK != status) { AJ_InfoPrintf(("ECDHEUnmarshalV3(ctx=%p, msg=%p): Unmarshal error\n", ctx, msg)); return status; } if (KEY_CRV_NISTP256 != pub.crv) { AJ_InfoPrintf(("ECDHEUnmarshalV3(ctx=%p, msg=%p): Invalid curve\n", ctx, msg)); return AJ_ERR_SECURITY; } if (KEY_ECC_PUB_SZ != size) { AJ_InfoPrintf(("ECDHEUnmarshalV3(ctx=%p, msg=%p): Invalid key material\n", ctx, msg)); return AJ_ERR_SECURITY; } // Copy the public key memcpy(pub.x, data, KEY_ECC_SZ); memcpy(pub.y, data + KEY_ECC_SZ, KEY_ECC_SZ); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, &pub.crv, sizeof (pub.crv)); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, data, size); status = GenerateShareSecret(ctx, &pub, &ctx->kectx.prv); return status; } static AJ_Status ECDHEUnmarshalV4(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; const char* variant; AJ_ECCPublicKey pub; AJ_InfoPrintf(("ECDHEUnmarshalV4(ctx=%p, msg=%p)\n", ctx, msg)); // Unmarshal the encoded key status = AJ_UnmarshalVariant(msg, &variant); if (AJ_OK != status) { AJ_InfoPrintf(("ECDHEUnmarshalV4(ctx=%p, msg=%p): Unmarshal error\n", ctx, msg)); return status; } status = AJ_UnmarshalECCPublicKey(msg, &pub, NULL); if (AJ_OK != status) { AJ_InfoPrintf(("ECDHEUnmarshalV4(ctx=%p, msg=%p): Unmarshal error\n", ctx, msg)); return status; } status = GenerateShareSecret(ctx, &pub, &ctx->kectx.prv); return status; } static AJ_Status ECDHEUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_Credential cred = { 0 }; AJ_InfoPrintf(("ECDHEUnmarshal(ctx=%p, msg=%p)\n", ctx, msg)); // Generate key pair if server if (AUTH_SERVER == ctx->role) { if (ctx->suite == AUTH_SUITE_ECDHE_SPEKE) { /* EC-SPEKE keygen depends on the password, use the callback */ if (ctx->bus->authListenerCallback == NULL) { AJ_InfoPrintf(("Authentication failure: Missing callback for ECDHE_SPEKE\n")); return AJ_ERR_INVALID; } status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_SPEKE, AJ_CRED_PASSWORD, &cred); if (status != AJ_OK) { AJ_InfoPrintf(("Authentication failure: callback failed for ECDHE_SPEKE\n")); return status; } if (cred.expiration) { ctx->expiration = cred.expiration; } status = AJ_GenerateSPEKEKeyPair(cred.data, cred.len, ctx->kactx.speke.remoteGUID, &ctx->kactx.speke.localGUID, &ctx->kectx.pub, &ctx->kectx.prv); } else { /* The other ECDH suites use traditional key generation */ status = AJ_GenerateECCKeyPair(&ctx->kectx.pub, &ctx->kectx.prv); } if (AJ_OK != status) { AJ_InfoPrintf(("ECDHEUnmarshal(ctx=%p, msg=%p): Key generation failed\n", ctx, msg)); return status; } } switch (AJ_UNPACK_AUTH_VERSION(ctx->version)) { case 1: case 2: status = ECDHEUnmarshalV1(ctx, msg); break; case 3: status = ECDHEUnmarshalV3(ctx, msg); break; case 4: status = ECDHEUnmarshalV4(ctx, msg); break; default: status = AJ_ERR_INVALID; break; } return status; } AJ_Status AJ_KeyExchangeMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status = AJ_ERR_SECURITY; switch (0xFFFF0000 & ctx->suite) { case AUTH_KEYX_ECDHE: status = ECDHEMarshal(ctx, msg); break; } return status; } AJ_Status AJ_KeyExchangeUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status = AJ_ERR_SECURITY; switch (0xFFFF0000 & ctx->suite) { case AUTH_KEYX_ECDHE: status = ECDHEUnmarshal(ctx, msg); break; } return status; } static AJ_Status NULLMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_Credential cred; uint8_t verifier[AUTH_VERIFIER_LEN]; AJ_InfoPrintf(("NULLMarshal(ctx=%p, msg=%p)\n", ctx, msg)); if (ctx->bus->authListenerCallback) { status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_NULL, 0, &cred); if (AJ_OK == status) { ctx->expiration = cred.expiration; } } if (AUTH_CLIENT == ctx->role) { status = ComputeVerifier(ctx, "client finished", verifier, sizeof (verifier)); } else { status = ComputeVerifier(ctx, "server finished", verifier, sizeof (verifier)); } if (AJ_OK != status) { return AJ_ERR_SECURITY; } status = AJ_MarshalArgs(msg, "v", "ay", verifier, sizeof (verifier)); if (AJ_OK == status) { AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, verifier, sizeof(verifier)); } return status; } static AJ_Status NULLUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; uint8_t local[AUTH_VERIFIER_LEN]; uint8_t* remote; size_t len; AJ_InfoPrintf(("NULLUnmarshal(ctx=%p, msg=%p)\n", ctx, msg)); if (AUTH_CLIENT == ctx->role) { status = ComputeVerifier(ctx, "server finished", local, sizeof (local)); } else { status = ComputeVerifier(ctx, "client finished", local, sizeof (local)); } if (AJ_OK != status) { return AJ_ERR_SECURITY; } status = AJ_UnmarshalArgs(msg, "v", "ay", &remote, &len); if (AJ_OK != status) { AJ_InfoPrintf(("NULLUnmarshal(ctx=%p, msg=%p): Unmarshal error\n", ctx, msg)); return AJ_ERR_SECURITY; } if (AUTH_VERIFIER_LEN != len) { AJ_InfoPrintf(("NULLUnmarshal(ctx=%p, msg=%p): Invalid signature size\n", ctx, msg)); return AJ_ERR_SECURITY; } if (0 != AJ_Crypto_Compare(local, remote, AUTH_VERIFIER_LEN)) { AJ_InfoPrintf(("NULLUnmarshal(ctx=%p, msg=%p): Invalid verifier\n", ctx, msg)); return AJ_ERR_SECURITY; } AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, local, sizeof (local)); return status; } static AJ_Status PSKSetHint(AJ_AuthenticationContext* ctx, const uint8_t* hint, size_t hintSize) { AJ_ASSERT(((NULL == ctx->kactx.psk.hint) && (ctx->kactx.psk.hintSize == 0)) || ((NULL != ctx->kactx.psk.hint) && (ctx->kactx.psk.hintSize > 0))); AJ_Free(ctx->kactx.psk.hint); ctx->kactx.psk.hint = AJ_Malloc(hintSize); if (NULL == ctx->kactx.psk.hint) { ctx->kactx.psk.hintSize = 0; return AJ_ERR_RESOURCES; } ctx->kactx.psk.hintSize = hintSize; memcpy(ctx->kactx.psk.hint, hint, hintSize); return AJ_OK; } static AJ_Status PSKSetKey(AJ_AuthenticationContext* ctx, const uint8_t* key, size_t keySize) { if (NULL != ctx->kactx.psk.key) { AJ_ASSERT(ctx->kactx.psk.keySize > 0); AJ_MemZeroSecure(ctx->kactx.psk.key, ctx->kactx.psk.keySize); AJ_Free(ctx->kactx.psk.key); } ctx->kactx.psk.key = AJ_Malloc(keySize); if (NULL == ctx->kactx.psk.key) { ctx->kactx.psk.keySize = 0; return AJ_ERR_RESOURCES; } ctx->kactx.psk.keySize = keySize; memcpy(ctx->kactx.psk.key, key, keySize); return AJ_OK; } static AJ_Status PSKCallbackV1(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; uint8_t data[PSK_V1_CALLBACK_BUFFER_SIZE]; size_t size = sizeof (data); /* * Assume application does not copy in more than this size buffer * Expiration not set by application */ size = ctx->bus->pwdCallback(data, (uint32_t)size); if (sizeof (data) < size) { AJ_MemZeroSecure(data, sizeof(data)); return AJ_ERR_RESOURCES; } status = PSKSetKey(ctx, data, size); AJ_MemZeroSecure(data, sizeof (data)); if (AJ_OK != status) { return status; } ctx->expiration = 0xFFFFFFFF; AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, ctx->kactx.psk.hint, ctx->kactx.psk.hintSize); /* Calling AJ_ConversationHash_SetSensitiveMode ensures the PSK won't end up in the log if conversation * hash tracing is turned on. */ AJ_ConversationHash_SetSensitiveMode(ctx, TRUE); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, ctx->kactx.psk.key, ctx->kactx.psk.keySize); AJ_ConversationHash_SetSensitiveMode(ctx, FALSE); if (AJ_UNPACK_AUTH_VERSION(ctx->version) < CONVERSATION_V4) { status = AJ_ConversationHash_GetDigest(ctx); } return status; } static AJ_Status PSKCallbackV2(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_Credential cred; switch (ctx->role) { case AUTH_CLIENT: cred.direction = AJ_CRED_REQUEST; status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_PSK, AJ_CRED_PUB_KEY, &cred); if (AJ_OK == status) { status = PSKSetHint(ctx, cred.data, cred.len); } break; case AUTH_SERVER: cred.direction = AJ_CRED_RESPONSE; cred.data = ctx->kactx.psk.hint; cred.len = ctx->kactx.psk.hintSize; status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_PSK, AJ_CRED_PUB_KEY, &cred); break; } if (AJ_OK != status) { return AJ_ERR_SECURITY; } cred.direction = AJ_CRED_REQUEST; status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_PSK, AJ_CRED_PRV_KEY, &cred); if (AJ_OK != status) { return AJ_ERR_SECURITY; } ctx->expiration = cred.expiration; // Hash in psk hint, then psk AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, ctx->kactx.psk.hint, ctx->kactx.psk.hintSize); /* Calling AJ_ConversationHash_SetSensitiveMode ensures the PSK won't end up in the log if conversation * hash tracing is turned on. */ AJ_ConversationHash_SetSensitiveMode(ctx, TRUE); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, cred.data, cred.len); AJ_ConversationHash_SetSensitiveMode(ctx, FALSE); if (AJ_UNPACK_AUTH_VERSION(ctx->version) < CONVERSATION_V4) { status = AJ_ConversationHash_GetDigest(ctx); if (AJ_OK != status) { return status; } } // CONVERSATION_V4 computes the PSK verifier based on these instead of including it in the conversation // hash, so save them for later. status = PSKSetKey(ctx, cred.data, cred.len); return status; } static AJ_Status PSKCallback(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_InfoPrintf(("PSKCallback(ctx=%p, msg=%p)\n", ctx, msg)); if (ctx->bus->authListenerCallback) { status = PSKCallbackV2(ctx, msg); } else if (ctx->bus->pwdCallback) { status = PSKCallbackV1(ctx, msg); } else { status = AJ_ERR_SECURITY; } return status; } static AJ_Status PSKMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status = AJ_ERR_SECURITY; const char* anon = ""; uint8_t verifier[AUTH_VERIFIER_LEN]; AJ_InfoPrintf(("PSKMarshal(ctx=%p, msg=%p)\n", ctx, msg)); switch (ctx->role) { case AUTH_CLIENT: // Default to anonymous status = PSKSetHint(ctx, (const uint8_t*) anon, strlen(anon)); if (AJ_OK != status) { return AJ_ERR_SECURITY; } status = PSKCallback(ctx, msg); if (AJ_OK != status) { return AJ_ERR_SECURITY; } status = ComputePSKVerifier(ctx, "client finished", verifier, sizeof (verifier)); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, verifier, sizeof (verifier)); break; case AUTH_SERVER: status = ComputePSKVerifier(ctx, "server finished", verifier, sizeof (verifier)); break; } if (AJ_OK != status) { return AJ_ERR_SECURITY; } status = AJ_MarshalArgs(msg, "v", "(ayay)", ctx->kactx.psk.hint, ctx->kactx.psk.hintSize, verifier, sizeof (verifier)); return status; } static AJ_Status PSKUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; uint8_t verifier[AUTH_VERIFIER_LEN]; uint8_t* hint; size_t hintSize; uint8_t* data; size_t size; AJ_InfoPrintf(("PSKUnmarshal(ctx=%p, msg=%p)\n", ctx, msg)); status = AJ_UnmarshalArgs(msg, "v", "(ayay)", &hint, &hintSize, &data, &size); if (AJ_OK != status) { return AJ_ERR_SECURITY; } if (AUTH_VERIFIER_LEN != size) { return AJ_ERR_SECURITY; } status = PSKSetHint(ctx, hint, hintSize); if (AJ_OK != status) { return AJ_ERR_SECURITY; } switch (ctx->role) { case AUTH_CLIENT: status = ComputePSKVerifier(ctx, "server finished", verifier, sizeof (verifier)); break; case AUTH_SERVER: status = PSKCallback(ctx, msg); if (AJ_OK != status) { return AJ_ERR_SECURITY; } status = ComputePSKVerifier(ctx, "client finished", verifier, sizeof (verifier)); if (AJ_OK == status) { AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, verifier, sizeof(verifier)); } break; default: return AJ_ERR_SECURITY; } if (AJ_OK != status) { return AJ_ERR_SECURITY; } if (0 != AJ_Crypto_Compare(verifier, data, AUTH_VERIFIER_LEN)) { AJ_InfoPrintf(("PSKUnmarshal(ctx=%p, msg=%p): Invalid verifier\n", ctx, msg)); return AJ_ERR_SECURITY; } return status; } /* * KeyAuthentication call expects yv = ya(ay) */ static AJ_Status MarshalCertificates(AJ_AuthenticationContext* ctx, X509CertificateChain* root, AJ_Message* msg) { AJ_Status status; AJ_Arg container; X509CertificateChain* head; uint8_t fmt = CERT_FMT_X509_DER; /* * X509CertificateChain is root first. * The wire protocol requires leaf first, * reverse it here, then reverse it back after marshalling. */ root = AJ_X509ReverseChain(root); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, &fmt, sizeof(fmt)); status = AJ_MarshalArgs(msg, "y", fmt); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalVariant(msg, "a(ay)"); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } head = root; while (head) { status = AJ_MarshalArgs(msg, "(ay)", head->certificate.der.data, head->certificate.der.size); if (AJ_OK != status) { goto Exit; } AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, head->certificate.der.data, head->certificate.der.size); head = head->next; } status = AJ_MarshalCloseContainer(msg, &container); Exit: root = AJ_X509ReverseChain(root); return status; } static AJ_Status ECDSAMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status; AJ_Arg container; AJ_ECCPrivateKey prv; AJ_ECCSignature sig; uint8_t verifier[AJ_SHA256_DIGEST_LENGTH]; X509CertificateChain* root = NULL; AJ_CredField field; uint8_t owns_data = FALSE; AJ_Credential cred; AJ_InfoPrintf(("ECDSAMarshal(ctx=%p, msg=%p)\n", ctx, msg)); ctx->expiration = 0xFFFFFFFF; field.data = NULL; field.size = 0; if (AUTH_CLIENT == ctx->role) { status = ComputeVerifier(ctx, "client finished", verifier, sizeof (verifier)); } else { status = ComputeVerifier(ctx, "server finished", verifier, sizeof (verifier)); } if (AJ_OK != status) { goto Exit; } /* Get certificate chain from keystore */ status = AJ_CredentialGet(AJ_CERTIFICATE_IDN_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, &field); if (AJ_OK == status) { status = AJ_X509ChainFromBuffer(&root, &field); if (AJ_OK != status) { goto Exit; } owns_data = TRUE; /* Get private key from keystore */ status = AJ_CredentialGetECCPrivateKey(AJ_ECC_SIG, NULL, NULL, &prv); if (AJ_OK != status) { AJ_WarnPrintf(("ECDSAMarshal(ctx=%p, msg=%p): Private key missing\n", ctx, msg)); goto Exit; } } else if (NULL != ctx->bus->authListenerCallback) { /* Get certificate chain from application */ cred.direction = AJ_CRED_REQUEST; status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_ECDSA, AJ_CRED_CERT_CHAIN, &cred); if (AJ_OK != status) { AJ_WarnPrintf(("ECDSAMarshal(ctx=%p, msg=%p): certificate chain missing\n", ctx, msg)); goto Exit; } root = (X509CertificateChain*) cred.data; /* Get private key from application */ cred.direction = AJ_CRED_REQUEST; cred.len = sizeof (AJ_ECCPrivateKey); cred.data = (uint8_t*) &prv; status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_ECDSA, AJ_CRED_PRV_KEY, &cred); if (AJ_OK != status) { AJ_WarnPrintf(("ECDSAMarshal(ctx=%p, msg=%p): Private key missing\n", ctx, msg)); goto Exit; } } if (AJ_OK != status) { AJ_WarnPrintf(("ECDSAMarshal(ctx=%p, msg=%p): certificate chain missing\n", ctx, msg)); goto Exit; } /* Sign verifier */ status = AJ_ECDSASignDigest(verifier, &prv, &sig); if (AJ_OK != status) { AJ_WarnPrintf(("ECDSAMarshal(ctx=%p, msg=%p): Sign verifier error\n", ctx, msg)); goto Exit; } AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, sig.r, KEY_ECC_SZ); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, sig.s, KEY_ECC_SZ); /* Marshal signature */ status = AJ_MarshalVariant(msg, "(vyv)"); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalContainer(msg, &container, AJ_ARG_STRUCT); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalArgs(msg, "v", "(yv)", SIG_FMT, "(ayay)", sig.r, KEY_ECC_SZ, sig.s, KEY_ECC_SZ); if (AJ_OK != status) { goto Exit; } /* Marshal certificate chain */ status = MarshalCertificates(ctx, root, msg); if (AJ_OK != status) { AJ_WarnPrintf(("ECDSAMarshal(ctx=%p, msg=%p): Marshal certificate chain error\n", ctx, msg)); goto Exit; } status = AJ_MarshalCloseContainer(msg, &container); Exit: if (owns_data) { AJ_X509ChainFree(root); } AJ_CredFieldFree(&field); return status; } static AJ_Status ECDSAUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg, uint32_t version) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; AJ_SHA256_Context* thumbprintHashCtx; const char* variant; uint8_t fmt; DER_Element der; AJ_ECCPublicKey pub; AJ_ECCSignature sig; uint8_t* sig_r; uint8_t* sig_s; size_t len_r; size_t len_s; X509CertificateChain* root = NULL; X509CertificateChain* node = NULL; AJ_Credential cred; uint8_t trusted = 0; uint32_t type; AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p)\n", ctx, msg)); if (AUTH_CLIENT == ctx->role) { status = ComputeVerifier(ctx, "server finished", digest, sizeof (digest)); } else { status = ComputeVerifier(ctx, "client finished", digest, sizeof (digest)); } if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalVariant(msg, &variant); if (AJ_OK != status) { goto Exit; } if (0 != strncmp(variant, "(vyv)", 5)) { status = AJ_ERR_SECURITY; goto Exit; } status = AJ_UnmarshalContainer(msg, &container1, AJ_ARG_STRUCT); if (AJ_OK != status) { goto Exit; } /* Unmarshal signature */ status = AJ_UnmarshalArgs(msg, "v", "(yv)", &fmt, "(ayay)", &sig_r, &len_r, &sig_s, &len_s); if (AJ_OK != status) { goto Exit; } if (SIG_FMT != fmt) { status = AJ_ERR_SECURITY; goto Exit; } if ((KEY_ECC_SZ != len_r) || (KEY_ECC_SZ != len_s)) { status = AJ_ERR_SECURITY; goto Exit; } memcpy(sig.r, sig_r, KEY_ECC_SZ); memcpy(sig.s, sig_s, KEY_ECC_SZ); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, sig_r, KEY_ECC_SZ); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, sig_s, KEY_ECC_SZ); /* Unmarshal certificate chain */ status = AJ_UnmarshalArgs(msg, "y", &fmt); if (AJ_OK != status) { goto Exit; } if (CERT_FMT_X509_DER != fmt) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): DER encoding expected\n", ctx, msg)); status = AJ_ERR_SECURITY; goto Exit; } AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, &fmt, sizeof(fmt)); status = AJ_UnmarshalVariant(msg, &variant); if (AJ_OK != status) { goto Exit; } if (0 != strncmp(variant, "a(ay)", 5)) { status = AJ_ERR_SECURITY; goto Exit; } status = AJ_UnmarshalContainer(msg, &container2, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } ctx->kactx.ecdsa.num = 0; while (AJ_OK == status) { status = AJ_UnmarshalArgs(msg, "(ay)", &der.data, &der.size); if (AJ_OK != status) { break; } AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V1, der.data, der.size); node = (X509CertificateChain*) AJ_Malloc(sizeof (X509CertificateChain)); if (NULL == node) { AJ_WarnPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Resource error\n", ctx, msg)); status = AJ_ERR_RESOURCES; goto Exit; } /* * Push the certificate on to the front of the chain. * We do this before decoding so that it is cleaned up in case of error. */ node->next = root; root = node; /* Set the der before its consumed */ node->certificate.der.size = der.size; node->certificate.der.data = der.data; status = AJ_X509DecodeCertificateDER(&node->certificate, &der); if (AJ_OK != status) { AJ_WarnPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Certificate decode failed\n", ctx, msg)); goto Exit; } /* * If this is the first certificate, check that it signed the verifier * Also save the subject public key and thumbprint for authorisation check */ if (NULL == node->next) { status = AJ_ECDSAVerifyDigest(digest, &sig, &node->certificate.tbs.publickey); if (AJ_OK != status) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Signature invalid\n", ctx, msg)); goto Exit; } thumbprintHashCtx = AJ_SHA256_Init(); if (!thumbprintHashCtx) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Could not allocate SHA256 context\n", ctx, msg)); goto Exit; } AJ_SHA256_Update(thumbprintHashCtx, node->certificate.der.data, node->certificate.der.size); status = AJ_SHA256_Final(thumbprintHashCtx, ctx->kactx.ecdsa.thumbprint); if (AJ_OK != status) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Got status %u from AJ_SHA256_Final\n", ctx, msg, status)); goto Exit; } ctx->kactx.ecdsa.thumbprintSize = AJ_SHA256_DIGEST_LENGTH; } /* Copy the public key */ ctx->kactx.ecdsa.num++; ctx->kactx.ecdsa.key = (AJ_ECCPublicKey*) AJ_Realloc(ctx->kactx.ecdsa.key, ctx->kactx.ecdsa.num * sizeof (AJ_ECCPublicKey)); if (NULL == ctx->kactx.ecdsa.key) { status = AJ_ERR_RESOURCES; goto Exit; } memcpy(&ctx->kactx.ecdsa.key[ctx->kactx.ecdsa.num - 1], &node->certificate.tbs.publickey, sizeof (AJ_ECCPublicKey)); } if (AJ_ERR_NO_MORE != status) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Certificate chain error %s\n", ctx, msg, AJ_StatusText(status))); status = AJ_ERR_SECURITY; goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container2); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container1); if (AJ_OK != status) { goto Exit; } if (NULL == root) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Certificate chain missing\n", ctx, msg)); status = AJ_ERR_SECURITY; goto Exit; } /* Initial chain verification to validate intermediate issuers. * Type is ignored for auth version < 4. */ if (AJ_UNPACK_AUTH_VERSION(version) < CONVERSATION_V4) { type = 0; } else { type = AJ_CERTIFICATE_IDN_X509; } status = AJ_X509VerifyChain(root, NULL, type); if (AJ_OK == status) { /* Verify the root certificate against the stored authorities */ status = AJ_PolicyVerifyCertificate(&root->certificate, &pub); if (AJ_OK == status) { /* Copy the public key (issuer) */ ctx->kactx.ecdsa.num++; ctx->kactx.ecdsa.key = (AJ_ECCPublicKey*) AJ_Realloc(ctx->kactx.ecdsa.key, ctx->kactx.ecdsa.num * sizeof (AJ_ECCPublicKey)); if (NULL == ctx->kactx.ecdsa.key) { status = AJ_ERR_RESOURCES; goto Exit; } memcpy(&ctx->kactx.ecdsa.key[ctx->kactx.ecdsa.num - 1], &pub, sizeof (pub)); } else { /* Search for the intermediate issuers in the stored authorities */ status = AJ_PolicyFindAuthority(root); } if (AJ_OK == status) { trusted = 1; } /* Last resort, ask the application to verify the chain */ if (!trusted && (NULL != ctx->bus->authListenerCallback)) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Certificate authority unknown\n", ctx, msg)); /* Ask the application to verify the chain */ cred.direction = AJ_CRED_RESPONSE; cred.data = (uint8_t*) root; status = ctx->bus->authListenerCallback(AUTH_SUITE_ECDHE_ECDSA, AJ_CRED_CERT_CHAIN, &cred); if (AJ_OK != status) { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Certificate chain rejected by app\n", ctx, msg)); goto Exit; } trusted = 1; } } else { AJ_InfoPrintf(("ECDSAUnmarshal(ctx=%p, msg=%p): Certificate chain invalid\n", ctx, msg)); } Exit: /* Free the cert chain */ while (root) { node = root; root = root->next; AJ_Free(node); } if (AJ_OK != status) { /* Free issuers */ if (ctx->kactx.ecdsa.key) { AJ_Free(ctx->kactx.ecdsa.key); ctx->kactx.ecdsa.key = NULL; ctx->kactx.ecdsa.num = 0; } } return trusted ? AJ_OK : AJ_ERR_SECURITY; } AJ_Status AJ_KeyAuthenticationMarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status = AJ_ERR_SECURITY; switch (ctx->suite) { case AUTH_SUITE_ECDHE_NULL: status = NULLMarshal(ctx, msg); break; case AUTH_SUITE_ECDHE_PSK: status = PSKMarshal(ctx, msg); break; case AUTH_SUITE_ECDHE_ECDSA: status = ECDSAMarshal(ctx, msg); break; case AUTH_SUITE_ECDHE_SPEKE: /* Same marshalling as ECDHE_NULL. */ status = NULLMarshal(ctx, msg); break; } return status; } AJ_Status AJ_KeyAuthenticationUnmarshal(AJ_AuthenticationContext* ctx, AJ_Message* msg) { AJ_Status status = AJ_ERR_SECURITY; switch (ctx->suite) { case AUTH_SUITE_ECDHE_NULL: status = NULLUnmarshal(ctx, msg); break; case AUTH_SUITE_ECDHE_PSK: status = PSKUnmarshal(ctx, msg); break; case AUTH_SUITE_ECDHE_ECDSA: status = ECDSAUnmarshal(ctx, msg, ctx->version); break; case AUTH_SUITE_ECDHE_SPEKE: /* Same unmarshalling as ECDHE_NULL. */ status = NULLUnmarshal(ctx, msg); break; } return status; } uint8_t AJ_IsSuiteEnabled(AJ_BusAttachment* bus, uint32_t suite, uint32_t version) { switch (suite) { case AUTH_SUITE_ECDHE_NULL: return 1 == bus->suites[0]; case AUTH_SUITE_ECDHE_PSK: return 1 == bus->suites[1]; case AUTH_SUITE_ECDHE_ECDSA: if (version < 3) { return 0; } return 1 == bus->suites[2]; case AUTH_SUITE_ECDHE_SPEKE: return 1 == bus->suites[3]; default: return 0; } return 0; } void AJ_EnableSuite(AJ_BusAttachment* bus, uint32_t suite) { switch (suite) { case AUTH_SUITE_ECDHE_NULL: bus->suites[0] = 1; break; case AUTH_SUITE_ECDHE_PSK: bus->suites[1] = 1; break; case AUTH_SUITE_ECDHE_ECDSA: bus->suites[2] = 1; break; case AUTH_SUITE_ECDHE_SPEKE: bus->suites[3] = 1; break; } } ajtcl-16.04/src/aj_authorisation.c000066400000000000000000002043641271074662300171400ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE AUTHORISATION #include #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgAUTHORISATION = 0; #endif #define POLICY_SPECIFICATION_VERSION 1 /** * Constants for some message argument signatures. */ static const char* s_ManifestMsgArgSignature = "(ua(ssa(syy))saysay)"; static const char* s_ManifestMsgArgDigestSignature = "(ua(ssa(syy))says)"; static const char* s_ManifestArrayMsgArgSignature = "a(ua(ssa(syy))saysay)"; /* * Policy helper struct. * Contains a buffer of the raw marshalled data, * and an AJ_Policy struct referencing inside the buffer. */ typedef struct _Policy { AJ_CredField buffer; AJ_Policy* policy; } Policy; Policy g_policy = { { 0, NULL }, NULL }; #define POLICY_METHOD_INCOMING 0x01 #define POLICY_METHOD_OUTGOING 0x02 #define POLICY_PRPSET_INCOMING 0x04 #define POLICY_PRPSET_OUTGOING 0x08 #define POLICY_SIGNAL_INCOMING POLICY_METHOD_INCOMING #define POLICY_SIGNAL_OUTGOING POLICY_METHOD_OUTGOING #define POLICY_PRPGET_INCOMING POLICY_METHOD_INCOMING #define POLICY_PRPGET_OUTGOING POLICY_METHOD_OUTGOING #define POLICY_PRPALL_INCOMING POLICY_METHOD_INCOMING #define POLICY_PRPALL_OUTGOING POLICY_METHOD_OUTGOING #define MANIFEST_METHOD_INCOMING (POLICY_METHOD_INCOMING << 4) #define MANIFEST_METHOD_OUTGOING (POLICY_METHOD_OUTGOING << 4) #define MANIFEST_PRPSET_INCOMING (POLICY_PRPSET_INCOMING << 4) #define MANIFEST_PRPSET_OUTGOING (POLICY_PRPSET_OUTGOING << 4) #define MANIFEST_SIGNAL_INCOMING MANIFEST_METHOD_INCOMING #define MANIFEST_SIGNAL_OUTGOING MANIFEST_METHOD_OUTGOING #define MANIFEST_PRPGET_INCOMING MANIFEST_METHOD_INCOMING #define MANIFEST_PRPGET_OUTGOING MANIFEST_METHOD_OUTGOING #define MANIFEST_PRPALL_INCOMING MANIFEST_METHOD_INCOMING #define MANIFEST_PRPALL_OUTGOING MANIFEST_METHOD_OUTGOING #define POLICY_INCOMING (POLICY_METHOD_INCOMING | POLICY_PRPSET_INCOMING) #define POLICY_OUTGOING (POLICY_METHOD_OUTGOING | POLICY_PRPSET_OUTGOING) #define MANIFEST_INCOMING (MANIFEST_METHOD_INCOMING | MANIFEST_PRPSET_INCOMING) #define MANIFEST_OUTGOING (MANIFEST_METHOD_OUTGOING | MANIFEST_PRPSET_OUTGOING) #define POLICY_ACCESS (POLICY_INCOMING | POLICY_OUTGOING) #define MANIFEST_ACCESS (MANIFEST_INCOMING | MANIFEST_OUTGOING) /* * The main access control structure. * Maps message ids to peer's access. */ typedef struct _AccessControlMember { uint32_t id; const char* obj; const char* ifn; const char* mbr; uint8_t deny[AJ_NAME_MAP_GUID_SIZE]; uint8_t allow[AJ_NAME_MAP_GUID_SIZE]; struct _AccessControlMember* next; } AccessControlMember; static AJ_PermissionRule* g_manifestRules = NULL; static AccessControlMember* g_access = NULL; static void AccessControlClose(void) { AccessControlMember* member; while (g_access) { member = g_access; g_access = g_access->next; AJ_Free(member); } } /* * Iterates through all object/interface descriptions * and saves the names and ids for each secure member. * The object, interface and member names are used when * applying policy. * The member id is used when applying access control * for each incoming or outgoing message. */ static AJ_Status AccessControlRegister(const AJ_Object* list, uint8_t l) { const AJ_Object* obj; const AJ_InterfaceDescription* interfaces; AJ_InterfaceDescription iface; const char* ifn; const char* mbr; uint8_t secure; uint8_t i, m; uint16_t n = 0; AccessControlMember* member; uint32_t properties; AJ_InfoPrintf(("AccessControlRegister(list=%p, l=%x)\n", list, l)); if (NULL == list) { /* Nothing to add to the list */ return AJ_OK; } while (list[n].path) { obj = &list[n++]; interfaces = obj->interfaces; if (!interfaces) { continue; } i = 0; properties = FALSE; while (*interfaces) { iface = *interfaces++; ifn = *iface++; AJ_ASSERT(ifn); secure = obj->flags & AJ_OBJ_FLAG_SECURE; secure |= (SECURE_TRUE == *ifn); secure &= ~(SECURE_OFF == *ifn); /* Only access control secure objects/interfaces */ if (secure) { m = 0; while (*iface) { mbr = *iface++; member = (AccessControlMember*) AJ_Malloc(sizeof (AccessControlMember)); if (NULL == member) { AJ_WarnPrintf(("AccessControlRegister(list=%p, l=%x): AJ_ERR_RESOURCES\n", list, l)); goto Exit; } memset(member, 0, sizeof (AccessControlMember)); member->obj = obj->path; member->ifn = ifn; member->mbr = mbr; member->id = AJ_ENCODE_MESSAGE_ID(l, n - 1, i, m); member->next = g_access; g_access = member; properties |= (PROPERTY == MEMBER_TYPE(*mbr)); AJ_InfoPrintf(("AccessControlRegister: id 0x%08X obj %s ifn %s mbr %s\n", member->id, obj->path, ifn, mbr)); m++; } if (properties) { /* Add special member to handle DBus.Properties GetAll method */ member = (AccessControlMember*) AJ_Malloc(sizeof (AccessControlMember)); if (NULL == member) { AJ_WarnPrintf(("AccessControlRegister(list=%p, l=%x): AJ_ERR_RESOURCES\n", list, l)); goto Exit; } memset(member, 0, sizeof (AccessControlMember)); member->obj = obj->path; member->ifn = ifn; /* Setting the member to "@" will match an PROPERTY with wildcard for member name */ member->mbr = "@"; member->id = AJ_INVALID_MSG_ID; member->next = g_access; g_access = member; AJ_InfoPrintf(("AccessControlRegister: id 0x%08X obj %s ifn %s mbr %s\n", member->id, obj->path, ifn, member->mbr)); } } i++; } } return AJ_OK; Exit: return AJ_ERR_RESOURCES; } static void AccessControlDeregister(uint8_t l) { AccessControlMember* node; AccessControlMember* head = g_access; /* Remove nodes from beginning of the list */ while (NULL != head) { if (l == (head->id >> 24)) { AJ_InfoPrintf(("AccessControlDeregister: id 0x%08X obj %s ifn %s mbr %s\n", head->id, head->obj, head->ifn, head->mbr)); node = head; head = head->next; AJ_Free(node); } else { break; } } g_access = head; if (NULL == g_access) { return; } /* Remove nodes from rest of the list */ while (NULL != head->next) { if (l == (head->next->id >> 24)) { AJ_InfoPrintf(("AccessControlDeregister: id 0x%08X obj %s ifn %s mbr %s\n", head->next->id, head->next->obj, head->next->ifn, head->next->mbr)); node = head->next; head->next = node->next; AJ_Free(node); } else { head = head->next; } } } static AccessControlMember* FindAccessControlMember(uint32_t id) { AccessControlMember* mbr; if (!g_access) { AJ_WarnPrintf(("FindAccessControlMember(id=0x%08X): Access table not initialised\n", id)); return NULL; } // This linked list is a reverse ordered list mbr = g_access; while (mbr && (id != mbr->id)) { mbr = mbr->next; } return mbr; } static uint32_t IsInterface(const char* std, const char* ifn) { const char* s = std; AJ_ASSERT(std); AJ_ASSERT(ifn); if (SECURE_OFF == *std) { s++; } return (0 == strcmp(s, ifn)); } static uint32_t PropertiesInterface(const char* ifn) { return IsInterface(AJ_PropertiesIface[0], ifn); } static uint32_t StandardInterface(const char* ifn) { /* * We could include all the standard interfaces. * Currently we only expect encrypted messages * on org.alljoyn.Bus.Peer.Authentication */ return IsInterface(PeerAuthInterface, ifn); } static AccessControlMember* FindGetAllMember(const void* buf, size_t len) { AccessControlMember* acm = g_access; const char* ifn; while (acm) { ifn = acm->ifn; /* Skip over secure annotation */ if ((SECURE_TRUE == *ifn) || (SECURE_OFF == *ifn)) { ifn++; } if ((AJ_INVALID_MSG_ID == acm->id) && (len == strlen(ifn) && (0 == AJ_Crypto_Compare(buf, acm->ifn, len)))) { /* Same interface */ return acm; } acm = acm->next; } return NULL; } static AJ_Status PropertiesInterfaceCheck(const AJ_Message* msg, uint8_t direction, uint32_t peer) { AccessControlMember* acm; uint8_t* buf; uint32_t len; uint8_t acc; AJ_InfoPrintf(("PropertiesInterfaceCheck(msg=%p, direction=%x, peer=%d): 0x%08X\n", msg, direction, peer, msg->msgId)); /* All incoming calls are handled when marshalling/unmarshalling the property id */ if (AJ_ACCESS_INCOMING == direction) { return AJ_OK; } /* Get and Set outgoing are handled when marshalling/unmarshalling the property id */ if ((AJ_PROP_GET == (msg->msgId & 0xFF)) || (AJ_PROP_SET == (msg->msgId & 0xFF))) { return AJ_OK; } /* * Get the target interface from the message body. */ buf = msg->bus->sock.tx.bufStart + sizeof(AJ_MsgHeader) + msg->hdr->headerLen + HEADERPAD(msg->hdr->headerLen); len = *(uint32_t*) buf; buf += sizeof (uint32_t); acm = FindGetAllMember(buf, len); if (acm) { acc = acm->deny[peer] ? 0 : acm->allow[peer]; if ((POLICY_PRPALL_OUTGOING & acc) && (MANIFEST_PRPALL_OUTGOING & acc)) { return AJ_OK; } } acm = acm->next; return AJ_ERR_ACCESS; } AJ_Status AJ_AccessControlCheckMessage(const AJ_Message* msg, const char* name, uint8_t direction) { AJ_Status status; AccessControlMember* mbr; uint32_t peer; uint8_t acc; AJ_InfoPrintf(("AJ_AccessControlCheckMessage(msg=%p, name=%s, direction=%x): Obj %s Ifn %s Mbr %s\n", msg, name, direction, msg->objPath, msg->iface, msg->member)); /* * We may get encrypted messages on "unsecured" interfaces. * org.freedesktop.DBus.Properties * org.alljoyn.Bus.Peer.Authentication */ if (StandardInterface(msg->iface)) { AJ_InfoPrintf(("AJ_AccessControlCheckMessage(msg=%p, name=%s, direction=%x): AJ_OK\n", msg, name, direction)); return AJ_OK; } /* Check Peer.Authentication before this because we don't have a peer entry yet */ status = AJ_GetPeerIndex(name, &peer); if (AJ_OK != status) { return AJ_ERR_ACCESS; } if (PropertiesInterface(msg->iface)) { status = PropertiesInterfaceCheck(msg, direction, peer); AJ_InfoPrintf(("AJ_AccessControlCheckMessage(msg=%p, name=%s, direction=%x): %s\n", msg, name, direction, AJ_StatusText(status))); return status; } mbr = FindAccessControlMember(msg->msgId); if (NULL == mbr) { AJ_WarnPrintf(("AJ_AccessControlCheckMessage(msg=%p, name=%s, direction=%x): Member 0x%08X not in table AJ_ERR_ACCESS\n", msg, name, direction, msg->msgId)); return AJ_ERR_ACCESS; } status = AJ_ERR_ACCESS; acc = mbr->deny[peer] ? 0 : mbr->allow[peer]; switch (direction) { case AJ_ACCESS_INCOMING: if ((POLICY_METHOD_INCOMING & acc) && (MANIFEST_METHOD_INCOMING & acc)) { status = AJ_OK; } break; case AJ_ACCESS_OUTGOING: if ((POLICY_METHOD_OUTGOING & acc) && (MANIFEST_METHOD_OUTGOING & acc)) { status = AJ_OK; } break; } AJ_InfoPrintf(("AJ_AccessControlCheck(msg=%p, name=%s, direction=%x): 0x%08X %X %s\n", msg, name, direction, msg->msgId, acc, AJ_StatusText(status))); return status; } AJ_Status AJ_AccessControlCheckProperty(const AJ_Message* msg, uint32_t id, const char* name, uint8_t direction) { AJ_Status status; AccessControlMember* mbr; uint32_t peer; uint8_t acc; AJ_InfoPrintf(("AJ_AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x)\n", msg, id, name, direction)); status = AJ_GetPeerIndex(name, &peer); if (AJ_OK != status) { AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x): Peer not in table\n", msg, id, name, direction)); return AJ_ERR_ACCESS; } mbr = FindAccessControlMember(id); if (NULL == mbr) { AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x): Property not in table AJ_ERR_ACCESS\n", msg, id, name, direction)); return AJ_ERR_ACCESS; } status = AJ_ERR_ACCESS; acc = mbr->deny[peer] ? 0 : mbr->allow[peer]; switch (direction) { case AJ_ACCESS_INCOMING: switch (msg->msgId & 0xFF) { case AJ_PROP_GET: case AJ_PROP_GET_ALL: if ((POLICY_PRPGET_INCOMING & acc) && (MANIFEST_PRPGET_INCOMING & acc)) { status = AJ_OK; } else { AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x, message id 0x%08X): acc = 0x%08X -> AJ_ERR_ACCESS\n", msg, id, name, direction, msg->msgId, (uint32_t)acc)); } break; case AJ_PROP_SET: if ((POLICY_PRPSET_INCOMING & acc) && (MANIFEST_PRPSET_INCOMING & acc)) { status = AJ_OK; } else { AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x, message id 0x%08X): acc = 0x%08X -> AJ_ERR_ACCESS\n", msg, id, name, direction, msg->msgId, (uint32_t)acc)); } break; default: AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x): Invalid message id 0x%08X\n", msg, id, name, direction, msg->msgId)); AJ_ASSERT(0); break; } break; case AJ_ACCESS_OUTGOING: switch (msg->msgId & 0xFF) { case AJ_PROP_GET: case AJ_PROP_GET_ALL: if ((POLICY_PRPGET_OUTGOING & acc) && (MANIFEST_PRPGET_OUTGOING & acc)) { status = AJ_OK; } else { AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x, message id 0x%08X): acc = 0x%08X -> AJ_ERR_ACCESS\n", msg, id, name, direction, msg->msgId, (uint32_t)acc)); } break; case AJ_PROP_SET: if ((POLICY_PRPSET_OUTGOING & acc) && (MANIFEST_PRPSET_OUTGOING & acc)) { status = AJ_OK; } else { AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x, message id 0x%08X): acc = 0x%08X -> AJ_ERR_ACCESS\n", msg, id, name, direction, msg->msgId, (uint32_t)acc)); } break; default: AJ_WarnPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x): Invalid message id 0x%08X\n", msg, id, name, direction, msg->msgId)); AJ_ASSERT(0); break; } break; } AJ_InfoPrintf(("AccessControlCheckProperty(msg=%p, id=0x%08X, name=%s, direction=%x): %s\n", msg, id, name, direction, AJ_StatusText(status))); return status; } /* * Clears all previous (if any) access control for an index */ AJ_Status AJ_AccessControlReset(const char* name) { AJ_Status status; AccessControlMember* node = g_access; uint32_t peer; AJ_InfoPrintf(("AJ_AccessControlReset(name=%s)\n", name)); status = AJ_GetPeerIndex(name, &peer); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_AccessControlReset(name=%s): Peer not in table\n", name)); return status; } while (node) { node->allow[peer] = 0; node->deny[peer] = 0; node = node->next; } return AJ_OK; } void AJ_ManifestTemplateSet(AJ_PermissionRule* manifest) { AJ_InfoPrintf(("AJ_ManifestTemplateSet(manifest=%p)\n", manifest)); g_manifestRules = manifest; } #ifndef NDEBUG static void PermissionMemberDump(AJ_PermissionMember* member) { while (member) { AJ_InfoPrintf((" Member %s (%x:%x)\n", member->mbr, member->type, member->action)); member = member->next; } } static void PermissionRuleDump(AJ_PermissionRule* rule) { while (rule) { AJ_InfoPrintf((" Rule : %s : %s\n", rule->obj, rule->ifn)); PermissionMemberDump(rule->members); rule = rule->next; } } static void ManifestDump(AJ_Manifest* manifest) { if (manifest) { AJ_InfoPrintf(("Manifest\n")); AJ_InfoPrintf(("Version: %u\n", manifest->version)); AJ_InfoPrintf(("Rules:\n----\n")); PermissionRuleDump(manifest->rules); AJ_InfoPrintf(("---\n")); AJ_InfoPrintf(("Thumbprint algorithm OID: %s\n", manifest->thumbprintAlgorithmOid)); AJ_DumpBytes("Thumbprint", manifest->thumbprint, manifest->thumbprintSize); AJ_InfoPrintf(("Signature algorithm OID: %s\n", manifest->signatureAlgorithmOid)); AJ_DumpBytes("Signature", manifest->signature, manifest->signatureSize); } } static void PermissionPeerDump(AJ_PermissionPeer* peer) { while (peer) { AJ_InfoPrintf((" Peer : Type %x\n", peer->type)); switch (peer->type) { case AJ_PEER_TYPE_FROM_CA: case AJ_PEER_TYPE_WITH_PUBLIC_KEY: AJ_InfoPrintf((" ECC PublicKey (algorithm %x, curve %x)\n", peer->pub.alg, peer->pub.crv)); AJ_DumpBytes("X", peer->pub.x, KEY_ECC_SZ); AJ_DumpBytes("Y", peer->pub.y, KEY_ECC_SZ); break; case AJ_PEER_TYPE_WITH_MEMBERSHIP: AJ_InfoPrintf((" ECC PublicKey (algorithm %x, curve %x)\n", peer->pub.alg, peer->pub.crv)); AJ_DumpBytes("X", peer->pub.x, KEY_ECC_SZ); AJ_DumpBytes("Y", peer->pub.y, KEY_ECC_SZ); AJ_DumpBytes("GROUP", peer->group.data, peer->group.size); break; } peer = peer->next; } } static void PermissionACLDump(AJ_PermissionACL* acl) { while (acl) { PermissionPeerDump(acl->peers); PermissionRuleDump(acl->rules); acl = acl->next; } } static void PolicyDump(AJ_Policy* policy) { if (policy) { AJ_InfoPrintf(("Policy : Specification %x : Version %x\n", policy->specification, policy->version)); PermissionACLDump(policy->acls); } } #endif static void AJ_PermissionMemberFree(AJ_PermissionMember* head) { AJ_PermissionMember* node; while (head) { node = head; head = head->next; AJ_Free(node); } } static void AJ_PermissionRuleFree(AJ_PermissionRule* head) { AJ_PermissionRule* node; while (head) { node = head; head = head->next; AJ_PermissionMemberFree(node->members); AJ_Free(node); } } void AJ_ManifestFree(AJ_Manifest* manifest) { if (manifest) { AJ_PermissionRuleFree(manifest->rules); AJ_Free(manifest); } } static void ManifestArrayElementFree(AJ_ManifestArray* node) { if (NULL != node) { AJ_ManifestFree(node->manifest); AJ_Free(node); } } void AJ_ManifestArrayFree(AJ_ManifestArray* manifests) { if (NULL != manifests) { AJ_ManifestArray* node; while (manifests) { node = manifests; manifests = manifests->next; ManifestArrayElementFree(node); } } } static void AJ_PermissionPeerFree(AJ_PermissionPeer* head) { AJ_PermissionPeer* node; while (head) { node = head; head = head->next; AJ_Free(node); } } static void AJ_PermissionACLFree(AJ_PermissionACL* head) { AJ_PermissionACL* node; while (head) { node = head; head = head->next; AJ_PermissionPeerFree(node->peers); AJ_PermissionRuleFree(node->rules); AJ_Free(node); } } void AJ_PolicyFree(AJ_Policy* policy) { if (policy) { AJ_PermissionACLFree(policy->acls); AJ_Free(policy); } } //SIG = a(syy) static AJ_Status AJ_PermissionMemberMarshal(const AJ_PermissionMember* head, AJ_Message* msg) { AJ_Status status; AJ_Arg container; status = AJ_MarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { return status; } while (head) { status = AJ_MarshalArgs(msg, "(syy)", head->mbr, (uint8_t) head->type, (uint8_t) head->action); if (AJ_OK != status) { return status; } head = head->next; } status = AJ_MarshalCloseContainer(msg, &container); return status; } //SIG = a(ssa(syy)) static AJ_Status AJ_PermissionRuleMarshal(const AJ_PermissionRule* head, AJ_Message* msg) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; status = AJ_MarshalContainer(msg, &container1, AJ_ARG_ARRAY); if (AJ_OK != status) { return status; } while (head) { status = AJ_MarshalContainer(msg, &container2, AJ_ARG_STRUCT); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(msg, "ss", head->obj, head->ifn); if (AJ_OK != status) { return status; } status = AJ_PermissionMemberMarshal(head->members, msg); if (AJ_OK != status) { return status; } status = AJ_MarshalCloseContainer(msg, &container2); if (AJ_OK != status) { return status; } head = head->next; } status = AJ_MarshalCloseContainer(msg, &container1); return status; } /* SIG = (ua(ssa(syy))saysay) if useForDigest is FALSE * SIG = (ua(ssa(syy))says) if useForDigest is TRUE */ AJ_Status AJ_ManifestMarshal(AJ_Manifest* manifest, AJ_Message* msg, uint8_t useForDigest) { AJ_Status status; AJ_Arg outerStruct; if (NULL == manifest) { return AJ_ERR_INVALID; } status = AJ_MarshalContainer(msg, &outerStruct, AJ_ARG_STRUCT); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(msg, "u", manifest->version); if (AJ_OK != status) { return status; } status = AJ_PermissionRuleMarshal(manifest->rules, msg); // SIG = a(ssa(syy)) if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(msg, "says", manifest->thumbprintAlgorithmOid, manifest->thumbprint, manifest->thumbprintSize, manifest->signatureAlgorithmOid); if (AJ_OK != status) { return status; } if (!useForDigest) { status = AJ_MarshalArgs(msg, "ay", manifest->signature, manifest->signatureSize); if (AJ_OK != status) { return status; } } status = AJ_MarshalCloseContainer(msg, &outerStruct); return status; } //SIG = a(ua(ssa(syy))saysay) AJ_Status AJ_ManifestArrayMarshal(AJ_ManifestArray* manifests, AJ_Message* msg) { AJ_Status status; AJ_Arg container; status = AJ_MarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { return status; } while (manifests) { status = AJ_ManifestMarshal(manifests->manifest, msg, FALSE); // SIG = (ua(ssa(syy))saysay) if (AJ_OK != status) { return status; } manifests = manifests->next; } status = AJ_MarshalCloseContainer(msg, &container); return status; } AJ_Status AJ_ManifestTemplateMarshal(AJ_Message* msg) { return AJ_PermissionRuleMarshal(g_manifestRules, msg); } AJ_Status AJ_MarshalDefaultPolicy(AJ_CredField* field, AJ_PermissionPeer* peer_ca, AJ_PermissionPeer* peer_admin) { AJ_Status status; /* Any authenticated peer */ AJ_PermissionPeer peer_any; peer_any.type = AJ_PEER_TYPE_ANY_TRUSTED; peer_any.next = NULL; { /* All allowed */ AJ_PermissionMember member_admin = { "*", AJ_MEMBER_TYPE_ANY, AJ_ACTION_PROVIDE | AJ_ACTION_OBSERVE | AJ_ACTION_MODIFY, NULL }; /* Outgoing allowed, incoming signal allowed */ AJ_PermissionMember member_any0 = { "*", AJ_MEMBER_TYPE_ANY, AJ_ACTION_PROVIDE, NULL }; AJ_PermissionMember member_any1 = { "*", AJ_MEMBER_TYPE_SIGNAL, AJ_ACTION_OBSERVE, &member_any0 }; AJ_PermissionRule rule_admin = { "*", "*", &member_admin, NULL }; AJ_PermissionRule rule_any = { "*", "*", &member_any1, NULL }; AJ_PermissionACL acl_ca = { peer_ca, NULL, NULL }; AJ_PermissionACL acl_admin = { peer_admin, &rule_admin, &acl_ca }; AJ_PermissionACL acl_any = { &peer_any, &rule_any, &acl_admin }; AJ_Policy policy = { POLICY_SPECIFICATION_VERSION, 0, &acl_any }; /* Marshal the policy */ status = AJ_PolicyToBuffer(&policy, field); } return status; } //SIG = a(ya(yyayay)ay) static AJ_Status AJ_PermissionPeerMarshal(const AJ_PermissionPeer* head, AJ_Message* msg) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; AJ_Arg container3; status = AJ_MarshalContainer(msg, &container1, AJ_ARG_ARRAY); if (AJ_OK != status) { return status; } while (head) { status = AJ_MarshalContainer(msg, &container2, AJ_ARG_STRUCT); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(msg, "y", head->type); if (AJ_OK != status) { return status; } // Marshal key (optional) status = AJ_MarshalContainer(msg, &container3, AJ_ARG_ARRAY); if (AJ_OK != status) { return status; } switch (head->type) { case AJ_PEER_TYPE_FROM_CA: case AJ_PEER_TYPE_WITH_PUBLIC_KEY: case AJ_PEER_TYPE_WITH_MEMBERSHIP: status = AJ_MarshalArgs(msg, "(yyayayay)", head->pub.alg, head->pub.crv, head->kid.data, head->kid.size, head->pub.x, KEY_ECC_SZ, head->pub.y, KEY_ECC_SZ); if (AJ_OK != status) { return status; } break; } status = AJ_MarshalCloseContainer(msg, &container3); if (AJ_OK != status) { return status; } // Marshal group (optional) if (AJ_PEER_TYPE_WITH_MEMBERSHIP == head->type) { status = AJ_MarshalArgs(msg, "ay", head->group.data, head->group.size); } else { status = AJ_MarshalArgs(msg, "ay", head->group.data, 0); } if (AJ_OK != status) { return status; } status = AJ_MarshalCloseContainer(msg, &container2); if (AJ_OK != status) { return status; } head = head->next; } status = AJ_MarshalCloseContainer(msg, &container1); return status; } //SIG = a(a(ya(yyayay)ay)a(ssa(syy))) static AJ_Status AJ_PermissionACLMarshal(const AJ_PermissionACL* head, AJ_Message* msg) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; status = AJ_MarshalContainer(msg, &container1, AJ_ARG_ARRAY); if (AJ_OK != status) { return status; } while (head) { status = AJ_MarshalContainer(msg, &container2, AJ_ARG_STRUCT); if (AJ_OK != status) { return status; } status = AJ_PermissionPeerMarshal(head->peers, msg); if (AJ_OK != status) { return status; } status = AJ_PermissionRuleMarshal(head->rules, msg); if (AJ_OK != status) { return status; } status = AJ_MarshalCloseContainer(msg, &container2); if (AJ_OK != status) { return status; } head = head->next; } status = AJ_MarshalCloseContainer(msg, &container1); return status; } //SIG = (qua(a(ya(yyayay)ay)a(ssa(syy)))) AJ_Status AJ_PolicyMarshal(const AJ_Policy* policy, AJ_Message* msg) { AJ_Status status; AJ_Arg container; if (NULL == policy) { return AJ_ERR_INVALID; } status = AJ_MarshalContainer(msg, &container, AJ_ARG_STRUCT); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(msg, "qu", policy->specification, policy->version); if (AJ_OK != status) { return status; } status = AJ_PermissionACLMarshal(policy->acls, msg); if (AJ_OK != status) { return status; } status = AJ_MarshalCloseContainer(msg, &container); return status; } //SIG = a(syy) static AJ_Status AJ_PermissionMemberUnmarshal(AJ_PermissionMember** head, AJ_Message* msg) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; AJ_PermissionMember* node; AJ_PermissionMember* curr = NULL; status = AJ_UnmarshalContainer(msg, &container1, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } while (AJ_OK == status) { status = AJ_UnmarshalContainer(msg, &container2, AJ_ARG_STRUCT); if (AJ_OK != status) { break; } node = (AJ_PermissionMember*) AJ_Malloc(sizeof (AJ_PermissionMember)); if (NULL == node) { goto Exit; } /* Push onto tail to maintain order */ node->next = NULL; if (curr) { curr->next = node; } else { *head = node; } curr = node; status = AJ_UnmarshalArgs(msg, "syy", &node->mbr, &node->type, &node->action); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container2); } if (AJ_ERR_NO_MORE != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container1); if (AJ_OK != status) { goto Exit; } return AJ_OK; Exit: //Cleanup AJ_PermissionMemberFree(*head); *head = NULL; return AJ_ERR_INVALID; } //SIG = a(ssa(syy)) static AJ_Status AJ_PermissionRuleUnmarshal(AJ_PermissionRule** head, AJ_Message* msg) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; AJ_PermissionRule* node; AJ_PermissionRule* curr = NULL; status = AJ_UnmarshalContainer(msg, &container1, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } while (AJ_OK == status) { status = AJ_UnmarshalContainer(msg, &container2, AJ_ARG_STRUCT); if (AJ_OK != status) { break; } node = (AJ_PermissionRule*) AJ_Malloc(sizeof (AJ_PermissionRule)); if (NULL == node) { goto Exit; } node->members = NULL; /* Push onto tail to maintain order */ node->next = NULL; if (curr) { curr->next = node; } else { *head = node; } curr = node; status = AJ_UnmarshalArgs(msg, "ss", &node->obj, &node->ifn); if (AJ_OK != status) { goto Exit; } status = AJ_PermissionMemberUnmarshal(&node->members, msg); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container2); } if (AJ_ERR_NO_MORE != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container1); if (AJ_OK != status) { goto Exit; } return AJ_OK; Exit: //Cleanup AJ_PermissionRuleFree(*head); *head = NULL; return AJ_ERR_INVALID; } //SIG = a(ua(ssa(syy))saysay) AJ_Status AJ_ManifestUnmarshal(AJ_Manifest** manifest, AJ_Message* msg) { AJ_Status status; AJ_Manifest* tmp; AJ_Arg outerStruct; uint8_t* beginning = NULL; tmp = (AJ_Manifest*) AJ_Malloc(sizeof (AJ_Manifest)); if (NULL == tmp) { return AJ_ERR_RESOURCES; } memset(tmp, 0, sizeof(AJ_Manifest)); beginning = msg->bus->sock.rx.readPtr; status = AJ_UnmarshalContainer(msg, &outerStruct, AJ_ARG_STRUCT); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalArgs(msg, "u", &tmp->version); if (AJ_OK != status) { goto Exit; } status = AJ_PermissionRuleUnmarshal(&tmp->rules, msg); // SIG = a(ssa(syy)) if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalArgs(msg, "saysay", &tmp->thumbprintAlgorithmOid, &tmp->thumbprint, &tmp->thumbprintSize, &tmp->signatureAlgorithmOid, &tmp->signature, &tmp->signatureSize); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &outerStruct); if (AJ_OK != status) { goto Exit; } AJ_ASSERT((msg->bus->sock.rx.readPtr - beginning) <= 0xFFFF); tmp->serializedSize = (uint16_t)(msg->bus->sock.rx.readPtr - beginning); *manifest = tmp; return AJ_OK; Exit: AJ_ManifestFree(tmp); return status; } AJ_Status AJ_ManifestArrayUnmarshal(AJ_ManifestArray** manifests, AJ_Message* msg) { AJ_Status status; AJ_Arg container; AJ_Manifest* manifest; AJ_ManifestArray* node; AJ_ManifestArray* curr = NULL; status = AJ_UnmarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { return status; } while (AJ_OK == status) { status = AJ_ManifestUnmarshal(&manifest, msg); if (AJ_OK != status) { break; } node = (AJ_ManifestArray*)AJ_Malloc(sizeof(AJ_ManifestArray)); if (NULL == node) { status = AJ_ERR_RESOURCES; break; } node->manifest = manifest; node->next = NULL; if (NULL != curr) { curr->next = node; } else { *manifests = node; } curr = node; } if (AJ_ERR_NO_MORE != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container); if (AJ_OK != status) { goto Exit; } return AJ_OK; Exit: AJ_ManifestArrayFree(*manifests); *manifests = NULL; return status; } //SIG = a(ya(yyayayay)ay) static AJ_Status AJ_PermissionPeerUnmarshal(AJ_PermissionPeer** head, AJ_Message* msg) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; AJ_Arg container3; AJ_PermissionPeer* node; AJ_PermissionPeer* curr = NULL; status = AJ_UnmarshalContainer(msg, &container1, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } while (AJ_OK == status) { status = AJ_UnmarshalContainer(msg, &container2, AJ_ARG_STRUCT); if (AJ_OK != status) { break; } node = (AJ_PermissionPeer*) AJ_Malloc(sizeof (AJ_PermissionPeer)); if (NULL == node) { status = AJ_ERR_RESOURCES; goto Exit; } /* Push onto tail to maintain order */ node->next = NULL; if (curr) { curr->next = node; } else { *head = node; } curr = node; status = AJ_UnmarshalArgs(msg, "y", &node->type); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalContainer(msg, &container3, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } // Unmarshal key (optional) switch (node->type) { case AJ_PEER_TYPE_FROM_CA: case AJ_PEER_TYPE_WITH_PUBLIC_KEY: case AJ_PEER_TYPE_WITH_MEMBERSHIP: status = AJ_UnmarshalECCPublicKey(msg, &node->pub, &node->kid); if (AJ_OK != status) { goto Exit; } break; } status = AJ_UnmarshalCloseContainer(msg, &container3); if (AJ_OK != status) { goto Exit; } // Unmarshal group (optional) status = AJ_UnmarshalArgs(msg, "ay", &node->group.data, &node->group.size); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container2); } if (AJ_ERR_NO_MORE != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container1); if (AJ_OK != status) { goto Exit; } return AJ_OK; Exit: //Cleanup AJ_PermissionPeerFree(*head); *head = NULL; return AJ_ERR_INVALID; } //SIG = a(a(ya(yyayayay)ay)a(ssa(syy))) static AJ_Status AJ_PermissionACLUnmarshal(AJ_PermissionACL** head, AJ_Message* msg) { AJ_Status status; AJ_Arg container1; AJ_Arg container2; AJ_PermissionACL* node; AJ_PermissionACL* curr = NULL; status = AJ_UnmarshalContainer(msg, &container1, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } while (AJ_OK == status) { status = AJ_UnmarshalContainer(msg, &container2, AJ_ARG_STRUCT); if (AJ_OK != status) { break; } node = (AJ_PermissionACL*) AJ_Malloc(sizeof (AJ_PermissionACL)); if (NULL == node) { goto Exit; } node->peers = NULL; node->rules = NULL; /* Push onto tail to maintain order */ node->next = NULL; if (curr) { curr->next = node; } else { *head = node; } curr = node; status = AJ_PermissionPeerUnmarshal(&node->peers, msg); if (AJ_OK != status) { break; } status = AJ_PermissionRuleUnmarshal(&node->rules, msg); if (AJ_OK != status) { break; } status = AJ_UnmarshalCloseContainer(msg, &container2); } if (AJ_ERR_NO_MORE != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container1); if (AJ_OK != status) { goto Exit; } return AJ_OK; Exit: //Cleanup AJ_PermissionACLFree(*head); *head = NULL; return AJ_ERR_INVALID; } //SIG = (qua(a(ya(yyayayay)ay)a(ssa(syy)))) AJ_Status AJ_PolicyUnmarshal(AJ_Policy** policy, AJ_Message* msg) { AJ_Status status; AJ_Arg container; AJ_Policy* tmp = NULL; tmp = (AJ_Policy*) AJ_Malloc(sizeof (AJ_Policy)); if (NULL == tmp) { goto Exit; } tmp->acls = NULL; status = AJ_UnmarshalContainer(msg, &container, AJ_ARG_STRUCT); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalArgs(msg, "qu", &tmp->specification, &tmp->version); if (AJ_OK != status) { goto Exit; } status = AJ_PermissionACLUnmarshal(&tmp->acls, msg); if (AJ_OK != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container); if (AJ_OK != status) { goto Exit; } *policy = tmp; return AJ_OK; Exit: //Cleanup AJ_PolicyFree(tmp); return AJ_ERR_INVALID; } AJ_Status AJ_ManifestDigest(AJ_CredField* manifest, uint8_t digest[AJ_SHA256_DIGEST_LENGTH]) { AJ_SHA256_Context* ctx; ctx = AJ_SHA256_Init(); if (!ctx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx, manifest->data, manifest->size); return AJ_SHA256_Final(ctx, digest); } void AJ_PolicyUnload(void) { AJ_CredFieldFree(&g_policy.buffer); g_policy.buffer.data = NULL; AJ_PolicyFree(g_policy.policy); g_policy.policy = NULL; } AJ_Status AJ_PolicyLoad(void) { AJ_Status status; AJ_InfoPrintf(("PolicyLoad()\n")); /* Unload any previously loaded policy */ AJ_PolicyUnload(); /* Read the installed policy from NVRAM */ status = AJ_CredentialGet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, NULL, &g_policy.buffer); if (AJ_OK != status) { AJ_InfoPrintf(("PolicyLoad(): No installed policy\n")); /* Read the default policy from NVRAM */ status = AJ_CredentialGet(AJ_POLICY_DEFAULT | AJ_CRED_TYPE_POLICY, NULL, NULL, &g_policy.buffer); } if (AJ_OK != status) { AJ_InfoPrintf(("PolicyLoad(): No default policy\n")); goto Exit; } /* Unmarshal the policy */ status = AJ_PolicyFromBuffer(&g_policy.policy, &g_policy.buffer); if (AJ_OK != status) { AJ_InfoPrintf(("PolicyLoad(): Unmarshal failed\n")); goto Exit; } #ifndef NDEBUG PolicyDump(g_policy.policy); #endif return AJ_OK; Exit: AJ_PolicyUnload(); return AJ_ERR_INVALID; } AJ_Status AJ_AuthorisationRegister(const AJ_Object* list, uint8_t l) { /* Register objects on the access control list, deregister any old entries first */ AccessControlDeregister(l); return AccessControlRegister(list, l); } void AJ_AuthorisationClose(void) { /* Unload access control list */ AccessControlClose(); /* Unload policy (if not unloaded during last handshake) */ AJ_PolicyUnload(); } uint8_t AJ_CommonPath(const char* name, const char* desc, uint8_t type) { if (!name || !desc) { return 0; } /* Skip past common characters, or until a wildcard is hit */ while (*name) { if ('*' == *name) { return 1; } if (*name++ != *desc++) { return 0; } } /* * Property annotation has read/write value directly after the name. * Methods and signals have a space before arguments or null if no arguments. */ if (PROPERTY == type) { return ((WRITE_ONLY == *desc) || (READ_WRITE == *desc) || (READ_ONLY == *desc)); } else { return (('\0' == *desc) || (' ' == *desc)); } } static uint8_t MemberType(uint8_t a, uint8_t b) { switch (a) { case AJ_MEMBER_TYPE_ANY: return 1; case AJ_MEMBER_TYPE_SIGNAL: return (SIGNAL == b); case AJ_MEMBER_TYPE_METHOD: return (METHOD == b); case AJ_MEMBER_TYPE_PROPERTY: return (PROPERTY == b); } return 0; } static uint8_t PermissionRuleAccess(AJ_PermissionRule* rule, AccessControlMember* acm, uint32_t peer, uint8_t with_public_key) { AJ_PermissionMember* member; uint8_t type; const char* obj; const char* ifn; const char* mbr; uint8_t acc = 0; obj = acm->obj; ifn = acm->ifn; /* Skip over secure annotation */ if ((SECURE_TRUE == *ifn) || (SECURE_OFF == *ifn)) { ifn++; } mbr = acm->mbr; type = MEMBER_TYPE(*mbr); mbr++; /* Skip over sessionless annotation */ if (SESSIONLESS == *mbr) { mbr++; } while (rule) { if (AJ_CommonPath(rule->obj, obj, 0) && AJ_CommonPath(rule->ifn, ifn, 0)) { member = rule->members; while (member) { if (AJ_CommonPath(member->mbr, mbr, type) && MemberType(member->type, type)) { /* Access is the union of all rules */ switch (type) { case SIGNAL: if (AJ_ACTION_OBSERVE & member->action) { acc |= POLICY_SIGNAL_OUTGOING; } if (AJ_ACTION_PROVIDE & member->action) { acc |= POLICY_SIGNAL_INCOMING; } break; case METHOD: if (AJ_ACTION_PROVIDE & member->action) { acc |= POLICY_METHOD_OUTGOING; } if (AJ_ACTION_MODIFY & member->action) { acc |= POLICY_METHOD_INCOMING; } break; case PROPERTY: if (AJ_ACTION_PROVIDE & member->action) { acc |= POLICY_PRPSET_OUTGOING; acc |= POLICY_PRPGET_OUTGOING; } if (AJ_ACTION_MODIFY & member->action) { acc |= POLICY_PRPSET_INCOMING; } if (AJ_ACTION_OBSERVE & member->action) { acc |= POLICY_PRPGET_INCOMING; } break; } /* Only apply DENY if WITH_PUBLIC_KEY and rule is all wildcard */ if (with_public_key && ('*' == rule->obj[0]) && ('*' == rule->ifn[0]) && ('*' == member->mbr[0]) && (0 == member->action)) { /* Explicit deny both directions */ acm->deny[peer] = 1; } } member = member->next; } } rule = rule->next; } return acc; } AJ_Status AJ_ManifestApply(AJ_Manifest* manifest, const char* name, AJ_AuthenticationContext* ctx) { AJ_Status status; uint32_t peer; uint8_t acc; AccessControlMember* acm; AJ_CredField manifest_data; AJ_SHA256_Context* digestHashCtx; AJ_ECCSignature eccSignature; uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; AJ_InfoPrintf(("AJ_ManifestApply(manifest=%p, name=%s, ctx=%p)\n", manifest, name, ctx)); /* 2.16.840.1.101.3.4.2.1 is SHA-256. */ if (0 != strcmp("2.16.840.1.101.3.4.2.1", manifest->thumbprintAlgorithmOid)) { /* No other algorithm is supported presently. */ AJ_InfoPrintf(("Unsupported thumbprint algorithm: %s\n", manifest->thumbprintAlgorithmOid)); return AJ_ERR_INVALID; } /* 1.2.840.10045.4.3.2 is ECDSA with SHA-256. */ if (0 != strcmp("1.2.840.10045.4.3.2", manifest->signatureAlgorithmOid)) { AJ_InfoPrintf(("Unsupported signature algorithm: %s\n", manifest->signatureAlgorithmOid)); return AJ_ERR_INVALID; } if (0 == ctx->kactx.ecdsa.thumbprintSize) { /* No stored thumbprint, so no way we can apply the manifest. */ AJ_InfoPrintf(("No stored thumbprint to match manifest against\n")); return AJ_ERR_SECURITY_DIGEST_MISMATCH; } AJ_ASSERT(AJ_SHA256_DIGEST_LENGTH == ctx->kactx.ecdsa.thumbprintSize); if (manifest->thumbprintSize != ctx->kactx.ecdsa.thumbprintSize) { /* Thumbprint sizes differ. */ AJ_InfoPrintf(("Thumbprint sizes differ: manifest is %u, stored is %u", (uint32_t)manifest->thumbprintSize, (uint32_t)ctx->kactx.ecdsa.thumbprintSize)); return AJ_ERR_SECURITY_DIGEST_MISMATCH; } AJ_ASSERT(AJ_SHA256_DIGEST_LENGTH == ctx->kactx.ecdsa.thumbprintSize); if (0 != memcmp(manifest->thumbprint, ctx->kactx.ecdsa.thumbprint, ctx->kactx.ecdsa.thumbprintSize)) { AJ_InfoPrintf(("Manifest thumbprint does not equal thumbprint from authentication context\n")); AJ_DumpBytes("ManifestThumbprint", manifest->thumbprint, (uint32_t)manifest->thumbprintSize); AJ_DumpBytes("StoredThumbprint", ctx->kactx.ecdsa.thumbprint, (uint32_t)ctx->kactx.ecdsa.thumbprintSize); return AJ_ERR_SECURITY_DIGEST_MISMATCH; } if (manifest->signatureSize != (sizeof(eccSignature.r) + sizeof(eccSignature.s))) { AJ_InfoPrintf(("Signature field is wrong size: expected %u, got %u\n", (uint32_t)(sizeof(eccSignature.r) + sizeof(eccSignature.s)), (uint32_t)manifest->signatureSize)); return AJ_ERR_SECURITY_DIGEST_MISMATCH; } if (ctx->kactx.ecdsa.num < 2) { AJ_InfoPrintf(("Don't have identity certificate issuer's public key\n")); return AJ_ERR_SECURITY_DIGEST_MISMATCH; } manifest_data.size = manifest->serializedSize; manifest_data.data = (uint8_t*)AJ_Malloc(manifest->serializedSize); if (NULL == manifest_data.data) { return AJ_ERR_RESOURCES; } status = AJ_ManifestToBuffer(manifest, &manifest_data, TRUE); if (AJ_OK != status) { AJ_CredFieldFree(&manifest_data); return status; } if (manifest_data.size > manifest->serializedSize) { return AJ_ERR_END_OF_DATA; } /* Compute hash of manifest minus signature field. */ digestHashCtx = AJ_SHA256_Init(); if (!digestHashCtx) { AJ_CredFieldFree(&manifest_data); return AJ_ERR_RESOURCES; } AJ_SHA256_Update(digestHashCtx, manifest_data.data, manifest_data.size); status = AJ_SHA256_Final(digestHashCtx, digest); AJ_CredFieldFree(&manifest_data); if (AJ_OK != status) { return status; } /* Copy signature into signature object and verify. */ eccSignature.alg = KEY_ALG_ECDSA_SHA256; eccSignature.crv = KEY_CRV_NISTP256; memcpy(eccSignature.r, manifest->signature, sizeof(eccSignature.r)); memcpy(eccSignature.s, manifest->signature + sizeof(eccSignature.r), sizeof(eccSignature.s)); status = AJ_ECDSAVerifyDigest(digest, &eccSignature, &ctx->kactx.ecdsa.key[1]); if (AJ_OK != status) { AJ_InfoPrintf(("Signature failed to verify\n")); return AJ_ERR_SECURITY_DIGEST_MISMATCH; } status = AJ_GetPeerIndex(name, &peer); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_ManifestApply(manifest=%p, name=%s): Peer not in table\n", manifest, name)); return AJ_ERR_ACCESS; } #ifndef NDEBUG ManifestDump(manifest); #endif acm = g_access; while (acm) { acc = PermissionRuleAccess(manifest->rules, acm, peer, FALSE); /* Manifest permissions are stored in the most significant part of the byte */ acc <<= 4; #ifndef NDEBUG if (acc) { AJ_InfoPrintf(("Access: 0x%08X %s %s %s %x\n", acm->id, acm->obj, acm->ifn, acm->mbr, acc)); } #endif acm->allow[peer] |= acc; acm = acm->next; } return AJ_OK; } void AJ_ManifestArrayApply(AJ_ManifestArray* manifests, const char* name, AJ_AuthenticationContext* ctx) { AJ_Status status; AJ_InfoPrintf(("AJ_ManifestArrayApply(manifests=%p, name=%s, ctx=%p)\n", manifests, name, ctx)); /* If the peer isn't enabled for Security 2.0, it won't have any manifests. This is OK. */ if (NULL == manifests) { AJ_InfoPrintf(("AJ_ManifestArrayApply(name=%s, ctx=%p): Zero manifests received\n", name, ctx)); } /* Try to apply any manifests we got. Log if they fail but carry on. */ for (; NULL != manifests; manifests = manifests->next) { status = AJ_ManifestApply(manifests->manifest, name, ctx); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_ManifestArrayApply(manifests=%p, name=%s, ctx=%p): AJ_ManifestApply of manifest %p returned %u\n", manifests, name, ctx, manifests->manifest, status)); } } } static uint8_t PermissionPeerFind(AJ_PermissionPeer* head, uint8_t type, AJ_ECCPublicKey* pub, DER_Element* group) { while (head) { if (type == head->type) { if ((AJ_PEER_TYPE_ALL == type) || (AJ_PEER_TYPE_ANY_TRUSTED == type)) { return 1; } else { /* Type is FROM_CA or WITH_PUBLIC_KEY or WITH_MEMBERSHIP */ AJ_ASSERT(pub); if (0 == memcmp((uint8_t*) pub, (uint8_t*) &head->pub, sizeof (AJ_ECCPublicKey))) { if (AJ_PEER_TYPE_WITH_MEMBERSHIP == type) { AJ_ASSERT(group); if ((group->size == head->group.size) && (0 == memcmp(group->data, head->group.data, group->size))) { return 1; } } else { return 1; } } } } head = head->next; } return 0; } AJ_Status AJ_PolicyApply(AJ_AuthenticationContext* ctx, const char* name) { AJ_Status status; Policy* policy = &g_policy; uint32_t peer; uint8_t acc; AccessControlMember* acm; AJ_PermissionACL* acl; uint16_t state; uint16_t capabilities; uint16_t info; uint8_t found; size_t i; AJ_InfoPrintf(("AJ_PolicyApply(ctx=%p, name=%s)\n", ctx, name)); status = AJ_GetPeerIndex(name, &peer); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PolicyApply(ctx=%p, name=%s): Peer not in table\n", ctx, name)); return AJ_ERR_ACCESS; } if (policy->policy) { acl = policy->policy->acls; while (acl) { found = 0; /* Look for a match in the peer list */ found |= PermissionPeerFind(acl->peers, AJ_PEER_TYPE_ALL, NULL, NULL); if (AUTH_SUITE_ECDHE_NULL != ctx->suite) { found |= PermissionPeerFind(acl->peers, AJ_PEER_TYPE_ANY_TRUSTED, NULL, NULL); } if (AUTH_SUITE_ECDHE_ECDSA == ctx->suite) { AJ_ASSERT(ctx->kactx.ecdsa.key); /* With public key applies deny rules, flip the 2nd bit to indicate this type */ /* Subject public key is in array index 0 */ found |= (PermissionPeerFind(acl->peers, AJ_PEER_TYPE_WITH_PUBLIC_KEY, &ctx->kactx.ecdsa.key[0], NULL) << 1); /* Issuer public keys are in array index > 0, check root and all intermediates */ for (i = 1; (i < ctx->kactx.ecdsa.num) && !found; i++) { found |= PermissionPeerFind(acl->peers, AJ_PEER_TYPE_FROM_CA, &ctx->kactx.ecdsa.key[i], NULL); } } if (found) { acm = g_access; while (acm) { acc = PermissionRuleAccess(acl->rules, acm, peer, found >> 1); if (AUTH_SUITE_ECDHE_ECDSA != ctx->suite) { /* We don't receive a manifest, so switch those bits on too */ acc |= (acc << 4); } #ifndef NDEBUG if (acc) { AJ_InfoPrintf(("Access: 0x%08X %s %s %s %x\n", acm->id, acm->obj, acm->ifn, acm->mbr, acc)); } #endif acm->allow[peer] |= acc; acm = acm->next; } } acl = acl->next; } } else { AJ_InfoPrintf(("AJ_PolicyApply(ctx=%p, name=%p): No stored policy\n", ctx, name)); /* Initial restricted access rights */ acm = g_access; while (acm) { acm->allow[peer] = 0; switch (acm->id) { case AJ_METHOD_SECURITY_GET_PROP: case AJ_PROPERTY_SEC_VERSION: case AJ_PROPERTY_SEC_APPLICATION_STATE: case AJ_PROPERTY_SEC_MANIFEST_DIGEST: case AJ_PROPERTY_SEC_ECC_PUBLICKEY: case AJ_PROPERTY_SEC_MANUFACTURER_CERTIFICATE: case AJ_PROPERTY_SEC_MANIFEST_TEMPLATE: case AJ_PROPERTY_SEC_CLAIM_CAPABILITIES: case AJ_PROPERTY_SEC_CLAIM_CAPABILITIES_INFO: case AJ_PROPERTY_CLAIMABLE_VERSION: acm->allow[peer] = POLICY_INCOMING | MANIFEST_INCOMING; break; case AJ_METHOD_CLAIMABLE_CLAIM: /* Only allow claim if correct claim capabilities set */ AJ_SecurityGetClaimConfig(&state, &capabilities, &info); if (APP_STATE_CLAIMABLE == state) { if ((CLAIM_CAPABILITY_ECDHE_NULL & capabilities) && (AUTH_SUITE_ECDHE_NULL == ctx->suite)) { acm->allow[peer] = POLICY_INCOMING | MANIFEST_INCOMING; } else if ((CLAIM_CAPABILITY_ECDHE_PSK & capabilities) && (AUTH_SUITE_ECDHE_PSK == ctx->suite)) { acm->allow[peer] = POLICY_INCOMING | MANIFEST_INCOMING; } else if ((CLAIM_CAPABILITY_ECDHE_SPEKE & capabilities) && (AUTH_SUITE_ECDHE_SPEKE == ctx->suite)) { acm->allow[peer] = POLICY_INCOMING | MANIFEST_INCOMING; } else if ((CLAIM_CAPABILITY_ECDHE_ECDSA & capabilities) && (AUTH_SUITE_ECDHE_ECDSA == ctx->suite)) { acm->allow[peer] = POLICY_INCOMING | MANIFEST_INCOMING; } } break; case AJ_METHOD_SECURITY_SET_PROP: case AJ_PROPERTY_MANAGED_VERSION: case AJ_PROPERTY_MANAGED_IDENTITY: case AJ_PROPERTY_MANAGED_MANIFESTS: case AJ_PROPERTY_MANAGED_IDENTITY_CERT_ID: case AJ_PROPERTY_MANAGED_POLICY_VERSION: case AJ_PROPERTY_MANAGED_POLICY: case AJ_PROPERTY_MANAGED_DEFAULT_POLICY: case AJ_PROPERTY_MANAGED_MEMBERSHIP_SUMMARY: case AJ_METHOD_MANAGED_RESET: case AJ_METHOD_MANAGED_UPDATE_IDENTITY: case AJ_METHOD_MANAGED_UPDATE_POLICY: case AJ_METHOD_MANAGED_RESET_POLICY: case AJ_METHOD_MANAGED_INSTALL_MEMBERSHIP: case AJ_METHOD_MANAGED_REMOVE_MEMBERSHIP: case AJ_METHOD_MANAGED_START_MANAGEMENT: case AJ_METHOD_MANAGED_END_MANAGEMENT: case AJ_METHOD_MANAGED_INSTALL_MANIFESTS: /* Default not allowed */ break; default: /* All allowed incoming and outgoing (Security 1.0) */ acm->allow[peer] = POLICY_ACCESS | MANIFEST_ACCESS; } acm = acm->next; } } return AJ_OK; } AJ_Status AJ_MembershipApply(X509CertificateChain* root, AJ_ECCPublicKey* issuer, DER_Element* group, const char* name) { AJ_Status status; Policy* policy = &g_policy; uint32_t peer; uint8_t acc; AccessControlMember* acm; AJ_PermissionACL* acl; uint8_t found; AJ_InfoPrintf(("AJ_MembershipApply(root=%p, issuer=%p, group=%p, name=%s)\n", root, issuer, group, name)); status = AJ_GetPeerIndex(name, &peer); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_MembershipApply(root=%p, issuer=%p, group=%p, name=%s): Peer not in table\n", root, issuer, group, name)); return AJ_ERR_ACCESS; } if (policy->policy) { acl = policy->policy->acls; while (acl) { found = 0; /* Check if root issuer is in the peer list */ if (issuer) { found = PermissionPeerFind(acl->peers, AJ_PEER_TYPE_WITH_MEMBERSHIP, issuer, group); } if (NULL != root) { /* Check if intermediate issuer is in the peer list */ while (!found && (NULL != root->next)) { found = PermissionPeerFind(acl->peers, AJ_PEER_TYPE_WITH_MEMBERSHIP, &root->certificate.tbs.publickey, group); root = root->next; } } if (found) { acm = g_access; while (acm) { acc = PermissionRuleAccess(acl->rules, acm, peer, FALSE); #ifndef NDEBUG if (acc) { AJ_InfoPrintf(("Access: 0x%08X %s %s %s %x\n", acm->id, acm->obj, acm->ifn, acm->mbr, acc)); } #endif acm->allow[peer] |= acc; acm = acm->next; } } acl = acl->next; } } return AJ_OK; } AJ_Status AJ_PolicyVersion(uint32_t* version) { AJ_Status status; Policy* policy = &g_policy; status = AJ_PolicyLoad(); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PolicyVersion(version=%p): Policy not loaded\n", version)); return AJ_ERR_INVALID; } *version = policy->policy->version; AJ_PolicyUnload(); return AJ_OK; } static uint32_t ValidIssuer(const X509Certificate* cert, uint32_t type) { uint32_t eku = cert->tbs.extensions.type; /* This peer type can issue Identity and Unrestricted certificates */ if ((AJ_PEER_TYPE_FROM_CA == type) && (AJ_CERTIFICATE_IDN_X509 & eku)) { return TRUE; } /* This peer type can issue Identity, Membership and Unrestricted certificates */ if ((AJ_PEER_TYPE_WITH_MEMBERSHIP == type) && (AJ_CERTIFICATE_UNR_X509 & eku)) { return TRUE; } return FALSE; } AJ_Status AJ_PolicyFindAuthority(const X509CertificateChain* root) { AJ_Status status; Policy* policy = &g_policy; AJ_PermissionACL* acl; AJ_PermissionPeer* peer; const X509CertificateChain* node; AJ_ASSERT(root); if (NULL == policy->policy) { AJ_InfoPrintf(("AJ_PolicyFindAuthority(root=%p): Policy not loaded\n", root)); return AJ_ERR_INVALID; } status = AJ_ERR_SECURITY; acl = policy->policy->acls; while (acl) { peer = acl->peers; while (peer) { node = root; while ((node->next) && (node->certificate.tbs.extensions.ca)) { if (ValidIssuer(&node->next->certificate, peer->type)) { if (0 == memcmp(&node->certificate.tbs.publickey, &peer->pub, sizeof (AJ_ECCPublicKey))) { status = AJ_OK; goto Exit; } } node = node->next; } peer = peer->next; } acl = acl->next; } Exit: return status; } AJ_Status AJ_PolicyVerifyCertificate(const X509Certificate* cert, AJ_ECCPublicKey* pub) { AJ_Status status; Policy* policy = &g_policy; AJ_PermissionACL* acl; AJ_PermissionPeer* peer; AJ_ASSERT(cert); /* * Policy and/or certificate may not include AKI for CA, * we need to try all keys. */ if (NULL == policy->policy) { AJ_InfoPrintf(("AJ_PolicyVerifyCertificate(cert=%p, pub=%p): Policy not loaded\n", cert, pub)); return AJ_ERR_INVALID; } status = AJ_ERR_SECURITY; acl = policy->policy->acls; while (acl) { peer = acl->peers; while (peer) { if (ValidIssuer(cert, peer->type)) { /* Verify certificate */ status = AJ_X509Verify(cert, &peer->pub); if (AJ_OK == status) { memcpy(pub, &peer->pub, sizeof (AJ_ECCPublicKey)); goto Exit; } } peer = peer->next; } acl = acl->next; } Exit: return status; } AJ_Status AJ_ManifestToBuffer(AJ_Manifest* manifest, AJ_CredField* field, uint8_t useForDigest) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; const char* messageSignature; if (useForDigest) { messageSignature = s_ManifestMsgArgDigestSignature; } else { messageSignature = s_ManifestMsgArgSignature; } AJ_LocalMsg(&bus, &hdr, &msg, messageSignature, field->data, field->size); status = AJ_ManifestMarshal(manifest, &msg, useForDigest); AJ_ASSERT((bus.sock.tx.writePtr - field->data) <= 0xFFFF); AJ_ASSERT((bus.sock.tx.writePtr - field->data) <= field->size); field->size = (uint16_t)(bus.sock.tx.writePtr - field->data); return status; } AJ_Status AJ_ManifestArrayToBuffer(AJ_ManifestArray* manifests, AJ_CredField* field) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; AJ_LocalMsg(&bus, &hdr, &msg, s_ManifestArrayMsgArgSignature, field->data, field->size); status = AJ_ManifestArrayMarshal(manifests, &msg); AJ_ASSERT((bus.sock.tx.writePtr - field->data) <= 0xFFFF); field->size = (uint16_t)(bus.sock.tx.writePtr - field->data); return status; } AJ_Status AJ_ManifestFromBuffer(AJ_Manifest** manifest, AJ_CredField* field) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; AJ_LocalMsg(&bus, &hdr, &msg, s_ManifestMsgArgSignature, field->data, field->size); status = AJ_ManifestUnmarshal(manifest, &msg); return status; } AJ_Status AJ_ManifestArrayFromBuffer(AJ_ManifestArray** manifests, AJ_CredField* field) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; AJ_LocalMsg(&bus, &hdr, &msg, s_ManifestArrayMsgArgSignature, field->data, field->size); status = AJ_ManifestArrayUnmarshal(manifests, &msg); return status; } AJ_Status AJ_PolicyToBuffer(AJ_Policy* policy, AJ_CredField* field) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; AJ_LocalMsg(&bus, &hdr, &msg, "(qua(a(ya(yyayayay)ay)a(ssa(syy))))", field->data, field->size); status = AJ_PolicyMarshal(policy, &msg); AJ_ASSERT((bus.sock.tx.writePtr - field->data) <= 0xFFFF); field->size = (uint16_t)(bus.sock.tx.writePtr - field->data); return status; } AJ_Status AJ_PolicyFromBuffer(AJ_Policy** policy, AJ_CredField* field) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; AJ_LocalMsg(&bus, &hdr, &msg, "(qua(a(ya(yyayayay)ay)a(ssa(syy))))", field->data, field->size); status = AJ_PolicyUnmarshal(policy, &msg); return status; } uint8_t AJ_ManifestHasSignature(const AJ_Manifest* manifest) { AJ_InfoPrintf(("AJ_ManifestIsSigned(manifest=%p)\n", manifest)); if ((NULL == manifest->thumbprintAlgorithmOid) || (0 == strlen(manifest->thumbprintAlgorithmOid))) { AJ_InfoPrintf(("Manifest has no thumbprint algorithm OID\n")); return FALSE; } if ((NULL == manifest->thumbprint) || (0 == manifest->thumbprintSize)) { AJ_InfoPrintf(("Manifest has no thumbprint\n")); return FALSE; } if ((NULL == manifest->signatureAlgorithmOid) || (0 == strlen(manifest->signatureAlgorithmOid))) { AJ_InfoPrintf(("Manifest has no signature algorithm OID\n")); return FALSE; } if ((NULL == manifest->signature) || (0 == manifest->signatureSize)) { AJ_InfoPrintf(("Manifest has no signature\n")); return FALSE; } return TRUE; } void AJ_ManifestArrayFilterUnsigned(AJ_ManifestArray** manifests) { AJ_ManifestArray** elementAddress = manifests; AJ_ManifestArray* element; while (*elementAddress != NULL) { element = *elementAddress; if (AJ_ManifestHasSignature(element->manifest)) { elementAddress = &element->next; } else { *elementAddress = element->next; ManifestArrayElementFree(element); } } } ajtcl-16.04/src/aj_bufio.c000066400000000000000000000041101271074662300153360ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE BUFIO #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgBUFIO = 0; #endif void AJ_IOBufInit(AJ_IOBuffer* ioBuf, uint8_t* buffer, uint32_t bufLen, uint8_t direction, void* context) { ioBuf->bufStart = buffer; ioBuf->bufSize = bufLen; ioBuf->readPtr = buffer; ioBuf->writePtr = buffer; ioBuf->direction = direction; ioBuf->context = context; } void AJ_IOBufRebase(AJ_IOBuffer* ioBuf, size_t preserve) { int32_t unconsumed = AJ_IO_BUF_AVAIL(ioBuf); /* * Move any unconsumed data to the start of the I/O buffer */ if (unconsumed) { memmove(ioBuf->bufStart + preserve, ioBuf->readPtr, unconsumed); } ioBuf->readPtr = ioBuf->bufStart + preserve; ioBuf->writePtr = ioBuf->bufStart + preserve + unconsumed; } ajtcl-16.04/src/aj_bus.c000066400000000000000000001163601271074662300150360ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE BUS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgBUS = 0; #endif static AJ_Session* AJ_BusGetOngoingHostedSessionByPort(AJ_BusAttachment* bus, uint16_t port); static AJ_Session* AJ_BusGetPendingSession(AJ_BusAttachment* bus, uint32_t serial); static AJ_Session* AJ_BusGetBoundSession(AJ_BusAttachment* bus, uint16_t port); static void AJ_BusAddPendingSession(AJ_BusAttachment* bus, const char* host, uint16_t port, uint32_t serial); static void AJ_BusRemovePendingSession(AJ_BusAttachment* bus, uint32_t serial); static void AJ_BusAddBoundSession(AJ_BusAttachment* bus, uint32_t port, int multipoint); static void AJ_BusRemoveBoundSession(AJ_BusAttachment* bus, uint16_t port); static void AJ_BusAddOngoingSession(AJ_BusAttachment* bus, uint32_t sessionId, uint16_t port, int host, int multipoint, const char* otherParticipant); static void AJ_BusReleaseOngoingSession(AJ_Session* session); static void AJ_BusRemoveOngoingSession(AJ_BusAttachment* bus, uint32_t sessionId); const char* AJ_GetUniqueName(AJ_BusAttachment* bus) { return (*bus->uniqueName) ? bus->uniqueName : NULL; } AJ_Status AJ_BusRequestName(AJ_BusAttachment* bus, const char* name, uint32_t flags) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusRequestName(bus=0x%p, name=\"%s\", flags=0x%x)\n", bus, name, flags)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_REQUEST_NAME, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "su", name, flags); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusReleaseName(AJ_BusAttachment* bus, const char* name) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusReleaseName(bus=0x%p, name=\"%s\")\n", bus, name)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_RELEASE_NAME, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", name); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusAdvertiseName(AJ_BusAttachment* bus, const char* name, uint16_t transportMask, uint8_t op, uint8_t flags) { AJ_Status status; AJ_Message msg; uint32_t msgId = (op == AJ_BUS_START_ADVERTISING) ? AJ_METHOD_ADVERTISE_NAME : AJ_METHOD_CANCEL_ADVERTISE; AJ_InfoPrintf(("AJ_BusAdvertiseName(bus=0x%p, name=\"%s\", transportMask=0x%x, op=%d.)\n", bus, name, transportMask, op)); status = AJ_MarshalMethodCall(bus, &msg, msgId, AJ_BusDestination, 0, flags, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "sq", name, transportMask); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusFindAdvertisedName(AJ_BusAttachment* bus, const char* namePrefix, uint8_t op) { AJ_Status status; AJ_Message msg; uint32_t msgId = (op == AJ_BUS_START_FINDING) ? AJ_METHOD_FIND_NAME : AJ_METHOD_CANCEL_FIND_NAME; AJ_InfoPrintf(("AJ_BusFindAdvertiseName(bus=0x%p, namePrefix=\"%s\", op=%d.)\n", bus, namePrefix, op)); status = AJ_MarshalMethodCall(bus, &msg, msgId, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", namePrefix); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusFindAdvertisedNameByTransport(AJ_BusAttachment* bus, const char* namePrefix, uint16_t transport, uint8_t op) { AJ_Status status; AJ_Message msg; uint32_t msgId = (op == AJ_BUS_START_FINDING) ? AJ_METHOD_FIND_NAME_BY_TRANSPORT : AJ_METHOD_CANCEL_FIND_NAME_BY_TRANSPORT; AJ_InfoPrintf(("AJ_BusFindAdvertiseNameByTransport(bus=0x%p, namePrefix=\"%s\", transport=%d., op=%d.)\n", bus, namePrefix, transport, op)); status = AJ_MarshalMethodCall(bus, &msg, msgId, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "sq", namePrefix, transport); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } static AJ_Status MarshalSessionOpts(AJ_Message* msg, const AJ_SessionOpts* opts) { AJ_Arg dictionary; AJ_MarshalContainer(msg, &dictionary, AJ_ARG_ARRAY); AJ_MarshalArgs(msg, "{sv}", "traf", "y", opts->traffic); AJ_MarshalArgs(msg, "{sv}", "multi", "b", opts->isMultipoint); AJ_MarshalArgs(msg, "{sv}", "prox", "y", opts->proximity); AJ_MarshalArgs(msg, "{sv}", "trans", "q", opts->transports); AJ_MarshalCloseContainer(msg, &dictionary); return AJ_OK; } static AJ_Status UnmarshalSessionOpts(AJ_Message* msg, AJ_SessionOpts* opts) { AJ_Status status; AJ_Arg dictionary; AJ_UnmarshalContainer(msg, &dictionary, AJ_ARG_ARRAY); while (TRUE) { const char* key; AJ_Arg entry; status = AJ_UnmarshalContainer(msg, &entry, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(msg, "s", &key); if (status != AJ_OK) { break; } if (strcmp(key, "traf") == 0) { status = AJ_UnmarshalArgs(msg, "v", "y", &opts->traffic); } else if (strcmp(key, "multi") == 0) { status = AJ_UnmarshalArgs(msg, "v", "b", &opts->isMultipoint); } else if (strcmp(key, "prox") == 0) { status = AJ_UnmarshalArgs(msg, "v", "y", &opts->proximity); } else if (strcmp(key, "trans") == 0) { status = AJ_UnmarshalArgs(msg, "v", "q", &opts->transports); } else { AJ_SkipArg(msg); } if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(msg, &entry); if (status != AJ_OK) { break; } } AJ_UnmarshalCloseContainer(msg, &dictionary); if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } return status; } /* * Default session options */ static const AJ_SessionOpts defaultSessionOpts = { AJ_SESSION_TRAFFIC_MESSAGES, AJ_SESSION_PROXIMITY_ANY, AJ_TRANSPORT_ANY, FALSE }; AJ_Status AJ_BusBindSessionPort(AJ_BusAttachment* bus, uint16_t port, const AJ_SessionOpts* opts, uint8_t flags) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusBindSessionPort(bus=0x%p, port=%d., opts=0x%p)\n", bus, port, opts)); if (!opts) { opts = &defaultSessionOpts; } status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_BIND_SESSION_PORT, AJ_BusDestination, 0, flags, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { AJ_MarshalArgs(&msg, "q", port); status = MarshalSessionOpts(&msg, opts); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } if (status == AJ_OK) { AJ_BusAddBoundSession(bus, port, opts->isMultipoint); } return status; } AJ_Status AJ_BusUnbindSession(AJ_BusAttachment* bus, uint16_t port) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusUnbindSession(bus=0x%p, port=%d.)\n", bus, port)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_UNBIND_SESSION, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { AJ_MarshalArgs(&msg, "q", port); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } if (status == AJ_OK) { AJ_BusRemoveBoundSession(bus, port); } return status; } AJ_Status AJ_BusCancelSessionless(AJ_BusAttachment* bus, uint32_t serialNum) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusCancelSessionless(bus=0x%p, serialNum=%d.)\n", bus, serialNum)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_CANCEL_SESSIONLESS, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { AJ_MarshalArgs(&msg, "u", serialNum); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusJoinSession(AJ_BusAttachment* bus, const char* sessionHost, uint16_t port, const AJ_SessionOpts* opts) { AJ_Status status; AJ_Message msg; uint32_t serialNum; AJ_InfoPrintf(("AJ_BusJoinSession(bus=0x%p, sessionHost=\"%s\", port=%d., opts=0x%p)\n", bus, sessionHost, port, opts)); if (!opts) { opts = &defaultSessionOpts; } status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_JOIN_SESSION, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "sq", sessionHost, port); if (status == AJ_OK) { status = MarshalSessionOpts(&msg, opts); } } serialNum = msg.hdr->serialNum; if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } if (status == AJ_OK) { AJ_BusAddPendingSession(bus, sessionHost, port, serialNum); } return status; } AJ_Status AJ_BusLeaveSession(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusLeaveSession(bus=0x%p, sessionId=%d.)\n", bus, sessionId)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_LEAVE_SESSION, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "u", sessionId); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusSetLinkTimeout(AJ_BusAttachment* bus, uint32_t sessionId, uint32_t linkTimeout) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusSetLinkTimeout(bus=0x%p, sessionId=%d., linkTimeout=%d.)\n", bus, sessionId, linkTimeout)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_SET_LINK_TIMEOUT, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { (void)AJ_MarshalArgs(&msg, "u", sessionId); (void)AJ_MarshalArgs(&msg, "u", linkTimeout); status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusSetSignalRule(AJ_BusAttachment* bus, const char* ruleString, uint8_t rule) { return AJ_BusSetSignalRuleFlags(bus, ruleString, rule, 0); } AJ_Status AJ_BusSetSignalRuleSerial(AJ_BusAttachment* bus, const char* ruleString, uint8_t rule, uint8_t flags, uint32_t* serialNum) { AJ_Status status; AJ_Message msg; uint32_t msgId = (rule == AJ_BUS_SIGNAL_ALLOW) ? AJ_METHOD_ADD_MATCH : AJ_METHOD_REMOVE_MATCH; AJ_InfoPrintf(("AJ_BusSetSignalRuleSerial(bus=0x%p, ruleString=\"%s\", rule=%d.)\n", bus, ruleString, rule)); status = AJ_MarshalMethodCall(bus, &msg, msgId, AJ_DBusDestination, 0, flags, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { uint32_t sz = 0; uint8_t nul = 0; if (serialNum) { *serialNum = msg.hdr->serialNum; } sz = (uint32_t)strlen(ruleString); status = AJ_DeliverMsgPartial(&msg, sz + 5); AJ_MarshalRaw(&msg, &sz, 4); AJ_MarshalRaw(&msg, ruleString, strlen(ruleString)); AJ_MarshalRaw(&msg, &nul, 1); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusAddSignalRule(AJ_BusAttachment* bus, const char* signalName, const char* interfaceName, uint8_t rule) { AJ_Status status; AJ_Message msg; const char* str[5]; uint32_t msgId = (rule == AJ_BUS_SIGNAL_ALLOW) ? AJ_METHOD_ADD_MATCH : AJ_METHOD_REMOVE_MATCH; AJ_InfoPrintf(("AJ_BusAddSignalRule(bus=0x%p, signalName=\"%s\", interfaceName=\"%s\", rule=%d.)\n", bus, signalName, interfaceName, rule)); str[0] = "type='signal',member='"; str[1] = signalName; str[2] = "',interface='"; str[3] = interfaceName; str[4] = "'"; status = AJ_MarshalMethodCall(bus, &msg, msgId, AJ_DBusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { size_t i; uint32_t sz = 0; uint8_t nul = 0; for (i = 0; i < ArraySize(str); ++i) { sz += (uint32_t)strlen(str[i]); } status = AJ_DeliverMsgPartial(&msg, sz + 5); AJ_MarshalRaw(&msg, &sz, 4); for (i = 0; i < ArraySize(str); ++i) { AJ_MarshalRaw(&msg, str[i], strlen(str[i])); } AJ_MarshalRaw(&msg, &nul, 1); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusSetSignalRuleFlags(AJ_BusAttachment* bus, const char* ruleString, uint8_t rule, uint8_t flags) { return AJ_BusSetSignalRuleSerial(bus, ruleString, rule, flags, NULL); } AJ_Status AJ_BusReplyAcceptSession(AJ_Message* msg, uint32_t acpt) { AJ_Message reply; AJ_InfoPrintf(("AJ_BusReplyAcceptSession(msg=0x%p, accept=%d.)\n", msg, acpt)); AJ_MarshalReplyMsg(msg, &reply); AJ_MarshalArgs(&reply, "b", acpt); return AJ_DeliverMsg(&reply); } static AJ_Status HandleGetMachineId(AJ_Message* msg, AJ_Message* reply) { char guidStr[33]; AJ_GUID localGuid; AJ_InfoPrintf(("HandleGetMachineId(msg=0x%p, reply=0x%p)\n", msg, reply)); AJ_MarshalReplyMsg(msg, reply); AJ_GetLocalGUID(&localGuid); AJ_GUID_ToString(&localGuid, guidStr, sizeof(guidStr)); return AJ_MarshalArgs(reply, "s", guidStr); } AJ_Status AJ_BusRemoveSessionMember(AJ_BusAttachment* bus, uint32_t sessionId, const char* member) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusRemoveSessionMember(bus=0x%p, sessionId=%d, member=%s.)\n", bus, sessionId, member)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_REMOVE_SESSION_MEMBER, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { AJ_MarshalArgs(&msg, "us", sessionId, member); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusPing(AJ_BusAttachment* bus, const char* name, uint32_t timeout) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_BusPing(bus=0x%p, name=%s, timeout=%d)\n", bus, name, timeout)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_BUS_PING, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { AJ_MarshalArgs(&msg, "su", name, timeout); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusHandleBusMessage(AJ_Message* msg) { AJ_Status status = AJ_OK; AJ_BusAttachment* bus = msg->bus; char* languageTag; AJ_Message reply; uint32_t disposition; uint16_t port; uint32_t session; char* joiner; AJ_InfoPrintf(("AJ_BusHandleBusMessage(msg=0x%p)\n", msg)); memset(&reply, 0, sizeof(AJ_Message)); /* * Check we actually have a message to handle */ if (!msg->hdr) { return AJ_OK; } switch (msg->msgId) { case AJ_METHOD_PING: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_PING\n")); status = AJ_MarshalReplyMsg(msg, &reply); break; case AJ_METHOD_GET_MACHINE_ID: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_GET_MACHINE_ID\n")); status = HandleGetMachineId(msg, &reply); break; case AJ_METHOD_INTROSPECT: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_INTROSPECT\n")); status = AJ_GetIntrospectionData(msg, &reply); break; case AJ_METHOD_GET_DESCRIPTION_LANG: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_GET_DESCRIPTION_LANG\n")); status = AJ_HandleGetDescriptionLanguages(msg, &reply); break; case AJ_METHOD_INTROSPECT_WITH_DESC: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_INTROSPECT_WITH_DESC\n")); AJ_UnmarshalArgs(msg, "s", &languageTag); status = AJ_HandleIntrospectRequest(msg, &reply, languageTag); break; case AJ_METHOD_EXCHANGE_GUIDS: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_EXCHANGE_GUIDS\n")); status = AJ_PeerHandleExchangeGUIDs(msg, &reply); break; case AJ_METHOD_GEN_SESSION_KEY: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_GEN_SESSION_KEY\n")); status = AJ_PeerHandleGenSessionKey(msg, &reply); break; case AJ_METHOD_EXCHANGE_GROUP_KEYS: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_EXCHANGE_GROUP_KEYS\n")); status = AJ_PeerHandleExchangeGroupKeys(msg, &reply); break; case AJ_METHOD_EXCHANGE_SUITES: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_EXCHANGE_SUITES\n")); status = AJ_PeerHandleExchangeSuites(msg, &reply); break; case AJ_METHOD_KEY_EXCHANGE: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_KEY_EXCHANGE\n")); status = AJ_PeerHandleKeyExchange(msg, &reply); break; case AJ_METHOD_KEY_AUTHENTICATION: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_KEY_AUTHENTICATION\n")); status = AJ_PeerHandleKeyAuthentication(msg, &reply); break; case AJ_METHOD_SEND_MANIFESTS: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_SEND_MANIFESTS\n")); status = AJ_PeerHandleSendManifests(msg, &reply); break; case AJ_METHOD_SEND_MEMBERSHIPS: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_SEND_MEMBERSHIPS\n")); status = AJ_PeerHandleSendMemberships(msg, &reply); break; case AJ_REPLY_ID(AJ_METHOD_EXCHANGE_GUIDS): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_EXCHANGE_GUIDS)\n")); status = AJ_PeerHandleExchangeGUIDsReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_GEN_SESSION_KEY): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_GEN_SESSION_KEY)\n")); status = AJ_PeerHandleGenSessionKeyReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_EXCHANGE_GROUP_KEYS): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_EXCHANGE_GROUP_KEYS)\n")); status = AJ_PeerHandleExchangeGroupKeysReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_EXCHANGE_SUITES): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_EXCHANGE_SUITES)\n")); status = AJ_PeerHandleExchangeSuitesReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_KEY_EXCHANGE): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_KEY_EXCHANGE)\n")); status = AJ_PeerHandleKeyExchangeReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_KEY_AUTHENTICATION): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_KEY_AUTHENTICATION)\n")); status = AJ_PeerHandleKeyAuthenticationReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_SEND_MANIFESTS): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_SEND_MANIFESTS)\n")); status = AJ_PeerHandleSendManifestsReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_SEND_MEMBERSHIPS): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_SEND_MEMBERSHIPS)\n")); status = AJ_PeerHandleSendMembershipsReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_CANCEL_SESSIONLESS): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_CANCEL_SESSIONLESS)\n")); // handle return code here status = AJ_OK; break; case AJ_METHOD_ACCEPT_SESSION: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_METHOD_ACCEPT_SESSION\n")); status = AJ_UnmarshalArgs(msg, "qus", &port, &session, &joiner); if (AJ_OK != status) { break; } status = AJ_MarshalReplyMsg(msg, &reply); if (AJ_OK != status) { break; } /* We only accept sessions to the Security Management port */ if (AJ_SECURE_MGMT_PORT == port) { status = AJ_MarshalArgs(&reply, "b", TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", session, joiner)); } else { status = AJ_MarshalArgs(&reply, "b", FALSE); AJ_InfoPrintf(("Rejected session session_id=%u joiner=%s\n", session, joiner)); } break; case AJ_SIGNAL_SESSION_JOINED: case AJ_SIGNAL_NAME_ACQUIRED: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_SIGNAL_{SESSION_JOINED|NAME_ACQUIRED}\n")); // nothing to do here status = AJ_OK; break; case AJ_REPLY_ID(AJ_METHOD_CANCEL_ADVERTISE): case AJ_REPLY_ID(AJ_METHOD_ADVERTISE_NAME): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_{CANCEL_ADVERTISE|ADVERTISE_NAME})\n")); if (msg->hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } break; case AJ_REPLY_ID(AJ_METHOD_BIND_SESSION_PORT): AJ_InfoPrintf(("AJ_BusHandleBusMessage(): AJ_REPLY_ID(AJ_METHOD_BIND_SESSION_PORT)\n")); if (AJ_MSG_ERROR == msg->hdr->msgType) { status = AJ_ERR_FAILURE; break; } status = AJ_UnmarshalArgs(msg, "uq", &disposition, &port); if (AJ_OK != status) { break; } if ((AJ_BINDSESSIONPORT_REPLY_SUCCESS == disposition) && (AJ_SECURE_MGMT_PORT == port)) { status = AJ_SecurityBound(bus); } break; case AJ_METHOD_ABOUT_GET_PROP: return AJ_AboutHandleGetProp(msg); case AJ_METHOD_ABOUT_GET_ABOUT_DATA: status = AJ_AboutHandleGetAboutData(msg, &reply); break; case AJ_METHOD_ABOUT_GET_OBJECT_DESCRIPTION: status = AJ_AboutHandleGetObjectDescription(msg, &reply); break; case AJ_METHOD_ABOUT_ICON_GET_PROP: return AJ_AboutIconHandleGetProp(msg); case AJ_METHOD_ABOUT_ICON_GET_URL: status = AJ_AboutIconHandleGetURL(msg, &reply); break; case AJ_METHOD_ABOUT_ICON_GET_CONTENT: status = AJ_AboutIconHandleGetContent(msg, &reply); break; #ifdef ANNOUNCE_BASED_DISCOVERY case AJ_SIGNAL_ABOUT_ANNOUNCE: status = AJ_AboutHandleAnnounce(msg, NULL, NULL, NULL, NULL); break; #endif case AJ_METHOD_SECURITY_GET_PROP: return AJ_SecurityGetProperty(msg); case AJ_METHOD_CLAIMABLE_CLAIM: status = AJ_SecurityClaimMethod(msg, &reply); break; case AJ_METHOD_MANAGED_RESET: status = AJ_SecurityResetMethod(msg, &reply); break; case AJ_METHOD_MANAGED_UPDATE_IDENTITY: status = AJ_SecurityUpdateIdentityMethod(msg, &reply); break; case AJ_METHOD_MANAGED_UPDATE_POLICY: status = AJ_SecurityUpdatePolicyMethod(msg, &reply); break; case AJ_METHOD_MANAGED_RESET_POLICY: status = AJ_SecurityResetPolicyMethod(msg, &reply); break; case AJ_METHOD_MANAGED_INSTALL_MEMBERSHIP: status = AJ_SecurityInstallMembershipMethod(msg, &reply); break; case AJ_METHOD_MANAGED_REMOVE_MEMBERSHIP: status = AJ_SecurityRemoveMembershipMethod(msg, &reply); break; case AJ_METHOD_MANAGED_START_MANAGEMENT: status = AJ_SecurityStartManagementMethod(msg, &reply); break; case AJ_METHOD_MANAGED_END_MANAGEMENT: status = AJ_SecurityEndManagementMethod(msg, &reply); break; case AJ_METHOD_MANAGED_INSTALL_MANIFESTS: status = AJ_SecurityInstallManifestsMethod(msg, &reply); break; default: AJ_InfoPrintf(("AJ_BusHandleBusMessage(): default\n")); if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) { status = AJ_MarshalErrorMsg(msg, &reply, AJ_ErrRejected); } break; } if ((status == AJ_OK) && (msg->hdr->msgType == AJ_MSG_METHOD_CALL)) { status = AJ_DeliverMsg(&reply); } /* * Check if there is anything to announce */ if (status == AJ_OK) { AJ_AboutAnnounce(bus); AJ_ApplicationStateSignal(bus); } return status; } void AJ_BusSetPasswordCallback(AJ_BusAttachment* bus, AJ_AuthPwdFunc pwdCallback) { AJ_WarnPrintf(("AJ_BusSetPasswordCallback(bus=0x%p, pwdCallback=0x%p): This call is being deprecated.\n", bus, pwdCallback)); bus->pwdCallback = pwdCallback; } /** * Set a callback for auth listener * until a password callback function has been set. * * @param bus The bus attachment struct * @param authListenerCallback The auth listener callback function. */ void AJ_BusSetAuthListenerCallback(AJ_BusAttachment* bus, AJ_AuthListenerFunc authListenerCallback) { AJ_InfoPrintf(("AJ_BusSetAuthListenerCallback(bus=0x%p, authListenerCallback=0x%p)\n", bus, authListenerCallback)); bus->authListenerCallback = authListenerCallback; } /** * Set a callback for handling requests to factory reset any application state. * * @param bus The bus attachment struct * @param factoryResetCallback The factory reset callback function. */ void AJ_BusSetFactoryResetCallback(AJ_BusAttachment* bus, AJ_FactoryResetFunc factoryResetCallback) { AJ_InfoPrintf(("AJ_BusSetFactoryResetCallback(bus=0x%p, factoryResetCallback=0x%p)\n", bus, factoryResetCallback)); bus->factoryResetCallback = factoryResetCallback; } /** * Set a callback for handling security policy change notifications. * * @param bus The bus attachment struct * @param policyChangedCallback The policy changed callback function. */ void AJ_BusSetPolicyChangedCallback(AJ_BusAttachment* bus, AJ_PolicyChangedFunc policyChangedCallback) { AJ_InfoPrintf(("AJ_BusSetPolicyChangedCallback(bus=0x%p, policyChangedCallback=0x%p)\n", bus, policyChangedCallback)); bus->policyChangedCallback = policyChangedCallback; } AJ_Status AJ_BusAuthenticatePeer(AJ_BusAttachment* bus, const char* peerName, AJ_BusAuthPeerCallback callback, void* cbContext) { AJ_InfoPrintf(("AJ_BusAuthenticatePeer(bus=0x%p, peerName=\"%s\", callback=0x%p, cbContext=0x%p)\n", bus, peerName, callback, cbContext)); return AJ_PeerAuthenticate(bus, peerName, callback, cbContext); } typedef struct { void* context; union { AJ_BusPropGetCallback Get; AJ_BusPropSetCallback Set; }; } PropCallback; static AJ_Status PropAccess(AJ_Message* msg, PropCallback* cb, uint8_t op) { AJ_Status status; AJ_Message reply; uint32_t propId; const char* sig; AJ_InfoPrintf(("PropAccess(msg=0x%p, cb=0x%p, op=%s)\n", msg, cb, (op == AJ_PROP_GET) ? "get" : "set")); /* * Find out which property is being accessed and whether the access is a GET or SET */ status = AJ_UnmarshalPropertyArgs(msg, &propId, &sig); if (status == AJ_OK) { AJ_MarshalReplyMsg(msg, &reply); /* * Callback to let the application marshal or unmarshal the value */ if (op == AJ_PROP_GET) { AJ_MarshalVariant(&reply, sig); status = cb->Get(&reply, propId, cb->context); } else { const char* variant; AJ_UnmarshalVariant(msg, &variant); /* * Check that the value has the expected signature */ if (strcmp(sig, variant) == 0) { status = cb->Set(msg, propId, cb->context); } else { AJ_InfoPrintf(("PropAccess(): AJ_ERR_SIGNATURE\n")); status = AJ_ERR_SIGNATURE; } } } if (status != AJ_OK) { AJ_MarshalStatusMsg(msg, &reply, status); } return AJ_DeliverMsg(&reply); } static AJ_Status PropAccessAll(AJ_Message* msg, PropCallback* cb) { AJ_Status status; AJ_Message reply; const char* iface; AJ_InfoPrintf(("PropAccessAll(msg=0x%p, cb=0x%p)\n", msg, cb)); status = AJ_UnmarshalArgs(msg, "s", &iface); if (status == AJ_OK) { status = AJ_MarshalReplyMsg(msg, &reply); } if (status == AJ_OK) { status = AJ_MarshalAllPropertiesArgs(&reply, iface, cb->Get, cb->context); } if (status != AJ_OK) { AJ_MarshalStatusMsg(msg, &reply, status); } return AJ_DeliverMsg(&reply); } AJ_Status AJ_BusPropGet(AJ_Message* msg, AJ_BusPropGetCallback callback, void* context) { PropCallback cb; AJ_InfoPrintf(("AJ_BusPropGet(msg=0x%p, callback=0x%p, context=0x%p)\n", msg, callback, context)); cb.context = context; cb.Get = callback; return PropAccess(msg, &cb, AJ_PROP_GET); } AJ_Status AJ_BusPropSet(AJ_Message* msg, AJ_BusPropSetCallback callback, void* context) { PropCallback cb; AJ_InfoPrintf(("AJ_BusPropSet(msg=0x%p, callback=0x%p, context=0x%p)\n", msg, callback, context)); cb.context = context; cb.Set = callback; return PropAccess(msg, &cb, AJ_PROP_SET); } AJ_Status AJ_BusPropGetAll(AJ_Message* msg, AJ_BusPropGetCallback callback, void* context) { PropCallback cb; AJ_InfoPrintf(("AJ_BusPropGetAll(msg=0x%p, callback=0x%p, context=0x%p)\n", msg, callback, context)); cb.context = context; cb.Get = callback; return PropAccessAll(msg, &cb); } AJ_Status AJ_BusEnableSecurity(AJ_BusAttachment* bus, const uint32_t* suites, size_t numsuites) { size_t i; AJ_InfoPrintf(("AJ_BusEnableSecurity(bus=0x%p, suites=0x%p)\n", bus, suites)); /* Disable all first to undo any previous calls */ memset((uint8_t*) bus->suites, 0, sizeof (bus->suites)); for (i = 0; i < numsuites; i++) { AJ_EnableSuite(bus, suites[i]); } return AJ_SecurityInit(bus); } AJ_Session* AJ_BusGetOngoingSession(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Session* iter; for (iter = bus->sessions; iter; iter = iter->next) { if (iter->sessionId == sessionId) { return iter; } } return NULL; } static AJ_Session* AJ_BusGetOngoingHostedSessionByPort(AJ_BusAttachment* bus, uint16_t port) { AJ_Session* iter; for (iter = bus->sessions; iter; iter = iter->next) { if (iter->sessionId != 0 && iter->host && iter->sessionPort == port) { return iter; } } return NULL; } static AJ_Session* AJ_BusGetPendingSession(AJ_BusAttachment* bus, uint32_t serial) { AJ_Session* iter; for (iter = bus->sessions; iter; iter = iter->next) { if (iter->sessionId == 0 && !iter->host && iter->joinCallSerial == serial) { return iter; } } return NULL; } static AJ_Session* AJ_BusGetBoundSession(AJ_BusAttachment* bus, uint16_t port) { AJ_Session* iter; for (iter = bus->sessions; iter; iter = iter->next) { if (iter->sessionId == 0 && iter->host && iter->sessionPort == port) { return iter; } } return NULL; } static AJ_Session* SessionAlloc() { AJ_Session* session = AJ_Malloc(sizeof(AJ_Session)); if (session) { AJ_MemZeroSecure(session, sizeof(AJ_Session)); } else { AJ_ErrPrintf(("Could not allocate Session structure -- out of memory.\n")); } return session; } static void AJ_BusAddPendingSession(AJ_BusAttachment* bus, const char* host, uint16_t port, uint32_t serial) { size_t hostlen = strlen(host); AJ_Session* session = SessionAlloc(); if (!session) { return; } session->host = FALSE; session->sessionPort = port; session->joinCallSerial = serial; /* * We leave multipoint as FALSE and always fill in otherParticipant. * If the session turns out to be multipoint, we'll correct this in * the JoinSession reply handler (see ProcessBusMessages) */ session->multipoint = FALSE; session->otherParticipant = AJ_Malloc(hostlen + 1); if (!session->otherParticipant) { AJ_ErrPrintf(("Could not allocate Session structure -- out of memory.\n")); AJ_BusReleaseOngoingSession(session); return; } strncpy(session->otherParticipant, host, hostlen); session->otherParticipant[hostlen] = '\0'; session->next = bus->sessions; bus->sessions = session; } static void AJ_BusRemovePendingSession(AJ_BusAttachment* bus, uint32_t serial) { AJ_Session* iter; AJ_Session* prev = NULL; for (iter = bus->sessions; iter; prev = iter, iter = iter->next) { if (iter->sessionId == 0 && !iter->host && iter->joinCallSerial == serial) { break; } } if (!iter) { return; } if (prev) { prev->next = iter->next; } else { bus->sessions = iter->next; } AJ_BusReleaseOngoingSession(iter); } static void AJ_BusAddBoundSession(AJ_BusAttachment* bus, uint32_t port, int multipoint) { AJ_Session* session = SessionAlloc(); if (!session) { return; } session->host = TRUE; session->sessionPort = port; session->multipoint = multipoint; session->next = bus->sessions; bus->sessions = session; } static void AJ_BusRemoveBoundSession(AJ_BusAttachment* bus, uint16_t port) { AJ_Session* iter; AJ_Session* prev = NULL; for (iter = bus->sessions; iter; prev = iter, iter = iter->next) { if (iter->sessionId == 0 && iter->host && iter->sessionPort == port) { break; } } if (!iter) { return; } if (prev) { prev->next = iter->next; } else { bus->sessions = iter->next; } AJ_BusReleaseOngoingSession(iter); } static void AJ_BusAddOngoingSession(AJ_BusAttachment* bus, uint32_t sessionId, uint16_t port, int host, int multipoint, const char* otherParticipant) { AJ_Session* session = SessionAlloc(); if (!session) { return; } session->sessionId = sessionId; session->sessionPort = port; session->host = host; session->multipoint = multipoint; if (otherParticipant) { size_t otherlen = strlen(otherParticipant); session->otherParticipant = AJ_Malloc(otherlen + 1); if (!session->otherParticipant) { AJ_ErrPrintf(("Could not allocate Session structure -- out of memory.\n")); AJ_BusReleaseOngoingSession(session); return; } strncpy(session->otherParticipant, otherParticipant, otherlen); session->otherParticipant[otherlen] = '\0'; } else { session->otherParticipant = NULL; } session->next = bus->sessions; bus->sessions = session; } static void AJ_BusReleaseOngoingSession(AJ_Session* session) { if (session->otherParticipant) { AJ_Free(session->otherParticipant); } AJ_Free(session); } static void AJ_BusRemoveOngoingSession(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Session* iter; AJ_Session* prev = NULL; for (iter = bus->sessions; iter; prev = iter, iter = iter->next) { if (iter->sessionId == sessionId) { break; } } if (!iter) { return; } if (prev) { prev->next = iter->next; } else { bus->sessions = iter->next; } AJ_BusReleaseOngoingSession(iter); } void AJ_BusRemoveAllSessions(AJ_BusAttachment* bus) { while (bus->sessions) { AJ_Session* session = bus->sessions; bus->sessions = session->next; AJ_BusReleaseOngoingSession(session); } } AJ_Status AJ_BusHandleSessionJoined(AJ_Message* msg) { uint16_t sessionPort; uint32_t sessionId; char* joiner; AJ_Session* boundsession; AJ_Status status = AJ_UnmarshalArgs(msg, "qus", &sessionPort, &sessionId, &joiner); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_BusHandleSessionJoined(msg=0x%p): Unmarshal error\n", msg)); return status; } boundsession = AJ_BusGetBoundSession(msg->bus, sessionPort); if (boundsession) { int multipoint = boundsession->multipoint; if (multipoint) { /* if there already is an OngoingSession entry for this session, * we don't have to add another one. */ AJ_Session* ongoing = AJ_BusGetOngoingHostedSessionByPort(msg->bus, sessionPort); if (ongoing != NULL) { return AJ_OK; } else { AJ_BusAddOngoingSession(msg->bus, sessionId, sessionPort, TRUE, TRUE, NULL); } } else { AJ_BusAddOngoingSession(msg->bus, sessionId, sessionPort, TRUE, FALSE, joiner); } } else { AJ_ErrPrintf(("AJ_BusHandleSessionJoined(msg=0x%p): unknown session port\n", msg)); return AJ_ERR_FAILURE; } return AJ_OK; } AJ_Status AJ_BusHandleSessionLost(AJ_Message* msg) { uint32_t sessionId; AJ_Status status = AJ_UnmarshalArgs(msg, "u", &sessionId); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_BusHandleSessionLost(msg=0x%p): Unmarshal error\n", msg)); return status; } AJ_BusRemoveOngoingSession(msg->bus, sessionId); return AJ_OK; } AJ_Status AJ_BusHandleSessionLostWithReason(AJ_Message* msg) { uint32_t sessionId; uint32_t reason; AJ_Status status = AJ_UnmarshalArgs(msg, "uu", &sessionId, &reason); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_BusHandleSessionLostWithReason(msg=0x%p): Unmarshal error\n", msg)); return status; } AJ_BusRemoveOngoingSession(msg->bus, sessionId); return AJ_OK; } AJ_Status AJ_BusHandleJoinSessionReply(AJ_Message* msg) { uint32_t resultCode; uint32_t sessionId; AJ_SessionOpts opts = { 0 }; AJ_Status status; AJ_Session* session; if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_InfoPrintf(("AJ_BusHandleSessionJoinSessionReply(msg=0x%p): error=%s.\n", msg, msg->error)); /* it's OK for the JoinSession reply to be an error message - it simply means * we can remove the pending session here */ AJ_BusRemovePendingSession(msg->bus, msg->replySerial); return AJ_OK; } status = AJ_UnmarshalArgs(msg, "uu", &resultCode, &sessionId); if (status != AJ_OK) { goto unmarshal_error; } status = UnmarshalSessionOpts(msg, &opts); if (status != AJ_OK) { goto unmarshal_error; } /* now we can fill in the pending AJ_Session structure */ session = AJ_BusGetPendingSession(msg->bus, msg->replySerial); if (session) { session->sessionId = sessionId; session->multipoint = opts.isMultipoint; if (opts.isMultipoint) { AJ_Free(session->otherParticipant); session->otherParticipant = NULL; } } else { AJ_ErrPrintf(("AJ_BusHandleSessionJoinSessionReply(msg=0x%p): JoinSession reply for unknown JoinSession call\n", msg)); return AJ_ERR_FAILURE; } return AJ_OK; unmarshal_error: AJ_ErrPrintf(("AJ_BusHandleJoinSessionReply(msg=0x%p): Unmarshal error\n", msg)); return status; } ajtcl-16.04/src/aj_cert.c000066400000000000000000001051651271074662300152030ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CERTIFICATE #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgCERTIFICATE = 0; #endif /** * DER encoding types. */ #define ASN_BOOLEAN 0x01 #define ASN_INTEGER 0x02 #define ASN_BITS 0x03 #define ASN_OCTETS 0x04 #define ASN_NULL 0x05 #define ASN_OID 0x06 #define ASN_UTF8 0x0C #define ASN_SEQ 0x10 #define ASN_SET_OF 0x11 #define ASN_PRINTABLE 0x13 #define ASN_ASCII 0x16 #define ASN_UTC_TIME 0x17 #define ASN_GEN_TIME 0x18 #define ASN_CONTEXT_SPECIFIC 0x80 #define ASN_UNKNOWN 0xFF /** * PEM encoding tags */ #define PEM_PRIV_BEG "-----BEGIN EC PRIVATE KEY-----" #define PEM_PRIV_END "-----END EC PRIVATE KEY-----" #define PEM_CERT_BEG "-----BEGIN CERTIFICATE-----" #define PEM_CERT_END "-----END CERTIFICATE-----" static uint8_t ASN1DecodeTag(DER_Element* der) { return der->size ? *der->data : ASN_UNKNOWN; } static AJ_Status ASN1DecodeLength(DER_Element* der, DER_Element* out) { size_t n; size_t len; if ((NULL == der->data) || (0 == der->size)) { return AJ_ERR_INVALID; } len = *(der->data)++; der->size--; if (0x80 & len) { n = len & 0x7F; if (n > sizeof (size_t)) { return AJ_ERR_INVALID; } len = 0; while (n && der->size) { len = (len << 8) + *(der->data)++; n--; der->size--; } } if (len > der->size) { return AJ_ERR_INVALID; } out->size = len; out->data = der->data; return AJ_OK; } /* * Currently, only UTF8String is supported in AJ certificates, so binary equivalence * is sufficient. If other ASN.1 string types are ever supported, make sure * DNs are stored internally in a canonical form that can still be checked for * binary equivalence, or this function will need to be updated to do the right things. . See RFC 5280 section 7.1 and RFC 4518 for equivalence between different string types. */ static uint32_t AJ_X509CompareNames(const X509DistinguishedName a, const X509DistinguishedName b) { /* Only OU and CN are supported as elements in a DN in AllJoyn */ if (a.ou.size != b.ou.size || a.cn.size != b.cn.size) { return FALSE; } if (0 != memcmp(a.ou.data, b.ou.data, a.ou.size) || 0 != memcmp(a.cn.data, b.cn.data, a.cn.size)) { return FALSE; } return TRUE; } AJ_Status AJ_ASN1DecodeElement(DER_Element* der, uint8_t tag, DER_Element* out) { uint8_t tmp; if ((NULL == der) || (NULL == out)) { return AJ_ERR_INVALID; } if ((NULL == der->data) || (0 == der->size)) { return AJ_ERR_INVALID; } /* * Decode tag and check it is what we expect */ tmp = ASN1DecodeTag(der); der->data++; der->size--; /* Turn off primitive/constructed flag */ tmp &= 0xDF; if (tmp != tag) { AJ_InfoPrintf(("AJ_ASN1DecodeElement(der=%p, tag=%x, out=%p): Tag error %x\n", der, tag, out, tmp)); return AJ_ERR_INVALID; } /* * Decode size */ if (AJ_OK != ASN1DecodeLength(der, out)) { AJ_InfoPrintf(("AJ_ASN1DecodeElement(der=%p, tag=%x, out=%p): Length error\n", der, tag, out)); return AJ_ERR_INVALID; } der->data += out->size; der->size -= out->size; return AJ_OK; } AJ_Status AJ_ASN1DecodeElements(DER_Element* der, const uint8_t* tags, size_t len, ...) { AJ_Status status = AJ_OK; DER_Element* out; va_list argp; uint8_t tag; uint32_t tmp; AJ_InfoPrintf(("AJ_ASN1DecodeElements(der=%p, tags=%p, len=%zu)\n", der, tags, len)); if ((NULL == der) || (NULL == tags)) { return AJ_ERR_INVALID; } va_start(argp, len); while ((AJ_OK == status) && len && (der->size)) { tag = *tags++; if (ASN_CONTEXT_SPECIFIC == tag) { tmp = va_arg(argp, uint32_t); tag = (ASN_CONTEXT_SPECIFIC | tmp); } out = va_arg(argp, DER_Element*); len--; status = AJ_ASN1DecodeElement(der, tag, out); } if (AJ_OK == status) { // If unset elements, fail if (len) { AJ_InfoPrintf(("AJ_ASN1DecodeElements(der=%p, tags=%p, len=%zu): Uninitialized elements\n", der, tags, len)); status = AJ_ERR_INVALID; } } va_end(argp); return status; } // 1.2.840.10045.4.3.2 const uint8_t OID_SIG_ECDSA_SHA256[8] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }; // 1.2.840.10045.2.1 const uint8_t OID_KEY_ECC[7] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }; // 1.2.840.10045.3.1.7 const uint8_t OID_CRV_PRIME256V1[8] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }; // 2.5.4.10 const uint8_t OID_DN_OU[3] = { 0x55, 0x04, 0x0B }; // 2.5.4.3 const uint8_t OID_DN_CN[3] = { 0x55, 0x04, 0x03 }; // 2.5.29.19 const uint8_t OID_BASIC_CONSTRAINTS[3] = { 0x55, 0x1D, 0x13 }; // 2.5.29.14 const uint8_t OID_SKI[3] = { 0x55, 0x1D, 0x0E }; // 2.5.29.35 const uint8_t OID_AKI[3] = { 0x55, 0x1D, 0x23 }; // 2.5.29.37 const uint8_t OID_EKU[3] = { 0x55, 0x1D, 0x25 }; // 2.5.29.27 const uint8_t OID_SUB_ALTNAME[3] = { 0x55, 0x1D, 0x11 }; // 2.16.840.1.101.3.4.2.1 const uint8_t OID_HASH_SHA256[9] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 }; // 1.3.6.1.4.1.44924.1.1 const uint8_t OID_CUSTOM_EKU_IDENTITY[10] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x01 }; // 1.3.6.1.4.1.44924.1.2 const uint8_t OID_CUSTOM_DIGEST[10] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x02 }; // 1.3.6.1.4.1.44924.1.3 const uint8_t OID_CUSTOM_GROUP[10] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x03 }; // 1.3.6.1.4.1.44924.1.4 const uint8_t OID_CUSTOM_ALIAS[10] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x04 }; // 1.3.6.1.4.1.44924.1.5 const uint8_t OID_CUSTOM_EKU_MEMBERSHIP[10] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x05 }; uint8_t CompareOID(DER_Element* der, const uint8_t* oid, size_t len) { if (der->size != len) { return 0; } return (0 == memcmp(der->data, oid, len)); } AJ_Status AJ_DecodePrivateKeyDER(AJ_ECCPrivateKey* key, DER_Element* der) { AJ_Status status; DER_Element seq; DER_Element ver; DER_Element prv; DER_Element alg; const uint8_t tags1[] = { ASN_SEQ }; const uint8_t tags2[] = { ASN_INTEGER, ASN_OCTETS, ASN_CONTEXT_SPECIFIC }; status = AJ_ASN1DecodeElements(der, tags1, sizeof (tags1), &seq); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElements(&seq, tags2, sizeof (tags2), &ver, &prv, 0, &alg); if (AJ_OK != status) { return status; } if ((1 != ver.size) || (1 != *ver.data)) { return AJ_ERR_INVALID; } if (KEY_ECC_PRV_SZ != prv.size) { return AJ_ERR_INVALID; } memcpy(key->x, prv.data, KEY_ECC_SZ); return status; } AJ_Status AJ_DecodePrivateKeyPEM(AJ_ECCPrivateKey* key, const char* pem) { AJ_Status status; const char* beg; const char* end; DER_Element der; uint8_t* buf = NULL; beg = strstr(pem, PEM_PRIV_BEG); if (NULL == beg) { return AJ_ERR_INVALID; } beg = pem + strlen(PEM_PRIV_BEG); end = strstr(beg, PEM_PRIV_END); if (NULL == end) { return AJ_ERR_INVALID; } der.size = 3 * (end - beg) / 4; der.data = (uint8_t*) AJ_Malloc(der.size); if (NULL == der.data) { return AJ_ERR_RESOURCES; } buf = der.data; status = AJ_B64ToRaw(beg, end - beg, der.data, der.size); if (AJ_OK != status) { goto Exit; } if ('=' == beg[end - beg - 1]) { der.size--; } if ('=' == beg[end - beg - 2]) { der.size--; } status = AJ_DecodePrivateKeyDER(key, &der); Exit: if (buf) { AJ_Free(buf); } return status; } static AJ_Status DecodeCertificateName(X509DistinguishedName* dn, DER_Element* der) { AJ_Status status = AJ_OK; DER_Element set; DER_Element seq; DER_Element oid; DER_Element tmp; memset(dn, 0, sizeof (X509DistinguishedName)); while ((AJ_OK == status) && (der->size)) { status = AJ_ASN1DecodeElement(der, ASN_SET_OF, &set); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElement(&set, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElement(&seq, ASN_OID, &oid); if (AJ_OK != status) { return status; } if (CompareOID(&oid, OID_DN_OU, sizeof (OID_DN_OU))) { // Only accept UTF8 strings status = AJ_ASN1DecodeElement(&seq, ASN_UTF8, &tmp); if (AJ_OK != status) { return status; } dn->ou.data = tmp.data; dn->ou.size = tmp.size; } else if (CompareOID(&oid, OID_DN_CN, sizeof (OID_DN_CN))) { // Only accept UTF8 strings status = AJ_ASN1DecodeElement(&seq, ASN_UTF8, &tmp); if (AJ_OK != status) { return status; } dn->cn.data = tmp.data; dn->cn.size = tmp.size; } } return status; } static AJ_Status DecodeCertificateTime(X509Validity* validity, DER_Element* der) { AJ_Status status; DER_Element time; uint8_t fmt; memset(validity, 0, sizeof (X509Validity)); if (!der->size) { return AJ_ERR_SECURITY; } fmt = *der->data; switch (fmt) { case ASN_UTC_TIME: status = AJ_ASN1DecodeElement(der, ASN_UTC_TIME, &time); if (AJ_OK != status) { return status; } validity->from = AJ_DecodeTime((char*) time.data, "%y%m%d%H%M%SZ"); break; case ASN_GEN_TIME: status = AJ_ASN1DecodeElement(der, ASN_GEN_TIME, &time); if (AJ_OK != status) { return status; } validity->from = AJ_DecodeTime((char*) time.data, "%Y%m%d%H%M%SZ"); break; default: return AJ_ERR_INVALID; } if (!der->size) { return AJ_ERR_SECURITY; } fmt = *der->data; switch (fmt) { case ASN_UTC_TIME: status = AJ_ASN1DecodeElement(der, ASN_UTC_TIME, &time); if (AJ_OK != status) { return status; } validity->to = AJ_DecodeTime((char*) time.data, "%y%m%d%H%M%SZ"); break; case ASN_GEN_TIME: status = AJ_ASN1DecodeElement(der, ASN_GEN_TIME, &time); if (AJ_OK != status) { return status; } validity->to = AJ_DecodeTime((char*) time.data, "%Y%m%d%H%M%SZ"); break; default: return AJ_ERR_INVALID; } return status; } static AJ_Status DecodeCertificatePub(AJ_ECCPublicKey* pub, DER_Element* der) { AJ_Status status; DER_Element seq; DER_Element bit; DER_Element oid1; DER_Element oid2; const uint8_t tags1[] = { ASN_SEQ, ASN_BITS }; const uint8_t tags2[] = { ASN_OID, ASN_OID }; status = AJ_ASN1DecodeElements(der, tags1, sizeof (tags1), &seq, &bit); if (AJ_OK != status) { return status; } /* * We only accept NISTP256 ECC keys at the moment. */ status = AJ_ASN1DecodeElements(&seq, tags2, sizeof (tags2), &oid1, &oid2); if (AJ_OK != status) { return status; } if (!CompareOID(&oid1, OID_KEY_ECC, sizeof (OID_KEY_ECC))) { return AJ_ERR_INVALID; } if (!CompareOID(&oid2, OID_CRV_PRIME256V1, sizeof (OID_CRV_PRIME256V1))) { return AJ_ERR_INVALID; } /* * We only accept uncompressed ECC points. */ if ((2 + KEY_ECC_PUB_SZ) != bit.size) { return AJ_ERR_INVALID; } if ((0x00 != bit.data[0]) || (0x04 != bit.data[1])) { return AJ_ERR_INVALID; } bit.data += 2; bit.size -= 2; pub->alg = KEY_ALG_ECDSA_SHA256; pub->crv = KEY_CRV_NISTP256; memcpy(pub->x, bit.data, KEY_ECC_SZ); memcpy(pub->y, bit.data + KEY_ECC_SZ, KEY_ECC_SZ); return status; } static AJ_Status DecodeCertificateExt(X509Extensions* extensions, DER_Element* der) { AJ_Status status; DER_Element tmp; DER_Element seq; DER_Element oid; DER_Element oct; uint8_t tag; uint8_t critical; const uint8_t tags1[] = { ASN_CONTEXT_SPECIFIC }; const uint8_t tags2[] = { ASN_OID, ASN_OCTETS }; const uint8_t tags3[] = { ASN_OID, ASN_CONTEXT_SPECIFIC }; memset(extensions, 0, sizeof (X509Extensions)); /* By default, a certificate is unrestricted. Only if we see an EKU extension * will this change. */ extensions->type = AJ_CERTIFICATE_UNR_X509; status = AJ_ASN1DecodeElement(der, ASN_SEQ, &tmp); if (AJ_OK != status) { return status; } der->size = tmp.size; der->data = tmp.data; while ((AJ_OK == status) && (der->size)) { status = AJ_ASN1DecodeElement(der, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElement(&seq, ASN_OID, &oid); if (AJ_OK != status) { return status; } critical = 0; tag = ASN1DecodeTag(&seq); if (ASN_BOOLEAN == tag) { // Critical extension status = AJ_ASN1DecodeElement(&seq, ASN_BOOLEAN, &tmp); if (AJ_OK != status) { return status; } if (0x1 == tmp.size) { critical = *tmp.data; } } status = AJ_ASN1DecodeElement(&seq, ASN_OCTETS, &oct); if (AJ_OK != status) { return status; } if (CompareOID(&oid, OID_BASIC_CONSTRAINTS, sizeof (OID_BASIC_CONSTRAINTS))) { status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } tag = ASN1DecodeTag(&seq); if (ASN_BOOLEAN == tag) { // Explicit boolean status = AJ_ASN1DecodeElement(&seq, ASN_BOOLEAN, &tmp); if (AJ_OK != status) { return status; } if (0x1 == tmp.size) { extensions->ca = *tmp.data; } } tag = ASN1DecodeTag(&seq); if (ASN_INTEGER == tag) { // Explicit pathlen status = AJ_ASN1DecodeElement(&seq, ASN_INTEGER, &tmp); if (AJ_OK != status) { return status; } // We are not using pathlen, so do nothing with it } } else if (CompareOID(&oid, OID_SKI, sizeof (OID_SKI))) { status = AJ_ASN1DecodeElement(&oct, ASN_OCTETS, &tmp); if (AJ_OK != status) { return status; } extensions->ski.data = tmp.data; extensions->ski.size = tmp.size; } else if (CompareOID(&oid, OID_AKI, sizeof (OID_AKI))) { status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElements(&seq, tags1, sizeof (tags1), 0, &tmp); if (AJ_OK != status) { return status; } extensions->aki.data = tmp.data; extensions->aki.size = tmp.size; } else if (CompareOID(&oid, OID_EKU, sizeof (OID_EKU))) { status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } if (seq.size == 0) { /* There must be at least one EKU in the sequence. Certificate is invalid if not. */ return AJ_ERR_INVALID; } /* We have at least one EKU, so clear out the type previously defaulted to unrestricted. */ extensions->type = 0; while (seq.size > 0) { status = AJ_ASN1DecodeElement(&seq, ASN_OID, &tmp); if (AJ_OK != status) { return status; } if (CompareOID(&tmp, OID_CUSTOM_EKU_IDENTITY, sizeof(OID_CUSTOM_EKU_IDENTITY))) { extensions->type |= AJ_CERTIFICATE_IDN_X509; } else if (CompareOID(&tmp, OID_CUSTOM_EKU_MEMBERSHIP, sizeof(OID_CUSTOM_EKU_MEMBERSHIP))) { extensions->type |= AJ_CERTIFICATE_MBR_X509; } /* Skip any unrecognized EKUs. */ } /* If we saw no AllJoyn EKUs, meaning we only saw non-AllJoyn EKUs, set the type as invalid for * AllJoyn purposes. */ if (0 == extensions->type) { extensions->type = AJ_CERTIFICATE_INV_X509; } } else if (CompareOID(&oid, OID_CUSTOM_DIGEST, sizeof (OID_CUSTOM_DIGEST))) { status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElements(&seq, tags2, sizeof (tags2), &oid, &oct); if (AJ_OK != status) { return status; } if (!CompareOID(&oid, OID_HASH_SHA256, sizeof (OID_HASH_SHA256))) { return AJ_ERR_INVALID; } extensions->digest.data = oct.data; extensions->digest.size = oct.size; } else if (CompareOID(&oid, OID_SUB_ALTNAME, sizeof (OID_SUB_ALTNAME))) { status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElements(&seq, tags1, sizeof (tags1), 0, &tmp); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElements(&tmp, tags3, sizeof (tags3), &oid, 0, &oct); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElement(&oct, ASN_OCTETS, &tmp); if (AJ_OK != status) { return status; } if (CompareOID(&oid, OID_CUSTOM_GROUP, sizeof (OID_CUSTOM_GROUP))) { extensions->group.data = tmp.data; extensions->group.size = tmp.size; } else if (CompareOID(&oid, OID_CUSTOM_ALIAS, sizeof (OID_CUSTOM_ALIAS))) { extensions->alias.data = tmp.data; extensions->alias.size = tmp.size; } } else { // Unknown OID, if critical return error if (critical) { return AJ_ERR_INVALID; } } } return status; } static AJ_Status DecodeCertificateTBS(X509TbsCertificate* tbs, DER_Element* der) { AJ_Status status; DER_Element ver; DER_Element oid; DER_Element iss; DER_Element utc; DER_Element sub; DER_Element pub; DER_Element ext; DER_Element tmp; const uint8_t tags[] = { ASN_CONTEXT_SPECIFIC, ASN_INTEGER, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_CONTEXT_SPECIFIC }; memset(tbs, 0, sizeof (X509TbsCertificate)); status = AJ_ASN1DecodeElements(der, tags, sizeof (tags), 0, &ver, &tbs->serial, &oid, &iss, &utc, &sub, &pub, 3, &ext); if (AJ_OK != status) { return status; } /* * We only accept X.509v3 certificates. */ status = AJ_ASN1DecodeElement(&ver, ASN_INTEGER, &tmp); if (AJ_OK != status) { return status; } if ((0x1 != tmp.size) || (0x2 != *tmp.data)) { return AJ_ERR_INVALID; } /* * We only accept ECDSA-SHA256 signed certificates at the moment. */ status = AJ_ASN1DecodeElement(&oid, ASN_OID, &tmp); if (AJ_OK != status) { return status; } if (!CompareOID(&tmp, OID_SIG_ECDSA_SHA256, sizeof (OID_SIG_ECDSA_SHA256))) { return AJ_ERR_INVALID; } status = DecodeCertificateName(&tbs->issuer, &iss); if (AJ_OK != status) { return status; } status = DecodeCertificateTime(&tbs->validity, &utc); if (AJ_OK != status) { return status; } status = DecodeCertificateName(&tbs->subject, &sub); if (AJ_OK != status) { return status; } status = DecodeCertificatePub(&tbs->publickey, &pub); if (AJ_OK != status) { return status; } status = DecodeCertificateExt(&tbs->extensions, &ext); if (AJ_OK != status) { return status; } return status; } static AJ_Status DecodeCertificateSig(AJ_ECCSignature* signature, DER_Element* der) { AJ_Status status; DER_Element seq; DER_Element int1; DER_Element int2; const uint8_t tags[] = { ASN_INTEGER, ASN_INTEGER }; status = AJ_ASN1DecodeElement(der, ASN_SEQ, &seq); if (AJ_OK != status) { return status; } status = AJ_ASN1DecodeElements(&seq, tags, sizeof (tags), &int1, &int2); if (AJ_OK != status) { return status; } /* * Skip over unused bits. */ if ((0 < int1.size) && (0 == *int1.data)) { int1.data++; int1.size--; } if ((0 < int2.size) && (0 == *int2.data)) { int2.data++; int2.size--; } if (KEY_ECC_SZ < int1.size) { return AJ_ERR_INVALID; } if (KEY_ECC_SZ < int2.size) { return AJ_ERR_INVALID; } memset(signature, 0, sizeof (AJ_ECCSignature)); // Copy into lsb memcpy(signature->r + (KEY_ECC_SZ - int1.size), int1.data, int1.size); memcpy(signature->s + (KEY_ECC_SZ - int2.size), int2.data, int2.size); return status; } AJ_Status AJ_X509DecodeCertificateDER(X509Certificate* certificate, DER_Element* der) { AJ_Status status; DER_Element seq; DER_Element tbs; DER_Element tmp; DER_Element oid; DER_Element sig; const uint8_t tags1[] = { ASN_SEQ }; const uint8_t tags2[] = { ASN_SEQ, ASN_SEQ, ASN_BITS }; AJ_InfoPrintf(("AJ_X509DecodeCertificateDER(certificate=%p, der=%p)\n", certificate, der)); if ((NULL == certificate) || (NULL == der)) { return AJ_ERR_INVALID; } status = AJ_ASN1DecodeElements(der, tags1, sizeof (tags1), &seq); if (AJ_OK != status) { return status; } /* Signed TBS section starts here */ certificate->raw.data = seq.data; status = AJ_ASN1DecodeElements(&seq, tags2, sizeof (tags2), &tbs, &tmp, &sig); if (AJ_OK != status) { return status; } certificate->raw.size = tbs.size + (tbs.data - certificate->raw.data); status = DecodeCertificateTBS(&certificate->tbs, &tbs); if (AJ_OK != status) { return status; } /* * We only accept ECDSA-SHA256 signed certificates at the moment. */ status = AJ_ASN1DecodeElement(&tmp, ASN_OID, &oid); if (AJ_OK != status) { return status; } if (!CompareOID(&oid, OID_SIG_ECDSA_SHA256, sizeof (OID_SIG_ECDSA_SHA256))) { return AJ_ERR_INVALID; } /* * Remove the byte specifying unused bits, this should always be zero. */ if ((0 == sig.size) || (0 != *sig.data)) { return AJ_ERR_INVALID; } sig.data++; sig.size--; status = DecodeCertificateSig(&certificate->signature, &sig); return status; } AJ_Status AJ_X509DecodeCertificatePEM(X509Certificate* certificate, const char* pem) { AJ_Status status; const char* beg = pem; const char* end; size_t len; DER_Element der; AJ_InfoPrintf(("AJ_X509DecodeCertificatePEM(certificate=%p, pem=%s)\n", certificate, pem)); beg = strstr(beg, PEM_CERT_BEG); if (NULL == beg) { AJ_InfoPrintf(("AJ_X509DecodeCertificatePEM(certificate=%p, pem=%s): Missing %s tag\n", certificate, pem, PEM_CERT_BEG)); return AJ_ERR_INVALID; } beg = beg + strlen(PEM_CERT_BEG); end = strstr(beg, PEM_CERT_END); if (NULL == end) { AJ_InfoPrintf(("AJ_X509DecodeCertificatePEM(certificate=%p, pem=%s): Missing %s tag\n", certificate, pem, PEM_CERT_END)); return AJ_ERR_INVALID; } len = end - beg; certificate->der.size = 3 * len / 4; certificate->der.data = (uint8_t*) AJ_Malloc(certificate->der.size); if (NULL == certificate->der.data) { return AJ_ERR_RESOURCES; } status = AJ_B64ToRaw(beg, len, certificate->der.data, certificate->der.size); if (AJ_OK != status) { AJ_Free(certificate->der.data); certificate->der.data = NULL; certificate->der.size = 0; return status; } if ('=' == beg[len - 1]) { certificate->der.size--; } if ('=' == beg[len - 2]) { certificate->der.size--; } /* AJ_X509DecodeCertificateDER modifies its second parameter, so copy the values * out so the certificate object itself won't be changed. */ der.data = certificate->der.data; der.size = certificate->der.size; return AJ_X509DecodeCertificateDER(certificate, &der); } X509CertificateChain* AJ_X509DecodeCertificateChainPEM(const char* pem) { AJ_Status status; X509CertificateChain* root = NULL; X509CertificateChain* node; const char* beg = pem; beg = strstr(beg, PEM_CERT_BEG); while (beg) { node = (X509CertificateChain*) AJ_Malloc(sizeof (X509CertificateChain)); if (NULL == node) { goto Exit; } /* * Push the node on to the head. * We do this before decoding so that it is cleaned up in case of error. */ node->next = root; root = node; status = AJ_X509DecodeCertificatePEM(&node->certificate, beg); if (AJ_OK != status) { goto Exit; } /* * Look for more certificates, anywhere after the current tag. */ beg = strstr(beg + 1, PEM_CERT_BEG); } return root; Exit: /* Free the cert chain */ AJ_X509FreeDecodedCertificateChain(root); return NULL; } void AJ_X509FreeDecodedCertificateChain(X509CertificateChain* root) { while (root) { X509CertificateChain* node = root; root = root->next; /* Free the der memory if it was created */ if (node->certificate.der.data) { AJ_Free(node->certificate.der.data); } AJ_Free(node); } } AJ_Status AJ_X509SelfVerify(const X509Certificate* certificate) { AJ_InfoPrintf(("AJ_X509SelfVerify(certificate=%p)\n", certificate)); return AJ_X509Verify(certificate, &certificate->tbs.publickey); } AJ_Status AJ_X509Verify(const X509Certificate* certificate, const AJ_ECCPublicKey* key) { AJ_InfoPrintf(("AJ_X509Verify(certificate=%p, key=%p)\n", certificate, key)); return AJ_ECDSAVerify(certificate->raw.data, certificate->raw.size, &certificate->signature, key); } AJ_Status AJ_X509VerifyChain(const X509CertificateChain* root, const AJ_ECCPublicKey* key, uint32_t type) { AJ_Status status; uint32_t chainValidForType = AJ_CERTIFICATE_UNR_X509; uint32_t akiRequired = 0; uint32_t isRoot = 1; AJ_InfoPrintf(("AJ_X509VerifyChain(root=%p, key=%p, type=%x)\n", root, key, type)); /* Certificates must have an AKI if they are membership or ID certs. * Unrestricted certs are both, so they require an AKI as well. * We don't check for the AKI on the root certificate. */ if ((type == AJ_CERTIFICATE_IDN_X509) || (type == AJ_CERTIFICATE_MBR_X509) || (type == AJ_CERTIFICATE_UNR_X509)) { akiRequired = 1; } while (root) { if (key) { status = AJ_X509Verify(&root->certificate, key); if (AJ_OK != status) { return status; } } /* This assertion makes sure invalid certificates will never be allowed, by making sure the bit * overlap between the internal representations for them and unrestricted certificates is zero, * to catch problems if the values of these constants are ever changed in the future. */ AJ_ASSERT((AJ_CERTIFICATE_UNR_X509 & AJ_CERTIFICATE_INV_X509) == 0); if ((chainValidForType & root->certificate.tbs.extensions.type) != root->certificate.tbs.extensions.type) { AJ_InfoPrintf(("AJ_X509VerifyChain(root=%p, key=%p, type=%x): Certificate fails transitive EKU check; chain so far is valid for type %X, current certificate has type %X\n", root, key, type, chainValidForType, root->certificate.tbs.extensions.type)); return AJ_ERR_SECURITY; } chainValidForType &= root->certificate.tbs.extensions.type; if (!isRoot && akiRequired && (root->certificate.tbs.extensions.aki.size == 0)) { AJ_InfoPrintf(("AJ_X509VerifyChain(root=%p, key=%p, type=%x): Certificate is missing AKI, but the certificate type requires it to be present.\n", root, key, type)); return AJ_ERR_SECURITY; } /* The subject field of the current certificate must equal the issuer field of the next certificate * in the chain. */ if (NULL != root->next) { if (!AJ_X509CompareNames(root->certificate.tbs.subject, root->next->certificate.tbs.issuer)) { AJ_InfoPrintf(("AJ_X509VerifyChain(root=%p, key=%p, type=%x): Subject/Issuer name mismatch\n", root, key, type)); return AJ_ERR_SECURITY; } if (0 == root->certificate.tbs.extensions.ca) { AJ_InfoPrintf(("AJ_X509VerifyChain(root=%p, key=%p, type=%x): Issuer is not a CA\n", root, key, type)); return AJ_ERR_SECURITY; } } else { /* This is the end entity cert. It must be the expected type if one was specified. */ if (type && type != root->certificate.tbs.extensions.type) { AJ_InfoPrintf(("AJ_X509VerifyChain(root=%p, key=%p, type=%x): End entity certificate has incorrect EKU\n", root, key, type)); return AJ_ERR_SECURITY; } } key = &root->certificate.tbs.publickey; root = root->next; isRoot = 0; } return AJ_OK; } void AJ_X509ChainFree(X509CertificateChain* root) { X509CertificateChain* node; while (root) { node = root; root = root->next; AJ_Free(node); } } AJ_Status AJ_X509ChainMarshal(X509CertificateChain* root, AJ_Message* msg) { AJ_Status status; AJ_Arg container; X509CertificateChain* node; /* * X509CertificateChain is root first. * The wire protocol requires leaf first, * reverse it here, then reverse it back after marshalling. */ root = AJ_X509ReverseChain(root); status = AJ_MarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } node = root; while (node) { status = AJ_MarshalArgs(msg, "(yay)", CERT_FMT_X509_DER, node->certificate.der.data, node->certificate.der.size); if (AJ_OK != status) { goto Exit; } node = node->next; } status = AJ_MarshalCloseContainer(msg, &container); if (AJ_OK != status) { goto Exit; } Exit: root = AJ_X509ReverseChain(root); return status; } AJ_Status AJ_X509ChainUnmarshal(X509CertificateChain** root, AJ_Message* msg) { AJ_Status status; AJ_Arg container; uint8_t fmt; DER_Element der; X509CertificateChain* head = NULL; X509CertificateChain* node = NULL; status = AJ_UnmarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } while (AJ_OK == status) { status = AJ_UnmarshalArgs(msg, "(yay)", &fmt, &der.data, &der.size); if (AJ_OK != status) { break; } if (CERT_FMT_X509_DER != fmt) { AJ_WarnPrintf(("AJ_X509ChainUnmarshal(root=%p, msg=%p): Certificate format unknown\n", root, msg)); goto Exit; } node = (X509CertificateChain*) AJ_Malloc(sizeof (X509CertificateChain)); if (NULL == node) { goto Exit; } node->certificate.der.size = der.size; node->certificate.der.data = der.data; node->next = head; head = node; status = AJ_X509DecodeCertificateDER(&node->certificate, &der); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_X509ChainUnmarshal(root=%p, msg=%p): Certificate decode failed\n", root, msg)); goto Exit; } } if (AJ_ERR_NO_MORE != status) { goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container); if (AJ_OK != status) { goto Exit; } *root = head; return status; Exit: /* Free the cert chain */ AJ_X509ChainFree(head); return AJ_ERR_FAILURE; } AJ_Status AJ_X509ChainToBuffer(X509CertificateChain* root, AJ_CredField* field) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; AJ_LocalMsg(&bus, &hdr, &msg, "a(yay)", field->data, field->size); status = AJ_X509ChainMarshal(root, &msg); field->size = bus.sock.tx.writePtr - field->data; return status; } AJ_Status AJ_X509ChainFromBuffer(X509CertificateChain** root, AJ_CredField* field) { AJ_Status status; AJ_BusAttachment bus; AJ_MsgHeader hdr; AJ_Message msg; AJ_LocalMsg(&bus, &hdr, &msg, "a(yay)", field->data, field->size); status = AJ_X509ChainUnmarshal(root, &msg); return status; } X509Certificate* AJ_X509LeafCertificate(X509CertificateChain* root) { if (NULL == root) { return NULL; } while (root->next) { root = root->next; } return &root->certificate; } X509CertificateChain* AJ_X509ReverseChain(X509CertificateChain* root) { X509CertificateChain* temp; X509CertificateChain* last = NULL; while (root) { temp = root->next; root->next = last; last = root; root = temp; } return last; } ajtcl-16.04/src/aj_connect.c000066400000000000000000001005531271074662300156730ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CONNECT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AJ_ARDP #include #endif #include #if !(defined(ARDUINO) || defined(__linux) || defined(_WIN32) || defined(__MACH__)) #include #endif #ifdef AJ_SERIAL_CONNECTION #include #endif /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG AJ_EXPORT uint8_t dbgCONNECT = 0; #endif /* * Protocol version of the router you have connected to */ static uint8_t routingProtoVersion = 0; /* * Minimum accepted protocol version of a router to be connected to * Version 10 (14.06) allows for NGNS and untrusted connection to router * May be set to earlier version with AJ_SetMinProtoVersion(). */ static uint8_t minProtoVersion = 10; /* * The amount of time to wait for routing node responses during discovery. * May be set to a different value with AJ_SetSelectionTimeout(). */ static uint32_t selectionTimeout = AJ_SELECTION_TIMEOUT; static const char daemonService[] = "org.alljoyn.BusNode"; uint8_t AJ_GetMinProtoVersion() { return minProtoVersion; } void AJ_SetMinProtoVersion(uint8_t min) { minProtoVersion = min; } void AJ_SetSelectionTimeout(uint32_t selection) { selectionTimeout = selection; } uint32_t AJ_GetSelectionTimeout(void) { return selectionTimeout; } void SetBusAuthPwdCallback(BusAuthPwdFunc callback) { /* * This functionality is no longer provided but the function is still defined for backwards * compatibility. */ } #if defined(AJ_TCP) || defined(AJ_SERIAL_CONNECTION) static AJ_Status SendHello(AJ_BusAttachment* bus) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("SendHello(bus=0x%p)\n", bus)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_HELLO, AJ_DBusDestination, 0, AJ_FLAG_ALLOW_REMOTE_MSG, 5000); if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } static void ResetRead(AJ_IOBuffer* rxBuf) { rxBuf->readPtr += AJ_IO_BUF_AVAIL(rxBuf); *rxBuf->writePtr = '\0'; } static AJ_Status ReadLine(AJ_IOBuffer* rxBuf) { /* * All the authentication messages end in a CR/LF so read until we get a newline */ AJ_Status status = AJ_OK; while ((AJ_IO_BUF_AVAIL(rxBuf) == 0) || (*(rxBuf->writePtr - 1) != '\n')) { status = rxBuf->recv(rxBuf, AJ_IO_BUF_SPACE(rxBuf), 3500); if (status != AJ_OK) { AJ_ErrPrintf(("ReadLine(): status=%s\n", AJ_StatusText(status))); break; } } return status; } static AJ_Status WriteLine(AJ_IOBuffer* txBuf, const char* line) { strcpy((char*) txBuf->writePtr, line); txBuf->writePtr += strlen(line); return txBuf->send(txBuf); } /** * Since the routing node expects any of its clients to use SASL with Anonymous * or PINX in order to connect, this method will send the necessary SASL * Anonymous exchange in order to connect. PINX is no longer supported on the * Thin Client. All thin clients will connect as untrusted clients to the * routing node. */ static AJ_Status AnonymousAuthAdvance(AJ_IOBuffer* rxBuf, AJ_IOBuffer* txBuf) { AJ_Status status = AJ_OK; AJ_GUID localGuid; char buf[40]; /* initiate the SASL exchange with AUTH ANONYMOUS */ status = WriteLine(txBuf, "AUTH ANONYMOUS\n"); ResetRead(rxBuf); if (status == AJ_OK) { /* expect server to send back OK GUID */ status = ReadLine(rxBuf); if (status == AJ_OK) { if (memcmp(rxBuf->readPtr, "OK", 2) != 0) { return AJ_ERR_ACCESS_ROUTING_NODE; } } } if (status == AJ_OK) { status = WriteLine(txBuf, "INFORM_PROTO_VERSION 10\n"); ResetRead(rxBuf); } if (status == AJ_OK) { /* expect server to send back INFORM_PROTO_VERSION version# */ status = ReadLine(rxBuf); } if (status == AJ_OK) { if (memcmp(rxBuf->readPtr, "INFORM_PROTO_VERSION", strlen("INFORM_PROTO_VERSION")) != 0) { status = AJ_ERR_ACCESS_ROUTING_NODE; } } if (status == AJ_OK) { routingProtoVersion = atoi((const char*)(rxBuf->readPtr + strlen("INFORM_PROTO_VERSION") + 1)); if (routingProtoVersion < AJ_GetMinProtoVersion()) { AJ_InfoPrintf(("AnonymousAuthAdvance():: Found version %u but minimum %u required", routingProtoVersion, AJ_GetMinProtoVersion())); status = AJ_ERR_OLD_VERSION; } } if (status == AJ_OK) { /* send BEGIN LocalGUID to server */ AJ_GetLocalGUID(&localGuid); strcpy(buf, "BEGIN "); status = AJ_GUID_ToString(&localGuid, buf + strlen(buf), 33); strcat(buf, "\n"); status = WriteLine(txBuf, buf); ResetRead(rxBuf); } if (status != AJ_OK) { AJ_ErrPrintf(("AnonymousAuthAdvance(): status=%s\n", AJ_StatusText(status))); } return status; } #endif uint8_t AJ_GetRoutingProtoVersion(void) { return routingProtoVersion; } static AJ_Status SetSignalRules(AJ_BusAttachment* bus) { AJ_Status status = AJ_OK; /* * AJ_GUID needs the NameOwnerChanged signal to clear out entries in * its map. Prior to router version 10 this means we must set a * signal rule to receive every NameOwnerChanged signal. With * version 10 the router supports the arg[0,1,...] key in match * rules, allowing us to set a signal rule for just the * NameOwnerChanged signals of entries in the map. See aj_guid.c * for usage of the arg key. */ if (AJ_GetRoutingProtoVersion() < 11) { status = AJ_BusSetSignalRule(bus, "type='signal',member='NameOwnerChanged',interface='org.freedesktop.DBus'", AJ_BUS_SIGNAL_ALLOW); if (status == AJ_OK) { uint8_t found_reply = FALSE; AJ_Message msg; AJ_Time timer; AJ_InitTimer(&timer); while (found_reply == FALSE && AJ_GetElapsedTime(&timer, TRUE) < 3000) { status = AJ_UnmarshalMsg(bus, &msg, 3000); if (status == AJ_OK) { switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_ADD_MATCH): found_reply = TRUE; break; default: // ignore everything else AJ_BusHandleBusMessage(&msg); break; } AJ_CloseMsg(&msg); } } } } return status; } AJ_Status AJ_Authenticate(AJ_BusAttachment* bus) { AJ_Status status = AJ_OK; AJ_Message helloResponse; if (bus->isAuthenticated) { // ARDP does not do SASL and it sends BusHello as part of the SYN message. // Therefore, Hello has already been sent by the time AJ_Net_Connect() returns, // *before* AJ_Authenticate is called. return AJ_OK; } #if defined(AJ_TCP) || defined(AJ_SERIAL_CONNECTION) /* * Send initial NUL byte */ bus->sock.tx.writePtr[0] = 0; bus->sock.tx.writePtr += 1; status = bus->sock.tx.send(&bus->sock.tx); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_Authenticate(): status=%s\n", AJ_StatusText(status))); goto ExitConnect; } /* Use SASL Anonymous to connect to routing node */ status = AnonymousAuthAdvance(&bus->sock.rx, &bus->sock.tx); if (status == AJ_OK) { status = SendHello(bus); } if (status == AJ_OK) { status = AJ_UnmarshalMsg(bus, &helloResponse, 5000); } if (status == AJ_OK) { if (helloResponse.hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_Authenticate(): AJ_ERR_TIMEOUT\n")); status = AJ_ERR_TIMEOUT; } else { AJ_Arg arg; status = AJ_UnmarshalArg(&helloResponse, &arg); if (status == AJ_OK) { if (arg.len >= (sizeof(bus->uniqueName) - 1)) { AJ_ErrPrintf(("AJ_Authenticate(): AJ_ERR_ACCESS_ROUTING_NODE\n")); status = AJ_ERR_ACCESS_ROUTING_NODE; } else { memcpy(bus->uniqueName, arg.val.v_string, arg.len); bus->uniqueName[arg.len] = '\0'; } } } AJ_CloseMsg(&helloResponse); } ExitConnect: if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Authenticate(): status=%s\n", AJ_StatusText(status))); } else { bus->isAuthenticated = TRUE; } #endif return status; } #define AJ_DHCP_TIMEOUT 5000 static void AddRoutingNodeToBlacklist(const AJ_Service* service, uint8_t addrTypes); AJ_Status AJ_FindBusAndConnect(AJ_BusAttachment* bus, const char* serviceName, uint32_t timeout) { AJ_Status status; AJ_Service service; AJ_Time connectionTimer; int32_t connectionTime; uint8_t finished = FALSE; #ifdef AJ_SERIAL_CONNECTION AJ_Time start, now; AJ_InitTimer(&start); #endif AJ_InfoPrintf(("AJ_FindBusAndConnect(bus=0x%p, serviceName=\"%s\", timeout=%d, selection timeout=%d.)\n", bus, serviceName, timeout, selectionTimeout)); /* * Clear the bus struct */ memset(bus, 0, sizeof(AJ_BusAttachment)); bus->isProbeRequired = TRUE; /* * Clear stale name->GUID mappings */ AJ_GUID_ClearNameMap(); /* * Discover a daemon or service to connect to */ if (!serviceName) { serviceName = daemonService; } while (finished == FALSE) { finished = TRUE; connectionTime = (int32_t) timeout; #if AJ_CONNECT_LOCALHOST service.ipv4port = 9955; #if HOST_IS_LITTLE_ENDIAN service.ipv4 = 0x0100007F; // 127.0.0.1 #endif #if HOST_IS_BIG_ENDIAN service.ipv4 = 0x7f000001; // 127.0.0.1 #endif service.addrTypes = AJ_ADDR_TCP4; #elif defined(ARDUINO) service.ipv4port = 9955; service.ipv4 = 0x6501A8C0; // 192.168.1.101 service.addrTypes = AJ_ADDR_TCP4; AJ_InitTimer(&connectionTimer); AJ_InfoPrintf(("AJ_FindBusAndConnect(): Connection timer started\n")); status = AJ_Discover(serviceName, &service, timeout, selectionTimeout); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #elif defined(AJ_SERIAL_CONNECTION) // don't bother with discovery, we are connected to a daemon. // however, take this opportunity to bring up the serial connection status = AJ_Serial_Up(); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Serial_Up status=%s\n", AJ_StatusText(status))); } #else AJ_InitTimer(&connectionTimer); AJ_InfoPrintf(("AJ_FindBusAndConnect(): Connection timer started\n")); status = AJ_Discover(serviceName, &service, timeout, selectionTimeout); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #endif // this calls into platform code that will decide whether to use UDP or TCP, based on what is available status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #ifdef AJ_SERIAL_CONNECTION // run the state machine for long enough to (hopefully) do the SLAP handshake do { AJ_StateMachine(); AJ_InitTimer(&now); } while (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE && AJ_GetTimeDifference(&now, &start) < timeout); if (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): Failed to establish active SLAP connection in %u msec\n", timeout)); AJ_SerialShutdown(); return AJ_ERR_TIMEOUT; } #endif status = AJ_Authenticate(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Authenticate status=%s\n", AJ_StatusText(status))); #if !AJ_CONNECT_LOCALHOST && !defined(ARDUINO) && !defined(AJ_SERIAL_CONNECTION) if ((status == AJ_ERR_ACCESS_ROUTING_NODE) || (status == AJ_ERR_OLD_VERSION)) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): Blacklisting routing node\n")); AddRoutingNodeToBlacklist(&service, AJ_ADDR_TCP4); } AJ_Disconnect(bus); // try again finished = FALSE; connectionTime -= AJ_GetElapsedTime(&connectionTimer, FALSE); // select a new node from the response list while (connectionTime > 0) { status = AJ_SelectRoutingNodeFromResponseList(&service); if (status == AJ_ERR_END_OF_DATA) { status = AJ_ERR_TIMEOUT; AJ_InfoPrintf(("Exhausted all the retries from the response list\n")); finished = FALSE; break; } AJ_InfoPrintf(("Retrying with a new selection from the routing node response list\n")); status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status))); goto ExitConnect; } status = AJ_Authenticate(bus); if (status == AJ_OK) { finished = TRUE; break; } if ((status == AJ_ERR_ACCESS_ROUTING_NODE) || (status == AJ_ERR_OLD_VERSION)) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): Blacklisting another routing node\n")); AddRoutingNodeToBlacklist(&service, AJ_ADDR_TCP4); } AJ_Disconnect(bus); connectionTime -= AJ_GetElapsedTime(&connectionTimer, FALSE); } #endif } if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Authenticate status=%s\n", AJ_StatusText(status))); goto ExitConnect; } status = SetSignalRules(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): SetSignalRules status=%s\n", AJ_StatusText(status))); goto ExitConnect; } AJ_InitRoutingNodeResponselist(); } ExitConnect: AJ_InitRoutingNodeResponselist(); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); } return status; } #ifdef AJ_ARDP AJ_Status AJ_ARDP_UDP_Connect(AJ_BusAttachment* bus, void* context, const AJ_Service* service, AJ_NetSocket* netSock) { AJ_Message hello; AJ_GUID localGuid; char guid_buf[33]; AJ_Status status; AJ_Message helloResponse; AJ_GetLocalGUID(&localGuid); AJ_GUID_ToString(&localGuid, guid_buf, sizeof(guid_buf)); AJ_MarshalMethodCall(bus, &hello, AJ_METHOD_BUS_SIMPLE_HELLO, AJ_BusDestination, 0, AJ_FLAG_ALLOW_REMOTE_MSG, AJ_UDP_CONNECT_TIMEOUT); AJ_MarshalArgs(&hello, "su", guid_buf, 10); hello.hdr->bodyLen = hello.bodyBytes; status = AJ_ARDP_Connect(bus->sock.tx.readPtr, AJ_IO_BUF_AVAIL(&bus->sock.tx), context, netSock); if (status != AJ_OK) { return status; } status = AJ_UnmarshalMsg(bus, &helloResponse, AJ_UDP_CONNECT_TIMEOUT); if (status == AJ_OK && helloResponse.msgId == AJ_REPLY_ID(AJ_METHOD_BUS_SIMPLE_HELLO)) { if (helloResponse.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_CONNECT; } else { AJ_Arg uniqueName, protoVersion; AJ_UnmarshalArg(&helloResponse, &uniqueName); AJ_SkipArg(&helloResponse); AJ_UnmarshalArg(&helloResponse, &protoVersion); /** * The two most-significant bits are reserved for the nameType, * which we don't currently care about in the thin client */ routingProtoVersion = (uint8_t) ((*protoVersion.val.v_uint32) & 0x3FFFFFFF); if (uniqueName.len >= (sizeof(bus->uniqueName) - 1)) { AJ_ErrPrintf(("AJ_ARDP_Connect(): Blacklisting routing node, uniqueName.len = %d\n", uniqueName.len)); AddRoutingNodeToBlacklist(service, AJ_ADDR_UDP4); status = AJ_ERR_ACCESS_ROUTING_NODE; } else { memcpy(bus->uniqueName, uniqueName.val.v_string, uniqueName.len); bus->uniqueName[uniqueName.len] = '\0'; } AJ_InfoPrintf(("Received name: %s and version %u\n", bus->uniqueName, routingProtoVersion)); if (routingProtoVersion < AJ_GetMinProtoVersion()) { AJ_InfoPrintf(("AJ_ARDP_Connect(): Blacklisting routing node, found %u but require >= %u\n", routingProtoVersion, AJ_GetMinProtoVersion())); // add to blacklist because of invalid version AddRoutingNodeToBlacklist(service, AJ_ADDR_UDP4); status = AJ_ERR_OLD_VERSION; } } } else { status = AJ_ERR_CONNECT; } AJ_CloseMsg(&helloResponse); // reset the transmit queue! AJ_IO_BUF_RESET(&bus->sock.tx); if (status == AJ_OK) { // ARDP does not require additional authentication bus->isAuthenticated = TRUE; // ARDP does not require ProbeReq/ProbeAck bus->isProbeRequired = FALSE; } return status; } #endif // AJ_ARDP void AJ_Disconnect(AJ_BusAttachment* bus) { /* * Close security module */ AJ_SecurityClose(bus); /* * We won't be getting any more method replies. */ AJ_ReleaseReplyContexts(); /* * Disconnect the network closing sockets etc. */ AJ_Net_Disconnect(&bus->sock); #ifdef AJ_SERIAL_CONNECTION AJ_SerialShutdown(); #endif /* * Clear auth context */ AJ_ClearAuthContext(); /* * Clear sent manifests flag */ AJ_ClearSentManifests(); /* * Set the routing nodes proto version to zero (not connected) */ routingProtoVersion = 0; /* * Clean up the ongoing session bookkeeping */ AJ_BusRemoveAllSessions(bus); } static uint32_t RNBlacklistIP[AJ_ROUTING_NODE_BLACKLIST_SIZE]; static uint16_t RNBlacklistPort[AJ_ROUTING_NODE_BLACKLIST_SIZE]; static uint8_t RNBlacklistIndex = 0; static AJ_Service RNResponseList[AJ_ROUTING_NODE_RESPONSELIST_SIZE]; static uint16_t RNAttemptsList[AJ_ROUTING_NODE_RESPONSELIST_SIZE]; static uint8_t RNResponseListIndex = 0; uint8_t AJ_IsRoutingNodeBlacklisted(AJ_Service* service) { uint8_t i = 0; for (; i < AJ_ROUTING_NODE_BLACKLIST_SIZE; ++i) { if (RNBlacklistIP[i]) { if (RNBlacklistIP[i] == service->ipv4 && RNBlacklistPort[i] == service->ipv4port) { return TRUE; } } else { // break early if list isn't full break; } } return FALSE; } void AJ_AddRoutingNodeToResponseList(AJ_Service* service) { /* * The routing node response list is an unsorted fixed length list * of routing node responses that have 1) highest protocol * version and 2) lowest service priority (inverse of static rank/score) * of the routing node responses that have been received so far. * When the list is full and there are new responses of the same rank * as entries in the list, the previously received responses are preferred * over the newer responses. This may have a side-effect of not * allowing some responses to be considered. An alternative is * to randomly select which responses will get added to the list * in such a situation. */ int i = 0; int candidate = 0; if (RNResponseListIndex < AJ_ROUTING_NODE_RESPONSELIST_SIZE) { candidate = RNResponseListIndex; } // pass through the list and either update responses already received or // identify candidate slot for replacement (the slot with the lowest rank // in the list for (i = 0; i < AJ_ROUTING_NODE_RESPONSELIST_SIZE; ++i) { // if this slot is occupied if (RNResponseList[i].ipv4 || RNResponseList[i].ipv4Udp) { // if the service is already on the list if ((RNResponseList[i].ipv4 && RNResponseList[i].ipv4 == service->ipv4 && RNResponseList[i].ipv4port == service->ipv4port) || (RNResponseList[i].ipv4Udp && RNResponseList[i].ipv4Udp == service->ipv4Udp && RNResponseList[i].ipv4portUdp == service->ipv4portUdp)) { // if the new response has higher protocol if (RNResponseList[i].pv < service->pv) { // update to the highest protocol version per service RNResponseList[i].pv = service->pv; RNResponseList[i].priority = service->priority; AJ_InfoPrintf(("Updated RN 0x%x pv (pv = %d, port = %d, priority = %d) (slot %d of %d)\n", service->ipv4, service->pv, service->ipv4port, service->priority, i, RNResponseListIndex)); } else if (RNResponseList[i].pv == service->pv) { // equal protocol version, update the priority to that of the latest response if (RNResponseList[i].priority != service->priority) { RNResponseList[i].priority = service->priority; AJ_InfoPrintf(("Updated RN 0x%x priority (pv = %d, port = %d, priority = %d) (slot %d of %d)\n", service->ipv4, service->pv, service->ipv4port, service->priority, i, RNResponseListIndex)); } } // else existing entry has better protocol version return; } else { // this response not on list, find a candidate for replacement if (RNResponseListIndex == AJ_ROUTING_NODE_RESPONSELIST_SIZE) { if (RNResponseList[i].pv > RNResponseList[candidate].pv) { // this slot has higher protocol version than current candidate continue; } else if (RNResponseList[i].pv < RNResponseList[candidate].pv) { // this slot has lower protocol version than current candidate, so new candidate candidate = i; } else if (RNResponseList[i].priority < RNResponseList[candidate].priority) { // this slot has better priority than current candidate continue; } else if (RNResponseList[i].priority > RNResponseList[candidate].priority) { // this slot has worse priority than current candidate, so new candidate candidate = i; } } } } else { // break early if list is not full break; } } // check if candidate is actually lower ranking than service if (RNResponseListIndex == AJ_ROUTING_NODE_RESPONSELIST_SIZE) { // if candidate for eviction has higher protocol version do not replace if (service->pv < RNResponseList[candidate].pv) { return; } // if candidate for eviction has equal protocol version but better priority then do not replace if (service->pv == RNResponseList[candidate].pv && service->priority >= RNResponseList[candidate].priority) { return; } AJ_InfoPrintf(("Evicting slot number %d\n", candidate)); } RNResponseList[candidate].ipv4 = service->ipv4; RNResponseList[candidate].ipv4port = service->ipv4port; RNResponseList[candidate].ipv4Udp = service->ipv4Udp; RNResponseList[candidate].ipv4portUdp = service->ipv4portUdp; RNResponseList[candidate].addrTypes = service->addrTypes; RNResponseList[candidate].pv = service->pv; RNResponseList[candidate].priority = service->priority; if (RNResponseListIndex < AJ_ROUTING_NODE_RESPONSELIST_SIZE) { RNResponseListIndex++; } AJ_InfoPrintf(("Added RN 0x%x (pv = %d, port = %d, priority = %d) to list (slot %d of %d)\n", service->ipv4, service->pv, service->ipv4port, service->priority, candidate, RNResponseListIndex)); } AJ_Status AJ_SelectRoutingNodeFromResponseList(AJ_Service* service) { /* * The selection involves choosing the router with the * highest protocol version and the lowest service priority * (inverse of static rank/score). */ uint8_t i = 1; uint8_t selectedIndex = 0; uint32_t runningSum = 0; uint8_t skip = 0; uint32_t priority_idx = 0; uint32_t priority_srv = 0; uint32_t rand32 = 0; if (RNResponseList[0].ipv4 || RNResponseList[0].ipv4Udp) { service->ipv4 = RNResponseList[0].ipv4; service->ipv4port = RNResponseList[0].ipv4port; service->ipv4Udp = RNResponseList[0].ipv4Udp; service->ipv4portUdp = RNResponseList[0].ipv4portUdp; service->pv = RNResponseList[0].pv; service->addrTypes = RNResponseList[0].addrTypes; service->priority = RNResponseList[0].priority; runningSum = service->priority; skip = RNAttemptsList[0]; if (skip) { AJ_InfoPrintf(("Index 0 was previously selected\n")); } for (; i < AJ_ROUTING_NODE_RESPONSELIST_SIZE; ++i) { if (RNResponseList[i].ipv4 || RNResponseList[i].ipv4Udp) { if (RNAttemptsList[i]) { AJ_InfoPrintf(("Index %d was previously selected\n", i)); continue; } if (skip) { service->ipv4 = RNResponseList[i].ipv4; service->ipv4port = RNResponseList[i].ipv4port; service->ipv4Udp = RNResponseList[i].ipv4Udp; service->ipv4portUdp = RNResponseList[i].ipv4portUdp; service->pv = RNResponseList[i].pv; service->addrTypes = RNResponseList[i].addrTypes; service->priority = RNResponseList[i].priority; selectedIndex = i; runningSum = service->priority; skip = 0; continue; } if (RNResponseList[i].pv < service->pv) { continue; } if (RNResponseList[i].pv > service->pv || (RNResponseList[i].pv == service->pv && RNResponseList[i].priority < service->priority)) { service->ipv4 = RNResponseList[i].ipv4; service->ipv4port = RNResponseList[i].ipv4port; service->ipv4Udp = RNResponseList[i].ipv4Udp; service->ipv4portUdp = RNResponseList[i].ipv4portUdp; service->pv = RNResponseList[i].pv; service->addrTypes = RNResponseList[i].addrTypes; service->priority = RNResponseList[i].priority; runningSum = service->priority; selectedIndex = i; AJ_InfoPrintf(("Tentatively selecting routing node %x (pv = %d, port = %d, priority = %d).\n", service->ipv4, service->pv, service->ipv4port, service->priority)); } else if (RNResponseList[i].priority == service->priority) { /* * Randomly select one of out of all the routing nodes with the same * protocol version and priority with each node given an equal chance * of being selected. To select from a pair of nodes, the first node's * priority is used as its associated sum, while the sum of the two * priorities under consideration is used as the second node's * associated sum. A uniform random number up to the sum of the two * priorities (inclusive) is chosen and the first node whose associated * sum is greater than or equal to the random number is selected. */ rand32 = 0; AJ_RandBytes((uint8_t*)&rand32, sizeof(rand32)); priority_idx = RNResponseList[i].priority + runningSum; priority_srv = runningSum; runningSum = priority_idx; rand32 %= (runningSum + 1); AJ_InfoPrintf(("P_idx is %u and P_srv is %u and random is %u\n", priority_idx, priority_srv, rand32)); if (rand32 > priority_srv) { AJ_InfoPrintf(("Picking index %d on this round\n", i)); service->ipv4 = RNResponseList[i].ipv4; service->ipv4port = RNResponseList[i].ipv4port; service->ipv4Udp = RNResponseList[i].ipv4Udp; service->ipv4portUdp = RNResponseList[i].ipv4portUdp; service->pv = RNResponseList[i].pv; service->addrTypes = RNResponseList[i].addrTypes; service->priority = RNResponseList[i].priority; selectedIndex = i; AJ_InfoPrintf(("Tentatively selecting routing node 0x%x (pv = %d, port = %d, priority = %d).\n", service->ipv4, service->pv, service->ipv4port, service->priority)); } } } else { // break early if list isn't full break; } } } else { AJ_InitRoutingNodeResponselist(); return AJ_ERR_TIMEOUT; } if (skip) { AJ_InfoPrintf(("All entries in the response list have been previously selected\n")); return AJ_ERR_END_OF_DATA; } RNAttemptsList[selectedIndex] = 1; AJ_InfoPrintf(("Selected routing node 0x%x (pv = %d, port = %d, priority = %d) out of %d responses in the list.\n", service->ipv4, service->pv, service->ipv4port, service->priority, RNResponseListIndex)); return AJ_OK; } uint8_t AJ_GetRoutingNodeResponseListSize() { return RNResponseListIndex; } static void AddRoutingNodeToBlacklist(const AJ_Service* service, uint8_t addrTypes) { if ((addrTypes & AJ_ADDR_TCP4) && (service->addrTypes & AJ_ADDR_TCP4)) { RNBlacklistIP[RNBlacklistIndex] = service->ipv4; RNBlacklistPort[RNBlacklistIndex] = service->ipv4port; RNBlacklistIndex = (RNBlacklistIndex + 1) % AJ_ROUTING_NODE_BLACKLIST_SIZE; } if ((addrTypes & AJ_ADDR_UDP4) && (service->addrTypes & AJ_ADDR_UDP4)) { RNBlacklistIP[RNBlacklistIndex] = service->ipv4Udp; RNBlacklistPort[RNBlacklistIndex] = service->ipv4portUdp; RNBlacklistIndex = (RNBlacklistIndex + 1) % AJ_ROUTING_NODE_BLACKLIST_SIZE; } } void AJ_InitRoutingNodeResponselist() { memset(RNResponseList, 0, sizeof(RNResponseList)); memset(RNAttemptsList, 0, sizeof(RNAttemptsList)); RNResponseListIndex = 0; } void AJ_InitRoutingNodeBlacklist() { memset(RNBlacklistIP, 0, sizeof(RNBlacklistIP)); memset(RNBlacklistPort, 0, sizeof(RNBlacklistPort)); RNBlacklistIndex = 0; } ajtcl-16.04/src/aj_conversationhash.c000066400000000000000000000172311271074662300176200ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CONVERSATIONHASH #include #include #include #include /* SECURITY NOTE: Because the pre-shared key is hashed into the conversation hash * for the ECDHE_PSK method in conversation versions <= 3, to avoid unintentional * disclosure, the bytes of the PSK not traced in the log, but instead an entry stating * that secret data is hashed in at that point is added. To override this behavior and * include secret data in the log, define the CONVERSATION_HASH_TRACE_SECRETS constant. */ #undef CONVERSATION_HASH_LOG_SECRETS /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgCONVERSATIONHASH = 0; #endif /* For purposes of debugging, try and keep the trace logging prints the same as they are * in standard client so diffing tools can be used. */ AJ_Status AJ_ConversationHash_Initialize(AJ_AuthenticationContext* ctx) { AJ_InfoPrintf(("InitializeConversationHash ------------------------------------\n")); ctx->hash = AJ_SHA256_Init(); if (ctx->hash) { return AJ_OK; } else { AJ_ErrPrintf(("AJ_ConversationHash_Initialize() failed\n")); return AJ_ERR_RESOURCES; } } uint8_t AJ_ConversationHash_IsInitialized(AJ_AuthenticationContext* ctx) { if (ctx->hash) { return 1; } return 0; } static inline int ConversationVersionDoesNotApply(uint32_t conversationVersion, uint32_t currentAuthVersion) { AJ_ASSERT((CONVERSATION_V1 == conversationVersion) || (CONVERSATION_V4 == conversationVersion)); /* The conversation version itself is computed by taking (currentAuthVersion >> 16). We return true * if the current conversation version does NOT apply to the conversation version for the message being hashed. */ if (CONVERSATION_V4 == conversationVersion) { return ((currentAuthVersion >> 16) != CONVERSATION_V4); } else { return ((currentAuthVersion >> 16) >= CONVERSATION_V4); } } void AJ_ConversationHash_Update_UInt8(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, uint8_t byte) { if (ConversationVersionDoesNotApply(conversationVersion, ctx->version)) { return; } AJ_SHA256_Update(ctx->hash, &byte, sizeof(byte)); AJ_InfoPrintf(("Hashed byte: %02X\n", byte)); } static void ConversationHash_Update_UInt32(AJ_AuthenticationContext* ctx, uint32_t u32) { /* Make sure any functions calling this code are doing the appropriate trace logging! */ uint8_t u32LE[sizeof(uint32_t)]; HostU32ToLittleEndianU8(&u32, sizeof(u32), u32LE); AJ_SHA256_Update(ctx->hash, u32LE, sizeof(u32LE)); } void AJ_ConversationHash_Update_UInt8Array(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, const uint8_t* buf, size_t bufSize) { if (ConversationVersionDoesNotApply(conversationVersion, ctx->version)) { return; } if (conversationVersion >= CONVERSATION_V4) { AJ_ASSERT(bufSize <= 0xFFFFFFFF); ConversationHash_Update_UInt32(ctx, (uint32_t)bufSize); #if defined(_MSC_VER) AJ_InfoPrintf(("Hashed size: %Iu\n", bufSize)); #else AJ_InfoPrintf(("Hashed size: %zu\n", bufSize)); #endif } AJ_SHA256_Update(ctx->hash, buf, bufSize); #ifndef CONVERSATION_HASH_LOG_SECRETS /* Compare != FALSE just in case a caller passes something nonzero but not TRUE (1) into * AJ_ConversationHash_SetSensitiveMode. */ if (ctx->sensitiveMode != FALSE) { AJ_InfoPrintf(("Hashed byte array of secret data; data intentionally not logged\n")); } else { #endif AJ_InfoPrintf(("Hashed byte array:\n")); AJ_DumpBytes(NULL, buf, bufSize); #ifndef CONVERSATION_HASH_LOG_SECRETS } #endif } void AJ_ConversationHash_Update_String(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, const char* str, size_t strSize) { AJ_ConversationHash_Update_UInt8Array(ctx, conversationVersion, (const uint8_t*)str, strSize); } void AJ_ConversationHash_Update_Message(AJ_AuthenticationContext* ctx, uint32_t conversationVersion, AJ_Message* msg, uint8_t isMarshaledMessage) { uint8_t* data; uint32_t size; AJ_MsgHeader hdr; if (ConversationVersionDoesNotApply(conversationVersion, ctx->version)) { return; } AJ_ASSERT((HASH_MSG_UNMARSHALED == isMarshaledMessage) || (HASH_MSG_MARSHALED == isMarshaledMessage)); AJ_ASSERT(!(msg->hdr->flags & AJ_FLAG_ENCRYPTED)); if (HASH_MSG_MARSHALED == isMarshaledMessage) { /* msg->hdr->bodyLen gets set by AJ_DeliverMsg when the message is sent out. We set it here as well * so that the buffer we hash equals what will actually go out on the wire. */ AJ_ASSERT(0 == msg->hdr->bodyLen); msg->hdr->bodyLen = msg->bodyBytes; data = msg->bus->sock.tx.bufStart; size = sizeof(AJ_MsgHeader) + msg->hdr->headerLen + HEADERPAD(msg->hdr->headerLen) + msg->hdr->bodyLen; AJ_ConversationHash_Update_UInt8Array(ctx, conversationVersion, data, size); } else { /* * AJ_UnmarshalMsg ensures that the Peer.Authentication interface messages are loaded into the buffer. * The message header may have been endian swapped, so we use the raw header saved during AJ_UnmarshalMsg. */ data = msg->bus->sock.rx.bufStart; size = sizeof(AJ_MsgHeader) + msg->hdr->headerLen + HEADERPAD(msg->hdr->headerLen) + msg->hdr->bodyLen; /* Save the current header */ memcpy(&hdr, data, sizeof(AJ_MsgHeader)); /* Replace with original header */ memcpy(data, &msg->raw, sizeof(AJ_MsgHeader)); AJ_ConversationHash_Update_UInt8Array(ctx, conversationVersion, data, size); /* Put the header back */ memcpy(data, &hdr, sizeof(AJ_MsgHeader)); } } AJ_Status AJ_ConversationHash_GetDigest(AJ_AuthenticationContext* ctx) { AJ_Status status; status = AJ_SHA256_GetDigest(ctx->hash, ctx->digest); AJ_InfoPrintf(("Got conversation digest ------------------------------------\n")); AJ_InfoPrintf(("Digest is: \n")); AJ_DumpBytes(NULL, ctx->digest, AJ_SHA256_DIGEST_LENGTH); return status; } AJ_Status AJ_ConversationHash_Reset(AJ_AuthenticationContext* ctx) { AJ_Status status; status = AJ_SHA256_Final(ctx->hash, NULL); if (status == AJ_OK) { /* Call to AJ_ConversationHash_Initialize will handle trace logging. */ status = AJ_ConversationHash_Initialize(ctx); } return status; } void AJ_ConversationHash_SetSensitiveMode(AJ_AuthenticationContext* ctx, uint8_t mode) { ctx->sensitiveMode = mode; } ajtcl-16.04/src/aj_crc16.c000066400000000000000000000073371271074662300151660ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include static const uint16_t crc16[256] = { 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 }; void AJ_CRC16_Compute(const uint8_t* buffer, uint16_t bufLen, uint16_t* runningCrc) { uint16_t crc = *runningCrc; while (bufLen--) { crc = crc16[(crc ^ *buffer++) & 0xFF] ^ (crc >> 8); } *runningCrc = crc; } void AJ_CRC16_Complete(uint16_t crc, uint8_t* crcBlock) { static const uint8_t rev[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; crcBlock[0] = (uint8_t) (rev[crc & 0xF] << 4) | rev[(crc >> 4) & 0xF]; crcBlock[1] = (uint8_t) (rev[(crc >> 8) & 0xF] << 4) | rev[crc >> 12]; } ajtcl-16.04/src/aj_creds.c000066400000000000000000000444501271074662300153450ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CREDS #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgCREDS = 0; #endif static AJ_Status CredValueRead(uint8_t* data, size_t size, AJ_NV_DATASET* handle) { return (size == AJ_NVRAM_Read(data, size, handle)) ? AJ_OK : AJ_ERR_FAILURE; } static AJ_Status CredValueWrite(const uint8_t* data, size_t size, AJ_NV_DATASET* handle) { return (size == AJ_NVRAM_Write(data, size, handle)) ? AJ_OK : AJ_ERR_FAILURE; } /** * If a data buffer exists in the input field, * the contents will be written straight to that buffer. * Its size taken into account. * If no data buffer exists in the input field, * a new buffer will be allocated and the contents written to it. * The caller must be aware, so they know whether to free it. */ static AJ_Status CredFieldRead(AJ_CredField* field, AJ_NV_DATASET* handle) { uint16_t size; /* Read size */ if (sizeof (uint16_t) != AJ_NVRAM_Read((uint8_t*) &size, sizeof (uint16_t), handle)) { return AJ_ERR_FAILURE; } /* If no data to read, return */ if (0 == size) { field->size = 0; return AJ_OK; } if (NULL == field->data) { /* If field->data not passed in, allocate memory for it */ field->size = 0; field->data = (uint8_t*) AJ_Malloc(size); if (NULL != field->data) { field->size = size; } } /* Check sufficient buffer */ if (field->size < size) { return AJ_ERR_RESOURCES; } /* Read data */ if (size != AJ_NVRAM_Read(field->data, size, handle)) { return AJ_ERR_FAILURE; } field->size = size; return AJ_OK; } static AJ_Status CredFieldWrite(const AJ_CredField* field, AJ_NV_DATASET* handle) { uint16_t size = 0; if (NULL != field) { size = field->size; } /* Write size */ if (sizeof (uint16_t) != AJ_NVRAM_Write((uint8_t*) &size, sizeof (uint16_t), handle)) { return AJ_ERR_FAILURE; } /* If no data to write, return */ if (0 == size) { return AJ_OK; } /* Write data */ if (field->size != AJ_NVRAM_Write((uint8_t*) field->data, field->size, handle)) { return AJ_ERR_FAILURE; } return AJ_OK; } static uint16_t CredentialSize(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_CredField* data) { uint16_t size = sizeof (type) + sizeof (id->size) + sizeof (data->size) + sizeof (expiration); if (id) { size += id->size; } if (data) { size += data->size; } return size; } static uint16_t FindCredsEmptySlot() { uint16_t id = AJ_CREDS_NV_ID_BEGIN; for (; id < AJ_CREDS_NV_ID_END; id++) { if (!AJ_NVRAM_Exist(id)) { return id; } } return 0; } static uint16_t CredentialFind(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_CredField* data, uint16_t slot) { AJ_Status status; AJ_NV_DATASET* handle; uint32_t exp; uint16_t value; AJ_CredField field; uint8_t found; for (; slot < AJ_CREDS_NV_ID_END; slot++) { if (!AJ_NVRAM_Exist(slot)) { continue; } handle = AJ_NVRAM_Open(slot, "r", 0); if (!handle) { continue; } /* Read type */ status = CredValueRead((uint8_t*) &value, sizeof (uint16_t), handle); if (AJ_OK != status) { AJ_NVRAM_Close(handle); return 0; } /* Compare type */ if (value != type) { AJ_NVRAM_Close(handle); continue; } if ((NULL == id) && (NULL == expiration) && (NULL == data)) { /* No more fields requested */ AJ_NVRAM_Close(handle); return slot; } /* Read id */ field.data = NULL; status = CredFieldRead(&field, handle); if (AJ_OK != status) { AJ_NVRAM_Close(handle); return 0; } /* Compare id */ found = 1; if (id) { if ((field.size != id->size) || (0 != memcmp(field.data, id->data, field.size))) { found = 0; } } AJ_CredFieldFree(&field); if (!found) { AJ_NVRAM_Close(handle); continue; } if ((NULL == expiration) && (NULL == data)) { /* No more fields requested */ AJ_NVRAM_Close(handle); return slot; } status = CredValueRead((uint8_t*) &exp, sizeof (uint32_t), handle); if (AJ_OK != status) { AJ_NVRAM_Close(handle); return 0; } if (expiration) { *expiration = exp; } if (NULL == data) { /* No more fields requested */ AJ_NVRAM_Close(handle); return slot; } status = CredFieldRead(data, handle); AJ_NVRAM_Close(handle); if (AJ_OK != status) { return 0; } return slot; } return 0; /* not found */ } static AJ_Status DeleteOldestCredential(uint16_t* deleted) { AJ_Status status = AJ_ERR_INVALID; AJ_NV_DATASET* handle; uint16_t slot = AJ_CREDS_NV_ID_BEGIN; uint16_t oldestslot = 0; uint32_t oldestexp = 0xFFFFFFFF; uint16_t type; AJ_CredField id; uint32_t expiration; AJ_InfoPrintf(("DeleteOldestCredential(deleted=%p)\n", deleted)); for (; slot < AJ_CREDS_NV_ID_END; slot++) { if (!AJ_NVRAM_Exist(slot)) { continue; } handle = AJ_NVRAM_Open(slot, "r", 0); if (!handle) { continue; } status = CredValueRead((uint8_t*) &type, sizeof (uint16_t), handle); if (AJ_OK != status) { AJ_NVRAM_Close(handle); continue; } if (AJ_CRED_TYPE_GENERIC != type) { AJ_NVRAM_Close(handle); continue; } /* Read id */ id.size = 0; id.data = NULL; status = CredFieldRead(&id, handle); AJ_CredFieldFree(&id); if (AJ_OK != status) { AJ_NVRAM_Close(handle); continue; } status = CredValueRead((uint8_t*) &expiration, sizeof (uint32_t), handle); if (AJ_OK != status) { AJ_NVRAM_Close(handle); continue; } /* If older */ if (expiration <= oldestexp) { oldestexp = expiration; oldestslot = slot; } } if (oldestslot) { AJ_InfoPrintf(("DeleteOldestCredential(deleted=%p): slot=%d exp=%08X\n", deleted, oldestslot, oldestexp)); status = AJ_CredentialDeleteSlot(type, oldestslot); if (AJ_OK != status) { AJ_ErrPrintf(("AJ_CredentialDeleteSlot() failed, status=%s\n", AJ_StatusText(status))); } else { *deleted = oldestslot; } return status; } return AJ_ERR_UNKNOWN; } static AJ_Status CredentialWrite(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_CredField* data, uint16_t slot) { AJ_Status status = AJ_OK; AJ_NV_DATASET* handle; size_t size; AJ_InfoPrintf(("CredentialWrite(type=%04x, id=%p, expiration=%08x, data=%p, slot=%d)\n", type, id, expiration, data, slot)); size = CredentialSize(type, id, expiration, data); handle = AJ_NVRAM_Open(slot, "w", size); if (!handle) { return AJ_ERR_FAILURE; } status = CredValueWrite((uint8_t*) &type, sizeof (uint16_t), handle); if (AJ_OK != status) { goto Exit; } status = CredFieldWrite(id, handle); if (AJ_OK != status) { goto Exit; } status = CredValueWrite((uint8_t*) &expiration, sizeof (uint32_t), handle); if (AJ_OK != status) { goto Exit; } status = CredFieldWrite(data, handle); if (AJ_OK != status) { goto Exit; } Exit: AJ_NVRAM_Close(handle); return status; } AJ_Status AJ_CredentialRead(uint16_t* type, AJ_CredField* id, uint32_t* expiration, AJ_CredField* data, uint16_t slot) { AJ_Status status; AJ_NV_DATASET* handle; AJ_InfoPrintf(("AJ_CredentialRead(type=%p, id=%p, expiration=%p, data=%p, slot=%d)\n", type, id, expiration, data, slot)); handle = AJ_NVRAM_Open(slot, "r", 0); if (!handle) { return AJ_ERR_FAILURE; } status = CredValueRead((uint8_t*) type, sizeof (uint16_t), handle); if (AJ_OK != status) { goto Exit; } status = CredFieldRead(id, handle); if (AJ_OK != status) { goto Exit; } status = CredValueRead((uint8_t*) expiration, sizeof (uint32_t), handle); if (AJ_OK != status) { goto Exit; } status = CredFieldRead(data, handle); if (AJ_OK != status) { goto Exit; } Exit: AJ_NVRAM_Close(handle); return status; } AJ_Status AJ_CredentialSet(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_CredField* data) { AJ_Status status = AJ_OK; uint16_t slot; uint32_t size; AJ_InfoPrintf(("AJ_CredentialSet(type=%04x, id=%p, expiration=%08x, data=%p)\n", type, id, expiration, data)); slot = CredentialFind(type, id, NULL, NULL, AJ_CREDS_NV_ID_BEGIN); if (!slot) { /* * Check there is sufficient space left. * If there isn't, keep deleting oldest credential until there is. */ size = CredentialSize(type, id, expiration, data); size = WORD_ALIGN(size); slot = FindCredsEmptySlot(); while ((AJ_OK == status) && (!slot || (size >= AJ_NVRAM_GetSizeRemaining()))) { status = DeleteOldestCredential(&slot); } } if (slot) { status = CredentialWrite(type, id, expiration, data, slot); } else { status = AJ_ERR_FAILURE; } return status; } AJ_Status AJ_CredentialGet(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_CredField* data) { AJ_InfoPrintf(("AJ_CredentialGet(type=%04x, id=%p, expiration=%p, data=%p)\n", type, id, expiration, data)); return CredentialFind(type, id, expiration, data, AJ_CREDS_NV_ID_BEGIN) ? AJ_OK : AJ_ERR_UNKNOWN; } AJ_Status AJ_CredentialGetNext(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_CredField* data, uint16_t* slot) { AJ_InfoPrintf(("AJ_CredentialGet(type=%04x, id=%p, expiration=%p, data=%p)\n", type, id, expiration, data)); *slot = CredentialFind(type, id, expiration, data, *slot); return *slot ? AJ_OK : AJ_ERR_UNKNOWN; } static AJ_Status CredentialSetLocal(uint16_t slot, const uint8_t* data, uint16_t size) { AJ_Status status; AJ_NV_DATASET* handle; handle = AJ_NVRAM_Open(slot, "w", size); if (!handle) { AJ_WarnPrintf(("CredentialSetLocal(slot=%d, data=%p, size=%d): Error opening slot\n", slot, data, size)); return AJ_ERR_FAILURE; } if (size == AJ_NVRAM_Write(data, size, handle)) { status = AJ_OK; } else { AJ_WarnPrintf(("CredentialSetLocal(slot=%d, data=%p, size=%d): Error writing slot\n", slot, data, size)); status = AJ_ERR_FAILURE; } AJ_NVRAM_Close(handle); return status; } static AJ_Status CredentialGetLocal(uint16_t slot, uint8_t* data, uint16_t size) { AJ_Status status; AJ_NV_DATASET* handle; if (!AJ_NVRAM_Exist(slot)) { return AJ_ERR_FAILURE; } handle = AJ_NVRAM_Open(slot, "r", 0); if (!handle) { AJ_WarnPrintf(("CredentialGetLocal(slot=%d, data=%p, size=%d): Error opening slot\n", slot, data, size)); return AJ_ERR_FAILURE; } if (size == AJ_NVRAM_Read(data, size, handle)) { status = AJ_OK; } else { AJ_WarnPrintf(("CredentialGetLocal(slot=%d, data=%p, size=%d): Error reading slot\n", slot, data, size)); status = AJ_ERR_FAILURE; } AJ_NVRAM_Close(handle); return status; } static AJ_Status CredentialSetGUID(AJ_GUID* guid) { AJ_InfoPrintf(("CredentialSetGUID(guid=%p)\n", guid)); return CredentialSetLocal(AJ_LOCAL_GUID_NV_ID, (uint8_t*) guid, sizeof (AJ_GUID)); } AJ_Status AJ_GetLocalGUID(AJ_GUID* guid) { AJ_Status status; AJ_InfoPrintf(("AJ_GetLocalGUID(guid=%p)\n", guid)); status = CredentialGetLocal(AJ_LOCAL_GUID_NV_ID, (uint8_t*) guid, sizeof (AJ_GUID)); if (AJ_OK != status) { AJ_RandBytes((uint8_t*) guid, sizeof (AJ_GUID)); status = CredentialSetGUID(guid); } return status; } AJ_Status AJ_CredentialSetPeer(uint16_t type, const AJ_GUID* guid, uint32_t expiration, const uint8_t* secret, uint16_t size) { AJ_CredField id; AJ_CredField data; AJ_Status status; AJ_InfoPrintf(("AJ_CredentialSetPeer(guid=%p, expiration=%08X, secret=%p, size=%d)\n", guid, expiration, secret, size)); id.size = sizeof (AJ_GUID); id.data = (uint8_t*) guid; data.size = size; data.data = (uint8_t*) secret; status = AJ_CredentialSet(type | AJ_CRED_TYPE_GENERIC, &id, expiration, &data); return status; } AJ_Status AJ_CredentialGetPeer(uint16_t type, const AJ_GUID* guid, uint32_t* expiration, AJ_CredField* data) { AJ_CredField id; id.size = sizeof (AJ_GUID); id.data = (uint8_t*) guid; return AJ_CredentialGet(type | AJ_CRED_TYPE_GENERIC, &id, expiration, data); } AJ_Status AJ_CredentialSetECCPublicKey(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_ECCPublicKey* pub) { AJ_CredField data; data.size = sizeof (AJ_ECCPublicKey); data.data = (uint8_t*) pub; return AJ_CredentialSet(type | AJ_CRED_TYPE_PUBLIC, id, expiration, &data); } AJ_Status AJ_CredentialGetECCPublicKey(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_ECCPublicKey* pub) { AJ_CredField data; data.size = sizeof (AJ_ECCPublicKey); data.data = (uint8_t*) pub; return AJ_CredentialGet(type | AJ_CRED_TYPE_PUBLIC, id, NULL, &data); } AJ_Status AJ_CredentialSetECCPrivateKey(uint16_t type, const AJ_CredField* id, uint32_t expiration, const AJ_ECCPrivateKey* prv) { AJ_CredField data; data.size = sizeof (AJ_ECCPrivateKey); data.data = (uint8_t*) prv; return AJ_CredentialSet(type | AJ_CRED_TYPE_PRIVATE, id, expiration, &data); } AJ_Status AJ_CredentialGetECCPrivateKey(uint16_t type, const AJ_CredField* id, uint32_t* expiration, AJ_ECCPrivateKey* prv) { AJ_CredField data; data.size = sizeof (AJ_ECCPrivateKey); data.data = (uint8_t*) prv; return AJ_CredentialGet(type | AJ_CRED_TYPE_PRIVATE, id, NULL, &data); } AJ_Status AJ_CredentialDeleteSlot(uint16_t type, uint16_t slot) { AJ_Status status = AJ_ERR_FAILURE; if (slot > 0) { if ((type == AJ_CRED_TYPE_AES) || (type == AJ_CRED_TYPE_PRIVATE) || (type == AJ_GENERIC_MASTER_SECRET) || (type == AJ_ECC_SIG)) { status = AJ_NVRAM_SecureDelete(slot); } else { status = AJ_NVRAM_Delete(slot); } } return status; } AJ_Status AJ_CredentialDelete(uint16_t type, const AJ_CredField* id) { AJ_Status status = AJ_ERR_FAILURE; uint16_t slot = CredentialFind(type, id, NULL, NULL, AJ_CREDS_NV_ID_BEGIN); AJ_InfoPrintf(("AJ_CredentialDelete(type=%04x, id=%p)\n", type, id)); status = AJ_CredentialDeleteSlot(type, slot); return status; } void AJ_CredentialDeletePeer(const AJ_GUID* guid) { AJ_CredField id; id.size = sizeof (AJ_GUID); id.data = (uint8_t*) guid; AJ_CredentialDelete(AJ_GENERIC_MASTER_SECRET | AJ_CRED_TYPE_GENERIC, &id); AJ_CredentialDelete(AJ_GENERIC_ECDSA_THUMBPRINT | AJ_CRED_TYPE_GENERIC, &id); AJ_CredentialDelete(AJ_GENERIC_ECDSA_KEYS | AJ_CRED_TYPE_GENERIC, &id); } AJ_Status AJ_ClearCredentials(uint16_t type) { AJ_Status status = AJ_OK; uint16_t slot = AJ_CREDS_NV_ID_BEGIN; uint16_t test; AJ_NV_DATASET* handle; AJ_InfoPrintf(("AJ_ClearCredentials(type=%04x)\n", type)); for (; slot < AJ_CREDS_NV_ID_END; ++slot) { if (!AJ_NVRAM_Exist(slot)) { continue; } if (type) { handle = AJ_NVRAM_Open(slot, "r", 0); if (!handle) { AJ_WarnPrintf(("AJ_ClearCredentials(type=%04x): Error opening slot %d\n", type, slot)); continue; } status = CredValueRead((uint8_t*) &test, sizeof (uint16_t), handle); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_ClearCredentials(type=%04x): Error reading slot %d\n", type, slot)); AJ_NVRAM_Close(handle); continue; } AJ_NVRAM_Close(handle); if (test != type) { continue; } } AJ_NVRAM_Delete(slot); } return status; } AJ_Status AJ_CredentialExpired(uint32_t expiration) { AJ_Time now; AJ_InitTimer(&now); if (now.seconds == 0) { /* don't know the current time so can't check the credential expriy */ return AJ_ERR_INVALID; } if (expiration > now.seconds) { return AJ_OK; } return AJ_ERR_KEY_EXPIRED; /* expires */ } void AJ_CredFieldFree(AJ_CredField* field) { if (field && field->data) { AJ_MemZeroSecure(field->data, field->size); AJ_Free(field->data); field->data = NULL; } } ajtcl-16.04/src/aj_crypto_util.c000066400000000000000000000037221271074662300166170ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CRYPTO_UTIL #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgCRYPTO_UTIL = 0; #endif AJ_Status AJ_RandHex(char* randBuf, uint32_t bufLen, uint32_t len) { AJ_RandBytes((uint8_t*)randBuf, len); return AJ_RawToHex((const uint8_t*) randBuf, len, randBuf, bufLen, FALSE); } int AJ_Crypto_Compare(const void* buf1, const void* buf2, size_t count) { size_t i = 0; uint8_t different = 0; AJ_ASSERT(buf1 != NULL); AJ_ASSERT(buf2 != NULL); /* This loop uses the same number of cycles for any two buffers of size count. */ for (i = 0; i < count; i++) { different |= ((uint8_t*)buf1)[i] ^ ((uint8_t*)buf2)[i]; } return (int)different; } ajtcl-16.04/src/aj_debug.c000066400000000000000000000161451271074662300153330ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE DEBUG #include uint8_t dbgDEBUG = 0; #ifndef NDEBUG #include #include #include #define Printable(c) (((c) >= ' ') && ((c) <= '~')) ? (c) : '.' void _AJ_DumpBytes(const char* tag, const uint8_t* data, uint32_t len) { uint32_t i; char ascii[AJ_DUMP_BYTE_SIZE + 1]; if (tag) { AJ_AlwaysPrintf(("%s: (%u)\n", tag, len)); } ascii[AJ_DUMP_BYTE_SIZE] = '\0'; for (i = 0; i < len; i += AJ_DUMP_BYTE_SIZE) { uint32_t j; for (j = 0; j < AJ_DUMP_BYTE_SIZE; ++j, ++data) { if ((i + j) < len) { uint8_t n = *data; ascii[j] = Printable(n); if (n < 0x10) { AJ_AlwaysPrintf(("0%x ", n)); } else { AJ_AlwaysPrintf(("%x ", n)); } } else { ascii[j] = '\0'; AJ_AlwaysPrintf((" ")); } } ascii[j] = '\0'; AJ_AlwaysPrintf((" %s\n", ascii)); } } static const char* const msgType[] = { "INVALID", "CALL", "REPLY", "ERROR", "SIGNAL" }; void _AJ_DumpMsg(const char* tag, AJ_Message* msg, uint8_t body) { if (msg->hdr && _AJ_DbgHeader(AJ_DEBUG_ERROR, NULL, 0)) { #if AJ_DUMP_MSG_RAW uint8_t* p = (uint8_t*)msg->hdr + sizeof(AJ_MsgHeader); uint32_t hdrBytes = ((msg->hdr->headerLen + 7) & ~7); #endif AJ_AlwaysPrintf(("%s message[%d] type %s sig=\"%s\"\n", tag, msg->hdr->serialNum, msgType[(msg->hdr->msgType <= 4) ? msg->hdr->msgType : 0], msg->signature)); switch (msg->hdr->msgType) { case AJ_MSG_SIGNAL: case AJ_MSG_METHOD_CALL: AJ_AlwaysPrintf((" %s::%s\n", msg->iface, msg->member)); break; case AJ_MSG_ERROR: AJ_AlwaysPrintf((" Error %s\n", msg->error)); case AJ_MSG_METHOD_RET: AJ_AlwaysPrintf((" Reply serial %d\n", msg->replySerial)); break; } AJ_AlwaysPrintf((" hdr len=%d\n", msg->hdr->headerLen)); #if AJ_DUMP_MSG_RAW AJ_DumpBytes(NULL, p, hdrBytes); AJ_AlwaysPrintf(("body len=%d\n", msg->hdr->bodyLen)); if (body) { AJ_DumpBytes(NULL, p + hdrBytes, msg->hdr->bodyLen); } AJ_AlwaysPrintf(("-----------------------\n")); #endif } } int _AJ_DbgHeader(AJ_DebugLevel level, const char* file, int line) { static AJ_Time initTime; uint32_t logTimeSecond; uint32_t logTimeMS; if (!(initTime.seconds | initTime.milliseconds)) { AJ_InitTimer(&initTime); } if (level <= AJ_DbgLevel) { AJ_Time debugTime; if (AJ_OK == AJ_GetDebugTime(&debugTime)) { logTimeSecond = debugTime.seconds; logTimeMS = debugTime.milliseconds; } else { uint32_t elapsedTime = AJ_GetElapsedTime(&initTime, TRUE); logTimeSecond = elapsedTime / 1000; logTimeMS = elapsedTime % 1000; } if (file) { const char* fn = file; while (*fn) { if ((*fn == '/') || (*fn == '\\')) { file = fn + 1; } ++fn; } AJ_AlwaysPrintf(("%03d.%03d %s:%d ", logTimeSecond, logTimeMS, file, line)); } else { AJ_AlwaysPrintf(("%03d.%03d ", logTimeSecond, logTimeMS)); } return TRUE; } else { return FALSE; } } AJ_DebugLevel AJ_DbgLevel = AJ_DEBUG_INFO; uint8_t dbgALL = 0; #endif #define AJ_CASE(_status) case _status: return # _status const char* AJ_StatusText(AJ_Status status) { #ifdef NDEBUG /* Expectation is that thin client status codes will NOT go beyond 255 */ static char code[4]; #ifdef _WIN32 _snprintf(code, sizeof(code), "%03u", status); #else snprintf(code, sizeof(code), "%03u", status); #endif return code; #else switch (status) { AJ_CASE(AJ_OK); AJ_CASE(AJ_ERR_NULL); AJ_CASE(AJ_ERR_UNEXPECTED); AJ_CASE(AJ_ERR_INVALID); AJ_CASE(AJ_ERR_IO_BUFFER); AJ_CASE(AJ_ERR_READ); AJ_CASE(AJ_ERR_WRITE); AJ_CASE(AJ_ERR_TIMEOUT); AJ_CASE(AJ_ERR_MARSHAL); AJ_CASE(AJ_ERR_UNMARSHAL); AJ_CASE(AJ_ERR_END_OF_DATA); AJ_CASE(AJ_ERR_RESOURCES); AJ_CASE(AJ_ERR_NO_MORE); AJ_CASE(AJ_ERR_SECURITY); AJ_CASE(AJ_ERR_CONNECT); AJ_CASE(AJ_ERR_UNKNOWN); AJ_CASE(AJ_ERR_NO_MATCH); AJ_CASE(AJ_ERR_SIGNATURE); AJ_CASE(AJ_ERR_DISALLOWED); AJ_CASE(AJ_ERR_FAILURE); AJ_CASE(AJ_ERR_RESTART); AJ_CASE(AJ_ERR_LINK_TIMEOUT); AJ_CASE(AJ_ERR_DRIVER); AJ_CASE(AJ_ERR_OBJECT_PATH); AJ_CASE(AJ_ERR_BUSY); AJ_CASE(AJ_ERR_DHCP); AJ_CASE(AJ_ERR_ACCESS); AJ_CASE(AJ_ERR_SESSION_LOST); AJ_CASE(AJ_ERR_LINK_DEAD); AJ_CASE(AJ_ERR_HDR_CORRUPT); AJ_CASE(AJ_ERR_RESTART_APP); AJ_CASE(AJ_ERR_INTERRUPTED); AJ_CASE(AJ_ERR_REJECTED); AJ_CASE(AJ_ERR_RANGE); AJ_CASE(AJ_ERR_ACCESS_ROUTING_NODE); AJ_CASE(AJ_ERR_KEY_EXPIRED); AJ_CASE(AJ_ERR_SPI_NO_SPACE); AJ_CASE(AJ_ERR_SPI_READ); AJ_CASE(AJ_ERR_SPI_WRITE); AJ_CASE(AJ_ERR_OLD_VERSION); AJ_CASE(AJ_ERR_NVRAM_READ); AJ_CASE(AJ_ERR_NVRAM_WRITE); AJ_CASE(AJ_ERR_WOULD_BLOCK); AJ_CASE(AJ_ERR_ARDP_DISCONNECTED); AJ_CASE(AJ_ERR_ARDP_DISCONNECTING); AJ_CASE(AJ_ERR_ARDP_REMOTE_CONNECTION_RESET); AJ_CASE(AJ_ERR_ARDP_PROBE_TIMEOUT); AJ_CASE(AJ_ERR_ARDP_BACKPRESSURE); AJ_CASE(AJ_ERR_ARDP_SEND_EXPIRED); AJ_CASE(AJ_ERR_ARDP_RECV_EXPIRED); AJ_CASE(AJ_ERR_ARDP_VERSION_NOT_SUPPORTED); AJ_CASE(AJ_ERR_SECURITY_DIGEST_MISMATCH); AJ_CASE(AJ_ERR_SECURITY_INVALID_CERTIFICATE); AJ_CASE(AJ_ERR_SECURITY_DUPLICATE_CERTIFICATE); AJ_CASE(AJ_ERR_SECURITY_POLICY_NOT_NEWER); AJ_CASE(AJ_ERR_SECURITY_CERTIFICATE_NOT_FOUND); AJ_CASE(AJ_ERR_MANAGEMENT_ALREADY_STARTED); AJ_CASE(AJ_ERR_MANAGEMENT_NOT_STARTED); default: return ""; } #endif } ajtcl-16.04/src/aj_disco.c000066400000000000000000001150201271074662300153360ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE DISCO #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgDISCO = 0; #endif typedef struct _NSHeader { uint8_t version; uint8_t qCount; uint8_t aCount; uint8_t ttl; uint8_t flags; uint8_t nameCount; } NSHeader; /* * Message V1 flag definitions */ #define U6_FLAG 0x01 #define R6_FLAG 0x02 #define U4_FLAG 0x04 #define R4_FLAG 0x08 #define C_FLAG 0x10 #define G_FLAG 0x20 #define MSG_TYPE(flags) ((flags) & 0xC0) #define WHO_HAS_MSG 0x80 #define IS_AT_MSG 0x40 #define MSG_VERSION(flags) ((flags) & 0x0F) #define MSG_V0 0x00 #define MSG_V1 0x01 #define NSV_V1 0x10 static AJ_Status ComposeWhoHas(AJ_IOBuffer* txBuf, const char* prefix) { size_t preLen = strlen(prefix); NSHeader* hdr = (NSHeader*)txBuf->writePtr; uint8_t* p = txBuf->writePtr + 6; size_t outLen = (6 + preLen + 2); AJ_InfoPrintf(("ComposeWhoHas(txbuf=0x%p, prefix=\"%s\")\n", txBuf, prefix)); if (outLen > AJ_IO_BUF_SPACE(txBuf)) { AJ_ErrPrintf(("ComposeWhoHas(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } hdr->version = MSG_V1 | NSV_V1; hdr->qCount = 1; hdr->aCount = 0; hdr->ttl = 0; hdr->flags = WHO_HAS_MSG; hdr->nameCount = 1; *p++ = (uint8_t)(preLen + 1); memcpy(p, prefix, preLen); /* * Tack wild-card onto the end of the name to indicate it's prefix */ p[preLen] = '*'; txBuf->writePtr += outLen; return AJ_OK; } static AJ_Status ParseIsAt(AJ_IOBuffer* rxBuf, const char* prefix, AJ_Service* service) { AJ_Status status = AJ_ERR_NO_MATCH; size_t preLen = strlen(prefix); NSHeader* hdr = (NSHeader*)rxBuf->readPtr; uint32_t len = AJ_IO_BUF_AVAIL(rxBuf); uint8_t* p = rxBuf->readPtr + 4; uint8_t* eod = (uint8_t*)hdr + len; AJ_InfoPrintf(("ParseIsAt(rxbuf=0x%p, prefix=\"%s\", service=0x%p)\n", rxBuf, prefix, service)); service->addrTypes = 0; /* * Silently ignore versions we don't know how to parse */ if (MSG_VERSION(hdr->version) != MSG_V1) { return status; } /* * Questions come in first - we currently ignore them */ while (hdr->qCount--) { uint8_t flags = *p++; uint8_t nameCount = *p++; /* * Questions must be WHO_HAS messages */ if (MSG_TYPE(flags) != WHO_HAS_MSG) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } while (nameCount--) { uint8_t sz = *p++; p += sz; if (p > eod) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_END_OF_DATA\n")); status = AJ_ERR_END_OF_DATA; goto Exit; } } } /* * Now the answers - this is what we are looking for */ while (hdr->aCount--) { uint8_t flags = *p++; uint8_t nameCount = *p++; /* * Answers must be IS_AT messages */ if (MSG_TYPE(flags) != IS_AT_MSG) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } /* * Get transport mask */ service->transportMask = (p[0] << 8) | p[1]; p += 2; /* * Decode addresses */ if (flags & R4_FLAG) { memcpy(&service->ipv4, p, sizeof(service->ipv4)); p += sizeof(service->ipv4); service->ipv4port = (p[0] << 8) | p[1]; p += 2; service->addrTypes |= AJ_ADDR_TCP4; } if (flags & U4_FLAG) { memcpy(&service->ipv4Udp, p, sizeof(service->ipv4Udp)); p += sizeof(service->ipv4Udp); service->ipv4portUdp = (p[0] << 8) | p[1]; p += 2; service->addrTypes |= AJ_ADDR_UDP4; } if (flags & R6_FLAG) { memcpy(&service->ipv6, p, sizeof(service->ipv6)); p += sizeof(service->ipv6); service->ipv6port = (p[0] << 8) | p[1]; p += 2; service->addrTypes |= AJ_ADDR_TCP6; } if (flags & U6_FLAG) { memcpy(&service->ipv6Udp, p, sizeof(service->ipv6Udp)); p += sizeof(service->ipv6Udp); service->ipv6portUdp = (p[0] << 8) | p[1]; p += 2; service->addrTypes |= AJ_ADDR_UDP6; } /* * Skip guid if it's present */ if (flags & G_FLAG) { uint8_t sz = *p++; len -= 1 + sz; p += sz; } if (p >= eod) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_END_OF_DATA\n")); return AJ_ERR_END_OF_DATA; } /* * Iterate over the names */ while (nameCount--) { uint8_t sz = *p++; { char sav = p[sz]; p[sz] = 0; AJ_InfoPrintf(("ParseIsAt(): Found \"%s\" IP 0x%x\n", p, service->addrTypes)); p[sz] = sav; } if ((preLen <= sz) && (memcmp(p, prefix, preLen) == 0)) { status = AJ_OK; goto Exit; } p += sz; if (p > eod) { status = AJ_ERR_END_OF_DATA; AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_END_OF_DATA\n")); goto Exit; } } } Exit: return status; } #define MDNS_QR 0x8000 typedef struct _MDNSHeader { uint16_t queryId; uint16_t qrType; uint16_t qdCount; uint16_t anCount; uint16_t m_nsCount; uint16_t arCount; } MDNSHeader; typedef struct _MDNSARData { char ipv4Addr[3 * 4 + 3 + 1]; } MDNSARData; typedef struct _MDNSDomainName { char name[256]; } MDNSDomainName; typedef struct _MDNSSrvRData { uint16_t priority; uint16_t weight; uint16_t port; MDNSDomainName target; } MDNSSrvRData; typedef struct _MDNSTextRData { char BusNodeName[256]; char BusNodeTransport[256]; char BusNodeProtocolVersion[8]; } MDNSTextRData; typedef union _MDNSRData { MDNSARData aRData; MDNSSrvRData srvRData; MDNSTextRData textRData; MDNSDomainName ptrRData; } MDNSRData; typedef enum _RRType { A = 1, //Host IPv4 Address NS = 2, //Authoritative name server MD = 3, //Mail destination MF = 4, //Mail forwarder CNAME = 5, //Canonical name for an alias SOA = 6, //Marks the start zone of an authority MB = 7, //Mailbox domain name MG = 8, //Mail group member MR = 9, //Mail rename domain RNULL = 10, //Null RR WKS = 11, //Well known service description PTR = 12, //Domain name pointer HINFO = 13, //Host information MINFO = 14, //Mailbox info MX = 15, //Mail Exchange TXT = 16, //Text strings AAAA = 28, //Host IPv6 Address SRV = 33, //SRV record OPT = 41, //OPT record NSEC = 47 //NSEC record } RRType; typedef enum _RRClass { INTERNET = 1, //Internet CS = 2, //CSNET class CH = 3, //CHAOS class HS = 4 //Hesoid } RRClass; typedef struct _MDNSResourceRecord { MDNSDomainName rrDomainName; RRType rrType; RRClass rrClass; uint32_t rrTTL; MDNSRData rdata; } MDNSResourceRecord; static AJ_Status ComposeMDnsReq(AJ_IOBuffer* txBuf, const char* prefix, AJ_GUID* guid, uint16_t sidVal) { uint16_t dataLength; int pktLen; static uint8_t hdr[] = { 0x00, 0x00, // transId 0x00, 0x00, // flags 0x00, 0x02, // qCount 0x00, 0x00, // aCount 0x00, 0x00, // nsCount 0x00, 0x02 // arCount }; static uint8_t queries[] = { // Question 1: 0x08, 0x5f, 0x61, 0x6c, 0x6c, 0x6a, 0x6f, 0x79, 0x6e, // _alljoyn 0x04, 0x5f, 0x74, 0x63, 0x70, // _tcp 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // local 0x00, 0x00, 0x0c, // Type 0x80, 0x01, // Class // Question 2: 0x08, 0x5f, 0x61, 0x6c, 0x6c, 0x6a, 0x6f, 0x79, 0x6e, // _alljoyn 0x04, 0x5f, 0x75, 0x64, 0x70, // _udp 0xc0, 0x1a, // local (compressed) 0x00, 0x0c, // Type 0x80, 0x01 // Class }; /* * Additional record: search..local */ static uint8_t search[] = { 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68 // search }; static uint8_t local[] = { 0xc0, 0x1a, // local (compressed) 0x00, 0x10, // Type (TXT) 0x00, 0x01, // Class 0x00, 0x00, 0x00, 0x78 // TTL }; static uint8_t txtvers[] = { 0x09, 0x74, 0x78, 0x74, 0x76, 0x65, 0x72, 0x73, 0x3d, 0x30 // txtvers=0 }; static uint8_t nameone[] = { 0x6e, 0x5f, 0x31, 0x3d // n_1= }; static uint8_t sendmatchonly[] = { // m=1 0x03, 0x6d, 0x3d, 0x31 }; /* * Additional record: sender-info..local */ static uint8_t senderinfo[] = { 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2d, // sender-info 0x69, 0x6e, 0x66, 0x6f, 0xc0, 0x40, // .local (compressed) 0x00, 0x10, // Type (TXT) 0x00, 0x01, // Class 0x00, 0x00, 0x00, 0x78, // TTL 0x00, 0x42, // Data Length=66 0x09, 0x74, 0x78, 0x74, 0x76, 0x65, 0x72, 0x73, // txtvers=0 0x3d, 0x30, 0x07, 0x61, 0x6a, 0x70, 0x76, 0x3d, 0x31, 0x30, // ajpv=10 0x04, 0x70, 0x76, 0x3d, 0x32, // pv=2 // These next three must be re-written by the net transmit layer 0x09, 0x73, 0x69, 0x64, 0x3d, 0x35, 0x35, 0x35, // sid=55555 0x35, 0x35, 0x0a, 0x69, 0x70, 0x76, 0x34, 0x3d, 0x35, 0x35, // ipv4=55555 0x35, 0x35, 0x35, 0x15, 0x75, 0x70, 0x63, 0x76, 0x34, 0x3d, 0x35, // upcv4=555.555.555.555 0x35, 0x35, 0x2e, 0x35, 0x35, 0x35, 0x2e, 0x35, 0x35, 0x35, 0x2e, 0x35, 0x35, 0x35 }; uint8_t* pkt = (uint8_t*)txBuf->writePtr; hdr[0] = (sidVal >> 8) & 0xFF; hdr[1] = sidVal & 0xFF; memcpy(pkt, hdr, sizeof(hdr)); pkt += sizeof(hdr); memcpy(pkt, queries, sizeof(queries)); pkt += sizeof(queries); /* * Append search TXT record with actual GUID and prefix */ memcpy(pkt, search, sizeof(search)); pkt += sizeof(search); *pkt++ = 32; AJ_GUID_ToString(guid, (char*) pkt, 33); pkt += 32; memcpy(pkt, local, sizeof(local)); pkt += sizeof(local); dataLength = sizeof(txtvers) + 1 + sizeof(nameone) + strlen(prefix) + 1 + sizeof(sendmatchonly); *pkt++ = (uint8_t) (dataLength >> 8); *pkt++ = (uint8_t) (dataLength & 0xFF); memcpy(pkt, txtvers, sizeof(txtvers)); pkt += sizeof(txtvers); if ((sizeof(nameone) + strlen(prefix) + 1) > 255) { AJ_ErrPrintf(("ComposeMDnsReq(): prefix too long: %d\n", strlen(prefix))); return AJ_ERR_INVALID; } *pkt++ = sizeof(nameone) + strlen(prefix) + 1; memcpy(pkt, nameone, sizeof(nameone)); pkt += sizeof(nameone); memcpy(pkt, prefix, strlen(prefix)); pkt += strlen(prefix); *pkt++ = '*'; memcpy(pkt, sendmatchonly, sizeof(sendmatchonly)); pkt += sizeof(sendmatchonly); /* * Append sender-info TXT record static fields */ memcpy(pkt, senderinfo, sizeof(senderinfo)); pkt += sizeof(senderinfo); pktLen = pkt - txBuf->writePtr; txBuf->writePtr += pktLen; return AJ_OK; } static size_t ParseMDNSHeader(uint8_t const* buffer, uint32_t bufsize, MDNSHeader* hdr) { size_t size = 0; if (bufsize < 12) { AJ_ErrPrintf(("ParseMDNSHeader(): Insufficient bufsize %d\n", bufsize)); return 0; } // // The first two octets are ID // hdr->queryId = (buffer[0] << 8) | buffer[1]; size += 2; // // The next two octects are the flags // hdr->qrType = (buffer[2] << 8) | buffer[3]; size += 2; // // The next two octets are QDCOUNT // hdr->qdCount = (buffer[4] << 8) | buffer[5]; size += 2; // // The next two octets are ANCOUNT // hdr->anCount = (buffer[6] << 8) | buffer[7]; size += 2; // // The next two octets are NSCOUNT // hdr->m_nsCount = (buffer[8] << 8) | buffer[9]; size += 2; // // The next two octets are ARCOUNT // hdr->arCount = (buffer[10] << 8) | buffer[11]; size += 2; bufsize -= 12; return size; } static size_t ParseMDNSARData(uint8_t const* buffer, uint32_t bufsize, MDNSARData* a) { memset(a->ipv4Addr, 0, 16); if (bufsize < 6) { return 0; } if (buffer[0] != 0 || buffer[1] != 4) { return 0; } memset(a->ipv4Addr, 0, 4); memcpy(a->ipv4Addr, (buffer + 2), 4); return 6; } static size_t ParseMDNSDefaultRData(uint8_t const* buffer, uint32_t bufsize) { // Default data is skipped as it's deemed to be a // resource record type that is not currently used // or reserved for future use. uint16_t rdlen = 0; if (bufsize < 2) { return 0; } rdlen = (buffer[0] << 8 | buffer[1]); bufsize -= 2; if (bufsize < rdlen) { return 0; } return rdlen + 2; } static size_t ParseMDNSDomainName(uint8_t const* buffer, uint32_t bufsize, MDNSDomainName* domainName, const uint8_t* payload, uint32_t paylen) { // The expression for domain names can be a series of labels, // a pointer to a byte offset of previously encountered series // of labels, or a series of labels ending with a pointer to // a previously encountered series of labels. Labels have a // size limit of 63 octets and domain names have a size limit // of 255 octets. We add an extra byte for the trailing null. // A pointer is denoted by an octet where the first two bits // are ones. Since the size of labels are at most 63 octets, // the size of labels begin with two zero bits and can be // easily distinguished from pointers. uint32_t offset = 0; size_t size = 0; uint8_t const* pos = buffer; int32_t len = bufsize; memset(domainName->name, 0, 256); while (len) { if (((*pos & 0xc0) >> 6) == 3 && len > 1) { uint32_t pointer = ((pos[0] << 8 | pos[1]) & 0x3FFF); if (pointer >= paylen) { AJ_ErrPrintf(("ParseMDNSDomainName(): Insufficient bufsize\n")); return 0; } if (payload[pointer] & 0xc0) { AJ_ErrPrintf(("ParseMDNSDomainName(): Invalid compression\n")); return 0; } if (pos >= buffer) { size += 2; } pos = payload + pointer; len = (paylen - pointer); } else { uint8_t label_len = *pos; pos++; len--; if (pos >= buffer) { size++; } if (label_len > len) { AJ_ErrPrintf(("ParseMDNSDomainName(): Insufficient bufsize\n")); return 0; } if (domainName->name[0]) { memcpy((domainName->name + offset), ".", 1); offset++; } if ((label_len > 0) && (offset + label_len) < 256) { memcpy((domainName->name + offset), (pos), label_len); len -= label_len; pos += label_len; if (pos >= buffer) { size += label_len; } offset += label_len; } else { break; } } } return size; } static size_t ParseMDNSTextRData(uint8_t const* buffer, uint32_t bufsize, MDNSTextRData* textRData, uint8_t const* payload, uint32_t paylen, const char* prefix) { // // If there's not enough data in the buffer to even get the string size out // then bail. // uint16_t rdlen = 0; uint8_t const* p = NULL; uint8_t* pos = NULL; uint8_t sz = 0; size_t size = 0; memset(textRData->BusNodeName, 0, 256); memset(textRData->BusNodeTransport, 0, 256); memset(textRData->BusNodeProtocolVersion, 0, 8); if (bufsize < 2) { AJ_ErrPrintf(("ParseMDNSTextRData(): Insufficient bufsize %d", bufsize)); return 0; } rdlen = buffer[0] << 8 | buffer[1]; bufsize -= 2; size = 2 + rdlen; // // If there's not enough data in the buffer then bail. // if (bufsize < rdlen) { AJ_ErrPrintf(("ParseMDNSTextRData(): Insufficient bufsize %d", bufsize)); return 0; } p = &buffer[2]; while (rdlen > 0 && bufsize > 0) { sz = *p++; bufsize--; if (!sz || !bufsize || bufsize < sz) { AJ_ErrPrintf(("ParseMDNSTextRData(): Insufficient bufsize %d", bufsize)); return 0; } // For now we are only interested in three specific // key-value pairs: the bus node transport, bus node // name and the bus node protocol version. pos = (uint8_t*) memchr((char const*)p, '=', sz); if (pos) { uint8_t indx = pos - p; uint8_t valsz = (sz - indx - 1); if (!memcmp(p, "ajpv", 4)) { if (valsz < 8) { memcpy(textRData->BusNodeProtocolVersion, pos + 1, valsz); } } if (!memcmp(p, "t_", 2) && !textRData->BusNodeName[0]) { memcpy(textRData->BusNodeTransport, pos + 1, valsz); } if (!memcmp(p, "n_", 2) && (prefix != NULL) && (valsz >= strlen(prefix)) && !memcmp(pos + 1, prefix, strlen(prefix))) { memcpy(textRData->BusNodeName, pos + 1, valsz); } } p += sz; rdlen -= sz + 1; bufsize -= sz; } if (rdlen != 0) { AJ_ErrPrintf(("ParseMDNSTextRData(): Mismatched RDLength")); return 0; } return size; } static size_t ParseMDNSSrvRData(uint8_t const* buffer, uint32_t bufsize, MDNSSrvRData* srvRData, uint8_t* payload, uint32_t paylen) { uint16_t length = 0; size_t size = 0; size_t ret = 0; uint8_t const* p = NULL; if (bufsize < 2) { AJ_ErrPrintf(("ParseMDNSSrvRData(): Insufficient bufsize %d", bufsize)); return 0; } length = buffer[0] << 8 | buffer[1]; bufsize -= 2; if (bufsize < length || length < 6) { AJ_ErrPrintf(("ParseMDNSSrvRData(): Insufficient bufsize %d or invalid length %d", bufsize, length)); return 0; } srvRData->priority = buffer[2] << 8 | buffer[3]; bufsize -= 2; srvRData->weight = buffer[4] << 8 | buffer[5]; bufsize -= 2; srvRData->port = buffer[6] << 8 | buffer[7]; bufsize -= 2; size = 8; p = &buffer[size]; ret = ParseMDNSDomainName(p, bufsize, &(srvRData->target), payload, paylen); if (ret) { return (size + ret); } else { return 0; } } static size_t ParseMDNSResourceRecord(uint8_t const* buffer, uint32_t bufsize, MDNSResourceRecord* record, uint8_t* payload, uint32_t paylen, const char* prefix) { size_t processed = 0; uint16_t ptr_len = 0; uint8_t const* p = NULL; size_t size = ParseMDNSDomainName(buffer, bufsize, &(record->rrDomainName), payload, paylen); if (size == 0 || bufsize < 8) { AJ_ErrPrintf(("ParseMDNSResourceRecord(): Error occured while deserializing domain name\n")); return 0; } if (size > bufsize || ((size + 8) > bufsize)) { AJ_ErrPrintf(("ParseMDNSResourceRecord(): Insufficient buffer size\n")); return 0; } record->rrType = (RRType)((buffer[size] << 8) | buffer[size + 1]); //Next two octets are CLASS record->rrClass = (RRClass)((buffer[size + 2] << 8) | buffer[size + 3]); //Next four octets are TTL record->rrTTL = (buffer[size + 4] << 24) | (buffer[size + 5] << 16) | (buffer[size + 6] << 8) | buffer[size + 7]; bufsize -= (size + 8); size += 8; p = &buffer[size]; switch (record->rrType) { case A: AJ_InfoPrintf(("ParseMDNSResourceRecord(): Found an A record\n")); processed = ParseMDNSARData(p, bufsize, &(record->rdata.aRData)); break; case PTR: AJ_InfoPrintf(("ParseMDNSResourceRecord(): Found a PTR record\n")); ptr_len = (*p << 8 | *(p + 1)); p += 2; bufsize -= 2; if (ptr_len > bufsize) { return 0; } processed = ParseMDNSDomainName(p, bufsize, &(record->rdata.ptrRData), payload, paylen); if (processed) { processed += 2; } break; case SRV: AJ_InfoPrintf(("ParseMDNSResourceRecord(): Found a SRV record\n")); processed = ParseMDNSSrvRData(p, bufsize, &(record->rdata.srvRData), payload, paylen); break; case TXT: AJ_InfoPrintf(("ParseMDNSResourceRecord(): Found a TXT record\n")); processed = ParseMDNSTextRData(p, bufsize, &(record->rdata.textRData), payload, paylen, prefix); break; case NS: case MD: case MF: case CNAME: case MB: case MG: case MR: case RNULL: case HINFO: case AAAA: default: AJ_InfoPrintf(("ParseMDNSResourceRecord(): Found a non-relevant or unknown record type that will be ignored\n")); processed = ParseMDNSDefaultRData(p, bufsize); break; } if (!processed) { AJ_ErrPrintf(("ParseMDNSResourceRecord(): Error occured while deserializing resource data")); return 0; } size += processed; return size; } static AJ_Status ParseMDNSResp(AJ_IOBuffer* rxBuf, const char* prefix, AJ_Service* service) { uint8_t* buffer = (uint8_t*)rxBuf->readPtr; uint32_t bufsize = AJ_IO_BUF_AVAIL(rxBuf); uint32_t paylen = bufsize; MDNSHeader header; uint8_t* p = NULL; int i = 0; size_t ret = 0; size_t size = 0; uint8_t alljoyn_ptr_record_tcp = 0; uint8_t alljoyn_ptr_record_udp = 0; uint8_t bus_transport = 0; uint8_t bus_protocol = 0; uint8_t bus_a_record = 0; uint16_t service_port_tcp = 0; uint16_t service_port_udp = 0; uint16_t service_priority = 0; uint32_t protocol_version; uint8_t bus_addr[3 * 4 + 3 + 1] = { 0 }; uint8_t service_target[256] = { 0 }; MDNSResourceRecord r; memset(&header, 0, sizeof(MDNSHeader)); size = ParseMDNSHeader(buffer, bufsize, &header); if (size == 0) { AJ_ErrPrintf(("Error occured while deserializing header\n")); return AJ_ERR_NO_MATCH; } else { AJ_InfoPrintf(("Successfully parsed header with %d answers and %d additional\n", header.anCount, header.arCount)); } if ((header.qrType & MDNS_QR) == 0) { return AJ_ERR_NO_MATCH; } if (!header.anCount || !header.arCount) { return AJ_ERR_NO_MATCH; } if (size >= bufsize) { return AJ_ERR_NO_MATCH; } bufsize -= size; p = &buffer[size]; for (i = 0; i < header.qdCount; i++) { memset(&r, 0, sizeof(MDNSResourceRecord)); ret = ParseMDNSResourceRecord(p, bufsize, &r, buffer, paylen, NULL); if (ret == 0 || ret > bufsize) { AJ_ErrPrintf(("Error while deserializing question record.\n")); return AJ_ERR_NO_MATCH; } size += ret; bufsize -= ret; p += ret; AJ_InfoPrintf(("Skipping unexpected question in response, will be silently ignored.\n")); } for (i = 0; i < header.anCount; i++) { memset(&r, 0, sizeof(MDNSResourceRecord)); ret = ParseMDNSResourceRecord(p, bufsize, &r, buffer, paylen, NULL); if (ret == 0 || ret > bufsize) { AJ_ErrPrintf(("Error while deserializing answer record.\n")); return AJ_ERR_NO_MATCH; } size += ret; bufsize -= ret; p += ret; AJ_InfoPrintf(("Processed answer %d\n", (i + 1))); if (r.rrType == PTR && !memcmp(r.rrDomainName.name, "_alljoyn._tcp.local", 19)) { AJ_InfoPrintf(("Found _alljoyn_.tcp.local PTR record.\n")); alljoyn_ptr_record_tcp = 1; } if (r.rrType == PTR && !memcmp(r.rrDomainName.name, "_alljoyn._udp.local", 19)) { AJ_InfoPrintf(("Found _alljoyn_._udp.local PTR record.\n")); alljoyn_ptr_record_udp = 1; } // We ignore the sender's "guid." (32 chars + 1 char for the dot) in the ._alljoyn._tcp.local domain name. if (r.rrType == SRV && !memcmp(r.rrDomainName.name + 33, "_alljoyn._tcp.local", 19)) { AJ_InfoPrintf(("Found a SRV answer with domain name %s.\n", r.rdata.srvRData.target.name)); memset(service_target, 0, 256); memcpy(service_target, r.rdata.srvRData.target.name, 256); service_port_tcp = r.rdata.srvRData.port; service_priority = r.rdata.srvRData.priority; } // We ignore the sender's "guid." (32 chars + 1 char for the dot) in the ._alljoyn._udp.local domain name. if (r.rrType == SRV && !memcmp(r.rrDomainName.name + 33, "_alljoyn._udp.local", 19)) { AJ_InfoPrintf(("Found a SRV answer with domain name %s.\n", r.rdata.srvRData.target.name)); memset(service_target, 0, 256); memcpy(service_target, r.rdata.srvRData.target.name, 256); service_port_udp = r.rdata.srvRData.port; service_priority = r.rdata.srvRData.priority; } } // PTR record must be parsed and service port should be non-zero // to continue with the parsing. Zero is an invalid service port. if ((!alljoyn_ptr_record_tcp && !alljoyn_ptr_record_udp) || (!service_port_tcp && !service_port_udp)) { return AJ_ERR_NO_MATCH; } for (i = 0; i < header.m_nsCount; i++) { memset(&r, 0, sizeof(MDNSResourceRecord)); ret = ParseMDNSResourceRecord(p, bufsize, &r, buffer, paylen, NULL); if (ret == 0 || ret > bufsize) { AJ_ErrPrintf(("Error while deserializing authority record.\n")); return AJ_ERR_NO_MATCH; } size += ret; bufsize -= ret; p += ret; AJ_InfoPrintf(("Skipping non-relevant authority record, will be silently ignored.\n")); } for (i = 0; i < header.arCount; i++) { memset(&r, 0, sizeof(MDNSResourceRecord)); ret = ParseMDNSResourceRecord(p, bufsize, &r, buffer, paylen, prefix); if (ret == 0 || ret > bufsize) { AJ_ErrPrintf(("Error while deserializing additional record.\n")); return AJ_ERR_NO_MATCH; } size += ret; bufsize -= ret; p += ret; AJ_InfoPrintf(("Processing additional record %d\n", (i + 1))); if (r.rrType == TXT) { // Ensure the advertise TXT record refers to the same guid in the SRV record. if (!memcmp(r.rrDomainName.name, "advertise.", 10) && !memcmp(r.rrDomainName.name + 10, service_target, 38)) { AJ_InfoPrintf(("Found advertise.* TXT record with full label %s.\n", r.rrDomainName.name)); // Ensure the sender-info TXT record included a transport and had the requested name prefix if (r.rdata.textRData.BusNodeTransport[0] && r.rdata.textRData.BusNodeName[0]) { bus_transport = 1; } } // Ensure the sender-info TXT record refers to the same guid in the SRV record. if (!memcmp(r.rrDomainName.name, "sender-info.", 12) && !memcmp(r.rrDomainName.name + 12, service_target, 38)) { AJ_InfoPrintf(("Found sender-info.* TXT record with full name: %s.\n", r.rrDomainName.name)); // If the sender-info TXT record included the protocol version protocol_version = 0; if (r.rdata.textRData.BusNodeProtocolVersion[0]) { // Ensure that it greater than or equal to the minimum allowed protocol_version = atoi(r.rdata.textRData.BusNodeProtocolVersion); if (protocol_version >= AJ_GetMinProtoVersion()) { bus_protocol = 1; } } else { // Only protocol version 10 does not send the protocol version // Ensure this is greater than or equal to the minimum allowed if (10 >= AJ_GetMinProtoVersion()) { protocol_version = 10; bus_protocol = 1; } } } } // Ensure the A record refers to the same guid in the SRV record. if (r.rrType == A && !memcmp(r.rrDomainName.name, service_target, 38)) { AJ_InfoPrintf(("Found an A additional record.\n")); memset(bus_addr, 0, (3 * 4 + 3 + 1)); memcpy(bus_addr, r.rdata.aRData.ipv4Addr, (3 * 4 + 3 + 1)); bus_a_record = 1; } } // To report a match, we must have successfully parsed an _alljoyn._tcp.local OR _alljoyn._udp.local // PRT record, SRV record, advertise TXT record and A record for the same // guid. Note that other records might have been ignored to ensure forward // compatibility with other record types that may be in use in the future. if ((alljoyn_ptr_record_tcp || alljoyn_ptr_record_udp) && (service_port_tcp || service_port_udp) && bus_transport && bus_protocol && bus_a_record) { // ignore this record if it's TCP-only but we want ARDP-only, or vice-versa AJ_Status status = AJ_ERR_NO_MATCH; // Check for a TCP response, but only if we're looking for TCP responses #ifdef AJ_TCP if (alljoyn_ptr_record_tcp && service_port_tcp) { service->ipv4port = service_port_tcp; memcpy(&service->ipv4, bus_addr, sizeof(service->ipv4)); service->addrTypes |= AJ_ADDR_TCP4; service->pv = protocol_version; service->priority = service_priority; status = AJ_OK; } #endif // similarly, check ARDP only if we care about it. #ifdef AJ_ARDP if (alljoyn_ptr_record_udp && service_port_udp) { service->ipv4portUdp = service_port_udp; memcpy(&service->ipv4Udp, bus_addr, sizeof(service->ipv4Udp)); service->addrTypes |= AJ_ADDR_UDP4; service->pv = protocol_version; service->priority = service_priority; status = AJ_OK; } #endif return status; } else { return AJ_ERR_NO_MATCH; } } #define AJ_BURST_INTERVAL 100 #define AJ_BURST_COUNT 3 #define AJ_INITIAL_INTERVAL 1000 static uint32_t searchId = 0; AJ_Status AJ_Discover(const char* prefix, AJ_Service* service, uint32_t timeout, uint32_t selectionTimeout) { AJ_Status status; uint32_t burstCount; uint32_t interval = AJ_INITIAL_INTERVAL; uint32_t queries = 0; int32_t discover = (int32_t) timeout; int32_t selection = (int32_t) selectionTimeout; int32_t listenInt; AJ_Time discoverTimer; AJ_Time listenTimer; AJ_Time selectionTimer; AJ_MCastSocket sock; AJ_GUID guid; if (selectionTimeout > timeout) { selectionTimeout = timeout; selection = (int32_t) selectionTimeout; } AJ_InfoPrintf(("AJ_Discover(prefix=\"%s\", service=0x%p, timeout=%d, selection timeout=%d.)\n", prefix, service, timeout, selectionTimeout)); /* * Enable multicast I/O for the discovery packets. */ status = AJ_Net_MCastUp(&sock); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Discover(): status=%s\n", AJ_StatusText(status))); return status; } /* * Perform discovery until node discovered or overall discover timeout reached */ burstCount = 0; AJ_InitTimer(&selectionTimer); AJ_InfoPrintf(("Selection timer started\n")); AJ_InitTimer(&discoverTimer); while (discover > 0) { burstCount++; /* * Only send WHO-HAS if configured to consider pre-14.06 routers. */ if (AJ_GetMinProtoVersion() < 10) { AJ_IO_BUF_RESET(&sock.tx); AJ_InfoPrintf(("AJ_Discover(): WHO-HAS \"%s\"\n", prefix)); status = ComposeWhoHas(&sock.tx, prefix); if (status == AJ_OK) { sock.tx.flags |= AJ_IO_BUF_AJ; status = sock.tx.send(&sock.tx); AJ_InfoPrintf(("AJ_Discover(): WHO-HAS send status=%s\n", AJ_StatusText(status))); /* * If the send failed the socket has probably gone away. */ if (status != AJ_OK) { goto _Exit; } } else { /* * If compose failed just continue on */ status = AJ_OK; } } status = AJ_GetLocalGUID(&guid); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_Discover(): No GUID!\n")); goto _Exit; } AJ_IO_BUF_RESET(&sock.tx); AJ_InfoPrintf(("AJ_Discover(): mDNS \"%s\"\n", prefix)); status = ComposeMDnsReq(&sock.tx, prefix, &guid, searchId); if (status == AJ_OK) { sock.tx.flags |= AJ_IO_BUF_MDNS; status = sock.tx.send(&sock.tx); AJ_InfoPrintf(("AJ_Discover(): mDNS send status=%s\n", AJ_StatusText(status))); if (status != AJ_OK) { goto _Exit; } } else { status = AJ_OK; } /* * Calculate listen interval */ if (burstCount >= AJ_BURST_COUNT) { burstCount = 0; searchId++; queries++; if (queries == 10) { interval = 10000; } else if (queries == 11) { interval = 20000; } else if (queries >= 12) { interval = 40000; } listenInt = interval + AJ_BURST_INTERVAL; } else { listenInt = AJ_BURST_INTERVAL; } /* * If selection period has not passed do not listen longer than the selection timeout */ if ((selection > 0) && (listenInt > selection)) { listenInt = selection; } /* * Do not listen longer than the overall discover timeout */ if (listenInt > discover) { listenInt = discover; } /* * recv for the listen period */ AJ_InitTimer(&listenTimer); while (listenInt > 0) { AJ_IO_BUF_RESET(&sock.rx); status = sock.rx.recv(&sock.rx, AJ_IO_BUF_SPACE(&sock.rx), listenInt); if (status != AJ_OK) { /* * Anything other than AJ_ERR_TIMEOUT means bail */ if (status != AJ_ERR_TIMEOUT) { goto _Exit; } } else { if (sock.rx.flags & AJ_IO_BUF_MDNS) { memset(service, 0, sizeof(AJ_Service)); status = ParseMDNSResp(&sock.rx, prefix, service); if (status == AJ_OK) { AJ_InfoPrintf(("AJ_Discover(): mDNS discovered \"%s\"\n", prefix)); // skip blacklisted addresses! if (!AJ_IsRoutingNodeBlacklisted(service)) { AJ_AddRoutingNodeToResponseList(service); } else { AJ_InfoPrintf(("AJ_Discover(): Skipping blacklisted Routing Node\n")); } } } if (sock.rx.flags & AJ_IO_BUF_AJ) { memset(service, 0, sizeof(AJ_Service)); status = ParseIsAt(&sock.rx, prefix, service); if (status == AJ_OK) { AJ_InfoPrintf(("AJ_Discover(): IS-AT discovered \"%s\"\n", prefix)); // skip blacklisted addresses! if (!AJ_IsRoutingNodeBlacklisted(service)) { AJ_AddRoutingNodeToResponseList(service); } else { AJ_InfoPrintf(("AJ_Discover(): Skipping blacklisted Routing Node\n")); } } } } listenInt -= AJ_GetElapsedTime(&listenTimer, FALSE); } selection -= AJ_GetElapsedTime(&selectionTimer, FALSE); if (selection < 0 && AJ_GetRoutingNodeResponseListSize() > 0) { break; } discover -= AJ_GetElapsedTime(&discoverTimer, FALSE); } _Exit: memset(service, 0, sizeof(AJ_Service)); status = AJ_SelectRoutingNodeFromResponseList(service); /* * All done with multicast for now */ AJ_Net_MCastDown(&sock); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Discover(): Stop discovery of \"%s\"\n", prefix)); } return status; } ajtcl-16.04/src/aj_guid.c000066400000000000000000000320021271074662300151630ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE GUID #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgGUID = 0; #endif typedef struct _NameToGUID { uint8_t keyRole; char uniqueName[AJ_MAX_NAME_SIZE + 1]; const char* serviceName; AJ_GUID guid; uint8_t sessionKey[AJ_SESSION_KEY_LEN]; uint8_t groupKey[AJ_SESSION_KEY_LEN]; uint32_t replySerial; uint32_t authVersion; AJ_SerialNum incoming; } NameToGUID; static uint8_t localGroupKey[AJ_SESSION_KEY_LEN]; static NameToGUID nameMap[AJ_NAME_MAP_GUID_SIZE]; static AJ_Status SetNameOwnerChangedRule(AJ_BusAttachment* bus, const char* oldOwner, uint8_t rule, uint32_t* serialNum); static AJ_Status NameHasOwner(AJ_Message* msg, const char* name, uint32_t* serialNum); AJ_Status AJ_GUID_ToString(const AJ_GUID* guid, char* buffer, uint32_t bufLen) { return AJ_RawToHex(guid->val, AJ_GUID_LEN, buffer, bufLen, TRUE); } AJ_Status AJ_GUID_FromString(AJ_GUID* guid, const char* str) { return AJ_HexToRaw(str, 2 * AJ_GUID_LEN, guid->val, AJ_GUID_LEN); } static NameToGUID* LookupName(const char* name) { uint32_t i; AJ_InfoPrintf(("LookupName(name=\"%s\")\n", name)); for (i = 0; i < AJ_NAME_MAP_GUID_SIZE; ++i) { if (strcmp(nameMap[i].uniqueName, name) == 0) { return &nameMap[i]; } if (nameMap[i].serviceName && (strcmp(nameMap[i].serviceName, name)) == 0) { return &nameMap[i]; } } AJ_InfoPrintf(("LookupName(): NULL\n")); return NULL; } static NameToGUID* LookupReplySerial(uint32_t replySerial) { uint32_t i; for (i = 0; i < AJ_NAME_MAP_GUID_SIZE; ++i) { if (nameMap[i].replySerial == replySerial) { return &nameMap[i]; } } return NULL; } AJ_Status AJ_GUID_AddNameMapping(AJ_BusAttachment* bus, const AJ_GUID* guid, const char* uniqueName, const char* serviceName) { AJ_Status status; size_t len = strlen(uniqueName); NameToGUID* mapping; int isNew; uint32_t serialNum; AJ_InfoPrintf(("AJ_GUID_AddNameMapping(guid=0x%p, uniqueName=\"%s\", serviceName=\"%s\")\n", guid, uniqueName, serviceName)); mapping = LookupName(uniqueName); isNew = !mapping; if (isNew) { mapping = LookupName(""); } if (mapping && (len <= AJ_MAX_NAME_SIZE)) { if (isNew && (AJ_GetRoutingProtoVersion() >= 11)) { status = SetNameOwnerChangedRule(bus, uniqueName, AJ_BUS_SIGNAL_ALLOW, &serialNum); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_GUID_AddNameMapping(guid=0x%p, uniqueName=\"%s\", serviceName=\"%s\"): Add match rule error\n", guid, uniqueName, serviceName)); return status; } mapping->replySerial = serialNum; } memcpy(&mapping->guid, guid, sizeof(AJ_GUID)); memcpy(&mapping->uniqueName, uniqueName, len + 1); mapping->serviceName = serviceName; mapping->incoming.serial = 0; mapping->incoming.offset = 0; return AJ_OK; } else { AJ_ErrPrintf(("AJ_GUID_AddNameMapping(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } } void AJ_GUID_DeleteNameMapping(AJ_BusAttachment* bus, const char* uniqueName) { AJ_Status status; NameToGUID* mapping; AJ_InfoPrintf(("AJ_GUID_DeleteNameMapping(uniqueName=\"%s\")\n", uniqueName)); mapping = LookupName(uniqueName); if (mapping) { if (AJ_GetRoutingProtoVersion() >= 11) { status = SetNameOwnerChangedRule(bus, uniqueName, AJ_BUS_SIGNAL_DENY, NULL); if (status != AJ_OK) { AJ_WarnPrintf(("AJ_GUID_DeleteNameMapping(uniqueName=\"%s\"): Remove match rule error\n", uniqueName)); } } memset(mapping, 0, sizeof(NameToGUID)); } } const AJ_GUID* AJ_GUID_Find(const char* name) { NameToGUID* mapping = LookupName(name); AJ_InfoPrintf(("AJ_GUID_Find(name=\"%s\")\n", name)); return mapping ? &mapping->guid : NULL; } void AJ_GUID_ClearNameMap(void) { AJ_InfoPrintf(("AJ_GUID_ClearNameMap()\n")); memset(nameMap, 0, sizeof(nameMap)); } AJ_Status AJ_SetGroupKey(const char* uniqueName, const uint8_t* key) { NameToGUID* mapping; AJ_InfoPrintf(("AJ_SetGroupKey(uniqueName=\"%s\", key=0x%p)\n", uniqueName, key)); mapping = LookupName(uniqueName); if (mapping) { memcpy(mapping->groupKey, key, AJ_SESSION_KEY_LEN); return AJ_OK; } else { AJ_WarnPrintf(("AJ_SetGroupKey(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } } AJ_Status AJ_SetSessionKey(const char* uniqueName, const uint8_t* key, uint8_t role, uint32_t authVersion) { NameToGUID* mapping; AJ_InfoPrintf(("AJ_SetGroupKey(uniqueName=\"%s\", key=0x%p)\n", uniqueName, key)); mapping = LookupName(uniqueName); if (mapping) { mapping->keyRole = role; mapping->authVersion = authVersion; memcpy(mapping->sessionKey, key, AJ_SESSION_KEY_LEN); return AJ_OK; } else { AJ_WarnPrintf(("AJ_SetSessionKey(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } } AJ_Status AJ_GetSessionKey(const char* name, uint8_t* key, uint8_t* role, uint32_t* authVersion) { NameToGUID* mapping; AJ_InfoPrintf(("AJ_GetSessionKey(name=\"%s\", key=0x%p, role=0x%p)\n", name, key, role)); mapping = LookupName(name); if (mapping) { *role = mapping->keyRole; *authVersion = mapping->authVersion; memcpy(key, mapping->sessionKey, AJ_SESSION_KEY_LEN); return AJ_OK; } else { AJ_WarnPrintf(("AJ_GetSessionKey(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } } AJ_Status AJ_GetPeerIndex(const char* name, uint32_t* peer) { NameToGUID* mapping; AJ_InfoPrintf(("AJ_GetPeerIndex(name=\"%s\", peer=%p)\n", name, peer)); mapping = LookupName(name); if (mapping) { *peer = (mapping - nameMap); AJ_ASSERT(*peer < AJ_NAME_MAP_GUID_SIZE); return AJ_OK; } else { AJ_WarnPrintf(("AJ_GetPeerIndex(name=\"%s\"): AJ_ERR_NO_MATCH\n", name)); return AJ_ERR_NO_MATCH; } } AJ_Status AJ_GetSerialNumbers(const char* name, AJ_SerialNum** incoming) { NameToGUID* mapping; AJ_InfoPrintf(("AJ_GetSerialNumbers(name=\"%s\", incoming=%p)\n", name, incoming)); mapping = LookupName(name); if (mapping) { if (incoming) { *incoming = &mapping->incoming; } return AJ_OK; } else { AJ_WarnPrintf(("AJ_GetSerialNumbers(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } } AJ_Status AJ_GetRemoteUniqueName(const char* name, const char** unique) { NameToGUID* mapping; AJ_InfoPrintf(("AJ_GetRemoteUniqueName(name=\"%s\", unique=%p)\n", name, unique)); mapping = LookupName(name); if (mapping) { *unique = mapping->uniqueName; return AJ_OK; } else { return AJ_ERR_NO_MATCH; } } AJ_Status AJ_GetGroupKey(const char* name, uint8_t* key) { AJ_InfoPrintf(("AJ_GetGroupKey(name=\"%s\", key=0x%p)\n", name, key)); if (name) { NameToGUID* mapping = LookupName(name); if (!mapping) { AJ_WarnPrintf(("AJ_GetGroupKey(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } memcpy(key, mapping->groupKey, AJ_SESSION_KEY_LEN); } else { /* * Check if the group key needs to be initialized */ memset(key, 0, AJ_SESSION_KEY_LEN); if (memcmp(localGroupKey, key, AJ_SESSION_KEY_LEN) == 0) { AJ_RandBytes(localGroupKey, AJ_SESSION_KEY_LEN); } memcpy(key, localGroupKey, AJ_SESSION_KEY_LEN); } return AJ_OK; } static AJ_Status SetNameOwnerChangedRule(AJ_BusAttachment* bus, const char* oldOwner, uint8_t rule, uint32_t* serialNum) { AJ_Status status; size_t ruleLen; char* ruleStr; const char* rulePrefix = "type='signal',member='NameOwnerChanged',interface='org.freedesktop.DBus',arg1='"; const char* ruleSuffix = "',arg2=''"; ruleLen = strlen(rulePrefix) + strlen(oldOwner) + strlen(ruleSuffix); ruleStr = (char*) AJ_Malloc(ruleLen + 1 /* \0 */); if (ruleStr == NULL) { return AJ_ERR_RESOURCES; } strcpy(ruleStr, rulePrefix); strcat(ruleStr, oldOwner); strcat(ruleStr, ruleSuffix); status = AJ_BusSetSignalRuleSerial(bus, ruleStr, rule, 0, serialNum); AJ_Free(ruleStr); return status; } AJ_Status AJ_GUID_HandleAddMatchReply(AJ_Message* msg) { AJ_Status status; NameToGUID* mapping; uint32_t serialNum = 0; AJ_InfoPrintf(("AJ_GUID_HandleAddMatchReply(msg=0x%p)\n", msg)); mapping = LookupReplySerial(msg->replySerial); if (!mapping) { return AJ_OK; } mapping->replySerial = 0; if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_GUID_HandleAddMatchReply(msg=0x%p): error=%s.\n", msg, msg->error)); AJ_GUID_DeleteNameMapping(msg->bus, mapping->uniqueName); return AJ_ERR_FAILURE; } /* * Add match complete. */ AJ_InfoPrintf(("Add match Complete\n")); status = NameHasOwner(msg, mapping->uniqueName, &serialNum); if (status == AJ_OK) { mapping->replySerial = serialNum; } else { AJ_GUID_DeleteNameMapping(msg->bus, mapping->uniqueName); } return status; } static AJ_Status NameHasOwner(AJ_Message* msg, const char* name, uint32_t* serialNum) { AJ_Status status; AJ_Message call; AJ_InfoPrintf(("NameHasOwner(msg=0x%p)\n", msg)); /* * Ask if name has an owner */ status = AJ_MarshalMethodCall(msg->bus, &call, AJ_METHOD_NAME_HAS_OWNER, AJ_DBusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { *serialNum = call.hdr->serialNum; status = AJ_MarshalArgs(&call, "s", name); } if (status != AJ_OK) { AJ_ErrPrintf(("NameHasOwner(msg=0x%p): Marshal error\n", msg)); return status; } return AJ_DeliverMsg(&call); } AJ_Status AJ_GUID_HandleNameHasOwnerReply(AJ_Message* msg) { AJ_Status status; NameToGUID* mapping; uint32_t hasOwner; AJ_InfoPrintf(("AJ_GUID_HandleNameHasOwnerReply(msg=0x%p)\n", msg)); mapping = LookupReplySerial(msg->replySerial); if (!mapping) { return AJ_OK; } mapping->replySerial = 0; if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_GUID_HandleNameHasOwnerReply(msg=0x%p): error=%s.\n", msg, msg->error)); status = AJ_ERR_FAILURE; AJ_GUID_DeleteNameMapping(msg->bus, mapping->uniqueName); return status; } status = AJ_UnmarshalArgs(msg, "b", &hasOwner); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_GUID_HandleNameHasOwnerReply(msg=0x%p): Unmarshal error\n", msg)); AJ_GUID_DeleteNameMapping(msg->bus, mapping->uniqueName); return status; } /* * Name has owner complete. */ AJ_InfoPrintf(("Name %s has owner %d\n", mapping->uniqueName, hasOwner)); if (!hasOwner) { AJ_GUID_DeleteNameMapping(msg->bus, mapping->uniqueName); } return status; } AJ_Status AJ_GUID_HandleNameOwnerChanged(AJ_Message* msg) { AJ_Status status; char* name; char* oldOwner; char* newOwner; status = AJ_UnmarshalArgs(msg, "sss", &name, &oldOwner, &newOwner); AJ_InfoPrintf(("AJ_GUID_HandleNameOwnerChanged(name=%s,oldOwner=%s,newOwner=%s)\n", name, oldOwner, newOwner)); if ((status == AJ_OK) && newOwner && oldOwner && newOwner[0] == '\0') { AJ_GUID_DeleteNameMapping(msg->bus, oldOwner); } return status; } AJ_Status AJ_GUID_HandleRemoveMatchReply(AJ_Message* msg) { if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_GUID_HandleRemoveMatchReply(msg=0x%p): error=%s.\n", msg, msg->error)); return AJ_ERR_FAILURE; } return AJ_OK; } ajtcl-16.04/src/aj_helper.c000066400000000000000000000636631271074662300155330ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE HELPER #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgHELPER = 0; #endif /** * Type to describe pending timers */ typedef struct { TimeoutHandler handler; /**< The callback handler */ void* context; /**< A context pointer passed in by the user */ uint32_t abs_time; /**< The absolute time when this timer will fire */ uint32_t repeat; /**< The amount of time between timer events */ } Timer; static Timer Timers[AJ_MAX_TIMERS] = { { NULL } }; static uint32_t RunExpiredTimers(uint32_t now) { uint32_t i = 0; uint32_t next = (uint32_t) -1; for (; i < AJ_MAX_TIMERS; ++i) { Timer* timer = Timers + i; if (timer->handler != NULL && timer->abs_time <= now) { (timer->handler)(timer->context); if (timer->repeat) { timer->abs_time += timer->repeat; } else { memset(timer, 0, sizeof(Timer)); } } // track the next time we need to run if (timer->handler != NULL && next > timer->abs_time) { next = timer->abs_time; } } // return the next timeout that will run return next; } uint32_t AJ_SetTimer(uint32_t relative_time, TimeoutHandler handler, void* context, uint32_t repeat) { uint32_t i; for (i = 0; i < AJ_MAX_TIMERS; ++i) { Timer* timer = Timers + i; // need to find an available timer slot if (timer->handler == NULL) { AJ_Time start = { 0, 0 }; uint32_t now = AJ_GetElapsedTime(&start, FALSE); timer->handler = handler; timer->context = context; timer->repeat = repeat; timer->abs_time = now + relative_time; return i + 1; } } // available slot not found! AJ_ErrPrintf(("AJ_SetTimer(): Slot not found\n")); return 0; } void AJ_CancelTimer(uint32_t id) { Timer* timer = Timers + (id - 1); AJ_ASSERT(id > 0 && id <= AJ_MAX_TIMERS); memset(timer, 0, sizeof(Timer)); } AJ_Status AJ_RunAllJoynService(AJ_BusAttachment* bus, AllJoynConfiguration* config) { uint8_t connected = FALSE; AJ_Status status = AJ_OK; AJ_InfoPrintf(("AJ_RunAllJoynService(bus=0x%p, config=0x%p)\n", bus, config)); while (TRUE) { AJ_Time start = { 0, 0 }; AJ_Message msg; uint32_t now; // get the next timeout uint32_t next; // wait forever uint32_t timeout = (uint32_t) -1; if (!connected) { status = AJ_StartService( bus, config->daemonName, config->connect_timeout, config->connected, config->session_port, config->service_name, config->flags, config->opts); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_RunAllJoynService(): status=%s.\n", AJ_StatusText(status))); continue; } AJ_InfoPrintf(("AJ_RunAllJoynService(): connected to daemon: \"%s\"\n", AJ_GetUniqueName(bus))); connected = TRUE; /* Register a callback for providing bus authentication password */ AJ_BusSetPasswordCallback(bus, config->password_callback); /* Register a callback for handling factory reset requests */ AJ_BusSetFactoryResetCallback(bus, config->factory_reset_callback); /* Register a callback for handling policy change notifications */ AJ_BusSetPolicyChangedCallback(bus, config->policy_changed_callback); /* Configure timeout for the link to the daemon bus */ AJ_SetBusLinkTimeout(bus, config->link_timeout); if (config->connection_handler != NULL) { (config->connection_handler)(connected); } } // absolute time in milliseconds now = AJ_GetElapsedTime(&start, FALSE); next = RunExpiredTimers(now); if (next != (uint32_t) -1) { // if no timers running, wait forever timeout = next; } status = AJ_UnmarshalMsg(bus, &msg, min(500, timeout)); if (AJ_ERR_TIMEOUT == status && AJ_ERR_LINK_TIMEOUT == AJ_BusLinkStateProc(bus)) { AJ_ErrPrintf(("AJ_RunAllJoynService(): AJ_ERR_READ\n")); status = AJ_ERR_READ; } if (status == AJ_ERR_TIMEOUT) { // go back around and handle the expired timers continue; } if (status == AJ_OK) { uint8_t handled = FALSE; const MessageHandlerEntry* message_entry = config->message_handlers; const PropHandlerEntry* prop_entry = config->prop_handlers; // check the user's handlers first. ANY message that AllJoyn can handle is override-able. while (handled != TRUE && message_entry->msgid != 0) { if (message_entry->msgid == msg.msgId) { if (msg.hdr->msgType == AJ_MSG_METHOD_CALL) { // build a method reply AJ_Message reply; status = AJ_MarshalReplyMsg(&msg, &reply); if (status == AJ_OK) { status = (message_entry->handler)(&msg, &reply); } if (status == AJ_OK) { status = AJ_DeliverMsg(&reply); } } else { // call the handler! status = (message_entry->handler)(&msg, NULL); } handled = TRUE; } ++message_entry; } // we need to check whether this is a property getter or setter. // these are stored in an array because multiple getters and setters can exist if running more than one bus object while (handled != TRUE && prop_entry->msgid != 0) { if (prop_entry->msgid == msg.msgId) { // extract the method from the ID; GetProperty or SetProperty uint32_t method = prop_entry->msgid & 0x000000FF; if (method == AJ_PROP_GET) { status = AJ_BusPropGet(&msg, prop_entry->callback, prop_entry->context); } else if (method == AJ_PROP_SET) { status = AJ_BusPropSet(&msg, prop_entry->callback, prop_entry->context); } else { // this should never happen!!! AJ_ASSERT(!"Invalid property method"); } handled = TRUE; } ++prop_entry; } // handler not found! if (handled == FALSE) { if (msg.msgId == AJ_METHOD_ACCEPT_SESSION) { uint8_t accepted = (config->acceptor)(&msg); status = AJ_BusReplyAcceptSession(&msg, accepted); } else { AJ_InfoPrintf(("AJ_RunAllJoynService(): AJ_BusHandleBusMessage()\n")); status = AJ_BusHandleBusMessage(&msg); } } // Any received packets indicates the link is active, so call to reinforce the bus link state AJ_NotifyLinkActive(); } /* * Unarshaled messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_InfoPrintf(("AJ_RunAllJoynService(): AJ_Disconnect(): daemon \"%s\"\n", AJ_GetUniqueName(bus))); AJ_Disconnect(bus); connected = FALSE; if (config->connection_handler != NULL) { (config->connection_handler)(connected); } /* * Sleep a little while before trying to reconnect */ AJ_InfoPrintf(("AJ_RunAllJoynService(): AJ_Sleep()\n")); AJ_Sleep(10 * 1000); } } // this will never actually return! return AJ_OK; } AJ_Status AJ_StartService(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, uint16_t port, const char* name, uint32_t flags, const AJ_SessionOpts* opts ) { AJ_Status status; AJ_Time timer; uint8_t serviceStarted = FALSE; uint32_t disposition; uint16_t retport; AJ_InfoPrintf(("AJ_StartService(bus=0x%p, daemonName=\"%s\", timeout=%d., connected=%d., port=%d., name=\"%s\", flags=0x%x, opts=0x%p)\n", bus, daemonName, timeout, connected, port, name, flags, opts)); AJ_InitTimer(&timer); while (TRUE) { if (AJ_GetElapsedTime(&timer, TRUE) > timeout) { return AJ_ERR_TIMEOUT; } if (!connected) { AJ_InfoPrintf(("AJ_StartService(): AJ_FindBusAndConnect()\n")); status = AJ_FindBusAndConnect(bus, daemonName, AJ_CONNECT_TIMEOUT); if (status != AJ_OK) { AJ_WarnPrintf(("AJ_StartService(): connect failed: sleeping for %d seconds\n", AJ_CONNECT_PAUSE / 1000)); AJ_Sleep(AJ_CONNECT_PAUSE); continue; } AJ_InfoPrintf(("AJ_StartService(): connected to bus\n")); } /* * Kick things off by binding a session port */ AJ_InfoPrintf(("AJ_StartService(): AJ_BindSessionPort()\n")); status = AJ_BusBindSessionPort(bus, port, opts, 0); if (status == AJ_OK) { break; } AJ_ErrPrintf(("AJ_StartService(): AJ_Disconnect(): status=%s.\n", AJ_StatusText(status))); AJ_Disconnect(bus); } while (!serviceStarted && (status == AJ_OK)) { AJ_Message msg; status = AJ_UnmarshalMsg(bus, &msg, AJ_UNMARSHAL_TIMEOUT); if (status == AJ_ERR_NO_MATCH) { // Ignore unknown messages status = AJ_OK; continue; } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_StartService(): status=%s.\n", AJ_StatusText(status))); break; } switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_BIND_SESSION_PORT): if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_StartService(): AJ_METHOD_BIND_SESSION_PORT: %s\n", msg.error)); status = AJ_ERR_FAILURE; break; } status = AJ_UnmarshalArgs(&msg, "uq", &disposition, &retport); if (AJ_OK != status) { break; } if (retport == port) { if (AJ_BINDSESSIONPORT_REPLY_SUCCESS == disposition) { AJ_InfoPrintf(("AJ_StartService(): AJ_BusRequestName()\n")); status = AJ_BusRequestName(bus, name, flags); } else { status = AJ_ERR_FAILURE; AJ_InfoPrintf(("AJ_StartService(bus=%p): AJ_METHOD_BIND_SESSION_PORT: disposition %d\n", bus, disposition)); break; } } break; case AJ_REPLY_ID(AJ_METHOD_REQUEST_NAME): if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_StartService(): AJ_METHOD_REQUEST_NAME: %s\n", msg.error)); status = AJ_ERR_FAILURE; } else { AJ_InfoPrintf(("AJ_StartService(): AJ_BusAdvertiseName()\n")); status = AJ_BusAdvertiseName(bus, name, (opts != NULL) ? opts->transports : AJ_TRANSPORT_ANY, AJ_BUS_START_ADVERTISING, 0); } break; case AJ_REPLY_ID(AJ_METHOD_ADVERTISE_NAME): if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_StartService(): AJ_METHOD_ADVERTISE_NAME: %s\n", msg.error)); status = AJ_ERR_FAILURE; } else { serviceStarted = TRUE; } break; default: /* * Pass to the built-in bus message handlers */ AJ_InfoPrintf(("AJ_StartService(): AJ_BusHandleBusMessage()\n")); status = AJ_BusHandleBusMessage(&msg); break; } AJ_CloseMsg(&msg); } if (AJ_OK != status) { AJ_WarnPrintf(("AJ_StartService(): AJ_Disconnect(): status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); return status; } status = AJ_AboutInit(bus, port); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_StartService(): AJ_AboutInit returned status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); return status; } return status; } static AJ_Status StartClient(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const char* name, uint16_t port, const char** interfaces, uint32_t* sessionId, char* serviceName, const AJ_SessionOpts* opts, char* fullName) { AJ_Status status = AJ_OK; AJ_Time timer; uint8_t found = FALSE; uint8_t clientStarted = FALSE; uint32_t elapsed = 0; char* rule; size_t ruleLen; const char* base = "interface='org.alljoyn.About',sessionless='t'"; const char* impl = ",implements='"; const char** ifaces; AJ_InfoPrintf(("AJ_StartClient(bus=0x%p, daemonName=\"%s\", timeout=%d., connected=%d., interface=\"%p\", sessionId=0x%p, serviceName=0x%p, opts=0x%p)\n", bus, daemonName, timeout, connected, interfaces, sessionId, serviceName, opts)); AJ_InitTimer(&timer); if ((name != NULL) && (interfaces != NULL)) { return AJ_ERR_INVALID; } while (elapsed < timeout) { if (!connected) { status = AJ_FindBusAndConnect(bus, daemonName, AJ_CONNECT_TIMEOUT); elapsed = AJ_GetElapsedTime(&timer, TRUE); if (status != AJ_OK) { elapsed += AJ_CONNECT_PAUSE; if (elapsed > timeout) { break; } AJ_WarnPrintf(("AJ_StartClient(): Failed to connect to bus, sleeping for %d seconds\n", AJ_CONNECT_PAUSE / 1000)); AJ_Sleep(AJ_CONNECT_PAUSE); continue; } AJ_InfoPrintf(("AJ_StartClient(): AllJoyn client connected to bus\n")); } if (name != NULL) { /* * Kick things off by finding the service names */ status = AJ_BusFindAdvertisedName(bus, name, AJ_BUS_START_FINDING); AJ_InfoPrintf(("AJ_StartClient(): AJ_BusFindAdvertisedName()\n")); } else { /* * Kick things off by registering for the Announce signal. * Optionally add the implements clause per given interface */ ruleLen = strlen(base) + 1; if (interfaces != NULL) { ifaces = interfaces; while (*ifaces != NULL) { ruleLen += strlen(impl) + strlen(*ifaces) + 1; ifaces++; } } rule = (char*) AJ_Malloc(ruleLen); if (rule == NULL) { status = AJ_ERR_RESOURCES; break; } strcpy(rule, base); if (interfaces != NULL) { ifaces = interfaces; while (*ifaces != NULL) { strcat(rule, impl); if ((*ifaces)[0] == '$') { strcat(rule, &(*ifaces)[1]); } else { strcat(rule, *ifaces); } strcat(rule, "'"); ifaces++; } } status = AJ_BusSetSignalRule(bus, rule, AJ_BUS_SIGNAL_ALLOW); AJ_InfoPrintf(("AJ_StartClient(): Client SetSignalRule: %s\n", rule)); AJ_Free(rule); } if (status == AJ_OK) { break; } if (!connected) { AJ_WarnPrintf(("AJ_StartClient(): Client disconnecting from bus: status=%s.\n", AJ_StatusText(status))); AJ_Disconnect(bus); } } if (elapsed > timeout) { AJ_WarnPrintf(("AJ_StartClient(): Client timed-out trying to connect to bus: status=%s.\n", AJ_StatusText(status))); return AJ_ERR_TIMEOUT; } timeout -= elapsed; if (status != AJ_OK) { return status; } *sessionId = 0; if (serviceName != NULL) { *serviceName = '\0'; } while (!clientStarted && (status == AJ_OK)) { AJ_Message msg; const uint32_t timeout2 = min(AJ_UNMARSHAL_TIMEOUT, timeout); status = AJ_UnmarshalMsg(bus, &msg, timeout2); if ((status == AJ_ERR_TIMEOUT) && !found) { /* * Timeouts are expected until we find a name or service */ if (timeout <= timeout2) { return status; } timeout -= timeout2; status = AJ_OK; continue; } if (status == AJ_ERR_NO_MATCH) { // Ignore unknown messages status = AJ_OK; continue; } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_StartClient(): status=%s\n", AJ_StatusText(status))); break; } switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_FIND_NAME): case AJ_REPLY_ID(AJ_METHOD_FIND_NAME_BY_TRANSPORT): if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_StartClient(): AJ_METHOD_FIND_NAME: %s\n", msg.error)); status = AJ_ERR_FAILURE; } else { uint32_t disposition; AJ_UnmarshalArgs(&msg, "u", &disposition); if ((disposition != AJ_FIND_NAME_STARTED) && (disposition != AJ_FIND_NAME_ALREADY)) { AJ_ErrPrintf(("AJ_StartClient(): AJ_ERR_FAILURE\n")); status = AJ_ERR_FAILURE; } } break; case AJ_SIGNAL_FOUND_ADV_NAME: { AJ_Arg arg; AJ_UnmarshalArg(&msg, &arg); AJ_InfoPrintf(("FoundAdvertisedName(%s)\n", arg.val.v_string)); if (!found) { if (fullName) { strncpy(fullName, arg.val.v_string, arg.len); fullName[arg.len] = '\0'; } found = TRUE; status = AJ_BusJoinSession(bus, arg.val.v_string, port, opts); } } break; case AJ_SIGNAL_ABOUT_ANNOUNCE: { uint16_t aboutVersion, aboutPort; #ifdef ANNOUNCE_BASED_DISCOVERY status = AJ_AboutHandleAnnounce(&msg, &aboutVersion, &aboutPort, serviceName, &found); if (interfaces != NULL) { found = TRUE; } if ((status == AJ_OK) && (found == TRUE)) { AJ_InfoPrintf(("AJ_StartClient(): AboutAnnounce from (%s) About Version: %d Port: %d\n", msg.sender, aboutVersion, aboutPort)); #else AJ_InfoPrintf(("AJ_StartClient(): AboutAnnounce from (%s)\n", msg.sender)); if (!found) { found = TRUE; AJ_UnmarshalArgs(&msg, "qq", &aboutVersion, &aboutPort); if (serviceName != NULL) { strncpy(serviceName, msg.sender, AJ_MAX_NAME_SIZE); serviceName[AJ_MAX_NAME_SIZE] = '\0'; } #endif /* * Establish a session with the provided port. * If port value is 0 use the About port unmarshalled from the Announcement instead. */ if (port == 0) { status = AJ_BusJoinSession(bus, msg.sender, aboutPort, opts); } else { status = AJ_BusJoinSession(bus, msg.sender, port, opts); } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_StartClient(): BusJoinSession failed (%s)\n", AJ_StatusText(status))); } } } break; case AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION): { uint32_t replyCode; if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_ErrPrintf(("AJ_StartClient(): AJ_METHOD_JOIN_SESSION: %s\n", msg.error)); status = AJ_ERR_FAILURE; } else { status = AJ_UnmarshalArgs(&msg, "uu", &replyCode, sessionId); if (replyCode == AJ_JOINSESSION_REPLY_SUCCESS) { clientStarted = TRUE; } else { AJ_ErrPrintf(("AJ_StartClient(): AJ_METHOD_JOIN_SESSION reply (%d)\n", replyCode)); status = AJ_ERR_FAILURE; } } } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * Force a disconnect */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_InfoPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } AJ_ErrPrintf(("AJ_StartClient(): AJ_SIGNAL_SESSION_LOST_WITH_REASON: AJ_ERR_READ\n")); status = AJ_ERR_READ; break; default: /* * Pass to the built-in bus message handlers */ AJ_InfoPrintf(("AJ_StartClient(): AJ_BusHandleBusMessage()\n")); status = AJ_BusHandleBusMessage(&msg); break; } AJ_CloseMsg(&msg); } if ((AJ_OK != status) && !connected) { AJ_WarnPrintf(("AJ_StartClient(): Client disconnecting from bus: status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); return status; } return status; } AJ_Status AJ_StartClientByName(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const char* name, uint16_t port, uint32_t* sessionId, const AJ_SessionOpts* opts, char* fullName) { return StartClient(bus, daemonName, timeout, connected, name, port, NULL, sessionId, NULL, opts, fullName); } AJ_Status AJ_StartClient(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const char* name, uint16_t port, uint32_t* sessionId, const AJ_SessionOpts* opts) { AJ_WarnPrintf(("AJ_StartClient(): This function is deprecated. Please use AJ_StartClientByName() instead\n")); return StartClient(bus, daemonName, timeout, connected, name, port, NULL, sessionId, NULL, opts, NULL); } AJ_Status AJ_StartClientByInterface(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const char** interfaces, uint32_t* sessionId, char* uniqueName, const AJ_SessionOpts* opts) { return StartClient(bus, daemonName, timeout, connected, NULL, 0, interfaces, sessionId, uniqueName, opts, NULL); } #ifdef ANNOUNCE_BASED_DISCOVERY AJ_Status AJ_StartClientByPeerDescription(AJ_BusAttachment* bus, const char* daemonName, uint32_t timeout, uint8_t connected, const AJ_AboutPeerDescription* peerDesc, uint16_t port, uint32_t* sessionId, char* uniqueName, const AJ_SessionOpts* opts) { if (peerDesc != NULL) { AJ_AboutRegisterAnnounceHandlers(peerDesc, 1); } return StartClient(bus, daemonName, timeout, connected, NULL, port, NULL, sessionId, uniqueName, opts, NULL); } #endif ajtcl-16.04/src/aj_init.c000066400000000000000000000040401271074662300151770ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE INIT #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgINIT = 0; #endif static uint8_t initialized = FALSE; void AJ_Initialize(void) { AJ_GUID localGuid; if (!initialized) { initialized = TRUE; AJ_NVRAM_Init(); /* * This will seed the random number generator */ AJ_RandBytes(NULL, 0); /* * This will initialize credentials if needed */ AJ_GetLocalGUID(&localGuid); /* * Clear the Routing Node black list */ AJ_InitRoutingNodeBlacklist(); AJ_InitRoutingNodeResponselist(); } } ajtcl-16.04/src/aj_introspect.c000066400000000000000000001607071271074662300164430ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE INTROSPECT #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgINTROSPECT = 0; #endif #if defined(_WIN32) #define strcasecmp _stricmp #endif /** * The various object lists */ static const AJ_Object* objectLists[AJ_MAX_OBJECT_LISTS] = { AJ_StandardObjects, NULL, NULL }; /** * The language list */ static const char* const* languageList = NULL; /** * The root object */ const AJ_Object AJ_ROOT_OBJECT = { "/", NULL, 0, NULL }; /** * ObjectIterator exclusion flags mask for Introspectable objects */ #define AJ_OBJ_FLAGS_INTROSPECTABLE_EXCLUDE_MASK (AJ_OBJ_FLAG_HIDDEN | AJ_OBJ_FLAG_DISABLED | AJ_OBJ_FLAG_IS_PROXY) /** * Struct for a reply context for a method call */ typedef struct _ReplyContext { AJ_Time callTime; /**< Time the method call was made - used for timeouts */ uint32_t timeout; /**< How long to wait for a reply */ uint32_t serial; /**< Serial number for the reply message */ uint32_t messageId; /**< The unique message id for the call */ char uniqueName[AJ_MAX_NAME_SIZE + 1]; /**< Reply sender's unique name */ } ReplyContext; static ReplyContext replyContexts[AJ_NUM_REPLY_CONTEXTS]; /** * Function used by XML generator to push generated XML */ typedef void (*XMLWriterFunc)(void* context, const char* str, uint32_t len); /* * Per object list description lookup function */ static AJ_DescriptionLookupFunc descriptionLookups[AJ_MAX_OBJECT_LISTS] = { NULL, NULL, NULL }; #define IN_ARG '<' /* 0x3C */ #define OUT_ARG '>' /* 0x3E */ #define SEPARATOR ' ' #define IS_DIRECTION(c) (((c) >= IN_ARG) && ((c) <= OUT_ARG)) #define IS_SESSIONLESS(c) ((c) == SESSIONLESS) static const char* const MemberOpen[] = { " \n", " \n", "/>\n", " \n", /* One element larger than the close to allow for a property to encompass a description tag */ }; static const char* const Access[] = { "\" access=\"write\"", "\" access=\"readwrite\"", "\" access=\"read\"" }; /* * Table contains 6 elements to allow for the ability to encompass a description tag if one exists. * The computed index for closure of the tag has 3 added to it when a description tag is present. */ static const char* const Direction[] = { "\" direction=\"in\"/>\n", "\"/>\n", "\" direction=\"out\"/>\n", "\" direction=\"in\">\n", "\">\n", "\" direction=\"out\">\n" }; static const char interfaceOpen[] = "\n"; static const char secureOff[] = "off\"/>\n"; static char ExpandAttribute(XMLWriterFunc XMLWriter, void* context, const char** str, const char* pre, const char* post) { uint32_t len = 0; char next = 0; const char* s = *str; XMLWriter(context, pre, 0); while (*s) { char c = *s++; if (IS_DIRECTION(c) || (c == SEPARATOR)) { next = c; break; } ++len; } XMLWriter(context, *str, len); XMLWriter(context, post, 0); *str = s; return next; } static void XMLWriteTag(XMLWriterFunc XMLWriter, void* context, const char* tag, const char* attr, const char* val, uint32_t valLen, uint8_t atom) { XMLWriter(context, tag, 0); if (attr != NULL) { XMLWriter(context, attr, 0); XMLWriter(context, val, valLen); XMLWriter(context, "\"", 1); } if (atom) { XMLWriter(context, "/>\n", 3); } else { XMLWriter(context, ">\n", 2); } } static const char* GetDescription(AJ_DescriptionLookupFunc descLookup, uint32_t descId, const char* languageTag) { if (descLookup == NULL) { return NULL; } return descLookup(descId, languageTag); } static void XMLWriteDescription(XMLWriterFunc XMLWriter, void* context, uint8_t level, const char* description, const char* languageTag) { if (description != NULL) { const uint8_t unifiedFormat = (languageTag == NULL); uint8_t i; for (i = 0; i < level; i++) { XMLWriter(context, " ", 4); } if (unifiedFormat) { XMLWriter(context, "\n", 5); } else { XMLWriter(context, " 0) { XMLWriter(context, " language=\"", 11); XMLWriter(context, languageTag, 0); XMLWriter(context, "\"", 1); } XMLWriter(context, ">", 1); XMLWriter(context, description, 0); XMLWriter(context, "\n", 15); } } return; } static AJ_Status ExpandInterfaces(XMLWriterFunc XMLWriter, void* context, const AJ_InterfaceDescription* iface, AJ_DescriptionLookupFunc descLookup, uint32_t descObjId, const char* languageTag) { uint32_t descId; uint8_t ifaceIndex = 0; const uint8_t unifiedFormat = (languageTag == NULL); if (!iface) { return AJ_OK; } while (*iface) { uint8_t memberIndex = 0; const char* const* entries = *iface; char flag = entries[0][0]; uint8_t dBus_std_iface = FALSE; const char* description = NULL; /* Increase the interface index since we start at 1 */ ++ifaceIndex; descId = descObjId | (((uint32_t)(ifaceIndex)) << 16); if ((flag == SECURE_TRUE) || (flag == SECURE_OFF)) { /* If it is a common standard interface, do not add any annotations.*/ if ((strcmp(entries[0], AJ_IntrospectionIface[0]) == 0) || (strcmp(entries[0], AJ_PropertiesIface[0]) == 0) || (strcmp(entries[0], DBusPeerInterface) == 0) || (strcmp(entries[0], AllSeenIntrospectableInterface) == 0)) { dBus_std_iface = TRUE; } /* * If flagged as secure or not secure, skip the first char (the '$' or '#') of the name */ XMLWriteTag(XMLWriter, context, interfaceOpen, nameAttr, entries[0] + 1, 0, FALSE); if (!dBus_std_iface) { XMLWriter(context, annotateSecure, sizeof(annotateSecure) - 1); if (flag == SECURE_TRUE) { XMLWriter(context, secureTrue, sizeof(secureTrue) - 1); } else { XMLWriter(context, secureOff, sizeof(secureOff) - 1); } } } else { XMLWriteTag(XMLWriter, context, interfaceOpen, nameAttr, entries[0], 0, FALSE); } description = GetDescription(descLookup, descId, languageTag); if (description != NULL) { XMLWriteDescription(XMLWriter, context, 0, description, languageTag); } while (*(++entries)) { uint8_t argIndex = 0; const char* member = *entries; uint8_t memberType = MEMBER_TYPE(*member++); uint8_t attr; uint8_t isSessionless = FALSE; /* Increase index since we start at 1 */ ++memberIndex; if (memberType > 2) { AJ_ErrPrintf(("ExpandInterfaces(): %s", AJ_StatusText(AJ_ERR_UNEXPECTED))); return AJ_ERR_UNEXPECTED; } XMLWriter(context, MemberOpen[memberType], 0); if (memberType == SIGNAL && IS_SESSIONLESS(*member)) { /* * Advance so that we do not return a '&' character */ member++; isSessionless = TRUE; } attr = ExpandAttribute(XMLWriter, context, &member, nameAttr, "\""); if (memberType == PROPERTY) { uint8_t acc; if (attr == SEPARATOR) { attr = member++[0]; } acc = attr - WRITE_ONLY; if (acc > 2) { AJ_ErrPrintf(("ExpandInterfaces(): %s", AJ_StatusText(AJ_ERR_UNEXPECTED))); return AJ_ERR_UNEXPECTED; } ExpandAttribute(XMLWriter, context, &member, typeAttr, Access[acc]); } else { /* * If we are using the AllSeen introspection then add isSessionless */ if (memberType == SIGNAL) { if (!unifiedFormat) { XMLWriter(context, sessionlessAttr, sizeof(sessionlessAttr) - 1); if (isSessionless) { XMLWriter(context, trueVal, sizeof(trueVal) - 1); } else { XMLWriter(context, falseVal, sizeof(falseVal) - 1); } } else { if (isSessionless) { XMLWriter(context, ">\n", 2); XMLWriter(context, annotateSessionless, sizeof(annotateSessionless) - 1); } } } XMLWriter(context, ">\n", 2); while (attr) { uint8_t dir; /* increase arg index since we start at 1 */ ++argIndex; XMLWriter(context, argOpen, sizeof(argOpen) - 1); if (IS_DIRECTION(*member)) { dir = *member++ - IN_ARG; } else { dir = ExpandAttribute(XMLWriter, context, &member, nameAttr, "\"") - IN_ARG; } if ((dir != 0) && (dir != 2)) { AJ_ErrPrintf(("ExpandInterfaces(): %s", AJ_StatusText(AJ_ERR_UNEXPECTED))); return AJ_ERR_UNEXPECTED; } if (memberType == SIGNAL) { dir = 1; } /* * If we have a description then wait to close the tag until after adding in a description tag */ description = GetDescription(descLookup, (descId | (((uint32_t)memberIndex) << 8) | ((uint32_t)argIndex)), languageTag); if (description != NULL) { dir += 3; } attr = ExpandAttribute(XMLWriter, context, &member, typeAttr, Direction[dir]); if (description != NULL) { XMLWriteDescription(XMLWriter, context, 2, description, languageTag); XMLWriter(context, argClose, sizeof(argClose) - 1); } } } description = GetDescription(descLookup, (descId | (((uint32_t)memberIndex) << 8)), languageTag); if (description != NULL) { if (memberType == PROPERTY) { XMLWriter(context, ">\n", 2); /* * Move to the alternate close for a propety * which is in the memberClose table of entry 4 */ memberType++; } XMLWriteDescription(XMLWriter, context, 1, description, languageTag); } XMLWriter(context, MemberClose[memberType], 0); } XMLWriter(context, interfaceClose, sizeof(interfaceClose) - 1); ++iface; } return AJ_OK; } /* * Check if the path c is child of path p if so return pointer to the start of the child path * relative to the parent. */ static const char* ChildPath(const char* p, const char* c, uint32_t* sz) { /* * Special case for parent == root (all nodes are children of root) */ if ((p[0] == '/') && (p[1] == 0)) { ++p; } while (*p && (*p == *c)) { ++p; ++c; } if ((*p == '\0') && (*c == '/')) { uint32_t len = 0; ++c; while (c[len] && c[len] != '/') { ++len; } if (sz) { *sz = len; } /* * Return then isolated node name of the child */ return len ? c : NULL; } else { return NULL; } } static const AJ_Object* FirstInstance(const char* path, const char* child, uint32_t sz) { AJ_ObjectIterator iter; const AJ_Object* obj = AJ_InitObjectIterator(&iter, AJ_OBJ_FLAGS_ALL_INCLUDE_MASK, AJ_OBJ_FLAGS_INTROSPECTABLE_EXCLUDE_MASK); while (obj != NULL) { uint32_t len; const char* c = ChildPath(path, obj->path, &len); if (c && (len == sz) && (memcmp(c, child, sz) == 0)) { return obj; } obj = AJ_NextObject(&iter); } return obj; } /* * Security applies if the interface is secure or if the object or it's parent object is flagged as * secure and the security is not explicitly OFF for the interface. */ static uint32_t SecurityApplies(const char* ifc, const AJ_Object* obj) { AJ_ObjectIterator iter; const AJ_Object* lookup; if (ifc) { if (*ifc == SECURE_TRUE) { return TRUE; } if (*ifc == SECURE_OFF) { return FALSE; } } if (obj->flags & AJ_OBJ_FLAG_SECURE) { return TRUE; } /* * Check that obj is not a child of a secure parent object */ lookup = AJ_InitObjectIterator(&iter, AJ_OBJ_FLAGS_ALL_INCLUDE_MASK, AJ_OBJ_FLAG_IS_PROXY); while (lookup != NULL) { if ((lookup->flags & AJ_OBJ_FLAG_SECURE) && ChildPath(lookup->path, obj->path, NULL)) { return TRUE; } lookup = AJ_NextObject(&iter); } return FALSE; } /* * Find the best matching language tag, using the lookup algorithm in * RFC 4647 section 3.4. This algorithm requires that the "supported" * languages be the least specific they can (e.g., "en" in order to match * both "en" and "en-US" if requested), and the "requested" language be * the most specific it can (e.g., "en-US" in order to match either "en-US" * or "en" if supported). */ #define MAX_LANG_SIZE 63 static const char* GetBestLanguage(const char* requested) { if ((requested != NULL) && (*requested != 0) && (languageList != NULL)) { char languageToCheck[MAX_LANG_SIZE + 1]; strncpy(languageToCheck, requested, MAX_LANG_SIZE); languageToCheck[MAX_LANG_SIZE] = '\0'; for (;;) { // Look for a supported language matching the language to check. size_t idx; char* pos; for (idx = 0; languageList[idx] != NULL; idx++) { if (strcasecmp(languageList[idx], languageToCheck) == 0) { return languageList[idx]; } } // Drop the last subtag and try again. pos = strrchr(languageToCheck, '-'); if (pos == NULL) { break; } *pos = 0; } } // No match found, so return the default language. return (languageList != NULL) ? languageList[0] : NULL; } static AJ_Status GenXML(XMLWriterFunc XMLWriter, void* context, const AJ_ObjectIterator* objIter, const AJ_Object* virtualObject, const char* languageTag) { AJ_Status status = AJ_OK; const AJ_Object* obj; AJ_DescriptionLookupFunc descLookup = NULL; if (objIter == NULL) { obj = virtualObject; } else { if (objIter->l >= ArraySize(objectLists) && virtualObject == NULL) { return AJ_OK; } obj = &(objectLists[objIter->l][objIter->n - 1]); } if (obj != NULL && obj->path != NULL) { AJ_ObjectIterator childObjectIter; const AJ_Object* childObj = AJ_InitObjectIterator(&childObjectIter, AJ_OBJ_FLAGS_ALL_INCLUDE_MASK, AJ_OBJ_FLAGS_INTROSPECTABLE_EXCLUDE_MASK); const char* description = NULL; /* * Ignore objects that are hidden or disabled or proxy */ if (obj->flags & (AJ_OBJ_FLAGS_INTROSPECTABLE_EXCLUDE_MASK)) { return AJ_OK; } /* * Find matching description lookup function. NULL indicates no descriptions */ if (languageTag != NULL) { if (objIter != NULL) { descLookup = descriptionLookups[objIter->l]; } languageTag = GetBestLanguage(languageTag); } /* * Generate object's XML */ XMLWriteTag(XMLWriter, context, nodeOpen, nameAttr, obj->path, 0, FALSE); if (SecurityApplies(NULL, obj)) { XMLWriter(context, annotateSecure, 51); XMLWriter(context, secureTrue, 8); } if (objIter != NULL) { description = GetDescription(descLookup, (objIter->n - 1) << 24, languageTag); } if (description != NULL) { XMLWriteDescription(XMLWriter, context, 0, description, languageTag); } if (status == AJ_OK) { if (objIter != NULL) { status = ExpandInterfaces(XMLWriter, context, obj->interfaces, descLookup, (objIter->n - 1) << 24, languageTag); } else { status = ExpandInterfaces(XMLWriter, context, obj->interfaces, descLookup, 0, languageTag); } } if (status == AJ_OK) { while (childObj != NULL) { uint32_t len; /* * Find immediate descendants */ const char* child = ChildPath(obj->path, childObj->path, &len); /* * If there is a child check that this is the first instance of this child. */ if (child && (FirstInstance(obj->path, child, len) == childObj)) { if (languageTag != NULL && childObjectIter.l < AJ_MAX_OBJECT_LISTS) { descLookup = descriptionLookups[childObjectIter.l]; } else { descLookup = NULL; } description = GetDescription(descLookup, (childObjectIter.n - 1) << 24, languageTag); if (description != NULL) { XMLWriteTag(XMLWriter, context, nodeOpen, nameAttr, child, len, FALSE); XMLWriteDescription(XMLWriter, context, 0, description, languageTag); XMLWriter(context, nodeClose, 8); } else { XMLWriteTag(XMLWriter, context, nodeOpen, nameAttr, child, len, TRUE); } } childObj = AJ_NextObject(&childObjectIter); } XMLWriter(context, nodeClose, 8); } if (status != AJ_OK) { AJ_ErrPrintf(("\nFailed to generate XML - check interface descriptions of %s for errors\n", obj->path)); } } return status; } /* * Historically, Thin Client programs print the XML for their app objects as a * banner indicating they are alive. For that reason we don't force users to * explicity turn on XML printing. We just default it to on as long as we are * in a debug build. */ #ifndef NDEBUG static void PrintXML(void* context, const char* str, uint32_t len) { if (len) { while (len--) { AJ_AlwaysPrintf(("%c", *str++)); } } else { AJ_AlwaysPrintf(("%s", str)); } } void AJ_PrintXML(const AJ_Object* objs) { AJ_PrintXMLWithDescriptions(objs, NULL); // without descriptions } void AJ_PrintXMLWithDescriptions(const AJ_Object* objs, const char* languageTag) { AJ_Status status; while (objs && objs->path) { if (strcmp(objs->path, "/") == 0) { status = GenXML(PrintXML, NULL, NULL, objs, languageTag); // with descriptions in the given language if (status != AJ_OK) { AJ_ErrPrintf(("\nFailed to generate XML - check interface descriptions of %s for errors\n", objs->path)); } } else { AJ_ObjectIterator iter; const AJ_Object* lookup; lookup = AJ_InitObjectIterator(&iter, AJ_OBJ_FLAGS_ALL_INCLUDE_MASK, AJ_OBJ_FLAGS_INTROSPECTABLE_EXCLUDE_MASK); while (lookup != NULL) { if (strcmp(lookup->path, objs->path) == 0) { break; } lookup = AJ_NextObject(&iter); } if (lookup != NULL) { status = GenXML(PrintXML, NULL, &iter, NULL, languageTag); // with descriptions in the given language if (status != AJ_OK) { AJ_ErrPrintf(("\nFailed to generate XML - check interface descriptions of %s for errors\n", objs->path)); } } else { AJ_AlwaysPrintf(("Reminder: Object not yet added to the ObjectList, do not forget to call RegisterObjects\n")); status = GenXML(PrintXML, NULL, NULL, objs, languageTag); } } objs++; } } #endif /* * Function to accumulate the length of the XML that will be generated */ void SizeXML(void* context, const char* str, uint32_t len) { if (!len) { len = (uint32_t)strlen(str); } *((uint32_t*)context) += len; } typedef struct _WriteContext { AJ_Message* reply; uint32_t len; AJ_Status status; } WriteContext; void WriteXML(void* context, const char* str, uint32_t len) { WriteContext* wctx = (WriteContext*)context; if (wctx->status == AJ_OK) { if (!len) { len = (uint32_t)strlen(str); } wctx->status = AJ_MarshalRaw(wctx->reply, str, len); } } AJ_Status AJ_HandleIntrospectRequestInternal(const AJ_Message* msg, AJ_Message* reply, const char* languageTag) { AJ_Status status = AJ_OK; AJ_ObjectIterator objIter; const AJ_Object* obj = AJ_InitObjectIterator(&objIter, AJ_OBJ_FLAGS_ALL_INCLUDE_MASK, AJ_OBJ_FLAGS_INTROSPECTABLE_EXCLUDE_MASK); const AJ_Object virtualObject = { msg->objPath, NULL, 0, NULL }; WriteContext context; uint32_t children = 0; /* * Find the requested object in the registered object lists */ while (obj != NULL) { /* * Find out which object we are introspecting. There are two possibilities: * * - The request has a complete object path to one of the application objects. * - The request has a path to a parent object of one or more application objects where the * parent itself is just a place-holder in the object hierarchy. */ if (strcmp(msg->objPath, obj->path) == 0) { break; } if (0 != strcmp(msg->objPath, "/")) { if (ChildPath(msg->objPath, obj->path, NULL)) { ++children; } } /* * If there was not a direct match but the requested node has children we create * a temporary AJ_Object for the parent and introspect that object. */ if (children) { obj = &virtualObject; break; } obj = AJ_NextObject(&objIter); } if (obj != NULL && obj->path != NULL) { /* * First pass computes the size of the XML string */ context.len = 0; if (children > 0) { status = GenXML(SizeXML, &context.len, NULL, &virtualObject, languageTag); } else { status = GenXML(SizeXML, &context.len, &objIter, NULL, languageTag); } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_HandleIntrospectRequest(): Failed to generate XML. status=%s", AJ_StatusText(status))); return status; } /* * Second pass marshals the XML */ AJ_InfoPrintf(("AJ_HandleIntrospectRequest() %d bytes of XML\n", context.len)); AJ_MarshalReplyMsg(msg, reply); /* * Do a partial delivery */ status = AJ_DeliverMsgPartial(reply, context.len + 5); /* * Marshal the string length */ if (status == AJ_OK) { status = AJ_MarshalRaw(reply, &context.len, 4); } if (status == AJ_OK) { uint8_t nul = 0; context.status = AJ_OK; context.reply = reply; if (children > 0) { GenXML(WriteXML, &context, NULL, &virtualObject, languageTag); } else { GenXML(WriteXML, &context, &objIter, NULL, languageTag); } status = context.status; if (status == AJ_OK) { /* * Marshal the terminating NUL */ status = AJ_MarshalRaw(reply, &nul, 1); } } } else { /* * Return a ServiceUnknown error response */ AJ_WarnPrintf(("AJ_HandleIntrospectRequest() NO MATCH for %s\n", msg->objPath)); AJ_MarshalErrorMsg(msg, reply, AJ_ErrServiceUnknown); } return status; } AJ_Status AJ_HandleIntrospectRequest(const AJ_Message* msg, AJ_Message* reply, const char* languageTag) { return AJ_HandleIntrospectRequestInternal(msg, reply, languageTag); } AJ_Status AJ_GetIntrospectionData(const AJ_Message* msg, AJ_Message* reply) { return AJ_HandleIntrospectRequestInternal(msg, reply, NULL); } AJ_Status AJ_HandleGetDescriptionLanguages(const AJ_Message* msg, AJ_Message* reply) { AJ_Status status = AJ_OK; AJ_Arg languageListArray; const char* const* languageTag; status = AJ_MarshalReplyMsg(msg, reply); if (status == AJ_OK) { status = AJ_MarshalContainer(reply, &languageListArray, AJ_ARG_ARRAY); } if (status == AJ_OK) { languageTag = languageList; while ((NULL != *languageTag) && status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", *languageTag); languageTag++; } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &languageListArray); } return status; } /* * Check that the signature in the message matches the encoded signature in the string */ static AJ_Status CheckSignature(const char* encoding, const AJ_Message* msg) { const char* sig = msg->signature ? msg->signature : ""; char direction = (msg->hdr->msgType == AJ_MSG_METHOD_CALL) ? IN_ARG : OUT_ARG; /* * Wild card in the message is ok. */ if (*sig == '*') { return AJ_OK; } while (*encoding) { /* * Skip until we find a direction character */ while (*encoding && (*encoding++ != direction)) { } /* * Match a single arg to the signature */ while (*encoding && (*sig == *encoding)) { ++sig; ++encoding; } if (*encoding && (*encoding != ' ')) { AJ_ErrPrintf(("CheckSignature(): AJ_ERR_SIGNATURE\n")); return AJ_ERR_SIGNATURE; } } /* * On a match we should have consumed both strings */ return (*encoding == *sig) ? AJ_OK : AJ_ERR_SIGNATURE; } /* * Composes a signature from the member encoding from an interface description. */ static AJ_Status ComposeSignature(const char* encoding, char direction, char* sig, size_t len) { while (*encoding) { /* * Skip until we find a direction character */ while (*encoding && (*encoding++ != direction)) { } /* * Match a single arg to the signature */ while (*encoding && (*encoding != ' ')) { if (--len == 0) { AJ_ErrPrintf(("ComposeSignature(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } *sig++ = *encoding++; } } *sig = '\0'; return AJ_OK; } static AJ_Status MatchProp(const char* member, const char* prop, uint8_t op, const char** sig) { AJ_Status status; const char* encoding = member; if (*encoding++ != '@') { AJ_InfoPrintf(("MatchProp(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } while (*prop) { if (*encoding++ != *prop++) { AJ_InfoPrintf(("MatchProp(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } } switch (*encoding) { case WRITE_ONLY: status = (AJ_PROP_SET == op) ? AJ_OK : AJ_ERR_DISALLOWED; break; case READ_ONLY: status = (AJ_PROP_GET == op) ? AJ_OK : AJ_ERR_DISALLOWED; break; case READ_WRITE: status = AJ_OK; break; default: AJ_InfoPrintf(("MatchProp(): AJ_ERR_NO_MATCH - incorrect annotation or substring match\n")); status = AJ_ERR_NO_MATCH; break; } if (AJ_OK == status) { *sig = ++encoding; } return status; } static uint32_t MatchMember(const char* encoding, const AJ_Message* msg) { const char* member = msg->member; uint8_t memberType = (msg->hdr->msgType == AJ_MSG_METHOD_CALL) ? METHOD : SIGNAL; if (MEMBER_TYPE(*encoding++) != memberType) { return FALSE; } if (memberType == SIGNAL && IS_SESSIONLESS(*encoding)) { /* * Advance so that we do not return a '&' character */ encoding++; } while (*member) { if (*encoding++ != *member++) { return FALSE; } } return (*encoding == '\0') || (*encoding == ' '); } static AJ_InterfaceDescription FindInterface(const AJ_InterfaceDescription* interfaces, const char* iface, uint8_t* idx) { *idx = 0; if (interfaces) { while (*interfaces) { AJ_InterfaceDescription desc = *interfaces++; const char* intfName = *desc; if (desc) { /* * Skip security specifier when comparing the interface name */ if ((*intfName == SECURE_TRUE) || (*intfName == SECURE_OFF)) { ++intfName; } if (strcmp(intfName, iface) == 0) { return desc; } } *idx += 1; } } return NULL; } /* * Match the object path. There are two wild card entries for object paths: '?' matches any method * call and '!' matches any signal. The method call wildcard is specifically to support the * introspection and ping methods. The signal wildcard allows for a single handler for a specific * signal emitted by any object. Note that these wildcards are expected to provide unique matches, * i.e. there should be no non-wildcarded entry in any object table that would also match. */ static uint8_t inline MatchPath(const char* path, AJ_Message* msg) { if ((*path == '?') && (msg->hdr->msgType == AJ_MSG_METHOD_CALL)) { return TRUE; } if ((*path == '!') && (msg->hdr->msgType == AJ_MSG_SIGNAL)) { return TRUE; } return strcmp(path, msg->objPath) == 0; } AJ_Status AJ_LookupMessageId(AJ_Message* msg, uint8_t* secure) { uint8_t oIndex = 0; for (oIndex = 0; oIndex < ArraySize(objectLists); ++oIndex) { uint8_t pIndex = 0; const AJ_Object* obj = objectLists[oIndex]; if (!obj) { continue; } for (; obj->path; ++pIndex, ++obj) { /* * Skip objects that are currently disabled */ if (obj->flags & AJ_OBJ_FLAG_DISABLED) { continue; } if (MatchPath(obj->path, msg)) { uint8_t iIndex; AJ_InterfaceDescription desc = FindInterface(obj->interfaces, msg->iface, &iIndex); if (desc) { uint8_t mIndex = 0; *secure = SecurityApplies(*desc, obj); /* * Skip the interface name and iterate over the members of the interface */ while (*(++desc)) { if (MatchMember(*desc, msg)) { msg->msgId = (oIndex << 24) | (pIndex << 16) | (iIndex << 8) | mIndex; AJ_InfoPrintf(("Identified message %x\n", msg->msgId)); return CheckSignature(*desc, msg); } ++mIndex; } } } } } AJ_ErrPrintf(("LookupMessageId(): AJ_ERR_NO_MATCH\n")); return AJ_ERR_NO_MATCH; } #ifndef NDEBUG /* * Validates an index into a NULL terminated array */ static uint8_t CheckIndex(const void* ptr, uint8_t idx, size_t stride) { if (!ptr) { return FALSE; } do { if (*((void**)ptr) == NULL) { AJ_ErrPrintf(("\n!!!Invalid msg identifier indicates programming error!!!\n")); return FALSE; } ptr = (((uint8_t*)ptr) + stride); } while (idx--); return TRUE; } #endif static AJ_Status UnpackMsgId(uint32_t msgId, const char** objPath, const char** iface, const char** member, uint8_t* secure) { uint8_t oIndex = (msgId >> 24); uint8_t pIndex = (msgId >> 16); uint8_t iIndex = (msgId >> 8); uint8_t mIndex = (uint8_t)(msgId) + 1; const AJ_Object* obj; AJ_InterfaceDescription ifc; #ifndef NDEBUG if ((oIndex >= ArraySize(objectLists)) || !CheckIndex(objectLists[oIndex], pIndex, sizeof(AJ_Object))) { AJ_ErrPrintf(("UnpackMsgId(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } obj = &objectLists[oIndex][pIndex]; if (!CheckIndex(obj->interfaces, iIndex, sizeof(AJ_InterfaceDescription))) { AJ_ErrPrintf(("UnpackMsgId(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } ifc = obj->interfaces[iIndex]; if (!CheckIndex(ifc, mIndex, sizeof(AJ_InterfaceDescription))) { AJ_ErrPrintf(("UnpackMsgId(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } #else obj = &objectLists[oIndex][pIndex]; ifc = obj->interfaces[iIndex]; #endif if (obj->flags & AJ_OBJ_FLAG_DISABLED) { return AJ_ERR_INVALID; } if (objPath) { *objPath = obj->path; } *secure = SecurityApplies(*ifc, obj); if (iface) { /* * Skip over security specifier if there is one */ if ((ifc[0][0] == SECURE_TRUE) || (ifc[0][0] == SECURE_OFF)) { *iface = *ifc + 1; } else { *iface = *ifc; } } if (member) { /* * Skip over sessionless signal specifier if there is one */ if (MEMBER_TYPE(ifc[mIndex][0]) == SIGNAL && IS_SESSIONLESS(ifc[mIndex][1])) { *member = ifc[mIndex] + 2; } else { *member = ifc[mIndex] + 1; } } return AJ_OK; } AJ_Status AJ_MarshalPropertyArgs(AJ_Message* msg, uint32_t propId) { AJ_Status status; const char* iface; const char* prop; uint8_t secure; size_t pos; AJ_Arg arg; status = UnpackMsgId(propId, NULL, &iface, &prop, &secure); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_MarhsalPropertyArgs(): status=%s\n", AJ_StatusText(status))); return status; } if (secure) { msg->hdr->flags |= AJ_FLAG_ENCRYPTED; } if (msg->hdr->flags & AJ_FLAG_ENCRYPTED) { /* * Check outgoing access policy */ status = AJ_AccessControlCheckProperty(msg, propId, msg->destination, AJ_ACCESS_OUTGOING); if (AJ_OK != status) { return status; } } /* * Marshal interface name */ AJ_MarshalArgs(msg, "s", iface); /* * Marshal property name */ pos = AJ_StringFindFirstOf(prop, "<=>"); AJ_InitArg(&arg, AJ_ARG_STRING, 0, prop, pos); status = AJ_MarshalArg(msg, &arg); /* * If setting a property handle the variant setup */ if ((status == AJ_OK) && ((msg->msgId & 0xFF) == AJ_PROP_SET)) { char sig[16]; ComposeSignature(prop, prop[pos], sig, sizeof(sig)); status = AJ_MarshalVariant(msg, sig); } return status; } /* * Hook for unit tests */ #ifndef NDEBUG AJ_MutterHook MutterHook = NULL; #endif AJ_Status AJ_InitMessageFromMsgId(AJ_Message* msg, uint32_t msgId, uint8_t msgType, uint8_t* secure) { /* * Static buffer for holding the signature for the message currently being marshaled. Since this * implementation can only marshal one message at a time we only need one of these buffers. The * size of the buffer dictates the maximum size signature we can marshal. The wire protocol * allows up to 255 characters in a signature but that would represent an outgrageously complex * message argument list. */ static char msgSignature[64]; AJ_Status status = AJ_OK; #ifndef NDEBUG if (MutterHook) { return MutterHook(msg, msgId, msgType); } #endif if (msgType == AJ_MSG_ERROR) { /* * The only thing to initialize for errors is the msgId */ msg->msgId = AJ_REPLY_ID(msgId); /* * Get the secure flag if we have a valid message id this will ensure that the error * response is encrypted if that is what is expected. */ if (msg->msgId != AJ_INVALID_MSG_ID) { status = UnpackMsgId(msgId, NULL, NULL, NULL, secure); } } else { const char* member = NULL; char direction = (msgType == AJ_MSG_METHOD_CALL) ? IN_ARG : OUT_ARG; /* * The rest is just indexing into the object and interface descriptions. */ if (msgType == AJ_MSG_METHOD_RET) { msg->msgId = AJ_REPLY_ID(msgId); status = UnpackMsgId(msgId, NULL, NULL, &member, secure); } else { msg->msgId = msgId; status = UnpackMsgId(msgId, &msg->objPath, &msg->iface, &member, secure); if (status == AJ_OK) { /* * Validate the object path */ if (!msg->objPath) { status = AJ_ERR_OBJECT_PATH; } else if (*msg->objPath == '?') { /* * The wildcard object path is a special for case methods implemented by all * objects. In the message header need a valid object path, it doesn't matter * which one by definition so use the root object because it is always valid. */ msg->objPath = "/"; } else if (*msg->objPath != '/') { status = AJ_ERR_OBJECT_PATH; } msg->member = member; } } /* * Compose the signature from information in the member encoding. */ if (status == AJ_OK) { status = ComposeSignature(member, direction, msgSignature, sizeof(msgSignature)); if (status == AJ_OK) { msg->signature = msgSignature; } } } return status; } static AJ_Status CheckReturnSignature(AJ_Message* msg, uint32_t msgId) { AJ_Status status; uint8_t secure = FALSE; const char* member; status = UnpackMsgId(msgId, NULL, NULL, &member, &secure); if (status != AJ_OK) { AJ_ErrPrintf(("CheckReturnSignature(): status=%s\n", AJ_StatusText(status))); return status; } /* * Check that if the interface was flagged secure that the reply was encrypted */ if (secure && !(msg->hdr->flags & AJ_FLAG_ENCRYPTED)) { return AJ_ERR_SECURITY; } /* * Nothing to check for error messages */ if (msg->hdr->msgType != AJ_MSG_ERROR) { status = CheckSignature(member, msg); } if (status == AJ_OK) { msg->msgId = AJ_REPLY_ID(msgId); } return status; } static ReplyContext* FindReplyContext(uint32_t serial) { size_t i; for (i = 0; i < ArraySize(replyContexts); ++i) { if (replyContexts[i].serial == serial) { return &replyContexts[i]; } } return NULL; } AJ_Status AJ_IdentifyProperty(AJ_Message* msg, const char* iface, const char* prop, uint32_t* propId, const char** sigPtr, uint8_t* secure) { AJ_Status status = AJ_OK; uint8_t oIndex = (msg->msgId >> 24); uint8_t pIndex = (msg->msgId >> 16); uint8_t iIndex; const AJ_Object* obj; AJ_InterfaceDescription desc; #ifndef NDEBUG if ((oIndex >= ArraySize(objectLists)) || !CheckIndex(objectLists[oIndex], pIndex, sizeof(AJ_Object))) { status = AJ_ERR_INVALID; AJ_ErrPrintf(("AJ_IdentifyProperty(): %s\n", AJ_StatusText(status))); return status; } #endif obj = &objectLists[oIndex][pIndex]; *propId = AJ_INVALID_PROP_ID; desc = FindInterface(obj->interfaces, iface, &iIndex); if (desc) { uint8_t mIndex = 0; /* * Security is based on the interface the property is defined on. */ *secure = SecurityApplies(*desc, obj); if (*secure == FALSE) { /* * For Properties interface security is based on the interface supplied */ if (strcmp(*desc, AJ_PropertiesIface[0]) == 0) { const char* actualIface; status = AJ_UnmarshalArgs(msg, "s", &actualIface); if (status == AJ_OK) { *secure = SecurityApplies(actualIface, obj); status = AJ_ResetArgs(msg); } } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_IdentifyProperty(): %s\n", AJ_StatusText(status))); return status; } } /* * Iterate over the interface members to locate the property that is being accessed. */ while (*(++desc)) { status = MatchProp(*desc, prop, msg->msgId & 0xFF, sigPtr); if (status != AJ_ERR_NO_MATCH) { if (status == AJ_OK) { *propId = (oIndex << 24) | (pIndex << 16) | (iIndex << 8) | mIndex; AJ_InfoPrintf(("Identified property %s:%s id=%x sig=\"%s\"\n", iface, prop, *propId, *sigPtr)); } break; } ++mIndex; } } return status; } AJ_Status AJ_UnmarshalPropertyArgs(AJ_Message* msg, uint32_t* propId, const char** sig) { AJ_Status status; uint8_t secure = FALSE; char* iface; char* prop; status = AJ_UnmarshalArgs(msg, "ss", &iface, &prop); if (status == AJ_OK) { status = AJ_IdentifyProperty(msg, iface, prop, propId, sig, &secure); /* * If the interface is secure check the message must be encrypted */ if ((status == AJ_OK) && secure) { if (!(msg->hdr->flags & AJ_FLAG_ENCRYPTED)) { AJ_WarnPrintf(("Security violation accessing property\n")); return AJ_ERR_SECURITY; } /* * Check incoming access policy */ status = AJ_AccessControlCheckProperty(msg, *propId, msg->sender, AJ_ACCESS_INCOMING); } } return status; } AJ_Status AJ_MarshalAllPropertiesArgs(AJ_Message* replyMsg, const char* iface, AJ_BusPropGetCallback callback, void* context) { AJ_Status status = AJ_ERR_MARSHAL; uint8_t oIndex = (replyMsg->msgId >> 24) & ~AJ_REP_ID_FLAG; uint8_t pIndex = replyMsg->msgId >> 16; uint8_t iIndex; const AJ_Object* obj = &objectLists[oIndex][pIndex]; uint8_t secure = SecurityApplies(iface, obj); AJ_InterfaceDescription desc; AJ_Arg array; /* * If the interface is secure check the message must be encrypted */ if (secure && !(replyMsg->hdr->flags & AJ_FLAG_ENCRYPTED)) { status = AJ_ERR_SECURITY; AJ_WarnPrintf(("Security violation accessing property\n")); goto Exit; } desc = FindInterface(obj->interfaces, iface, &iIndex); if (desc != NULL) { uint8_t mIndex = 0; status = AJ_MarshalContainer(replyMsg, &array, AJ_ARG_ARRAY); if (status != AJ_OK) { goto Exit; } /* * Iterate over the interface members to locate the properties that are being accessed. */ while (*(++desc) != NULL) { const char* prop = *desc; size_t pos; AJ_Arg dict; AJ_Arg key; uint32_t propId = AJ_ENCODE_PROPERTY_ID(oIndex, pIndex, iIndex, mIndex++); /* * Consume member type in member definition and skip member if not a Property */ if (MEMBER_TYPE(*(prop++)) != PROPERTY) { continue; } /* * Skip Write Only properties */ pos = AJ_StringFindFirstOf(prop, "<=>"); if ((pos > 1) && (prop[pos - 1] == WRITE_ONLY)) { continue; } if (secure) { /* * Check incoming access policy */ status = AJ_AccessControlCheckProperty(replyMsg, propId, replyMsg->destination, AJ_ACCESS_INCOMING); if (AJ_OK != status) { /* Skip this property */ continue; } } status = AJ_MarshalContainer(replyMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { goto Exit; } /* * Marshal property name */ AJ_InitArg(&key, AJ_ARG_STRING, 0, prop, pos); status = AJ_MarshalArg(replyMsg, &key); /* * Marshal property value as Variant setting up the signature */ if (status == AJ_OK) { char sig[16]; ComposeSignature(prop, prop[pos], sig, sizeof(sig)); status = AJ_MarshalVariant(replyMsg, sig); } /* * Marshal property value argument */ if ((status == AJ_OK) && (callback != NULL)) { status = callback(replyMsg, propId, context); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(replyMsg, &dict); } if (status != AJ_OK) { goto Exit; } } status = AJ_MarshalCloseContainer(replyMsg, &array); } Exit: return status; } AJ_Status AJ_IdentifyMessage(AJ_Message* msg) { AJ_Status status = AJ_ERR_NO_MATCH; uint8_t secure = FALSE; #ifndef NDEBUG if (MutterHook) { return AJ_OK; } #endif msg->msgId = AJ_INVALID_MSG_ID; if ((msg->hdr->msgType == AJ_MSG_METHOD_CALL) || (msg->hdr->msgType == AJ_MSG_SIGNAL)) { /* * Methods and signals */ status = AJ_LookupMessageId(msg, &secure); if ((status == AJ_OK) && secure && !(msg->hdr->flags & AJ_FLAG_ENCRYPTED)) { AJ_ErrPrintf(("AJ_IdentifyMessage(): AJ_ERR_SECURITY\n")); status = AJ_ERR_SECURITY; } /* * Generate an error response for an invalid method call rather than reporting an invalid * message id to the application. */ if ((status != AJ_OK) && (msg->hdr->msgType == AJ_MSG_METHOD_CALL) && !(msg->hdr->flags & AJ_FLAG_NO_REPLY_EXPECTED)) { AJ_Message reply; AJ_DumpMsg("Rejecting unidentified method call", msg, FALSE); AJ_MarshalStatusMsg(msg, &reply, status); status = AJ_DeliverMsg(&reply); /* * Cleanup the message we are ignoring. */ AJ_CloseMsg(msg); } } else { ReplyContext* repCtx = FindReplyContext(msg->replySerial); if (repCtx) { status = CheckReturnSignature(msg, repCtx->messageId); if (AJ_OK == status && (msg->hdr->flags & AJ_FLAG_ENCRYPTED)) { /* Make sure the authenticated sender was the expected recipient * of the method call. */ if (0 != strncmp(msg->sender, repCtx->uniqueName, AJ_MAX_NAME_SIZE)) { status = AJ_ERR_NO_MATCH; } } /* * Release the reply context */ repCtx->serial = 0; } } return status; } void AJ_RegisterObjects(const AJ_Object* localObjects, const AJ_Object* proxyObjects) { AJ_ASSERT(AJ_PRX_ID_FLAG < ArraySize(objectLists)); objectLists[AJ_APP_ID_FLAG] = localObjects; objectLists[AJ_PRX_ID_FLAG] = proxyObjects; } AJ_Status AJ_RegisterObjectsACL() { AJ_Status status; int i; for (i = 0; i < AJ_MAX_OBJECT_LISTS; i++) { status = AJ_AuthorisationRegister(objectLists[i], i); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_RegisterObjectsACL(): index(%d) %s\n", i, AJ_StatusText(status))); return status; } } return AJ_OK; } void AJ_RegisterDescriptionLanguages(const char* const* languages) { languageList = languages; } AJ_Status AJ_RegisterObjectListWithDescriptions(const AJ_Object* objList, uint8_t idx, AJ_DescriptionLookupFunc descLookup) { if (idx >= ArraySize(objectLists)) { return AJ_ERR_RANGE; } objectLists[idx] = objList; descriptionLookups[idx] = descLookup; return AJ_AuthorisationRegister(objList, idx); } AJ_Status AJ_RegisterObjectList(const AJ_Object* objList, uint8_t idx) { return AJ_RegisterObjectListWithDescriptions(objList, idx, NULL); } AJ_Status AJ_SetProxyObjectPath(AJ_Object* proxyObjects, uint32_t msgId, const char* objPath) { int i; uint8_t oIndex = (msgId >> 24); uint8_t pIndex = (msgId >> 16); if ((oIndex != AJ_PRX_ID_FLAG) || (proxyObjects != objectLists[oIndex])) { AJ_ErrPrintf(("AJ_SetProxyObjectPath(): AJ_ERR_UNKNOWN\n")); return AJ_ERR_UNKNOWN; } for (i = 0; i < pIndex; ++i) { if (!proxyObjects[i].interfaces) { AJ_ErrPrintf(("AJ_SetProxyObjectPath(): AJ_ERR_UNKNOWN\n")); return AJ_ERR_UNKNOWN; } } proxyObjects[pIndex].path = objPath; return AJ_OK; } AJ_Status AJ_AllocReplyContext(AJ_Message* msg, uint32_t timeout) { if (msg->hdr->flags & AJ_FLAG_NO_REPLY_EXPECTED) { /* * Not expecting a reply so don't allocate a reply context */ return AJ_OK; } else { ReplyContext* repCtx = FindReplyContext(0); AJ_ASSERT(msg->hdr->msgType == AJ_MSG_METHOD_CALL); if (repCtx) { AJ_Status status; const char* unique; repCtx->serial = msg->hdr->serialNum; repCtx->messageId = msg->msgId; repCtx->timeout = timeout ? timeout : AJ_DEFAULT_REPLY_TIMEOUT; AJ_InitTimer(&repCtx->callTime); status = AJ_GetRemoteUniqueName(msg->destination, &unique); if (AJ_OK == status) { strncpy(repCtx->uniqueName, unique, AJ_MAX_NAME_SIZE); repCtx->uniqueName[AJ_MAX_NAME_SIZE] = '\0'; } else { /* Lookup failed, but that doesn't matter for unencrypted messages */ repCtx->uniqueName[0] = '\0'; } return AJ_OK; } else { AJ_ErrPrintf(("AJ_AllocReplyContext(): Failed to allocate reply context. status=AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } } } void AJ_ReleaseReplyContext(AJ_Message* msg) { if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) { ReplyContext* repCtx = FindReplyContext(msg->hdr->serialNum); if (repCtx) { repCtx->serial = 0; } } } uint8_t AJ_TimedOutMethodCall(AJ_Message* msg) { ReplyContext* repCtx = replyContexts; size_t i; for (i = 0; i < ArraySize(replyContexts); ++i, ++repCtx) { if (repCtx->serial && (AJ_GetElapsedTime(&repCtx->callTime, TRUE) > repCtx->timeout)) { /* * Set the reply serial and message id for the timeout error */ msg->replySerial = repCtx->serial; msg->msgId = AJ_REPLY_ID(repCtx->messageId); /* * Release the reply context */ repCtx->serial = 0; return TRUE; } } return FALSE; } void AJ_ReleaseReplyContexts(void) { memset(replyContexts, 0, sizeof(replyContexts)); } AJ_Status AJ_SetObjectFlags(const char* objPath, uint8_t setFlags, uint8_t clearFlags) { AJ_Status status = AJ_ERR_NO_MATCH; AJ_Object* list = (AJ_Object*)objectLists[AJ_APP_ID_FLAG]; uint32_t secure = FALSE; if (list && objPath) { /* * Set flags on the object and all its children */ while (list->path) { if ((strcmp(objPath, list->path) == 0) || ChildPath(objPath, list->path, NULL)) { list->flags &= ~clearFlags; list->flags |= setFlags; AJ_InfoPrintf(("Setting flags for %s to 0x%02x\n", list->path, list->flags)); status = AJ_OK; if (AJ_OBJ_FLAG_SECURE & setFlags) { secure = TRUE; } } ++list; } } if (secure) { /* Object became secure, register with the ACL */ status = AJ_AuthorisationRegister(objectLists[AJ_APP_ID_FLAG], AJ_APP_ID_FLAG); } return status; } AJ_MemberType AJ_GetMemberType(uint32_t identifier, const char** member, uint8_t* isSecure) { const char* name; uint8_t secure; AJ_Status status = UnpackMsgId(identifier, NULL, NULL, &name, &secure); if (status == AJ_OK) { if (isSecure) { *isSecure = secure; } if (member) { *member = name; } return (AJ_MemberType) * (name - 1); } else { return AJ_INVALID_MEMBER; } } const AJ_Object* AJ_InitObjectIterator(AJ_ObjectIterator* iter, uint8_t inFlags, uint8_t exFlags) { iter->fin = inFlags; iter->fex = exFlags; iter->l = 0; iter->n = 0; return AJ_NextObject(iter); } const AJ_Object* AJ_NextObject(AJ_ObjectIterator* iter) { while (iter->l < ArraySize(objectLists)) { const AJ_Object* list = objectLists[iter->l]; if (list) { while (list[iter->n].path) { const AJ_Object* obj = &list[iter->n++]; /* Skip announcing the DeviceIcon interface unless it has been set explicitly */ if ((iter->l == AJ_BUS_ID_FLAG) && (0 == strcmp(obj->path, "/About/DeviceIcon"))) { if (!AJ_AboutHasIcon()) { continue; } } uint8_t objFlags = obj->flags; /* * For backwards compatibility the third entry is reserved for proxy objects. Going forward * proxy objects are identified in the object list by the AJ_OBJ_FLAG_IS_PROXY. */ if (iter->l == AJ_PRX_ID_FLAG) { objFlags &= AJ_OBJ_FLAG_IS_PROXY; } if ((objFlags & iter->fin || (objFlags == 0 && iter->fin == AJ_OBJ_FLAGS_ALL_INCLUDE_MASK)) && !(objFlags & iter->fex)) { return obj; } } } iter->n = 0; ++iter->l; } return NULL; } ajtcl-16.04/src/aj_link_timeout.c000066400000000000000000000120571271074662300167460ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE LINK_TIMEOUT #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgLINK_TIMEOUT = 0; #endif typedef struct _AJ_BusLinkWatcher { uint8_t numOfPingTimedOut; /**< Number of probe request packets already sent but unacked */ uint8_t linkTimerInited; /**< If timer linkTimer is inited */ uint8_t pingTimerInited; /**< If timer pingTimer is inited */ AJ_Time linkTimer; /**< Timer for tracking activities over the link to the daemon bus */ AJ_Time pingTimer; /**< Timer for tracking probe request packets */ } AJ_BusLinkWatcher; static uint32_t busLinkTimeout; /**< Timeout value for the link to the daemon bus */ static AJ_BusLinkWatcher busLinkWatcher; /**< Data structure that maintains information for tracking the link to the daemon bus */ AJ_Status AJ_SetBusLinkTimeout(AJ_BusAttachment* bus, uint32_t timeout) { if (!timeout) { return AJ_ERR_FAILURE; } timeout = (timeout > AJ_MIN_BUS_LINK_TIMEOUT) ? timeout : AJ_MIN_BUS_LINK_TIMEOUT; busLinkTimeout = timeout * 1000; return AJ_OK; } AJ_Status AJ_SetIdleTimeouts(AJ_BusAttachment* bus, uint32_t idleTo, uint32_t probeTo) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_SetIdleTimeouts(bus=0x%p, idleTo=%d, probeTo=%d)\n", bus, idleTo, probeTo)); status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_BUS_SET_IDLE_TIMEOUTS, AJ_BusDestination, 0, 0, AJ_METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "uu", idleTo, probeTo); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } void AJ_NotifyLinkActive() { memset(&busLinkWatcher, 0, sizeof(AJ_BusLinkWatcher)); } static AJ_Status AJ_SendLinkProbeReq(AJ_BusAttachment* bus) { AJ_Status status; AJ_Message msg; status = AJ_MarshalSignal(bus, &msg, AJ_SIGNAL_PROBE_REQ, AJ_BusDestination, 0, 0, 0); if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } AJ_Status AJ_BusLinkStateProc(AJ_BusAttachment* bus) { AJ_Status status = AJ_OK; if (bus->isProbeRequired && busLinkTimeout) { if (!busLinkWatcher.linkTimerInited) { busLinkWatcher.linkTimerInited = TRUE; AJ_InitTimer(&(busLinkWatcher.linkTimer)); } else { uint32_t eclipse = AJ_GetElapsedTime(&(busLinkWatcher.linkTimer), TRUE); if (eclipse >= busLinkTimeout) { if (!busLinkWatcher.pingTimerInited) { busLinkWatcher.pingTimerInited = TRUE; AJ_InitTimer(&(busLinkWatcher.pingTimer)); if (AJ_OK != AJ_SendLinkProbeReq(bus)) { AJ_ErrPrintf(("AJ_BusLinkStateProc(): AJ_SendLinkProbeReq() failure")); } } else { eclipse = AJ_GetElapsedTime(&(busLinkWatcher.pingTimer), TRUE); if (eclipse >= AJ_BUS_LINK_PING_TIMEOUT) { if (++busLinkWatcher.numOfPingTimedOut < AJ_MAX_LINK_PING_PACKETS) { AJ_InitTimer(&(busLinkWatcher.pingTimer)); if (AJ_OK != AJ_SendLinkProbeReq(bus)) { AJ_ErrPrintf(("AJ_BusLinkStateProc(): AJ_SendLinkProbeReq() failure")); } } else { AJ_ErrPrintf(("AJ_BusLinkStateProc(): AJ_ERR_LINK_TIMEOUT")); status = AJ_ERR_LINK_TIMEOUT; // stop sending probe messages until next link timeout event memset(&busLinkWatcher, 0, sizeof(AJ_BusLinkWatcher)); } } } } } } return status; } ajtcl-16.04/src/aj_msg.c000066400000000000000000002462711271074662300150400ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE MSG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AJ_ARDP #include #endif /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgMSG = 0; #endif #define AJ_STRUCT_CLOSE ')' #define AJ_DICT_ENTRY_CLOSE '}' /* * The size of the previous MAC for encrypted messages */ #define PREVIOUS_MAC_LENGTH 8 /* * The size of the MAC for encrypted messages */ #define MAC_LENGTH 16 /* * The size of the maximum MAC for encrypted messages */ #define MAX_MAC_LENGTH 16 /* * The minimum version with a full MAC length */ #define MIN_AUTH_FULL_MAC_LENGTH 0x0003 /* * The size of the previous nonce for encrypted messages */ #define PREVIOUS_NONCE_LENGTH 5 /* * The size of the MAC for encrypted messages */ #define NONCE_LENGTH 13 /* * The size of the maximum nonce for encrypted messages */ #define MAX_NONCE_LENGTH 13 /* * The minimum version with a full MAC length */ #define MIN_AUTH_FULL_NONCE_LENGTH 0x0003 /* * The minimum version with an extra nonce */ #define MIN_AUTH_EXTRA_NONCE 0x0003 /* * The fallback version */ #define MIN_AUTH_FALLBACK_VERSION 0x0002 /* * gcc defines __va_copy() other compilers allow direct assignent of a va_list */ #ifndef __va_copy #define __va_copy(a, b) (a) = (b) #endif /* * The types for each of the header fields. */ static const uint8_t TypeForHdr[] = { AJ_ARG_INVALID, AJ_ARG_OBJ_PATH, /* AJ_HDR_OBJ_PATH */ AJ_ARG_STRING, /* AJ_HDR_INTERFACE */ AJ_ARG_STRING, /* AJ_HDR_MEMBER */ AJ_ARG_STRING, /* AJ_HDR_ERROR_NAME */ AJ_ARG_UINT32, /* AJ_HDR_REPLY_SERIAL */ AJ_ARG_STRING, /* AJ_HDR_DESTINATION */ AJ_ARG_STRING, /* AJ_HDR_SENDER */ AJ_ARG_SIGNATURE, /* AJ_HDR_SIGNATURE */ AJ_ARG_UINT32, /* AJ_HDR_HANDLES */ AJ_ARG_INVALID, AJ_ARG_INVALID, AJ_ARG_INVALID, AJ_ARG_INVALID, AJ_ARG_INVALID, AJ_ARG_INVALID, AJ_ARG_UINT32, /* AJ_HDR_TIMESTAMP */ AJ_ARG_UINT16, /* AJ_HDR_TIME_TO_LIVE */ AJ_ARG_UINT32, /* AJ_HDR_COMPRESSION_TOKEN */ AJ_ARG_UINT32 /* AJ_HDR_SESSION_ID */ }; #define AJ_SCALAR 0x10 #define AJ_CONTAINER 0x20 #define AJ_STRING 0x40 #define AJ_VARIANT 0x80 /** * Characterizes the various argument types */ static const uint8_t TypeFlags[] = { 0x08 | AJ_CONTAINER, /* AJ_ARG_STRUCT '(' */ 0, /* ')' */ 0x04 | AJ_CONTAINER, /* AJ_ARG_ARRAY 'a' */ 0x04 | AJ_SCALAR, /* AJ_ARG_BOOLEAN 'b' */ 0, 0x08 | AJ_SCALAR, /* AJ_ARG_DOUBLE 'd' */ 0, 0, 0x01 | AJ_STRING, /* AJ_ARG_SIGNATURE 'g' */ 0x04 | AJ_SCALAR, /* AJ_ARG_HANDLE 'h' */ 0x04 | AJ_SCALAR, /* AJ_ARG_INT32 'i' */ 0, 0, 0, 0, 0x02 | AJ_SCALAR, /* AJ_ARG_INT16 'n' */ 0x04 | AJ_STRING, /* AJ_ARG_OBJ_PATH 'o' */ 0, 0x02 | AJ_SCALAR, /* AJ_ARG_UINT16 'q' */ 0, 0x04 | AJ_STRING, /* AJ_ARG_STRING 's' */ 0x08 | AJ_SCALAR, /* AJ_ARG_UINT64 't' */ 0x04 | AJ_SCALAR, /* AJ_ARG_UINT32 'u' */ 0x01 | AJ_VARIANT, /* AJ_ARG_VARIANT 'v' */ 0, 0x08 | AJ_SCALAR, /* AJ_ARG_INT64 'x' */ 0x01 | AJ_SCALAR, /* AJ_ARG_BYTE 'y' */ 0, 0x08 | AJ_CONTAINER, /* AJ_ARG_DICT_ENTRY '{' */ 0, 0 /* '}' */ }; /** * This macro makes sure that the signature contains valid characters * in the TypeFlags array. If the index passed is below ascii 'a' * or above ascii '}' and not ascii '(' or ')' then the signature is invalid. * Below is the macro broken into smaller chunks: * * ((t) == '(' || (t) == ')') ? (t) - '(' --> If the value is ) or (, get the value in TypeFlags * : * (((t) < 'a' || (t) > '}') ? '}' + 2 - 'a' --> The value is too high or too low, return TypeFlags[30] (0) * : * (t) + 2 - 'a' --> The value is valid, get the value in TypeFlags */ #define TYPE_FLAG(t) TypeFlags[((t) == '(' || (t) == ')') ? (t) - '(' : (((t) < 'a' || (t) > '}') ? '}' + 2 - 'a' : (t) + 2 - 'a') ] /** * Extract the alignment from the TypeFlags */ #define ALIGNMENT(t) (TYPE_FLAG(t) & 0xF) /* * For scalar types returns the size of the type */ #define SizeOfType(typeId) (TYPE_FLAG(typeId) & 0xF) /* * Returns true if the specified type is represented as a number */ #define IsScalarType(typeId) (TYPE_FLAG(typeId) & AJ_SCALAR) /* * A basic type is a scalar or one of the string types */ #define IsBasicType(typeId) (TYPE_FLAG(typeId) & (AJ_STRING | AJ_SCALAR)) int AJ_IsContainerType(char typeId) { return (TYPE_FLAG(typeId) & AJ_CONTAINER) != 0; } int AJ_IsScalarType(char typeId) { return IsScalarType(typeId) != 0; } int AJ_IsStringType(char typeId) { return (TYPE_FLAG(typeId) & AJ_STRING) != 0; } int AJ_IsBasicType(char typeId) { return IsBasicType(typeId) != 0; } size_t AJ_GetTypeSize(char typeId) { return SizeOfType(typeId); } /* * Checks that the current message is closed */ #ifndef NDEBUG static AJ_Message* currentMsg = NULL; #endif static void InitArg(AJ_Arg* arg, uint8_t typeId, const void* val) { if (arg) { arg->typeId = typeId; arg->flags = 0; arg->len = 0; arg->val.v_data = (void*)val; arg->sigPtr = NULL; arg->container = NULL; } } /* * Returns the number of bytes of padding to align the type */ static uint32_t PadForType(char typeId, AJ_IOBuffer* ioBuf) { uint8_t* base = (ioBuf->direction == AJ_IO_BUF_RX) ? ioBuf->readPtr : ioBuf->writePtr; uint32_t offset = (uint32_t)(base - ioBuf->bufStart); uint32_t alignment = ALIGNMENT(typeId); return (alignment - offset) & (alignment - 1); } #define ENDSWAP16(v) (((v) >> 8) | ((v) << 8)) #define ENDSWAP32(v) (((v) >> 24) | (((v) & 0xFF0000) >> 8) | (((v) & 0x00FF00) << 8) | ((v) << 24)) static void EndianSwap(AJ_Message* msg, uint8_t typeId, void* data, uint32_t num) { if (msg->hdr->endianess != HOST_ENDIANESS) { switch (SizeOfType(typeId)) { case 2: { uint16_t* p = (uint16_t*)data; while (num--) { uint16_t v = *p; *p++ = ENDSWAP16(v); } } break; case 4: { uint32_t* p = (uint32_t*)data; while (num--) { uint32_t v = *p; *p++ = ENDSWAP32(v); } } break; case 8: { uint32_t* p = (uint32_t*)data; while (num--) { uint32_t v = p[0]; uint32_t u = p[1]; *p++ = ENDSWAP32(u); *p++ = ENDSWAP32(v); } } break; } } } static uint32_t wrapped_offset(uint32_t a, uint32_t b) { uint32_t offset; if (b <= a) { offset = a - b; } else { offset = (0xFFFFFFFFUL - b) + a + 1; } return offset; } /* * Serial number on incoming methods and signals. */ AJ_Status AJ_CheckIncomingSerial(AJ_SerialNum* prev, uint32_t curr) { uint32_t offset; uint64_t mask; AJ_ASSERT(prev); if (curr == 0) { /* 0 is never a valid serial number */ AJ_WarnPrintf(("AJ_CheckIncomingSerial: 0 is invalid\n")); return AJ_ERR_INVALID; } if (prev->serial == 0) { offset = 0; prev->offset = 0; } else { offset = wrapped_offset(curr, prev->serial); if (0 == offset) { /* Current serial number matches highest recent serial */ AJ_WarnPrintf(("AJ_CheckIncomingSerial: Repeated serial %x %x %llx\n", curr, prev->serial, prev->offset)); return AJ_ERR_INVALID; } else if (0xFFFFFFC0UL < offset) { /* Current serial number is in the recent past. Check mask but don't move the window */ offset = (0xFFFFFFFFUL - offset) + 1; mask = ((uint64_t) 1) << offset; if (mask & prev->offset) { AJ_WarnPrintf(("AJ_CheckIncomingSerial: Repeated serial %x %x %llx\n", curr, prev->serial, prev->offset)); return AJ_ERR_INVALID; } /* Switch this mask on to mark this serial number as "seen" */ prev->offset |= mask; return AJ_OK; } else if (0x80000000UL <= offset) { /* Too far in the past */ AJ_WarnPrintf(("AJ_CheckIncomingSerial: Invalid serial %x %x %llx\n", curr, prev->serial, prev->offset)); return AJ_ERR_INVALID; } /* Moving window ahead. */ if (offset < 64) { prev->offset <<= offset; } else { prev->offset = 0; } } prev->serial = curr; prev->offset |= 1; return AJ_OK; } /* * Computes total size of a message - note header is padded to an 8 byte boundary */ static uint32_t MessageLen(AJ_Message* msg) { return sizeof(AJ_MsgHeader) + ((msg->hdr->headerLen + 7) & 0xFFFFFFF8) + msg->hdr->bodyLen; } static uint32_t MessageRequiresLongerCryptoValues(AJ_Message* msg, uint32_t versionCheck) { return ((versionCheck <= (msg->authVersion >> 16)) && // version !((msg->hdr->msgType == AJ_MSG_SIGNAL) && !msg->destination)); // rollback for multicast/broadcast } static uint32_t GetMACLength(AJ_Message* msg) { uint32_t macLen = MAC_LENGTH; if (!MessageRequiresLongerCryptoValues(msg, MIN_AUTH_FULL_MAC_LENGTH)) { macLen = PREVIOUS_MAC_LENGTH; } return macLen; } static uint32_t GetNonceLength(AJ_Message* msg) { uint32_t nonceLen = NONCE_LENGTH; if (!MessageRequiresLongerCryptoValues(msg, MIN_AUTH_FULL_NONCE_LENGTH)) { nonceLen = PREVIOUS_NONCE_LENGTH; } return nonceLen; } static AJ_Status InitNonce(AJ_Message* msg, uint8_t role, uint8_t* nonce, uint32_t nonceLen, uint8_t* extraNonce, uint32_t extraNonceLen) { uint32_t serial = msg->hdr->serialNum; nonce[0] = role; nonce[1] = (uint8_t)(serial >> 24); nonce[2] = (uint8_t)(serial >> 16); nonce[3] = (uint8_t)(serial >> 8); nonce[4] = (uint8_t)(serial); if (nonceLen < (PREVIOUS_NONCE_LENGTH + extraNonceLen)) { return AJ_ERR_SECURITY; } if (0 < extraNonceLen) { memcpy(&nonce[PREVIOUS_NONCE_LENGTH], extraNonce, extraNonceLen); AJ_InfoPrintf(("Nonce %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", nonce[0], nonce[1], nonce[2], nonce[3], nonce[4], nonce[5], nonce[6], nonce[7], nonce[8], nonce[9], nonce[10], nonce[11], nonce[12])); } else { AJ_InfoPrintf(("Nonce %02x%02x%02x%02x%02x\n", nonce[0], nonce[1], nonce[2], nonce[3], nonce[4])); } return AJ_OK; } static AJ_Status DecryptMessage(AJ_Message* msg) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; AJ_Status status; uint8_t key[16]; uint8_t nonce[MAX_NONCE_LENGTH]; uint8_t role = AJ_ROLE_KEY_UNDEFINED; uint32_t mlen = MessageLen(msg); uint32_t hLen = mlen - msg->hdr->bodyLen; uint32_t macLen; uint32_t nonceLen; uint32_t extraNonceLen; uint32_t cryptoValsLen; AJ_SerialNum* incoming; /* * Use the group key for multicast and broadcast signals the session key otherwise. */ if ((msg->hdr->msgType == AJ_MSG_SIGNAL) && !msg->destination) { status = AJ_GetGroupKey(msg->sender, key); msg->authVersion = MIN_AUTH_FALLBACK_VERSION; } else { status = AJ_GetSessionKey(msg->sender, key, &role, &msg->authVersion); /* * We use the oppsite role when decrypting. */ role ^= 3; if (AJ_OK == status) { status = AJ_GetSerialNumbers(msg->sender, &incoming); } } if (status != AJ_OK) { AJ_ErrPrintf(("DecryptMessage(): AJ_ERR_NO_MATCH\n")); } else { macLen = GetMACLength(msg); nonceLen = GetNonceLength(msg); extraNonceLen = nonceLen - PREVIOUS_NONCE_LENGTH; cryptoValsLen = macLen + extraNonceLen; AJ_InfoPrintf(("DecryptMessage(): \n")); InitNonce(msg, role, nonce, sizeof(nonce), ioBuf->bufStart + mlen - extraNonceLen, extraNonceLen); EndianSwap(msg, AJ_ARG_INT32, &msg->hdr->bodyLen, 3); status = AJ_Decrypt_CCM(key, ioBuf->bufStart, mlen - cryptoValsLen, hLen, macLen, nonce, nonceLen); EndianSwap(msg, AJ_ARG_INT32, &msg->hdr->bodyLen, 3); if (AJ_OK == status) { if ((AJ_MSG_METHOD_CALL == msg->hdr->msgType) || (AJ_MSG_SIGNAL == msg->hdr->msgType)) { /* Methods and signals */ status = AJ_CheckIncomingSerial(incoming, msg->hdr->serialNum); } } } AJ_MemZeroSecure(key, 16); return status; } static AJ_Status EncryptMessage(AJ_Message* msg) { AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; AJ_Status status; uint8_t key[16]; uint8_t nonce[MAX_NONCE_LENGTH]; uint8_t role = AJ_ROLE_KEY_UNDEFINED; uint32_t mlen = MessageLen(msg); uint32_t hlen = mlen - msg->hdr->bodyLen; uint32_t macLen; uint32_t nonceLen; uint32_t extraNonceLen; uint32_t cryptoValsLen; /* * Use the group key for multicast and broadcast signals the session key otherwise. */ if ((msg->hdr->msgType == AJ_MSG_SIGNAL) && !msg->destination) { status = AJ_GetGroupKey(NULL, key); if (AJ_OK == status) { msg->authVersion = MIN_AUTH_FALLBACK_VERSION; } } else { status = AJ_GetSessionKey(msg->destination, key, &role, &msg->authVersion); } if (AJ_OK == status) { macLen = GetMACLength(msg); nonceLen = GetNonceLength(msg); extraNonceLen = nonceLen - PREVIOUS_NONCE_LENGTH; cryptoValsLen = macLen + extraNonceLen; /* * Check there is room to append the MAC and Nonce */ if (AJ_IO_BUF_SPACE(ioBuf) < cryptoValsLen) { AJ_ErrPrintf(("EncryptMessage(): AJ_ERR_RESOURCES\n")); AJ_MemZeroSecure(key, 16); return AJ_ERR_RESOURCES; } msg->hdr->bodyLen += cryptoValsLen; ioBuf->writePtr += cryptoValsLen; if (MessageRequiresLongerCryptoValues(msg, MIN_AUTH_FULL_NONCE_LENGTH)) { AJ_RandBytes(ioBuf->bufStart + mlen + macLen, extraNonceLen); } AJ_InfoPrintf(("EncryptMessage(): ")); InitNonce(msg, role, nonce, sizeof(nonce), ioBuf->bufStart + mlen + macLen, extraNonceLen); status = AJ_Encrypt_CCM(key, ioBuf->bufStart, mlen, hlen, macLen, nonce, nonceLen); } else { AJ_ErrPrintf(("EncryptMesssage(): peer %s not authenticated", msg->destination)); /* Leave status from AJ_GetGroupKey/AJ_GetStatusKey unmodified. * Caller checks for AJ_ERR_NO_MATCH. */ } AJ_MemZeroSecure(key, 16); return status; } static AJ_Status AuthoriseOutgoingMessage(const AJ_Message* msg) { if ((msg->hdr->msgType != AJ_MSG_METHOD_CALL) && (msg->hdr->msgType != AJ_MSG_SIGNAL)) { return AJ_OK; } return AJ_AccessControlCheckMessage(msg, msg->destination, AJ_ACCESS_OUTGOING); } static AJ_Status AuthoriseIncomingMessage(const AJ_Message* msg) { if ((msg->hdr->msgType != AJ_MSG_METHOD_CALL) && (msg->hdr->msgType != AJ_MSG_SIGNAL)) { return AJ_OK; } return AJ_AccessControlCheckMessage(msg, msg->sender, AJ_ACCESS_INCOMING); } AJ_Status AJ_DeliverMsg(AJ_Message* msg) { AJ_Status status = AJ_OK; AJ_IOBuffer* ioBuf; if (!msg || !msg->bus) { return AJ_ERR_MARSHAL; } ioBuf = &msg->bus->sock.tx; /* * If the header has already been marshaled (due to partial delivery) it will be NULL */ if (msg->hdr) { /* * Write the final body length to the header */ msg->hdr->bodyLen = msg->bodyBytes; AJ_DumpMsg("SENDING", msg, TRUE); if (msg->hdr->flags & AJ_FLAG_ENCRYPTED) { status = AuthoriseOutgoingMessage(msg); if (AJ_OK == status) { status = EncryptMessage(msg); } if (AJ_ERR_NO_MATCH == status && AJ_MSG_ERROR == msg->hdr->msgType && msg->error == AJ_ErrSecurityViolation) { /* Allow an unencrypted reply in this specific key-not-found error case. */ status = AJ_OK; } } } else { /* * Check that the entire body was written */ if (msg->bodyBytes) { AJ_ErrPrintf(("AJ_DeliverMsg(): AJ_ERR_MARSHAL\n")); status = AJ_ERR_MARSHAL; } } if (status == AJ_OK) { //#pragma calls = AJ_Net_Send status = ioBuf->send(ioBuf); } memset(msg, 0, sizeof(AJ_Message)); return status; } /* * Make sure we have the required number of bytes in the I/O buffer */ static AJ_Status LoadBytes(AJ_IOBuffer* ioBuf, uint16_t numBytes, uint8_t pad, AJ_Message* msg) { AJ_Status status = AJ_OK; AJ_Time msgTimer; uint32_t* timeout = &msg->timeout; AJ_InitTimer(&msgTimer); numBytes += pad; /* * Needs to be enough headroom in the buffer to satisfy the read */ if (numBytes > (ioBuf->bufSize - AJ_IO_BUF_CONSUMED(ioBuf))) { AJ_ErrPrintf(("LoadBytes(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } AJ_InfoPrintf(("LoadBytes(): Start loop numBytes=%u, ioBufBytes=%u\n", numBytes, AJ_IO_BUF_AVAIL(ioBuf))); while (AJ_IO_BUF_AVAIL(ioBuf) < numBytes) { //#pragma calls = AJ_Net_Recv AJ_InfoPrintf(("LoadBytes(): numBytes=%u, ioBufBytes=%u\n", numBytes, AJ_IO_BUF_AVAIL(ioBuf))); status = ioBuf->recv(ioBuf, numBytes - AJ_IO_BUF_AVAIL(ioBuf), *timeout); if (status != AJ_OK) { /* * Ignore interrupted recv calls for now we can't handle resumption */ if (status == AJ_ERR_INTERRUPTED) { continue; } /* * Timeouts after we have started to unmarshal a message are a bad sign. */ if (status == AJ_ERR_TIMEOUT) { /* * Work around recv implementations that return too soon. */ uint32_t elapsed = AJ_GetElapsedTime(&msgTimer, FALSE); if (*timeout > elapsed) { *timeout -= elapsed; continue; } AJ_ErrPrintf(("LoadBytes(): AJ_ERR_READ\n")); status = AJ_ERR_READ; } else if (status == AJ_ERR_ARDP_RECV_EXPIRED) { AJ_ErrPrintf(("LoadBytes(): AJ_ERR_ARDP_RECV_EXPIRED -> AJ_ERR_UNMARSHAL\n")); msg->expired = TRUE; status = AJ_ERR_UNMARSHAL; } break; } } /* * Skip over pad bytes (The wire protocol says these should be zeroes). * Only skip if bytes have actually been read. */ if (status == AJ_OK) { ioBuf->readPtr += pad; } return status; } /* * Write bytes to an I/O buffer */ static AJ_Status WriteBytes(AJ_Message* msg, const void* data, size_t numBytes, size_t pad) { AJ_Status status = AJ_OK; AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; if (numBytes && !data) { AJ_ErrPrintf(("WriteBytes(): AJ_ERR_NULL\n")); return AJ_ERR_NULL; } while (numBytes + pad) { size_t canWrite = AJ_IO_BUF_SPACE(ioBuf); if ((numBytes + pad) > canWrite) { /* * If we have already marshaled the header we can write what we have in the buffer */ if (msg->hdr) { AJ_ErrPrintf(("WriteBytes(): AJ_ERR_RESOURCES\n")); status = AJ_ERR_RESOURCES; } else { //#pragma calls = AJ_Net_Send status = ioBuf->send(ioBuf); } if (status != AJ_OK) { break; } canWrite = AJ_IO_BUF_SPACE(ioBuf); } /* * Write pad bytes */ while (pad) { *ioBuf->writePtr++ = 0; --canWrite; --pad; } if (numBytes < canWrite) { canWrite = numBytes; } memcpy(ioBuf->writePtr, data, canWrite); data = (uint8_t*)data + canWrite; ioBuf->writePtr += canWrite; numBytes -= canWrite; } return status; } /* * Write pad bytes to an I/O buffer */ #define WritePad(msg, pad) WriteBytes(msg, NULL, 0, pad) AJ_Status AJ_CloseMsg(AJ_Message* msg) { AJ_Status status = AJ_OK; /* * This function is idempotent */ if (msg->bus) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; if (msg->expired == TRUE) { AJ_IO_BUF_RESET(ioBuf); } else { /* * Skip any unconsumed bytes */ while (msg->bodyBytes) { uint16_t sz = AJ_IO_BUF_AVAIL(ioBuf); sz = min(sz, msg->bodyBytes); if (!sz) { AJ_IO_BUF_RESET(ioBuf); sz = min(msg->bodyBytes, ioBuf->bufSize); } status = LoadBytes(ioBuf, sz, 0, msg); if (status != AJ_OK) { break; } msg->bodyBytes -= sz; ioBuf->readPtr += sz; } } memset(msg, 0, sizeof(AJ_Message)); #ifndef NDEBUG currentMsg = NULL; #endif } return status; } AJ_Status AJ_CloseMsgAndSaveReplyContext(AJ_Message* msg, AJ_MsgReplyContext* replyCtx) { if (replyCtx) { size_t len = strlen(msg->sender) + 1; if (len > sizeof(replyCtx->sender)) { AJ_CloseMsg(msg); return AJ_ERR_RESOURCES; } memcpy(replyCtx->sender, msg->sender, len + 1); replyCtx->bus = msg->bus; replyCtx->flags = msg->hdr->flags; replyCtx->serialNum = msg->hdr->serialNum; replyCtx->msgId = msg->msgId; replyCtx->sessionId = msg->sessionId; } return AJ_CloseMsg(msg); } /** * Get the length of the signature of the first complete type in sig */ static uint8_t CompleteTypeSigLen(const char* sig) { if (sig) { const char* start = sig; int32_t open = 0; while (*sig) { char typeId = *sig++; if (typeId == AJ_STRUCT_CLOSE || typeId == AJ_DICT_ENTRY_CLOSE) { if (!open) { return 0; } --open; if (!open) { break; } } else if (typeId == AJ_ARG_STRUCT || typeId == AJ_ARG_DICT_ENTRY) { ++open; } else if (!open && typeId != AJ_ARG_ARRAY) { break; } } return (uint8_t)(sig - start); } else { return 0; } } /* * Forward declaration */ static AJ_Status Unmarshal(AJ_Message* msg, const char** sig, AJ_Arg* arg); /* * Unmarshal a struct or dict entry argument. * * @param msg The message * @param sig The struct signature * @param arg Pointer to the arg structure to return */ static AJ_Status UnmarshalStruct(AJ_Message* msg, const char** sig, AJ_Arg* arg, uint8_t pad) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; AJ_Status status = LoadBytes(ioBuf, 0, pad, msg); arg->val.v_data = ioBuf->readPtr; arg->sigPtr = *sig; /* * Consume the entire struct signature. */ *sig -= 1; *sig += CompleteTypeSigLen(*sig); return status; } /* * Indicates that scalar arrays should be unmarshaled element by element. This value is set to TRUE * in AJ_UnmarshalContainer() for the duration of a single call to AJ_UnmarshalArgs(). If we ever * have to make the unmarshaler thread-safe this will need to be moved into AJ_Message. */ static uint8_t unmarshalScalarAsElement = FALSE; /* * Unmarshal an array argument. * * @param msg The message * @param sig The array element signature * @param arg Pointer to the structure to return the array */ static AJ_Status UnmarshalArray(AJ_Message* msg, const char** sig, AJ_Arg* arg, uint8_t pad) { AJ_Status status; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; char typeId = **sig; uint32_t numBytes; /* * Get the byte count for the array */ status = LoadBytes(ioBuf, 4, pad, msg); if (status != AJ_OK) { return status; } EndianSwap(msg, AJ_ARG_UINT32, ioBuf->readPtr, 1); numBytes = *((uint32_t*)ioBuf->readPtr); ioBuf->readPtr += 4; /* * We are already aligned on 4 byte boundary but there may be padding after the array length if * the array element types align on an 8 byte boundary. */ pad = PadForType(typeId, ioBuf); status = LoadBytes(ioBuf, numBytes, pad, msg); if (status != AJ_OK) { return status; } arg->val.v_data = ioBuf->readPtr; arg->sigPtr = *sig; arg->len = numBytes; if (!unmarshalScalarAsElement && IsScalarType(typeId)) { /* * For scalar types we do an inplace endian swap (if needed) and return a pointer into the read buffer. */ EndianSwap(msg, typeId, (void*)arg->val.v_data, arg->len); ioBuf->readPtr += numBytes; arg->typeId = typeId; arg->flags = AJ_ARRAY_FLAG; } else { /* * For all other types the elements must be individually unmarshalled. */ arg->typeId = AJ_ARG_ARRAY; } /* * Consume the array element signature. */ *sig += CompleteTypeSigLen(*sig); return status; } /* * Unmarshal a single argument */ static AJ_Status Unmarshal(AJ_Message* msg, const char** sig, AJ_Arg* arg) { AJ_Status status; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; char typeId; uint32_t pad; uint32_t sz; memset(arg, 0, sizeof(AJ_Arg)); if (!*sig || !**sig) { AJ_ErrPrintf(("Unmarshal(): AJ_ERR_END_OF_DATA\n")); return AJ_ERR_END_OF_DATA; } typeId = **sig; *sig += 1; pad = PadForType(typeId, ioBuf); if (IsScalarType(typeId)) { sz = SizeOfType(typeId); status = LoadBytes(ioBuf, sz, pad, msg); if (status != AJ_OK) { return status; } /* * For numeric types we just return a pointer into the buffer */ arg->typeId = typeId; arg->val.v_byte = ioBuf->readPtr; arg->len = 0; ioBuf->readPtr += sz; EndianSwap(msg, typeId, (void*)arg->val.v_byte, 1); } else if (TYPE_FLAG(typeId) & (AJ_STRING | AJ_VARIANT)) { /* * Length field for a signature is 1 byte, for regular strings its 4 bytes */ uint32_t lenSize = ALIGNMENT(typeId); /* * Read the string length. Note the length doesn't include the terminating NUL * so an empty string in encoded as two zero bytes. */ status = LoadBytes(ioBuf, lenSize, pad, msg); if (status != AJ_OK) { return status; } if (lenSize == 4) { EndianSwap(msg, AJ_ARG_UINT32, ioBuf->readPtr, 1); sz = *((uint32_t*)ioBuf->readPtr); } else { sz = (uint32_t)(*ioBuf->readPtr); } ioBuf->readPtr += lenSize; status = LoadBytes(ioBuf, sz + 1, 0, msg); if (status != AJ_OK) { return status; } arg->typeId = typeId; arg->len = sz; arg->val.v_string = (char*)ioBuf->readPtr; ioBuf->readPtr += sz + 1; /* * If unmarshalling a variant store offset to start of signature */ if (typeId == AJ_ARG_VARIANT) { msg->varOffset = (uint8_t)(sz + 1); } } else if (typeId == AJ_ARG_ARRAY) { status = UnmarshalArray(msg, sig, arg, pad); } else if ((typeId == AJ_ARG_STRUCT) || (typeId == AJ_ARG_DICT_ENTRY)) { arg->typeId = typeId; status = UnmarshalStruct(msg, sig, arg, pad); } else { AJ_ErrPrintf(("Unmarshal(): AJ_ERR_UNMARSHAL\n")); status = AJ_ERR_UNMARSHAL; } return status; } static const AJ_MsgHeader internalErrorHdr = { HOST_ENDIANESS, AJ_MSG_ERROR, 0, 0, 0, 1, 0 }; /* * Check that the required header fields are present for the message */ static AJ_Status ValidateHeader(const AJ_Message* msg) { AJ_Status status = AJ_ERR_UNMARSHAL; /* * Sender field is mandatory for all messages */ if ((msg->sender) && (msg->objPath)) { /* * Check required fields are present for each message type */ switch (msg->hdr->msgType) { case AJ_MSG_SIGNAL: if (msg->iface && msg->member) { status = AJ_OK; } break; case AJ_MSG_METHOD_CALL: if (msg->destination && msg->iface && msg->member) { status = AJ_OK; } break; case AJ_MSG_ERROR: if (msg->destination && msg->error && msg->replySerial) { status = AJ_OK; } else { AJ_ErrPrintf(("The connection was rejected by the routing node\n")); status = AJ_ERR_REJECTED; return status; } break; case AJ_MSG_METHOD_RET: if (msg->destination && msg->replySerial) { status = AJ_OK; } break; } } if (status != AJ_OK) { AJ_ErrPrintf(("Header does not contain the required fields for the message type\n")); } return status; } AJ_Status AJ_ResetArgs(AJ_Message* msg) { AJ_Status status = AJ_OK;; if (!msg->hdr) { return AJ_ERR_NULL; } /* * Nothing to do if the message has no arguments */ if (!msg->signature || (msg->signature[0] == '\0')) { return status; } /* * The arguments must fully unmarshaled before we can do a reset */ while (msg->bodyBytes && (status == AJ_OK)) { status = AJ_SkipArg(msg); } AJ_ASSERT(msg->sigOffset == strlen(msg->signature)); if (status == AJ_OK) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; size_t hdrSize = sizeof(AJ_MsgHeader) + msg->hdr->headerLen + HEADERPAD(msg->hdr->headerLen); /* * Args have already been converted to native endianess in place in the input buffer, this * prevents the unmarshaler from incorrectly undoing the conversion. */ msg->hdr->endianess = AJ_NATIVE_ENDIAN; /* * Reset the read pointer to the start of the argument list */ ioBuf->readPtr = ioBuf->bufStart + hdrSize; AJ_ASSERT(ioBuf->readPtr < ioBuf->writePtr); /* * Reset signature and body offsets */ msg->sigOffset = 0; msg->bodyBytes = msg->hdr->bodyLen; } return status; } /* * Process certain bus messages before they are handed to the application. * This prevents the application from swallowing a message. * * @param msg The message */ static AJ_Status ProcessBusMessages(AJ_Message* msg) { AJ_Status status = AJ_OK; int resetArgs = TRUE; /* Check for the special case messages */ switch (msg->msgId) { case AJ_REPLY_ID(AJ_METHOD_NAME_HAS_OWNER): AJ_InfoPrintf(("ProcessBusMessages(): AJ_REPLY_ID(AJ_METHOD_NAME_HAS_OWNER)\n")); status = AJ_GUID_HandleNameHasOwnerReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_ADD_MATCH): AJ_InfoPrintf(("ProcessBusMessages(): AJ_REPLY_ID(AJ_METHOD_ADD_MATCH)\n")); status = AJ_GUID_HandleAddMatchReply(msg); break; case AJ_REPLY_ID(AJ_METHOD_REMOVE_MATCH): AJ_InfoPrintf(("ProcessBusMessages(): AJ_REPLY_ID(AJ_METHOD_REMOVE_MATCH)\n")); status = AJ_GUID_HandleRemoveMatchReply(msg); break; case AJ_SIGNAL_NAME_OWNER_CHANGED: AJ_InfoPrintf(("ProcessBusMessages(): AJ_SIGNAL_NAME_OWNER_CHANGED)\n")); status = AJ_GUID_HandleNameOwnerChanged(msg); break; case AJ_SIGNAL_SESSION_JOINED: AJ_InfoPrintf(("ProcessBusMessages(): AJ_SIGNAL_SESSION_JOINED\n")); status = AJ_BusHandleSessionJoined(msg); break; case AJ_SIGNAL_SESSION_LOST: AJ_InfoPrintf(("ProcessBusMessages(): AJ_SIGNAL_SESSION_LOST\n")); status = AJ_BusHandleSessionLost(msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: AJ_InfoPrintf(("ProcessBusMessages(): AJ_SIGNAL_SESSION_LOST_WITH_REASON\n")); status = AJ_BusHandleSessionLostWithReason(msg); break; case AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION): AJ_InfoPrintf(("ProcessBusMessages(): AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION)\n")); status = AJ_BusHandleJoinSessionReply(msg); break; default: resetArgs = FALSE; break; } if (resetArgs && status == AJ_OK) { /* * Reset the message so the application can handle it too. Don't * overwrite any error detected during the handling of messages above. */ status = AJ_ResetArgs(msg); } return status; } AJ_Status AJ_UnmarshalMsg(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t timeout) { AJ_Status status; AJ_IOBuffer* ioBuf = &bus->sock.rx; void* hdrRaw = NULL; uint8_t* endOfHeader; uint32_t hdrPad; AJ_Time msgTimer; AJ_InfoPrintf(("AJ_UnmarshalMsg()\n")); AJ_InitTimer(&msgTimer); /* * Clear message then set the bus and overall timeout */ memset(msg, 0, sizeof(AJ_Message)); msg->msgId = AJ_INVALID_MSG_ID; msg->bus = bus; msg->timeout = timeout; /* * Check that the read and write pointers are within the bounds of the recv buffer */ if ((ioBuf->readPtr < ioBuf->bufStart) || (ioBuf->readPtr > (ioBuf->bufStart + ioBuf->bufSize)) || (ioBuf->writePtr < ioBuf->readPtr) || (ioBuf->writePtr > (ioBuf->bufStart + ioBuf->bufSize))) { AJ_ErrPrintf(("AJ_UnmarshalMsg(): recv buffer pointer out of bounds: AJ_ERR_IO_BUFFER\n")); return AJ_ERR_READ; //Buffer pointer is out of bounds, this is unrecoverable } /* * Move any unconsumed data to the start of the I/O buffer */ AJ_IOBufRebase(ioBuf, 0); /* * Load the message header */ AJ_InfoPrintf(("AJ_UnmarshalMsg(): start loop ioBufBytes=%u\n", AJ_IO_BUF_AVAIL(ioBuf))); while (AJ_IO_BUF_AVAIL(ioBuf) < sizeof(AJ_MsgHeader)) { //#pragma calls = AJ_Net_Recv AJ_InfoPrintf(("AJ_UnmarshalMsg(): ioBufBytes=%u\n", AJ_IO_BUF_AVAIL(ioBuf))); status = ioBuf->recv(ioBuf, sizeof(AJ_MsgHeader) - AJ_IO_BUF_AVAIL(ioBuf), msg->timeout); if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { /* * Work around recv implementations that return too soon. */ uint32_t elapsed = AJ_GetElapsedTime(&msgTimer, FALSE); if (msg->timeout > elapsed) { msg->timeout -= elapsed; continue; } } /* * If there were no messages to receive check if we have any methods call that have * timed-out and if so generate an internal error message to allow the application to * proceed. */ if ((status == AJ_ERR_TIMEOUT) && AJ_TimedOutMethodCall(msg)) { msg->hdr = (AJ_MsgHeader*)&internalErrorHdr; msg->error = AJ_ErrTimeout; msg->sender = AJ_GetUniqueName(msg->bus); msg->destination = msg->sender; status = AJ_OK; } else if (status == AJ_ERR_ARDP_RECV_EXPIRED) { status = AJ_ERR_UNMARSHAL; msg->expired = TRUE; } return status; } } /* * Header was unmarshalled directly into the rx buffer */ msg->hdr = (AJ_MsgHeader*)ioBuf->bufStart; AJ_ASSERT(msg->hdr); /* Save raw header before endian swaps */ memcpy(&msg->raw, msg->hdr, sizeof (AJ_MsgHeader)); ioBuf->readPtr += sizeof(AJ_MsgHeader); /* * Quick sanity check on the header - unrecoverable error if this check fails */ if ((msg->hdr->endianess != AJ_LITTLE_ENDIAN) && (msg->hdr->endianess != AJ_BIG_ENDIAN)) { AJ_ErrPrintf(("AJ_UnmarshalMsg(): AJ_ERR_READ\n")); return AJ_ERR_READ; } /* * Endian swap header info - conveniently they are contiguous in the header */ EndianSwap(msg, AJ_ARG_INT32, &msg->hdr->bodyLen, 3); msg->bodyBytes = msg->hdr->bodyLen; /* * The header is null-padded to an 8-byte boundary */ hdrPad = HEADERPAD(msg->hdr->headerLen); /* * Make sure the header (plus pad) isn't going to overrun the buffer * and that the total header length doesn't overflow. */ if ((msg->hdr->headerLen + hdrPad) > (ioBuf->bufSize - sizeof(AJ_MsgHeader))) { AJ_ErrPrintf(("AJ_UnmarshalMsg(): Header was too large: AJ_ERR_HDR_CORRUPT\n")); return AJ_ERR_READ; //Unrecoverable state, return read error } /* * Load the header */ status = LoadBytes(ioBuf, msg->hdr->headerLen + hdrPad, 0, msg); if (status != AJ_OK) { return status; } #ifndef NDEBUG /* * Check that messages are getting closed */ AJ_ASSERT(!currentMsg); currentMsg = msg; #endif /* * If the endianess of the message is different than the local host * endianness we need to copy the header bytes before we unmarshal the header and swizzle all * the integers. */ if ((msg->hdr->endianess != HOST_ENDIANESS)) { hdrRaw = AJ_Malloc(msg->hdr->headerLen); if (hdrRaw) { memcpy(hdrRaw, ioBuf->readPtr, msg->hdr->headerLen); } } /* * Assume an empty signature */ msg->signature = ""; /* * We have the header in the buffer now we can unmarshal the header fields */ endOfHeader = ioBuf->bufStart + sizeof(AJ_MsgHeader) + msg->hdr->headerLen; while (ioBuf->readPtr < endOfHeader) { const char* fieldSig; uint8_t fieldId; AJ_Arg hdrVal; /* * Custom unmarshal the header field - signature is "(yv)" so starts off with STRUCT aligment. */ status = LoadBytes(ioBuf, 4, PadForType(AJ_ARG_STRUCT, ioBuf), msg); if (status != AJ_OK) { break; } fieldId = ioBuf->readPtr[0]; fieldSig = (const char*)&ioBuf->readPtr[2]; ioBuf->readPtr += 4; /* * Now unmarshal the field value */ status = Unmarshal(msg, &fieldSig, &hdrVal); if (status != AJ_OK) { break; } /* * Check the field has the type we expect - we ignore fields we don't know */ if ((fieldId <= AJ_HDR_SESSION_ID) && (TypeForHdr[fieldId] != hdrVal.typeId)) { AJ_ErrPrintf(("AJ_UnmarshalMsg(): AJ_ERR_UNMARSHAL\n")); status = AJ_ERR_UNMARSHAL; break; } /* * Set the field value in the message */ switch (fieldId) { case AJ_HDR_OBJ_PATH: msg->objPath = hdrVal.val.v_objPath; break; case AJ_HDR_INTERFACE: msg->iface = hdrVal.val.v_string; break; case AJ_HDR_MEMBER: msg->member = hdrVal.val.v_string; break; case AJ_HDR_ERROR_NAME: msg->error = hdrVal.val.v_string; break; case AJ_HDR_REPLY_SERIAL: msg->replySerial = *(hdrVal.val.v_uint32); break; case AJ_HDR_DESTINATION: msg->destination = hdrVal.val.v_string; break; case AJ_HDR_SENDER: msg->sender = hdrVal.val.v_string; break; case AJ_HDR_SIGNATURE: msg->signature = hdrVal.val.v_signature; break; case AJ_HDR_TIMESTAMP: msg->timestamp = *(hdrVal.val.v_uint32); break; case AJ_HDR_TIME_TO_LIVE: msg->ttl = *(hdrVal.val.v_uint32); break; case AJ_HDR_SESSION_ID: msg->sessionId = *(hdrVal.val.v_uint32); break; case AJ_HDR_COMPRESSION_TOKEN: AJ_ErrPrintf(("Compressed headers not currently handled\n")); status = AJ_ERR_UNMARSHAL; break; case AJ_HDR_HANDLES: default: /* Ignored */ break; } } /* * Check that the required header fields are present */ if (status == AJ_OK) { status = ValidateHeader(msg); } /* * If we copied the raw header earlier we copy it back now. * This only happens if endianness of the message is different from the local host's endianness. */ if (hdrRaw) { memcpy(ioBuf->bufStart + sizeof(AJ_MsgHeader), hdrRaw, msg->hdr->headerLen); AJ_Free(hdrRaw); hdrRaw = NULL; } if (ioBuf->readPtr != endOfHeader) { status = AJ_ERR_HDR_CORRUPT; } if (status == AJ_OK) { AJ_ASSERT(ioBuf->readPtr == endOfHeader); /* * Consume the header pad bytes. */ ioBuf->readPtr += hdrPad; /* * If the message is encrypted load the entire message body and decrypt it. */ if (msg->hdr->flags & AJ_FLAG_ENCRYPTED) { status = LoadBytes(ioBuf, msg->hdr->bodyLen, 0, msg); if (status == AJ_OK) { status = DecryptMessage(msg); /* * If session key missing, reply with error message. * If decryption failed, silently ignore message below. */ if ((AJ_ERR_NO_MATCH == status) && (msg->hdr->msgType == AJ_MSG_METHOD_CALL) && !(msg->hdr->flags & AJ_FLAG_NO_REPLY_EXPECTED)) { AJ_Message reply; AJ_Status replyStatus; status = AJ_ERR_SECURITY; replyStatus = AJ_MarshalStatusMsg(msg, &reply, status); if (AJ_OK == replyStatus) { replyStatus = AJ_DeliverMsg(&reply); } if (AJ_OK != replyStatus) { /* Fail to send an error reply, log and continue */ AJ_InfoPrintf(("AJ_UnmarshalMsg(): %s\n", AJ_StatusText(replyStatus))); } } } } /* * Toggle the AUTO_START flag so in the API no flags == 0 * * Note we must do this after decrypting the message or message authentication will fail. */ msg->hdr->flags ^= AJ_FLAG_AUTO_START; /* * If the message looks good try to identify it. */ if (status == AJ_OK) { status = AJ_IdentifyMessage(msg); } /* * If this is the Peer.Authentication interface, * load the entire message into the buffer. * Only do this if it wasn't done above (encrypted message). */ if ((AJ_BUS_MESSAGE_ID(0xFF, 0xFF, 0) & msg->msgId) == AJ_PEER_AUTHENTICATION_IFN) { if (!(msg->hdr->flags & AJ_FLAG_ENCRYPTED)) { status = LoadBytes(ioBuf, msg->hdr->bodyLen, 0, msg); } } /* * Check incoming policy */ if ((AJ_OK == status) && (msg->hdr->flags & AJ_FLAG_ENCRYPTED)) { status = AuthoriseIncomingMessage(msg); if ((AJ_OK != status) && (msg->hdr->msgType == AJ_MSG_METHOD_CALL) && !(msg->hdr->flags & AJ_FLAG_NO_REPLY_EXPECTED)) { AJ_Message reply; AJ_Status replyStatus; replyStatus = AJ_MarshalStatusMsg(msg, &reply, status); if (AJ_OK == replyStatus) { replyStatus = AJ_DeliverMsg(&reply); } if (AJ_OK != replyStatus) { /* Fail to send an error reply, log and continue */ AJ_InfoPrintf(("AJ_UnmarshalMsg(): %s\n", AJ_StatusText(replyStatus))); } } } } else { /* * Consume entire header */ ioBuf->readPtr = endOfHeader + hdrPad; } if (status == AJ_OK) { AJ_DumpMsg("RECEIVED", msg, FALSE); } else { /* * Silently discard message unless in debug mode */ AJ_WarnPrintf(("Discarding unknown message %s\n", AJ_StatusText(status))); AJ_DumpMsg("DISCARDING", msg, FALSE); AJ_CloseMsg(msg); } if (status == AJ_OK) { status = ProcessBusMessages(msg); } return status; } AJ_Status AJ_SkipArg(AJ_Message* msg) { AJ_Status status; AJ_Arg skippy; /* * Variants must be skipped atomically */ if (msg->varOffset) { return AJ_ERR_UNEXPECTED; } status = AJ_UnmarshalArg(msg, &skippy); if (status != AJ_OK) { return status; } if (msg->varOffset) { status = AJ_UnmarshalArg(msg, &skippy); } if (TYPE_FLAG(skippy.typeId) == 0) { return AJ_ERR_SIGNATURE; } /* * If skipping a container skip the contents */ if (TYPE_FLAG(skippy.typeId) & AJ_CONTAINER) { skippy.container = msg->outer; msg->outer = &skippy; if (skippy.typeId == AJ_ARG_ARRAY) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; /* * Just consume the array bytes */ status = LoadBytes(ioBuf, skippy.len, 0, msg); if (status == AJ_OK) { ioBuf->readPtr += skippy.len; msg->bodyBytes -= skippy.len; } } else { /* * Skip the individual elements */ char closeType = (skippy.typeId == AJ_ARG_STRUCT) ? AJ_STRUCT_CLOSE : AJ_DICT_ENTRY_CLOSE; while (*skippy.sigPtr != closeType) { status = AJ_SkipArg(msg); if (status != AJ_OK) { break; } } } if (status == AJ_OK) { status = AJ_UnmarshalCloseContainer(msg, &skippy); } msg->outer = skippy.container; } return status; } const char* AJ_NextArgSig(AJ_Message* msg) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; AJ_Arg* container = msg->outer; const char* sig; if (msg->varOffset) { /* * Variant - get the signature from the I/O buffer */ sig = (const char*)(ioBuf->readPtr - msg->varOffset); } else if (container) { /* * Component of a container - use the container's signature */ sig = container->sigPtr; } else { /* * Everything else - use the message signature */ sig = msg->signature + msg->sigOffset; } return sig; } AJ_Status AJ_UnmarshalArg(AJ_Message* msg, AJ_Arg* arg) { AJ_Status status; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; AJ_Arg* container = msg->outer; uint8_t* argStart = ioBuf->readPtr; size_t consumed; const char* sig = AJ_NextArgSig(msg); if (msg->varOffset) { msg->varOffset = 0; status = Unmarshal(msg, &sig, arg); } else if (container) { if (container->typeId == AJ_ARG_ARRAY) { size_t len = (uint16_t)(ioBuf->readPtr - (uint8_t*)container->val.v_data); /* * Return an error status if there are no more array elements. */ if (len == container->len) { memset(arg, 0, sizeof(AJ_Arg)); AJ_InfoPrintf(("AJ_UnmarshalMsg(): AJ_ERR_NO_MORE\n")); status = AJ_ERR_NO_MORE; } else { status = Unmarshal(msg, &sig, arg); } } else { status = Unmarshal(msg, &sig, arg); container->sigPtr = sig; } } else { /* * The signature representing the message body does not match the number of body bytes */ if (!msg->bodyBytes) { AJ_ErrPrintf(("AJ_UnmarshalArg(): Message body length is incorrect, status = AJ_ERR_UNMARSHAL\n")); status = AJ_ERR_UNMARSHAL; } else { status = Unmarshal(msg, &sig, arg); msg->sigOffset = (uint8_t)(sig - msg->signature); } } consumed = (ioBuf->readPtr - argStart); if (consumed > msg->bodyBytes) { /* * Unrecoverable */ AJ_ErrPrintf(("AJ_UnmarshalArg(): AJ_ERR_READ\n")); status = AJ_ERR_READ; } else { msg->bodyBytes -= (uint16_t)consumed; } return status; } static AJ_Status VUnmarshalArgs(AJ_Message* msg, const char** sig, va_list* argpp) { AJ_Status status = AJ_OK; AJ_Arg arg; AJ_Arg container; va_list argp; __va_copy(argp, *argpp); container.typeId = AJ_ARG_INVALID; while (**sig) { uint8_t typeId = (uint8_t)*((*sig)++); void* val; if (!IsBasicType(typeId)) { if ((typeId == AJ_ARG_STRUCT) || (typeId == AJ_ARG_DICT_ENTRY)) { /* * This function supports unmarshaling of a single level structs. */ status = AJ_UnmarshalContainer(msg, &container, typeId); if (status != AJ_OK) { break; } status = VUnmarshalArgs(msg, sig, &argp); /* * Upon successful return from a nested call, continue from * where the inner call advanced in the signature. */ if (status == AJ_OK) { char tId = *(*sig - 1); if ((tId == AJ_STRUCT_CLOSE) || (tId == AJ_DICT_ENTRY_CLOSE)) { status = AJ_UnmarshalCloseContainer(msg, &container); if (status != AJ_OK) { break; } } else { status = AJ_ERR_UNMARSHAL; break; } continue; } else { break; } continue; } if ((typeId == AJ_ARG_ARRAY) && IsBasicType(**sig)) { const void** ptr = va_arg(argp, const void**); size_t* len = va_arg(argp, size_t*); (*sig)++; status = AJ_UnmarshalArg(msg, &arg); if (status != AJ_OK) { break; } *ptr = arg.val.v_data; *len = arg.len; continue; } if ((typeId == AJ_STRUCT_CLOSE) || (typeId == AJ_DICT_ENTRY_CLOSE)) { break; } if (typeId == AJ_ARG_VARIANT) { const char* vsigExpect = va_arg(argp, const char*); const char* vsig; status = AJ_UnmarshalVariant(msg, &vsig); if (status == AJ_OK) { if (strcmp(vsig, vsigExpect) != 0) { status = AJ_ERR_SIGNATURE; break; } status = VUnmarshalArgs(msg, &vsig, &argp); } if (status == AJ_OK) { continue; } } AJ_ErrPrintf(("AJ_UnmarshalArgs(): AJ_ERR_UNEXPECTED\n")); status = AJ_ERR_UNEXPECTED; break; } status = AJ_UnmarshalArg(msg, &arg); if (status != AJ_OK) { break; } if (arg.typeId != typeId) { AJ_ErrPrintf(("AJ_UnmarshalArgs(): AJ_ERR_UNMARSHAL\n")); status = AJ_ERR_UNMARSHAL; break; } val = va_arg(argp, void*); if (IsScalarType(typeId)) { switch (SizeOfType(typeId)) { case 1: *((uint8_t*)val) = *arg.val.v_byte; break; case 2: *((uint16_t*)val) = *arg.val.v_uint16; break; case 4: *((uint32_t*)val) = *arg.val.v_uint32; break; case 8: *((uint64_t*)val) = *arg.val.v_uint64; break; } } else { *((const char**)val) = arg.val.v_string; } } __va_copy(*argpp, argp); return status; } AJ_Status AJ_UnmarshalArgs(AJ_Message* msg, const char* sig, ...) { AJ_Status status; va_list argp; va_start(argp, sig); status = VUnmarshalArgs(msg, &sig, &argp); va_end(argp); return status; } AJ_Status AJ_UnmarshalRaw(AJ_Message* msg, const void** data, size_t len, size_t* actual) { AJ_Status status; size_t sz; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; size_t hdrSize = sizeof(AJ_MsgHeader) + msg->hdr->headerLen + HEADERPAD(msg->hdr->headerLen); /* * A sig offset of 0xFF indicates we are already doing raw unnmarshaling */ if (msg->sigOffset != 0xFF) { uint8_t typeId = msg->signature[msg->sigOffset]; uint8_t pad; /* * There must be arguments to unmarshal */ if (!typeId) { AJ_ErrPrintf(("AJ_UnmarshalRaw(): AJ_ERR_SIGNATURE\n")); return AJ_ERR_SIGNATURE; } /* * There may be padding before the argument */ pad = PadForType(typeId, ioBuf); if (pad > msg->bodyBytes) { AJ_ErrPrintf(("AJ_UnmarshalRaw(): AJ_ERR_UNMARSHAL\n")); return AJ_ERR_UNMARSHAL; } status = LoadBytes(ioBuf, 0, pad, msg); if (status != AJ_OK) { return status; } msg->bodyBytes -= pad; /* * Standard signature matching is now meaningless */ msg->signature = ""; /* * Flag we are in raw-unmarshal mode */ msg->sigOffset = 0xFF; } /* * Return an error if caller is attempting read off the end of the body */ if (len > msg->bodyBytes) { AJ_ErrPrintf(("AJ_UnmarshalRaw(): AJ_ERR_UNMARSHAL\n")); return AJ_ERR_UNMARSHAL; } /* * We want to return the requested data as contiguous bytes if possible */ sz = AJ_IO_BUF_AVAIL(ioBuf); if (sz < len) { AJ_IOBufRebase(ioBuf, hdrSize); } /* * If we try to load more than the available space we will get an error */ len = min(len, AJ_IO_BUF_SPACE(ioBuf)); status = LoadBytes(ioBuf, (uint16_t)len, 0, msg); if (status == AJ_OK) { sz = AJ_IO_BUF_AVAIL(ioBuf); if (sz < len) { len = sz; } *data = ioBuf->readPtr; *actual = len; ioBuf->readPtr += len; msg->bodyBytes -= (uint16_t)len; } return status; } AJ_Status AJ_UnmarshalContainer(AJ_Message* msg, AJ_Arg* arg, uint8_t typeId) { AJ_Status status = AJ_ERR_UNMARSHAL; if ((TYPE_FLAG(typeId) & AJ_CONTAINER)) { unmarshalScalarAsElement = TRUE; status = AJ_UnmarshalArg(msg, arg); unmarshalScalarAsElement = FALSE; if (status == AJ_OK) { if (arg->typeId == typeId) { arg->container = msg->outer; msg->outer = arg; } else { AJ_ErrPrintf(("AJ_UnmarshalContainer(): AJ_ERR_UNMARSHAL\n")); status = AJ_ERR_UNMARSHAL; } } } return status; } AJ_Status AJ_UnmarshalCloseContainer(AJ_Message* msg, AJ_Arg* arg) { AJ_ASSERT(TYPE_FLAG(arg->typeId) & AJ_CONTAINER); AJ_ASSERT(msg->outer == arg); msg->outer = arg->container; if (arg->typeId == AJ_ARG_ARRAY) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; /* * Check that all the array elements have been unmarshaled */ size_t len = (uint16_t)(ioBuf->readPtr - (uint8_t*)arg->val.v_data); if (len != arg->len) { AJ_ErrPrintf(("AJ_UnmarshalCloseContainer(): AJ_ERR_UNMARSHAL\n")); return AJ_ERR_UNMARSHAL; } } else { /* * Check that all of the struct elements have been unmarshaled */ if ((arg->typeId == AJ_ARG_STRUCT) && (*arg->sigPtr != AJ_STRUCT_CLOSE)) { AJ_ErrPrintf(("AJ_UnmarshalCloseContainer(): AJ_ERR_SIGNATURE\n")); return AJ_ERR_SIGNATURE; } if ((arg->typeId == AJ_ARG_DICT_ENTRY) && (*arg->sigPtr != AJ_DICT_ENTRY_CLOSE)) { AJ_ErrPrintf(("AJ_UnmarshalCloseContainer(): AJ_ERR_SIGNATURE\n")); return AJ_ERR_SIGNATURE; } } return AJ_OK; } AJ_Status AJ_UnmarshalVariant(AJ_Message* msg, const char** sig) { AJ_Arg arg; AJ_Status status = AJ_UnmarshalArg(msg, &arg); if (status == AJ_OK) { if (sig) { *sig = arg.val.v_string; } } return status; } /* * Forward declaration */ static AJ_Status Marshal(AJ_Message* msg, const char** sig, AJ_Arg* arg); static AJ_Status MarshalContainer(AJ_Message* msg, const char** sig, AJ_Arg* arg, uint8_t pad) { AJ_Status status; AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; *sig -= 1; arg->sigPtr = *sig + 1; if (**sig == AJ_ARG_ARRAY) { /* * Reserve space for the length and save a pointer to it */ status = WriteBytes(msg, NULL, 0, pad + 4); arg->val.v_data = ioBuf->writePtr - 4; /* * Might need to pad if the elements align on an 8 byte boundary */ if (status == AJ_OK) { status = WritePad(msg, PadForType(arg->sigPtr[0], ioBuf)); } } else { status = WritePad(msg, pad); } /* * Consume container signature */ *sig += CompleteTypeSigLen(*sig); return status; } static AJ_Status Marshal(AJ_Message* msg, const char** sig, AJ_Arg* arg) { AJ_Status status = AJ_OK; AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; char typeId = **sig; uint32_t pad = PadForType(typeId, ioBuf); size_t sz; if (!arg) { AJ_ErrPrintf(("Marshal(): AJ_ERR_NULL\n")); return AJ_ERR_NULL; } *sig += 1; if (IsScalarType(arg->typeId)) { if (arg->flags & AJ_ARRAY_FLAG) { uint32_t szu32; if ((typeId != AJ_ARG_ARRAY) || (**sig != arg->typeId)) { AJ_ErrPrintf(("Marshal(): AJ_ERR_MARSHAL\n")); return AJ_ERR_MARSHAL; } *sig += 1; sz = arg->len; szu32 = (uint32_t)sz; status = WriteBytes(msg, &szu32, 4, pad); if (status == AJ_OK) { /* * May need to pad if the elements required 8 byte alignment */ pad = PadForType(arg->typeId, ioBuf); } } else { if (typeId != arg->typeId) { AJ_ErrPrintf(("Marshal(): AJ_ERR_MARSHAL\n")); return AJ_ERR_MARSHAL; } sz = SizeOfType(typeId); } if (status == AJ_OK) { status = WriteBytes(msg, arg->val.v_data, sz, pad); } } else if (TYPE_FLAG(typeId) & (AJ_STRING | AJ_VARIANT)) { if (typeId != arg->typeId) { AJ_ErrPrintf(("Marshal(): AJ_ERR_MARSHAL\n")); return AJ_ERR_MARSHAL; } sz = arg->len ? arg->len : strlen(arg->val.v_string); /* * Length field for a signature is 1 byte, for regular strings its 4 bytes */ if (ALIGNMENT(typeId) == 1) { uint8_t szu8 = (uint8_t)sz; if (sz > 255) { return AJ_ERR_MARSHAL; } status = WriteBytes(msg, &szu8, 1, pad); } else { uint32_t szu32 = (uint32_t)sz; status = WriteBytes(msg, &szu32, 4, pad); } if (status == AJ_OK) { status = WriteBytes(msg, arg->val.v_string, sz, 0); /* * String must be NUL terminated on the wire */ if (status == AJ_OK) { status = WritePad(msg, 1); } /* * If marshalling a variant store offset to start of signature */ if (typeId == AJ_ARG_VARIANT) { msg->varOffset = (uint8_t)(sz + 1); } } } else if (TYPE_FLAG(typeId) & AJ_CONTAINER) { if (typeId != arg->typeId) { AJ_ErrPrintf(("Marshal(): AJ_ERR_MARSHAL\n")); return AJ_ERR_MARSHAL; } status = MarshalContainer(msg, sig, arg, pad); } else { AJ_ErrPrintf(("Marshal(): AJ_ERR_MARSHAL\n")); return AJ_ERR_MARSHAL; } return status; } static AJ_Status MarshalMsg(AJ_Message* msg, uint8_t msgType, uint32_t msgId, uint8_t flags) { AJ_Status status = AJ_OK; AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; uint8_t fieldId; uint8_t secure = FALSE; if (!ioBuf->bufStart) { AJ_ErrPrintf(("MarshalMsg(): ioBuf has not been initialized\n")); return AJ_ERR_IO_BUFFER; } #ifdef AJ_ARDP status = AJ_ARDP_StartMsgSend(msg->ttl); #endif /* * Use the msgId to lookup information in the object and interface descriptions to * initialize the message header fields. */ status = AJ_InitMessageFromMsgId(msg, msgId, msgType, &secure); if (status != AJ_OK) { AJ_ErrPrintf(("MarshalMsg(): status=%s\n", AJ_StatusText(status))); return status; } AJ_IO_BUF_RESET(ioBuf); msg->hdr = (AJ_MsgHeader*)ioBuf->bufStart; memset(msg->hdr, 0, sizeof(AJ_MsgHeader)); ioBuf->writePtr += sizeof(AJ_MsgHeader); msg->hdr->endianess = HOST_ENDIANESS; msg->hdr->msgType = msgType; msg->hdr->flags = flags; if (secure) { msg->hdr->flags |= AJ_FLAG_ENCRYPTED; } /* * The wire-protocol calls this flag NO_AUTO_START we toggle the meaning in the API * so the default flags value can be zero. */ msg->hdr->flags ^= AJ_FLAG_AUTO_START; /* * Serial number cannot be zero (wire-spec weirdness) */ do { msg->hdr->serialNum = msg->bus->serial++; } while (msg->bus->serial == 1); /* * Marshal the header fields */ for (fieldId = AJ_HDR_OBJ_PATH; fieldId <= AJ_HDR_SESSION_ID; ++fieldId) { char typeId = TypeForHdr[fieldId]; char buf[4]; const char* fieldSig = &buf[2]; AJ_Arg hdrVal; /* * Skip field id's that are not currently used. */ if (typeId == AJ_ARG_INVALID) { continue; } InitArg(&hdrVal, typeId, NULL); switch (fieldId) { case AJ_HDR_OBJ_PATH: if ((msgType == AJ_MSG_METHOD_CALL) || (msgType == AJ_MSG_SIGNAL)) { hdrVal.val.v_objPath = msg->objPath; } break; case AJ_HDR_INTERFACE: hdrVal.val.v_string = msg->iface; break; case AJ_HDR_MEMBER: if (msgType != AJ_MSG_ERROR) { int32_t len = AJ_StringFindFirstOf(msg->member, " "); hdrVal.val.v_string = msg->member; hdrVal.len = (len >= 0) ? len : 0; } break; case AJ_HDR_ERROR_NAME: if (msgType == AJ_MSG_ERROR) { hdrVal.val.v_string = msg->error; } break; case AJ_HDR_REPLY_SERIAL: if ((msgType == AJ_MSG_METHOD_RET) || (msgType == AJ_MSG_ERROR)) { hdrVal.val.v_uint32 = &msg->replySerial; } break; case AJ_HDR_DESTINATION: hdrVal.val.v_string = msg->destination; break; case AJ_HDR_SENDER: hdrVal.val.v_string = AJ_GetUniqueName(msg->bus); break; case AJ_HDR_SIGNATURE: hdrVal.val.v_signature = msg->signature; break; case AJ_HDR_TIMESTAMP: if (msg->ttl) { AJ_Time timer; timer.seconds = 0; timer.milliseconds = 0; msg->timestamp = AJ_GetElapsedTime(&timer, FALSE); hdrVal.val.v_uint32 = &msg->timestamp; } break; case AJ_HDR_TIME_TO_LIVE: if (msg->ttl) { hdrVal.val.v_uint32 = &msg->ttl; } break; case AJ_HDR_SESSION_ID: if (msg->sessionId) { hdrVal.val.v_uint32 = &msg->sessionId; } break; case AJ_HDR_HANDLES: case AJ_HDR_COMPRESSION_TOKEN: default: continue; } /* * Ignore empty fields. */ if (!hdrVal.val.v_data) { continue; } /* * Custom marshal the header field - signature is "(yv)" so starts off with STRUCT aligment. */ buf[0] = fieldId; buf[1] = 1; buf[2] = typeId; buf[3] = 0; WriteBytes(msg, buf, 4, PadForType(AJ_ARG_STRUCT, ioBuf)); /* * Now marshal the field value */ Marshal(msg, &fieldSig, &hdrVal); } if (status == AJ_OK) { /* * Write the header length */ msg->hdr->headerLen = (uint32_t)((ioBuf->writePtr - ioBuf->bufStart) - sizeof(AJ_MsgHeader)); /* * Header must be padded to an 8 byte boundary */ status = WritePad(msg, HEADERPAD(msg->hdr->headerLen)); } return status; } AJ_Status AJ_MarshalArg(AJ_Message* msg, AJ_Arg* arg) { AJ_Status status; AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; uint8_t* argStart = ioBuf->writePtr; if (msg->varOffset) { /* * Marshaling a variant - get the signature from the I/O buffer */ const char* sig = (const char*)(argStart - msg->varOffset); msg->varOffset = 0; status = Marshal(msg, &sig, arg); } else if (msg->outer) { /* * Marshaling a component of a container use the container's signature */ const char* sig = msg->outer->sigPtr; if (!*sig) { AJ_ErrPrintf(("AJ_MarshalArg(): AJ_ERR_END_OF_DATA\n")); return AJ_ERR_END_OF_DATA; } status = Marshal(msg, &sig, arg); /* * Only advance the signature for struct elements */ if (msg->outer->typeId != AJ_ARG_ARRAY) { msg->outer->sigPtr = sig; } } else { const char* sig = msg->signature + msg->sigOffset; /* * Marshalling anything else use the message signature */ if (!*sig) { AJ_ErrPrintf(("AJ_MarshalArg(): AJ_ERR_END_OF_DATA\n")); return AJ_ERR_END_OF_DATA; } status = Marshal(msg, &sig, arg); msg->sigOffset = (uint8_t)(sig - msg->signature); } if (status == AJ_OK) { msg->bodyBytes += (uint16_t)(ioBuf->writePtr - argStart); } else { AJ_ReleaseReplyContext(msg); } return status; } AJ_Arg* AJ_InitArg(AJ_Arg* arg, uint8_t typeId, uint8_t flags, const void* val, size_t len) { if (!IsBasicType(typeId)) { memset(arg, 0, sizeof(AJ_Arg)); return NULL; } else { arg->typeId = typeId; arg->flags = flags; arg->len = (uint16_t)len; arg->val.v_data = (void*)val; arg->sigPtr = NULL; arg->container = NULL; return arg; } } static AJ_Status VMarshalArgs(AJ_Message* msg, const char** sig, va_list* argpp) { AJ_Status status = AJ_ERR_UNEXPECTED; AJ_Arg arg; AJ_Arg container; va_list argp; __va_copy(argp, *argpp); container.typeId = AJ_ARG_INVALID; while (**sig) { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; double d; uint8_t typeId = (uint8_t)*((*sig)++); void* val; if (!IsBasicType(typeId)) { if ((typeId == AJ_ARG_STRUCT) || (typeId == AJ_ARG_DICT_ENTRY)) { status = AJ_MarshalContainer(msg, &container, typeId); if (status != AJ_OK) { break; } status = VMarshalArgs(msg, sig, &argp); /* * Upon successful return from a nested call, continue from * where the inner call advanced in the signature. */ if (status == AJ_OK) { status = AJ_MarshalCloseContainer(msg, &container); } if (status != AJ_OK) { break; } continue; } if ((typeId == AJ_ARG_ARRAY) && IsBasicType(**sig)) { const void* aval = va_arg(argp, const void*); size_t len = va_arg(argp, size_t); AJ_InitArg(&arg, (uint8_t)*((*sig)++), AJ_ARRAY_FLAG, aval, len); status = AJ_MarshalArg(msg, &arg); continue; } if ((typeId == AJ_STRUCT_CLOSE) || (typeId == AJ_DICT_ENTRY_CLOSE)) { break; } if (typeId == AJ_ARG_VARIANT) { const char* vsig = va_arg(argp, const char*); status = AJ_MarshalVariant(msg, vsig); if (status == AJ_OK) { status = VMarshalArgs(msg, &vsig, &argp); } if (status == AJ_OK) { continue; } } AJ_ErrPrintf(("AJ_MarshalArgs(): AJ_ERR_UNEXPECTED\n")); status = AJ_ERR_UNEXPECTED; break; } if (IsScalarType(typeId)) { if (SizeOfType(typeId) == 8) { if (typeId == 'd') { d = va_arg(argp, double); val = &d; } else { u64 = va_arg(argp, uint64_t); val = &u64; } } else if (SizeOfType(typeId) == 4) { u32 = va_arg(argp, uint32_t); val = &u32; } else if (SizeOfType(typeId) == 2) { u16 = (uint16_t)va_arg(argp, uint32_t); val = &u16; } else { u8 = (uint8_t)va_arg(argp, uint32_t); val = &u8; } } else { val = va_arg(argp, char*); } InitArg(&arg, typeId, val); status = AJ_MarshalArg(msg, &arg); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_MarshalArgs(): status=%s\n", AJ_StatusText(status))); break; } } __va_copy(*argpp, argp); return status; } AJ_Status AJ_MarshalArgs(AJ_Message* msg, const char* sig, ...) { AJ_Status status; va_list argp; va_start(argp, sig); status = VMarshalArgs(msg, &sig, &argp); va_end(argp); return status; } AJ_Status AJ_DeliverMsgPartial(AJ_Message* msg, uint32_t bytesRemaining) { AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; uint8_t typeId = msg->signature[msg->sigOffset]; size_t pad; AJ_ASSERT(!msg->outer); if (!msg->hdr || !bytesRemaining) { AJ_ErrPrintf(("AJ_DeliverMsgPartial(): AJ_ERR_UNEXPECTED\n")); return AJ_ERR_UNEXPECTED; } /* * Partial delivery not currently supported for messages that must be encrypted. */ if (msg->hdr->flags & AJ_FLAG_ENCRYPTED) { AJ_ErrPrintf(("AJ_DeliverMsgPartial(): AJ_ERR_SECURITY\n")); return AJ_ERR_SECURITY; } /* * There must be arguments to marshal */ if (!typeId) { AJ_ErrPrintf(("AJ_DeliverMsgPartial(): AJ_ERR_SIGNATURE\n")); return AJ_ERR_SIGNATURE; } /* * Pad to the start of the argument. */ pad = PadForType(typeId, ioBuf); if (pad) { AJ_Status status = WritePad(msg, pad); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_DeliverMsgPartial(): status=%s\n", AJ_StatusText(status))); return status; } } /* * Set the body length in the header buffer. */ msg->hdr->bodyLen = (uint32_t)(msg->bodyBytes + pad + bytesRemaining); AJ_DumpMsg("SENDING(partial)", msg, FALSE); /* * The buffer space occupied by the header is going to be overwritten * so the header is going to become invalid. */ msg->hdr = NULL; /* * From now on we are going to count down the remaining body bytes */ msg->bodyBytes = (uint32_t)bytesRemaining; /* * Standard signature matching is now meaningless */ msg->signature = ""; msg->sigOffset = 0;; return AJ_OK; } AJ_Status AJ_MarshalRaw(AJ_Message* msg, const void* data, size_t len) { if (msg->hdr) { AJ_ErrPrintf(("AJ_MarshalRaw(): AJ_ERR_SECURITY\n")); return AJ_ERR_UNEXPECTED; } /* * It is a fatal error to write too many bytes */ if (len > msg->bodyBytes) { AJ_ErrPrintf(("AJ_MarshalRaw(): AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } msg->bodyBytes -= (uint32_t)len; return WriteBytes(msg, data, len, 0); } AJ_Status AJ_MarshalContainer(AJ_Message* msg, AJ_Arg* arg, uint8_t typeId) { AJ_Status status; InitArg(arg, typeId, NULL); status = AJ_MarshalArg(msg, arg); if (status == AJ_OK) { arg->container = msg->outer; msg->outer = arg; } return status; } AJ_Status AJ_MarshalCloseContainer(AJ_Message* msg, AJ_Arg* arg) { AJ_IOBuffer* ioBuf = &msg->bus->sock.tx; AJ_Status status = AJ_OK; AJ_ASSERT(TYPE_FLAG(arg->typeId) & AJ_CONTAINER); AJ_ASSERT(msg->outer == arg); msg->outer = arg->container; if (arg->typeId == AJ_ARG_ARRAY) { uint32_t lenOffset = (uint32_t)((uint8_t*)arg->val.v_data - ioBuf->bufStart); /* * The length we marshal does not include the length field itself. */ arg->len = (uint16_t)(ioBuf->writePtr - (uint8_t*)arg->val.v_data) - 4; /* * If the array element is 8 byte aligned and the array is not empty check if there was * padding after the length. The length we marshal should not include the padding. */ if ((ALIGNMENT(*arg->sigPtr) == 8) && !(lenOffset & 4) && arg->len) { arg->len -= 4; } /* * Write array length into the buffer */ *(arg->val.v_uint32) = arg->len; } else { arg->len = 0; /* * Check the signature is correctly closed. */ if ((arg->typeId == AJ_ARG_STRUCT) && (*arg->sigPtr != AJ_STRUCT_CLOSE)) { AJ_ErrPrintf(("AJ_MarshalCloseContainer(): AJ_ERR_SIGNATURE\n")); return AJ_ERR_SIGNATURE; } if ((arg->typeId == AJ_ARG_DICT_ENTRY) && (*arg->sigPtr != AJ_DICT_ENTRY_CLOSE)) { AJ_ErrPrintf(("AJ_MarshalCloseContainer(): AJ_ERR_SIGNATURE\n")); return AJ_ERR_SIGNATURE; } } return status; } AJ_Status AJ_MarshalVariant(AJ_Message* msg, const char* sig) { AJ_Arg arg; /* * A variant type must be a single complete type */ if (CompleteTypeSigLen(sig) != strlen(sig)) { AJ_ErrPrintf(("AJ_MarshalVariant(): AJ_ERR_UNEXPECTED\n")); return AJ_ERR_UNEXPECTED; } InitArg(&arg, AJ_ARG_VARIANT, sig); return AJ_MarshalArg(msg, &arg); } AJ_Status AJ_MarshalMethodCall(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t msgId, const char* destination, AJ_SessionId sessionId, uint8_t flags, uint32_t timeout) { AJ_Status status; memset(msg, 0, sizeof(AJ_Message)); msg->bus = bus; msg->destination = destination; msg->sessionId = sessionId; msg->ttl = timeout; status = MarshalMsg(msg, AJ_MSG_METHOD_CALL, msgId, flags); if (status == AJ_OK) { status = AJ_AllocReplyContext(msg, timeout); } return status; } AJ_Status AJ_MarshalSignal(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t msgId, const char* destination, AJ_SessionId sessionId, uint8_t flags, uint32_t ttl) { memset(msg, 0, sizeof(AJ_Message)); msg->bus = bus; msg->destination = destination; msg->sessionId = sessionId; /* Special case: if destination == NULL and sessionId != 0 and the corresponding session * is unicast, this is functionally equivalent to a unicast signal over that session. * As a matter of fact, it is common practice to emit signals in this way. The Security 2.0 * policy checking code treats both cases differently, though, and to preserve the * equivalent behavior of before, we just fill in the destination here, if it's NULL. */ if (destination == NULL && sessionId != 0) { AJ_Session* session = AJ_BusGetOngoingSession(bus, sessionId); if (session && !session->multipoint) { msg->destination = session->otherParticipant; } } msg->ttl = ttl; return MarshalMsg(msg, AJ_MSG_SIGNAL, msgId, flags); } AJ_Status AJ_MarshalReplyMsg(const AJ_Message* methodCall, AJ_Message* reply) { AJ_ASSERT(methodCall->hdr->msgType == AJ_MSG_METHOD_CALL); memset(reply, 0, sizeof(AJ_Message)); reply->bus = methodCall->bus; reply->destination = methodCall->sender; reply->sessionId = methodCall->sessionId; reply->replySerial = methodCall->hdr->serialNum; return MarshalMsg(reply, AJ_MSG_METHOD_RET, methodCall->msgId, methodCall->hdr->flags & AJ_FLAG_ENCRYPTED); } AJ_Status AJ_MarshalErrorMsgWithInfo(const AJ_Message* methodCall, AJ_Message* reply, const char* error, const char* info) { AJ_Status status; AJ_ASSERT(methodCall->hdr->msgType == AJ_MSG_METHOD_CALL); memset(reply, 0, sizeof(AJ_Message)); reply->bus = methodCall->bus; reply->destination = methodCall->sender; reply->sessionId = methodCall->sessionId; reply->replySerial = methodCall->hdr->serialNum; reply->error = error; if (info) { reply->signature = "s"; } status = MarshalMsg(reply, AJ_MSG_ERROR, methodCall->msgId, methodCall->hdr->flags & AJ_FLAG_ENCRYPTED); if ((status == AJ_OK) && info) { status = AJ_MarshalArgs(reply, "s", info); } return status; } AJ_Status AJ_MarshalErrorMsg(const AJ_Message* methodCall, AJ_Message* reply, const char* error) { return AJ_MarshalErrorMsgWithInfo(methodCall, reply, error, NULL); } static const char* StatusToErrorStrings(AJ_Status status, const char** info) { switch (status) { case AJ_ERR_NO_MATCH: *info = NULL; return AJ_ErrServiceUnknown; case AJ_ERR_SECURITY: *info = NULL; return AJ_ErrSecurityViolation; case AJ_ERR_ACCESS: *info = NULL; return AJ_ErrPermissionDenied; case AJ_ERR_SECURITY_DIGEST_MISMATCH: *info = NULL; return AJ_ErrDigestMismatch; case AJ_ERR_SECURITY_INVALID_CERTIFICATE: *info = NULL; return AJ_ErrInvalidCertificate; case AJ_ERR_SECURITY_DUPLICATE_CERTIFICATE: *info = NULL; return AJ_ErrDuplicateCertificate; case AJ_ERR_SECURITY_CERTIFICATE_NOT_FOUND: *info = NULL; return AJ_ErrCertificateNotFound; case AJ_ERR_SECURITY_POLICY_NOT_NEWER: *info = NULL; return AJ_ErrPolicyNotNewer; default: *info = AJ_StatusText(status); return AJ_ErrRejected; } } AJ_Status AJ_MarshalStatusMsg(const AJ_Message* methodCall, AJ_Message* reply, AJ_Status status) { const char* info; const char* err = StatusToErrorStrings(status, &info); return AJ_MarshalErrorMsgWithInfo(methodCall, reply, err, info); } AJ_Status AJ_MarshalReplyMsgAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply) { AJ_Status status; if (!replyCtx) { return AJ_ERR_NULL; } if (!replyCtx->msgId) { return AJ_ERR_INVALID; } memset(reply, 0, sizeof(AJ_Message)); reply->bus = replyCtx->bus; reply->destination = replyCtx->sender; reply->sessionId = replyCtx->sessionId; reply->replySerial = replyCtx->serialNum; status = MarshalMsg(reply, AJ_MSG_METHOD_RET, replyCtx->msgId, replyCtx->flags & AJ_FLAG_ENCRYPTED); /* * Ensure reply context is only be used once */ memset(replyCtx, 0, sizeof(*replyCtx)); return status; } AJ_Status AJ_MarshalErrorMsgAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply, const char* error) { return AJ_MarshalErrorMsgWithInfoAsync(replyCtx, reply, error, NULL); } AJ_Status AJ_MarshalErrorMsgWithInfoAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply, const char* error, const char* info) { AJ_Status status; if (!replyCtx) { return AJ_ERR_NULL; } if (!replyCtx->msgId) { return AJ_ERR_INVALID; } memset(reply, 0, sizeof(AJ_Message)); reply->bus = replyCtx->bus; reply->destination = replyCtx->sender; reply->sessionId = replyCtx->sessionId; reply->replySerial = replyCtx->serialNum; reply->error = error; if (info) { reply->signature = "s"; } status = MarshalMsg(reply, AJ_MSG_ERROR, replyCtx->msgId, replyCtx->flags & AJ_FLAG_ENCRYPTED); if ((status == AJ_OK) && info) { status = AJ_MarshalArgs(reply, "s", info); } /* * Ensure reply context is only be used once */ memset(replyCtx, 0, sizeof(*replyCtx)); return status; } AJ_Status AJ_MarshalStatusMsgAsync(AJ_MsgReplyContext* replyCtx, AJ_Message* reply, AJ_Status status) { const char* info; const char* err = StatusToErrorStrings(status, &info); return AJ_MarshalErrorMsgWithInfoAsync(replyCtx, reply, err, info); } AJ_Status rx_noop(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { buf->writePtr += len; return AJ_OK; } AJ_Status tx_noop(AJ_IOBuffer* buf) { return AJ_OK; } /* This is the minimum requirements to unmarshal a message locally */ void AJ_LocalMsg(AJ_BusAttachment* bus, AJ_MsgHeader* hdr, AJ_Message* msg, const char* sig, uint8_t* data, size_t size) { memset(msg, 0, sizeof (AJ_Message)); memset(hdr, 0, sizeof (AJ_MsgHeader)); hdr->endianess = AJ_NATIVE_ENDIAN; msg->hdr = hdr; msg->bus = bus; msg->signature = sig; msg->bodyBytes = size; bus->sock.rx.direction = AJ_IO_BUF_RX; bus->sock.rx.recv = rx_noop; bus->sock.rx.bufSize = size; bus->sock.rx.bufStart = data; bus->sock.rx.readPtr = bus->sock.rx.bufStart; bus->sock.rx.writePtr = bus->sock.rx.bufStart; bus->sock.tx.direction = AJ_IO_BUF_TX; bus->sock.tx.send = tx_noop; bus->sock.tx.bufSize = size; bus->sock.tx.bufStart = data; bus->sock.tx.readPtr = bus->sock.tx.bufStart; bus->sock.tx.writePtr = bus->sock.tx.bufStart; } ajtcl-16.04/src/aj_peer.c000066400000000000000000002200671271074662300152000ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE PEER #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgPEER = 0; #endif /* * Version number of the key generation algorithm. */ #define MIN_KEYGEN_VERSION 0x00 #define MAX_KEYGEN_VERSION 0x00 /* * The base authentication version number */ #define MIN_AUTH_VERSION 0x0002 #define MAX_AUTH_VERSION 0x0004 #define REQUIRED_AUTH_VERSION (((uint32_t)MAX_AUTH_VERSION << 16) | MIN_KEYGEN_VERSION) #define SEND_MEMBERSHIPS_NONE 0 #define SEND_MEMBERSHIPS_MORE 1 #define SEND_MEMBERSHIPS_LAST 2 static AJ_Status SaveMasterSecret(const AJ_GUID* peerGuid, uint32_t expiration); static AJ_Status SaveECDSAContext(const AJ_GUID* peerGuid, uint32_t expiration); static AJ_Status ExchangeSuites(AJ_Message* msg); static AJ_Status KeyExchange(AJ_BusAttachment* bus); static AJ_Status KeyAuthentication(AJ_Message* msg); static AJ_Status GenSessionKey(AJ_Message* msg); static AJ_Status SendMemberships(AJ_Message* msg); typedef enum { AJ_AUTH_NONE, AJ_AUTH_EXCHANGED, AJ_AUTH_SUCCESS } HandshakeState; typedef struct _PeerContext { HandshakeState state; AJ_BusAuthPeerCallback callback; /* Callback function to report completion */ void* cbContext; /* Context to pass to the callback function */ const AJ_GUID* peerGuid; /* GUID pointer for the currently authenticating peer */ const char* peerName; /* Name of the peer being authenticated */ AJ_Time timer; /* Timer for detecting failed authentication attempts */ char nonce[2 * AJ_NONCE_LEN + 1]; /* Nonce as ascii hex */ } PeerContext; static PeerContext peerContext; static AJ_AuthenticationContext authContext = { 0 }; static uint8_t sentManifests = FALSE; static uint32_t GetAcceptableVersion(uint32_t srcV) { uint16_t authV = AJ_UNPACK_AUTH_VERSION(srcV); uint16_t keyV = AJ_UNPACK_KEYGEN_VERSION(srcV); if ((authV < MIN_AUTH_VERSION) || (authV > MAX_AUTH_VERSION)) { return 0; } if (keyV > MAX_KEYGEN_VERSION) { return 0; } if (authV < MAX_AUTH_VERSION) { return srcV; } if (keyV < MAX_KEYGEN_VERSION) { return srcV; } return REQUIRED_AUTH_VERSION; } static AJ_Status KeyGen(const char* peerName, uint8_t role, const char* nonce1, const char* nonce2, uint8_t* outBuf, uint32_t len) { AJ_Status status; const uint8_t* data[4]; uint8_t lens[4]; const AJ_GUID* peerGuid = AJ_GUID_Find(peerName); AJ_InfoPrintf(("KeyGen(peerName=\"%s\", role=%d., nonce1=\"%s\", nonce2=\"%s\", outbuf=%p, len=%d.)\n", peerName, role, nonce1, nonce2, outBuf, len)); if (NULL == peerGuid) { AJ_ErrPrintf(("KeyGen(): AJ_ERR_UNEXPECTED\n")); return AJ_ERR_UNEXPECTED; } data[0] = authContext.mastersecret; lens[0] = (uint32_t)AJ_MASTER_SECRET_LEN; data[1] = (uint8_t*)"session key"; lens[1] = 11; data[2] = (uint8_t*)nonce1; lens[2] = (uint32_t)strlen(nonce1); data[3] = (uint8_t*)nonce2; lens[3] = (uint32_t)strlen(nonce2); /* * We use the outBuf to store both the key and verifier string. * Check that there is enough space to do so. */ if (len < (AJ_SESSION_KEY_LEN + AJ_VERIFIER_LEN)) { AJ_WarnPrintf(("KeyGen(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } status = AJ_Crypto_PRF_SHA256(data, lens, ArraySize(data), outBuf, AJ_SESSION_KEY_LEN + AJ_VERIFIER_LEN); /* * Store the session key and compose the verifier string. */ if (status == AJ_OK) { status = AJ_SetSessionKey(peerName, outBuf, role, authContext.version); } if (status == AJ_OK) { memmove(outBuf, outBuf + AJ_SESSION_KEY_LEN, AJ_VERIFIER_LEN); status = AJ_RawToHex(outBuf, AJ_VERIFIER_LEN, (char*) outBuf, len, FALSE); } AJ_InfoPrintf(("KeyGen Verifier = %s.\n", outBuf)); return status; } void AJ_ClearSentManifests() { sentManifests = FALSE; } void AJ_ClearAuthContext() { /* Free issuers, hash, and PSK */ AJ_Free(authContext.kactx.ecdsa.key); if (authContext.hash) { AJ_SHA256_Final(authContext.hash, NULL); } AJ_ASSERT(((NULL == authContext.kactx.psk.hint) && (authContext.kactx.psk.hintSize == 0)) || ((NULL != authContext.kactx.psk.hint) && (authContext.kactx.psk.hintSize > 0))); AJ_Free(authContext.kactx.psk.hint); if (NULL != authContext.kactx.psk.key) { AJ_ASSERT(authContext.kactx.psk.keySize > 0); AJ_MemZeroSecure(authContext.kactx.psk.key, authContext.kactx.psk.keySize); AJ_Free(authContext.kactx.psk.key); } memset(&peerContext, 0, sizeof (PeerContext)); memset(&authContext, 0, sizeof (AJ_AuthenticationContext)); } static void HandshakeComplete(AJ_Status status) { AJ_InfoPrintf(("HandshakeComplete(status=%d.)\n", status)); /* If ECDSA/PSK failed, try NULL */ if ((AJ_OK != status) && (AUTH_SUITE_ECDHE_NULL != authContext.suite) && AJ_IsSuiteEnabled(authContext.bus, AUTH_SUITE_ECDHE_NULL, AJ_UNPACK_AUTH_VERSION(authContext.version))) { if (AUTH_CLIENT == authContext.role) { authContext.suite = AUTH_SUITE_ECDHE_NULL; KeyExchange(authContext.bus); } return; } if ((AJ_OK == status) && authContext.expiration) { status = SaveMasterSecret(peerContext.peerGuid, authContext.expiration); if (AJ_OK != status) { AJ_WarnPrintf(("HandshakeComplete(status=%d): Save master secret error\n", status)); goto Exit; } if (AUTH_SUITE_ECDHE_ECDSA == authContext.suite) { status = SaveECDSAContext(peerContext.peerGuid, authContext.expiration); if (AJ_OK != status) { AJ_WarnPrintf(("HandshakeComplete(status=%d): Save ecdsa context error\n", status)); goto Exit; } } } Exit: /* Policy no longer needed in memory */ AJ_PolicyUnload(); if (peerContext.callback) { peerContext.callback(peerContext.cbContext, status); } AJ_ClearAuthContext(); } static AJ_Status SaveMasterSecret(const AJ_GUID* peerGuid, uint32_t expiration) { AJ_Status status; AJ_InfoPrintf(("SaveMasterSecret(peerGuid=%p, expiration=%d)\n", peerGuid, expiration)); if (NULL == peerGuid) { return AJ_ERR_SECURITY; } /* * If the authentication was succesful write the credentials for the authenticated peer to * NVRAM otherwise delete any stale credentials that might be stored. */ if (AJ_AUTH_SUCCESS == peerContext.state) { status = AJ_CredentialSetPeer(AJ_GENERIC_MASTER_SECRET, peerGuid, expiration, authContext.mastersecret, AJ_MASTER_SECRET_LEN); } else { AJ_WarnPrintf(("SaveMasterSecret(peerGuid=%p, expiration=%d): Invalid state\n", peerGuid, expiration)); AJ_CredentialDeletePeer(peerGuid); } return status; } static AJ_Status LoadMasterSecret(const AJ_GUID* peerGuid) { AJ_Status status; uint32_t expiration; AJ_CredField data; AJ_InfoPrintf(("LoadMasterSecret(peerGuid=%p)\n", peerGuid)); if (NULL == peerGuid) { return AJ_ERR_SECURITY; } /* Write directly to mastersecret buffer */ data.size = AJ_MASTER_SECRET_LEN; data.data = authContext.mastersecret; status = AJ_CredentialGetPeer(AJ_GENERIC_MASTER_SECRET, peerGuid, &expiration, &data); if (AJ_OK != status) { return status; } status = AJ_CredentialExpired(expiration); return status; } static AJ_Status SaveECDSAContext(const AJ_GUID* peerGuid, uint32_t expiration) { AJ_Status status; AJ_InfoPrintf(("SaveECDSAContext(peerGuid=%p, expiration=%d)\n", peerGuid, expiration)); if (NULL == peerGuid) { return AJ_ERR_SECURITY; } if ((AJ_AUTH_SUCCESS == peerContext.state) && (authContext.kactx.ecdsa.thumbprintSize > 0)) { status = AJ_CredentialSetPeer(AJ_GENERIC_ECDSA_THUMBPRINT, peerGuid, expiration, authContext.kactx.ecdsa.thumbprint, (uint16_t)authContext.kactx.ecdsa.thumbprintSize); if (AJ_OK != status) { return status; } status = AJ_CredentialSetPeer(AJ_GENERIC_ECDSA_KEYS, peerGuid, expiration, (uint8_t*) authContext.kactx.ecdsa.key, (uint16_t) (authContext.kactx.ecdsa.num * sizeof (AJ_ECCPublicKey))); if (AJ_OK != status) { return status; } } return status; } static AJ_Status LoadECDSAContext(const AJ_GUID* peerGuid) { AJ_Status status; AJ_CredField data; AJ_InfoPrintf(("LoadECDSAContext(peerGuid=%p)\n", peerGuid)); /* Check if we have a stored identity thumbprint */ data.size = AJ_SHA256_DIGEST_LENGTH; data.data = authContext.kactx.ecdsa.thumbprint; status = AJ_CredentialGetPeer(AJ_GENERIC_ECDSA_THUMBPRINT, peerGuid, NULL, &data); if (AJ_OK == status) { authContext.kactx.ecdsa.thumbprintSize = data.size; } else { peerContext.state = AJ_AUTH_SUCCESS; return AJ_OK; } /* If we have an identity certificate thumbprint, we require stored public keys */ data.size = 0; /* Keys is NULL, AJ_CredentialGetPeer will allocate the memory */ data.data = (uint8_t*) authContext.kactx.ecdsa.key; status = AJ_CredentialGetPeer(AJ_GENERIC_ECDSA_KEYS, peerGuid, NULL, &data); if (AJ_OK != status) { return status; } if (0 != (data.size % sizeof (AJ_ECCPublicKey))) { /* Keys corrupted */ return AJ_ERR_INVALID; } authContext.kactx.ecdsa.key = (AJ_ECCPublicKey*) data.data; authContext.kactx.ecdsa.num = data.size / (sizeof (AJ_ECCPublicKey)); authContext.suite = AUTH_SUITE_ECDHE_ECDSA; /* Set expiration to zero so we don't resave the credential */ authContext.expiration = 0; peerContext.state = AJ_AUTH_SUCCESS; return status; } static AJ_Status HandshakeTimeout() { uint8_t zero[sizeof (AJ_GUID)]; memset(zero, 0, sizeof (zero)); /* * If handshake started, check peer is still around * If peer disappeared, AJ_GUID_DeleteNameMapping writes zeros */ if (peerContext.peerGuid) { if (0 == memcmp(peerContext.peerGuid, zero, sizeof (zero))) { AJ_WarnPrintf(("AJ_HandshakeTimeout(): Peer disappeared\n")); peerContext.peerGuid = NULL; HandshakeComplete(AJ_ERR_TIMEOUT); return AJ_ERR_TIMEOUT; } } if (AJ_GetElapsedTime(&peerContext.timer, TRUE) >= AJ_MAX_AUTH_TIME) { AJ_WarnPrintf(("AJ_HandshakeTimeout(): AJ_ERR_TIMEOUT\n")); HandshakeComplete(AJ_ERR_TIMEOUT); return AJ_ERR_TIMEOUT; } return AJ_OK; } static AJ_Status HandshakeValid(const AJ_GUID* peerGuid) { /* * Handshake not yet started */ if (!peerContext.peerGuid) { AJ_InfoPrintf(("AJ_HandshakeValid(peerGuid=%p): Invalid peer guid\n", peerGuid)); return AJ_ERR_SECURITY; } /* * Handshake timed out */ if (AJ_OK != HandshakeTimeout()) { AJ_InfoPrintf(("AJ_HandshakeValid(peerGuid=%p): Handshake timed out\n", peerGuid)); return AJ_ERR_TIMEOUT; } /* * Handshake call from different peer */ if ((NULL == peerGuid) || (peerGuid != peerContext.peerGuid)) { AJ_WarnPrintf(("AJ_HandshakeValid(peerGuid=%p): Invalid peer guid\n", peerGuid)); return AJ_ERR_RESOURCES; } return AJ_OK; } static AJ_Status HashGuids(AJ_AuthenticationContext* ctx, const AJ_GUID* remoteGuid) { AJ_GUID localGuid; AJ_Status status; uint8_t authVersionLE[4]; AJ_ASSERT(remoteGuid != NULL); AJ_ASSERT(AJ_ConversationHash_IsInitialized(ctx)); /* Auth version is a 32-bit integer, we hash it in little endian order. */ HostU32ToLittleEndianU8(&(ctx->version), 1, authVersionLE); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V4, authVersionLE, sizeof(authVersionLE)); status = AJ_GetLocalGUID(&localGuid); if (AJ_OK != status) { return status; } if (ctx->role == AUTH_CLIENT) { AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V4, (uint8_t*)&localGuid, AJ_GUID_LEN); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V4, (uint8_t*)remoteGuid, AJ_GUID_LEN); } else { AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V4, (uint8_t*)remoteGuid, AJ_GUID_LEN); AJ_ConversationHash_Update_UInt8Array(ctx, CONVERSATION_V4, (uint8_t*)&localGuid, AJ_GUID_LEN); } return AJ_OK; } AJ_Status AJ_PeerAuthenticate(AJ_BusAttachment* bus, const char* peerName, AJ_PeerAuthenticateCallback callback, void* cbContext) { AJ_Status status; AJ_Message msg; char guidStr[2 * AJ_GUID_LEN + 1]; AJ_GUID localGuid; AJ_InfoPrintf(("PeerAuthenticate(bus=%p, peerName=\"%s\", callback=%p, cbContext=%p)\n", bus, peerName, callback, cbContext)); /* * If handshake in progress and not timed-out */ if (peerContext.peerGuid) { status = HandshakeTimeout(); if (AJ_ERR_TIMEOUT != status) { AJ_InfoPrintf(("PeerAuthenticate(): Handshake in progress\n")); return AJ_ERR_RESOURCES; } } /* * No handshake in progress or previous timed-out */ AJ_ClearAuthContext(); AJ_ClearSentManifests(); peerContext.callback = callback; peerContext.cbContext = cbContext; peerContext.peerName = peerName; AJ_InitTimer(&peerContext.timer); authContext.bus = bus; authContext.role = AUTH_CLIENT; /* Load policy into memory */ status = AJ_PolicyLoad(); if (AJ_OK != status) { AJ_InfoPrintf(("PeerAuthenticate(): No policy\n")); } if (bus->pwdCallback) { AJ_EnableSuite(bus, AUTH_SUITE_ECDHE_PSK); AJ_EnableSuite(bus, AUTH_SUITE_ECDHE_SPEKE); } /* * Kick off authentication with an ExchangeGUIDS method call */ status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_EXCHANGE_GUIDS, peerName, 0, AJ_NO_FLAGS, AJ_CALL_TIMEOUT); if (AJ_OK != status) { return status; } status = AJ_GetLocalGUID(&localGuid); if (AJ_OK != status) { return status; } status = AJ_GUID_ToString(&localGuid, guidStr, sizeof(guidStr)); if (AJ_OK != status) { return status; } authContext.version = REQUIRED_AUTH_VERSION; status = AJ_MarshalArgs(&msg, "su", guidStr, authContext.version); if (AJ_OK != status) { return status; } /* * Hashing the contents of the ExchangeGuids call is handled differently * from the other messages, since the ExchangeGuids call must be * idempotent. The conversation hash state is initialized in a subsequent * call, in either ExchangeSuites or GenSessionKey (depending on whether * the peers share a key). At that time both GUIDs and the authentication * version are hashed, capturing the information from ExchangeGuids in the * conversation hash. */ return AJ_DeliverMsg(&msg); } AJ_Status AJ_PeerHandleExchangeGUIDs(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; char guidStr[33]; char* str; AJ_GUID remoteGuid; AJ_GUID localGuid; AJ_InfoPrintf(("AJ_PeerHandleExchangeGuids(msg=%p, reply=%p)\n", msg, reply)); /* * If handshake in progress and not timed-out */ if (peerContext.peerGuid) { status = HandshakeTimeout(); if (AJ_ERR_TIMEOUT != status) { AJ_InfoPrintf(("AJ_PeerHandleExchangeGuids(msg=%p, reply=%p): Handshake in progress\n", msg, reply)); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrResources); } } /* * No handshake in progress or previous timed-out */ AJ_ClearAuthContext(); AJ_ClearSentManifests(); AJ_InitTimer(&peerContext.timer); authContext.bus = msg->bus; authContext.role = AUTH_SERVER; /* Load policy into memory */ status = AJ_PolicyLoad(); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleExchangeGuids(msg=%p, reply=%p): No policy\n", msg, reply)); } if (msg->bus->pwdCallback) { AJ_EnableSuite(msg->bus, AUTH_SUITE_ECDHE_PSK); AJ_EnableSuite(msg->bus, AUTH_SUITE_ECDHE_SPEKE); } status = AJ_UnmarshalArgs(msg, "su", &str, &authContext.version); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleExchangeGuids(msg=%p, reply=%p): Unmarshal error\n", msg, reply)); HandshakeComplete(AJ_ERR_SECURITY); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } status = AJ_GUID_FromString(&remoteGuid, str); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleExchangeGuids(msg=%p, reply=%p): Invalid GUID\n", msg, reply)); HandshakeComplete(AJ_ERR_SECURITY); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } status = AJ_GUID_AddNameMapping(msg->bus, &remoteGuid, msg->sender, NULL); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleExchangeGuids(msg=%p, reply=%p): Add name mapping error\n", msg, reply)); HandshakeComplete(AJ_ERR_RESOURCES); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrResources); } peerContext.peerGuid = AJ_GUID_Find(msg->sender); /* * Reset access control from previous peer */ AJ_AccessControlReset(msg->sender); /* * If we have a mastersecret stored - use it */ status = LoadMasterSecret(peerContext.peerGuid); if (AJ_OK == status) { status = LoadECDSAContext(peerContext.peerGuid); } if (AJ_OK != status) { /* Credential expired or failed to load */ AJ_CredentialDeletePeer(peerContext.peerGuid); /* Clear master secret buffer */ AJ_MemZeroSecure(authContext.mastersecret, AJ_MASTER_SECRET_LEN); } /* * We are not currently negotiating versions so we tell the peer what version we require. */ authContext.version = GetAcceptableVersion(authContext.version); if (0 == authContext.version) { authContext.version = REQUIRED_AUTH_VERSION; } AJ_InfoPrintf(("AJ_PeerHandleExchangeGuids(msg=%p, reply=%p): Version %x\n", msg, reply, authContext.version)); status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { goto Exit; } status = AJ_GetLocalGUID(&localGuid); if (AJ_OK != status) { goto Exit; } status = AJ_GUID_ToString(&localGuid, guidStr, sizeof(guidStr)); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalArgs(reply, "su", guidStr, authContext.version); if (AJ_OK != status) { goto Exit; } return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } AJ_Status AJ_PeerHandleExchangeGUIDsReply(AJ_Message* msg) { AJ_Status status; const char* guidStr; AJ_GUID remoteGuid; AJ_InfoPrintf(("AJ_PeerHandleExchangeGUIDsReply(msg=%p)\n", msg)); if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGUIDsReply(msg=%p): error=%s.\n", msg, msg->error)); if (0 == strncmp(msg->error, AJ_ErrResources, sizeof(AJ_ErrResources))) { status = AJ_ERR_RESOURCES; } else { status = AJ_ERR_SECURITY; HandshakeComplete(status); } return status; } /* * If handshake in progress and not timed-out */ if (peerContext.peerGuid) { status = HandshakeTimeout(); if (AJ_ERR_TIMEOUT != status) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGUIDsReply(msg=%p): Handshake in progress\n", msg)); return AJ_ERR_RESOURCES; } } status = AJ_UnmarshalArgs(msg, "su", &guidStr, &authContext.version); if (status != AJ_OK) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGUIDsReply(msg=%p): Unmarshal error\n", msg)); goto Exit; } authContext.version = GetAcceptableVersion(authContext.version); if (0 == authContext.version) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGUIDsReply(msg=%p): Invalid version\n", msg)); goto Exit; } status = AJ_GUID_FromString(&remoteGuid, guidStr); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGUIDsReply(msg=%p): Invalid GUID\n", msg)); goto Exit; } /* * Two name mappings to add, the well known name, and the unique name from the message. */ status = AJ_GUID_AddNameMapping(msg->bus, &remoteGuid, msg->sender, peerContext.peerName); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGUIDsReply(msg=%p): Add name mapping error\n", msg)); goto Exit; } /* * Remember which peer is being authenticated */ peerContext.peerGuid = AJ_GUID_Find(msg->sender); /* * Reset access control from previous peer */ AJ_AccessControlReset(msg->sender); /* * If we have a mastersecret stored - use it */ status = LoadMasterSecret(peerContext.peerGuid); if (AJ_OK == status) { status = LoadECDSAContext(peerContext.peerGuid); } if (AJ_OK == status) { status = GenSessionKey(msg); return status; } else { /* Credential expired or failed to load */ AJ_CredentialDeletePeer(peerContext.peerGuid); /* Clear master secret buffer */ AJ_MemZeroSecure(authContext.mastersecret, AJ_MASTER_SECRET_LEN); } /* * Start the ALLJOYN conversation */ status = ExchangeSuites(msg); return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } static AJ_Status ExchangeSuites(AJ_Message* msg) { AJ_Status status; AJ_Message call; uint32_t suites[AJ_AUTH_SUITES_NUM]; size_t num = 0; AJ_InfoPrintf(("ExchangeSuites(msg=%p)\n", msg)); authContext.role = AUTH_CLIENT; /* * Send suites in this priority order */ if (AJ_IsSuiteEnabled(msg->bus, AUTH_SUITE_ECDHE_ECDSA, AJ_UNPACK_AUTH_VERSION(authContext.version))) { suites[num++] = AUTH_SUITE_ECDHE_ECDSA; } if (AJ_IsSuiteEnabled(msg->bus, AUTH_SUITE_ECDHE_PSK, AJ_UNPACK_AUTH_VERSION(authContext.version))) { suites[num++] = AUTH_SUITE_ECDHE_PSK; } if (AJ_IsSuiteEnabled(msg->bus, AUTH_SUITE_ECDHE_SPEKE, AJ_UNPACK_AUTH_VERSION(authContext.version))) { suites[num++] = AUTH_SUITE_ECDHE_SPEKE; } if (AJ_IsSuiteEnabled(msg->bus, AUTH_SUITE_ECDHE_NULL, AJ_UNPACK_AUTH_VERSION(authContext.version))) { suites[num++] = AUTH_SUITE_ECDHE_NULL; } if (!num) { AJ_WarnPrintf(("ExchangeSuites(msg=%p): No suites available\n", msg)); goto Exit; } status = AJ_MarshalMethodCall(msg->bus, &call, AJ_METHOD_EXCHANGE_SUITES, msg->sender, 0, AJ_NO_FLAGS, AJ_AUTH_CALL_TIMEOUT); if (AJ_OK != status) { AJ_WarnPrintf(("ExchangeSuites(msg=%p): Marshal error\n", msg)); goto Exit; } status = AJ_MarshalArgs(&call, "au", suites, num * sizeof (uint32_t)); if (AJ_OK != status) { AJ_WarnPrintf(("ExchangeSuites(msg=%p): Marshal error\n", msg)); goto Exit; } /* * Initialize conversation hash and hash GUIDs. * May have already been done by GenSessionKey. */ if (!AJ_ConversationHash_IsInitialized(&authContext)) { status = AJ_ConversationHash_Initialize(&authContext); if (AJ_OK != status) { goto Exit; } status = HashGuids(&authContext, peerContext.peerGuid); if (AJ_OK != status) { goto Exit; } } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, &call, HASH_MSG_MARSHALED); return AJ_DeliverMsg(&call); Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } AJ_Status AJ_PeerHandleExchangeSuites(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_Arg array; uint32_t* suites; size_t numsuites; uint32_t i; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_PeerHandleExchangeSuites(msg=%p, reply=%p)\n", msg, reply)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrResources); } /* * Initialize the conversation hash and hash the GUIDs. * May have already been done by GenSessionKey. */ if (!AJ_ConversationHash_IsInitialized(&authContext)) { status = AJ_ConversationHash_Initialize(&authContext); if (AJ_OK != status) { goto Exit; } status = HashGuids(&authContext, peerGuid); if (AJ_OK != status) { goto Exit; } } /* Update hash before unmarshalling (endian swaps may occur) */ AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); authContext.role = AUTH_SERVER; /* * Receive suites */ status = AJ_UnmarshalArgs(msg, "au", &suites, &numsuites); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleExchangeSuites(msg=%p, reply=%p): Unmarshal error\n", msg, reply)); goto Exit; } numsuites /= sizeof (uint32_t); /* * Calculate common suites */ status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalContainer(reply, &array, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } /* Iterate through the available suites. * If it's enabled, marshal the suite to send to the other peer. */ for (i = 0; i < numsuites; i++) { if (AJ_IsSuiteEnabled(msg->bus, suites[i], AJ_UNPACK_AUTH_VERSION(authContext.version))) { status = AJ_MarshalArgs(reply, "u", suites[i]); if (AJ_OK != status) { goto Exit; } } } status = AJ_MarshalCloseContainer(reply, &array); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleExchangeSuites(msg=%p, reply=%p): Marshal error\n", msg, reply)); goto Exit; } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); AJ_InfoPrintf(("Exchange Suites Complete\n")); return status; Exit: if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleExchangeSuites(msg=%p, reply=%p): Marshal error\n", msg, reply)); } HandshakeComplete(AJ_ERR_SECURITY); status = AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); if (AJ_OK == status) { AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); } return status; } AJ_Status AJ_PeerHandleExchangeSuitesReply(AJ_Message* msg) { AJ_Status status; uint32_t* suites; size_t numsuites; size_t i; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_PeerHandleExchangeSuitesReply(msg=%p)\n", msg)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } /* Update hash before unmarshalling (endian swaps may occur) */ AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleExchangeSuitesReply(msg=%p): error=%s.\n", msg, msg->error)); goto Exit; } /* * Receive suites */ status = AJ_UnmarshalArgs(msg, "au", &suites, &numsuites); if (AJ_OK != status) { goto Exit; } numsuites /= sizeof (uint32_t); /* * Double check we can support (ie. that server didn't send something bogus) */ authContext.suite = 0; for (i = 0; i < numsuites; i++) { if (AJ_IsSuiteEnabled(msg->bus, suites[i], AJ_UNPACK_AUTH_VERSION(authContext.version))) { // Pick the highest priority suite, which happens to be the highest integer authContext.suite = (suites[i] > authContext.suite) ? suites[i] : authContext.suite; } } if (!authContext.suite) { AJ_InfoPrintf(("AJ_PeerHandleExchangeSuitesReply(msg=%p): No common suites\n", msg)); goto Exit; } /* * Exchange suites complete. */ AJ_InfoPrintf(("Exchange Suites Complete\n")); status = KeyExchange(msg->bus); return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } static AJ_Status AJ_SetKeyAuthContext(AJ_AuthenticationContext* ctx, const char* peerName) { AJ_Status status; if (ctx->suite == AUTH_SUITE_ECDHE_SPEKE) { status = AJ_GetLocalGUID(&ctx->kactx.speke.localGUID); if (status != AJ_OK) { return status; } ctx->kactx.speke.remoteGUID = AJ_GUID_Find(peerName); if (ctx->kactx.speke.remoteGUID == NULL) { return AJ_ERR_NO_MATCH; } } return AJ_OK; } static AJ_Status KeyExchange(AJ_BusAttachment* bus) { AJ_Status status; uint8_t suiteb8[sizeof (uint32_t)]; AJ_Message call; AJ_InfoPrintf(("KeyExchange(bus=%p)\n", bus)); AJ_InfoPrintf(("Authenticating using suite %x\n", authContext.suite)); /* * Send suite and key material */ status = AJ_MarshalMethodCall(bus, &call, AJ_METHOD_KEY_EXCHANGE, peerContext.peerName, 0, AJ_NO_FLAGS, AJ_AUTH_CALL_TIMEOUT); if (AJ_OK != status) { AJ_WarnPrintf(("KeyExchange(bus=%p): Marshal error\n", bus)); goto Exit; } status = AJ_MarshalArgs(&call, "u", authContext.suite); if (AJ_OK != status) { AJ_WarnPrintf(("KeyExchange(bus=%p): Marshal error\n", bus)); goto Exit; } status = AJ_SetKeyAuthContext(&authContext, peerContext.peerName); if (AJ_OK != status) { goto Exit; } HostU32ToBigEndianU8(&authContext.suite, sizeof (authContext.suite), suiteb8); AJ_ConversationHash_Update_UInt8Array(&authContext, CONVERSATION_V1, suiteb8, sizeof (suiteb8)); status = AJ_KeyExchangeMarshal(&authContext, &call); if (AJ_OK != status) { AJ_WarnPrintf(("KeyExchange(bus=%p): Key exchange marshal error\n", bus)); goto Exit; } AJ_ASSERT(AUTH_CLIENT == authContext.role); AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, &call, HASH_MSG_MARSHALED); return AJ_DeliverMsg(&call); Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } AJ_Status AJ_PeerHandleKeyExchange(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; uint8_t suiteb8[sizeof (uint32_t)]; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_PeerHandleKeyExchange(msg=%p, reply=%p)\n", msg, reply)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrResources); } /* Update hash before unmarshalling (endian swaps may occur) */ AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); /* * Receive suite */ status = AJ_UnmarshalArgs(msg, "u", &authContext.suite); if (AJ_OK != status) { goto Exit; } if (!AJ_IsSuiteEnabled(msg->bus, authContext.suite, AJ_UNPACK_AUTH_VERSION(authContext.version))) { goto Exit; } HostU32ToBigEndianU8(&authContext.suite, sizeof (authContext.suite), suiteb8); AJ_ConversationHash_Update_UInt8Array(&authContext, CONVERSATION_V1, suiteb8, sizeof (suiteb8)); status = AJ_SetKeyAuthContext(&authContext, msg->sender); if (AJ_OK != status) { goto Exit; } /* * Receive key material */ status = AJ_KeyExchangeUnmarshal(&authContext, msg); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleKeyExchange(msg=%p, reply=%p): Key exchange unmarshal error\n", msg, reply)); goto Exit; } /* * Send key material */ status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalArgs(reply, "u", authContext.suite); if (AJ_OK != status) { goto Exit; } AJ_ConversationHash_Update_UInt8Array(&authContext, CONVERSATION_V1, (uint8_t*)suiteb8, sizeof(suiteb8)); status = AJ_KeyExchangeMarshal(&authContext, reply); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleKeyExchange(msg=%p, reply=%p): Key exchange marshal error\n", msg, reply)); goto Exit; } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); peerContext.state = AJ_AUTH_EXCHANGED; AJ_InfoPrintf(("Key Exchange Complete\n")); return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); status = AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); if (AJ_OK == status) { AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); } return status; } AJ_Status AJ_PeerHandleKeyExchangeReply(AJ_Message* msg) { AJ_Status status; uint32_t suite; uint8_t suiteb8[sizeof (uint32_t)]; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_PeerHandleKeyExchangeReply(msg=%p)\n", msg)); if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleKeyExchangeReply(msg=%p): error=%s.\n", msg, msg->error)); if (0 == strncmp(msg->error, AJ_ErrResources, sizeof(AJ_ErrResources))) { status = AJ_ERR_RESOURCES; } else { status = AJ_ERR_SECURITY; HandshakeComplete(status); } return status; } status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } /* Update hash before unmarshalling (endian swaps may occur) */ AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); /* * Receive key material */ status = AJ_UnmarshalArgs(msg, "u", &suite); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleKeyExchangeReply(msg=%p): Unmarshal error\n", msg)); goto Exit; } if (suite != authContext.suite) { AJ_WarnPrintf(("AJ_PeerHandleKeyExchangeReply(msg=%p): Suite mismatch\n", msg)); goto Exit; } HostU32ToBigEndianU8(&suite, sizeof (suite), suiteb8); AJ_ConversationHash_Update_UInt8Array(&authContext, CONVERSATION_V1, suiteb8, sizeof(suiteb8)); status = AJ_KeyExchangeUnmarshal(&authContext, msg); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleKeyExchangeReply(msg=%p): Key exchange unmarshal error\n", msg)); goto Exit; } /* * Key exchange complete - start the authentication */ peerContext.state = AJ_AUTH_EXCHANGED; AJ_InfoPrintf(("Key Exchange Complete\n")); status = KeyAuthentication(msg); return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } static AJ_Status KeyAuthentication(AJ_Message* msg) { AJ_Status status; AJ_Message call; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_KeyAuthentication(msg=%p)\n", msg)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } /* FYI: msg is hashed in AJ_PeerHandleKeyExchangeReply, so don't hash it here as well. */ /* * Send authentication material */ status = AJ_MarshalMethodCall(msg->bus, &call, AJ_METHOD_KEY_AUTHENTICATION, msg->sender, 0, AJ_NO_FLAGS, AJ_AUTH_CALL_TIMEOUT); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_KeyAuthentication(msg=%p): Key authentication marshal error\n", msg)); goto Exit; } /* Get the conversation digest before it's updated with this message */ status = AJ_ConversationHash_GetDigest(&authContext); if (AJ_OK != status) { goto Exit; } status = AJ_KeyAuthenticationMarshal(&authContext, &call); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_KeyAuthentication(msg=%p): Key authentication marshal error\n", msg)); goto Exit; } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, &call, HASH_MSG_MARSHALED); return AJ_DeliverMsg(&call); Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } AJ_Status AJ_PeerHandleKeyAuthentication(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_PeerHandleKeyAuthentication(msg=%p, reply=%p)\n", msg, reply)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrResources); } if (AJ_AUTH_EXCHANGED != peerContext.state) { AJ_InfoPrintf(("AJ_PeerHandleKeyAuthentication(msg=%p, reply=%p): Invalid state\n", msg, reply)); AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); goto Exit; } /* Get the conversation digest before it's updated with this message */ status = AJ_ConversationHash_GetDigest(&authContext); if (AJ_OK != status) { goto Exit; } /* Update hash before unmarshalling (endian swaps may occur) */ AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); /* * Receive authentication material */ status = AJ_KeyAuthenticationUnmarshal(&authContext, msg); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleKeyAuthentication(msg=%p, reply=%p): Key authentication unmarshal error\n", msg, reply)); goto Exit; } /* * Send authentication material */ status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { goto Exit; } /* Get the conversation digest before it's updated with this reply */ status = AJ_ConversationHash_GetDigest(&authContext); if (AJ_OK != status) { goto Exit; } status = AJ_KeyAuthenticationMarshal(&authContext, reply); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleKeyAuthentication(msg=%p, reply=%p): Key authentication marshal error\n", msg, reply)); goto Exit; } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); AJ_InfoPrintf(("Key Authentication Complete\n")); peerContext.state = AJ_AUTH_SUCCESS; return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); status = AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); if (AJ_OK == status) { AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); } return status; } AJ_Status AJ_PeerHandleKeyAuthenticationReply(AJ_Message* msg) { AJ_Status status; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_PeerHandleKeyAuthenticationReply(msg=%p)\n", msg)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleKeyAuthenticationReply(msg=%p): error=%s.\n", msg, msg->error)); AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); if (0 == strncmp(msg->error, AJ_ErrResources, sizeof(AJ_ErrResources))) { status = AJ_ERR_RESOURCES; } else { status = AJ_ERR_SECURITY; HandshakeComplete(status); } return status; } if (AJ_AUTH_EXCHANGED != peerContext.state) { AJ_WarnPrintf(("AJ_PeerHandleKeyAuthenticationReply(msg=%p): Invalid state\n", msg)); AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); goto Exit; } /* Get the conversation digest before it's updated with this message */ status = AJ_ConversationHash_GetDigest(&authContext); if (AJ_OK != status) { goto Exit; } /* Update hash before unmarshalling (endian swaps may occur) */ AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); /* * Receive authentication material */ status = AJ_KeyAuthenticationUnmarshal(&authContext, msg); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_PeerHandleKeyAuthenticationReply(msg=%p): Key authentication unmarshal error\n", msg)); goto Exit; } /* * Key authentication complete - start the session */ AJ_InfoPrintf(("Key Authentication Complete\n")); peerContext.state = AJ_AUTH_SUCCESS; status = GenSessionKey(msg); return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } static AJ_Status GenSessionKey(AJ_Message* msg) { AJ_Status status; AJ_Message call; char guidStr[33]; AJ_GUID localGuid; AJ_InfoPrintf(("GenSessionKey(msg=%p)\n", msg)); status = AJ_MarshalMethodCall(msg->bus, &call, AJ_METHOD_GEN_SESSION_KEY, msg->sender, 0, AJ_NO_FLAGS, AJ_CALL_TIMEOUT); if (AJ_OK != status) { return status; } /* * Marshal local peer GUID, remote peer GUID, and local peer's GUID */ status = AJ_GetLocalGUID(&localGuid); if (AJ_OK != status) { return status; } status = AJ_GUID_ToString(&localGuid, guidStr, sizeof(guidStr)); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(&call, "s", guidStr); if (AJ_OK != status) { return status; } status = AJ_GUID_ToString(peerContext.peerGuid, guidStr, sizeof(guidStr)); if (AJ_OK != status) { return status; } status = AJ_RandHex(peerContext.nonce, sizeof(peerContext.nonce), AJ_NONCE_LEN); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(&call, "ss", guidStr, peerContext.nonce); if (AJ_OK != status) { return status; } /* * Initialize the conversation hash and hash the GUIDs. * May have already been done by ExchangeSuites. */ if (!AJ_ConversationHash_IsInitialized(&authContext)) { status = AJ_ConversationHash_Initialize(&authContext); if (AJ_OK != status) { return status; } status = HashGuids(&authContext, peerContext.peerGuid); if (AJ_OK != status) { return status; } } /* Hash the message */ AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, &call, HASH_MSG_MARSHALED); return AJ_DeliverMsg(&call); } AJ_Status AJ_PeerHandleGenSessionKey(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; char* remGuid; char* locGuid; char* nonce; AJ_GUID guid; AJ_GUID localGuid; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); /* * For 12 bytes of verifier, we need at least 12 * 2 characters * to store its representation in hex (24 octets + 1 octet for \0). * However, the KeyGen function demands a bigger buffer * (to store 16 bytes key in addition to the 12 bytes verifier). * Hence we allocate, the maximum of (12 * 2 + 1) and (16 + 12). */ char verifier[AJ_SESSION_KEY_LEN + AJ_VERIFIER_LEN]; AJ_InfoPrintf(("AJ_PeerHandleGenSessionKey(msg=%p, reply=%p)\n", msg, reply)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrResources); } /* * Initialize conversation hash and hash GUIDs. * May have already been done by ExchangeSuites. */ if (!AJ_ConversationHash_IsInitialized(&authContext)) { status = AJ_ConversationHash_Initialize(&authContext); if (AJ_OK != status) { goto Exit; } status = HashGuids(&authContext, peerGuid); if (AJ_OK != status) { goto Exit; } } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); if (AJ_AUTH_SUCCESS != peerContext.state) { /* * We don't have a saved master secret and we haven't generated one yet */ AJ_InfoPrintf(("AJ_PeerHandleGenSessionKey(msg=%p, reply=%p): Key not available\n", msg, reply)); status = AJ_MarshalErrorMsg(msg, reply, AJ_ErrRejected); if (AJ_OK == status) { AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); } return status; } /* * Remote peer GUID, Local peer GUID and Remote peer's nonce */ status = AJ_UnmarshalArgs(msg, "sss", &remGuid, &locGuid, &nonce); if (AJ_OK != status) { goto Exit; } /* * We expect arg[1] to be the local GUID */ status = AJ_GUID_FromString(&guid, locGuid); if (AJ_OK != status) { goto Exit; } status = AJ_GetLocalGUID(&localGuid); if (AJ_OK != status) { goto Exit; } if (0 != memcmp(&guid, &localGuid, sizeof(AJ_GUID))) { goto Exit; } status = AJ_RandHex(peerContext.nonce, sizeof(peerContext.nonce), AJ_NONCE_LEN); if (AJ_OK != status) { goto Exit; } status = KeyGen(msg->sender, AJ_ROLE_KEY_RESPONDER, nonce, peerContext.nonce, (uint8_t*)verifier, sizeof(verifier)); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalArgs(reply, "ss", peerContext.nonce, verifier); if (AJ_OK != status) { goto Exit; } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); status = AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); if (AJ_OK == status) { AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, reply, HASH_MSG_MARSHALED); } return status; } AJ_Status AJ_PeerHandleGenSessionKeyReply(AJ_Message* msg) { AJ_Status status; /* * For 12 bytes of verifier, we need at least 12 * 2 characters * to store its representation in hex (24 octets + 1 octet for \0). * However, the KeyGen function demands a bigger buffer * (to store 16 bytes key in addition to the 12 bytes verifier). * Hence we allocate, the maximum of (12 * 2 + 1) and (16 + 12). */ char verifier[AJ_VERIFIER_LEN + AJ_SESSION_KEY_LEN]; char* nonce; char* remVerifier; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_Arg key; AJ_Message call; uint8_t groupKey[AJ_SESSION_KEY_LEN]; AJ_InfoPrintf(("AJ_PeerHandleGenSessionKeyReply(msg=%p)\n", msg)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } AJ_ConversationHash_Update_Message(&authContext, CONVERSATION_V4, msg, HASH_MSG_UNMARSHALED); if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleGenSessionKeyReply(msg=%p): error=%s.\n", msg, msg->error)); if (0 == strncmp(msg->error, AJ_ErrResources, sizeof(AJ_ErrResources))) { status = AJ_ERR_RESOURCES; } else if (0 == strncmp(msg->error, AJ_ErrRejected, sizeof(AJ_ErrRejected))) { status = ExchangeSuites(msg); } else { status = AJ_ERR_SECURITY; HandshakeComplete(status); } return status; } status = AJ_UnmarshalArgs(msg, "ss", &nonce, &remVerifier); if (AJ_OK != status) { goto Exit; } status = KeyGen(msg->sender, AJ_ROLE_KEY_INITIATOR, peerContext.nonce, nonce, (uint8_t*)verifier, sizeof(verifier)); if (AJ_OK != status) { goto Exit; } /* * Check verifier strings match as expected */ if (0 != strncmp(remVerifier, verifier, sizeof (verifier))) { AJ_WarnPrintf(("AJ_PeerHandleGenSessionKeyReply(): AJ_ERR_SECURITY\n")); status = AJ_ERR_SECURITY; goto Exit; } /* * Group keys are exchanged via an encrypted message */ status = AJ_MarshalMethodCall(msg->bus, &call, AJ_METHOD_EXCHANGE_GROUP_KEYS, msg->sender, 0, AJ_FLAG_ENCRYPTED, AJ_CALL_TIMEOUT); if (AJ_OK != status) { goto Exit; } status = AJ_GetGroupKey(NULL, groupKey); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalArg(&call, AJ_InitArg(&key, AJ_ARG_BYTE, AJ_ARRAY_FLAG, groupKey, sizeof(groupKey))); if (AJ_OK != status) { goto Exit; } status = AJ_DeliverMsg(&call); return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } AJ_Status AJ_PeerHandleExchangeGroupKeys(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_Arg key; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); uint8_t groupKey[AJ_SESSION_KEY_LEN]; AJ_InfoPrintf(("AJ_PeerHandleExchangeGroupKeys(msg=%p, reply=%p)\n", msg, reply)); if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGroupKeys(msg=%p): error=%s.\n", msg, msg->error)); if (0 == strncmp(msg->error, AJ_ErrResources, sizeof(AJ_ErrResources))) { status = AJ_ERR_RESOURCES; } else { status = AJ_ERR_SECURITY; HandshakeComplete(status); } return status; } status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } status = AJ_UnmarshalArg(msg, &key); if (AJ_OK != status) { goto Exit; } /* * We expect the key to be 16 bytes */ if (key.len != AJ_SESSION_KEY_LEN) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGroupKeys(): AJ_ERR_INVALID\n")); goto Exit; } status = AJ_SetGroupKey(msg->sender, key.val.v_byte); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { goto Exit; } status = AJ_GetGroupKey(NULL, groupKey); if (AJ_OK != status) { goto Exit; } status = AJ_MarshalArg(reply, AJ_InitArg(&key, AJ_ARG_BYTE, AJ_ARRAY_FLAG, groupKey, sizeof(groupKey))); if (AJ_OK != status) { goto Exit; } status = AJ_PolicyApply(&authContext, msg->sender); if (AUTH_SUITE_ECDHE_ECDSA != authContext.suite) { HandshakeComplete(status); } /* Search for membership certificates from the beginning */ authContext.slot = AJ_CREDS_NV_ID_BEGIN; authContext.code = SEND_MEMBERSHIPS_NONE; status = AJ_CredentialGetNext(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, NULL, &authContext.slot); if (AJ_OK == status) { /* There is at least one cert to send, we don't know if the last yet */ authContext.code = SEND_MEMBERSHIPS_MORE; } status = AJ_OK; return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } AJ_Status AJ_PeerHandleExchangeGroupKeysReply(AJ_Message* msg) { AJ_Status status; AJ_Arg arg; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_InfoPrintf(("AJ_PeerHandleExchangeGroupKeysReply(msg=%p)\n", msg)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } status = AJ_UnmarshalArg(msg, &arg); if (AJ_OK != status) { goto Exit; } /* * We expect the key to be 16 bytes */ if (arg.len != AJ_SESSION_KEY_LEN) { AJ_WarnPrintf(("AJ_PeerHandleExchangeGroupKeysReply(msg=%p): AJ_ERR_INVALID\n", msg)); goto Exit; } status = AJ_SetGroupKey(msg->sender, arg.val.v_byte); if (AJ_OK != status) { goto Exit; } status = AJ_PolicyApply(&authContext, msg->sender); if (AJ_OK != status) { goto Exit; } if ((AUTH_SUITE_ECDHE_ECDSA == authContext.suite) && (AJ_UNPACK_AUTH_VERSION(authContext.version) >= CONVERSATION_V4)) { /* Search for membership certificates from the beginning */ authContext.slot = AJ_CREDS_NV_ID_BEGIN; authContext.code = SEND_MEMBERSHIPS_NONE; status = AJ_CredentialGetNext(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, NULL, &authContext.slot); AJ_InfoPrintf(("AJ_PeerHandleExchangeGroupKeysReply(msg=%p): Membership slot %d\n", msg, authContext.slot)); if (AJ_OK == status) { /* There is at least one certificate to send, we don't know if the last yet */ authContext.code = SEND_MEMBERSHIPS_MORE; } status = AJ_PeerSendManifests(msg, FALSE); } else { HandshakeComplete(status); } return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } AJ_Status AJ_PeerSendManifests(AJ_Message* msg, uint8_t outgoing) { AJ_Status status; AJ_Message call; const AJ_GUID* peerGuid = AJ_GUID_Find(outgoing ? msg->destination : msg->sender); AJ_CredField field = { 0, NULL }; AJ_ManifestArray* manifests = NULL; uint8_t mustClearAuthContext = FALSE; AJ_InfoPrintf(("AJ_PeerSendManifests(msg=%p, outgoing=%u)\n", msg, outgoing)); if (sentManifests) { /* Already sent. */ return AJ_OK; } if (NULL == authContext.bus) { status = LoadECDSAContext(peerGuid); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerSendManifests(msg=%p, outgoing=%u): Could not load ECDSA context for peer\n", msg, outgoing)); return AJ_ERR_SECURITY; } mustClearAuthContext = TRUE; } if (AUTH_SUITE_ECDHE_ECDSA != authContext.suite) { /* No need to send. */ status = AJ_OK; goto Exit; } status = AJ_MarshalMethodCall(msg->bus, &call, AJ_METHOD_SEND_MANIFESTS, (outgoing ? msg->destination : msg->sender), 0, AJ_FLAG_ENCRYPTED, AJ_AUTH_CALL_TIMEOUT); if (AJ_OK != status) { goto Exit; } status = AJ_CredentialGet(AJ_CRED_TYPE_MANIFESTS, NULL, NULL, &field); if (AJ_OK == status) { status = AJ_ManifestArrayFromBuffer(&manifests, &field); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerSendManifests(msg=%p): Manifests buffer failed\n", msg)); goto Exit; } } status = AJ_ManifestArrayMarshal(manifests, &call); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerSendManifests(msg=%p): Manifests marshal failed\n", msg)); goto Exit; } Exit: AJ_CredFieldFree(&field); AJ_ManifestArrayFree(manifests); if (AJ_OK == status) { status = AJ_DeliverMsg(&call); if (AJ_OK == status) { sentManifests = TRUE; } } if (mustClearAuthContext) { AJ_ClearAuthContext(); } return status; } AJ_Status AJ_PeerHandleSendManifests(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_CredField field = { 0, NULL }; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_ManifestArray* manifests = NULL; uint8_t mustClearAuthContext = FALSE; AJ_InfoPrintf(("AJ_PeerHandleSendManifests(msg=%p, reply=%p)\n", msg, reply)); /* * This might get called during handshake, or after. If after, load the ECDSA context * so the identity certificate thumbprint is available. */ if (NULL == authContext.bus) { status = LoadECDSAContext(peerGuid); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendManifests(msg=%p, reply=%p): Could not load ECDSA context for peer\n", msg, reply)); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } mustClearAuthContext = TRUE; } status = AJ_ManifestArrayUnmarshal(&manifests, msg); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendManifests(msg=%p, reply=%p): Manifests unmarshal failed\n", msg, reply)); goto Exit; } AJ_ManifestArrayApply(manifests, msg->sender, &authContext); AJ_ManifestArrayFree(manifests); manifests = NULL; status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendManifests(msg=%p, reply=%p): Manifest marshal failed\n", msg, reply)); goto Exit; } status = AJ_CredentialGet(AJ_CRED_TYPE_MANIFESTS, NULL, NULL, &field); if (AJ_OK == status) { status = AJ_ManifestArrayFromBuffer(&manifests, &field); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendManifests(msg=%p, reply=%p): Manifests buffer failed\n", msg, reply)); goto Exit; } } status = AJ_ManifestArrayMarshal(manifests, reply); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendManifests(msg=%p, reply=%p): Manifests marshal failed\n", msg, reply)); goto Exit; } AJ_ManifestArrayFree(manifests); manifests = NULL; Exit: AJ_CredFieldFree(&field); AJ_ManifestArrayFree(manifests); if (mustClearAuthContext) { AJ_ClearAuthContext(); } if (AJ_OK == status) { sentManifests = TRUE; return status; } else { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } } AJ_Status AJ_PeerHandleSendManifestsReply(AJ_Message* msg) { AJ_Status status; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); AJ_ManifestArray* manifests = NULL; uint8_t mustClearAuthContext = FALSE; AJ_InfoPrintf(("AJ_PeerHandleSendManifestsReply(msg=%p)\n", msg)); if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleSendManifestsReply(msg=%p): error=%s.\n", msg, msg->error)); goto Exit; } status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } /* * This might get called during handshake, or after. If after, load the ECDSA context * so the identity certificate thumbprint is available. */ if (NULL == authContext.bus) { status = LoadECDSAContext(peerGuid); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendManifestsReply(msg=%p): Could not load ECDSA context for peer\n", msg)); status = AJ_ERR_SECURITY; goto Exit; } mustClearAuthContext = TRUE; } status = AJ_ManifestArrayUnmarshal(&manifests, msg); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendManifestsReply(msg=%p): Manifests unmarshal failed\n", msg)); goto Exit; } AJ_ManifestArrayApply(manifests, msg->sender, &authContext); AJ_ManifestArrayFree(manifests); manifests = NULL; /* Search for membership certificates from the beginning */ authContext.slot = AJ_CREDS_NV_ID_BEGIN; authContext.code = SEND_MEMBERSHIPS_NONE; status = AJ_CredentialGetNext(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, NULL, &authContext.slot); AJ_InfoPrintf(("AJ_PeerHandleSendManifestsReply(msg=%p): Membership slot %d\n", msg, authContext.slot)); if (AJ_OK == status) { /* There is at least one cert to send, we don't know if the last yet */ authContext.code = SEND_MEMBERSHIPS_MORE; } status = AJ_OK; Exit: AJ_ManifestArrayFree(manifests); if (mustClearAuthContext) { AJ_ClearAuthContext(); } if (AJ_OK == status) { sentManifests = TRUE; return SendMemberships(msg); } else { HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } } static AJ_Status MarshalCertificates(X509CertificateChain* root, AJ_Message* msg) { AJ_Status status; AJ_Arg container; X509CertificateChain* head; uint8_t fmt = CERT_FMT_X509_DER; /* * X509CertificateChain is root first. * The wire protocol requires leaf first, * reverse it here, then reverse it back after marshalling. */ root = AJ_X509ReverseChain(root); status = AJ_MarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } head = root; while (head) { status = AJ_MarshalArgs(msg, "(yay)", fmt, head->certificate.der.data, head->certificate.der.size); if (AJ_OK != status) { goto Exit; } head = head->next; } status = AJ_MarshalCloseContainer(msg, &container); Exit: root = AJ_X509ReverseChain(root); return status; } static AJ_Status CommonIssuer(X509CertificateChain* root) { AJ_Status status = AJ_ERR_UNKNOWN; X509CertificateChain* node; size_t i; AJ_ASSERT(root); for (i = 1; i < authContext.kactx.ecdsa.num; i++) { node = root; /* Check if intermediate issuer signed the root */ if (AJ_OK == AJ_X509Verify(&node->certificate, &authContext.kactx.ecdsa.key[i])) { status = AJ_OK; goto Exit; } /* Check if intermediate issuer is a subject */ while (node && node->certificate.tbs.extensions.ca) { if (0 == memcmp(&node->certificate.tbs.publickey, &authContext.kactx.ecdsa.key[i], sizeof (AJ_ECCPublicKey))) { status = AJ_OK; goto Exit; } node = node->next; } } Exit: return status; } static AJ_Status MarshalMembership(AJ_Message* msg) { AJ_Status status = AJ_ERR_UNKNOWN; AJ_Arg container; AJ_CredField data; X509CertificateChain* root = NULL; AJ_ASSERT(SEND_MEMBERSHIPS_LAST != authContext.code); data.size = 0; data.data = NULL; while ((AJ_ERR_UNKNOWN == status) && (SEND_MEMBERSHIPS_MORE == authContext.code)) { /* * Read membership certificate at current slot, there should be one. * We then check if the root issuer is the same as any of the issuers * of the identity certificate (ASACORE-2104) */ status = AJ_CredentialGetNext(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, &data, &authContext.slot); authContext.slot++; if (AJ_OK == status) { status = AJ_X509ChainFromBuffer(&root, &data); if (AJ_OK == status) { status = CommonIssuer(root); AJ_InfoPrintf(("MarshalMembership(msg=%p): Common issuer %s\n", msg, AJ_StatusText(status))); } if (AJ_OK != status) { AJ_CredFieldFree(&data); AJ_X509ChainFree(root); root = NULL; status = AJ_ERR_UNKNOWN; } } else { authContext.code = SEND_MEMBERSHIPS_NONE; status = AJ_OK; } } if (SEND_MEMBERSHIPS_NONE == authContext.code) { AJ_InfoPrintf(("MarshalMembership(msg=%p): None certificate\n", msg)); status = AJ_MarshalArgs(msg, "y", authContext.code); if (AJ_OK != status) { AJ_InfoPrintf(("MarshalMembership(msg=%p): Marshal error\n", msg)); goto Exit; } status = AJ_MarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { AJ_InfoPrintf(("MarshalMembership(msg=%p): Marshal error\n", msg)); goto Exit; } status = AJ_MarshalCloseContainer(msg, &container); if (AJ_OK != status) { AJ_InfoPrintf(("MarshalMembership(msg=%p): Marshal error\n", msg)); goto Exit; } return status; } AJ_ASSERT(SEND_MEMBERSHIPS_MORE == authContext.code); /* Find slot of next membership certificate (if available) */ status = AJ_CredentialGetNext(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, NULL, &authContext.slot); if (AJ_OK != status) { AJ_InfoPrintf(("MarshalMembership(msg=%p): Last certificate\n", msg)); authContext.code = SEND_MEMBERSHIPS_LAST; } else { AJ_InfoPrintf(("MarshalMembership(msg=%p): More certificate\n", msg)); } /* Marshal code and certificate */ status = AJ_MarshalArgs(msg, "y", authContext.code); if (AJ_OK != status) { AJ_InfoPrintf(("MarshalMembership(msg=%p): Marshal error\n", msg)); goto Exit; } status = MarshalCertificates(root, msg); if (AJ_OK != status) { AJ_InfoPrintf(("MarshalMembership(msg=%p): Marshal error\n", msg)); goto Exit; } /* Once we send the last code, set it to none so we don't send any more */ if (SEND_MEMBERSHIPS_LAST == authContext.code) { authContext.code = SEND_MEMBERSHIPS_NONE; } Exit: AJ_X509ChainFree(root); AJ_CredFieldFree(&data); return status; } static AJ_Status SendMemberships(AJ_Message* msg) { AJ_Status status; AJ_Message call; AJ_InfoPrintf(("SendMemberships(msg=%p)\n", msg)); status = AJ_MarshalMethodCall(msg->bus, &call, AJ_METHOD_SEND_MEMBERSHIPS, msg->sender, 0, AJ_FLAG_ENCRYPTED, AJ_AUTH_CALL_TIMEOUT); if (AJ_OK != status) { AJ_InfoPrintf(("SendMemberships(msg=%p): Marshal error\n", msg)); goto Exit; } status = MarshalMembership(&call); if (AJ_OK != status) { AJ_InfoPrintf(("SendMemberships(msg=%p): Marshal error\n", msg)); goto Exit; } return AJ_DeliverMsg(&call); Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } static void UnmarshalCertificates(AJ_Message* msg) { AJ_Status status; AJ_Arg container; uint8_t alg; DER_Element der; X509CertificateChain* root = NULL; X509CertificateChain* node = NULL; AJ_ECCPublicKey* pub = NULL; DER_Element* group; uint32_t type; status = AJ_UnmarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } while (AJ_OK == status) { status = AJ_UnmarshalArgs(msg, "(yay)", &alg, &der.data, &der.size); if (AJ_OK != status) { break; } node = (X509CertificateChain*) AJ_Malloc(sizeof (X509CertificateChain)); if (NULL == node) { AJ_WarnPrintf(("UnmarshalCertificates(msg=%p): Resource error\n", msg)); goto Exit; } node->next = root; root = node; /* Set the der before it's consumed */ node->certificate.der.size = der.size; node->certificate.der.data = der.data; status = AJ_X509DecodeCertificateDER(&node->certificate, &der); if (AJ_OK != status) { AJ_WarnPrintf(("UnmarshalCertificates(msg=%p): Certificate decode failed\n", msg)); goto Exit; } /* * If this is the first certificate, check the subject public key * is the same as the authenticated one (from identity certificate) * Also save the group for authorisation check */ if (NULL == node->next) { AJ_ASSERT(authContext.kactx.ecdsa.key); AJ_ASSERT(authContext.kactx.ecdsa.num); if (0 != memcmp((uint8_t*) &node->certificate.tbs.publickey, (uint8_t*) &authContext.kactx.ecdsa.key[0], sizeof (AJ_ECCPublicKey))) { AJ_InfoPrintf(("UnmarshalCertificates(msg=%p): Subject invalid\n", msg)); goto Exit; } group = &node->certificate.tbs.extensions.group; AJ_DumpBytes("GROUP", group->data, group->size); } } if (AJ_ERR_NO_MORE != status) { AJ_InfoPrintf(("UnmarshalCertificates(msg=%p): Certificate chain error %s\n", msg, AJ_StatusText(status))); goto Exit; } status = AJ_UnmarshalCloseContainer(msg, &container); if (AJ_OK != status) { goto Exit; } /* Initial chain verification to validate intermediate issuers. * Type is ignored for auth version < 4. */ if (AJ_UNPACK_AUTH_VERSION(authContext.version) < CONVERSATION_V4) { type = 0; } else { type = AJ_CERTIFICATE_MBR_X509; } status = AJ_X509VerifyChain(root, NULL, type); if (AJ_OK != status) { AJ_InfoPrintf(("UnmarshalCertificates(msg=%p): Certificate chain invalid\n", msg)); goto Exit; } /* Verify the root certificate against the stored authorities */ pub = (AJ_ECCPublicKey*) AJ_Malloc(sizeof (AJ_ECCPublicKey)); if (NULL == pub) { AJ_InfoPrintf(("UnmarshalCertificates(msg=%p): AJ_ERR_RESOURCES\n", msg)); goto Exit; } status = AJ_PolicyVerifyCertificate(&root->certificate, pub); if (AJ_OK != status) { AJ_Free(pub); pub = NULL; /* Search for the intermediate issuers in the stored authorities */ status = AJ_PolicyFindAuthority(root); if (AJ_OK != status) { } } if (AJ_OK != status) { AJ_InfoPrintf(("UnmarshalCertificates(msg=%p): Certificate authority unknown\n", msg)); goto Exit; } AJ_InfoPrintf(("UnmarshalCertificates(msg=%p): Certificate chain valid\n", msg)); AJ_MembershipApply(root, pub, group, msg->sender); Exit: AJ_Free(pub); /* Free the cert chain */ while (root) { node = root; root = root->next; AJ_Free(node); } } AJ_Status AJ_PeerHandleSendMemberships(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); uint8_t code; AJ_InfoPrintf(("AJ_PeerHandleSendMemberships(msg=%p, reply=%p)\n", msg, reply)); status = HandshakeValid(peerGuid); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrResources); } status = AJ_UnmarshalArgs(msg, "y", &code); if (AJ_OK != status) { goto Exit; } AJ_InfoPrintf(("AJ_PeerHandleSendMemberships(msg=%p, reply=%p): Received code %d\n", msg, reply, code)); if (SEND_MEMBERSHIPS_NONE != code) { /* * Unmarshal certificate chain, verify and apply membership rules * If failure occured (eg. false certificate), the rules will not be applied. */ UnmarshalCertificates(msg); if (SEND_MEMBERSHIPS_LAST == code) { code = SEND_MEMBERSHIPS_NONE; } if (SEND_MEMBERSHIPS_LAST == code) { code = SEND_MEMBERSHIPS_NONE; } } status = AJ_MarshalReplyMsg(msg, reply); if (AJ_OK != status) { goto Exit; } status = MarshalMembership(reply); if (AJ_OK != status) { goto Exit; } if ((SEND_MEMBERSHIPS_NONE == authContext.code) && (SEND_MEMBERSHIPS_NONE == code)) { /* * Nothing more to send or receive. Try to send manifests. Don't call HandshakeComplete * until after so the authContext is still present. */ status = AJ_PeerSendManifests(msg, FALSE); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_PeerHandleSendMemberships(msg=%p, reply=%p): Couldn't AJ_PeerSendManifests; got %u\n", msg, reply, status)); } HandshakeComplete(status); } return status; Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } AJ_Status AJ_PeerHandleSendMembershipsReply(AJ_Message* msg) { AJ_Status status; const AJ_GUID* peerGuid = AJ_GUID_Find(msg->sender); uint8_t code; AJ_InfoPrintf(("AJ_PeerHandleSendMembershipsReply(msg=%p)\n", msg)); if (msg->hdr->msgType == AJ_MSG_ERROR) { AJ_WarnPrintf(("AJ_PeerHandleSendMembershipsReply(msg=%p): error=%s.\n", msg, msg->error)); goto Exit; } status = HandshakeValid(peerGuid); if (AJ_OK != status) { return status; } status = AJ_UnmarshalArgs(msg, "y", &code); if (AJ_OK != status) { goto Exit; } if (SEND_MEMBERSHIPS_NONE != code) { /* * Unmarshal certificate chain, verify and apply membership rules * If failure occured (eg. false certificate), the rules will not be applied. */ UnmarshalCertificates(msg); if (SEND_MEMBERSHIPS_LAST == code) { code = SEND_MEMBERSHIPS_NONE; } } if ((SEND_MEMBERSHIPS_NONE == authContext.code) && (SEND_MEMBERSHIPS_NONE == code)) { /* Nothing more to send or receive */ HandshakeComplete(status); return status; } else { return SendMemberships(msg); } Exit: HandshakeComplete(AJ_ERR_SECURITY); return AJ_ERR_SECURITY; } ajtcl-16.04/src/aj_security.c000066400000000000000000001254021271074662300161110ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE SECURITY #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgSECURITY = 0; #endif #define APPLICATION_VERSION 1 #define SECURITY_APPLICATION_VERSION 1 #define SECURITY_CLAIMABLE_APPLICATION_VERSION 2 #define SECURITY_MANAGED_APPLICATION_VERSION 1 #define PUBLICKEY_ALG_ECDSA_SHA256 0 #define PUBLICKEY_CRV_NISTP256 0 #define DIGEST_ALG_SHA256 0 static uint8_t initialised = FALSE; static uint8_t emit = FALSE; static uint8_t clear = FALSE; /** * Thin client does not keep authentication content in memory. * This includes: certificates, manifests, memberships, etc. * The access control for a peer is established during the * authentication handshake at the beginning of the session. * Hence it is not possible to dynamically modify access control * policy on existing sessions; that is, any management operations * that modify the policy will not affect current sessions. * This includes: * org.alljoyn.Bus.Security.ManagedApplication.Reset * org.alljoyn.Bus.Security.ManagedApplication.UpdatePolicy * org.alljoyn.Bus.Security.ManagedApplication.ResetPolicy * To avoid potential security issues, any policy modifications * will result in current sessions being dropped (session keys cleared). * This takes effect immediately after the method reply to the * management operation. * Affected peers will receive org.alljoyn.Bus.SecurityViolation error * on subsequent calls. These peers must reauthenticate. */ typedef struct _ClaimConfig { uint16_t state; uint16_t capabilities; uint16_t info; } ClaimConfig; static ClaimConfig g_config = { APP_STATE_NOT_CLAIMABLE, 0, 0 }; static AJ_Status SaveClaimConfig() { AJ_Status status; AJ_CredField data; data.size = sizeof (g_config); data.data = (uint8_t*) &g_config; status = AJ_CredentialSet(AJ_CONFIG_CLAIMSTATE | AJ_CRED_TYPE_CONFIG, NULL, 0xFFFFFFFF, &data); return status; } static AJ_Status LoadClaimConfig() { AJ_Status status; AJ_CredField data; data.size = sizeof (g_config); data.data = (uint8_t*) &g_config; status = AJ_CredentialGet(AJ_CONFIG_CLAIMSTATE | AJ_CRED_TYPE_CONFIG, NULL, NULL, &data); if (AJ_OK != status) { AJ_InfoPrintf(("LoadClaimConfig(): No stored config - using defaults\n")); g_config.state = APP_STATE_NOT_CLAIMABLE; g_config.capabilities = 0; g_config.info = 0; } return status; } void AJ_SecuritySetClaimConfig(AJ_BusAttachment* bus, uint16_t state, uint16_t capabilities, uint16_t info) { AJ_Status status; /* * Update state and emit signal. * Its up to the application to set/change this to a sensible option. */ g_config.state = state; g_config.capabilities = capabilities; g_config.info = info; status = SaveClaimConfig(); if (AJ_OK != status) { AJ_ErrPrintf(("AJ_SecuritySetClaimConfig(): failed to save claim config %s\n", AJ_StatusText(status))); } /* Explicitly emit the signal */ emit = TRUE; AJ_ApplicationStateSignal(bus); } void AJ_SecurityGetClaimConfig(uint16_t* state, uint16_t* capabilities, uint16_t* info) { *state = g_config.state; *capabilities = g_config.capabilities; *info = g_config.info; } AJ_Status AJ_SecurityInit(AJ_BusAttachment* bus) { AJ_Status status; AJ_ECCPublicKey pub; AJ_ECCPrivateKey prv; AJ_InfoPrintf(("AJ_SecurityInit(bus=%p): Initialised = %x\n", bus, initialised)); if (initialised) { return AJ_OK; } /* Check I have a key pair */ status = AJ_CredentialGetECCPublicKey(AJ_ECC_SIG, NULL, NULL, NULL); if (AJ_OK != status) { /* Generate my communication signing key */ status = AJ_GenerateECCKeyPair(&pub, &prv); if (AJ_OK != status) { return status; } status = AJ_CredentialSetECCPublicKey(AJ_ECC_SIG, NULL, 0xFFFFFFFF, &pub); if (AJ_OK != status) { return status; } status = AJ_CredentialSetECCPrivateKey(AJ_ECC_SIG, NULL, 0xFFFFFFFF, &prv); if (AJ_OK != status) { return status; } } /* Load the initial claim config */ LoadClaimConfig(); /* Only emit notification if state other then Not Claimable */ if (APP_STATE_NOT_CLAIMABLE != g_config.state) { emit = TRUE; } status = AJ_RegisterObjectsACL(); if (AJ_OK != status) { AJ_WarnPrintf(("AJ_SecurityInit(bus=%p): %s\n", bus, AJ_StatusText(status))); return status; } /* * Bind to the security management port */ AJ_InfoPrintf(("AJ_SecurityInit(bus=%p): Bind Session Port %d\n", bus, AJ_SECURE_MGMT_PORT)); status = AJ_BusBindSessionPort(bus, AJ_SECURE_MGMT_PORT, NULL, 0); return status; } AJ_Status AJ_SecurityBound(AJ_BusAttachment* bus) { AJ_InfoPrintf(("AJ_SecurityBound(bus=%p): Bind OK\n", bus)); initialised = TRUE; return AJ_OK; } void AJ_SecurityClose(AJ_BusAttachment* bus) { AJ_Status status; AJ_Message msg; AJ_InfoPrintf(("AJ_SecurityClose(bus=%p)\n", bus)); /* We don't need to wait for the response */ status = AJ_MarshalMethodCall(bus, &msg, AJ_METHOD_UNBIND_SESSION, AJ_BusDestination, 0, AJ_FLAG_NO_REPLY_EXPECTED, 0); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "q", AJ_SECURE_MGMT_PORT); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } initialised = FALSE; AJ_AuthorisationClose(); } AJ_Status AJ_UnmarshalECCPublicKey(AJ_Message* msg, AJ_ECCPublicKey* pub, DER_Element* kid) { AJ_Status status = AJ_OK; uint8_t* x; uint8_t* y; size_t xlen; size_t ylen; if (NULL == kid) { /* Unmarshal key */ status = AJ_UnmarshalArgs(msg, "(yyayay)", &pub->alg, &pub->crv, &x, &xlen, &y, &ylen); } else { /* Unmarshal key with identifier */ status = AJ_UnmarshalArgs(msg, "(yyayayay)", &pub->alg, &pub->crv, &kid->data, &kid->size, &x, &xlen, &y, &ylen); } if (AJ_OK != status) { goto Exit; } if (PUBLICKEY_ALG_ECDSA_SHA256 != pub->alg) { goto Exit; } if (PUBLICKEY_CRV_NISTP256 != pub->crv) { goto Exit; } if ((KEY_ECC_SZ != xlen) || (KEY_ECC_SZ != ylen)) { goto Exit; } memcpy(pub->x, x, KEY_ECC_SZ); memcpy(pub->y, y, KEY_ECC_SZ); return AJ_OK; Exit: return AJ_ERR_INVALID; } AJ_Status AJ_GetCertificateId(X509CertificateChain* root, AJ_CertificateId* id) { AJ_Status status; X509Certificate* leaf; AJ_ASSERT(id); AJ_ASSERT(root); leaf = AJ_X509LeafCertificate(root); AJ_ASSERT(leaf); /* AKI is in the root certificate */ id->aki.data = root->certificate.tbs.extensions.aki.data; id->aki.size = root->certificate.tbs.extensions.aki.size; /* Serial number is in the leaf certificate */ id->serial.data = leaf->tbs.serial.data; id->serial.size = leaf->tbs.serial.size; /* Authority PublicKey is in the policy, can't rely on AKI */ AJ_PolicyLoad(); status = AJ_PolicyVerifyCertificate(&root->certificate, &id->pub); AJ_PolicyUnload(); return status; } static AJ_Status SetDefaultPolicy(AJ_PermissionPeer* ca, AJ_PermissionPeer* admin) { AJ_Status status; AJ_CredField data = { 0, NULL }; /* Create a marshalled policy message - 512 bytes should be sufficient */ data.size = 512; data.data = AJ_Malloc(data.size); if (NULL == data.data) { goto Exit; } status = AJ_MarshalDefaultPolicy(&data, ca, admin); if (AJ_OK != status) { goto Exit; } /* Store the default policy */ status = AJ_CredentialSet(AJ_POLICY_DEFAULT | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &data); Exit: AJ_CredFieldFree(&data); return status; } //SIG = a(ayayyyayay) static AJ_Status MarshalMembershipIds(AJ_Message* msg) { AJ_Status status; AJ_Arg container; AJ_CredField data = { 0, NULL }; X509CertificateChain* root = NULL; AJ_CertificateId certificate; uint16_t slot = AJ_CREDS_NV_ID_BEGIN; status = AJ_MarshalContainer(msg, &container, AJ_ARG_ARRAY); if (AJ_OK != status) { goto Exit; } while (AJ_OK == status) { data.data = NULL; status = AJ_CredentialGetNext(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, &data, &slot); slot++; if (AJ_OK == status) { status = AJ_X509ChainFromBuffer(&root, &data); if (AJ_OK != status) { goto Exit; } status = AJ_GetCertificateId(root, &certificate); if (AJ_OK != status) { goto Exit; } AJ_X509ChainFree(root); root = NULL; status = AJ_MarshalArgs(msg, "(ayay(yyayay))", certificate.serial.data, certificate.serial.size, certificate.aki.data, certificate.aki.size, certificate.pub.alg, certificate.pub.crv, certificate.pub.x, KEY_ECC_SZ, certificate.pub.y, KEY_ECC_SZ); if (AJ_OK != status) { goto Exit; } } AJ_CredFieldFree(&data); } status = AJ_MarshalCloseContainer(msg, &container); Exit: AJ_X509ChainFree(root); AJ_CredFieldFree(&data); return status; } AJ_Status AJ_ApplicationStateSignal(AJ_BusAttachment* bus) { AJ_Status status = AJ_OK; AJ_Message msg; AJ_ECCPublicKey pub; /* Clear session keys if required */ if (clear) { AJ_InfoPrintf(("AJ_ApplicationStateSignal(bus=%p): Clear session keys\n", bus)); AJ_GUID_ClearNameMap(); clear = FALSE; } if (!emit || !initialised) { return AJ_OK; } emit = FALSE; AJ_InfoPrintf(("AJ_ApplicationStateSignal(bus=%p)\n", bus)); status = AJ_MarshalSignal(bus, &msg, AJ_SIGNAL_APPLICATION_STATE, NULL, 0, ALLJOYN_FLAG_SESSIONLESS, 0); if (AJ_OK != status) { return status; } status = AJ_CredentialGetECCPublicKey(AJ_ECC_SIG, NULL, NULL, &pub); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(&msg, "(yyayay)", pub.alg, pub.crv, pub.x, sizeof (pub.x), pub.y, sizeof (pub.y)); if (AJ_OK != status) { return status; } status = AJ_MarshalArgs(&msg, "q", g_config.state); if (AJ_OK != status) { return status; } status = AJ_DeliverMsg(&msg); return status; } /* * org.alljoyn.Bus.Security.Application implementation */ static AJ_Status SecurityGetProperty(AJ_Message* reply, uint32_t id, void* context) { AJ_Status status = AJ_ERR_UNEXPECTED; AJ_CredField field = { 0, NULL }; AJ_ECCPublicKey pub; uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; uint32_t version; AJ_ManifestArray* manifests = NULL; AJ_Policy* policy = NULL; AJ_CertificateId certificate; X509CertificateChain* root = NULL; AJ_InfoPrintf(("SecurityGetProperty(reply=%p, id=%x, context=%p)\n", reply, id, context)); switch (id) { case AJ_PROPERTY_APPLICATION_VERSION: status = AJ_MarshalArgs(reply, "q", (uint16_t) APPLICATION_VERSION); break; case AJ_PROPERTY_SEC_VERSION: status = AJ_MarshalArgs(reply, "q", (uint16_t) SECURITY_APPLICATION_VERSION); break; case AJ_PROPERTY_SEC_APPLICATION_STATE: status = AJ_MarshalArgs(reply, "q", g_config.state); break; case AJ_PROPERTY_SEC_MANIFEST_DIGEST: status = AJ_CredentialGet(AJ_CRED_TYPE_MANIFESTS, NULL, NULL, &field); if (AJ_OK != status) { break; } status = AJ_ManifestDigest(&field, digest); if (AJ_OK != status) { break; } status = AJ_MarshalArgs(reply, "(yay)", DIGEST_ALG_SHA256, digest, AJ_SHA256_DIGEST_LENGTH); break; case AJ_PROPERTY_SEC_ECC_PUBLICKEY: status = AJ_CredentialGetECCPublicKey(AJ_ECC_SIG, NULL, NULL, &pub); if (AJ_OK != status) { break; } status = AJ_MarshalArgs(reply, "(yyayay)", pub.alg, pub.crv, pub.x, sizeof (pub.x), pub.y, sizeof (pub.y)); break; case AJ_PROPERTY_SEC_MANUFACTURER_CERTIFICATE: status = AJ_CredentialGet(AJ_CERTIFICATE_OEM_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, &field); if (AJ_OK != status) { break; } status = AJ_X509ChainFromBuffer(&root, &field); if (AJ_OK != status) { break; } status = AJ_X509ChainMarshal(root, reply); break; case AJ_PROPERTY_SEC_MANIFEST_TEMPLATE: status = AJ_ManifestTemplateMarshal(reply); break; case AJ_PROPERTY_SEC_CLAIM_CAPABILITIES: status = AJ_MarshalArgs(reply, "q", g_config.capabilities); break; case AJ_PROPERTY_SEC_CLAIM_CAPABILITIES_INFO: status = AJ_MarshalArgs(reply, "q", g_config.info); break; case AJ_PROPERTY_CLAIMABLE_VERSION: status = AJ_MarshalArgs(reply, "q", (uint16_t) SECURITY_CLAIMABLE_APPLICATION_VERSION); break; case AJ_PROPERTY_MANAGED_VERSION: status = AJ_MarshalArgs(reply, "q", (uint16_t) SECURITY_MANAGED_APPLICATION_VERSION); break; case AJ_PROPERTY_MANAGED_IDENTITY: status = AJ_CredentialGet(AJ_CERTIFICATE_IDN_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, &field); if (AJ_OK != status) { break; } status = AJ_X509ChainFromBuffer(&root, &field); if (AJ_OK != status) { break; } status = AJ_X509ChainMarshal(root, reply); break; case AJ_PROPERTY_MANAGED_MANIFESTS: status = AJ_CredentialGet(AJ_CRED_TYPE_MANIFESTS, NULL, NULL, &field); if (AJ_OK != status) { break; } status = AJ_ManifestArrayFromBuffer(&manifests, &field); if (AJ_OK != status) { break; } status = AJ_ManifestArrayMarshal(manifests, reply); if (AJ_OK != status) { break; } break; case AJ_PROPERTY_MANAGED_IDENTITY_CERT_ID: status = AJ_CredentialGet(AJ_CERTIFICATE_IDN_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, NULL, &field); if (AJ_OK != status) { break; } status = AJ_X509ChainFromBuffer(&root, &field); if (AJ_OK != status) { break; } status = AJ_GetCertificateId(root, &certificate); if (AJ_OK != status) { break; } status = AJ_MarshalArgs(reply, "(ayay(yyayay))", certificate.serial.data, certificate.serial.size, certificate.aki.data, certificate.aki.size, certificate.pub.alg, certificate.pub.crv, certificate.pub.x, KEY_ECC_SZ, certificate.pub.y, KEY_ECC_SZ); break; case AJ_PROPERTY_MANAGED_POLICY_VERSION: status = AJ_PolicyVersion(&version); if (AJ_OK != status) { break; } status = AJ_MarshalArgs(reply, "u", version); break; case AJ_PROPERTY_MANAGED_POLICY: status = AJ_CredentialGet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, NULL, &field); if (AJ_OK != status) { break; } status = AJ_PolicyFromBuffer(&policy, &field); if (AJ_OK != status) { break; } status = AJ_PolicyMarshal(policy, reply); if (AJ_OK != status) { break; } AJ_PolicyFree(policy); policy = NULL; break; case AJ_PROPERTY_MANAGED_DEFAULT_POLICY: status = AJ_CredentialGet(AJ_POLICY_DEFAULT | AJ_CRED_TYPE_POLICY, NULL, NULL, &field); if (AJ_OK != status) { break; } status = AJ_PolicyFromBuffer(&policy, &field); if (AJ_OK != status) { break; } status = AJ_PolicyMarshal(policy, reply); if (AJ_OK != status) { break; } AJ_PolicyFree(policy); policy = NULL; break; case AJ_PROPERTY_MANAGED_MEMBERSHIP_SUMMARY: status = MarshalMembershipIds(reply); break; default: status = AJ_ERR_UNEXPECTED; break; } AJ_CredFieldFree(&field); AJ_X509ChainFree(root); AJ_ManifestArrayFree(manifests); AJ_PolicyFree(policy); return status; } AJ_Status AJ_SecurityGetProperty(AJ_Message* msg) { return AJ_BusPropGet(msg, SecurityGetProperty, NULL); } static AJ_Status VerifyIdentityCertificateChain(X509CertificateChain* root, AJ_ECCPublicKey* issuer) { AJ_Status status; AJ_ECCPublicKey pub; X509Certificate* leaf; leaf = AJ_X509LeafCertificate(root); if (NULL == leaf) { status = AJ_ERR_SECURITY; goto Exit; } /* Verify certificate in case of buggy security manager */ status = AJ_X509VerifyChain(root, issuer, AJ_CERTIFICATE_IDN_X509); if (AJ_OK != status) { status = AJ_ERR_SECURITY_INVALID_CERTIFICATE; goto Exit; } /* Check leaf certificate public key is mine */ status = AJ_CredentialGetECCPublicKey(AJ_ECC_SIG, NULL, NULL, &pub); if (AJ_OK != status) { goto Exit; } if (0 != memcmp((uint8_t*) &pub, &leaf->tbs.publickey, sizeof (pub))) { status = AJ_ERR_SECURITY; goto Exit; } status = AJ_OK; Exit: return status; } static AJ_Status VerifyMembershipCertificateChain(X509CertificateChain* root) { AJ_Status status; AJ_ECCPublicKey pub; X509Certificate* leaf; leaf = AJ_X509LeafCertificate(root); if (NULL == leaf) { status = AJ_ERR_SECURITY; goto Exit; } /* Verify certificate in case of buggy security manager */ status = AJ_X509VerifyChain(root, NULL, AJ_CERTIFICATE_MBR_X509); if (AJ_OK != status) { status = AJ_ERR_SECURITY_INVALID_CERTIFICATE; goto Exit; } /* Check leaf certificate public key is mine */ status = AJ_CredentialGetECCPublicKey(AJ_ECC_SIG, NULL, NULL, &pub); if (AJ_OK != status) { goto Exit; } if (0 != memcmp((uint8_t*) &pub, &leaf->tbs.publickey, sizeof (pub))) { status = AJ_ERR_SECURITY; goto Exit; } status = AJ_OK; Exit: return status; } /* * org.alljoyn.Bus.Security.ClaimableApplication implementation */ AJ_Status AJ_SecurityClaimMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status = AJ_OK; AJ_PermissionPeer ca; AJ_PermissionPeer admin; AJ_CredField data; X509CertificateChain* identity = NULL; AJ_CredField identity_data = { 0, NULL }; AJ_ManifestArray* manifests = NULL; AJ_CredField manifests_data = { 0, NULL }; AJ_InfoPrintf(("AJ_SecurityClaimMethod(msg=%p, reply=%p)\n", msg, reply)); if (APP_STATE_CLAIMABLE != g_config.state) { AJ_InfoPrintf(("AJ_SecurityClaimMethod(msg=%p, reply=%p): Not in claimable state\n", msg, reply)); return AJ_MarshalErrorMsg(msg, reply, AJ_ErrPermissionDenied); } /* Unmarshal certificate authority */ status = AJ_UnmarshalECCPublicKey(msg, &ca.pub, NULL); if (AJ_OK != status) { goto Exit; } /* Unmarshal certificate authority identifier */ status = AJ_UnmarshalArgs(msg, "ay", &ca.kid.data, &ca.kid.size); if (AJ_OK != status) { goto Exit; } if (0 == ca.kid.size) { AJ_InfoPrintf(("AJ_SecurityClaimMethod(msg=%p, reply=%p): Empty AKI\n", msg, reply)); status = AJ_ERR_SECURITY; goto Exit; } /* Unmarshal admin group guid */ status = AJ_UnmarshalArgs(msg, "ay", &admin.group.data, &admin.group.size); if (AJ_OK != status) { goto Exit; } /* Store the admin group guid */ data.size = admin.group.size; data.data = admin.group.data; status = AJ_CredentialSet(AJ_CONFIG_ADMIN_GROUP | AJ_CRED_TYPE_CONFIG, NULL, 0xFFFFFFFF, &data); if (AJ_OK != status) { goto Exit; } /* Unmarshal admin certificate authority */ status = AJ_UnmarshalECCPublicKey(msg, &admin.pub, NULL); if (AJ_OK != status) { goto Exit; } /* Unmarshal admin certificate authority identifier */ status = AJ_UnmarshalArgs(msg, "ay", &admin.kid.data, &admin.kid.size); if (AJ_OK != status) { goto Exit; } if (0 == admin.kid.size) { AJ_InfoPrintf(("AJ_SecurityClaimMethod(msg=%p, reply=%p): Empty AKI\n", msg, reply)); status = AJ_ERR_SECURITY; goto Exit; } /* Unmarshal identity certificate */ identity_data.data = msg->bus->sock.rx.readPtr; status = AJ_X509ChainUnmarshal(&identity, msg); if (AJ_OK != status) { identity_data.data = NULL; goto Exit; } identity_data.size = msg->bus->sock.rx.readPtr - identity_data.data; /* Allow additional 8 bytes for maximum padding */ identity_data.size += 8; identity_data.data = AJ_Malloc(identity_data.size); if (NULL == identity_data.data) { status = AJ_ERR_RESOURCES; goto Exit; } status = AJ_X509ChainToBuffer(identity, &identity_data); if (AJ_OK != status) { goto Exit; } /* Unmarshal manifests */ manifests_data.data = msg->bus->sock.rx.readPtr; status = AJ_ManifestArrayUnmarshal(&manifests, msg); if (AJ_OK != status) { manifests_data.data = NULL; goto Exit; } /* Filter out any unsigned manifests. */ AJ_ManifestArrayFilterUnsigned(&manifests); /* If none succeded, fail. */ if (NULL == manifests) { status = AJ_ERR_SECURITY_DIGEST_MISMATCH; manifests_data.data = NULL; goto Exit; } manifests_data.size = msg->bus->sock.rx.readPtr - manifests_data.data; /* Allow additional 8 bytes for maximum padding */ manifests_data.size += 8; manifests_data.data = AJ_Malloc(manifests_data.size); if (NULL == manifests_data.data) { status = AJ_ERR_RESOURCES; goto Exit; } status = AJ_ManifestArrayToBuffer(manifests, &manifests_data); if (AJ_OK != status) { goto Exit; } /* Validate Identity chain */ status = VerifyIdentityCertificateChain(identity, &ca.pub); if (AJ_OK != status) { status = VerifyIdentityCertificateChain(identity, &admin.pub); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_SecurityClaimMethod(msg=%p, reply=%p): %s\n", msg, reply, AJ_StatusText(status))); goto Exit; } } /* Store identity certificate as raw marshalled body */ status = AJ_CredentialSet(AJ_CERTIFICATE_IDN_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, 0xFFFFFFFF, &identity_data); if (AJ_OK != status) { goto Exit; } /* Store manifest as raw marshalled body */ status = AJ_CredentialSet(AJ_CRED_TYPE_MANIFESTS, NULL, 0xFFFFFFFF, &manifests_data); if (AJ_OK != status) { goto Exit; } /* Set default policy */ ca.type = AJ_PEER_TYPE_FROM_CA; ca.next = NULL; admin.type = AJ_PEER_TYPE_WITH_MEMBERSHIP; admin.next = NULL; status = SetDefaultPolicy(&ca, &admin); if (AJ_OK != status) { goto Exit; } /* Clear master secrets, do not fail on error (missing entries) */ AJ_ClearCredentials(AJ_GENERIC_MASTER_SECRET | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_THUMBPRINT | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_KEYS | AJ_CRED_TYPE_GENERIC); /* Set claim state and save to nvram */ g_config.state = APP_STATE_CLAIMED; status = SaveClaimConfig(); if (AJ_OK != status) { AJ_ErrPrintf(("AJ_SecurityClaimMethod(): failed to save claim config %s\n", AJ_StatusText(status))); } /* Claim state changes from Claimable to Claimed --> emit notification */ emit = TRUE; Exit: AJ_X509ChainFree(identity); AJ_CredFieldFree(&identity_data); AJ_ManifestArrayFree(manifests); AJ_CredFieldFree(&manifests_data); if (AJ_OK == status) { if (msg->bus->policyChangedCallback) { msg->bus->policyChangedCallback(); } return AJ_MarshalReplyMsg(msg, reply); } else { /* Remove stored values on error */ AJ_ClearCredentials(AJ_CONFIG_ADMIN_GROUP | AJ_CRED_TYPE_CONFIG); AJ_ClearCredentials(AJ_CERTIFICATE_IDN_X509 | AJ_CRED_TYPE_CERTIFICATE); AJ_ClearCredentials(AJ_CRED_TYPE_MANIFESTS); AJ_ClearCredentials(AJ_POLICY_DEFAULT | AJ_CRED_TYPE_POLICY); return AJ_MarshalStatusMsg(msg, reply, status); } } /* * org.alljoyn.Bus.Security.ManagedApplication implementation */ AJ_Status AJ_SecurityResetMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_InfoPrintf(("AJ_SecurityResetMethod(msg=%p, reply=%p)\n", msg, reply)); status = AJ_SecurityReset(msg->bus); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } else { return AJ_MarshalReplyMsg(msg, reply); } } AJ_Status AJ_SecurityReset(AJ_BusAttachment* bus) { AJ_Status status; AJ_ECCPublicKey pub; AJ_ECCPrivateKey prv; if (bus->factoryResetCallback) { status = bus->factoryResetCallback(); if (AJ_OK != status) { goto Exit; } } /* Clear everything out except ECDSA signature pair */ /* Ignore failures getting keys - they're about to be cleared */ AJ_CredentialGetECCPublicKey(AJ_ECC_SIG, NULL, NULL, &pub); AJ_CredentialGetECCPrivateKey(AJ_ECC_SIG, NULL, NULL, &prv); status = AJ_ClearCredentials(0); if (AJ_OK != status) { goto Exit; } status = AJ_CredentialSetECCPublicKey(AJ_ECC_SIG, NULL, 0xFFFFFFFF, &pub); if (AJ_OK != status) { goto Exit; } status = AJ_CredentialSetECCPrivateKey(AJ_ECC_SIG, NULL, 0xFFFFFFFF, &prv); if (AJ_OK != status) { goto Exit; } /* Set claim state and save to nvram */ g_config.state = APP_STATE_NOT_CLAIMABLE; status = SaveClaimConfig(); if (AJ_OK != status) { AJ_ErrPrintf(("AJ_SecurityResetMethod(): failed to save claim config %s\n", AJ_StatusText(status))); goto Exit; } /* Claim state changes from Claimed to Not Claimable --> emit notification */ emit = TRUE; /* Clear session keys, can't do it now because we need to reply */ clear = TRUE; if (bus->policyChangedCallback) { bus->policyChangedCallback(); } return AJ_OK; Exit: return AJ_ERR_SECURITY; } AJ_Status AJ_SecurityUpdateIdentityMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; X509CertificateChain* identity = NULL; AJ_CredField identity_data = { 0, NULL }; AJ_ManifestArray* manifests = NULL; AJ_CredField manifests_data = { 0, NULL }; AJ_InfoPrintf(("AJ_SecurityUpdateIdentityMethod(msg=%p, reply=%p)\n", msg, reply)); /* Unmarshal identity certificate */ identity_data.data = msg->bus->sock.rx.readPtr; status = AJ_X509ChainUnmarshal(&identity, msg); if (AJ_OK != status) { identity_data.data = NULL; goto Exit; } identity_data.size = msg->bus->sock.rx.readPtr - identity_data.data; /* Allow additional 8 bytes for maximum padding */ identity_data.size += 8; identity_data.data = AJ_Malloc(identity_data.size); if (NULL == identity_data.data) { status = AJ_ERR_RESOURCES; goto Exit; } status = AJ_X509ChainToBuffer(identity, &identity_data); if (AJ_OK != status) { goto Exit; } /* Validate Identity chain */ status = VerifyIdentityCertificateChain(identity, NULL); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_SecurityUpdateIdentityMethod(msg=%p, reply=%p): %s\n", msg, reply, AJ_StatusText(status))); goto Exit; } /* Unmarshal manifests */ manifests_data.data = msg->bus->sock.rx.readPtr; status = AJ_ManifestArrayUnmarshal(&manifests, msg); if (AJ_OK != status) { manifests_data.data = NULL; goto Exit; } /* Filter out any unsigned manifests. */ AJ_ManifestArrayFilterUnsigned(&manifests); /* If none succeded, fail. */ if (NULL == manifests) { status = AJ_ERR_SECURITY_DIGEST_MISMATCH; manifests_data.data = NULL; goto Exit; } manifests_data.size = msg->bus->sock.rx.readPtr - manifests_data.data; /* Allow additional 8 bytes for maximum padding */ manifests_data.size += 8; manifests_data.data = AJ_Malloc(manifests_data.size); if (NULL == manifests_data.data) { status = AJ_ERR_RESOURCES; goto Exit; } status = AJ_ManifestArrayToBuffer(manifests, &manifests_data); if (AJ_OK != status) { goto Exit; } /* Store identity certificate as raw marshalled body */ status = AJ_CredentialSet(AJ_CERTIFICATE_IDN_X509 | AJ_CRED_TYPE_CERTIFICATE, NULL, 0xFFFFFFFF, &identity_data); if (AJ_OK != status) { goto Exit; } /* Store manifest as raw marshalled body */ status = AJ_CredentialSet(AJ_CRED_TYPE_MANIFESTS, NULL, 0xFFFFFFFF, &manifests_data); if (AJ_OK != status) { goto Exit; } AJ_ASSERT((APP_STATE_CLAIMED == g_config.state) || (APP_STATE_NEED_UPDATE == g_config.state)); /* If state was need update, set back to claimed and emit notification */ if (APP_STATE_NEED_UPDATE == g_config.state) { /* Set claim state and save to nvram */ g_config.state = APP_STATE_CLAIMED; status = SaveClaimConfig(); if (AJ_OK != status) { AJ_ErrPrintf(("AJ_SecurityUpdateIdentityMethod(): failed to save claim config %s\n", AJ_StatusText(status))); } /* Claim state changes from Need update to Claimed --> emit notification */ emit = TRUE; } Exit: AJ_X509ChainFree(identity); AJ_CredFieldFree(&identity_data); AJ_ManifestArrayFree(manifests); AJ_CredFieldFree(&manifests_data); if (AJ_OK == status) { return AJ_MarshalReplyMsg(msg, reply); } else { return AJ_MarshalStatusMsg(msg, reply, status); } } AJ_Status AJ_SecurityUpdatePolicyMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_Policy* policy = NULL; AJ_CredField policy_data = { 0, NULL }; uint32_t version = 0; AJ_InfoPrintf(("AJ_SecurityUpdatePolicyMethod(msg=%p, reply=%p)\n", msg, reply)); /* Get current version */ status = AJ_PolicyVersion(&version); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_SecurityUpdatePolicyMethod(msg=%p, reply=%p): No installed or default policy\n", msg, reply)); } /* Unmarshal policy */ policy_data.data = msg->bus->sock.rx.readPtr; status = AJ_PolicyUnmarshal(&policy, msg); if (AJ_OK != status) { policy_data.data = NULL; goto Exit; } AJ_ASSERT(policy); if (policy->version <= version) { status = AJ_ERR_SECURITY_POLICY_NOT_NEWER; policy_data.data = NULL; goto Exit; } policy_data.size = msg->bus->sock.rx.readPtr - policy_data.data; /* Allow additional 8 bytes for maximum padding */ policy_data.size += 8; policy_data.data = AJ_Malloc(policy_data.size); if (NULL == policy_data.data) { status = AJ_ERR_RESOURCES; goto Exit; } status = AJ_PolicyToBuffer(policy, &policy_data); if (AJ_OK != status) { goto Exit; } AJ_PolicyFree(policy); policy = NULL; /* Store policy as raw marshalled body */ status = AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &policy_data); if (AJ_OK != status) { goto Exit; } AJ_CredFieldFree(&policy_data); /* Clear master secrets, do not fail on error (missing entries) */ AJ_ClearCredentials(AJ_GENERIC_MASTER_SECRET | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_THUMBPRINT | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_KEYS | AJ_CRED_TYPE_GENERIC); /* Clear session keys, can't do it now because we need to reply */ clear = TRUE; Exit: AJ_PolicyFree(policy); AJ_CredFieldFree(&policy_data); if (AJ_OK == status) { return AJ_MarshalReplyMsg(msg, reply); } else { return AJ_MarshalStatusMsg(msg, reply, status); } } AJ_Status AJ_SecurityResetPolicyMethod(AJ_Message* msg, AJ_Message* reply) { AJ_InfoPrintf(("AJ_SecurityResetPolicyMethod(msg=%p, reply=%p)\n", msg, reply)); /* Delete installed policy, do not fail on error (missing entry) */ AJ_CredentialDelete(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL); /* Clear master secrets, do not fail on error (missing entries) */ AJ_ClearCredentials(AJ_GENERIC_MASTER_SECRET | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_THUMBPRINT | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_KEYS | AJ_CRED_TYPE_GENERIC); /* Clear session keys, can't do it now because we need to reply */ clear = TRUE; return AJ_MarshalReplyMsg(msg, reply); } AJ_Status AJ_SecurityInstallMembershipMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_CredField id = { 0, NULL }; X509CertificateChain* membership = NULL; AJ_CredField membership_data = { 0, NULL }; AJ_CertificateId certificate; uint8_t* tmp; AJ_InfoPrintf(("AJ_SecurityInstallMembershipMethod(msg=%p, reply=%p)\n", msg, reply)); /* Unmarshal membership certificate */ membership_data.data = msg->bus->sock.rx.readPtr; status = AJ_X509ChainUnmarshal(&membership, msg); if (AJ_OK != status) { membership_data.data = NULL; goto Exit; } membership_data.size = msg->bus->sock.rx.readPtr - membership_data.data; /* Allow additional 8 bytes for maximum padding */ membership_data.size += 8; membership_data.data = AJ_Malloc(membership_data.size); if (NULL == membership_data.data) { status = AJ_ERR_RESOURCES; goto Exit; } status = AJ_X509ChainToBuffer(membership, &membership_data); if (AJ_OK != status) { goto Exit; } status = AJ_GetCertificateId(membership, &certificate); if (AJ_OK != status) { status = AJ_ERR_SECURITY_INVALID_CERTIFICATE; goto Exit; } /* Validate Membership chain */ status = VerifyMembershipCertificateChain(membership); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_SecurityInstallMembershipMethod(msg=%p, reply=%p): %s\n", msg, reply, AJ_StatusText(status))); goto Exit; } id.size = certificate.serial.size + certificate.aki.size; id.data = AJ_Malloc(id.size); if (NULL == id.data) { goto Exit; } tmp = id.data; memcpy(tmp, certificate.serial.data, certificate.serial.size); tmp += certificate.serial.size; memcpy(tmp, certificate.aki.data, certificate.aki.size); tmp += certificate.aki.size; /* Do not allow duplication/replacement */ status = AJ_CredentialGet(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, &id, NULL, NULL); if (AJ_OK == status) { status = AJ_ERR_SECURITY_DUPLICATE_CERTIFICATE; goto Exit; } /* Store membership certificate as raw marshalled body */ status = AJ_CredentialSet(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, &id, 0xFFFFFFFF, &membership_data); Exit: AJ_CredFieldFree(&id); AJ_CredFieldFree(&membership_data); AJ_X509ChainFree(membership); if (AJ_OK == status) { return AJ_MarshalReplyMsg(msg, reply); } else { return AJ_MarshalStatusMsg(msg, reply, status); } } AJ_Status AJ_SecurityRemoveMembershipMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_CredField id = { 0, NULL }; AJ_CertificateId certificate; uint8_t* x; uint8_t* y; size_t xlen; size_t ylen; uint8_t* tmp; AJ_InfoPrintf(("AJ_SecurityRemoveMembershipMethod(msg=%p, reply=%p)\n", msg, reply)); status = AJ_UnmarshalArgs(msg, "(ayay(yyayay))", &certificate.serial.data, &certificate.serial.size, &certificate.aki.data, &certificate.aki.size, &certificate.pub.alg, &certificate.pub.crv, &x, &xlen, &y, &ylen); if (AJ_OK != status) { goto Exit; } if (PUBLICKEY_ALG_ECDSA_SHA256 != certificate.pub.alg) { goto Exit; } if (PUBLICKEY_CRV_NISTP256 != certificate.pub.crv) { goto Exit; } if ((KEY_ECC_SZ != xlen) || (KEY_ECC_SZ != ylen)) { goto Exit; } memcpy(certificate.pub.x, x, KEY_ECC_SZ); memcpy(certificate.pub.y, y, KEY_ECC_SZ); /* Delete membership certificate */ id.size = certificate.serial.size + certificate.aki.size; id.data = AJ_Malloc(id.size); if (NULL == id.data) { goto Exit; } tmp = id.data; memcpy(tmp, certificate.serial.data, certificate.serial.size); tmp += certificate.serial.size; memcpy(tmp, certificate.aki.data, certificate.aki.size); tmp += certificate.aki.size; status = AJ_CredentialDelete(AJ_CERTIFICATE_MBR_X509 | AJ_CRED_TYPE_CERTIFICATE, &id); if (AJ_OK != status) { AJ_InfoPrintf(("AJ_SecurityRemoveMembershipMethod(msg=%p, reply=%p): Certificate not found\n", msg, reply)); status = AJ_ERR_SECURITY_CERTIFICATE_NOT_FOUND; } Exit: AJ_CredFieldFree(&id); if (AJ_OK == status) { return AJ_MarshalReplyMsg(msg, reply); } else { return AJ_MarshalStatusMsg(msg, reply, status); } } AJ_Status AJ_SecurityStartManagementMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_InfoPrintf(("AJ_SecurityStartManagementMethod(msg=%p, reply=%p)\n", msg, reply)); status = AJ_SecurityStartManagement(msg->bus); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } else { return AJ_MarshalReplyMsg(msg, reply); } } AJ_Status AJ_SecurityStartManagement(AJ_BusAttachment* bus) { if (bus->managementStarted) { return AJ_ERR_MANAGEMENT_ALREADY_STARTED; } bus->managementStarted = TRUE; if (bus->startManagementCallback) { bus->startManagementCallback(); } return AJ_OK; } AJ_Status AJ_SecurityEndManagementMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_InfoPrintf(("AJ_SecurityEndManagementMethod(msg=%p, reply=%p)\n", msg, reply)); status = AJ_SecurityEndManagement(msg->bus); if (AJ_OK != status) { return AJ_MarshalErrorMsg(msg, reply, AJ_ErrSecurityViolation); } else { return AJ_MarshalReplyMsg(msg, reply); } } AJ_Status AJ_SecurityEndManagement(AJ_BusAttachment* bus) { if (!bus->managementStarted) { return AJ_ERR_MANAGEMENT_NOT_STARTED; } bus->managementStarted = FALSE; if (bus->endManagementCallback) { bus->endManagementCallback(); } return AJ_OK; } AJ_Status AJ_SecurityInstallManifestsMethod(AJ_Message* msg, AJ_Message* reply) { AJ_Status status; AJ_ManifestArray* currentManifests = NULL; AJ_ManifestArray* newManifests = NULL; AJ_ManifestArray* lastCurr = NULL; AJ_CredField currentManifests_data = { 0, NULL }; AJ_CredField newManifests_data = { 0, NULL }; AJ_CredField combinedManifests_data = { 0, NULL }; uint16_t manifestCount = 0; AJ_InfoPrintf(("AJ_SecurityInstallManifestsMethod(msg=%p, reply=%p)\n", msg, reply)); /* Retrieve existing array of manifests to append to them. */ status = AJ_CredentialGet(AJ_CRED_TYPE_MANIFESTS, NULL, NULL, ¤tManifests_data); if (AJ_OK != status) { return status; } /* Retrieve array of manifests from the message. */ status = AJ_ManifestArrayFromBuffer(¤tManifests, ¤tManifests_data); if (AJ_OK != status) { goto Exit; } /* Unmarshal new manifests from message. */ newManifests_data.data = msg->bus->sock.rx.readPtr; status = AJ_ManifestArrayUnmarshal(&newManifests, msg); if (AJ_OK != status) { goto Exit; } /* Check and make sure each manifest has been signed. */ AJ_ManifestArrayFilterUnsigned(&newManifests); /* If none passed, fail. */ if (NULL == newManifests) { status = AJ_ERR_SECURITY_DIGEST_MISMATCH; newManifests_data.data = NULL; goto Exit; } /* Append the new list of manifests to the current list. */ for (lastCurr = currentManifests; NULL != lastCurr->next; lastCurr = lastCurr->next); lastCurr->next = newManifests; newManifests = NULL; /* currentManifests now owns all this memory. */ /* Count the manifests for allocating memory to store the combined list. */ for (lastCurr = currentManifests; NULL != lastCurr; lastCurr = lastCurr->next) { manifestCount++; } /* Sum the serialized sizes of the two sets of manifests. */ combinedManifests_data.size = currentManifests_data.size + (msg->bus->sock.rx.readPtr - newManifests_data.data); /* Allow additional 8 bytes per manifest for maximum padding. */ combinedManifests_data.size += (8 * manifestCount); combinedManifests_data.data = AJ_Malloc(combinedManifests_data.size); if (NULL == combinedManifests_data.data) { status = AJ_ERR_RESOURCES; goto Exit; } status = AJ_ManifestArrayToBuffer(currentManifests, &combinedManifests_data); if (AJ_OK != status) { goto Exit; } /* Store manifests as raw marshalled body. */ status = AJ_CredentialSet(AJ_CRED_TYPE_MANIFESTS, NULL, 0xFFFFFFFF, &combinedManifests_data); if (AJ_OK != status) { goto Exit; } Exit: AJ_ManifestArrayFree(currentManifests); AJ_ManifestArrayFree(newManifests); AJ_CredFieldFree(¤tManifests_data); AJ_CredFieldFree(&combinedManifests_data); /* Don't AJ_CredFieldFree(&newManifests_data). That memory belongs to the message. */ if (AJ_OK != status) { return AJ_MarshalStatusMsg(msg, reply, status); } else { return AJ_MarshalReplyMsg(msg, reply); } } ajtcl-16.04/src/aj_serial.c000066400000000000000000000374751271074662300155350ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_SERIAL_CONNECTION /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE SERIAL #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgSERIAL = 0; #endif #define SLAP_VERSION 1 /** * SLAP added a disconnect feature in version 1 */ const uint8_t SLAP_VERSION_DISCONNECT_FEATURE = 1; /** * global variable for link parameters */ AJ_LinkParameters AJ_SerialLinkParams; /** * controls rate at which we send synch packets when the link is down in milliseconds */ const uint32_t CONN_TIMEOUT = 200; /** * controls how long we will wait for a confirmation packet after we synchronize in milliseconds */ const uint32_t NEGO_TIMEOUT = 200; /** * controls how long we will send disconnect packet when the application is closing the link in milliseconds */ const uint32_t DISC_TIMEOUT = 200; #define LINK_PACKET_SIZE 4 #define NEGO_PACKET_SIZE 3 /** link packet types */ typedef enum { UNKNOWN_PKT = 0, CONN_PKT, ACPT_PKT, NEGO_PKT, NRSP_PKT, RESU_PKT, DISC_PKT, DRSP_PKT } LINK_PKT_TYPE; /* * link establishment packets */ static const char ConnPkt[LINK_PACKET_SIZE] = { 'C', 'O', 'N', 'N' }; static const char AcptPkt[LINK_PACKET_SIZE] = { 'A', 'C', 'P', 'T' }; static const char NegoPkt[LINK_PACKET_SIZE] = { 'N', 'E', 'G', 'O' }; static const char NrspPkt[LINK_PACKET_SIZE] = { 'N', 'R', 'S', 'P' }; static const char ResuPkt[LINK_PACKET_SIZE] = { 'R', 'E', 'S', 'U' }; static const char DiscPkt[LINK_PACKET_SIZE] = { 'D', 'I', 'S', 'C' }; static const char DrspPkt[LINK_PACKET_SIZE] = { 'D', 'R', 'S', 'P' }; /** * Time to send the LinkPacket */ static AJ_Time sendLinkPacketTime; /** * link configuration information */ static uint8_t NegotiationPacket[LINK_PACKET_SIZE + NEGO_PACKET_SIZE]; /************ forward declarations *****************/ static void ScheduleLinkControlPacket(uint32_t timeout); /********* end of forward declarations *************/ // calculate the timeout values in milliseconds based on transmission paramters static void AdjustTimeoutValues(uint32_t packetSize) { // one start bit, eight data bits, one parity, and one stop bit equals eleven bits sent per byte // acknowledgement packets should be sent within twice the time to send one packet // resends should be sent shortly after three times the packet delivery time AJ_SerialLinkParams.txAckTimeout = (packetSize * 11 * 1000 * 2) / AJ_SerialLinkParams.bitRate; AJ_SerialLinkParams.txResendTimeout = (packetSize * 11 * 1000 * 3) / AJ_SerialLinkParams.bitRate; AJ_InfoPrintf(("new ack timeout %i, new resend timeout %i\n", AJ_SerialLinkParams.txAckTimeout, AJ_SerialLinkParams.txResendTimeout)); } // Converge the remote endpoint's values with my own static void ProcessNegoPacket(const uint8_t* buffer) { uint16_t max_payload; uint8_t proto_version; uint8_t window_size; max_payload = (((uint16_t) buffer[4]) << 8) | ((uint16_t) buffer[5]); AJ_AlwaysPrintf(("Read max payload: %u\n", max_payload)); AJ_SerialLinkParams.packetSize = min(AJ_SerialLinkParams.packetSize, max_payload); proto_version = (buffer[6] >> 2) & 0x003F; AJ_AlwaysPrintf(("Read protocol version: %u\n", proto_version)); AJ_SerialLinkParams.protoVersion = min(AJ_SerialLinkParams.protoVersion, proto_version); // last two bits window_size = buffer[6] & 0x03; // translate the window size switch (window_size) { case 0: window_size = 1; break; case 1: window_size = 2; break; case 2: window_size = 4; break; case 4: window_size = 8; break; default: AJ_AlwaysPrintf(("Invalid window size: %u\n", window_size)); break; } AJ_AlwaysPrintf(("Read max window size: %u\n", window_size)); AJ_SerialLinkParams.windowSize = min(AJ_SerialLinkParams.maxWindowSize, window_size); } static void SendNegotiationPacket(const char* pkt_type) { uint8_t encoded_window_size = 0; // NegoPkt is the packet type memset(&NegotiationPacket[0], 0, sizeof(NegotiationPacket)); // can be NEGO or NRSP memcpy(&NegotiationPacket[0], pkt_type, LINK_PACKET_SIZE); // max payload length we can support NegotiationPacket[4] = (AJ_SerialLinkParams.packetSize & 0xFF00) >> 8; NegotiationPacket[5] = (AJ_SerialLinkParams.packetSize & 0x00FF); switch (AJ_SerialLinkParams.maxWindowSize) { case 1: encoded_window_size = 0; break; case 2: encoded_window_size = 1; break; case 4: encoded_window_size = 2; break; case 8: encoded_window_size = 3; break; default: break; } NegotiationPacket[6] = (AJ_SerialLinkParams.protoVersion << 2) | encoded_window_size; AJ_SerialTX_EnqueueCtrl(NegotiationPacket, sizeof(NegotiationPacket), AJ_SERIAL_CTRL); } /** * a function that periodically sends sync or conf packets depending on * the link state */ static void SendLinkPacket() { switch (AJ_SerialLinkParams.linkState) { case AJ_LINK_UNINITIALIZED: /* * Send a sync packet. */ AJ_SerialTX_EnqueueCtrl((uint8_t*) ConnPkt, sizeof(ConnPkt), AJ_SERIAL_CTRL); AJ_AlwaysPrintf(("Send CONN\n")); ScheduleLinkControlPacket(CONN_TIMEOUT); break; case AJ_LINK_INITIALIZED: /* * Send a conf packet. */ SendNegotiationPacket(NegoPkt); AJ_AlwaysPrintf(("Send NEGO\n")); ScheduleLinkControlPacket(NEGO_TIMEOUT); break; case AJ_LINK_DYING: /* * only send a DISC packet to daemons that understand them. */ if (AJ_SerialLinkParams.protoVersion >= SLAP_VERSION_DISCONNECT_FEATURE) { AJ_SerialTX_EnqueueCtrl((uint8_t*) DiscPkt, sizeof(DiscPkt), AJ_SERIAL_CTRL); AJ_InfoPrintf(("Send DISC\n")); ScheduleLinkControlPacket(DISC_TIMEOUT); break; } default: /** * Do nothing. No more link control packets to be sent. */ ScheduleLinkControlPacket(AJ_TIMER_FOREVER); break; } } /** * This function registers the time to send a link control packet * specified by the timeout parameter. * * @param timeout time (in milliseconds) when the link control packet * must be sent */ static void ScheduleLinkControlPacket(uint32_t timeout) { AJ_InitTimer(&sendLinkPacketTime); AJ_TimeAddOffset(&sendLinkPacketTime, timeout); } /** * This function returns a link packet type, given a packet as an argument. * * @param buffer pointer to the buffer holding the packet * @param bufLen size of the buffer */ static LINK_PKT_TYPE ClassifyPacket(uint8_t* buffer, uint16_t bufLen) { if (bufLen < LINK_PACKET_SIZE) { return UNKNOWN_PKT; } if (0 == memcmp(buffer, ConnPkt, sizeof(ConnPkt))) { return CONN_PKT; } else if (0 == memcmp(buffer, AcptPkt, sizeof(AcptPkt))) { return ACPT_PKT; } else if (0 == memcmp(buffer, NegoPkt, sizeof(NegoPkt))) { return NEGO_PKT; } else if (0 == memcmp(buffer, NrspPkt, sizeof(NrspPkt))) { return NRSP_PKT; } else if (0 == memcmp(buffer, ResuPkt, sizeof(ResuPkt))) { return RESU_PKT; } else if (0 == memcmp(buffer, DiscPkt, sizeof(DiscPkt))) { return DISC_PKT; } else if (0 == memcmp(buffer, DrspPkt, sizeof(DrspPkt))) { return DRSP_PKT; } return UNKNOWN_PKT; } void AJ_Serial_LinkPacket(uint8_t* buffer, uint16_t len) { LINK_PKT_TYPE pktType = ClassifyPacket(buffer, len); if (pktType == UNKNOWN_PKT) { AJ_WarnPrintf(("Unknown link packet type %x\n", (int) pktType)); return; } switch (AJ_SerialLinkParams.linkState) { case AJ_LINK_UNINITIALIZED: /* * In the uninitialized state we need to respond to conn packets * and acpt packets. */ if (pktType == CONN_PKT) { AJ_SerialTX_EnqueueCtrl((uint8_t*) AcptPkt, sizeof(AcptPkt), AJ_SERIAL_CTRL); } else if (pktType == ACPT_PKT) { AJ_InfoPrintf(("Received sync response - moving to LINK_INITIALIZED\n")); AJ_SerialLinkParams.linkState = AJ_LINK_INITIALIZED; SendNegotiationPacket(NegoPkt); } break; case AJ_LINK_INITIALIZED: /* * In the initialized state we need to respond to conn packets, nego * packets, and nego-resp packets. */ if (pktType == CONN_PKT) { AJ_SerialTX_EnqueueCtrl((uint8_t*) AcptPkt, sizeof(AcptPkt), AJ_SERIAL_CTRL); } else if (pktType == NEGO_PKT) { ProcessNegoPacket(buffer); SendNegotiationPacket(NrspPkt); } else if (pktType == NRSP_PKT) { AJ_InfoPrintf(("Received nego response - Moving to LINK_ACTIVE\n")); AJ_SerialLinkParams.linkState = AJ_LINK_ACTIVE; // update the timeout values now that the link is active AdjustTimeoutValues(AJ_SerialLinkParams.packetSize); } break; case AJ_LINK_ACTIVE: /* * In the initialized state we need to respond to nego-resp packets. */ if (pktType == NEGO_PKT) { ProcessNegoPacket(buffer); SendNegotiationPacket(NrspPkt); } else if (pktType == CONN_PKT) { // got a connection after active, so the link must have gone down without our knowledge AJ_WarnPrintf(("Received CONN while in active state - Moving to LINK_DEAD\n")); AJ_SerialLinkParams.linkState = AJ_LINK_DEAD; } else if (pktType == DISC_PKT) { // received a disconnect packet, move to link dying state. AJ_WarnPrintf(("Received DISC while in active state - other side is going away.\n")); AJ_SerialTX_EnqueueCtrl((uint8_t*) DrspPkt, sizeof(DrspPkt), AJ_SERIAL_CTRL); AJ_SerialLinkParams.linkState = AJ_LINK_DYING; } break; case AJ_LINK_DYING: if (pktType == DISC_PKT) { // simultaneous DISC while in dying state, send a DRSP to cleanly shutdown the other side. AJ_WarnPrintf(("Received DISC while in dying state.\n")); AJ_SerialLinkParams.linkState = AJ_LINK_DEAD; AJ_SerialTX_EnqueueCtrl((uint8_t*) DrspPkt, sizeof(DrspPkt), AJ_SERIAL_CTRL); } else if (pktType == DRSP_PKT) { AJ_WarnPrintf(("Received DRSP while in dying state - other side knows we are going away.\n")); AJ_SerialLinkParams.linkState = AJ_LINK_DEAD; } break; case AJ_LINK_DEAD: break; } /* * Ignore any other packets. */ AJ_ErrPrintf(("Discarding link packet %d in state %d\n", pktType, AJ_SerialLinkParams.linkState)); } AJ_Status AJ_SerialInit(const char* ttyName, uint32_t bitRate, uint8_t windowSize, uint16_t packetSize) { AJ_Status status; if ((windowSize < MIN_WINDOW_SIZE) || (windowSize > MAX_WINDOW_SIZE)) { return AJ_ERR_INVALID; } AJ_AlwaysPrintf(("Initializing serial transport\n")); /** Initialize protocol default values */ AJ_SerialLinkParams.protoVersion = SLAP_VERSION; AJ_SerialLinkParams.maxWindowSize = windowSize; AJ_SerialLinkParams.windowSize = windowSize; AJ_SerialLinkParams.packetSize = packetSize; AJ_SerialLinkParams.linkState = AJ_LINK_UNINITIALIZED; AJ_SerialLinkParams.bitRate = bitRate; AdjustTimeoutValues(AJ_LINK_PACKET_PAYLOAD); /** Initialize serial ports */ status = AJ_SerialTargetInit(ttyName, bitRate); if (status != AJ_OK) { return status; } /** Initialize transmit buffers, state */ status = AJ_SerialTX_Init(); if (status != AJ_OK) { return status; } /** Initialize receive buffers, state */ status = AJ_SerialRX_Init(); if (status != AJ_OK) { return status; } AJ_SerialLinkParams.linkState = AJ_LINK_UNINITIALIZED; ScheduleLinkControlPacket(10); return AJ_OK; } void AJ_SerialShutdown(void) { AJ_SerialTX_Shutdown(); AJ_SerialRX_Shutdown(); } extern AJ_Time resendTime; extern AJ_Time ackTime; volatile int dataReceived; volatile int dataSent = 1; /** This state machine is called from AJ_SerialRecv and AJ_SerialSend. * This processes any buffers copied in the Recieve Callback, adds * buffers to be written in the Transmit Callback, resends packets * after a timeout and sends pure acks in the case of lack of data to send. * Also, this sends link control packets periodically depending on the state. */ void AJ_StateMachine() { AJ_Time now; AJ_InitTimer(&now); if (dataReceived) { /* Data has been received in the receive callback, process the data, * convert it into SLAP packets, validate and process the packets */ AJ_ProcessRxBufferList(); } if (dataSent) { /* There is space in the transmit free list, queue up more buffers to be * sent if there are SLAP packets to be sent */ AJ_FillTxBufferList(); } if (AJ_CompareTime(resendTime, now) < 0) { /* Resend any data packets that have not been acked */ ResendPackets(); } if (AJ_CompareTime(ackTime, now) < 0) { /* Send an ack for a received packet.(If there is data to send, * the ack is sent as a part of the header, but in this case, * this end didnt have data to send, so we send an explicit * ack packet.) */ SendAck(); } if (AJ_CompareTime(sendLinkPacketTime, now) < 0) { /* Time to send a link packet to get the Link to the active state. */ SendLinkPacket(); } } void ClearSlippedBuffer(volatile AJ_SlippedBuffer* buf) { while (buf != NULL) { volatile AJ_SlippedBuffer* prev = buf; AJ_Free(buf->buffer); buf = buf->next; AJ_Free((void*) prev); } } void AJ_SerialDisconnect(void) { AJ_Time start, now; AJ_InitTimer(&start); if (AJ_SerialLinkParams.linkState != AJ_LINK_DEAD) { AJ_SerialLinkParams.linkState = AJ_LINK_DYING; ScheduleLinkControlPacket(DISC_TIMEOUT); // Run the state machine up to 4 timeouts to wait for DRSP packets do { AJ_StateMachine(); AJ_InitTimer(&now); } while (AJ_SerialLinkParams.linkState != AJ_LINK_DEAD && AJ_GetTimeDifference(&now, &start) < DISC_TIMEOUT * 4); if (AJ_SerialLinkParams.linkState != AJ_LINK_DEAD) { AJ_InfoPrintf(("serial link wasn't gracefully disconnected\n")); AJ_SerialLinkParams.linkState = AJ_LINK_DEAD; } } } #endif /* AJ_SERIAL_CONNECTION */ ajtcl-16.04/src/aj_serial_rx.c000066400000000000000000000444721271074662300162410ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_SERIAL_CONNECTION /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE SERIAL_RX #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgSERIAL_RX = 0; #endif /** * maximum read size */ static uint16_t maxRxFrameSize; /** * This enumerated type is for tracking the state of the receive packet as it is being decoded. */ typedef enum { PACKET_NEW, PACKET_OPEN, PACKET_FLUSH, PACKET_ESCAPE } PKT_STATE; typedef struct _RX_PKT { uint8_t* buffer; uint16_t len; PKT_STATE state; struct _RX_PKT volatile* next; } RX_PKT; static RX_PKT volatile* RxPacket; static RX_PKT volatile* RxRecv; static RX_PKT volatile* RxFreeList; //Linked list of free buffers that can be used to recieve data. static AJ_SlippedBuffer volatile* bufferRxFreeList; //Linked list of received slipped buffers static AJ_SlippedBuffer volatile* bufferRxQueue; // the buffer currently being sent static AJ_SlippedBuffer volatile* pendingRecvBuffer; /** * number of received packets waiting to be delivered to the upper layers */ static uint8_t volatile pendingRecv; /** * sequence number expected in the next packet */ static uint8_t expectedSeq; void AJ_ReceiveCallback(uint8_t* buffer, uint16_t bytesRead) { // move pendingRecvBuffer from the pending list to the free list // it will be reused dataReceived = 1; if (bufferRxQueue == NULL) { bufferRxQueue = pendingRecvBuffer; } else { volatile AJ_SlippedBuffer* buf = bufferRxQueue; while (buf->next != NULL) { buf = buf->next; } buf->next = pendingRecvBuffer; } pendingRecvBuffer->next = NULL; pendingRecvBuffer->actualLen = bytesRead; pendingRecvBuffer = bufferRxFreeList; // if anything is pending, send it! if (pendingRecvBuffer != NULL) { bufferRxFreeList = bufferRxFreeList->next; pendingRecvBuffer->next = NULL; AJ_RX(pendingRecvBuffer->buffer, pendingRecvBuffer->allocatedLen); AJ_ResumeRX(); } } #ifdef AJ_DEBUG_PACKET_LISTS void _AJ_DebugCheckPacketList(RX_PKT volatile* list, char* listName) { // BUGBUG take a lock RX_PKT volatile* iter = list; AJ_AlwaysPrintf(("%s list %p\n", listName, list)); while (iter) { AJ_ASSERT(iter != iter->next); //check for a single loop AJ_AlwaysPrintf(("%s list %p, iter %p next %p\n", listName, list, iter, iter->next)); iter = iter->next; } } #define AJ_DebugCheckPacketList(a, b) _AJ_DebugCheckPacketList(a, b) #else #define AJ_DebugCheckPacketList(a, b) #endif #ifdef AJ_DEBUG_SERIAL_RECV #define AJ_DebugDumpSerialRecv(a, b, c) AJ_DumpBytes(a, b, c) #else #define AJ_DebugDumpSerialRecv(a, b, c) #endif /** * global timer id that controls waiting in AJ_SerialRecv */ #define AJ_SERIAL_READ_TIMER 0x100 static void DeleteRxPacket(volatile RX_PKT* pkt) { while (pkt != NULL) { volatile RX_PKT* prev = pkt; AJ_Free(pkt->buffer); pkt = pkt->next; AJ_Free((void*) prev); } } void AJ_SerialRX_Shutdown(void) { AJ_PauseRX(); ClearSlippedBuffer(bufferRxFreeList); bufferRxFreeList = NULL; ClearSlippedBuffer(bufferRxQueue); bufferRxQueue = NULL; ClearSlippedBuffer(pendingRecvBuffer); pendingRecvBuffer = NULL; DeleteRxPacket(RxPacket); RxPacket = NULL; DeleteRxPacket(RxFreeList); RxFreeList = NULL; DeleteRxPacket(RxRecv); RxRecv = NULL; } /** * This function initializes the receive path */ AJ_Status AJ_SerialRX_Init(void) { int i; RX_PKT volatile* prev; AJ_SlippedBuffer volatile* prevBuf = NULL; if (AJ_SerialLinkParams.packetSize == 0) { return AJ_ERR_FAILURE; } /* * Initialize local static data */ RxRecv = NULL; RxPacket = NULL; pendingRecv = 0; expectedSeq = 0; dataReceived = 0; /* * The maximum frame size is the packet length plus the header length plus * two bytes for the packet boundary bytes. */ maxRxFrameSize = AJ_SerialLinkParams.packetSize + 2 + AJ_SERIAL_HDR_LEN; /* * Data packets: To maximize throughput we need as many packets as the * window size, plus one for the current packet */ for (i = 0; i < AJ_SerialLinkParams.maxWindowSize + 1; ++i) { void* buf; prev = RxFreeList; RxFreeList = AJ_Malloc(sizeof(RX_PKT)); buf = AJ_Malloc(maxRxFrameSize); if (!RxFreeList || !buf) { return AJ_ERR_RESOURCES; } RxFreeList->buffer = buf; RxFreeList->state = PACKET_NEW; RxFreeList->len = 0; RxFreeList->next = prev; } bufferRxFreeList = NULL; for (i = 0; i < AJ_SerialLinkParams.maxWindowSize + 1; i++) { void* buf; prevBuf = bufferRxFreeList; bufferRxFreeList = AJ_Malloc(sizeof(AJ_SlippedBuffer)); buf = AJ_Malloc(SLIPPED_LEN(AJ_SerialLinkParams.packetSize)); if (!bufferRxFreeList || !buf) { return AJ_ERR_RESOURCES; } bufferRxFreeList->buffer = buf; bufferRxFreeList->actualLen = 0; bufferRxFreeList->allocatedLen = SLIPPED_LEN(AJ_SerialLinkParams.packetSize); bufferRxFreeList->next = prevBuf; } AJ_SetRxCB(&AJ_ReceiveCallback); pendingRecvBuffer = bufferRxFreeList; bufferRxFreeList = bufferRxFreeList->next; pendingRecvBuffer->next = NULL; AJ_RX(pendingRecvBuffer->buffer, pendingRecvBuffer->allocatedLen); AJ_ResumeRX(); // pull the first buffer off of the free list. RxPacket = RxFreeList; RxFreeList = RxFreeList->next; RxPacket->next = NULL; AJ_DebugCheckPacketList(RxFreeList, "RxFreeList during init"); AJ_DebugCheckPacketList(RxRecv, "RxRecv during init"); AJ_DebugCheckPacketList(RxPacket, "RxPacket during init"); return AJ_OK; } void AJ_SerialReturnPacketToFreeList(volatile RX_PKT* pkt) { // return the packet to the free list and reinitialize it if (pkt) { pkt->state = PACKET_NEW; pkt->next = RxFreeList; RxFreeList = pkt; } } /** * This function resets the receive path for the serial transport. */ AJ_Status AJ_SerialRX_Reset(void) { RX_PKT volatile* pkt; /* * Put ACL packets back on the free list. */ while (RxRecv != NULL) { pkt = RxRecv; RxRecv = RxRecv->next; AJ_SerialReturnPacketToFreeList(pkt); } AJ_DebugCheckPacketList(RxFreeList, "RxFreeList reset"); AJ_DebugCheckPacketList(RxRecv, "RxRecv during reset"); AJ_DebugCheckPacketList(RxPacket, "RxPacket during reset"); expectedSeq = 0; pendingRecv = 0; RxPacket->state = PACKET_NEW; return AJ_OK; } AJ_Status AJ_SerialRecv(uint8_t* buffer, uint16_t req, uint32_t timeout, uint16_t* recv) { AJ_Status status = AJ_OK; // call the target-specific routine that copies data when // it arrives into the buffer we are providing. uint16_t len = req; AJ_Time now; AJ_Time readTimeoutTimeStamp; AJ_InitTimer(&readTimeoutTimeStamp); AJ_TimeAddOffset(&readTimeoutTimeStamp, timeout); AJ_InitTimer(&now); do { if (AJ_SerialLinkParams.linkState == AJ_LINK_DEAD) { status = AJ_ERR_LINK_DEAD; break; } /* * Fill as many packets as we can */ while (RxRecv && len) { RX_PKT volatile* pkt = RxRecv; uint16_t num = min(pkt->len - 6, len); AJ_DebugCheckPacketList(RxFreeList, "RxFreeList serialrecv"); AJ_DebugCheckPacketList(RxRecv, "RxRecv during serialrecv"); AJ_DebugCheckPacketList(RxPacket, "RxPacket during serialrecv"); AJ_DebugDumpSerialRecv("AJ_SerialRecv", pkt->buffer, num + 4); memcpy(buffer + (req - len), pkt->buffer + 4, num); len -= num; if (num == (pkt->len - 6)) { /// use pkt->len, because we might have eaten out of this buffer already // we used a full packet // put that packet back on the RxFreeList, decrement pendingRecv, and send Ack. RxRecv = RxRecv->next; AJ_SerialReturnPacketToFreeList(pkt); AJ_DebugCheckPacketList(RxFreeList, "RxFreeList serialrecv AFTER FULL PACKET"); AJ_DebugCheckPacketList(RxRecv, "RxRecv serialrecv AFTER FULL PACKET"); AJ_DebugCheckPacketList(RxPacket, "RxFreeList serialrecv AFTER FULL PACKET"); --pendingRecv; } else { // move the data in the buffer over, then return from this function. memmove(pkt->buffer + 4, pkt->buffer + 4 + num, pkt->len - num); pkt->len -= num; } } // Running state machine, waiting for RxRecv to get another buffer. AJ_StateMachine(); AJ_InitTimer(&now); } while (len && (AJ_CompareTime(readTimeoutTimeStamp, now) > 0)); if (AJ_CompareTime(readTimeoutTimeStamp, now) <= 0 && (req == len)) { status = AJ_ERR_TIMEOUT; } if (recv) { *recv = req - len; } return status; } /** * This function checks packet integrity and forwards good packets to the appropriate * upper-layer interface. */ static void CompletePacket() { RX_PKT volatile* pkt = RxPacket; uint8_t ack; uint8_t seq; uint8_t pktType; uint16_t expectedLen; uint8_t checksum; uint8_t* rcvdCrc = &pkt->buffer[pkt->len - 2]; uint8_t checkCrc[2]; uint16_t crc = AJ_SERIAL_CRC_INIT; if (pkt->len < AJ_SERIAL_HDR_LEN) { /* * Packet is too small. */ AJ_AlwaysPrintf(("Short packet %d\n", pkt->len)); return; } /* * Compute the CRC on the packet header and payload. */ AJ_CRC16_Compute(pkt->buffer, pkt->len - 2, &crc); AJ_CRC16_Complete(crc, checkCrc); /* * Check the computed and received CRC's match. */ if ((rcvdCrc[0] != checkCrc[0]) || (rcvdCrc[1] != checkCrc[1])) { AJ_AlwaysPrintf(("Data integrity error - discarding packet\n")); AJ_AlwaysPrintf(("rcvdCrc = %u %u\n", rcvdCrc[0], rcvdCrc[1])); AJ_AlwaysPrintf(("checkCrc = %u %u\n", checkCrc[0], checkCrc[1])); return; } seq = (pkt->buffer[0] >> 4); ack = pkt->buffer[0] & 0x0F; pktType = pkt->buffer[1] & 0x0F; /* * Check that the payload length in the header matches the bytes read. */ expectedLen = ((uint16_t) pkt->buffer[2]) << 8; expectedLen |= (pkt->buffer[3]); if (expectedLen != (pkt->len - AJ_SERIAL_HDR_LEN - 2)) { AJ_AlwaysPrintf(("Wrong packet length header says %d read %d bytes\n", expectedLen, pkt->len - AJ_SERIAL_HDR_LEN - 2)); return; } //AJ_AlwaysPrintf("Rx %d, seq=%d, ack=%d\n", pktType, seq, ack); /* * Handle link control packets. */ if (pktType == AJ_SERIAL_CTRL) { AJ_Serial_LinkPacket(pkt->buffer + AJ_SERIAL_HDR_LEN, expectedLen); return; } /* * If the link is not active non-link packets are discarded. */ if (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE) { AJ_AlwaysPrintf(("Link not up - discarding data packet\n")); return; } /* * Pass the ACK to the transmit side. */ AJ_SerialTx_ReceivedAck(ack); if (pktType == AJ_SERIAL_DATA) { /* * If a reliable packet does not have the expected sequence number, then * it is either a repeated packet or we missed a packet. In either case, * we must ignore the packet but we need to ACK repeated packets. */ if (seq != expectedSeq) { if (SEQ_GT(seq, expectedSeq)) { AJ_AlwaysPrintf(("Missing packet - expected = %d, got %d\n", expectedSeq, seq)); } else { AJ_AlwaysPrintf(("Repeated packet seq = %d, expected %d\n", seq, expectedSeq)); AJ_SerialTx_ReceivedSeq(seq); } } else { if (RxFreeList != NULL) { // push the RxPacket on to the back of the RxRecv list. RX_PKT volatile* last; expectedSeq = (expectedSeq + 1) & 0x07; /* * Add to the end of the receive queue. */ if (RxRecv == NULL) { RxRecv = pkt; } else { last = RxRecv; while (last->next != NULL) { last = last->next; } last->next = pkt; } pkt->next = NULL; RxPacket = RxFreeList; RxFreeList = RxFreeList->next; RxPacket->next = NULL; ++pendingRecv; // we now have another packet enqueued. AJ_SerialTx_ReceivedSeq(seq); } } } } /** * This function is called from the physical transport layer when data is received. * @param buffer pointer to the buffer holding the received data * @param bytes length of the received data in bytes */ static uint32_t UART_RxComplete(uint8_t* buffer, uint16_t bytes) { uint8_t rx; while (bytes-- > 0) { rx = *buffer++; switch (RxPacket->state) { case PACKET_FLUSH: /* * If we are not at a packet boundary as expected, then we need to flush * the receive system until we see a closing packet boundary. */ if (rx == BOUNDARY_BYTE) { RxPacket->state = PACKET_NEW; } break; case PACKET_NEW: /* * If we are not at a packet boundary as expected we need to flush * rx until we see a closing packet boundary. */ if (rx == BOUNDARY_BYTE) { RxPacket->state = PACKET_OPEN; } else { RxPacket->state = PACKET_FLUSH; AJ_AlwaysPrintf(("AJ_SerialRx_Receive: Flushing input at %2x\n", rx)); } RxPacket->len = 0; break; case PACKET_ESCAPE: /* * Handle a SLIP escape sequence. */ RxPacket->state = PACKET_OPEN; if (rx == BOUNDARY_SUBSTITUTE) { RxPacket->buffer[RxPacket->len++] = BOUNDARY_BYTE; break; } if (rx == ESCAPE_SUBSTITUTE) { RxPacket->buffer[RxPacket->len++] = ESCAPE_BYTE; break; } AJ_AlwaysPrintf(("AJ_SerialRx_Receive: Bad escape sequence %2x\n", rx)); /* * Bad escape sequence: discard everything up to the current * byte. This means that we need to restore the current byte. */ ++bytes; --buffer; RxPacket->state = PACKET_NEW; break; case PACKET_OPEN: /* * Decode received bytes and transfer them to the receive packet. */ if (rx == BOUNDARY_BYTE) { RX_PKT volatile* pkt = RxPacket; pkt->state = PACKET_NEW; pkt->next = NULL; CompletePacket(); // the packet will be put back on the RxFreeList when the upper layer has retrieved it. break; } if (rx == ESCAPE_BYTE) { RxPacket->state = PACKET_ESCAPE; break; } if (RxPacket->len == maxRxFrameSize) { /* * Packet overrun: discard the packet. */ RxPacket->state = PACKET_NEW; AJ_AlwaysPrintf(("AJ_SerialRx_Receive: Packet overrun %d\n", RxPacket->len)); break; } RxPacket->buffer[RxPacket->len++] = rx; break; default: AJ_ASSERT(FALSE); } } /* * Only read as many bytes as we can consume. */ return maxRxFrameSize - RxPacket->len; } void AJ_ProcessRxBufferList() { AJ_SlippedBuffer volatile* currentSlippedBuffer; if (!RxFreeList) { return; } AJ_PauseRX(); while (bufferRxQueue && RxFreeList) { // Pull the head off the queue. currentSlippedBuffer = bufferRxQueue; bufferRxQueue = bufferRxQueue->next; AJ_ResumeRX(); UART_RxComplete(currentSlippedBuffer->buffer, currentSlippedBuffer->actualLen); AJ_PauseRX(); if (pendingRecvBuffer == NULL) { //Free list was previously NULL, so re-enable reading //Save a pointer to the recv buffer, so we can keep track when the AJ_RecieveCallback occurs. pendingRecvBuffer = currentSlippedBuffer; pendingRecvBuffer->next = NULL; AJ_RX(pendingRecvBuffer->buffer, pendingRecvBuffer->allocatedLen); } else { currentSlippedBuffer->next = bufferRxFreeList; bufferRxFreeList = currentSlippedBuffer; } } if (!bufferRxQueue) { dataReceived = FALSE; } AJ_ResumeRX(); } #endif /* AJ_SERIAL_CONNECTION */ ajtcl-16.04/src/aj_serial_tx.c000066400000000000000000000500311271074662300162270ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_SERIAL_CONNECTION /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE SERIAL_TX #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgSERIAL_TX = 0; #endif /** * Throughput may be improved by always ack'ing received packets immediately. */ //#define ALWAYS_ACK 1 /* * transmit packet */ typedef struct _TxPkt { struct _TxPkt volatile* next; uint16_t len; uint8_t seq; uint8_t type; uint8_t* payload; } TxPkt; /** * packets queued and ready to send */ static TxPkt volatile* txQueue; /** * packets sent but not yet acknowledged */ static TxPkt volatile* txSent; /** * Free list for data packets */ static TxPkt volatile* txFreeList; /** * packet reserved for sending unreliable (control and ack) packets */ static TxPkt volatile* txUnreliable; /* Linked list of slipped buffers to be transmitted */ static AJ_SlippedBuffer volatile* bufferTxPending; /* Linked list of buffers that can be filled with slipped SLAP packets * and transferred into bufferTxPending */ static AJ_SlippedBuffer volatile* bufferTxFreeList; /* The buffer currently being sent by the Transmit callback */ static AJ_SlippedBuffer volatile* pendingSendBuffer; /** * current transmit sequence number */ static uint8_t txSeqNum; /** * number of received packets waiting to be ACKed */ static uint8_t pendingAcks; /** * sequence number of the packet we expect to ACK next */ static uint8_t currentTxAck; static uint8_t resendPrimed = FALSE; /** * When to resend un-acked packets */ AJ_Time resendTime; /** * When to send explicit ACK */ AJ_Time ackTime; /****************** Forward declarations *******************/ void ResendTimer(uint32_t timerId, void* context); void SendPureAck(uint32_t timerId, void* context); extern AJ_Status AJ_UART_Tx(uint8_t* buffer, uint16_t len); extern void __AJ_TX(uint8_t* buf, uint32_t len); /************** End of forward declarations *****************/ #ifdef AJ_DEBUG_SERIAL_SEND #define AJ_DebugDumpSerialSend(a, b, c) AJ_DumpBytes(a, b, c) #else #define AJ_DebugDumpSerialSend(a, b, c) #endif void AJ_TransmitCallback(uint8_t* buffer, uint16_t bytesRead); AJ_Status AJ_SerialTX_Init() { int i; TxPkt volatile* prev; if (AJ_SerialLinkParams.packetSize == 0) { return AJ_ERR_DRIVER; } /* * Initialize local static data */ txQueue = NULL; txSent = NULL; txFreeList = NULL; txUnreliable = NULL; txSeqNum = 0; resendPrimed = FALSE; pendingAcks = 0; currentTxAck = 0; dataSent = 1; /* * Data packets: To maximize throughput we need as many packets as the * window size. */ for (i = 0; i < AJ_SerialLinkParams.maxWindowSize; ++i) { void* payload; prev = txFreeList; txFreeList = AJ_Malloc(sizeof(TxPkt)); payload = AJ_Malloc(AJ_SerialLinkParams.packetSize); if (!txFreeList || !payload) { return AJ_ERR_RESOURCES; } txFreeList->payload = payload; txFreeList->next = prev; } AJ_SlippedBuffer volatile* prevBuf = NULL; bufferTxFreeList = NULL; for (i = 0; i < AJ_SerialLinkParams.maxWindowSize; i++) { void* buf; prevBuf = bufferTxFreeList; bufferTxFreeList = AJ_Malloc(sizeof(AJ_SlippedBuffer)); buf = AJ_Malloc(SLIPPED_LEN(AJ_SerialLinkParams.packetSize)); //TODO: calculate slipped length based on packet size if (!bufferTxFreeList || !buf) { return AJ_ERR_RESOURCES; } bufferTxFreeList->buffer = buf; bufferTxFreeList->actualLen = 0; bufferTxFreeList->allocatedLen = SLIPPED_LEN(AJ_SerialLinkParams.packetSize); bufferTxFreeList->next = prevBuf; } prevBuf = bufferTxFreeList; /* * Buffer for unreliable packets */ txUnreliable = AJ_Malloc(sizeof(TxPkt)); memset((void*)txUnreliable, 0, sizeof(TxPkt)); txUnreliable->payload = AJ_Malloc(AJ_LINK_PACKET_PAYLOAD); AJ_InitTimer(&resendTime); AJ_TimeAddOffset(&resendTime, AJ_TIMER_FOREVER); resendPrimed = FALSE; AJ_InitTimer(&ackTime); AJ_TimeAddOffset(&ackTime, AJ_TIMER_FOREVER); AJ_SetTxSerialTransmit(&__AJ_TX); AJ_SetTxCB(&AJ_TransmitCallback); return AJ_OK; } static void DeleteTxPacket(volatile TxPkt* pkt) { while (pkt != NULL) { volatile TxPkt* prev = pkt; pkt = pkt->next; AJ_Free(prev->payload); AJ_Free((void*) prev); prev = NULL; } } void AJ_SerialTX_Shutdown(void) { AJ_PauseTX(); // delete the unreliable packet in a moment if (txUnreliable == txQueue) { txQueue = txUnreliable->next; txUnreliable->next = NULL; } DeleteTxPacket(txQueue); txQueue = NULL; DeleteTxPacket(txSent); txSent = NULL; DeleteTxPacket(txFreeList); txFreeList = NULL; DeleteTxPacket(txUnreliable); txUnreliable = NULL; ClearSlippedBuffer(bufferTxFreeList); bufferTxFreeList = NULL; ClearSlippedBuffer(bufferTxPending); bufferTxPending = NULL; ClearSlippedBuffer(pendingSendBuffer); pendingSendBuffer = NULL; } /** * This function resets the transmit side of the transport. */ AJ_Status AJ_SerialTX_Reset(void) { TxPkt volatile* pkt; /* * Hold the timeouts. */ AJ_InitTimer(&resendTime); AJ_TimeAddOffset(&resendTime, AJ_TIMER_FOREVER); AJ_InitTimer(&ackTime); AJ_TimeAddOffset(&ackTime, AJ_TIMER_FOREVER); /* * Put ACL packets back on the free list. */ while (txSent != NULL) { pkt = txSent; txSent = txSent->next; if (pkt->type == AJ_SERIAL_DATA) { pkt->next = txFreeList; txFreeList = pkt; } } while (txQueue != NULL) { pkt = txQueue; txQueue = txQueue->next; if (pkt->type == AJ_SERIAL_DATA) { pkt->next = txFreeList; txFreeList = pkt; } } /* * Re-initialize global state. */ txSeqNum = 0; pendingAcks = 0; currentTxAck = 0; txSeqNum = 0; resendPrimed = FALSE; return AJ_OK; } /** * This function is called if an acknowledgement is not received within the required * timeout period. */ void ResendPackets() { TxPkt volatile* last; /* * Re-register the send timeout callback, it will not be primed until it * is needed. */ resendPrimed = FALSE; AJ_InitTimer(&resendTime); AJ_TimeAddOffset(&resendTime, AJ_TIMER_FOREVER); /* * No resends if the link is not up. */ if (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE) { return; } /* * To preserve packet order, all unacknowleged packets must be resent. This * simply means moving packets on txSent to the head of txQueue. */ if (txSent != NULL) { last = txSent; while (last->next != NULL) { last = last->next; } /* * Put resend packets after the unreliable packet. */ if (txQueue == txUnreliable) { last->next = txQueue->next; txQueue->next = last; } else { last->next = txQueue; txQueue = txSent; } txSent = NULL; } } /** * Unreliable packets are given priority by putting them at the front of the * transmit queue. */ static void QueueUnreliable(void) { /* * Except for ACK packets, unreliable packets have a zero seq number. */ txUnreliable->seq = (txUnreliable->type == AJ_SERIAL_ACK) ? currentTxAck : 0; /* * Add to front of transmit queue. It is possible that the unreliable packet * structure has already been queued due to a explicit ACK or due to an earlier * link control packet. In any case, because these are unreliable packets it is OK * for the new packet to overwrite the older packet. It would NOT be OK for * the unreliable packet to get queued twice. */ if (txQueue == txUnreliable) { AJ_AlwaysPrintf(("QueueUnreliable: type %i unreliable packet already queued! %p\n", txUnreliable->type, txUnreliable)); } else { txUnreliable->next = txQueue; txQueue = txUnreliable; } } /** * Reliable packets are sent in order so are appended to the end of the transmit queue. */ static void QueueReliable(TxPkt volatile* pkt) { TxPkt volatile* last; pkt->seq = txSeqNum; pkt->next = NULL; /* * updates sequence number */ txSeqNum = (txSeqNum + 1) & 0x7; /* * Add to the end of the transmit queue. */ if (txQueue == NULL) { txQueue = pkt; } else { last = txQueue; while (last->next != NULL) { last = last->next; } last->next = pkt; } } AJ_Status AJ_SerialSend(uint8_t* buffer, uint16_t bufLen) { AJ_Status status = AJ_OK; uint16_t len = bufLen; while (len) { if (AJ_SerialLinkParams.linkState == AJ_LINK_DEAD) { status = AJ_ERR_LINK_DEAD; break; } // wait until there is space to send a packet. if (!txFreeList || AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE) { AJ_StateMachine(); continue; } /* * Fill as many packets as we can */ while (txFreeList && len) { uint16_t num = min(AJ_SerialLinkParams.packetSize, len); TxPkt volatile* pkt = txFreeList; txFreeList = txFreeList->next; pkt->type = AJ_SERIAL_DATA; pkt->len = num; memcpy(pkt->payload, buffer + (bufLen - len), num); QueueReliable(pkt); len -= num; } } return status; } void AJ_SerialTX_EnqueueCtrl(const uint8_t* packet, uint16_t pktLen, uint8_t type) { /* * Unreliable packets are given special treatment because they are sent * ahead of any packets already in the txQueue and do not require * acknowledgment. */ txUnreliable->type = type; memcpy(txUnreliable->payload, packet, min(pktLen, AJ_LINK_PACKET_PAYLOAD)); txUnreliable->len = pktLen; QueueUnreliable(); } static uint16_t SlipBytes(AJ_SlippedBuffer volatile* slip, uint8_t* data, uint16_t len) { uint16_t i; uint8_t b; for (i = 0; i < len; ++i) { if (slip->actualLen == slip->allocatedLen) { AJ_ASSERT(FALSE); break; } b = *data++; if ((b == BOUNDARY_BYTE) || (b == ESCAPE_BYTE)) { /* * need room for two bytes */ if ((slip->actualLen + 1) == slip->allocatedLen) { break; } slip->buffer[slip->actualLen++] = ESCAPE_BYTE; b = (b == ESCAPE_BYTE) ? ESCAPE_SUBSTITUTE : BOUNDARY_SUBSTITUTE; } slip->buffer[slip->actualLen++] = b; } return i; } /* * Number of packets on the txSent queue. These are packets that have been sent * but not yet acknowledged. */ static uint8_t txSentPending(void) { uint8_t n = 0; static TxPkt volatile* pkt; for (pkt = txSent; pkt != NULL; pkt = pkt->next) { ++n; } AJ_ASSERT(n <= AJ_SerialLinkParams.windowSize); return n; } void ConvertPacketToBytes(AJ_SlippedBuffer volatile* slip, TxPkt volatile* txCurrent) { uint8_t header[4]; uint16_t crc = AJ_SERIAL_CRC_INIT; uint8_t crcBytes[2]; //AJ_DumpBytes("Raw buffer",txCurrent->payload,txCurrent->len); slip->actualLen = 0; /* * Apply SLIP encoding to the header. */ slip->buffer[slip->actualLen++] = BOUNDARY_BYTE; /* * Compose flags */ // byte 1 is the message type header[1] = txCurrent->type; if (txCurrent->type == AJ_SERIAL_DATA) { /* * If we have maxed the windows we need to go idle */ if (txSentPending() == AJ_SerialLinkParams.windowSize) { AJ_AlwaysPrintf(("TxSend - reached window size: %u\n", txSentPending())); AJ_ASSERT(FALSE); } header[0] = (txCurrent->seq << 4); // AJ_AlwaysPrintf("Tx seq %d, ack %d\n", txCurrent->seq, currentTxAck); } else { header[0] = 0; // AJ_AlwaysPrintf("Tx %s seq %d\n", !txCurrent->type ? "ack" : "unreliable", txCurrent->seq); } /* * All packets except link control packets carry ACK information. */ if (txCurrent->type != AJ_SERIAL_CTRL) { // Acknowledge the last packet received. header[0] |= (currentTxAck & 0x0F); /* * If there was an ACK backlog, we halt the explicit ACK timeout. */ if (pendingAcks) { pendingAcks = 0; pendingAcks = 0; AJ_InitTimer(&ackTime); AJ_TimeAddOffset(&ackTime, AJ_TIMER_FOREVER); } } // bytes 2 and 3 are the payload length header[2] = txCurrent->len >> 8; header[3] = txCurrent->len & 0x00FF; AJ_CRC16_Compute(header, ArraySize(header), &crc); AJ_CRC16_Compute(txCurrent->payload, txCurrent->len, &crc); SlipBytes(slip, header, 4); SlipBytes(slip, txCurrent->payload, txCurrent->len); AJ_CRC16_Complete(crc, crcBytes); SlipBytes(slip, crcBytes, 2); slip->buffer[slip->actualLen++] = BOUNDARY_BYTE; } /** * This function is called by the receive layer when a data packet or an explicit ACK * has been received. The ACK value is one greater (modulo 8) than the seq number of the * last packet successfully received. */ void AJ_SerialTx_ReceivedAck(uint8_t ack) { TxPkt volatile* ackedPkt = NULL; if (txSent == NULL) { return; } /* * Remove acknowledged packets from sent queue. */ while ((txSent != NULL) && SEQ_GT(ack, txSent->seq)) { ackedPkt = txSent; txSent = txSent->next; //AJ_AlwaysPrintf("Releasing seq=%d (acked by %d)\n", ackedPkt->seq, ack); AJ_ASSERT(ackedPkt->type == AJ_SERIAL_DATA); /* * Return pkt to ACL free list. */ ackedPkt->next = txFreeList; txFreeList = ackedPkt; /* * If all packet have been ack'd, halt the resend timer and return. */ if (txSent == NULL) { AJ_InitTimer(&resendTime); AJ_TimeAddOffset(&resendTime, AJ_TIMER_FOREVER); resendPrimed = FALSE; return; } } /* * Reset the resend timer if one or more packets were ack'd. */ if (ackedPkt != NULL) { AJ_InitTimer(&resendTime); AJ_TimeAddOffset(&resendTime, AJ_SerialLinkParams.txResendTimeout); resendPrimed = TRUE; } } /* * Send a explicit ACK (acknowledgement). */ void SendAck() { if (pendingAcks) { pendingAcks = 0; AJ_SerialTX_EnqueueCtrl(NULL, 0, AJ_SERIAL_ACK); } /* * Disable explicit ack. */ AJ_InitTimer(&ackTime); AJ_TimeAddOffset(&ackTime, AJ_TIMER_FOREVER); } /* * This function is called from the receive side with the sequence number of * the last packet received. */ void AJ_SerialTx_ReceivedSeq(uint8_t seq) { /* * If we think we have already acked this sequence number we don't adjust * the ack count. */ if (!SEQ_GT(currentTxAck, seq)) { currentTxAck = (seq + 1) & 0x7; } #ifdef ALWAYS_ACK AJ_SerialTX_EnqueueCtrl(NULL, 0, AJ_SERIAL_ACK); #else ++pendingAcks; /* * If there are no packets to send we are allowed to accumulate a * backlog of pending ACKs up to a maximum equal to the window size. * In any case we are required to send an ack within a timeout * period so if this is the first pending ack we need to prime a timer. */ if (pendingAcks == 1) { AJ_InitTimer(&ackTime); AJ_TimeAddOffset(&ackTime, AJ_SerialLinkParams.txAckTimeout); return; } /* * If we have hit our pending ACK limit send a explicit ACK packet immediately. */ if (pendingAcks == AJ_SerialLinkParams.windowSize) { AJ_SerialTX_EnqueueCtrl(NULL, 0, AJ_SERIAL_ACK); } #endif } void AJ_TransmitCallback(uint8_t* buffer, uint16_t bytesWritten) { dataSent = 1; AJ_ASSERT((buffer == pendingSendBuffer->buffer) && (bytesWritten == pendingSendBuffer->actualLen)); // put pendingSendBuffer on the free list pendingSendBuffer->next = bufferTxFreeList; bufferTxFreeList = pendingSendBuffer; pendingSendBuffer = bufferTxPending; if (pendingSendBuffer != NULL) { bufferTxPending = bufferTxPending->next; pendingSendBuffer->next = NULL; AJ_TX(pendingSendBuffer->buffer, pendingSendBuffer->actualLen); AJ_ResumeTX(); } } void AJ_FillTxBufferList() { AJ_SlippedBuffer volatile* currentSlippedBuffer; if (!txQueue) { return; } AJ_PauseTX(); while (bufferTxFreeList && txQueue) { // Pull the head off the queue. TxPkt volatile* txCurrent; currentSlippedBuffer = bufferTxFreeList; bufferTxFreeList = bufferTxFreeList->next; currentSlippedBuffer->next = NULL; if (pendingSendBuffer != NULL) { AJ_ResumeTX(); } txCurrent = txQueue; txQueue = txQueue->next; txCurrent->next = NULL; ConvertPacketToBytes(currentSlippedBuffer, txCurrent); if (txCurrent->type == AJ_SERIAL_DATA) { //put it onto txSent if (txSent == NULL) { txSent = txCurrent; } else { TxPkt volatile* last = txSent; while (last->next != NULL) { last = last->next; } last->next = txCurrent; } if (!resendPrimed) { AJ_InitTimer(&resendTime); AJ_TimeAddOffset(&resendTime, AJ_SerialLinkParams.txResendTimeout); resendPrimed = FALSE; } } AJ_PauseTX(); //put the buffer on the pending list if (pendingSendBuffer == NULL) { //Free list was previously NULL, so re-enable reading //Save a pointer to the recv buffer, so we can keep track when the AJ_RecieveCallback occurs. pendingSendBuffer = currentSlippedBuffer; //pendingSendBuffer->next = NULL; AJ_TX(pendingSendBuffer->buffer, pendingSendBuffer->actualLen); } else { if (bufferTxPending != NULL) { volatile AJ_SlippedBuffer* buf = bufferTxPending; while (buf->next != NULL) { buf = buf->next; } buf->next = currentSlippedBuffer; } else { bufferTxPending = currentSlippedBuffer; } } } if (!bufferTxFreeList) { dataSent = FALSE; } if (pendingSendBuffer != NULL) { AJ_ResumeTX(); } } #endif /* AJ_SERIAL_CONNECTION */ ajtcl-16.04/src/aj_std.c000066400000000000000000000237141271074662300150370ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include const char AJ_DBusDestination[] = "org.freedesktop.DBus"; const char AJ_BusDestination[] = "org.alljoyn.Bus"; const char AJ_ErrServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown"; const char AJ_ErrTimeout[] = "org.alljoyn.Bus.Timeout"; const char AJ_ErrRejected[] = "org.alljoyn.Bus.Rejected"; const char AJ_ErrResources[] = "org.alljoyn.Bus.Resources"; const char AJ_ErrUpdateNotAllowed[] = "org.alljoyn.Error.UpdateNotAllowed"; const char AJ_ErrInvalidValue[] = "org.alljoyn.Error.InvalidValue"; const char AJ_ErrFeatureNotAvailable[] = "org.alljoyn.Error.FeatureNotAvailable"; const char AJ_ErrMaxSizeExceeded[] = "org.alljoyn.Error.MaxSizeExceeded"; const char AJ_ErrLanguageNotSuppored[] = "org.alljoyn.Error.LanguageNotSupported"; const char AJ_ErrMethodNotAllowed[] = "org.alljoyn.Error.MethodNotAllowed"; /* Security specific errors */ const char AJ_ErrSecurityViolation[] = "org.alljoyn.Bus.SecurityViolation"; const char AJ_ErrPermissionDenied[] = "org.alljoyn.Bus.Security.Error.PermissionDenied"; const char AJ_ErrDigestMismatch[] = "org.alljoyn.Bus.Security.Error.DigestMismatch"; const char AJ_ErrInvalidCertificate[] = "org.alljoyn.Bus.Security.Error.InvalidCertificate"; const char AJ_ErrDuplicateCertificate[] = "org.alljoyn.Bus.Security.Error.DuplicateCertificate"; const char AJ_ErrCertificateNotFound[] = "org.alljoyn.Bus.Security.Error.CertificateNotFound"; const char AJ_ErrPolicyNotNewer[] = "org.alljoyn.Bus.Security.Error.PolicyNotNewer"; static const char DBusObjectPath[] = "/org/freedesktop/DBus"; static const char DBusInterface[] = "org.freedesktop.DBus"; const char DBusPeerInterface[] = "#org.freedesktop.DBus.Peer"; static const char DBusPropsInterface[] = "#org.freedesktop.DBus.Properties"; static const char DBusIntrospectableInterface[] = "#org.freedesktop.DBus.Introspectable"; static const char BusObjectPath[] = "/org/alljoyn/Bus"; static const char BusInterface[] = "org.alljoyn.Bus"; static const char DaemonObjectPath[] = "/"; static const char DaemonInterface[] = "org.alljoyn.Daemon"; static const char PeerObjectPath[] = "/org/alljoyn/Bus/Peer"; static const char PeerSessionInterface[] = "org.alljoyn.Bus.Peer.Session"; const char PeerAuthInterface[] = "org.alljoyn.Bus.Peer.Authentication"; static const char AboutObjectPath[] = "/About"; static const char AboutInterface[] = "org.alljoyn.About"; static const char AboutIconObjectPath[] = "/About/DeviceIcon"; static const char AboutIconInterface[] = "org.alljoyn.Icon"; const char AllSeenIntrospectableInterface[] = "#org.allseen.Introspectable"; static const char SecurityObjectPath[] = "/org/alljoyn/Bus/Security"; static const char ApplicationInterface[] = "org.alljoyn.Bus.Application"; static const char SecurityApplicationInterface[] = "$org.alljoyn.Bus.Security.Application"; static const char SecurityClaimableApplicationInterface[] = "$org.alljoyn.Bus.Security.ClaimableApplication"; static const char SecurityManagedApplicationInterface[] = "$org.alljoyn.Bus.Security.ManagedApplication"; const char* const AJ_PropertiesIface[] = { DBusPropsInterface, "?Get v", "?Set a{sv}", "!PropertiesChanged >s >a{sv} >as", NULL }; const char* const AJ_IntrospectionIface[] = { DBusIntrospectableInterface, "?Introspect >s", NULL }; const char* const AJ_AllSeenIntrospectionIface[] = { AllSeenIntrospectableInterface, "?GetDescriptionLanguages >as", "?IntrospectWithDescription s", NULL }; static const char* const DBusIface[] = { DBusInterface, "?Hello >s", "!NameOwnerChanged >s >s >s", "!NameAcquired >s", "!NameLost >s", "?RequestName u", "?AddMatch u", "?NameHasOwner b", NULL }; static const char* const DBusPeerIface[] = { DBusPeerInterface, "?Ping", "?GetMachineId >s", NULL }; static const AJ_InterfaceDescription DBusIfaces[] = { DBusIface, NULL }; static const char* const BusIface[] = { BusInterface, "!SessionLost >u", "!FoundAdvertisedName >s >q >s", "!LostAdvertisedName >s >q >s", "!MPSessionChanged >u >s >b", "?AdvertiseName u", "?CancelAdvertiseName u", "?FindAdvertisedName u", "?CancelFindAdvertisedName u", "?BindSessionPort u >q", "?UnbindSessionPort u", "?JoinSession u >u >a{sv}", "?LeaveSession u", "?CancelSessionlessMessage u", "?FindAdvertisedNameByTransport u", "?CancelFindAdvertisedNameByTransport u", "?SetLinkTimeout u >u", "?RemoveSessionMember u", "!SessionLostWithReason >u >u", "?Ping u", "?SetIdleTimeouts u >u >u", "?SimpleHello s >s >u", NULL }; static const char* const DaemonIface[] = { DaemonInterface, "!ProbeReq", "!ProbeAck", NULL }; static const char* const PeerSessionIface[] = { PeerSessionInterface, "?AcceptSession b", "!SessionJoined >q >u >s", NULL }; static const char* const PeerAuthIface[] = { PeerAuthInterface, "?ExchangeGuids s >u", "?GenSessionKey s >s", "?ExchangeGroupKeys ay", "?AuthChallenge s", "?ExchangeSuites au", "?KeyExchange u >v", "?KeyAuthentication v", "?SendManifests a(ua(ssa(syy))saysay)", "?SendMemberships ya(yay)", "@Mechanisms>s", "@Version>u", NULL }; static const char* const AboutIface[] = { AboutInterface, "@Version>q", "?GetAboutData a{sv}", "?GetObjectDescription >a(oas)", "!&Announce >q >q >a(oas) >a{sv}", NULL }; static const char* const AboutIconIface[] = { AboutIconInterface, "@Version>q", "@MimeType>s", "@Size>u", "?GetUrl >s", "?GetContent >ay", NULL }; static const char* const ApplicationIface[] = { ApplicationInterface, "@Version>q", "!&State >(yyayay) >q", NULL }; static const char* const SecurityApplicationIface[] = { SecurityApplicationInterface, "@Version>q", "@ApplicationState>q", "@ManifestTemplateDigest>(yay)", "@EccPublicKey>(yyayay)", "@ManufacturerCertificate>a(yay)", "@ManifestTemplate>a(ssa(syy))", "@ClaimCapabilities>q", "@ClaimCapabilityAdditionalInfo>q", NULL }; static const char* const SecurityClaimableApplicationIface[] = { SecurityClaimableApplicationInterface, "@Version>q", "?Claim <(yyayay) q", "@Identity>a(yay)", "@Manifests>a(ua(ssa(syy))saysay)", "@IdentityCertificateId>(ayay(yyayay))", "@PolicyVersion>u", "@Policy>(qua(a(ya(yyayayay)ay)a(ssa(syy))))", "@DefaultPolicy>(qua(a(ya(yyayayay)ay)a(ssa(syy))))", "@MembershipSummaries>a(ayay(yyayay))", "?Reset", "?UpdateIdentity /* * Identifies an AJ NVRAM block */ #define AJ_NV_SENTINEL ('A' | ('J' << 8) | ('N' << 16) | ('V' << 24)) #define INVALID_ID (0) #define INVALID_DATA (0xFFFF) #define INVALID_DATA_BYTE (0xFF) #define SENTINEL_OFFSET (4) typedef struct _NV_EntryHeader { uint16_t id; /**< The unique id */ uint16_t capacity; /**< The data set size */ } NV_EntryHeader; #define ENTRY_HEADER_SIZE (sizeof(NV_EntryHeader)) #define AJ_NVRAM_END_ADDRESS (AJ_NVRAM_BASE_ADDRESS + AJ_NVRAM_SIZE) /** * Write a block of data to NVRAM * * @param dest Pointer a location of NVRAM * @param buf Pointer to data to be written * @param size The number of bytes to be written */ void _AJ_NV_Write(void* dest, const void* buf, uint16_t size); /** * Read a block of data from NVRAM * * @param src Pointer a location of NVRAM * @param buf Pointer to data to be written * @param size The number of bytes to be written */ void _AJ_NV_Read(void* src, void* buf, uint16_t size); /** * Erase the whole NVRAM sector and write the sentinel data */ void _AJ_NVRAM_Clear(); /** * Load NVRAM data from a file */ AJ_Status _AJ_LoadNVFromFile(); /** * Write NVRAM data to a file for persistent storage */ AJ_Status _AJ_StoreNVToFile(); #endif ajtcl-16.04/src/aj_util.c000066400000000000000000000212011271074662300152070ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #define AJ_TO_STRING(x) # x #define AJ_VERSION_STRING(a, b, c, d, e) AJ_TO_STRING(a) "." AJ_TO_STRING(b) "." AJ_TO_STRING(c) AJ_TO_STRING(d) " Tag " AJ_TO_STRING(e) "\0" const char* AJ_GetVersion() { static const char VERSION[] = AJ_VERSION_STRING(AJ_RELEASE_YEAR_STR, AJ_RELEASE_MONTH_STR, AJ_FEATURE_VERSION_STR, AJ_BUGFIX_VERSION_STR, AJ_RELEASE_TAG); return &VERSION[0]; } static uint8_t A2H(char hex, AJ_Status* status) { if (hex >= '0' && hex <= '9') { return hex - '0'; } hex |= 0x20; if (hex >= 'a' && hex <= 'f') { return 10 + hex - 'a'; } else if (hex >= 'A' && hex <= 'F') { return 10 + hex - 'A'; } else { *status = AJ_ERR_INVALID; return 0; } } int32_t AJ_StringFindFirstOf(const char* str, const char* chars) { if (str) { const char* p = str; do { const char* c = chars; while (*c) { if (*p == *c++) { return (int32_t)(p - str); } } } while (*(++p)); } return -1; } AJ_Status AJ_RawToHex(const uint8_t* raw, size_t rawLen, char* hex, size_t hexLen, uint8_t lower) { static const char nibble_upper[] = "0123456789ABCDEF"; static const char nibble_lower[] = "0123456789abcdef"; const char* nibble = lower ? nibble_lower : nibble_upper; char* h = hex + 2 * rawLen; const uint8_t* a = raw + rawLen; if ((2 * rawLen + 1) > hexLen) { return AJ_ERR_RESOURCES; } h[0] = '\0'; /* * Running backwards encode each byte in inStr as a pair of ascii hex digits. * Going backwards allows the raw and hex buffers to be the same buffer. */ while (rawLen--) { uint8_t n = *(--a); h -= 2; h[0] = nibble[n >> 4]; h[1] = nibble[n & 0xF]; } return AJ_OK; } AJ_Status AJ_HexToRaw(const char* hex, size_t hexLen, uint8_t* raw, size_t rawLen) { AJ_Status status = AJ_OK; char* p = (char*)raw; size_t sz = hexLen ? hexLen : strlen(hex); size_t i; /* * Length of encoded hex must be an even number */ if (sz & 1) { return AJ_ERR_UNEXPECTED; } if (rawLen < (sz / 2)) { return AJ_ERR_RESOURCES; } for (i = 0; (i < sz) && (status == AJ_OK); i += 2, hex += 2) { *p++ = (A2H(hex[0], &status) << 4) | A2H(hex[1], &status); } return status; } static const char encode_token[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const uint8_t decode_token[] = { 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, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; AJ_Status AJ_RawToB64(const uint8_t* raw, size_t rawlen, char* pem, size_t pemlen) { char* p = pem; uint32_t b; int n = rawlen; if (pemlen < 4 * ((rawlen + 2) / 3) + 1) { return AJ_ERR_RESOURCES; } while (n > 0) { b = 0; b |= (n > 0 ? (*raw++) << 2 * 8 : 0); b |= (n > 1 ? (*raw++) << 1 * 8 : 0); b |= (n > 2 ? (*raw++) << 0 * 8 : 0); *p++ = encode_token[(b >> 3 * 6) & 0x3F]; *p++ = encode_token[(b >> 2 * 6) & 0x3F]; *p++ = (n > 1 ? encode_token[(b >> 1 * 6) & 0x3F] : '='); *p++ = (n > 2 ? encode_token[(b >> 0 * 6) & 0x3F] : '='); n -= 3; } *p = '\0'; return AJ_OK; } AJ_Status AJ_B64ToRaw(const char* pem, size_t pemlen, uint8_t* raw, size_t rawlen) { uint8_t* r = raw; uint32_t b; int n = pemlen; if (rawlen < 3 * (pemlen / 4)) { return AJ_ERR_RESOURCES; } if (0 != (pemlen % 4)) { return AJ_ERR_RESOURCES; } /* * Don't need to explicitly look for '=' padding, * the decode_token for '=' is 0x00. */ while (n > 0) { b = 0; b |= decode_token[(uint8_t) *pem++] << 3 * 6; b |= decode_token[(uint8_t) *pem++] << 2 * 6; b |= decode_token[(uint8_t) *pem++] << 1 * 6; b |= decode_token[(uint8_t) *pem++] << 0 * 6; *r++ = (b >> 2 * 8) & 0xFF; *r++ = (b >> 1 * 8) & 0xFF; *r++ = (b >> 0 * 8) & 0xFF; n -= 4; } return AJ_OK; } void HostU16ToBigEndianU8(uint16_t* u16, size_t len, uint8_t* u8) { uint16_t x; size_t i; for (i = 0; i < len; i += sizeof(uint16_t)) { x = u16[i / sizeof(uint16_t)]; #if HOST_IS_LITTLE_ENDIAN x = AJ_ByteSwap16(x); #endif memcpy(&u8[i], &x, sizeof(x)); } } void HostU16ToLittleEndianU8(uint16_t* u16, size_t len, uint8_t* u8) { uint16_t x; size_t i; for (i = 0; i < len; i += sizeof(uint16_t)) { x = u16[i / sizeof(uint16_t)]; #if HOST_IS_BIG_ENDIAN x = AJ_ByteSwap16(x); #endif memcpy(&u8[i], &x, sizeof(x)); } } void HostU32ToLittleEndianU8(uint32_t* u32, size_t len, uint8_t* u8) { uint32_t x; size_t i; for (i = 0; i < len; i += sizeof(uint32_t)) { x = u32[i / sizeof(uint32_t)]; #if HOST_IS_BIG_ENDIAN x = AJ_ByteSwap32(x); #endif memcpy(&u8[i], &x, sizeof(x)); } } void HostU32ToBigEndianU8(uint32_t* u32, size_t len, uint8_t* u8) { uint32_t x; size_t i; for (i = 0; i < len; i += sizeof (uint32_t)) { x = u32[i / sizeof (uint32_t)]; #if HOST_IS_LITTLE_ENDIAN x = AJ_ByteSwap32(x); #endif memcpy(&u8[i], &x, sizeof (x)); } } void BigEndianU8ToHostU32(uint8_t* u8, uint32_t* u32, size_t len) { uint32_t x; size_t i; for (i = 0; i < len; i += sizeof (uint32_t)) { memcpy(&x, &u8[i], sizeof (x)); #if HOST_IS_LITTLE_ENDIAN x = AJ_ByteSwap32(x); #endif u32[i / sizeof (uint32_t)] = x; } } void HostU64ToBigEndianU8(uint64_t* u64, size_t len, uint8_t* u8) { uint64_t x; size_t i; for (i = 0; i < len; i += sizeof(uint64_t)) { x = u64[i / sizeof(uint64_t)]; #if HOST_IS_LITTLE_ENDIAN x = AJ_ByteSwap64(x); #endif memcpy(&u8[i], &x, sizeof(x)); } } void HostU64ToLittleEndianU8(uint64_t* u64, size_t len, uint8_t* u8) { uint64_t x; size_t i; for (i = 0; i < len; i += sizeof(uint64_t)) { x = u64[i / sizeof(uint64_t)]; #if HOST_IS_BIG_ENDIAN x = AJ_ByteSwap64(x); #endif memcpy(&u8[i], &x, sizeof(x)); } } ajtcl-16.04/src/bsp/000077500000000000000000000000001271074662300142045ustar00rootroot00000000000000ajtcl-16.04/src/bsp/aj_bsp.h000066400000000000000000000061701271074662300156170ustar00rootroot00000000000000/** * @file Platform specific function declarations that must be defined per platform port */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_BSP_H_ #define AJ_BSP_H_ #include #ifdef __cplusplus extern "C" { #endif /* * This file contains the layer between alljoyn and platform specific code. * All the functions in this header need to be implemented in the platform * folder for example 'due'. */ /* * This function should include any initialization that needs to be done * for the specific platform. (Clock, UART, SPI, GPIO etc.) */ void AJ_PlatformInit(void); /** * Platform specific SPI write function. This function write 1 byte of data to the SPI * peripheral. * * @param spi_device The SPI device to write to (on the FRDM platform this has no effect) * @param byte Byte of data to write to SPI * @param pcs Chip Select device your writing to (on the FRDM platform this has no effect) * @param cont Signals whether or not to assert/de-assert chip select to end the transfer * * @return SPI_OK on success, SPI_ERR upon error */ aj_spi_status AJ_SPI_WRITE(uint8_t* spi_device, uint8_t byte, uint8_t pcs, uint8_t cont); /** * Platform specific SPI read function. Read 1 byte of data from the SPI peripheral * * @param spi_device The SPI device to read from (on the FRDM platform this has no effect) * @param data Pointer to a buffer to read into * @param pcs Chip select device to read from (on the FRDM platform this has no effect) */ aj_spi_status AJ_SPI_READ(uint8_t* spi_device, uint8_t* data, uint8_t pcs); /* * This function should be implemented on a specific platform to initialize * the SPI hardware */ void AJ_WSL_SPI_InitializeSPIController(void); /* * This function should be implemented on a specific platform to shutdown * the SPI hardware */ void AJ_WSL_SPI_ShutdownSPIController(void); /* * This function should be implemented on a specific platform as the * SPI interrupt handler */ void AJ_WSL_SPI_ISR(void); void AJ_WSL_SPI_CHIP_SPI_ISR(uint32_t id, uint32_t mask); AJ_Status AJ_WSL_SPI_DMATransfer(uint8_t* buffer, uint16_t len, uint8_t direction); #ifdef __cplusplus } #endif #endif /* AJ_BSP_H_ */ ajtcl-16.04/src/crypto/000077500000000000000000000000001271074662300147405ustar00rootroot00000000000000ajtcl-16.04/src/crypto/aj_crypto_aes.c000066400000000000000000000206631271074662300177350ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CRYPTO #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgCRYPTO = 0; #endif /* * AES-128 processes data 16 bytes at a time */ #define AJ_BLOCKSZ 16 #if AJ_CCM_TRACE #define Trace(tag, data, len) AJ_DumpBytes(tag, data, len) #else #define Trace(tag, data, len) #endif /* * Struct for a single AES data block */ typedef struct _AES_Block { uint8_t data[AJ_BLOCKSZ]; } AES_Block; #define ZERO(b) memset((b).data, 0, AJ_BLOCKSZ); /* * Struct holding CCM state information */ typedef struct _CCM_Context { AES_Block T; /* authentication tag */ AES_Block ivec0; /* ivec for CBC MAC */ AES_Block ivec; /* ivec for CTR mode encrypt/decrypt */ union { AES_Block A; /* Working data for CBC MAC */ AES_Block B_0; /* Initial block for CBC MAC */ }; } CCM_Context; /** * Compute the CBC MAC over some data */ static void CBC_MAC(const uint8_t* key, const uint8_t* in, uint32_t len, CCM_Context* context) { while (len >= AJ_BLOCKSZ) { AJ_AES_CBC_128_ENCRYPT(key, in, context->T.data, AJ_BLOCKSZ, context->ivec0.data); Trace("After AES", context->T.data, AJ_BLOCKSZ); in += AJ_BLOCKSZ; len -= AJ_BLOCKSZ; } if (len) { ZERO(context->A); memcpy(context->A.data, in, len); AJ_AES_CBC_128_ENCRYPT(key, context->A.data, context->T.data, AJ_BLOCKSZ, context->ivec0.data); Trace("After AES", context->T.data, AJ_BLOCKSZ); } } /** * Compute the AES-CCM authentication tag. */ static void Compute_CCM_AuthTag(const uint8_t* key, CCM_Context* context, const uint8_t* msg, uint32_t mLen, uint32_t hdrLen) { /* * Initialize CBC-MAC with B_0 initialization vector is 0. */ Trace("CBC IV in", context->B_0.data, AJ_BLOCKSZ); AJ_AES_CBC_128_ENCRYPT(key, context->B_0.data, context->T.data, AJ_BLOCKSZ, context->ivec0.data); Trace("CBC IV out", context->T.data, AJ_BLOCKSZ); /* * Compute CBC-MAC for the add data. */ if (hdrLen) { uint32_t firstFew; /* * This encodes the header data length and the first few bytes of the header data */ ZERO(context->A); context->A.data[0] = (uint8_t)(hdrLen >> 8); context->A.data[1] = (uint8_t)(hdrLen >> 0); firstFew = min(hdrLen, 14); memcpy(&context->A.data[2], msg, firstFew); /* * Adjust for the hdr data bytes that were encoded in the length block */ msg += firstFew; hdrLen -= firstFew; /* * Continue the MAC by encrypting the length block */ Trace("Before AES", context->A.data, AJ_BLOCKSZ); AJ_AES_CBC_128_ENCRYPT(key, context->A.data, context->T.data, AJ_BLOCKSZ, context->ivec0.data); Trace("After AES", context->T.data, AJ_BLOCKSZ); /* * Continue computing the CBC-MAC */ CBC_MAC(key, msg, hdrLen, context); msg += hdrLen; } /* * Continue computing CBC-MAC over the message data. */ if (mLen) { CBC_MAC(key, msg, mLen, context); } Trace("CBC-MAC", context->T.data, context->M); } static CCM_Context* InitCCMContext(const uint8_t* nonce, uint32_t nLen, uint32_t hdrLen, uint32_t msgLen, uint8_t M) { int i; int l; uint8_t L = 15 - max(nLen, 11); uint8_t flags = ((hdrLen) ? 0x40 : 0) | (((M - 2) / 2) << 3) | (L - 1); CCM_Context* context; AJ_ASSERT(nLen <= 15); context = (CCM_Context*)AJ_Malloc(sizeof(CCM_Context)); if (context) { memset(context, 0, sizeof(CCM_Context)); /* * Set ivec and other initial args. */ context->ivec.data[0] = L - 1; memcpy(&context->ivec.data[1], nonce, nLen); /* * Compute the B_0 block. This encodes the flags, the nonce, and the message length. */ context->B_0.data[0] = flags; memcpy(&context->B_0.data[1], nonce, nLen); for (i = 15, l = msgLen - hdrLen; l != 0; i--) { context->B_0.data[i] = (uint8_t)l; l >>= 8; } } return context; } /* * Implements AES-CCM (Counter with CBC-MAC) encryption as described in RFC 3610 */ AJ_Status AJ_Encrypt_CCM(const uint8_t* key, uint8_t* msg, uint32_t msgLen, uint32_t hdrLen, uint8_t tagLen, const uint8_t* nonce, uint32_t nLen) { AJ_Status status = AJ_OK; CCM_Context* context; if (!(context = InitCCMContext(nonce, nLen, hdrLen, msgLen, tagLen))) { AJ_ErrPrintf(("AJ_Encrypt_CCM(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } /* * Do any platform specific operations to enable AES */ AJ_AES_Enable(key); /* * Compute the authentication tag */ Compute_CCM_AuthTag(key, context, msg, msgLen - hdrLen, hdrLen); /* * Encrypt the authentication tag */ AJ_AES_CTR_128(key, context->T.data, msg + msgLen, tagLen, context->ivec.data); Trace("CTR Start", context->ivec.data, AJ_BLOCKSZ); /* * Encrypt the message */ if (msgLen != hdrLen) { AJ_AES_CTR_128(key, msg + hdrLen, msg + hdrLen, msgLen - hdrLen, context->ivec.data); } /* * Balance the enable call above */ AJ_AES_Disable(); /* * Done with the context */ AJ_Free(context); return status; } /* * Implements AES-CCM (Counter with CBC-MAC) decryption as described in RFC 3610 */ AJ_Status AJ_Decrypt_CCM(const uint8_t* key, uint8_t* msg, uint32_t msgLen, uint32_t hdrLen, uint8_t tagLen, const uint8_t* nonce, uint32_t nLen) { AJ_Status status = AJ_OK; CCM_Context* context; if (!(context = InitCCMContext(nonce, nLen, hdrLen, msgLen, tagLen))) { AJ_ErrPrintf(("AJ_Decrypt_CCM(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } /* * Do any platform specific operations to enable AES */ AJ_AES_Enable(key); /* * Decrypt the authentication field */ AJ_AES_CTR_128(key, msg + msgLen, msg + msgLen, tagLen, context->ivec.data); /* * Decrypt message. */ if (msgLen != hdrLen) { AJ_AES_CTR_128(key, msg + hdrLen, msg + hdrLen, msgLen - hdrLen, context->ivec.data); } /* * Compute and verify the authentication tag T. */ Compute_CCM_AuthTag(key, context, msg, msgLen - hdrLen, hdrLen); /* * Balance the enable call above */ AJ_AES_Disable(); if (AJ_Crypto_Compare(context->T.data, msg + msgLen, tagLen) != 0) { /* * Authentication failed Clear the decrypted data */ memset(msg, 0, msgLen + tagLen); AJ_ErrPrintf(("AJ_Decrypt_CCM(): AJ_ERR_SECURITY\n")); status = AJ_ERR_SECURITY; } /* * Done with the context */ AJ_Free(context); return status; } ajtcl-16.04/src/crypto/aj_crypto_drbg.c000066400000000000000000000121011271074662300200670ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CRYPTO_DRBG #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgCRYPTO_DRBG = 0; #endif /* * CTR DRBG is implemented using algorithms described in the * NIST SP 800-90A standard, which can be found at * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf */ static void AES_CTR_DRBG_Increment(uint8_t* data, size_t size) { while (size--) { data[size]++; if (data[size]) { break; } } } static void AES_CTR_DRBG_Update(CTR_DRBG_CTX* ctx, uint8_t data[SEEDLEN]) { size_t i = 0; uint8_t tmp[SEEDLEN]; uint8_t* t = tmp; AJ_AES_Enable(ctx->k); for (i = 0; i < SEEDLEN; i += OUTLEN) { AES_CTR_DRBG_Increment(ctx->v, OUTLEN); AJ_AES_ECB_128_ENCRYPT(ctx->k, ctx->v, t); t += OUTLEN; } for (i = 0; i < SEEDLEN; i++) { tmp[i] ^= data[i]; } memcpy(ctx->k, tmp, KEYLEN); memcpy(ctx->v, tmp + KEYLEN, OUTLEN); } static void AES_CTR_DRBG_BCC(uint8_t* k, uint8_t* data, size_t size, uint8_t* out) { size_t i; size_t j; AJ_ASSERT(0 == (size % OUTLEN)); memset(out, 0, OUTLEN); AJ_AES_Enable(k); for (i = 0; i < size; i += OUTLEN) { for (j = 0; j < OUTLEN; j++) { out[j] ^= data[j]; } AJ_AES_ECB_128_ENCRYPT(k, out, out); data += OUTLEN; } } static void AES_CTR_DRBG_DF(uint8_t* seed, size_t size, uint8_t data[SEEDLEN]) { // Variable names reflect NIST SP 800-90A uint32_t i = 0; uint32_t L = size; uint32_t N = SEEDLEN; uint32_t n = OUTLEN + sizeof (L) + sizeof (N) + size + sizeof (0x80); uint8_t* S; uint8_t* s; uint8_t k[KEYLEN]; uint8_t K[KEYLEN]; uint8_t X[KEYLEN]; n += (OUTLEN - (n % OUTLEN)); AJ_ASSERT(0 == (n % OUTLEN)); S = AJ_Malloc(n); if (NULL == S) { // Errors are not propagated up return; } memset(S, 0, n); s = S + OUTLEN; *s++ = (L >> 24) & 0xFF; *s++ = (L >> 16) & 0xFF; *s++ = (L >> 8) & 0xFF; *s++ = (L >> 0) & 0xFF; *s++ = (N >> 24) & 0xFF; *s++ = (N >> 16) & 0xFF; *s++ = (N >> 8) & 0xFF; *s++ = (N >> 0) & 0xFF; memcpy(s, seed, size); s += size; *s++ = 0x80; for (i = 0; i < KEYLEN; i++) { k[i] = i; } AES_CTR_DRBG_BCC(k, S, n, K); AES_CTR_DRBG_Increment(S, 4); AES_CTR_DRBG_BCC(k, S, n, X); AJ_AES_Enable(K); AJ_AES_ECB_128_ENCRYPT(K, X, X); memcpy(data, X, OUTLEN); data += OUTLEN; AJ_AES_ECB_128_ENCRYPT(K, X, X); memcpy(data, X, OUTLEN); AJ_Free(S); } void AES_CTR_DRBG_Reseed(CTR_DRBG_CTX* ctx, uint8_t* seed, size_t size) { uint8_t data[SEEDLEN]; if (ctx->df) { AES_CTR_DRBG_DF(seed, size, data); AES_CTR_DRBG_Update(ctx, data); } else { AJ_ASSERT(SEEDLEN == size); AES_CTR_DRBG_Update(ctx, seed); } ctx->c = 1; } void AES_CTR_DRBG_Instantiate(CTR_DRBG_CTX* ctx, uint8_t* seed, size_t size, uint8_t df) { memset(ctx->k, 0, KEYLEN); memset(ctx->v, 0, OUTLEN); ctx->df = df; AES_CTR_DRBG_Reseed(ctx, seed, size); } AJ_Status AES_CTR_DRBG_Generate(CTR_DRBG_CTX* ctx, uint8_t* randBuf, size_t size) { uint8_t data[SEEDLEN]; size_t copy; // Reseed interval 2^32 (counter wraps to zero) if (0 == ctx->c) { return AJ_ERR_SECURITY; } AJ_AES_Enable(ctx->k); while (size) { AES_CTR_DRBG_Increment(ctx->v, OUTLEN); AJ_AES_ECB_128_ENCRYPT(ctx->k, ctx->v, data); copy = (size < OUTLEN) ? size : OUTLEN; memcpy(randBuf, data, copy); randBuf += copy; size -= copy; } memset(data, 0, SEEDLEN); AES_CTR_DRBG_Update(ctx, data); ctx->c++; return AJ_OK; } ajtcl-16.04/src/crypto/aj_crypto_ec_p256.c000066400000000000000000001104641271074662300203270ustar00rootroot00000000000000/** * @file ec_p256.c Implementation curve arithmetic (NIST-P256) for ECC. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #define W_VARBASE 6 /* Parameter for scalar multiplication. Should use 2-2.5 KB. Must be >= 2. */ static digit256_tc P256_A = { 0xFFFFFFFFFFFFFFFCULL, 0x00000000FFFFFFFFULL, 0x0000000000000000ULL, 0xFFFFFFFF00000001ULL }; static digit256_tc P256_B = { 0x3BCE3C3E27D2604BULL, 0x651D06B0CC53B0F6ULL, 0xB3EBBD55769886BCULL, 0x5AC635D8AA3A93E7ULL }; static digit256_tc P256_ORDER = { 0xF3B9CAC2FC632551ULL, 0xBCE6FAADA7179E84ULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFF00000000ULL }; static digit256_tc P256_GENERATOR_X = { 0xF4A13945D898C296ULL, 0x77037D812DEB33A0ULL, 0xF8BCE6E563A440F2ULL, 0x6B17D1F2E12C4247ULL }; static digit256_tc P256_GENERATOR_Y = { 0xCBB6406837BF51F5ULL, 0x2BCE33576B315ECEULL, 0x8EE7EB4A7C0F9E16ULL, 0x4FE342E2FE1A7F9BULL }; AJ_Status ec_getcurve(ec_t* curve, curveid_t curveid) { AJ_Status status = AJ_ERR_UNKNOWN; if (curve == NULL) { status = AJ_ERR_NULL; goto Exit; } if (curveid == NISTP256r1) { memset(curve, 0x00, sizeof(ec_t)); curve->curveid = curveid; curve->rbits = 256; curve->pbits = 256; curve->prime = AJ_Malloc(sizeof(digit256_t)); curve->a = AJ_Malloc(sizeof(digit256_tc)); curve->b = AJ_Malloc(sizeof(digit256_tc)); curve->order = AJ_Malloc(sizeof(digit256_tc)); if (curve->prime == NULL || curve->a == NULL || curve->b == NULL || curve->order == NULL) { status = AJ_ERR_RESOURCES; goto Exit; } fpgetprime_p256(curve->prime); fpcopy_p256(P256_A, curve->a); fpcopy_p256(P256_B, curve->b); fpcopy_p256(P256_ORDER, curve->order); fpcopy_p256(P256_GENERATOR_X, curve->generator.x); fpcopy_p256(P256_GENERATOR_Y, curve->generator.y); /* These two curve fields are required for ECDSA, Montgomery arithmetic modulo the group order. Precompute and set here.*/ // digit_t* Rprime; /* (2^W)^2 mod r, where r is the order and W is its bitlength */ // digit_t* rprime; /* -(r^-1) mod 2^W */ status = AJ_OK; } else { /* Unknown curve. */ status = AJ_ERR_INVALID; goto Exit; } Exit: if (status != AJ_OK) { ec_freecurve(curve); } return status; } void ec_freecurve(ec_t* curve) { if (curve != NULL) { // Cleanup AJ_Free(curve->a); AJ_Free(curve->b); AJ_Free(curve->order); AJ_Free(curve->prime); memset(curve, 0x00, sizeof(ec_t)); } } /* Convert affine point Q = (x,y) to Jacobian P = (X:Y:1), where X=x, Y=y */ void ec_affine_tojacobian(const ecpoint_t* Q, ecpoint_jacobian_t* P) { AJ_ASSERT(Q != NULL); AJ_ASSERT(P != NULL); fpcopy_p256(Q->x, P->X); fpcopy_p256(Q->y, P->Y); fpzero_p256(P->Z); P->Z[0] = 1; } /* Set P to the generator of the curve. */ void ec_get_generator(ecpoint_t* P, ec_t* curve) { AJ_ASSERT(curve != NULL); memcpy(P->x, curve->generator.x, sizeof(digit256_t)); memcpy(P->y, curve->generator.y, sizeof(digit256_t)); } /* Set the jacobian point P to zero (0,0,0). */ static void ecpoint_jacobian_zero(ecpoint_jacobian_t* P) { AJ_ASSERT(P != NULL); fpzero_p256(P->X); fpzero_p256(P->Y); fpzero_p256(P->Z); } /* Copy Jacobian points, set src = dst. */ static void ecpoint_jacobian_copy(ecpoint_jacobian_t* src, ecpoint_jacobian_t* dst) { AJ_ASSERT(src != NULL); AJ_ASSERT(dst != NULL); fpcopy_p256(src->X, dst->X); fpcopy_p256(src->Y, dst->Y); fpcopy_p256(src->Z, dst->Z); } static void ecpoint_chudnovsky_zero(ecpoint_chudnovsky_t* P) { AJ_ASSERT(P != NULL); fpzero_p256(P->X); fpzero_p256(P->Y); fpzero_p256(P->Z); fpzero_p256(P->Z2); fpzero_p256(P->Z3); } /* Check if point P is the point at infinity (0,0) */ boolean_t ec_is_infinity(const ecpoint_t* P, ec_t* curve) { size_t i = 0; digit_t c = 0; size_t num_digits = NBITS_TO_NDIGITS(curve->pbits); for (i = 0; i < num_digits; i++) { c = c | P->x[i] | P->y[i]; } return is_digit_zero_ct(c); } /* Check if Jacobian point P is the point at infinity (0:Y:0) */ boolean_t ec_is_infinity_jacobian(const ecpoint_jacobian_t* P, ec_t* curve) { size_t i = 0; digit_t c = 0; size_t num_digits = NBITS_TO_NDIGITS(curve->pbits); for (i = 0; i < num_digits; i++) { c = c | P->X[i] | P->Z[i]; } return is_digit_zero_ct(c); } boolean_t ec_oncurve(const ecpoint_t* P, ec_t* curve) { digit256_t t1, t2, t3; digit_t temps[P256_TEMPS]; boolean_t oncurve; /* Do (x,y) satisfy the curve equation y^2 = x^3 -3x + b (mod p) */ fpsqr_p256(P->y, t1, temps); /* t1 = y^2 */ fpsqr_p256(P->x, t2, temps); /* t2 = x^2 */ fpmul_p256(P->x, t2, t2, temps); /* t2 = x^3 */ fpadd_p256(t2, P256_B, t2); /* t2 = x^3 +b */ fpadd_p256(P->x, P->x, t3); /* t3 = 2x*/ fpadd_p256(P->x, t3, t3); /* t3 = 3x */ fpsub_p256(t2, t3, t2); /* t2 = x^3 - 3x + b */ oncurve = fpequal_p256(t1, t2); fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); AJ_MemZeroSecure(temps, sizeof(temps)); return oncurve; } /* Check that P=(x,y) lies on the curve, is nonzero has x and y in [0, p-1]. */ boolean_t ecpoint_validation(const ecpoint_t* P, ec_t* curve) { if (ec_is_infinity(P, curve)) { return B_FALSE; } if (!fpvalidate_p256(P->x) || !fpvalidate_p256(P->y)) { return B_FALSE; } if (!ec_oncurve(P, curve)) { return B_FALSE; } return B_TRUE; } /* Convert the Jacobian point Q = (X:Y:Z) to an affine point P = (x,y) */ void ec_toaffine(ecpoint_jacobian_t* Q, ecpoint_t* P, ec_t* curve) { digit256_t t1, t2, t3; digit_t temps[P256_TEMPS]; /* Check if Q is the point at infinity (0:Y:0) */ /* SECURITY NOTE: this if-statement evaluates over public information when the function is called from constant-time scalar multiplications, i.e., * Q is never the point at infinity when the call is from ec_scalarmul(). */ if (ec_is_infinity_jacobian(Q, curve) == B_TRUE) { fpzero_p256(P->x); fpzero_p256(P->y); /* Output the point at infinity P = (0,0) */ return; } fpinv_p256(Q->Z, t1, temps); /* t1 = Z^-1 */ fpsqr_p256(t1, t2, temps); /* t2 = Z^-2 */ fpmul_p256(Q->X, t2, t3, temps); /* t3 = X/Z^2 */ fpcopy_p256(t3, P->x); /* x = X/Z^2 */ fpmul_p256(t1, t2, t3, temps); /* t3 = Z^-3 */ fpmul_p256(Q->Y, t3, t1, temps); /* t1 = Y/Z^3 */ fpcopy_p256(t1, P->y); /* y = Y/Z^3 */ /* cleanup */ fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); AJ_MemZeroSecure(temps, sizeof(temps)); } /* Point doubling P = 2P * Weierstrass a=-3 curve * Input: P = (X,Y,Z) in Jacobian coordinates * Output: 2P = (X,Y,Z) in Jacobian coordinates */ void ec_double_jacobian(ecpoint_jacobian_t* P) { digit256_t t1, t2, t3, t4; digit_t temps[P256_TEMPS]; /* SECURITY NOTE: this function does not produce exceptions on prime-order Weierstrass curves (such as NIST P256). */ fpsqr_p256(P->Z, t1, temps); /* t1 = z^2 */ fpmul_p256(P->Z, P->Y, t4, temps); /* t4 = zy */ fpadd_p256(P->X, t1, t2); /* t2 = x + z^2 */ fpsub_p256(P->X, t1, t1); /* t1 = x - z^2 */ fpcopy_p256(t4, P->Z); /* Zfinal = zy */ fpmul_p256(t1, t2, t3, temps); /* t3 = (x + z^2)(x - z^2) */ fpdiv2_p256(t3, t2, temps); /* t2 = (x + u.z^2)(x - u.z^2)/2 */ fpadd_p256(t3, t2, t1); /* t1 = alpha = 3(x + u.z^2)(x - u.z^2)/2 */ fpsqr_p256(P->Y, t2, temps); /* t2 = y^2 */ fpsqr_p256(t1, t4, temps); /* t4 = alpha^2 */ fpmul_p256(P->X, t2, t3, temps); /* t3 = beta = xy^2 */ fpsub_p256(t4, t3, t4); /* t4 = alpha^2-beta */ fpsub_p256(t4, t3, P->X); /* Xfinal = alpha^2-2beta */ fpsub_p256(t3, P->X, t4); /* t4 = beta-Xfinal */ fpsqr_p256(t2, t3, temps); /* t3 = y^4 */ fpmul_p256(t1, t4, t2, temps); /* t2 = alpha.(beta-Xfinal) */ fpsub_p256(t2, t3, P->Y); /* Yfinal = alpha.(beta-Xfinal)-y^4 */ /* cleanup */ fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); fpzero_p256(t4); AJ_MemZeroSecure(temps, sizeof(temps)); } /* Point addition P = 2P+Q * Weierstrass a=-3 curve * Inputs: P = (X1,Y1,Z1) in Jacobian coordinates * Q = (X2,Y2,Z2,Z2^2,Z2^3) in Chudnovsky coordinates * Output: P = (X1,Y1,Z1) in Jacobian coordinates */ void ec_doubleadd(ecpoint_chudnovsky_t* Q, ecpoint_jacobian_t* P, ec_t* curve) { digit256_t t1, t2, t3, t4, t5, t6, t7; digit_t temps[P256_TEMPS]; /* SECURITY NOTE: this function does not produce exceptions when P!=inf, Q!=inf, P!=Q, P!=-Q or Q!=-2P. * In particular, it is exception-free when called from ec_scalarmul(). */ UNREFERENCED_PARAMETER(curve); fpsqr_p256(P->Z, t2, temps); /* t2 = z1^2 */ fpmul_p256(Q->Z3, P->Y, t3, temps); /* t3 = z2^3*y1 */ fpmul_p256(P->Z, t2, t4, temps); /* t4 = z1^3 */ fpmul_p256(t2, Q->X, t1, temps); /* t1 = z1^2*x2 */ fpmul_p256(Q->Y, t4, t2, temps); /* t2 = z1^3*y2 */ fpmul_p256(Q->Z2, P->X, t6, temps); /* t6 = z2^2*x1 */ fpsub_p256(t2, t3, t2); /* t2 = alpha = z1^3*y2-z2^3*y1 */ fpsub_p256(t1, t6, t1); /* t1 = beta = z1^2*x2-z2^2*x1 */ fpsqr_p256(t2, t4, temps); /* t4 = alpha^2 */ fpsqr_p256(t1, t5, temps); /* t5 = beta^2 */ fpmul_p256(P->Z, Q->Z, t7, temps); /* t5 = z1*z2 */ fpmul_p256(t6, t5, P->X, temps); /* x1 = x1' = z2^2*x1*beta^2 */ fpmul_p256(t1, t5, t6, temps); /* t6 = beta^3 */ fpsub_p256(t4, t6, t4); /* t4 = alpha^2 - beta^3 */ fpsub_p256(t4, P->X, t4); /* t4 = alpha^2 - beta^3 - x1' */ fpsub_p256(t4, P->X, t4); /* t4 = alpha^2 - beta^3 - 2*x1' */ fpsub_p256(t4, P->X, t4); /* t4 = omega = alpha^2 - beta^3 - 3*x1' */ fpmul_p256(t6, t3, P->Y, temps); /* y1 = y1' = z2^3*y1*beta^3 */ fpmul_p256(t1, t7, t3, temps); /* t3 = z1' = z1*z2*beta */ fpmul_p256(t2, t4, t1, temps); /* t1 = alpha.omega */ fpsqr_p256(t4, t2, temps); /* t2 = omega^2 */ fpadd_p256(t1, P->Y, t1); /* t1 = alpha.omega + y1' */ fpadd_p256(t1, P->Y, t1); /* t1 = theta = alpha.omega + 2y1' */ fpmul_p256(t3, t4, P->Z, temps); /* Zfinal = z1'*omega */ fpmul_p256(t2, t4, t5, temps); /* t5 = omega^3 */ fpmul_p256(t2, P->X, t4, temps); /* t4 = x1'*omega^2 */ fpsqr_p256(t1, t3, temps); /* t3 = theta^2 */ fpsub_p256(t3, t5, t3); /* t3 = theta^2 - omega^3 */ fpsub_p256(t3, t4, t3); /* t3 = theta^2 - omega^3 - x1'*omega^2 */ fpsub_p256(t3, t4, P->X); /* Xfinal = theta^2 - omega^3 - 2*x1'*omega^2 */ fpsub_p256(P->X, t4, t3); /* t3 = Xfinal-x1'*omega^2 */ fpmul_p256(P->Y, t5, t2, temps); /* t2 = y1'*omega^3 */ fpmul_p256(t3, t1, t5, temps); /* t5 = theta.(Xfinal-x1'*omega^2) */ fpsub_p256(t5, t2, P->Y); /* Yfinal = theta.(Xfinal-x1'*omega^2) - y1'*omega^3 */ /* cleanup */ fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); fpzero_p256(t4); fpzero_p256(t5); fpzero_p256(t6); fpzero_p256(t7); AJ_MemZeroSecure(temps, sizeof(temps)); } /* Special point addition R = P+Q with identical Z-coordinate for the precomputation * Weierstrass a=-3 curve * Inputs: P = (X1,Y1,Z) in Jacobian coordinates with the same Z-coordinate * Q = (X2,Y2,Z,Z^2,Z^3) in Chudnovsky coordinates with the same Z-coordinate * Values (X1',Y1') * Outputs: R = (X3,Y3,Z3,Z3^2,Z3^2) in Chudnovsky coordinates * new representation P = (X1',Y1',Z1') = (X1.(X2-X1)^2, X1.(X2-X1)^3, Z.(X2-X1)) in Jacobian coordinates */ static void ecadd_precomp(ecpoint_jacobian_t* P, ecpoint_chudnovsky_t* Q, ecpoint_chudnovsky_t* R) { digit256_t t1, t2, t3, t4; digit_t temps[P256_TEMPS]; /* SECURITY NOTE: this function does not produce exceptions in the context of variable-base precomputation. */ fpsub_p256(Q->X, P->X, t1); /* t1 = x2-x1 */ fpmul_p256(P->Z, t1, R->Z, temps); /* Zfinal = z.(x2-x1) */ fpcopy_p256(R->Z, P->Z); /* Z1' = z.(x2-x1) */ fpsqr_p256(t1, t2, temps); /* t2 = (x2-x1)^2 */ fpsqr_p256(R->Z, R->Z2, temps); /* Z2final = Zfinal^2 */ fpmul_p256(t1, t2, t3, temps); /* t3 = (x2-x1)^3 */ fpmul_p256(P->X, t2, t4, temps); /* t4 = X1' = x1.(x2-x1)^2 */ fpcopy_p256(t4, P->X); /* X1' */ fpsub_p256(Q->Y, P->Y, t1); /* t1 = y2-y1 */ fpsqr_p256(t1, R->X, temps); /* X3 = (y2-y1)^2 */ fpmul_p256(R->Z, R->Z2, R->Z3, temps); /* Z3final = Zfinal^3 */ fpsub_p256(R->X, t3, R->X); /* X3 = (y2-y1)^2 - (x2-x1)^3 */ fpsub_p256(R->X, t4, R->X); /* X3 = (y2-y1)^2 - (x2-x1)^3 - x1.(x2-x1)^2 */ fpsub_p256(R->X, t4, R->X); /* X3final = (y2-y1)^2 - (x2-x1)^3 - 2*x1.(x2-x1)^2 */ fpsub_p256(t4, R->X, t2); /* t2 = x1.(x2-x1)^2-X3 */ fpmul_p256(t1, t2, t4, temps); /* t4 = (y2-y1)[x1.(x2-x1)^2-X3] */ fpmul_p256(P->Y, t3, t2, temps); /* t2 = Y1' = y1*(x2-x1)^3 */ fpcopy_p256(t2, P->Y); /* Y1' */ fpsub_p256(t4, t2, R->Y); /* Yfinal = (y2-y1)[x1.(x2-x1)^2-X3] - y1*(x2-x1)^3 */ /* cleanup */ fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); fpzero_p256(t4); AJ_MemZeroSecure(temps, sizeof(temps)); } /* Precomputation scheme using Jacobian coordinates * Weierstrass a=-3 curve * Input: P = (x,y) * Outputs: T[0] = P, T[1] = 3*P, ... , T[npoints-1] = (2*npoints-1)*P in coordinates (X:Y:Z:Z^2:Z^3) */ static void ec_precomp(const ecpoint_t* P, ecpoint_chudnovsky_t* T, unsigned int npoints, ec_t* curve) { ecpoint_jacobian_t P2; digit256_t t1, t2, t3; size_t i; digit_t temps[P256_TEMPS]; UNREFERENCED_PARAMETER(curve); /* SECURITY NOTE: this function does not produce exceptions in the context of variable-base scalar multiplication and double-scalar multiplication. */ /* Generating 2P = 2(x,y) = (X2,Y2,Z2) and P = (x,y) = (X1',Y1',Z1',Z1^2',Z1^3') = (x*y^2, y*y^3, y, y^2, y^3) */ fpzero_p256(t2); t2[0] = 1; /* t2 = 1 */ fpsqr_p256(P->x, t1, temps); /* t1 = x^2 */ fpsub_p256(t1, t2, t1); /* t1 = x^2-1 */ fpdiv2_p256(t1, t2, temps); /* t2 = (x^2-1)/2 */ fpadd_p256(t1, t2, t1); /* t1 = alpha = 3(x^2-1)/2 */ fpsqr_p256(P->y, T[0].Z2, temps); /* Z1^2' = y^2 */ fpmul_p256(T[0].Z2, P->x, T[0].X, temps); /* X1' = beta = xy^2 */ fpmul_p256(T[0].Z2, P->y, T[0].Z3, temps); /* Z1^3' = y^3 */ fpsqr_p256(t1, t2, temps); /* t2 = alpha^2 */ fpsub_p256(t2, T[0].X, t2); /* t2 = alpha^2-beta */ fpsub_p256(t2, T[0].X, P2.X); /* X2final = alpha^2-2beta */ fpcopy_p256(P->y, P2.Z); /* Z2final = y */ fpcopy_p256(P->y, T[0].Z); /* Z1' = y */ fpsqr_p256(T[0].Z2, T[0].Y, temps); /* Y1' = y^4 */ fpsub_p256(T[0].X, P2.X, t2); /* t2 = beta-Xfinal */ fpmul_p256(t1, t2, t3, temps); /* t3 = alpha.(beta-Xfinal) */ fpsub_p256(t3, T[0].Y, P2.Y); /* Y2final = alpha.(beta-Xfinal)-y^4 */ for (i = 1; i < npoints; i++) { /* T[i] = 2P'+T[i-1] = (2*i+1)P = (X_(2*i+1),Y_(2*i+1),Z_(2*i+1),Z_(2*i+1)^2,Z_(2*i+1)^3) * and new 2P' s.t. Z(2P')=Z_(2*i+1) */ ecadd_precomp(&P2, &(T[i - 1]), &(T[i])); } /* cleanup */ ecpoint_jacobian_zero(&P2); fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); AJ_MemZeroSecure(temps, sizeof(temps)); } /* Constant-time table lookup to extract a Chudnovsky point (X:Y:Z:Z^2:Z^3) from the precomputed table * Weierstrass a=-3 curve * Operation: P = sign * table[(|digit|-1)/2], where sign=1 if digit>0 and sign=-1 if digit<0 */ static void lut_chudnovsky(ecpoint_chudnovsky_t* table, ecpoint_chudnovsky_t* P, int digit, unsigned int npoints, ec_t* curve) { unsigned int i, j; size_t nwords = NBITS_TO_NDIGITS(curve->pbits); digit_t sign, mask, pos; ecpoint_chudnovsky_t point, temp_point; sign = ((digit_t)digit >> (RADIX_BITS - 1)) - 1; /* if digit<0 then sign = 0x00...0 else sign = 0xFF...F */ pos = ((sign & ((digit_t)digit ^ (digit_t)-digit)) ^ (digit_t)-digit) >> 1; /* position = (|digit|-1)/2 */ fpcopy_p256(table[0].X, point.X); /* point = table[0] */ fpcopy_p256(table[0].Y, point.Y); fpcopy_p256(table[0].Z, point.Z); fpcopy_p256(table[0].Z2, point.Z2); fpcopy_p256(table[0].Z3, point.Z3); for (i = 1; i < npoints; i++) { pos--; /* If match then mask = 0xFF...F else mask = 0x00...0 */ mask = is_digit_nonzero_ct(pos) - 1; fpcopy_p256(table[i].X, temp_point.X); /* temp_point = table[i+1] */ fpcopy_p256(table[i].Y, temp_point.Y); fpcopy_p256(table[i].Z, temp_point.Z); fpcopy_p256(table[i].Z2, temp_point.Z2); fpcopy_p256(table[i].Z3, temp_point.Z3); /* If mask = 0x00...0 then point = point, else if mask = 0xFF...F then point = temp_point */ for (j = 0; j < nwords; j++) { point.X[j] = (mask & (point.X[j] ^ temp_point.X[j])) ^ point.X[j]; point.Y[j] = (mask & (point.Y[j] ^ temp_point.Y[j])) ^ point.Y[j]; point.Z[j] = (mask & (point.Z[j] ^ temp_point.Z[j])) ^ point.Z[j]; point.Z2[j] = (mask & (point.Z2[j] ^ temp_point.Z2[j])) ^ point.Z2[j]; point.Z3[j] = (mask & (point.Z3[j] ^ temp_point.Z3[j])) ^ point.Z3[j]; } } fpcopy_p256(point.X, P->X); fpcopy_p256(point.Y, P->Y); fpcopy_p256(point.Z, P->Z); fpcopy_p256(point.Z2, P->Z2); fpcopy_p256(point.Z3, P->Z3); fpneg_p256(P->Y); /* point.Y: y coordinate */ fpcopy_p256(P->Y, temp_point.Y); /* temp_point.Y: -y coordinate */ for (j = 0; j < nwords; j++) { /* if sign = 0x00...0 then choose negative of the point */ point.Y[j] = (sign & (point.Y[j] ^ temp_point.Y[j])) ^ temp_point.Y[j]; } fpcopy_p256(point.Y, P->Y); /* cleanup */ ecpoint_chudnovsky_zero(&point); ecpoint_chudnovsky_zero(&temp_point); } /* * Evaluation for the complete addition * Determines the index for table lookup and the mask for element selections using complete_select */ static unsigned int lut_complete_eval(digit256_t val1, digit256_t val2, digit256_t val3, digit_t*mask) { digit_t idx_temp = 0, idx = 3; digit_t eval1, eval2; eval1 = (digit_t)(fpiszero_p256(val1) - 1); /* if val1 = 0 then eval1 = 0, else eval1 = -1 */ idx = (eval1 & (idx ^ idx_temp)) ^ idx_temp; /* if val1 = 0 then idx = 0 */ idx_temp = 2; eval2 = (digit_t)(fpiszero_p256(val3) - 1); /* if val3 = 0 then eval2 = 0, else eval2 = -1 */ idx = ((eval1 | eval2) & (idx ^ idx_temp)) ^ idx_temp; /* if (val1 = 0 & val3 = 0) then idx = 2 */ idx_temp = 1; eval1 = (digit_t)(fpiszero_p256(val2) - 1); /* if val2 = 0 then eval1 = 0, else eval1 = -1 */ idx = (eval1 & (idx ^ idx_temp)) ^ idx_temp; /* if val2 = 0 then idx = 1 */ /* If idx=3 then mask = 0xFF...F else mask = 0x00...0 */ *mask = is_digit_nonzero_ct(idx - 3) - 1; return (unsigned int)idx; } /* Point extraction from LUT for the complete addition */ static void complete_lut(ecpoint_jacobian_t* table, unsigned int idx, ecpoint_jacobian_t* P, unsigned int npoints, ec_t* curve) { size_t i, j, nwords = NBITS_TO_NDIGITS(curve->pbits); digit_t pos, mask; ecpoint_jacobian_t point, temp_point; pos = (digit_t)idx; // Load digit position ecpoint_jacobian_copy(&table[0], &point); // point = table[0] for (i = 1; i < npoints; i++) { pos--; // If match then mask = 0xFF...F else mask = 0x00...0 mask = is_digit_nonzero_ct(pos) - 1; ecpoint_jacobian_copy(&table[i], &temp_point); // temp_point = table[i+1] // If mask = 0x00...0 then point = point, else if mask = 0xFF...F then point = temp_point for (j = 0; j < nwords; j++) { point.X[j] = (mask & (point.X[j] ^ temp_point.X[j])) ^ point.X[j]; point.Y[j] = (mask & (point.Y[j] ^ temp_point.Y[j])) ^ point.Y[j]; point.Z[j] = (mask & (point.Z[j] ^ temp_point.Z[j])) ^ point.Z[j]; } } ecpoint_jacobian_copy(&point, P); // cleanup ecpoint_jacobian_zero(&point); ecpoint_jacobian_zero(&temp_point); } /* * Field element selection for the complete addition * Operation: if mask = 0 then out = in1, else if mask = 0xff...ff then out = in2 */ static void complete_select(digit256_t in1, digit256_t in2, digit256_t out, digit_t mask) { size_t i = 0; size_t nwords = NBITS_TO_NDIGITS(sizeof(digit256_t) * 8); for (i = 0; i < nwords; i++) { out[i] = (mask & (in1[i] ^ in2[i])) ^ in1[i]; } } /* Complete point addition: if P=-Q then P=0, else if P=0 then P=Q, else if P=Q then P=2P, else P=P+Q * Constant-time extraction over 5-LUT: table[0] = inf, table[1] = Q, table[2] = 2P, table[3] = P+Q, table[4] = P. First two entries and last one are assumed to be pre-loaded. * Weierstrass a=-3 curve * Inputs: P = (X1,Y1,Z1) in Jacobian coordinates * Q = (X2,Y2,Z2) in Jacobian coordinates * Output: P = P+Q = (X1,Y1,Z1) + (X2,Y2,Z2) in Jacobian coordinates */ static void ecadd_jacobian_no_init(ecpoint_jacobian_t* Q, ecpoint_jacobian_t* P, ecpoint_jacobian_t* table, ec_t* curve) { digit256_t t1, t2, t3, t4, t5, t6, t7, t8; unsigned int idx = 0; digit_t mask = 0; digit_t mask1 = 0; digit_t temps[P256_TEMPS]; /* SECURITY NOTE: this constant-time addition function is complete (i.e., it works for any possible inputs, including the cases P!=Q, P=Q, P=-Q and P=inf) on prime-order Weierstrass curves. */ fpsqr_p256(P->Z, t2, temps); /* t2 = z1^2 */ fpmul_p256(P->Z, t2, t3, temps); /* t3 = z1^3 */ fpmul_p256(t2, Q->X, t1, temps); /* t1 = z1^2*x2 */ fpmul_p256(t3, Q->Y, t4, temps); /* t4 = z1^3*y2 */ fpsqr_p256(Q->Z, t3, temps); /* t3 = z2^2 */ fpmul_p256(Q->Z, t3, t5, temps); /* t5 = z2^3 */ fpmul_p256(t3, P->X, t7, temps); /* t7 = z2^2*x1 */ fpmul_p256(t5, P->Y, t8, temps); /* t8 = z2^3*y1 */ fpsub_p256(t1, t7, t1); /* t1 = beta2 = z1^2*x2-z2^2*x1 */ fpsub_p256(t4, t8, t4); /* t4 = alpha2 = z1^3*y2-z2^3*y1 */ idx = lut_complete_eval(t1, P->Z, t4, &mask); /* if t1=0 (P=-Q) then idx=0, if Z1=0 (P inf) then idx=1, if t4=0 (P=Q) then idx=2, else idx=3 */ /* if idx=3 then mask = 0xff...ff, else mask = 0 */ AJ_ASSERT(sizeof(digit_t) == sizeof(int64_t)); mask1 = ~(-(int64_t) fpiszero_p256(Q->Z)); /* if Z2=0 (Q inf) then mask1 = 0, else mask1 = 0xff...ff */ idx = (mask1 & (idx ^ 4)) ^ 4; /* if mask1 = 0 then idx=4, else if mask1 = 0xff...ff then keep previous idx */ fpadd_p256(P->X, t2, t3); /* t3 = x1+z1^2 */ fpsub_p256(P->X, t2, t6); /* t6 = x1-z1^2 */ complete_select(P->Y, t1, t2, mask); /* If mask=0 (DBL) then t2=y1, else if mask=-1 (ADD) then t2=beta2 */ fpsqr_p256(t2, t5, temps); /* t5 = y1^2 (DBL) or beta2^2 (ADD) */ complete_select(P->X, t7, t7, mask); /* If mask=0 (DBL) then t7=x1, else if mask=-1 (ADD) then t7=z2^2*x1 */ fpmul_p256(t5, t7, t1, temps); /* t1 = x1y1^2 = beta1 (DBL) or z2^2*x1*beta2^2 (ADD) */ fpmul_p256(P->Z, t2, table[2].Z, temps); /* Z2Pfinal = z1y1 */ fpmul_p256(Q->Z, table[2].Z, table[3].Z, temps); /* ZPQfinal = z1*z2*beta2 */ complete_select(t3, t2, t3, mask); /* If mask=0 (DBL) then t3=x1+z1^2, else if mask=-1 (ADD) then t3=beta2 */ complete_select(t6, t5, t6, mask); /* If mask=0 (DBL) then t6=x1-z1^2, else if mask=-1 (ADD) then t6=beta2^2 */ fpmul_p256(t3, t6, t2, temps); /* t2 = (x1+z1^2)(x1-z1^2) (DBL) or beta2^3 (ADD) */ fpdiv2_p256(t2, t3, temps); /* t3 = (x1+z1^2)(x1-z1^2)/2 */ fpadd_p256(t2, t3, t3); /* t3 = alpha1 = 3(x1+z1^2)(x1-z1^2)/2 */ complete_select(t3, t4, t3, mask); /* If mask=0 (DBL) then t3=alpha1, else if mask=-1 (ADD) then t3=alpha2 */ fpsqr_p256(t3, t4, temps); /* t4 = alpha1^2 (DBL) or alpha2^2 (ADD) */ fpsub_p256(t4, t1, t4); /* t4 = alpha1^2-beta1 (DBL) or alpha2^2-z2^2*x1*beta2^2 */ fpsub_p256(t4, t1, table[2].X); /* X2Pfinal = alpha1^2-2beta1 (DBL) or alpha2^2-2z2^2*x1*beta2^2 (ADD) */ fpsub_p256(table[2].X, t2, table[3].X); /* XPQfinal = alpha^2-beta2^3-2z2^2*x1*beta2^2 */ complete_select(table[2].X, table[3].X, t4, mask); /* If mask=0 (DBL) then t4=X2Pfinal, else if mask=-1 (ADD) then t4=XPQfinal */ fpsub_p256(t1, t4, t1); /* t1 = beta1-X2Pfinal (DBL) or (ADD) z2^2*x1*beta2^2-XPQfinal */ fpmul_p256(t3, t1, t4, temps); /* t4 = alpha1.(beta1-X2Pfinal) or alpha2.(z2^2*x1*beta2^2-XPQfinal) */ complete_select(t5, t8, t1, mask); /* If mask=0 (DBL) then t1=y1^2, else if mask=-1 (ADD) then t1=z2^3*y1 */ complete_select(t5, t2, t2, mask); /* If mask=0 (DBL) then t2=y1^2, else if mask=-1 (ADD) then t2=beta2^3 */ fpmul_p256(t1, t2, t3, temps); /* t3 = y1^4 (DBL) or z2^3*y1*beta2^3 (ADD) */ fpsub_p256(t4, t3, table[2].Y); /* Y2Pfinal = alpha1.(beta1-X2Pfinal)-y1^4 (DBL) or alpha2.(z2^2*x1*beta2^2-XPQfinal)-z2^3*y1*beta2^3 (ADD) */ fpcopy_p256(table[2].Y, table[3].Y); /* YPQfinal = alpha2.(z2^2*x1*beta2^2-XPQfinal)-z2^3*y1*beta2^3 */ complete_lut(table, idx, P, 5, curve); /* P = table[idx] (5 is the table size) */ /* cleanup */ fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); fpzero_p256(t4); fpzero_p256(t5); fpzero_p256(t6); fpzero_p256(t7); fpzero_p256(t8); AJ_MemZeroSecure(temps, sizeof(temps)); } /* Complete point addition: if P=-Q then P=0, else if P=0 then P=Q, else if P=Q then P=2P, else P=P+Q * Constant-time extraction over 5-LUT: table[0] = inf, table[1] = Q, table[2] = 2P, table[3] = P+Q, table[4] = P. * Weierstrass a=-3 curve * Inputs: P = (X1,Y1,Z1) in Jacobian coordinates * Q = (X2,Y2,Z2) in Jacobian coordinates * Output: P = P+Q = (X1,Y1,Z1) + (X2,Y2,Z2) in Jacobian coordinates */ void ec_add_jacobian(ecpoint_jacobian_t* Q, ecpoint_jacobian_t* P, ec_t* curve) { ecpoint_jacobian_t table[5]; memset(table, 0, sizeof(table)); table[0].Y[0] = 1; /* Initialize table[0] with the point at infinity (0:1:0) */ ecpoint_jacobian_copy(Q, &table[1]); /* Initialize table[1] with Q */ ecpoint_jacobian_copy(P, &table[4]); /* Initialize table[4] with P */ ecadd_jacobian_no_init(Q, P, table, curve); /* cleanup */ ecpoint_jacobian_zero(&table[0]); ecpoint_jacobian_zero(&table[1]); ecpoint_jacobian_zero(&table[2]); ecpoint_jacobian_zero(&table[3]); ecpoint_jacobian_zero(&table[4]); } /* Complete point addition for affine coordinates. * Computes P = P + Q */ void ec_add(ecpoint_t* P, const ecpoint_t* Q, ec_t* curve) { ecpoint_jacobian_t Qj, Pj; ec_affine_tojacobian(P, &Pj); ec_affine_tojacobian(Q, &Qj); ec_add_jacobian(&Qj, &Pj, curve); /* Pj = Pj + Qj */ ec_toaffine(&Pj, P, curve); ecpoint_jacobian_zero(&Pj); ecpoint_jacobian_zero(&Qj); } /* Is x < y? */ static inline unsigned char is_digit_lessthan_ct(digit_t x, digit_t y) { return (unsigned char)((x ^ ((x ^ y) | ((x - y) ^ y))) >> (RADIX_BITS - 1)); } /* Digit shift right */ #define SHIFTR(highIn, lowIn, shift, shiftOut) \ (shiftOut) = ((lowIn) >> (shift)) ^ ((highIn) << (RADIX_BITS - (shift))) /* Computes the fixed window representation of scalar, where nonzero digits are in the set {+-1,+-3,...,+-(2^(w-1)-1)} */ void fixed_window_recode(digit256_t scalar, unsigned int nbit, unsigned int w, int* digits) { digit_t i, j, val, mask, t, cwords; digit_t temp, res, borrow; cwords = NBITS_TO_NDIGITS(nbit); /* Number of computer words to represent scalar */ t = (nbit + (w - 2)) / (w - 1); /* Fixed length of the fixed window representation */ mask = (1 << w) - 1; /* w-bit mask */ val = (digit_t)(1 << (w - 1)); /* 2^(w-1) */ for (i = 0; i <= (t - 1); i++) { temp = (scalar[0] & mask) - val; /* ki = (k mod 2^w) - 2^(w-1) */ *digits = (int)temp; digits++; res = scalar[0] - temp; /* k = (k - ki) */ borrow = ((temp >> (RADIX_BITS - 1)) - 1) & ((digit_t)is_digit_lessthan_ct(scalar[0], temp)); scalar[0] = res; for (j = 1; j < cwords; j++) { res = scalar[j]; scalar[j] = res - borrow; borrow = (digit_t)is_digit_lessthan_ct(res, borrow); } for (j = 0; j < cwords - 1; j++) { /* k / 2^(w-1) */ SHIFTR(scalar[j + 1], scalar[j], (w - 1), scalar[j]); } scalar[cwords - 1] = scalar[cwords - 1] >> (w - 1); } *digits = (int)scalar[0]; /* kt = k (t+1 digits) */ // zero temporaries temp = res = borrow = 0; res = temp; // prevent compiler removal } /* Number of digits in the representation of the scalar. W_VARBASE is the window size. */ #define DIGITS_TABLE_SIZE (((sizeof(digit256_t) * 8) + W_VARBASE - 2) / (W_VARBASE - 1) + 1) /* * Variable-base scalar multiplication Q = k.P using fixed-window method * Weierstrass a=-3 curve */ AJ_Status ec_scalarmul(const ecpoint_t* P, digit256_t k, ecpoint_t* Q, ec_t* curve) { unsigned int npoints = 1 << (W_VARBASE - 2); size_t num_digits = NBITS_TO_NDIGITS(curve->pbits); /* Number of words to represent field elements and elements in modulo the group order */ int digits[DIGITS_TABLE_SIZE] = { 0 }; size_t t = (curve->rbits + (W_VARBASE - 2)) / (W_VARBASE - 1); /* Fixed length of the fixed window representation */ size_t i = 0; size_t j = 0; sdigit_t odd = 0; ecpoint_jacobian_t T; ecpoint_jacobian_t TT; ecpoint_chudnovsky_t table[1 << (W_VARBASE - 2)]; ecpoint_chudnovsky_t R; digit256_t temp, t1, t2, t3; AJ_Status status = AJ_ERR_UNKNOWN; /* SECURITY NOTE: the crypto sensitive part of this function is protected against timing attacks and runs in constant-time on prime-order Weierstrass curves. * Conditional if-statements evaluate public data only and the number of iterations for all loops is public. * DISCLAIMER: the caller is responsible for guaranteeing that early termination produced after detecting errors during input validation * (of scalar k or base point P) does not leak any secret information. */ if (P == NULL || k == NULL || Q == NULL || curve == NULL) { return AJ_ERR_INVALID; } /* Input validation: */ /* Check if P is the point at infinity (0,0) */ if (ec_is_infinity(P, curve) == B_TRUE) { return AJ_ERR_INVALID; } /* Is scalar k in [1,r-1]? */ if ((fpiszero_p256(k) == B_TRUE) || (validate_256(k, curve->order) == B_FALSE)) { return AJ_ERR_INVALID; } /* Are (x,y) in [0,p-1]? */ if (fpvalidate_p256(P->x) == B_FALSE || fpvalidate_p256(P->y) == B_FALSE) { return AJ_ERR_INVALID; } /* The question of if P lies on the curve should be checked before calling scalarmul */ /* end input validation */ ec_precomp(P, table, npoints, curve); /* Precomputation of points T[0],...,T[npoints-1] */ odd = -((sdigit_t)k[0] & 1); fpsub_p256(curve->order, k, temp); /* Converting scalar to odd (r-k if even) */ for (j = 0; j < num_digits; j++) { /* If (even) then k = k_temp else k = k */ temp[j] = (odd & (k[j] ^ temp[j])) ^ temp[j]; } fixed_window_recode(temp, (unsigned int)curve->rbits, W_VARBASE, digits); lut_chudnovsky(table, &R, digits[t], npoints, curve); fpcopy_p256(R.X, T.X); /* Initialize T = (X_T:Y_T:Z_T) with a point from the precomputed table */ fpcopy_p256(R.Y, T.Y); fpcopy_p256(R.Z, T.Z); for (i = (t - 1); i >= 1; i--) { for (j = 0; j < (W_VARBASE - 2); j++) { ec_double_jacobian(&T); /* Double (X_T:Y_T:Z_T) = 2(X_T:Y_T:Z_T) */ } lut_chudnovsky(table, &R, digits[i], npoints, curve); /* Load R = (X_R:Y_R:Z_R:Z_R^2:Z_R^3) with a point from the precomputed table */ ec_doubleadd(&R, &T, curve); /* Double-add (X_T:Y_T:Z_T) = 2(X_T:Y_T:Z_T) + (X_R:Y_R:Z_R:Z_R^2:Z_R^3) */ } /* Perform last iteration */ for (j = 0; j < (W_VARBASE - 1); j++) { ec_double_jacobian(&T); /* Double (X_T:Y_T:Z_T) = 2(X_T:Y_T:Z_T) */ } lut_chudnovsky(table, &R, digits[0], npoints, curve); /* Load R = (X_R:Y_R:Z_R:Z_R^2:Z_R^3) with a point from the precomputed table */ fpcopy_p256(R.X, TT.X); /* TT = R = (X_R:Y_R:Z_R) */ fpcopy_p256(R.Y, TT.Y); fpcopy_p256(R.Z, TT.Z); ec_add_jacobian(&TT, &T, curve); /* Complete addition (X_T:Y_T:Z_T) = (X_T:Y_T:Z_T) + (X_R:Y_R:Z_R) */ fpcopy_p256(T.Y, temp); fpneg_p256(temp); /* Correcting scalar (-Ty if even) */ for (j = 0; j < num_digits; j++) { /* If (even) then Ty = -Ty */ T.Y[j] = (odd & (T.Y[j] ^ temp[j])) ^ temp[j]; } ec_toaffine(&T, Q, curve); /* Output Q = (x,y) */ status = AJ_OK; AJ_MemZeroSecure(digits, DIGITS_TABLE_SIZE * sizeof(int)); ecpoint_jacobian_zero(&T); ecpoint_jacobian_zero(&TT); ecpoint_chudnovsky_zero(&R); for (j = 0; j < (1 << (W_VARBASE - 2)); j++) { ecpoint_chudnovsky_zero(&table[j]); } fpzero_p256(temp); fpzero_p256(t1); fpzero_p256(t2); fpzero_p256(t3); return status; } ajtcl-16.04/src/crypto/aj_crypto_ecc.c000066400000000000000000001517311271074662300177200ustar00rootroot00000000000000/** * @file aj_crypto_ecc.cc * * Class for Elliptic Curve Cryptography */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #define BIGLEN 9 /* * For P256 bigval_t types hold 288-bit 2's complement numbers (9 * 32-bit words). For P192 they hold 224-bit 2's complement numbers * (7 32-bit words). * * The representation is little endian by word and native endian * within each word. */ typedef struct { uint32_t data[BIGLEN]; } bigval_t; typedef struct { bigval_t x; bigval_t y; uint32_t infinity; } affine_point_t; typedef struct { bigval_t r; bigval_t s; } ECDSA_sig_t; /* P256 is tested directly with known answer tests from example in ANSI X9.62 Annex L.4.2. (See item in pt_mpy_testcases below.) Mathematica code, written in a non-curve-specific way, was also tested on the ANSI example, then used to generate both P192 and P256 test cases. */ /* * This file exports the functions ECDH_generate, ECDH_derive, and * optionally, ECDSA_sign and ECDSA_verify. */ /* * References: * * [KnuthV2] is D.E. Knuth, The Art of Computer Programming, Volume 2: * Seminumerical Algorithms, 1969. * * [HMV] is D. Hankerson, A. Menezes, and S. Vanstone, Guide to * Elliptic Curve Cryptography, 2004. * * [Wallace] is C.S. Wallace, "A suggestion for a Fast Multiplier", * IEEE Transactions on Electronic Computers, EC-13 no. 1, pp 14-17, * 1964. * * [ANSIX9.62] is ANSI X9.62-2005, "Public Key Cryptography for the Financial * Services Industry The Elliptic Curve Digital Signature Algorithm * (ECDSA)". */ /* * The vast majority of cycles in programs like this are spent in * modular multiplication. The usual approach is Montgomery * multiplication, which effectively does two multiplications in place * of one multiplication and one reduction. However, this program is * dedicated to the NIST standard curves P256 and P192. Most of the * NIST curves have the property that they can be expressed as a_i * * 2^(32*i), where a_i is -1, 0, or +1. For example P192 is 2^(6*32) * - 2^(2*32) - 2^(0*32). This allows easy word-oriented reduction * (32 bit words): The word at position 6 can just be subtracted from * word 6 (i.e. word 6 zeroed), and added to words 2 and 0. This is * faster than Montgomery multiplication. * * Two problems with the naive implementation suggested above are carry * propagation and getting the reduction precise. * * Every time you do an add or subtract you have to propagate carries. * The result might come out between the modulus and 2^192 or 2^256, * in which case you subtract the modulus. Most carry propagation is avoided * by using 64 bit words during computation, even though the radix is only * 2^32. A carry propagation is done once in the multiplication * and once again after the reduction step. (This idea comes from the carry * save adder used in hardware designs.) * * Exact reduction is required for only a few operations: comparisons, * and halving. The multiplier for point multiplication must also be * exactly reduced. So we do away with the requirement for exact * reduction in most operations. Thus, any reduced value, X, can may * represented by X + k * modulus, for any integer k, as long as the * result is representable in the data structure. Typically k is * between -1 and 1. (A bigval_t has one more 32 bit word than is * required to hold the modulus, and is interpreted as 2's complement * binary, little endian by word, native endian within words.) * * An exact reduction function is supplied, and must be called as necessary. */ /* * CONFIGURATION STUFF * * All these values are undefined. It seems better to set the * preprocessor variables in the makefile, and thus avoid * generating many different versions of the code. * This may not be practical with ECC_P192 and ECC_P256, but at * least that is only in the ecc.h file. */ /* define ECDSA to include ECDSA functions */ #define ECDSA /* define ECC_TEST to rename the the exported symbols to avoid name collisions with openSSL, and a few other things necessary for linking with the test program ecctest.c */ /* define ARM7_ASM to use assembly code specially for the ARM7 processor */ // #define ARM7_ASM /* define SMALL_CODE to skip unrolling loops */ // #define SMALL_CODE /* define SPECIAL_SQUARE to generate a special case for squaring. Special squaring should just about halve the number of multiplies, but on Windows machines and if loops are unrolled (SMALL_CODE not defined) actually causes slight slowing. */ #define SPECIAL_SQUARE /* define MPY2BITS to consume the multiplier two bits at a time. */ #define MPY2BITS #ifdef ECC_TEST /* rename to avoid conflicts with OpenSSL in ecctest.c code. */ #define ECDSA_sign TEST_ECDSA_sign #define ECDSA_verify TEST_ECDSA_verify #define COND_STATIC #else /* ECC_TEST not defined */ #define COND_STATIC static #endif /* ECC_TEST not defined */ typedef struct { int64_t data[2 * BIGLEN]; } dblbigval_t; /* These values describe why the verify failed. This simplifies testing. */ typedef enum {V_SUCCESS = 0, V_R_ZERO, V_R_BIG, V_S_ZERO, V_S_BIG, V_INFINITY, V_UNEQUAL, V_INTERNAL} verify_res_t; typedef enum {MOD_MODULUS = 0, MOD_ORDER} modulus_val_t; #define MSW (BIGLEN - 1) static void big_adjustP(bigval_t* tgt, bigval_t const* a, int64_t k); static void big_1wd_mpy(bigval_t* tgt, bigval_t const* a, int32_t k); static void big_sub(bigval_t* tgt, bigval_t const* a, bigval_t const* b); static void big_precise_reduce(bigval_t* tgt, bigval_t const* a, bigval_t const* modulus); #define big_is_negative(a) ((int32_t)(a)->data[MSW] < 0) /* * Does approximate reduction. Subtracts most significant word times * modulus from src. The double cast is important to get sign * extension right. */ #define big_approx_reduceP(tgt, src) \ big_adjustP(tgt, src, -(int64_t)(int32_t)(src)->data[MSW]) /* if tgt is a modular value, it must be precisely reduced */ #define big_is_odd(tgt) ((tgt)->data[0] & 1) // Squares, always modulo the modulus #define big_sqrP(tgt, a) big_mpyP(tgt, a, a, MOD_MODULUS) #define m1 0xffffffffU #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define OVERFLOWCHECK(sum, a, b) ((((a) > 0) && ((b) > 0) && ((sum) <= 0)) || \ (((a) < 0) && ((b) < 0) && ((sum) >= 0))) /* NOTE WELL! The Z component must always be precisely reduced. */ typedef struct { bigval_t X; bigval_t Y; bigval_t Z; } jacobian_point_t; static bigval_t const big_zero = { { 0, 0, 0, 0, 0, 0, 0 } }; static bigval_t const big_one = { { 1, 0, 0, 0, 0, 0, 0 } }; static affine_point_t const affine_infinity = { { { 0, 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0, 0 } }, B_TRUE }; static jacobian_point_t const jacobian_infinity = { { { 1, 0, 0, 0, 0, 0, 0 } }, { { 1, 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0, 0 } } }; static bigval_t const modulusP256 = { { m1, m1, m1, 0, 0, 0, 1, m1, 0 } }; static bigval_t const b_P256 = { { 0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8, 0x00000000 } }; static bigval_t const orderP256 = { { 0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000 } }; #ifdef ECDSA static dblbigval_t const orderDBL256 = { { 0xfc632551LL - 0x100000000LL, 0xf3b9cac2LL - 0x100000000LL + 1LL, 0xa7179e84LL - 0x100000000LL + 1LL, 0xbce6faadLL - 0x100000000LL + 1LL, 0xffffffffLL - 0x100000000LL + 1LL, 0xffffffffLL - 0x100000000LL + 1LL, 0x00000000LL + 0x1LL, 0xffffffffLL - 0x100000000LL, 0x00000000LL + 1LL } }; #endif /* ECDSA */ static affine_point_t const baseP256 = { { { 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81, 0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2 } }, { { 0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357, 0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2 } }, B_FALSE }; #define modulusP modulusP256 #define orderP orderP256 #define orderDBL orderDBL256 #define base_point baseP256 #define curve_b b_P256 #ifdef ARM7_ASM #define MULACC(a, b) \ __asm \ { \ UMULL tmpr0, tmpr1, a, b; \ ADDS sum0, sum0, tmpr0; \ ADCS sum1, sum1, tmpr1; \ ADC cum_carry, cum_carry, 0x0; \ } // cumcarry: 32-bit word that accumulates carries // sum0: lower half 32-bit word of sum // sum1: higher half 32-bit word of sum // a : 32-bit operand to be multiplied // b : 32-bit operand to be multiplied // tmpr0, tmpr1: two temporary words // sum = sum + A*B where cout may contain carry info from previous operations #define MULACC_DOUBLE(a, b) \ __asm \ { \ UMULL tmpr0, tmpr1, a, b; \ ADDS sum0, sum0, tmpr0; \ ADCS sum1, sum1, tmpr1; \ ADC cum_carry, cum_carry, 0x0; \ ADDS sum0, sum0, tmpr0; \ ADCS sum1, sum1, tmpr1; \ ADC cum_carry, cum_carry, 0x0; \ } #define ACCUM(ap, bp) MULACC(*(ap), *(bp)) #define ACCUMDBL(ap, bp) MULACC_DOUBLE(*(ap), *(bp)) #else /* ARM7_ASM, below is platform independent */ /* (sum, carry) += a * b */ static void mpy_accum(int* cumcarry, uint64_t* sum, uint32_t a, uint32_t b) { uint64_t product = (uint64_t)a * (uint64_t)b; uint64_t lsum = *sum; lsum += product; if (lsum < product) { *cumcarry += 1; } *sum = lsum; } #ifdef SPECIAL_SQUARE /* (sum, carry += 2 * a * b. Attempts to reduce writes to memory and branches caused slowdown on windows machines. */ static void mpy_accum_dbl(int* cumcarry, uint64_t* sum, uint32_t a, uint32_t b) { uint64_t product = (uint64_t)a * (uint64_t)b; uint64_t lsum = *sum; lsum += product; if (lsum < product) { *cumcarry += 1; } lsum += product; if (lsum < product) { *cumcarry += 1; } *sum = lsum; } #endif /* SPECIAL_SQUARE */ /* ap and bp are pointers to the words to be multiplied and accumulated */ #define ACCUM(ap, bp) mpy_accum(&cum_carry, &u_accum, *(ap), *(bp)) #define ACCUMDBL(ap, bp) mpy_accum_dbl(&cum_carry, &u_accum, *(ap), *(bp)) #endif /* !ARM7_ASM, ie platform independent */ /* * The big_mpyP algorithm first multiplies the two arguments, with the * outer loop indexing over output words, and the inner "loop" * (unrolled unless SMALL_CODE is defined), collecting all the terms * that contribute to that output word. * * The impementation is inspired by the Wallace Tree often used in * hardware [Wallace], where (0, 1) terms of the same weight are * collected together into a sequence values each of which can be on * the order of the number of bits in a word, and then the sequence is * turned into a binary number with a carry save adder. This is * generized from base 2 to base 2^32. * * The first part of the algorithm sums together products of equal * weight. The outer loop does carry propagation and makes each value * at most 32 bits. * * Then corrections are applied for negative arguments. (The first * part essentially does unsigned multiplication.) * * The reduction proceeds in 2 steps. The first treats the 32 bit * values (in 64 bit words) from above as though they were * polynomials, and reduces by the paper and pencil method. Carries * are propagated and the result collapsed to a sequence of 32 bit * words (in the target). The second step subtracts MSW * modulus * from the result. This usually (but not always) results in the MSW * being zero. (And that makes subsequent mutliplications faster.) * * The modselect parameter chooses whether reduction is mod the modulus * or the order of the curve. If ECDSA is not defined, this parameter * is ignored, and the curve modulus is used. */ /* * Computes a * b, approximately reduced mod modulusP or orderP, * depending on the modselect flag. */ static void big_mpyP(bigval_t* tgt, bigval_t const* a, bigval_t const* b, modulus_val_t modselect) { int64_t w[2 * BIGLEN]; int64_t s_accum; /* signed */ int i, minj, maxj, a_words, b_words, cum_carry; #ifdef SMALL_CODE int j; #else uint32_t const* ap; uint32_t const* bp; #endif #ifdef ARM7_ASM uint32_t tmpr0, tmpr1, sum0, sum1; #else uint64_t u_accum; #endif #ifdef ECDSA #define MODSELECT modselect #else #define MODSELECT MOD_MODULUS #endif a_words = BIGLEN; while (a_words > 0 && a->data[a_words - 1] == 0) { --a_words; } /* * i is target index. The j (in comments only) indexes * through the multiplier. */ #ifdef ARM7_ASM sum0 = 0; sum1 = 0; cum_carry = 0; #else u_accum = 0; cum_carry = 0; #endif #ifndef SPECIAL_SQUARE #define NO_SPECIAL_SQUARE 1 #else #define NO_SPECIAL_SQUARE 0 #endif if (NO_SPECIAL_SQUARE || a != b) { /* normal multiply */ /* compute length of b */ b_words = BIGLEN; while (b_words > 0 && b->data[b_words - 1] == 0) { --b_words; } /* iterate over words of output */ for (i = 0; i < a_words + b_words - 1; ++i) { /* Run j over all possible values such that 0 <= j < b_words && 0 <= i-j < a_words. Hence j >= 0 and j > i - a_words and j < b_words and j <= i (j exists only in the mind of the reader.) */ maxj = MIN(b_words - 1, i); minj = MAX(0, i - a_words + 1); /* ACCUM accumlates into . */ #ifdef SMALL_CODE for (j = minj; j <= maxj; ++j) { ACCUM(a->data + i - j, b->data + j); } #else /* SMALL_CODE not defined */ /* * The inner loop (over j, running from minj to maxj) is * unrolled. Sequentially increasing case values in the code * are intended to coax the compiler into emitting a jump * table. Here j runs from maxj to minj, but addition is * commutative, so it doesn't matter. */ ap = &a->data[i - minj]; bp = &b->data[minj]; /* the order is opposite the loop, but addition is commutative */ switch (8 - (maxj - minj)) { case 0: ACCUM(ap - 8, bp + 8); /* j = 8 */ case 1: ACCUM(ap - 7, bp + 7); case 2: ACCUM(ap - 6, bp + 6); case 3: ACCUM(ap - 5, bp + 5); case 4: ACCUM(ap - 4, bp + 4); case 5: ACCUM(ap - 3, bp + 3); case 6: ACCUM(ap - 2, bp + 2); case 7: ACCUM(ap - 1, bp + 1); case 8: ACCUM(ap - 0, bp + 0); /* j = 0 */ } #endif /* SMALL_CODE not defined */ /* The total value is w + u_accum << (32 *i) + cum_carry << (32 * i + 64). The steps from here to the end of the i-loop (not counting squaring branch) and the increment of i by the loop maintain the invariant that the value is constant. (Assume w had been initialized to zero, even though we really didn't.) */ #ifdef ARM7_ASM w[i] = sum0; sum0 = sum1; sum1 = cum_carry; cum_carry = 0; #else w[i] = u_accum & 0xffffffffULL; u_accum = (u_accum >> 32) + ((uint64_t)cum_carry << 32); cum_carry = 0; #endif } } else { /* squaring */ #ifdef SPECIAL_SQUARE /* a[i] * a[j] + a[j] * a[i] == 2 * (a[i] * a[j]), so we can cut the number of multiplies nearly in half. */ for (i = 0; i < 2 * a_words - 1; ++i) { /* Run j over all possible values such that 0 <= j < a_words && 0 <= i-j < a_words && j < i-j Hence j >= 0 and j > i - a_words and j < a_words and 2*j < i */ maxj = MIN(a_words - 1, i); /* Only go half way. Must use (i-1)>> 1, not (i-1)/ 2 */ maxj = MIN(maxj, (i - 1) >> 1); minj = MAX(0, i - a_words + 1); #ifdef SMALL_CODE for (j = minj; j <= maxj; ++j) { ACCUMDBL(a->data + i - j, a->data + j); } /* j live */ if ((i & 1) == 0) { ACCUM(a->data + j, a->data + j); } #else /* SMALL_CODE not defined */ ap = &a->data[i - minj]; bp = &a->data[minj]; switch (8 - (maxj - minj)) { case 0: ACCUMDBL(ap - 8, bp + 8); /* j = 8 */ case 1: ACCUMDBL(ap - 7, bp + 7); case 2: ACCUMDBL(ap - 6, bp + 6); case 3: ACCUMDBL(ap - 5, bp + 5); case 4: ACCUMDBL(ap - 4, bp + 4); case 5: ACCUMDBL(ap - 3, bp + 3); case 6: ACCUMDBL(ap - 2, bp + 2); case 7: ACCUMDBL(ap - 1, bp + 1); case 8: ACCUMDBL(ap - 0, bp + 0); /* j = 0 */ } /* Even numbered columns (zero based) have a middle element. */ if ((i & 1) == 0) { ACCUM(a->data + maxj + 1, a->data + maxj + 1); } #endif /* SMALL_CODE not defined */ /* The total value is w + u_accum << (32 *i) + cum_carry << (32 * i + 64). The steps from here to the end of i-loop and the increment of i by the loop maintain the invariant that the total value is unchanged. (Assume w had been initialized to zero, even though we really didn't.) */ #ifdef ARM7_ASM w[i] = sum0; sum0 = sum1; sum1 = cum_carry; cum_carry = 0; #else /* ARM7_ASM not defined */ w[i] = u_accum & 0xffffffffULL; u_accum = (u_accum >> 32) + ((uint64_t)cum_carry << 32); cum_carry = 0; #endif /* ARM7_ASM not defined */ } #endif /* SPECIAL_SQUARE */ } /* false branch of NO_SPECIAL_SQUARE || (a != b) */ /* The total value as indicated above is maintained invariant down to the approximate reduction code below. */ /* propagate any residual to next to end of array */ for (; i < 2 * BIGLEN - 1; ++i) { #ifdef ARM7_ASM w[i] = sum0; sum0 = sum1; sum1 = 0; #else w[i] = u_accum & 0xffffffffULL; u_accum >>= 32; #endif } /* i is still live */ /* from here on, think of w as containing signed values */ /* Last value of the array, still using i. We store the entire 64 bits. There are two reasons for this. The pedantic one is that this clearly maintains our invariant that the value has not changed. The other one is that this makes w[BIGNUM-1] negative if the result was negative, and reduction depends on this. */ #ifdef ARM7_ASM w[i] = ((uint64_t)sum1 << 32) | sum0; /* sum1 = sum0 = 0; maintain invariant */ #else w[i] = u_accum; /* u_accum = 0; maintain invariant */ #endif /* * Apply correction if a or b are negative. It would be nice to * put this inside the i-loop to reduce memory bandwidth. Later... * * signvedval(a) = unsignedval(a) - 2^(32*BIGLEN)*isneg(a). * * so signval(a) * signedval(b) = unsignedval(a) * unsignedval[b] - * isneg(a) * unsignedval(b) * 2^(32*BIGLEN) - * isneg(b) * unsingedval(a) * 2^ (32*BIGLEN) + * isneg(a) * isneg(b) * 2 ^(2 * 32 * BIGLEN) * * If one arg is zero and the other is negative, obviously no * correction is needed, but we do not make a special case, since * the "correction" only adds in zero. */ if (big_is_negative(a)) { for (i = 0; i < BIGLEN; ++i) { w[i + BIGLEN] -= b->data[i]; } } if (big_is_negative(b)) { for (i = 0; i < BIGLEN; ++i) { w[i + BIGLEN] -= a->data[i]; } if (big_is_negative(a)) { /* both negative */ w[2 * BIGLEN - 1] += 1ULL << 32; } } /* * The code from here to the end of the function maintains w mod * modulusP constant, even though it changes the value of w. */ /* reduce (approximate) */ if (MODSELECT == MOD_MODULUS) { for (i = 2 * BIGLEN - 1; i >= MSW; --i) { int64_t v; v = w[i]; if (v != 0) { w[i] = 0; w[i - 1] += v; w[i - 2] -= v; w[i - 5] -= v; w[i - 8] += v; } } } else { /* modulo order. Not performance critical */ #ifdef ECDSA int64_t carry; /* convert to 32 bit values, except for most signifiant word */ carry = 0; for (i = 0; i < 2 * BIGLEN - 1; ++i) { w[i] += carry; carry = w[i] >> 32; w[i] -= carry << 32; } /* i is live */ w[i] += carry; /* each iteration knocks off word i */ for (i = 2 * BIGLEN - 1; i >= MSW; --i) { /* most to least significant */ int64_t v; int64_t tmp; int64_t tmp2; int j; int k; for (k = 0; w[i] != 0 && k < 3; ++k) { v = w[i]; carry = 0; for (j = i - MSW; j < 2 * BIGLEN; ++j) { if (j <= i) { tmp2 = -(v * orderDBL.data[j - i + MSW]); tmp = w[j] + tmp2 + carry; } else { tmp = w[j] + carry; } if (j < 2 * BIGLEN - 1) { carry = tmp >> 32; tmp -= carry << 32; } else { carry = 0; } w[j] = tmp; } } } #endif /* ECDSA */ } /* propagate carries and copy out to tgt in 32 bit chunks. */ s_accum = 0; for (i = 0; i < BIGLEN; ++i) { s_accum += w[i]; tgt->data[i] = (uint32_t)s_accum; s_accum >>= 32; /* signed, so sign bit propagates */ } /* final approximate reduction */ if (MODSELECT == MOD_MODULUS) { big_approx_reduceP(tgt, tgt); } else { #ifdef ECDSA if (tgt->data[MSW]) { /* Keep it simple! At one time all this was done in place, and was totally unobvious. */ bigval_t tmp; /* The most significant word is signed, even though the whole array has declared uint32_t. */ big_1wd_mpy(&tmp, &orderP, (int32_t)tgt->data[MSW]); big_sub(tgt, tgt, &tmp); } #endif /* ECDSA */ } } /* * Adds k * modulusP to a and stores into target. -2^62 <= k <= 2^62 . * (This is conservative.) */ static void big_adjustP(bigval_t* tgt, bigval_t const* a, int64_t k) { #define RDCSTEP(i, adj) \ w += a->data[i]; \ w += (adj); \ tgt->data[i] = (uint32_t)(int32_t)w; \ w >>= 32; /* add k * modulus */ if (k != 0) { int64_t w = 0; RDCSTEP(0, -k); RDCSTEP(1, 0); RDCSTEP(2, 0); RDCSTEP(3, k); RDCSTEP(4, 0); RDCSTEP(5, 0); RDCSTEP(6, k); RDCSTEP(7, -k); RDCSTEP(8, k); } else if (tgt != a) { *tgt = *a; } } /* * Computes k * a and stores into target. Conditions: product must * be representable in bigval_t. */ static void big_1wd_mpy(bigval_t* tgt, bigval_t const* a, int32_t k) { int64_t w = 0; int64_t tmp; int64_t prod; int j; for (j = 0; j <= MSW; ++j) { prod = (int64_t)k * (int64_t)a->data[j]; tmp = w + prod; w = tmp; tgt->data[j] = (uint32_t)w; w -= tgt->data[j]; w >>= 32; } } /* * Adds a to b as signed (2's complement) numbers. Ok to use for * modular values if you don't let the sum overflow. */ COND_STATIC void big_add(bigval_t* tgt, bigval_t const* a, bigval_t const* b) { uint64_t v; int i; v = 0; for (i = 0; i < BIGLEN; ++i) { v += a->data[i]; v += b->data[i]; tgt->data[i] = (uint32_t)v; v >>= 32; } } /* 2's complement subtraction */ static void big_sub(bigval_t* tgt, bigval_t const* a, bigval_t const* b) { uint64_t v; int i; /* negation is equivalent to 1's complement and increment */ v = 1; /* increment */ for (i = 0; i < BIGLEN; ++i) { v += a->data[i]; v += ~b->data[i]; /* 1's complement */ tgt->data[i] = (uint32_t)v; v >>= 32; } } /* returns 1 if a > b, -1 if a < b, and 0 if a == b. a and b are 2's complement. When applied to modular values, args must be precisely reduced. */ static int big_cmp(bigval_t const* a, bigval_t const* b) { int i; /* most significant word is treated as 2's complement */ if ((int32_t)a->data[MSW] > (int32_t)b->data[MSW]) { return (1); } else if ((int32_t)a->data[MSW] < (int32_t)b->data[MSW]) { return (-1); } /* remainder treated as unsigned */ for (i = MSW - 1; i >= 0; --i) { if (a->data[i] > b->data[i]) { return (1); } else if (a->data[i] < b->data[i]) { return (-1); } } return (0); } /* * Computes tgt = a mod modulus. Only works with modluii slightly * less than 2**(32*(BIGLEN-1)). Both modulusP and orderP qualify. */ static void big_precise_reduce(bigval_t* tgt, bigval_t const* a, bigval_t const* modulus) { /* * src is a trick to avoid an extra copy of a to arg a to a * temporary. Every statement uses src as the src and tgt as the * destination, and it executes src = tgt, so all subsequent * operations affect the modified data, not the original. There is * a case to handle the situation of no modifications having been * made. */ bigval_t const* src = a; /* If tgt < 0, a positive value gets added in, so eventually tgt will be >= 0. If tgt > 0 and the MSW is non-zero, a non-zero value smaller than tgt gets subtracted, so eventually target becomes < 1 * 2**(32*MSW), but not negative, i.e. tgt->data[MSW] == 0, and thus loop termination is guaranteed. */ while ((int32_t)src->data[MSW] != 0) { if (modulus != &modulusP) { /* General case. Keep it simple! */ bigval_t tmp; /* The most significant word is signed, even though the whole array has been declared uint32_t. */ big_1wd_mpy(&tmp, modulus, (int32_t)src->data[MSW]); big_sub(tgt, src, &tmp); } else { /* just an optimization. The other branch would work, but slower. */ big_adjustP(tgt, src, -(int64_t)(int32_t)src->data[MSW]); } src = tgt; } while (big_cmp(src, modulus) >= 0) { big_sub(tgt, src, modulus); src = tgt; } while ((int32_t)src->data[MSW] < 0) { big_add(tgt, src, modulus); src = tgt; } /* copy src to tgt if not already done */ if (src != tgt) { *tgt = *src; } } /* computes floor(a / 2), 2's complement. */ static void big_halve(bigval_t* tgt, bigval_t const* a) { uint32_t shiftval; uint32_t new_shiftval; int i; /* most significant word is 2's complement. Do it separately. */ shiftval = a->data[MSW] & 1; tgt->data[MSW] = (uint32_t)((int32_t)a->data[MSW] >> 1); for (i = MSW - 1; i >= 0; --i) { new_shiftval = a->data[i] & 1; tgt->data[i] = (a->data[i] >> 1) | (shiftval << 31); shiftval = new_shiftval; } } /* returns B_TRUE if a is zero */ boolean_t big_is_zero(bigval_t const* a) { int i; for (i = 0; i < BIGLEN; ++i) { if (a->data[i] != 0) { return (B_FALSE); } } return (B_TRUE); } /* returns B_TRUE if a is one */ static boolean_t big_is_one(bigval_t const* a) { int i; if (a->data[0] != 1) { return (B_FALSE); } for (i = 1; i < BIGLEN; ++i) { if (a->data[i] != 0) { return (B_FALSE); } } return (B_TRUE); } /* * This uses the extended binary GCD (Greatest Common Divisor) * algorithm. The binary GCD algorithm is presented in [KnuthV2] as * Algorithm X. The extension to do division is presented in Homework * Problem 15 and its solution in the back of the book. * * The implementation here follows the presentation in [HMV] Algorithm * 2.22. * * If the denominator is zero, it will loop forever. Be careful! * Modulus must be odd. num and den must be positive. */ static void big_divide(bigval_t* tgt, bigval_t const* num, bigval_t const* den, bigval_t const* modulus) { bigval_t u, v, x1, x2; u = *den; v = *modulus; x1 = *num; x2 = big_zero; while (!big_is_one(&u) && !big_is_one(&v)) { while (!big_is_odd(&u)) { big_halve(&u, &u); if (big_is_odd(&x1)) { big_add(&x1, &x1, modulus); } big_halve(&x1, &x1); } while (!big_is_odd(&v)) { big_halve(&v, &v); if (big_is_odd(&x2)) { big_add(&x2, &x2, modulus); } big_halve(&x2, &x2); } if (big_cmp(&u, &v) >= 0) { big_sub(&u, &u, &v); big_sub(&x1, &x1, &x2); } else { big_sub(&v, &v, &u); big_sub(&x2, &x2, &x1); } } if (big_is_one(&u)) { big_precise_reduce(tgt, &x1, modulus); } else { big_precise_reduce(tgt, &x2, modulus); } } /* * Convert a digit256_t (internal representation of field elements) to a * bigval_t. Note: dst must have space for sizeof(digit256_t) + 4 bytes. */ void digit256_to_bigval(digit256_tc src, bigval_t* dst) { AJ_ASSERT((BIGLEN - 1) * sizeof(uint32_t) == sizeof(digit256_t)); memcpy(dst->data, src, sizeof(digit256_t)); dst->data[BIGLEN - 1] = 0; #if HOST_IS_BIG_ENDIAN int i; for (i = 0; i < (BIGLEN - 1); i += 2) { /* Swap adjacent 32-bit words */ SWAP(dst->data[i], dst->data[i + 1]); } #endif } /* * Convert a bigval_t to a digit256_t. Return TRUE if src was * successfully converted, FALSE otherwise. */ boolean_t bigval_to_digit256(const bigval_t* src, digit256_t dst) { AJ_ASSERT((BIGLEN - 1) * sizeof(uint32_t) == sizeof(digit256_t)); /* Fail on negative inputs, since any negative value received in the * bigval_t format is invalid. */ if (big_is_negative(src)) { return B_FALSE; } memcpy(dst, src->data, sizeof(digit256_t)); #if HOST_IS_BIG_ENDIAN int i; uint32_t* data = (uint32_t*)dst; for (i = 0; i < (BIGLEN - 1); i += 2) { /* Swap adjacent 32-bit words */ SWAP(data[i], data[i + 1]); } #endif return B_TRUE; } COND_STATIC boolean_t in_curveP(affine_point_t const* P) { ecpoint_t Pt; ec_t curve; boolean_t fInfinity; boolean_t fValid; AJ_Status status; status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { return B_FALSE; } fInfinity = P->infinity; bigval_to_digit256(&P->x, Pt.x); bigval_to_digit256(&P->y, Pt.y); fValid = (boolean_t)ecpoint_validation(&Pt, &curve); ec_freecurve(&curve); return(fInfinity | fValid); } int ECDH_generate(affine_point_t* P1, bigval_t* k) { /* Compute a key pair (r, Q) then re-encode and ouput as (k, P1). */ digit256_t r; ecpoint_t g, Q; ec_t curve; AJ_Status status; status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { goto Exit; } /* Choose random r in [0, curve order - 1]*/ do { AJ_RandBytes((uint8_t*)r, sizeof(digit256_t)); } while (!validate_256(r, curve.order)); ec_get_generator(&g, &curve); ec_scalarmul(&g, r, &Q, &curve); /* Q = g^r */ /* Convert out of internal representation. */ digit256_to_bigval(r, k); digit256_to_bigval(Q.x, &(P1->x)); digit256_to_bigval(Q.y, &(P1->y)); P1->infinity = B_FALSE; Exit: fpzero_p256(r); fpzero_p256(Q.x); fpzero_p256(Q.y); ec_freecurve(&curve); return status; } /* Compute tgt = Q^k. Q is validated. */ COND_STATIC boolean_t ECDH_derive_pt(affine_point_t* tgt, bigval_t const* k, affine_point_t const* Q) { boolean_t status; AJ_Status ajstatus; ecpoint_t theirPublic; /* internal representation of Q */ ecpoint_t sharedSecret; digit256_t ourPrivate; /* internal representation of k */ ec_t curve; ajstatus = ec_getcurve(&curve, NISTP256r1); if (ajstatus != AJ_OK) { status = B_FALSE; goto Exit; } /* Convert to internal representation */ status = bigval_to_digit256(k, ourPrivate); status = status && bigval_to_digit256(&(Q->x), theirPublic.x); status = status && bigval_to_digit256(&(Q->y), theirPublic.y); if (!status) { goto Exit; } if (!ecpoint_validation(&theirPublic, &curve)) { status = B_FALSE; goto Exit; } /* Compute sharedSecret = theirPublic^ourPrivate */ ec_scalarmul(&theirPublic, ourPrivate, &sharedSecret, &curve); /* Copy sharedSecret to tgt */ digit256_to_bigval(sharedSecret.x, &(tgt->x)); digit256_to_bigval(sharedSecret.y, &(tgt->y)); Exit: /* Clean up local copies. */ fpzero_p256(sharedSecret.x); fpzero_p256(sharedSecret.y); fpzero_p256(ourPrivate); ec_freecurve(&curve); return status; } static void BigvalEncode(const bigval_t* src, uint8_t* tgt, size_t tgtlen) { size_t i; uint8_t v; uint8_t highbytes = big_is_negative(src) ? 0xff : 0; /* LSbyte to MS_byte */ for (i = 0; i < 4 * BIGLEN; ++i) { if (i < tgtlen) { v = src->data[i / 4] >> (8 * (i % 4)); ((uint8_t*)tgt)[tgtlen - 1 - i] = v; } } /* i is live */ for (; i < tgtlen; ++i) { ((uint8_t*)tgt)[tgtlen - 1 - i] = highbytes; } } static void BigvalDecode(const uint8_t* src, bigval_t* tgt, size_t srclen) { size_t i; uint8_t v; /* zero the bigval_t */ memset((uint8_t*) tgt, 0, sizeof (bigval_t)); /* scan from LSbyte to MSbyte */ for (i = 0; i < srclen && i < 4 * BIGLEN; ++i) { v = ((uint8_t*)src)[srclen - 1 - i]; tgt->data[i / 4] |= (uint32_t)v << (8 * (i % 4)); } } #ifdef ECDSA /* * This function sets the r and s fields of sig. The implementation * follows HMV Algorithm 4.29. */ static int ECDSA_sign(bigval_t const* msgdgst, bigval_t const* privkey, ECDSA_sig_t* sig) { int rv; affine_point_t P1; bigval_t k; bigval_t t; startpoint: rv = ECDH_generate(&P1, &k); if (rv) { return (rv); } big_precise_reduce(&sig->r, &P1.x, &orderP); if (big_is_zero(&sig->r)) { goto startpoint; } big_mpyP(&t, privkey, &sig->r, MOD_ORDER); big_add(&t, &t, msgdgst); big_precise_reduce(&t, &t, &orderP); /* may not be necessary */ big_divide(&sig->s, &t, &k, &orderP); if (big_is_zero(&sig->s)) { goto startpoint; } return (0); } /* * Returns B_TRUE if the signature is valid. * The implementation follow HMV Algorithm 4.30. */ static verify_res_t ECDSA_verify_inner(bigval_t const* msgdgst, affine_point_t const* pubkey, ECDSA_sig_t const* sig) { /* We could reuse variables and save stack space. If stack space is tight, u1 and u2 could be the same variable by interleaving the big multiplies and the point multiplies. P2 and X could be the same variable. X.x could be reduced in place, eliminating v. And if you really wanted to get tricky, I think one could use unions between the affine and jacobian versions of points. But check that out before doing it. */ verify_res_t res; bigval_t v; bigval_t w; bigval_t u1; bigval_t u2; digit256_t digU1; digit256_t digU2; ecpoint_t Q; ecpoint_t P1; ecpoint_t P2; ecpoint_t G; ecpoint_t X; ec_t curve; boolean_t status; AJ_Status ajstatus; ajstatus = ec_getcurve(&curve, NISTP256r1); if (ajstatus != AJ_OK) { /* curve has already been free'd */ return (V_INTERNAL); } ec_get_generator(&G, &curve); status = bigval_to_digit256(&(pubkey->x), Q.x); status = status && bigval_to_digit256(&(pubkey->y), Q.y); status = status && ecpoint_validation(&Q, &curve); if (!status) { res = (V_INTERNAL); goto Exit; } if (big_cmp(&sig->r, &big_one) < 0) { res = (V_R_ZERO); goto Exit; } if (big_cmp(&sig->r, &orderP) >= 0) { res = (V_R_BIG); goto Exit; } if (big_cmp(&sig->s, &big_one) < 0) { res = (V_S_ZERO); goto Exit; } if (big_cmp(&sig->s, &orderP) >= 0) { res = (V_S_BIG); goto Exit; } big_divide(&w, &big_one, &sig->s, &orderP); big_mpyP(&u1, msgdgst, &w, MOD_ORDER); big_precise_reduce(&u1, &u1, &orderP); big_mpyP(&u2, &sig->r, &w, MOD_ORDER); big_precise_reduce(&u2, &u2, &orderP); status = bigval_to_digit256(&u1, digU1); status = status && bigval_to_digit256(&u2, digU2); if (!status) { res = (V_INTERNAL); goto Exit; } ec_scalarmul(&(curve.generator), digU1, &P1, &curve); ec_scalarmul(&Q, digU2, &P2, &curve); // copy P1 point over memcpy(X.x, P1.x, sizeof(digit256_t)); memcpy(X.y, P1.y, sizeof(digit256_t)); ec_add(&X, &P2, &curve); if (ec_is_infinity(&X, &curve)) { res = (V_INFINITY); goto Exit; } digit256_to_bigval(X.x, &v); if (big_cmp(&v, &sig->r) != 0) { res = (V_UNEQUAL); goto Exit; } res = (V_SUCCESS); Exit: ec_freecurve(&curve); return res; } boolean_t ECDSA_verify(bigval_t const* msgdgst, affine_point_t const* pubkey, ECDSA_sig_t const* sig) { if (ECDSA_verify_inner(msgdgst, pubkey, sig) == V_SUCCESS) { return B_TRUE; } return B_FALSE; } /* * Converts a hash value to a bigval_t. The rules for this in * ANSIX9.62 are strange. Let b be the number of octets necessary to * represent the modulus. If the size of the hash is less than or * equal to b, the hash is interpreted directly as a number. * Otherwise the left most b octets of the hash are converted to a * number. The hash must be big-endian by byte. There is no alignment * requirement on hashp. */ void ECC_hash_to_bigval(bigval_t* tgt, void const* hashp, unsigned int hashlen) { unsigned int i; /* The "4"s in the rest of this function are the number of bytes in a uint32_t (what bigval_t's are made of). The "8" is the number of bits in a byte. */ /* reduce hashlen to modulus size, if necessary */ if (hashlen > 4 * (BIGLEN - 1)) { hashlen = 4 * (BIGLEN - 1); } *tgt = big_zero; /* move one byte at a time starting with least significant byte */ for (i = 0; i < hashlen; ++i) { tgt->data[i / 4] |= ((uint8_t*)hashp)[hashlen - 1 - i] << (8 * (i % 4)); } } #endif /* ECDSA */ #ifdef ECC_TEST char* ECC_feature_list(void) { return ("ECC_P256" #ifdef ECDSA " ECDSA" #endif #ifdef SPECIAL_SQUARE " SPECIAL_SQUARE" #endif #ifdef SMALL_CODE " SMALL_CODE" #endif #ifdef MPY2BITS " MPY2BITS" #endif #ifdef ARM7_ASM " ARM7_ASM" #endif ); } #endif /* ECC_TEST */ typedef bigval_t ecc_privatekey; typedef affine_point_t ecc_publickey; typedef affine_point_t ecc_secret; typedef ECDSA_sig_t ecc_signature; AJ_Status AJ_GenerateECCKeyPair(AJ_ECCPublicKey* pub, AJ_ECCPrivateKey* prv) { ecc_publickey publickey; ecc_privatekey privatekey; if (0 != ECDH_generate(&publickey, &privatekey)) { return AJ_ERR_SECURITY; } /* Encode native to big-endian structures */ pub->alg = KEY_ALG_ECDSA_SHA256; pub->crv = KEY_CRV_NISTP256; prv->alg = KEY_ALG_ECDSA_SHA256; prv->crv = KEY_CRV_NISTP256; BigvalEncode(&publickey.x, pub->x, KEY_ECC_SZ); BigvalEncode(&publickey.y, pub->y, KEY_ECC_SZ); BigvalEncode(&privatekey, prv->x, KEY_ECC_SZ); return AJ_OK; } AJ_Status AJ_GenerateShareSecret(AJ_ECCPublicKey* pub, AJ_ECCPrivateKey* prv, AJ_ECCSecret* sec) { boolean_t derive_rv; ecc_publickey publickey; ecc_privatekey privatekey; ecc_secret secret; /* Decode big-endian structures to native */ publickey.infinity = B_FALSE; BigvalDecode(pub->x, &publickey.x, KEY_ECC_SZ); BigvalDecode(pub->y, &publickey.y, KEY_ECC_SZ); BigvalDecode(prv->x, &privatekey, KEY_ECC_SZ); derive_rv = ECDH_derive_pt(&secret, &privatekey, &publickey); if (!derive_rv) { return AJ_ERR_SECURITY; /* bad */ } else if (!in_curveP(&secret)) { return AJ_ERR_SECURITY; /* bad */ } /* Encode native to big-endian structures */ sec->crv = KEY_CRV_NISTP256; BigvalEncode(&secret.x, sec->x, KEY_ECC_SZ); return AJ_OK; } AJ_Status AJ_ECDSASignDigest(const uint8_t* digest, const AJ_ECCPrivateKey* prv, AJ_ECCSignature* sig) { bigval_t source; ecc_privatekey privatekey; ecc_signature signature; /* Decode big-endian structures to native */ BigvalDecode(prv->x, &privatekey, KEY_ECC_SZ); ECC_hash_to_bigval(&source, digest, AJ_SHA256_DIGEST_LENGTH); if (0 != ECDSA_sign(&source, &privatekey, &signature)) { return AJ_ERR_SECURITY; } /* Encode native to big-endian structures */ sig->alg = KEY_ALG_ECDSA_SHA256; sig->crv = KEY_CRV_NISTP256; BigvalEncode(&signature.r, sig->r, KEY_ECC_SZ); BigvalEncode(&signature.s, sig->s, KEY_ECC_SZ); return AJ_OK; } AJ_Status AJ_ECDSASign(const uint8_t* buf, uint16_t len, const AJ_ECCPrivateKey* prv, AJ_ECCSignature* sig) { AJ_SHA256_Context* ctx; uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; AJ_Status status; ctx = AJ_SHA256_Init(); if (!ctx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx, buf, (size_t) len); status = AJ_SHA256_Final(ctx, digest); if (status != AJ_OK) { return status; } return AJ_ECDSASignDigest(digest, prv, sig); } AJ_Status AJ_ECDSAVerifyDigest(const uint8_t* digest, const AJ_ECCSignature* sig, const AJ_ECCPublicKey* pub) { bigval_t source; ecc_publickey publickey; ecc_signature signature; /* Decode big-endian structures to native */ publickey.infinity = B_FALSE; BigvalDecode(pub->x, &publickey.x, KEY_ECC_SZ); BigvalDecode(pub->y, &publickey.y, KEY_ECC_SZ); BigvalDecode(sig->r, &signature.r, KEY_ECC_SZ); BigvalDecode(sig->s, &signature.s, KEY_ECC_SZ); ECC_hash_to_bigval(&source, digest, AJ_SHA256_DIGEST_LENGTH); if (ECDSA_verify(&source, &publickey, &signature) == B_TRUE) { return AJ_OK; } return AJ_ERR_SECURITY; } AJ_Status AJ_ECDSAVerify(const uint8_t* buf, uint16_t len, const AJ_ECCSignature* sig, const AJ_ECCPublicKey* pub) { AJ_SHA256_Context* ctx; uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; AJ_Status status; ctx = AJ_SHA256_Init(); if (!ctx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx, (const uint8_t*) buf, (size_t) len); status = AJ_SHA256_Final(ctx, digest); if (status != AJ_OK) { return status; } return AJ_ECDSAVerifyDigest(digest, sig, pub); } void AJ_BigEndianEncodePublicKey(AJ_ECCPublicKey* pub, uint8_t* b8) { ecc_publickey publickey; publickey.infinity = B_FALSE; BigvalDecode(pub->x, &publickey.x, KEY_ECC_SZ); BigvalDecode(pub->y, &publickey.y, KEY_ECC_SZ); HostU32ToBigEndianU8((uint32_t*) &publickey, sizeof (ecc_publickey), b8); } void AJ_BigEndianDecodePublicKey(AJ_ECCPublicKey* pub, uint8_t* b8) { ecc_publickey publickey; BigEndianU8ToHostU32(b8, (uint32_t*) &publickey, sizeof (ecc_publickey)); BigvalEncode(&publickey.x, pub->x, KEY_ECC_SZ); BigvalEncode(&publickey.y, pub->y, KEY_ECC_SZ); } AJ_Status AJ_GenerateShareSecretOld(AJ_ECCPublicKey* pub, AJ_ECCPrivateKey* prv, AJ_ECCPublicKey* sec) { boolean_t derive_rv; ecc_publickey publickey; ecc_privatekey privatekey; ecc_secret secret; /* Decode big-endian structures to native */ publickey.infinity = B_FALSE; BigvalDecode(pub->x, &publickey.x, KEY_ECC_SZ); BigvalDecode(pub->y, &publickey.y, KEY_ECC_SZ); BigvalDecode(prv->x, &privatekey, KEY_ECC_SZ); derive_rv = ECDH_derive_pt(&secret, &privatekey, &publickey); if (!derive_rv) { return AJ_ERR_SECURITY; /* bad */ } else if (!in_curveP(&secret)) { return AJ_ERR_SECURITY; /* bad */ } /* Encode native to big-endian structures */ sec->crv = KEY_CRV_NISTP256; BigvalEncode(&secret.x, sec->x, KEY_ECC_SZ); BigvalEncode(&secret.y, sec->y, KEY_ECC_SZ); return AJ_OK; } /* * Not a general-purpose implementation of REDP-1 from IEEE 1363. * Only used in AllJoyn to derive two basepoints, from the fixed constants * "ALLJOYN-ECSPEKE-1" and "ALLJOYN-ECSPEKE-2" * pi is not treated as a secret value. * This function is not constant-time. */ AJ_Status ec_REDP1(const uint8_t* pi, size_t len, ecpoint_t* Q, ec_t* curve) { AJ_Status status = AJ_OK; AJ_SHA256_Context* ctx; uint8_t digest_i1[AJ_SHA256_DIGEST_LENGTH]; uint8_t bytes_O3[AJ_SHA256_DIGEST_LENGTH]; digit256_t x, alpha, beta; digit256_t tmp; digit_t temps[P256_TEMPS]; int mu, carry, i; digit256_tc P256_A = { 0xFFFFFFFFFFFFFFFCULL, 0x00000000FFFFFFFFULL, 0x0000000000000000ULL, 0xFFFFFFFF00000001ULL }; digit256_tc P256_B = { 0x3BCE3C3E27D2604BULL, 0x651D06B0CC53B0F6ULL, 0xB3EBBD55769886BCULL, 0x5AC635D8AA3A93E7ULL }; /* Steps and notation follow IEEE 1363.2 Section 8.2.17 "[EC]REDP-1" */ /* Hash pi to an octet string -- Step (a)*/ ctx = AJ_SHA256_Init(); if (!ctx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx, pi, len); AJ_SHA256_Final(ctx, digest_i1); while (1) { /* mu is rightmost bit of digest_i1 */ mu = digest_i1[sizeof(digest_i1) - 1] % 2; /* Hash the hash -- Steps (b), (c), (d). */ ctx = AJ_SHA256_Init(); if (!ctx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx, digest_i1, sizeof(digest_i1)); AJ_SHA256_Final(ctx, bytes_O3); /* Convert octets O3 to the field element x -- Step (e) */ fpimport_p256(bytes_O3, x, temps, TRUE); /* Compute alpha = x^3 + a*x + b (mod p) */ fpmul_p256(x, x, alpha, temps); /* alpha = x^2 */ fpmul_p256(alpha, x, alpha, temps); /* alpha = x^3 */ fpmul_p256(x, P256_A, tmp, temps); /* tmp = a*x */ fpadd_p256(alpha, tmp, alpha); /* alpha = x^3 + a*x */ fpadd_p256(alpha, P256_B, alpha); /* alpha = x^3 + a*x + b */ /* Compute beta = a sqrt of alpha, if possible, if not begin a new iteration. */ if (fpissquare_p256(alpha, temps)) { fpsqrt_p256(alpha, beta, temps); } else { /* Increment digest_i1 (as a big endian integer) then start a new iteration */ carry = 1; for (i = sizeof(digest_i1) - 1; i >= 0; i--) { digest_i1[i] += carry; carry = (digest_i1[i] == 0); } if (carry) { /* It's overflown sizeof(digest_i1), fail. The probability of * this occuring is negligible. */ status = AJ_ERR_FAILURE; goto Exit; } continue; } if (mu) { fpneg_p256(beta); } /* Output (x,beta) */ memcpy(Q->x, x, sizeof(digit256_t)); memcpy(Q->y, beta, sizeof(digit256_t)); break; } /* Make sure the point is valid, and is not the identity. */ if (!ecpoint_validation(Q, curve)) { status = AJ_ERR_FAILURE; goto Exit; } Exit: /* Nothing to zero since inputs are public. */ return status; } /* Computes R = Q1*Q2^pi */ AJ_Status ec_REDP2(const uint8_t pi[sizeof(digit256_t)], const ecpoint_t* Q1, const ecpoint_t* Q2, ecpoint_t* R, ec_t* curve) { digit256_t t; digit_t temps[P256_TEMPS]; AJ_Status status = AJ_OK; fpimport_p256(pi, t, temps, TRUE); status = ec_scalarmul(Q2, t, R, curve); /* R = Q2^t*/ ec_add(R, Q1, curve); /* R = Q1*Q2^t*/ fpzero_p256(t); AJ_MemZeroSecure(temps, P256_TEMPS * sizeof(digit_t)); return status; } /* * Get the two precomputed points * Q1 = REDP-1(ALLJOYN-ECSPEKE-1), Q2 = REDP-1(ALLJOYN-ECSPEKE-2). */ void ec_get_REDP_basepoints(ecpoint_t* Q1, ecpoint_t* Q2, curveid_t curveid) { digit256_tc x1 = { 0x9F011EB0E927BBB7ULL, 0xDCD485337A6C1035ULL, 0x0AF630115AA734C0ULL, 0xE7F425D4C27D2BA1ULL }; digit256_tc y1 = { 0xDD836A9DF0702B55ULL, 0x8A4AE230F7C50D50ULL, 0x4115DB75D35208F6ULL, 0x8B4ADF4EBD690598ULL }; digit256_tc x2 = { 0x4CEC1D03497217AAULL, 0x966C293CD3634462ULL, 0xE4E36BBB81CD843DULL, 0xF9F2EF394FCB375EULL }; digit256_tc y2 = { 0x40D6ACB2274CCFC2ULL, 0x5EAAF49A32B58CFAULL, 0x77999C42D8DDAB41ULL, 0xF5EFE6B53FF34102ULL }; AJ_ASSERT(curveid == NISTP256r1); fpcopy_p256(x1, Q1->x); fpcopy_p256(y1, Q1->y); fpcopy_p256(x2, Q2->x); fpcopy_p256(y2, Q2->y); } static AJ_Status GenerateSPEKEKeyPair_inner(const uint8_t* pw, size_t pwLen, const AJ_GUID* clientGUID, const AJ_GUID* serviceGUID, ecpoint_t* publicKey, digit256_t privateKey) { AJ_Status status; AJ_SHA256_Context* ctx = NULL; uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; digit_t temps[P256_TEMPS]; ecpoint_t Q1, Q2; /* Base points for REDP-2. */ ecpoint_t B; /* Base point for ECDH, derived from pw. */ ec_t curve; if (clientGUID == NULL || serviceGUID == NULL || pw == NULL || pwLen == 0) { return AJ_ERR_NULL; } status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { goto Exit; } /* Compute digest = SHA-256(pw||clientGUID||serviceGUID) */ ctx = AJ_SHA256_Init(); if (!ctx) { status = AJ_ERR_RESOURCES; goto Exit; } AJ_SHA256_Update(ctx, pw, pwLen); AJ_SHA256_Update(ctx, clientGUID->val, sizeof(AJ_GUID)); AJ_SHA256_Update(ctx, serviceGUID->val, sizeof(AJ_GUID)); AJ_SHA256_Final(ctx, digest); /* Compute basepoint B for keypair. */ ec_get_REDP_basepoints(&Q1, &Q2, curve.curveid); status = ec_REDP2(digest, &Q1, &Q2, &B, &curve); if (status != AJ_OK) { goto Exit; } /* Compute private key. */ do { AJ_RandBytes((uint8_t*)privateKey, sizeof(digit256_t)); } while (!validate_256(privateKey, curve.order)); status = ec_scalarmul(&B, privateKey, publicKey, &curve); /* Public key publicKey = B^r */ Exit: fpzero_p256(B.x); fpzero_p256(B.y); AJ_MemZeroSecure(temps, P256_TEMPS * sizeof(digit_t)); AJ_MemZeroSecure(digest, AJ_SHA256_DIGEST_LENGTH); ec_freecurve(&curve); /* The hash context was either not initialized, or securely zeroed and freed by AJ_SHA256_Final*/ return status; } AJ_Status AJ_GenerateSPEKEKeyPair(const uint8_t* pw, size_t pwLen, const AJ_GUID* clientGUID, const AJ_GUID* serviceGUID, AJ_ECCPublicKey* publicKey, AJ_ECCPrivateKey* privateKey) { AJ_Status status; ecpoint_t pub; digit256_t priv; ecc_publickey pubTemp; ecc_privatekey privTemp; status = GenerateSPEKEKeyPair_inner(pw, pwLen, clientGUID, serviceGUID, &pub, priv); if (status != AJ_OK) { return status; } /* Convert pub to ecc_publickey then AJ_ECCPublicKey */ digit256_to_bigval(pub.x, &(pubTemp.x)); digit256_to_bigval(pub.y, &(pubTemp.y)); BigvalEncode(&pubTemp.x, publicKey->x, KEY_ECC_SZ); BigvalEncode(&pubTemp.y, publicKey->y, KEY_ECC_SZ); /* Convert priv to ecc_privatekey then AJ_ECCPrivateKey */ digit256_to_bigval(priv, &privTemp); BigvalEncode(&privTemp, privateKey->x, KEY_ECC_SZ); privateKey->alg = KEY_ALG_ECSPEKE; privateKey->crv = KEY_CRV_NISTP256; AJ_MemZeroSecure(&privTemp, KEY_ECC_SZ); return AJ_OK; }ajtcl-16.04/src/crypto/aj_crypto_field_p256.c000066400000000000000000000574451271074662300210340ustar00rootroot00000000000000/** * @file field_p256.c Implementation of field arithmetic for ECC. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include /* for byte swaping function(s) */ #if defined(_WIN32) && defined(_umul128) #include #pragma intrinsic(_umul128) #endif /* * This file contains modular multiplication (in constant time) * for the NIST prime P-256: * 2^256-2^224+2^192+2^96-1 * on 64-bit platforms. * * based on the approach from * * J. A. Solinas. Generalized Mersenne numbers. * Technical Report CORR 99–39, Centre for Applied Cryptographic * Research, University of Waterloo, 1999. * * but adopted to 64-bit limbs. * * Let C = \sum_{i=0}^{7} ci * 2^{64*i} be our product * such that the different ci are that 0 <= ci < 2^64. * We denote * s = c3 * 2^192 + c2 * 2^128 + c1 * 2^64 + c0 * by s = ( c3, c2, c1, c0 ). The higher 32-bit parts of a * 64-bit limbs c is denoted by c_h and the lower 32-bit part * by c_\ell. We can convert Solinas' scheme to 64-bit platforms * as follows * * s1 = ( c3, c2, c1, c0 ), * s2 = ( c7, c6, c5_h||0, 0 ) * s3 = ( 0||c7_h, c7_\ell||c6_h, c6_\ell||0, 0 ), * s4 = ( c7, 0, 0||c5_\ell, c4 ) * s5 = ( c4_\ell||c6_h, c7, c6_h||c5_h, c5_\ell||c4_h ), * s6 = ( c5_\ell||c4_\ell, 0, 0||c6_h, c6_\ell||c5_h ) * s7 = ( c5_h||c4_h, 0, c7, c6 ), * s8 = ( c6_\ell||0, c5_\ell||c4_h, c4_\ell||c7_h, c7_\ell||c6_h ) * s9 = ( c6_h||0, c5, c4_h||0, c7 ) * d = s_1+2s_2+2s_3+s_4+s_5 - (s_6+s_7+s_8+s_9) * * We prefer positive d and instead we compute * d = s_1+2s_2+2s_3+s_4+s_5 + 4*p256 - (s_6+s_7+s_8+s_9) * such that 0 <= d < 11*p256 * Next we perform one additional reduction step and a conditional * subtraction (in constant time) to ensure the result is between * zero and p256. */ static digit256_tc P256_MODULUS = { 18446744073709551615ULL, 4294967295ULL, 0ULL, 18446744069414584321ULL }; /* Macros to extract the lower and upper parts. */ #define getlow_tolow(x) ((x) & (digit_t) 0xFFFFFFFF) #define getlow_tohigh(x) ((x) << (digit_t) 32) #define gethigh_tohigh(x) ((x) & (digit_t) 0xFFFFFFFF00000000) #define gethigh_tolow(x) ((x) >> (digit_t) 32) /* Is x != 0? */ inline digit_t is_digit_nonzero_ct(digit_t x) { return ((x | (0 - x)) >> (RADIX_BITS - 1)); } /* Is x == 0? */ inline digit_t is_digit_zero_ct(digit_t x) { return (1 ^ is_digit_nonzero_ct(x)); } static inline unsigned char is_digit_lessthan_ct(digit_t x, digit_t y) { /* Look at the high bit of x, y and (x - y) to determine whether x < y. */ return (unsigned char)((x ^ ((x ^ y) | ((x - y) ^ y))) >> (RADIX_BITS - 1)); } /* Software macros for addition, may be substituted if intrinsics are available * on a given platform. */ #define add3(c0, c1, c2, c3, a0, a1, a2, b0, b1, b2) \ { \ digit_t _t; \ ADDC(_t, c0, a0, b0, 0); \ ADDC(_t, c1, a1, b1, _t); \ ADDC(c3, c2, a2, b2, _t); \ } #define add2_ncout(c0, c1, a0, a1, b0, b1) \ { \ digit_t _t; \ ADDC(_t, c0, a0, b0, 0); \ ADDC(_t, c1, a1, b1, _t); \ } #define add3_ncout(c0, c1, c2, a0, a1, a2, b0, b1, b2) \ { \ digit_t _t; \ ADDC(_t, c0, a0, b0, 0); \ ADDC(_t, c1, a1, b1, _t); \ ADDC(_t, c2, a2, b2, _t); \ } #define add4_ncout(c0, c1, c2, c3, a0, a1, a2, a3, b0, b1, b2, b3) \ { \ digit_t _t; \ ADDC(_t, c0, a0, b0, 0); \ ADDC(_t, c1, a1, b1, _t); \ ADDC(_t, c2, a2, b2, _t); \ ADDC(_t, c3, a3, b3, _t); \ } #define add4(c0, c1, c2, c3, c4, a0, a1, a2, a3, b0, b1, b2, b3) \ { \ digit_t _t; \ ADDC(_t, c0, a0, b0, 0); \ ADDC(_t, c1, a1, b1, _t); \ ADDC(_t, c2, a2, b2, _t); \ ADDC(c4, c3, a3, b3, _t); \ } #define add5_ncout(c0, c1, c2, c3, c4, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ { \ digit_t _t; \ ADDC(_t, c0, a0, b0, 0); \ ADDC(_t, c1, a1, b1, _t); \ ADDC(_t, c2, a2, b2, _t); \ ADDC(_t, c3, a3, b3, _t); \ ADDC(_t, c4, a4, b4, _t); \ } #define sub4_nborrow(c0, c1, c2, c3, a0, a1, a2, a3, b0, b1, b2, b3) \ { \ digit_t _t; \ SUBC(_t, c0, a0, b0, 0); \ SUBC(_t, c1, a1, b1, _t); \ SUBC(_t, c2, a2, b2, _t); \ SUBC(_t, c3, a3, b3, _t); \ } #define sub5_nborrow(c0, c1, c2, c3, c4, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ { \ digit_t _t; \ SUBC(_t, c0, a0, b0, 0); \ SUBC(_t, c1, a1, b1, _t); \ SUBC(_t, c2, a2, b2, _t); \ SUBC(_t, c3, a3, b3, _t); \ SUBC(_t, c4, a4, b4, _t); \ } #define sub5(B, c0, c1, c2, c3, c4, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ { \ digit_t _t; \ SUBC(_t, c0, a0, b0, 0); \ SUBC(_t, c1, a1, b1, _t); \ SUBC(_t, c2, a2, b2, _t); \ SUBC(_t, c3, a3, b3, _t); \ SUBC(B, c4, a4, b4, _t); \ } /******* Intrinsics/macros for Fp implementation *********/ /* 64x64 -> 128 * returns the high 64-bits of the product * Software implementation of the _umul128 intrinsic, for when it's not present. * stdint.h guarantees we have uint64_t. */ uint64_t software_umul128(uint64_t u, uint64_t v, uint64_t* high) { uint64_t u1, v1, t, w3, k, w1; u1 = (u & 0xFFFFFFFF); v1 = (v & 0xFFFFFFFF); t = (u1 * v1); u >>= 32; w3 = (t & 0xFFFFFFFF); k = (t >> 32); t = (u * v1) + k; v >>= 32; k = (t & 0xFFFFFFFF); w1 = (t >> 32); t = (u1 * v) + k; v1 = (u * v); k = (t >> 32); (*high) = v1 + k + w1; return (t << 32) + w3; } #ifndef _umul128 #define _umul128 software_umul128 #endif #if RADIX_BITS != 64 #error Unexpected radix bits; expecting 64. #endif /* * Macros to encapsulate intrinsics when and if they are defined. */ /* 64 x 64 --> 128-bit multiplication * (c1,c0) = a * b */ #define mul(c0, c1, a, b) c0 = _umul128(a, b, &c1) /* Multiply-and-accumulate * (c1,c0) = a*b+c0 */ #define muladd(c0, c1, a, b) { \ digit_t _c = c0; \ mul(c0, c1, a, b); \ ADD(_c, c0, c0, _c); \ c1 += _c; \ } /* Multiply-and-accumulate-accumulate * (c1,c0) = a*b+c0+c1 */ #define muladdadd(c0, c1, a, b) { \ digit_t _C0 = c0, _C1 = c1, carry; \ mul(c0, c1, a, b); \ ADD(carry, c0, c0, _C0); \ ADDC(carry, c1, c1, 0, carry); \ ADD(carry, c0, c0, _C1); \ ADDC(carry, c1, c1, 0, carry); \ } /* Adds two operands, and produces sum of the two inputs and the carry bit. * This is ideally an intrinsic, but is emulated when an intrinsic is not available. */ #define ADD(carryOut, sumOut, addend1, addend2) { \ digit_t sum = (addend1) + (addend2); \ carryOut = (digit_t)is_digit_lessthan_ct(sum, (addend1)); \ (sumOut) = sum; } /* Adds two operands and a carry bit, produces sum of the three inputs and the carry bit. * This is ideally an intrinsic, but is emulated when an intrinsic is not available.*/ #pragma warning(suppress:4296) #define ADDC(carryOut, sumOut, addend1, addend2, carryIn) { \ digit_t tempReg = (addend1) + (digit_t)(carryIn); \ (sumOut) = (addend2) + tempReg; \ (carryOut) = (is_digit_lessthan_ct(tempReg, (digit_t)(carryIn)) | is_digit_lessthan_ct((sumOut), tempReg)); } /* Subtract operation. * Subtract one number from the other, and return the difference and the borrow (carry) bit. */ #define SUB(borrowOut, differenceOut, minuend, subtrahend) { \ (borrowOut) = (digit_t)is_digit_lessthan_ct((minuend), (subtrahend)); \ (differenceOut) = (minuend) - (subtrahend); } /* Subtraction with borrow (carry). * Subtract one number from the other with borrow (carry), and return the difference and the borrow (carry) bit.*/ #define SUBC(borrowOut, differenceOut, minuend, subtrahend, borrowIn) { \ digit_t tempReg = (minuend) - (subtrahend); \ digit_t borrowReg = ((digit_t)is_digit_lessthan_ct((minuend), (subtrahend)) | ((borrowIn) & is_digit_zero_ct(tempReg))); \ (differenceOut) = tempReg - (digit_t)(borrowIn); \ (borrowOut) = borrowReg; } /* Move if carry is set. */ #define CMOVC(dest, src, selector) { \ digit_t mask = is_digit_nonzero_ct(selector) - 1; \ (dest) = ((~mask) & (src)) | (mask & (dest)); } /* Zero of a 256-bit field element, a = 0 */ void fpzero_p256(digit256_t a) { AJ_ASSERT(a != NULL); AJ_MemZeroSecure(a, sizeof(digit256_t)); } /* Is a == 0? (as integers, not mod P256) */ digit_t fpiszero_p256(digit256_t a) { size_t i; digit_t c; AJ_ASSERT(a != NULL); c = a[0]; for (i = 1; i < P256_DIGITS; i++) { c = c | a[i]; } return is_digit_zero_ct(c); } boolean_t validate_256(digit256_tc a, digit256_tc modulus) { boolean_t valid = B_FALSE; digit256_t t1; AJ_ASSERT(a != NULL); AJ_ASSERT(modulus != NULL); fpcopy_p256(a, t1); valid = fpneg_p256(t1); /* valid = B_TRUE if a <= modulus */ valid = (valid & (fpiszero_p256(t1) ^ 1)); /* valid = B_TRUE if a < modulus (use & instead of && for constant-time execution) */ /* cleanup */ fpzero_p256(t1); return valid; } /* Validate that a 256-bit value is in [0, P256_MODULUS-1] * Returns = B_TRUE if 0 <= a < modulus, else returns B_FALSE.*/ boolean_t fpvalidate_p256(digit256_tc a) { AJ_ASSERT(a != NULL); return validate_256(a, P256_MODULUS); } /* Set a = p256 (the prime that defines this finite field). */ void fpgetprime_p256(digit256_t a) { AJ_ASSERT(a != NULL); memcpy(a, P256_MODULUS, sizeof(P256_MODULUS)); } /* Compute c = a * b for 256-bit a and b * Private function used to implement fpmul_p256. */ static void mul_p256( digit256_tc a, digit256_tc b, digit_t* c) /* Note this must have size at least 2*P256_DIGITS */ { digit_t A, t; AJ_ASSERT(a != NULL); AJ_ASSERT(b != NULL); AJ_ASSERT(c != NULL); A = a[0]; mul(c[0], c[1], A, b[0]); muladd(c[1], c[2], A, b[1]); muladd(c[2], c[3], A, b[2]); muladd(c[3], c[4], A, b[3]); A = a[1]; muladd(c[1 + 0], t, A, b[0]); muladdadd(c[1 + 1], t, A, b[1]); muladdadd(c[1 + 2], t, A, b[2]); muladdadd(c[1 + 3], t, A, b[3]); c[1 + 4] = t; A = a[2]; muladd(c[2 + 0], t, A, b[0]); muladdadd(c[2 + 1], t, A, b[1]); muladdadd(c[2 + 2], t, A, b[2]); muladdadd(c[2 + 3], t, A, b[3]); c[2 + 4] = t; A = a[3]; muladd(c[3 + 0], t, A, b[0]); muladdadd(c[3 + 1], t, A, b[1]); muladdadd(c[3 + 2], t, A, b[2]); muladdadd(c[3 + 3], t, A, b[3]); c[3 + 4] = t; } /* Compute c = a mod 2^256-2^224+2^192+2^96-1 * such that 0 <= c < 2^256-2^224+2^192+2^96-1 * Private function used to implement fpmul_p256. */ static void reduce_p256( digit_t* a, digit256_t c) { /* 4*p = 0x 3 FFFFFFFC00000004 0000000000000000 00000003FFFFFFFF FFFFFFFFFFFFFFFC */ digit_t c0, c1, c2, c3, c4, c5, c6, c7; digit_t r0, r1, r2, r3, r4; digit_t p0, p1, p2, p3, p4; digit_t q0, q1, q2, q3, q4; digit_t t; AJ_ASSERT(a != NULL); AJ_ASSERT(c != NULL); c0 = a[0]; c1 = a[1]; c2 = a[2]; c3 = a[3]; c4 = a[4]; c5 = a[5]; c6 = a[6]; c7 = a[7]; /* compute s2 + s2 = [r4, r3, r2, r1, 0] */ t = gethigh_tohigh(c5); add3(r1, r2, r3, r4, t, c6, c7, t, c6, c7); /* compute s3 + s3 = [p3, p2, p1, 0] */ p1 = getlow_tohigh(c6); p2 = (gethigh_tolow(c6) | getlow_tohigh(c7)); p3 = gethigh_tolow(c7); add3_ncout(p1, p2, p3, p1, p2, p3, p1, p2, p3); /* Compute 2s_2 + 2s_3 = [p4, p3, p2, p1, 0] */ add4_ncout(p1, p2, p3, p4, p1, p2, p3, 0, r1, r2, r3, r4); /* Compute s_1+s_4 = [q4, q3, q2, q1, q0] */ q1 = getlow_tolow(c5); add4(q0, q1, q2, q3, q4, c0, c1, c2, c3, c4, q1, 0, c7); /* Compute s_1+s_4+2s_2+2s_3 = [q4,q3,q2,q1,q0] */ add4_ncout(q1, q2, q3, q4, q1, q2, q3, q4, p1, p2, p3, p4); /* Compute s_1+s_4+2s_2+2s_3+s_5 = [q4,q3,q2,q1,q0] */ p0 = (gethigh_tolow(c4) | getlow_tohigh(c5)); p1 = (gethigh_tolow(c5) | gethigh_tohigh(c6)); p3 = (gethigh_tolow(c6) | getlow_tohigh(c4)); add4(q0, q1, q2, q3, p4, q0, q1, q2, q3, p0, p1, c7, p3); q4 += p4; /* Compute s_1+s_4+2s_2+2s_3+s_5+4p_256 = [q4,q3,q2,q1,q0] */ add5_ncout(q0, q1, q2, q3, q4, q0, q1, q2, q3, q4, \ 0xFFFFFFFFFFFFFFFC, 0x3FFFFFFFF, 0x0, 0xFFFFFFFC00000004, 0x3); /* Compute s_6+s_7 = [p4,p3,p2,p1,p0] */ t = (gethigh_tolow(c4) | gethigh_tohigh(c5)); p0 = (gethigh_tolow(c5) | getlow_tohigh(c6)); p1 = gethigh_tolow(c6); p2 = 0; p3 = (getlow_tolow(c4) | getlow_tohigh(c5)); add4(p0, p1, p2, p3, p4, c6, c7, 0, t, p0, p1, p2, p3); /* Compute s_6+s_7+s_8 = [p4,p3,p2,p1,p0] */ r0 = (gethigh_tolow(c6) | getlow_tohigh(c7)); r1 = (gethigh_tolow(c7) | getlow_tohigh(c4)); r2 = (gethigh_tolow(c4) | getlow_tohigh(c5)); r3 = getlow_tohigh(c6); add4(p0, p1, p2, p3, r4, r0, r1, r2, r3, p0, p1, p2, p3); p4 += r4; /* Compute s_6+s_7+s_8+s_9 = [p4,p3,p2,p1,p0] */ r1 = gethigh_tohigh(c4); r3 = gethigh_tohigh(c6); add4(p0, p1, p2, p3, r4, c7, r1, c5, r3, p0, p1, p2, p3); p4 += r4; /* Compute d = s_1+2s_2+2s_3+s_4+s_5 - (s_6+s_7+s_8+s_9) */ sub5_nborrow(q0, q1, q2, q3, q4, q0, q1, q2, q3, q4, p0, p1, p2, p3, p4); /* [q0+q4], [q1-q4*2^32], [q2], [q3-d+d*2^32] */ p4 = 0; add4(q0, q1, q2, q3, p4, q0, q1, q2, q3, q4, 0, 0, 0); p0 = (q4 << (digit_t)32); sub4_nborrow(q1, q2, q3, p4, q1, q2, q3, p4, p0, 0, 0, 0); p0 = p0 - q4; add2_ncout(q3, p4, q3, p4, p0, 0); /* Compute the conditional subtraction. */ sub5(p0, c0, c1, c2, c3, c4, q0, q1, q2, q3, p4, \ 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF, 0x0000000000000000, 0xFFFFFFFF00000001, 0); CMOVC(c0, q0, p0); CMOVC(c1, q1, p0); CMOVC(c2, q2, p0); CMOVC(c3, q3, p0); c[0] = c0; c[1] = c1; c[2] = c2; c[3] = c3; } void fpmul_p256( digit256_tc multiplier, digit256_tc multiplicand, digit256_t product, digit_t* temps) { AJ_ASSERT(multiplier != NULL); AJ_ASSERT(multiplicand != NULL); AJ_ASSERT(product != NULL); AJ_ASSERT(temps != NULL); mul_p256(multiplier, multiplicand, temps); reduce_p256(temps, product); } void fpsqr_p256( digit256_tc multiplier, digit256_t product, digit_t* temps) { AJ_ASSERT(multiplier != NULL); AJ_ASSERT(product != NULL); AJ_ASSERT(temps != NULL); fpmul_p256(multiplier, multiplier, product, temps); } void fpadd_p256( digit256_tc addend1, digit256_tc addend2, digit256_t pSum) { digit_t carry = 0; digit_t borrow = 0; digit_t mask; AJ_ASSERT(addend1 != NULL); AJ_ASSERT(addend2 != NULL); AJ_ASSERT(pSum != NULL); /* (carry,sum) = a1 + a2 */ ADD(carry, pSum[0], addend1[0], addend2[0]); ADDC(carry, pSum[1], addend1[1], addend2[1], carry); ADDC(carry, pSum[2], addend1[2], addend2[2], carry); ADDC(carry, pSum[3], addend1[3], addend2[3], carry); /* Constant time reduction: subtract the modulus, and move only if there is a carry out. * (borrow,sum) = (carry,sum) - P256_MODULUS */ SUB(borrow, pSum[0], pSum[0], P256_MODULUS[0]); SUBC(borrow, pSum[1], pSum[1], P256_MODULUS[1], borrow); SUBC(borrow, pSum[2], pSum[2], P256_MODULUS[2], borrow); SUBC(borrow, pSum[3], pSum[3], P256_MODULUS[3], borrow); borrow = borrow ^ carry; /* bit-level subtraction. Don't use - */ /* both carry from addition and borrow can't happen, since a1m => (a1+a2-m)>0. */ AJ_ASSERT((carry & borrow) == 0); /* Conditional correction without conditional branches */ /* If there is a borrow bit, revert the subtration by adding back the modulus. * 'mask' is either an all-zero or an all-one digit mask. * If there is no borrow, add an all-zero P256_MODULUS. Otherwise, add P256_MODULUS. * if (borrow) sum = sum + P256_MODULUS */ mask = 0 - borrow; ADD(carry, pSum[0], pSum[0], mask & P256_MODULUS[0]); ADDC(carry, pSum[1], pSum[1], mask & P256_MODULUS[1], carry); ADDC(carry, pSum[2], pSum[2], mask & P256_MODULUS[2], carry); ADDC(carry, pSum[3], pSum[3], mask & P256_MODULUS[3], carry); /* If there was no effective addition (borrow=0,mask=0), then carry=0, * since adding zero does not produce a carry out. * If there was an addition (borrow=1,mask=~0), then carry=1 * so that the high-order all-1 digits produced after the ill-conceived subtraction * would go back to being zero when added 1.*/ AJ_ASSERT(carry == borrow); } void fpsub_p256( digit256_tc minuend, digit256_tc subtrahend, digit256_t pDifference) { digit_t borrow = 0; digit_t carry = 0; digit_t mask = 0; AJ_ASSERT(minuend != NULL); AJ_ASSERT(subtrahend != NULL); AJ_ASSERT(pDifference != NULL); /* Constant time reduction: subtract the modulus, and move only if there is a carry out. * Trade-off: instead of conditional mode and using more memory, add the modulus back conditionally. */ SUB(borrow, pDifference[0], minuend[0], subtrahend[0]); SUBC(borrow, pDifference[1], minuend[1], subtrahend[1], borrow); SUBC(borrow, pDifference[2], minuend[2], subtrahend[2], borrow); SUBC(borrow, pDifference[3], minuend[3], subtrahend[3], borrow); /* If there is a borrow bit, revert the subtration by adding back the modulus. * What does 'mask' do? It is either an all-zero or an all-one digit mask. * If there is no borrow, add an all-zero modulus. Otherwise, add modulus. */ mask = 0 - borrow; ADD(carry, pDifference[0], pDifference[0], mask & P256_MODULUS[0]); ADDC(carry, pDifference[1], pDifference[1], mask & P256_MODULUS[1], carry); ADDC(carry, pDifference[2], pDifference[2], mask & P256_MODULUS[2], carry); ADDC(carry, pDifference[3], pDifference[3], mask & P256_MODULUS[3], carry); /* If there was no effective addition (borrow=0,mask=0), then carry=0, * since adding zero does not produce a carry out. * If there was an addition (borrow=1,mask=~0), then carry=1 * so that the high-order all-1 digits produced after the ill-conceived subtraction * would go back to being zero when added 1.*/ AJ_ASSERT(carry == borrow); } /* Negate a * If a <= modulus returns B_TRUE, else returns B_FALSE. */ boolean_t fpneg_p256( digit256_t a) { digit_t i, res, carry = 0, borrow = 0; AJ_ASSERT(a != NULL); for (i = 0; i < P256_DIGITS; i++) { res = P256_MODULUS[i] - a[i]; carry = is_digit_lessthan_ct(P256_MODULUS[i], a[i]); a[i] = res - borrow; borrow = carry | (borrow & is_digit_zero_ct(res)); } return (boolean_t)(borrow ^ 1); } void fpdiv2_p256( digit256_tc numerator, digit256_t quotient, digit_t* temps) { /* The constant 1/2 (mod p256): */ digit256_tc half = { 0ULL, 2147483648ULL, 9223372036854775808ULL, 9223372034707292160ULL }; AJ_ASSERT(numerator != NULL); AJ_ASSERT(quotient != NULL); AJ_ASSERT(temps != NULL); fpmul_p256(half, numerator, quotient, temps); } void fpcopy_p256(digit256_tc pSrc, digit256_t pDest) { memcpy(pDest, pSrc, sizeof(digit256_t)); } boolean_t fpequal_p256(digit256_tc f1, digit256_tc f2) { digit_t temp = 0; boolean_t equal; AJ_ASSERT(f1 != NULL); AJ_ASSERT(f2 != NULL); temp |= (f1[0] ^ f2[0]); temp |= (f1[1] ^ f2[1]); temp |= (f1[2] ^ f2[2]); temp |= (f1[3] ^ f2[3]); equal = (boolean_t) ~((((sdigit_t)temp) >> (RADIX_BITS - 1)) | (-((sdigit_t)temp) >> (RADIX_BITS - 1))) & 1; return equal; } /* Set a to the single digit dig0. */ void fpset_p256(digit_t dig0, digit256_t a) { AJ_ASSERT(a != NULL); memset(a, 0x00, P256_DIGITS * sizeof(digit_t)); a[0] = dig0; } /* Exponentiation via square-and-multiply. Not constant time, should not be used when e is private. */ static void fpexp_naive_p256(digit256_tc a, digit256_tc e, digit256_t out, digit_t* temps) { size_t digIdx = 0, bitIdx = 0, bitI = 0; size_t i = 0; fpset_p256((digit_t)1, out); /* out = 1; */ for (i = 0; i < 256; i++) { digIdx = (255 - i) / RADIX_BITS; bitIdx = (255 - i) % RADIX_BITS; bitI = (e[digIdx] >> bitIdx) & 1; fpsqr_p256(out, out, temps); if (bitI) { fpmul_p256(out, a, out, temps); } } } void fpinv_p256( digit256_tc a, digit256_t inv, digit_t* temps) { /* Exponentiation by (p-2). */ digit256_tc P256m2 = { 18446744073709551613ULL, 4294967295ULL, 0ULL, 18446744069414584321ULL }; fpexp_naive_p256(a, P256m2, inv, temps); } /* Swaps the byte order of the digits in a. The order of digits is not changed. * i.e., a[i] = ByteSwap(a[i]). */ void fpdigitswap_p256(digit256_t a) { size_t i; AJ_ASSERT(sizeof(digit_t) == 8); for (i = 0; i < P256_DIGITS; i++) { a[i] = AJ_ByteSwap64(a[i]); } } /* Reverse a byte array. */ static void reverse(uint8_t* in, size_t inlen) { size_t i = 0; for (i = 0; i < inlen / 2; i++) { SWAP(in[i], in[inlen - 1 - i]); } } /* Create a field element x from a byte string. * Input buffer must have length sizeof(digit256_t) * Inputs larger than P256 will be reduced mod P256. */ void fpimport_p256(const uint8_t* bytes, digit256_t x, digit_t* temps, boolean_t is_bigendian) { digit256_t tmp; memcpy(x, bytes, sizeof(digit256_t)); if (is_bigendian) { /* Input is a big endian octect string. */ reverse((uint8_t*)x, sizeof(digit256_t)); } fpset_p256(1, tmp); /* tmp = 1 */ fpmul_p256(x, tmp, x, temps); /* x = tmp*x = x mod P256 */ fpzero_p256(tmp); #if HOST_IS_BIG_ENDIAN /* Convert words to machine's endianness. */ fpdigitswap_p256(x); #endif } /* Returns B_TRUE if a is a square mod P256. */ boolean_t fpissquare_p256(digit256_tc a, digit_t* temps) { digit256_t one, legendre; digit256_tc P256m1div2 = { 0xFFFFFFFFFFFFFFFFULL, 0x000000007FFFFFFFULL, 0x8000000000000000ULL, 0x7FFFFFFF80000000ULL }; /* (P256-1)/2 */ fpset_p256(1, one); fpexp_naive_p256(a, P256m1div2, legendre, temps); /* legendre = a^((P256-1)/2) mod P256 */ if (fpequal_p256(legendre, one)) { /* if the Legendre symbol of a is one, a is a square mod P256 */ return B_TRUE; } return B_FALSE; } /* Returns sqrt = sqrt(a) mod P256. Correct only if a is a square (see fpissquare_p256). */ void fpsqrt_p256(digit256_tc a, digit256_t sqrt, digit_t* temps) { digit256_tc P256p1div4 = { 0x0000000000000000ULL, 0x0000000040000000ULL, 0x4000000000000000ULL, 0x3FFFFFFFC0000000ULL }; /* (P256 + 1)/4*/ /* Since p = 3 mod 4, a^((p+1)/4) is a square root of a. */ fpexp_naive_p256(a, P256p1div4, sqrt, temps); }ajtcl-16.04/src/crypto/aj_crypto_sha2.c000066400000000000000000000216341271074662300200210ustar00rootroot00000000000000/** * @file aj_crypto_sha2.c * * Class for SHA-256 */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE CRYPTO_SHA2 #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgCRYPTO_SHA2 = 0; #endif #if AJ_SHA256_DIGEST_LENGTH != SHA256_DIGEST_LENGTH #error Digest length mismatch #endif #define HMAC_SHA256_DIGEST_LENGTH SHA256_DIGEST_LENGTH #define HMAC_SHA256_BLOCK_LENGTH 64 struct AJ_SHA256_Context { SHA256_CTX internal; }; typedef struct _AJ_HMAC_SHA256_CTX { uint8_t ipad[HMAC_SHA256_BLOCK_LENGTH]; uint8_t opad[HMAC_SHA256_BLOCK_LENGTH]; AJ_SHA256_Context* hashCtx; } AJ_HMAC_SHA256_CTX; static AJ_Status AJ_HMAC_SHA256_Init(AJ_HMAC_SHA256_CTX* ctx, const uint8_t* key, size_t keyLen); static void AJ_HMAC_SHA256_Update(AJ_HMAC_SHA256_CTX* ctx, const uint8_t* data, size_t dataLen); static AJ_Status AJ_HMAC_SHA256_Final(AJ_HMAC_SHA256_CTX* ctx, uint8_t* digest); /** * Initialize the hash context. Calls to this function must be * matched with a call to AJ_SHA256_Final() to ensure that resources * are released. * * @return Pointer to context. NULL if init failed. */ AJ_SHA256_Context* AJ_SHA256_Init(void) { AJ_SHA256_Context* context; context = AJ_Malloc(sizeof(*context)); if (context) { SHA256_Init(&context->internal); } else { AJ_ErrPrintf(("SHA256 context allocation failure\n")); } return context; } /** * Update the digest using the specific bytes * @param context the hash context * @param buf the bytes to digest * @param bufSize the number of bytes to digest */ void AJ_SHA256_Update(AJ_SHA256_Context* context, const uint8_t* buf, size_t bufSize) { SHA256_Update(&context->internal, buf, bufSize); } /** * Retrieve the digest * @param context the hash context * @param digest the buffer to hold the digest. Must be of size AJ_SHA256_DIGEST_LENGTH * @param keepAlive keep the digest process alive for continuing digest * @return AJ_OK if successful, otherwise error. */ static AJ_Status getDigest(AJ_SHA256_Context* context, uint8_t* digest, const uint8_t keepAlive) { AJ_SHA256_Context tempCtx; AJ_SHA256_Context* finalCtx; if (keepAlive) { memcpy(&tempCtx, context, sizeof(AJ_SHA256_Context)); finalCtx = &tempCtx; } else { finalCtx = context; } SHA256_Final(digest, &finalCtx->internal); AJ_MemZeroSecure(finalCtx, sizeof(*finalCtx)); if (!keepAlive) { AJ_Free(context); } return AJ_OK; } /** * Retrieve the digest but keep the hash active for further updates. * @param context the hash context * @param digest the buffer to hold the digest. Must be of size AJ_SHA256_DIGEST_LENGTH * @return AJ_OK if successful, otherwise error. */ AJ_Status AJ_SHA256_GetDigest(AJ_SHA256_Context* context, uint8_t* digest) { return getDigest(context, digest, 1); } /** * Finish the hash calculation and free resources. * @param context the hash context * @param digest - the buffer to hold the digest. * Must be NULL or of size AJ_SHA256_DIGEST_LENGTH. * If the value is NULL, resources are freed but the digest * is not calculated. * @return AJ_OK if successful, otherwise error. */ AJ_Status AJ_SHA256_Final(AJ_SHA256_Context* context, uint8_t* digest) { AJ_Status status = AJ_OK; if (!digest) { AJ_MemZeroSecure(context, sizeof(*context)); AJ_Free(context); } else { status = getDigest(context, digest, 0); } return status; } /** * Initialize the HMAC context * @param ctx the HMAC context * @param key the key * @param keyLen the length of the key * @return * - AJ_OK if successful * - AJ_ERR_INVALID if the length is negative */ static AJ_Status AJ_HMAC_SHA256_Init(AJ_HMAC_SHA256_CTX* ctx, const uint8_t* key, size_t keyLen) { int cnt; memset(ctx->ipad, 0, HMAC_SHA256_BLOCK_LENGTH); memset(ctx->opad, 0, HMAC_SHA256_BLOCK_LENGTH); /* if keyLen > 64, hash it and use it as key */ if (keyLen > HMAC_SHA256_BLOCK_LENGTH) { uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; AJ_Status status; ctx->hashCtx = AJ_SHA256_Init(); if (!ctx->hashCtx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx->hashCtx, key, keyLen); status = AJ_SHA256_Final(ctx->hashCtx, digest); if (status != AJ_OK) { return status; } keyLen = AJ_SHA256_DIGEST_LENGTH; memcpy(ctx->ipad, digest, AJ_SHA256_DIGEST_LENGTH); memcpy(ctx->opad, digest, AJ_SHA256_DIGEST_LENGTH); } else { memcpy(ctx->ipad, key, keyLen); memcpy(ctx->opad, key, keyLen); } /* * the HMAC_SHA256 process * * SHA256(K XOR opad, SHA256(K XOR ipad, msg)) * * K is the key * ipad is filled with 0x36 * opad is filled with 0x5c * msg is the message */ /* * prepare inner hash SHA256(K XOR ipad, msg) * K XOR ipad */ for (cnt = 0; cnt < HMAC_SHA256_BLOCK_LENGTH; cnt++) { ctx->ipad[cnt] ^= 0x36; } ctx->hashCtx = AJ_SHA256_Init(); if (!ctx->hashCtx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx->hashCtx, ctx->ipad, HMAC_SHA256_BLOCK_LENGTH); return AJ_OK; } /** * Update the hash with data * @param ctx the HMAC context * @param data the data * @param dataLen the length of the data * @return * - AJ_OK if successful * - AJ_ERR_INVALID if the length is negative */ static void AJ_HMAC_SHA256_Update(AJ_HMAC_SHA256_CTX* ctx, const uint8_t* data, size_t dataLen) { AJ_SHA256_Update(ctx->hashCtx, data, dataLen); } /** * Retrieve the final digest for the HMAC * @param ctx the HMAC context * @param digest the buffer to hold the digest. Must be of size AJ_SHA256_DIGEST_LENGTH */ static AJ_Status AJ_HMAC_SHA256_Final(AJ_HMAC_SHA256_CTX* ctx, uint8_t* digest) { int cnt; AJ_Status status; /* complete inner hash SHA256(K XOR ipad, msg) */ status = AJ_SHA256_Final(ctx->hashCtx, digest); if (status != AJ_OK) { return status; } /* * perform outer hash SHA256(K XOR opad, SHA256(K XOR ipad, msg)) */ for (cnt = 0; cnt < HMAC_SHA256_BLOCK_LENGTH; cnt++) { ctx->opad[cnt] ^= 0x5c; } ctx->hashCtx = AJ_SHA256_Init(); if (!ctx->hashCtx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx->hashCtx, ctx->opad, HMAC_SHA256_BLOCK_LENGTH); AJ_SHA256_Update(ctx->hashCtx, digest, AJ_SHA256_DIGEST_LENGTH); status = AJ_SHA256_Final(ctx->hashCtx, digest); return status; } AJ_Status AJ_Crypto_PRF_SHA256(const uint8_t** inputs, const uint8_t* lengths, uint32_t count, uint8_t* out, uint32_t outLen) { uint32_t cnt; AJ_HMAC_SHA256_CTX msgHash; uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; uint32_t len = 0; AJ_Status status; if (count < 2) { return AJ_ERR_INVALID; } while (outLen) { /* * Initialize SHA256 in HMAC mode with the secret */ status = AJ_HMAC_SHA256_Init(&msgHash, inputs[0], lengths[0]); if (status != AJ_OK) { return status; } /* * If this is not the first iteration hash in the digest from the previous iteration. */ if (len) { AJ_HMAC_SHA256_Update(&msgHash, digest, sizeof(digest)); } for (cnt = 1; cnt < count; cnt++) { AJ_HMAC_SHA256_Update(&msgHash, inputs[cnt], lengths[cnt]); } AJ_HMAC_SHA256_Final(&msgHash, digest); if (outLen < sizeof(digest)) { len = outLen; } else { len = sizeof(digest); } memcpy(out, digest, len); outLen -= len; out += len; } return AJ_OK; } ajtcl-16.04/src/crypto/aj_sw_crypto.c000066400000000000000000000255021271074662300176130ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #define MAX_SCHEDULE_LEN 48 typedef struct { uint32_t fkey[MAX_SCHEDULE_LEN]; } AES_CTX; static AES_CTX aes_context; #define ROTL8(x) ((((uint32_t)(x)) << 8) | (((uint32_t)(x)) >> 24)) #define ROTL16(x) ((((uint32_t)(x)) << 16) | (((uint32_t)(x)) >> 16)) #define ROTL24(x) ((((uint32_t)(x)) << 24) | (((uint32_t)(x)) >> 8)) #define SHFL8(x) (((uint32_t)(x)) << 8) #define SHFL16(x) (((uint32_t)(x)) << 16) #define SHFL24(x) (((uint32_t)(x)) << 24) #define ROW_0(x) (uint8_t)(x) #define ROW_1(x) (uint8_t)((x) >> 8) #define ROW_2(x) (uint8_t)((x) >> 16) #define ROW_3(x) (uint8_t)((x) >> 24) /* The Rijndael S-box matrix */ static const uint8_t sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; static const uint32_t ftable[256] = { 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c }; static const uint32_t Rconst[12] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8 }; #define round_column(x0, x1, x2, x3) \ ftable[ROW_0(x0)] ^ ROTL8(ftable[ROW_1(x1)]) ^ ROTL16(ftable[ROW_2(x2)]) ^ ROTL24(ftable[ROW_3(x3)]) /* * yn are inputs xn are outputs */ #define round(y0, y1, y2, y3, x0, x1, x2, x3, key) \ y0 = round_column(x0, x1, x2, x3) ^ *key++; \ y1 = round_column(x1, x2, x3, x0) ^ *key++; \ y2 = round_column(x2, x3, x0, x1) ^ *key++; \ y3 = round_column(x3, x0, x1, x2) ^ *key++; #define lastround_column(x0, x1, x2, x3) \ (uint32_t)sbox[ROW_0(x0)] ^ SHFL8(sbox[ROW_1(x1)]) ^ SHFL16(sbox[ROW_2(x2)]) ^ SHFL24(sbox[ROW_3(x3)]) /* * yn are inputs xn are outputs */ #define lastround(y0, y1, y2, y3, x0, x1, x2, x3, key) \ y0 = lastround_column(x0, x1, x2, x3) ^ *key++; \ y1 = lastround_column(x1, x2, x3, x0) ^ *key++; \ y2 = lastround_column(x2, x3, x0, x1) ^ *key++; \ y3 = lastround_column(x3, x0, x1, x2) ^ *key++; static void Pack32(uint32_t* u32, const uint8_t* u8) { #if HOST_IS_LITTLE_ENDIAN memcpy(u32, u8, 16); #else int i; for (i = 0; i < 4; ++i, ++u32, u8 += 4) { *u32 = (uint32_t)u8[0] | (u8[1] << 8) | (u8[2] << 16) | (u8[3] << 24); } #endif } static void Unpack32(uint8_t* u8, const uint32_t* u32) { #if HOST_IS_LITTLE_ENDIAN memcpy(u8, u32, 16); #else int i; for (i = 0; i < 4; ++i, ++u32) { *u8++ = (uint8_t)(*u32); *u8++ = (uint8_t)(*u32 >> 8); *u8++ = (uint8_t)(*u32 >> 16); *u8++ = (uint8_t)(*u32 >> 24); } #endif } static uint32_t SubBytes(uint32_t a) { return (uint32_t)sbox[(uint8_t)(a)] | (sbox[(uint8_t)(a >> 8)] << 8) | (sbox[(uint8_t)(a >> 16)] << 16) | (sbox[(uint8_t)(a >> 24)] << 24); } #define ROUNDS 10 static void EncryptRounds(uint32_t* out, uint32_t* in, uint32_t* key) { int i; uint32_t x0 = in[0]; uint32_t x1 = in[1]; uint32_t x2 = in[2]; uint32_t x3 = in[3]; uint32_t y0; uint32_t y1; uint32_t y2; uint32_t y3; for (i = 0; i < 4; i++) { round(y0, y1, y2, y3, x0, x1, x2, x3, key); round(x0, x1, x2, x3, y0, y1, y2, y3, key); } round(y0, y1, y2, y3, x0, x1, x2, x3, key); lastround(x0, x1, x2, x3, y0, y1, y2, y3, key); out[0] = x0; out[1] = x1; out[2] = x2; out[3] = x3; } void AJ_AES_Enable(const uint8_t* key) { int i; uint32_t* fkey = aes_context.fkey; Pack32(fkey, key); for (i = 0; i <= ROUNDS; ++i, fkey += 4) { fkey[4] = fkey[0] ^ SubBytes(ROTL24(fkey[3])) ^ Rconst[i]; fkey[5] = fkey[1] ^ fkey[4]; fkey[6] = fkey[2] ^ fkey[5]; fkey[7] = fkey[3] ^ fkey[6]; } } void AJ_AES_Disable(void) { AJ_MemZeroSecure(&aes_context, sizeof(aes_context)); } void AJ_AES_CTR_128(const uint8_t* key, const uint8_t* in, uint8_t* out, uint32_t len, uint8_t* ctr) { uint32_t counter[4]; Pack32(counter, ctr); while (len) { uint32_t tmp[4]; uint32_t i; uint32_t n = min(len, 16); uint8_t* p = (uint8_t*)tmp; for (i = 0; i < 4; ++i) { tmp[i] = counter[i] ^ aes_context.fkey[i]; } EncryptRounds(tmp, tmp, &aes_context.fkey[4]); len -= n; while (n--) { *out++ = *p++ ^ *in++; } AJ_MemZeroSecure((uint8_t*)tmp, sizeof(tmp)); /* * The counter field is big-endian */ #if HOST_IS_LITTLE_ENDIAN counter[3] = AJ_ByteSwap32(1 + AJ_ByteSwap32(counter[3])); #else counter[3] += 1; #endif } Unpack32(ctr, counter); } void AJ_AES_CBC_128_ENCRYPT(const uint8_t* key, const uint8_t* in, uint8_t* out, uint32_t len, uint8_t* iv) { uint32_t xorbuf[4]; uint32_t ivt[4]; AJ_ASSERT((len % 16) == 0); Pack32(ivt, iv); while (len) { int i; Pack32(xorbuf, in); for (i = 0; i < 4; ++i) { xorbuf[i] ^= ivt[i] ^ aes_context.fkey[i]; } EncryptRounds(ivt, xorbuf, &aes_context.fkey[4]); AJ_MemZeroSecure((uint8_t*)xorbuf, sizeof(xorbuf)); Unpack32(out, ivt); out += 16; in += 16; len -= 16; } Unpack32(iv, ivt); } void AJ_AES_ECB_128_ENCRYPT(const uint8_t* key, const uint8_t* in, uint8_t* out) { uint32_t in32[4]; uint32_t out32[4]; Pack32(in32, in); EncryptRounds(out32, in32, &aes_context.fkey[4]); Unpack32(out, out32); } ajtcl-16.04/src/external/000077500000000000000000000000001271074662300152425ustar00rootroot00000000000000ajtcl-16.04/src/external/sha2/000077500000000000000000000000001271074662300160775ustar00rootroot00000000000000ajtcl-16.04/src/external/sha2/sha2.c000066400000000000000000001012051271074662300170770ustar00rootroot00000000000000/* * FILE: sha2.c * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ * * Copyright (c) 2000-2001, Aaron D. Gifford * 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 copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) 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. * */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include /* memcpy()/memset() or bcopy()/bzero() */ #include /* assert() */ #include "sha2.h" /* * ASSERT NOTE: * Some sanity checking code is included using assert(). On my FreeBSD * system, this additional code can be removed by compiling with NDEBUG * defined. Check your own systems manpage on assert() to see how to * compile WITHOUT the sanity checking code on your system. * * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ /*** SHA-256/384/512 Machine Architecture Definitions *****************/ /* * BYTE_ORDER NOTE: * * Please make sure that your system defines BYTE_ORDER. If your * architecture is little-endian, make sure it also defines * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are * equivilent. * * If your system does not define the above, then you can do so by * hand like this: * * #define LITTLE_ENDIAN 1234 * #define BIG_ENDIAN 4321 * * And for little-endian machines, add: * * #define BYTE_ORDER LITTLE_ENDIAN * * Or for big-endian machines: * * #define BYTE_ORDER BIG_ENDIAN * * The FreeBSD machine this was written on defines BYTE_ORDER * appropriately by including (which in turn includes * where the appropriate definitions are actually * made). */ #if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) #define LITTLE_ENDIAN 1234 #define BIG_ENDIAN 4321 #if HOST_IS_LITTLE_ENDIAN #define BYTE_ORDER LITTLE_ENDIAN #else #define BYTE_ORDER BIG_ENDIAN #endif #endif /* * Define the followingsha2_* types to types of the correct length on * the native archtecture. Most BSD systems and Linux define u_intXX_t * types. Machines with very recent ANSI C headers, can use the * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H * during compile or in the sha.h header file. * * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t * will need to define these three typedefs below (and the appropriate * ones in sha.h too) by hand according to their system architecture. * * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. */ #ifdef SHA2_USE_INTTYPES_H typedef uint8_t sha2_byte; /* Exactly 1 byte */ typedef uint32_t sha2_word32; /* Exactly 4 bytes */ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ #else /* SHA2_USE_INTTYPES_H */ typedef u_int8_t sha2_byte; /* Exactly 1 byte */ typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ #endif /* SHA2_USE_INTTYPES_H */ /*** SHA-256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) /*** ENDIAN REVERSAL MACROS *******************************************/ #if BYTE_ORDER == LITTLE_ENDIAN #if !defined(ALIGNED_ACCESS_REQUIRED) #define REVERSE32(w,x) { \ sha2_word32 tmp = (w); \ tmp = (tmp >> 16) | (tmp << 16); \ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ } #else #define REVERSE32(w,x) { \ sha2_byte *b = (sha2_byte*) &w; \ sha2_word32 tmp = 0; \ tmp = ((sha2_word32)*b++); \ tmp = (tmp << 8) | ((sha2_word32)*b++); \ tmp = (tmp << 8) | ((sha2_word32)*b++); \ tmp = (tmp << 8) | ((sha2_word32)*b++); \ (x) = tmp; \ } #endif /* ALIGNED_ACCESS_REQUIRED */ #define REVERSE64(w,x) { \ sha2_word64 tmp = (w); \ tmp = (tmp >> 32) | (tmp << 32); \ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ ((tmp & 0x0000ffff0000ffffULL) << 16); \ } #endif /* BYTE_ORDER == LITTLE_ENDIAN */ /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) { \ (w)[0] += (sha2_word64)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } /* * Macros for copying blocks of memory and for zeroing out ranges * of memory. Using these macros makes it easy to switch from * using memset()/memcpy() and using bzero()/bcopy(). * * Please define either SHA2_USE_MEMSET_MEMCPY or define * SHA2_USE_BZERO_BCOPY depending on which function set you * choose to use: */ #if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) /* Default to memset()/memcpy() if no option is specified */ #define SHA2_USE_MEMSET_MEMCPY 1 #endif #if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) /* Abort with an error if BOTH options are defined */ #error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! #endif #ifdef SHA2_USE_MEMSET_MEMCPY #define MEMSET_BZERO(p,l) memset((p), 0, (l)) #define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) #endif #ifdef SHA2_USE_BZERO_BCOPY #define MEMSET_BZERO(p,l) bzero((p), (l)) #define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) #endif /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** INTERNAL FUNCTION PROTOTYPES *************************************/ /* NOTE: These should not be accessed directly from outside this * library -- they are intended for private internal visibility/use * only. */ void SHA512_Last(SHA512_CTX*); void SHA256_Transform(SHA256_CTX*, const sha2_word32*); void SHA512_Transform(SHA512_CTX*, const sha2_word64*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ const static sha2_word32 K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ const static sha2_word32 sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; /* Hash constant words K for SHA-384 and SHA-512: */ const static sha2_word64 K512[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; /* Initial hash value H for SHA-384 */ const static sha2_word64 sha384_initial_hash_value[8] = { 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL }; /* Initial hash value H for SHA-512 */ const static sha2_word64 sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL }; /* * Constant used by SHA256/384/512_End() functions for converting the * digest to a readable hexadecimal character string: */ static const char *sha2_hex_digits = "0123456789abcdef"; /*** SHA-256: *********************************************************/ void SHA256_Init(SHA256_CTX* context) { if (context == (SHA256_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); context->bitcount = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #if BYTE_ORDER == LITTLE_ENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE32(*data++, W256[j]); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + (W256[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND256(a,b,c,d,e,f,g,h) \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, *W256; int j; W256 = (sha2_word32*)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds to 64: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, T2, *W256; int j; W256 = (sha2_word32*)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #if BYTE_ORDER == LITTLE_ENDIAN /* Copy data while converting to host byte order */ REVERSE32(*data++,W256[j]); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; #else /* BYTE_ORDER == LITTLE_ENDIAN */ /* Apply the SHA-256 compression function to update a..h with copy */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); #endif /* BYTE_ORDER == LITTLE_ENDIAN */ T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); context->bitcount += freespace << 3; len -= freespace; data += freespace; SHA256_Transform(context, (sha2_word32*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); context->bitcount += len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA256_Transform(context, (sha2_word32*)data); context->bitcount += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); context->bitcount += len << 3; } /* Clean up: */ usedspace = freespace = 0; } void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { sha2_word32 *d = (sha2_word32*)digest; unsigned int usedspace; /* Sanity check: */ assert(context != (SHA256_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; #if BYTE_ORDER == LITTLE_ENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount,context->bitcount); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA256_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA256_Transform(context, (sha2_word32*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Set the bit count: */ *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; /* Final transform: */ SHA256_Transform(context, (sha2_word32*)context->buffer); #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE32(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); #endif } /* Clean up state data: */ MEMSET_BZERO(context, sizeof(SHA256_CTX)); usedspace = 0; } char *SHA256_End(SHA256_CTX* context, char buffer[]) { sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; int i; /* Sanity check: */ assert(context != (SHA256_CTX*)0); if (buffer != (char*)0) { SHA256_Final(digest, context); for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; *buffer++ = sha2_hex_digits[*d & 0x0f]; d++; } *buffer = (char)0; } else { MEMSET_BZERO(context, sizeof(SHA256_CTX)); } MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); return buffer; } char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { SHA256_CTX context; SHA256_Init(&context); SHA256_Update(&context, data, len); return SHA256_End(&context, digest); } /*** SHA-512: *********************************************************/ void SHA512_Init(SHA512_CTX* context) { if (context == (SHA512_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #if BYTE_ORDER == LITTLE_ENDIAN #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE64(*data++, W512[j]); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + W512[j]; \ (d) += T1, \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ j++ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + (W512[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND512(a,b,c,d,e,f,g,h) \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ REVERSE64(*data++, W512[j]); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; #else /* BYTE_ORDER == LITTLE_ENDIAN */ /* Apply the SHA-512 compression function to update a..h with copy */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); #endif /* BYTE_ORDER == LITTLE_ENDIAN */ T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; SHA512_Transform(context, (sha2_word64*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA512_Transform(context, (sha2_word64*)data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } void SHA512_Last(SHA512_CTX* context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; #if BYTE_ORDER == LITTLE_ENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount[0],context->bitcount[0]); REVERSE64(context->bitcount[1],context->bitcount[1]); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA512_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA512_Transform(context, (sha2_word64*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits): */ *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; /* Final transform: */ SHA512_Transform(context, (sha2_word64*)context->buffer); } void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != (SHA512_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { SHA512_Last(context); /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); #endif } /* Zero out state data */ MEMSET_BZERO(context, sizeof(SHA512_CTX)); } char *SHA512_End(SHA512_CTX* context, char buffer[]) { sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; int i; /* Sanity check: */ assert(context != (SHA512_CTX*)0); if (buffer != (char*)0) { SHA512_Final(digest, context); for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; *buffer++ = sha2_hex_digits[*d & 0x0f]; d++; } *buffer = (char)0; } else { MEMSET_BZERO(context, sizeof(SHA512_CTX)); } MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); return buffer; } char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { SHA512_CTX context; SHA512_Init(&context); SHA512_Update(&context, data, len); return SHA512_End(&context, digest); } /*** SHA-384: *********************************************************/ void SHA384_Init(SHA384_CTX* context) { if (context == (SHA384_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { SHA512_Update((SHA512_CTX*)context, data, len); } void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != (SHA384_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { SHA512_Last((SHA512_CTX*)context); /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 6; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); #endif } /* Zero out state data */ MEMSET_BZERO(context, sizeof(SHA384_CTX)); } char *SHA384_End(SHA384_CTX* context, char buffer[]) { sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; int i; /* Sanity check: */ assert(context != (SHA384_CTX*)0); if (buffer != (char*)0) { SHA384_Final(digest, context); for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; *buffer++ = sha2_hex_digits[*d & 0x0f]; d++; } *buffer = (char)0; } else { MEMSET_BZERO(context, sizeof(SHA384_CTX)); } MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); return buffer; } char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { SHA384_CTX context; SHA384_Init(&context); SHA384_Update(&context, data, len); return SHA384_End(&context, digest); } ajtcl-16.04/src/external/sha2/sha2.h000066400000000000000000000137541271074662300171170ustar00rootroot00000000000000/* * FILE: sha2.h * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ * * Copyright (c) 2000-2001, Aaron D. Gifford * 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 copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) 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. * * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ */ #ifndef __SHA2_H__ #define __SHA2_H__ #define SHA2_USE_INTTYPES_H #include /*** SHA-256/384/512 Various Length Definitions ***********************/ #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #define SHA384_BLOCK_LENGTH 128 #define SHA384_DIGEST_LENGTH 48 #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) /*** SHA-256/384/512 Context Structures *******************************/ /* NOTE: If your architecture does not define either u_intXX_t types or * uintXX_t (from inttypes.h), you may need to define things by hand * for your system: */ #if 0 typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ #endif /* * Most BSD systems already define u_intXX_t types, as does Linux. * Some systems, however, like Compaq's Tru64 Unix instead can use * uintXX_t types defined by very recent ANSI C standards and included * in the file: * * #include * * If you choose to use then please define: * * #define SHA2_USE_INTTYPES_H * * Or on the command line during compile: * * cc -DSHA2_USE_INTTYPES_H ... */ #ifdef SHA2_USE_INTTYPES_H typedef struct _SHA256_CTX { uint32_t state[8]; uint64_t bitcount; uint8_t buffer[SHA256_BLOCK_LENGTH]; } SHA256_CTX; typedef struct _SHA512_CTX { uint64_t state[8]; uint64_t bitcount[2]; uint8_t buffer[SHA512_BLOCK_LENGTH]; } SHA512_CTX; #else /* SHA2_USE_INTTYPES_H */ typedef struct _SHA256_CTX { u_int32_t state[8]; u_int64_t bitcount; u_int8_t buffer[SHA256_BLOCK_LENGTH]; } SHA256_CTX; typedef struct _SHA512_CTX { u_int64_t state[8]; u_int64_t bitcount[2]; u_int8_t buffer[SHA512_BLOCK_LENGTH]; } SHA512_CTX; #endif /* SHA2_USE_INTTYPES_H */ typedef SHA512_CTX SHA384_CTX; /*** SHA-256/384/512 Function Prototypes ******************************/ #ifndef NOPROTO #ifdef SHA2_USE_INTTYPES_H void SHA256_Init(SHA256_CTX *); void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); void SHA384_Init(SHA384_CTX*); void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t); void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); char* SHA384_Data(const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); void SHA512_Init(SHA512_CTX*); void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); #else /* SHA2_USE_INTTYPES_H */ void SHA256_Init(SHA256_CTX *); void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t); void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); void SHA384_Init(SHA384_CTX*); void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t); void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); void SHA512_Init(SHA512_CTX*); void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t); void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); #endif /* SHA2_USE_INTTYPES_H */ #else /* NOPROTO */ void SHA256_Init(); void SHA256_Update(); void SHA256_Final(); char* SHA256_End(); char* SHA256_Data(); void SHA384_Init(); void SHA384_Update(); void SHA384_Final(); char* SHA384_End(); char* SHA384_Data(); void SHA512_Init(); void SHA512_Update(); void SHA512_Final(); char* SHA512_End(); char* SHA512_Data(); #endif /* NOPROTO */ #endif /* __SHA2_H__ */ ajtcl-16.04/src/freertos/000077500000000000000000000000001271074662300152515ustar00rootroot00000000000000ajtcl-16.04/src/freertos/aj_rtos.h000066400000000000000000000147111271074662300170670ustar00rootroot00000000000000/** * @file RTOS abstraction layer contains declarations for all the needed * RTOS primitives that should be implemented for a specific RTOS. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_RTOS_H_ #define AJ_RTOS_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /* * These are opaque types that hold RTOS specific types; */ struct AJ_Queue; struct AJ_TaskHandle; struct AJ_Mutex; uint32_t AJ_MsToTicks(uint32_t ms); /** * create a queue * * @param name Name of the queue to create * * @return pointer to an AJ_Queue object */ struct AJ_Queue* AJ_QueueCreate(const char* name); /** * delete a queue * * @param q pointer to the AJ_Queue to delete, deletes the opaque type as well * */ void AJ_QueueDelete(struct AJ_Queue* q); /** * Peek at an item in a queue * * @param q pointer to the AJ_Queue structure * @param data location for the item in the queue to go * * @return AJ_OK if an item was in the queue * AJ_ERR_NULL if the queue was empty */ AJ_Status AJ_QueuePeek(struct AJ_Queue* q, void* data); /** * Reset or flush a queue * * @param q The AJ_Queue structure you want to empty * * @return This will always return AJ_OK */ AJ_Status AJ_QueueReset(struct AJ_Queue* q); /** * push an item on to a queue, wait at most until timeout * * @param q pointer to the AJ_Queue to push * @param data data to push onto the queue * @param timeout amount of time in milliseconds to wait to push an item * * @return AJ_OK item was pushed * AJ_ERR_RESOURCES item couldn't be pushed within timeout */ AJ_Status AJ_QueuePush(struct AJ_Queue* q, void* data, uint32_t timeout); /** * Push an item to the front of a queue from an ISR * note: This function pushes to the front of the queue (used for immediate signaling) * * @param q pointer to the queue * @param data pointer to the data you adding to the queue */ AJ_Status AJ_QueuePushFromISR(struct AJ_Queue* q, void* data); /** * peek at an item in the queue from an ISR * * @param q pointer to the queue * @param data location for the item in the queue to go * * @return AJ_OK if the peek was successful * AJ_ERR_NULL if there was no item to peek at */ AJ_Status AJ_QueuePeekFromISR(struct AJ_Queue* q, void* data); /** * pull an item from a queue, wait at most until timeout * * @param q pointer to the AJ_Queue to pull * @param data data to pull from the queue * @param timeout amount of time in milliseconds to wait to pull an item * * @return AJ_OK item was pulled * AJ_ERR_RESOURCES item couldn't be pulled before timeout */ AJ_Status AJ_QueuePull(struct AJ_Queue* q, void* data, uint32_t timeout); /* * Create a mutex */ struct AJ_Mutex* AJ_MutexCreate(void); /* * Try and take a lock on a mutex * * @param m Pointer to the mutex created by AJ_MutexCreate() * @param timeout How long to block if the mutex is already locked */ AJ_Status AJ_MutexLock(struct AJ_Mutex* m, uint32_t timeout); /* * Unlock a mutex * * @param m Mutex pointer */ AJ_Status AJ_MutexUnlock(struct AJ_Mutex* m); /* * Delete a muted * * @param m Mutex to delete */ void AJ_MutexDelete(struct AJ_Mutex* m); /* * Create a task to be started * * @param task Function pointer to where you want the task to start * @param name Name for the task * @param stackDepth How big you want the stack to be * @param parameters Any parameters to pass into the task when its started * @param priority Priority of the task * @param handle A context for referencing the task */ AJ_Status AJ_CreateTask(void (*task)(void*), const signed char* const name, unsigned short stackDepth, void* parameters, uint8_t priority, struct AJ_TaskHandle** handle); /* * Remove a task from running * * @param handle The handle that was set by AJ_CreateTask() */ AJ_Status AJ_DestroyTask(struct AJ_TaskHandle* handle); /* * suspend a task from running * * @param handle The handle that was set by AJ_CreateTask() */ AJ_Status AJ_SuspendTask(struct AJ_TaskHandle* handle); /* * resume a suspended task, possibly from an ISR * * @param handle The handle that was set by AJ_CreateTask() * @param inISR is this being called from an interrupt service routine? */ AJ_Status AJ_ResumeTask(struct AJ_TaskHandle* handle, uint8_t inISR); /* * Start the RTOS specific scheduler */ void AJ_StartScheduler(void); /** * force the current task to yield its timeslice */ void AJ_YieldCurrentTask(void); /** * Disable interrupts for a time */ void AJ_EnterCriticalRegion(void); /** * exit the critical region and enable interrupts if needed */ void AJ_LeaveCriticalRegion(void); /** * Do any platform specific initialization * - Clock init, serial debug, SPI etc. */ void AJ_PlatformInit(void); /** * Pre-AllJoyn entry function. This function does all the network initialization * that AllJoyn needs to run. Before calling AJ_Main() a network needs to be setup * which entails connecting to an access point (or softAP) and getting an IP address */ void AllJoyn_Start(unsigned long arg); #ifdef __cplusplus } #endif #endif /* RTOS_H_ */ ajtcl-16.04/src/freertos/aj_target_rtos.c000066400000000000000000000265061271074662300204350ustar00rootroot00000000000000/** * @file RTOS specific implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * Any time in this file there is a comment including FreeRTOS or calling a * FreeRTOS API, note that the API associated with it may be subject to the * FreeRTOS GPL with exception license copied here: * http://www.freertos.org/license.txt : * The FreeRTOS.org source code is licensed by the modified GNU General Public * License (GPL) text provided below. The FreeRTOS download also includes * demo application source code, some of which is provided by third parties * AND IS LICENSED SEPARATELY FROM FREERTOS.ORG. * For the avoidance of any doubt refer to the comment included at the top * of each source and header file for license and copyright information. ******************************************************************************/ #define AJ_MODULE TARGET_RTOS #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_RTOS = 0; #endif /* * Temporary queue and item size * - Still need to determine how big the queue should be * - What type of structure we are sending -> to find the size */ #define QUEUE_SIZE 5 #define ITEM_SIZE sizeof(void*) uint32_t AJ_MsToTicks(uint32_t ms); /* * The opaque AJ types are now declared with FreeRTOS types */ struct AJ_Queue { xQueueHandle q; }; struct AJ_Mutex { xSemaphoreHandle m; }; struct AJ_TaskHandle { xTaskHandle t; }; struct AJ_Queue* AJ_QueueCreate(const char* name) { struct AJ_Queue* p = (struct AJ_Queue*)AJ_Malloc(sizeof(struct AJ_Queue)); if (p) { p->q = xQueueCreate(QUEUE_SIZE, ITEM_SIZE); vQueueAddToRegistry(p->q, (signed char*)name); } return p; } void AJ_QueueDelete(struct AJ_Queue* q) { if (q && q->q) { vQueueUnregisterQueue(q->q); vQueueDelete(q->q); AJ_Free(q); } } AJ_Status AJ_QueuePeek(struct AJ_Queue* q, void* data) { uint8_t ret; if (q && q->q) { ret = xQueuePeek(q->q, data, 0); if (ret == pdTRUE) { return AJ_OK; } } return AJ_ERR_NULL; } AJ_Status AJ_QueueReset(struct AJ_Queue* q) { if (q && q->q) { xQueueReset(q->q); } return AJ_OK; } AJ_Status AJ_QueuePush(struct AJ_Queue* q, void* data, uint32_t timeout) { uint8_t ret; if (q && q->q && data) { ret = xQueueSend(q->q, data, AJ_MsToTicks(timeout)); if (ret == errQUEUE_FULL) { return AJ_ERR_RESOURCES; } return AJ_OK; } return AJ_ERR_NULL; } AJ_Status AJ_QueuePushFromISR(struct AJ_Queue* q, void* data) { uint8_t hasWoken; uint8_t ret; if (q && q->q && data) { ret = xQueueSendToFrontFromISR(q->q, data, (long int*)&hasWoken); } return AJ_OK; } AJ_Status AJ_QueuePeekFromISR(struct AJ_Queue* q, void* data) { uint8_t ret; if (q && q->q) { ret = xQueuePeekFromISR(q->q, data); if (ret) { return AJ_OK; } } return AJ_ERR_NULL; } AJ_Status AJ_QueuePull(struct AJ_Queue* q, void* data, uint32_t timeout) { uint8_t ret; if (q && q->q) { ret = xQueueReceive(q->q, data, AJ_MsToTicks(timeout)); if (ret) { return AJ_OK; } return AJ_ERR_RESOURCES; } return AJ_ERR_NULL; } uint32_t AJ_MsToTicks(uint32_t ms) { return (ms); } /** * Create a mutex. AllJoyn stores the mutex as null pointer * in the AJ_Mutex structure so if changing to another RTOS * this pointer can easily point to a new type of structure */ struct AJ_Mutex* AJ_MutexCreate(void) { struct AJ_Mutex* mutex = (struct AJ_Mutex*)AJ_Malloc(sizeof(struct AJ_Mutex)); if (mutex) { mutex->m = xSemaphoreCreateBinary(); xSemaphoreGive(mutex->m); } return mutex; } /** * Locks a mutex * @param m The mutex your locking * @param timeout How long to wait if the mutex is locked (ms) */ AJ_Status AJ_MutexLock(struct AJ_Mutex* m, uint32_t timeout) { uint8_t ret; if (m->m) { ret = xSemaphoreTake(m->m, AJ_MsToTicks(timeout)); if (ret) { return AJ_OK; } return AJ_ERR_TIMEOUT; } return AJ_ERR_UNKNOWN; } AJ_Status AJ_MutexUnlock(struct AJ_Mutex* m) { uint8_t ret; if (m->m) { ret = xSemaphoreGive(m->m); if (ret) { return AJ_OK; } /* The semaphore was not obtained correctly */ return AJ_ERR_DISALLOWED; } return AJ_ERR_NULL; } void AJ_MutexDelete(struct AJ_Mutex* m) { vSemaphoreDelete(m->m); } /** * @param task the function you want to execute as this task * @param name name of the task * @param stackDepth size of the stack for this task * @param parameters any parameters you want to pass in */ AJ_Status AJ_CreateTask(void (*task)(void*), const signed char* const name, unsigned short stackDepth, void* parameters, uint8_t priority, struct AJ_TaskHandle** handle) { int status; if (handle) { struct AJ_TaskHandle* th = (struct AJ_TaskHandle*)AJ_Malloc(sizeof(struct AJ_TaskHandle)); if (th) { status = xTaskCreate(task, name, stackDepth, parameters, priority, &th->t); *handle = th; } else { return AJ_ERR_RESOURCES; } } else { status = xTaskCreate(task, name, stackDepth, parameters, priority, NULL); } if (status == pdPASS) { return AJ_OK; } else { return AJ_ERR_UNKNOWN; } } AJ_Status AJ_DestroyTask(struct AJ_TaskHandle* handle) { vTaskDelete(handle->t); return AJ_OK; } AJ_Status AJ_SuspendTask(struct AJ_TaskHandle* handle) { vTaskSuspend(handle); return AJ_OK; } AJ_Status AJ_ResumeTask(struct AJ_TaskHandle* handle, uint8_t inISR) { if (inISR) { xTaskResumeFromISR(handle->t); } else { vTaskResume(handle->t); } return AJ_OK; } void AJ_StartScheduler(void) { vTaskStartScheduler(); } void AJ_YieldCurrentTask(void) { taskYIELD(); } void AJ_EnterCriticalRegion(void) { taskENTER_CRITICAL(); } void AJ_LeaveCriticalRegion(void) { taskEXIT_CRITICAL(); } void AJ_PlatformInit(void) { _AJ_PlatformInit(); } /* AJ_Status AJ_SuspendWifi(uint32_t msec) { return AJ_OK; } */ void AJ_Sleep(uint32_t time) { /* This function does not work until AJ_StartScheduler is called */ const portTickType delay = (time / portTICK_RATE_MS); vTaskDelay(delay); } uint32_t AJ_GetElapsedTime(AJ_Time* timer, uint8_t cumulative) { uint32_t elapsed; uint32_t now_msec = xTaskGetTickCount() / portTICK_RATE_MS; uint32_t now_sec = now_msec / 1000; //Get the seconds now_msec = now_msec - (now_sec * 1000); //Get the additional msec's elapsed = (1000 * (now_sec - timer->seconds)) + (now_msec - timer->milliseconds); if (!cumulative) { //Timer has not been initialized timer->seconds = now_sec; timer->milliseconds = now_msec; } return elapsed; } void AJ_InitTimer(AJ_Time* timer) { uint32_t now_msec = xTaskGetTickCount() / portTICK_RATE_MS; uint32_t now_sec = now_msec / 1000; //Get the seconds now_msec = now_msec - (now_sec * 1000); //Get the additional msec's timer->seconds = now_sec; timer->milliseconds = now_msec; } int32_t AJ_GetTimeDifference(AJ_Time* timerA, AJ_Time* timerB) { int32_t diff; diff = (1000 * (timerA->seconds - timerB->seconds)) + (timerA->milliseconds - timerB->milliseconds); return diff; } void AJ_TimeAddOffset(AJ_Time* timerA, uint32_t msec) { uint32_t msecNew; if (msec == -1) { timerA->seconds = -1; timerA->milliseconds = -1; } else { msecNew = (timerA->milliseconds + msec); timerA->seconds = timerA->seconds + (msecNew / 1000); timerA->milliseconds = msecNew % 1000; } } int8_t AJ_CompareTime(AJ_Time timerA, AJ_Time timerB) { if (timerA.seconds == timerB.seconds) { if (timerA.milliseconds == timerB.milliseconds) { return 0; } else if (timerA.milliseconds > timerB.milliseconds) { return 1; } else { return -1; } } else if (timerA.seconds > timerB.seconds) { return 1; } else { return -1; } } uint64_t AJ_DecodeTime(char* der, const char* fmt) { return 0; } void* AJ_Malloc(size_t sz) { return pvPortMalloc(sz); } void AJ_Free(void* mem) { if (mem) { vPortFree(mem); } } void AJ_MemZeroSecure(void* s, size_t n) { volatile unsigned char* p = s; while (n--) *p++ = '\0'; return; } void* AJ_Realloc(void* ptr, size_t size) { void* ptrNew; #ifdef AJ_HEAP4 if (!ptr) { return AJ_Malloc(size); } ptrNew = AJ_Malloc(size); if (ptrNew) { memcpy(ptrNew, ptr, size); AJ_Free(ptr); } #else vTaskSuspendAll(); ptrNew = realloc(ptr, size); xTaskResumeAll(); #endif return ptrNew; } void AJ_RandBytes(uint8_t* random, uint32_t len) { AJ_SeedRNG(); while (len) { *random = AJ_SeedRNG() & 0xFF; len -= 1; random += 1; } } uint16_t AJ_EphemeralPort(void) { AJ_SeedRNG(); uint16_t random = AJ_SeedRNG() & 0xFFFF; return 49152 + random % (65535 - 49152); } /* * This function is called when a malloc failure is detected */ void vApplicationMallocFailedHook(void) { AJ_ASSERT(FALSE); while (1) { } ; } /* * This function is called when a stack overflow is detected */ void vApplicationStackOverflowHook(xTaskHandle pxTask, signed char*pcTaskName) { AJ_ASSERT(FALSE); while (1) { } ; } #ifndef NDEBUG /* * This is not intended, nor required to be particularly efficient. If you want * efficiency, turn of debugging. */ int _AJ_DbgEnabled(const char* module) { char buffer[128]; char* env; strcpy(buffer, "ER_DEBUG_ALL"); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } strcpy(buffer, "ER_DEBUG_"); strcat(buffer, module); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } return FALSE; } #endif ajtcl-16.04/src/freertos/aj_target_rtos.h000066400000000000000000000067761271074662300204510ustar00rootroot00000000000000/** * @file RTOS specific header file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * Any time in this file there is a comment including FreeRTOS or calling a * FreeRTOS API, note that the API associated with it may be subject to the * FreeRTOS GPL with exception license copied here: * http://www.freertos.org/license.txt : * The FreeRTOS.org source code is licensed by the modified GNU General Public * License (GPL) text provided below. The FreeRTOS download also includes * demo application source code, some of which is provided by third parties * AND IS LICENSED SEPARATELY FROM FREERTOS.ORG. * For the avoidance of any doubt refer to the comment included at the top * of each source and header file for license and copyright information. ******************************************************************************/ #ifndef AJ_TARGET_RTOS_H_ #define AJ_TARGET_RTOS_H_ #include #include #include #include #include #include "aj_rtos.h" #ifdef __cplusplus extern "C" { #endif typedef struct _AJ_FW_Version { uint32_t host_ver; uint32_t target_ver; uint32_t wlan_ver; uint32_t abi_ver; } AJ_FW_Version; /** * This function is called when freeRTOS fails to allocate */ void vApplicationMallocFailedHook(void); /** * This function is called when a tasks stack overflows * * @param pxTask Task handle of the task thats stack overflowed * @param pcTaskName Name of the task */ void vApplicationStackOverflowHook(xTaskHandle pxTask, signed char*pcTaskName); /** * Enter a critical region of code. This function will disable all interrupts * until AJ_LeaveCriticalRegion() is called */ void AJ_EnterCriticalRegion(void); /** * Leave a critical region of code. This function re-enables interrupts after * calling AJ_EnterCriticalRegion() */ void AJ_LeaveCriticalRegion(void); /** * Generate an ephemeral (random) port. * * @return A random port number */ uint16_t AJ_EphemeralPort(void); /** * Initialize the platform. This function contains initialization such * as GPIO, Clock, UART etc. */ void AJ_PlatformInit(void); /** * Resume a task that has been previously started * * @param handle The task handle (returned from AJ_CreateTask()) * @param inISR If the calling function is in an interrupt routine * * @return AJ_OK if the task was resumed sucessfully */ AJ_Status AJ_ResumeTask(struct AJ_TaskHandle* handle, uint8_t inISR); #ifdef __cplusplus } #endif #endif /* AJ_TARGET_RTOS_H_ */ ajtcl-16.04/src/malloc/000077500000000000000000000000001271074662300146675ustar00rootroot00000000000000ajtcl-16.04/src/malloc/aj_malloc.c000066400000000000000000000171371271074662300167650ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE MALLOC #include #include #include #include #include "aj_malloc.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgMALLOC = 0; #endif typedef struct { void* endOfPool; /* Address of end of this pool */ void* freeList; /* Free list for this pool */ #ifndef NDEBUG uint16_t use; /* Number of entries in use */ uint16_t hwm; /* High-water mark */ uint16_t max; /* Max allocation from this pool */ #endif } Pool; typedef struct _MemBlock { struct _MemBlock* next; uint8_t mem[sizeof(void*)]; } MemBlock; static const AJ_HeapConfig* heapConfig; static Pool* heapPools; static uint8_t numPools; static uint8_t* heapStart; size_t AJ_PoolRequired(const AJ_HeapConfig* poolConfig, uint8_t poolCnt) { size_t heapSz = sizeof(Pool) * poolCnt; uint8_t i; for (i = 0; i < poolCnt; ++i) { size_t sz = poolConfig[i].size; sz += AJ_HEAP_POOL_ROUNDING - (sz & (AJ_HEAP_POOL_ROUNDING - 1)); heapSz += sz * poolConfig[i].entries; } return heapSz; } void AJ_PoolTerminate(void* heap) { heapPools = NULL; } AJ_Status AJ_PoolInit(void* heap, size_t heapSz, const AJ_HeapConfig* poolConfig, uint8_t num) { uint8_t i; uint16_t n; uint8_t* heapEnd = (uint8_t*)heap + sizeof(Pool) * num; Pool* p = (Pool*)heap; heapPools = p; heapStart = heapEnd; heapConfig = poolConfig; numPools = num; /* * Clear the heap pool info block */ memset(heapPools, 0, heapStart - (uint8_t*)heap); for (i = 0; i < numPools; ++i, ++p) { size_t sz = poolConfig[i].size; sz += AJ_HEAP_POOL_ROUNDING - (sz & (AJ_HEAP_POOL_ROUNDING - 1)); /* * Add all blocks to the pool free list */ for (n = poolConfig[i].entries; n != 0; --n) { MemBlock* block = (MemBlock*)heapEnd; if (sz > heapSz) { AJ_ErrPrintf(("Heap is too small for the requested pool allocations\n")); return AJ_ERR_RESOURCES; } block->next = (MemBlock*)p->freeList; p->freeList = (void*)block; heapEnd += sz; heapSz -= sz; } /* * Save end of pool pointer for use by AJ_PoolFree */ p->endOfPool = (void*)heapEnd; #ifndef NDEBUG p->use = 0; p->hwm = 0; p->max = 0; #endif } return AJ_OK; } uint8_t AJ_PoolIsInitialized() { return heapPools != NULL; } void* AJ_PoolAlloc(size_t sz) { Pool* p = heapPools; uint8_t i; if (!p) { AJ_ErrPrintf(("Heap not initialized\n")); return NULL; } /* * Find pool that can satisfy the allocation */ for (i = 0; i < numPools; ++i, ++p) { if (sz <= heapConfig[i].size) { MemBlock* block = (MemBlock*)p->freeList; if (!block) { /* * Are we allowed to borrowing from next pool? */ if (heapConfig[i].borrow) { continue; } break; } AJ_InfoPrintf(("AJ_PoolAlloc pool[%d] allocated %d\n", heapConfig[i].size, (int)sz)); p->freeList = block->next; #ifndef NDEBUG ++p->use; p->hwm = max(p->use, p->hwm); p->max = max(p->max, sz); #endif return (void*)block; } } AJ_ErrPrintf(("AJ_PoolAlloc of %d bytes failed\n", (int)sz)); AJ_PoolDump(); return NULL; } void AJ_PoolFree(void* mem) { Pool* p = heapPools; uint8_t i; if (mem) { assert((ptrdiff_t)mem >= (ptrdiff_t)heapStart); /* * Locate the pool from which the released memory was allocated */ for (i = 0; i < numPools; ++i, ++p) { if ((ptrdiff_t)mem < (ptrdiff_t)p->endOfPool) { MemBlock* block = (MemBlock*)mem; block->next = (MemBlock*)p->freeList; p->freeList = block; AJ_InfoPrintf(("AJ_PoolFree pool[%d]\n", heapConfig[i].size)); #ifndef NDEBUG --p->use; #endif break; } } assert(i < numPools); } } void* AJ_PoolRealloc(void* mem, size_t newSz) { Pool* p = heapPools; uint8_t i; if (mem) { assert((ptrdiff_t)mem >= (ptrdiff_t)heapStart); /* * Locate the pool from which the released memory was allocated */ for (i = 0; i < numPools; ++i, ++p) { if ((ptrdiff_t)mem < (ptrdiff_t)p->endOfPool) { size_t oldSz = heapConfig[i].size; /* * Don't need to do anything if the same block would be reused */ if ((newSz <= oldSz) && ((i == 0) || (newSz > heapConfig[i - 1].size))) { AJ_InfoPrintf(("AJ_Realloc pool[%d] %d bytes in place\n", (int)oldSz, (int)newSz)); } else { MemBlock* block = (MemBlock*)mem; AJ_InfoPrintf(("AJ_Realloc pool[%d] by AJ_Alloc(%d)\n", (int)oldSz, (int)newSz)); mem = AJ_PoolAlloc(newSz); if (mem) { memcpy(mem, (void*)block, min(oldSz, newSz)); /* * Put old block on the free list */ block->next = (MemBlock*)p->freeList; p->freeList = block; #ifndef NDEBUG --p->use; #endif } } return mem; } } } else { return AJ_PoolAlloc(newSz); } AJ_ErrPrintf(("AJ_Realloc of %d bytes failed\n", (int)newSz)); AJ_PoolDump(); return NULL; } #ifndef NDEBUG void AJ_PoolDump(void) { uint8_t i; size_t memUse = 0; size_t memHigh = 0; size_t memTotal = 0; Pool* p = heapPools; AJ_AlwaysPrintf(("======= dump of %d heap pools ======\n", numPools)); for (i = 0; i < numPools; ++i, ++p) { AJ_AlwaysPrintf(("pool[%d] used=%d free=%d high-water=%d max-alloc=%d\n", heapConfig[i].size, p->use, heapConfig[i].entries - p->use, p->hwm, p->max)); memUse += p->use * heapConfig[i].size; memHigh += p->hwm * heapConfig[i].size; memTotal += p->hwm * p->max; } AJ_AlwaysPrintf(("======= heap hwm = %d use = %d waste = %d ======\n", (int)memHigh, (int)memUse, (int)(memHigh - memTotal))); } #endif ajtcl-16.04/src/malloc/aj_malloc.h000066400000000000000000000100361271074662300167610ustar00rootroot00000000000000/** * @file A pool based memory allocator designed for embedded systemms. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include /* * Indicates that allocations can be borrowed from the the next larger pool if the best-fit pool is * exhausted. */ #define AJ_POOL_BORROW 1 typedef struct _Aj_HeapConfig { const uint16_t size; /* Size of the pool entries in bytes */ const uint16_t entries; /* Number of entries in this pool */ const uint8_t borrow; /* Indicates if pool can borrow from then next larger pool */ } AJ_HeapConfig; /* * This should be 4 or 8 */ #define AJ_HEAP_POOL_ROUNDING 4 /** * Example of a heap pool description. Note that the pool sizes must be in ascending order of size * and should be rounded according to AJ_HEAP_POOL_ROUNDING. @code static const AJ_HeapConfig memPools[] = { { 32, 1, AJ_POOL_BORROW }, { 96, 4, }, { 192, 1, } }; @endcode */ /** * Compute the required size of the heap for the given pool list. * * @param heapConfig Description of the pools to require. * @param numPools The number of different sized memory pools, maximum is 255. * * @return Returns the total heap size required. */ size_t AJ_PoolRequired(const AJ_HeapConfig* heapConfig, uint8_t numPools); /** * Initialize the heap. * * @param heap Pointer to the heap storage * @param heapSz Size of the heap for sanity checking * @param heapConfig Description of the pools to allocate. This structure must remain valid for the * lifetime of the heap * @param numPools The number of different sized memory pools, maximum is 255. * * @return - AJ_OK if the heap was allocated and pools were initialized * - AJ_ERR_RESOURCES of the heap is not big enough to allocate the requested pools. */ AJ_Status AJ_PoolInit(void* heap, size_t heapSz, const AJ_HeapConfig* heapConfig, uint8_t numPools); /** * Terminate the heap */ void AJ_PoolTerminate(void* heap); /** * Indicates if the heap has been initialized */ uint8_t AJ_PoolIsInitialized(); /** * Allocate memory * * @param sz The size of the memory block to allocate * * @return A pointer to the allocated memory block or NULL if the request could not be satisfied. */ void* AJ_PoolAlloc(size_t sz); /** * Free a memory block returning it to the pool from which it was allocated. * * @param mem Pointer to the memory block to free, can be NULL */ void AJ_PoolFree(void* mem); /** * Reallocates a memory block with a larger or smaller size. If the current block is large enough to * satisfy the request that block is simply returned, otherwise a new larger block is allocated, the * contents of the old block are copied over and the old block is freed. * * @param mem Pointer to the memory block to reallocate, can be NULL which case this is equivalent * to calling AJ_PoolAlloc. * @param newSz The size of the new memory block * * @return A pointer to the allocated memory block or NULL if the request could not be satisfied. */ void* AJ_PoolRealloc(void* mem, size_t newSz); #ifndef NDEBUG void AJ_PoolDump(void); #else #define AJ_PoolDump() #endif ajtcl-16.04/src/mbedrtos/000077500000000000000000000000001271074662300152375ustar00rootroot00000000000000ajtcl-16.04/src/mbedrtos/aj_rtos.h000066400000000000000000000147111271074662300170550ustar00rootroot00000000000000/** * @file RTOS abstraction layer contains declarations for all the needed * RTOS primitives that should be implemented for a specific RTOS. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_RTOS_H_ #define AJ_RTOS_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /* * These are opaque types that hold RTOS specific types; */ struct AJ_Queue; struct AJ_TaskHandle; struct AJ_Mutex; uint32_t AJ_MsToTicks(uint32_t ms); /** * create a queue * * @param name Name of the queue to create * * @return pointer to an AJ_Queue object */ struct AJ_Queue* AJ_QueueCreate(const char* name); /** * delete a queue * * @param q pointer to the AJ_Queue to delete, deletes the opaque type as well * */ void AJ_QueueDelete(struct AJ_Queue* q); /** * Peek at an item in a queue * * @param q pointer to the AJ_Queue structure * @param data location for the item in the queue to go * * @return AJ_OK if an item was in the queue * AJ_ERR_NULL if the queue was empty */ AJ_Status AJ_QueuePeek(struct AJ_Queue* q, void* data); /** * Reset or flush a queue * * @param q The AJ_Queue structure you want to empty * * @return This will always return AJ_OK */ AJ_Status AJ_QueueReset(struct AJ_Queue* q); /** * push an item on to a queue, wait at most until timeout * * @param q pointer to the AJ_Queue to push * @param data data to push onto the queue * @param timeout amount of time in milliseconds to wait to push an item * * @return AJ_OK item was pushed * AJ_ERR_RESOURCES item couldn't be pushed within timeout */ AJ_Status AJ_QueuePush(struct AJ_Queue* q, void* data, uint32_t timeout); /** * Push an item to the front of a queue from an ISR * note: This function pushes to the front of the queue (used for immediate signaling) * * @param q pointer to the queue * @param data pointer to the data you adding to the queue */ AJ_Status AJ_QueuePushFromISR(struct AJ_Queue* q, void* data); /** * peek at an item in the queue from an ISR * * @param q pointer to the queue * @param data location for the item in the queue to go * * @return AJ_OK if the peek was successful * AJ_ERR_NULL if there was no item to peek at */ AJ_Status AJ_QueuePeekFromISR(struct AJ_Queue* q, void* data); /** * pull an item from a queue, wait at most until timeout * * @param q pointer to the AJ_Queue to pull * @param data data to pull from the queue * @param timeout amount of time in milliseconds to wait to pull an item * * @return AJ_OK item was pulled * AJ_ERR_RESOURCES item couldn't be pulled before timeout */ AJ_Status AJ_QueuePull(struct AJ_Queue* q, void* data, uint32_t timeout); /* * Create a mutex */ struct AJ_Mutex* AJ_MutexCreate(void); /* * Try and take a lock on a mutex * * @param m Pointer to the mutex created by AJ_MutexCreate() * @param timeout How long to block if the mutex is already locked */ AJ_Status AJ_MutexLock(struct AJ_Mutex* m, uint32_t timeout); /* * Unlock a mutex * * @param m Mutex pointer */ AJ_Status AJ_MutexUnlock(struct AJ_Mutex* m); /* * Delete a muted * * @param m Mutex to delete */ void AJ_MutexDelete(struct AJ_Mutex* m); /* * Create a task to be started * * @param task Function pointer to where you want the task to start * @param name Name for the task * @param stackDepth How big you want the stack to be * @param parameters Any parameters to pass into the task when its started * @param priority Priority of the task * @param handle A context for referencing the task */ AJ_Status AJ_CreateTask(void (*task)(void*), const signed char* const name, unsigned short stackDepth, void* parameters, uint8_t priority, struct AJ_TaskHandle** handle); /* * Remove a task from running * * @param handle The handle that was set by AJ_CreateTask() */ AJ_Status AJ_DestroyTask(struct AJ_TaskHandle* handle); /* * suspend a task from running * * @param handle The handle that was set by AJ_CreateTask() */ AJ_Status AJ_SuspendTask(struct AJ_TaskHandle* handle); /* * resume a suspended task, possibly from an ISR * * @param handle The handle that was set by AJ_CreateTask() * @param inISR is this being called from an interrupt service routine? */ AJ_Status AJ_ResumeTask(struct AJ_TaskHandle* handle, uint8_t inISR); /* * Start the RTOS specific scheduler */ void AJ_StartScheduler(void); /** * force the current task to yield its timeslice */ void AJ_YieldCurrentTask(void); /** * Disable interrupts for a time */ void AJ_EnterCriticalRegion(void); /** * exit the critical region and enable interrupts if needed */ void AJ_LeaveCriticalRegion(void); /** * Do any platform specific initialization * - Clock init, serial debug, SPI etc. */ void AJ_PlatformInit(void); /** * Pre-AllJoyn entry function. This function does all the network initialization * that AllJoyn needs to run. Before calling AJ_Main() a network needs to be setup * which entails connecting to an access point (or softAP) and getting an IP address */ void AllJoyn_Start(unsigned long arg); #ifdef __cplusplus } #endif #endif /* RTOS_H_ */ ajtcl-16.04/src/mbedrtos/aj_target_rtos.cpp000066400000000000000000000237171271074662300207640ustar00rootroot00000000000000/** * @file RTOS specific implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE TARGET_RTOS #include #include #include #include #include #include #include #include "mbed.h" #include "rtos.h" extern "C" { /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_RTOS = 0; #endif /* * Temporary queue and item size * - Still need to determine how big the queue should be * - What type of structure we are sending -> to find the size */ #define QUEUE_SIZE 5 #define ITEM_SIZE sizeof(void*) uint32_t AJ_MsToTicks(uint32_t ms); typedef struct { void* data; } TopOfQueue; /* * The opaque AJ types are now declared with FreeRTOS types */ struct AJ_Queue { Queue* q; }; struct AJ_Mutex { int m; }; struct AJ_TaskHandle { Thread* t; }; struct AJ_Queue* AJ_QueueCreate(const char* name) { struct AJ_Queue* p = (struct AJ_Queue*)AJ_Malloc(sizeof(struct AJ_Queue)); if (p) { Queue* queue = new Queue(); p->q = queue; } return p; } void AJ_QueueDelete(struct AJ_Queue* q) { if (q) { if (q->q) { delete q->q } AJ_Free(q); } } /* * Place holder for the top of the queue so peek can be implemented */ static void* topOfQueue = NULL; AJ_Status AJ_QueuePeek(struct AJ_Queue* q, void** data) { if (q && q->q) { /* * The top of queue place holder is empty so we need to get a new one * and return the data pointer */ if (topOfQueue == NULL) { osEvent event = q->q->get(0); if (event.status == osEventMessage) { topOfQueue = event.value.p; *data = topOfQueue; } else { return AJ_ERR_NULL; } /* * There is already something there so just return that */ } else { *data = topOfQueue; } return AJ_OK; } return AJ_ERR_NULL; } AJ_Status AJ_QueueReset(struct AJ_Queue* q) { return AJ_OK; } AJ_Status AJ_QueuePush(struct AJ_Queue* q, void** data, uint32_t timeout) { if (q && q->q) { q->q->put(*data, timeout); return AJ_OK; } return AJ_ERR_NULL; } AJ_Status AJ_QueuePushFromISR(struct AJ_Queue* q, void** data) { AJ_QueuePush(q, data, 0); return AJ_OK; } AJ_Status AJ_QueuePeekFromISR(struct AJ_Queue* q, void** data) { AJ_QueuePeek(q, data); return AJ_ERR_NULL; } AJ_Status AJ_QueuePull(struct AJ_Queue* q, void** data, uint32_t timeout) { if (q && q->q) { /* * No peek item place holder so pull normally */ if (topOfQueue == NULL) { osEvent event = q->q->get(timeout); if (event.status == osEventMessage) { *data = event.value.p; } else { return AJ_ERR_NULL; } /* * There was a place holder so get it and reset it to NULL */ } else { *data = topOfQueue; topOfQueue = NULL; } return AJ_OK; } return AJ_ERR_NULL; } uint32_t AJ_MsToTicks(uint32_t ms) { return (ms); } /** * Nothing in the WSL driver uses mutex's currently so none * of the mutex functions are implemented. */ struct AJ_Mutex* AJ_MutexCreate(void) { return NULL; } /** * Locks a mutex * @param m The mutex your locking * @param timeout How long to wait if the mutex is locked (ms) */ AJ_Status AJ_MutexLock(struct AJ_Mutex* m, uint32_t timeout) { return AJ_ERR_UNKNOWN; } AJ_Status AJ_MutexUnlock(struct AJ_Mutex* m) { return AJ_ERR_NULL; } void AJ_MutexDelete(struct AJ_Mutex* m) { } /** * @param task the function you want to execute as this task * @param name name of the task * @param stackDepth size of the stack for this task * @param parameters any parameters you want to pass in */ AJ_Status AJ_CreateTask(void (*task)(void*), const signed char* const name, unsigned short stackDepth, void* parameters, uint8_t priority, struct AJ_TaskHandle** handle) { /* * Create a new thread. Previous RTOS implementations (FreeRTOS) configured the stack depth in words, not bytes * for this reason we must multiply the stack depth by 4 because the higher level implementation assumed this */ Thread* thread = new Thread((void (*)(const void*))task, parameters, osPriorityNormal, stackDepth * 4, NULL); if (thread) { struct AJ_TaskHandle* th = (struct AJ_TaskHandle*)AJ_Malloc(sizeof(struct AJ_TaskHandle)); th->t = thread; if (handle) { *handle = th; } return AJ_OK; } AJ_ErrPrintf(("AJ_CreateTask(): Could not create task\n")); return AJ_ERR_NULL; } AJ_Status AJ_DestroyTask(struct AJ_TaskHandle* handle) { handle->t->terminate(); if (handle->t) { delete handle->t; } return AJ_OK; } AJ_Status AJ_SuspendTask(struct AJ_TaskHandle* handle) { handle->t->signal_wait(0x1); return AJ_OK; } AJ_Status AJ_ResumeTask(struct AJ_TaskHandle* handle, uint8_t inISR) { handle->t->signal_set(0x1); return AJ_OK; } void AJ_StartScheduler(void) { /* * After we create our main task (AllJoyn task) we can't return * out of main so we just have to loop forever. */ while (1); } void AJ_YieldCurrentTask(void) { Thread::yield(); } void AJ_EnterCriticalRegion(void) { __disable_irq(); } void AJ_LeaveCriticalRegion(void) { __enable_irq(); } void AJ_PlatformInit(void) { _AJ_PlatformInit(); } void AJ_Sleep(uint32_t time) { Thread::wait(time); } extern uint32_t os_time; uint32_t AJ_GetElapsedTime(AJ_Time* timer, uint8_t cumulative) { uint32_t elapsed; uint32_t now_msec = os_time; uint32_t now_sec = os_time / 1000; //Get the seconds now_msec = now_msec - (now_sec * 1000); elapsed = (1000 * (now_sec - timer->seconds)) + (now_msec - timer->milliseconds); if (!cumulative) { //Timer has not been initialized timer->seconds = now_sec; timer->milliseconds = now_msec; } return elapsed; } void AJ_InitTimer(AJ_Time* timer) { uint32_t seconds = os_time / 1000; uint32_t msec = os_time - (seconds * 1000); timer->seconds = seconds; timer->milliseconds = msec; } int32_t AJ_GetTimeDifference(AJ_Time* timerA, AJ_Time* timerB) { int32_t diff; diff = (1000 * (timerA->seconds - timerB->seconds)) + (timerA->milliseconds - timerB->milliseconds); return diff; } void AJ_TimeAddOffset(AJ_Time* timerA, uint32_t msec) { uint32_t msecNew; if ((int32_t)msec == -1) { timerA->seconds = -1; timerA->milliseconds = -1; } else { msecNew = (timerA->milliseconds + msec); timerA->seconds = timerA->seconds + (msecNew / 1000); timerA->milliseconds = msecNew % 1000; } } int8_t AJ_CompareTime(AJ_Time timerA, AJ_Time timerB) { if (timerA.seconds == timerB.seconds) { if (timerA.milliseconds == timerB.milliseconds) { return 0; } else if (timerA.milliseconds > timerB.milliseconds) { return 1; } else { return -1; } } else if (timerA.seconds > timerB.seconds) { return 1; } else { return -1; } } uint64_t AJ_DecodeTime(char* der, const char* fmt) { return 0; } /* * AJ_Malloc, AJ_Free, and AJ_Realloc must be wrapped with * AJ_Enter/LeaveCriticalRegion as to not get interrupted. * Interruptions in the middle of malloc/free can result in * duplicate pointers being returned from different malloc calls. */ void* AJ_Malloc(size_t sz) { AJ_EnterCriticalRegion(); void* ptr = malloc(sz); AJ_LeaveCriticalRegion(); return ptr; } void AJ_Free(void* mem) { if (mem) { AJ_EnterCriticalRegion(); free(mem); AJ_LeaveCriticalRegion(); } } void* AJ_Realloc(void* ptr, size_t size) { void* ptrNew; AJ_EnterCriticalRegion(); ptrNew = realloc(ptr, size); AJ_LeaveCriticalRegion(); return ptrNew; } void AJ_MemZeroSecure(void* s, size_t n) { volatile unsigned char* p = (volatile unsigned char*)s; while (n--) *p++ = '\0'; return; } uint16_t AJ_EphemeralPort(void) { uint16_t random = rand() & 0xFFFF; return 49152 + random % (65535 - 49152); } #ifndef NDEBUG /* * This is not intended, nor required to be particularly efficient. If you want * efficiency, turn off debugging. */ int _AJ_DbgEnabled(const char* module) { char buffer[128]; char* env; strcpy(buffer, "ER_DEBUG_ALL"); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } strcpy(buffer, "ER_DEBUG_"); strcat(buffer, module); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } return FALSE; } #endif } ajtcl-16.04/src/mbedrtos/aj_target_rtos.h000066400000000000000000000036571271074662300204320ustar00rootroot00000000000000/** * @file RTOS specific header file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_TARGET_RTOS_H_ #define AJ_TARGET_RTOS_H_ #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _AJ_FW_Version { uint32_t host_ver; uint32_t target_ver; uint32_t wlan_ver; uint32_t abi_ver; } AJ_FW_Version; /** * Enter a critical region of code. This function will disable all interrupts * until AJ_LeaveCriticalRegion() is called */ void AJ_EnterCriticalRegion(void); /** * Leave a critical region of code. This function re-enables interrupts after * calling AJ_EnterCriticalRegion() */ void AJ_LeaveCriticalRegion(void); /** * Generate an ephemeral (random) port. * * @return A random port number */ uint16_t AJ_EphemeralPort(void); /** * Initialize the platform. This function contains initialization such * as GPIO, Clock, UART etc. */ void AJ_PlatformInit(void); #ifdef __cplusplus } #endif #endif /* AJ_TARGET_RTOS_H_ */ ajtcl-16.04/src/nvram/000077500000000000000000000000001271074662300145435ustar00rootroot00000000000000ajtcl-16.04/src/nvram/aj_nvram.c000066400000000000000000000271551271074662300165160ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE NVRAM #include #include #include "../aj_target_nvram.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgNVRAM = 0; #endif extern uint8_t* AJ_NVRAM_BASE_ADDRESS; static uint8_t isCompact = FALSE; #define AJ_NVRAM_END_ADDRESS (AJ_NVRAM_BASE_ADDRESS + AJ_NVRAM_SIZE) uint32_t AJ_NVRAM_GetSize(void) { uint32_t size = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); uint16_t entryId = 0; uint16_t capacity = 0; while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS && *data != INVALID_DATA) { entryId = *data; capacity = *(data + 1); if (entryId != 0) { size += capacity + ENTRY_HEADER_SIZE; } data += (ENTRY_HEADER_SIZE + capacity) >> 1; } return size + SENTINEL_OFFSET; } extern AJ_Status _AJ_CompactNVStorage(); uint32_t AJ_NVRAM_GetSizeRemaining(void) { if (!isCompact) { _AJ_CompactNVStorage(); isCompact = TRUE; } return AJ_NVRAM_SIZE - AJ_NVRAM_GetSize(); } void AJ_NVRAM_Layout_Print() { int i = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); uint16_t entryId = 0; uint16_t capacity = 0; AJ_AlwaysPrintf(("============ AJ NVRAM Map ===========\n")); for (i = 0; i < SENTINEL_OFFSET; i++) { AJ_AlwaysPrintf(("%c", *((uint8_t*)(AJ_NVRAM_BASE_ADDRESS + i)))); } AJ_AlwaysPrintf(("\n")); while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS && *data != INVALID_DATA) { entryId = *data; capacity = *(data + 1); AJ_AlwaysPrintf(("ID = %d, capacity = %d\n", entryId, capacity)); data += (ENTRY_HEADER_SIZE + capacity) >> 1; } AJ_AlwaysPrintf(("============ End ===========\n")); } /** * Find an entry in the NVRAM with the specific id * * @return Pointer pointing to an entry in the NVRAM if an entry with the specified id is found * NULL otherwise */ uint8_t* AJ_FindNVEntry(uint16_t id) { uint16_t capacity = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); AJ_InfoPrintf(("AJ_FindNVEntry(id=%d.)\n", id)); while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS) { if (*data != id) { capacity = *(data + 1); if (*data == INVALID_DATA) { break; } data += (ENTRY_HEADER_SIZE + capacity) >> 1; } else { AJ_InfoPrintf(("AJ_FindNVEntry(): data=0x%p\n", data)); return (uint8_t*)data; } } AJ_InfoPrintf(("AJ_FindNVEntry(): data=NULL\n")); return NULL; } AJ_Status AJ_NVRAM_Create(uint16_t id, uint16_t capacity) { uint8_t* ptr; NV_EntryHeader header; AJ_InfoPrintf(("AJ_NVRAM_Create(id=%d., capacity=%d.)\n", id, capacity)); if (id == INVALID_DATA || !capacity || AJ_NVRAM_Exist(id)) { AJ_ErrPrintf(("AJ_NVRAM_Create(): AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } capacity = WORD_ALIGN(capacity); // 4-byte alignment ptr = AJ_FindNVEntry(INVALID_DATA); if (!ptr || (ptr + ENTRY_HEADER_SIZE + capacity > AJ_NVRAM_END_ADDRESS)) { if (!isCompact) { AJ_InfoPrintf(("AJ_NVRAM_Create(): _AJ_CompactNVStorage()\n")); _AJ_CompactNVStorage(); isCompact = TRUE; } ptr = AJ_FindNVEntry(INVALID_DATA); if (!ptr || ptr + ENTRY_HEADER_SIZE + capacity > AJ_NVRAM_END_ADDRESS) { AJ_InfoPrintf(("AJ_NVRAM_Create(): AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } } header.id = id; header.capacity = capacity; _AJ_NV_Write(ptr, &header, ENTRY_HEADER_SIZE); return AJ_OK; } AJ_Status AJ_NVRAM_SecureDelete(uint16_t id) { NV_EntryHeader newHeader; uint8_t* ptr = NULL; AJ_InfoPrintf(("AJ_NVRAM_SecureDelete(id=%d.)\n", id)); if (id != INVALID_DATA) { ptr = AJ_FindNVEntry(id); } if (!ptr) { AJ_ErrPrintf(("AJ_NVRAM_SecureDelete(): AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } memcpy(&newHeader, ptr, ENTRY_HEADER_SIZE); newHeader.id = 0; _AJ_NV_Write(ptr, &newHeader, ENTRY_HEADER_SIZE); isCompact = FALSE; uint8_t* buf = AJ_Malloc(newHeader.capacity); if (!buf) { AJ_ErrPrintf(("AJ_NVRAM_SecureDelete(): AJ_ERR_RESOURCES\n")); return AJ_ERR_RESOURCES; } AJ_MemZeroSecure(buf, newHeader.capacity); _AJ_NV_Write(ptr + ENTRY_HEADER_SIZE, buf, sizeof(buf)); free(buf); return AJ_OK; } AJ_Status AJ_NVRAM_Delete(uint16_t id) { NV_EntryHeader newHeader; uint8_t* ptr = NULL; AJ_InfoPrintf(("AJ_NVRAM_Delete(id=%d.)\n", id)); if (id != INVALID_DATA) { ptr = AJ_FindNVEntry(id); } if (!ptr) { AJ_ErrPrintf(("AJ_NVRAM_Delete(): AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } memcpy(&newHeader, ptr, ENTRY_HEADER_SIZE); newHeader.id = 0; _AJ_NV_Write(ptr, &newHeader, ENTRY_HEADER_SIZE); isCompact = FALSE; return AJ_OK; } AJ_NV_DATASET* AJ_NVRAM_Open(uint16_t id, const char* mode, uint16_t capacity) { AJ_Status status = AJ_OK; uint8_t* entry = NULL; AJ_NV_DATASET* handle = NULL; AJ_InfoPrintf(("AJ_NVRAM_Open(id=%d., mode=\"%s\", capacity=%d.)\n", id, mode, capacity)); if (!id || id == INVALID_DATA) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid id\n")); goto OPEN_ERR_EXIT; } if (!mode || mode[1] || (*mode != 'r' && *mode != 'w')) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid access mode\n")); goto OPEN_ERR_EXIT; } if (*mode == AJ_NV_DATASET_MODE_WRITE) { if (capacity == 0) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid capacity\n")); goto OPEN_ERR_EXIT; } if (AJ_NVRAM_Exist(id)) { status = AJ_NVRAM_Delete(id); } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_NVRAM_Open(): AJ_NVRAM_Delete() failure: status=%s\n", AJ_StatusText(status))); goto OPEN_ERR_EXIT; } status = AJ_NVRAM_Create(id, capacity); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_NVRAM_Open(): AJ_NVRAM_Create() failure: status=%s\n", AJ_StatusText(status))); goto OPEN_ERR_EXIT; } entry = AJ_FindNVEntry(id); if (!entry) { AJ_ErrPrintf(("AJ_NVRAM_Open(): Data set %d. does not exist\n", id)); goto OPEN_ERR_EXIT; } } else { entry = AJ_FindNVEntry(id); if (!entry) { AJ_WarnPrintf(("AJ_NVRAM_Open(): Data set %d. does not exist\n", id)); goto OPEN_ERR_EXIT; } } handle = (AJ_NV_DATASET*)AJ_Malloc(sizeof(AJ_NV_DATASET)); if (!handle) { AJ_ErrPrintf(("AJ_NVRAM_Open(): AJ_Malloc() failure\n")); goto OPEN_ERR_EXIT; } handle->id = id; handle->curPos = 0; handle->mode = *mode; handle->capacity = ((NV_EntryHeader*)entry)->capacity; handle->inode = entry; return handle; OPEN_ERR_EXIT: if (handle) { AJ_Free(handle); handle = NULL; } AJ_ErrPrintf(("AJ_NVRAM_Open(): failure: status=%s\n", AJ_StatusText(status))); return NULL; } size_t AJ_NVRAM_Write(const void* ptr, uint16_t size, AJ_NV_DATASET* handle) { uint16_t bytesWrite = 0; uint8_t patchBytes = 0; uint8_t* buf = (uint8_t*)ptr; NV_EntryHeader* header; if (!handle || handle->mode == AJ_NV_DATASET_MODE_READ) { AJ_ErrPrintf(("AJ_NVRAM_Write(): AJ_ERR_ACCESS\n")); return -1; } header = (NV_EntryHeader*)handle->inode; AJ_InfoPrintf(("AJ_NVRAM_Write(ptr=0x%p, size=%d., handle=0x%p)\n", ptr, size, handle)); if (header->capacity <= handle->curPos) { AJ_AlwaysPrintf(("AJ_NVRAM_Write(): AJ_ERR_RESOURCES\n")); return -1; } bytesWrite = header->capacity - handle->curPos; bytesWrite = (bytesWrite < size) ? bytesWrite : size; if (bytesWrite > 0 && ((handle->curPos & 0x3) != 0)) { uint8_t tmpBuf[4]; uint16_t alignedPos = handle->curPos & (~0x3); memset(tmpBuf, INVALID_DATA_BYTE, sizeof(tmpBuf)); patchBytes = 4 - (handle->curPos & 0x3); memcpy(tmpBuf, handle->inode + sizeof(NV_EntryHeader) + alignedPos, handle->curPos & 0x3); if (patchBytes > bytesWrite) { patchBytes = (uint8_t)bytesWrite; } memcpy(tmpBuf + (handle->curPos & 0x3), buf, patchBytes); _AJ_NV_Write(handle->inode + sizeof(NV_EntryHeader) + alignedPos, tmpBuf, 4); buf += patchBytes; bytesWrite -= patchBytes; handle->curPos += patchBytes; } if (bytesWrite > 0) { _AJ_NV_Write(handle->inode + sizeof(NV_EntryHeader) + handle->curPos, buf, bytesWrite); handle->curPos += bytesWrite; } return bytesWrite + patchBytes; } const void* AJ_NVRAM_Peek(AJ_NV_DATASET* handle) { if (!handle || handle->mode == AJ_NV_DATASET_MODE_WRITE) { AJ_ErrPrintf(("AJ_NVRAM_Peek(): AJ_ERR_ACCESS\n")); return NULL; } return (const void*)(handle->inode + sizeof(NV_EntryHeader) + handle->curPos); } size_t AJ_NVRAM_Read(void* ptr, uint16_t size, AJ_NV_DATASET* handle) { uint16_t bytesRead = 0; NV_EntryHeader* header; if (!handle || handle->mode == AJ_NV_DATASET_MODE_WRITE) { AJ_ErrPrintf(("AJ_NVRAM_Read(): AJ_ERR_ACCESS\n")); return -1; } header = (NV_EntryHeader*)handle->inode; AJ_InfoPrintf(("AJ_NVRAM_Read(ptr=0x%p, size=%d., handle=0x%p)\n", ptr, size, handle)); if (header->capacity <= handle->curPos) { AJ_ErrPrintf(("AJ_NVRAM_Read(): AJ_ERR_RESOURCES\n")); return -1; } bytesRead = header->capacity - handle->curPos; bytesRead = (bytesRead < size) ? bytesRead : size; if (bytesRead > 0) { _AJ_NV_Read(handle->inode + sizeof(NV_EntryHeader) + handle->curPos, ptr, bytesRead); handle->curPos += bytesRead; } return bytesRead; } AJ_Status AJ_NVRAM_Close(AJ_NV_DATASET* handle) { AJ_InfoPrintf(("AJ_NVRAM_Close(handle=0x%p)\n", handle)); if (!handle) { AJ_ErrPrintf(("AJ_NVRAM_Close(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } AJ_Free(handle); handle = NULL; return AJ_OK; } uint8_t AJ_NVRAM_Exist(uint16_t id) { AJ_InfoPrintf(("AJ_NVRAM_Exist(id=%d.)\n", id)); if (!id || id == INVALID_DATA) { AJ_ErrPrintf(("AJ_NVRAM_Exist(): AJ_ERR_INVALID\n")); return FALSE; // the unique id is not allowed to be 0 or 0xffff } return (NULL != AJ_FindNVEntry(id)); } void AJ_NVRAM_Clear() { _AJ_NVRAM_Clear(); } ajtcl-16.04/src/target/000077500000000000000000000000001271074662300147065ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/000077500000000000000000000000001271074662300163475ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/CopyAjToArduino.bat000066400000000000000000000003401271074662300220460ustar00rootroot00000000000000SETLOCAL SET SRC=c:\cygwin\home\%USERNAME%\repos\alljoyn-tc\ajtcl SET DST=c:\arduino\arduino-1.5.2\hardware\arduino\sam\libraries\AllJoyn rmdir /S /Q %DST% xcopy /Y /D /S /I %SRC%\build\arduino_due\libraries\AllJoyn %DST% ajtcl-16.04/src/target/arduino/aj_net.c000066400000000000000000000257561271074662300177720ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE NET #include #include #include #include #include #include #ifdef WIFI_UDP_WORKING #include #include #include #include #else #include #include #include #endif static uint8_t rxDataStash[256]; static uint16_t rxLeftover = 0; /* * IANA assigned IPv4 multicast group for AllJoyn. */ static const char AJ_IPV4_MULTICAST_GROUP[] = "224.0.0.113"; /* * IANA assigned IPv6 multicast group for AllJoyn. */ static const char AJ_IPV6_MULTICAST_GROUP[] = "ff02::13a"; /* * IANA assigned UDP multicast port for AllJoyn */ #define AJ_UDP_PORT 9956 #ifdef WIFI_UDP_WORKING static WiFiClient g_client; static WiFiUDP g_clientUDP; #else static EthernetClient g_client; static EthernetUDP g_clientUDP; #endif AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { uint32_t ret; uint32_t tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_Send(buf=0x%p)\n", buf)); if (tx > 0) { ret = g_client.write(buf->readPtr, tx); if (ret == 0) { AJ_ErrPrintf(("AJ_Net_Send(): send() failed. error=%d, status=AJ_ERR_WRITE\n", g_client.getWriteError())); return AJ_ERR_WRITE; } buf->readPtr += ret; } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_Net_Send(): status=AJ_OK\n")); return AJ_OK; } AJ_Status AJ_Net_Recv(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { AJ_Status status = AJ_ERR_READ; uint32_t ret; uint32_t rx = AJ_IO_BUF_SPACE(buf); uint32_t recvd = 0; unsigned long Recv_lastCall = millis(); // first we need to clear out our buffer uint32_t M = 0; AJ_InfoPrintf(("AJ_Net_Recv(buf=0x%p, len=%d., timeout=%d.)\n", buf, len, timeout)); if (rxLeftover != 0) { // there was something leftover from before, AJ_InfoPrintf(("AJ_NetRecv(): leftover was: %d\n", rxLeftover)); M = min(rx, rxLeftover); memcpy(buf->writePtr, rxDataStash, M); // copy leftover into buffer. buf->writePtr += M; // move the data pointer over memmove(rxDataStash, rxDataStash + M, rxLeftover - M); // shift left-overs toward the start. rxLeftover -= M; recvd += M; // we have read as many bytes as we can // higher level isn't requesting any more if (recvd == rx) { AJ_InfoPrintf(("AJ_Net_Recv(): status=AJ_OK\n")); return AJ_OK; } } if ((M != 0) && (rxLeftover != 0)) { AJ_InfoPrintf(("AJ_Net_REcv(): M was: %d, rxLeftover was: %d\n", M, rxLeftover)); } // wait for data to become available // time out if nothing arrives while (g_client.connected() && g_client.available() == 0 && (millis() - Recv_lastCall < timeout)) { delay(50); // wait for data or timeout } // return timeout if nothing is available AJ_InfoPrintf(("AJ_Net_Recv(): millis %d, Last_call %d timeout %d Avail: %d\n", millis(), Recv_lastCall, timeout, g_client.available())); if (g_client.connected() && (millis() - Recv_lastCall >= timeout) && (g_client.available() == 0)) { AJ_InfoPrintf(("AJ_Net_Recv(): timeout. status=AJ_ERR_TIMEOUT\n")); return AJ_ERR_TIMEOUT; } if (g_client.connected()) { uint32_t askFor = rx; askFor -= M; AJ_InfoPrintf(("AJ_Net_Recv(): ask for: %d\n", askFor)); ret = g_client.read(buf->writePtr, askFor); AJ_InfoPrintf(("AJ_Net_Recv(): read(): ret %d askfor %d\n", ret, askFor)); if (askFor < ret) { AJ_InfoPrintf(("AJ_Net_Recv(): BUFFER OVERRUN: askFor=%u, ret=%u\n", askFor, ret)); } if (ret == -1) { AJ_ErrPrintf(("AJ_Net_Recv(): read() failed. status=AJ_ERR_READ\n")); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_Recv(): ret now %d\n", ret)); AJ_DumpBytes("Recv", buf->writePtr, ret); if (ret > askFor) { AJ_InfoPrintf(("AJ_Net_Recv(): new leftover %d\n", ret - askFor)); // now shove the extra into the stash memcpy(rxDataStash + rxLeftover, buf->writePtr + askFor, ret - askFor); rxLeftover += (ret - askFor); buf->writePtr += rx; } else { buf->writePtr += ret; } status = AJ_OK; } } return status; } /* * Need enough RX buffer space to receive a complete name service packet when * used in UDP mode. NS expects MTU of 1500 subtracts UDP, IP and Ethernet * Type II overhead. 1500 - 8 -20 - 18 = 1454. txData buffer size needs to * be big enough to hold a NS WHO-HAS for one name (4 + 2 + 256 = 262) in UDP * mode. TCP buffer size dominates in that case. */ static uint8_t rxData[1454]; static uint8_t txData[1024]; AJ_Status AJ_Net_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { int ret; IPAddress ip(service->ipv4); if (!(service->addrTypes & AJ_ADDR_TCP4)) { AJ_ErrPrintf(("AJ_Net_Connect(): only IPV4 TCP supported\n", ret)); return AJ_ERR_CONNECT; } AJ_InfoPrintf(("AJ_Net_Connect(bus=0x%p, addrType=%d.)\n", bus, service->addrTypes)); ret = g_client.connect(ip, service->ipv4port); if (ret != 1) { AJ_ErrPrintf(("AJ_Net_Connect(): connect() failed: %d: status=AJ_ERR_CONNECT\n", ret)); return AJ_ERR_CONNECT; } else { AJ_IOBufInit(&bus->sock.rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, (void*)&g_client); bus->sock.rx.recv = AJ_Net_Recv; AJ_IOBufInit(&bus->sock.tx, txData, sizeof(txData), AJ_IO_BUF_TX, (void*)&g_client); bus->sock.tx.send = AJ_Net_Send; AJ_ErrPrintf(("AJ_Net_Connect(): connect() success: status=AJ_OK\n")); return AJ_OK; } AJ_ErrPrintf(("AJ_Net_Connect(): connect() failed: %d: status=AJ_ERR_CONNECT\n", ret)); return AJ_ERR_CONNECT; } void AJ_Net_Disconnect(AJ_NetSocket* netSock) { AJ_InfoPrintf(("AJ_Net_Disconnect(nexSock=0x%p)\n", netSock)); g_client.stop(); } AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { int ret; uint32_t tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); if (tx > 0) { // send to subnet-directed broadcast address #ifdef WIFI_UDP_WORKING IPAddress subnet = WiFi.subnetMask(); IPAddress localIp = WiFi.localIP(); #else IPAddress subnet = Ethernet.subnetMask(); IPAddress localIp = Ethernet.localIP(); #endif uint32_t directedBcastAddr = (uint32_t(subnet) & uint32_t(localIp)) | (~uint32_t(subnet)); IPAddress a(directedBcastAddr); ret = g_clientUDP.beginPacket(IPAddress(directedBcastAddr), AJ_UDP_PORT); AJ_InfoPrintf(("AJ_Net_SendTo(): beginPacket to %d.%d.%d.%d, result = %d\n", a[0], a[1], a[2], a[3], ret)); if (ret == 0) { AJ_InfoPrintf(("AJ_Net_SendTo(): no sender\n")); } ret = g_clientUDP.write(buf->readPtr, tx); AJ_InfoPrintf(("AJ_Net_SendTo(): SendTo write %d\n", ret)); if (ret == 0) { AJ_ErrPrintf(("AJ_Net_Sendto(): no bytes. status=AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } buf->readPtr += ret; ret = g_clientUDP.endPacket(); if (ret == 0) { AJ_ErrPrintf(("AJ_Net_Sendto(): endPacket() error. status=AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } } AJ_IO_BUF_RESET(buf); AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; } AJ_Status AJ_Net_RecvFrom(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { AJ_InfoPrintf(("AJ_Net_RecvFrom(buf=0x%p, len=%d., timeout=%d.)\n", buf, len, timeout)); AJ_Status status = AJ_OK; int ret; uint32_t rx = AJ_IO_BUF_SPACE(buf); unsigned long Recv_lastCall = millis(); AJ_InfoPrintf(("AJ_Net_RecvFrom(): len %d, rx %d, timeout %d\n", len, rx, timeout)); rx = min(rx, len); while ((g_clientUDP.parsePacket() == 0) && (millis() - Recv_lastCall < timeout)) { delay(10); // wait for data or timeout } AJ_InfoPrintf(("AJ_Net_RecvFrom(): millis %d, Last_call %d, timeout %d, Avail %d\n", millis(), Recv_lastCall, timeout, g_clientUDP.available())); ret = g_clientUDP.read(buf->writePtr, rx); AJ_InfoPrintf(("AJ_Net_RecvFrom(): read() returns %d, rx %d\n", ret, rx)); if (ret == -1) { AJ_InfoPrintf(("AJ_Net_RecvFrom(): read() fails. status=AJ_ERR_READ\n")); status = AJ_ERR_READ; } else { if (ret != -1) { AJ_DumpBytes("AJ_Net_RecvFrom", buf->writePtr, ret); } buf->writePtr += ret; AJ_InfoPrintf(("AJ_Net_RecvFrom(): status=AJ_OK\n")); status = AJ_OK; } AJ_InfoPrintf(("AJ_Net_RecvFrom(): status=%s\n", AJ_StatusText(status))); return status; } uint16_t AJ_EphemeralPort(void) { // Return a random port number in the IANA-suggested range return 49152 + random(65535 - 49152); } AJ_Status AJ_Net_MCastUp(AJ_MCastSocket* mcastSock) { uint8_t ret = 0; AJ_InfoPrintf(("AJ_Net_MCastUp(mcastSock=0x%p)\n", mcastSock)); // // Arduino does not choose an ephemeral port if we enter 0 -- it happily // uses 0 and then increments each time we bind, up through the well-known // system ports. // ret = g_clientUDP.begin(AJ_EphemeralPort()); if (ret != 1) { g_clientUDP.stop(); AJ_ErrPrintf(("AJ_Net_MCastUp(): begin() fails. status=AJ_ERR_READ\n")); return AJ_ERR_READ; } else { AJ_IOBufInit(&mcastSock->rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, (void*)&g_clientUDP); mcastSock->rx.recv = AJ_Net_RecvFrom; AJ_IOBufInit(&mcastSock->tx, txData, sizeof(txData), AJ_IO_BUF_TX, (void*)&g_clientUDP); mcastSock->tx.send = AJ_Net_SendTo; } AJ_InfoPrintf(("AJ_Net_MCastUp(): status=AJ_OK\n")); return AJ_OK; } void AJ_Net_MCastDown(AJ_MCastSocket* mcastSock) { AJ_InfoPrintf(("AJ_Net_MCastDown(mcastSock=0x%p)\n", mcastSock)); g_clientUDP.flush(); g_clientUDP.stop(); } ajtcl-16.04/src/target/arduino/aj_target.h000066400000000000000000000060001271074662300204540ustar00rootroot00000000000000#ifndef _AJ_TARGET_H #define _AJ_TARGET_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_EXPORT #include #include #include typedef signed char int8_t; /** 8-bit signed integer */ typedef unsigned char uint8_t; /** 8-bit unsigned integer */ typedef signed long long int64_t; /** 64-bit signed integer */ typedef unsigned long long uint64_t; /** 64-bit unsigned integer */ typedef uint16_t suint32_t; /* amount of data sent into a socket */ #include #include #include #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif // Begin Memory Diagnostics static const char* ramstart = (char*)0x20070000; static const char* ramend = (char*)0x20088000; extern char _end; inline int stack_used() { register char* stack_ptr asm ("sp"); return (ramend - stack_ptr); } inline int static_used() { return (&_end - ramstart); } inline int heap_used() { struct mallinfo mi = mallinfo(); return (mi.uordblks); } void ram_diag(); // End Memory Diagnostics #define WORD_ALIGN(x) ((x & 0x3) ? ((x >> 2) + 1) << 2 : x) #define HOST_IS_LITTLE_ENDIAN TRUE #define HOST_IS_BIG_ENDIAN FALSE #ifdef WIFI_UDP_WORKING #include #include #else #include #include #endif #define AJ_Printf(fmat, ...) \ do { printf(fmat, ## __VA_ARGS__); } while (0) #ifndef NDEBUG extern uint8_t dbgCONFIGUREME; extern uint8_t dbgINIT; extern uint8_t dbgNET; extern uint8_t dbgTARGET_CRYPTO; extern uint8_t dbgTARGET_NVRAM; extern uint8_t dbgTARGET_UTIL; #endif #define AJ_ASSERT(x) assert(x) /* * AJ_Reboot() is a NOOP on this platform */ #define AJ_Reboot() #define AJ_CreateNewGUID AJ_RandBytes #define AJ_GetDebugTime(x) AJ_ERR_RESOURCES #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) #define AJ_DEPRECATED(func) func __attribute__((deprecated)) /**< mark a function as deprecated in gcc. */ #else #define AJ_DEPRECATED(func) func /**< not all gcc versions support the deprecated attribute. */ #endif #endif ajtcl-16.04/src/target/arduino/aj_target_crypto.c000066400000000000000000000046301271074662300220560ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include "Arduino.h" // for digitalRead, digitalWrite, etc #include #include #include #include /* * Context for AES-128 CTR DRBG */ static CTR_DRBG_CTX drbgctx; int analogPin = 3; /* * The host has various ADC's. We are going to accumulate entropy by repeatedly * reading the ADC and accumulating the least significant bit or each reading. */ uint32_t AJ_PlatformEntropy(uint8_t* data, uint32_t size) { int i; uint32_t val; /* * Start accumulating entropy one bit at a time */ for (i = 0; i < (8 * size); ++i) { val = analogRead(analogPin); data[i / 8] ^= ((val & 1) << (i & 7)); } return size; } void AJ_RandBytes(uint8_t* rand, uint32_t size) { AJ_Status status = AJ_ERR_SECURITY; uint8_t seed[SEEDLEN]; if (rand && size) { status = AES_CTR_DRBG_Generate(&drbgctx, rand, size); if (AJ_OK != status) { // Reseed required AJ_PlatformEntropy(seed, sizeof (seed)); AES_CTR_DRBG_Reseed(&drbgctx, seed, sizeof (seed)); status = AES_CTR_DRBG_Generate(&drbgctx, rand, size); } } else { // This is the first call to initialize size = AJ_PlatformEntropy(seed, sizeof (seed)); drbgctx.df = (SEEDLEN == size) ? 0 : 1; AES_CTR_DRBG_Instantiate(&drbgctx, seed, sizeof (seed), drbgctx.df); } } ajtcl-16.04/src/target/arduino/aj_target_nvram.c000066400000000000000000000051121271074662300216550ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include uint8_t AJ_EMULATED_NVRAM[AJ_NVRAM_SIZE]; uint8_t* AJ_NVRAM_BASE_ADDRESS; extern void AJ_NVRAM_Layout_Print(); void AJ_NVRAM_Init() { AJ_NVRAM_BASE_ADDRESS = AJ_EMULATED_NVRAM; static uint8_t inited = FALSE; if (!inited) { inited = TRUE; _AJ_NVRAM_Clear(); } } void _AJ_NV_Write(void* dest, const void* buf, uint16_t size) { memcpy(dest, buf, size); } void _AJ_NV_Move(void* dest, const void* buf, uint16_t size) { memmove(dest, buf, size); } void _AJ_NV_Read(void* src, void* buf, uint16_t size) { memcpy(buf, src, size); } void _AJ_NVRAM_Clear() { memset((uint8_t*)AJ_NVRAM_BASE_ADDRESS, INVALID_DATA_BYTE, AJ_NVRAM_SIZE); *((uint32_t*)AJ_NVRAM_BASE_ADDRESS) = AJ_NV_SENTINEL; } // Compact the storage by removing invalid entries AJ_Status _AJ_CompactNVStorage() { uint16_t capacity = 0; uint16_t id = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); uint8_t* writePtr = (uint8_t*)data; uint16_t entrySize = 0; uint16_t garbage = 0; //AJ_NVRAM_Layout_Print(); while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS && *data != INVALID_DATA) { id = *data; capacity = *(data + 1); entrySize = ENTRY_HEADER_SIZE + capacity; if (id != INVALID_ID) { _AJ_NV_Move(writePtr, data, entrySize); writePtr += entrySize; } else { garbage += entrySize; } data += entrySize >> 1; } memset(writePtr, INVALID_DATA_BYTE, garbage); //AJ_NVRAM_Layout_Print(); return AJ_OK; } ajtcl-16.04/src/target/arduino/aj_target_nvram.h000066400000000000000000000041701271074662300216650ustar00rootroot00000000000000#ifndef _AJ_TARGET_NVRAM_H_ #define _AJ_TARGET_NVRAM_H_ /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include /* * Identifies an AJ NVRAM block */ #define AJ_NV_SENTINEL ('A' | ('J' << 8) | ('N' << 16) | ('V' << 24)) #define INVALID_ID (0) #define INVALID_DATA (0xFFFF) #define INVALID_DATA_BYTE (0xFF) #define SENTINEL_OFFSET (4) typedef struct _NV_EntryHeader { uint16_t id; /**< The unique id */ uint16_t capacity; /**< The data set size */ } NV_EntryHeader; #define ENTRY_HEADER_SIZE (sizeof(NV_EntryHeader)) #define AJ_NVRAM_END_ADDRESS (AJ_NVRAM_BASE_ADDRESS + AJ_NVRAM_SIZE) /** * Write a block of data to NVRAM * * @param dest Pointer a location of NVRAM * @param buf Pointer to data to be written * @param size The number of bytes to be written */ void _AJ_NV_Write(void* dest, const void* buf, uint16_t size); /** * Read a block of data from NVRAM * * @param src Pointer a location of NVRAM * @param buf Pointer to data to be written * @param size The number of bytes to be written */ void _AJ_NV_Read(void* src, void* buf, uint16_t size); /** * Erase the whole NVRAM sector and write the sentinel data */ void _AJ_NVRAM_Clear(); #endif ajtcl-16.04/src/target/arduino/aj_target_util.c000066400000000000000000000111311271074662300215050ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include "Arduino.h" #include #include #include #include #include typedef struct time_struct { /* The number of milliseconds in the time. */ uint32_t milliseconds; } TIME_STRUCT; void AJ_Sleep(uint32_t time) { delay(time); } uint32_t AJ_GetElapsedTime(AJ_Time* timer, uint8_t cumulative) { uint32_t elapsed; TIME_STRUCT now; now.milliseconds = millis(); elapsed = (uint32_t)now.milliseconds - (timer->seconds * 1000 + timer->milliseconds); // watch for wraparound if (!cumulative) { timer->seconds = (uint32_t)(now.milliseconds / 1000); timer->milliseconds = (uint16_t)(now.milliseconds % 1000); } return elapsed; } void AJ_InitTimer(AJ_Time* timer) { TIME_STRUCT now; now.milliseconds = millis(); timer->seconds = (uint32_t)(now.milliseconds / 1000); timer->milliseconds = (uint16_t)(now.milliseconds % 1000); } uint64_t AJ_DecodeTime(char* der, const char* fmt) { time_t ret; char* tz; struct tm tm; if (!strptime(der, fmt, &tm)) { return 0; } /* * mktime() assumes that tm is in local time but it is in UTC. * So we set the time zone to UTC first, and reset it after the * call to mktime(). */ tz = getenv("TZ"); setenv("TZ", "", 1); tzset(); ret = mktime(&tm); if (tz) { setenv("TZ", tz, 1); } else { unsetenv("TZ"); } tzset(); if (ret == -1) { return 0; } return (uint64_t) ret; } void* AJ_Malloc(size_t sz) { return malloc(sz); } void* AJ_Realloc(void* ptr, size_t size) { return realloc(ptr, size); } void AJ_Free(void* mem) { if (mem) { free(mem); } } void AJ_MemZeroSecure(void* s, size_t n) { volatile unsigned char* p = (unsigned char*) s; while (n--) *p++ = '\0'; return; } void ram_diag() { AJ_AlwaysPrintf(("SRAM usage (stack, heap, static): %d, %d, %d\n", stack_used(), heap_used(), static_used())); } uint8_t AJ_StartReadFromStdIn() { return FALSE; } uint8_t AJ_StopReadFromStdIn() { return FALSE; } uint16_t AJ_ByteSwap16(uint16_t x) { #ifdef __GNUC__ return __builtin_bswap16(x); #else return ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8); #endif } uint32_t AJ_ByteSwap32(uint32_t x) { #ifdef __GNUC__ return __builtin_bswap32(x); #else return ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24); #endif } uint64_t AJ_ByteSwap64(uint64_t x) { #ifdef __GNUC__ return __builtin_bswap64(x); #else return ((x & UINT64_C(0x00000000000000FF)) << 56) | ((x & UINT64_C(0x000000000000FF00)) << 40) | ((x & UINT64_C(0x0000000000FF0000)) << 24) | ((x & UINT64_C(0x00000000FF000000)) << 8) | ((x & UINT64_C(0x000000FF00000000)) >> 8) | ((x & UINT64_C(0x0000FF0000000000)) >> 24) | ((x & UINT64_C(0x00FF000000000000)) >> 40) | ((x & UINT64_C(0xFF00000000000000)) >> 56); #endif } char* AJ_GetCmdLine(char* buf, size_t num) { if (Serial.available() > 0) { int countBytesRead; // read the incoming bytes until a newline character: countBytesRead = Serial.readBytesUntil('\n', buf, num); buf[countBytesRead] = '\0'; return buf; } else { return NULL; } } #ifndef NDEBUG uint8_t dbgCONFIGUREME = 0; uint8_t dbgNET = 0; uint8_t dbgTARGET_CRYPTO = 0; uint8_t dbgTARGET_NVRAM = 0; uint8_t dbgTARGET_UTIL = 0; int _AJ_DbgEnabled(const char* module) { return FALSE; } #endif ajtcl-16.04/src/target/arduino/examples/000077500000000000000000000000001271074662300201655ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/examples/AJ_LedService/000077500000000000000000000000001271074662300225645ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/examples/AJ_LedService/AJ_LedService.ino000066400000000000000000000061221271074662300256730ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #undef WIFI_UDP_WORKING #include #ifdef WIFI_UDP_WORKING #include #else #include #endif #include #include "due_led.h" #include int led = 13; #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network #endif void DUE_led_timed(uint32_t msec) { AJ_AlwaysPrintf(("DUE_led_timed\n")); digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) delay(msec); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the voltage LOW delay(msec); // wait for a second } void DUE_led(uint8_t on) { AJ_AlwaysPrintf(("DUE_led(%u)\n", on)); digitalWrite(led, on ? HIGH : LOW); // turn the LED on (HIGH is the voltage level) } // the setup routine runs once when you press reset: void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); Serial.begin(115200); while (!Serial); digitalWrite(led, LOW); #ifdef WIFI_UDP_WORKING // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { AJ_AlwaysPrintf(("Failed to configure Ethernet using DHCP\n")); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_AlwaysPrintf(("Hello\n")); AJ_Main(); } ajtcl-16.04/src/target/arduino/examples/AJ_LedService/due_led.cpp000066400000000000000000000134221271074662300246730ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE DUE_LED #include #include #include "due_led.h" #include #include uint8_t dbgDUE_LED = 0; void DUE_led_timed(uint32_t msec); void DUE_led(uint8_t on); static const char ServiceName[] = "org.alljoyn.sample.ledservice"; static const char DaemonServiceName[] = "org.alljoyn.BusNode.Led"; static const uint16_t ServicePort = 24; static const char* const testInterface[] = { "org.alljoyn.sample.ledcontroller", "?Flash msec #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_SecureClientECDHE/000077500000000000000000000000001271074662300235035ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_SecureClientECDHE/AJ_SecureClientECDHE.ino000066400000000000000000000050211271074662300277000ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_SecureService/000077500000000000000000000000001271074662300231345ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_SecureService/AJ_SecureService.ino000066400000000000000000000050211271074662300267620ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_SecureServiceECDHE/000077500000000000000000000000001271074662300236655ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_SecureServiceECDHE/AJ_SecureServiceECDHE.ino000066400000000000000000000050211271074662300302440ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_basic_client/000077500000000000000000000000001271074662300230045ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_basic_client/AJ_basic_client.ino000066400000000000000000000050211271074662300265020ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_basic_service/000077500000000000000000000000001271074662300231665ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_basic_service/AJ_basic_service.ino000066400000000000000000000050211271074662300270460ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_nameChange_client/000077500000000000000000000000001271074662300237515ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_nameChange_client/AJ_nameChange_client.ino000066400000000000000000000050211271074662300304140ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_signalConsumer_client/000077500000000000000000000000001271074662300247145ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_signalConsumer_client/AJ_signalConsumer_client.ino000066400000000000000000000050211271074662300323220ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/samples/AJ_signal_service/000077500000000000000000000000001271074662300233625ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/samples/AJ_signal_service/AJ_signal_service.ino000066400000000000000000000050211271074662300274360ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); // the setup routine runs once when you press reset: void setup() { Serial.begin(115200); while (!Serial) { ; } AJ_Printf("setup...\n"); #ifdef WIFI_UDP_WORKING char ssid[] = "yourNetwork"; // the name of your network // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: AJ_Printf("Connecting ethernet...\n"); if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } // the loop routine runs over and over again forever: void loop() { AJ_Printf("Hello\n"); AJ_Main(); } ajtcl-16.04/src/target/arduino/tests/000077500000000000000000000000001271074662300175115ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_aestest/000077500000000000000000000000001271074662300215335ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_aestest/AJ_aestest.ino000066400000000000000000000026121271074662300242650ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include //#include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif #include int AJ_Main(void); void setup() { //Initialize serial and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } } void loop() { AJ_Main(); } ajtcl-16.04/src/target/arduino/tests/AJ_bastress2/000077500000000000000000000000001271074662300217735ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_bastress2/AJ_bastress2.ino000066400000000000000000000051741271074662300247730ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #undef WIFI_UDP_WORKING #include #ifdef WIFI_UDP_WORKING #include #else #include #endif #include #ifdef WIFI_UDP_WORKING static char ssid[] = "yourNetwork"; static char pass[] = "71DF437B55"; // passphrase for the SSID #endif void setup() { //Initialize serial and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } AJ_Printf("hello, world.\n"); #ifdef WIFI_UDP_WORKING // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); // Connect to WEP private network WiFi.begin(ssid, 0, pass); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } int AJ_Main(void); void loop() { AJ_Main(); } ajtcl-16.04/src/target/arduino/tests/AJ_clientlite/000077500000000000000000000000001271074662300222175ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_clientlite/AJ_clientlite.ino000066400000000000000000000053231271074662300254370ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #undef WIFI_UDP_WORKING #include #ifdef WIFI_UDP_WORKING #include #else #include #endif #include #ifdef WIFI_UDP_WORKING static char ssid[] = "YOUR-WIFI"; static char pass[] = "71DF437B55"; // hex password for the SSID #endif void setup() { //Initialize serial and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } AJ_Printf("hello, world.\n"); #ifdef WIFI_UDP_WORKING // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); // Connect to WEP private network WiFi.begin(ssid, 0, pass); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif // you're connected now, so print out the data: AJ_Printf("You're connected to the network\n"); } int AJ_Main(void); void loop() { AJ_Main(); } ajtcl-16.04/src/target/arduino/tests/AJ_mutter/000077500000000000000000000000001271074662300214035ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_mutter/AJ_mutter.ino000066400000000000000000000026551271074662300240140ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif #include void setup() { //Initialize serial and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } AJ_Printf("hello, world.\n"); } int AJ_Main(void); void loop() { AJ_Main(); } ajtcl-16.04/src/target/arduino/tests/AJ_sessions/000077500000000000000000000000001271074662300217315ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_sessions/AJ_sessions.ino000066400000000000000000000051671271074662300246710ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #undef WIFI_UDP_WORKING #include #ifdef WIFI_UDP_WORKING #include #else #include #endif #include #ifdef WIFI_UDP_WORKING static char ssid[] = "pez-wifi"; static char pass[] = "71DF437B55"; // passphrase for the SSID #endif int AJ_Main(); void setup() { //Initialize serial and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } AJ_Printf("hello, world.\n"); #ifdef WIFI_UDP_WORKING // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); // Connect to WEP private network WiFi.begin(ssid, 0, pass); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } void loop() { AJ_Main(); } ajtcl-16.04/src/target/arduino/tests/AJ_siglite/000077500000000000000000000000001271074662300215235ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_siglite/AJ_siglite.ino000066400000000000000000000046571271074662300242600ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); void setup() { //Initialize serial and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } AJ_Printf("setup"); #ifdef WIFI_UDP_WORKING char ssid[] = "eric-wifi"; // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xA7, 0xCA }; // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } void loop() { AJ_Main(); } ajtcl-16.04/src/target/arduino/tests/AJ_svclite/000077500000000000000000000000001271074662300215345ustar00rootroot00000000000000ajtcl-16.04/src/target/arduino/tests/AJ_svclite/AJ_svclite.ino000066400000000000000000000047041271074662300242730ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include //#include #include #include #ifdef WIFI_UDP_WORKING #include #else #include #endif int AJ_Main(void); void setup() { //Initialize serial and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } AJ_Printf("setup"); #ifdef WIFI_UDP_WORKING char ssid[] = "eric-wifi"; // check for the presence of the shield: unsigned int retries = 10; while (WiFi.status() == WL_NO_SHIELD) { if (retries == 0) { Serial.println("WiFi shield not present"); // don't continue: while (true); } retries--; delay(500); } // attempt to connect to Wifi network: while (true) { Serial.print("Attempting to connect to open SSID: "); Serial.println(ssid); WiFi.begin(ssid); if (WiFi.status() == WL_CONNECTED) { break; } delay(10000); } IPAddress ip = WiFi.localIP(); Serial.print("Connected: "); Serial.println(ip); #else byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xA7, 0xCA }; // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { AJ_Printf("Failed to configure Ethernet using DHCP\n"); // no point in carrying on, so do nothing forevermore: for (;;) ; } #endif } void loop() { AJ_Main(); } ajtcl-16.04/src/target/arduino/udp-fix.patch000066400000000000000000000110611271074662300207430ustar00rootroot00000000000000diff --git a/libraries/WiFi/WiFiClient.cpp b/libraries/WiFi/WiFiClient.cpp index 1fc34e0..f930cd9 100755 --- a/libraries/WiFi/WiFiClient.cpp +++ b/libraries/WiFi/WiFiClient.cpp @@ -1,7 +1,11 @@ extern "C" { #include "utility/wl_definitions.h" #include "utility/wl_types.h" - #include "socket.h" +#if 0 + #include "socket.h" +#else + #define SOCK_NOT_AVAIL 255 +#endif #include "string.h" #include "utility/debug.h" } @@ -69,8 +73,20 @@ size_t WiFiClient::write(const uint8_t *buf, size_t size) { return 0; } + size_t i = size; + // I found there was an issue sending more than 90 bytes at a time to the WiFi shield. + for ( ; i > 90 ; ) { + Serial.print("WiFiClient::write i:"); + Serial.println(i); + if (!ServerDrv::sendData(_sock, buf + (size-i), 90)) + { + setWriteError(__LINE__); + return 0; + } + i -= 90; + } - if (!ServerDrv::sendData(_sock, buf, size)) + if (!ServerDrv::sendData(_sock, buf + (size-i), i)) { setWriteError(); return 0; @@ -104,9 +120,16 @@ int WiFiClient::read() { int WiFiClient::read(uint8_t* buf, size_t size) { - if (!ServerDrv::getDataBuf(_sock, buf, &size)) - return -1; - return 0; + if(available()) { + uint16_t sizeN = size; + if (!ServerDrv::getDataBuf(_sock, buf, &sizeN)) { + return -1; + } else { + return sizeN; + } + } else { + return -1; + } } int WiFiClient::peek() { diff --git a/libraries/WiFi/WiFiUdp.cpp b/libraries/WiFi/WiFiUdp.cpp index 7020df8..b2d135d 100644 --- a/libraries/WiFi/WiFiUdp.cpp +++ b/libraries/WiFi/WiFiUdp.cpp @@ -115,7 +115,7 @@ int WiFiUDP::read(unsigned char* buffer, size_t len) { if (available()) { - size_t size = 0; + uint16_t size = 0; if (!ServerDrv::getDataBuf(_sock, buffer, &size)) return -1; // TODO check if the buffer is too smal respect to buffer size diff --git a/libraries/WiFi/utility/spi_drv.cpp b/libraries/WiFi/utility/spi_drv.cpp index 12a320b..2c32470 100644 --- a/libraries/WiFi/utility/spi_drv.cpp +++ b/libraries/WiFi/utility/spi_drv.cpp @@ -1,5 +1,6 @@ #include "Arduino.h" +#include #include "spi_drv.h" #include "pins_arduino.h" //#define _DEBUG_ @@ -14,45 +15,29 @@ extern "C" { #define SLAVEREADY 7 // handshake pin #define WIFILED 9 // led on wifi shield -#define DELAY_100NS do { asm volatile("nop"); }while(0); -#define DELAY_SPI(X) { int ii=0; do { asm volatile("nop"); }while(++ii #include "wl_definitions.h" #define CMD_FLAG 0 ajtcl-16.04/src/target/darwin/000077500000000000000000000000001271074662300161725ustar00rootroot00000000000000ajtcl-16.04/src/target/darwin/SConscript000066400000000000000000000003401271074662300202010ustar00rootroot00000000000000Import('src_env') # Enable common components for Linux src_env['crypto'] = True src_env['external_sha2'] = True src_env['malloc'] = True src_env['nvram'] = True # Build target source src_env['srcs'] += src_env.Glob('*.c') ajtcl-16.04/src/target/darwin/aj_net.c000066400000000000000000000741251271074662300176070ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE NET #include #include #include #include #include #include #include #define __APPLE_USE_RFC_3542 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgNET = 0; #endif #define INVALID_SOCKET (-1) #define SO_REUSEADDR SO_REUSEPORT #ifndef IPV6_ADD_MEMBERSHIP #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #endif #ifndef IPV6_DROP_MEMBERSHIP #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif #define MSG_NOSIGNAL 0 /* * IANA assigned IPv4 multicast group for AllJoyn. */ static const char AJ_IPV4_MULTICAST_GROUP[] = "224.0.0.113"; /* * IANA assigned IPv6 multicast group for AllJoyn. */ static const char AJ_IPV6_MULTICAST_GROUP[] = "ff02::13a"; /* * IANA assigned UDP multicast port for AllJoyn */ #define AJ_UDP_PORT 9956 /* * IANA-assigned IPv4 multicast group for mDNS. */ static const char MDNS_IPV4_MULTICAST_GROUP[] = "224.0.0.251"; /* * IANA-assigned IPv6 multicast group for mDNS. */ static const char MDNS_IPV6_MULTICAST_GROUP[] = "ff02::fb"; /* * IANA-assigned UDP multicast port for mDNS */ #define MDNS_UDP_PORT 5353 /** * Target-specific contexts for network I/O */ typedef struct { int tcpSock; } NetContext; typedef struct { int udpSock; int udp6Sock; int mDnsSock; int mDns6Sock; int mDnsRecvSock; uint32_t mDnsRecvAddr; uint16_t mDnsRecvPort; } MCastContext; static NetContext netContext = { INVALID_SOCKET }; static MCastContext mCastContext = { INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET }; static AJ_Status CloseNetSock(AJ_NetSocket* netSock) { NetContext* context = (NetContext*)netSock->rx.context; if (context) { if (context->tcpSock != INVALID_SOCKET) { struct linger l; l.l_onoff = 1; l.l_linger = 0; setsockopt(context->tcpSock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l)); shutdown(context->tcpSock, SHUT_RDWR); close(context->tcpSock); } context->tcpSock = INVALID_SOCKET; memset(netSock, 0, sizeof(AJ_NetSocket)); } return AJ_OK; } static AJ_Status CloseMCastSock(AJ_MCastSocket* mcastSock) { MCastContext* context = (MCastContext*)mcastSock->rx.context; if (context) { if (context->udpSock != INVALID_SOCKET) { close(context->udpSock); } if (context->udp6Sock != INVALID_SOCKET) { close(context->udp6Sock); } if (context->mDnsSock != INVALID_SOCKET) { close(context->mDnsSock); } if (context->mDns6Sock != INVALID_SOCKET) { close(context->mDns6Sock); } if (context->mDnsRecvSock != INVALID_SOCKET) { close(context->mDnsRecvSock); } context->udpSock = context->udp6Sock = context->mDnsSock = context->mDns6Sock = context->mDnsRecvSock = INVALID_SOCKET; memset(mcastSock, 0, sizeof(AJ_MCastSocket)); } return AJ_OK; } AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { NetContext* context = (NetContext*) buf->context; ssize_t ret; size_t tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_Send(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { ret = send(context->tcpSock, buf->readPtr, tx, MSG_NOSIGNAL); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_Send(): send() failed. errno=\"%s\", status=AJ_ERR_WRITE\n", strerror(errno))); return AJ_ERR_WRITE; } buf->readPtr += ret; } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_Net_Send(): status=AJ_OK\n")); return AJ_OK; } /* * An eventfd handle used for interrupting a network read blocked on select */ static int interruptFd = INVALID_SOCKET; /* * The socket that is blocked in select */ static uint8_t blocked; /* * This function is called to cancel a pending select. */ void AJ_Net_Interrupt() { if (blocked) { uint64_t u64; write(interruptFd, &u64, sizeof(u64)); } } AJ_Status AJ_Net_Recv(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { NetContext* context = (NetContext*) buf->context; AJ_Status status = AJ_OK; size_t rx = AJ_IO_BUF_SPACE(buf); fd_set fds; int rc = 0; int maxFd = context->tcpSock; struct timeval tv = { timeout / 1000, 1000 * (timeout % 1000) }; // AJ_InfoPrintf(("AJ_Net_Recv(buf=0x%p, len=%d, timeout=%d)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); FD_ZERO(&fds); FD_SET(context->tcpSock, &fds); if (interruptFd >= 0) { FD_SET(interruptFd, &fds); maxFd = max(maxFd, interruptFd); } blocked = TRUE; rc = select(maxFd + 1, &fds, NULL, NULL, &tv); blocked = FALSE; if (rc == 0) { return AJ_ERR_TIMEOUT; } if ((interruptFd >= 0) && FD_ISSET(interruptFd, &fds)) { uint64_t u64; read(interruptFd, &u64, sizeof(u64)); return AJ_ERR_INTERRUPTED; } rx = min(rx, len); if (rx) { ssize_t ret = recv(context->tcpSock, buf->writePtr, rx, 0); if ((ret == -1) || (ret == 0)) { AJ_ErrPrintf(("AJ_Net_Recv(): recv() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_Recv(): recv'd %d from tcp\n", ret)); buf->writePtr += ret; } } return status; } static uint8_t rxData[AJ_RX_DATA_SIZE]; static uint8_t txData[AJ_TX_DATA_SIZE]; AJ_Status AJ_Net_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { int ret; struct sockaddr_storage addrBuf; socklen_t addrSize; int tcpSock = INVALID_SOCKET; AJ_InfoPrintf(("AJ_Net_Connect(bus=0x%p, addrType=%d.)\n", bus, service->addrTypes)); memset(&addrBuf, 0, sizeof(addrBuf)); tcpSock = socket(AF_INET, SOCK_STREAM, 0); if (tcpSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_Connect(): socket() failed. status=AJ_ERR_CONNECT\n")); goto ConnectError; } if (service->addrTypes & AJ_ADDR_TCP4) { struct sockaddr_in* sa = (struct sockaddr_in*)&addrBuf; sa->sin_family = AF_INET; sa->sin_port = htons(service->ipv4port); sa->sin_addr.s_addr = service->ipv4; addrSize = sizeof(struct sockaddr_in); AJ_InfoPrintf(("AJ_Net_Connect(): Connect to \"%s:%u\"\n", inet_ntoa(sa->sin_addr), service->ipv4port));; } else if (service->addrTypes & AJ_ADDR_TCP6) { struct sockaddr_in6* sa = (struct sockaddr_in6*)&addrBuf; sa->sin6_family = AF_INET6; sa->sin6_port = htons(service->ipv6port); memcpy(sa->sin6_addr.s6_addr, service->ipv6, sizeof(sa->sin6_addr.s6_addr)); addrSize = sizeof(struct sockaddr_in6); } else { AJ_ErrPrintf(("AJ_Net_Connect: only TCPv6 and TCPv4 are supported\n")); goto ConnectError; } ret = connect(tcpSock, (struct sockaddr*)&addrBuf, addrSize); if (ret < 0) { AJ_ErrPrintf(("AJ_Net_Connect(): connect() failed. errno=\"%s\", status=AJ_ERR_CONNECT\n", strerror(errno))); goto ConnectError; } else { netContext.tcpSock = tcpSock; AJ_IOBufInit(&bus->sock.rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, &netContext); bus->sock.rx.recv = AJ_Net_Recv; AJ_IOBufInit(&bus->sock.tx, txData, sizeof(txData), AJ_IO_BUF_TX, &netContext); bus->sock.tx.send = AJ_Net_Send; AJ_InfoPrintf(("AJ_Net_Connect(): status=AJ_OK\n")); } return AJ_OK; ConnectError: if (interruptFd != INVALID_SOCKET) { close(interruptFd); interruptFd = INVALID_SOCKET; } if (tcpSock != INVALID_SOCKET) { close(tcpSock); } return AJ_ERR_CONNECT; } void AJ_Net_Disconnect(AJ_NetSocket* netSock) { if (interruptFd >= 0) { close(interruptFd); interruptFd = -1; } CloseNetSock(netSock); } static void sendToBroadcast(int sock, uint16_t port, void* ptr, size_t tx) { struct ifaddrs* addrs; struct ifaddrs* addr; getifaddrs(&addrs); addr = addrs; while (addr != NULL) { // only care about IPV4 if (addr->ifa_addr != NULL && addr->ifa_addr->sa_family == AF_INET) { char buf[INET_ADDRSTRLEN]; struct sockaddr_in* sin_bcast = &((struct sockaddr_in*) addr->ifa_addr)->sin_addr; sin_bcast->sin_port = htons(port); inet_ntop(AF_INET, &(sin_bcast->sin_addr), buf, sizeof(buf)); AJ_InfoPrintf(("sendToBroadcast: sending to bcast addr %s\n", buf)); sendto(sock, ptr, tx, MSG_NOSIGNAL, (struct sockaddr*) sin_bcast, sizeof(struct sockaddr_in)); } addr = addr->ifa_next; } freeifaddrs(addrs); } static AJ_Status RewriteSenderInfo(AJ_IOBuffer* buf, uint32_t addr, uint16_t port) { uint16_t sidVal; const char send[4] = { 'd', 'n', 'e', 's' }; const char ipv4[] = { 'i', 'p', 'v', '4', '=' }; const char sid[] = { 's', 'i', 'd', '=' }; const char upcv4[] = { 'u', 'p', 'c', 'v', '4', '=' }; char sidStr[6]; char ipv4Str[17]; char upcv4Str[6]; uint8_t* pkt; uint16_t dataLength; int match; AJ_Status status; // first, pluck the search ID from the mDNS header sidVal = *(buf->readPtr) << 8; sidVal += *(buf->readPtr + 1); // convert to strings status = AJ_IntToString((int32_t) sidVal, sidStr, sizeof(sidStr)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_IntToString((int32_t) port, upcv4Str, sizeof(upcv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_InetToString(addr, ipv4Str, sizeof(ipv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } // ASSUMPTIONS: sender-info resource record is the final resource record in the packet. // sid, ipv4, and upcv4 key value pairs are the final three key/value pairs in the record. // The length of the other fields in the record are static. // // search backwards through packet to find the start of "sender-info" pkt = buf->writePtr; match = 0; do { if (*(pkt--) == send[match]) { match++; } else { match = 0; } } while (pkt != buf->readPtr && match != 4); if (match != 4) { return AJ_ERR_WRITE; } // move forward to the Data Length field pkt += 22; // actual data length is the length of the static values already in the buffer plus // the three dynamic key-value pairs to re-write dataLength = 23 + 1 + sizeof(ipv4) + strlen(ipv4Str) + 1 + sizeof(sid) + strlen(sidStr) + 1 + sizeof(upcv4) + strlen(upcv4Str); *pkt++ = (dataLength >> 8) & 0xFF; *pkt++ = dataLength & 0xFF; // move forward past the static key-value pairs pkt += 23; // ASSERT: must be at the start of "sid=" assert(*(pkt + 1) == 's'); // re-write new values *pkt++ = sizeof(ipv4) + strlen(ipv4Str); memcpy(pkt, ipv4, sizeof(ipv4)); pkt += sizeof(ipv4); memcpy(pkt, ipv4Str, strlen(ipv4Str)); pkt += strlen(ipv4Str); *pkt++ = sizeof(sid) + strlen(sidStr); memcpy(pkt, sid, sizeof(sid)); pkt += sizeof(sid); memcpy(pkt, sidStr, strlen(sidStr)); pkt += strlen(sidStr); *pkt++ = sizeof(upcv4) + strlen(upcv4Str); memcpy(pkt, upcv4, sizeof(upcv4)); pkt += sizeof(upcv4); memcpy(pkt, upcv4Str, strlen(upcv4Str)); pkt += strlen(upcv4Str); buf->writePtr = pkt; return AJ_OK; } AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { ssize_t ret = -1; uint8_t sendSucceeded = FALSE; size_t tx = AJ_IO_BUF_AVAIL(buf); MCastContext* context = (MCastContext*) buf->context; AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { if ((context->udpSock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_AJ)) { struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(AJ_UDP_PORT); if (inet_pton(AF_INET, AJ_IPV4_MULTICAST_GROUP, &sin.sin_addr) == 1) { ret = sendto(context->udpSock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*)&sin, sizeof(sin)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto AJ IPv4 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid AJ IP address. errno=\"%s\"\n", strerror(errno))); } sendToBroadcast(context->udpSock, AJ_UDP_PORT, buf->readPtr, tx); } // now sendto the ipv6 address if ((context->udp6Sock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_AJ)) { struct sockaddr_in6 sin6; sin6.sin6_family = AF_INET6; sin6.sin6_flowinfo = 0; sin6.sin6_scope_id = 0; sin6.sin6_port = htons(AJ_UDP_PORT); if (inet_pton(AF_INET6, AJ_IPV6_MULTICAST_GROUP, &sin6.sin6_addr) == 1) { ret = sendto(context->udp6Sock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*) &sin6, sizeof(sin6)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto AJ IPv6 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid AJ IPv6 address. errno=\"%s\"\n", strerror(errno))); } } } if (buf->flags & AJ_IO_BUF_MDNS) { if (RewriteSenderInfo(buf, context->mDnsRecvAddr, context->mDnsRecvPort) != AJ_OK) { AJ_WarnPrintf(("AJ_Net_SendTo(): RewriteSenderInfo failed.\n")); tx = 0; } else { tx = AJ_IO_BUF_AVAIL(buf); } } if (tx > 0) { if ((context->mDnsSock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_MDNS)) { struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(MDNS_UDP_PORT); if (inet_pton(AF_INET, MDNS_IPV4_MULTICAST_GROUP, &sin.sin_addr) == 1) { ret = sendto(context->mDnsSock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*)&sin, sizeof(sin)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto mDNS IPv4 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid mDNS IP address. errno=\"%s\"\n", strerror(errno))); } sendToBroadcast(context->mDnsSock, MDNS_UDP_PORT, buf->readPtr, tx); } if ((context->mDns6Sock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_MDNS)) { struct sockaddr_in6 sin6; sin6.sin6_family = AF_INET6; sin6.sin6_flowinfo = 0; sin6.sin6_scope_id = 0; sin6.sin6_port = htons(MDNS_UDP_PORT); if (inet_pton(AF_INET6, MDNS_IPV6_MULTICAST_GROUP, &sin6.sin6_addr) == 1) { ret = sendto(context->mDns6Sock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*) &sin6, sizeof(sin6)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto mDNS IPv6 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid mDNS IPv6 address. errno=\"%s\"\n", strerror(errno))); } } if (!sendSucceeded) { /* Not a single send succeeded, return an error */ AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed. errno=\"%s\", status=AJ_ERR_WRITE\n", strerror(errno))); return AJ_ERR_WRITE; } buf->readPtr += ret; } AJ_IO_BUF_RESET(buf); AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; } AJ_Status AJ_Net_RecvFrom(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { MCastContext* context = (MCastContext*) buf->context; AJ_Status status = AJ_OK; ssize_t ret; size_t rx; fd_set fds; int maxFd = INVALID_SOCKET; int rc = 0; struct timeval tv = { timeout / 1000, 1000 * (timeout % 1000) }; // AJ_InfoPrintf(("AJ_Net_RecvFrom(buf=0x%p, len=%d, timeout=%d)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); assert(context->mDnsRecvSock != INVALID_SOCKET); FD_ZERO(&fds); FD_SET(context->mDnsRecvSock, &fds); maxFd = context->mDnsRecvSock; if (context->udpSock != INVALID_SOCKET) { FD_SET(context->udpSock, &fds); maxFd = max(maxFd, context->udpSock); } if (context->udp6Sock != INVALID_SOCKET) { FD_SET(context->udp6Sock, &fds); maxFd = max(maxFd, context->udp6Sock); } rc = select(maxFd + 1, &fds, NULL, NULL, &tv); if (rc == 0) { AJ_InfoPrintf(("AJ_Net_RecvFrom(): select() timed out. status=AJ_ERR_TIMEOUT\n")); return AJ_ERR_TIMEOUT; } // we need to read from the first socket that has data available. rx = AJ_IO_BUF_SPACE(buf); if (context->mDnsRecvSock != INVALID_SOCKET && FD_ISSET(context->mDnsRecvSock, &fds)) { rx = min(rx, len); if (rx) { ret = recvfrom(context->mDnsRecvSock, buf->writePtr, rx, 0, NULL, 0); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): mDnsRecvSock recvfrom() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_RecvFrom(): recv'd %d from mDNS\n", (int) ret)); buf->flags |= AJ_IO_BUF_MDNS; buf->writePtr += ret; status = AJ_OK; goto Finished; } } } rx = AJ_IO_BUF_SPACE(buf); if (context->udp6Sock != INVALID_SOCKET && FD_ISSET(context->udp6Sock, &fds)) { rx = min(rx, len); if (rx) { ret = recvfrom(context->udp6Sock, buf->writePtr, rx, 0, NULL, 0); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): recvfrom() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_RecvFrom(): recv'd %d from udp6\n", (int) ret)); buf->flags |= AJ_IO_BUF_AJ; buf->writePtr += ret; status = AJ_OK; goto Finished; } } } rx = AJ_IO_BUF_SPACE(buf); if (context->udpSock != INVALID_SOCKET && FD_ISSET(context->udpSock, &fds)) { rx = min(rx, len); if (rx) { ret = recvfrom(context->udpSock, buf->writePtr, rx, 0, NULL, 0); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): recvfrom() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_RecvFrom(): recv'd %d from udp\n", (int) ret)); buf->flags |= AJ_IO_BUF_AJ; buf->writePtr += ret; status = AJ_OK; goto Finished; } } } Finished: if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Net_RecvFrom(): status=%s\n", AJ_StatusText(status))); } return status; } /* * Need enough space to receive a complete name service packet when used in UDP * mode. NS expects MTU of 1500 subtracts UDP, IP and ethertype overhead. * 1500 - 8 -20 - 18 = 1454. txData buffer size needs to be big enough to hold * max(NS WHO-HAS for one name (4 + 2 + 256 = 262), * mDNS query for one name (194 + 5 + 5 + 15 + 256 = 475)) = 475 */ static uint8_t rxDataMCast[1454]; static uint8_t txDataMCast[475]; static int MCastUp4(const char group[], uint16_t port) { int ret; struct ip_mreq mreq; struct sockaddr_in sin; int reuse = 1; int bcast = 1; int mcastSock; int disableSigPipe = 1; mcastSock = socket(AF_INET, SOCK_DGRAM, 0); if (mcastSock == INVALID_SOCKET) { AJ_ErrPrintf(("MCastUp4(): socket() fails. status=AJ_ERR_READ\n")); return INVALID_SOCKET; } ret = setsockopt(mcastSock, SOL_SOCKET, SO_NOSIGPIPE, &disableSigPipe, sizeof(disableSigPipe)); if (ret != 0) { AJ_ErrPrintf(("MCastUp4(): setsockopt(SO_NOSIGPIPE) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } ret = setsockopt(mcastSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (ret != 0) { AJ_ErrPrintf(("MCastUp4(): setsockopt(SO_REUSEADDR) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } // enable IP broadcast on this socket. // This is needed for bcast router discovery int r = setsockopt(mcastSock, SOL_SOCKET, SO_BROADCAST, (void*) &bcast, sizeof(bcast)); if (r != 0) { AJ_ErrPrintf(("BcastUp4(): setsockopt(SOL_SOCKET, SO_BROADCAST) failed. errno=\"%s\"\n", strerror(errno))); goto ExitError; } /* * Bind supplied port */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.s_addr = INADDR_ANY; ret = bind(mcastSock, (struct sockaddr*) &sin, sizeof(sin)); if (ret < 0) { AJ_ErrPrintf(("MCastUp4(): bind() failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } /* * Join our multicast group */ memset(&mreq, 0, sizeof(mreq)); inet_pton(AF_INET, group, &mreq.imr_multiaddr); mreq.imr_interface.s_addr = INADDR_ANY; ret = setsockopt(mcastSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); if (ret < 0) { AJ_WarnPrintf(("MCastUp4(): setsockopt(IP_ADD_MEMBERSHIP) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); } return mcastSock; ExitError: close(mcastSock); return INVALID_SOCKET; } static int MCastUp6(const char* group, uint16_t port) { int ret; struct ipv6_mreq mreq6; struct sockaddr_in6 sin6; int reuse = 1; int mcastSock; mcastSock = socket(AF_INET6, SOCK_DGRAM, 0); if (mcastSock == INVALID_SOCKET) { AJ_ErrPrintf(("MCastUp6(): socket() fails. errno=\"%s\" status=AJ_ERR_READ\n", strerror(errno))); return INVALID_SOCKET; } ret = setsockopt(mcastSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (ret != 0) { AJ_ErrPrintf(("MCastUp6(): setsockopt(SO_REUSEADDR) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } /* * Bind supplied port */ memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); sin6.sin6_addr = in6addr_any; ret = bind(mcastSock, (struct sockaddr*) &sin6, sizeof(sin6)); if (ret < 0) { AJ_ErrPrintf(("MCastUp6(): bind() failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } /* * Join multicast group */ memset(&mreq6, 0, sizeof(mreq6)); inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = 0; ret = setsockopt(mcastSock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)); if (ret < 0) { AJ_ErrPrintf(("MCastUp6(): setsockopt(IP_ADD_MEMBERSHIP) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } return mcastSock; ExitError: close(mcastSock); return INVALID_SOCKET; } static uint32_t chooseMDnsRecvAddr() { uint32_t recvAddr = 0; struct ifaddrs* addrs; struct ifaddrs* addr; #ifndef NDEBUG const char*env = getenv("ER_DEBUG_MDNS_RECV_ADDR"); if (env) { struct in_addr ip; if (inet_pton(AF_INET, env, &ip)) { return ip.s_addr; } AJ_ErrPrintf(("chooseMDnsRecvAddr(): ER_DEBUG_MDNS_RECV_ADDR address (%s) is not a valid IPv4 address \n", env)); } #endif getifaddrs(&addrs); addr = addrs; while (addr != NULL) { // Choose first IPv4 address that is not LOOPBACK if (addr->ifa_addr != NULL && addr->ifa_addr->sa_family == AF_INET && !(addr->ifa_flags & IFF_LOOPBACK)) { struct sockaddr_in* sin = (struct sockaddr_in*) addr->ifa_addr; recvAddr = sin->sin_addr.s_addr; } addr = addr->ifa_next; } freeifaddrs(addrs); return recvAddr; } static int MDnsRecvUp() { int ret; struct sockaddr_in sin; int reuse = 1; int recvSock; recvSock = socket(AF_INET, SOCK_DGRAM, 0); if (recvSock == INVALID_SOCKET) { AJ_ErrPrintf(("MDnsRecvUp(): socket() fails. status=AJ_ERR_READ\n")); goto ExitError; } ret = setsockopt(recvSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (ret != 0) { AJ_ErrPrintf(("MDnsRecvUp(): setsockopt(SO_REUSEADDR) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } sin.sin_family = AF_INET; sin.sin_port = htons(0); sin.sin_addr.s_addr = INADDR_ANY; ret = bind(recvSock, (struct sockaddr*) &sin, sizeof(sin)); if (ret < 0) { AJ_ErrPrintf(("MDnsRecvUp(): bind() failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } return recvSock; ExitError: close(recvSock); return INVALID_SOCKET; } AJ_Status AJ_Net_MCastUp(AJ_MCastSocket* mcastSock) { struct sockaddr_storage addrBuf; socklen_t addrLen = sizeof(addrBuf); struct sockaddr_in* sin; AJ_Status status = AJ_ERR_READ; mCastContext.mDnsRecvSock = MDnsRecvUp(); if (mCastContext.mDnsRecvSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_MCastUp(): MDnsRecvUp for mDnsRecvPort failed")); return status; } if (getsockname(mCastContext.mDnsRecvSock, (struct sockaddr*) &addrBuf, &addrLen)) { AJ_ErrPrintf(("AJ_Net_MCastUp(): getsockname for mDnsRecvPort failed")); goto ExitError; } sin = (struct sockaddr_in*) &addrBuf; mCastContext.mDnsRecvPort = ntohs(sin->sin_port); mCastContext.mDnsRecvAddr = ntohl(chooseMDnsRecvAddr()); if (mCastContext.mDnsRecvAddr == 0) { AJ_ErrPrintf(("AJ_Net_MCastUp(): no mDNS recv address")); goto ExitError; } AJ_InfoPrintf(("AJ_Net_MCastUp(): mDNS recv on %d.%d.%d.%d:%d\n", ((mCastContext.mDnsRecvAddr >> 24) & 0xFF), ((mCastContext.mDnsRecvAddr >> 16) & 0xFF), ((mCastContext.mDnsRecvAddr >> 8) & 0xFF), (mCastContext.mDnsRecvAddr & 0xFF), mCastContext.mDnsRecvPort)); mCastContext.mDnsSock = MCastUp4(MDNS_IPV4_MULTICAST_GROUP, MDNS_UDP_PORT); mCastContext.mDns6Sock = INVALID_SOCKET; //MCastUp6(MDNS_IPV6_MULTICAST_GROUP, MDNS_UDP_PORT); if (AJ_GetMinProtoVersion() < 10) { mCastContext.udpSock = MCastUp4(AJ_IPV4_MULTICAST_GROUP, 0); mCastContext.udp6Sock = INVALID_SOCKET; //MCastUp6(AJ_IPV6_MULTICAST_GROUP, 0); } if (mCastContext.udpSock != INVALID_SOCKET || mCastContext.udp6Sock != INVALID_SOCKET || mCastContext.mDnsSock != INVALID_SOCKET || mCastContext.mDns6Sock != INVALID_SOCKET) { AJ_IOBufInit(&mcastSock->rx, rxDataMCast, sizeof(rxDataMCast), AJ_IO_BUF_RX, &mCastContext); mcastSock->rx.recv = AJ_Net_RecvFrom; AJ_IOBufInit(&mcastSock->tx, txDataMCast, sizeof(txDataMCast), AJ_IO_BUF_TX, &mCastContext); mcastSock->tx.send = AJ_Net_SendTo; status = AJ_OK; } return status; ExitError: close(mCastContext.mDnsRecvSock); return status; } void AJ_Net_MCastDown(AJ_MCastSocket* mcastSock) { MCastContext* context = (MCastContext*) mcastSock->rx.context; AJ_InfoPrintf(("AJ_Net_MCastDown(mcastSock=0x%p)\n", mcastSock)); if (context->udpSock != INVALID_SOCKET) { struct ip_mreq mreq; inet_pton(AF_INET, AJ_IPV4_MULTICAST_GROUP, &mreq.imr_multiaddr); mreq.imr_interface.s_addr = INADDR_ANY; setsockopt(context->udpSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*) &mreq, sizeof(mreq)); } if (context->udp6Sock != INVALID_SOCKET) { struct ipv6_mreq mreq6; inet_pton(AF_INET6, AJ_IPV6_MULTICAST_GROUP, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = 0; setsockopt(context->udp6Sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6)); } if (context->mDnsSock != INVALID_SOCKET) { struct ip_mreq mreq; inet_pton(AF_INET, MDNS_IPV4_MULTICAST_GROUP, &mreq.imr_multiaddr); mreq.imr_interface.s_addr = INADDR_ANY; setsockopt(context->udpSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*) &mreq, sizeof(mreq)); } if (context->mDns6Sock != INVALID_SOCKET) { struct ipv6_mreq mreq6; inet_pton(AF_INET6, MDNS_IPV6_MULTICAST_GROUP, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = 0; setsockopt(context->udp6Sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6)); } CloseMCastSock(mcastSock); } ajtcl-16.04/src/target/darwin/aj_target.h000066400000000000000000000047221271074662300203100ustar00rootroot00000000000000#ifndef _AJ_TARGET_H #define _AJ_TARGET_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef max #define max(x, y) ((x) > (y) ? (x) : (y)) #endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define WORD_ALIGN(x) ((x & 0x3) ? ((x >> 2) + 1) << 2 : x) #if defined(__LITTLE_ENDIAN__) #define HOST_IS_LITTLE_ENDIAN TRUE #define HOST_IS_BIG_ENDIAN FALSE #else #define HOST_IS_LITTLE_ENDIAN FALSE #define HOST_IS_BIG_ENDIAN TRUE #endif #define AJ_Printf(fmat, ...) \ do { printf(fmat, ## __VA_ARGS__); } while (0) #ifndef NDEBUG extern uint8_t dbgCONFIGUREME; extern uint8_t dbgINIT; extern uint8_t dbgNET; extern uint8_t dbgTARGET_CRYPTO; extern uint8_t dbgTARGET_NVRAM; extern uint8_t dbgTARGET_SERIAL; extern uint8_t dbgTARGET_TIMER; extern uint8_t dbgTARGET_UTIL; #endif #define AJ_ASSERT(x) assert(x) /* * AJ_Reboot() is a NOOP on this platform */ #define AJ_Reboot() #define AJ_CreateNewGUID AJ_RandBytes #define AJ_GetDebugTime(x) AJ_ERR_RESOURCES #define AJ_EXPORT #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) #define AJ_DEPRECATED(func) func __attribute__((deprecated)) /**< mark a function as deprecated in gcc. */ #else #define AJ_DEPRECATED(func) func /**< not all gcc versions support the deprecated attribute. */ #endif #endif ajtcl-16.04/src/target/darwin/aj_target_crypto.c000066400000000000000000000047001271074662300216770ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE TARGET_CRYPTO #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_CRYPTO = 0; #endif /* * Context for AES-128 CTR DRBG */ static CTR_DRBG_CTX drbgctx; uint32_t AJ_PlatformEntropy(uint8_t* data, uint32_t size) { FILE* f = fopen("/dev/urandom", "r"); if (NULL == f) { return 0; } size = fread(data, sizeof (uint8_t), size, f); fclose(f); return size; } void AJ_RandBytes(uint8_t* rand, uint32_t size) { AJ_Status status = AJ_ERR_SECURITY; uint8_t seed[SEEDLEN]; if (rand && size) { status = AES_CTR_DRBG_Generate(&drbgctx, rand, size); if (AJ_OK != status) { // Reseed required AJ_PlatformEntropy(seed, sizeof (seed)); AES_CTR_DRBG_Reseed(&drbgctx, seed, sizeof (seed)); status = AES_CTR_DRBG_Generate(&drbgctx, rand, size); } } else { // This is the first call to initialize size = AJ_PlatformEntropy(seed, sizeof (seed)); drbgctx.df = (SEEDLEN == size) ? 0 : 1; AES_CTR_DRBG_Instantiate(&drbgctx, seed, sizeof (seed), drbgctx.df); } } ajtcl-16.04/src/target/darwin/aj_target_nvram.c000066400000000000000000000074121271074662300215050ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE TARGET_NVRAM #include #include #include "../../aj_target_nvram.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_NVRAM = 0; #endif uint8_t AJ_EMULATED_NVRAM[AJ_NVRAM_SIZE]; uint8_t* AJ_NVRAM_BASE_ADDRESS; extern void AJ_NVRAM_Layout_Print(); void AJ_NVRAM_Init() { AJ_NVRAM_BASE_ADDRESS = AJ_EMULATED_NVRAM; _AJ_LoadNVFromFile(); if (*((uint32_t*)AJ_NVRAM_BASE_ADDRESS) != AJ_NV_SENTINEL) { AJ_NVRAM_Clear(); _AJ_StoreNVToFile(); } } void _AJ_NV_Write(void* dest, const void* buf, uint16_t size) { memcpy(dest, buf, size); _AJ_StoreNVToFile(); } void _AJ_NV_Move(void* dest, const void* buf, uint16_t size) { memmove(dest, buf, size); _AJ_StoreNVToFile(); } void _AJ_NV_Read(void* src, void* buf, uint16_t size) { memcpy(buf, src, size); } void _AJ_NVRAM_Clear() { memset((uint8_t*)AJ_NVRAM_BASE_ADDRESS, INVALID_DATA_BYTE, AJ_NVRAM_SIZE); *((uint32_t*)AJ_NVRAM_BASE_ADDRESS) = AJ_NV_SENTINEL; _AJ_StoreNVToFile(); } AJ_Status _AJ_LoadNVFromFile() { FILE* f = fopen("ajlite.nvram", "rb"); if (f == NULL) { AJ_ErrPrintf(("_AJ_LoadNVFromFile(): LoadNVFromFile() failed. status=AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } memset(AJ_NVRAM_BASE_ADDRESS, INVALID_DATA_BYTE, AJ_NVRAM_SIZE); fread(AJ_NVRAM_BASE_ADDRESS, AJ_NVRAM_SIZE, 1, f); fclose(f); return AJ_OK; } AJ_Status _AJ_StoreNVToFile() { FILE* f = fopen("ajlite.nvram", "wb"); if (!f) { AJ_ErrPrintf(("_AJ_StireNVToFile(): LoadNVFromFile() failed. status=AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } fwrite(AJ_NVRAM_BASE_ADDRESS, AJ_NVRAM_SIZE, 1, f); fclose(f); return AJ_OK; } // Compact the storage by removing invalid entries AJ_Status _AJ_CompactNVStorage() { uint16_t capacity = 0; uint16_t id = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); uint8_t* writePtr = (uint8_t*)data; uint16_t entrySize = 0; uint16_t garbage = 0; //AJ_NVRAM_Layout_Print(); while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS && *data != INVALID_DATA) { id = *data; capacity = *(data + 1); entrySize = ENTRY_HEADER_SIZE + capacity; if (id != INVALID_ID) { _AJ_NV_Move(writePtr, data, entrySize); writePtr += entrySize; } else { garbage += entrySize; } data += entrySize >> 1; } memset(writePtr, INVALID_DATA_BYTE, garbage); _AJ_StoreNVToFile(); //AJ_NVRAM_Layout_Print(); return AJ_OK; } ajtcl-16.04/src/target/darwin/aj_target_util.c000066400000000000000000000166541271074662300213470ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE TARGET_UTIL #include #include #include #include #include #include #include #include #include #include #include #include #include #include uint8_t dbgTARGET_UTIL = 0; void AJ_Sleep(uint32_t time) { struct timespec waittime = { }; waittime.tv_sec = time / 1000; waittime.tv_nsec = (time % 1000) * 1000000LL; // nanosleep returns the amount of time slept before being interrupted by a signal, // so loop until the full sleep is finished while (nanosleep(&waittime, &waittime) == -1 && errno == EINTR) { continue; } } uint32_t AJ_GetElapsedTime(AJ_Time* timer, uint8_t cumulative) { uint32_t elapsed; struct timespec now; clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); now.tv_sec = mts.tv_sec; now.tv_nsec = mts.tv_nsec; //clock_gettime(CLOCK_MONOTONIC, &now); elapsed = (1000 * (now.tv_sec - timer->seconds)) + ((now.tv_nsec / 1000000) - timer->milliseconds); if (!cumulative) { timer->seconds = now.tv_sec; timer->milliseconds = now.tv_nsec / 1000000; } return elapsed; } void AJ_InitTimer(AJ_Time* timer) { struct timespec now; clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); now.tv_sec = mts.tv_sec; now.tv_nsec = mts.tv_nsec; //clock_gettime(CLOCK_MONOTONIC, &now); timer->seconds = now.tv_sec; timer->milliseconds = now.tv_nsec / 1000000; } int32_t AJ_GetTimeDifference(AJ_Time* timerA, AJ_Time* timerB) { int32_t diff; diff = (1000 * (timerA->seconds - timerB->seconds)) + (timerA->milliseconds - timerB->milliseconds); return diff; } void AJ_TimeAddOffset(AJ_Time* timerA, uint32_t msec) { uint32_t msecNew; if (msec == -1) { timerA->seconds = -1; timerA->milliseconds = -1; } else { msecNew = (timerA->milliseconds + msec); timerA->seconds = timerA->seconds + (msecNew / 1000); timerA->milliseconds = msecNew % 1000; } } int8_t AJ_CompareTime(AJ_Time timerA, AJ_Time timerB) { if (timerA.seconds == timerB.seconds) { if (timerA.milliseconds == timerB.milliseconds) { return 0; } else if (timerA.milliseconds > timerB.milliseconds) { return 1; } else { return -1; } } else if (timerA.seconds > timerB.seconds) { return 1; } else { return -1; } } uint64_t AJ_DecodeTime(char* der, const char* fmt) { struct tm tm; if (!strptime(der, fmt, &tm)) { return 0; } return (uint64_t) timegm(&tm); } void* AJ_Malloc(size_t sz) { return malloc(sz); } void* AJ_Realloc(void* ptr, size_t size) { return realloc(ptr, size); } void AJ_Free(void* mem) { if (mem) { free(mem); } } void AJ_MemZeroSecure(void* s, size_t n) { volatile unsigned char* p = s; while (n--) *p++ = '\0'; return; } /* * get a line of input from the the file pointer (most likely stdin). * This will capture the the num-1 characters or till a newline character is * entered. * * @param[out] str a pointer to a character array that will hold the user input * @param[in] num the size of the character array 'str' * @param[in] fp the file pointer the sting will be read from. (most likely stdin) * * @return returns the same string as 'str' if there has been a read error a null * pointer will be returned and 'str' will remain unchanged. */ char*AJ_GetLine(char*str, size_t num, void*fp) { char*p = fgets(str, num, fp); if (p != NULL) { size_t last = strlen(str) - 1; if (str[last] == '\n') { str[last] = '\0'; } } return p; } static uint8_t ioThreadRunning = FALSE; static char cmdline[1024]; static uint8_t consumed = TRUE; static pthread_t threadId; void* RunFunc(void* threadArg) { while (ioThreadRunning) { if (consumed) { AJ_GetLine(cmdline, sizeof(cmdline), stdin); consumed = FALSE; } AJ_Sleep(1000); } return 0; } uint8_t AJ_StartReadFromStdIn() { int ret = 0; if (!ioThreadRunning) { ret = pthread_create(&threadId, NULL, RunFunc, NULL); if (ret != 0) { AJ_ErrPrintf(("Error: fail to spin a thread for reading from stdin\n")); } ioThreadRunning = TRUE; return TRUE; } return FALSE; } char* AJ_GetCmdLine(char* buf, size_t num) { if (!consumed) { strncpy(buf, cmdline, num); buf[num - 1] = '\0'; consumed = TRUE; return buf; } return NULL; } uint8_t AJ_StopReadFromStdIn() { void* exit_status; if (ioThreadRunning) { ioThreadRunning = FALSE; pthread_join(threadId, &exit_status); return TRUE; } return FALSE; } #ifndef NDEBUG /* * This is not intended, nor required to be particularly efficient. If you want * efficiency, turn of debugging. */ int _AJ_DbgEnabled(const char* module) { char buffer[128]; char* env; strcpy(buffer, "ER_DEBUG_ALL"); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } strcpy(buffer, "ER_DEBUG_"); strcat(buffer, module); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } return FALSE; } #endif AJ_Status AJ_IntToString(int32_t val, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = snprintf(buf, buflen, "%d", val); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } AJ_Status AJ_InetToString(uint32_t addr, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = snprintf((char*)buf, buflen, "%u.%u.%u.%u", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF)); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } uint16_t AJ_ByteSwap16(uint16_t x) { return OSSwapInt16(x); } uint32_t AJ_ByteSwap32(uint32_t x) { return OSSwapInt32(x); } uint64_t AJ_ByteSwap64(uint64_t x) { return OSSwapInt64(x); } ajtcl-16.04/src/target/freertos-due/000077500000000000000000000000001271074662300173125ustar00rootroot00000000000000ajtcl-16.04/src/target/freertos-due/FreeRTOSConfig.h000066400000000000000000000075431271074662300222130ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef FREERTOSCONFIG_H_ #define FREERTOSCONFIG_H_ #include /* * Configuration options */ #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_MALLOC_FAILED_HOOK 1 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ (84000000UL) #define configTICK_RATE_HZ ((portTickType) 1000) #define configMAX_PRIORITIES ((unsigned portBASE_TYPE) 12) #define configMINIMAL_STACK_SIZE ((unsigned short) 120) #define configTOTAL_HEAP_SIZE ((size_t) 60000) #define configMAX_TASK_NAME_LEN (10) #define configUSE_TRACE_FACILITY 0 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_COUNTING_SEMAPHORES 1 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configQUEUE_REGISTRY_SIZE 8 //#define configGENERATE_RUN_TIME_STATS 1 #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES (2) #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) #define configTIMER_QUEUE_LENGTH 5 #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) #define configCOMMAND_INT_MAX_OUTPUT_SIZE 400 /* * Define what functions should be included */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 /* * Priority configurations: * Cortex-Mx may have its own priority definition and levels */ #if defined(__NVIC_PRIO_BITS) #define PRIORITY_BITS __NVIC_PRIO_BITS #else #define PRIORITY_BITS 4 #endif #define LOWEST_PRIORITY 15 #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 #define configKERNEL_INTERRUPT_PRIORITY (LOWEST_PRIORITY << (8 - PRIORITY_BITS)) #define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - PRIORITY_BITS)) #define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); while (1); } #define INCLUDE_MODULE_TEST 0 #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler #endif /* FREERTOSCONFIG_H_ */ ajtcl-16.04/src/target/freertos-due/SConscript000066400000000000000000000045621271074662300213330ustar00rootroot00000000000000Import('src_env') # Enable common components for Arduino Due running FreeRTOS src_env['crypto'] = True src_env['external_sha2'] = True src_env['malloc'] = True src_env['freertos'] = True src_env['wsl'] = True src_env['nvram'] = True # Build target source src_env['srcs'].extend(Glob('*.c')) src_env['srcs'].extend(Glob(src_env['FREE_RTOS_DIR'] + '/Source/*.c')) src_env['srcs'].extend(Glob(src_env['FREE_RTOS_DIR'] + '/Source/portable/GCC/ARM_CM3/*.c')) src_env['srcs'].extend(File([ src_env['FREE_RTOS_DIR'] + '/Source/portable/GCC/ARM_CM3/port.c', src_env['FREE_RTOS_DIR'] + '/Source/portable/MemMang/heap_3.c', src_env['ATMEL_DIR'] + '/common/services/clock/sam3x/sysclk.c', src_env['ATMEL_DIR'] + '/common/services/spi/sam_spi/spi_master.c', src_env['ATMEL_DIR'] + '/common/services/freertos/sam/freertos_peripheral_control.c', src_env['ATMEL_DIR'] + '/common/services/freertos/sam/freertos_usart_serial.c', src_env['ATMEL_DIR'] + '/common/utils/interrupt/interrupt_sam_nvic.c', src_env['ATMEL_DIR'] + '/common/utils/stdio/read.c', src_env['ATMEL_DIR'] + '/common/utils/stdio/write.c', src_env['ATMEL_DIR'] + '/common/drivers/nvm/sam/sam_nvm.c', src_env['ATMEL_DIR'] + '/sam/boards/arduino_due_x/init.c', src_env['ATMEL_DIR'] + '/sam/boards/arduino_due_x/led.c', src_env['ATMEL_DIR'] + '/sam/drivers/pdc/pdc.c', src_env['ATMEL_DIR'] + '/sam/drivers/pio/pio.c', src_env['ATMEL_DIR'] + '/sam/drivers/pio/pio_handler.c', src_env['ATMEL_DIR'] + '/sam/drivers/pmc/pmc.c', src_env['ATMEL_DIR'] + '/sam/drivers/pmc/sleep.c', src_env['ATMEL_DIR'] + '/sam/drivers/uart/uart.c', src_env['ATMEL_DIR'] + '/sam/drivers/usart/usart.c', src_env['ATMEL_DIR'] + '/sam/drivers/spi/spi.c', src_env['ATMEL_DIR'] + '/sam/drivers/efc/efc.c', src_env['ATMEL_DIR'] + '/sam/drivers/tc/tc.c', src_env['ATMEL_DIR'] + '/sam/drivers/trng/trng.c', src_env['ATMEL_DIR'] + '/sam/drivers/rstc/rstc.c', src_env['ATMEL_DIR'] + '/sam/utils/cmsis/sam3x/source/templates/exceptions.c', src_env['ATMEL_DIR'] + '/sam/utils/cmsis/sam3x/source/templates/system_sam3x.c', src_env['ATMEL_DIR'] + '/sam/utils/cmsis/sam3x/source/templates/gcc/startup_sam3x.c', src_env['ATMEL_DIR'] + '/sam/services/flash_efc/flash_efc.c', src_env['ATMEL_DIR'] + '/sam/utils/syscalls/gcc/syscalls.c', src_env['ATMEL_DIR'] + '/sam/drivers/dmac/dmac.c' ])) ajtcl-16.04/src/target/freertos-due/aj_spi.c000066400000000000000000000347371271074662300207410ustar00rootroot00000000000000/** * @file SPI functionality */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * Any time in this file there is a comment including: ioport_***, pio_***, pmc_***, spi_***, sysclk_***, dmac_*** * note that the API associated with it may be subject to this Atmel license: * (information about it is also at www.atmel.com/asf) * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * 4. This software may only be redistributed and used in connection with an * Atmel microcontroller product. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN * NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include #include #include #include #include #include #include #include "dmac.h" /** DMAC receive channel of master. */ #define AJ_DMA_RX_CHANNEL 0 #define AJ_DMA_TX_CHANNEL 1 /** SPI DMA Operation type, receive or send */ #define AJ_DMA_RX 0 #define AJ_DMA_TX 1 /** DMAC Channel HW Interface Number for SPI. */ #define AJ_SPI_TX_INDEX 1 #define AJ_SPI_RX_INDEX 2 /** Address that can enable an interrupt in the system, from the datasheet */ #define AJ_SPI_ISER1_IEN_ADDR 0xE000E104 /** Bit value that will enable the DMAC interrupt, from the datasheet */ #define AJ_SPI_DMAC_IEN_BIT (1 << 7) /** * Two-dimensional array of structures the control how the DMA controller * writes and reads data between RAM and the SPI hardware. * The structures contain source then destination address, control register * settings, followed by an empty field that would allow linking larger requests */ static const dma_transfer_descriptor_t transfer_descriptors[2][2] = { { /* AJ_DMA_RX descriptors */ { /* AJ_DMA_RX_CHANNEL */ (uint32_t) &SPI0->SPI_RDR, (uint32_t) NULL, DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE, DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING, (uint32_t) NULL }, { /* AJ_DMA_TX_CHANNEL */ (uint32_t) NULL, (uint32_t) &SPI0->SPI_TDR, DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE, DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_FIXED, (uint32_t) NULL } }, { /* AJ_DMA_TX descriptors */ { /* AJ_DMA_RX_CHANNEL */ (uint32_t) &SPI0->SPI_RDR, (uint32_t) NULL, DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE, DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_FIXED, (uint32_t) NULL }, { /* AJ_DMA_TX_CHANNEL */ (uint32_t) NULL, (uint32_t) &SPI0->SPI_TDR, DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE, DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_FIXED, (uint32_t) NULL } } }; void AJ_WSL_SPI_CHIP_SPI_ISR(uint32_t id, uint32_t mask); /* * Configure the SPI hardware, including SPI clock speed, mode, delays, chip select pins * It uses values listed in */ void AJ_WSL_SPI_InitializeSPIController(void) { uint32_t config; /* Initialize and enable DMA controller. */ pmc_enable_periph_clk(ID_DMAC); dmac_init(DMAC); dmac_set_priority_mode(DMAC, DMAC_PRIORITY_ROUND_ROBIN); dmac_enable(DMAC); /* Configure DMA TX channel. */ config = 0; config |= DMAC_CFG_DST_PER(AJ_SPI_TX_INDEX) | DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG; dmac_channel_set_configuration(DMAC, AJ_DMA_TX_CHANNEL, config); /* Configure DMA RX channel. */ config = 0; config |= DMAC_CFG_SRC_PER(AJ_SPI_RX_INDEX) | DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG; dmac_channel_set_configuration(DMAC, AJ_DMA_RX_CHANNEL, config); /* Enable receive channel interrupt for DMAC. */ uint8_t* interruptEnableAddress = AJ_SPI_ISER1_IEN_ADDR; *interruptEnableAddress = AJ_SPI_DMAC_IEN_BIT; dmac_enable_interrupt(DMAC, (1 << AJ_DMA_RX_CHANNEL)); dmac_enable_interrupt(DMAC, (1 << AJ_DMA_TX_CHANNEL)); //AJ_WSL_DMA_Setup(); dmac_channel_disable(DMAC, AJ_DMA_TX_CHANNEL); dmac_channel_disable(DMAC, AJ_DMA_RX_CHANNEL); /* * Configure the hardware to enable SPI and some output pins */ { pmc_enable_periph_clk(ID_PIOA); pmc_enable_periph_clk(ID_PIOB); pmc_enable_periph_clk(ID_PIOC); pmc_enable_periph_clk(ID_PIOD); // make all of these pins controlled by the right I/O controller pio_configure_pin_group(PIOA, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_A); pio_configure_pin_group(PIOB, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_B); pio_configure_pin_group(PIOC, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_C); pio_configure_pin_group(PIOD, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_D); /* * Reset the device by toggling the CHIP_POWER */ ioport_set_pin_dir(AJ_WSL_SPI_CHIP_POWER_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_level(AJ_WSL_SPI_CHIP_POWER_PIN, IOPORT_PIN_LEVEL_LOW); AJ_Sleep(10); ioport_set_pin_level(AJ_WSL_SPI_CHIP_POWER_PIN, IOPORT_PIN_LEVEL_HIGH); /* * Reset the device by toggling the CHIP_PWD# signal */ ioport_set_pin_dir(AJ_WSL_SPI_CHIP_PWD_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_level(AJ_WSL_SPI_CHIP_PWD_PIN, IOPORT_PIN_LEVEL_LOW); AJ_Sleep(10); ioport_set_pin_level(AJ_WSL_SPI_CHIP_PWD_PIN, IOPORT_PIN_LEVEL_HIGH); /* configure the pin that detects SPI data ready from the target chip */ ioport_set_pin_dir(AJ_WSL_SPI_CHIP_SPI_INT_PIN, IOPORT_DIR_INPUT); ioport_set_pin_sense_mode(AJ_WSL_SPI_CHIP_SPI_INT_PIN, IOPORT_SENSE_LEVEL_LOW); pio_handler_set(PIOC, ID_PIOC, AJ_WSL_SPI_CHIP_SPI_INT_BIT, (PIO_PULLUP | PIO_IT_FALL_EDGE), &AJ_WSL_SPI_CHIP_SPI_ISR); pio_handler_set_priority(PIOD, (IRQn_Type) ID_PIOC, 0xB); pio_enable_interrupt(PIOC, AJ_WSL_SPI_CHIP_SPI_INT_BIT); } spi_enable_clock(AJ_WSL_SPI_DEVICE); spi_reset(AJ_WSL_SPI_DEVICE); spi_set_lastxfer(AJ_WSL_SPI_DEVICE); spi_set_master_mode(AJ_WSL_SPI_DEVICE); spi_disable_mode_fault_detect(AJ_WSL_SPI_DEVICE); spi_set_peripheral_chip_select_value(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS); spi_set_clock_polarity(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, AJ_WSL_SPI_CLOCK_POLARITY); spi_set_clock_phase(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, AJ_WSL_SPI_CLOCK_PHASE); spi_set_bits_per_transfer(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, SPI_CSR_BITS_8_BIT); spi_set_baudrate_div(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, (sysclk_get_cpu_hz() / AJ_WSL_SPI_CLOCK_RATE)); spi_set_transfer_delay(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, AJ_WSL_SPI_DELAY_BEFORE_CLOCK, AJ_WSL_SPI_DELAY_BETWEEN_TRANSFERS); spi_set_fixed_peripheral_select(AJ_WSL_SPI_DEVICE); spi_configure_cs_behavior(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, SPI_CS_RISE_FORCED); spi_enable_interrupt(AJ_WSL_SPI_DEVICE, SPI_IER_TDRE | SPI_IER_RDRF); spi_enable(AJ_WSL_SPI_DEVICE); } /** * send_done is set to non-zero when a DMA operation completes, * This allows AJ_WSL_SPI_DMATransfer to finish */ volatile uint32_t AJ_WSL_DMA_send_done = 0; /** * This interrupt handler is called when a DMA operation completes and clears the waiting code * (via send_done) The handler overrides the weak reference to the default interrupt handler. */ void DMAC_Handler(void) { uint32_t ret; ret = dmac_get_status(DMAC); if (ret & (1 << AJ_DMA_TX_CHANNEL)) { AJ_WSL_DMA_send_done = 1; } } void AJ_WSL_SPI_DMATransfer(void* buffer, uint32_t size, uint8_t direction) { dma_transfer_descriptor_t transfer; AJ_ASSERT(AJ_WSL_DMA_send_done == 0); /* Disable both channels before parameters are set */ dmac_channel_disable(DMAC, AJ_DMA_TX_CHANNEL); dmac_channel_disable(DMAC, AJ_DMA_RX_CHANNEL); if (direction == AJ_DMA_TX) { /* Direction is TX so set the destination to the SPI hardware */ transfer = transfer_descriptors[AJ_DMA_TX][AJ_DMA_TX_CHANNEL]; /* Set the source to the buffer your sending */ transfer.ul_source_addr = (uint32_t) buffer; transfer.ul_ctrlA |= size; dmac_channel_single_buf_transfer_init(DMAC, AJ_DMA_TX_CHANNEL, (dma_transfer_descriptor_t*) &transfer); /* Enable the channel to start DMA */ dmac_channel_enable(DMAC, AJ_DMA_TX_CHANNEL); /* Setup RX direction as NULL destination and SPI0 as source */ transfer = transfer_descriptors[AJ_DMA_TX][AJ_DMA_RX_CHANNEL]; transfer.ul_ctrlA |= size; dmac_channel_single_buf_transfer_init(DMAC, AJ_DMA_RX_CHANNEL, &transfer); /* Enable the channel to start DMA */ dmac_channel_enable(DMAC, AJ_DMA_RX_CHANNEL); /* Wait for the transfer to complete */ while (!AJ_WSL_DMA_send_done); } else { /* We are transferring in the RX direction */ /* Set up the destination address */ transfer = transfer_descriptors[AJ_DMA_RX][AJ_DMA_RX_CHANNEL]; transfer.ul_destination_addr = (uint32_t) buffer; transfer.ul_ctrlA |= size; dmac_channel_single_buf_transfer_init(DMAC, AJ_DMA_RX_CHANNEL, &transfer); dmac_channel_enable(DMAC, AJ_DMA_RX_CHANNEL); /* Setup the TX channel to transfer from a NULL pointer * This must be done in order for the transfer to start */ transfer = transfer_descriptors[AJ_DMA_RX][AJ_DMA_TX_CHANNEL]; transfer.ul_ctrlA |= size; dmac_channel_single_buf_transfer_init(DMAC, AJ_DMA_TX_CHANNEL, (dma_transfer_descriptor_t*) &transfer); dmac_channel_enable(DMAC, AJ_DMA_TX_CHANNEL); while (!AJ_WSL_DMA_send_done); } /* reset the DMA completed indicator */ AJ_WSL_DMA_send_done = 0; dmac_channel_disable(DMAC, AJ_DMA_TX_CHANNEL); dmac_channel_disable(DMAC, AJ_DMA_RX_CHANNEL); } void AJ_WSL_SPI_ShutdownSPIController(void) { spi_disable(AJ_WSL_SPI_DEVICE); spi_disable_interrupt(AJ_WSL_SPI_DEVICE, 0xFFFFFFFF); } aj_spi_status AJ_SPI_READ(Spi* p_spi, uint8_t* us_data, uint8_t* p_pcs) { aj_spi_status status; uint16_t data; status = spi_read(p_spi, &data, p_pcs); AJ_ASSERT(status == SPI_OK); *us_data = data & 0xFF; // AJ_InfoPrintf(("=R= %02x\n", (*us_data) & 0xFF)); return status; } aj_spi_status AJ_SPI_WRITE(Spi* p_spi, uint16_t us_data, uint8_t uc_pcs, uint8_t uc_last) { aj_spi_status status; // AJ_InfoPrintf(("=WRITE= %x\n", us_data)); status = spi_write(p_spi, us_data, uc_pcs, uc_last); AJ_ASSERT(status == SPI_OK); return status; } /* * These routines are specific to the hardware target, so they should exist in an aj_target_wsl_spi.c */ /** TX interrupt occurred */ volatile uint8_t g_b_spi_interrupt_tx_ready = false; /** RX interrupt occurred */ volatile uint8_t g_b_spi_interrupt_rx_ready = false; extern struct AJ_TaskHandle* AJ_WSL_MBoxListenHandle; /** * SPI interrupt service routine */ void AJ_WSL_SPI_ISR(void) { uint32_t status = spi_read_status(AJ_WSL_SPI_DEVICE); if (status & SPI_SR_TDRE) { //g_b_spi_interrupt_tx_ready = true; spi_disable_interrupt(AJ_WSL_SPI_DEVICE, SPI_IDR_TDRE); } if (status & SPI_SR_RDRF) { //g_b_spi_interrupt_rx_ready = true; spi_disable_interrupt(AJ_WSL_SPI_DEVICE, SPI_IDR_RDRF); } } volatile uint8_t g_b_spi_interrupt_data_ready = false; /** * ISR that handles the target chip asserting a data ready signal. */ void AJ_WSL_SPI_CHIP_SPI_ISR(uint32_t id, uint32_t mask) { if (ID_PIOC != id || AJ_WSL_SPI_CHIP_SPI_INT_BIT != mask) { return; } pio_disable_interrupt(PIOC, AJ_WSL_SPI_CHIP_SPI_INT_BIT); if (mask & AJ_WSL_SPI_CHIP_SPI_INT_BIT) { g_b_spi_interrupt_data_ready = TRUE; AJ_ResumeTask(AJ_WSL_MBoxListenHandle, TRUE); } pio_enable_interrupt(PIOC, AJ_WSL_SPI_CHIP_SPI_INT_BIT); } ajtcl-16.04/src/target/freertos-due/aj_syscalls.c000066400000000000000000000044701271074662300217720ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include /* * System calls for the STM32F407 */ extern int __io_putchar(int ch) __attribute__((weak)); extern int __io_getchar(void) __attribute__((weak)); int _exit(int s) { while (1); } caddr_t _sbrk(int inc) { static char* end_of_heap; register char* stack asm ("sp"); char* prev_end_of_heap; extern char ld_end asm ("_end"); if (end_of_heap == 0) { end_of_heap = &ld_end; } /* Check that we haven't hit the stack */ if (end_of_heap + inc > stack) { return (caddr_t) -1; } prev_end_of_heap = end_of_heap; end_of_heap += inc; return (caddr_t)prev_end_of_heap; } int _kill(int id, int s) { return -1; } int _getpid(void) { return 0; } int _write(int f, char*pointer, int length) { int i = 0; while (i < length) { __io_putchar(*(pointer + i)); i++; } return length; } int _close(int f) { return 0; } int _fstat(int f, struct stat* s) { return 0; } int _isatty(int f) { return 1; } int _lseek(int f, int p, int d) { return 0; } int _read(int f, char* pointer, int length) { int i = 0; while (i < length) { *(pointer + i) = __io_getchar(); i++; } return length; } ajtcl-16.04/src/target/freertos-due/aj_target.h000066400000000000000000000046331271074662300214310ustar00rootroot00000000000000#ifndef _AJ_TARGET_H #define _AJ_TARGET_H /** * @file WSL target macros and includes */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #define AJ_EXPORT #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef max #define max(x, y) ((x) > (y) ? (x) : (y)) #endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define WORD_ALIGN(x) ((x & 0x3) ? ((x >> 2) + 1) << 2 : x) #define HOST_IS_LITTLE_ENDIAN 1 #define HOST_IS_BIG_ENDIAN 0 #define HOST_ENDIANESS AJ_LITTLE_ENDIAN #ifndef NDEBUG extern uint8_t dbgCONFIGUREME; extern uint8_t dbgINIT; extern uint8_t dbgNET; extern uint8_t dbgTARGET_CRYPTO; extern uint8_t dbgTARGET_NVRAM; extern uint8_t dbgTARGET_SERIAL; extern uint8_t dbgTARGET_TIMER; extern uint8_t dbgTARGET_UTIL; #endif #define AJ_ASSERT(x) assert(x) /* * AJ_Reboot() is a NOOP on this platform */ #define AJ_Reboot() _AJ_Reboot() #define AJ_CreateNewGUID AJ_RandBytes #define AJ_GetDebugTime(x) AJ_ERR_RESOURCES #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) #define AJ_DEPRECATED(func) func __attribute__((deprecated)) /**< mark a function as deprecated in gcc. */ #else #define AJ_DEPRECATED(func) func /**< not all gcc versions support the deprecated attribute. */ #endif #ifdef __cplusplus } #endif #endif ajtcl-16.04/src/target/freertos-due/aj_target_platform.c000066400000000000000000000172571271074662300233360ustar00rootroot00000000000000/** * @file Platform specific functions */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * Any time in this file there is a comment including: nvm_***, sysclk_***, board_***, stdio_***, rstc_*** * note that the API associated with it may be subject to this Atmel license: * (information about it is also at www.atmel.com/asf) * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * 4. This software may only be redistributed and used in connection with an * Atmel microcontroller product. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN * NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include #include #include #include "../../aj_target_nvram.h" #include "aj_bsp.h" void ASSERT(int i) { if (!i) { printf("ASSERT FAILED"); } } #define AJ_NVRAM_SECTOR_SIZE (1024) // Reserve one sector as a buffer for NVRAM storage compaction //#define AJ_NVRAM_COMPACTION_BUF (total - AJ_NVRAM_SECTOR_SIZE) uint8_t* const AJ_NVRAM_BASE_ADDRESS = (uint8_t*)(0x100000 - AJ_NVRAM_SECTOR_SIZE - AJ_NVRAM_SIZE); uint8_t* const AJ_NVRAM_COMPACTION_BUF = (uint8_t*)(0x100000 - AJ_NVRAM_SECTOR_SIZE); #define AJ_NVRAM_END_ADDRESS (AJ_NVRAM_BASE_ADDRESS + AJ_NVRAM_SIZE) uint32_t AJ_NVRAM_PageSize = 256; /* default page size of NVRAM memory */ void _AJ_NV_Write(void* dest, const void* buf, uint16_t size) { nvm_write(INT_FLASH, (uint32_t)dest, buf, size); } void _AJ_NV_Read(void* src, void* buf, uint16_t size) { nvm_read(INT_FLASH, (uint32_t)src, buf, size); } void AJ_NVRAM_Init() { nvm_init(INT_FLASH); nvm_get_page_size(INT_FLASH, &AJ_NVRAM_PageSize); if (*((uint32_t*)AJ_NVRAM_BASE_ADDRESS) != AJ_NV_SENTINEL) { AJ_AlwaysPrintf(("Sentinel has not been set, clearing NVRAM\n")); _AJ_NVRAM_Clear(); } } void AJ_NV_EraseSector(uint32_t sector) { int i; for (i = 0; i < (AJ_NVRAM_SECTOR_SIZE / AJ_NVRAM_PageSize); i++) { uint32_t page_number; nvm_get_pagenumber(INT_FLASH, sector + (i * AJ_NVRAM_PageSize), &page_number); nvm_page_erase(INT_FLASH, page_number); } } void _AJ_NVRAM_Clear() { //Erase the first sector starting at the base address int i; uint8_t* eraseSectorAddr = AJ_NVRAM_BASE_ADDRESS; AJ_NV_EraseSector(eraseSectorAddr); // Write the sentinel string _AJ_NV_Write(AJ_NVRAM_BASE_ADDRESS, "AJNV", 4); eraseSectorAddr += AJ_NVRAM_SECTOR_SIZE; while (eraseSectorAddr < AJ_NVRAM_END_ADDRESS) { AJ_NV_EraseSector(eraseSectorAddr); eraseSectorAddr += AJ_NVRAM_SECTOR_SIZE; } } // Compact the storage by removing invalid entries AJ_Status _AJ_CompactNVStorage() { uint16_t capacity = 0; uint16_t id = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); uint16_t entrySize = 0; uint16_t offset = 0; uint16_t copyBytes = 0; uint8_t* buf = (uint8_t*)AJ_NVRAM_COMPACTION_BUF; uint8_t* eraseSectorAddr = AJ_NVRAM_BASE_ADDRESS; // copy sentinel AJ_NV_EraseSector(AJ_NVRAM_COMPACTION_BUF); _AJ_NV_Write(AJ_NVRAM_COMPACTION_BUF, "AJNV", SENTINEL_OFFSET); offset += SENTINEL_OFFSET; extern void AJ_NVRAM_Layout_Print(); //AJ_NVRAM_Layout_Print(); while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS && (*data != INVALID_DATA)) { id = *data; capacity = *(data + 1); entrySize = ENTRY_HEADER_SIZE + capacity; if (id != INVALID_ID) { if (offset + entrySize >= AJ_NVRAM_SECTOR_SIZE) { uint16_t leftOver = 0; copyBytes = AJ_NVRAM_SECTOR_SIZE - offset; leftOver = entrySize - copyBytes; _AJ_NV_Write(buf + offset, data, copyBytes); AJ_NV_EraseSector(eraseSectorAddr); _AJ_NV_Write(eraseSectorAddr, buf, AJ_NVRAM_SECTOR_SIZE); AJ_NV_EraseSector(AJ_NVRAM_COMPACTION_BUF); eraseSectorAddr += AJ_NVRAM_SECTOR_SIZE; offset = 0; if (leftOver > 0) { _AJ_NV_Write((uint8_t*)data + copyBytes, buf + offset, leftOver); offset = leftOver; } } else { _AJ_NV_Write(buf + offset, data, entrySize); offset += entrySize; } } data += entrySize >> 1; } if (offset > 0) { AJ_NV_EraseSector(eraseSectorAddr); _AJ_NV_Write(eraseSectorAddr, buf, offset); eraseSectorAddr += AJ_NVRAM_SECTOR_SIZE; } while (eraseSectorAddr < AJ_NVRAM_END_ADDRESS) { AJ_NV_EraseSector(eraseSectorAddr); eraseSectorAddr += AJ_NVRAM_SECTOR_SIZE; } //AJ_NVRAM_Layout_Print(); return AJ_OK; } /* * Initialize functions for DUE * (Called by AJ_PlatformInit()) */ void _AJ_PlatformInit(void) { /* * Init sequence for the DUE */ const usart_serial_options_t usart_serial_options = { .baudrate = 115200, .charlength = 0, .paritytype = UART_MR_PAR_NO, .stopbits = false }; sysclk_init(); board_init(); //configure_uart(); stdio_serial_init(CONSOLE_UART, &usart_serial_options); AJ_WSL_ModuleInit(); AJ_InitRNG(); } uint16_t AJ_ByteSwap16(uint16_t x) { return swap16(x); } uint32_t AJ_ByteSwap32(uint32_t x) { return swap32(x); } uint64_t AJ_ByteSwap64(uint64_t x) { return swap64(x); } void _AJ_Reboot(void) { rstc_start_software_reset(RSTC); } ajtcl-16.04/src/target/freertos-due/aj_target_platform.h000066400000000000000000000104251271074662300233310ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * Any time in this file there is a comment including: nvm_***, sysclk_***, board_***, stdio_*** * note that the API associated with it may be subject to this Atmel license: * (information about it is also at www.atmel.com/asf) * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * 4. This software may only be redistributed and used in connection with an * Atmel microcontroller product. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN * NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #ifndef AJ_TARGET_PLATFORM_H_ #define AJ_TARGET_PLATFORM_H_ /* * Platform specific functions * Similar to target.h but specific to the DUE */ #include #include "efc.h" #include "flash_efc.h" #include "common_nvm.h" #include #include "ioport.h" #include "pio.h" #include "spi.h" #include #include #include #include #include #include #include "dmac.h" #include "rstc.h" // assign the WSL ISR to the interrupt slot for the correct SPI device #define AJ_WSL_SPI_ISR SPI0_Handler #define AJ_WSL_SPI_DEVICE SPI0 #define AJ_WSL_SPI_DEVICE_ID ID_SPI0 #define AJ_WSL_SPI_DEVICE_NPCS 0 #define AJ_WSL_SPI_PCS 0b1110 #define AJ_WSL_SPI_CHIP_PWD_PIN PIO_PB25_IDX /* currently connected to the Reset pin on the ICSP header*/ #define AJ_WSL_SPI_CHIP_SPI_INT_PIN PIO_PC23_IDX /* pin D7 on the Arduino Due */ #define AJ_WSL_SPI_CHIP_SPI_INT_BIT PIO_PC23 #define AJ_WSL_SPI_CHIP_POWER_PIN PIO_PC28_IDX /* pin D3 on the Arduino Due */ #define AJ_WSL_STACK_SIZE 2000 typedef spi_status_t aj_spi_status; #ifndef NDEBUG #define AJ_Printf(fmat, ...) \ do { \ AJ_EnterCriticalRegion(); \ printf(fmat, ## __VA_ARGS__); \ AJ_LeaveCriticalRegion(); \ } while (0) #else #define AJ_Printf(fmat, ...) \ do { printf(fmat, ## __VA_ARGS__); } while (0) #endif void ASSERT(int i); #endif /* AJ_TARGET_PLATFORM_H_ */ ajtcl-16.04/src/target/freertos-due/aj_trng.c000066400000000000000000000070161271074662300211060ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * Any time in this file there is a comment including: pio_***, pmc_***, trng_*** * note that the API associated with it may be subject to this Atmel license: * (information about it is also at www.atmel.com/asf) * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * 4. This software may only be redistributed and used in connection with an * Atmel microcontroller product. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN * NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include #include "trng.h" static uint32_t rand_num = 0; /* * True Random Number Generator ISR handler */ void TRNG_Handler(void) { if ((trng_get_interrupt_status(TRNG) & TRNG_ISR_DATRDY) == TRNG_ISR_DATRDY) { rand_num = trng_read_output_data(TRNG); } trng_disable_interrupt(TRNG); } void AJ_InitRNG(void) { rand_num = 0; pmc_enable_periph_clk(ID_TRNG); trng_enable(TRNG); trng_enable_interrupt(TRNG); pio_handler_set_priority(TRNG, TRNG_IRQn, 0xC); } uint32_t AJ_SeedRNG(void) { /* Reset the seed */ rand_num = 0; /* Enable the generator */ trng_enable_interrupt(TRNG); while (rand_num == 0) { } return rand_num; } ajtcl-16.04/src/target/freertos-due/atmel/000077500000000000000000000000001271074662300204145ustar00rootroot00000000000000ajtcl-16.04/src/target/freertos-due/atmel/conf_uart_serial.h000066400000000000000000000021501271074662300241020ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /* * This file is expected to exist by the ATMEL software pack. * AllJoyn/WSL has no use for it but it must be here to make * the compiler happy. */ ajtcl-16.04/src/target/freertos-stm32/000077500000000000000000000000001271074662300175055ustar00rootroot00000000000000ajtcl-16.04/src/target/freertos-stm32/README.txt000066400000000000000000000022771271074662300212130ustar00rootroot00000000000000This code statically links to code available from http://www.st.com/web/en/catalog/tools/ and that code is subject to a license agreement with terms and conditions that you will be responsible for from STMicroelectronics if you employ that code. Use of such code is your responsibility. Neither AllSeen Alliance nor any contributor to this AllSeen code base has any obligations with respect to the STMicroelectronics code that to which you will be statically linking this code. One requirement in the license is that the STMicroelectronics code may only be used with STMicroelectronics processors as set forth in their agreement. The board support package (BSP) for the STM32 is provided untested and is intended for the community to develop and better. It is NOT an officially supported platform for the WSL driver or any other AllJoyn component. If you have a desire to use this BSP you are welcome to do so, but there may be bugs, and there will be limited support. If problems are found with this BSP it would be helpful if that problem could be communicated to the AllJoyn community, or better yet if fixes are provided as contributions to the project, as the intent is to keep this under active development. ajtcl-16.04/src/target/freertos-stm32/SConscript000066400000000000000000000045621271074662300215260ustar00rootroot00000000000000Import('src_env') # Enable common components for STM32 running FreeRTOS src_env['crypto'] = True src_env['external_sha2'] = True src_env['malloc'] = True src_env['freertos'] = True src_env['wsl'] = True src_env['nvram'] = True # Build target source src_env['srcs'].extend(Glob('*.c')) src_env['srcs'].extend(Glob(src_env['FREE_RTOS_DIR'] + '/Source/*.c')) src_env['srcs'].extend(File([src_env['FREE_RTOS_DIR'] + '/Source/portable/GCC/ARM_CM3/port.c', src_env['FREE_RTOS_DIR'] + '/Source/portable/MemMang/heap_3.c', src_env['STM_SRC_DIR'] + '/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f4xx.s', src_env['STM_SRC_DIR'] + '/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_wwdg.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_spi.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_flash.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rng.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_tim.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_adc.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_i2c.c', src_env['STM_SRC_DIR'] + '/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_syscfg.c' ])) ajtcl-16.04/src/target/freertos-stm32/aj_spi.c000066400000000000000000000215501271074662300211210ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * This code statically links to code available from * http://www.st.com/web/en/catalog/tools/ and that code is subject to a license * agreement with terms and conditions that you will be responsible for from * STMicroelectronics if you employ that code. Use of such code is your responsibility. * Neither AllSeen Alliance nor any contributor to this AllSeen code base has any * obligations with respect to the STMicroelectronics code that to which you will be * statically linking this code. One requirement in the license is that the * STMicroelectronics code may only be used with STMicroelectronics processors as set * forth in their agreement." *******************************************************************************/ #include #include #include GPIO_InitTypeDef SPI_PWD_PIN; GPIO_InitTypeDef SPI_FET_PIN; /** TX interrupt occurred */ volatile uint8_t g_b_spi_interrupt_tx_ready = FALSE; /** RX interrupt occurred */ volatile uint8_t g_b_spi_interrupt_rx_ready = FALSE; volatile uint8_t g_b_spi_interrupt_data_ready = FALSE; static volatile uint8_t read_buf; static uint8_t write_buf; aj_spi_status AJ_SPI_WRITE(uint8_t* spi_device, uint8_t byte, uint8_t pcs, uint8_t cont) { SPI_SSOutputCmd(SPI1, ENABLE); while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)); SPI_I2S_SendData(SPI1, byte); while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)); read_buf = SPI_I2S_ReceiveData(SPI1) & 0xFF; if (cont == 1) { SPI_SSOutputCmd(SPI1, DISABLE); } return SPI_OK; } aj_spi_status AJ_SPI_READ(uint8_t spi_device, uint8_t* data, uint8_t pcs) { memcpy(data, &read_buf, 1); return SPI_OK; } AJ_Status AJ_WSL_SPI_DMATransfer(uint8_t* buffer, uint16_t len, uint8_t direction) { DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); SPI_SSOutputCmd(SPI1, ENABLE); DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_Channel = DMA_Channel_3; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(SPI1->DR); DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; if (direction == 1) { // Configure DMA for transmit DMA_DeInit(DMA2_Stream3); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = len; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_Init(DMA2_Stream3, &DMA_InitStructure); SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE); DMA_Cmd(DMA2_Stream3, ENABLE); // Wait for DMA to finish while (DMA_GetCmdStatus(DMA2_Stream3) == ENABLE); while (!DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_TCIF3)); } else { uint8_t zero = 0; // Configure DMA for receive DMA_DeInit(DMA2_Stream0); DMA_DeInit(DMA2_Stream3); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = len; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_Init(DMA2_Stream0, &DMA_InitStructure); DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&zero; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_Init(DMA2_Stream3, &DMA_InitStructure); SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE); DMA_Cmd(DMA2_Stream0, ENABLE); DMA_Cmd(DMA2_Stream3, ENABLE); // Wait for DMA to finish while (DMA_GetCmdStatus(DMA2_Stream3) == ENABLE); while (!DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_TCIF3)); DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_TCIF3); DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0); } SPI_SSOutputCmd(SPI1, DISABLE); } void AJ_WSL_SPI_PowerCycleChip(void) { SPI_SSOutputCmd(SPI1, DISABLE); /* PWD */ GPIO_ResetBits(GPIOE, GPIO_Pin_7); AJ_Sleep(10); GPIO_SetBits(GPIOE, GPIO_Pin_7); } void AJ_WSL_SPI_InitializeSPIController(void) { GPIO_InitTypeDef SPI_Pins; GPIO_InitTypeDef PowerPin; EXTI_InitTypeDef SPI_Int; NVIC_InitTypeDef Int_NVIC; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOE, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); SPI_Pins.GPIO_Pin = 0xF0; SPI_Pins.GPIO_Mode = GPIO_Mode_AF; SPI_Pins.GPIO_Speed = GPIO_Speed_50MHz; SPI_Pins.GPIO_OType = GPIO_OType_PP; SPI_Pins.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &SPI_Pins); SPI_Pins.GPIO_Pin = GPIO_Pin_7; SPI_Pins.GPIO_Mode = GPIO_Mode_OUT; SPI_Pins.GPIO_Speed = GPIO_Speed_50MHz; SPI_Pins.GPIO_OType = GPIO_OType_PP; SPI_Pins.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOE, &SPI_Pins); GPIOE->ODR = 0; RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); AJ_SPIHandle.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; AJ_SPIHandle.SPI_CPHA = SPI_CPHA_2Edge; AJ_SPIHandle.SPI_CPOL = SPI_CPOL_High; AJ_SPIHandle.SPI_DataSize = SPI_DataSize_8b; AJ_SPIHandle.SPI_Direction = SPI_Direction_2Lines_FullDuplex; AJ_SPIHandle.SPI_FirstBit = SPI_FirstBit_MSB; AJ_SPIHandle.SPI_Mode = SPI_Mode_Master; AJ_SPIHandle.SPI_NSS = SPI_NSS_Soft; AJ_SPIHandle.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &AJ_SPIHandle); /* Configure the SPI interrupt line */ SPI_Pins.GPIO_Pin = GPIO_Pin_1; SPI_Pins.GPIO_Mode = GPIO_Mode_IN; SPI_Pins.GPIO_Speed = GPIO_Speed_2MHz; SPI_Pins.GPIO_OType = 0xA5; SPI_Pins.GPIO_PuPd = GPIO_PuPd_NOPULL; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource1); GPIO_Init(GPIOA, &SPI_Pins); SPI_Int.EXTI_Line = EXTI_Line1; SPI_Int.EXTI_LineCmd = ENABLE; SPI_Int.EXTI_Mode = EXTI_Mode_Interrupt; SPI_Int.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&SPI_Int); Int_NVIC.NVIC_IRQChannel = EXTI1_IRQn; Int_NVIC.NVIC_IRQChannelPreemptionPriority = 6; Int_NVIC.NVIC_IRQChannelSubPriority = 6; Int_NVIC.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&Int_NVIC); GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); AJ_WSL_SPI_PowerCycleChip(); SPI_Cmd(SPI1, ENABLE); } void AJ_WSL_SPI_ShutdownSPIController(void) { } void AJ_WSL_SPI_ISR(void) { } void EXTI1_IRQHandler(void) { AJ_EnterCriticalRegion(); if (EXTI_GetITStatus(EXTI_Line1) != RESET) { //Handle the interrupt EXTI_ClearITPendingBit(EXTI_Line1); EXTI_ClearFlag(EXTI_Line1); AJ_WSL_SPI_CHIP_SPI_ISR(1, 1); } AJ_LeaveCriticalRegion(); } extern struct AJ_TaskHandle* AJ_WSL_MBoxListenHandle; void AJ_WSL_SPI_CHIP_SPI_ISR(uint32_t id, uint32_t mask) { //__disable_irq(); g_b_spi_interrupt_data_ready = TRUE; AJ_ResumeTask(AJ_WSL_MBoxListenHandle, TRUE); //__enable_irq(); } ajtcl-16.04/src/target/freertos-stm32/aj_target.h000066400000000000000000000045011271074662300216160ustar00rootroot00000000000000#ifndef _AJ_TARGET_H #define _AJ_TARGET_H /** * @file WSL target macros and includes */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_EXPORT #include #include #include #include #include #include #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef max #define max(x, y) ((x) > (y) ? (x) : (y)) #endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define WORD_ALIGN(x) ((x & 0x3) ? ((x >> 2) + 1) << 2 : x) #define HOST_IS_LITTLE_ENDIAN 1 #define HOST_IS_BIG_ENDIAN 0 #define HOST_ENDIANESS AJ_LITTLE_ENDIAN #ifndef NDEBUG extern uint8_t dbgCONFIGUREME; extern uint8_t dbgINIT; extern uint8_t dbgNET; extern uint8_t dbgTARGET_CRYPTO; extern uint8_t dbgTARGET_NVRAM; extern uint8_t dbgTARGET_SERIAL; extern uint8_t dbgTARGET_TIMER; extern uint8_t dbgTARGET_UTIL; #endif #define AJ_ASSERT(x) assert(x) /* * AJ_Reboot() is a NOOP on this platform */ #define AJ_Reboot() _AJ_Reboot() #define AJ_CreateNewGUID AJ_RandBytes #define AJ_GetDebugTime(x) AJ_ERR_RESOURCES #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) #define AJ_DEPRECATED(func) func __attribute__((deprecated)) /**< mark a function as deprecated in gcc. */ #else #define AJ_DEPRECATED(func) func /**< not all gcc versions support the deprecated attribute. */ #endif #endif ajtcl-16.04/src/target/freertos-stm32/aj_target_platform.c000066400000000000000000000327431271074662300235260ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * This code statically links to code available from * http://www.st.com/web/en/catalog/tools/ and that code is subject to a license * agreement with terms and conditions that you will be responsible for from * STMicroelectronics if you employ that code. Use of such code is your responsibility. * Neither AllSeen Alliance nor any contributor to this AllSeen code base has any * obligations with respect to the STMicroelectronics code that to which you will be * statically linking this code. One requirement in the license is that the * STMicroelectronics code may only be used with STMicroelectronics processors as set * forth in their agreement." *******************************************************************************/ #define AJ_MODULE STM_NVRAM #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgSTM_NVRAM = 0; #endif /* * Identifies an AJ NVRAM block */ static const char AJ_NV_SENTINEL[4] = "AJNV"; #define INVALID_ID (0) #define INVALID_DATA (0xFFFF) #define INVALID_DATA_BYTE (0xFF) #define AJ_NVRAM_SECTOR_SIZE (4 * 1024) uint8_t* const AJ_NV_SECTOR0 = (uint8_t*)(0x080C0000); uint8_t* const AJ_NV_SECTOR1 = (uint8_t*)(0x080E0000); uint8_t* AJ_NVRAM_BASE_ADDRESS; // = AJ_NV_SECTOR0; uint8_t* AJS_BASE_ADDRESS = (uint8_t*)(0x080E0000); /* * How much space in flash we request to allocate for NVRAM. This will be rounded up to a whole * number of sectors so the actual space allocated may be larger. */ #define AJ_NVRAM_REQUESTED AJ_NVRAM_SIZE typedef struct _NV_EntryHeader { uint16_t id; uint16_t sz; } NV_EntryHeader; #define ALIGN_SIZE(x) ((x + 7) & 0xFFF8) static void NV_ErasePartition(uint32_t offset); void AJ_NVRAM_Layout_Print(void); void* AJ_Flash_GetBaseAddr(); void _AJ_NVRAM_Clear(void); /* * Sector size */ static uint32_t NV_SectorSize = AJ_NVRAM_SIZE; /* * Size of each of the two partitions */ static uint32_t NV_PartitionSize = AJ_NVRAM_SIZE; /* * Base offset for active parition */ static uint32_t NV_Active; /* * Base offset for backup parition */ static uint32_t NV_Backup; static uint8_t* NV_BaseAddr; static uint8_t NV_Busy; static void NV_Dump(uint8_t* base, const char* tag) { uint32_t pos = sizeof(AJ_NV_SENTINEL); AJ_InfoPrintf(("============ AJ NVRAM Map %s===========\n", tag)); AJ_InfoPrintf(("0x%x\n", base)); while (pos < NV_PartitionSize) { NV_EntryHeader* nvEntry = (NV_EntryHeader*)(base + pos); if (nvEntry->id == INVALID_DATA) { break; } AJ_InfoPrintf(("ID = %d, capacity = %d addr=0x%x\n", nvEntry->id, nvEntry->sz, nvEntry)); pos += nvEntry->sz + sizeof(NV_EntryHeader); } AJ_InfoPrintf(("============ End ===========\n")); } /* * Swap out the active and passive partitions */ static void NV_SwapPartitions() { uint32_t tmp = NV_Active; NV_Active = NV_Backup; NV_Backup = tmp; } /* * Read from the active NVRAM section. * * @param dest An offset relative to the start of the active NVRAM section * @param data Buffer to receive the data * @param size The size of the data to read */ void _AJ_NV_Read(uint32_t src, void* buf, uint16_t size) { //uint8_t* base = NV_BaseAddr + NV_Active + src; uint8_t* base = src; memcpy(buf, base, size); return size; } /* * Write to the active NVRAM section. * * @param dest An offset relative to the start of the active NVRAM section * @param data The data to write * @param size The size of the data to write */ void _AJ_NV_Write(uint32_t dest, void* data, uint16_t size) { int i; FLASH_Unlock(); FLASH_SetLatency(FLASH_Latency_7); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); for (i = 0; i < size; i++) { FLASH_ProgramByte(dest + i, (uint8_t)*((uint8_t*)data + i)); } return AJ_OK; } AJ_Status _AJ_CompactNVStorage(void) { AJ_Status status; uint8_t* srcPos = sizeof(AJ_NV_SENTINEL); uint8_t* destPos = NV_Backup + sizeof(AJ_NV_SENTINEL); uint32_t swap; /* * First erase the new partition that we are compacting into */ if (NV_Active > 0) { // We're in the second partition so erase the first FLASH_EraseSector(FLASH_Sector_10, VoltageRange_4); } else { // We're in the first partition so erase the second FLASH_EraseSector(FLASH_Sector_11, VoltageRange_4); } while (srcPos < NV_SectorSize) { uint16_t sz; NV_EntryHeader nvEntry; _AJ_NV_Read((uint32_t)AJ_NVRAM_BASE_ADDRESS + (uint32_t)srcPos, &nvEntry, sizeof(nvEntry)); if (nvEntry.sz == INVALID_DATA) { break; } sz = nvEntry.sz + sizeof(nvEntry); if (nvEntry.id != INVALID_DATA) { _AJ_NV_Write((uint32_t)NV_BaseAddr + (uint32_t)destPos, (uint32_t)AJ_NVRAM_BASE_ADDRESS + (uint32_t)srcPos, sz); destPos += sz; } srcPos += sz; } if (NV_Active > 0) { // We copied from sector 1 so erase it FLASH_EraseSector(FLASH_Sector_11, VoltageRange_4); // Set the base to sector 0 AJ_NVRAM_BASE_ADDRESS = AJ_NV_SECTOR0; } else { // We copied from sector 0 so erase it FLASH_EraseSector(FLASH_Sector_10, VoltageRange_4); // Set the base to sector 1 AJ_NVRAM_BASE_ADDRESS = AJ_NV_SECTOR1; } swap = NV_Backup; NV_Backup = NV_Active; NV_Active = swap; _AJ_NV_Write(AJ_NVRAM_BASE_ADDRESS, AJ_NV_SENTINEL, sizeof(AJ_NV_SENTINEL)); } void _AJ_NVRAM_Clear(void) { FLASH_EraseSector(FLASH_Sector_10, VoltageRange_1); FLASH_EraseSector(FLASH_Sector_11, VoltageRange_1); _AJ_NV_Write((uint32_t)NV_BaseAddr + NV_Active, "AJNV", 4); } void AJ_NVRAM_Init() { FLASH_Unlock(); FLASH_SetLatency(FLASH_Latency_7); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); // Base address will always be sector 0 NV_BaseAddr = AJ_NV_SECTOR0; if (*((uint32_t*)AJ_NV_SECTOR0) == *((uint32_t*)AJ_NV_SENTINEL)) { // NVRAM is in sector 0. Set the active partition offset to zero // and the backup to the size which is the distance to sector 1 AJ_NVRAM_BASE_ADDRESS = AJ_NV_SECTOR0; NV_Active = 0; //base + 0 NV_Backup = AJ_NVRAM_SIZE; //base + size } else if (*((uint32_t*)AJ_NV_SECTOR1) == *((uint32_t*)AJ_NV_SENTINEL)) { // NVRAM is in sector 1. Set the active partition offset to sector 1 // and the backup to zero (sector 0) AJ_NVRAM_BASE_ADDRESS = AJ_NV_SECTOR1; NV_Active = AJ_NVRAM_SIZE; //base + size NV_Backup = 0; //base + 0 } else { // No sentinel so set the base address to sector 0 AJ_InfoPrintf(("Sentinel has not been set, clearing NVRAM\n")); AJ_NVRAM_BASE_ADDRESS = AJ_NV_SECTOR0; NV_Active = 0; //base + 0 NV_Backup = AJ_NVRAM_SIZE; //base + size _AJ_NVRAM_Clear(); } return; } static NV_EntryHeader* NV_FindEntry(uint16_t id, uint8_t* base) { size_t pos = sizeof(AJ_NV_SENTINEL); NV_EntryHeader* nvEntry; if (base == NULL) { base = NV_BaseAddr + NV_Active; } while (pos < NV_PartitionSize) { nvEntry = (NV_EntryHeader*)(base + pos); if (nvEntry->id == id) { return nvEntry; } pos += nvEntry->sz + sizeof(NV_EntryHeader); } return NULL; } static NV_EntryHeader* NV_Create(uint8_t* mem, uint16_t id, uint16_t sz) { NV_EntryHeader* entry; AJ_ASSERT(sz > 0); entry = NV_FindEntry(INVALID_DATA, mem); /* * Check there is space for this entry */ if (!entry || (sz + sizeof(NV_EntryHeader) > (NV_PartitionSize - ((uint8_t*)entry - mem)))) { AJ_ErrPrintf(("Error: Do not have enough NVRAM storage space.\n")); return NULL; } entry->id = id; entry->sz = sz; return entry; } static void DeleteEntry(uint8_t* mem, uint16_t id) { NV_EntryHeader* entry = NV_FindEntry(id, mem); if (entry) { size_t sz = entry->sz + sizeof(NV_EntryHeader); size_t before = (uint8_t*)entry - mem; size_t after = NV_PartitionSize - (before + sz); /* * This should use memmove but memmove is broken */ size_t i; uint32_t* dest = (uint32_t*)entry; uint32_t* src = dest + sz / 4; for (i = 0; i < after / 4; ++i) { *dest++ = *src++; } memset(mem + before + after, INVALID_DATA_BYTE, sz); } } void* AJ_Flash_GetBaseAddr() { return (uint8_t*)AJS_BASE_ADDRESS; } AJ_Status AJ_Flash_Write(uint32_t offset, void* data, size_t len) { _AJ_NV_Write(AJ_Flash_GetBaseAddr() + offset, data, len); return AJ_OK; } AJ_Status AJ_Flash_Clear() { FLASH_Unlock(); FLASH_SetLatency(FLASH_Latency_7); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); FLASH_EraseSector(FLASH_Sector_11, VoltageRange_1); return AJ_OK; } size_t AJ_Flash_GetSize() { return (size_t)AJ_NVRAM_SIZE; } USART_InitTypeDef UartHandle; /* * Function that hooks into printf */ int __io_putchar(char c) { while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); if (c == '\n') { USART_SendData(USART2, '\r'); USART_SendData(USART2, '\n'); return 1; } USART_SendData(USART2, c); return 1; } /* * SysTick handler for FreeRTOS. This function also increments the STM32 * HAL layer system tick count */ void fill_ccm() __attribute__ ((section(".init"))); void fill_ccm() { extern char _eidata, _sccm, _eccm; char*data = &_eidata; char*ccm = &_sccm; while (ccm < &_eccm) { *ccm++ = *data++; } } void _AJ_PlatformInit(void) { GPIO_InitTypeDef USART_GPIO; USART_ClockInitTypeDef USART_ClkInit; fill_ccm(); /* Enable GPIOA clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /* Enable UART2 clock */ //RCC_AHB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); /* Enable SPI1 reset state */ RCC_AHB1PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* Enable GPIOE clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); /* Enable RNG Clock */ RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE); /* Configure GPIOA pin 2 as UART TX */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); USART_Cmd(USART2, ENABLE); USART_GPIO.GPIO_Pin = GPIO_Pin_2; USART_GPIO.GPIO_Mode = GPIO_Mode_AF; USART_GPIO.GPIO_Speed = GPIO_Speed_50MHz; USART_GPIO.GPIO_OType = GPIO_OType_PP; USART_GPIO.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &USART_GPIO); /* Initialise USART clock to its default values */ USART_ClockStructInit(&USART_ClkInit); USART_ClockInit(USART2, &USART_ClkInit); /* Setup UART */ UartHandle.USART_BaudRate = 345600; UartHandle.USART_HardwareFlowControl = USART_HardwareFlowControl_None; UartHandle.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; UartHandle.USART_Parity = USART_Parity_No; UartHandle.USART_StopBits = USART_StopBits_1; UartHandle.USART_WordLength = USART_WordLength_8b; USART_Init(USART2, &UartHandle); RNG_Cmd(ENABLE); return; } uint16_t AJ_ByteSwap16(uint16_t x) { return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)); } uint32_t swap32(uint32_t x) { return AJ_ByteSwap32(x); } uint32_t AJ_ByteSwap32(uint32_t x) { return ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) | ((x << 24) & 0xFF000000) | ((x << 8) & 0x00FF0000); } uint64_t AJ_ByteSwap64(uint64_t x) { return ((x >> 56) & 0x00000000000000FF) | ((x >> 40) & 0x000000000000FF00) | ((x << 56) & 0xFF00000000000000) | ((x << 40) & 0x00FF000000000000) | ((x >> 24) & 0x0000000000FF0000) | ((x >> 8) & 0x00000000FF000000) | ((x << 24) & 0x0000FF0000000000) | ((x << 8) & 0x000000FF00000000); } uint8_t AJ_SeedRNG(void) { while (RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET); return RNG_GetRandomNumber(); } void AJ_PreSchedulerInit(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); } void _AJ_Reboot(void) { NVIC_SystemReset(); } ajtcl-16.04/src/target/freertos-stm32/aj_target_platform.h000066400000000000000000000063131271074662300235250ustar00rootroot00000000000000/** * @file NVRAM function declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * This code statically links to code available from * http://www.st.com/web/en/catalog/tools/ and that code is subject to a license * agreement with terms and conditions that you will be responsible for from * STMicroelectronics if you employ that code. Use of such code is your responsibility. * Neither AllSeen Alliance nor any contributor to this AllSeen code base has any * obligations with respect to the STMicroelectronics code that to which you will be * statically linking this code. One requirement in the license is that the * STMicroelectronics code may only be used with STMicroelectronics processors as set * forth in their agreement." *******************************************************************************/ #ifndef _AJ_TARGET_PLATFORM_H_ #define _AJ_TARGET_PLATFORM_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include SPI_InitTypeDef AJ_SPIHandle; #define A_UINT32 uint32_t #ifdef AJ_NVRAM_SIZE #undef AJ_NVRAM_SIZE #define AJ_NVRAM_SIZE (0x20000) #else #define AJ_NVRAM_SIZE (0x20000) #endif #define AJ_WSL_SPI_DEVICE (void*)0 #define AJ_WSL_SPI_DEVICE_ID 0 #define AJ_WSL_SPI_DEVICE_NPCS 0 #define AJ_WSL_SPI_PCS 0 #define AJ_WSL_SPI_CHIP_PWD_PIN 0 /* currently connected to the Reset pin on the ICSP header*/ #define AJ_WSL_SPI_CHIP_SPI_INT_PIN 0 /* pin D7 on the Arduino Due */ #define AJ_WSL_SPI_CHIP_SPI_INT_BIT 0 #define AJ_WSL_SPI_CHIP_POWER_PIN 0 /* pin D3 on the Arduino Due */ #define AJ_WSL_STACK_SIZE 3000 typedef enum { SPI_OK, SPI_ERR }aj_spi_status; int printf(const char* fmat, ...); #ifndef NDEBUG #define AJ_Printf(fmat, ...) \ do { \ AJ_EnterCriticalRegion(); \ printf(fmat, ## __VA_ARGS__); \ AJ_LeaveCriticalRegion(); \ } while (0) #else #define AJ_Printf(fmat, ...) \ do { printf(fmat, ## __VA_ARGS__); } while (0) #endif #endif ajtcl-16.04/src/target/freertos-stm32/stm32/000077500000000000000000000000001271074662300204555ustar00rootroot00000000000000ajtcl-16.04/src/target/freertos-stm32/stm32/FreeRTOSConfig.h000066400000000000000000000074521271074662300233550ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef FREERTOSCONFIG_H_ #define FREERTOSCONFIG_H_ #include /* * Configuration options */ #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_MALLOC_FAILED_HOOK 1 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ (168000000UL) #define configTICK_RATE_HZ ((portTickType) 1000) #define configMAX_PRIORITIES ((unsigned portBASE_TYPE) 12) #define configMINIMAL_STACK_SIZE ((unsigned short) 120) #define configTOTAL_HEAP_SIZE ((size_t) 112471) #define configMAX_TASK_NAME_LEN (10) #define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_COUNTING_SEMAPHORES 1 #define configCHECK_FOR_STACK_OVERFLOW 2 #define configQUEUE_REGISTRY_SIZE 8 //#define configGENERATE_RUN_TIME_STATS 1 #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES (2) #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) #define configTIMER_QUEUE_LENGTH 5 #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) #define configCOMMAND_INT_MAX_OUTPUT_SIZE 400 /* * Define what functions should be included */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 /* * Priority configurations: * Cortex-Mx may have its own priority definition and levels */ #if defined(__NVIC_PRIO_BITS) #define PRIORITY_BITS __NVIC_PRIO_BITS #else #define PRIORITY_BITS 4 #endif #define LOWEST_PRIORITY 15 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 #define configKERNEL_INTERRUPT_PRIORITY (LOWEST_PRIORITY << (8 - PRIORITY_BITS)) #define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - PRIORITY_BITS)) #define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); while (1); } #define INCLUDE_MODULE_TEST 0 #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler #endif /* FREERTOSCONFIG_H_ */ ajtcl-16.04/src/target/freertos-stm32/stm32/stm32f4xx_conf.h000066400000000000000000000021261271074662300234160ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef STM32F4XX_HAL_CONF_H_ #define STM32F4XX_HAL_CONF_H_ #define assert_param(expr) ((void)0) #endif /* STM32F4XX_HAL_CONF_H_ */ ajtcl-16.04/src/target/freertos-stm32/syscalls.c000066400000000000000000000061531271074662300215130ustar00rootroot00000000000000/****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /****************************************************************************** * This code statically links to code available from * http://www.st.com/web/en/catalog/tools/ and that code is subject to a license * agreement with terms and conditions that you will be responsible for from * STMicroelectronics if you employ that code. Use of such code is your responsibility. * Neither AllSeen Alliance nor any contributor to this AllSeen code base has any * obligations with respect to the STMicroelectronics code that to which you will be * statically linking this code. One requirement in the license is that the * STMicroelectronics code may only be used with STMicroelectronics processors as set * forth in their agreement." *******************************************************************************/ #include #include #include #include #include #include #include #include /* * System calls for the STM32F407 */ extern int __io_putchar(int ch) __attribute__((weak)); extern int __io_getchar(void) __attribute__((weak)); int _exit(int s) { while (1); } caddr_t _sbrk(int inc) { static char* end_of_heap; register char* stack asm ("sp"); char* prev_end_of_heap; extern char ld_end asm ("end"); if (end_of_heap == 0) { end_of_heap = &ld_end; } /* Check that we haven't hit the stack */ if (end_of_heap + inc > stack) { return (caddr_t) -1; } prev_end_of_heap = end_of_heap; end_of_heap += inc; return (caddr_t)prev_end_of_heap; } int _kill(int id, int s) { return -1; } int _getpid(void) { return 0; } int _write(int f, char*pointer, int length) { int i = 0; while (i < length) { __io_putchar(*(pointer + i)); i++; } return length; } int _close(int f) { return 0; } int _fstat(int f, struct stat* s) { return 0; } int _isatty(int f) { return 1; } int _lseek(int f, int p, int d) { return 0; } int _read(int f, char* pointer, int length) { int i = 0; while (i < length) { *(pointer + i) = __io_getchar(); i++; } return length; } ajtcl-16.04/src/target/linux/000077500000000000000000000000001271074662300160455ustar00rootroot00000000000000ajtcl-16.04/src/target/linux/SConscript000066400000000000000000000003401271074662300200540ustar00rootroot00000000000000Import('src_env') # Enable common components for Linux src_env['crypto'] = True src_env['external_sha2'] = True src_env['malloc'] = True src_env['nvram'] = True # Build target source src_env['srcs'] += src_env.Glob('*.c') ajtcl-16.04/src/target/linux/aj_net.c000066400000000000000000001121001271074662300174440ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE NET #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 #ifdef AJ_ARDP #include #endif /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgNET = 0; #endif #define INVALID_SOCKET (-1) /* * IANA assigned IPv4 multicast group for AllJoyn. */ static const char AJ_IPV4_MULTICAST_GROUP[] = "224.0.0.113"; /* * IANA assigned IPv6 multicast group for AllJoyn. */ static const char AJ_IPV6_MULTICAST_GROUP[] = "ff02::13a"; /* * IANA assigned UDP multicast port for AllJoyn */ #define AJ_UDP_PORT 9956 /* * IANA-assigned IPv4 multicast group for mDNS. */ static const char MDNS_IPV4_MULTICAST_GROUP[] = "224.0.0.251"; /* * IANA-assigned IPv6 multicast group for mDNS. */ static const char MDNS_IPV6_MULTICAST_GROUP[] = "ff02::fb"; /* * IANA-assigned UDP multicast port for mDNS */ #define MDNS_UDP_PORT 5353 /** * Target-specific contexts for network I/O */ typedef struct { int tcpSock; int udpSock; } NetContext; typedef struct { int udpSock; int udp6Sock; int mDnsSock; int mDns6Sock; int mDnsRecvSock; uint32_t mDnsRecvAddr; uint16_t mDnsRecvPort; } MCastContext; static NetContext netContext = { INVALID_SOCKET, INVALID_SOCKET }; static MCastContext mCastContext = { INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET }; #ifdef AJ_ARDP /** * Need to predeclare a few things for ARDP */ static AJ_Status AJ_Net_ARDP_Connect(AJ_BusAttachment* bus, const AJ_Service* service); static void AJ_Net_ARDP_Disconnect(AJ_NetSocket* netSock); #endif // AJ_ARDP #ifdef AJ_TCP static AJ_Status CloseNetSock(AJ_NetSocket* netSock) { NetContext* context = (NetContext*)netSock->rx.context; if (context) { if (context->tcpSock != INVALID_SOCKET) { struct linger l; l.l_onoff = 1; l.l_linger = 0; setsockopt(context->tcpSock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l)); shutdown(context->tcpSock, SHUT_RDWR); close(context->tcpSock); } context->tcpSock = INVALID_SOCKET; memset(netSock, 0, sizeof(AJ_NetSocket)); } return AJ_OK; } #endif static AJ_Status CloseMCastSock(AJ_MCastSocket* mcastSock) { MCastContext* context = (MCastContext*)mcastSock->rx.context; if (context) { if (context->udpSock != INVALID_SOCKET) { close(context->udpSock); } if (context->udp6Sock != INVALID_SOCKET) { close(context->udp6Sock); } if (context->mDnsSock != INVALID_SOCKET) { close(context->mDnsSock); } if (context->mDns6Sock != INVALID_SOCKET) { close(context->mDns6Sock); } if (context->mDnsRecvSock != INVALID_SOCKET) { close(context->mDnsRecvSock); } context->udpSock = context->udp6Sock = context->mDnsSock = context->mDns6Sock = context->mDnsRecvSock = INVALID_SOCKET; memset(mcastSock, 0, sizeof(AJ_MCastSocket)); } return AJ_OK; } #ifdef AJ_TCP AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { NetContext* context = (NetContext*) buf->context; ssize_t ret; size_t tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_Send(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { ret = send(context->tcpSock, buf->readPtr, tx, MSG_NOSIGNAL); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_Send(): send() failed. errno=\"%s\", status=AJ_ERR_WRITE\n", strerror(errno))); return AJ_ERR_WRITE; } buf->readPtr += ret; } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_Net_Send(): status=AJ_OK\n")); return AJ_OK; } #endif /* * An eventfd handle used for interrupting a network read blocked on select */ static int interruptFd = INVALID_SOCKET; /* * The socket that is blocked in select */ static uint8_t blocked; /* * This function is called to cancel a pending select. */ void AJ_Net_Interrupt() { if (blocked) { uint64_t u64; if (write(interruptFd, &u64, sizeof(u64)) < 0) { AJ_ErrPrintf(("AJ_Net_Interrupt(): write() failed. errno=\"%s\"\n", strerror(errno))); } } } #ifdef AJ_TCP AJ_Status AJ_Net_Recv(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { NetContext* context = (NetContext*) buf->context; AJ_Status status = AJ_OK; size_t rx = AJ_IO_BUF_SPACE(buf); fd_set fds; int rc = 0; int maxFd = context->tcpSock; struct timeval tv = { timeout / 1000, 1000 * (timeout % 1000) }; // AJ_InfoPrintf(("AJ_Net_Recv(buf=0x%p, len=%d, timeout=%d)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); FD_ZERO(&fds); FD_SET(context->tcpSock, &fds); if (interruptFd >= 0) { FD_SET(interruptFd, &fds); maxFd = max(maxFd, interruptFd); } blocked = TRUE; rc = select(maxFd + 1, &fds, NULL, NULL, &tv); blocked = FALSE; if (rc == 0) { return AJ_ERR_TIMEOUT; } if ((interruptFd >= 0) && FD_ISSET(interruptFd, &fds)) { uint64_t u64; if (read(interruptFd, &u64, sizeof(u64)) < 0) { AJ_ErrPrintf(("AJ_Net_Recv(): read() failed during interrupt. errno=\"%s\"\n", strerror(errno))); } return AJ_ERR_INTERRUPTED; } rx = min(rx, len); if (rx) { ssize_t ret = recv(context->tcpSock, buf->writePtr, rx, 0); if ((ret == -1) || (ret == 0)) { AJ_ErrPrintf(("AJ_Net_Recv(): recv() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_Recv(): recv'd %d from tcp\n", ret)); buf->writePtr += ret; } } return status; } #endif static uint8_t rxData[AJ_RX_DATA_SIZE]; static uint8_t txData[AJ_TX_DATA_SIZE]; #ifdef AJ_TCP static AJ_Status AJ_TCP_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { int ret; struct sockaddr_storage addrBuf; socklen_t addrSize; int tcpSock = INVALID_SOCKET; interruptFd = eventfd(0, O_NONBLOCK); // Use O_NONBLOCK instead of EFD_NONBLOCK due to bug in OpenWrt's uCLibc if (interruptFd < 0) { AJ_ErrPrintf(("AJ_TCP_Connect(): failed to created interrupt event\n")); goto ConnectError; } memset(&addrBuf, 0, sizeof(addrBuf)); tcpSock = socket(AF_INET, SOCK_STREAM, 0); if (tcpSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_TCP_Connect(): socket() failed. status=AJ_ERR_CONNECT\n")); goto ConnectError; } if (service->addrTypes & AJ_ADDR_TCP4) { struct sockaddr_in* sa = (struct sockaddr_in*)&addrBuf; sa->sin_family = AF_INET; sa->sin_port = htons(service->ipv4port); sa->sin_addr.s_addr = service->ipv4; addrSize = sizeof(struct sockaddr_in); AJ_InfoPrintf(("AJ_TCP_Connect(): Connect to \"%s:%u\"\n", inet_ntoa(sa->sin_addr), service->ipv4port));; } else if (service->addrTypes & AJ_ADDR_TCP6) { struct sockaddr_in6* sa = (struct sockaddr_in6*)&addrBuf; sa->sin6_family = AF_INET6; sa->sin6_port = htons(service->ipv6port); memcpy(sa->sin6_addr.s6_addr, service->ipv6, sizeof(sa->sin6_addr.s6_addr)); addrSize = sizeof(struct sockaddr_in6); } else { AJ_ErrPrintf(("AJ_TCP_Connect(): Invalid addrTypes %u, status=AJ_ERR_CONNECT\n", service->addrTypes)); goto ConnectError; } ret = connect(tcpSock, (struct sockaddr*)&addrBuf, addrSize); if (ret < 0) { AJ_ErrPrintf(("AJ_TCP_Connect(): connect() failed. errno=\"%s\", status=AJ_ERR_CONNECT\n", strerror(errno))); goto ConnectError; } else { netContext.tcpSock = tcpSock; AJ_IOBufInit(&bus->sock.rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, &netContext); bus->sock.rx.recv = AJ_Net_Recv; AJ_IOBufInit(&bus->sock.tx, txData, sizeof(txData), AJ_IO_BUF_TX, &netContext); bus->sock.tx.send = AJ_Net_Send; AJ_InfoPrintf(("AJ_TCP_Connect(): status=AJ_OK\n")); } return AJ_OK; ConnectError: if (interruptFd != INVALID_SOCKET) { close(interruptFd); interruptFd = INVALID_SOCKET; } if (tcpSock != INVALID_SOCKET) { close(tcpSock); } return AJ_ERR_CONNECT; } #endif AJ_Status AJ_Net_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { AJ_Status status = AJ_ERR_CONNECT; AJ_InfoPrintf(("AJ_Net_Connect(bus=0x%p, addrType=%d.)\n", bus, service->addrTypes)); #ifdef AJ_ARDP if (service->addrTypes & (AJ_ADDR_UDP4 | AJ_ADDR_UDP6)) { status = AJ_Net_ARDP_Connect(bus, service); if (status == AJ_OK) { return status; } } #endif #ifdef AJ_TCP if (service->addrTypes & (AJ_ADDR_TCP4 | AJ_ADDR_TCP6)) { status = AJ_TCP_Connect(bus, service); } #endif return status; } void AJ_Net_Disconnect(AJ_NetSocket* netSock) { if (interruptFd >= 0) { close(interruptFd); interruptFd = INVALID_SOCKET; } if (netContext.udpSock != INVALID_SOCKET) { #ifdef AJ_ARDP // we are using UDP! AJ_Net_ARDP_Disconnect(netSock); memset(netSock, 0, sizeof(AJ_NetSocket)); #endif } else if (netContext.tcpSock != INVALID_SOCKET) { #ifdef AJ_TCP CloseNetSock(netSock); #endif } } static uint8_t sendToBroadcast(int sock, uint16_t port, void* ptr, size_t tx) { ssize_t ret = -1; uint8_t sendSucceeded = FALSE; struct ifaddrs* addrs; struct ifaddrs* addr; getifaddrs(&addrs); addr = addrs; while (addr != NULL) { // only care about IPV4 if (addr->ifa_addr != NULL && addr->ifa_addr->sa_family == AF_INET) { char buf[INET_ADDRSTRLEN]; struct sockaddr_in* sin_bcast = (struct sockaddr_in*) addr->ifa_ifu.ifu_broadaddr; sin_bcast->sin_port = htons(port); inet_ntop(AF_INET, &(sin_bcast->sin_addr), buf, sizeof(buf)); AJ_InfoPrintf(("sendToBroadcast: sending to bcast addr %s\n", buf)); ret = sendto(sock, ptr, tx, MSG_NOSIGNAL, (struct sockaddr*) sin_bcast, sizeof(struct sockaddr_in)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("sendToBroadcast(): sendto failed. errno=\"%s\"\n", strerror(errno))); } } addr = addr->ifa_next; } freeifaddrs(addrs); return sendSucceeded; } static AJ_Status RewriteSenderInfo(AJ_IOBuffer* buf, uint32_t addr, uint16_t port) { uint16_t sidVal; const char snd[4] = { 'd', 'n', 'e', 's' }; const char sid[] = { 's', 'i', 'd', '=' }; const char ipv4[] = { 'i', 'p', 'v', '4', '=' }; const char upcv4[] = { 'u', 'p', 'c', 'v', '4', '=' }; char sidStr[6]; char ipv4Str[17]; char upcv4Str[6]; uint8_t* pkt; uint16_t dataLength; int match; AJ_Status status; // first, pluck the search ID from the mDNS header sidVal = *(buf->readPtr) << 8; sidVal += *(buf->readPtr + 1); // convert to strings status = AJ_IntToString((int32_t) sidVal, sidStr, sizeof(sidStr)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_IntToString((int32_t) port, upcv4Str, sizeof(upcv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_InetToString(addr, ipv4Str, sizeof(ipv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } // ASSUMPTIONS: sender-info resource record is the final resource record in the packet. // sid, ipv4, and upcv4 key value pairs are the final three key/value pairs in the record. // The length of the other fields in the record are static. // // search backwards through packet to find the start of "sender-info" pkt = buf->writePtr; match = 0; do { if (*(pkt--) == snd[match]) { match++; } else { match = 0; } } while (pkt != buf->readPtr && match != 4); if (match != 4) { return AJ_ERR_WRITE; } // move forward to the Data Length field pkt += 22; // actual data length is the length of the static values already in the buffer plus // the three dynamic key-value pairs to re-write dataLength = 23 + 1 + sizeof(sid) + strlen(sidStr) + 1 + sizeof(ipv4) + strlen(ipv4Str) + 1 + sizeof(upcv4) + strlen(upcv4Str); *pkt++ = (dataLength >> 8) & 0xFF; *pkt++ = dataLength & 0xFF; // move forward past the static key-value pairs pkt += 23; // ASSERT: must be at the start of "sid=" assert(*(pkt + 1) == 's'); // re-write new values *pkt++ = sizeof(sid) + strlen(sidStr); memcpy(pkt, sid, sizeof(sid)); pkt += sizeof(sid); memcpy(pkt, sidStr, strlen(sidStr)); pkt += strlen(sidStr); *pkt++ = sizeof(ipv4) + strlen(ipv4Str); memcpy(pkt, ipv4, sizeof(ipv4)); pkt += sizeof(ipv4); memcpy(pkt, ipv4Str, strlen(ipv4Str)); pkt += strlen(ipv4Str); *pkt++ = sizeof(upcv4) + strlen(upcv4Str); memcpy(pkt, upcv4, sizeof(upcv4)); pkt += sizeof(upcv4); memcpy(pkt, upcv4Str, strlen(upcv4Str)); pkt += strlen(upcv4Str); buf->writePtr = pkt; return AJ_OK; } AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { ssize_t ret = -1; uint8_t sendSucceeded = FALSE; size_t tx = AJ_IO_BUF_AVAIL(buf); MCastContext* context = (MCastContext*) buf->context; AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { if ((context->udpSock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_AJ)) { struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(AJ_UDP_PORT); if (inet_pton(AF_INET, AJ_IPV4_MULTICAST_GROUP, &sin.sin_addr) == 1) { ret = sendto(context->udpSock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*)&sin, sizeof(sin)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto AJ IPv4 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid AJ IP address. errno=\"%s\"\n", strerror(errno))); } if (sendToBroadcast(context->udpSock, AJ_UDP_PORT, buf->readPtr, tx) == TRUE) { sendSucceeded = TRUE; } // leave sendSucceeded unchanged if FALSE } // now sendto the ipv6 address if ((context->udp6Sock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_AJ)) { struct sockaddr_in6 sin6; sin6.sin6_family = AF_INET6; sin6.sin6_flowinfo = 0; sin6.sin6_scope_id = 0; sin6.sin6_port = htons(AJ_UDP_PORT); if (inet_pton(AF_INET6, AJ_IPV6_MULTICAST_GROUP, &sin6.sin6_addr) == 1) { ret = sendto(context->udp6Sock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*) &sin6, sizeof(sin6)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto AJ IPv6 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid AJ IPv6 address. errno=\"%s\"\n", strerror(errno))); } } } if (buf->flags & AJ_IO_BUF_MDNS) { if (RewriteSenderInfo(buf, context->mDnsRecvAddr, context->mDnsRecvPort) != AJ_OK) { AJ_WarnPrintf(("AJ_Net_SendTo(): RewriteSenderInfo failed.\n")); tx = 0; } else { tx = AJ_IO_BUF_AVAIL(buf); } } if (tx > 0) { if ((context->mDnsSock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_MDNS)) { struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(MDNS_UDP_PORT); if (inet_pton(AF_INET, MDNS_IPV4_MULTICAST_GROUP, &sin.sin_addr) == 1) { ret = sendto(context->mDnsSock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*)&sin, sizeof(sin)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto mDNS IPv4 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid mDNS IP address. errno=\"%s\"\n", strerror(errno))); } if (sendToBroadcast(context->mDnsSock, MDNS_UDP_PORT, buf->readPtr, tx) == TRUE) { sendSucceeded = TRUE; } // leave sendSucceeded unchanged if FALSE } if ((context->mDns6Sock != INVALID_SOCKET) && (buf->flags & AJ_IO_BUF_MDNS)) { struct sockaddr_in6 sin6; sin6.sin6_family = AF_INET6; sin6.sin6_flowinfo = 0; sin6.sin6_scope_id = 0; sin6.sin6_port = htons(MDNS_UDP_PORT); if (inet_pton(AF_INET6, MDNS_IPV6_MULTICAST_GROUP, &sin6.sin6_addr) == 1) { ret = sendto(context->mDns6Sock, buf->readPtr, tx, MSG_NOSIGNAL, (struct sockaddr*) &sin6, sizeof(sin6)); if (tx == ret) { sendSucceeded = TRUE; } else { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto mDNS IPv6 failed. errno=\"%s\"\n", strerror(errno))); } } else { AJ_ErrPrintf(("AJ_Net_SendTo(): Invalid mDNS IPv6 address. errno=\"%s\"\n", strerror(errno))); } } if (!sendSucceeded) { /* Not a single send succeeded, return an error */ AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed. errno=\"%s\", status=AJ_ERR_WRITE\n", strerror(errno))); return AJ_ERR_WRITE; } buf->readPtr += ret; } AJ_IO_BUF_RESET(buf); AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; } AJ_Status AJ_Net_RecvFrom(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { MCastContext* context = (MCastContext*) buf->context; AJ_Status status = AJ_OK; ssize_t ret; size_t rx; fd_set fds; int maxFd = INVALID_SOCKET; int rc = 0; struct timeval tv = { timeout / 1000, 1000 * (timeout % 1000) }; // AJ_InfoPrintf(("AJ_Net_RecvFrom(buf=0x%p, len=%d, timeout=%d)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); assert(context->mDnsRecvSock != INVALID_SOCKET); FD_ZERO(&fds); FD_SET(context->mDnsRecvSock, &fds); maxFd = context->mDnsRecvSock; if (context->udpSock != INVALID_SOCKET) { FD_SET(context->udpSock, &fds); maxFd = max(maxFd, context->udpSock); } if (context->udp6Sock != INVALID_SOCKET) { FD_SET(context->udp6Sock, &fds); maxFd = max(maxFd, context->udp6Sock); } rc = select(maxFd + 1, &fds, NULL, NULL, &tv); if (rc == 0) { AJ_InfoPrintf(("AJ_Net_RecvFrom(): select() timed out. status=AJ_ERR_TIMEOUT\n")); return AJ_ERR_TIMEOUT; } // we need to read from the first socket that has data available. rx = AJ_IO_BUF_SPACE(buf); if (context->mDnsRecvSock != INVALID_SOCKET && FD_ISSET(context->mDnsRecvSock, &fds)) { rx = min(rx, len); if (rx) { ret = recvfrom(context->mDnsRecvSock, buf->writePtr, rx, 0, NULL, 0); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): mDnsRecvSock recvfrom() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_RecvFrom(): recv'd %d from mDNS\n", (int) ret)); buf->flags |= AJ_IO_BUF_MDNS; buf->writePtr += ret; status = AJ_OK; goto Finished; } } } rx = AJ_IO_BUF_SPACE(buf); if (context->udp6Sock != INVALID_SOCKET && FD_ISSET(context->udp6Sock, &fds)) { rx = min(rx, len); if (rx) { ret = recvfrom(context->udp6Sock, buf->writePtr, rx, 0, NULL, 0); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): recvfrom() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_RecvFrom(): recv'd %d from udp6\n", (int) ret)); buf->flags |= AJ_IO_BUF_AJ; buf->writePtr += ret; status = AJ_OK; goto Finished; } } } rx = AJ_IO_BUF_SPACE(buf); if (context->udpSock != INVALID_SOCKET && FD_ISSET(context->udpSock, &fds)) { rx = min(rx, len); if (rx) { ret = recvfrom(context->udpSock, buf->writePtr, rx, 0, NULL, 0); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): recvfrom() failed. errno=\"%s\"\n", strerror(errno))); status = AJ_ERR_READ; } else { AJ_InfoPrintf(("AJ_Net_RecvFrom(): recv'd %d from udp\n", (int) ret)); buf->flags |= AJ_IO_BUF_AJ; buf->writePtr += ret; status = AJ_OK; goto Finished; } } } Finished: if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Net_RecvFrom(): status=%s\n", AJ_StatusText(status))); } return status; } /* * Need enough space to receive a complete name service packet when used in UDP * mode. NS expects MTU of 1500 subtracts UDP, IP and ethertype overhead. * 1500 - 8 -20 - 18 = 1454. txData buffer size needs to be big enough to hold * max(NS WHO-HAS for one name (4 + 2 + 256 = 262), * mDNS query for one name (194 + 5 + 5 + 15 + 256 = 475)) = 475 */ static uint8_t rxDataMCast[1454]; static uint8_t txDataMCast[475]; static int MCastUp4(const char group[], uint16_t port) { int ret; struct ip_mreq mreq; struct sockaddr_in sin; int reuse = 1; int bcast = 1; int mcastSock; mcastSock = socket(AF_INET, SOCK_DGRAM, 0); if (mcastSock == INVALID_SOCKET) { AJ_ErrPrintf(("MCastUp4(): socket() fails. status=AJ_ERR_READ\n")); return INVALID_SOCKET; } ret = setsockopt(mcastSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (ret != 0) { AJ_ErrPrintf(("MCastUp4(): setsockopt(SO_REUSEADDR) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } // enable IP broadcast on this socket. // This is needed for bcast router discovery int r = setsockopt(mcastSock, SOL_SOCKET, SO_BROADCAST, (void*) &bcast, sizeof(bcast)); if (r != 0) { AJ_ErrPrintf(("BcastUp4(): setsockopt(SOL_SOCKET, SO_BROADCAST) failed. errno=\"%s\"\n", strerror(errno))); goto ExitError; } /* * Bind supplied port */ sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.s_addr = INADDR_ANY; ret = bind(mcastSock, (struct sockaddr*) &sin, sizeof(sin)); if (ret < 0) { AJ_ErrPrintf(("MCastUp4(): bind() failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } /* * Join our multicast group */ memset(&mreq, 0, sizeof(mreq)); inet_pton(AF_INET, group, &mreq.imr_multiaddr); mreq.imr_interface.s_addr = INADDR_ANY; ret = setsockopt(mcastSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); if (ret < 0) { /* * Not all Linux based systems setup an IPv4 multicast route. * Since we were successful in setting up IPv4 broadcast for * this socket, we'll just use that and not use IPv4 multicast. */ AJ_WarnPrintf(("MCastUp4(): setsockopt(IP_ADD_MEMBERSHIP) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); } return mcastSock; ExitError: close(mcastSock); return INVALID_SOCKET; } static int MCastUp6(const char* group, uint16_t port) { int ret; struct ipv6_mreq mreq6; struct sockaddr_in6 sin6; int reuse = 1; int mcastSock; mcastSock = socket(AF_INET6, SOCK_DGRAM, 0); if (mcastSock == INVALID_SOCKET) { AJ_ErrPrintf(("MCastUp6(): socket() fails. errno=\"%s\" status=AJ_ERR_READ\n", strerror(errno))); return INVALID_SOCKET; } ret = setsockopt(mcastSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (ret != 0) { AJ_ErrPrintf(("MCastUp6(): setsockopt(SO_REUSEADDR) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } /* * Bind supplied port */ memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); sin6.sin6_addr = in6addr_any; ret = bind(mcastSock, (struct sockaddr*) &sin6, sizeof(sin6)); if (ret < 0) { AJ_ErrPrintf(("MCastUp6(): bind() failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } /* * Join multicast group */ memset(&mreq6, 0, sizeof(mreq6)); inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = 0; ret = setsockopt(mcastSock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)); if (ret < 0) { AJ_ErrPrintf(("MCastUp6(): setsockopt(IP_ADD_MEMBERSHIP) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } return mcastSock; ExitError: close(mcastSock); return INVALID_SOCKET; } static uint32_t chooseMDnsRecvAddr() { uint32_t recvAddr = 0; struct ifaddrs* addrs; struct ifaddrs* addr; getifaddrs(&addrs); addr = addrs; while (addr != NULL) { // Choose first IPv4 address that is not LOOPBACK if (addr->ifa_addr != NULL && addr->ifa_addr->sa_family == AF_INET && !(addr->ifa_flags & IFF_LOOPBACK)) { struct sockaddr_in* sin = (struct sockaddr_in*) addr->ifa_addr; recvAddr = sin->sin_addr.s_addr; } addr = addr->ifa_next; } freeifaddrs(addrs); return recvAddr; } static int MDnsRecvUp() { int ret; struct sockaddr_in sin; int reuse = 1; int recvSock; recvSock = socket(AF_INET, SOCK_DGRAM, 0); if (recvSock == INVALID_SOCKET) { AJ_ErrPrintf(("MDnsRecvUp(): socket() fails. status=AJ_ERR_READ\n")); goto ExitError; } ret = setsockopt(recvSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if (ret != 0) { AJ_ErrPrintf(("MDnsRecvUp(): setsockopt(SO_REUSEADDR) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } sin.sin_family = AF_INET; sin.sin_port = htons(0); sin.sin_addr.s_addr = INADDR_ANY; ret = bind(recvSock, (struct sockaddr*) &sin, sizeof(sin)); if (ret < 0) { AJ_ErrPrintf(("MDnsRecvUp(): bind() failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); goto ExitError; } return recvSock; ExitError: close(recvSock); return INVALID_SOCKET; } AJ_Status AJ_Net_MCastUp(AJ_MCastSocket* mcastSock) { struct sockaddr_storage addrBuf; socklen_t addrLen = sizeof(addrBuf); struct sockaddr_in* sin; AJ_Status status = AJ_ERR_READ; mCastContext.mDnsRecvSock = MDnsRecvUp(); if (mCastContext.mDnsRecvSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_MCastUp(): MDnsRecvUp for mDnsRecvPort failed")); return status; } if (getsockname(mCastContext.mDnsRecvSock, (struct sockaddr*) &addrBuf, &addrLen)) { AJ_ErrPrintf(("AJ_Net_MCastUp(): getsockname for mDnsRecvPort failed")); goto ExitError; } sin = (struct sockaddr_in*) &addrBuf; mCastContext.mDnsRecvPort = ntohs(sin->sin_port); mCastContext.mDnsRecvAddr = ntohl(chooseMDnsRecvAddr()); if (mCastContext.mDnsRecvAddr == 0) { AJ_ErrPrintf(("AJ_Net_MCastUp(): no mDNS recv address")); goto ExitError; } AJ_InfoPrintf(("AJ_Net_MCastUp(): mDNS recv on %d.%d.%d.%d:%d\n", ((mCastContext.mDnsRecvAddr >> 24) & 0xFF), ((mCastContext.mDnsRecvAddr >> 16) & 0xFF), ((mCastContext.mDnsRecvAddr >> 8) & 0xFF), (mCastContext.mDnsRecvAddr & 0xFF), mCastContext.mDnsRecvPort)); mCastContext.mDnsSock = MCastUp4(MDNS_IPV4_MULTICAST_GROUP, MDNS_UDP_PORT); mCastContext.mDns6Sock = MCastUp6(MDNS_IPV6_MULTICAST_GROUP, MDNS_UDP_PORT); if (AJ_GetMinProtoVersion() < 10) { mCastContext.udpSock = MCastUp4(AJ_IPV4_MULTICAST_GROUP, 0); mCastContext.udp6Sock = MCastUp6(AJ_IPV6_MULTICAST_GROUP, 0); } if (mCastContext.udpSock != INVALID_SOCKET || mCastContext.udp6Sock != INVALID_SOCKET || mCastContext.mDnsSock != INVALID_SOCKET || mCastContext.mDns6Sock != INVALID_SOCKET) { AJ_IOBufInit(&mcastSock->rx, rxDataMCast, sizeof(rxDataMCast), AJ_IO_BUF_RX, &mCastContext); mcastSock->rx.recv = AJ_Net_RecvFrom; AJ_IOBufInit(&mcastSock->tx, txDataMCast, sizeof(txDataMCast), AJ_IO_BUF_TX, &mCastContext); mcastSock->tx.send = AJ_Net_SendTo; status = AJ_OK; } return status; ExitError: close(mCastContext.mDnsRecvSock); return status; } void AJ_Net_MCastDown(AJ_MCastSocket* mcastSock) { MCastContext* context = (MCastContext*) mcastSock->rx.context; AJ_InfoPrintf(("AJ_Net_MCastDown(mcastSock=0x%p)\n", mcastSock)); if (context->udpSock != INVALID_SOCKET) { struct ip_mreq mreq; inet_pton(AF_INET, AJ_IPV4_MULTICAST_GROUP, &mreq.imr_multiaddr); mreq.imr_interface.s_addr = INADDR_ANY; setsockopt(context->udpSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*) &mreq, sizeof(mreq)); } if (context->udp6Sock != INVALID_SOCKET) { struct ipv6_mreq mreq6; inet_pton(AF_INET6, AJ_IPV6_MULTICAST_GROUP, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = 0; setsockopt(context->udp6Sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6)); } if (context->mDnsSock != INVALID_SOCKET) { struct ip_mreq mreq; inet_pton(AF_INET, MDNS_IPV4_MULTICAST_GROUP, &mreq.imr_multiaddr); mreq.imr_interface.s_addr = INADDR_ANY; setsockopt(context->udpSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*) &mreq, sizeof(mreq)); } if (context->mDns6Sock != INVALID_SOCKET) { struct ipv6_mreq mreq6; inet_pton(AF_INET6, MDNS_IPV6_MULTICAST_GROUP, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = 0; setsockopt(context->udp6Sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6)); } CloseMCastSock(mcastSock); } #ifdef AJ_ARDP static AJ_Status AJ_ARDP_UDP_Send(void* context, uint8_t* buf, size_t len, size_t* sent, uint8_t confirm) { AJ_Status status = AJ_OK; ssize_t ret; NetContext* ctx = (NetContext*) context; AJ_InfoPrintf(("AJ_ARDP_UDP_Send(buf=0x%p, len=%lu)\n", buf, len)); // we can send( rather than sendto( because we did a UDP connect() ret = send(ctx->udpSock, buf, len, (confirm == TRUE) ? MSG_CONFIRM : 0); if (ret == -1) { status = AJ_ERR_WRITE; } else { *sent = (size_t) ret; } return status; } static AJ_Status AJ_ARDP_UDP_Recv(void* context, uint8_t** data, uint32_t* recved, uint32_t timeout) { fd_set fds; struct timeval tv = { timeout / 1000, 1000 * (timeout % 1000) }; int ret; NetContext* ctx = (NetContext*) context; int maxFd = max(ctx->udpSock, interruptFd); /** * Let the platform code own this buffer. This makes it easier to avoid double-buffering * on platforms that allow it. */ static uint8_t buffer[UDP_SEGBMAX]; *data = NULL; AJ_InfoPrintf(("AJ_ARDP_UDP_Recv(data=0x%p, recved=0x%p, timeout=%u)\n", data, recved, timeout)); FD_ZERO(&fds); FD_SET(ctx->udpSock, &fds); if (interruptFd > 0) { FD_SET(interruptFd, &fds); } blocked = TRUE; ret = select(maxFd + 1, &fds, NULL, NULL, &tv); blocked = FALSE; if (ret == 0) { // timeout! return AJ_ERR_TIMEOUT; } else if (ret == -1) { perror("select"); return AJ_ERR_READ; } else if ((interruptFd > 0) && FD_ISSET(interruptFd, &fds)) { uint64_t u64; read(interruptFd, &u64, sizeof(u64)); return AJ_ERR_INTERRUPTED; } else if (FD_ISSET(ctx->udpSock, &fds)) { ret = recvfrom(ctx->udpSock, buffer, sizeof(buffer), 0, NULL, 0); if (ret == -1) { // this will only happen if we are on a local machine perror("recvfrom"); return AJ_ERR_READ; } *recved = ret; *data = buffer; } return AJ_OK; } static AJ_Status AJ_Net_ARDP_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { int udpSock = INVALID_SOCKET; AJ_Status status; struct sockaddr_storage addrBuf; socklen_t addrSize; int ret; AJ_ARDP_InitFunctions(AJ_ARDP_UDP_Recv, AJ_ARDP_UDP_Send); memset(&addrBuf, 0, sizeof(addrBuf)); interruptFd = eventfd(0, O_NONBLOCK); // Use O_NONBLOCK instead of EFD_NONBLOCK due to bug in OpenWrt's uCLibc if (interruptFd < 0) { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): failed to created interrupt event\n")); goto ConnectError; } if (service->addrTypes & AJ_ADDR_UDP4) { struct sockaddr_in* sa = (struct sockaddr_in*) &addrBuf; udpSock = socket(AF_INET, SOCK_DGRAM, 0); if (udpSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): socket() failed. status=AJ_ERR_CONNECT\n")); goto ConnectError; } sa->sin_family = AF_INET; sa->sin_port = htons(service->ipv4portUdp); sa->sin_addr.s_addr = service->ipv4Udp; addrSize = sizeof(struct sockaddr_in); AJ_InfoPrintf(("AJ_Net_ARDP_Connect(): Connect to \"%s:%u\"\n", inet_ntoa(sa->sin_addr), service->ipv4portUdp));; } else if (service->addrTypes & AJ_ADDR_UDP6) { struct sockaddr_in6* sa = (struct sockaddr_in6*) &addrBuf; udpSock = socket(AF_INET6, SOCK_DGRAM, 0); if (udpSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): socket() failed. status=AJ_ERR_CONNECT\n")); goto ConnectError; } sa->sin6_family = AF_INET6; sa->sin6_port = htons(service->ipv6portUdp); memcpy(sa->sin6_addr.s6_addr, service->ipv6Udp, sizeof(sa->sin6_addr.s6_addr)); addrSize = sizeof(struct sockaddr_in6); } else { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): Invalid addrTypes %u, status=AJ_ERR_CONNECT\n", service->addrTypes)); return AJ_ERR_CONNECT; } // When you 'connect' a UDP socket, it means that this is the default sendto address. // Therefore, we don't have to make the address a global variable and can // simply use send() rather than sendto(). See: man 7 udp ret = connect(udpSock, (struct sockaddr*) &addrBuf, addrSize); // must do this before calling AJ_MarshalMethodCall! if (ret == 0) { netContext.udpSock = udpSock; AJ_IOBufInit(&bus->sock.rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, &netContext); bus->sock.rx.recv = AJ_ARDP_Recv; AJ_IOBufInit(&bus->sock.tx, txData, sizeof(txData), AJ_IO_BUF_TX, &netContext); bus->sock.tx.send = AJ_ARDP_Send; } else { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): Error connecting\n")); perror("connect"); goto ConnectError; } status = AJ_ARDP_UDP_Connect(bus, &netContext, service, &bus->sock); if (status != AJ_OK) { AJ_Net_ARDP_Disconnect(&bus->sock); goto ConnectError; } return AJ_OK; ConnectError: if (interruptFd != INVALID_SOCKET) { close(interruptFd); interruptFd = INVALID_SOCKET; } if (udpSock != INVALID_SOCKET) { close(udpSock); } return AJ_ERR_CONNECT; } static void AJ_Net_ARDP_Disconnect(AJ_NetSocket* netSock) { AJ_ARDP_Disconnect(FALSE); close(netContext.udpSock); netContext.udpSock = INVALID_SOCKET; memset(netSock, 0, sizeof(AJ_NetSocket)); } #endif // AJ_ARDP ajtcl-16.04/src/target/linux/aj_target.h000066400000000000000000000055641271074662300201700ustar00rootroot00000000000000#ifndef _AJ_TARGET_H #define _AJ_TARGET_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef max #define max(x, y) ((x) > (y) ? (x) : (y)) #endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define WORD_ALIGN(x) ((x & 0x3) ? ((x >> 2) + 1) << 2 : x) #if __BYTE_ORDER == __LITTLE_ENDIAN #define HOST_IS_LITTLE_ENDIAN TRUE #define HOST_IS_BIG_ENDIAN FALSE #else #define HOST_IS_LITTLE_ENDIAN FALSE #define HOST_IS_BIG_ENDIAN TRUE #endif /** * Set or clear the log file for debug output. * * @param file A file path or NULL if clearing the log file. * @param maxLen Maximum length the log file is allowed to grow. The log file is periodically * truncated to keep the length between maxLen / 2 and maxLen. Zero means no limit. */ int AJ_SetLogFile(const char* file, uint32_t maxLen); void AJ_Printf(const char* fmat, ...); #ifndef NDEBUG extern uint8_t dbgCONFIGUREME; extern uint8_t dbgINIT; extern uint8_t dbgNET; extern uint8_t dbgTARGET_CRYPTO; extern uint8_t dbgTARGET_NVRAM; extern uint8_t dbgTARGET_SERIAL; extern uint8_t dbgTARGET_TIMER; extern uint8_t dbgTARGET_UTIL; #endif #define AJ_ASSERT(x) assert(x) /* * AJ_Reboot() is a NOOP on this platform */ #define AJ_Reboot() #define AJ_CreateNewGUID AJ_RandBytes #define AJ_EXPORT /* * Main method allows argc, argv */ #define MAIN_ALLOWS_ARGS #define AJ_GetDebugTime(x) _AJ_GetDebugTime(x) #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) #define AJ_DEPRECATED(func) func __attribute__((deprecated)) /**< mark a function as deprecated in gcc. */ #else #define AJ_DEPRECATED(func) func /**< not all gcc versions support the deprecated attribute. */ #endif #endif ajtcl-16.04/src/target/linux/aj_target_crypto.c000066400000000000000000000047141271074662300215570ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE TARGET_CRYPTO #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_CRYPTO = 0; #endif /* * Context for AES-128 CTR DRBG */ static CTR_DRBG_CTX drbgctx; uint32_t AJ_PlatformEntropy(uint8_t* data, uint32_t size) { FILE* f = fopen("/dev/urandom", "r"); if (NULL == f) { return 0; } size = fread(data, sizeof (uint8_t), size, f); fclose(f); return size; } void AJ_RandBytes(uint8_t* randBuf, uint32_t size) { AJ_Status status = AJ_ERR_SECURITY; uint8_t seed[SEEDLEN]; if (randBuf && size) { status = AES_CTR_DRBG_Generate(&drbgctx, randBuf, size); if (AJ_OK != status) { // Reseed required AJ_PlatformEntropy(seed, sizeof (seed)); AES_CTR_DRBG_Reseed(&drbgctx, seed, sizeof (seed)); status = AES_CTR_DRBG_Generate(&drbgctx, randBuf, size); } } else { // This is the first call to initialize size = AJ_PlatformEntropy(seed, sizeof (seed)); drbgctx.df = (SEEDLEN == size) ? 0 : 1; AES_CTR_DRBG_Instantiate(&drbgctx, seed, sizeof (seed), drbgctx.df); } } ajtcl-16.04/src/target/linux/aj_target_nvram.c000066400000000000000000000076231271074662300213640ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE TARGET_NVRAM #include #include #include "../../aj_target_nvram.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_NVRAM = 0; #endif uint8_t AJ_EMULATED_NVRAM[AJ_NVRAM_SIZE]; uint8_t* AJ_NVRAM_BASE_ADDRESS; extern void AJ_NVRAM_Layout_Print(); #define NV_FILE "ajtcl.nvram" const char* nvFile = NV_FILE; void AJ_SetNVRAM_FilePath(const char* path) { if (path) { nvFile = path; } } void AJ_NVRAM_Init() { AJ_NVRAM_BASE_ADDRESS = AJ_EMULATED_NVRAM; _AJ_LoadNVFromFile(); if (*((uint32_t*)AJ_NVRAM_BASE_ADDRESS) != AJ_NV_SENTINEL) { AJ_NVRAM_Clear(); _AJ_StoreNVToFile(); } } void _AJ_NV_Write(void* dest, const void* buf, uint16_t size) { memcpy(dest, buf, size); _AJ_StoreNVToFile(); } void _AJ_NV_Move(void* dest, const void* buf, uint16_t size) { memmove(dest, buf, size); _AJ_StoreNVToFile(); } void _AJ_NV_Read(void* src, void* buf, uint16_t size) { memcpy(buf, src, size); } void _AJ_NVRAM_Clear() { memset((uint8_t*)AJ_NVRAM_BASE_ADDRESS, INVALID_DATA_BYTE, AJ_NVRAM_SIZE); *((uint32_t*)AJ_NVRAM_BASE_ADDRESS) = AJ_NV_SENTINEL; _AJ_StoreNVToFile(); } AJ_Status _AJ_LoadNVFromFile() { FILE* f = fopen(nvFile, "r"); if (f == NULL) { AJ_ErrPrintf(("_AJ_LoadNVFromFile(): LoadNVFromFile() failed. status=AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } memset(AJ_NVRAM_BASE_ADDRESS, INVALID_DATA_BYTE, AJ_NVRAM_SIZE); fread(AJ_NVRAM_BASE_ADDRESS, AJ_NVRAM_SIZE, 1, f); fclose(f); return AJ_OK; } AJ_Status _AJ_StoreNVToFile() { FILE* f = fopen(nvFile, "w"); if (!f) { AJ_ErrPrintf(("_AJ_StoreNVToFile(): StoreNVToFile() failed. status=AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } fwrite(AJ_NVRAM_BASE_ADDRESS, AJ_NVRAM_SIZE, 1, f); fclose(f); return AJ_OK; } // Compact the storage by removing invalid entries AJ_Status _AJ_CompactNVStorage() { uint16_t capacity = 0; uint16_t id = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); uint8_t* writePtr = (uint8_t*)data; uint16_t entrySize = 0; uint16_t garbage = 0; //AJ_NVRAM_Layout_Print(); while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS && *data != INVALID_DATA) { id = *data; capacity = *(data + 1); entrySize = ENTRY_HEADER_SIZE + capacity; if (id != INVALID_ID) { _AJ_NV_Move(writePtr, data, entrySize); writePtr += entrySize; } else { garbage += entrySize; } data += entrySize >> 1; } memset(writePtr, INVALID_DATA_BYTE, garbage); _AJ_StoreNVToFile(); //AJ_NVRAM_Layout_Print(); return AJ_OK; } ajtcl-16.04/src/target/linux/aj_target_serial.c000066400000000000000000000047471271074662300215240ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE TARGET_SERIAL #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_SERIAL = 0; #endif #include /** * This function initialized the UART piece of the transport. */ AJ_Status AJ_SerialTargetInit(const char* ttyName) { AJ_ErrPrintf(("AJ_SerialTargetInit(): Serial undefined on this target\n")); assert(0); return AJ_ERR_UNEXPECTED; } AJ_Status AJ_UART_Tx(uint8_t* buffer, uint16_t len) { AJ_ErrPrintf(("AJ_UART_Tx(): Serial undefined on this target\n")); assert(0); return AJ_ERR_UNEXPECTED; } void OI_HCIIfc_DeviceHasBeenReset(void) { AJ_ErrPrintf(("OI_HCIIfc_DeviceHasBeenReset(): Serial undefined on this target\n")); assert(0); } const char* OI_HciDataTypeText(uint8_t hciDataType) { AJ_ErrPrintf(("OI_HciDataTypeText(): Serial undefined on this target\n")); assert(0); return("ERROR: Serial undefined on this target \n"); } void WaitForAck(void) { AJ_ErrPrintf(("WaitForAck(): Serial undefined on this target\n")); assert(0); } void OI_HCIIfc_SendCompleted(uint8_t sendType, AJ_Status status) { AJ_ErrPrintf(("OI_HCIIfc_SendCompleted(): Serial undefined on this target\n")); assert(0); } ajtcl-16.04/src/target/linux/aj_target_util.c000066400000000000000000000207461271074662300212170ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE TARGET_UTIL #include "aj_target.h" #include #include #include #include #include #include #include #include #include #include uint8_t dbgTARGET_UTIL = 0; void AJ_Sleep(uint32_t ms) { struct timespec waittime = { }; waittime.tv_sec = ms / 1000; waittime.tv_nsec = (ms % 1000) * 1000000LL; // nanosleep returns the amount of time slept before being interrupted by a signal, // so loop until the full sleep is finished while (nanosleep(&waittime, &waittime) == -1) { continue; } } #ifndef NDEBUG AJ_Status _AJ_GetDebugTime(AJ_Time* timer) { static int useEpoch = -1; char* env; struct timespec now; AJ_Status status = AJ_ERR_RESOURCES; if (useEpoch == -1) { env = getenv("ER_DEBUG_EPOCH"); useEpoch = env && (strcmp(env, "1") == 0); } if (useEpoch) { clock_gettime(CLOCK_REALTIME, &now); timer->seconds = now.tv_sec; timer->milliseconds = now.tv_nsec / 1000000; status = AJ_OK; } return status; } #endif uint32_t AJ_GetElapsedTime(AJ_Time* timer, uint8_t cumulative) { uint32_t elapsed; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); elapsed = (1000 * (now.tv_sec - timer->seconds)) + ((now.tv_nsec / 1000000) - timer->milliseconds); if (!cumulative) { timer->seconds = now.tv_sec; timer->milliseconds = now.tv_nsec / 1000000; } return elapsed; } void AJ_InitTimer(AJ_Time* timer) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); timer->seconds = now.tv_sec; timer->milliseconds = now.tv_nsec / 1000000; } int32_t AJ_GetTimeDifference(AJ_Time* timerA, AJ_Time* timerB) { int32_t diff; diff = (1000 * (timerA->seconds - timerB->seconds)) + (timerA->milliseconds - timerB->milliseconds); return diff; } void AJ_TimeAddOffset(AJ_Time* timerA, uint32_t msec) { uint32_t msecNew; if (msec == -1) { timerA->seconds = -1; timerA->milliseconds = -1; } else { msecNew = (timerA->milliseconds + msec); timerA->seconds = timerA->seconds + (msecNew / 1000); timerA->milliseconds = msecNew % 1000; } } int8_t AJ_CompareTime(AJ_Time timerA, AJ_Time timerB) { if (timerA.seconds == timerB.seconds) { if (timerA.milliseconds == timerB.milliseconds) { return 0; } else if (timerA.milliseconds > timerB.milliseconds) { return 1; } else { return -1; } } else if (timerA.seconds > timerB.seconds) { return 1; } else { return -1; } } uint64_t AJ_DecodeTime(char* der, const char* fmt) { struct tm tm; if (!strptime(der, fmt, &tm)) { return 0; } return (uint64_t) timegm(&tm); } void* AJ_Malloc(size_t sz) { return malloc(sz); } void* AJ_Realloc(void* ptr, size_t size) { return realloc(ptr, size); } void AJ_Free(void* mem) { if (mem) { free(mem); } } void AJ_MemZeroSecure(void* s, size_t n) { volatile unsigned char* p = s; while (n--) *p++ = '\0'; return; } /* * get a line of input from the the file pointer (most likely stdin). * This will capture the the num-1 characters or till a newline character is * entered. * * @param[out] str a pointer to a character array that will hold the user input * @param[in] num the size of the character array 'str' * @param[in] fp the file pointer the sting will be read from. (most likely stdin) * * @return returns the same string as 'str' if there has been a read error a null * pointer will be returned and 'str' will remain unchanged. */ char*AJ_GetLine(char*str, size_t num, void*fp) { char*p = fgets(str, num, fp); if (p != NULL) { size_t last = strlen(str) - 1; if (str[last] == '\n') { str[last] = '\0'; } } return p; } static uint8_t ioThreadRunning = FALSE; static char cmdline[1024]; static uint8_t consumed = TRUE; static pthread_t threadId; void* RunFunc(void* threadArg) { while (ioThreadRunning) { if (consumed) { AJ_GetLine(cmdline, sizeof(cmdline), stdin); consumed = FALSE; } AJ_Sleep(1000); } return 0; } uint8_t AJ_StartReadFromStdIn() { int ret = 0; if (!ioThreadRunning) { ret = pthread_create(&threadId, NULL, RunFunc, NULL); if (ret != 0) { AJ_ErrPrintf(("Error: fail to spin a thread for reading from stdin\n")); } ioThreadRunning = TRUE; return TRUE; } return FALSE; } char* AJ_GetCmdLine(char* buf, size_t num) { if (!consumed) { strncpy(buf, cmdline, num); buf[num - 1] = '\0'; consumed = TRUE; return buf; } return NULL; } uint8_t AJ_StopReadFromStdIn() { void* exit_status; if (ioThreadRunning) { ioThreadRunning = FALSE; pthread_join(threadId, &exit_status); return TRUE; } return FALSE; } #ifndef NDEBUG /* * This is not intended, nor required to be particularly efficient. If you want * efficiency, turn of debugging. */ int _AJ_DbgEnabled(const char* module) { char buffer[128]; char* env; strcpy(buffer, "ER_DEBUG_ALL"); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } strcpy(buffer, "ER_DEBUG_"); strcat(buffer, module); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } return FALSE; } #endif uint16_t AJ_ByteSwap16(uint16_t x) { return bswap_16(x); } uint32_t AJ_ByteSwap32(uint32_t x) { return bswap_32(x); } uint64_t AJ_ByteSwap64(uint64_t x) { return bswap_64(x); } AJ_Status AJ_IntToString(int32_t val, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = snprintf(buf, buflen, "%d", val); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } AJ_Status AJ_InetToString(uint32_t addr, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = snprintf((char*)buf, buflen, "%u.%u.%u.%u", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF)); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } static FILE* logFile = NULL; static uint32_t logLim = 0; int AJ_SetLogFile(const char* file, uint32_t maxLen) { if (logFile) { fclose(logFile); } if (!file) { logFile = NULL; } else { logFile = fopen(file, "w+"); if (!logFile) { return -1; } logLim = maxLen / 2; } return 0; } void AJ_Printf(const char* fmat, ...) { va_list args; va_start(args, fmat); if (logFile) { vfprintf(logFile, fmat, args); if (logLim) { /* * Don't allow the log file to grow to more than 2 x logLim bytes */ long pos = ftell(logFile); if (pos >= (2 * logLim)) { void* buf = malloc(logLim); if (buf) { fseek(logFile, -logLim, SEEK_CUR); fread(buf, logLim, 1, logFile); fseek(logFile, 0, SEEK_SET); ftruncate(fileno(logFile), 0); fwrite(buf, logLim, 1, logFile); free(buf); } } } fflush(logFile); } else { vprintf(fmat, args); fflush(stdout); } va_end(args); } ajtcl-16.04/src/target/mbedrtos-frdm/000077500000000000000000000000001271074662300174535ustar00rootroot00000000000000ajtcl-16.04/src/target/mbedrtos-frdm/SConscript000066400000000000000000000015371271074662300214730ustar00rootroot00000000000000Import('src_env') # Enable common components for FRDM-K64F running MbedRTOS src_env['crypto'] = True src_env['external_sha2'] = True src_env['malloc'] = True src_env['freertos'] = False src_env['mbedrtos'] = True src_env['wsl'] = True src_env['nvram'] = False # Target source targ_files = [Glob('*.c'), Glob('*.cpp')] # Mbed, Mbed-rtos, SDFileSystem and FATFileSystem source mbed_files = [Glob(src_env['MBED_DIR'] + '/mbed-rtos/rtx/TARGET_M3/TOOLCHAIN_GCC/*.s'), Glob(src_env['MBED_DIR'] + '/mbed-rtos/rtx/*.c'), Glob(src_env['MBED_DIR'] + '/mbed-rtos/rtos/*.cpp'), Glob(src_env['MBED_DIR'] + '/FATFileSystem/*.cpp'), Glob(src_env['MBED_DIR'] + '/FATFileSystem/ChaN/*.cpp'), Glob(src_env['MBED_DIR'] + '/SDFileSystem/*.cpp')] src_env['srcs'].extend([targ_files, mbed_files]) ajtcl-16.04/src/target/mbedrtos-frdm/aj_nvram.cpp000066400000000000000000000271701271074662300217630ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE NVRAM #include "mbed.h" #include "SDFileSystem.h" #include #include "../../aj_target_nvram.h" #include extern "C" { /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgNVRAM = 0; #endif #define MAX_FNAME_SZ 14 static void idToString(uint16_t id, char* str) { sprintf(str, "/sd/%u.ajnv", id); } static uint16_t stringToId(char* str) { uint8_t i = 0; char buf[6]; uint16_t id; while (i < strlen(str)) { if (str[i] == '.') { break; } buf[i] = str[i]; i++; } buf[i] = '\0'; id = atoi(buf); return id; } static uint8_t isEntry(char* file) { uint8_t len = strlen(file); if (file[len - 4] == 'a' && file[len - 3] == 'j' && file[len - 2] == 'n' && file[len - 1] == 'v') { return 1; } return 0; } void AJ_NVRAM_Init(void) { return; } uint32_t AJ_NVRAM_GetSize(void) { DIR* dir; FILE* f; struct dirent* entry; uint32_t size = 0; size_t remainingOutputSize; dir = opendir("/sd"); if (dir) { while ((entry = readdir(dir)) != NULL) { uint16_t sz = 0; char buf[MAX_FNAME_SZ + 1]; buf[0] = '\0'; if (isEntry(entry->d_name)) { strcpy(buf, "/sd/"); /* Append 11 characters max: "12345.ajnv\0" */ remainingOutputSize = ArraySize(buf) - strlen(buf) - 1; strncat(buf, entry->d_name, min(remainingOutputSize, 11)); f = fopen(buf, "r"); if (f == NULL) { AJ_ErrPrintf(("AJ_NVRAM_GetSize(): Error opening file\n")); return 0; } fread(&sz, 1, sizeof(uint16_t), f); size += sz; fclose(f); } } closedir(dir); } return size; } uint32_t AJ_NVRAM_GetSizeRemaining(void) { return AJ_NVRAM_SIZE - AJ_NVRAM_GetSize(); } void AJ_NVRAM_Layout_Print() { DIR* dir; FILE* f; struct dirent* entry; size_t remainingOutputSize; dir = opendir("/sd"); AJ_AlwaysPrintf(("============ AJ NVRAM Map ===========\n")); if (dir) { while ((entry = readdir(dir)) != NULL) { uint16_t sz; char buf[MAX_FNAME_SZ + 1]; buf[0] = '\0'; if (isEntry(entry->d_name)) { strcpy(buf, "/sd/"); remainingOutputSize = ArraySize(buf) - strlen(buf) - 1; strncat(buf, entry->d_name, min(remainingOutputSize, 11)); f = fopen(buf, "r"); if (f == NULL) { AJ_ErrPrintf(("AJ_NVRAM_Layout_Print(): Could not open file, AJ_ERR_FAILURE\n")); continue; } fread(&sz, 1, sizeof(uint16_t), f); AJ_AlwaysPrintf(("ID = %d, capacity = %d\n", stringToId(entry->d_name), sz)); fclose(f); } } closedir(dir); } AJ_AlwaysPrintf(("============ End ===========\n")); } uint8_t AJ_NVRAM_Exist(uint16_t id) { char fname[MAX_FNAME_SZ + 1]; DIR* dir; struct dirent* entry; idToString(id, fname); dir = opendir("/sd"); if (dir) { while ((entry = readdir(dir)) != NULL) { if (isEntry(entry->d_name)) { if (strcmp(entry->d_name, fname + 4) == 0) { return 1; } } } closedir(dir); } return 0; } AJ_Status AJ_NVRAM_Create(uint16_t id, uint16_t capacity) { char fname[MAX_FNAME_SZ + 1]; idToString(id, fname); FILE* f; AJ_InfoPrintf(("AJ_NVRAM_Create(id=%d., capacity=%d.)\n", id, capacity)); if (!capacity || AJ_NVRAM_Exist(id)) { AJ_ErrPrintf(("AJ_NVRAM_Create(): AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } f = fopen(fname, "w"); if (f == NULL) { AJ_ErrPrintf(("AJ_NVRAM_Create(): Could not open file, AJ_ERR_FAILURE\n")); return AJ_ERR_FAILURE; } fwrite(&capacity, sizeof(uint16_t), 1, f); fflush(f); fclose(f); return AJ_OK; } AJ_Status AJ_NVRAM_Delete(uint16_t id) { char fname[MAX_FNAME_SZ + 1]; idToString(id, fname); if (remove(fname) != 0) { AJ_ErrPrintf(("AJ_NVRAM_Delete(): Could not delete file %s\n", fname)); return AJ_ERR_FAILURE; } return AJ_OK; } uint8_t* AJ_FindNVEntry(uint16_t id) { FILE* f; char fname[MAX_FNAME_SZ + 1]; uint16_t size; uint8_t* data; idToString(id, fname); f = fopen(fname, "r"); if (f == NULL) { AJ_ErrPrintf(("AJ_FindNVEntry(): Error opening file\n")); return NULL; } fseek(f, 0, SEEK_SET); fread(&size, 1, sizeof(uint16_t), f); if (!size) { AJ_ErrPrintf(("AJ_FindNVEntry(): Error when reading entry, zero size\n")); fclose(f); return NULL; } data = (uint8_t*)AJ_Malloc(size + sizeof(uint16_t)); fseek(f, 0, SEEK_SET); fread(data, size + sizeof(uint16_t), 1, f); fflush(f); fclose(f); return data; } FILE* _AJ_NV_Open(uint16_t id, char* mode) { FILE* f; char fname[MAX_FNAME_SZ + 1]; idToString(id, fname); if (!id) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid id\n")); goto OPEN_ERR_EXIT; } if (!mode || mode[1] || (*mode != 'r' && *mode != 'w')) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid access mode\n")); goto OPEN_ERR_EXIT; } if (*mode == 'w') { /* * File already has the length written from AJ_NVRAM_Create() so * opening as mode "w" would erase that from the file. */ f = fopen(fname, "a"); } else { f = fopen(fname, "r"); } if (f == NULL) { AJ_ErrPrintf(("_AJ_NV_Open(): Could not open file\n")); goto OPEN_ERR_EXIT; } return f; OPEN_ERR_EXIT: AJ_ErrPrintf(("AJ_NVRAM_Open(): failure: status=%s\n", AJ_StatusText(AJ_ERR_FAILURE))); return NULL; } AJ_NV_DATASET* AJ_NVRAM_Open(uint16_t id, char* mode, uint16_t capacity) { AJ_Status status = AJ_OK; uint8_t* entry = NULL; AJ_NV_DATASET* handle = NULL; AJ_InfoPrintf(("AJ_NVRAM_Open(id=%d., mode=\"%s\", capacity=%d.)\n", id, mode, capacity)); if (!id) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid id\n")); goto OPEN_ERR_EXIT; } if (!mode || mode[1] || (*mode != 'r' && *mode != 'w')) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid access mode\n")); goto OPEN_ERR_EXIT; } if (*mode == AJ_NV_DATASET_MODE_WRITE) { if (capacity == 0) { AJ_ErrPrintf(("AJ_NVRAM_Open(): invalid capacity\n")); goto OPEN_ERR_EXIT; } if (AJ_NVRAM_Exist(id)) { status = AJ_NVRAM_Delete(id); } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_NVRAM_Open(): AJ_NVRAM_Delete() failure: status=%s\n", AJ_StatusText(status))); goto OPEN_ERR_EXIT; } if (!AJ_NVRAM_Exist(id)) { status = AJ_NVRAM_Create(id, capacity); } if (status != AJ_OK) { AJ_ErrPrintf(("AJ_NVRAM_Open(): AJ_NVRAM_Create() failure: status=%s\n", AJ_StatusText(status))); goto OPEN_ERR_EXIT; } entry = AJ_FindNVEntry(id); if (!entry) { AJ_ErrPrintf(("AJ_NVRAM_Open(): Data set %d. does not exist\n", id)); goto OPEN_ERR_EXIT; } } else { entry = AJ_FindNVEntry(id); if (!entry) { AJ_WarnPrintf(("AJ_NVRAM_Open(): Data set %d. does not exist\n", id)); goto OPEN_ERR_EXIT; } } handle = (AJ_NV_DATASET*)AJ_Malloc(sizeof(AJ_NV_DATASET)); if (!handle) { AJ_ErrPrintf(("AJ_NVRAM_Open(): AJ_Malloc() failure\n")); goto OPEN_ERR_EXIT; } handle->id = id; handle->curPos = 0; handle->mode = *mode; handle->capacity = capacity; handle->inode = entry; handle->internal = (void*)_AJ_NV_Open(id, mode); return handle; OPEN_ERR_EXIT: if (handle) { AJ_Free(handle); handle = NULL; } AJ_ErrPrintf(("AJ_NVRAM_Open(): failure: status=%s\n", AJ_StatusText(status))); return NULL; } size_t AJ_NVRAM_Write(const void* ptr, uint16_t size, AJ_NV_DATASET* handle) { FILE* f; if (!handle || handle->mode == AJ_NV_DATASET_MODE_READ) { AJ_ErrPrintf(("AJ_NVRAM_Write(): AJ_ERR_ACCESS\n")); return -1; } f = (FILE*)handle->internal; /* Copy the data into the current RAM section */ memcpy(handle->inode + handle->curPos + sizeof(uint16_t), ptr, size); fseek(f, handle->curPos + sizeof(uint16_t), SEEK_SET); /* fwrite returns number of items written, which should be 1 */ if (fwrite(ptr, size, 1, f) != 1) { AJ_ErrPrintf(("AJ_NVRAM_Write(): Could not write to file\n")); return -1; } fflush(f); handle->curPos += size; return size; } const void* AJ_NVRAM_Peek(AJ_NV_DATASET* handle) { if (!handle || handle->mode == AJ_NV_DATASET_MODE_WRITE) { AJ_ErrPrintf(("AJ_NVRAM_Peek(): AJ_ERR_ACCESS\n")); return NULL; } return (const void*)(handle->inode + sizeof(uint16_t) + handle->curPos); } size_t AJ_NVRAM_Read(void* ptr, uint16_t size, AJ_NV_DATASET* handle) { if (!handle || handle->mode == AJ_NV_DATASET_MODE_WRITE) { AJ_ErrPrintf(("AJ_NVRAM_Read(): AJ_ERR_ACCESS\n")); return -1; } /* Copy the data from the current RAM section */ memcpy(ptr, handle->inode + handle->curPos + sizeof(uint16_t), size); handle->curPos += size; return size; } AJ_Status AJ_NVRAM_Close(AJ_NV_DATASET* handle) { if (!handle) { AJ_ErrPrintf(("AJ_NVRAM_Close(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } fclose((FILE*)handle->internal); AJ_Free(handle->inode); AJ_Free(handle); return AJ_OK; } void AJ_NVRAM_Clear() { DIR* dir; struct dirent* entry; int ret = 0; size_t remainingOutputSize; dir = opendir("/sd"); if (dir) { while ((entry = readdir(dir)) != NULL) { char fname[MAX_FNAME_SZ + 1]; fname[0] = '\0'; if (isEntry(entry->d_name)) { strcat(fname, "/sd/"); remainingOutputSize = ArraySize(fname) - strlen(fname) - 1; strncat(fname, entry->d_name, min(remainingOutputSize, 11)); ret = remove(fname); if (ret != 0) { AJ_ErrPrintf(("Could not remove entry %s, ret = %d\n", entry->d_name, ret)); } } } closedir(dir); } } } ajtcl-16.04/src/target/mbedrtos-frdm/aj_target.h000066400000000000000000000047011271074662300215660ustar00rootroot00000000000000#ifndef _AJ_TARGET_H #define _AJ_TARGET_H /** * @file WSL target macros and includes */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #define AJ_EXPORT #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef max #define max(x, y) ((x) > (y) ? (x) : (y)) #endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define WORD_ALIGN(x) ((x & 0x3) ? ((x >> 2) + 1) << 2 : x) #define HOST_IS_LITTLE_ENDIAN 1 #define HOST_IS_BIG_ENDIAN 0 #define HOST_ENDIANESS AJ_LITTLE_ENDIAN #ifndef NDEBUG extern uint8_t dbgCONFIGUREME; extern uint8_t dbgINIT; extern uint8_t dbgNET; extern uint8_t dbgTARGET_CRYPTO; extern uint8_t dbgTARGET_NVRAM; extern uint8_t dbgTARGET_SERIAL; extern uint8_t dbgTARGET_TIMER; extern uint8_t dbgTARGET_UTIL; #endif #define AJ_ASSERT(x) assert(x) /* * AJ_Reboot() is a NOOP on this platform */ #define _AJ_Reboot() do { } while (0) #define AJ_Reboot() _AJ_Reboot() #define AJ_CreateNewGUID AJ_RandBytes #define AJ_GetDebugTime(x) AJ_ERR_RESOURCES #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) #define AJ_DEPRECATED(func) func __attribute__((deprecated)) /**< mark a function as deprecated in gcc. */ #else #define AJ_DEPRECATED(func) func /**< not all gcc versions support the deprecated attribute. */ #endif #ifdef __cplusplus } #endif #endif ajtcl-16.04/src/target/mbedrtos-frdm/aj_target_mbed.cpp000066400000000000000000000174111271074662300231120ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * This C++ file is a wrapper for the MBED C++ API's so they can * be call-able from C. The file extension gets changed to .cpp * at compile time. */ #include "mbed.h" #include "SDFileSystem.h" #include "fsl_uart_hal.h" #include #include #include #include "fsl_dspi_hal.h" #include #include "fsl_port_hal.h" #include #include #include SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); Serial pc(PTB17, PTB16); SPI spi(PTD2, PTD3, PTD1, NC); DigitalOut* pwd; InterruptIn* interrupt; extern "C" { void BoardPrintf(const char* fmat, ...) { char buf[256]; va_list args; va_start(args, fmat); vsnprintf(buf, 256, fmat, args); AJ_EnterCriticalRegion(); pc.printf("%s", buf); AJ_LeaveCriticalRegion(); va_end(args); } void BoardPrintfInit(uint32_t baud) { pc.baud(baud); } /** TX interrupt occurred */ volatile uint8_t g_b_spi_interrupt_tx_ready = 0; /** RX interrupt occurred */ volatile uint8_t g_b_spi_interrupt_rx_ready = 0; volatile uint8_t g_b_spi_interrupt_data_ready = 0; aj_spi_status AJ_SPI_WRITE(uint8_t* spi_device, uint8_t byte, uint8_t pcs, uint8_t cont) { /* * spi_device is not used since we always know the SPI peripheral controlling * the WiFI chip */ dspi_command_config_t commandConfig; commandConfig.isChipSelectContinuous = cont ? 0 : 1; commandConfig.whichCtar = kDspiCtar0; commandConfig.whichPcs = kDspiPcs0; commandConfig.clearTransferCount = true; commandConfig.isEndOfQueue = false; dspi_hal_write_data_master_mode(0, &commandConfig, byte); /* Wait for the TX Complete flag meaning the SPI operation (write) has finished */ while (!dspi_hal_get_status_flag(0, kDspiTxComplete)); /* Un-set the flag for the next call to AJ_SPI_WRITE */ dspi_hal_clear_status_flag(0, kDspiTxComplete); return SPI_OK; } aj_spi_status AJ_SPI_READ(uint8_t spi_device, uint8_t* data, uint8_t pcs) { /* * spi_device is not used since we always know the SPI peripheral controlling * the WiFi chip. * pcs (chip select) is not used in the context of read because in reality the * SPI read has already taken place. This call simply copies the data. */ uint32_t read = dspi_hal_read_data(0); memcpy(data, (const void*)&read, 1); return SPI_OK; } AJ_Status AJ_WSL_SPI_DMATransfer(uint8_t* buffer, uint16_t len, uint8_t direction) { int32_t i = 0; if (direction == 1) { //Transmit uint8_t toss; while (i < (len - 1)) { AJ_SPI_WRITE(0, *(buffer + i), 0, 0); AJ_SPI_READ(0, &toss, 0); i++; } AJ_SPI_WRITE(0, *(buffer + i), 0, 1); AJ_SPI_READ(0, &toss, 0); } else { // Receive while (i < (len - 1)) { AJ_SPI_WRITE(0, 0, 0, 0); AJ_SPI_READ(0, (buffer + i), 0); i++; } AJ_SPI_WRITE(0, 0, 0, 1); AJ_SPI_READ(0, (buffer + i), 1); } return AJ_OK; } void AJ_WSL_SPI_PowerCycleWiFiChip(void) { pwd->write(0); AJ_Sleep(100); pwd->write(1); } extern struct AJ_TaskHandle* AJ_WSL_MBoxListenHandle; void AJ_WSL_SPI_CHIP_SPI_ISR(void) { __disable_irq(); g_b_spi_interrupt_data_ready = TRUE; AJ_ResumeTask(AJ_WSL_MBoxListenHandle, TRUE); __enable_irq(); } void AJ_WSL_SPI_InitializeSPIController(void) { uint32_t calculatedBaudRate; dspi_master_config_t dspiConfig; dspi_delay_settings_config_t delayConfig; dspiConfig.isEnabled = false; dspiConfig.whichCtar = kDspiCtar0; dspiConfig.bitsPerSec = 0; dspiConfig.sourceClockInHz = 120000000; dspiConfig.isSckContinuous = false; dspiConfig.whichPcs = kDspiPcs0; dspiConfig.pcsPolarity = kDspiPcs_ActiveLow; dspiConfig.masterInSample = kDspiSckToSin_1Clock; dspiConfig.isModifiedTimingFormatEnabled = true; dspiConfig.isTxFifoDisabled = false; dspiConfig.isRxFifoDisabled = false; dspiConfig.dataConfig.bitsPerFrame = 8; dspiConfig.dataConfig.clkPolarity = kDspiClockPolarity_ActiveLow; dspiConfig.dataConfig.clkPhase = kDspiClockPhase_SecondEdge; dspiConfig.dataConfig.direction = kDspiMsbFirst; dspi_hal_disable(0); dspi_hal_master_init(0, &dspiConfig, &calculatedBaudRate); PORTD_PCR0 = PORT_PCR_MUX(2); delayConfig.pcsToSckPre = 0x4; delayConfig.pcsToSck = 0x4; delayConfig.afterSckPre = 0x3; delayConfig.afterSck = 0x3; delayConfig.afterTransferPre = 0x5; delayConfig.afterTransfer = 0x5; dspi_hal_configure_delays(0, kDspiCtar0, &delayConfig); dspi_hal_configure_interrupt(0, kDspiTxComplete, true); dspi_hal_enable(0); pwd = new DigitalOut(PTA1, 0); AJ_WSL_SPI_PowerCycleWiFiChip(); NVIC_SetPriority(PORTC_IRQn, 0x0f); interrupt = new InterruptIn(PTC3); interrupt->mode(PullUp); interrupt->fall(&AJ_WSL_SPI_CHIP_SPI_ISR); NVIC_SetPriority(PORTC_IRQn, 0x0f); AJ_WSL_SPI_PowerCycleWiFiChip(); } void AJ_WSL_SPI_ShutdownSPIController(void) { if (pwd) { delete pwd; pwd = NULL; } } static uint8_t seed[16]; static uint8_t key[16]; static uint8_t RandBit(AnalogIn* adc) { return (uint8_t)(adc->read_u16() & 1); } static void GatherBits(uint8_t* buffer, uint32_t len) { int i; AnalogIn* adc = new AnalogIn(PTC10); if (adc) { memset(buffer, 0, len); for (i = 0; i < len; ++i) { int j; uint8_t r = 0; for (j = 0; j < 8; ++j) { r <<= 1; r |= RandBit(adc); } buffer[i] = r; } delete adc; } else { AJ_ErrPrintf(("GatherBits(): Could access ADC device\n")); } #ifdef SHOW_RANDOM_BITS for (i = 0; i < len; ++i) { int j; int r = buffer[i]; for (j = 0; j < 8; ++j) { AJ_Printf("%c", '0' + (r & 1)); r >>= 1; } } AJ_Printf("\n"); #endif } /* Variable holding the number of milliseconds since startup */ extern uint32_t os_time; void AJ_RandBytes(uint8_t* rand, uint32_t len) { /* * If this is the first call we need to accumulate * entropy for the seed and key */ if (seed[0] == 0) { GatherBits(seed, sizeof(seed)); GatherBits(key, sizeof(key)); } AJ_AES_Enable(key); while (len) { uint32_t tmp[4]; uint32_t sz = min(16, len); uint32_t ticks = os_time; //Tick rate is 1000 Hz: 1 tick per millisecond tmp[0] = ticks; tmp[1] += 1; AJ_AES_ECB_128_ENCRYPT(key, (uint8_t*)tmp, (uint8_t*)tmp); AJ_AES_CBC_128_ENCRYPT(key, seed, seed, 16, (uint8_t*)tmp); memcpy(rand, seed, sz); AJ_AES_CBC_128_ENCRYPT(key, seed, seed, 16, (uint8_t*)tmp); len -= sz; rand += sz; } AJ_AES_Disable(); } } ajtcl-16.04/src/target/mbedrtos-frdm/aj_target_mbed.h000066400000000000000000000040651271074662300225600ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_TARGET_MBED_H_ #define AJ_TARGET_MBED_H_ typedef enum { SPI_OK, SPI_ERR }aj_spi_status; /** * Printf function that prints to the serial port on the MBED board * * @param fmat Format string (same as printf) * @param ... List of arguments that will be placed in the format string * * note: Currently this function only supports printing 256 characters per call. * Anything over that would need to have successive BoardPrintf calls. */ void BoardPrintf(const char* fmat, ...); /** * Initialize the serial port so BoardPrintf can be used. This must be called * before BoardPrintf or it will not function. * * @param baud Baud rate for the serial port */ void BoardPrintfInit(uint32_t baud); /** * Initialize the SPI controller. This function does all the initialization in order for the SPI * peripheral to work the the GT-202/QCA4004/2 */ void AJ_WSL_SPI_InitializeSPIController(void); /** * Sleep for a specified time * * @param time Time to sleep in milliseconds */ void AJ_Sleep(uint32_t time); #endif /* AJ_TARGET_MBED_H_ */ ajtcl-16.04/src/target/mbedrtos-frdm/aj_target_platform.c000066400000000000000000000037651271074662300234760ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include void _AJ_PlatformInit(void) { BoardPrintfInit(115200); return; } uint16_t AJ_ByteSwap16(uint16_t x) { return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)); } uint32_t swap32(uint32_t x) { return AJ_ByteSwap32(x); } uint32_t AJ_ByteSwap32(uint32_t x) { return ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) | ((x << 24) & 0xFF000000) | ((x << 8) & 0x00FF0000); } uint64_t AJ_ByteSwap64(uint64_t x) { return ((x >> 56) & 0x00000000000000FF) | ((x >> 40) & 0x000000000000FF00) | ((x << 56) & 0xFF00000000000000) | ((x << 40) & 0x00FF000000000000) | ((x >> 24) & 0x0000000000FF0000) | ((x >> 8) & 0x00000000FF000000) | ((x << 24) & 0x0000FF0000000000) | ((x << 8) & 0x000000FF00000000); } uint8_t AJ_SeedRNG(void) { return 1; } void _exit(int i) { while (1); } int _kill(int pid) { return 1; } int _getpid() { return 0; } void _gettimeofday() { return; } ajtcl-16.04/src/target/mbedrtos-frdm/aj_target_platform.h000066400000000000000000000035001271074662300234660ustar00rootroot00000000000000#ifndef _AJ_TARGET_PLATFORM_H_ #define _AJ_TARGET_PLATFORM_H_ /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef __cplusplus extern "C" { #endif #include #include #define AJ_Printf BoardPrintf #define A_UINT32 uint32_t #ifdef AJ_NVRAM_SIZE #undef AJ_NVRAM_SIZE #define AJ_NVRAM_SIZE (0x10000) #else #define AJ_NVRAM_SIZE (0x10000) #endif #define AJ_WSL_SPI_DEVICE 0 #define AJ_WSL_SPI_DEVICE_ID 0 #define AJ_WSL_SPI_DEVICE_NPCS 0 #define AJ_WSL_SPI_PCS 0 #define AJ_WSL_SPI_CHIP_PWD_PIN 0 #define AJ_WSL_SPI_CHIP_SPI_INT_PIN 0 #define AJ_WSL_SPI_CHIP_SPI_INT_BIT 0 #define AJ_WSL_SPI_CHIP_POWER_PIN 0 #define AJ_WSL_STACK_SIZE 3000 void _AJ_NVRAM_Clear(void); void AJ_NVRAM_Init(void); void _AJ_PlatformInit(void); uint8_t AJ_SeedRNG(void); /* * AJ_Reboot() is a NOOP on this platform */ #define AJ_Reboot() _AJ_Reboot() #ifdef __cplusplus } #endif #endif ajtcl-16.04/src/target/win32/000077500000000000000000000000001271074662300156505ustar00rootroot00000000000000ajtcl-16.04/src/target/win32/SConscript000066400000000000000000000003401271074662300176570ustar00rootroot00000000000000Import('src_env') # Enable common components for Win32 src_env['crypto'] = True src_env['external_sha2'] = True src_env['malloc'] = True src_env['nvram'] = True # Build target source src_env['srcs'] += src_env.Glob('*.c') ajtcl-16.04/src/target/win32/aj_net.c000066400000000000000000001222741271074662300172640ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE NET #include #include #include #pragma comment(lib, "Ws2_32.lib") #include #pragma comment(lib, "iphlpapi.lib") #include #include #include #include #include #include #include #include #include #include #include #ifdef AJ_ARDP #include #endif /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgNET = 0; #endif static void WinsockCheck() { static uint8_t initialized = FALSE; if (!initialized) { WSADATA wsaData; WORD version = MAKEWORD(2, 0); int ret; AJ_InfoPrintf(("WinsockCheck\n")); ret = WSAStartup(version, &wsaData); if (ret) { AJ_ErrPrintf(("WSAStartup failed with error: %d\n", ret)); } else { initialized = TRUE; } } } /* * IANA assigned IPv4 multicast group for AllJoyn. */ static const char AJ_IPV4_MULTICAST_GROUP[] = "224.0.0.113"; /* * IANA assigned IPv6 multicast group for AllJoyn. */ static const char AJ_IPV6_MULTICAST_GROUP[] = "ff02::13a"; /* * IANA assigned UDP multicast port for AllJoyn */ #define AJ_UDP_PORT 9956 /* * IANA-assigned IPv4 multicast group for mDNS. */ static const char MDNS_IPV4_MULTICAST_GROUP[] = "224.0.0.251"; /* * IANA-assigned IPv6 multicast group for mDNS. */ static const char MDNS_IPV6_MULTICAST_GROUP[] = "ff02::fb"; /* * IANA-assigned UDP multicast port for mDNS */ #define MDNS_UDP_PORT 5353 /* * Various events for I/O */ static WSAEVENT interruptEvent = WSA_INVALID_EVENT; static WSAEVENT recvEvent = WSA_INVALID_EVENT; static WSAEVENT sendEvent = WSA_INVALID_EVENT; /** * Target-specific contexts for network I/O */ typedef struct { SOCKET tcpSock; SOCKET udpSock; } NetContext; static NetContext netContext = { INVALID_SOCKET, INVALID_SOCKET }; #ifdef AJ_ARDP /** * Need to predeclare a few things for ARDP */ static AJ_Status AJ_Net_ARDP_Connect(AJ_BusAttachment* bus, const AJ_Service* service); #endif // AJ_ARDP /* * This function is called to cancel a pending select. */ void AJ_Net_Interrupt() { if (interruptEvent != WSA_INVALID_EVENT) { WSASetEvent(interruptEvent); } } #ifdef AJ_TCP static AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { DWORD ret; DWORD tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_Send(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { NetContext* ctx = (NetContext*) buf->context; WSAOVERLAPPED ov; DWORD flags = 0; WSABUF wsbuf; memset(&ov, 0, sizeof(ov)); ov.hEvent = sendEvent; wsbuf.len = tx; wsbuf.buf = buf->readPtr; ret = WSASend(ctx->tcpSock, &wsbuf, 1, NULL, flags, &ov, NULL); if (!WSAGetOverlappedResult(ctx->tcpSock, &ov, &tx, TRUE, &flags)) { AJ_ErrPrintf(("AJ_Net_Send(): send() failed. WSAGetLastError()=0x%x, status=AJ_ERR_WRITE\n", WSAGetLastError())); return AJ_ERR_WRITE; } buf->readPtr += tx; } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_Net_Send(): status=AJ_OK\n")); return AJ_OK; } #endif static WSAOVERLAPPED wsaOverlapped; static WSABUF wsbuf; #ifdef AJ_TCP static AJ_Status AJ_Net_Recv(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { AJ_Status status = AJ_ERR_READ; WSAEVENT events[2]; DWORD rx = AJ_IO_BUF_SPACE(buf); DWORD flags = 0; DWORD ret = SOCKET_ERROR; NetContext* ctx = (NetContext*) buf->context; AJ_InfoPrintf(("AJ_Net_Recv(buf=0x%p, len=%d, timeout=%d)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); rx = min(rx, len); if (!rx) { return AJ_OK; } /* * Overlapped receives cannot be cancelled. We are relying the fact that a timedout or * interrupted receive will be eventually reposted with the same buffer. */ if (wsaOverlapped.hEvent == INVALID_HANDLE_VALUE) { wsbuf.len = rx; wsbuf.buf = buf->writePtr; memset(&wsaOverlapped, 0, sizeof(WSAOVERLAPPED)); wsaOverlapped.hEvent = recvEvent; ret = WSARecv(ctx->tcpSock, &wsbuf, 1, NULL, &flags, &wsaOverlapped, NULL); if ((ret == SOCKET_ERROR) && (WSAGetLastError() != WSA_IO_PENDING)) { AJ_ErrPrintf(("WSARecv(): failed WSAGetLastError()=%d\n", WSAGetLastError())); return AJ_ERR_READ; } } /* * Assert that the buffer and length are the same in the case where this is a reposting of the * receive after an timeout or interrupt. */ AJ_ASSERT(wsbuf.buf == buf->writePtr); AJ_ASSERT(wsbuf.len == rx); events[0] = wsaOverlapped.hEvent; events[1] = interruptEvent; ret = WSAWaitForMultipleEvents(2, events, FALSE, timeout, TRUE); if (ret == WSA_WAIT_EVENT_0) { if (WSAGetOverlappedResult(ctx->tcpSock, &wsaOverlapped, &rx, TRUE, &flags)) { status = AJ_OK; } } else if (ret == WSA_WAIT_TIMEOUT) { status = AJ_ERR_TIMEOUT; } else if (ret == (WSA_WAIT_EVENT_0 + 1)) { WSAResetEvent(interruptEvent); status = AJ_ERR_INTERRUPTED; } else { AJ_ErrPrintf(("AJ_Net_Recv(): WSAGetLastError()=%d\n", WSAGetLastError())); } if (status == AJ_OK) { /* * Reset recv event and clear overlapped struct for the next call */ WSAResetEvent(wsaOverlapped.hEvent); wsaOverlapped.hEvent = INVALID_HANDLE_VALUE; buf->writePtr += rx; AJ_InfoPrintf(("AJ_Net_Recv(): read %d bytes\n", rx)); } return status; } #endif /* * Statically sized buffers for I/O */ static uint8_t rxData[AJ_RX_DATA_SIZE]; static uint8_t txData[AJ_TX_DATA_SIZE]; #ifdef AJ_TCP static AJ_Status AJ_TCP_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { DWORD ret; SOCKADDR_STORAGE addrBuf; socklen_t addrSize; SOCKET sock; AJ_InfoPrintf(("AJ_TCP_Connect(bus=0x%p, addrType=%d.)\n", bus, service->addrTypes)); memset(&addrBuf, 0, sizeof(addrBuf)); if (service->addrTypes & AJ_ADDR_TCP4) { struct sockaddr_in* sa = (struct sockaddr_in*)&addrBuf; sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_TCP_Connect(): invalid socket. status=AJ_ERR_CONNECT\n")); return AJ_ERR_CONNECT; } sa->sin_family = AF_INET; sa->sin_port = htons(service->ipv4port); sa->sin_addr.s_addr = service->ipv4; addrSize = sizeof(*sa); AJ_InfoPrintf(("AJ_TCP_Connect(): Connect to \"%s:%u\"\n", inet_ntoa(sa->sin_addr), service->ipv4port));; } else if (service->addrTypes & AJ_ADDR_TCP6) { struct sockaddr_in6* sa = (struct sockaddr_in6*)&addrBuf; sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_TCP_Connect(): invalid socket. status=AJ_ERR_CONNECT\n")); return AJ_ERR_CONNECT; } sa->sin6_family = AF_INET6; sa->sin6_port = htons(service->ipv6port); memcpy(sa->sin6_addr.s6_addr, service->ipv6, sizeof(sa->sin6_addr.s6_addr)); addrSize = sizeof(*sa); } else { AJ_ErrPrintf(("AJ_TCP_Connect: only TCPv6 and TCPv4 are supported\n")); return AJ_ERR_CONNECT; } ret = connect(sock, (struct sockaddr*)&addrBuf, addrSize); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_TCP_Connect(): connect() failed. WSAGetLastError()=0x%x, status=AJ_ERR_CONNECT\n", WSAGetLastError())); closesocket(sock); return AJ_ERR_CONNECT; } else { AJ_IOBufInit(&bus->sock.rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, &netContext); bus->sock.rx.recv = AJ_Net_Recv; AJ_IOBufInit(&bus->sock.tx, txData, sizeof(txData), AJ_IO_BUF_TX, &netContext); bus->sock.tx.send = AJ_Net_Send; netContext.tcpSock = sock; AJ_InfoPrintf(("AJ_Net_Connect(): status=AJ_OK\n")); sendEvent = CreateEvent(NULL, TRUE, FALSE, NULL); recvEvent = CreateEvent(NULL, TRUE, FALSE, NULL); interruptEvent = CreateEvent(NULL, TRUE, FALSE, NULL); wsaOverlapped.hEvent = INVALID_HANDLE_VALUE; return AJ_OK; } } #endif AJ_Status AJ_Net_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { AJ_Status status = AJ_ERR_CONNECT; /* Initialize Winsock, if not done already */ WinsockCheck(); #ifdef AJ_ARDP if (service->addrTypes & (AJ_ADDR_UDP4 | AJ_ADDR_UDP6)) { status = AJ_Net_ARDP_Connect(bus, service); if (status == AJ_OK) { return status; } } #endif #ifdef AJ_TCP if (service->addrTypes & (AJ_ADDR_TCP4 | AJ_ADDR_TCP6)) { status = AJ_TCP_Connect(bus, service); } #endif return status; } void AJ_Net_Disconnect(AJ_NetSocket* netSock) { AJ_InfoPrintf(("AJ_Net_Disconnect(nexSock=0x%p)\n", netSock)); if (netContext.tcpSock != INVALID_SOCKET) { #ifdef AJ_TCP shutdown(netContext.tcpSock, 0); closesocket(netContext.tcpSock); netContext.tcpSock = INVALID_SOCKET; #endif } else if (netContext.udpSock != INVALID_SOCKET) { #ifdef AJ_ARDP AJ_ARDP_Disconnect(FALSE); shutdown(netContext.udpSock, 0); closesocket(netContext.udpSock); netContext.udpSock = INVALID_SOCKET; #endif } memset(netSock, 0, sizeof(AJ_NetSocket)); WSACloseEvent(recvEvent); WSACloseEvent(sendEvent); WSACloseEvent(interruptEvent); } typedef struct { SOCKET sock; int family; struct in_addr v4_bcast; uint16_t recv_port; uint8_t is_mdns; uint8_t is_mdnsrecv; uint8_t has_mcast4; uint8_t has_mcast6; struct in_addr v4_addr; } mcast_info_t; static mcast_info_t* McastSocks = NULL; static size_t NumMcastSocks = 0; static AJ_Status RewriteSenderInfo(AJ_IOBuffer* buf, uint32_t addr, uint16_t port) { size_t tx = AJ_IO_BUF_AVAIL(buf); uint16_t sidVal; const char send[4] = { 'd', 'n', 'e', 's' }; const char sid[] = { 's', 'i', 'd', '=' }; const char ipv4[] = { 'i', 'p', 'v', '4', '=' }; const char upcv4[] = { 'u', 'p', 'c', 'v', '4', '=' }; char sidStr[6]; char ipv4Str[17]; char upcv4Str[6]; uint8_t* pkt; uint16_t dataLength; int match; AJ_Status status; // first, pluck the search ID from the mDNS header sidVal = *(buf->readPtr) << 8; sidVal += *(buf->readPtr + 1); // convert to strings status = AJ_IntToString((int32_t) sidVal, sidStr, sizeof(sidStr)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_IntToString((int32_t) port, upcv4Str, sizeof(upcv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_InetToString(addr, ipv4Str, sizeof(ipv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } // ASSUMPTIONS: sender-info resource record is the final resource record in the packet. // sid, ipv4, and upcv4 key value pairs are the final three key/value pairs in the record. // The length of the other fields in the record are static. // // search backwards through packet to find the start of "sender-info" pkt = buf->writePtr; match = 0; do { if (*(pkt--) == send[match]) { match++; } else { match = 0; } } while (pkt != buf->readPtr && match != 4); if (match != 4) { return AJ_ERR_WRITE; } // move forward to the Data Length field pkt += 22; // actual data length is the length of the static values already in the buffer plus // the three dynamic key-value pairs to re-write dataLength = 23 + 1 + sizeof(sid) + strlen(sidStr) + 1 + sizeof(ipv4) + strlen(ipv4Str) + 1 + sizeof(upcv4) + strlen(upcv4Str); *pkt++ = (dataLength >> 8) & 0xFF; *pkt++ = dataLength & 0xFF; // move forward past the static key-value pairs pkt += 23; // ASSERT: must be at the start of "sid=" assert(*(pkt + 1) == 's'); // re-write new values *pkt++ = sizeof(sid) + strlen(sidStr); memcpy(pkt, sid, sizeof(sid)); pkt += sizeof(sid); memcpy(pkt, sidStr, strlen(sidStr)); pkt += strlen(sidStr); *pkt++ = sizeof(ipv4) + strlen(ipv4Str); memcpy(pkt, ipv4, sizeof(ipv4)); pkt += sizeof(ipv4); memcpy(pkt, ipv4Str, strlen(ipv4Str)); pkt += strlen(ipv4Str); *pkt++ = sizeof(upcv4) + strlen(upcv4Str); memcpy(pkt, upcv4, sizeof(upcv4)); pkt += sizeof(upcv4); memcpy(pkt, upcv4Str, strlen(upcv4Str)); pkt += strlen(upcv4Str); buf->writePtr = pkt; return AJ_OK; } static AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { DWORD ret; DWORD tx = AJ_IO_BUF_AVAIL(buf); int numWrites = 0; AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); assert(NumMcastSocks > 0); if (tx > 0) { size_t i; // our router (hopefully) lives on one of the networks but we don't know which one. // send discovery requests to all of them. for (i = 0; i < NumMcastSocks; ++i) { SOCKET sock = McastSocks[i].sock; int family = McastSocks[i].family; if ((buf->flags & AJ_IO_BUF_AJ) && !McastSocks[i].is_mdns) { // try sending IPv6 multicast if (family == AF_INET6) { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(struct sockaddr_in6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(AJ_UDP_PORT); inet_pton(AF_INET6, AJ_IPV6_MULTICAST_GROUP, &sin6.sin6_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin6, sizeof(struct sockaddr_in6)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (IPV6). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv4 multicast if (family == AF_INET && McastSocks[i].has_mcast4) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(AJ_UDP_PORT); inet_pton(AF_INET, AJ_IPV4_MULTICAST_GROUP, &sin.sin_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (IPV4). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv4 subnet broadcast if (family == AF_INET && McastSocks[i].v4_bcast.s_addr) { struct sockaddr_in bsin; memset(&bsin, 0, sizeof(bsin)); bsin.sin_family = AF_INET; bsin.sin_port = htons(AJ_UDP_PORT); bsin.sin_addr.s_addr = McastSocks[i].v4_bcast.s_addr; ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &bsin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (bcast). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } } if ((buf->flags & AJ_IO_BUF_MDNS) && McastSocks[i].is_mdns) { // Update the packet with receiver info for this socket if (RewriteSenderInfo(buf, ntohl(McastSocks[i].v4_addr.s_addr), McastSocks[i].recv_port) != AJ_OK) { AJ_WarnPrintf(("AJ_Net_SendTo(): RewriteSenderInfo failed.\n")); continue; } tx = AJ_IO_BUF_AVAIL(buf); // try sending IPv4 multicast if (family == AF_INET && McastSocks[i].has_mcast4) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(MDNS_UDP_PORT); inet_pton(AF_INET, MDNS_IPV4_MULTICAST_GROUP, &sin.sin_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() multicast failed (IPV4). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv4 subnet broadcast if (family == AF_INET && McastSocks[i].v4_bcast.s_addr) { struct sockaddr_in bsin; memset(&bsin, 0, sizeof(bsin)); bsin.sin_family = AF_INET; bsin.sin_port = htons(MDNS_UDP_PORT); bsin.sin_addr.s_addr = McastSocks[i].v4_bcast.s_addr; ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &bsin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() broadcast failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv6 multicast if (family == AF_INET6) { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(struct sockaddr_in6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(MDNS_UDP_PORT); inet_pton(AF_INET6, MDNS_IPV6_MULTICAST_GROUP, &sin6.sin6_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin6, sizeof(struct sockaddr_in6)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (IPV6). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } } } if (numWrites == 0) { AJ_ErrPrintf(("AJ_Net_SendTo(): Did not sendto() at least one socket. status=AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } buf->readPtr += ret; } AJ_IO_BUF_RESET(buf); AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; } static AJ_Status AJ_Net_RecvFrom(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { AJ_Status status; DWORD ret; DWORD rx = AJ_IO_BUF_SPACE(buf); fd_set fds; size_t rc = 0; size_t i; const struct timeval tv = { timeout / 1000, 1000 * (timeout % 1000) }; SOCKET sock; int numSocks = 0; AJ_InfoPrintf(("AJ_Net_RecvFrom(buf=0x%p, len=%d., timeout=%d.)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); assert(NumMcastSocks > 0); // we sent the discovery requests out on ALL broadcast and multicast interfaces // now we need to listen on the NS version 1 sockets and the mDNS recv sockets FD_ZERO(&fds); for (i = 0; i < NumMcastSocks; ++i) { if (!McastSocks[i].is_mdns || McastSocks[i].is_mdnsrecv) { SOCKET sock = McastSocks[i].sock; FD_SET(sock, &fds); numSocks++; } } // wait for discovery response rc = select(numSocks, &fds, NULL, NULL, &tv); if (rc == 0) { AJ_InfoPrintf(("AJ_Net_RecvFrom(): select() timed out. status=AJ_ERR_TIMEOUT\n")); return AJ_ERR_TIMEOUT; } else if (rc < 0) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): select() failed. WSAGetLastError()=0x%x, status=AJ_ERR_READ\n", WSAGetLastError())); return AJ_ERR_READ; } // ignore multiple replies; only consider the first one to arrive rx = min(rx, len); for (i = 0; i < NumMcastSocks; ++i) { if (!McastSocks[i].is_mdns || McastSocks[i].is_mdnsrecv) { if (FD_ISSET(McastSocks[i].sock, &fds)) { sock = McastSocks[i].sock; if (McastSocks[i].is_mdnsrecv) { buf->flags |= AJ_IO_BUF_MDNS; } else { buf->flags |= AJ_IO_BUF_AJ; } break; } } } if (sock != INVALID_SOCKET) { ret = recvfrom(sock, buf->writePtr, rx, 0, NULL, 0); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): recvfrom() failed. WSAGetLastError()=0x%x, status=AJ_ERR_READ\n", WSAGetLastError())); status = AJ_ERR_READ; } else { buf->writePtr += ret; status = AJ_OK; } } else { AJ_ErrPrintf(("AJ_Net_RecvFrom(): invalid socket. status=AJ_ERR_READ\n")); status = AJ_ERR_READ; } AJ_InfoPrintf(("AJ_Net_RecvFrom(): status=%s\n", AJ_StatusText(status))); return status; } /* * Need enough space to receive a complete name service packet when used in UDP * mode. NS expects MTU of 1500 subtracts UDP, IP and ethertype overhead. * 1500 - 8 -20 - 18 = 1454. txData buffer size needs to be big enough to hold * max(NS WHO-HAS for one name (4 + 2 + 256 = 262), * mDNS query for one name (194 + 5 + 5 + 15 + 256 = 475)) = 475 */ static uint8_t rxDataMCast[1454]; static uint8_t txDataMCast[475]; static void Mcast6Up(const char* group, uint16_t port, uint8_t mdns, uint16_t recv_port) { char iface_buffer[sizeof(IP_ADAPTER_ADDRESSES) * 150]; char v4_iface_buffer[sizeof(IP_ADAPTER_ADDRESSES) * 150]; PIP_ADAPTER_ADDRESSES interfaces = (PIP_ADAPTER_ADDRESSES) iface_buffer; PIP_ADAPTER_ADDRESSES v4_interfaces = (PIP_ADAPTER_ADDRESSES) v4_iface_buffer; DWORD num_bytes = sizeof(iface_buffer); // Get the IPv6 adapter addresses if (ERROR_SUCCESS != GetAdaptersAddresses(AF_INET6, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, interfaces, &num_bytes)) { AJ_ErrPrintf(("Mcast6Up(): GetAdaptersAddresses for IPv6 failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); return; } // Get the IPv4 adapter addresses if (ERROR_SUCCESS != GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, v4_interfaces, &num_bytes)) { AJ_ErrPrintf(("Mcast6Up(): GetAdaptersAddresses for IPv4 failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); return; } for (; interfaces != NULL; interfaces = interfaces->Next) { int ret = 0; struct sockaddr_in6 addr; struct sockaddr_in v4_addr; struct ipv6_mreq mreq6; mcast_info_t new_sock; PIP_ADAPTER_ADDRESSES v4_addr_begin = v4_interfaces; new_sock.sock = INVALID_SOCKET; new_sock.family = AF_INET6; new_sock.recv_port = recv_port; new_sock.has_mcast4 = FALSE; new_sock.is_mdns = mdns; new_sock.v4_bcast.s_addr = 0; new_sock.v4_addr.s_addr = 0; memset(&mreq6, 0, sizeof(struct ipv6_mreq)); if (interfaces->OperStatus != IfOperStatusUp || interfaces->NoMulticast) { continue; } memcpy(&addr, interfaces->FirstUnicastAddress->Address.lpSockaddr, sizeof(struct sockaddr_in6)); // find and save the IPv4 address from this same adapter for (; v4_addr_begin != NULL; v4_addr_begin = v4_addr_begin->Next) { if (interfaces->Ipv6IfIndex == v4_addr_begin->IfIndex) { memcpy(&v4_addr, v4_addr_begin->FirstUnicastAddress->Address.lpSockaddr, sizeof(struct sockaddr_in)); new_sock.v4_addr.s_addr = v4_addr.sin_addr.s_addr; break; } } if (!new_sock.v4_addr.s_addr) { AJ_ErrPrintf(("Mcast6Up(): IPV4 address not found for interface %u\n", interfaces->Ipv6IfIndex)); continue; } // create a socket new_sock.sock = socket(AF_INET6, SOCK_DGRAM, 0); if (new_sock.sock == INVALID_SOCKET) { AJ_ErrPrintf(("Mcast6Up(): socket() failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); continue; } // bind the socket to the supplied port addr.sin6_family = AF_INET6; addr.sin6_port = htons(port); ret = bind(new_sock.sock, (struct sockaddr*) &addr, sizeof(struct sockaddr_in6)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("Mcast6Up(): bind() failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); closesocket(new_sock.sock); new_sock.sock = INVALID_SOCKET; continue; } // because routers are advertised silently, the reply will be unicast // however, Windows forces us to join the multicast group before we can broadcast our WhoHas packets inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = interfaces->IfIndex; ret = setsockopt(new_sock.sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*) &mreq6, sizeof(mreq6)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("Mcast6Up(): setsockopt(IP_ADD_MEMBERSHIP) failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); closesocket(new_sock.sock); new_sock.sock = INVALID_SOCKET; continue; } if (new_sock.sock != INVALID_SOCKET) { NumMcastSocks++; McastSocks = realloc(McastSocks, NumMcastSocks * sizeof(mcast_info_t)); memcpy(&McastSocks[NumMcastSocks - 1], &new_sock, sizeof(mcast_info_t)); } } } static void Mcast4Up(const char* group, uint16_t port, uint8_t mdns, uint16_t recv_port) { int ret = 0; INTERFACE_INFO interfaces[150]; DWORD num_bytes, num_ifaces; SOCKET tmp_sock; uint32_t i = 0; int reuse = 1; tmp_sock = socket(AF_INET, SOCK_DGRAM, 0); if (tmp_sock == INVALID_SOCKET) { AJ_ErrPrintf(("Mcast4Up(): socket failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); return; } if (SOCKET_ERROR == WSAIoctl(tmp_sock, SIO_GET_INTERFACE_LIST, 0, 0, &interfaces, sizeof(interfaces), &num_bytes, 0, 0)) { AJ_ErrPrintf(("Mcast4Up(): WSAIoctl failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); return; } closesocket(tmp_sock); num_ifaces = num_bytes / sizeof(INTERFACE_INFO); for (i = 0; i < num_ifaces; ++i) { LPINTERFACE_INFO info = &interfaces[i]; struct sockaddr_in* addr = &info->iiAddress.AddressIn; mcast_info_t new_sock; new_sock.sock = INVALID_SOCKET; new_sock.family = AF_INET; new_sock.has_mcast4 = FALSE; new_sock.is_mdnsrecv = FALSE; new_sock.is_mdns = mdns; new_sock.v4_bcast.s_addr = 0; new_sock.recv_port = recv_port; new_sock.v4_addr.s_addr = 0; if (!(info->iiFlags & IFF_UP)) { continue; } // create a socket new_sock.sock = socket(AF_INET, SOCK_DGRAM, 0); if (new_sock.sock == INVALID_SOCKET) { AJ_ErrPrintf(("Mcast4Up(): socket() failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); continue; } ret = setsockopt(new_sock.sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)); if (ret != 0) { AJ_ErrPrintf(("MCast4Up(): setsockopt(SO_REUSEADDR) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); closesocket(new_sock.sock); new_sock.sock = INVALID_SOCKET; continue; } new_sock.v4_addr.s_addr = info->iiAddress.AddressIn.sin_addr.s_addr; // if this address supports IPV4 broadcast, calculate the subnet bcast address and save it if (info->iiFlags & IFF_BROADCAST) { int bcast = 1; ret = setsockopt(new_sock.sock, SOL_SOCKET, SO_BROADCAST, (void*) &bcast, sizeof(bcast)); if (ret != 0) { AJ_ErrPrintf(("Mcast4Up(): setsockopt(SO_BROADCAST) failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); closesocket(new_sock.sock); new_sock.sock = INVALID_SOCKET; continue; } new_sock.v4_bcast.s_addr = info->iiAddress.AddressIn.sin_addr.s_addr | ~(info->iiNetmask.AddressIn.sin_addr.s_addr); } // and if it supports multicast, join the IPV4 mcast group if (info->iiFlags & IFF_MULTICAST) { struct ip_mreq mreq; struct sockaddr_in sin; memset(&mreq, 0, sizeof(struct ip_mreq)); // bind the socket to the address with supplied port sin.sin_family = AF_INET; sin.sin_port = htons(port); // need to bind to INADDR_ANY for mdns if (mdns == TRUE) { sin.sin_addr.s_addr = INADDR_ANY; } else { memcpy(&sin, addr, sizeof(struct sockaddr_in)); } AJ_InfoPrintf(("MCast4Up(): Binding to port %d and group %s\n", port, group)); ret = bind(new_sock.sock, (struct sockaddr*) &sin, sizeof(sin)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("Mcast4Up(): bind() failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); closesocket(new_sock.sock); new_sock.sock = INVALID_SOCKET; continue; } // because routers are advertised silently, the reply will be unicast // however, Windows forces us to join the multicast group before we can broadcast our WhoHas packets inet_pton(AF_INET, group, &mreq.imr_multiaddr); memcpy(&mreq.imr_interface, &sin.sin_addr, sizeof(struct in_addr)); ret = setsockopt(new_sock.sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mreq, sizeof(mreq)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("Mcast4Up(): setsockopt(IP_ADD_MEMBERSHIP) failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); closesocket(new_sock.sock); new_sock.sock = INVALID_SOCKET; continue; } new_sock.has_mcast4 = TRUE; } if (new_sock.sock != INVALID_SOCKET) { NumMcastSocks++; McastSocks = realloc(McastSocks, NumMcastSocks * sizeof(mcast_info_t)); memcpy(&McastSocks[NumMcastSocks - 1], &new_sock, sizeof(mcast_info_t)); } } } static SOCKET MDnsRecvUp() { int ret = 0; SOCKET tmp_sock; uint32_t i = 0; struct sockaddr_in sin; mcast_info_t new_sock; tmp_sock = socket(AF_INET, SOCK_DGRAM, 0); if (tmp_sock == INVALID_SOCKET) { AJ_ErrPrintf(("MDnsRecvUp(): socket failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); return tmp_sock; } // bind the socket to an ephemeral port sin.sin_family = AF_INET; sin.sin_port = htons(0); sin.sin_addr.s_addr = INADDR_ANY; ret = bind(tmp_sock, (struct sockaddr*) &sin, sizeof(sin)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("MDnsRecvUp(): bind() failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); closesocket(tmp_sock); tmp_sock = INVALID_SOCKET; return tmp_sock; } new_sock.sock = tmp_sock; new_sock.family = AF_INET; new_sock.has_mcast4 = FALSE; new_sock.is_mdns = FALSE; new_sock.is_mdnsrecv = TRUE; new_sock.v4_bcast.s_addr = 0; new_sock.v4_addr.s_addr = 0; NumMcastSocks++; McastSocks = realloc(McastSocks, NumMcastSocks * sizeof(mcast_info_t)); memcpy(&McastSocks[NumMcastSocks - 1], &new_sock, sizeof(mcast_info_t)); return tmp_sock; } AJ_Status AJ_Net_MCastUp(AJ_MCastSocket* mcastSock) { AJ_Status status = AJ_OK; size_t numMDnsRecvSocks; struct sockaddr_storage addrBuf; socklen_t addrLen = sizeof(addrBuf); struct sockaddr_in* sin; SOCKET tmp_sock = INVALID_SOCKET; // bring up WinSock WinsockCheck(); AJ_InfoPrintf(("AJ_Net_MCastUp(mcastSock=0x%p)\n", mcastSock)); // create the mDNS recv socket tmp_sock = MDnsRecvUp(); if (tmp_sock != INVALID_SOCKET) { getsockname(tmp_sock, (struct sockaddr*) &addrBuf, &addrLen); sin = (struct sockaddr_in*) &addrBuf; AJ_InfoPrintf(("AJ_Net_MCastUp(): mDNS recv port: %d\n", ntohs(sin->sin_port))); } if (NumMcastSocks == 0) { AJ_ErrPrintf(("AJ_Net_MCastUp(): No mDNS recv socket found. status=AJ_ERR_READ\n")); return AJ_ERR_READ; } numMDnsRecvSocks = NumMcastSocks; // create the sending sockets Mcast4Up(MDNS_IPV4_MULTICAST_GROUP, MDNS_UDP_PORT, TRUE, ntohs(sin->sin_port)); Mcast6Up(MDNS_IPV6_MULTICAST_GROUP, MDNS_UDP_PORT, TRUE, ntohs(sin->sin_port)); // create the NS sockets only if considering pre-14.06 routers if (AJ_GetMinProtoVersion() < 10) { Mcast4Up(AJ_IPV4_MULTICAST_GROUP, AJ_UDP_PORT, FALSE, 0); Mcast6Up(AJ_IPV6_MULTICAST_GROUP, AJ_UDP_PORT, FALSE, 0); } AJ_IOBufInit(&mcastSock->rx, rxDataMCast, sizeof(rxDataMCast), AJ_IO_BUF_RX, (void*) McastSocks); mcastSock->rx.recv = AJ_Net_RecvFrom; AJ_IOBufInit(&mcastSock->tx, txDataMCast, sizeof(txDataMCast), AJ_IO_BUF_TX, (void*) McastSocks); mcastSock->tx.send = AJ_Net_SendTo; return AJ_OK; } void AJ_Net_MCastDown(AJ_MCastSocket* mcastSock) { size_t i; AJ_InfoPrintf(("AJ_Net_MCastDown(nexSock=0x%p)\n", mcastSock)); // shutdown and close all sockets for (i = 0; i < NumMcastSocks; ++i) { SOCKET sock = McastSocks[i].sock; // leave multicast groups if ((McastSocks[i].family == AF_INET) && McastSocks[i].has_mcast4) { struct ip_mreq mreq; inet_pton(AF_INET, AJ_IPV4_MULTICAST_GROUP, &mreq.imr_multiaddr); mreq.imr_interface.s_addr = INADDR_ANY; setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*) &mreq, sizeof(mreq)); } else if ((McastSocks[i].family == AF_INET6) && McastSocks[i].has_mcast6) { struct ipv6_mreq mreq6; inet_pton(AF_INET6, AJ_IPV6_MULTICAST_GROUP, &mreq6.ipv6mr_multiaddr); mreq6.ipv6mr_interface = 0; setsockopt(sock, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char*) &mreq6, sizeof(mreq6)); } shutdown(sock, 0); closesocket(sock); } NumMcastSocks = 0; free(McastSocks); McastSocks = NULL; memset(mcastSock, 0, sizeof(AJ_MCastSocket)); } #ifdef AJ_ARDP static AJ_Status AJ_ARDP_UDP_Send(void* context, uint8_t* buf, size_t len, size_t* sent, uint8_t confirm) { AJ_Status status = AJ_OK; DWORD ret; NetContext* ctx = (NetContext*) context; WSAOVERLAPPED ov; DWORD flags = 0; WSABUF wsbuf; memset(&ov, 0, sizeof(ov)); ov.hEvent = sendEvent; wsbuf.len = len; wsbuf.buf = buf; AJ_InfoPrintf(("AJ_ARDP_UDP_Send(buf=0x%p, len=%lu)\n", buf, len)); ret = WSASend(ctx->udpSock, &wsbuf, 1, NULL, flags, &ov, NULL); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_ARDP_UDP_Send(): WSASend() failed. WSAGetLastError()=0x%x, status=AJ_ERR_WRITE\n", WSAGetLastError())); *sent = 0; return AJ_ERR_WRITE; } if (!WSAGetOverlappedResult(ctx->udpSock, &ov, (DWORD*) sent, TRUE, &flags)) { AJ_ErrPrintf(("AJ_ARDP_UDP_Send(): WSAGetOverlappedResult() failed. WSAGetLastError()=0x%x, status=AJ_ERR_WRITE\n", WSAGetLastError())); return AJ_ERR_WRITE; } return status; } static AJ_Status AJ_ARDP_UDP_Recv(void* context, uint8_t** data, uint32_t* recved, uint32_t timeout) { NetContext* ctx = (NetContext*) context; DWORD ret = SOCKET_ERROR; WSAEVENT events[2]; DWORD flags = 0; static uint8_t buffer[UDP_SEGBMAX]; *data = NULL; if (wsaOverlapped.hEvent == INVALID_HANDLE_VALUE) { wsbuf.len = sizeof(buffer); wsbuf.buf = buffer; memset(&wsaOverlapped, 0, sizeof(WSAOVERLAPPED)); wsaOverlapped.hEvent = recvEvent; ret = WSARecvFrom(ctx->udpSock, &wsbuf, 1, NULL, &flags, NULL, NULL, &wsaOverlapped, NULL); if ((ret == SOCKET_ERROR) && (WSAGetLastError() != WSA_IO_PENDING)) { AJ_ErrPrintf(("WSARecvFrom(): failed WSAGetLastError()=%d\n", WSAGetLastError())); return AJ_ERR_READ; } } events[0] = wsaOverlapped.hEvent; events[1] = interruptEvent; ret = WSAWaitForMultipleEvents(2, events, FALSE, timeout, TRUE); switch (ret) { case WSA_WAIT_EVENT_0: flags = 0; if (WSAGetOverlappedResult(ctx->udpSock, &wsaOverlapped, recved, TRUE, &flags)) { WSAResetEvent(wsaOverlapped.hEvent); wsaOverlapped.hEvent = INVALID_HANDLE_VALUE; *data = buffer; return AJ_OK; } else { AJ_ErrPrintf(("AJ_ARDP_UDP_Recv(): WSAGetOverlappedResult error; WSAGetLastError()=%d\n", WSAGetLastError())); return AJ_ERR_READ; } break; case WSA_WAIT_EVENT_0 + 1: WSAResetEvent(interruptEvent); return AJ_ERR_INTERRUPTED; case WSA_WAIT_TIMEOUT: return AJ_ERR_TIMEOUT; break; default: AJ_ErrPrintf(("AJ_ARDP_UDP_Recv(): WSAWaitForMultipleEvents error; WSAGetLastError()=%d\n", WSAGetLastError())); return AJ_ERR_READ; } } static AJ_Status AJ_Net_ARDP_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { SOCKET udpSock = INVALID_SOCKET; AJ_Status status; SOCKADDR_STORAGE addrBuf; socklen_t addrSize; DWORD ret; AJ_ARDP_InitFunctions(AJ_ARDP_UDP_Recv, AJ_ARDP_UDP_Send); memset(&addrBuf, 0, sizeof(addrBuf)); if (service->addrTypes & AJ_ADDR_UDP4) { struct sockaddr_in* sa = (struct sockaddr_in*) &addrBuf; udpSock = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); if (udpSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): socket() failed. status=AJ_ERR_CONNECT\n")); goto ConnectError; } sa->sin_family = AF_INET; sa->sin_port = htons(service->ipv4portUdp); sa->sin_addr.s_addr = service->ipv4Udp; addrSize = sizeof(struct sockaddr_in); AJ_InfoPrintf(("AJ_Net_ARDP_Connect(): Connect to \"%s:%u\"\n", inet_ntoa(sa->sin_addr), service->ipv4portUdp));; } else if (service->addrTypes & AJ_ADDR_UDP6) { struct sockaddr_in6* sa = (struct sockaddr_in6*) &addrBuf; udpSock = WSASocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); if (udpSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): socket() failed. status=AJ_ERR_CONNECT\n")); goto ConnectError; } sa->sin6_family = AF_INET6; sa->sin6_port = htons(service->ipv6portUdp); memcpy(sa->sin6_addr.s6_addr, service->ipv6Udp, sizeof(sa->sin6_addr.s6_addr)); addrSize = sizeof(struct sockaddr_in6); } else { AJ_ErrPrintf(("AJ_Net_ARDP_Connect(): Invalid addrTypes %u, status=AJ_ERR_CONNECT\n", service->addrTypes)); return AJ_ERR_CONNECT; } ret = connect(udpSock, (struct sockaddr*) &addrBuf, addrSize); // must do this before calling AJ_MarshalMethodCall! if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_Connect(): connect() failed. WSAGetLastError()=0x%x, status=AJ_ERR_CONNECT\n", WSAGetLastError())); goto ConnectError; } else { netContext.udpSock = udpSock; AJ_IOBufInit(&bus->sock.rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, &netContext); bus->sock.rx.recv = AJ_ARDP_Recv; AJ_IOBufInit(&bus->sock.tx, txData, sizeof(txData), AJ_IO_BUF_TX, &netContext); bus->sock.tx.send = AJ_ARDP_Send; sendEvent = CreateEvent(NULL, TRUE, FALSE, NULL); recvEvent = CreateEvent(NULL, TRUE, FALSE, NULL); interruptEvent = CreateEvent(NULL, TRUE, FALSE, NULL); wsaOverlapped.hEvent = INVALID_HANDLE_VALUE; } status = AJ_ARDP_UDP_Connect(bus, &netContext, service, &bus->sock); if (status != AJ_OK) { goto ConnectError; } return AJ_OK; ConnectError: if (udpSock != INVALID_SOCKET) { closesocket(udpSock); } return AJ_ERR_CONNECT; } #endif // AJ_ARDP ajtcl-16.04/src/target/win32/aj_target.h000066400000000000000000000053351271074662300177670ustar00rootroot00000000000000#ifndef _AJ_TARGET_H #define _AJ_TARGET_H /** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #if _MSC_VER >= 1600 /* MSVC 2010 or higher */ #include #else typedef signed char int8_t; /** 8-bit signed integer */ typedef unsigned char uint8_t; /** 8-bit unsigned integer */ typedef signed short int16_t; /** 16-bit signed integer */ typedef unsigned short uint16_t; /** 16-bit unsigned integer */ typedef signed int int32_t; /** 32-bit signed integer */ typedef unsigned int uint32_t; /** 32-bit unsigned integer */ typedef signed long long int64_t; /** 64-bit signed integer */ typedef unsigned long long uint64_t; /** 64-bit unsigned integer */ #endif #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef max #define max(x, y) ((x) > (y) ? (x) : (y)) #endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define WORD_ALIGN(x) ((x & 0x3) ? ((x >> 2) + 1) << 2 : x) #define HOST_IS_LITTLE_ENDIAN TRUE #define HOST_IS_BIG_ENDIAN FALSE #define AJ_Printf(fmat, ...) \ do { printf(fmat, ## __VA_ARGS__); fflush(stdout); } while (0) #ifndef NDEBUG extern uint8_t dbgCONFIGUREME; extern uint8_t dbgINIT; extern uint8_t dbgNET; extern uint8_t dbgTARGET_CRYPTO; extern uint8_t dbgTARGET_NVRAM; extern uint8_t dbgTARGET_UTIL; #endif #define AJ_ASSERT(x) _ASSERT(x) /* * AJ_Reboot() is a NOOP on this platform */ #define AJ_Reboot() #define AJ_EXPORT __declspec(dllexport) #define AJ_CreateNewGUID AJ_RandBytes #define AJ_GetDebugTime(x) AJ_ERR_RESOURCES #define inline __inline #define AJ_DEPRECATED(func) __declspec(deprecated) func /* * Main method allows argc, argv */ #define MAIN_ALLOWS_ARGS #endif ajtcl-16.04/src/target/win32/aj_target_crypto.c000066400000000000000000000032561271074662300213620ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE TARGET_CRYPTO #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_CRYPTO = 0; #endif void AJ_RandBytes(uint8_t* rand, uint32_t len) { HCRYPTPROV hProvider; CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); CryptGenRandom(hProvider, len, rand); CryptReleaseContext(hProvider, 0); } ajtcl-16.04/src/target/win32/aj_target_nvram.c000066400000000000000000000075731271074662300211730ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE TARGET_NVRAM #include #include #include "../../aj_target_nvram.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgTARGET_NVRAM = 0; #endif uint8_t AJ_EMULATED_NVRAM[AJ_NVRAM_SIZE]; uint8_t* AJ_NVRAM_BASE_ADDRESS; extern void AJ_NVRAM_Layout_Print(); #define NV_FILE "ajtcl.nvram" const char* nvFile = NV_FILE; void AJ_SetNVRAM_FilePath(const char* path) { if (path) { nvFile = path; } } void AJ_NVRAM_Init() { AJ_NVRAM_BASE_ADDRESS = AJ_EMULATED_NVRAM; _AJ_LoadNVFromFile(); if (*((uint32_t*)AJ_NVRAM_BASE_ADDRESS) != AJ_NV_SENTINEL) { _AJ_NVRAM_Clear(); _AJ_StoreNVToFile(); } } void _AJ_NV_Write(void* dest, const void* buf, uint16_t size) { memcpy(dest, buf, size); _AJ_StoreNVToFile(); } void _AJ_NV_Move(void* dest, const void* buf, uint16_t size) { memmove(dest, buf, size); _AJ_StoreNVToFile(); } void _AJ_NV_Read(void* src, void* buf, uint16_t size) { memcpy(buf, src, size); } void _AJ_NVRAM_Clear() { memset((uint8_t*)AJ_NVRAM_BASE_ADDRESS, INVALID_DATA_BYTE, AJ_NVRAM_SIZE); *((uint32_t*)AJ_NVRAM_BASE_ADDRESS) = AJ_NV_SENTINEL; _AJ_StoreNVToFile(); } static AJ_Status _AJ_LoadNVFromFile() { FILE* f = fopen(nvFile, "rb"); if (f == NULL) { AJ_AlwaysPrintf(("Error: AJ_LoadNVFromFile(\"%s\") failed\n", nvFile)); return AJ_ERR_FAILURE; } memset(AJ_NVRAM_BASE_ADDRESS, INVALID_DATA_BYTE, AJ_NVRAM_SIZE); fread(AJ_NVRAM_BASE_ADDRESS, AJ_NVRAM_SIZE, 1, f); fclose(f); return AJ_OK; } AJ_Status _AJ_StoreNVToFile() { FILE* f = fopen(nvFile, "wb"); if (!f) { AJ_AlwaysPrintf(("Error: AJ_StoreNVToFile(\"%s\") failed\n", nvFile)); return AJ_ERR_FAILURE; } fwrite(AJ_NVRAM_BASE_ADDRESS, AJ_NVRAM_SIZE, 1, f); fclose(f); return AJ_OK; } // Compact the storage by removing invalid entries AJ_Status _AJ_CompactNVStorage() { uint16_t capacity = 0; uint16_t id = 0; uint16_t* data = (uint16_t*)(AJ_NVRAM_BASE_ADDRESS + SENTINEL_OFFSET); uint8_t* writePtr = (uint8_t*)data; uint16_t entrySize = 0; uint16_t garbage = 0; //AJ_NVRAM_Layout_Print(); while ((uint8_t*)data < (uint8_t*)AJ_NVRAM_END_ADDRESS && *data != INVALID_DATA) { id = *data; capacity = *(data + 1); entrySize = ENTRY_HEADER_SIZE + capacity; if (id != INVALID_ID) { _AJ_NV_Move(writePtr, data, entrySize); writePtr += entrySize; } else { garbage += entrySize; } data += entrySize >> 1; } memset(writePtr, INVALID_DATA_BYTE, garbage); _AJ_StoreNVToFile(); //AJ_NVRAM_Layout_Print(); return AJ_OK; } ajtcl-16.04/src/target/win32/aj_target_util.c000066400000000000000000000141771271074662300210230ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE TARGET_UTIL #include #include #include #include #include #include #include #include #include #include uint8_t dbgTARGET_UTIL = 0; void AJ_Sleep(uint32_t time) { Sleep(time); } uint32_t AJ_GetElapsedTime(AJ_Time* timer, uint8_t cumulative) { uint32_t elapsed; struct _timeb now; _ftime(&now); elapsed = (uint32_t)((1000 * (now.time - timer->seconds)) + (now.millitm - timer->milliseconds)); if (!cumulative) { timer->seconds = (uint32_t)now.time; timer->milliseconds = (uint32_t)now.millitm; } return elapsed; } void AJ_InitTimer(AJ_Time* timer) { struct _timeb now; _ftime(&now); timer->seconds = (uint32_t)now.time; timer->milliseconds = (uint32_t)now.millitm; } /* * get a line of input from the the file pointer (most likely stdin). * This will capture the the num-1 characters or till a newline character is * entered. * * @param[out] str a pointer to a character array that will hold the user input * @param[in] num the size of the character array 'str' * @param[in] fp the file pointer the sting will be read from. (most likely stdin) * * @return returns the same string as 'str' if there has been a read error a null * pointer will be returned and 'str' will remain unchanged. */ char* AJ_GetLine(char* str, size_t num, void* fp) { char*p = fgets(str, (int)num, (FILE*)fp); if (p != NULL) { size_t last = strlen(str) - 1; if (str[last] == '\n') { str[last] = '\0'; } } return p; } static uint8_t ioThreadRunning = FALSE; static char cmdline[1024]; static const uint32_t stacksize = 80 * 1024; static uint8_t consumed = TRUE; static HANDLE handle; static unsigned int threadId; unsigned __stdcall RunFunc(void* threadArg) { while (ioThreadRunning) { if (consumed) { AJ_GetLine(cmdline, sizeof(cmdline), stdin); consumed = FALSE; } AJ_Sleep(1000); } return 0; } uint8_t AJ_StartReadFromStdIn() { if (!ioThreadRunning) { handle = (HANDLE)_beginthreadex(NULL, stacksize, &RunFunc, NULL, 0, &threadId); if (handle <= 0) { AJ_ErrPrintf(("Fail to spin a thread for reading from stdin\n")); return FALSE; } ioThreadRunning = TRUE; return TRUE; } return FALSE; } char* AJ_GetCmdLine(char* buf, size_t num) { if (!consumed) { strncpy(buf, cmdline, num); buf[num - 1] = '\0'; consumed = TRUE; return buf; } return NULL; } uint8_t AJ_StopReadFromStdIn() { if (ioThreadRunning) { ioThreadRunning = FALSE; return TRUE; } return FALSE; } uint64_t AJ_DecodeTime(char* der, const char* fmt) { //TODO return 0; } void* AJ_Malloc(size_t sz) { return malloc(sz); } void* AJ_Realloc(void* ptr, size_t size) { return realloc(ptr, size); } void AJ_Free(void* p) { free(p); } void AJ_MemZeroSecure(void* s, size_t n) { SecureZeroMemory(s, n); } #ifndef NDEBUG /* * This is not intended, nor required to be particularly efficient. If you want * efficiency, turn of debugging. */ int _AJ_DbgEnabled(const char* module) { char buffer[128]; char* env; strcpy(buffer, "ER_DEBUG_ALL"); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } strcpy(buffer, "ER_DEBUG_"); strcat(buffer, module); env = getenv(buffer); if (env && strcmp(env, "1") == 0) { return TRUE; } return FALSE; } #endif uint16_t AJ_ByteSwap16(uint16_t x) { return _byteswap_ushort(x); } uint32_t AJ_ByteSwap32(uint32_t x) { return _byteswap_ulong(x); } uint64_t AJ_ByteSwap64(uint64_t x) { return _byteswap_uint64(x); } AJ_Status AJ_IntToString(int32_t val, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = _snprintf(buf, buflen, "%d", val); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } AJ_Status AJ_InetToString(uint32_t addr, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = _snprintf(buf, buflen, "%u.%u.%u.%u", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF)); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } void AJ_TimeAddOffset(AJ_Time* timerA, uint32_t msec) { uint32_t msecNew; if (msec == -1) { timerA->seconds = -1; timerA->milliseconds = -1; } else { msecNew = (timerA->milliseconds + msec); timerA->seconds = timerA->seconds + (msecNew / 1000); timerA->milliseconds = msecNew % 1000; } } int8_t AJ_CompareTime(AJ_Time timerA, AJ_Time timerB) { if (timerA.seconds == timerB.seconds) { if (timerA.milliseconds == timerB.milliseconds) { return 0; } else if (timerA.milliseconds > timerB.milliseconds) { return 1; } else { return -1; } } else if (timerA.seconds > timerB.seconds) { return 1; } else { return -1; } } ajtcl-16.04/src/wsl/000077500000000000000000000000001271074662300142255ustar00rootroot00000000000000ajtcl-16.04/src/wsl/aj_buf.c000066400000000000000000000300471271074662300156230ustar00rootroot00000000000000/** * @file Buffer list implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef __cplusplus extern "C" { #endif /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE BUFLIST #include #include #include #include #include "aj_wsl_target.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgBUFLIST = 0; #endif #ifndef NDEBUG AJ_BUFLIST_FUNC_TABLE AJ_BUFLIST_OPS; #endif void AJ_BufList_ModuleInit() { /* * Configure the indirection table with the default functions */ #ifndef NDEBUG AJ_BUFLIST_OPS.readByteFromWire = &AJ_BufListReadByteFromWire_Simulated; AJ_BUFLIST_OPS.writeToWire = &AJ_BufListWriteToWire_Simulated; #endif } #ifndef NDEBUG //DEBUG data: simulate SPI read/write using a fixed buffer AJ_BUF_WIREBUFFER toTarget; AJ_BUF_WIREBUFFER fromTarget; #endif AJ_BufList* AJ_BufListCreate(void) { AJ_BufList* list; list = (AJ_BufList*)AJ_WSL_Malloc(sizeof(AJ_BufList)); memset(list, 0, sizeof(AJ_BufList)); return list; } AJ_BufList* AJ_BufListCreateCopy(AJ_BufList* listIn) { AJ_BufList* list; AJ_BufNode* nodeA; uint16_t listInLength; list = (AJ_BufList*)AJ_WSL_Malloc(sizeof(AJ_BufList)); memset(list, 0, sizeof(AJ_BufList)); listInLength = AJ_BufListLengthOnWire(listIn); nodeA = AJ_BufListCreateNodeZero(listInLength, FALSE); AJ_BufListCopyBytes(listIn, listInLength, nodeA->bufferStart); AJ_BufListPushHead(list, nodeA); return list; } AJ_BufNode* AJ_BufListCreateNodeZero(uint16_t bufferSize, uint8_t zeroBuffer) { AJ_BufNode* newNode = (AJ_BufNode*)AJ_WSL_Malloc(sizeof(AJ_BufNode)); newNode->buffer = (uint8_t*)AJ_WSL_Malloc(bufferSize); if (zeroBuffer) { memset(newNode->buffer, 0, bufferSize); } newNode->length = bufferSize; newNode->next = NULL; newNode->bufferStart = newNode->buffer; newNode->flags = 0; return newNode; } AJ_BufNode* AJ_BufListCreateNode(uint16_t bufferSize) { return AJ_BufListCreateNodeZero(bufferSize, 1); } AJ_BufNode* AJ_BufListCreateNodeExternalZero(uint8_t* buffer, uint16_t bufferSize, uint8_t zeroBuffer) { AJ_BufNode* newNode = (AJ_BufNode*)AJ_WSL_Malloc(sizeof(AJ_BufNode)); newNode->buffer = buffer; if (zeroBuffer) { memset(newNode->buffer, 0, bufferSize); } newNode->length = bufferSize; newNode->next = NULL; newNode->bufferStart = newNode->buffer; newNode->flags = AJ_BUFNODE_EXTERNAL_BUFFER; return newNode; } AJ_BufNode* AJ_BufNodeCreateAndTakeOwnership(AJ_BufNode* giving) { AJ_BufNode* newNode = (AJ_BufNode*)AJ_WSL_Malloc(sizeof(AJ_BufNode)); memcpy(newNode, giving, sizeof(AJ_BufNode)); giving->flags = AJ_BUFNODE_EXTERNAL_BUFFER; return newNode; } AJ_BufNode* AJ_BufListCreateNodeExternalBuffer(uint8_t* buffer, uint16_t bufferSize) { return AJ_BufListCreateNodeExternalZero(buffer, bufferSize, 1); } void AJ_BufListPushHead(AJ_BufList* list, AJ_BufNode* newNode) { if (!list->head) { list->tail = newNode; list->head = newNode; } else { newNode->next = list->head; list->head = newNode; } } void AJ_BufListPushTail(AJ_BufList* list, AJ_BufNode* newNode) { if (!list->head || !list->tail) { list->tail = newNode; list->head = newNode; } else { list->tail->next = newNode; list->tail = newNode; } } void AJ_BufListCoalesce(AJ_BufNode* node) { if (node->next) { AJ_BufNode* nextNode; uint8_t* biggerBuffer; nextNode = node->next; AJ_ASSERT(!(node->flags | nextNode->flags) & AJ_BUFNODE_EXTERNAL_BUFFER); if ((node->flags | nextNode->flags) & AJ_BUFNODE_EXTERNAL_BUFFER) { /* one of the nodes has an external buffer, don't coalesce */ AJ_ASSERT((node->flags | nextNode->flags) & AJ_BUFNODE_EXTERNAL_BUFFER); } // create a new buffer with the data from two buffers biggerBuffer = (uint8_t*)AJ_WSL_Malloc(node->length + nextNode->length); memcpy(biggerBuffer, node->buffer, node->length); memcpy(biggerBuffer + node->length, nextNode->buffer, nextNode->length); AJ_WSL_Free(node->buffer); node->buffer = biggerBuffer; node->bufferStart = node->buffer; node->length += nextNode->length; // remove the following node node->next = nextNode->next; AJ_BufListFreeNodeAndBuffer(nextNode, NULL); } } AJ_EXPORT void AJ_BufNodePullBytes(AJ_BufNode* node, uint16_t count) { // while there are bytes to remove, pull bytes out of the node. // then move to the next node if needed while ((node != NULL) && (count > 0)) { // taking less than the whole buffer if (count <= node->length) { node->length -= count; node->buffer += count; count = 0; break; } else { // shorten the list and free the buffer we have now. AJ_BufNode* nodeNext = node->next; count -= node->length; AJ_BufListFreeNodeAndBuffer(node, NULL); node = nodeNext; } } // AJ_ASSERT(count == 0); } AJ_EXPORT void AJ_BufListPullBytes(AJ_BufList* list, uint16_t count) { // while there are bytes to remove, pull bytes out of the head node of the list. while ((list != NULL) && (count > 0)) { AJ_BufNode* node = list->head; // taking less than the whole buffer if (count <= node->length) { node->length -= count; node->buffer += count; count = 0; break; } else { // shorten the list and free the buffer we have now. list->head = node->next; count -= node->length; AJ_BufListFreeNodeAndBuffer(node, NULL); } } // AJ_ASSERT(count == 0); } /* * This function takes a AJ_BufList and copies it to a user buffer */ AJ_EXPORT void AJ_BufListCopyBytes(AJ_BufList* list, uint16_t count, uint8_t* userBuffer) { // while there are bytes to remove, pull bytes out of the head node of the list. if (list != NULL) { AJ_BufNode* node = list->head; while ((node != NULL) && (count > 0)) { // taking less than the whole buffer if (count <= node->length) { memcpy(userBuffer, node->buffer, count); break; } else { // copy what is in this node and advance to the next. memcpy(userBuffer, node->buffer, node->length); userBuffer += node->length; count -= node->length; node = node->next; } } } } //DEBUG function #ifndef NDEBUG void AJ_BufListWriteToWire_Simulated(AJ_BufNode* node, AJ_BUF_WIREBUFFER* target) { uint16_t iter = 0; memcpy(target->fakeWireWrite, node->buffer, node->length); target->fakeWireWrite += node->length; #ifndef NDEBUG if (AJ_DbgLevel > AJ_DEBUG_INFO) { while (iter < node->length) { AJ_AlwaysPrintf(("%02x ", node->buffer[iter])); iter++; } } #endif } //DEBUG function: simulate an SPI read using a stored data buffer // read a byte from the buffer, advance the read pointer, return the byte. uint8_t AJ_BufListReadByteFromWire_Simulated(AJ_BUF_WIREBUFFER* source) { uint8_t byteRead = *source->fakeWireRead; source->fakeWireRead++; // AJ_AlwaysPrintf(("Byte Read %02x ", byteRead)); return byteRead; } //DEBUG function: simulate an SPI read using a stored data buffer // read a byte from the buffer, advance the read pointer, return the byte. void AJ_BufListReadBytesFromWire_Simulated(uint16_t numberToRead, uint8_t* output, AJ_BUF_WIREBUFFER* source) { while (numberToRead > 0) { *output = AJ_BUFLIST_OPS.readByteFromWire(source); output++; numberToRead--; } } #endif //DEBUG function: print node header info void AJ_BufListNodePrint(AJ_BufNode* node, void* context) { AJ_AlwaysPrintf(("BufList node %p, flags %x length %d, buffer %p, bufferStart %p\n", node, node->flags, node->length, node->buffer, node->bufferStart)); } //DEBUG function: print node contents void AJ_BufListNodePrintDump(AJ_BufNode* node, void* context) { uint16_t iter = 0; AJ_BufListNodePrint(node, NULL); while (iter < node->length) { AJ_AlwaysPrintf(("%02x ", node->buffer[iter])); iter++; } AJ_AlwaysPrintf(("%s", "\n")); } // deprecate, perhaps void AJ_BufNodeIterate(AJ_BufNodeFunc nodeFunc, AJ_BufList* list, void* context) { if (list != NULL) { AJ_BufNode* node = list->head; while (node != NULL) { AJ_BufNode* nextNode = node->next; nodeFunc(node, context); node = nextNode; } } } AJ_Status AJ_BufListIterate(AJ_BufNodeFunc nodeFunc, AJ_BufList* list, void* context) { AJ_Status status = AJ_OK; if (list != NULL) { AJ_BufNode* node = list->head; while ((status == AJ_OK) && (node != NULL)) { AJ_BufNode* nextNode = node->next; nodeFunc(node, context); node = nextNode; } } return status; } void AJ_BufListPrintDump(AJ_BufList* list) { AJ_BufNode* node = list->head; while (node != NULL) { AJ_BufListNodePrintDump(node, NULL); node = node->next; } } void AJ_BufListPrintDumpContinuous(AJ_BufList* list) { int i; AJ_BufNode* node = list->head; while (node != NULL) { for (i = 0; i < node->length; i++) { AJ_AlwaysPrintf(("%02x ", *(node->buffer + i))); } //AJ_BufListNodePrintDump(node, NULL); node = node->next; } AJ_AlwaysPrintf(("\n")); } #ifndef NDEBUG //DEBUG function: print node header info void AJ_BufListIterateOnWire(AJ_BufNodeFuncWireBuf nodeFunc, AJ_BufList* list, AJ_BUF_WIREBUFFER* wire) { if (list != NULL) { AJ_BufNode* node = list->head; while (node != NULL) { AJ_BufNode* nextNode = node->next; nodeFunc(node, wire); node = nextNode; } } } #endif uint16_t AJ_BufListLengthOnWire(AJ_BufList* list) { uint16_t sum = 0; if (list != NULL) { AJ_BufNode* node = list->head; while (node != NULL) { sum += node->length; node = node->next; } } return sum; } void AJ_BufListFreeNode(AJ_BufNode* node, void* context) { AJ_WSL_Free(node); } void AJ_BufListFreeNodeAndBuffer(AJ_BufNode* node, void* context) { if (node && !(node->flags & AJ_BUFNODE_EXTERNAL_BUFFER)) { AJ_WSL_Free(node->bufferStart); } AJ_WSL_Free(node); } void AJ_BufListFree(AJ_BufList* list, uint8_t freeNodeBuffers) { AJ_BufListIterate(freeNodeBuffers ? AJ_BufListFreeNodeAndBuffer : AJ_BufListFreeNode, list, NULL); AJ_WSL_Free(list); } uint32_t AJ_BufListGetSize(AJ_BufList* list) { uint32_t size; AJ_BufNode* node; size = 0; node = list->head; while (node != NULL) { size += node->length; node = node->next; } return size; } #ifdef __cplusplus } #endif ajtcl-16.04/src/wsl/aj_buf.h000066400000000000000000000132751271074662300156340ustar00rootroot00000000000000/** * @file Buffer list function declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_BUF_H_ #define AJ_BUF_H_ #include #include #include "aj_wsl_target.h" #ifdef __cplusplus extern "C" { #endif #ifndef __cplusplus #pragma pack(push, 1) #endif void AJ_BufList_ModuleInit(void); typedef struct _AJ_BufNode { uint16_t length; uint8_t flags; uint8_t* buffer; //moves around when we pull data out. uint8_t* bufferStart; // stays put struct _AJ_BufNode* next; } AJ_BufNode; /* * flag indicating the buffer is allocated elsewhere */ #define AJ_BUFNODE_EXTERNAL_BUFFER (1 << 0) /* * This structure is passed down each layer of the protocol stack. * It is populated at each layer. * When data is received, each element can point to an entry in a buffer. */ typedef struct _AJ_BufList { AJ_BufNode* head; AJ_BufNode* tail; } AJ_BufList; AJ_BufList* AJ_BufListCreate(void); void AJ_BufListFree(AJ_BufList* list, uint8_t freeNodeBuffers); AJ_BufList* AJ_BufListCreateCopy(AJ_BufList* listIn); /* * Create a new node, allocate a payload buffer, and zero the memory contents */ AJ_BufNode* AJ_BufListCreateNodeZero(uint16_t bufferSize, uint8_t zeroBuffer); /* * Create a new node, allocate a buffer. * Use when the full payload will be filled with known data */ AJ_BufNode* AJ_BufListCreateNode(uint16_t bufferSize); AJ_BufNode* AJ_BufListCreateNodeExternalZero(uint8_t* buffer, uint16_t bufferSize, uint8_t zeroBuffer); AJ_BufNode* AJ_BufListCreateNodeExternalBuffer(uint8_t* buffer, uint16_t bufferSize); /* * Create a new node, and assign the buffer info from the giving node. * Use when the the underlying buffer will be used and released elsewhere */ AJ_BufNode* AJ_BufNodeCreateAndTakeOwnership(AJ_BufNode* giving); /* * Free the parameter node, (!but not the payload!) */ void AJ_BufListFreeNode(AJ_BufNode* node, void* context); /* * Free the parameter node, and the payload buffer */ void AJ_BufListFreeNodeAndBuffer(AJ_BufNode* node, void* context); /* * create a new payload of the parameter node * by combining the payloads of the parameter node and its follower */ void AJ_BufListCoalesce(AJ_BufNode* node); /* * Add a AJ_BufNode to the start of the AJ_BufList */ void AJ_BufListPushHead(AJ_BufList* list, AJ_BufNode* newNode); /* * Add a AJ_BufNode to the end of the AJ_BufList */ void AJ_BufListPushTail(AJ_BufList* list, AJ_BufNode* newNode); AJ_EXPORT void AJ_BufNodePullBytes(AJ_BufNode* node, uint16_t count); AJ_EXPORT void AJ_BufListPullBytes(AJ_BufList* list, uint16_t count); AJ_EXPORT void AJ_BufListCopyBytes(AJ_BufList* list, uint16_t count, uint8_t* userBuffer); // prototype for functions that do something with a buffer list node typedef void (*AJ_BufNodeFunc)(AJ_BufNode* node, void* context); typedef AJ_Status (*AJ_BufListFunc)(AJ_BufList* node, void* context); // perform operation on each node in a buffer list AJ_Status AJ_BufListIterate(AJ_BufNodeFunc nodeFunc, AJ_BufList* list, void* context); void AJ_BufNodeIterate(AJ_BufNodeFunc nodeFunc, AJ_BufList* list, void* context); /* * AJ_BufList Helper functions */ /* * This function returns how many bytes will be sent on the wire for this AJ_BufList. */ uint16_t AJ_BufListLengthOnWire(AJ_BufList* list); /* * This function returns the length of unconsumed data contained in the AJ_BufList. */ uint32_t AJ_BufListGetSize(AJ_BufList* list); #ifndef NDEBUG //DEBUG data: simulate SPI read/write using a fixed buffer typedef struct _AJ_BUF_WIREBUFFER { uint8_t fakeWireBuffer[512]; uint8_t* fakeWireCurr; uint8_t* fakeWireWrite; uint8_t* fakeWireRead; } AJ_BUF_WIREBUFFER; extern AJ_BUF_WIREBUFFER toTarget; extern AJ_BUF_WIREBUFFER fromTarget; // prototype for functions that do something with a buffer list node and a wirebuffer typedef void (*AJ_BufNodeFuncWireBuf)(AJ_BufNode* node, AJ_BUF_WIREBUFFER* wireBuffer); /* * Provide support for hooking the low level SPI functions */ typedef uint8_t (*AJ_BufListReadByteFromWire_Func)(AJ_BUF_WIREBUFFER* source); typedef struct _AJ_BUFLIST_FUNC_TABLE { AJ_BufNodeFuncWireBuf writeToWire; AJ_BufListReadByteFromWire_Func readByteFromWire; } AJ_BUFLIST_FUNC_TABLE; //DEBUG functions void AJ_BufListNodePrint(AJ_BufNode* node, void* context); void AJ_BufListNodePrintDump(AJ_BufNode* node, void* context); void AJ_BufListWriteToWire_Simulated(AJ_BufNode* node, AJ_BUF_WIREBUFFER* target); uint8_t AJ_BufListReadByteFromWire_Simulated(AJ_BUF_WIREBUFFER* source); void AJ_BufListReadBytesFromWire_Simulated(uint16_t numberToRead, uint8_t* output, AJ_BUF_WIREBUFFER* source); void AJ_BufListIterateOnWire(AJ_BufNodeFuncWireBuf nodeFunc, AJ_BufList* list, AJ_BUF_WIREBUFFER* wire); #endif #ifndef __cplusplus #pragma pack(pop) #endif #ifdef __cplusplus } #endif #endif /* AJ_BUF_H_ */ ajtcl-16.04/src/wsl/aj_net.c000066400000000000000000000553751271074662300156500ustar00rootroot00000000000000/** * @file Alljoyn network function implementations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE NET #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgNET = 0; #endif /* * IANA assigned IPv4 multicast group for AllJoyn. */ static const char AJ_IPV4_MULTICAST_GROUP[] = "224.0.0.113"; #define AJ_IPV4_MCAST_GROUP 0xe0000071 /* * IANA assigned IPv6 multicast group for AllJoyn. */ static const char AJ_IPV6_MULTICAST_GROUP[] = "ff02::13a"; static uint8_t AJ_IPV6_MCAST_GROUP[16] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a }; /* * IANA assigned UDP multicast port for AllJoyn */ #define AJ_UDP_PORT 9956 /* * IANA-assigned IPv4 multicast group for mDNS. */ static const char MDNS_IPV4_MULTICAST_GROUP[] = "224.0.0.251"; #define MDNS_IPV4_MCAST_GROUP 0xe00000fb /* * IANA-assigned IPv6 multicast group for mDNS. */ static const char MDNS_IPV6_MULTICAST_GROUP[] = "ff02::fb"; static uint8_t MDNS_IPV6_MCAST_GROUP[16] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; /* * IANA-assigned UDP multicast port for mDNS */ #define MDNS_UDP_PORT 5353 /** * Target-specific context for network I/O */ typedef struct { int tcpSock; } NetContext; typedef struct { int udpSock; int udp6Sock; int mDnsSock; int mDns6Sock; int mDnsRecvSock; uint32_t mDnsRecvAddr; uint16_t mDnsRecvPort; } MCastContext; /* * Current socket thats blocked inside select */ static int selectSock; static NetContext netContext = { INVALID_SOCKET }; static MCastContext mCastContext = { INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET, INVALID_SOCKET, 0, 0 }; AJ_Status AJ_IntToString(int32_t val, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = snprintf(buf, buflen, "%d", val); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } AJ_Status AJ_InetToString(uint32_t addr, char* buf, size_t buflen) { AJ_Status status = AJ_OK; int c = snprintf(buf, buflen, "%u.%u.%u.%u", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF)); if (c <= 0 || c > buflen) { status = AJ_ERR_RESOURCES; } return status; } /* * Call this function from an interrupt context to unblock a select call * This only has an effect if select is in a blocking state, any other blocking * calls will be unaffected by this call */ void AJ_Net_Interrupt(void) { AJ_WSL_NET_signal_interrupted(selectSock); } static AJ_Status CloseNetSock(AJ_NetSocket* netSock) { NetContext* context = (NetContext*)netSock->rx.context; if (context) { if (context->tcpSock != INVALID_SOCKET) { AJ_WSL_NET_socket_close(context->tcpSock); } context->tcpSock = INVALID_SOCKET; memset(netSock, 0, sizeof(AJ_NetSocket)); } return AJ_OK; } static AJ_Status CloseMCastSock(AJ_MCastSocket* mcastSock) { MCastContext* context = (MCastContext*)mcastSock->rx.context; if (context) { if (context->udpSock != INVALID_SOCKET) { AJ_WSL_NET_socket_close(context->udpSock); } if (context->udp6Sock != INVALID_SOCKET) { AJ_WSL_NET_socket_close(context->udp6Sock); } if (context->mDnsSock != INVALID_SOCKET) { AJ_WSL_NET_socket_close(context->mDnsSock); } if (context->mDns6Sock != INVALID_SOCKET) { AJ_WSL_NET_socket_close(context->mDns6Sock); } if (context->mDnsRecvSock != INVALID_SOCKET) { AJ_WSL_NET_socket_close(context->mDnsRecvSock); } context->udpSock = context->udp6Sock = context->mDnsSock = context->mDns6Sock = context->mDnsRecvSock = INVALID_SOCKET; memset(mcastSock, 0, sizeof(AJ_MCastSocket)); } return AJ_OK; } AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { NetContext* context = (NetContext*) buf->context; int ret; size_t tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_Send(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { ret = AJ_WSL_NET_socket_send(context->tcpSock, buf->readPtr, tx, 0); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_Send(): send() failed. errno=\"%s\", status=AJ_ERR_WRITE\n", strerror(errno))); return AJ_ERR_WRITE; } buf->readPtr += ret; } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_Net_Send(): status=AJ_OK\n")); return AJ_OK; } AJ_Status AJ_Net_Recv(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { AJ_Status status = AJ_OK; int16_t ret; AJ_Time timer; NetContext* context = (NetContext*) buf->context; size_t rx = AJ_IO_BUF_SPACE(buf); AJ_InfoPrintf(("AJ_Net_Recv(buf=0x%p, len=%ld., timeout=%ld.)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); selectSock = context->tcpSock; AJ_InitTimer(&timer); ret = AJ_WSL_NET_socket_select(context->tcpSock, timeout); if (ret == -2) { // Select timed out return AJ_ERR_TIMEOUT; } else if (ret == -1) { // We were interrupted return AJ_ERR_INTERRUPTED; } else if (ret == 0) { // The socket was closed return AJ_ERR_READ; } // If we pass these checks there is data ready for receive timeout -= AJ_GetElapsedTime(&timer, TRUE); rx = min(rx, len); if (rx) { ret = AJ_WSL_NET_socket_recv(context->tcpSock, buf->writePtr, rx, timeout); if (ret == -1) { status = AJ_ERR_READ; } else if (ret == 0) { status = AJ_ERR_TIMEOUT; } else { buf->writePtr += ret; } } // AJ_InfoPrintf(("AJ_Net_Recv(): status=%s\n", AJ_StatusText(status))); return status; } static uint8_t rxData[1024]; static uint8_t txData[1500]; AJ_Status AJ_Net_Connect(AJ_BusAttachment* bus, const AJ_Service* service) { int ret; AJ_InfoPrintf(("AJ_Net_Connect(netSock=0x%p, port=%d., addrType=%d., addr=0x%lx)\n", netSock, port, addrType, *addr)); int tcpSock = AJ_WSL_NET_socket_open(WSL_AF_INET, WSL_SOCK_STREAM, 0); if (tcpSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_Connect(): socket() failed. status=AJ_ERR_CONNECT\n")); return AJ_ERR_CONNECT; } if (service->addrTypes & AJ_ADDR_TCP4) { // only supported protocol for now! } else { AJ_WSL_NET_socket_close(tcpSock); return AJ_ERR_CONNECT; //TODO: IPv6 connect. Alljoyn never uses IPv6 TCP but maybe in the future } ret = AJ_WSL_NET_socket_connect(tcpSock, BE32_TO_CPU(service->ipv4), service->ipv4port, WSL_AF_INET); if (ret < 0) { AJ_WSL_NET_socket_close(tcpSock); //AJ_ErrPrintf(("AJ_Net_Connect(): connect() failed. errno=\"%s\", status=AJ_ERR_CONNECT\n", strerror(errno))); return AJ_ERR_CONNECT; } else { netContext.tcpSock = tcpSock; AJ_IOBufInit(&bus->sock.rx, rxData, sizeof(rxData), AJ_IO_BUF_RX, &netContext); bus->sock.rx.recv = AJ_Net_Recv; AJ_IOBufInit(&bus->sock.tx, txData, sizeof(txData), AJ_IO_BUF_TX, &netContext); bus->sock.tx.send = AJ_Net_Send; AJ_InfoPrintf(("AJ_Net_Connect(): status=AJ_OK\n")); return AJ_OK; } return AJ_OK; } void AJ_Net_Disconnect(AJ_NetSocket* netSock) { CloseNetSock(netSock); } static AJ_Status RewriteSenderInfo(AJ_IOBuffer* buf, uint32_t addr, uint16_t port) { uint16_t sidVal; const char send[4] = { 'd', 'n', 'e', 's' }; const char sid[] = { 's', 'i', 'd', '=' }; const char ipv4[] = { 'i', 'p', 'v', '4', '=' }; const char upcv4[] = { 'u', 'p', 'c', 'v', '4', '=' }; char sidStr[6]; char ipv4Str[17]; char upcv4Str[6]; uint8_t* pkt; uint16_t dataLength; int match; AJ_Status status; // first, pluck the search ID from the mDNS header sidVal = *(buf->readPtr) << 8; sidVal += *(buf->readPtr + 1); // convert to strings status = AJ_IntToString((int32_t) sidVal, sidStr, sizeof(sidStr)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_IntToString((int32_t) port, upcv4Str, sizeof(upcv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_InetToString(addr, ipv4Str, sizeof(ipv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } // ASSUMPTIONS: sender-info resource record is the final resource record in the packet. // sid, ipv4, and upcv4 key value pairs are the final three key/value pairs in the record. // The length of the other fields in the record are static. // // search backwards through packet to find the start of "sender-info" pkt = buf->writePtr; match = 0; do { if (*(pkt--) == send[match]) { match++; } else { match = 0; } } while (pkt != buf->readPtr && match != 4); if (match != 4) { return AJ_ERR_WRITE; } // move forward to the Data Length field pkt += 22; // actual data length is the length of the static values already in the buffer plus // the three dynamic key-value pairs to re-write dataLength = 23 + 1 + sizeof(sid) + strlen(sidStr) + 1 + sizeof(ipv4) + strlen(ipv4Str) + 1 + sizeof(upcv4) + strlen(upcv4Str); *pkt++ = (dataLength >> 8) & 0xFF; *pkt++ = dataLength & 0xFF; // move forward past the static key-value pairs pkt += 23; // ASSERT: must be at the start of "sid=" assert(*(pkt + 1) == 's'); // re-write new values *pkt++ = sizeof(sid) + strlen(sidStr); memcpy(pkt, sid, sizeof(sid)); pkt += sizeof(sid); memcpy(pkt, sidStr, strlen(sidStr)); pkt += strlen(sidStr); *pkt++ = sizeof(ipv4) + strlen(ipv4Str); memcpy(pkt, ipv4, sizeof(ipv4)); pkt += sizeof(ipv4); memcpy(pkt, ipv4Str, strlen(ipv4Str)); pkt += strlen(ipv4Str); *pkt++ = sizeof(upcv4) + strlen(upcv4Str); memcpy(pkt, upcv4, sizeof(upcv4)); pkt += sizeof(upcv4); memcpy(pkt, upcv4Str, strlen(upcv4Str)); pkt += strlen(upcv4Str); buf->writePtr = pkt; return AJ_OK; } AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { int ret; size_t tx = 0; MCastContext* context = (MCastContext*) buf->context; AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (buf->flags & AJ_IO_BUF_AJ) { tx = AJ_IO_BUF_AVAIL(buf); } if (tx > 0) { // Send out IPv4 multicast if (context->udpSock != INVALID_SOCKET) { ret = AJ_WSL_NET_socket_sendto(context->udpSock, buf->readPtr, tx, BE32_TO_CPU(AJ_IPV4_MCAST_GROUP), AJ_UDP_PORT, 0); } // Send to the IPv6 address if (context->udp6Sock != INVALID_SOCKET) { ret = AJ_WSL_NET_socket_sendto6(context->udp6Sock, buf->readPtr, tx, AJ_IPV6_MULTICAST_GROUP, AJ_UDP_PORT, 0); } } tx = 0; if (buf->flags & AJ_IO_BUF_MDNS) { if (RewriteSenderInfo(buf, context->mDnsRecvAddr, context->mDnsRecvPort) == AJ_OK) { tx = AJ_IO_BUF_AVAIL(buf); } else { AJ_ErrPrintf(("AJ_Net_SendTo(): RewriteSenderInfo failed.\n")); } } if (tx > 0) { // Send out IPv4 multicast if (context->mDnsSock != INVALID_SOCKET) { ret = AJ_WSL_NET_socket_sendto(context->mDnsSock, buf->readPtr, tx, BE32_TO_CPU(MDNS_IPV4_MCAST_GROUP), MDNS_UDP_PORT, 0); } // Send to the IPv6 address if (context->mDns6Sock != INVALID_SOCKET) { ret = AJ_WSL_NET_socket_sendto6(context->mDns6Sock, buf->readPtr, tx, MDNS_IPV6_MULTICAST_GROUP, MDNS_UDP_PORT, 0); } } if (ret == -1) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed. errno=\"%s\", status=AJ_ERR_WRITE\n", strerror(errno))); return AJ_ERR_WRITE; } AJ_IO_BUF_RESET(buf); AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; } AJ_Status AJ_Net_RecvFrom(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { AJ_Status status = AJ_OK; int ret; MCastContext* context = (MCastContext*) buf->context; int sock = context->mDnsRecvSock; uint32_t poll = min(100, timeout / 2); size_t rx = AJ_IO_BUF_SPACE(buf); AJ_InfoPrintf(("AJ_Net_RecvFrom(buf=0x%p, len=%ld, timeout=%ld)\n", buf, len, timeout)); assert(buf->direction == AJ_IO_BUF_RX); assert(context->mDnsRecvSock != INVALID_SOCKET); while (1) { ret = AJ_WSL_NET_socket_recv(sock, buf->writePtr, rx, poll); if (ret == -1) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): Invalid socket: %d\n", ret)); status = AJ_ERR_READ; break; } if (ret > 0) { if (sock == context->mDnsRecvSock) { buf->flags |= AJ_IO_BUF_MDNS; } else { buf->flags |= AJ_IO_BUF_AJ; } buf->writePtr += ret; break; } if (timeout < 100) { AJ_ErrPrintf(("AJ_Net_RecvFrom(): select() timed out.\n")); status = AJ_ERR_TIMEOUT; break; } // rotate to the next valid socket if (sock == context->mDnsRecvSock) { if (context->udpSock != INVALID_SOCKET) { sock = context->udpSock; } else if (context->udp6Sock != INVALID_SOCKET) { sock = context->udp6Sock; } } else if (sock == context->udpSock) { if (context->udp6Sock != INVALID_SOCKET) { sock = context->udp6Sock; } else { sock = context->mDnsRecvSock; } } else if (sock == context->udp6Sock) { sock = context->mDnsRecvSock; } timeout -= 100; } AJ_InfoPrintf(("AJ_Net_RecvFrom(): status=%s\n", AJ_StatusText(status))); return status; } /* * Need enough space to receive a complete name service packet when used in UDP * mode. NS expects MTU of 1500 subtracts UDP, IP and ethertype overhead. * 1500 - 8 -20 - 18 = 1454. txData buffer size needs to be big enough to hold * max(NS WHO-HAS for one name (4 + 2 + 256 = 262), * mDNS query for one name (194 + 5 + 5 + 15 + 256 = 475)) = 475 */ const uint16_t rxDataMCastSize = 1454; const uint16_t txDataMCastSize = 475; #ifndef SO_REUSEPORT #define SO_REUSEPORT SO_REUSEADDR #endif static int MCastUp4(const char group[], uint16_t port) { int ret; int mcastSock; AJ_InfoPrintf(("MCastUp4()\n")); /* * Open socket */ mcastSock = AJ_WSL_NET_socket_open(WSL_AF_INET, WSL_SOCK_DGRAM, 0); if (mcastSock == INVALID_SOCKET) { AJ_ErrPrintf(("MCastUp4(): socket() fails. status=AJ_ERR_READ\n")); return INVALID_SOCKET; } /* * Bind port */ ret = AJ_WSL_NET_socket_bind(mcastSock, 0x00000000, port); /* * Join multicast group */ uint32_t optval[2] = { group, AJ_INADDR_ANY }; ret = AJ_WSL_NET_set_sock_options(mcastSock, WSL_IPPROTO_IP, WSL_ADD_MEMBERSHIP, sizeof(optval), (uint8_t*)&optval); if (ret < 0) { AJ_ErrPrintf(("MCastUp4(): setsockopt(WSL_ADD_MEMBERSHIP) failed: %d. errno=\"%s\"\n", ret, strerror(errno))); AJ_WSL_NET_socket_close(mcastSock); return INVALID_SOCKET; } return mcastSock; } static int MCastUp6(const char group[], uint16_t port) { int ret; int mcastSock; uint8_t gblAddr[16]; uint8_t locAddr[16]; uint8_t gwAddr[16]; uint8_t gblExtAddr[16]; uint32_t linkPrefix = 0; uint32_t glbPrefix = 0; uint32_t gwPrefix = 0; uint32_t glbExtPrefix = 0; uint16_t IP6_ADDR_ANY[8]; memset(&IP6_ADDR_ANY, 0, 16); /* * We pass the current local IPv6 address into the sockopt for joining the multicast group. */ AJ_WSL_ip6config(IPCONFIG_QUERY, (uint8_t*)&gblAddr, (uint8_t*)&locAddr, (uint8_t*)&gwAddr, (uint8_t*)&gblExtAddr, linkPrefix, glbPrefix, gwPrefix, glbExtPrefix); AJ_InfoPrintf(("Local Address:\n")); AJ_InfoPrintf(("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", locAddr[0], locAddr[1], locAddr[2], locAddr[3], locAddr[4], locAddr[5], locAddr[6], locAddr[7], locAddr[8], locAddr[9], locAddr[10], locAddr[11], locAddr[12], locAddr[13], locAddr[14], locAddr[15])); mcastSock = AJ_WSL_NET_socket_open(WSL_AF_INET6, WSL_SOCK_DGRAM, 0); if (mcastSock == INVALID_SOCKET) { AJ_ErrPrintf(("MCastUp6(): socket() fails. status=AJ_ERR_READ\n")); return INVALID_SOCKET; } ret = AJ_WSL_NET_socket_bind6(mcastSock, (uint8_t*)&IP6_ADDR_ANY, port); uint8_t optval[32]; memcpy(&optval, group, 16); memcpy(&optval[16], &locAddr, 16); ret = AJ_WSL_NET_set_sock_options(mcastSock, WSL_IPPROTO_IP, WSL_JOIN_GROUP, 32, (uint8_t*)&optval); if (ret < 0) { AJ_ErrPrintf(("MCastUp6(): setsockopt(WSL_JOIN_GROUP) failed. errno=\"%s\", status=AJ_ERR_READ\n", strerror(errno))); AJ_WSL_NET_socket_close(mcastSock); return INVALID_SOCKET; } return mcastSock; } static int MDnsRecvUp(uint16_t* port) { AJ_Status status; uint16_t p; int ret; int mDnsRecvSock; /* * Open socket */ mDnsRecvSock = AJ_WSL_NET_socket_open(WSL_AF_INET, WSL_SOCK_DGRAM, 0); if (mDnsRecvSock == INVALID_SOCKET) { AJ_ErrPrintf(("MCastUp4(): socket() failed. status=AJ_ERR_READ\n")); return INVALID_SOCKET; } /* * Bind ephemeral port */ p = AJ_EphemeralPort(); status = AJ_WSL_NET_socket_bind(mDnsRecvSock, 0x00000000, p); if (status != AJ_OK) { AJ_ErrPrintf(("MDnsRecvUp(): bind() failed: %d. errno=\"%s\", status=AJ_ERR_READ\n", ret, strerror(errno))); goto ExitError; } *port = p; return mDnsRecvSock; ExitError: AJ_WSL_NET_socket_close(mDnsRecvSock); return INVALID_SOCKET; } AJ_Status AJ_Net_MCastUp(AJ_MCastSocket* mcastSock) { AJ_Status status = AJ_ERR_READ; uint32_t ip; uint32_t mask; uint32_t gateway; uint16_t port; mCastContext.mDnsRecvSock = MDnsRecvUp(&port); if (mCastContext.mDnsRecvSock == INVALID_SOCKET) { AJ_ErrPrintf(("AJ_Net_MCastUp(): MDnsRecvUp for mDnsRecvPort failed")); return status; } mCastContext.mDnsRecvPort = port; if (AJ_GetIPAddress(&ip, &mask, &gateway) != AJ_OK) { AJ_ErrPrintf(("AJ_Net_MCastUp(): no IP address")); goto ExitError; } mCastContext.mDnsRecvAddr = ip; if (mCastContext.mDnsRecvAddr == 0) { AJ_ErrPrintf(("AJ_Net_MCastUp(): no mDNS recv address")); goto ExitError; } AJ_InfoPrintf(("AJ_Net_MCastUp(): mDNS recv on %d.%d.%d.%d:%d\n", ((mCastContext.mDnsRecvAddr & 0xFF) >> 24), ((mCastContext.mDnsRecvAddr >> 16) & 0xFF), ((mCastContext.mDnsRecvAddr >> 8) & 0xFF), (mCastContext.mDnsRecvAddr & 0xFF), mCastContext.mDnsRecvPort)); mCastContext.mDnsSock = MCastUp4(MDNS_IPV4_MCAST_GROUP, MDNS_UDP_PORT); mCastContext.mDns6Sock = MCastUp6(MDNS_IPV6_MCAST_GROUP, MDNS_UDP_PORT); if (AJ_GetMinProtoVersion() < 10) { mCastContext.udpSock = MCastUp4(AJ_IPV4_MCAST_GROUP, AJ_UDP_PORT); mCastContext.udp6Sock = MCastUp6(AJ_IPV4_MCAST_GROUP, AJ_UDP_PORT); } if (mCastContext.udpSock != INVALID_SOCKET || mCastContext.udp6Sock != INVALID_SOCKET || mCastContext.mDnsSock != INVALID_SOCKET || mCastContext.mDns6Sock != INVALID_SOCKET) { uint8_t* rxDataMCast = NULL; uint8_t* txDataMCast = NULL; rxDataMCast = (uint8_t*)AJ_Malloc(rxDataMCastSize); txDataMCast = (uint8_t*)AJ_Malloc(txDataMCastSize); if (!rxDataMCast || !txDataMCast) { return AJ_ERR_UNEXPECTED; } AJ_IOBufInit(&mcastSock->rx, rxDataMCast, rxDataMCastSize, AJ_IO_BUF_RX, &mCastContext); mcastSock->rx.recv = AJ_Net_RecvFrom; AJ_IOBufInit(&mcastSock->tx, txDataMCast, txDataMCastSize, AJ_IO_BUF_TX, &mCastContext); mcastSock->tx.send = AJ_Net_SendTo; status = AJ_OK; } return status; ExitError: AJ_WSL_NET_socket_close(mCastContext.mDnsRecvSock); return status; } void AJ_Net_MCastDown(AJ_MCastSocket* mcastSock) { int ret; MCastContext* context = (MCastContext*) mcastSock->rx.context; AJ_InfoPrintf(("AJ_Net_MCastDown(mcastSock=0x%p)\n", mcastSock)); if (context->udpSock != INVALID_SOCKET) { /* * Leave AJ multicast group */ uint32_t optval[2] = { AJ_IPV4_MCAST_GROUP, AJ_INADDR_ANY }; ret = AJ_WSL_NET_set_sock_options(context->udpSock, WSL_IPPROTO_IP, WSL_DROP_MEMBERSHIP, sizeof(optval), (uint8_t*)&optval); if (ret < 0) { AJ_ErrPrintf(("MCastDown(): setsockopt(WSL_DROP_MEMBERSHIP) failed. errno=\"%d\", status=AJ_ERR_READ\n", ret)); AJ_WSL_NET_socket_close(context->udpSock); } } if (context->mDnsSock != INVALID_SOCKET) { /* * Leave mDNS multicast group */ uint32_t optval[2] = { MDNS_IPV4_MCAST_GROUP, AJ_INADDR_ANY }; ret = AJ_WSL_NET_set_sock_options(context->mDnsSock, WSL_IPPROTO_IP, WSL_DROP_MEMBERSHIP, sizeof(optval), (uint8_t*)&optval); if (ret < 0) { AJ_ErrPrintf(("MCastDown(): setsockopt(WSL_DROP_MEMBERSHIP) failed. errno=\"%d\", status=AJ_ERR_READ\n", ret)); AJ_WSL_NET_socket_close(context->udpSock); } } /* release the dynamically allocated buffers */ AJ_Free(mcastSock->rx.bufStart); AJ_Free(mcastSock->tx.bufStart); CloseMCastSock(mcastSock); } ajtcl-16.04/src/wsl/aj_target_spi.h000066400000000000000000000061701271074662300172150ustar00rootroot00000000000000/** * @file Platform specific function declarations that must be defined per platform port */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_BSP_H_ #define AJ_BSP_H_ #include #ifdef __cplusplus extern "C" { #endif /* * This file contains the layer between alljoyn and platform specific code. * All the functions in this header need to be implemented in the platform * folder for example 'due'. */ /* * This function should include any initialization that needs to be done * for the specific platform. (Clock, UART, SPI, GPIO etc.) */ void AJ_PlatformInit(void); /** * Platform specific SPI write function. This function write 1 byte of data to the SPI * peripheral. * * @param spi_device The SPI device to write to (on the FRDM platform this has no effect) * @param byte Byte of data to write to SPI * @param pcs Chip Select device your writing to (on the FRDM platform this has no effect) * @param cont Signals whether or not to assert/de-assert chip select to end the transfer * * @return SPI_OK on success, SPI_ERR upon error */ aj_spi_status AJ_SPI_WRITE(uint8_t* spi_device, uint8_t byte, uint8_t pcs, uint8_t cont); /** * Platform specific SPI read function. Read 1 byte of data from the SPI peripheral * * @param spi_device The SPI device to read from (on the FRDM platform this has no effect) * @param data Pointer to a buffer to read into * @param pcs Chip select device to read from (on the FRDM platform this has no effect) */ aj_spi_status AJ_SPI_READ(uint8_t* spi_device, uint8_t* data, uint8_t pcs); /* * This function should be implemented on a specific platform to initialize * the SPI hardware */ void AJ_WSL_SPI_InitializeSPIController(void); /* * This function should be implemented on a specific platform to shutdown * the SPI hardware */ void AJ_WSL_SPI_ShutdownSPIController(void); /* * This function should be implemented on a specific platform as the * SPI interrupt handler */ void AJ_WSL_SPI_ISR(void); void AJ_WSL_SPI_CHIP_SPI_ISR(uint32_t id, uint32_t mask); AJ_Status AJ_WSL_SPI_DMATransfer(uint8_t* buffer, uint16_t len, uint8_t direction); #ifdef __cplusplus } #endif #endif /* AJ_BSP_H_ */ ajtcl-16.04/src/wsl/aj_wifi_ctrl.c000066400000000000000000000414401271074662300170300ustar00rootroot00000000000000/** * @file Functions relating to wifi configuration and initialization */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE WIFI #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWIFI = 0; #endif extern AJ_WifiCallbackFunc AJ_WSL_WifiConnectCallback; static char* AddrStr(uint32_t addr) { static char txt[17]; sprintf((char*)&txt, "%3lu.%3lu.%3lu.%3lu\0", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF) ); return txt; } static AJ_Status AJ_Network_Up(); #define MAX_SSID_LENGTH 32 static const uint32_t startIP = 0xC0A80101; static const uint32_t endIP = 0xC0A80102; #define IP_LEASE (60 * 60 * 1000) static const uint8_t IP6RoutePrefix[16] = { 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; #define PREFIX_LEN 64 #define PREFIX_LIFETIME 12000 AJ_WiFiConnectState AJ_WSL_connectState = AJ_WIFI_IDLE; static uint32_t athSecType = AJ_WIFI_SECURITY_NONE; AJ_WiFiConnectState AJ_GetWifiConnectState(void) { return AJ_WSL_connectState; } #define RSNA_AUTH_FAILURE 10 #define RSNA_AUTH_SUCCESS 16 static void WiFiCallback(int val) { AJ_InfoPrintf(("\nWiFiCallback %d\n", val)); if (val == 0) { if (AJ_WSL_connectState == AJ_WIFI_DISCONNECTING || AJ_WSL_connectState == AJ_WIFI_CONNECT_OK) { AJ_WSL_connectState = AJ_WIFI_IDLE; AJ_InfoPrintf(("\nWiFi Disconnected\n")); } else if (AJ_WSL_connectState != AJ_WIFI_CONNECT_FAILED) { AJ_WSL_connectState = AJ_WIFI_CONNECT_FAILED; AJ_InfoPrintf(("\nWiFi Connect Failed\n")); } } else if (val == 1) { /* * With WEP or no security a callback value == 1 means we are done. In the case of wEP this * means there is no way to tell if the association succeeded or failed. */ if ((athSecType == AJ_WIFI_SECURITY_NONE) || (athSecType == AJ_WIFI_SECURITY_WEP)) { AJ_WSL_connectState = AJ_WIFI_CONNECT_OK; AJ_InfoPrintf(("\nConnected to AP\n")); } } else if (val == RSNA_AUTH_SUCCESS) { AJ_WSL_connectState = AJ_WIFI_CONNECT_OK; AJ_InfoPrintf(("\nConnected to AP\n")); } else if (val == RSNA_AUTH_FAILURE) { AJ_WSL_connectState = AJ_WIFI_AUTH_FAILED; AJ_InfoPrintf(("\nWiFi Authentication Failed\n")); } /* * Set up for IPV6 */ if (AJ_WSL_connectState == AJ_WIFI_CONNECT_OK) { AJ_WSL_NET_ip6config_router_prefix(IP6RoutePrefix, PREFIX_LEN, PREFIX_LIFETIME, PREFIX_LIFETIME); } } static void SoftAPCallback(int val) { if (val == 0) { if (AJ_WSL_connectState == AJ_WIFI_DISCONNECTING || AJ_WSL_connectState == AJ_WIFI_SOFT_AP_UP) { AJ_WSL_connectState = AJ_WIFI_IDLE; AJ_InfoPrintf(("Soft AP Down\n")); } else if (AJ_WSL_connectState == AJ_WIFI_STATION_OK) { AJ_WSL_connectState = AJ_WIFI_SOFT_AP_UP; AJ_InfoPrintf(("Soft AP Station Disconnected\n")); } else { AJ_WSL_connectState = AJ_WIFI_CONNECT_FAILED; AJ_InfoPrintf(("Soft AP Connect Failed\n")); } } else if (val == 1) { if (AJ_WSL_connectState == AJ_WIFI_SOFT_AP_INIT) { AJ_InfoPrintf(("Soft AP Initialized\n")); AJ_WSL_connectState = AJ_WIFI_SOFT_AP_UP; } else { AJ_InfoPrintf(("Soft AP Station Connected\n")); AJ_WSL_connectState = AJ_WIFI_STATION_OK; } } } AJ_Status AJ_PrintFWVersion() { AJ_Status status = AJ_OK; AJ_FW_Version version; AJ_Network_Up(); extern AJ_FW_Version AJ_WSL_TargetFirmware; version = AJ_WSL_TargetFirmware; if (status == AJ_OK) { AJ_InfoPrintf(("Host version : %ld.%ld.%ld.%ld.%ld\n", (version.host_ver & 0xF0000000) >> 28, (version.host_ver & 0x0F000000) >> 24, (version.host_ver & 0x00FC0000) >> 18, (version.host_ver & 0x0003FF00) >> 8, (version.host_ver & 0x000000FF))); AJ_InfoPrintf(("Target version : 0x%lx\n", version.target_ver)); AJ_InfoPrintf(("Firmware version : %ld.%ld.%ld.%ld.%ld\n", (version.wlan_ver & 0xF0000000) >> 28, (version.wlan_ver & 0x0F000000) >> 24, (version.wlan_ver & 0x00FC0000) >> 18, (version.wlan_ver & 0x0003FF00) >> 8, (version.wlan_ver & 0x000000FF))); AJ_InfoPrintf(("Interface version: %ld\n", version.abi_ver)); } return status; } static AJ_Status AJ_ConnectWiFiHelper(const char* ssid, AJ_WiFiSecurityType secType, AJ_WiFiCipherType cipherType, const char* passphrase) { AJ_Status status; WSL_NET_AUTH_MODE secMode; WSL_NET_CRYPTO_TYPE cipher; /* * In WifiCallback we need to know if the connection was secure */ athSecType = secType; /* * Clear the old connection state */ AJ_WSL_connectState = AJ_WIFI_IDLE; status = AJ_DisconnectWiFi(); if (status != AJ_OK) { return status; } /* * Set the new SSID */ if (strlen(ssid) > MAX_SSID_LENGTH) { AJ_ErrPrintf(("SSID length exceeds Maximum value\n")); return AJ_ERR_INVALID; } /* * security mode */ switch (secType) { case AJ_WIFI_SECURITY_WEP: secMode = WSL_NET_AUTH_NONE; break; case AJ_WIFI_SECURITY_WPA2: secMode = WSL_NET_AUTH_WPA2_PSK; break; case AJ_WIFI_SECURITY_WPA: secMode = WSL_NET_AUTH_WPA_PSK; break; case AJ_WIFI_SECURITY_NONE: secMode = WSL_NET_AUTH_NONE; break; default: secMode = WSL_NET_AUTH_WPA2_PSK; break; } /* * Setup the security parameters if needed */ cipher = WSL_NET_CRYPTO_NONE; if (athSecType != AJ_WIFI_SECURITY_NONE) { uint32_t passLen = strlen(passphrase); /* * Cipher type - same for unicast and multicast */ switch (cipherType) { case AJ_WIFI_CIPHER_WEP: cipher = WSL_NET_CRYPTO_WEP; break; case AJ_WIFI_CIPHER_TKIP: cipher = WSL_NET_CRYPTO_TKIP; break; case AJ_WIFI_CIPHER_CCMP: cipher = WSL_NET_CRYPTO_AES; break; default: cipher = WSL_NET_CRYPTO_NONE; break; } if (secType == AJ_WIFI_SECURITY_WEP) { AJ_WSL_NET_add_cipher_key(0, (uint8_t*)passphrase, 5); } } /* * Set power mode to Max-Perf */ AJ_WSL_NET_SetPowerMode(2); /* * Set the callback for the connect state */ AJ_WSL_WifiConnectCallback = &WiFiCallback; /* * Begin the actual connection process */ AJ_WSL_connectState = AJ_WIFI_CONNECTING; status = AJ_WSL_NET_connect(ssid, passphrase, secMode, cipher, FALSE); return status; } #define DHCP_TIMEOUT 5000 AJ_Status AJ_ConnectWiFi(const char* ssid, AJ_WiFiSecurityType secType, AJ_WiFiCipherType cipherType, const char* passphrase) { AJ_WiFiConnectState connectState; uint32_t ip; uint32_t mask; uint32_t gateway; AJ_Status status = AJ_Network_Up(); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_ConnectWiFi(): AJ_Network_Up error")); return status; } AJ_SetIPAddress(0, 0, 0); status = AJ_ConnectWiFiHelper(ssid, secType, cipherType, passphrase); if (status != AJ_OK) { AJ_ErrPrintf(("ConfigureWifi error\n")); return status; } /* * Poll until we are connected or the connection fails */ connectState = AJ_GetWifiConnectState(); while (connectState == AJ_WIFI_CONNECTING) { AJ_InfoPrintf(("ConnectWiFi Connecting...\n")); AJ_Sleep(250); connectState = AJ_GetWifiConnectState(); } if (connectState == AJ_WIFI_CONNECT_OK) { status = AJ_AcquireIPAddress(&ip, &mask, &gateway, DHCP_TIMEOUT); AJ_InfoPrintf(("AJ_ConnectWiFi(): AJ_AcquireIPAddress status=%s\n", AJ_StatusText(status))); if (status == AJ_OK) { AJ_AlwaysPrintf(("Got IP %s\n", AddrStr(ip))); } } else if (connectState == AJ_WIFI_CONNECT_FAILED) { AJ_ErrPrintf(("ConnectWiFi failed to connect\n")); status = AJ_ERR_CONNECT; } else if (connectState == AJ_WIFI_AUTH_FAILED) { AJ_ErrPrintf(("ConnectWiFi failed to authenticate\n")); status = AJ_ERR_SECURITY; } else { AJ_ErrPrintf(("ConnectWiFi failed\n")); status = AJ_ERR_UNKNOWN; } return status; } AJ_Status AJ_DisconnectWiFi(void) { AJ_Status status = AJ_OK; AJ_WiFiConnectState oldState = AJ_WSL_connectState; if (oldState != AJ_WIFI_DISCONNECTING) { /* * Commit the changes */ if (oldState != AJ_WIFI_IDLE) { AJ_WSL_connectState = AJ_WIFI_DISCONNECTING; } AJ_WSL_NET_disconnect(); } return status; } static AJ_Status AJ_EnableSoftAPHelper(const char* ssid, uint8_t hidden, const char* passphrase) { AJ_Status status = AJ_OK; WSL_NET_AUTH_MODE secType = passphrase ? WSL_NET_AUTH_WPA2_PSK : WSL_NET_AUTH_NONE; WSL_NET_CRYPTO_TYPE cipher = WSL_NET_CRYPTO_NONE; /* * Clear the current connection */ AJ_WSL_connectState = AJ_WIFI_IDLE; if (strlen(ssid) > MAX_SSID_LENGTH) { AJ_ErrPrintf(("SSID length exceeds Maximum value\n")); return AJ_ERR_INVALID; } /* * Set flag to indicate if AP SSID is hidden */ if (hidden) { status = AJ_WSL_NET_SetHiddenAP(hidden); if (status != AJ_OK) { return status; } } /* * Set security parameters if AP is not open */ if (secType != WSL_NET_AUTH_NONE) { /* * Set cipher type to CCMP */ cipher = WSL_NET_CRYPTO_AES; /* * Set the passphrase */ status = AJ_WSL_NET_SetPassphrase(ssid, passphrase, strlen(passphrase)); if (status != AJ_OK) { return status; } } /* * Set the callback for the connect state */ AJ_WSL_WifiConnectCallback = &SoftAPCallback; /* * Set the IP range for DHCP */ if (AJ_WSL_NET_ipconfig_dhcp_pool(&startIP, &endIP, IP_LEASE) != AJ_OK) { return AJ_ERR_DRIVER; } /* * Set up for IPV6 */ if (AJ_WSL_NET_ip6config_router_prefix(IP6RoutePrefix, PREFIX_LEN, PREFIX_LIFETIME, PREFIX_LIFETIME) != AJ_OK) { return AJ_ERR_DRIVER; } /* * Begin the creation of the SoftAP on the target */ AJ_WSL_connectState = AJ_WIFI_SOFT_AP_INIT; AJ_WSL_NET_connect(ssid, passphrase, secType, cipher, TRUE); return status; } #define SOFTAP_SLEEP_TIMEOUT 100 // block until somebody connects to us or the timeout expires AJ_Status AJ_EnableSoftAP(const char* ssid, uint8_t hidden, const char* passphrase, const uint32_t timeout) { AJ_Status status = AJ_Network_Up(); uint32_t time2 = 0; if (status != AJ_OK) { AJ_ErrPrintf(("AJ_EnableSoftAP(): AJ_Network_Up error")); return status; } status = AJ_EnableSoftAPHelper(ssid, hidden, passphrase); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_EnableSoftAP error\n")); return status; } /* * Wait until a remote station connects */ AJ_InfoPrintf(("Waiting for remote station to connect\n")); do { AJ_Sleep(SOFTAP_SLEEP_TIMEOUT); time2 += SOFTAP_SLEEP_TIMEOUT; } while (AJ_GetWifiConnectState() != AJ_WIFI_STATION_OK && (timeout == 0 || time2 < timeout)); return (AJ_GetWifiConnectState() == AJ_WIFI_STATION_OK) ? AJ_OK : AJ_ERR_TIMEOUT; } AJ_Status AJ_WiFiScan(void* context, AJ_WiFiScanResult callback, uint8_t maxAPs) { AJ_Status status = AJ_OK; AJ_WSL_RegisterWiFiCallback(context, callback); status = AJ_Network_Up(); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_WiFiScan(): AJ_Network_Up error")); return status; } AJ_WSL_InitScanList(maxAPs); AJ_WSL_NET_scan(); AJ_WSL_NET_scan_stop(); WSL_ClearScanList(); AJ_WSL_UnregisterWiFiCallback(); return status; } static uint8_t get_tx_status() { return 0; } AJ_Status AJ_SuspendWifi(uint32_t msec) { static uint8_t suspendEnabled = FALSE; return AJ_OK; } static uint8_t wifi_initialized = FALSE; static uint32_t wifi_state = 0; static AJ_Status AJ_Network_Up() { AJ_Status status = AJ_OK; AJ_WSL_connectState = AJ_WIFI_IDLE; if (wifi_initialized == FALSE) { AJ_WSL_ModuleInit(); wifi_initialized = TRUE; } if (wifi_state == 0) { wifi_state = 1; /* * Initialize the device */ status = AJ_WSL_DriverStart(); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_WSL_DriverStart failed %d\n", status)); return AJ_ERR_DRIVER; } else { AJ_WSL_NET_StackInit(); } } return status; } static AJ_Status AJ_Network_Down() { AJ_Status err; AJ_WSL_connectState = AJ_WIFI_IDLE; if (wifi_state == 1) { wifi_state = 0; err = AJ_WSL_DriverStop(); if (err != AJ_OK) { AJ_ErrPrintf(("AJ_WSL_DriverStop failed %d\n", err)); return AJ_ERR_DRIVER; } } return AJ_OK; } AJ_Status AJ_ResetWiFi(void) { AJ_Status status; AJ_InfoPrintf(("Reset WiFi driver\n")); AJ_WSL_connectState = AJ_WIFI_IDLE; status = AJ_Network_Down(); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_ResetWiFi(): AJ_Network_Down failed %s\n", AJ_StatusText(status))); return status; } wifi_initialized = FALSE; // restarting _everything_ return AJ_Network_Up(); } AJ_Status AJ_GetIPAddress(uint32_t* ip, uint32_t* mask, uint32_t* gateway) { // set to zero first *ip = *mask = *gateway = 0; return AJ_WSL_ipconfig(IPCONFIG_QUERY, ip, mask, gateway); } #define DHCP_WAIT 100 AJ_Status AJ_AcquireIPAddress(uint32_t* ip, uint32_t* mask, uint32_t* gateway, int32_t timeout) { AJ_Status status; AJ_WiFiConnectState current_wifi_state = AJ_GetWifiConnectState(); switch (current_wifi_state) { case AJ_WIFI_CONNECT_OK: break; // no need to do anything in Soft-AP mode case AJ_WIFI_SOFT_AP_INIT: case AJ_WIFI_SOFT_AP_UP: case AJ_WIFI_STATION_OK: return AJ_OK; // shouldn't call this function unless already connected! case AJ_WIFI_IDLE: case AJ_WIFI_CONNECTING: case AJ_WIFI_CONNECT_FAILED: case AJ_WIFI_AUTH_FAILED: case AJ_WIFI_DISCONNECTING: return AJ_ERR_DHCP; } status = AJ_GetIPAddress(ip, mask, gateway); if (status != AJ_OK) { return status; } while (0 == *ip) { if (timeout < 0) { AJ_ErrPrintf(("AJ_AcquireIPAddress(): DHCP Timeout\n")); return AJ_ERR_TIMEOUT; } AJ_InfoPrintf(("Sending DHCP request\n")); /* * This call kicks off DHCP but we need to poll until the values are populated */ status = AJ_WSL_ipconfig(IPCONFIG_DHCP, ip, mask, gateway); if (status != AJ_OK) { return AJ_ERR_DHCP; } AJ_Sleep(DHCP_WAIT); status = AJ_GetIPAddress(ip, mask, gateway); if (status != AJ_OK) { return status; } timeout -= DHCP_WAIT; } if (status == AJ_OK) { AJ_InfoPrintf(("*********** DHCP succeeded %s\n", AddrStr(*ip))); } return status; } AJ_Status AJ_SetIPAddress(uint32_t ip, uint32_t mask, uint32_t gateway) { return AJ_WSL_ipconfig(IPCONFIG_STATIC, &ip, &mask, &gateway); } ajtcl-16.04/src/wsl/aj_wsl_htc.c000066400000000000000000000222001271074662300165020ustar00rootroot00000000000000/** * @file HTC layer implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE WSL_HTC #include #include #include #include #include #include #include "aj_wsl_spi.h" #include "aj_wsl_htc.h" #include "aj_wsl_wmi.h" #include "aj_wsl_unmarshal.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_HTC = 0; #endif /** * global variable for WSL_HTC state */ AJ_WSL_HTC_CONTEXT AJ_WSL_HTC_Global; void AJ_WSL_HTC_ModuleInit(void) { //Initialize the credit-tracking information memset(&AJ_WSL_HTC_Global, 0, sizeof(AJ_WSL_HTC_Global)); AJ_WSL_HTC_Global.endpoints[0].txCredits = 1; AJ_WSL_HTC_Global.endpoints[1].txCredits = 2; AJ_WSL_HTC_Global.endpoints[2].txCredits = 10; AJ_WSL_HTC_Global.started = FALSE; AJ_WSL_SPI_ModuleInit(); } uint8_t AJ_WSL_IsDriverStarted() { return AJ_WSL_HTC_Global.started; } void AJ_WSL_HTC_ProcessInterruptCause(void) { uint16_t cause = 0; AJ_Status status = AJ_ERR_SPI_READ; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_INTR_CAUSE, (uint8_t*)&cause); AJ_ASSERT(status == AJ_OK); cause = LE16_TO_CPU(cause); if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_DATA_AVAILABLE) { AJ_WSL_HTC_ProcessIncoming(); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_DATA_AVAILABLE; //clear the bit } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_READ_DONE) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_READ_DONE); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_READ_DONE; } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_WRITE_DONE) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_WRITE_DONE); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_WRITE_DONE; } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_CPU_AWAKE) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_CPU_AWAKE); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_CPU_AWAKE; } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_COUNTER) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_COUNTER); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_COUNTER; } if (cause & ~AJ_WSL_SPI_REG_INTR_CAUSE_DATA_AVAILABLE) { //AJ_InfoPrintf(("Some other interrupt cause as well %x\n", cause)); } } /* * read from the mailbox and do something useful with the HTC message. */ void AJ_WSL_HTC_ProcessIncoming(void) { uint16_t lenRead; uint8_t* bufRead; AJ_BufNode* pNodeHTCBody; uint8_t endpointID; uint8_t flags; uint16_t payloadLength; uint8_t controlBytes[2]; AJ_Status status; status = AJ_WSL_ReadFromMBox(AJ_WSL_SPI_MBOX_0, &lenRead, &bufRead); AJ_ASSERT(status == AJ_OK); // now create a AJ_BufList from the data we read pNodeHTCBody = AJ_BufListCreateNodeExternalZero(bufRead, lenRead, FALSE); pNodeHTCBody->flags = 0; // reset the AJ_BUFNODE_EXTERNAL_BUFFER flag, because I own this now. WMI_Unmarshal(pNodeHTCBody->buffer, "yyqyy", &endpointID, &flags, &payloadLength, &controlBytes[0], &controlBytes[1]); AJ_BufNodePullBytes(pNodeHTCBody, 6); //AJ_WSL_WMI_PrintMessage(pNodeHTCBody); AJ_DumpBytes("HTC_CONTROL", pNodeHTCBody->buffer, pNodeHTCBody->length); /* examine the endpoint of the HTC message*/ if ((flags & AJ_WSL_HTC_RECV_TRAILER_PRESENT) && ((payloadLength - controlBytes[0]) > 0)) { switch (endpointID) { case AJ_WSL_HTC_CONTROL_ENDPOINT: { uint16_t* messageID = (uint16_t*)pNodeHTCBody->buffer; AJ_InfoPrintf(("Read HTC control endpoint, messageID %x\n", *messageID)); switch (*messageID) { case AJ_WSL_HTC_MSG_READY_ID: { /* process the message and change state */ uint16_t readyMessageID; WMI_Unmarshal(pNodeHTCBody->buffer, "qqqyyy", &readyMessageID, &AJ_WSL_HTC_Global.creditCount, &AJ_WSL_HTC_Global.creditSize, &AJ_WSL_HTC_Global.maxEndpoints, &AJ_WSL_HTC_Global.HTCVersion, &AJ_WSL_HTC_Global.maxMessagesPerBundle); /* SIDE EFFECT */ AJ_WarnPrintf(("MSG_READY, credit count %x, credit size:%d\n", AJ_WSL_HTC_Global.creditCount, AJ_WSL_HTC_Global.creditSize)); AJ_WSL_HTC_Global.endpoints[AJ_WSL_HTC_CONTROL_ENDPOINT].state = AJ_WSL_HTC_UNINITIALIZED_RECV_READY; break; } case AJ_WSL_HTC_SERVICE_CONNECT_RESPONSE_ID: { AJ_WarnPrintf(("HTC MSG AJ_WSL_HTC_SERVICE_CONNECT_RESPONSE_ID\n")); break; } default: AJ_WarnPrintf(("HTC MSG ID unknown\n")); AJ_DumpBytes("WMI_SOCKET_RESPONSE", pNodeHTCBody->buffer, pNodeHTCBody->length); break; } break; } case AJ_WSL_HTC_DATA_ENDPOINT1: { // AJ_DumpBytes("DATA ENDPOINT WMI ", pNodeHTCBody->buffer, pNodeHTCBody->length); AJ_WSL_WMI_ProcessWMIEvent(pNodeHTCBody); break; } case AJ_WSL_HTC_DATA_ENDPOINT2: case AJ_WSL_HTC_DATA_ENDPOINT3: case AJ_WSL_HTC_DATA_ENDPOINT4: { AJ_DumpBytes("DATA ENDPOINT WMI_SOCKET_RESPONSE", pNodeHTCBody->bufferStart, pNodeHTCBody->length); AJ_WSL_WMI_ProcessSocketDataResponse(pNodeHTCBody); //AJ_InfoPrintf(("Read HTC data endpoint %d\n", htcHdr.endpointID)); // TODO send the data up to the next API level //AJ_WSL_WMI_PrintMessage(pNodeHTCBody); break; } default: AJ_ErrPrintf(("UNKNOWN Endpoint %d", endpointID)); AJ_ASSERT(FALSE); break; } } /* * Trailers can come on any packet */ if (flags & AJ_WSL_HTC_RECV_TRAILER_PRESENT) { uint16_t packetLength; uint8_t trailerLength = controlBytes[0]; packetLength = payloadLength - trailerLength; //AJ_InfoPrintf(("Read HTC RX trailer, length %d\n", htcHdr.controlBytes[0])); AJ_BufNodePullBytes(pNodeHTCBody, packetLength); // consume the packet, leave the trailer /* * handle multiple trailers per HTC message */ while (trailerLength) { uint8_t trailerType; uint8_t length; //AJ_BufListNodePrintDump(pNodeHTCBody, NULL); WMI_Unmarshal(pNodeHTCBody->buffer, "yy", &trailerType, &length); AJ_BufNodePullBytes(pNodeHTCBody, 2); // consume the trailer trailerLength -= 2; switch (trailerType) { case AJ_WSL_HTC_RXTRAILER_CREDIT_REPORT: { uint8_t credits; uint8_t endpoint; WMI_Unmarshal(pNodeHTCBody->buffer, "yy", &endpoint, &credits); AJ_InfoPrintf(("Add %d credits to endpoint %d\n", credits, endpoint)); AJ_WSL_HTC_Global.endpoints[endpoint].txCredits += credits; break; } default: { AJ_InfoPrintf(("HTC trailer: type not handled %d\n", trailerType)); } } trailerLength -= length; AJ_BufNodePullBytes(pNodeHTCBody, length); // consume the trailer } } //intentionally freeing the buffer here AJ_BufListFreeNodeAndBuffer(pNodeHTCBody, NULL); } ajtcl-16.04/src/wsl/aj_wsl_htc.h000066400000000000000000000046251271074662300165220ustar00rootroot00000000000000/** * @file HTC layer function declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_HTC_H_ #define AJ_WSL_HTC_H_ #include #include #include #include "aj_wsl_target.h" #include "aj_wsl_spi_constants.h" #ifdef __cplusplus extern "C" { #endif #pragma pack(push, 1) void AJ_WSL_HTC_ModuleInit(void); uint8_t AJ_WSL_IsDriverStarted(void); /* * Endpoints can be in any of these states */ typedef enum _AJ_WSL_HTC_STATE { AJ_WSL_HTC_UNINITIALIZED, AJ_WSL_HTC_UNINITIALIZED_RECV_READY, AJ_WSL_HTC_UNINITIALIZED_SENT_CRED_REQ, AJ_WSL_HTC_INITIALIZED, AJ_WSL_HTC_NO_CREDS, /**< no credits available for this endpoint */ AJ_WSL_HTC_CREDS /**< okay to send packets to the target */ } AJ_WSL_HTC_STATE; typedef struct _WSL_HTC_EP { uint8_t endpointId; uint16_t serviceId; uint16_t txCredits; AJ_WSL_HTC_STATE state; } WSL_HTC_EP; typedef struct _WSL_HTC_CONTEXT { uint16_t creditCount; uint16_t creditSize; uint8_t maxEndpoints; uint8_t HTCVersion; uint8_t maxMessagesPerBundle; WSL_HTC_EP endpoints[AJ_WSL_HTC_ENDPOINT_COUNT_MAX]; uint8_t started; } AJ_WSL_HTC_CONTEXT; /* * HTC header flags */ #define AJ_WSL_HTC_NEED_CREDIT_UPDATE (1 << 0) #define AJ_WSL_HTC_RECV_TRAILER_PRESENT (1 << 1) void AJ_WSL_HTC_ProcessInterruptCause(void); void AJ_WSL_HTC_ProcessIncoming(void); #pragma pack(pop) #ifdef __cplusplus } #endif #endif /* AJ_WSL_HTC_H_ */ ajtcl-16.04/src/wsl/aj_wsl_marshal.c000066400000000000000000000203741271074662300173650ustar00rootroot00000000000000/** * @file Marshaling implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE WSL_MARSHAL #include #include #include #include #include #include #include #include #ifndef NDEBUG uint8_t dbgWSL_MARSHAL = 5; #endif static uint8_t packetId = 0; uint8_t WMI_MarshalArgsBuf(AJ_BufList* data, const char* sig, uint16_t size, va_list* argpp) { va_list argp; va_copy(argp, *argpp); AJ_BufNode* node; node = AJ_BufListCreateNode(size); uint8_t* ptr = node->buffer; while (*sig) { switch (*sig++) { case (WMI_ARG_UINT64): { uint64_t u64; u64 = (uint64_t)va_arg(argp, uint64_t); memcpy(ptr, &u64, sizeof(uint64_t)); ptr += 8; } break; case (WMI_ARG_UINT32): { uint32_t u32; u32 = (uint32_t)va_arg(argp, uint32_t); memcpy(ptr, &u32, sizeof(uint32_t)); ptr += 4; } break; case (WMI_ARG_IPV4): { uint8_t* IPv4; IPv4 = (uint8_t*)va_arg(argp, uint32_t); memcpy(ptr, IPv4, sizeof(uint8_t) * 4); ptr += 4; } break; case (WMI_ARG_IPV6): { uint16_t* IPv6; IPv6 = (uint16_t*)va_arg(argp, uint32_t); memcpy(ptr, IPv6, sizeof(uint16_t) * 8); ptr += 16; } break; case (WMI_ARG_UINT16): { uint16_t u16; u16 = (uint16_t)va_arg(argp, uint32_t); memcpy(ptr, &u16, sizeof(uint16_t)); ptr += 2; } break; case (WMI_ARG_BYTE): { uint8_t u8; u8 = (uint8_t)va_arg(argp, uint32_t); memcpy(ptr, &u8, sizeof(uint8_t)); ptr += 1; } break; case (WMI_ARG_MAC): { uint8_t* mac; mac = (uint8_t*)va_arg(argp, uint32_t); memcpy(ptr, mac, sizeof(uint8_t) * 6); ptr += 6; } break; case (WMI_ARG_SSID): { char* str; str = (char*)va_arg(argp, char*); memcpy(ptr, str, sizeof(char*) * strlen(str)); ptr += 32; } break; case (WMI_ARG_PASSPHRASE): { char* str; str = (char*)va_arg(argp, char*); memcpy(ptr, str, sizeof(char*) * strlen(str)); ptr += 64; } break; case (WMI_ARG_KEY): { uint8_t* key; key = (uint8_t*)va_arg(argp, uint32_t); memcpy(ptr, key, sizeof(uint8_t) * 32); ptr += 32; } break; default: AJ_ErrPrintf(("WMI_MarshalArgsBuf(): Unknown signature: %c\n", *sig)); return 0; } } va_end(argp); AJ_BufListPushTail(data, node); return 1; } void WMI_MarshalHeader(AJ_BufList* packet, uint8_t endpoint, uint8_t flags) { AJ_BufNode* header; uint16_t size; uint8_t trailer; header = AJ_BufListCreateNode(6); size = AJ_BufListGetSize(packet); trailer = 0x00; memcpy(header->buffer, &endpoint, sizeof(uint8_t)); memcpy(header->buffer + 1, &flags, sizeof(uint8_t)); memcpy(header->buffer + 2, &size, sizeof(uint16_t)); memcpy(header->buffer + 4, &trailer, sizeof(uint8_t)); memcpy(header->buffer + 5, &packetId, sizeof(uint8_t)); packetId++; AJ_BufListPushHead(packet, header); } void WSL_MarshalPacket(AJ_BufList* packet, wsl_wmi_command_list command, ...) { va_list args; uint16_t size; uint16_t cmd; uint32_t zero = 0; AJ_BufNode* cmdid; const char* signature; va_start(args, command); cmd = getCommandId(command); // Socket commands need to get their signature from a different map if (command == WSL_SOCKET) { cmdid = AJ_BufListCreateNode(10); memcpy(cmdid->buffer, &cmd, sizeof(uint16_t)); memcpy(cmdid->buffer + 2, &zero, sizeof(uint32_t)); uint32_t sock_cmd = (uint32_t)va_arg(args, uint32_t); memcpy(cmdid->buffer + 6, &sock_cmd, sizeof(uint32_t)); signature = (char*)getSockSignature((wsl_socket_cmds)sock_cmd); size = getSockSize((wsl_socket_cmds)sock_cmd); AJ_BufListPushTail(packet, cmdid); WMI_MarshalArgsBuf(packet, signature, size - 4, &args); } else if ((command == WSL_SEND) || (command == WSL_SENDTO) || (command == WSL_SENDTO6)) { signature = (char*)getCommandSignature(command); size = getPacketSize(command); WMI_MarshalArgsBuf(packet, signature, size, &args); } else if (command == WSL_BIND6) { signature = (char*)getCommandSignature(command); size = getPacketSize(command); cmdid = AJ_BufListCreateNode(2); uint16_t cmd_bind = 0xf08d; memcpy(cmdid->buffer, &cmd_bind, 2); AJ_BufListPushTail(packet, cmdid); WMI_MarshalArgsBuf(packet, signature, size - 2, &args); } else { cmdid = AJ_BufListCreateNode(sizeof(uint16_t)); memcpy(cmdid->buffer, &cmd, sizeof(uint16_t)); AJ_BufListPushTail(packet, cmdid); signature = (char*)getCommandSignature(command); size = getPacketSize(command); WMI_MarshalArgsBuf(packet, signature + 1, size - 2, &args); } } void WMI_MarshalSend(AJ_BufList* packet, uint32_t sock, AJ_BufNode* data, uint16_t size) { WSL_MarshalPacket(packet, WSL_SEND, 0xa0000000, 0x009c0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sock, size); // send and sendto are marshaled differently. There packet structure is not similar to other WMI commands AJ_BufListPushTail(packet, data); WMI_MarshalHeader(packet, 2, 1); packetId++; } void WMI_MarshalSendTo(AJ_BufList* packet, uint32_t sock, AJ_BufNode* data, uint16_t size, uint32_t addr, uint16_t port) { AJ_BufNode* zero23; AJ_BufNode* whereto; whereto = AJ_BufListCreateNode(9); zero23 = AJ_BufListCreateNode(23); memset(zero23->buffer, 0, 23); WSL_MarshalPacket(packet, WSL_SENDTO, 0xa0000000, 0x009c0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sock, size); memcpy(whereto->buffer, &port, 2); memcpy(whereto->buffer + 2, (void*)2, 2); memcpy(whereto->buffer + 4, &addr, 4); memcpy(whereto->buffer + 8, (void*)8, 1); AJ_BufListPushTail(packet, whereto); AJ_BufListPushTail(packet, zero23); AJ_BufListPushTail(packet, data); WMI_MarshalHeader(packet, 2, 1); packetId++; } void WMI_MarshalSendTo6(AJ_BufList* packet, uint32_t sock, AJ_BufNode* data, uint16_t size, uint8_t* addr, uint16_t port) { AJ_BufNode* zero6; zero6 = AJ_BufListCreateNode(6); memset(zero6->buffer, 0, 6); WSL_MarshalPacket(packet, WSL_SENDTO6, 0xa0000000, 0x00bc0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sock, 0x1b, 0, 0, 0, 0, 0, 0, 0, 0x03, port, 0, addr, 0, size + 1); AJ_BufListPushTail(packet, zero6); AJ_BufListPushTail(packet, data); //AJ_BufListPushTail(packet, zero6); WMI_MarshalHeader(packet, 2, 1); packetId++; } ajtcl-16.04/src/wsl/aj_wsl_marshal.h000066400000000000000000000100621271074662300173630ustar00rootroot00000000000000/** * @file Marshaling function declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_MARSHAL_H_ #define AJ_WSL_MARSHAL_H_ #include #include "aj_wsl_wmi.h" #include "aj_wsl_spi_constants.h" #ifdef __cplusplus extern "C" { #endif /** * Marshal a list of arguments into a AJ_BufList. * * @param data The AJ_BufList to contain the marshaled data * @param sig The signature matching the parameters following it * @param ... The arguments that will be marshaled into the AJ_BufList * in the order they appear. * * @return 1 If the data was successfully marshaled * 0 If there was an error */ uint8_t WMI_MarshalArgsBuf(AJ_BufList* data, const char* sig, uint16_t size, va_list* argpp); /** * Marshals the header onto an already existing packet. * * @param data The AJ_BufList already containing the packet data */ void WMI_MarshalHeader(AJ_BufList* packet, uint8_t endpoint, uint8_t flags); /** * Marshals an entire packet to send over SPI * * @param command The command ID you are marshaling * @param AJ_BufList An empty, malloc'ed buffer list to hold the packet data * @param ... The list of arguments to put into the packet. * (note: the list of arguments must match the signature of the * packet you are trying to marshal. This includes, starting with, * the command ID followed by a 32 bit unsigned int (usually 0), * then the arguments for the packet.) * * @return The size of the packet that was marshaled (not including header) * 0 If there was an error */ void WSL_MarshalPacket(AJ_BufList* packet, wsl_wmi_command_list command, ...); /** * Marshal a IPv6 sendTo packet. * * @param packet The buf list where the marshalled data will be stored * @param sock The socket your sending the packet over * @param data Pointer to the data your sending * @param size Size of the data your sending * @param addr Endpoint address your sending to * @param port The port your sending over */ void WMI_MarshalSendTo6(AJ_BufList* packet, uint32_t sock, AJ_BufNode* data, uint16_t size, uint8_t* addr, uint16_t port); /** * Marshal a IPv4 sendTo packet. * * @param packet The buf list where the marshalled data will be stored * @param sock The socket your sending the packet over * @param data Pointer to the data your sending * @param size Size of the data your sending * @param addr Endpoint address your sending to * @param port The port your sending over */ void WMI_MarshalSendTo(AJ_BufList* packet, uint32_t sock, AJ_BufNode* data, uint16_t size, uint32_t addr, uint16_t port); /** * Marshal a IPv4 send packet. * * @param packet The buf list where the marshalled data will be stored * @param sock The socket your sending the packet over * @param data Pointer to the data your sending * @param size Size of the data your sending */ void WMI_MarshalSend(AJ_BufList* packet, uint32_t sock, AJ_BufNode* data, uint16_t size); #ifdef __cplusplus } #endif #endif /* AJ_WSL_MARSHAL_H_ */ ajtcl-16.04/src/wsl/aj_wsl_net.c000066400000000000000000001376611271074662300165340ustar00rootroot00000000000000/** * @file Network functionality implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE WSL_NET #include #include #include #include #include "aj_wsl_target.h" #include "aj_wsl_spi_constants.h" #include "aj_wsl_wmi.h" #include "aj_wsl_htc.h" #include "aj_wsl_net.h" #include "aj_wsl_unmarshal.h" #include "aj_wsl_marshal.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_NET = 0; #endif /* * Timeout for all network calls that don't have an explicit timeout passed in */ #define AJ_NET_TIMEOUT 2000 /* * Maximum timeout for DHCP */ #define AJ_IPCONFIG_TIMEOUT 60000 #define AJ_WSL_AF_INET 2 #define AJ_WSL_TCP 1 #define AJ_WSL_UDP 2 extern uint32_t AJ_WSL_MBOX_BLOCK_SIZE; wsl_socket_context AJ_WSL_SOCKET_CONTEXT[5]; static wsl_scan_list list; static AJ_WiFiScanResult wifiCallback = NULL; static void* wifiContext; static uint8_t maxAPs; void AJ_WSL_RegisterWiFiCallback(void* context, AJ_WiFiScanResult callback) { wifiContext = context; wifiCallback = callback; } void AJ_WSL_UnregisterWiFiCallback(void) { wifiCallback = NULL; } /* * Callback function for BSSINFO packets */ void AJ_WSL_BSSINFO_Recv(AJ_BufNode* node) { wsl_scan_item* item; item = (wsl_scan_item*)WMI_UnmarshalScan(node->bufferStart, node->length); memcpy(&list.items[list.size], item, sizeof(wsl_scan_item)); if (wifiCallback) { wifiCallback(wifiContext, list.items[list.size].ssid, list.items[list.size].bssid, list.items[list.size].rssi, list.items[list.size].secType, list.items[list.size].cipherType); } AJ_WSL_Free(item); list.size++; } void WSL_ClearScanList() { int i; for (i = 0; i < list.size; i++) { AJ_WSL_Free(list.items[i].ssid); } AJ_WSL_Free(list.items); list.size = 0; } wsl_scan_item* WSL_InitScanItem(void) { wsl_scan_item* item; item = (wsl_scan_item*)AJ_WSL_Malloc(sizeof(wsl_scan_item)); return item; } void AJ_WSL_InitScanList(uint8_t maxAP) { maxAPs = maxAP; list.items = AJ_WSL_Malloc(sizeof(wsl_scan_item) * maxAPs); list.size = 0; } wsl_scan_item* AJ_WSL_GetScanList(void) { return (wsl_scan_item*)&list; } int list_compare(const void* a, const void* b) { wsl_scan_item* wsl_a = (wsl_scan_item*)a; wsl_scan_item* wsl_b = (wsl_scan_item*)b; return wsl_b->rssi - wsl_a->rssi; } void WSL_PrintScan(void) { int i; for (i = 0; i < list.size; i++) { AJ_AlwaysPrintf(("%-17.17s ", list.items[i].ssid)); AJ_AlwaysPrintf(("RSSI: %u ", list.items[i].rssi)); AJ_AlwaysPrintf(("BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", list.items[i].bssid[0], list.items[i].bssid[1], list.items[i].bssid[2], list.items[i].bssid[3], list.items[i].bssid[4], list.items[i].bssid[5])); } } void WSL_PrintScanSorted(void) { qsort(&list.items[0], list.size, sizeof(wsl_scan_item), list_compare); WSL_PrintScan(); } void AJ_WSL_WMI_PadPayload(AJ_BufList* bssfilter) { AJ_BufNode* node; uint16_t sizeTail; sizeTail = (AJ_BufListLengthOnWire(bssfilter) % AJ_WSL_MBOX_BLOCK_SIZE); if (sizeTail) { node = AJ_BufListCreateNode(AJ_WSL_MBOX_BLOCK_SIZE - sizeTail); AJ_BufListPushTail(bssfilter, node); } } void AJ_WSL_NET_BSS_FILTER(uint8_t flag) { AJ_InfoPrintf(("AJ_WSL_NET_BSS_FILTER(): SET_BSS_FILTER\n")); AJ_BufList* bssfilter; bssfilter = AJ_BufListCreate(); WSL_MarshalPacket(bssfilter, WSL_SET_BSS_FILTER, 0, flag, 0, 0, 0); WMI_MarshalHeader(bssfilter, 1, 1); AJ_WSL_WMI_PadPayload(bssfilter); AJ_WSL_WMI_QueueWorkItem(0, WSL_SET_BSS_FILTER, AJ_WSL_HTC_DATA_ENDPOINT1, bssfilter); } void AJ_WSL_SetProbedSSID(const char* ssid, uint8_t flag) { AJ_BufList* probed_ssid; probed_ssid = AJ_BufListCreate(); WSL_MarshalPacket(probed_ssid, WSL_SET_PROBED_SSID, 0, 0, flag, strlen(ssid), ssid); WMI_MarshalHeader(probed_ssid, 1, 1); AJ_WSL_WMI_PadPayload(probed_ssid); AJ_WSL_WMI_QueueWorkItem(0, WSL_SET_PROBED_SSID, AJ_WSL_HTC_DATA_ENDPOINT1, probed_ssid); } void AJ_WSL_NET_add_cipher_key(uint8_t keyIndex, uint8_t* key, uint8_t keyLength) { AJ_BufList* add_key; add_key = AJ_BufListCreate(); static const uint8_t zero_mac[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; WSL_MarshalPacket(add_key, WSL_ADD_CIPHER_KEY, 0, 0, 0x02, 0x03, keyLength, 0, 0, key, 0x03, &zero_mac); WMI_MarshalHeader(add_key, 1, 1); AJ_WSL_WMI_PadPayload(add_key); AJ_WSL_WMI_QueueWorkItem(0, WSL_ADD_CIPHER_KEY, AJ_WSL_HTC_DATA_ENDPOINT1, add_key); } void AJ_WSL_NET_set_scan_params(void) { AJ_BufList* packet; AJ_InfoPrintf(("AJ_WSL_NET_scan(): SET_SCAN_PARAMS\n")); packet = AJ_BufListCreate(); WSL_MarshalPacket(packet, WSL_SET_SCAN_PARAMS, 0, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x0000, 0x2f03, 0x00000000); WMI_MarshalHeader(packet, 1, 1); AJ_WSL_WMI_PadPayload(packet); AJ_WSL_WMI_QueueWorkItem(0, WSL_SET_SCAN_PARAMS, AJ_WSL_HTC_DATA_ENDPOINT1, packet); } AJ_Status AJ_WSL_NET_scan(void) { AJ_Status status; AJ_BufList* start_scan; wsl_work_item* item; AJ_WSL_NET_BSS_FILTER(1); AJ_WSL_NET_set_scan_params(); AJ_InfoPrintf((("AJ_WSL_NET_scan(): START_SCAN\n"))); start_scan = AJ_BufListCreate(); WSL_MarshalPacket(start_scan, WSL_START_SCAN, 0, 0, 0, 0, 0, 0, 0, 0); WMI_MarshalHeader(start_scan, 1, 1); AJ_WSL_WMI_PadPayload(start_scan); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_NET_SCAN), AJ_WSL_HTC_DATA_ENDPOINT1, start_scan); status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_NET_SCAN), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { if (item->itemType == WSL_NET_SCAN) { AJ_InfoPrintf(("AJ_WSL_NET_scan(): WORK ITEM RECEIVED\n")); uint16_t WMIEvent; uint32_t toss; uint32_t error; WMI_Unmarshal(item->node->buffer, "quu", &WMIEvent, &toss, &error); if (error != 0) { AJ_ErrPrintf(("AJ_WSL_NET_scan(): Scan error, scan returned: %u", error)); status = AJ_ERR_INVALID; } } else { AJ_WarnPrintf(("AJ_WSL_NET_scan(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } return status; } void AJ_WSL_NET_scan_stop(void) { AJ_InfoPrintf(("AJ_WSL_NET_scan_stop(): SET_BSS_FILTER\n")); AJ_WSL_NET_BSS_FILTER(0); } AJ_Status AJ_WSL_NET_SetPassphrase(const char* SSID, const char* passphrase, uint32_t passLen) { AJ_Status status = AJ_OK; AJ_BufList* passphraseList; passphraseList = AJ_BufListCreate(); uint8_t* hexPassphrase = NULL; if (passLen == 64) { hexPassphrase = (uint8_t*)AJ_WSL_Malloc(32); status = AJ_HexToRaw(passphrase, 64, hexPassphrase, 32); if (status == AJ_OK) { WSL_MarshalPacket(passphraseList, WMI_SET_PMK, 0, hexPassphrase, 32); } } else { WSL_MarshalPacket(passphraseList, WSL_SET_PASSPHRASE, 0, SSID, passphrase, strlen(SSID), passLen); } if (status == AJ_OK) { WMI_MarshalHeader(passphraseList, 1, 1); AJ_InfoPrintf(("AJ_WSL_NET_SetPassphrase(): SET_PASSPHRASE\n")); AJ_WSL_WMI_PadPayload(passphraseList); //AJ_BufListPrintDumpContinuous(passphraseList); status = AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_SET_PASSPHRASE), AJ_WSL_HTC_DATA_ENDPOINT1, passphraseList); } if (hexPassphrase != NULL) { AJ_MemZeroSecure(hexPassphrase, 32); AJ_WSL_Free(hexPassphrase); } return status; } AJ_Status AJ_WSL_NET_SetHiddenAP(uint8_t hidden) { AJ_Status status; AJ_BufList* hiddenList; hiddenList = AJ_BufListCreate(); WSL_MarshalPacket(hiddenList, WSL_SET_HIDDEN_AP, 0, hidden); WMI_MarshalHeader(hiddenList, 1, 1); AJ_InfoPrintf(("AJ_WSL_NET_SetHiddenAP(): AP_HIDDEN_SSID\n")); AJ_WSL_WMI_PadPayload(hiddenList); //AJ_BufListPrintDumpContinuous(passphraseList); status = AJ_WSL_WMI_QueueWorkItem(0, WSL_SET_HIDDEN_AP, AJ_WSL_HTC_DATA_ENDPOINT1, hiddenList); return status; } AJ_Status AJ_WSL_NET_SetPowerMode(uint8_t mode) { AJ_Status status; AJ_BufList* power_mode; power_mode = AJ_BufListCreate(); WSL_MarshalPacket(power_mode, WSL_SET_POWER_MODE, 0, mode); WMI_MarshalHeader(power_mode, 1, 1); AJ_WSL_WMI_PadPayload(power_mode); //AJ_BufListPrintDumpContinuous(power_mode); status = AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_SET_POWER_MODE), AJ_WSL_HTC_DATA_ENDPOINT1, power_mode); return status; } void AJ_WSL_NET_StackInit(void) { AJ_InfoPrintf(("AJ_WSL_NET_StackInit(): STACK_INIT\n")); AJ_BufList* stack_init; stack_init = AJ_BufListCreate(); WSL_MarshalPacket(stack_init, WSL_SOCKET, WSL_SOCK_STACK_INIT, 0x04, 0x01, 0x05, 0x08, 0x1f); WMI_MarshalHeader(stack_init, 1, 1); AJ_WSL_WMI_PadPayload(stack_init); //AJ_BufListPrintDumpContinuous(stack_init); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_STACK_INIT), AJ_WSL_HTC_DATA_ENDPOINT1, stack_init); } /* * Get an AP's mac address from a SSID scan list */ static uint8_t getMacFromSSID(const char* ssid, uint8_t* mac, wsl_scan_list* list) { int i; for (i = 0; i < list->size; i++) { if (0 == strcmp(list->items[i].ssid, ssid)) { memcpy(mac, list->items[i].bssid, 6); return 1; } } return 0; } #define AJ_WSL_CONNECT_WAIT 500 #define AJ_WSL_CONNECT_TIMEOUT 20000 AJ_EXPORT AJ_Status AJ_WSL_NET_connect(const char* SSID, const char* passphrase, WSL_NET_AUTH_MODE auth, WSL_NET_CRYPTO_TYPE crypto, uint8_t softAP) { AJ_Status status = AJ_OK; wsl_scan_list* list; list = (wsl_scan_list*)AJ_WSL_GetScanList(); AJ_WSL_NET_SetPowerMode(2); uint8_t bss_mac[6]; // Open auth does not require you to explicitly set the BSSID so this secondary scan is not needed if (!softAP) { if (auth != WSL_NET_AUTH_NONE) { AJ_Time timer; uint8_t found = 0; AJ_InitTimer(&timer); while (!found) { AJ_WSL_InitScanList(AJ_WSL_SCAN_LIST_SIZE); AJ_WSL_SetProbedSSID(SSID, 1); status = AJ_WSL_NET_scan(); // Some kind of scan error if (status != AJ_OK) { WSL_ClearScanList(); continue; } AJ_WSL_NET_scan_stop(); if (AJ_GetElapsedTime(&timer, TRUE) > AJ_WSL_CONNECT_TIMEOUT) { AJ_ErrPrintf(("AJ_WSL_NET_connect() Could not find the access point %s\n", SSID)); WSL_ClearScanList(); return AJ_ERR_FAILURE; } // Find the SSID you want to connect to in the second scan list if (getMacFromSSID(SSID, bss_mac, list)) { WSL_ClearScanList(); found = 1; break; } else { WSL_ClearScanList(); AJ_Sleep(AJ_WSL_CONNECT_WAIT); continue; } } if (crypto != WSL_NET_CRYPTO_WEP) { status = AJ_WSL_NET_SetPassphrase(SSID, passphrase, strlen(passphrase)); if (status != AJ_OK) { return status; } } } } { AJ_BufList* connect; AJ_BufList* connectOut; static const uint8_t zero_mac[6] = { 0, 0, 0, 0, 0, 0 }; uint8_t connect_mac[6]; wsl_work_item* item = NULL; connect = AJ_BufListCreate(); /* Three different ways connect can be called. * 1. SoftAP: The devices mac is fetched and used * 2. Using Auth: The SSID's mac is found and used * 3. Open auth: A zero'ed mac is used */ if (softAP) { WSL_MarshalPacket(connect, WSL_SET_SOFT_AP, 0, 0x04, 0x01, auth, crypto, 0x00, crypto, 0x00, strlen(SSID), SSID, 0x0, getDeviceMac(), 0x0044, 0x0000); WMI_MarshalHeader(connect, 1, 1); } else if ((auth != WSL_NET_AUTH_NONE) && (crypto != WSL_NET_CRYPTO_WEP)) { WSL_MarshalPacket(connect, WSL_CONNECT, 0, 0x01, 0x01, auth, crypto, 0x00, crypto, 0x00, strlen(SSID), SSID, 0x0, &bss_mac, 0x0044, 0x0000); WMI_MarshalHeader(connect, 1, 1); } else { // if the auth mode is open, use zero_mac, and set flags to zero WSL_MarshalPacket(connect, WSL_CONNECT, 0, 0x01, 0x01, auth, crypto, 0x00, crypto, 0x00, strlen(SSID), SSID, 0x0, &zero_mac, 0x0000, 0x0000); WMI_MarshalHeader(connect, 1, 1); } AJ_InfoPrintf(("AJ_WSL_NET_connect(): CONNECT\n")); AJ_WSL_WMI_PadPayload(connect); //AJ_BufListPrintDumpContinuous(connect); connectOut = AJ_BufListCreateCopy(connect); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_NET_CONNECT), AJ_WSL_HTC_DATA_ENDPOINT1, connectOut); if (softAP) { AJ_AlwaysPrintf(("Waiting for a connection to the softAP %s\n", SSID)); memcpy(&connect_mac, (uint8_t*)getDeviceMac(), sizeof(connect_mac)); while (memcmp((uint8_t*)&connect_mac, (uint8_t*)getDeviceMac(), 6) == 0) { status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_NET_CONNECT), &item, AJ_TIMER_FOREVER); if (item && (status == AJ_OK)) { if (item->itemType == WSL_NET_CONNECT) { AJ_InfoPrintf(("AJ_WSL_NET_connect(): WORK ITEM RECEIVED\n")); uint16_t WMIEvent; uint32_t toss; uint16_t channel; WMI_Unmarshal(item->node->buffer, "quqM", &WMIEvent, &toss, &channel, &connect_mac); } else { AJ_WarnPrintf(("AJ_WSL_NET_connect(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } } else { status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_NET_CONNECT), &item, AJ_TIMER_FOREVER); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } } AJ_BufListFree(connect, 1); return status; } } void AJ_WSL_PrintIP(uint32_t ip) { uint8_t* ptr; ptr = (uint8_t*)&ip; AJ_AlwaysPrintf(("%i.%i.%i.%i\n", *(ptr + 3), *(ptr + 2), *(ptr + 1), *(ptr))); } AJ_Status AJ_WSL_ip6config(uint32_t mode, uint8_t* globalAddr, uint8_t* localAddr, uint8_t* gateway, uint8_t* exAddr, uint32_t linkPrefix, uint32_t globalPrefix, uint32_t gwPrefix, uint32_t glbPrefixExt) { AJ_Status status; if (mode != IPCONFIG_QUERY) { AJ_ErrPrintf(("AJ_WSL_ip6config(): Can only query IPV6, cannot use mode %lu\n", mode)); return AJ_ERR_UNEXPECTED; } AJ_BufList* ip6config; ip6config = AJ_BufListCreate(); //First zeros are for v4 WSL_MarshalPacket(ip6config, WSL_SOCKET, WSL_SOCK_IP6CONFIG, 0x60, 0, 0, 0, 0, globalAddr, localAddr, gateway, exAddr, linkPrefix, globalPrefix, gwPrefix, glbPrefixExt); WMI_MarshalHeader(ip6config, 1, 1); AJ_WSL_WMI_PadPayload(ip6config); //AJ_BufListPrintDumpContinuous(ip6config); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IP6CONFIG), AJ_WSL_HTC_DATA_ENDPOINT1, ip6config); { wsl_work_item* item = NULL; status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IP6CONFIG), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IP6CONFIG)) { AJ_InfoPrintf(("AJ_WSL_ip6config(): WORK ITEM RECEIVED\n")); uint16_t WMIEvent; uint32_t reserved; uint32_t _command; uint32_t _handle; uint32_t _error; uint32_t _mode; uint32_t _ipv4 = 0; uint32_t _ipv4mask = 0; uint32_t _ipv4gateway = 0; WMI_Unmarshal(item->node->buffer, "quuuuuuuu6666uuuu", &WMIEvent, &reserved, &_command, &_handle, &_error, &_mode, &_ipv4, &_ipv4mask, &_ipv4gateway, localAddr, globalAddr, gateway, exAddr, &linkPrefix, &globalPrefix, &gwPrefix, &glbPrefixExt); //AJ_DumpBytes("IPV6", item->node->buffer, 0x60); } else { AJ_WarnPrintf(("AJ_WSL_ip6config(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } return status; } AJ_Status AJ_WSL_ipconfig(uint32_t mode, uint32_t* ip, uint32_t* mask, uint32_t* gateway) { AJ_Status status = AJ_ERR_DHCP; uint16_t ipv6[8] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; wsl_work_item* item = NULL; switch (mode) { case (IPCONFIG_QUERY): { AJ_InfoPrintf(("AJ_WSL_ipconfig(): IPCONFIG_QUERY\n")); AJ_BufList* ipconfig; ipconfig = AJ_BufListCreate(); WSL_MarshalPacket(ipconfig, WSL_SOCKET, WSL_SOCK_IPCONFIG, 0x60, 0, ip, mask, gateway, &ipv6, &ipv6, &ipv6, &ipv6, 0, 0, 0, 0); WMI_MarshalHeader(ipconfig, 1, 1); AJ_WSL_WMI_PadPayload(ipconfig); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IPCONFIG), AJ_WSL_HTC_DATA_ENDPOINT1, ipconfig); { status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IPCONFIG), &item, AJ_IPCONFIG_TIMEOUT); if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IPCONFIG)) { AJ_InfoPrintf(("AJ_WSL_ipconfig(): WORK ITEM RECEIVED\n")); uint16_t WMIEvent; uint32_t reserved; uint32_t _command; uint32_t _handle; uint32_t _error; uint32_t _mode; WMI_Unmarshal(item->node->buffer, "quuuuuuuu", &WMIEvent, &reserved, &_command, &_handle, &_error, &_mode, ip, mask, gateway); if (ip != 0) { status = AJ_OK; } } else { AJ_WarnPrintf(("AJ_WSL_ipconfig(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } } break; case (IPCONFIG_STATIC): AJ_InfoPrintf(("AJ_WSL_ipconfig(): IPCONFIG_STATIC\n")); AJ_BufList* ipconfig_dhcp_static; ipconfig_dhcp_static = AJ_BufListCreate(); WSL_MarshalPacket(ipconfig_dhcp_static, WSL_SOCKET, WSL_SOCK_IPCONFIG, 0x60, 1, ip, mask, gateway, &ipv6, &ipv6, &ipv6, &ipv6, 0, 0, 0, 0); WMI_MarshalHeader(ipconfig_dhcp_static, 1, 1); AJ_WSL_WMI_PadPayload(ipconfig_dhcp_static); //AJ_BufListPrintDumpContinuous(ipconfig_dhcp_static); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IPCONFIG), AJ_WSL_HTC_DATA_ENDPOINT1, ipconfig_dhcp_static); status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IPCONFIG), &item, AJ_IPCONFIG_TIMEOUT); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } AJ_Sleep(1000); break; case (IPCONFIG_DHCP): AJ_InfoPrintf(("AJ_WSL_ipconfig(): IPCONFIG_DHCP\n")); AJ_BufList* ipconfig_dhcp; ipconfig_dhcp = AJ_BufListCreate(); WSL_MarshalPacket(ipconfig_dhcp, WSL_SOCKET, WSL_SOCK_IPCONFIG, 0x60, 2, ip, mask, gateway, &ipv6, &ipv6, &ipv6, &ipv6, 0, 0, 0, 0); WMI_MarshalHeader(ipconfig_dhcp, 1, 1); AJ_WSL_WMI_PadPayload(ipconfig_dhcp); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IPCONFIG), AJ_WSL_HTC_DATA_ENDPOINT1, ipconfig_dhcp); status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IPCONFIG), &item, AJ_IPCONFIG_TIMEOUT); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } AJ_Sleep(100); break; } return status; } #define DHCP_WAIT 100 /* * create the WMI request to open a socket on the target device */ int8_t AJ_WSL_NET_socket_open(uint16_t domain, uint16_t type, uint16_t protocol) { AJ_Status status; int8_t handle = INVALID_SOCKET; AJ_BufList* open; open = AJ_BufListCreate(); WSL_MarshalPacket(open, WSL_SOCKET, WSL_SOCK_OPEN, 0x0c, domain, type, protocol); WMI_MarshalHeader(open, 1, 1); AJ_WSL_WMI_PadPayload(open); //AJ_BufListPrintDumpContinuous(open); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_OPEN), AJ_WSL_HTC_DATA_ENDPOINT1, open); // wait until the command completes { wsl_work_item* item = NULL; status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_OPEN), &item, AJ_NET_TIMEOUT); if (status != AJ_OK) { //AJ_WSL_WMI_FreeWorkItem(item); return -1; } if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_OPEN)) { AJ_InfoPrintf(("AJ_WSL_NET_socket_open(): WORK ITEM RECEIVED\n")); uint16_t WMIEvent; uint32_t reserved; uint32_t _command; uint32_t _handle; uint32_t _error; uint32_t _mode; WMI_Unmarshal(item->node->buffer, "quuuuu", &WMIEvent, &reserved, &_command, &_handle, &_error, &_mode); AJ_InfoPrintf((" Socket Open: handle %08lx error %08lx\n", _handle, _error)); handle = AJ_WSL_FindOpenSocketContext(); if (handle != INVALID_SOCKET) { AJ_WSL_SOCKET_CONTEXT[handle].targetHandle = _handle; AJ_WSL_SOCKET_CONTEXT[handle].valid = TRUE; AJ_WSL_SOCKET_CONTEXT[handle].domain = domain; AJ_WSL_SOCKET_CONTEXT[handle].type = type; AJ_WSL_SOCKET_CONTEXT[handle].protocol = protocol; } } else { AJ_WarnPrintf(("AJ_WSL_NET_socket_open(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } AJ_Sleep(100); return handle; } /* * create the WMI request to close a socket on the target device */ AJ_Status AJ_WSL_NET_socket_close(AJ_WSL_SOCKNUM sock) { AJ_Status status; AJ_BufList* close; if (AJ_WSL_SOCKET_CONTEXT[sock].valid == TRUE) { close = AJ_BufListCreate(); WSL_MarshalPacket(close, WSL_SOCKET, WSL_SOCK_CLOSE, 0x0, AJ_WSL_SOCKET_CONTEXT[sock].targetHandle); WMI_MarshalHeader(close, 1, 1); AJ_WSL_WMI_PadPayload(close); //AJ_BufListPrintDumpContinuous(close); AJ_WSL_WMI_QueueWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CLOSE), AJ_WSL_HTC_DATA_ENDPOINT1, close); // wait until the command completes do { wsl_work_item* item = NULL; status = AJ_WSL_WMI_WaitForWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CLOSE), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CLOSE)) { AJ_InfoPrintf(("AJ_WSL_NET_socket_close(): WORK ITEM RECEIVED\n")); uint16_t WMIEvent; uint32_t reserved; uint32_t _command; uint32_t _handle; uint32_t _error; uint32_t _mode; WMI_Unmarshal(item->node->buffer, "quuuuu", &WMIEvent, &reserved, &_command, &_handle, &_error, &_mode); AJ_InfoPrintf((" Socket close: handle %08lx error %08lx\n", _handle, _error)); if (_handle == AJ_WSL_SOCKET_CONTEXT[sock].targetHandle) { AJ_WSL_SOCKET_CONTEXT[sock].targetHandle = UINT32_MAX; AJ_WSL_SOCKET_CONTEXT[sock].valid = FALSE; } AJ_WSL_WMI_FreeWorkItem(item); break; // waited until close command completed } else { AJ_InfoPrintf(("AJ_WSL_NET_socket_close(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } while (1); } return status; } /* * create the WMI request to bind a socket on the target device to an address and port */ AJ_Status AJ_WSL_NET_socket_bind(AJ_WSL_SOCKNUM sock, uint32_t addr, uint16_t port) { AJ_Status status; AJ_BufList* bind; wsl_work_item* item; bind = AJ_BufListCreate(); WSL_MarshalPacket(bind, WSL_SOCKET, WSL_SOCK_BIND, 0x0, AJ_WSL_SOCKET_CONTEXT[sock].targetHandle, port, AJ_WSL_UDP, &addr, 0x8); WMI_MarshalHeader(bind, 1, 1); AJ_WSL_WMI_PadPayload(bind); //AJ_BufListPrintDumpContinuous(bind); AJ_WSL_WMI_QueueWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_BIND), AJ_WSL_HTC_DATA_ENDPOINT1, bind); status = AJ_WSL_WMI_WaitForWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_BIND), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } return status; } AJ_Status AJ_WSL_NET_socket_bind6(AJ_WSL_SOCKNUM sock, uint8_t* addr, uint16_t port) { AJ_Status status; AJ_BufList* bind; wsl_work_item* item; bind = AJ_BufListCreate(); WSL_MarshalPacket(bind, WSL_BIND6, 0x0, 0x03, 0x24, AJ_WSL_SOCKET_CONTEXT[sock].targetHandle, 0x00, port, addr, 0x00, 0x00020383, 0x0002001c); WMI_MarshalHeader(bind, 1, 1); AJ_WSL_WMI_PadPayload(bind); //AJ_BufListPrintDumpContinuous(bind); AJ_WSL_WMI_QueueWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_BIND), AJ_WSL_HTC_DATA_ENDPOINT1, bind); status = AJ_WSL_WMI_WaitForWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_BIND), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } return status; } /* * create the WMI request to connect to a socket */ AJ_Status AJ_WSL_NET_socket_connect(AJ_WSL_SOCKNUM sock, uint32_t addr, uint16_t port, uint16_t family) { AJ_Status status; AJ_BufList* connectV4; wsl_work_item* item = NULL; connectV4 = AJ_BufListCreate(); WSL_MarshalPacket(connectV4, WSL_SOCKET, WSL_SOCK_CONNECT, 0x0, AJ_WSL_SOCKET_CONTEXT[sock].targetHandle, port, family, &addr, 0x8); WMI_MarshalHeader(connectV4, 1, 1); AJ_WSL_WMI_PadPayload(connectV4); //AJ_BufListPrintDumpContinuous(connectV4); AJ_WSL_WMI_QueueWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CONNECT), AJ_WSL_HTC_DATA_ENDPOINT1, connectV4); do { status = AJ_WSL_WMI_WaitForWorkItem(sock, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CONNECT), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CONNECT)) { AJ_InfoPrintf(("AJ_WSL_NET_socket_connect(): WORK ITEM RECEIVED\n")); AJ_WSL_WMI_FreeWorkItem(item); break; } else { AJ_WarnPrintf(("AJ_WSL_NET_socket_connect(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } while (1); return status; } /* * Poll over a socket until there is data ready or till a timeout * * Returns -2 on timeout * -1 on interrupted * 1 on success * 0 on close * */ int16_t AJ_WSL_NET_socket_select(AJ_WSL_SOCKNUM sock, uint32_t timeout) { AJ_Time timer; wsl_work_item* peek; AJ_Status status; int16_t ret = 0; // Check if the socket is valid if ((sock >= AJ_WSL_SOCKET_MAX) || (sock < 0)) { // tried to get data from an invalid socket, return an error return ret; } if (AJ_WSL_SOCKET_CONTEXT[sock].valid == FALSE) { // tried to get data from an invalid socket, return the data read from the stash AJ_BufListFree(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList, 1); AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList = AJ_BufListCreate(); //flush the queue return ret; } AJ_InitTimer(&timer); // There are 5 conditions that we need to check for // 1. If we got an interrupted work item // 2. If there is data in the RX stash // 3. If there is a RX work item in the queue // 4. If there is a socket close work item in the queue // 5. If the timeout has expired while (1) { status = AJ_QueuePeek(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &peek); //AJ_AlwaysPrintf(("Item type = %u\n", peek->itemType)); if ((status == AJ_OK) && (peek->itemType == WSL_NET_INTERUPT)) { // Pull the interrupted item off because we dont need it anymore status = AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &peek, 0); if (peek && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(peek); } ret = -1; break; } else if (AJ_BufListLengthOnWire(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList) > 0) { ret = 1; break; } else if ((status == AJ_OK) && (peek->itemType == WSL_NET_DATA_RX)) { ret = 1; break; } else if ((status == AJ_OK) && (peek->itemType == WSL_NET_CLOSE || peek->itemType == WSL_NET_DISCONNECT || peek->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CLOSE))) { wsl_work_item* clear; // Pull the close work item off the queue AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &peek, 0); // Socket was closed so tear down the connections AJ_WSL_SOCKET_CONTEXT[sock].valid = FALSE; // Removed any stashed data AJ_BufListFree(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList, 1); // Reallocate a new stash AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList = AJ_BufListCreate(); // Reset the queue, any work items are now invalid since the socket was closed while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workTxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue); AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[sock].workTxQueue); AJ_WSL_WMI_FreeWorkItem(peek); ret = 0; break; } else if (AJ_GetElapsedTime(&timer, TRUE) >= timeout) { ret = -2; break; } } return ret; } void AJ_WSL_NET_signal_interrupted(AJ_WSL_SOCKNUM sock) { wsl_work_item* item = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); item->itemType = WSL_NET_INTERUPT; item->sequenceNumber = 0; item->list = NULL; item->node = NULL; item->size = 0; item->endpoint = 0; if (AJ_WSL_SOCKET_CONTEXT[sock].valid == FALSE) { return; } // Push the interrupted work item to the front of the RX queue AJ_QueuePushFromISR(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &item); } /************************************************************************/ /* there isn't a command to recv....you have to grab data as it comes....*/ /************************************************************************/ /* * create the WMI request to bind a socket on the target device to an address and port */ int16_t AJ_WSL_NET_socket_recv(AJ_WSL_SOCKNUM sock, uint8_t* buffer, uint32_t sizeBuffer, uint32_t timeout) { // AJ_InfoPrintf(("AJ_WSL_NET_socket_recv()\n")); int16_t ret = -1; uint32_t rx = sizeBuffer; uint32_t stash = 0; // read from stash first. uint16_t stashLength; if ((sock >= AJ_WSL_SOCKET_MAX) || (sock < 0)) { // tried to get data from an invalid socket, return an error return ret; } if (AJ_WSL_SOCKET_CONTEXT[sock].valid == FALSE) { wsl_work_item* clear; // tried to get data from an invalid socket, return the data read from the stash AJ_BufListFree(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList, 1); AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList = AJ_BufListCreate(); //flush the queue while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue); return ret; } if (AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList) { stashLength = AJ_BufListLengthOnWire(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList); if (stashLength != 0) { stash = min(rx, stashLength); AJ_BufListCopyBytes(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList, stash, buffer); AJ_BufListPullBytes(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList, stash); // shift left-overs toward the start. ret = stash; sizeBuffer -= stash; } } // wait until there is data if (sizeBuffer) { wsl_work_item* item = NULL; AJ_Status status; // the stash was depleted and you want more data if (AJ_WSL_SOCKET_CONTEXT[sock].valid == FALSE) { // tried to get data from an invalid socket, return the data read from the stash return ret; } status = AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &item, timeout); if (item && (status == AJ_OK)) { if (item->itemType == WSL_NET_INTERUPT) { // At this point we dont care about the interrupted signal but we are expecting a RX packet // so we need to pull the next item off the queue AJ_WSL_WMI_FreeWorkItem(item); status = AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &item, timeout); } if ((status == AJ_OK) && (item->itemType == WSL_NET_DISCONNECT)) { AJ_InfoPrintf(("Disconnect received\n")); // Clean up the network queues int i; for (i = 0; i < AJ_WSL_SOCKET_MAX; i++) { wsl_work_item* clear; AJ_WSL_SOCKET_CONTEXT[i].valid = FALSE; // Removed any stashed data AJ_BufListFree(AJ_WSL_SOCKET_CONTEXT[i].stashedRxList, 1); // Reallocate a new stash AJ_WSL_SOCKET_CONTEXT[i].stashedRxList = AJ_BufListCreate(); // Reset the queue, any work items are now invalid since the socket was closed while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workRxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[i].workRxQueue); AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue); } ret = -1; } else if ((status == AJ_OK) && (item->itemType == WSL_NET_CLOSE || item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CLOSE))) { wsl_work_item* clear; // Pull the close work item off the queue AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &item, 0); // Socket was closed so tear down the connections AJ_WSL_SOCKET_CONTEXT[sock].valid = FALSE; // Removed any stashed data AJ_BufListFree(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList, 1); // Reallocate a new stash AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList = AJ_BufListCreate(); // Reset the queue, any work items are now invalid since the socket was closed while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[sock].workTxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[sock].workRxQueue); AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[sock].workTxQueue); ret = -1; } else if ((status == AJ_OK) && (item->itemType == WSL_NET_DATA_RX)) { //AJ_InfoPrintf(("=====DATA RX ITEM RECEIVED=====\n")); //AJ_DumpBytes("DATA RX ITEM", item->node->buffer, item->size); rx = min(sizeBuffer, item->size); memcpy(buffer + stash, item->node->buffer, rx); AJ_BufNodePullBytes(item->node, rx); // check node: if not empty assign to stash. if (item->node->length) { AJ_BufListPushTail(AJ_WSL_SOCKET_CONTEXT[sock].stashedRxList, item->node); item->node = NULL; } ret = rx + stash; } else { AJ_InfoPrintf(("AJ_WSL_NET_socket_recv(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } else { ret = 0; AJ_InfoPrintf(("socket_recv timed out\n")); } } return ret; } int16_t AJ_WSL_NET_socket_send(uint32_t socket, uint8_t* data, uint16_t size, uint32_t timeout) { AJ_Status status; AJ_InfoPrintf(("AJ_WSL_NET_socket_send()\n")); AJ_BufList* send; AJ_BufNode* tx_data_node; if (AJ_WSL_SOCKET_CONTEXT[socket].valid == FALSE) { AJ_InfoPrintf(("send on invalid socket %lu\n", socket)); return -1; } send = AJ_BufListCreate(); tx_data_node = AJ_BufListCreateNodeExternalZero(data, size, FALSE); WMI_MarshalSend(send, AJ_WSL_SOCKET_CONTEXT[socket].targetHandle, tx_data_node, size); //send now contains the header info for the two part packet your sending //now write send to the MBOX then the data your sending AJ_WSL_WMI_PadPayload(send); AJ_WSL_WMI_QueueWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX), AJ_WSL_HTC_DATA_ENDPOINT2, send); /* * Because these are blocking sends, we need to wait until the data has been passed to the target. */ do { wsl_work_item* item = NULL; status = AJ_WSL_WMI_WaitForWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX), &item, timeout); if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX)) { AJ_InfoPrintf(("AJ_WSL_NET_socket_send(): WORK ITEM RECEIVED\n")); AJ_WSL_WMI_FreeWorkItem(item); break; } else { AJ_WarnPrintf(("AJ_WSL_NET_socket_send(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } while (1); return size; } int16_t AJ_WSL_NET_socket_sendto6(uint32_t socket, uint8_t* data, uint16_t size, uint8_t* addr, uint16_t port, uint32_t timeout) { AJ_Status status; AJ_InfoPrintf(("AJ_WSL_NET_socket_sendto()\n")); AJ_BufList* send; AJ_BufNode* tx_data_node; if (AJ_WSL_SOCKET_CONTEXT[socket].valid == FALSE) { AJ_InfoPrintf(("sendto on invalid socket %ld\n", socket)); return -1; } send = AJ_BufListCreate(); tx_data_node = AJ_BufListCreateNodeExternalZero(data, size, FALSE); WMI_MarshalSendTo6(send, AJ_WSL_SOCKET_CONTEXT[socket].targetHandle, tx_data_node, size, addr, port); //send now contains the header info for the two part packet your sending //now write send to the MBOX then the data your sending AJ_WSL_WMI_PadPayload(send); //AJ_BufListPrintDumpContinuous(send); AJ_WSL_WMI_QueueWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX), AJ_WSL_HTC_DATA_ENDPOINT2, send); wsl_work_item* item = NULL; /* * Because these are blocking sends, we need to wait until the data has been passed to the target. */ do { status = AJ_WSL_WMI_WaitForWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX), &item, timeout); if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX)) { AJ_InfoPrintf(("AJ_WSL_NET_socket_send(): WORK ITEM RECEIVED\n")); AJ_WSL_WMI_FreeWorkItem(item); break; } else { AJ_InfoPrintf(("AJ_WSL_NET_socket_sendto(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } while (1); return size; } int16_t AJ_WSL_NET_socket_sendto(uint32_t socket, uint8_t* data, uint16_t size, uint32_t addr, uint16_t port, uint32_t timeout) { AJ_Status status; AJ_InfoPrintf(("AJ_WSL_NET_socket_sendto()\n")); AJ_BufList* send; AJ_BufNode* tx_data_node; if (AJ_WSL_SOCKET_CONTEXT[socket].valid == FALSE) { AJ_InfoPrintf(("sendto on invalid socket %ld\n", socket)); return -1; } send = AJ_BufListCreate(); tx_data_node = AJ_BufListCreateNodeExternalZero(data, size, FALSE); WMI_MarshalSendTo(send, AJ_WSL_SOCKET_CONTEXT[socket].targetHandle, tx_data_node, size, AJ_ByteSwap32(addr), port); //send now contains the header info for the two part packet your sending //now write send to the MBOX then the data your sending AJ_WSL_WMI_PadPayload(send); AJ_WSL_WMI_QueueWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX), AJ_WSL_HTC_DATA_ENDPOINT2, send); wsl_work_item* item = NULL; /* * Because these are blocking sends, we need to wait until the data has been passed to the target. */ do { status = AJ_WSL_WMI_WaitForWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX), &item, timeout); if (item && (status == AJ_OK)) { if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX)) { AJ_InfoPrintf(("AJ_WSL_NET_socket_send(): WORK ITEM RECEIVED\n")); AJ_WSL_WMI_FreeWorkItem(item); break; } else { AJ_InfoPrintf(("AJ_WSL_NET_socket_sendto(): BAD WORK ITEM RECEIVED\n")); } AJ_WSL_WMI_FreeWorkItem(item); } } while (1); return size; } #define AJ_SOCK_OPTS_OFFSET 19 AJ_Status AJ_WSL_NET_set_sock_options(uint32_t socket, uint32_t level, uint32_t optname, uint32_t optlen, uint8_t* optval) { AJ_Status status; AJ_InfoPrintf(("AJ_WSL_NET_set_sock_options()\n")); wsl_work_item* item; AJ_BufList* opts; AJ_BufNode* trailer; uint32_t total_length; opts = AJ_BufListCreate(); total_length = AJ_SOCK_OPTS_OFFSET + optlen; WSL_MarshalPacket(opts, WSL_SOCKET, WSL_SOCK_SETSOCKOPT, total_length, AJ_WSL_SOCKET_CONTEXT[socket].targetHandle, level, optname, optlen); if (optname == WSL_JOIN_GROUP) { trailer = AJ_BufListCreateNode((optlen / 2) + 2); memcpy(opts->tail->buffer + opts->tail->length - 17, optval, (optlen / 2) + 1); memcpy(trailer->buffer, optval + 17, 15); } else { trailer = AJ_BufListCreateNode(optlen + 3); memset(trailer->buffer, 0, optlen + 3); } AJ_BufListPushTail(opts, trailer); WMI_MarshalHeader(opts, 1, 1); //AJ_BufListPrintDumpContinuous(opts); AJ_WSL_WMI_QueueWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_SETSOCKOPT), AJ_WSL_HTC_DATA_ENDPOINT1, opts); // wait until the command completes status = AJ_WSL_WMI_WaitForWorkItem(socket, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_SETSOCKOPT), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } return status; } AJ_Status AJ_WSL_NET_set_hostname(const char* hostname) { AJ_Status status; AJ_InfoPrintf(("===== SET HOSTNAME ====\n")); wsl_work_item* item; AJ_BufList* host; host = AJ_BufListCreate(); WSL_MarshalPacket(host, WSL_SOCKET, WSL_SOCK_IP_HOST_NAME, 0x21, hostname); WMI_MarshalHeader(host, 1, 1); AJ_WSL_WMI_PadPayload(host); //AJ_BufListPrintDumpContinuous(host); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IP_HOST_NAME), AJ_WSL_HTC_DATA_ENDPOINT1, host); status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IP_HOST_NAME), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } return status; } AJ_Status AJ_WSL_NET_ip6config_router_prefix(const uint8_t* ipv6addr, uint32_t prefix_length, uint32_t lifetimePrefix, uint32_t lifetimeValid) { AJ_InfoPrintf(("===== ip6config router prefix ====\n")); AJ_BufList* prefix; prefix = AJ_BufListCreate(); WSL_MarshalPacket(prefix, WSL_SOCKET, WSL_SOCK_IP6CONFIG_ROUTER_PREFIX, 0x21, ipv6addr, prefix_length, lifetimePrefix, lifetimeValid); WMI_MarshalHeader(prefix, 1, 1); AJ_WSL_WMI_PadPayload(prefix); //AJ_BufListPrintDumpContinuous(prefix); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_IP6CONFIG_ROUTER_PREFIX), AJ_WSL_HTC_DATA_ENDPOINT1, prefix); return AJ_OK; } AJ_Status AJ_WSL_NET_ipconfig_dhcp_pool(const uint32_t* startIP, const uint32_t* endIP, uint32_t leaseTime) { AJ_InfoPrintf(("===== ipconfig dhcp pool ====\n")); AJ_BufList* pool; pool = AJ_BufListCreate(); WSL_MarshalPacket(pool, WSL_SOCKET, WSL_SOCK_IPCONFIG_DHCP_POOL, 0x0c, startIP, endIP, leaseTime); WMI_MarshalHeader(pool, 1, 1); AJ_WSL_WMI_PadPayload(pool); //AJ_BufListPrintDumpContinuous(pool); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_SOCK_IPCONFIG_DHCP_POOL), AJ_WSL_HTC_DATA_ENDPOINT1, pool); return AJ_OK; } AJ_Status AJ_WSL_NET_disconnect(void) { AJ_Status status; AJ_BufList* disconnect; wsl_work_item* item; AJ_InfoPrintf((("AJ_WSL_NET_disconnect(): DISCONNECT\n"))); disconnect = AJ_BufListCreate(); WSL_MarshalPacket(disconnect, WSL_DISCONNECT, 0, 0, 0, 0, 0, 0, 0, 0); WMI_MarshalHeader(disconnect, 1, 1); AJ_WSL_WMI_PadPayload(disconnect); //AJ_BufListPrintDumpContinuous(disconnect); AJ_WSL_WMI_QueueWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_NET_DISCONNECT), AJ_WSL_HTC_DATA_ENDPOINT1, disconnect); status = AJ_WSL_WMI_WaitForWorkItem(0, AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, WSL_NET_DISCONNECT), &item, AJ_NET_TIMEOUT); if (item && (status == AJ_OK)) { AJ_WSL_WMI_FreeWorkItem(item); } return status; } ajtcl-16.04/src/wsl/aj_wsl_net.h000066400000000000000000000337211271074662300165310ustar00rootroot00000000000000/** * @file Network functionality function declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_NET_H_ #define AJ_WSL_NET_H_ #include #include #include #include "aj_wsl_target.h" #ifdef __cplusplus extern "C" { #endif #ifndef __cplusplus #pragma pack(push, 1) #endif typedef int8_t AJ_WSL_SOCKNUM; #define AJ_WSL_SCAN_LIST_SIZE 32 #define INVALID_SOCKET (-1) #define AJ_WSL_SOCKET_MAX 5 typedef struct _wsl_scan_item { char* ssid; uint8_t rssi; uint8_t bssid[6]; uint8_t secType; uint8_t cipherType; } wsl_scan_item; typedef struct _wsl_scan_list { wsl_scan_item* items; uint16_t size; } wsl_scan_list; typedef enum { WSL_NET_SCAN, WSL_NET_CONNECT, WSL_NET_DISCONNECT, WSL_NET_IPCONFIG, WSL_NET_IP6CONFIG, WSL_NET_OPEN, WSL_NET_CLOSE, WSL_NET_BIND, WSL_NET_DATA_RX, WSL_NET_DATA_TX, WSL_NET_INTERUPT, WSL_NET_SETSOCKOPTS } AJ_WSL_NET_COMMAND; typedef enum { WSL_NET_AUTH_NONE = 0x01, WSL_NET_AUTH_WPA = 0x02, WSL_NET_AUTH_WPA2 = 0x04, WSL_NET_AUTH_WPA_PSK = 0x08, WSL_NET_AUTH_WPA2_PSK = 0x10, WSL_NET_AUTH_WPA_CCKM = 0x20, WSL_NET_AUTH_WPA2_CCKM = 0x40 }WSL_NET_AUTH_MODE; typedef enum { WSL_NET_CRYPTO_NONE = 0x01, WSL_NET_CRYPTO_WEP = 0x02, WSL_NET_CRYPTO_TKIP = 0x04, WSL_NET_CRYPTO_AES = 0x08 }WSL_NET_CRYPTO_TYPE; typedef enum { WSL_AF_INET6 = 3, WSL_AF_INET = 2 }WSL_SOCK_DOMAIN; typedef enum { WSL_SOCK_STREAM = 1, WSL_SOCK_DGRAM = 2 }WSL_SOCK_TYPE; typedef enum { WSL_ADD_MEMBERSHIP = 12, WSL_DROP_MEMBERSHIP = 13, WSL_JOIN_GROUP = 83, WSL_LEAVE_GROUP = 84 }WSL_MULTICAST_OPT; typedef enum { WSL_IPPROTO_IP = 0, WSL_IPPROTO_UDP = 17, WSL_IPPROTO_TCP = 6 }WSL_MCAST_LEVEL; #define AJ_IPV4_MCAST_GROUP 0xe0000071 //0x710000e0 //224.0.0.113 - Alljoyn Multicast Group #define AJ_INADDR_ANY 0x00000000 //0.0.0.0 /** * Connect to a wifi network * * @param SSID The SSID of the network * @param passphrase The access points password * @param auth The type of authentication (NONE, WPA, WPA2 ...) * @param crypto The type of cryptography used (WEP, TKIP, AES ...) */ AJ_EXPORT AJ_Status AJ_WSL_NET_connect(const char* SSID, const char* passphrase, WSL_NET_AUTH_MODE auth, WSL_NET_CRYPTO_TYPE crypto, uint8_t softAP); /** * Disconnect from the current wifi network * */ AJ_EXPORT AJ_Status AJ_WSL_NET_disconnect(void); /** * Used to configure IP parameters * * @param mode What type of configuration are you doing (QUERY, STATIC, DHCP) * @param ip IP address (either an uninitialized pointer (DHCP/QUERY) or * an actual address for static ip configuration * @param mask subnet mask * @param gateway router gateway * @param softAP Flag to start up a softAP rather than connect to an access point * * @return success code */ AJ_EXPORT AJ_Status AJ_WSL_ipconfig(uint32_t mode, uint32_t* ip, uint32_t* mask, uint32_t* gateway); /** * Send data over a socket * * @param socket The socket your sending over * @param data Pointer to the data your sending * @param size Size of the data your sending * @param timeout Max time to try to send * * @return Number of bytes sent (not done yet) */ AJ_EXPORT int16_t AJ_WSL_NET_socket_send(uint32_t socket, uint8_t* data, uint16_t size, uint32_t timeout); /** * Send to a specific address * * @param socket Socket your sending data over * @param data Pointer to the data your sending * @param size Size of the data * @param addr IP address you wish to send to * @param port Port to send over * @param timeout How long you try and send the data * * @return Number of bytes that was sent */ AJ_EXPORT int16_t AJ_WSL_NET_socket_sendto(uint32_t socket, uint8_t* data, uint16_t size, uint32_t addr, uint16_t port, uint32_t timeout); /** * Open a socket * * @param domain Domain your opening (INET, INET6) * @param type Type of socket (SOCK_STREAM_TYPE, SOCK_DGRAM_TYPE) * @param protocol Usually zero * * @return Returns a socket number */ AJ_EXPORT int8_t AJ_WSL_NET_socket_open(uint16_t domain, uint16_t type, uint16_t protocol); /** * Ping an address * * @param addr Address to send a ping to * @param size Size of the ping packet */ AJ_EXPORT void AJ_WSL_NET_ping(uint32_t addr, uint32_t size); /** * Close a socket * * @param socketHandle The handle of the socket to close * @return AJ_OK on success * AJ_ERR_LINK_DEAD if the socket didn't exist * AJ_ERR_NULL if there was an unexpected error */ AJ_EXPORT AJ_Status AJ_WSL_NET_socket_close(AJ_WSL_SOCKNUM socketHandle); /** * Connect to another socket * * @param sock The opened socket your using * @param addr The address of the machine your connecting to * @param port The open port at the address * @param family The socket family of the connection (AF_INET, AF_INET6) * * @return 1 on connection success */ AJ_EXPORT AJ_Status AJ_WSL_NET_socket_connect(AJ_WSL_SOCKNUM sock, uint32_t addr, uint16_t port, uint16_t family); /** * Bind to a port * * @param sock The socket handle your binding the port to * @param addr Address to associate to that port * @param port The port your binding to * * @return 1 on bind success * @return AJ_OK on success * AJ_ERR_LINK_DEAD if the socket didn't exist * AJ_ERR_NULL if there was an unexpected error */ AJ_EXPORT AJ_Status AJ_WSL_NET_bind(AJ_WSL_SOCKNUM sock, uint32_t addr, uint16_t port); /** * Receive bytes of data over a socket * * @param sock Socket to receive data * @param buffer Buffer to put the data into * @param size How much data is coming * @param timeout How long to try and reveive for * * @return Number of bytes received */ AJ_EXPORT int16_t AJ_WSL_NET_socket_recv(AJ_WSL_SOCKNUM sock, uint8_t* buffer, uint32_t sizeBuffer, uint32_t timeout); /** * Set custom options for an opened socket * * @param socket The socket your configuring * @param level Options are: WSL_IPPROTO_IP, WSL_IPPROTO_UDP, WSL_IPPROTO_TCP * @param optname What option your setting: WSL_ADD_MEMBERSHIP, * WSL_DROP_MEMBERSHIP, * WSL_JOIN_GROUP, * WSL_LEAVE_GROUP * @param optlen The length of the options that follow * @param optval An array of option values e.g. {AJ_IPV4_MCAST_GROUP, AJ_INADDR_ANY} * * @return success or error code */ AJ_EXPORT AJ_Status AJ_WSL_NET_set_sock_options(uint32_t socket, uint32_t level, uint32_t optname, uint32_t optlen, uint8_t* optval); /* * Set the host name on the QCA4002 */ AJ_EXPORT AJ_Status AJ_WSL_NET_set_hostname(const char* hostname); /** * Used to configure IPV6 router prefix * * @param ipv6addr IP address * @param gateway router gateway * @param softAP Flag to start up a softAP rather than connect to an access point * * @return success code */ AJ_EXPORT AJ_Status AJ_WSL_NET_ip6config_router_prefix(const uint8_t* ipv6addr, uint32_t prefix_length, uint32_t lifetimePrefix, uint32_t lifetimeValid); /** * Used to configure DHCP pool address range and lease time * * @param startIP first IP address to give out * @param endIP last IP address to give out * @param leaseTime amount of time a DHCP address is valid * * @return success code */ AJ_EXPORT AJ_Status AJ_WSL_NET_ipconfig_dhcp_pool(const uint32_t* startIP, const uint32_t* endIP, uint32_t leaseTime); /** * Get an initialized scan item * * @return A new scan item */ wsl_scan_item* WSL_InitScanItem(void); /** * Push an interrupted work item onto the front of the queue. Used to break * out of receive if needed. * * @param sock Socket to send the interrupted call to */ void AJ_WSL_NET_signal_interrupted(AJ_WSL_SOCKNUM sock); /** * Select (poll) for data over a socket. This will return when data is available. * * @param sock Socket to poll for data on * @param timeout Timeout * * @return 1 if data is avaliable * <1 if there was an error */ int16_t AJ_WSL_NET_socket_select(AJ_WSL_SOCKNUM sock, uint32_t timeout); /** * Send UDP data over IPv6 * * @param socket The socket to send over * @param data Pointer to the data your sending * @param size Size of the data your sending * @param addr Endpoint address your sending to * @param port Port your sending over * @param timeout Timeout value (unused) * * @return Number of bytes sent */ int16_t AJ_WSL_NET_socket_sendto6(uint32_t socket, uint8_t* data, uint16_t size, uint8_t* addr, uint16_t port, uint32_t timeout); /** * Bind an IPv4 address to a port * * @param sock Opened socket * @param addr Address to bind to * @param port Port to bind to * * @return AJ_OK if the port was successfully bound. */ AJ_Status AJ_WSL_NET_socket_bind(AJ_WSL_SOCKNUM sock, uint32_t addr, uint16_t port); /** * Bind an IPv6 address to a port * * @param sock Opened socket * @param addr Address to bind to * @param port Port to bind to * * @return AJ_OK if the port was successfully bound. */ AJ_Status AJ_WSL_NET_socket_bind6(AJ_WSL_SOCKNUM sock, uint8_t* addr, uint16_t port); /** * Configure your IPv6 address * * @param mode Mode (DHCP, Static) * @param globalAddr Global IPv6 address (returned if DHCP, provided if static) * @param localAddr Local IPv6 address (returned if DHCP, provided if static) * @param gateway Gateway IPv6 address (returned if DHCP, provided if static) * @param exAddr External Address (returned if DHCP, provided if static) * @param linkPrefix Link prefix * @param globalPrefix Global prefix * @param gwPrefix * @param gblPrefixExt Global prefix extension * * @return AJ_OK on success */ AJ_Status AJ_WSL_ip6config(uint32_t mode, uint8_t* globalAddr, uint8_t* localAddr, uint8_t* gateway, uint8_t* exAddr, uint32_t linkPrefix, uint32_t globalPrefix, uint32_t gwPrefix, uint32_t glbPrefixExt); /** * Add a cipher key. Used for WEP security * * @param keyIndex Index where the target will hold the key * @param key Pointer to the hex key * @param keyLength Length of the key * * @return AJ_OK on success */ void AJ_WSL_NET_add_cipher_key(uint8_t keyIndex, uint8_t* key, uint8_t keyLength); /** * Set the passphrase for WPA and WPA2 security * * @param SSID SSID for this passphrase * @param passphrase ASCII passphrase * @param passLen Length of the passphrase * * @return AJ_OK on success */ AJ_Status AJ_WSL_NET_SetPassphrase(const char* SSID, const char* passphrase, uint32_t passLen); /** * Set the power mode on the target * * @param mode Mode to set * * @return AJ_OK if the mode was set sucessfully */ AJ_Status AJ_WSL_NET_SetPowerMode(uint8_t mode); /** * Initialize the scan list for scanning SSID's * * @param maxAP Maximum number of AP's stored in the scan. */ void AJ_WSL_InitScanList(uint8_t maxAP); /** * Initiate a wifi scan. This will populate a list of SSID/RSSI/BSSID's */ AJ_Status AJ_WSL_NET_scan(void); /** * Stop an already started SSID scan */ void AJ_WSL_NET_scan_stop(void); /** * Clear and free a scan list. This function has to be called after * calling AJ_WSL_InitScanList() or it will leak memory */ void WSL_ClearScanList(); /** * Get a stored scan list. This function will not return a valid list * unless the scanning functions were called properly. * * @return A pointer to the list of SSID's */ wsl_scan_item* AJ_WSL_GetScanList(void); /** * Set the softAP to hidden * * @param hidden 1 for hidden, 0 for not hidden */ AJ_Status AJ_WSL_NET_SetHiddenAP(uint8_t hidden); /** * Print the list of scanned SSID's */ void WSL_PrintScanSorted(void); /** * Register a callback function to be called whenever a BSSINFO (scan) packet * is received over the wire. * * @param context Context pointer * @param callback Function pointer to the callback function */ void AJ_WSL_RegisterWiFiCallback(void* context, AJ_WiFiScanResult callback); /** * Unregister a BSSINFO (scan) callback function. This function should be called * after a scan has completed or else the callback will be called later on * when connecting to an access point. */ void AJ_WSL_UnregisterWiFiCallback(void); #ifndef __cplusplus #pragma pack(pop) #endif #ifdef __cplusplus } #endif #endif /* AJ_WSL_NET_H_ */ ajtcl-16.04/src/wsl/aj_wsl_spi.h000066400000000000000000000103401271074662300165260ustar00rootroot00000000000000/** * @file SPI function declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_SPI_H_ #define AJ_WSL_SPI_H_ #include #include #include #include "aj_wsl_target.h" #include "aj_wsl_spi_constants.h" #ifdef __cplusplus extern "C" { #endif #pragma pack(push, 1) /* * These methods are */ void AJ_WSL_SPI_ModuleInit(void); /* * These methods are SPI module interfaces, and are target-specific implementations */ void AJ_WSL_SPI_InitializeSPIController(void); void AJ_WSL_SPI_ShutdownSPIController(void); /* * signal to the SPI hardware if more data is coming in this transaction */ #define AJ_WSL_SPI_CONTINUE 0 #define AJ_WSL_SPI_END 1 /* * Define the layout of the SPI commands between the host and target */ #define AJ_WSL_SPI_WRITE 0 #define AJ_WSL_SPI_READ 1 #define AJ_WSL_SPI_EXTERNAL 0 #define AJ_WSL_SPI_INTERNAL 1 #define AJ_WSL_SPI_REG_READ ((AJ_WSL_SPI_READ << 1) | AJ_WSL_SPI_INTERNAL) #define AJ_WSL_SPI_REG_WRITE ((AJ_WSL_SPI_WRITE << 1) | AJ_WSL_SPI_INTERNAL) #define AJ_WSL_SPI_DMA_READ ((AJ_WSL_SPI_READ << 1) | AJ_WSL_SPI_EXTERNAL) #define AJ_WSL_SPI_DMA_WRITE ((AJ_WSL_SPI_WRITE << 1) | AJ_WSL_SPI_EXTERNAL) #define AJ_WSL_SPI_REG_EXTERNAL_WRITE ((AJ_WSL_SPI_WRITE << 1) | AJ_WSL_SPI_EXTERNAL) #define AJ_WSL_SPI_HDR_REG_READ ((uint16_t) AJ_WSL_SPI_REG_READ << 14) #define AJ_WSL_SPI_HDR_REG_WRITE ((uint16_t) AJ_WSL_SPI_REG_WRITE << 14) #define AJ_WSL_SPI_HDR_DMA_READ ((uint16_t) AJ_WSL_SPI_DMA_READ << 14) #define AJ_WSL_SPI_HDR_DMA_WRITE ((uint16_t) AJ_WSL_SPI_DMA_WRITE << 14) typedef struct _wsl_spi_command { uint16_t cmd_addr : 14, cmd_reg : 1, cmd_rx : 1; } wsl_spi_command; typedef struct _wsl_spi_status { uint8_t ready : 1, wr_err : 1, rd_err : 1, addr_err : 1, res : 4; } wsl_spi_status; /* * Global definitions */ extern wsl_spi_command qsc_HOST_INT_STATUS; AJ_Status AJ_WSL_SPI_WriteByte8(uint8_t spi_data, uint8_t end); AJ_Status AJ_WSL_SPI_WriteByte16(uint16_t spi_data, uint8_t end); /* * Helper functions */ AJ_Status AJ_WSL_GetDMABufferSize(uint16_t* dmaSize); AJ_Status AJ_WSL_SetDMABufferSize(uint16_t dmaSize); AJ_Status AJ_WSL_GetWriteBufferSpaceAvailable(uint16_t* spaceAvailable); AJ_Status AJ_WSL_GetReadBufferSpaceAvailable(uint16_t* spaceAvailable); AJ_Status AJ_WSL_SPI_RegisterRead(uint16_t reg, uint8_t* spi_data); AJ_Status AJ_WSL_SPI_RegisterWrite(uint16_t reg, uint16_t spi_data); AJ_Status AJ_WSL_SPI_DMAWriteStart(uint16_t targetAddress); AJ_Status AJ_WSL_SPI_DMAWrite8(uint16_t targetAddress, uint16_t len, uint8_t* spi_data); AJ_Status AJ_WSL_SPI_DMAWrite16(uint16_t targetAddress, uint16_t len, uint16_t* spi_data); AJ_Status AJ_WSL_SPI_DMARead16(uint16_t targetAddress, uint16_t len, uint16_t* spi_data); AJ_Status AJ_WSL_SPI_HostControlRegisterWrite(uint32_t targetRegister, uint8_t increment, uint16_t cbLen, uint8_t* spi_data); AJ_Status AJ_WSL_SPI_HostControlRegisterRead(uint32_t targetRegister, uint8_t increment, uint16_t cbLen, uint8_t* spi_data); AJ_EXPORT AJ_Status AJ_WSL_ReadFromMBox(uint8_t box, uint16_t* len, uint8_t** buf); AJ_EXPORT AJ_Status AJ_WSL_WriteBufListToMBox(uint8_t box, uint8_t endpoint, uint16_t len, AJ_BufList* list); #pragma pack(pop) #ifdef __cplusplus } #endif #endif /* AJ_WSL_SPI_H_ */ ajtcl-16.04/src/wsl/aj_wsl_spi_constants.h000066400000000000000000000164731271074662300206370ustar00rootroot00000000000000/** * @file Constants related to the QCA4004 wifi module */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_SPI_CONSTANTS_H_ #define AJ_WSL_SPI_CONSTANTS_H_ #pragma pack(push, 1) #define AJ_WSL_SPI_MBOX_SIZE 0xFF #define AJ_WSL_SPI_MBOX_0 0x0 #define AJ_WSL_SPI_MBOX_0_END (AJ_WSL_SPI_MBOX_0 + AJ_WSL_SPI_MBOX_SIZE) #define AJ_WSL_SPI_MBOX_0_EOM (AJ_WSL_SPI_MBOX_0_END + 1) #define AJ_WSL_SPI_MBOX_ALIAS_SIZE 0x7FF #define AJ_WSL_SPI_MBOX_0_ALIAS 0x800 #define AJ_WSL_SPI_MBOX_0_ALIAS_END (AJ_WSL_SPI_MBOX_0_ALIAS + AJ_WSL_SPI_MBOX_ALIAS_SIZE) #define AJ_WSL_SPI_MBOX_0_EOM_ALIAS (AJ_WSL_SPI_MBOX_0_ALIAS_END + 1) //Address for AHB Read Access #define AJ_WSL_SPI_HOST_INT_STATUS 0x400 //CPU Sourced Interrupt Status #define AJ_WSL_SPI_CPU_INT_STATUS 0x401 //Credit Counter Direct Access #define AJ_WSL_SPI_CREDIT_COUNT 0x420 //Data transfer value #define AJ_WSL_SPI_TARGET_VALUE 0x474 //Data transfer write from the host #define AJ_WSL_SPI_TARGET_ADDR_WRITE 0x478 //Data transfer read from the target #define AJ_WSL_SPI_TARGET_ADDR_READ 0x047C //SPI Slave Interface #define AJ_WSL_SPI_SPI_CONFIG 0x480 //SPI Status #define AJ_WSL_SPI_SPI_STATUS 0x481 /* * SPI internal registers * description followed by register address */ //DMA size ( #define AJ_WSL_SPI_REG_DMA_SIZE 0x0100 //Write buffer space available #define AJ_WSL_SPI_REG_WRBUF_SPC_AVA 0x0200 //Read buffer byte available #define AJ_WSL_SPI_REG_RDBUF_BYTE_AVA 0x0300 //SPI configuration #define AJ_WSL_SPI_REG_SPI_CONFIG 0x0400 //SPI status #define AJ_WSL_SPI_REG_SPI_STATUS 0x0500 //Host control register access byte size #define AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE 0x0600 //Host control register configure #define AJ_WSL_SPI_REG_HOST_CTRL_CONFIG 0x0700 //Host control register read port #define AJ_WSL_SPI_REG_HOST_CTRL_RD_PORT 0x0800 //Host control register write port #define AJ_WSL_SPI_REG_HOST_CTRL_WR_PORT 0x0A00 //Interrupt cause #define AJ_WSL_SPI_REG_INTR_CAUSE 0x0C00 #define AJ_WSL_SPI_REG_INTR_CAUSE_DATA_AVAILABLE (1 << 0) #define AJ_WSL_SPI_REG_INTR_CAUSE_READ_DONE (1 << 9) #define AJ_WSL_SPI_REG_INTR_CAUSE_WRITE_DONE (1 << 8) #define AJ_WSL_SPI_REG_INTR_CAUSE_CPU_AWAKE (1 << 6) #define AJ_WSL_SPI_REG_INTR_CAUSE_COUNTER (1 << 5) //Interrupt enable #define AJ_WSL_SPI_REG_INTR_ENABLE 0x0D00 //Write buffer Watermark #define AJ_WSL_SPI_REG_WRBUF_WATERMARK 0x1300 //Read buffer lookahead 1 #define AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD1 0x1400 //Read buffer lookahead 2 #define AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD2 0x1500 // magic value from driver context data #define AJ_WSL_AR4100_BUFFER_SIZE 1664 #define AJ_WSL_SPI_TARGET_CLOCK_SPEED_ADDR 0x00428878 #define AJ_WSL_SPI_TARGET_FLASH_PRESENT_ADDR 0x0042880C #define AJ_WSL_SPI_TARGET_MBOX_BLOCKSZ_ADDR 0x0042886C typedef enum { WMI_CONNECT_CMDID = 0x0001, WMI_RECONNECT_CMDID = 0x0002, WMI_DISCONNECT_CMDID = 0x0003, WMI_SYNCHRONIZE_CMDID = 0x0004, WMI_START_SCAN_CMDID = 0x0007, WMI_SET_SCAN_PARAMS_CMDID = 0x0008, WMI_SET_BSS_FILTER_CMDID = 0x0009, WMI_SET_PROBED_SSID_CMDID = 0x000a, WMI_SET_LISTEN_INT_CMDID = 0x000b, WMI_ALLOW_AGGR_CMDID = 0xf01b, WMI_SET_CHANNEL_CMDID = 0xf042, WMI_GET_PMK_CMDID = 0xf047, WMI_SET_POWER_MODE_CMDID = 0x0012, WMI_SET_PASSPHRASE_CMDID = 0xf048, WMI_STORERECALL_CONFIGURE_CMDID = 0xf05e, WMI_STORERECALL_RECALL_CMDID = 0xf05f, WMI_STORERECALL_HOST_READY_CMDID = 0xf060, /*Socket commands*/ WMI_SOCKET_CMDID = 0xf08d, WMI_SET_SOFT_AP_CMDID = 0xf00f } wsl_wmi_command_id; typedef enum _wsl_SOCKET_CMDS { WSL_SOCK_OPEN = 0x0, /*Open a socket*/ WSL_SOCK_CLOSE = 0x1, /*Close existing socket*/ WSL_SOCK_CONNECT = 0x2, /*Connect to a peer*/ WSL_SOCK_BIND = 0x3, /*Bind to interface*/ WSL_SOCK_SELECT = 0x6, /*Wait for specified file descriptors*/ WSL_SOCK_SETSOCKOPT = 0x7, /*Set specified socket option*/ WSL_SOCK_GETSOCKOPT = 0x8, /*Get socket option*/ WSL_SOCK_ERRNO, /*Get error number for last error*/ WSL_SOCK_IPCONFIG = 0xA, /*Set static IP information, or get current IP config*/ WSL_SOCK_PING, WSL_SOCK_STACK_INIT = 0xC, /*Command to initialize stack*/ WSL_SOCK_STACK_MISC, /*Used to exchanges miscellaneous info, e.g. reassembly etc*/ WSL_SOCK_PING6, WSL_SOCK_IP6CONFIG = 0xF, /*Set static IP information, or get current IP config*/ WSL_SOCK_IPCONFIG_DHCP_POOL, /*Set DHCP Pool */ WSL_SOCK_IP6CONFIG_ROUTER_PREFIX, /* Set ipv6 router prefix */ WSL_SOCK_IP_SET_TCP_EXP_BACKOFF_RETRY, /* set tcp exponential backoff retry */ WSL_SOCK_IP_SET_IP6_STATUS, /* set ip6 module status enable/disable */ WSL_SOCK_IP_DHCP_RELEASE, /* Release the DHCP IP Addres */ WSL_SOCK_IP_SET_TCP_RX_BUF, /* set tcp rx buffer space */ WSL_SOCK_IP_HOST_NAME = 0x1d /* Command to set the hostname on the QCA4002 */ } wsl_socket_cmds; typedef enum _WSL_WMI_EVENTID { WSL_WMI_READY_EVENTID = 0x1001, WSL_WMI_CONNECT_EVENTID = 0x1002, WSL_WMI_DISCONNECT_EVENTID = 0x1003, WSL_BSS_INFO_EVENTID = 0x1004, WSL_CMDERROR_EVENTID = 0x1005, WSL_REGDOMAIN_EVENTID = 0x1006, WSL_UNKNOWN1_EVENTID = 0x1008, WSL_WMI_SCAN_COMPLETE_EVENTID = 0x100A, WSL_WMI_APLIST_EVENTID = 0x1017, WSL_WMI_PEER_NODE_EVENTID = 0x101B, WSL_WMI_WLAN_VERSION_EVENTID = 0x101E, WSL_UNKNOWN2_EVENTID = 0x103b, WSL_WMI_SOCKET_RESPONSE_EVENTID = 0x9016, } WSL_WMI_EVENTID; enum AJ_WSL_HTC_ENDPOINT_COUNT { AJ_WSL_HTC_CONTROL_ENDPOINT = 0, AJ_WSL_HTC_DATA_ENDPOINT1 = 1, AJ_WSL_HTC_DATA_ENDPOINT2 = 2, AJ_WSL_HTC_DATA_ENDPOINT3 = 3, AJ_WSL_HTC_DATA_ENDPOINT4 = 4, AJ_WSL_HTC_ENDPOINT_COUNT_MAX, }; /* * RX trailer type Ids */ #define AJ_WSL_HTC_RXTRAILER_CREDIT_REPORT 1 // message id values #define AJ_WSL_HTC_MSG_READY_ID 1 #define AJ_WSL_HTC_CONNECT_SERVICE_ID 2 #define AJ_WSL_HTC_SERVICE_CONNECT_RESPONSE_ID 3 #define AJ_WSL_HTC_SETUP_COMPLETE_ID 4 #define AJ_WSL_HTC_HOST_READY_ID 5 #pragma pack(pop) #endif /* AJ_WSL_SPI_CONSTANTS_H_ */ ajtcl-16.04/src/wsl/aj_wsl_spi_mbox.c000066400000000000000000000560051271074662300175560ustar00rootroot00000000000000/** * @file SPI MBOX implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE WSL_SPI_MBOX #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_SPI_MBOX = 0; #endif extern AJ_WSL_HTC_CONTEXT AJ_WSL_HTC_Global; uint32_t AJ_WSL_MBOX_BLOCK_SIZE; void AJ_WSL_SPI_ModuleInit(void) { AJ_BufList_ModuleInit(); } AJ_Status AJ_WSL_GetDMABufferSize(uint16_t* dmaSize) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t size = 0; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_DMA_SIZE, (uint8_t*)&size); *dmaSize = size & ((1 << 12) - 1); return status; } AJ_Status AJ_WSL_SetDMABufferSize(uint16_t dmaSize) { AJ_ASSERT(0 != dmaSize); dmaSize &= ((1 << 12) - 1); // mask the reserved bits return AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_DMA_SIZE, dmaSize); } AJ_Status AJ_WSL_GetWriteBufferSpaceAvailable(uint16_t* spaceAvailable) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t space = 0; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, (uint8_t*)&space); *spaceAvailable = space & ((1 << 12) - 1); AJ_InfoPrintf(("write buffer space available: %x %d\n", space, *spaceAvailable)); return status; } AJ_Status AJ_WSL_GetReadBufferSpaceAvailable(uint16_t* spaceAvailable) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t space = 0; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_BYTE_AVA, (uint8_t*)&space); *spaceAvailable = space & ((1 << 12) - 1); return status; } static void AJ_WSL_BufListIterate_DMA(AJ_BufList* list) { if (list != NULL) { AJ_BufNode* node = list->head; while (node != NULL) { AJ_BufNode* nextNode = node->next; AJ_WSL_SPI_DMATransfer(node->buffer, node->length, 1); node = nextNode; } } } AJ_EXPORT AJ_Status AJ_WSL_WriteBufListToMBox(uint8_t box, uint8_t endpoint, uint16_t len, AJ_BufList* list) { AJ_Status status = AJ_ERR_SPI_WRITE; uint16_t spaceAvailable = 0; uint16_t bytesRemaining; uint16_t cause = 0; AJ_ASSERT(0 == box); // AJ_InfoPrintf(("=HTC Credits 0:%x, 1:%x, 2:%x\n", AJ_WSL_HTC_Global.endpoints[0].txCredits, AJ_WSL_HTC_Global.endpoints[1].txCredits, AJ_WSL_HTC_Global.endpoints[2].txCredits)); AJ_Time credit_timer; AJ_InitTimer(&credit_timer); while (AJ_WSL_HTC_Global.endpoints[endpoint].txCredits < 1) { // do nothing and wait until there are credits if (AJ_GetElapsedTime(&credit_timer, TRUE) > 1500) { AJ_WSL_HTC_Global.endpoints[endpoint].txCredits++; break; } AJ_YieldCurrentTask(); } // don't let the other tasks interrupt our SPI access AJ_EnterCriticalRegion(); AJ_Time space_timer; AJ_InitTimer(&space_timer); // read space available in mbox from register do { if (AJ_GetElapsedTime(&space_timer, TRUE) > 1500) { spaceAvailable = 0xc5b; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, 1 << 15); break; } status = AJ_WSL_GetWriteBufferSpaceAvailable(&spaceAvailable); } while (spaceAvailable == 0); AJ_ASSERT((status == AJ_OK) && (spaceAvailable >= len)); if ((status == AJ_OK) && (spaceAvailable >= len)) { uint16_t targetAddress; // write size to be transferred status = AJ_WSL_SetDMABufferSize(len); AJ_ASSERT(status == AJ_OK); // write the target address (where we want to send data) // the write should end up at the end of the MBox alias // example 0xFFF - len targetAddress = AJ_WSL_SPI_MBOX_0_EOM_ALIAS - len; status = AJ_WSL_SPI_DMAWriteStart(targetAddress); AJ_ASSERT(status == AJ_OK); bytesRemaining = len; // Take the AJ_BufList to write out and write it out to the SPI interface via DMA AJ_WSL_BufListIterate_DMA(list); // clear the packet available interrupt cause = 0x1f; status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, cause); AJ_ASSERT(status == AJ_OK); AJ_WSL_HTC_Global.endpoints[endpoint].txCredits -= 1; } else { status = AJ_ERR_SPI_NO_SPACE; } AJ_LeaveCriticalRegion(); return status; } void AJ_WSL_SPI_ReadIntoBuffer(uint16_t bytesToRead, uint8_t** buf) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_READ; uint8_t pcs = AJ_WSL_SPI_PCS; uint16_t toss; // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_READ; send.cmd_reg = AJ_WSL_SPI_EXTERNAL; send.cmd_addr = AJ_WSL_SPI_MBOX_0_EOM_ALIAS - bytesToRead; // write the register rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, (uint8_t*)&toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, (uint8_t*)&toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); AJ_WSL_SPI_DMATransfer((uint8_t*)*buf, bytesToRead, 0); } //Mailbox Read Steps: //1. Interrupt going from the QCA4002 to the SPI host. //2. INTERNAL read from INTR_CAUSE register. //3. INTERNAL read from RDBUF_BYTE_AVA register. //4. Internal read from RDBUF_LOOKAHEAD1 register //5. Internal read from RDBUF_LOOKAHEAD2 register. From the 4 bytes we have read from RDBUF_LOOKAHEAD registers, get the packet size. //6. INTERNAL write to DMA_SIZE register with the packet size. //7. Start DMA read command and start reading the data by de-asserting chip select pin. //8. The packet available will be cleared by HW at the end of the DMA read. // AJ_EXPORT AJ_Status AJ_WSL_ReadFromMBox(uint8_t box, uint16_t* len, uint8_t** buf) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t cause = 0; uint16_t bytesInBuffer = 0; uint16_t bytesToRead = 0; uint16_t lookAhead; uint16_t payloadLength; AJ_ASSERT(0 == box); AJ_EnterCriticalRegion(); //2. INTERNAL read from INTR_CAUSE register. do { //3. INTERNAL read from RDBUF_BYTE_AVA register. status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_BYTE_AVA, (uint8_t*)&bytesInBuffer); AJ_ASSERT(status == AJ_OK); //bytesInBuffer = CPU_TO_BE16(bytesInBuffer); // The first few bytes of the packet can now be examined and the right amount of data read from the target //4. Internal read from RDBUF_LOOKAHEAD1 register //5. Internal read from RDBUF_LOOKAHEAD2 register. From the 4 bytes we have read from RDBUF_LOOKAHEAD registers, get the packet size. status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD1, (uint8_t*)&lookAhead); AJ_ASSERT(status == AJ_OK); lookAhead = CPU_TO_BE16(lookAhead); status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD2, (uint8_t*)&payloadLength); AJ_ASSERT(status == AJ_OK); payloadLength = CPU_TO_BE16(payloadLength); // calculate number of bytes to read from the lookahead info, and round up to the next block size bytesToRead = payloadLength + 6; //sizeof(header); bytesToRead = ((bytesToRead / AJ_WSL_MBOX_BLOCK_SIZE) + ((bytesToRead % AJ_WSL_MBOX_BLOCK_SIZE) ? 1 : 0)) * AJ_WSL_MBOX_BLOCK_SIZE; *buf = (uint8_t*)AJ_WSL_Malloc(bytesToRead); *len = bytesToRead; //6. INTERNAL write to DMA_SIZE register with the packet size. // write size to be transferred status = AJ_WSL_SetDMABufferSize(bytesToRead); AJ_ASSERT(status == AJ_OK); AJ_WSL_SPI_ReadIntoBuffer(bytesToRead, buf); // clear the packet available interrupt cause = 0x1; status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, cause); AJ_ASSERT(status == AJ_OK); break; } while (0); AJ_LeaveCriticalRegion(); return status; } AJ_Status AJ_WSL_SPI_RegisterRead(uint16_t reg, uint8_t* spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_READ; uint8_t pcs = AJ_WSL_SPI_PCS; // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_READ; send.cmd_reg = AJ_WSL_SPI_INTERNAL; send.cmd_addr = reg; /* Test write: should return OK. */ rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); // toss. AJ_ASSERT(rc == SPI_OK); // read the first byte of response rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0 /*xFF*/, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); // junk to write while reading AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); AJ_ASSERT(rc == SPI_OK); status = AJ_OK; } // read the second byte spi_data++; rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0 /*xFF*/, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); // junk to write while reading AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); AJ_ASSERT(rc == SPI_OK); status = AJ_OK; } spi_data--; // move back to the original location *(uint16_t*)spi_data = CPU_TO_BE16(*(uint16_t*)spi_data); return status; } AJ_Status AJ_WSL_SPI_RegisterWrite(uint16_t reg, uint16_t spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t pcs = AJ_WSL_SPI_PCS; uint8_t toss; uint8_t* bytePoint = (uint8_t*)&spi_data; // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_WRITE; send.cmd_reg = AJ_WSL_SPI_INTERNAL; send.cmd_addr = reg; // write the register, one byte at a time, in the right order rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(bytePoint + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { status = AJ_OK; } } if (rc == SPI_OK) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(bytePoint) & 0xFF, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { status = AJ_OK; } } return status; } // Set up a transfer: send a write command with an address AJ_Status AJ_WSL_SPI_DMAWriteStart(uint16_t targetAddress) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t toss; uint8_t pcs = AJ_WSL_SPI_PCS; // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_WRITE; send.cmd_reg = AJ_WSL_SPI_EXTERNAL; send.cmd_addr = targetAddress; // write the register rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { status = AJ_OK; } return status; } // Set up a transfer: send a write command with an address AJ_Status AJ_WSL_SPI_DMAWrite16(uint16_t targetAddress, uint16_t len, uint16_t* spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t toss; uint8_t pcs = AJ_WSL_SPI_PCS; uint8_t* bytePoint = (uint8_t*)spi_data; // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_WRITE; send.cmd_reg = AJ_WSL_SPI_EXTERNAL; send.cmd_addr = targetAddress; // write the register rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { while ((rc == SPI_OK) && (len > 1)) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *bytePoint, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); bytePoint++; len = len - 1; } if (rc == SPI_OK) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *bytePoint, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); } if (rc == SPI_OK) { status = AJ_OK; } } return status; } // Set up a transfer: send a write command with an address AJ_Status AJ_WSL_SPI_DMARead16(uint16_t targetAddress, uint16_t len, uint16_t* spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_READ; uint8_t pcs = AJ_WSL_SPI_PCS; uint8_t toss; uint8_t* bytePoint = (uint8_t*)spi_data; // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_READ; send.cmd_reg = AJ_WSL_SPI_EXTERNAL; send.cmd_addr = targetAddress; // write the register rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); while ((rc == SPI_OK) && (len > 1)) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0 /*xFF*/, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, bytePoint, pcs); AJ_ASSERT(rc == SPI_OK); bytePoint++; len = len - 1; } if (rc == SPI_OK) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0 /*xFF*/, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, bytePoint, pcs); AJ_ASSERT(rc == SPI_OK); } if (rc == SPI_OK) { status = AJ_OK; } return status; } /* * @remarks SPI mode is not being changed here. */ AJ_Status AJ_WSL_SPI_WriteByte8(uint8_t spi_data, uint8_t end) { aj_spi_status rc; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t pcs = AJ_WSL_SPI_PCS; uint8_t toss; rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, (uint16_t)spi_data, AJ_WSL_SPI_PCS, end); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { status = AJ_OK; } return status; } /* * @remarks SPI mode is not being changed here. */ AJ_Status AJ_WSL_SPI_WriteByte16(uint16_t spi_data, uint8_t end) { aj_spi_status rc; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t pcs = AJ_WSL_SPI_PCS; uint8_t toss; rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, spi_data, AJ_WSL_SPI_PCS, end); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, spi_data & 0xFF, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, spi_data >> 8, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { status = AJ_OK; } return status; } AJ_Status AJ_WSL_SPI_HostControlRegisterWrite(uint32_t targetRegister, uint8_t increment, uint16_t cbLen, uint8_t* spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t toss; uint8_t pcs = AJ_WSL_SPI_PCS; // write the size AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE, cbLen | (increment ? 0 : 0x40)); // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_WRITE; send.cmd_reg = AJ_WSL_SPI_INTERNAL; send.cmd_addr = AJ_WSL_SPI_REG_HOST_CTRL_WR_PORT; // write the register, one byte at a time, in the right order rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); // toss. AJ_ASSERT(rc == SPI_OK); if (rc == SPI_OK) { while ((rc == SPI_OK) && (cbLen > 1)) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *spi_data, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); spi_data++; cbLen = cbLen - 1; } if (rc == SPI_OK) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *spi_data, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, &toss, pcs); AJ_ASSERT(rc == SPI_OK); } if (rc == SPI_OK) { status = AJ_OK; } } // now send the host_control_config register update { uint16_t externalRegister = 0; externalRegister = (1 << 15) | (1 << 14) | (targetRegister); // external access, write, counter dec externalRegister = CPU_TO_LE16(externalRegister); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_CONFIG, externalRegister); } // clear the rd/wr buffer interrupt { uint16_t spi_16 = 0x300; spi_16 = CPU_TO_LE16(spi_16); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, spi_16); } return status; } AJ_Status AJ_WSL_SPI_HostControlRegisterRead(uint32_t targetRegister, uint8_t increment, uint16_t cbLen, uint8_t* spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t pcs = AJ_WSL_SPI_PCS; // write the size AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE, cbLen | (increment ? 0 : 0x40)); // now send the host_control_config register update { uint16_t externalRegister = 0; externalRegister = (1 << 15) | (0 << 14) | (targetRegister); // external access, write, counter dec externalRegister = CPU_TO_LE16(externalRegister); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_CONFIG, externalRegister); } // get the spi status { uint16_t spi_16 = 0; AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_SPI_STATUS, (uint8_t*)&spi_16); spi_16 = LE16_TO_CPU(spi_16); } // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_READ; send.cmd_reg = AJ_WSL_SPI_INTERNAL; send.cmd_addr = AJ_WSL_SPI_REG_HOST_CTRL_RD_PORT; // write the register, one byte at a time, in the right order rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); // toss. AJ_ASSERT(rc == SPI_OK); // now, read the data back if (rc == SPI_OK) { while ((rc == SPI_OK) && (cbLen > 1)) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); AJ_ASSERT(rc == SPI_OK); spi_data++; cbLen = cbLen - 1; } if (rc == SPI_OK) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, pcs); AJ_ASSERT(rc == SPI_OK); } if (rc == SPI_OK) { status = AJ_OK; } } // clear the rd/wr buffer interrupt { uint16_t spi_16 = 0x300; spi_16 = CPU_TO_LE16(spi_16); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, spi_16); } return status; } ajtcl-16.04/src/wsl/aj_wsl_target.h000066400000000000000000000063541271074662300172330ustar00rootroot00000000000000/** * @file WSL module header */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_TARGET_H__ #define AJ_WSL_TARGET_H__ #include "aj_target_platform.h" #include #include "aj_rtos.h" #include #ifdef __cplusplus extern "C" { #endif void AJ_WSL_ModuleInit(void); AJ_Status AJ_WSL_DriverStart(void); AJ_Status AJ_WSL_DriverStop(void); void AJ_WSL_NET_StackInit(void); /* * Platform specific defines are here */ #define AJ_WSL_SPI_CLOCK_RATE 28000000 #define AJ_WSL_SPI_CLOCK_POLARITY 1 #define AJ_WSL_SPI_CLOCK_PHASE 0 #define AJ_WSL_SPI_DELAY_BEFORE_CLOCK 0x01 #define AJ_WSL_SPI_DELAY_BETWEEN_TRANSFERS 0x01 #ifdef AJ_WSL_USE_REGULAR_MALLOC #define AJ_WSL_Malloc AJ_Malloc #define AJ_WSL_Free AJ_Free #else /* * WSL memory allocations come from a WSL-specific heap */ void* AJ_WSL_Malloc(size_t size); void AJ_WSL_Free(void* ptr); #endif AJ_Status AJ_WSL_SPI_RegisterRead(uint16_t reg, uint8_t* spi_data); /** * global flag that indicates the target chip has SPI data available */ extern volatile uint8_t g_b_spi_interrupt_data_ready; /* * Set the native endianness */ #if HOST_IS_BIG_ENDIAN #define BE8_8_TO_CPU(v, w) (((v) << 8) | (w)) #define BE16_TO_CPU(v) (v) #define BE32_TO_CPU(v) (v) #define CPU_TO_BE16(v) (v) #define CPU_TO_BE32(v) (v) #define LE8_8_TO_CPU(v, w) ((v) | ((w) << 8)) #define LE16_TO_CPU(v) (((v) >> 8) | ((v) << 8)) #define LE32_TO_CPU(v) (((v) >> 24) | (((v) & 0xFF0000) >> 8) | (((v) & 0x00FF00) << 8) | ((v) << 24)) #define CPU_TO_LE16(v) (((v) >> 8) | ((v) << 8)) #define CPU_TO_LE32(v) (((v) >> 24) | (((v) & 0xFF0000) >> 8) | (((v) & 0x00FF00) << 8) | ((v) << 24)) #else #define BE8_8_TO_CPU(v, w) ((v) | ((w) << 8)) #ifndef LE16_TO_CPU #define BE16_TO_CPU(v) (((v) >> 8) | ((v) << 8)) #define BE32_TO_CPU(v) (((v) >> 24) | (((v) & 0xFF0000) >> 8) | (((v) & 0x00FF00) << 8) | ((v) << 24)) #define CPU_TO_BE16(v) (((v) >> 8) | ((v) << 8)) #define CPU_TO_BE32(v) (((v) >> 24) | (((v) & 0xFF0000) >> 8) | (((v) & 0x00FF00) << 8) | ((v) << 24)) #endif #define LE8_8_TO_CPU(v, w) (((v) << 8) | (w)) #ifndef LE16_TO_CPU #define LE16_TO_CPU(v) (v) #define LE32_TO_CPU(v) (v) #define CPU_TO_LE16(v) (v) #define CPU_TO_LE32(v) (v) #endif #endif #ifdef __cplusplus } #endif #endif // AJ_WSL_TARGET_H__ ajtcl-16.04/src/wsl/aj_wsl_tasks.c000066400000000000000000000334361271074662300170660ustar00rootroot00000000000000/** * @file Implementation for tasks related to WSL */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE WSL_TASKS #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_TASKS = 0; #endif extern uint32_t AJ_WSL_MBOX_BLOCK_SIZE; static void set_SPI_registers(void) { volatile uint16_t spi_API = 0; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); // reset the target // spi_API = (1 << 15); // AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, spi_API); // AJ_Sleep(1 << 22); // one extra write to force the device out of the reset state. spi_API = 0x80; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, spi_API); AJ_Sleep(100); // write spi_API = 0x80; // same as capture AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, spi_API); // AJ_InfoPrintf(("AJ_WSL_SPI_REG_SPI_CONFIG was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_WRBUF_SPC_AVA was %04x\n", spi_API)); spi_API = 0x40; // same as capture AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_WRBUF_WATERMARK, spi_API); // AJ_InfoPrintf(("AJ_WSL_SPI_REG_SPI_CONFIG was %04x\n", spi_API)); spi_API = 0x400; // same as capture AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_CAUSE was %04x\n", spi_API)); spi_API = 0x3ff; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x0e; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x1e; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x0; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x1e; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); AJ_Sleep(100); } /* * This test reads a few registers using the SPI hardware. */ /* static void examine_SPI_registers(void) { uint16_t spi_API = 0; uint16_t spi_lookahead[2]; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_DMA_SIZE, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_DMA_SIZE was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_WRBUF_SPC_AVA was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_BYTE_AVA, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_RDBUF_BYTE_AVA was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_SPI_CONFIG, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_SPI_CONFIG was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_SPI_STATUS, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_SPI_STATUS was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_HOST_CTRL_CONFIG, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_HOST_CTRL_CONFIG was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_INTR_CAUSE, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_CAUSE was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_WATERMARK, (uint8_t*)&spi_API); spi_API = CPU_TO_LE16(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_WRBUF_WATERMARK was %04x\n", spi_API)); memset(spi_lookahead, 0, sizeof(spi_lookahead)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD1, (uint8_t*)&spi_lookahead[0]); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD1 was %04x\n", spi_lookahead[0])); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD2, (uint8_t*)&spi_lookahead[1]); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD2 was %04x\n", spi_lookahead[1])); } */ static void write_BOOT_PARAM(void) { uint32_t spi_API = 0; uint16_t spi_API16 = 0; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); // read the clock speed value spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_CLOCK_SPEED_ADDR; //0x00428878; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ, TRUE, 4, (uint8_t*)&spi_API); // now read back the value from the data port. AJ_WSL_SPI_HostControlRegisterRead(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = LE32_TO_CPU(spi_API); //AJ_InfoPrintf(("cycles read back was %ld \n", spi_API)); // read the flash is present value { // let's try this dance of writing multiple times... spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_FLASH_PRESENT_ADDR; //0x0042880C; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ, TRUE, 4, (uint8_t*)&spi_API); // now read back the value from the data port. AJ_WSL_SPI_HostControlRegisterRead(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = LE32_TO_CPU(spi_API); //AJ_InfoPrintf(("host if flash is present read back was %ld \n", spi_API)); } // now write out the flash_is_present value spi_API = 0x00000002; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_FLASH_PRESENT_ADDR; //0x0042880C; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE, TRUE, 4, (uint8_t*)&spi_API); // read the mbox block size spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_MBOX_BLOCKSZ_ADDR; //0x0042886C; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ, TRUE, 4, (uint8_t*)&spi_API); // now read back the value from the data port. AJ_WSL_SPI_HostControlRegisterRead(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = LE32_TO_CPU(spi_API); AJ_WSL_MBOX_BLOCK_SIZE = spi_API; //AJ_InfoPrintf(("block size was %ld \n", spi_API)); spi_API16 = 0x001f; spi_API16 = CPU_TO_LE16(spi_API16); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API16); // wait until the write has been processed. spi_API16 = 0; while (!(spi_API16 & 1)) { AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_SPI_STATUS, (uint8_t*)&spi_API16); spi_API16 = LE16_TO_CPU(spi_API16); uint16_t space = 0; AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, (uint8_t*)&space); } // clear the read and write interrupt cause register spi_API = (1 << 9) | (1 << 8); spi_API = CPU_TO_LE16(spi_API); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, spi_API); { spi_API16 = 0x1; spi_API16 = CPU_TO_LE16(spi_API16); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE, spi_API16); // waiting seems to allow the following write to succeed and thus enable interrupts. // we need something more deterministic. AJ_Sleep(1000); spi_API16 = 0x00FF; spi_API = CPU_TO_LE16(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_CPU_INT_STATUS, FALSE, 1, (uint8_t*)&spi_API16); } } extern AJ_WSL_HTC_CONTEXT AJ_WSL_HTC_Global; extern wsl_socket_context AJ_WSL_SOCKET_CONTEXT[5]; extern volatile uint8_t g_b_spi_interrupt_data_ready; void AJ_WSL_MBoxListenAndProcessTask(void* parameters) { g_b_spi_interrupt_data_ready = FALSE; AJ_WSL_SPI_InitializeSPIController(); set_SPI_registers(); write_BOOT_PARAM(); g_b_spi_interrupt_data_ready = FALSE; // loop and process all of the responses while (1) { AJ_Status status; AJ_WSL_HTC_ProcessInterruptCause(); uint8_t i; for (i = 0; i < AJ_WSL_SOCKET_MAX; i++) { do { wsl_work_item* item = NULL; // peek at the queue, then make sure we have enough credits // if we have enough, pull and send the workitem to the MBOX // otherwise, move to the next socket and then eventually out of this loop. // Credits would be available again once AJ_WSL_HTC_ProcessInterruptCause has // read any credit-adjustment trailers status = AJ_QueuePeek(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue, &item); if ((status != AJ_OK) || (AJ_WSL_HTC_Global.endpoints[item->endpoint].txCredits < 1)) { break; } // pull a work item off of a socket queue and send it status = AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue, &item, 0); if (!item || (status != AJ_OK) || !item->list) { break; } else { //AJ_AlwaysPrintf(("AJ_WSL_MBoxListenAndProcessTask: %x\n", item->itemType)); AJ_WSL_WriteBufListToMBox(0, item->endpoint, AJ_BufListLengthOnWire(item->list), item->list); /* * if this item is sending data, create a workitem indicating completion * this special check is needed because there is no socket send command in WMI, * otherwise we could handle it in AJ_WSL_WMI_ProcessWMIEvent */ if (item->itemType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_NET_DATA_TX)) { wsl_work_item** ppWork; wsl_work_item* sockWork; sockWork = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(sockWork, 0, sizeof(wsl_work_item)); sockWork->itemType = item->itemType; sockWork->endpoint = item->endpoint; ppWork = &sockWork; AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[i].workRxQueue, ppWork, AJ_TIMER_FOREVER); } AJ_WSL_WMI_FreeWorkItem(item); } } while (1); } if (!g_b_spi_interrupt_data_ready) { AJ_YieldCurrentTask(); } g_b_spi_interrupt_data_ready = FALSE; // reset the state of the interrupt signal } } ajtcl-16.04/src/wsl/aj_wsl_tasks.h000066400000000000000000000026151271074662300170660ustar00rootroot00000000000000/** * @file Function declarations for tasks */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_TASKS_H_ #define AJ_WSL_TASKS_H_ #include #include #include "aj_wsl_target.h" #ifdef __cplusplus extern "C" { #endif /** * This file contains the task and structure definitions for the WSL "driver" code * */ AJ_EXPORT void AJ_WSL_MBoxListenAndProcessTask(void* parameters); #ifdef __cplusplus } #endif #endif /* AJ_WSL_TASKS_H_ */ ajtcl-16.04/src/wsl/aj_wsl_unmarshal.c000066400000000000000000000133631271074662300177300ustar00rootroot00000000000000/** * @file Unmarshaling implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include #define str(x) # x #define xstr(x) str(x) #define PRE 0x10 #define POST 0x00 #define AJ_WSL_SSID_IE 0x00 #define AJ_WSL_RSN_IE 0x30 #define AJ_RSSI_BYTE 15 //Byte location where the signal strength is #define AJ_MAC_BYTE 16 //Byte location where the mac address is #define AJ_80211_START 36 //Byte location where the 802.11 IE section begins wsl_scan_item* WMI_UnmarshalScan(void* data, uint16_t length) { wsl_scan_item* scan; uint8_t* ptr; uint16_t i = AJ_80211_START; //start of IE section uint8_t hasSecurity = 0; ptr = (uint8_t*)data; scan = (wsl_scan_item*)WSL_InitScanItem(); /* * Get signal strength */ scan->rssi = *(ptr + AJ_RSSI_BYTE); /* * Get MAC address */ memcpy(scan->bssid, (ptr + AJ_MAC_BYTE), 6); /* * Go through each IE until the packet it over and get what we need * (SSID and RSN). */ while (i < (length - AJ_80211_START)) { uint8_t EID; uint8_t EIDlen; EID = *(ptr + i); i++; EIDlen = *(ptr + i); i++; switch (EID) { case (0x00): scan->ssid = (char*)AJ_WSL_Malloc((sizeof(char) * EIDlen) + 1); memcpy(scan->ssid, (ptr + i), EIDlen); scan->ssid[EIDlen] = '\0'; i += EIDlen; break; case (0x30): /* * 5 bytes into the RSN IE is the security information */ if (*(ptr + i + 5) == 2) { scan->secType = AJ_WIFI_SECURITY_WPA; scan->cipherType = AJ_WIFI_CIPHER_TKIP; } else if (*(ptr + i + 5) == 4) { scan->secType = AJ_WIFI_SECURITY_WPA2; scan->cipherType = AJ_WIFI_CIPHER_CCMP; } else { scan->secType = AJ_WIFI_SECURITY_WEP; scan->cipherType = AJ_WIFI_CIPHER_WEP; } hasSecurity = 1; i += EIDlen; break; default: i += EIDlen; break; } } if (!hasSecurity) { scan->secType = AJ_WIFI_SECURITY_NONE; scan->cipherType = AJ_WIFI_CIPHER_NONE; } return scan; } int32_t WMI_Unmarshal(void* data, const char* sig, ...) { va_list args; uint8_t* ptr; va_start(args, sig); ptr = (uint8_t*)data; while (*sig) { switch (*sig++) { case (WMI_ARG_UINT64): { uint64_t* u64; u64 = (uint64_t*)va_arg(args, uint64_t); memcpy(u64, ptr, sizeof(uint64_t)); ptr += 8; } break; case (WMI_ARG_UINT32): { uint32_t* u32; u32 = (uint32_t*)va_arg(args, uint32_t); memcpy(u32, ptr, sizeof(uint32_t)); ptr += 4; } break; case (WMI_ARG_UINT16): { uint16_t* u16; u16 = (uint16_t*)va_arg(args, uint32_t); memcpy(u16, ptr, sizeof(uint16_t)); ptr += 2; } break; case (WMI_ARG_MAC): { uint8_t* mac; mac = (uint8_t*)va_arg(args, uint32_t); memcpy(mac, ptr, sizeof(uint8_t) * 6); ptr += 6; } break; case (WMI_ARG_IPV4): { uint8_t* IPv4; IPv4 = (uint8_t*)va_arg(args, uint32_t); memcpy(IPv4, ptr, sizeof(uint8_t) * 4); ptr += 4; } break; case (WMI_ARG_IPV6): { uint8_t* IPv6; IPv6 = (uint8_t*)va_arg(args, uint32_t); memcpy(IPv6, ptr, sizeof(uint8_t) * 16); ptr += 16; } break; case (WMI_ARG_BYTE): { uint8_t* u8; u8 = (uint8_t*)va_arg(args, uint32_t); memcpy(u8, ptr, sizeof(uint8_t)); ptr += 1; } break; case (WMI_ARG_STRING): { char** str; uint8_t size; memcpy(&size, ptr, sizeof(uint8_t)); ptr++; str = (char**)va_arg(args, char*); *str = (char*)AJ_WSL_Malloc(sizeof(char) * size + 1); memcpy(*str, ptr, sizeof(char) * size + 1); (*str)[size] = '\0'; ptr += size; } break; } } va_end(args); return ptr - (uint8_t*)data; } ajtcl-16.04/src/wsl/aj_wsl_unmarshal.h000066400000000000000000000116141271074662300177320ustar00rootroot00000000000000/** * @file Unmarshaling declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include "aj_wsl_target.h" #include "aj_wsl_wmi.h" #include "aj_wsl_net.h" #ifdef __cplusplus extern "C" { #endif /* * Basic Types */ #define WMI_ARG_INVALID '\0' /**< AllJoyn invalid type */ #define WMI_ARG_ARRAY 'a' /**< AllJoyn array container type */ #define WMI_ARG_BOOLEAN 'b' /**< AllJoyn boolean basic type */ #define WMI_ARG_INT32 'i' /**< AllJoyn 32-bit signed integer basic type */ #define WMI_ARG_INT16 'n' /**< AllJoyn 16-bit signed integer basic type */ #define WMI_ARG_UINT16 'q' /**< AllJoyn 16-bit unsigned integer basic type */ #define WMI_ARG_STRING 's' /**< AllJoyn UTF-8 NULL terminated string basic type */ #define WMI_ARG_UINT32 'u' /**< AllJoyn 32-bit unsigned integer basic type */ #define WMI_ARG_UINT64 't' #define WMI_ARG_VARIANT 'v' /**< AllJoyn variant container type */ #define WMI_ARG_BYTE 'y' /**< AllJoyn 8-bit unsigned integer basic type */ #define WMI_ARG_STRUCT '(' /**< AllJoyn struct container type */ #define WMI_ARG_DICT_ENTRY '{' /**< AllJoyn dictionary or map container type - an array of key-value pairs */ /* * Specific WMI types */ #define WMI_ARG_MAC 'M' /**< MAC address */ #define WMI_ARG_IPV4 '4' /**< IPV4 Address */ #define WMI_ARG_IPV6 '6' /**< IPV6 Address */ #define WMI_ARG_SSID 'S' /**< SSID 32 byte */ #define WMI_ARG_BSSID 'B' /**< BSSID */ #define WMI_ARG_ENCRYPTION 'E' /**< Encryption type */ #define WMI_ARG_SIZE 'Z' /**< Size specifier */ #define WMI_ARG_RSSI 'R' /**< RSSI */ #define WMI_ARG_HEADER 'H' /**< WMI Header */ #define WMI_ARG_PASSPHRASE 'P' /**< 64 Byte pass phrase */ #define WMI_ARG_TAG 'T' /**< Tag identifier */ #define WMI_ARG_KEY 'K' /**< Cipher key/ Pairwise master key (32 byte) */ //#define WMI_TYPE_SCAN "HP09RMP0eS" /**< WiFi scan. [Header][RSSI][MAC][SSID] */ typedef enum { BSS_SCAN = 0x1004 }EVENT; typedef enum { TAG_SSID = 0, TAG_CHANNEL = 3, TAG_RSN = 48, TAG_VENDOR = 221 }TAG_NUMBERS; typedef struct { uint8_t length; void* data; }RSN_INFO; typedef struct { uint8_t size; void* data; }TAG_INFO; typedef struct { uint16_t channel; uint8_t frame; uint8_t rssi; uint8_t bssid[6]; uint32_t seq_num; }BSS_INFO; typedef struct _WMI_HDR_INFO { uint8_t flag; /* Flag in the header (second byte) */ uint16_t size; /* Size of the packet (bytes 3 and 4) */ uint8_t offset; /* Offset (byte 5) */ uint8_t id; /* Packet ID (byte 6) */ uint16_t event; /* Event type (bytes 7 and 8) */ }WMI_HDR_INFO; typedef struct { WMI_HDR_INFO* hdr_info; union { BSS_INFO bss; }event; uint8_t timestamp[8]; uint16_t interval; uint16_t capabilities; char* SSID; uint8_t channel; RSN_INFO rsn_info; uint8_t* vendor; }SCAN_PACKET; /** * Generic unmarshal function. This will take a block of data and fill in * the parameters byte by byte according to the signature passed in. * * @param data Pointer to a block of data * @param sig Signature string that corresponds to the subsequent parameters * @param ...[out] Variable length list of parameters that correspond to the signature. * * @return The total size of data that was unmarshalled. */ int32_t WMI_Unmarshal(void* data, const char* sig, ...); /** * Unmarshal a BSSINFO (scan) packet. * * @param data Pointer to a block of data containing the scan info * @param lenght Size of the data block * * @return Pointer to a scan item containing parsed data. */ wsl_scan_item* WMI_UnmarshalScan(void* data, uint16_t length); #ifdef __cplusplus } #endif ajtcl-16.04/src/wsl/aj_wsl_wmi.c000066400000000000000000000663531271074662300165410ustar00rootroot00000000000000/** * @file WMI layer implementation */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE WSL_WMI #include #include #include #include #include #include #include "aj_wsl_target.h" #include "aj_wsl_spi_constants.h" #include "aj_wsl_htc.h" #include "aj_wsl_wmi.h" #include "aj_wsl_net.h" #include "aj_wsl_tasks.h" #include "aj_wsl_unmarshal.h" /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_WMI = 5; #endif extern AJ_WSL_HTC_CONTEXT AJ_WSL_HTC_Global; static uint8_t deviceMAC[6]; /* * global that holds target hardware info. */ AJ_FW_Version AJ_WSL_TargetFirmware; AJ_WifiCallbackFunc AJ_WSL_WifiConnectCallback; extern wsl_socket_context AJ_WSL_SOCKET_CONTEXT[AJ_WSL_SOCKET_MAX]; /** * globals to track open socket slots */ uint32_t AJ_WSL_SOCKET_HANDLE_INVALID = UINT32_MAX; struct AJ_TaskHandle* AJ_WSL_MBoxListenHandle; #ifndef NDEBUG const char* WSL_WorkItemText(uint32_t status); #endif /* * Maps command ID's and signatures * Use the enum "wsl_wmi_command_list" to index */ const CMDID_SIG_MAP cmd_map[] = { { 0x0001, "quyyyyyyyySqMqq", 0x3a }, //CONNECT { 0x0007, "quuuuuyyq", 0x1a }, //START_SCAN { 0x0008, "quqqqqqyyqqu", 0x1a }, //SET_SCAN_PARAMS { 0x0009, "quyyqu", 0x0e }, //SET_BSS_FILTER { 0x000a, "quyyyS", 0x29 }, //SET_PROBED_SSID { 0xf01b, "quqq", 0x0a }, //ALLOW_AGGR { 0x0012, "quy", 0x07 }, //SET_POWER_MODE { 0xf048, "quSPyy", 0x68 }, //SET_PASSPHRASE { 0xf04e, "quyy", 0x08 }, //STORECALL_CONFIGURE { 0xf08d, "", 0 }, //SOCKET { 0xf00f, "quyyyyyyyySqMqq", 0x3a }, //SET_SOFT_AP { 0, "uuyyyyyyyyyyuy", 0x52 }, //SEND { 0, "uuyyyyyyyyyyuy", 0x1e }, //SENDTO { 0x0003, "qu", 0x06 }, //DISCONNECT { 0xf00b, "quy", 0x07 }, //SET_HIDDEN_AP { 0, "uuyyyyyyyyyyuyyyyyyyyqqu6uy", 0x4c }, //SENDTO6 { 0, "uuuuqq6uuu", 0x32 }, //BIND6 { 0x0016, "quyyyyuuKyM", 0x39 }, //ADD_CIPHER_KEY { 0xf028, "quKy", 0x27 } //SET_PMK }; const uint16_t getCommandId(wsl_wmi_command_list command) { return cmd_map[command].id; } const char* getCommandSignature(wsl_wmi_command_list command) { return cmd_map[command].signature; } const uint16_t getPacketSize(wsl_wmi_command_list command) { return cmd_map[command].size; } /* * Map of socket commands to signatures * The socket id is the index in the array */ const SOCKET_SIG_MAP sock_map[] = { { "uuuu", 20 }, //OPEN { "uu", 12 }, //CLOSE { "uuqq4q", 26 }, //CONNECT { "uuqq4q", 26 }, //BIND { "", 0 }, { "", 0 }, { "", 0 }, { "uuuuu", 41 }, //SETSOCKOPT { "", 0 }, { "", 0 }, { "uu4446666uuuu", 110 }, //IP_CONFIG { "", 0 }, { "uyyyy", 12 }, //STACK_INIT { "", 0 }, { "", 0 }, { "uu4446666uuuu", 104 }, //IP6_CONFIG { "u44u", 20 }, //IPCONFIG_DHCP_POOL { "u6uuu", 36 }, //IP6_CONFIG_ROUTER_PREFIX { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "uS", 46 } //SET_HOSTNAME }; const char* getSockSignature(wsl_socket_cmds command) { return sock_map[command].signature; } uint16_t getSockSize(wsl_socket_cmds command) { return sock_map[command].size; } uint8_t* getDeviceMac(void) { return (uint8_t*)&deviceMAC; } static const AJ_HeapConfig wsl_heapConfig[] = { { 8, 30, 0 }, { 16, 100, 0 }, { 20, 80, 0 }, { 24, 10, 0 }, { 32, 20, 0 }, { 48, 10, 0 }, { 64, 10, 0 }, { 84, 6, 0 }, { 100, 2, 0 }, }; #define WSL_HEAP_WORD_COUNT (7360 / 4) static uint32_t wsl_heap[WSL_HEAP_WORD_COUNT]; void* AJ_WSL_Malloc(size_t size) { void* mem = NULL; // allocate from the WSL pool first. AJ_EnterCriticalRegion(); if (size <= 100) { mem = AJ_PoolAlloc(size); } // if the pool was full or the size too big, fall back to malloc if (!mem) { mem = AJ_Malloc(size); } if (!mem) { AJ_ErrPrintf(("AJ_WSL_Malloc(): Malloc failed\n")); AJ_Reboot(); } AJ_LeaveCriticalRegion(); return mem; } void AJ_WSL_Free(void* ptr) { AJ_EnterCriticalRegion(); // if the address is within the WSL heap, free the pool entry, else fallback to free. if ((ptr > (void*)&wsl_heap) && (ptr < (void*)&wsl_heap[WSL_HEAP_WORD_COUNT])) { AJ_PoolFree(ptr); } else { AJ_Free(ptr); } AJ_LeaveCriticalRegion(); } void AJ_WSL_ModuleInit(void) { //prepare the WSL heap size_t heapSz; heapSz = AJ_PoolRequired(wsl_heapConfig, ArraySize(wsl_heapConfig)); if (heapSz > sizeof(wsl_heap)) { AJ_ErrPrintf(("Heap space is too small %d required %d\n", sizeof(wsl_heap), heapSz)); return; } AJ_InfoPrintf(("Allocated heap %d bytes\n", (int)heapSz)); AJ_PoolInit(wsl_heap, heapSz, wsl_heapConfig, ArraySize(wsl_heapConfig)); AJ_PoolDump(); AJ_WSL_SOCKNUM i; for (i = 0; i < AJ_WSL_SOCKET_MAX; i++) { memset(&AJ_WSL_SOCKET_CONTEXT[i], 0, sizeof(AJ_WSL_SOCKET_CONTEXT[0])); AJ_WSL_SOCKET_CONTEXT[i].targetHandle = AJ_WSL_SOCKET_HANDLE_INVALID; AJ_WSL_SOCKET_CONTEXT[i].stashedRxList = AJ_BufListCreate(); AJ_WSL_SOCKET_CONTEXT[i].workRxQueue = AJ_QueueCreate("RxQueue"); AJ_WSL_SOCKET_CONTEXT[i].workTxQueue = AJ_QueueCreate("TxQueue"); } AJ_WSL_WMI_ModuleInit(); } AJ_Status AJ_WSL_DriverStart(void) { AJ_CreateTask(AJ_WSL_MBoxListenAndProcessTask, (const signed char*)"AJWSLMBoxListen", 1000, NULL, 2, &AJ_WSL_MBoxListenHandle); while (!AJ_WSL_IsDriverStarted()); return AJ_OK; } AJ_Status AJ_WSL_DriverStop(void) { AJ_DestroyTask(AJ_WSL_MBoxListenHandle); return AJ_OK; } void AJ_WSL_WMI_ModuleInit() { AJ_WSL_HTC_ModuleInit(); } void AJ_WSL_WMI_PrintMessage(AJ_BufNode* pNodeWMIPacket) { AJ_AlwaysPrintf(("WMI_PrintMessage node %p, length %d, buffer %p\n", pNodeWMIPacket, pNodeWMIPacket->length, pNodeWMIPacket->buffer)); } /** * return index of matching socket or AJ_WSL_SOCKET_MAX on not found * skip the global socket context */ AJ_WSL_SOCKNUM AJ_WSL_FindOpenSocketContext(void) { AJ_WSL_SOCKNUM i; for (i = 1; i < ArraySize(AJ_WSL_SOCKET_CONTEXT); i++) { if (AJ_WSL_SOCKET_CONTEXT[i].valid == FALSE) { return i; } } return INVALID_SOCKET; } /** * return index of matching socket or AJ_WSL_SOCKET_MAX on not found */ AJ_WSL_SOCKNUM AJ_WSL_FindSocketContext(uint32_t handle) { AJ_WSL_SOCKNUM i; for (i = 0; i < ArraySize(AJ_WSL_SOCKET_CONTEXT); i++) { if (AJ_WSL_SOCKET_CONTEXT[i].targetHandle == handle) { return i; } } return INVALID_SOCKET; } void AJ_WSL_WMI_ProcessWMIEvent(AJ_BufNode* pNodeHTCBody) { uint16_t eventID; uint16_t info1; uint16_t reserved; int32_t dataUnmarshaled; dataUnmarshaled = WMI_Unmarshal(pNodeHTCBody->buffer, "qqq", &eventID, &info1, &reserved); switch (eventID) { case WSL_WMI_READY_EVENTID: { uint8_t capability; dataUnmarshaled += WMI_Unmarshal(pNodeHTCBody->buffer + dataUnmarshaled, "uuMy", &AJ_WSL_TargetFirmware.target_ver, &AJ_WSL_TargetFirmware.abi_ver, &deviceMAC, &capability); AJ_InfoPrintf(("WMI_READY, version A %08lx, version B %08lx capability %x\n", AJ_WSL_TargetFirmware.target_ver, AJ_WSL_TargetFirmware.abi_ver, capability)); AJ_InfoPrintf(("Device MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", deviceMAC[0], deviceMAC[1], deviceMAC[2], deviceMAC[3], deviceMAC[4], deviceMAC[5])); AJ_WSL_HTC_Global.started = TRUE; break; } case WSL_BSS_INFO_EVENTID: { extern void AJ_WSL_BSSINFO_Recv(AJ_BufNode* node); AJ_WSL_BSSINFO_Recv(pNodeHTCBody); break; } case WSL_CMDERROR_EVENTID: { uint16_t commandId; uint8_t error; dataUnmarshaled += WMI_Unmarshal(pNodeHTCBody->buffer + dataUnmarshaled, "qy", &commandId, &error); AJ_InfoPrintf(("WMI_CMDERROR, last command %04x, error code %02x \n", commandId, error)); break; } case WSL_WMI_SCAN_COMPLETE_EVENTID: { // now signal the waiting code that the scan has completed // we can do this by posting an item to the global socket context recv queue // the client will pull off a scan complete event and then continue. wsl_work_item* scanCompleteResponse; wsl_work_item** pItem; scanCompleteResponse = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(scanCompleteResponse, 0, sizeof(wsl_work_item)); scanCompleteResponse->itemType = WSL_NET_SCAN; scanCompleteResponse->node = AJ_BufNodeCreateAndTakeOwnership(pNodeHTCBody); pItem = &scanCompleteResponse; AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[0].workRxQueue, pItem, AJ_TIMER_FOREVER); break; } case WSL_WMI_DISCONNECT_EVENTID: { uint16_t protocolReason; uint8_t bssid[6]; uint16_t disconnectReason; WMI_Unmarshal(pNodeHTCBody->buffer + dataUnmarshaled, "qMq", &protocolReason, &bssid, &disconnectReason); AJ_InfoPrintf(("WMI_DISCONNECT event: protocolReason %x, disconnectReason %x\n", protocolReason, disconnectReason)); if (AJ_WSL_WifiConnectCallback) { (AJ_WSL_WifiConnectCallback)(0); } // now signal the waiting code that the scan has completed // we can do this by posting an item to the global socket context recv queue // the client will pull off a scan complete event and then continue. wsl_work_item* disconnectResponse; wsl_work_item** pItem; disconnectResponse = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(disconnectResponse, 0, sizeof(wsl_work_item)); disconnectResponse->itemType = WSL_NET_DISCONNECT; disconnectResponse->node = AJ_BufNodeCreateAndTakeOwnership(pNodeHTCBody); pItem = &disconnectResponse; AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[0].workRxQueue, pItem, AJ_TIMER_FOREVER); break; } case WSL_WMI_CONNECT_EVENTID: { // now signal the waiting code that the scan has completed // we can do this by posting an item to the global socket context recv queue // the client will pull off a scan complete event and then continue. wsl_work_item* connectResponse; wsl_work_item** pItem; connectResponse = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(connectResponse, 0, sizeof(wsl_work_item)); connectResponse->itemType = WSL_NET_CONNECT; connectResponse->node = AJ_BufNodeCreateAndTakeOwnership(pNodeHTCBody); pItem = &connectResponse; AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[0].workRxQueue, pItem, AJ_TIMER_FOREVER); if (AJ_WSL_WifiConnectCallback) { (AJ_WSL_WifiConnectCallback)(1); } break; } case WSL_WMI_SOCKET_RESPONSE_EVENTID: { uint32_t responseType; uint32_t socketHandle; uint32_t error; WMI_Unmarshal(pNodeHTCBody->buffer + dataUnmarshaled, "uuu", &responseType, &socketHandle, &error); int8_t socketIndex; //AJ_BufListNodePrintDump(pNodeHTCBody, NULL); /* look for the matching handle in the global context then mark it invalid */ switch (responseType) { // some of the commands operate on the global socket context case WSL_SOCK_OPEN: case WSL_SOCK_IPCONFIG: case WSL_SOCK_IP6CONFIG: case WSL_SOCK_STACK_INIT: case WSL_SOCK_IP_HOST_NAME: socketIndex = 0; break; default: { socketIndex = AJ_WSL_FindSocketContext(socketHandle); if (socketIndex == INVALID_SOCKET) { AJ_DumpBytes("INVALID SOCKET DUMP", pNodeHTCBody->buffer, pNodeHTCBody->length); AJ_WarnPrintf(("SOCKET_PING response for invalid socket!\n")); break; } } } if (socketIndex != INVALID_SOCKET) { AJ_Status status = AJ_OK; //push a work item into the Read queue if (status == AJ_OK) { wsl_work_item** ppWork; wsl_work_item* sockResp; sockResp = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(sockResp, 0, sizeof(wsl_work_item)); sockResp->itemType = AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, responseType); //sockResp->size = payloadSize; sockResp->node = AJ_BufNodeCreateAndTakeOwnership(pNodeHTCBody); ppWork = &sockResp; AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[socketIndex].workRxQueue, ppWork, AJ_TIMER_FOREVER); } if ((responseType == AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, WSL_SOCK_CLOSE)) && (socketIndex != INVALID_SOCKET)) { AJ_WSL_SOCKET_CONTEXT[socketIndex].targetHandle = UINT32_MAX; AJ_WSL_SOCKET_CONTEXT[socketIndex].valid = FALSE; } } break; } case WSL_WMI_PEER_NODE_EVENTID: { uint8_t reason; WMI_Unmarshal(pNodeHTCBody->buffer + dataUnmarshaled, "q", &reason); if ((reason == 0) /*&& (AJ_WSL_connectState == AJ_WIFI_CONNECTING)*/) { /* * The 4-way handshake is complete, indicate the state has changed */ if (AJ_WSL_WifiConnectCallback) { (AJ_WSL_WifiConnectCallback)(16 /*RSNA_AUTH_SUCCESS*/); } } break; } // There are several WMI events that aren't parsed. case WSL_REGDOMAIN_EVENTID: case WSL_UNKNOWN2_EVENTID: case WSL_UNKNOWN1_EVENTID: break; default: { AJ_InfoPrintf(("Unknown WMI Event %x\n", eventID)); return; } } AJ_InfoPrintf(("Processed WMI Event: %s\n", WSL_WorkItemText(eventID))); } void AJ_WSL_WMI_ProcessSocketDataResponse(AJ_BufNode* pNodeHTCBody) { int8_t socketIndex; uint32_t u32; uint16_t lead, payloadSize, _port; uint32_t _handle, srcAddr; uint16_t ipv6addr[8]; uint16_t bufferOffset = 0; wsl_work_item** ppWork; wsl_work_item* sockResp; // AJ_DumpBytes("WMI_SOCKET_RESPONSE B", pNodeHTCBody->buffer, pNodeHTCBody->length); // Get the initial bytes of data in the packet WMI_Unmarshal(pNodeHTCBody->buffer, "quuq", &lead, &u32, &_handle, &_port); //AJ_BufNodePullBytes(pNodeHTCBody, 12); bufferOffset += 12; // look for the matching handle in the global context then mark it invalid socketIndex = AJ_WSL_FindSocketContext(_handle); if (socketIndex == INVALID_SOCKET) { AJ_WarnPrintf(("data returned for invalid socket. Handle = %lu\n", _handle)); return; } if (AJ_WSL_SOCKET_CONTEXT[socketIndex].domain == WSL_AF_INET6) { bufferOffset += 6; // Get the IPv6 address and payload size WMI_Unmarshal(pNodeHTCBody->buffer + bufferOffset, "6uq", &ipv6addr, &u32, &payloadSize); // Advance the buffer to the start of the payload bufferOffset += 28; } else { bufferOffset += 2; // Get the IPv4 address WMI_Unmarshal(pNodeHTCBody->buffer + bufferOffset, "4q", &srcAddr, &payloadSize); // Advance the buffer to the start of the payload bufferOffset += 12; } sockResp = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(sockResp, 0, sizeof(wsl_work_item)); sockResp->itemType = WSL_NET_DATA_RX; sockResp->size = payloadSize; sockResp->node = AJ_BufNodeCreateAndTakeOwnership(pNodeHTCBody); AJ_BufNodePullBytes(sockResp->node, bufferOffset); /// the length of the socket header info header sockResp->node->length = payloadSize; ppWork = &sockResp; AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[socketIndex].workRxQueue, ppWork, AJ_TIMER_FOREVER); } AJ_Status AJ_WSL_WMI_QueueWorkItem(uint32_t socket, uint8_t command, uint8_t endpoint, AJ_BufList* list) { AJ_InfoPrintf(("AJ_WSL_WMI_QueueWorkItem(): %s\n", WSL_WorkItemText(command))); wsl_work_item** ppWork; wsl_work_item* sockWork; sockWork = (wsl_work_item*)AJ_WSL_Malloc(sizeof(wsl_work_item)); memset(sockWork, 0, sizeof(wsl_work_item)); sockWork->itemType = command; sockWork->list = list; sockWork->endpoint = endpoint; ppWork = &sockWork; AJ_ResumeTask(AJ_WSL_MBoxListenHandle, 0); // wake up the driver task so it can create space in the workTxQueue AJ_QueuePush(AJ_WSL_SOCKET_CONTEXT[socket].workTxQueue, ppWork, AJ_TIMER_FOREVER); AJ_ResumeTask(AJ_WSL_MBoxListenHandle, 0); // wake up the driver task after pushing, allowing the task to process the workitem return AJ_OK; } /* * This function just returns the work item. If there is data inside that you want * you have to unmarshal it after you receive the work item. */ AJ_Status AJ_WSL_WMI_WaitForWorkItem(uint32_t socket, uint8_t command, wsl_work_item** item, uint32_t timeout) { AJ_Status status; AJ_Time timer; AJ_InitTimer(&timer); // AJ_AlwaysPrintf(("WaitForWorkItem: %x\n", command)); //wsl_work_item* item; status = AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[socket].workRxQueue, item, timeout); timeout -= AJ_GetElapsedTime(&timer, TRUE); if ((status == AJ_OK) && item && *item) { if ((status == AJ_OK) && ((*item)->itemType == WSL_NET_INTERUPT)) { // We don't care about the interrupted signal for any calls using this function AJ_WSL_WMI_FreeWorkItem((*item)); status = AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[socket].workRxQueue, item, timeout); } if ((status == AJ_OK) && ((*item)->itemType == command)) { AJ_InfoPrintf(("AJ_WSL_WMI_WaitForWorkItem(): Received work item %s\n", WSL_WorkItemText(command))); return AJ_OK; } else if ((status == AJ_OK) && ((*item)->itemType == WSL_NET_DISCONNECT)) { AJ_InfoPrintf(("Got disconnect while waiting for %s\n", WSL_WorkItemText(command))); // Clean up the network queues int i; for (i = 0; i < AJ_WSL_SOCKET_MAX; i++) { wsl_work_item* clear; AJ_WSL_SOCKET_CONTEXT[i].valid = FALSE; // Removed any stashed data AJ_BufListFree(AJ_WSL_SOCKET_CONTEXT[i].stashedRxList, 1); // Reallocate a new stash AJ_WSL_SOCKET_CONTEXT[i].stashedRxList = AJ_BufListCreate(); // Reset the queue, any work items are now invalid since the socket was closed while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workRxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue, &clear, 0) == AJ_OK) { AJ_WSL_WMI_FreeWorkItem(clear); } AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[i].workRxQueue); AJ_QueueReset(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue); } AJ_WSL_WMI_FreeWorkItem((*item)); return AJ_ERR_LINK_DEAD; } else if ((status == AJ_OK) && ((*item)->itemType == WSL_NET_DATA_RX)) { // If we got data we want to save it and not throw it away, its still not what we // wanted so we can free the work item as it wont be needed at a higher level AJ_InfoPrintf(("Got data while waiting for %s\n", WSL_WorkItemText(command))); if ((*item)->node->length) { AJ_BufNode* new_node = AJ_BufNodeCreateAndTakeOwnership((*item)->node); AJ_BufListPushTail(AJ_WSL_SOCKET_CONTEXT[socket].stashedRxList, new_node); AJ_WSL_WMI_FreeWorkItem((*item)); return AJ_ERR_NULL; } } else { AJ_WarnPrintf(("AJ_WSL_WMI_WaitForWorkItem(): Received incorrect work item %s, wanted %s\n", WSL_WorkItemText((*item)->itemType), WSL_WorkItemText(command))); // Wrong work item, but return NULL because we can free the item internally AJ_WSL_WMI_FreeWorkItem((*item)); return AJ_ERR_NULL; } } return AJ_ERR_NULL; } void AJ_WSL_WMI_FreeWorkItem(wsl_work_item* item) { if (item) { AJ_BufListFree(item->list, TRUE); AJ_BufListFreeNodeAndBuffer(item->node, NULL); AJ_WSL_Free(item); } } #ifndef NDEBUG #define AJ_CASE_NETWORK(_status) case AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_NETWORK, _status): return # _status #define AJ_CASE_SOCKET(_status) case AJ_WSL_WORKITEM(AJ_WSL_WORKITEM_SOCKET, _status): return # _status #define AJ_CASE_GENERIC(_status) case _status: return # _status const char* WSL_WorkItemText(uint32_t status) { static char buf[4]; switch (status) { // Network cases AJ_CASE_NETWORK(WSL_CONNECT); AJ_CASE_NETWORK(WSL_START_SCAN); AJ_CASE_NETWORK(WSL_SET_SCAN_PARAMS); AJ_CASE_NETWORK(WSL_SET_BSS_FILTER); AJ_CASE_NETWORK(WSL_SET_PROBED_SSID); AJ_CASE_NETWORK(WSL_ALLOW_AGGR); AJ_CASE_NETWORK(WSL_SET_POWER_MODE); AJ_CASE_NETWORK(WSL_SET_PASSPHRASE); AJ_CASE_NETWORK(WSL_STORECALL_CONFIGURE); AJ_CASE_NETWORK(WSL_SOCKET); AJ_CASE_NETWORK(WSL_SET_SOFT_AP); AJ_CASE_NETWORK(WSL_SEND); AJ_CASE_NETWORK(WSL_SENDTO); AJ_CASE_NETWORK(WSL_DISCONNECT); AJ_CASE_NETWORK(WSL_SET_HIDDEN_AP); AJ_CASE_NETWORK(WSL_SENDTO6); AJ_CASE_NETWORK(WSL_BIND6); AJ_CASE_NETWORK(WSL_ADD_CIPHER_KEY); AJ_CASE_NETWORK(WMI_SET_PMK); // Socket cases AJ_CASE_SOCKET(WSL_SOCK_OPEN); AJ_CASE_SOCKET(WSL_SOCK_CLOSE); AJ_CASE_SOCKET(WSL_SOCK_CONNECT); AJ_CASE_SOCKET(WSL_SOCK_BIND); AJ_CASE_SOCKET(WSL_SOCK_SELECT); AJ_CASE_SOCKET(WSL_SOCK_SETSOCKOPT); AJ_CASE_SOCKET(WSL_SOCK_GETSOCKOPT); AJ_CASE_SOCKET(WSL_SOCK_IPCONFIG); AJ_CASE_SOCKET(WSL_SOCK_IP6CONFIG); AJ_CASE_SOCKET(WSL_SOCK_PING); AJ_CASE_SOCKET(WSL_SOCK_STACK_INIT); AJ_CASE_SOCKET(WSL_SOCK_STACK_MISC); AJ_CASE_SOCKET(WSL_NET_DATA_TX); AJ_CASE_SOCKET(WSL_SOCK_IP_HOST_NAME); AJ_CASE_SOCKET(WSL_SOCK_IP6CONFIG_ROUTER_PREFIX); // Events AJ_CASE_GENERIC(WSL_WMI_READY_EVENTID); AJ_CASE_GENERIC(WSL_WMI_CONNECT_EVENTID); AJ_CASE_GENERIC(WSL_WMI_DISCONNECT_EVENTID); AJ_CASE_GENERIC(WSL_BSS_INFO_EVENTID); AJ_CASE_GENERIC(WSL_CMDERROR_EVENTID); AJ_CASE_GENERIC(WSL_WMI_SCAN_COMPLETE_EVENTID); AJ_CASE_GENERIC(WSL_WMI_APLIST_EVENTID); AJ_CASE_GENERIC(WSL_WMI_PEER_NODE_EVENTID); AJ_CASE_GENERIC(WSL_WMI_WLAN_VERSION_EVENTID); AJ_CASE_GENERIC(WSL_WMI_SOCKET_RESPONSE_EVENTID); default: snprintf(buf, sizeof(buf), "%lu", (uint32_t)status); return buf; } } /* * Print relevant information about the drivers current state. This should * only be called upon a crash as it will corrupt the current state information * after it has been called. */ void AJ_WSL_PrintDriverTraceback(void) { int i; dbgWSL_WMI = 5; AJ_AlwaysPrintf(("Driver state: ")); if (AJ_WSL_HTC_Global.started) { AJ_AlwaysPrintf(("Started\n")); } else { AJ_AlwaysPrintf(("Not Started\n")); } for (i = 0; i < 4; i++) { AJ_AlwaysPrintf(("Endpoint %d credits: %d\n", i, AJ_WSL_HTC_Global.endpoints[i].txCredits)); } for (i = 0; i < AJ_WSL_SOCKET_MAX; i++) { uint32_t stashSz = 0; AJ_BufNode* stashNode = AJ_WSL_SOCKET_CONTEXT[i].stashedRxList->head; int j = 0; wsl_work_item* item; AJ_AlwaysPrintf(("------ SOCKET CONTEXT %d -----\n", i)); AJ_AlwaysPrintf(("\tSocket Handle: 0x%x\n", AJ_WSL_SOCKET_CONTEXT[i].targetHandle)); if (AJ_WSL_SOCKET_CONTEXT[i].domain == WSL_AF_INET) { AJ_AlwaysPrintf(("Domain: AF_INET\n")); } else { AJ_AlwaysPrintf(("Domain: AF_INET6\n")); } if (AJ_WSL_SOCKET_CONTEXT[i].type == WSL_SOCK_STREAM) { AJ_AlwaysPrintf(("Type: SOCK_STREAM\n")); } else { AJ_AlwaysPrintf(("Type: SOCK_DGRAM\n")); } if (AJ_WSL_SOCKET_CONTEXT[i].valid) { while (stashNode != NULL) { stashSz += stashNode->length; stashNode = stashNode->next; } AJ_AlwaysPrintf(("\tStash size = %u\n", stashSz)); AJ_AlwaysPrintf(("\tworkRxQueue:\n")); while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workRxQueue, &item, 0) == AJ_OK) { AJ_AlwaysPrintf(("\t\tQueue Index %i:", j)); AJ_AlwaysPrintf(("\tItem Type: %s\n", WSL_WorkItemText(item->itemType))); j++; } if (j == 0) { AJ_AlwaysPrintf(("\tworkRxQueue empty\n")); } j = 0; AJ_AlwaysPrintf(("\tworkTxQueue:\n")); while (AJ_QueuePull(AJ_WSL_SOCKET_CONTEXT[i].workTxQueue, &item, 0) == AJ_OK) { AJ_AlwaysPrintf(("\t\tQueue Index %i:", j)); AJ_AlwaysPrintf(("\tItem Type: %s\n", WSL_WorkItemText(item->itemType))); j++; } if (j == 0) { AJ_AlwaysPrintf(("\tworkTxQueue empty\n")); } } else { AJ_AlwaysPrintf(("Socket context %d: Not valid or not open\n", i)); } AJ_AlwaysPrintf(("\n")); } } void HardFault_Handler(void) { AJ_AlwaysPrintf(("HARD FAULT OCCURED, PRINTING DRIVER TRACEBACK\n")); AJ_WSL_PrintDriverTraceback(); while (1); } #endif ajtcl-16.04/src/wsl/aj_wsl_wmi.h000066400000000000000000000221251271074662300165330ustar00rootroot00000000000000/** * @file WMI layer function declarations */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifndef AJ_WSL_WMI_H_ #define AJ_WSL_WMI_H_ #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif void AJ_WSL_WMI_ModuleInit(void); // prototype for functions that are invoked for wifi connection status typedef void (*AJ_WifiCallbackFunc)(int val); /* * Defines what byte maps to data in the header for commands/events */ #define WMI_HDR_START 0 #define WMI_HDR_FLAGS 1 #define WMI_HDR_PKT_SIZE 2 #define WMI_HDR_TRAILER_SIZE 4 #define WMI_HDR_PKT_ID 5 #define WMI_HDR_CMD_ID 6 #define IPCONFIG_QUERY 0 #define IPCONFIG_STATIC 1 #define IPCONFIG_DHCP 2 #define NUM_COMMANDS 30 #define NUM_SOCK_CMDS 29 typedef struct _CMDID_SIG_MAP { const uint16_t id; const char* signature; const uint16_t size; } CMDID_SIG_MAP; typedef struct _SOCKET_SIG_MAP { const char* signature; const uint16_t size; }SOCKET_SIG_MAP; /* * Signature definitions for various WMI Commands * Will always start with "q" (command ID) */ #define WMI_SIG_SET_SCAN_PARAMS "quqqqqqyyqqu" #define WMI_SIG_START_SCAN "quuuuuyyq" #define WMI_SIG_ALLOW_AGGR "quqq" #define WMI_SIG_CONNECT "quyyyyyyyySqMqq" #define WMI_SIG_SET_PASSPHRASE "quSPyy" #define WMI_SIG_SET_PROBED_SSID "quyyyS" #define WMI_SIG_ALLOW_AGGR "quqq" #define WMI_SIG_SET_BSS_FILTER "quyyqu" //note: on socket signatures dont add the command ID or socket command // they are marshaled in automatically #define WMI_SIG_SOCKET_IPCONFIG "uu4446666uuuu" #define WMI_SIG_SOCKET_STACK_INIT "uyyyy" #define WMI_SIG_SOCKET_OPEN "uuuu" #define WMI_SIG_SOCKET_CLOSE "uu" #define WMI_SIG_SOCKET_CONNECT "uuqq4q" #define WMI_SIG_SOCKET_BIND "uuqq4q" #define WMI_SIG_SET_POWER_MODE "quy" #define WMI_STORERECALL_CONFIG "quyy" #define WMI_SIG_IP_HOST_NAME "uS" #define WMI_SIG_SET_SOFT_AP "quyyyyyyyySqMqq" //#define WMI_SIG_CONNECT_EVENT "qMqquyyyay" #define WMI_SIG_SETSOCKOPTS "uuuuu" //ay" //Array of options is marshaled in separately typedef struct ip6_addr { uint8_t addr[16]; /* 128 bit IPv6 address */ } IP6_ADDR_T; #ifdef WIN32 typedef struct sockaddr_in SOCKADDR_T; typedef struct sockaddr_in SOCKADDR_6_T; #else typedef struct sockaddr { uint16_t sin_port; //Port number uint16_t sin_family; //ATH_AF_INET uint32_t sin_addr; //IPv4 Address } SOCKADDR_T; typedef struct sockaddr_6 { uint16_t sin6_family; // ATH_AF_INET6 uint16_t sin6_port; // transport layer port # uint32_t sin6_flowinfo; // IPv6 flow information IP6_ADDR_T sin6_addr; // IPv6 address uint32_t sin6_scope_id; // set of interfaces for a scope } SOCKADDR_6_T; #endif /* * This list is used for indexing into the CMDID_SIG_MAP */ typedef enum { WSL_CONNECT = 0, WSL_START_SCAN, WSL_SET_SCAN_PARAMS, WSL_SET_BSS_FILTER, WSL_SET_PROBED_SSID, WSL_ALLOW_AGGR, WSL_SET_POWER_MODE, WSL_SET_PASSPHRASE, WSL_STORECALL_CONFIGURE, WSL_SOCKET, WSL_SET_SOFT_AP, WSL_SEND, WSL_SENDTO, WSL_DISCONNECT, WSL_SET_HIDDEN_AP, WSL_SENDTO6, WSL_BIND6, WSL_ADD_CIPHER_KEY, WMI_SET_PMK }wsl_wmi_command_list; /* * This macro converts socket command numbers into WSL workitem numbers */ #define AJ_WSL_WORKITEM(g, c) (((uint8_t)(g) << 6) | (c)) /**< Encode a socket command into a workitem */ #define AJ_WSL_WORKITEM_NETWORK 0 #define AJ_WSL_WORKITEM_SOCKET 1 #define AJ_WSL_WORKITEM_DEVICE 2 AJ_EXPORT void AJ_WSL_WMI_PrintMessage(AJ_BufNode* pNodeWMIPacket); typedef struct _wsl_work_item { uint16_t itemType; /**< what type of work item is this*/ uint16_t sequenceNumber; /**< use this match a call with the response data */ AJ_BufList* list; /**< either the data going into or coming out of the function, direction depends on the call type */ AJ_BufNode* node; /**< either the data going into or coming out of the function, direction depends on the call type */ uint32_t size; uint8_t endpoint; /**< Which endpoint does the workitem use */ } wsl_work_item; /** * structure that maps socket handles on the target to socket handles on the host */ typedef struct _wsl_socket_context { uint32_t targetHandle; /**< holds the target-side handle value */ uint8_t valid; /**< is the socket valid? */ struct AJ_Queue* workTxQueue; /**< work items to be sent to the target are pushed here */ struct AJ_Queue* workRxQueue; /**< work items received from the target are pulled from here */ AJ_BufList* stashedRxList; /**< leftover data from a network packet waiting to be read */ uint32_t domain; /**< AF_INET or AF_INET6 */ uint32_t type; /**< SOCK_STREAM or SOCK_DGRAM*/ uint32_t protocol; /**< */ union { SOCKADDR_T name; SOCKADDR_6_T name6; }; } wsl_socket_context; /** * Find a socket number * * @param handle The socket handle * * @return The socket number with associated handle */ AJ_WSL_SOCKNUM AJ_WSL_FindSocketContext(uint32_t handle); /** * Find a socket that you can open * * @return The socket number avaliable */ AJ_WSL_SOCKNUM AJ_WSL_FindOpenSocketContext(void); /** * Process a WMI event * * @param pNodeHTCBody The buf node that was received over WMI */ AJ_EXPORT void AJ_WSL_WMI_ProcessWMIEvent(AJ_BufNode* pNodeHTCBody); /** * Process a data WMI event * * @param pNodeHTCBody The buf node that was received over WMI */ AJ_EXPORT void AJ_WSL_WMI_ProcessSocketDataResponse(AJ_BufNode* pNodeHTCBody); /** * Queue a work item to be sent to the target * * @param socket Socket to send over * @param command Enum WMI command your sending * @param endpoint Endpoint on the target to send to * @param list Buf List that your sending (must be previously marshalled) * * @return AJ_OK on success */ AJ_Status AJ_WSL_WMI_QueueWorkItem(uint32_t socket, uint8_t command, uint8_t endpoint, AJ_BufList* list); /** * Wait for a work item that was previously send on the queue * * @param socket Socket that the work item was sent to * @param command Command the was sent * @param item Address of the work item pointer * @param timeout Milliseconds to wait for this work item */ AJ_Status AJ_WSL_WMI_WaitForWorkItem(uint32_t socket, uint8_t command, wsl_work_item** item, uint32_t timeout); /** * Free a work item pointer. This frees everything inside the work item structure * * @param item Item to be freed */ void AJ_WSL_WMI_FreeWorkItem(wsl_work_item* item); /** * Get the WMI command ID from the enum command list * * @param command Enum command your getting the ID for * * @return The command ID */ const uint16_t getCommandId(wsl_wmi_command_list command); /** * Get the command signature * * @param command Command you want the signature to * * @return The signature */ const char* getCommandSignature(wsl_wmi_command_list command); /** * Get the packet size for a given command * * @param command The command you need the size for * * @return The size of the packet */ const uint16_t getPacketSize(wsl_wmi_command_list command); /** * Get the socket signature for a socket command * * @param command The SOCKET command you need the signature for * * @return The signature */ const char* getSockSignature(wsl_socket_cmds command); /** * Get the packet size for a socket command * * @param command The command you need the size for * * @return The size of the socket packet */ uint16_t getSockSize(wsl_socket_cmds command); /** * Get the devices MAC address * * @return Pointer to the MAC address data */ uint8_t* getDeviceMac(void); #ifdef __cplusplus } #endif #endif /* AJ_WSL_WMI_H_ */ ajtcl-16.04/src/wsl/alljoyn.c000066400000000000000000000140051271074662300160410ustar00rootroot00000000000000/** * @file Startup sequence for Alljoyn under the WSL build */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE ALLJOYN #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG AJ_EXPORT uint8_t dbgALLJOYN = 0; #endif #define NET_UP_TIMEOUT 5000 extern void AJ_Main(); #ifdef WIFI_SSID /* * This function is provided for testing convenience. Generates a 5 byte WEP hex key from an ascii * passphrase. We don't support the 13 byte version which uses an MD5 hash to generate the hex key * from the passphrase. */ static AJ_Status WEPKey(const char* pwd, uint8_t* hex, uint32_t hexLen) { static const uint32_t WEP_MAGIC1 = 0x343FD; static const uint32_t WEP_MAGIC2 = 0x269EC3; uint32_t i; uint32_t seed; uint8_t key[5]; for (i = 0; *pwd; ++i) { seed ^= *pwd++ << (i & 3) << 8; } for (i = 0; i < (hexLen / 2); ++i) { seed = WEP_MAGIC1 * seed + WEP_MAGIC2; key[i] = (seed >> 16); } return AJ_RawToHex(key, sizeof(key), hex, hexLen, FALSE); } static AJ_Status ConfigureWifi() { AJ_Status status = AJ_ERR_CONNECT; static const char ssid[] = WIFI_SSID; # ifdef WIFI_PASSPHRASE static const char passphrase[] = WIFI_PASSPHRASE; const AJ_WiFiSecurityType secType = AJ_WIFI_SECURITY_WPA2; # else const char* passphrase = NULL; const AJ_WiFiSecurityType secType = AJ_WIFI_SECURITY_NONE; # endif # ifdef WIFI_DEVICE_NAME static const char deviceName[] = WIFI_DEVICE_NAME; AJ_WSL_NET_set_hostname(deviceName); #endif AJ_AlwaysPrintf(("Trying to connect to AP %s\n", ssid)); if (secType == AJ_WIFI_SECURITY_WEP) { char wepKey[11]; WEPKey(passphrase, wepKey, sizeof(wepKey)); status = AJ_ConnectWiFi(ssid, AJ_WIFI_SECURITY_WEP, AJ_WIFI_CIPHER_WEP, wepKey); } else { status = AJ_ConnectWiFi(ssid, secType, AJ_WIFI_CIPHER_CCMP, passphrase); } if (status != AJ_OK) { AJ_AlwaysPrintf(("ConfigureWifi error\n")); } if (AJ_GetWifiConnectState() == AJ_WIFI_AUTH_FAILED) { AJ_AlwaysPrintf(("ConfigureWifi authentication failed\n")); status = AJ_ERR_SECURITY; } return status; } static char* AddrStr(uint32_t addr) { static char txt[17]; sprintf((char*)&txt, "%3lu.%3lu.%3lu.%3lu\0", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF) ); return txt; } #endif #ifdef SOFTAP_SSID static AJ_Status ConfigureSoftAP() { AJ_Status status = AJ_ERR_CONNECT; static const char ssid[] = SOFTAP_SSID; # ifdef SOFTAP_PASSPHRASE static const char passphrase[] = SOFTAP_PASSPHRASE; # else const char* passphrase = NULL; # endif AJ_AlwaysPrintf(("Configuring soft AP %s\n", ssid)); status = AJ_EnableSoftAP(ssid, FALSE, passphrase, UINT32_MAX); if (status == AJ_ERR_TIMEOUT) { AJ_AlwaysPrintf(("AJ_EnableSoftAP timeout\n")); } else if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_EnableSoftAP error\n")); } return status; } #endif #ifdef WIFI_SCAN static void ScanResult(void* context, const char* ssid, const uint8_t mac[6], uint8_t rssi, AJ_WiFiSecurityType secType, AJ_WiFiCipherType cipherType) { static const char* const sec[] = { "OPEN", "WEP", "WPA", "WPA2" }; static const char* const typ[] = { "", ":TKIP", ":CCMP", ":WEP" }; AJ_AlwaysPrintf(("SSID %s [%02x:%02X:%02x:%02x:%02x:%02x] RSSI=%d security=%s%s\n", ssid, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], rssi, sec[secType], typ[cipherType])); } #endif void AllJoyn_Start(unsigned long arg) { AJ_Status status = AJ_OK; AJ_AlwaysPrintf(("\n******************************************************")); AJ_AlwaysPrintf(("\n AllJoyn Thin-Client")); AJ_AlwaysPrintf(("\n******************************************************\n")); AJ_PrintFWVersion(); AJ_InfoPrintf(("AllJoyn Version %s\n", AJ_GetVersion())); #ifdef AJ_CONFIGURE_WIFI_UPON_START #ifdef WIFI_SCAN status = AJ_WiFiScan(NULL, ScanResult, 32); if (status != AJ_OK) { AJ_AlwaysPrintf(("WiFi scan failed\n")); } #endif #ifdef WIFI_SSID while (1) { uint32_t ip, mask, gw; status = ConfigureWifi(); if (status != AJ_OK) { AJ_InfoPrintf(("AllJoyn_Start(): ConfigureWifi status=%s", AJ_StatusText(status))); continue; } else { status = AJ_AcquireIPAddress(&ip, &mask, &gw, NET_UP_TIMEOUT); AJ_AlwaysPrintf(("Got IP %s\n", AddrStr(ip))); if (status != AJ_OK) { AJ_InfoPrintf(("AllJoyn_Start(): AJ_AcquireIPAddress status=%s", AJ_StatusText(status))); } break; } } #elif defined SOFTAP_SSID status = ConfigureSoftAP(); #endif #endif if (status == AJ_OK) { AJ_Main(); } AJ_AlwaysPrintf(("Quitting\n")); while (TRUE) { } } ajtcl-16.04/src/wsl/main.c000066400000000000000000000031171271074662300153170ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include static void main_task(void* parameters) { AJ_PlatformInit(); AJ_AlwaysPrintf((" ==============================================\n")); AJ_AlwaysPrintf(("|| Alljoyn Thin Client + FreeRTOS ||\n")); AJ_AlwaysPrintf((" ==============================================\n")); AllJoyn_Start(0); while (1); } int main(void) { AJ_CreateTask(main_task, (const signed char*)"AlljoynTask", AJ_WSL_STACK_SIZE, NULL, 2, NULL); AJ_StartScheduler(); return 0; } ajtcl-16.04/test/000077500000000000000000000000001271074662300136105ustar00rootroot00000000000000ajtcl-16.04/test/.gitignore000066400000000000000000000001541271074662300156000ustar00rootroot00000000000000aesbench aestest ajlite bastress2 clientlite mutter nvramtest sessions siglite svclite nvrampersistencetest ajtcl-16.04/test/SConscript000066400000000000000000000067301271074662300156300ustar00rootroot00000000000000Import('env') test_env = env.Clone() test_env.Append(LIBPATH = ['#dist/lib', '#build/$VARIANT']) test_env.Append(LIBS = "ajtcl") progs = [] progs.extend([ test_env.Program('mutter', ['mutter.c']), test_env.Program('ajlite', ['ajlite.c']), test_env.Program('aestest', ['aestest.c']), test_env.Program('aesbench', ['aesbench.c']), test_env.Program('svclite', ['svclite.c']), test_env.Program('clientlite', ['clientlite.c']), test_env.Program('siglite', ['siglite.c']), test_env.Program('sessionslite', ['sessionslite.c']), test_env.Program('nvramtest', ['nvramtest.c']), test_env.Program('nvramdump', ['nvramdump.c']), test_env.Program('nvrampersistencetest', ['nvrampersistencetest.c']), test_env.Program('bastress2', ['bastress2.c']), test_env.Program('certificate', ['certificate.c']), test_env.Program('base64', ['base64.c']), test_env.Program('codisco', ['codisco.c']), test_env.Program('sigtest', ['sigtest.c']), test_env.Program('ctrdrbg', ['ctrdrbg.c']), test_env.Program('shatest', ['shatest.c']), test_env.Program('doorsvc', ['doorsvc.c']), test_env.Program('ecctest', ['ecctest.c']), test_env.Program('pcclient', ['pcclient.c']), test_env.Program('pcservice', ['pcservice.c']) ]) # Build the test programs on win32/linux if test_env['TARG'] == 'win32' or test_env['TARG'] == 'linux': progs.extend([ test_env.Program('sessions', ['sessions.c']), test_env.Program('marshal_unmarshal_test', ['marshal_unmarshal_test.c']) ]) # if test_env['TARG'] == 'linux-uart': # test_env.Object('uarttest.o', ['uarttest.c']) # test_env.Object('uarttest1.o', ['uarttest1.c']) # test_env.Object('uartbigsmallsend.o', ['uartbigsmall.c']) # test_env.Object('echo.o', ['echo.c']) # progs.extend([ # test_env.Program('timertest', ['timertest.c']), # test_env.Program('semaphoretest', ['semaphoretest.c']), # test_env.Program('uarttest', ['uarttest.c']), # test_env.Program('uarttest1', ['uarttest1.o']), # test_env.Program('uartbigsmallsend', ['uartbigsmallsend.o']), # test_env.Program('echo', ['echo.o']) # ]) # # Buld the same source into the receiving side executable # uartTest_Env = test_env.Clone() # uartTest_Env.Append(CPPDEFINES = ['READTEST']) # uartTest_Env.Object('uartbigsmallrecv.o', ['uartbigsmall.c']) # uartTest_Env.Object('uarttestReceiver.o', ['uarttest.c']) # uartTest_Env.Object('uarttest1Receiver.o', ['uarttest1.c']) # uartTest_Env.Object('echoReceiver.o', ['echo.c']) # progs.extend([ # uartTest_Env.Program('uartbigsmallrecv', ['uartbigsmallrecv.o']), # uartTest_Env.Program('uarttestReceiver', ['uarttestReceiver.o']), # uartTest_Env.Program('uarttest1Receiver', ['uarttest1Receiver.o']), # uartTest_Env.Program('echoReceiver', ['echoReceiver.o']) # ]) # if test_env['TARG'] == 'on': # test_env.Program('wsltest', ['WSL/unit_test.c']) # test_env.Program('bufferlisttest', ['WSL/bufferlisttest.c']) # test_env.Program('spi_test', ['WSL/spi_test.c']) # test_env.Program('unmarshal_test', ['WSL/unmarshal_test.c']) if progs: test_env.Install('#dist/test', progs) ajtcl-16.04/test/WSL/000077500000000000000000000000001271074662300142555ustar00rootroot00000000000000ajtcl-16.04/test/WSL/bufferlisttest.c000066400000000000000000000115561271074662300174760ustar00rootroot00000000000000/** * @file Unit tests for AJ_WSL buffer list. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef __cplusplus extern "C" { #endif #define AJ_MODULE WSL_UNIT_TEST #include #include "../../src/wsl/aj_buf.h" #include "../../src/wsl/aj_wsl_htc.h" #include "../../src/wsl/aj_wsl_spi.h" #include "../../src/wsl/aj_wsl_wmi.h" #include "../../src/wsl/aj_wsl_net.h" #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_UNIT_TEST = 5; #endif static void run_buflist_external(const struct test_case* test) { uint8_t externA[10]; uint8_t externB[10]; /* * verify the buffer list management */ AJ_BufList* list1 = AJ_BufListCreate(); AJ_BufNode* pNode1 = AJ_BufListCreateNodeExternalBuffer((uint8_t*)&externA, sizeof(externA)); AJ_BufNode* pNode2 = AJ_BufListCreateNodeExternalBuffer((uint8_t*)&externB, sizeof(externB)); AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); memset(pNode1->buffer, 0x1, pNode1->length); memset(pNode2->buffer, 0x2, pNode2->length); AJ_BufListPushHead(list1, pNode1); AJ_BufListPushTail(list1, pNode2); AJ_BufNodeIterate(AJ_BufListNodePrint, list1, NULL); AJ_BufNodeIterate(AJ_BufListNodePrintDump, list1, NULL); AJ_BufListFree(list1, 1); } static void run_buflist_coalesce(const struct test_case* test) { /* * verify the buffer list management */ AJ_BufList* list1 = AJ_BufListCreate(); AJ_BufNode* pNode1 = AJ_BufListCreateNode(100); AJ_BufNode* pNode2 = AJ_BufListCreateNode(200); AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); memset(pNode1->buffer, 0x1, pNode1->length); memset(pNode2->buffer, 0x2, pNode2->length); AJ_BufListPushHead(list1, pNode1); AJ_BufListPushTail(list1, pNode2); AJ_BufNodeIterate(AJ_BufListNodePrint, list1, NULL); AJ_BufNodeIterate(AJ_BufListNodePrintDump, list1, NULL); AJ_BufListFree(list1, 1); // Test squeezing together a few buffer nodes in a list. AJ_AlwaysPrintf(("%s", "\n\nTEST: Coalesce Start\n")); { AJ_BufList* list3 = AJ_BufListCreate(); AJ_BufNode* pNodeA = AJ_BufListCreateNode(8); AJ_BufNode* pNodeB = AJ_BufListCreateNode(8); AJ_BufNode* pNodeC = AJ_BufListCreateNode(8); AJ_BufNode* pNodeD = AJ_BufListCreateNode(8); memset(pNodeA->buffer, 0xA1, 8); memset(pNodeB->buffer, 0xB2, 8); memset(pNodeC->buffer, 0xC3, 8); memset(pNodeD->buffer, 0xD4, 8); AJ_BufListPushHead(list3, pNodeA); AJ_BufListPushTail(list3, pNodeB); AJ_BufListPushTail(list3, pNodeC); AJ_BufListPushTail(list3, pNodeD); AJ_BufNodeIterate(AJ_BufListNodePrintDump, list3, NULL); AJ_AlwaysPrintf(("%s", "\n\nTEST: coalesce the head twice, then dump\n")); AJ_BufListCoalesce(list3->head); AJ_BufListCoalesce(list3->head); AJ_BufNodeIterate(AJ_BufListNodePrintDump, list3, NULL); AJ_AlwaysPrintf(("%s", "\n\nTEST: Next pull 16 bytes then dump\n")); AJ_BufListPullBytes(list3, 4); AJ_BufListPullBytes(list3, 4); AJ_BufListPullBytes(list3, 8); AJ_BufNodeIterate(AJ_BufListNodePrintDump, list3, NULL); AJ_AlwaysPrintf(("%s", "\n\nTEST: PULL BYTES 16 end\n")); AJ_BufListFree(list3, 1); } AJ_AlwaysPrintf(("%s", "\nTEST: Coalesce End\n")); } /** * Run buffer list tests. */ int main(void) { AJ_WSL_ModuleInit(); toTarget.fakeWireCurr = toTarget.fakeWireBuffer; toTarget.fakeWireRead = toTarget.fakeWireBuffer; toTarget.fakeWireWrite = toTarget.fakeWireBuffer; fromTarget.fakeWireCurr = fromTarget.fakeWireBuffer; fromTarget.fakeWireRead = fromTarget.fakeWireBuffer; fromTarget.fakeWireWrite = fromTarget.fakeWireBuffer; run_buflist_external(NULL); run_buflist_coalesce(NULL); } #ifdef __cplusplus } #endif ajtcl-16.04/test/WSL/spi_test.c000066400000000000000000000070441271074662300162600ustar00rootroot00000000000000/** * @file Unit tests for AJ_WSL SPI list. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef __cplusplus extern "C" { #endif #define AJ_MODULE WSL_UNIT_TEST #include #include "../../src/wsl/aj_buf.h" #include "../../src/wsl/aj_wsl_htc.h" #include "../../src/wsl/aj_wsl_spi.h" #include "../../src/wsl/aj_wsl_wmi.h" #include "../../src/wsl/aj_wsl_net.h" #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_UNIT_TEST = 5; #endif static void run_fill_mbox(const struct test_case* test) { uint16_t MBoxSpaceAvailable = 0; AJ_BufList* list1 = AJ_BufListCreate(); AJ_BufNode* pNode1; AJ_BufNode* pNode2; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, &MBoxSpaceAvailable); // fill up a mailbox with 'Z' pNode1 = AJ_BufListCreateNode(MBoxSpaceAvailable); memset(pNode1->bufferStart, 0x5A, MBoxSpaceAvailable); AJ_BufListPushHead(list1, pNode1); // fill up a mailbox with '!' pNode2 = AJ_BufListCreateNode(MBoxSpaceAvailable); memset(pNode2->bufferStart, 0x21, MBoxSpaceAvailable); AJ_BufListPushTail(list1, pNode2); AJ_WSL_WriteBufListToMBox(0, MBoxSpaceAvailable, list1); AJ_WSL_WriteBufListToMBox(0, MBoxSpaceAvailable * 2, list1); AJ_BufListFree(list1, TRUE); }; static void run_read_from_mbox(const struct test_case* test) { uint8_t* rawMboxMessage; uint16_t MBoxSpaceAvailable = 0; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); AJ_WSL_ReadFromMBox(0, &MBoxSpaceAvailable, &rawMboxMessage); AJ_Free(rawMboxMessage); }; /** * Run buffer list tests. */ int main(void) { AJ_WSL_ModuleInit(); toTarget.fakeWireCurr = toTarget.fakeWireBuffer; toTarget.fakeWireRead = toTarget.fakeWireBuffer; toTarget.fakeWireWrite = toTarget.fakeWireBuffer; fromTarget.fakeWireCurr = fromTarget.fakeWireBuffer; fromTarget.fakeWireRead = fromTarget.fakeWireBuffer; fromTarget.fakeWireWrite = fromTarget.fakeWireBuffer; //// hook the SPI operations to run without SPI hardware //AJ_WSL_SPI_RegisterRead = &Hooked_AJ_WSL_RegisterRead; //AJ_WSL_SPI_RegisterWrite = &Hooked_AJ_WSL_RegisterWrite; //AJ_WSL_SPI_OPS.writeDMA = &Hooked_AJ_WSL_DMAWrite; //AJ_WSL_SPI_OPS.readDMA = &Hooked_AJ_WSL_DMARead; //AJ_WSL_SPI_WriteByte8 = &Hooked_AJ_WSL_WriteByte8; //AJ_WSL_SPI_WriteByte16 = &Hooked_AJ_WSL_WriteByte16; // run_fill_mbox(NULL); run_read_from_mbox(NULL); } #ifdef __cplusplus } #endif ajtcl-16.04/test/WSL/unit_test.c000066400000000000000000000472651271074662300164550ustar00rootroot00000000000000/** * @file Unit tests for SPI AJ_WSL. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef __cplusplus extern "C" { #endif #define AJ_MODULE WSL_UNIT_TEST #include #include "../../src/wsl/aj_buf.h" #include "../../src/wsl/aj_wsl_htc.h" #include "../../src/wsl/aj_wsl_spi.h" #include "../../src/wsl/aj_wsl_wmi.h" #include "../../src/wsl/aj_wsl_net.h" #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ #ifndef NDEBUG uint8_t dbgWSL_UNIT_TEST = 5; #endif static void ResetFakeWireBuffers() { toTarget.fakeWireWrite = toTarget.fakeWireBuffer; // reset the write pointer to the start of our buffer toTarget.fakeWireRead = toTarget.fakeWireBuffer; // reset the read pointer to the start of our buffer fromTarget.fakeWireWrite = fromTarget.fakeWireBuffer; // reset the write pointer to the start of our buffer fromTarget.fakeWireRead = fromTarget.fakeWireBuffer; // reset the read pointer to the start of our buffer } static void run_wsl_htc_parsing(const struct test_case* test) { /* * create a chain of buffers that simulate each protocol layer wrapping the layer above it. * The values chosen to populate the buffers are not legal protocol values, they just show * where the bytes are laid out in memory. */ AJ_BufList* list2 = AJ_BufListCreate(); AJ_BufNode* pNodeAppData = AJ_BufListCreateNodeZero(16, 1); AJ_BufNode_WMI* pNodeWMI; AJ_BufNode* pNodeWMITrail; AJ_BufNode* pNodeHTC; wsl_htc_msg_connect_service* msgConnectService; AJ_BufNode* pNodeHTCTrail; AJ_BufNode* pNodeHTCHeader; wsl_htc_hdr* msgHdr; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); strcpy((char*)pNodeAppData->buffer, "AppData string"); pNodeWMI = AJ_BufListCreateNode(sizeof(wsl_spi_command)); // stuff the buffer with a command. ((wsl_spi_command*)pNodeWMI->buffer)->cmd_addr = AJ_WSL_SPI_SPI_STATUS; ((wsl_spi_command*)pNodeWMI->buffer)->cmd_rx = 1; ((wsl_spi_command*)pNodeWMI->buffer)->cmd_reg = 1; *((uint16_t*)pNodeWMI->buffer) = CPU_TO_BE16(*(uint16_t*)pNodeWMI->buffer); // Swap the bytes around // create a bogus trailer pNodeWMITrail = AJ_BufListCreateNode(8); memset(pNodeWMITrail->buffer, 0xA1, 8); // create an HTC command pNodeHTC = AJ_BufListCreateNode(sizeof(wsl_htc_msg_connect_service)); msgConnectService = (wsl_htc_msg_connect_service*)pNodeHTC->buffer; msgConnectService->msg.messageID = AJ_WSL_HTC_CONNECT_SERVICE_ID; msgConnectService->serviceID = 0x5678; // random choice msgConnectService->flags = 0xCDEF; // random choice msgConnectService->serviceMetadataLength = 0; // random choice msgConnectService->metadata = 0; // random choice AJ_WSL_HTC_MSG_CONNECT_TO_WIRE(msgConnectService); // create another bogus trailer pNodeHTCTrail = AJ_BufListCreateNode(8); memset(pNodeHTCTrail->buffer, 0xB2, 8); // AppData was added then WMI was added, then HTC wrapped around that AJ_BufListPushHead(list2, pNodeAppData); AJ_BufListPushHead(list2, pNodeWMI); AJ_BufListPushTail(list2, pNodeWMITrail); AJ_BufListPushHead(list2, pNodeHTC); AJ_BufListPushTail(list2, pNodeHTCTrail); // create an HTC header structure with the correct size field (based on the size of the data to send on the wire) pNodeHTCHeader = AJ_BufListCreateNode(sizeof(wsl_htc_hdr)); msgHdr = (wsl_htc_hdr*)pNodeHTCHeader->buffer; msgHdr->endpointID = AJ_WSL_HTC_CONTROL_ENDPOINT; msgHdr->flags = 0; msgHdr->controlBytes[0] = 0xAB; msgHdr->controlBytes[1] = 0xCD; msgHdr->payloadLength = AJ_BufListLengthOnWire(list2); AJ_WSL_HTC_HDR_TO_WIRE(msgHdr); AJ_AlwaysPrintf(("\n\nPayload size would be: %d\n\n", AJ_BufListLengthOnWire(list2))); AJ_BufListPushHead(list2, pNodeHTCHeader); AJ_AlwaysPrintf(("%s", "write this to the wire\n\n")); AJ_BufListIterateOnWire(AJ_BufListWriteToWire_Simulated, list2, &toTarget); AJ_AlwaysPrintf(("\n\nDone wire write, length on wire: %d\n\n", AJ_BufListLengthOnWire(list2))); AJ_BufListFree(list2, 1); /* { // simulate a number of reads from the SPI buffer fakeWireRead = fakeWireBuffer; uint16_t readBufferSize = sizeof(fakeWireBuffer); AJ_AlwaysPrintf(("%s", "Wire Bufer\n")); while (readBufferSize > 0) { uint8_t byteRead = AJ_BufListReadByteFromWire_Simulated(); AJ_AlwaysPrintf(("%02X ", byteRead)); readBufferSize--; } } */ toTarget.fakeWireRead = toTarget.fakeWireBuffer; // fakeWireRead = fakeWireBuffer; // reset the read pointer to the start of our buffer { wsl_htc_hdr htcHdr1; AJ_BufNode* pNodeHTCBody; wsl_htc_msg* htcMsg1; AJ_AlwaysPrintf(("%s", "Read HTC header from wire buffer\n")); AJ_BufListReadBytesFromWire_Simulated(sizeof(htcHdr1), (uint8_t*)&htcHdr1, &toTarget); // convert the fields to the correct endianness AJ_WSL_HTC_HDR_FROM_WIRE(&htcHdr1); AJ_AlwaysPrintf(("\n HTC Hdr payload length 0x%04x\n\n", htcHdr1.payloadLength)); AJ_AlwaysPrintf(("%s", "Read HTC from wire buffer\n")); pNodeHTCBody = AJ_BufListCreateNode(htcHdr1.payloadLength /*+ sizeof(wsl_htc_msg)*/); htcMsg1 = (wsl_htc_msg*)pNodeHTCBody->buffer; AJ_BufListReadBytesFromWire_Simulated(pNodeHTCBody->length, pNodeHTCBody->buffer, &toTarget); switch (htcHdr1.endpointID) { case AJ_WSL_HTC_CONTROL_ENDPOINT: AJ_AlwaysPrintf(("%s", "Read HTC control endpoint\n")); // break; case AJ_WSL_HTC_DATA_ENDPOINT1: case AJ_WSL_HTC_DATA_ENDPOINT2: case AJ_WSL_HTC_DATA_ENDPOINT3: case AJ_WSL_HTC_DATA_ENDPOINT4: AJ_AlwaysPrintf(("\n%s %d\n", "Read HTC data endpoint", htcHdr1.endpointID)); // TODO send the data up to the next API level AJ_WSL_WMI_PrintMessage(pNodeHTCBody); break; default: AJ_AlwaysPrintf(("%s %d", "UNKNOWN Endpoint", htcHdr1.endpointID)); break; } // AJ_BufListReadBytesFromWire_Simulated(pNodeHTCBody->length, pNodeHTCBody->buffer); AJ_WSL_HTC_MSG_FROM_WIRE(htcMsg1); switch (htcMsg1->messageID) { case AJ_WSL_HTC_MSG_READY_ID: { wsl_htc_msg_ready* htcMsgReady1 = (wsl_htc_msg_ready*)pNodeHTCBody->buffer; AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_MSG_READY_ID \n")); AJ_WSL_HTC_MSG_READY_FROM_WIRE(htcMsgReady1); AJ_AlwaysPrintf(("\n HTC connect service message 0x%04x, CreditCount 0x%04X CreditSize 0x%04X\n\n", htcMsgReady1->msg.messageID, htcMsgReady1->creditCount, htcMsgReady1->creditSize)); break; } case AJ_WSL_HTC_CONNECT_SERVICE_ID: { wsl_htc_msg_connect_service* htcMsgCS1 = (wsl_htc_msg_connect_service*) pNodeHTCBody->buffer; AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_CONNECT_SERVICE_ID \n")); AJ_WSL_HTC_MSG_CONNECT_FROM_WIRE(htcMsgCS1); AJ_AlwaysPrintf(("\n HTC connect service message 0x%04x, serviceID 0x%04X \n\n", htcMsgCS1->msg.messageID, htcMsgCS1->serviceID)); break; } case AJ_WSL_HTC_SERVICE_CONNECT_RESPONSE_ID: { wsl_htc_msg_service_connect_response* htcServiceConnectResponse1 = (wsl_htc_msg_service_connect_response*)pNodeHTCBody->buffer; AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_SERVICE_CONNECT_RESPONSE_ID \n")); AJ_WSL_HTC_MSG_SERVICE_CONNECT_RESPONSE_FROM_WIRE(htcServiceConnectResponse1); AJ_AlwaysPrintf(("\n HTC service connect response 0x%04x, serviceID 0x%04X metadatalength 0x%04X\n\n", htcServiceConnectResponse1->msg.messageID, htcServiceConnectResponse1->serviceID, htcServiceConnectResponse1->serviceMetadataLength)); break; } case AJ_WSL_HTC_SETUP_COMPLETE_ID: { AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_SETUP_COMPLETE_ID \n")); break; } case AJ_WSL_HTC_HOST_READY_ID: { AJ_AlwaysPrintf(("%s", "Read HTC msg AJ_WSL_HTC_HOST_READY_ID \n")); break; } default: { AJ_ASSERT(htcMsg1->messageID <= AJ_WSL_HTC_HOST_READY_ID); break; } } } } static void AJ_WSL_HTCProcessControlMessage_Fake(AJ_BufNode* pNodeHTCBody) { wsl_wmi_cmd_hdr* wmiCmdHdr2; wmiCmdHdr2 = (wsl_wmi_cmd_hdr*)pNodeHTCBody->buffer; AJ_WSL_WMI_CMD_HDR_FROM_WIRE(wmiCmdHdr2); AJ_WSL_WMI_CMD_HDR_Print(wmiCmdHdr2); AJ_BufNodePullBytes(pNodeHTCBody, sizeof(wsl_wmi_cmd_hdr)); if (wmiCmdHdr2->commandID == WMI_SOCKET_CMDID) { wsl_wmi_socket_cmd* pSocketCmd = (wsl_wmi_socket_cmd*)pNodeHTCBody->buffer; AJ_WSL_WMI_SOCKET_CMD_FROM_WIRE(pSocketCmd); AJ_WSL_WMI_SOCKET_CMD_HDR_Print(pSocketCmd); if (pSocketCmd->cmd_type == WSL_SOCK_PING) { switch (pSocketCmd->cmd_type) { case WSL_SOCK_OPEN: { wsl_wmi_sock_open* open = (wsl_wmi_sock_open*)pNodeHTCBody->buffer; AJ_WSL_WMI_SOCK_OPEN_FROM_WIRE(open); AJ_AlwaysPrintf(("OPEN call was received over the wire: domain 0x%x, type 0x%x protocol 0x%x\n\n", open->domain, open->protocol, open->type)); break; } case WSL_SOCK_PING: { wsl_wmi_sock_ping* ping = (wsl_wmi_sock_ping*)pNodeHTCBody->buffer; AJ_WSL_WMI_SOCK_PING_FROM_WIRE(ping); AJ_AlwaysPrintf(("PING call was received over the wire: addr 0x%x, size 0x%x\n\n", ping->ip_addr, ping->size)); break; } default: AJ_ASSERT("unknown socket command\n\n"); } } } } static void AJ_WSL_HTCProcessControlMessageResponse_Fake(AJ_BufNode* pNodeHTCBody) { wsl_wmi_cmd_hdr* wmiCmdHdr2; wmiCmdHdr2 = (wsl_wmi_cmd_hdr*)pNodeHTCBody->buffer; AJ_WSL_WMI_CMD_HDR_FROM_WIRE(wmiCmdHdr2); AJ_WSL_WMI_CMD_HDR_Print(wmiCmdHdr2); AJ_BufNodePullBytes(pNodeHTCBody, sizeof(wsl_wmi_cmd_hdr)); if (wmiCmdHdr2->commandID == WMI_SOCKET_CMDID) { wsl_wmi_socket_response_event* pSocketResp = (wsl_wmi_socket_response_event*)pNodeHTCBody->buffer; AJ_WSL_WMI_SOCK_RESPONSE_FROM_WIRE(pSocketResp); switch (pSocketResp->responseType) { case WSL_SOCK_OPEN: { //AJ_AlwaysPrintf(("PING response was received over the wire: addr 0x%x, size 0x%x\n\n", ping->ip_addr, ping->size)); AJ_AlwaysPrintf(("OPEN response was received over the wire, Handle is %x\n\n", pSocketResp->socketHandle)); break; } case WSL_SOCK_PING: { //wsl_wmi_sock_ping* ping = (wsl_wmi_sock_ping*)pNodeHTCBody->buffer; //AJ_WSL_WMI_SOCK_PING_FROM_WIRE(ping); //AJ_AlwaysPrintf(("PING response was received over the wire: addr 0x%x, size 0x%x\n\n", ping->ip_addr, ping->size)); AJ_AlwaysPrintf(("PING response was received over the wire, Handle is %x\n\n", pSocketResp->socketHandle)); break; } default: AJ_ASSERT("unknown socket command\n\n"); } } } static void run_wsl_simulate_ping(const struct test_case* test) { AJ_BufNode* pNodeHTCBody; wsl_htc_hdr htcHdr1; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); toTarget.fakeWireWrite = toTarget.fakeWireBuffer; // reset the write pointer to the start of our buffer toTarget.fakeWireRead = toTarget.fakeWireBuffer; // reset the read pointer to the start of our buffer AJ_WSL_NET_ping(0xC0A80101, 100); // now, try to receive a command from the target (we should really try to receive a response and event id) AJ_AlwaysPrintf(("%s", "Read HTC header from wire buffer\n")); AJ_BufListReadBytesFromWire_Simulated(sizeof(htcHdr1), (uint8_t*)&htcHdr1, &toTarget); // convert the fields to the correct endianness AJ_WSL_HTC_HDR_FROM_WIRE(&htcHdr1); AJ_AlwaysPrintf(("\n HTC Hdr payload length 0x%04x\n\n", htcHdr1.payloadLength)); AJ_AlwaysPrintf(("%s", "Read HTC from wire buffer\n")); pNodeHTCBody = AJ_BufListCreateNode(htcHdr1.payloadLength); AJ_BufListReadBytesFromWire_Simulated(pNodeHTCBody->length, pNodeHTCBody->buffer, &toTarget); /* examine the endpoint of the HTC message*/ switch (htcHdr1.endpointID) { case AJ_WSL_HTC_CONTROL_ENDPOINT: { AJ_AlwaysPrintf(("%s", "Read HTC control endpoint\n")); /* For this test, we know this is a control endpoint */ AJ_WSL_HTCProcessControlMessage_Fake(pNodeHTCBody); break; } case AJ_WSL_HTC_DATA_ENDPOINT1: case AJ_WSL_HTC_DATA_ENDPOINT2: case AJ_WSL_HTC_DATA_ENDPOINT3: case AJ_WSL_HTC_DATA_ENDPOINT4: AJ_AlwaysPrintf(("\n%s %d\n", "Read HTC data endpoint", htcHdr1.endpointID)); // TODO send the data up to the next API level AJ_WSL_WMI_PrintMessage(pNodeHTCBody); break; default: AJ_AlwaysPrintf(("%s %d", "UNKNOWN Endpoint", htcHdr1.endpointID)); break; } // wsl_htc_msg* htcMsg1 = pNodeHTCBody->buffer; // AJ_WSL_HTC_MSG_FROM_WIRE(htcMsg1); } /* * This test builds a ping response in a simulated wire buffer, and then parses the response */ static void run_wsl_simulate_ping_recv(const struct test_case* test) { AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); ResetFakeWireBuffers(); AJ_WSL_NET_ping_FAKERESPONSE(); AJ_WSL_HTC_ProcessIncoming(); } /* * This test builds a ping response in a simulated wire buffer, and then parses the response */ static void run_wsl_simulate_socket_open_recv(const struct test_case* test) { AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); ResetFakeWireBuffers(); AJ_WSL_NET_socket_open_FAKERESPONSE(); AJ_WSL_HTC_ProcessIncoming(); } /* * This test builds a socket close response in a simulated wire buffer, and then parses the response */ static void run_wsl_simulate_socket_close_recv(const struct test_case* test) { AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); ResetFakeWireBuffers(); AJ_WSL_NET_socket_close_FAKERESPONSE(); AJ_WSL_HTC_ProcessIncoming(); } /* * This test builds a ping response in a simulated wire buffer, and then parses the response */ static void run_wsl_simulate_state_machine(const struct test_case* test) { AJ_Status status = AJ_OK; uint16_t i; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); /* * reset the state of the simulated wire buffers */ memset(toTarget.fakeWireBuffer, 0, sizeof(toTarget.fakeWireBuffer)); toTarget.fakeWireCurr = toTarget.fakeWireBuffer; memset(fromTarget.fakeWireBuffer, 0, sizeof(fromTarget.fakeWireBuffer)); fromTarget.fakeWireCurr = fromTarget.fakeWireBuffer; ResetFakeWireBuffers(); /* * reset the state of the HTC endpoints */ memset(&AJ_WSL_HTC_Global, 0, sizeof(AJ_WSL_HTC_Global)); /* * TODO: prime the state machine by creating a HTC Ready packet and adding it to the simulated wirebufer */ { wsl_htc_hdr readyHdr; wsl_htc_msg_ready readyMsg; readyMsg.msg.messageID = AJ_WSL_HTC_MSG_READY_ID; readyMsg.creditCount = 20; readyMsg.creditSize = 512; readyMsg.HTCVersion = 0; readyMsg.maxEndpoints = 5; readyMsg.maxMessagesPerBundle = 1; AJ_WSL_HTC_MSG_READY_TO_WIRE(&readyMsg); readyHdr.endpointID = 0; readyHdr.flags = 0; readyHdr.controlBytes[0] = 0; readyHdr.controlBytes[1] = 0; readyHdr.payloadLength = sizeof(wsl_htc_msg_ready); AJ_WSL_HTC_HDR_TO_WIRE(&readyHdr); memcpy(fromTarget.fakeWireBuffer, &readyHdr, sizeof(readyHdr)); memcpy(fromTarget.fakeWireBuffer + sizeof(readyHdr), &readyMsg, sizeof(readyMsg)); } for (i = 0; i < 5; ++i) { switch (i) { case 0: case 1: case 2: { AJ_AlwaysPrintf(("Case %d send\n", i)); AJ_WSL_HTC_StateMachine(&AJ_WSL_HTC_Global.endpoints[0]); if (status != AJ_OK) { break; } break; } default: break; } // now send the thing. // now process the other side of the thing switch (i) { case 0: case 1: case 2: { AJ_AlwaysPrintf(("Case %d response\n", i)); AJ_WSL_HTC_StateMachine(&AJ_WSL_HTC_Global.endpoints[0]); if (status != AJ_OK) { break; } break; } default: break; } } AJ_DumpBytes(__FUNCTION__, fromTarget.fakeWireBuffer, sizeof(fromTarget.fakeWireBuffer)); } /* * This test builds a opens and closes a socket in a simulated wire buffer */ static void run_wsl_open_and_close(const struct test_case* test) { AJ_Status status = AJ_OK; AJ_WSL_SOCKNUM sockNum; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); // 2 = AF_INET // 1 = SOCK_STREAM sockNum = AJ_WSL_NET_socket_open(2, 1, 0); AJ_WSL_NET_socket_close(sockNum); } /* * This test sends small amount of data using a simulated wire buffer */ static void run_wsl_send_small(const struct test_case* test) { AJ_Status status = AJ_OK; AJ_WSL_SOCKNUM sockNum; char* hello = "Hello, World.\0"; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); // 2 = AF_INET // 1 = SOCK_STREAM sockNum = AJ_WSL_NET_socket_open(2, 1, 0); // fake a connect AJ_WSL_SOCKET_CONTEXT[sockNum].domain = 2; // AF_INET AJ_WSL_SOCKET_CONTEXT[sockNum].type = 1; //sock_stream AJ_WSL_SOCKET_CONTEXT[sockNum].name.sin_addr.s_addr = 0xAABBCCDD; AJ_WSL_SOCKET_CONTEXT[sockNum].name.sin_port = 0x9988; AJ_WSL_NET_send(sockNum, hello, 13, UINT32_MAX); AJ_WSL_NET_socket_close(sockNum); } /** * \brief Run SPI driver unit test. */ int AJ_Main(void) { AJ_WSL_ModuleInit(); toTarget.fakeWireCurr = toTarget.fakeWireBuffer; fromTarget.fakeWireCurr = fromTarget.fakeWireBuffer; ResetFakeWireBuffers(); run_wsl_htc_parsing(NULL); run_wsl_simulate_ping(NULL); run_wsl_simulate_state_machine(NULL); run_wsl_simulate_socket_open_recv(NULL); run_wsl_simulate_ping_recv(NULL); run_wsl_simulate_socket_close_recv(NULL); run_wsl_simulate_ping_recv(NULL); // this one would return failure because the socket has been closed run_wsl_open_and_close(NULL); run_wsl_send_small(NULL); } #ifdef __cplusplus } #endif ajtcl-16.04/test/WSL/unmarshal_test.c000066400000000000000000000241201271074662300174510ustar00rootroot00000000000000/** * @file Unit tests unmarshaling data in AJ_WSL. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include "../../src/src/wsl/aj_wsl_unmarshal.h" /* SSID fishing2 [00:23:69:7e:bb:fe] RSSI=34 security=WPA2:CCMP */ static const uint8_t fishing2[] = { 0x01, 0x02, 0xe9, 0x00, 0x08, 0x12, 0x04, 0x10, 0x00, 0x00, 0x00, 0x23, 0x85, 0x09, 0x02, 0x22, 0x00, 0x23, 0x69, 0x7e, 0xbb, 0xfe, 0x00, 0x10, 0xb5, 0x6d, 0x44, 0xf9, 0xc7, 0x00, 0x00, 0x00, 0x64, 0x00, 0x31, 0x04, 0x00, 0x08, 0x66, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x32, 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x03, 0x01, 0x06, 0x30, 0x14, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, 0xdd, 0x09, 0x00, 0x03, 0x7f, 0x01, 0x01, 0x00, 0x00, 0xff, 0x7f, 0xdd, 0x0a, 0x00, 0x03, 0x7f, 0x04, 0x01, 0x00, 0x02, 0x00, 0x40, 0x00, 0xdd, 0x74, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x44, 0x00, 0x01, 0x02, 0x10, 0x3b, 0x00, 0x01, 0x03, 0x10, 0x47, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x23, 0x69, 0x7e, 0xbb, 0xfe, 0x10, 0x21, 0x00, 0x0c, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x79, 0x73, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x10, 0x23, 0x00, 0x07, 0x57, 0x52, 0x54, 0x35, 0x34, 0x47, 0x32, 0x10, 0x24, 0x00, 0x07, 0x76, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x32, 0x10, 0x42, 0x00, 0x01, 0x30, 0x10, 0x54, 0x00, 0x08, 0x00, 0x06, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x10, 0x11, 0x00, 0x07, 0x57, 0x52, 0x54, 0x35, 0x34, 0x47, 0x32, 0x10, 0x08, 0x00, 0x02, 0x00, 0x84, 0x10, 0x3c, 0x00, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00, 0x0c, 0x0a, 0x01, 0x00, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t SEAQUICAP1[] = { 0x01, 0x02, 0x7e, 0x01, 0x08, 0x0d, 0x04, 0x10, 0x00, 0x00, 0x2c, 0xb0, 0x6c, 0x09, 0x02, 0x31, 0x2c, 0xb0, 0x5d, 0x82, 0xef, 0xb5, 0x00, 0x10, 0x76, 0xbe, 0x97, 0xa3, 0x08, 0x00, 0x00, 0x00, 0x64, 0x00, 0x31, 0x00, 0x00, 0x0b, 0x53, 0x45, 0x41, 0x51, 0x55, 0x49, 0x43, 0x2d, 0x41, 0x50, 0x31, 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x03, 0x01, 0x01, 0x30, 0x14, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x00, 0x2a, 0x01, 0x02, 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x83, 0x00, 0x03, 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, 0x62, 0x32, 0x2f, 0x00, 0xdd, 0x1e, 0x00, 0x90, 0x4c, 0x33, 0xcc, 0x11, 0x1b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x1a, 0xcc, 0x11, 0x1b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x1a, 0x00, 0x90, 0x4c, 0x34, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x16, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x09, 0x00, 0x03, 0x7f, 0x01, 0x01, 0x00, 0x00, 0xff, 0x7f, 0xdd, 0x0a, 0x00, 0x03, 0x7f, 0x04, 0x01, 0x00, 0x02, 0x00, 0x40, 0x00, 0xdd, 0x7c, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x44, 0x00, 0x01, 0x02, 0x10, 0x3b, 0x00, 0x01, 0x03, 0x10, 0x47, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x2c, 0xb0, 0x5d, 0x82, 0xef, 0xb5, 0x10, 0x21, 0x00, 0x07, 0x4e, 0x65, 0x74, 0x67, 0x65, 0x61, 0x72, 0x10, 0x23, 0x00, 0x08, 0x57, 0x4e, 0x44, 0x52, 0x33, 0x38, 0x30, 0x30, 0x10, 0x24, 0x00, 0x02, 0x56, 0x31, 0x10, 0x42, 0x00, 0x04, 0x6e, 0x6f, 0x6e, 0x65, 0x10, 0x54, 0x00, 0x08, 0x00, 0x06, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x10, 0x11, 0x00, 0x15, 0x57, 0x4e, 0x44, 0x52, 0x33, 0x38, 0x30, 0x30, 0x28, 0x57, 0x69, 0x72, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x41, 0x50, 0x29, 0x10, 0x08, 0x00, 0x02, 0x00, 0x86, 0x10, 0x3c, 0x00, 0x01, 0x03, 0x02, 0x06, 0x00, 0x00, 0x0c, 0x0a, 0x01, 0x00, 0x01, 0x01, 0x02, 0x06, 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 uint8_t unknown[] = { 0x01, 0x02, 0x48, 0x01, 0x08, 0x0f, 0x04, 0x10, 0x00, 0x00, 0x74, 0x44, 0x6c, 0x09, 0x02, 0x17, 0x74, 0x44, 0x01, 0x31, 0x04, 0x6d, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x11, 0x04, 0x00, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, 0x03, 0x01, 0x01, 0x2a, 0x01, 0x00, 0x2f, 0x01, 0x00, 0x30, 0x14, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x00, 0x32, 0x04, 0x0c, 0x12, 0x18, 0x60, 0x2d, 0x1a, 0xfc, 0x18, 0x1b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x16, 0x01, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x0e, 0x14, 0x00, 0x0a, 0x00, 0x2c, 0x01, 0xc8, 0x00, 0x14, 0x00, 0x05, 0x00, 0x19, 0x00, 0x7f, 0x01, 0x01, 0xdd, 0x8b, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x44, 0x00, 0x01, 0x02, 0x10, 0x3b, 0x00, 0x01, 0x03, 0x10, 0x47, 0x00, 0x10, 0xf6, 0xbb, 0xf4, 0xbf, 0xf4, 0x2d, 0xe1, 0x45, 0xde, 0xf0, 0x48, 0x81, 0x85, 0x0a, 0xf8, 0xf9, 0x10, 0x21, 0x00, 0x0d, 0x4e, 0x45, 0x54, 0x47, 0x45, 0x41, 0x52, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x10, 0x23, 0x00, 0x0a, 0x57, 0x4e, 0x44, 0x52, 0x33, 0x37, 0x30, 0x30, 0x76, 0x33, 0x10, 0x24, 0x00, 0x0a, 0x57, 0x4e, 0x44, 0x52, 0x33, 0x37, 0x30, 0x30, 0x76, 0x33, 0x10, 0x42, 0x00, 0x02, 0x30, 0x31, 0x10, 0x54, 0x00, 0x08, 0x00, 0x06, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x10, 0x11, 0x00, 0x0c, 0x57, 0x69, 0x72, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x50, 0x30, 0x31, 0x10, 0x08, 0x00, 0x02, 0x00, 0x04, 0x10, 0x3c, 0x00, 0x01, 0x03, 0x10, 0x49, 0x00, 0x06, 0x00, 0x37, 0x2a, 0x00, 0x01, 0x20, 0xdd, 0x09, 0x00, 0x10, 0x18, 0x02, 0x00, 0xf0, 0x28, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x0c, 0x0a, 0x01, 0x00, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t unknown2[] = { 0x01, 0x02, 0x41, 0x01, 0x08, 0x15, 0x04, 0x10, 0x00, 0x00, 0x68, 0x7f, 0x85, 0x09, 0x02, 0x1a, 0x68, 0x7f, 0x74, 0x82, 0x89, 0xd8, 0x00, 0x10, 0x15, 0xea, 0x0f, 0x01, 0x02, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x21, 0x04, 0x00, 0x09, 0x70, 0x65, 0x72, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x03, 0x01, 0x06, 0x2a, 0x01, 0x00, 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x02, 0x00, 0x03, 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, 0x62, 0x32, 0x2f, 0x00, 0x2d, 0x1a, 0x4c, 0x10, 0x1b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x16, 0x06, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x93, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x44, 0x00, 0x01, 0x02, 0x10, 0x41, 0x00, 0x01, 0x00, 0x10, 0x3b, 0x00, 0x01, 0x03, 0x10, 0x47, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x68, 0x7f, 0x74, 0x82, 0x89, 0xd8, 0x10, 0x21, 0x00, 0x13, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x79, 0x73, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x23, 0x00, 0x07, 0x57, 0x52, 0x54, 0x31, 0x32, 0x30, 0x4e, 0x10, 0x24, 0x00, 0x07, 0x76, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x34, 0x10, 0x42, 0x00, 0x0c, 0x4a, 0x55, 0x54, 0x30, 0x30, 0x4b, 0x35, 0x31, 0x39, 0x33, 0x30, 0x30, 0x10, 0x54, 0x00, 0x08, 0x00, 0x06, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x10, 0x11, 0x00, 0x14, 0x57, 0x69, 0x72, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x28, 0x57, 0x46, 0x41, 0x29, 0x10, 0x08, 0x00, 0x02, 0x00, 0x84, 0xdd, 0x09, 0x00, 0x03, 0x7f, 0x01, 0x01, 0x00, 0x00, 0xff, 0x7f, 0xdd, 0x0a, 0x00, 0x03, 0x7f, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0xaa, 0x01, 0x02, 0x48, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; int AJ_Main(void) { WMI_Unmarshal2(fishing2); AJ_AlwaysPrintf(("==============================\n")); WMI_Unmarshal2(SEAQUICAP1); AJ_AlwaysPrintf(("==============================\n")); WMI_Unmarshal2(unknown); AJ_AlwaysPrintf(("==============================\n")); WMI_Unmarshal2(unknown2); AJ_AlwaysPrintf(("==============================\n")); return 1; } ajtcl-16.04/test/aesbench.c000066400000000000000000000047711271074662300155350ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include static const uint8_t key[] = { 0xC6, 0xC4, 0xFC, 0xEF, 0x31, 0x85, 0xFB, 0x66, 0xAA, 0xB8, 0x62, 0xBC, 0x03, 0x76, 0xAB, 0xBE }; static uint8_t msg[1024]; static uint32_t nonce[2] = { 0x2AC45FAD, 0xD617159A }; int main(void) { AJ_Status status = AJ_OK; size_t i; uint8_t cmp[1024]; for (i = 0; i < sizeof(msg); ++i) { msg[i] = (uint8_t)(127 + i * 11 + i * 13 + i * 17); } for (i = 0; i < 10000; ++i) { uint8_t hdrLen; for (hdrLen = 10; hdrLen < 60; hdrLen += 3) { memcpy(cmp, msg, sizeof(msg)); status = AJ_Encrypt_CCM(key, msg, sizeof(msg), hdrLen, 12, (const uint8_t*) nonce, sizeof(nonce)); if (status != AJ_OK) { AJ_AlwaysPrintf(("Encryption failed (%d) for test #%zu\n", status, i)); goto ErrorExit; } status = AJ_Decrypt_CCM(key, msg, sizeof(msg), hdrLen, 12, (const uint8_t*) nonce, sizeof(nonce)); if (status != AJ_OK) { AJ_AlwaysPrintf(("Authentication failure (%d) for test #%zu\n", status, i)); goto ErrorExit; } if (memcmp(cmp, msg, sizeof(msg)) != 0) { AJ_AlwaysPrintf(("Decrypt verification failure \n")); goto ErrorExit; } nonce[0] += 1; } } return 0; ErrorExit: AJ_AlwaysPrintf(("AES CCM unit test FAILED\n")); return 1; } ajtcl-16.04/test/aestest.c000066400000000000000000000362121271074662300154300ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include "aestest_bigdata.h" typedef struct { const char* key; /* AES key */ const char* nonce; /* Nonce */ uint8_t hdrLen; /* Number of clear text bytes */ const char* input; /* Input text) */ uint32_t repeat; /* Number of times to repeat input */ const char* output; /* Authenticated and encrypted output for verification */ uint8_t authLen; /* Length of the authentication field */ } TEST_CASE; /* Test vectors from RFC 3610 "Counter with CBC-MAC (CCM)", https://tools.ietf.org/html/rfc3610 */ static TEST_CASE const testVector[] = { { /* =============== RFC 3610 Packet Vector #1 ================== */ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000003020100A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E", 1, "0001020304050607588C979A61C663D2F066D0C2C0F989806D5F6B61DAC38417E8D12CFDF926E0", 8 }, { /* =============== RFC 3610 Packet Vector #2 ================== */ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000004030201A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", 1, "000102030405060772C91A36E135F8CF291CA894085C87E3CC15C439C9E43A3BA091D56E10400916", 8 }, { /*===============RFC3610PacketVector#3==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000005040302A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", 1, "000102030405060751B1E5F44A197D1DA46B0F8E2D282AE871E838BB64DA8596574ADAA76FBD9FB0C5", 8 }, { /*===============RFC3610PacketVector#4==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000006050403A0A1A2A3A4A5", 12, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E", 1, "000102030405060708090A0BA28C6865939A9A79FAAA5C4C2A9D4A91CDAC8C96C861B9C9E61EF1", 8 }, { /*===============RFC3610PacketVector#5==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000007060504A0A1A2A3A4A5", 12, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", 1, "000102030405060708090A0BDCF1FB7B5D9E23FB9D4E131253658AD86EBDCA3E51E83F077D9C2D93", 8 }, { /*===============RFC3610PacketVector#6==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000008070605A0A1A2A3A4A5", 12, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", 1, "000102030405060708090A0B6FC1B011F006568B5171A42D953D469B2570A4BD87405A0443AC91CB94", 8 }, { /*===============RFC3610PacketVector#7==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000009080706A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E", 1, "00010203040506070135D1B2C95F41D5D1D4FEC185D166B8094E999DFED96C048C56602C97ACBB7490", 10 }, { /*===============RFC3610PacketVector#8==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "0000000A090807A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", 1, "00010203040506077B75399AC0831DD2F0BBD75879A2FD8F6CAE6B6CD9B7DB24C17B4433F434963F34B4", 10 }, { /*===============RFC3610PacketVector#9==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "0000000B0A0908A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", 1, "000102030405060782531A60CC24945A4B8279181AB5C84DF21CE7F9B73F42E197EA9C07E56B5EB17E5F4E", 10 }, { /*===============RFC3610PacketVector#10==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "0000000C0B0A09A0A1A2A3A4A5", 12, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E", 1, "000102030405060708090A0B07342594157785152B074098330ABB141B947B566AA9406B4D999988DD", 10 }, { /*===============RFC3610PacketVector#11==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "0000000D0C0B0AA0A1A2A3A4A5", 12, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", 1, "000102030405060708090A0B676BB20380B0E301E8AB79590A396DA78B834934F53AA2E9107A8B6C022C", 10 }, { /*===============RFC3610PacketVector#12==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "0000000E0D0C0BA0A1A2A3A4A5", 12, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", 1, "000102030405060708090A0BC0FFA0D6F05BDB67F24D43A4338D2AA4BED7B20E43CD1AA31662E7AD65D6DB", 10 }, { /*===============RFC3610PacketVector#13==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "00412B4EA9CDBE3C9696766CFA", 8, "0BE1A88BACE018B108E8CF97D820EA258460E96AD9CF5289054D895CEAC47C", 1, "0BE1A88BACE018B14CB97F86A2A4689A877947AB8091EF5386A6FFBDD080F8E78CF7CB0CDDD7B3", 8 }, { /*===============RFC3610PacketVector#14==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "0033568EF7B2633C9696766CFA", 8, "63018F76DC8A1BCB9020EA6F91BDD85AFA0039BA4BAFF9BFB79C7028949CD0EC", 1, "63018F76DC8A1BCB4CCB1E7CA981BEFAA0726C55D378061298C85C92814ABC33C52EE81D7D77C08A", 8 }, { /*===============RFC3610PacketVector#15==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "00103FE41336713C9696766CFA", 8, "AA6CFA36CAE86B40B916E0EACC1C00D7DCEC68EC0B3BBB1A02DE8A2D1AA346132E", 1, "AA6CFA36CAE86B40B1D23A2220DDC0AC900D9AA03C61FCF4A559A4417767089708A776796EDB723506", 8 }, { /*===============RFC3610PacketVector#16==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "00764C63B8058E3C9696766CFA", 12, "D0D0735C531E1BECF049C24412DAAC5630EFA5396F770CE1A66B21F7B2101C", 1, "D0D0735C531E1BECF049C24414D253C3967B70609B7CBB7C499160283245269A6F49975BCADEAF", 8 }, { /*===============RFC3610PacketVector#17==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "00F8B678094E3B3C9696766CFA", 12, "77B60F011C03E1525899BCAEE88B6A46C78D63E52EB8C546EFB5DE6F75E9CC0D", 1, "77B60F011C03E1525899BCAE5545FF1A085EE2EFBF52B2E04BEE1E2336C73E3F762C0C7744FE7E3C", 8 }, { /*===============RFC3610PacketVector#18==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "00D560912D3F703C9696766CFA", 12, "CD9044D2B71FDB8120EA60C06435ACBAFB11A82E2F071D7CA4A5EBD93A803BA87F", 1, "CD9044D2B71FDB8120EA60C0009769ECABDF48625594C59251E6035722675E04C847099E5AE0704551", 8 }, { /*===============RFC3610PacketVector#19==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "0042FFF8F1951C3C9696766CFA", 8, "D85BC7E69F944FB88A19B950BCF71A018E5E6701C91787659809D67DBEDD18", 1, "D85BC7E69F944FB8BC218DAA947427B6DB386A99AC1AEF23ADE0B52939CB6A637CF9BEC2408897C6BA", 10 }, { /*===============RFC3610PacketVector#20==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "00920F40E56CDC3C9696766CFA", 8, "74A0EBC9069F5B371761433C37C5A35FC1F39F406302EB907C6163BE38C98437", 1, "74A0EBC9069F5B375810E6FD25874022E80361A478E3E9CF484AB04F447EFFF6F0A477CC2FC9BF548944", 10 }, { /*===============RFC3610PacketVector#21==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "0027CA0C7120BC3C9696766CFA", 8, "44A3AA3AAE6475CAA434A8E58500C6E41530538862D686EA9E81301B5AE4226BFA", 1, "44A3AA3AAE6475CAF2BEED7BC5098E83FEB5B31608F8E29C38819A89C8E776F1544D4151A4ED3A8B87B9CE", 10 }, { /*===============RFC3610PacketVector#22==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "005B8CCBCD9AF83C9696766CFA", 12, "EC46BB63B02520C33C49FD70B96B49E21D621741632875DB7F6C9243D2D7C2", 1, "EC46BB63B02520C33C49FD7031D750A09DA3ED7FDDD49A2032AABF17EC8EBF7D22C8088C666BE5C197", 10 }, { /*===============RFC3610PacketVector#23==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "003EBE94044B9A3C9696766CFA", 12, "47A65AC78B3D594227E85E71E2FCFBB880442C731BF95167C8FFD7895E337076", 1, "47A65AC78B3D594227E85E71E882F1DBD38CE3EDA7C23F04DD65071EB41342ACDF7E00DCCEC7AE52987D", 10 }, { /*===============RFC3610PacketVector#24==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "008D493B30AE8B3C9696766CFA", 12, "6E37A6EF546D955D34AB6059ABF21C0B02FEB88F856DF4A37381BCE3CC128517D4", 1, "6E37A6EF546D955D34AB6059F32905B88A641B04B9C9FFB58CC390900F3DA12AB16DCE9E82EFA16DA62059", 10 }, { /*===============Authenticationonly==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "008D493B30AE8B3C9696766CFA", 33, "6E37A6EF546D955D34AB6059ABF21C0B02FEB88F856DF4A37381BCE3CC128517D4", 1, "6E37A6EF546D955D34AB6059ABF21C0B02FEB88F856DF4A37381BCE3CC128517D4CA35DC8A1EBD6BC7EAD7", 10 }, { /*===============Noheader==================*/ "D7828D13B2B0BDC325A76236DF93CC6B", "008D493B30AE8B3C9696766CFA", 0, "6E37A6EF546D955D34AB6059ABF21C0B02FEB88F856DF4A37381BCE3CC128517D4", 1, "36ECBF5CDCF736D6080F6B4F54B03078C1D19CB2E0B18A3C3883AA48B3ABEE5A795300F8778A19BD45BC34", 10 }, { /*===============16byteauthenticationfield==================*/ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000003020100A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E", 1, "0001020304050607588C979A61C663D2F066D0C2C0F989806D5F6B61DAC384509DA654E32DEAC369C2DAE7133CB08D", 16 }, { /* =============== Small payload ================== */ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000003020100A0A1A2A3A4A5", 8, "000102030405060708090A0B0C0D", 1, "0001020304050607588C979A61C6B7C00BB077809CAE", 8 }, { /* =============== Small payload ================== */ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000003020100A0A1A2A3A4A5", 1, "000102030405060708090A0B0C0D0E0F1011", 1, "0051879E9568CD6AD5E97DC9DDD9E29087643EB868CBF8E0E0CC", 8 }, { /* =============== Minimal header and payload ================== */ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", "00000003020100A0A1A2A3A4A5", 1, "0001", 1, "0051C0EED548220130D4", 8 }, { /* =============== Big Data ================== */ "D7828D13B2B0BDC325A76236DF93CC6B", "008D493B30AE8B3C9696766CFA", 42, "0BF89E3B7DB8624B5A7DEC72FD5A32369A6B84FE05D74A115E4D40A9055C6C0AD65609BEEFF93DBACCA5506AF7766196950671DEF6C70A7114225F1535BB8D", 1040, expectedBigData, 10 } }; int AJ_Main(void) { AJ_Status status = AJ_OK; uint32_t i; AJ_AlwaysPrintf(("AES CCM unit test start\n")); for (i = 0; i < ArraySize(testVector); i++) { uint8_t key[16]; uint8_t input[64]; uint8_t* msg; uint8_t nonce[16]; uint32_t nlen = (uint32_t)strlen(testVector[i].nonce) / 2; uint32_t ilen = (uint32_t)strlen(testVector[i].input) / 2; uint32_t mlen = ilen * testVector[i].repeat; uint32_t j; char* out; size_t olen; AJ_HexToRaw(testVector[i].key, 0, key, sizeof(key)); AJ_HexToRaw(testVector[i].nonce, 0, nonce, nlen); AJ_HexToRaw(testVector[i].input, 0, input, mlen); msg = AJ_Malloc(mlen + testVector[i].authLen); if (!msg) { AJ_AlwaysPrintf(("Allocation failed for test #%zu\n", i)); goto ErrorExit; } for (j = 0; j < testVector[i].repeat; j++) { memcpy(&msg[ilen * j], &input[0], ilen); } olen = 2 * (mlen + testVector[i].authLen) + 1; out = AJ_Malloc(olen); if (!out) { AJ_AlwaysPrintf(("Allocation failed for test #%zu\n", i)); goto ErrorExit; } status = AJ_Encrypt_CCM(key, msg, mlen, testVector[i].hdrLen, testVector[i].authLen, nonce, nlen); if (status != AJ_OK) { AJ_AlwaysPrintf(("Encryption failed (%d) for test #%u\n", status, i)); goto ErrorExit; } AJ_RawToHex(msg, mlen + testVector[i].authLen, out, olen, FALSE); if (strcmp(out, testVector[i].output) != 0) { AJ_AlwaysPrintf(("Encrypt verification failure for test #%u\n%s\n", i, out)); goto ErrorExit; } /* * Verify decryption. */ status = AJ_Decrypt_CCM(key, msg, mlen, testVector[i].hdrLen, testVector[i].authLen, nonce, nlen); if (status != AJ_OK) { AJ_AlwaysPrintf(("Authentication failure (%d) for test #%u\n", status, i)); goto ErrorExit; } AJ_RawToHex(msg, mlen, out, olen, FALSE); for (j = 0; j < testVector[i].repeat; j++) { if (strncmp(&out[2 * ilen * j], testVector[i].input, ilen * 2) != 0) { AJ_AlwaysPrintf(("Decrypt verification failure for test #%u\n%s\n", i, out)); goto ErrorExit; } } AJ_AlwaysPrintf(("Passed and verified test #%zu\n", i)); AJ_Free(msg); AJ_Free(out); } AJ_AlwaysPrintf(("AES CCM unit test PASSED\n")); return 0; ErrorExit: AJ_AlwaysPrintf(("AES CCM unit test FAILED\n")); return 1; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/aestest_bigdata.h000066400000000000000000025023221271074662300171120ustar00rootroot00000000000000/** * @file * * One large string. */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /* This is AES-CCM encrypted data for the "Big Data" test case in aestest.c * It is encoded as an array because some compilers have size limits for string * literals. * The plaintext consists of 63 repeated random bytes. */ static const char expectedBigData[] = { '0', 'B', 'F', '8', '9', 'E', '3', 'B', '7', 'D', 'B', '8', '6', '2', '4', 'B', '5', 'A', '7', 'D', 'E', 'C', '7', '2', 'F', 'D', '5', 'A', '3', '2', '3', '6', '9', 'A', '6', 'B', '8', '4', 'F', 'E', '0', '5', 'D', '7', '4', 'A', '1', '1', '5', 'E', '4', 'D', '4', '0', 'A', '9', '0', '5', '5', 'C', '6', 'C', '0', 'A', 'D', '6', '5', '6', '0', '9', 'B', 'E', 'E', 'F', 'F', '9', '3', 'D', 'B', 'A', 'C', 'C', 'A', '5', '0', '8', 'B', '1', 'E', 'E', 'C', '5', 'E', '9', '0', 'C', '3', '6', '8', 'D', '4', 'D', '7', 'A', 'F', 'D', 'D', '1', 'F', '5', '3', '3', '3', '8', '5', '1', '9', 'C', '3', 'A', '1', '1', '8', '6', 'E', '8', 'D', '7', '8', '6', '0', '1', '7', '0', '7', 'F', 'A', 'E', 'C', '9', '3', '4', 'E', '3', '1', '6', 'A', '1', 'D', 'F', '6', 'D', 'F', 'E', '1', '8', '6', 'D', '0', '3', '2', '0', '2', 'D', '0', '9', '3', 'B', '5', 'B', 'D', 'E', '8', '6', '6', '5', '5', '6', '4', 'E', 'F', '7', '4', '5', '0', 'F', '7', 'A', 'A', 'D', '4', 'E', 'B', 'C', 'A', '6', '5', '7', 'D', '3', 'D', '6', '8', 'B', 'A', '5', 'B', '5', '4', '0', '8', 'B', '0', '9', 'C', 'D', 'B', 'E', 'C', '1', 'C', 'B', '4', '1', '7', '6', '4', 'E', '3', '5', 'A', 'C', '4', '4', '2', '0', 'B', '2', 'F', '8', '5', 'D', '5', '9', '2', 'B', '0', 'D', '9', '8', '6', 'D', 'D', '2', 'C', 'A', '1', '1', 'C', 'D', '7', '0', 'D', 'B', '1', '9', 'E', 'D', '8', '0', '1', 'D', 'C', 'E', '8', '0', 'A', '1', '7', '5', '9', 'D', '9', '8', 'E', '8', '8', '6', 'A', '1', 'B', '2', '1', '3', '1', '7', '5', 'C', 'E', 'F', 'D', '2', '1', '1', 'E', '5', '4', '5', '7', '0', 'D', '0', '9', 'D', '9', '5', '7', 'F', '2', 'A', 'B', 'D', '9', '1', '4', '4', 'E', '5', '6', 'F', '2', 'B', '5', '4', '8', '0', '5', '6', '9', '9', 'C', 'D', '0', '5', '9', 'F', '9', 'A', 'B', 'D', 'C', '0', '4', '9', 'B', 'A', '9', 'A', 'A', '3', 'F', 'F', 'E', '1', 'F', '3', '2', 'C', '5', '0', '2', '2', '5', '4', 'C', '5', 'D', '0', '4', '2', '7', 'F', 'F', '8', '4', '6', '6', 'E', '2', 'C', '6', 'D', '9', '3', '9', '9', '3', 'C', 'C', '3', 'B', 'E', 'F', 'F', 'F', '0', '5', '3', 'B', 'A', '9', '3', '4', '9', '2', 'F', 'F', '1', 'A', 'A', '2', '5', 'A', '1', 'E', 'C', '3', '5', '2', '2', '3', 'F', '9', '3', '4', '1', '9', '8', '3', 'E', 'C', 'C', '2', '6', 'F', '9', '4', '5', '5', 'D', '5', '9', '1', '8', '9', 'B', '5', 'D', '7', '0', '5', 'B', '0', '3', '9', '9', 'D', '8', '7', 'F', 'D', '9', 'E', '2', '5', '4', '3', '5', '7', '3', '5', '2', 'E', '7', '1', 'D', 'F', '7', '4', '1', '0', '0', 'B', '1', 'D', '9', '3', '5', '1', 'B', '8', 'C', '7', '5', '6', 'D', '9', 'A', '2', '9', 'B', 'E', 'E', 'C', 'E', '3', '9', '4', 'A', '7', '4', '1', '4', '2', 'B', '1', '5', 'F', 'B', '8', '1', 'E', 'C', '7', '0', 'E', 'E', '7', '9', 'E', '6', 'C', '3', 'A', 'D', '7', '8', '7', '1', 'F', '4', '6', '6', '0', 'C', '7', 'E', '0', '3', 'B', 'A', 'A', '2', '5', '8', 'C', '6', '8', 'F', '7', 'E', '8', '4', 'B', '5', 'D', 'B', 'B', 'B', '1', '7', '1', 'B', 'C', 'C', 'F', '2', '5', 'F', '7', 'B', '8', '0', '2', '4', '5', 'A', '8', '4', 'A', '0', '5', '7', '4', 'B', 'D', '3', 'F', 'C', '7', 'A', 'A', '3', '1', 'F', 'C', '1', 'A', 'B', 'E', '7', '5', 'D', 'E', '0', '0', 'C', '1', 'A', '4', 'C', '2', 'D', 'D', '6', '1', '6', 'D', 'F', '1', '4', '2', '8', '4', 'B', '7', '5', '4', 'E', '1', 'D', 'E', 'C', '8', '5', '0', '1', 'A', '8', '9', '2', 'E', 'B', '8', '1', '0', '7', '0', '9', 'E', 'A', '4', 'B', '3', '8', 'C', '7', 'B', '0', '1', 'E', '1', '6', '0', 'E', 'D', 'D', '1', 'E', '7', '0', '5', '7', '0', 'A', 'C', '4', 'B', 'A', '3', '6', '9', '5', 'D', '5', '9', 'D', '6', 'B', '3', 'A', 'D', 'C', 'A', '2', '9', '0', 'B', 'C', '7', '7', '8', '2', '2', '2', '4', '4', '7', '7', 'F', '6', '8', 'A', '3', 'E', 'B', '4', '1', '1', '3', '0', '4', '6', '8', 'C', '7', '5', '8', '3', '7', 'C', '6', '0', '5', '6', 'D', '5', 'E', '1', '8', '5', '6', 'B', '1', 'E', 'C', 'F', '6', '0', '4', 'D', '6', 'E', '5', '8', 'F', 'C', 'D', 'F', '4', 'B', 'F', '6', '3', 'E', '5', '5', '2', '5', 'B', 'A', '0', '6', '1', '1', 'D', '4', 'B', '9', '9', '1', 'C', 'B', 'E', 'E', '4', '4', '6', 'E', 'E', 'A', '6', '3', '5', '1', 'C', 'C', '1', '5', '9', '9', 'C', 'E', '1', '5', 'E', 'E', '6', 'F', '1', '7', 'F', '0', 'A', 'F', '3', 'B', '0', 'E', '4', 'C', '1', 'B', 'F', '8', 'B', '3', '3', '3', '5', 'B', '7', 'D', 'E', '9', 'A', '2', '5', '1', '4', '9', '6', 'B', '1', '3', '2', 'F', '1', '2', 'F', '4', 'B', '4', '4', '5', '2', 'E', '4', 'A', '6', 'A', 'D', '7', '1', '9', '4', 'D', 'E', 'B', 'B', '5', 'C', '5', 'B', '2', 'C', 'B', '8', '9', '5', '2', '6', '5', '9', '5', '1', '2', '9', '7', 'E', 'B', '2', '4', '0', '7', '4', '1', 'A', '6', '0', '2', '8', '0', 'D', 'F', '5', 'D', '6', '9', '8', '4', '1', 'E', '5', 'E', '6', 'B', '9', '7', 'B', 'B', 'E', 'C', '1', 'E', '6', '1', '5', 'C', 'A', '3', '2', '6', '0', '5', '6', '1', 'F', '4', 'D', 'F', 'F', '8', '6', 'D', '0', 'D', 'B', '2', 'B', 'A', '2', 'F', 'C', 'D', '6', 'E', 'D', '3', 'F', '5', 'E', '4', '1', 'F', 'A', 'C', 'D', 'B', 'E', '8', 'D', '1', '5', '9', '1', '1', '6', 'F', '6', '1', 'B', '8', 'C', 'C', '2', '8', '7', '0', '9', '9', '5', '0', 'B', 'B', '1', 'B', '9', 'F', '5', '5', 'F', '8', '2', '6', '8', '8', '0', '5', 'C', '1', '1', '5', '4', '2', '9', 'F', '0', 'F', 'C', '8', '6', '5', 'E', '1', 'D', 'C', '7', '0', 'D', 'C', '2', 'A', '1', 'E', '9', 'B', '4', 'C', '3', 'A', '7', '5', '8', '0', 'A', 'F', 'B', '7', 'F', '0', 'F', '9', '9', '5', '7', '8', '5', 'F', 'D', '6', '2', '8', 'C', 'A', '6', '7', '4', '6', 'F', '5', '5', 'D', '5', 'D', '9', 'F', '4', 'F', '4', 'F', 'F', '5', '4', '5', '3', 'A', 'F', 'B', 'F', '7', 'F', 'D', 'D', '5', 'D', 'B', '0', 'B', '6', 'C', '7', 'E', 'A', '8', '4', '9', '6', 'C', 'E', 'D', '1', '7', '5', 'E', 'F', '2', '5', '2', 'D', 'C', '3', '3', 'E', '0', '0', 'F', '0', 'D', '0', 'B', '8', '3', 'E', 'F', '0', '7', '7', '8', '4', 'A', '1', '4', 'D', 'A', '0', 'D', '7', '2', 'D', '3', 'A', '0', '5', '5', '5', '0', '4', '9', 'D', '4', '1', 'B', '1', 'A', '6', 'C', '0', 'E', '3', 'F', '0', 'A', '4', '4', 'D', '9', 'B', 'D', '0', '2', 'E', 'F', '4', '2', '0', 'A', '5', '9', '9', '7', '5', '8', '0', '2', '6', '8', '5', '7', '0', 'D', '3', '6', '2', 'F', 'B', 'A', 'B', 'D', '1', '7', '2', '9', 'E', '4', '9', '6', '2', '3', 'D', '5', '8', '4', 'F', '6', '8', 'C', 'B', '3', 'C', 'B', '5', '7', '9', '1', 'E', 'F', '1', '0', 'D', '4', '9', '7', '6', '4', 'A', '4', '1', '9', 'F', '9', 'A', '2', 'F', '9', '3', '0', '8', 'D', '9', '3', '5', '7', '9', 'E', 'A', '6', 'F', 'E', '1', '0', '9', '5', '6', 'D', 'F', 'B', 'F', 'D', '5', '3', '6', '6', '2', '5', '7', '6', '4', '8', 'A', 'F', '4', '2', '6', '6', 'E', '6', '6', 'A', '8', '1', 'E', '6', '3', 'B', '9', 'B', 'B', 'C', '0', '0', '7', '7', 'D', '9', 'A', '8', '8', '2', '8', 'B', '0', '0', '1', '7', '0', '3', '6', '1', 'C', 'D', 'D', 'B', '4', '0', '3', 'B', 'A', '1', 'B', 'C', '2', 'A', 'F', '7', '9', '1', '8', 'A', '5', '5', 'B', '2', '6', 'E', 'B', '3', '5', '0', 'E', '5', '0', '2', '7', 'B', '5', 'A', 'B', 'E', 'C', '9', '0', '1', 'D', '6', '5', 'C', '8', '9', 'D', 'C', 'A', 'A', 'E', 'B', 'C', '0', 'A', '2', 'C', '5', 'F', '4', 'E', '5', '4', '0', '8', 'C', 'B', '3', '8', '9', '9', 'F', '9', '6', 'E', '3', 'D', '9', '5', '7', 'C', '5', '7', '2', 'E', 'E', '6', '7', 'C', '6', 'C', '8', 'F', 'D', '5', '1', '2', 'A', 'A', '7', 'A', '5', 'F', '6', 'A', '4', 'D', '7', 'F', '3', '1', '3', '2', '1', '2', '6', 'F', '3', '5', 'A', '2', 'B', '7', '6', '4', 'B', '6', 'F', '9', 'F', '3', '7', 'C', '3', 'D', '1', '1', '7', '9', 'B', '1', 'E', '7', '4', '6', '1', 'D', '5', '5', 'A', '3', 'C', '2', '1', '6', '9', '0', '5', '3', '4', '6', 'D', 'A', '4', 'A', '3', '9', 'E', 'C', 'E', 'D', '7', 'B', '1', '7', '1', 'B', 'E', '4', 'B', '1', 'D', 'B', '4', '8', '5', '0', '1', '9', 'B', '8', 'D', '9', '2', '1', '0', '6', 'D', 'A', '9', '5', '4', '5', '1', '5', '0', 'F', '9', 'A', '4', 'B', '4', '5', 'A', 'F', 'D', '6', '3', 'B', '3', '4', '1', '9', '7', '2', '4', '8', '6', '1', 'F', '9', '2', 'C', 'A', 'A', 'B', 'B', 'B', 'C', '9', '1', '3', 'A', '8', 'D', 'D', '8', '1', 'B', '8', '0', '9', '9', 'C', '9', '9', '1', 'C', '2', 'E', '6', '1', '4', '3', '1', 'E', 'F', '5', '0', '2', '6', '3', '2', 'C', '1', '7', 'E', '0', '8', '5', '3', '7', '0', '9', '0', 'D', '8', '5', 'E', '7', '7', 'C', '9', '0', 'B', '4', '5', '3', '2', '4', '1', '0', 'A', 'E', 'A', '5', 'A', '8', '5', 'B', '2', '4', 'C', 'F', '0', 'D', '9', 'A', '3', 'F', '6', '9', '0', 'A', '5', '9', 'A', 'A', 'E', 'C', 'E', '3', 'A', '0', 'B', 'C', 'B', 'D', '1', 'B', '5', '9', 'D', 'E', 'A', '7', 'D', '4', 'B', '2', '1', 'E', 'C', '0', '2', '5', 'D', '5', '4', '4', 'F', '1', 'C', 'C', 'F', '6', 'E', '3', '2', '3', 'B', '2', '9', '8', '0', 'C', 'C', '9', '9', '9', '2', 'F', 'E', '4', 'C', '3', '0', 'B', '2', '7', '8', '6', '3', 'D', 'E', '3', '8', '7', '2', '0', 'B', '7', 'C', '0', '3', '6', 'D', '7', '4', '5', 'F', '4', 'B', 'D', '5', 'B', '1', 'D', '6', '9', '3', '4', 'D', '6', '7', '3', '9', '4', 'C', '4', 'F', 'C', '0', '9', '5', 'A', '2', 'D', '3', '8', '3', '0', '1', '9', '5', 'E', '6', '0', '1', 'F', 'A', '7', 'E', '0', '7', '4', '3', '2', '9', '2', 'E', 'B', '1', '6', '3', 'C', '4', 'E', '2', 'E', 'A', '2', 'B', '0', 'A', '2', 'E', 'F', '0', '2', 'F', 'F', '1', '5', 'B', 'C', 'B', '9', '9', '9', '4', 'E', 'F', 'D', '7', 'E', '1', '5', '8', '9', 'F', 'A', '2', 'F', '2', '1', '9', '5', '8', '2', 'C', '7', '2', '2', '3', '8', '1', 'C', 'D', 'E', 'E', 'A', 'D', '2', '6', '0', '7', '2', '1', 'C', 'E', '4', 'C', '2', 'C', '8', 'E', 'B', 'B', 'F', '4', '3', 'A', '9', '1', '5', 'E', 'B', '6', '0', '1', '6', 'E', '3', '9', '8', 'A', '4', '2', 'C', '3', 'E', '5', '6', '2', '6', 'C', '4', 'A', '7', '0', '2', 'D', '5', '7', 'E', '7', 'B', 'A', 'B', 'F', 'F', 'C', '4', '6', '7', 'F', 'A', 'E', '9', 'B', '7', 'F', '5', '6', '9', 'A', '9', 'F', '2', 'B', 'A', '7', '9', '5', 'A', '0', 'D', '8', '0', '4', '1', 'C', 'D', '1', '7', 'F', '5', '2', 'C', 'E', '6', '3', '5', '3', '0', '7', 'A', '8', '7', '0', '5', 'C', '8', '5', '2', 'D', 'B', 'F', 'D', 'A', 'B', '1', 'D', '6', '6', '2', '5', 'E', 'B', '6', '8', '9', '3', '3', '3', 'F', 'D', '6', '1', 'A', '3', '0', '4', '9', 'C', '5', '7', 'A', '3', '5', '1', '5', '9', '6', 'F', 'D', '2', 'B', 'B', '1', 'A', '3', '9', 'C', 'E', '5', '8', 'C', 'C', '6', 'A', 'A', 'D', '0', 'E', 'B', '1', '0', 'E', 'D', '7', '3', '2', '3', '5', '9', 'C', 'E', '2', '0', '4', '7', '7', '5', '4', '6', '5', 'E', '6', '5', 'C', '5', 'E', '4', 'C', '4', '1', '6', '2', 'B', 'C', 'E', 'C', 'D', 'B', '9', '8', 'C', '5', '1', '0', '4', '0', '4', '9', '5', '9', '5', 'B', 'E', '1', 'F', 'A', '8', '1', '7', 'F', '1', '0', '4', 'D', '7', '4', '2', '5', '6', '0', '1', '1', '4', 'E', '5', '4', '8', '4', '4', 'A', 'F', '9', '4', '6', '5', 'F', 'B', '6', 'B', '9', '7', 'D', 'D', '7', '9', 'E', '2', '0', '0', '5', 'D', '1', '7', 'F', 'B', '7', '1', 'A', 'E', 'B', '5', 'B', '2', '8', '9', '1', '6', '3', '4', '6', 'D', '5', 'F', 'F', '4', '5', '7', '4', '8', 'E', '6', 'A', '7', 'C', 'B', '3', '0', '0', '5', 'E', '2', '3', '3', '8', 'B', 'C', 'D', '6', '8', '4', 'D', 'A', '4', '1', '2', 'F', 'F', '3', 'C', 'A', '2', 'A', '8', '8', '8', '0', '3', 'E', 'D', '8', '5', '9', 'F', '8', '0', 'C', 'B', 'A', 'C', 'E', 'F', 'C', '3', '6', '5', 'A', '4', 'E', 'B', '8', '4', 'C', 'C', 'A', '0', '6', 'C', 'B', 'C', '4', 'B', '8', 'E', 'D', '4', '7', '1', '7', '0', 'A', 'D', '6', 'E', '0', '1', '9', '9', '3', 'E', '4', '7', '9', '8', 'B', 'C', '1', '1', '6', '3', 'C', '2', '2', '4', 'A', '8', '1', 'A', '6', 'A', 'F', '2', '8', '3', 'C', 'E', '5', '1', '8', '3', '8', 'D', '7', '3', '6', '0', 'A', '0', 'A', 'F', '3', '8', 'B', '1', '5', '0', '9', '1', '0', '8', '0', '2', '8', '7', '4', 'F', 'E', 'F', '3', '7', '2', '0', '4', 'C', '2', '2', '5', '1', '1', '7', '3', '2', '6', '6', '2', 'E', '9', '3', 'E', '7', 'B', '0', '3', '0', 'A', 'B', 'D', '9', '5', '1', '9', '1', '5', '1', '8', 'D', '7', '9', 'F', '4', '9', '3', '1', '9', 'E', '4', 'E', '9', 'A', '2', 'C', 'E', 'F', '7', '2', '1', '7', '7', '4', '5', 'E', '9', 'D', '3', '5', 'F', '3', '1', '5', '4', '1', '3', 'A', 'C', '1', '6', '3', '3', '0', '7', 'A', 'E', '1', 'F', '7', '5', '8', '1', '6', 'A', 'B', 'B', 'E', '0', 'A', '5', 'A', 'C', 'C', '1', 'E', '7', '2', 'D', '6', 'E', 'B', 'D', 'E', 'F', '5', '8', '5', '4', 'F', '7', 'D', '6', '4', 'F', 'B', '2', '1', '0', 'E', '7', '0', '0', 'D', '2', '2', 'A', 'B', 'B', 'E', '0', 'A', '9', '3', 'D', '5', 'F', '6', '1', 'E', '0', '5', '8', '7', '6', 'A', '4', '3', '8', 'C', '8', '6', 'D', '2', 'A', '7', 'C', '6', '2', 'F', '4', '1', '7', '8', '1', '7', 'F', '7', '1', '7', '4', 'D', '0', '8', '9', 'D', '3', 'B', '9', '4', '9', 'C', 'C', '0', 'C', 'B', '4', 'C', 'F', '4', '3', '9', 'F', '3', 'D', '7', 'F', '9', '8', 'B', 'D', '1', 'C', 'A', '0', 'A', '6', '6', '1', 'F', 'E', '0', '9', 'B', '6', 'B', 'C', 'F', 'C', 'D', '2', '5', '3', '5', 'C', '8', '5', 'E', '6', '0', 'B', '4', '9', '9', 'D', 'A', 'A', '3', '4', '3', '9', '7', 'C', '6', '3', 'C', 'C', 'E', 'B', 'D', 'C', '1', '1', '8', '3', 'B', '9', '5', 'D', '8', 'F', '2', '3', '7', 'E', '0', '6', 'D', '7', 'C', '9', '3', 'A', 'C', 'B', 'B', '3', '0', 'D', 'B', 'C', '5', 'D', 'F', 'A', 'E', 'A', 'C', 'B', '0', '7', '4', '2', '4', '0', '2', '5', 'F', '4', '4', 'C', '8', '0', '9', '8', '6', '9', 'A', '1', '2', '2', '5', 'E', '7', 'B', '8', '5', '9', 'F', 'D', '3', '0', '9', '2', 'F', '8', '3', '6', '5', 'F', '6', 'F', 'B', 'E', 'F', '4', '7', 'F', '4', 'E', '8', '2', '5', 'C', '2', '2', 'D', '5', 'D', 'E', 'A', '2', 'B', '6', 'A', '6', 'C', 'D', 'E', '4', '9', 'B', 'D', '5', 'F', '9', 'F', '4', '5', '5', '6', 'D', '8', '4', '7', 'C', '1', 'A', '6', '5', '1', '0', '3', '3', '6', 'D', 'C', 'A', 'D', '0', 'C', 'C', 'F', 'E', '6', '6', 'E', 'C', '1', '4', '2', '7', 'A', '0', '0', 'B', 'D', '5', '6', '6', '6', '4', '9', 'A', '3', '7', 'B', 'D', 'C', '5', 'E', '6', '2', '6', '9', 'C', 'E', '2', '8', '8', '9', '6', 'F', '9', 'A', '4', '3', '6', 'D', 'C', '8', 'B', '3', 'C', '2', 'F', '3', '4', 'C', '7', '6', '6', '1', '7', 'E', '9', 'B', 'B', 'C', '2', '1', 'E', 'D', 'F', '3', 'B', '9', 'F', 'D', '1', '5', '3', '5', '7', '5', 'D', 'B', 'C', '0', '0', '4', '4', '8', '5', '9', '1', '4', 'D', 'A', 'A', '2', '1', 'B', 'E', '8', '2', 'D', '1', '1', 'E', '7', '3', 'A', '8', '5', 'D', '5', 'D', 'C', '4', 'A', 'B', '2', '5', '9', 'A', 'B', '3', 'D', '2', 'A', '5', 'C', '3', 'F', 'E', 'F', 'F', '4', 'A', 'F', '2', '2', '9', 'D', '2', '6', '0', '4', '1', '9', 'F', '3', '1', 'A', 'B', '4', 'C', '1', '5', '0', '5', '7', '9', '2', '8', '2', 'D', 'B', '3', '9', 'F', 'F', '2', '8', '1', '5', '7', 'F', 'D', 'B', '5', 'D', '4', '5', '4', '7', '6', 'E', '5', '1', '5', 'E', '8', '6', '7', '6', 'A', '4', '9', 'C', '5', '1', 'D', 'F', 'A', '9', '3', 'A', 'F', 'B', 'F', 'C', '5', '0', '1', '6', 'A', 'D', 'F', 'C', '3', '4', 'C', 'F', '9', 'B', '2', '2', '4', '9', '9', 'C', '3', '5', '5', '6', '5', 'F', 'E', '3', 'B', '9', '8', '2', '4', '6', 'B', '6', 'D', '3', '0', '1', '0', 'F', 'C', '9', '6', '0', 'D', '1', '6', '4', '2', '9', 'F', 'D', '2', '6', 'B', '7', 'F', '9', 'E', 'C', '3', 'C', 'C', '5', '4', 'C', '7', '7', 'E', '9', '2', 'D', '2', 'E', 'F', 'D', '7', 'C', 'F', '5', 'F', 'B', 'B', 'D', '9', 'F', 'E', '2', '3', '9', '7', '7', 'E', 'F', '9', 'C', '8', '9', '9', '7', 'B', '9', '0', '1', '9', 'D', 'C', 'B', '5', '5', '9', 'B', '4', '1', '3', 'D', '3', '5', 'B', '4', 'D', '4', '2', '1', '9', 'E', 'D', 'F', '5', '1', '3', '9', '5', '2', '3', '9', '5', '7', 'D', 'D', 'F', 'B', 'D', '9', 'C', '7', 'E', '1', 'F', '2', '0', 'D', 'B', '6', '4', '5', 'D', 'C', '8', '6', 'F', '0', 'D', '4', 'B', '4', '8', '7', 'E', 'E', 'D', 'E', 'C', '9', 'E', '3', '3', 'E', 'D', '8', 'F', '8', '2', 'A', '1', '9', '2', '5', '5', '9', '0', '5', 'A', 'B', '5', 'A', 'B', 'E', 'D', '0', '4', 'C', '6', '5', 'A', '5', '6', '0', '2', '1', '3', '9', 'E', '1', 'E', '3', '5', '6', '1', 'C', 'F', '6', 'D', '7', 'C', '1', '5', '2', '4', '3', '3', '2', 'C', '4', 'D', '6', 'E', '7', '8', '5', 'B', 'B', 'C', '7', '4', '0', 'D', '0', 'E', 'C', '5', '7', 'C', 'F', 'F', '2', 'F', '6', 'F', '7', 'F', '3', 'C', 'A', '1', '3', 'F', 'E', 'F', '2', '3', 'D', 'E', '6', 'A', '0', 'E', 'A', '5', '7', '0', '0', 'F', '5', 'A', '2', '5', '1', '8', '6', '3', 'A', '4', 'D', '5', '6', '9', '3', 'D', 'A', 'F', '9', 'B', '7', '1', 'D', 'B', '7', '8', 'C', '3', '5', '8', '0', 'F', '7', '6', 'A', 'E', '6', 'A', '8', '4', '9', '2', '4', 'B', 'F', '0', 'C', '1', '6', 'C', 'B', '7', '6', '2', '8', '5', '8', 'C', '1', '0', 'A', '1', '6', 'E', 'D', '3', '1', '5', '2', '9', '2', 'D', '0', 'F', '4', '0', '4', 'D', '8', 'B', '8', 'B', 'F', 'E', 'B', 'A', '0', '3', '4', 'F', 'D', '3', 'F', '9', 'C', 'F', '4', 'C', '8', '6', '5', '4', '4', 'B', 'F', '9', '2', 'B', '4', 'E', 'A', 'F', '8', '9', '4', 'B', '8', '0', '0', 'D', '9', '5', 'F', '7', '6', '0', 'B', '7', 'C', 'B', '1', 'B', '0', '2', '4', '9', '3', '2', '9', '1', 'E', 'A', '2', '1', '5', 'E', '1', '2', '7', 'A', 'F', 'A', 'A', 'A', '7', 'C', '8', 'B', 'E', 'E', 'B', '6', '4', '9', '5', 'E', '9', 'A', '6', '8', '1', '9', 'F', '4', 'F', '8', 'E', '7', 'E', '9', '4', 'A', 'F', '7', 'D', '2', '9', '1', '7', 'B', 'F', '6', 'D', '1', '8', 'C', '0', '0', '0', '3', 'A', 'E', 'D', 'A', 'C', 'C', '1', '8', '7', 'B', '3', '4', 'B', 'A', '7', '9', '6', '0', '7', 'E', 'B', 'D', '6', '4', '2', '0', '2', 'D', '8', 'E', 'F', '6', '6', '2', '6', '2', '8', 'B', 'A', '2', 'E', '8', 'A', 'B', '4', 'C', '6', '1', 'A', 'B', '1', 'A', '5', 'B', '7', 'C', '5', '5', 'B', '5', 'B', 'D', '7', '3', 'A', 'F', 'E', '3', '5', 'A', 'F', 'D', '1', '4', '6', '4', '8', 'B', '2', 'A', '0', '0', 'D', '0', 'F', 'E', 'F', 'F', 'A', 'D', '5', '9', '3', 'F', '5', 'B', '9', 'E', 'C', 'D', '7', '3', '6', '1', 'D', '8', '2', '3', 'D', '4', '1', 'C', 'E', '3', 'F', '7', '9', '8', '2', '4', '3', 'C', '1', 'F', '8', '8', '6', '8', 'C', '1', 'D', '3', '3', '3', '9', 'B', '3', '6', 'E', '3', 'E', 'E', 'F', '3', '0', '2', 'F', '9', '1', '5', 'C', '8', '6', '8', 'E', '9', '1', '1', '2', '7', '7', '0', 'D', '6', '5', '0', 'C', 'B', 'B', 'D', 'B', 'F', '5', '2', '3', 'A', '2', 'D', '4', '5', '5', '0', '2', '8', 'B', '7', 'E', '9', 'D', '6', 'D', '4', 'F', '6', 'D', 'E', 'D', '6', 'A', 'A', '7', '5', '1', '5', 'A', '8', '7', '5', 'D', '5', '5', 'E', 'D', 'D', '3', '5', '8', 'D', 'F', '1', '0', 'C', 'F', '3', '8', 'F', 'B', '5', 'F', 'C', '0', 'D', '3', '1', '2', 'B', 'F', '4', '3', 'B', '2', '1', '5', '8', '8', 'B', '6', 'B', 'F', '6', '5', '6', '5', '7', '0', 'F', '0', '8', '0', 'F', '9', 'A', 'A', '3', 'F', 'D', '7', '0', '9', '4', '9', 'A', '4', 'A', 'A', 'D', '9', 'E', 'F', '9', 'F', '8', '3', '4', '6', '8', 'C', '2', '9', 'C', 'B', '3', '0', '8', '8', 'E', 'E', 'E', '6', 'A', '5', 'F', '6', '5', '0', '5', '8', '6', '7', 'E', 'B', '8', 'E', 'A', '5', '3', '9', '5', 'D', 'E', '8', 'F', '5', '7', '4', 'C', '9', '7', '9', 'A', '0', '6', '1', 'C', 'E', 'C', 'F', '4', '6', 'D', 'F', '9', '9', 'B', '1', 'D', '1', '2', 'F', '5', 'A', '9', 'C', '8', '0', '5', '7', 'E', '6', 'C', '1', '2', 'D', '1', '1', '7', 'D', 'F', '1', '2', 'E', 'B', 'D', '4', '7', 'A', '1', '4', '7', '4', '8', '8', '7', 'C', '9', '0', '5', '3', '9', 'D', '3', 'E', '5', 'F', 'E', 'F', '9', '3', '3', 'B', 'F', '2', 'B', '2', '3', '0', '7', 'B', '2', 'B', '1', '6', '4', 'A', '1', '6', '8', 'E', '4', 'F', '2', 'A', '6', '5', '6', '1', '6', '5', 'B', '2', 'E', '1', 'E', '1', 'E', '2', 'B', '4', 'E', 'A', 'B', 'A', 'B', 'E', '7', '8', 'C', '4', '8', 'E', 'F', '3', '9', 'A', '7', 'B', '6', '4', '2', 'C', '7', '4', '3', '1', '7', 'A', '9', '6', 'C', '2', 'C', '7', '0', '5', '5', '8', '2', 'A', '6', 'A', 'A', '3', 'F', 'A', '0', '4', '2', 'E', 'B', '5', '9', '3', '4', 'A', '8', '3', 'E', '0', '8', '8', 'C', '6', '1', '8', '3', '6', 'D', '9', '2', '5', 'F', 'A', '8', '7', '6', '3', 'B', 'B', 'B', '2', 'F', 'C', 'A', 'A', 'A', 'D', 'A', 'E', '5', '1', '6', '6', 'B', '3', '6', '5', 'B', '3', '3', '5', '3', '1', '1', '0', '5', '6', '4', 'D', '6', '4', '4', 'E', 'E', '8', 'C', 'F', '7', '0', '3', 'C', '2', 'E', 'B', 'B', '1', 'B', '3', 'B', '8', '3', 'A', '8', 'D', '1', '3', '3', '8', 'B', 'C', '3', '9', '7', 'B', '6', '0', '4', '3', 'C', 'E', '8', '6', '1', '1', 'D', '2', 'D', '1', '1', 'F', 'C', 'D', '5', '2', '4', '2', 'D', '8', '6', '9', '5', '2', 'E', '6', 'E', '2', 'D', 'D', '8', 'F', '8', 'A', 'B', '5', '2', '7', '0', 'C', '3', '9', 'A', '2', 'C', '9', '7', '3', 'D', '7', '9', 'D', '6', 'D', '6', '5', '4', 'D', '5', '9', '4', '7', '0', 'F', '8', '6', '4', '0', 'D', '4', '3', '8', '8', 'E', 'E', '0', '4', 'F', '6', '9', '6', '1', '8', '8', 'B', '0', 'B', '6', 'E', 'F', '8', 'F', '1', '5', 'E', 'C', 'B', 'F', '5', 'B', '1', '2', 'D', '7', 'E', '3', '7', 'D', '0', 'E', '8', '3', '7', '1', '1', '6', '5', '4', '7', 'E', 'A', '2', 'D', '8', 'D', '4', '4', 'F', 'E', 'B', 'F', '0', '8', 'D', 'B', '9', '3', '4', '6', '1', '6', 'E', '0', '6', '2', '3', '5', '2', '1', '1', '5', '1', '0', '2', 'D', '5', 'B', 'E', '4', '1', 'D', 'C', 'A', 'E', '2', '1', 'C', 'F', '6', '0', 'D', '0', '7', '9', '8', 'F', 'A', '3', '2', '4', '1', '3', 'E', '1', 'D', '9', '0', '1', '9', '0', 'E', 'B', 'A', '6', '4', '1', 'A', '2', 'B', 'A', '5', '3', '7', '5', '6', '9', '8', '7', 'D', '8', 'A', 'A', '5', '3', '6', '0', '2', 'F', '2', '5', '9', '4', 'F', '8', '3', '5', '1', '6', 'A', 'D', '4', '0', 'F', '5', '7', 'C', 'F', '1', '5', 'C', '6', '0', '5', '1', 'B', 'D', '7', '2', 'B', 'A', '0', '8', '6', '1', 'C', '4', '9', '0', 'A', '5', '2', '2', '6', '9', 'E', '5', '5', '2', '2', 'F', 'D', '8', '2', '5', 'F', 'F', '0', 'F', '2', '5', '9', '0', '9', '7', 'F', '1', 'B', '5', '0', '2', '3', 'D', 'F', 'F', '8', 'A', 'C', '0', '3', 'F', '8', '0', '0', '1', 'C', '2', '1', 'B', '5', '0', '3', '8', 'E', '0', '0', 'E', '3', '8', 'B', '9', 'C', 'F', 'B', '2', '5', '3', 'E', 'F', '3', 'B', 'D', '9', '1', '6', 'E', '6', 'A', '5', '8', '5', 'A', '9', '3', '7', '0', 'D', '3', '1', 'F', '7', 'B', '3', '6', '3', '7', '9', '4', '9', '4', '9', '0', '9', '2', '9', 'A', 'D', 'C', '1', '3', '3', 'C', '0', '0', '4', 'E', '9', '5', '3', '2', '0', 'D', '9', 'D', '1', '3', 'F', 'E', 'A', '8', '4', '6', 'A', 'B', '5', '3', '0', '0', '9', '5', '0', 'D', '0', '2', 'C', 'E', '9', '6', 'B', 'A', '3', '5', 'D', '0', 'D', 'B', '9', '1', 'D', 'D', '2', 'B', '6', '8', '0', '2', '2', '5', '7', '4', '2', 'E', '6', '1', '3', 'A', '3', '4', '6', 'A', 'A', '3', 'C', '0', '6', '8', '0', '1', '8', '4', 'B', 'C', 'C', '9', 'B', '2', '6', 'D', 'A', '6', '7', 'F', '6', '4', 'D', 'B', 'F', '0', '0', '8', '6', '9', 'E', '5', '1', '5', 'C', '0', '5', 'A', '0', '5', '8', 'D', '4', '3', '5', 'D', 'F', '6', '9', '1', 'C', 'A', '0', '0', '1', '7', 'F', '8', '9', '1', 'D', 'A', 'E', '4', '7', '6', 'B', '5', 'C', '9', '5', '4', '1', '3', 'E', 'E', '9', 'B', '0', 'F', '8', '7', 'C', '1', '8', '1', 'F', 'D', 'F', 'E', '2', '5', 'D', '4', '0', '9', '3', 'C', 'B', '9', 'E', '1', '5', '4', '7', 'C', '5', '1', '4', '9', 'B', '4', '0', '8', '7', '4', '5', '1', 'E', 'F', 'F', 'F', 'B', '4', '4', '8', '7', 'D', '9', '4', '4', '1', '7', '1', '4', '1', 'C', 'F', '1', '8', '6', 'B', 'F', 'D', 'E', '4', 'E', '2', '2', 'E', '9', 'F', '2', '3', '0', '6', 'E', '6', 'A', '0', '8', '8', 'D', 'E', '3', '6', '0', 'B', '1', 'C', '4', '8', '3', '0', 'A', '0', '1', 'A', 'B', '8', '9', '0', 'D', 'A', '4', '3', 'B', '8', '0', 'D', 'E', '7', '3', 'B', 'E', 'B', 'C', '6', '7', 'E', '1', '8', '4', '8', '6', '4', '0', '5', 'B', '7', 'C', '7', '5', '8', '0', '2', 'F', '9', 'D', 'B', '2', '4', 'E', '3', 'C', '3', 'F', '0', '8', '1', 'A', '9', '7', '4', '0', '4', 'F', 'E', '9', '3', '2', '3', '8', 'B', '1', '4', '5', 'E', '8', 'E', 'E', '5', '2', '7', '2', '0', 'D', 'E', '9', '6', '1', 'D', 'A', '7', 'A', 'A', 'D', '4', 'A', '7', '6', '7', '4', '6', '6', '3', 'F', '4', '4', '6', '1', '0', 'D', '6', '1', 'F', '2', 'F', '9', '0', '1', 'B', '1', '2', 'A', '4', '3', '7', '0', '3', '4', 'E', '3', '2', 'D', '7', '1', 'B', '9', '1', '7', '3', '4', '1', '0', 'E', '3', '0', '1', '8', 'B', '6', '4', 'F', '9', 'C', '5', '8', '1', 'E', '2', '8', 'F', 'D', '5', 'C', '7', 'D', 'C', '5', 'B', 'A', '9', '2', '7', '4', '9', '7', 'B', '3', '8', 'E', 'B', 'F', '8', '2', '9', '4', '9', '2', 'B', 'E', '7', '6', 'D', '9', 'C', '8', '9', '9', 'E', '5', '9', '8', '7', 'C', 'C', '1', '5', 'A', '4', '5', '3', 'D', 'A', 'A', 'A', '6', 'F', 'B', 'D', '9', '4', '4', 'E', 'D', '1', '9', 'F', 'A', '9', '2', 'E', '9', '9', '4', '2', '1', '1', 'F', '8', '1', '7', '9', '8', '5', 'D', '2', 'B', '5', '8', 'F', '5', '1', '8', '3', '9', '2', '9', '3', '6', 'C', '2', '6', '7', '6', 'F', '2', '0', '6', '6', 'A', '0', '4', '6', '8', 'A', '7', 'F', 'C', 'E', 'D', 'A', '1', '8', '7', 'C', '7', '8', '4', '1', '4', '6', 'A', '0', '8', '7', '7', '7', 'F', '0', 'C', '1', '1', '3', '9', '0', '3', '0', '9', 'D', '1', '8', '9', '7', 'C', '0', '5', '4', '2', 'B', '7', '1', '7', '8', '8', '7', '6', '7', 'A', '1', '6', '4', '0', '2', '2', '8', '1', '3', '4', 'F', '2', '4', 'B', '7', '3', 'F', '8', '7', 'C', 'D', '7', '6', '8', '8', '8', '9', 'F', '2', 'E', '0', '4', 'E', 'F', 'D', '4', 'F', 'B', '2', '9', '4', '7', '8', '8', 'E', 'D', '3', '6', 'C', '3', '7', 'C', '4', '6', '2', '7', 'C', 'C', '2', 'E', 'E', 'C', '0', 'F', 'A', '6', 'B', 'E', '8', '0', '8', '4', 'D', '1', 'A', '4', 'A', '6', '4', '8', 'B', 'E', 'C', '7', '1', '7', '3', '8', '5', '7', 'C', '0', '9', '0', 'C', 'A', 'A', 'C', '4', '4', 'D', '5', '8', '1', '4', '3', 'C', 'B', 'D', '2', '2', 'E', '0', '1', '8', 'A', '8', '8', '7', '0', '5', 'F', 'E', 'D', 'F', '0', '7', '8', '5', '7', '1', '6', 'C', '5', 'E', '6', '6', 'B', '1', 'A', '0', 'D', 'A', '6', '7', 'D', '1', '7', '5', '1', '4', '2', 'D', 'C', '7', '1', 'A', 'B', '0', '3', '4', 'B', 'A', '0', '0', 'A', '6', '6', 'A', 'A', 'A', '1', '2', '4', '3', '7', 'B', '1', '6', 'B', 'A', '2', 'C', '1', 'B', 'D', '6', 'C', '2', '8', 'A', 'E', '8', '2', '6', '4', 'C', '6', 'D', '2', '5', '9', '9', 'C', 'D', '7', '4', '3', '4', 'E', 'D', '7', '0', '7', '6', '1', 'C', 'F', '9', 'C', '8', '8', '4', 'A', 'A', '7', 'B', 'B', '2', '8', 'B', 'D', '3', '7', 'E', 'E', '7', 'F', 'E', 'E', 'B', '0', 'F', 'B', '4', '8', '0', 'A', '8', 'F', '9', '6', '7', 'C', 'E', '0', 'D', '2', '3', '0', '3', 'A', '2', '9', '9', '0', 'A', 'B', 'C', '1', 'C', '5', 'E', '7', '7', 'F', '3', 'E', '2', 'E', 'C', '1', 'C', 'D', 'A', '6', '7', '3', 'D', 'A', '4', '3', '9', '8', '3', '0', '0', '1', '2', '7', '4', 'E', '8', '1', 'E', '4', '6', 'C', '7', 'A', '1', '7', '0', 'D', '6', '6', 'C', '8', 'D', '5', '3', '6', '6', 'E', 'E', '5', '0', '8', '7', '3', 'A', 'F', '1', '4', 'A', '3', '0', '4', 'E', 'A', '0', '2', 'C', '5', 'F', 'A', '6', 'B', '0', 'C', 'C', 'F', 'B', '0', '8', '2', 'F', '8', '8', '2', 'E', 'E', 'A', '5', '8', '5', '7', 'F', '7', 'D', 'B', '9', '7', '9', '1', 'B', '0', '1', 'D', '3', '0', 'D', '4', '9', 'D', '2', '2', '9', '3', '5', 'B', '7', '6', '9', '8', '3', 'E', '7', '3', '1', 'B', '1', '9', 'A', '0', 'E', '9', '9', 'F', 'E', '9', '3', '6', '4', '9', 'D', '6', '8', 'E', 'F', 'C', 'D', 'F', '6', 'D', '0', '0', '9', '3', '9', '4', '0', 'B', '7', 'D', '1', '1', '7', '8', 'A', 'D', 'C', 'A', '4', 'C', '5', '3', 'F', 'F', '0', 'E', '2', 'C', '7', '2', '5', 'A', '1', '0', '5', '1', 'E', '6', '2', '2', '9', 'E', 'B', 'E', '6', '7', '0', '6', '4', '5', '6', '5', 'B', '6', '4', '3', '7', 'F', 'C', 'D', '5', 'D', 'F', 'E', 'A', '5', '6', 'B', 'C', '5', '7', 'B', '7', 'C', 'A', '8', '0', 'C', '2', 'E', 'A', '0', '8', '5', '0', '0', '9', '5', 'E', 'C', '9', '9', '8', '3', 'C', '4', 'F', 'B', '2', 'A', 'F', 'A', '3', 'F', 'A', 'E', '3', 'C', 'B', 'B', '0', '8', '5', 'B', 'E', 'F', '9', '2', '0', '3', '8', 'B', '2', '9', '0', '5', 'D', '2', '8', '8', '3', 'A', 'F', '9', '8', 'E', '0', '8', '0', 'D', '2', 'E', '8', 'D', '2', 'D', '7', '8', '0', '3', 'C', '5', '0', '0', 'C', '4', '0', 'C', '8', 'E', 'C', '5', '6', 'D', 'A', 'A', 'F', 'C', '3', 'D', '4', '3', 'D', '1', 'C', '7', '8', '5', '5', 'E', '3', '1', 'F', '5', 'F', 'F', '5', '3', '0', 'F', 'A', '9', '0', 'A', '4', '6', '6', '0', '0', 'B', 'F', '1', 'F', '8', '0', 'E', '1', '1', '7', '6', '3', '8', '6', 'C', '7', '6', '3', '3', 'F', '6', 'F', 'C', 'A', 'E', '6', '3', '2', '5', '0', 'C', '0', 'B', '0', 'C', '7', 'B', 'B', '1', '7', 'B', 'D', 'F', '3', 'D', '4', 'A', '7', '6', 'D', '7', '6', 'E', '8', 'C', '2', 'E', '2', '4', '6', 'B', 'A', '1', '6', '3', '1', 'F', 'E', '1', 'D', '8', '2', 'D', 'F', 'F', '4', '2', '7', 'C', 'F', 'C', '7', '8', 'A', '7', '5', 'B', '8', '0', 'D', 'C', 'A', '2', 'C', 'D', 'D', '8', '0', '1', '8', 'D', '8', '3', '7', '0', 'E', 'C', '3', '4', '7', '2', 'B', '4', 'F', 'B', '0', '8', '0', '9', '4', '5', '5', 'C', '0', '0', '3', '5', 'A', 'E', '9', 'A', '4', '4', 'D', '4', '3', 'B', '2', '9', 'A', '1', 'F', 'F', '8', '1', '5', '9', '8', 'A', 'A', '6', 'C', '2', 'A', '9', '8', 'F', '7', 'B', 'E', '0', '8', '2', '5', '0', '9', 'F', '3', '9', '4', 'B', '3', '1', 'A', 'F', '1', '3', 'A', 'A', '1', '9', '8', 'D', '9', 'C', 'A', '0', '6', '7', 'A', '0', '2', '6', '9', '0', '2', 'D', 'B', '3', '5', '6', '9', 'F', 'B', 'F', '3', '5', '5', '7', 'A', '7', '6', '6', 'D', 'B', '6', '7', '3', '9', '6', '3', '5', '0', '2', 'F', '5', '0', 'C', '7', 'E', '0', '3', '4', 'C', '4', '4', 'D', 'C', 'A', '7', '3', '5', 'B', 'C', '4', 'F', 'B', 'E', 'C', '9', '1', '7', 'B', '5', '5', 'D', '1', 'F', 'F', '5', '1', 'E', 'C', '6', '3', '9', '6', '8', 'D', 'C', 'A', 'A', '2', '5', '8', '2', '5', 'F', '1', 'D', 'E', 'D', '7', '8', '1', '4', 'A', '6', '1', '4', '4', '4', '5', '1', '0', '2', '1', '6', 'C', '8', '2', 'A', '5', '7', '7', '4', 'B', 'C', 'D', 'A', '2', '3', '9', '5', '0', 'C', 'E', '4', 'F', '9', 'D', 'F', 'B', '9', '6', '1', '0', '3', 'C', '5', '4', '8', 'E', '7', 'D', '3', '4', '0', '4', '8', '9', '3', 'A', '8', '4', 'C', '6', '6', 'D', 'E', 'D', '1', '5', 'E', '5', 'C', '3', 'A', '0', 'D', '3', '0', 'D', '3', '8', '0', '6', '4', '4', '2', 'E', '3', 'D', '0', '9', '6', '0', '8', '9', '2', '1', '7', '1', 'B', 'A', '0', 'C', '7', '7', '1', '4', '7', '5', 'D', 'E', 'F', '4', 'D', '4', 'F', 'F', 'D', '0', 'B', '6', '2', '2', '4', '4', '7', '1', '2', '3', 'E', 'F', '0', '0', '1', 'C', '7', 'A', 'A', 'B', 'A', '6', '5', 'C', '6', '5', '1', '2', '3', '3', '6', '9', '6', 'E', '6', '0', '9', '6', 'F', '4', 'C', 'F', 'B', '8', '0', '6', '8', '4', '9', 'F', '7', 'E', 'C', '9', 'A', '6', '4', '9', 'F', 'F', '8', '8', '0', '1', 'F', 'B', 'B', '8', '7', '8', '2', '1', 'F', 'A', '3', '1', '1', '3', '2', 'D', '8', '8', '5', 'A', 'C', 'F', '2', '4', '0', 'C', '5', 'A', '3', 'A', '4', '6', '1', 'E', '3', '2', '9', 'D', '4', 'A', 'E', '8', '4', 'C', 'E', '3', '1', 'E', '8', 'E', '6', 'D', '8', '4', 'D', 'A', '0', 'C', 'E', '3', 'C', 'E', 'A', 'A', '9', '7', '1', '2', '5', '3', 'C', '2', '6', '2', '2', '6', '6', 'D', 'A', '9', '5', '3', '1', '9', '2', 'B', '3', '9', '8', '1', '2', '4', '8', '2', 'F', '8', '1', '6', '1', 'E', '9', 'B', '4', '8', 'F', '1', '4', '1', '8', '3', 'A', 'E', '7', '3', 'F', '0', '8', '5', '5', 'D', '6', '9', '0', 'C', 'C', '5', '4', '6', '8', '1', '3', '8', 'F', 'B', 'E', '5', '7', '3', '3', '2', 'C', '2', 'D', 'B', '3', 'F', '2', '5', '3', 'A', '4', '8', 'C', 'B', '9', 'F', '6', '9', 'D', 'D', '2', '0', '4', '7', '0', '5', 'A', 'A', '8', '4', '6', 'E', 'C', '2', '3', '5', '9', '8', '1', 'B', '4', 'D', 'B', '6', 'F', '9', 'F', '4', '1', '1', 'D', 'C', '3', 'F', '8', '5', '8', 'F', 'D', '9', '3', 'B', '3', '8', 'B', '6', '8', '0', '1', '6', 'D', '5', 'E', '7', 'B', '3', 'C', '2', '3', '7', '5', '8', '6', 'B', 'A', 'B', '2', 'D', 'E', '2', '9', '0', '4', 'F', 'A', '4', '8', 'F', '5', 'F', 'B', '9', '3', '5', '7', '3', '2', '1', 'C', '3', '8', 'F', '9', 'F', 'B', 'E', 'A', 'E', '9', '3', '0', 'D', '5', 'B', 'D', 'F', '7', '5', '6', '1', '6', 'B', 'D', '3', '8', '7', '0', '8', '9', '5', '5', '8', 'B', '0', '9', '1', '3', '9', '6', '3', 'C', 'E', 'F', 'D', '5', 'D', 'A', '6', '5', '5', 'B', '5', 'B', 'E', 'B', 'E', '7', '5', 'A', '7', '7', 'E', '1', 'A', 'F', 'B', '6', 'B', '6', '8', '2', 'B', '3', '7', 'A', 'C', 'E', 'D', '8', '5', '8', '3', '2', '7', '7', 'B', '1', '5', '9', 'C', '7', '7', 'D', 'E', '3', '7', 'D', '4', '6', 'A', '6', 'D', 'C', '1', '4', 'D', '5', '1', 'E', 'F', '8', '5', '8', '0', 'C', 'A', '0', '9', 'A', '2', 'F', '8', '6', '9', '4', 'F', '1', 'A', 'C', 'C', 'F', 'D', '5', '3', '0', 'C', '4', '6', 'B', '3', 'E', '1', 'F', 'C', 'F', '1', '5', '7', '0', '3', 'B', '7', 'C', 'D', 'C', '2', '2', '9', 'B', '2', '7', '8', 'D', 'C', '5', '5', '9', 'A', '0', 'F', '1', '6', '8', '5', 'F', '7', '6', '4', 'B', 'D', '0', 'E', '8', '6', '3', '3', 'C', '5', '1', 'C', 'C', 'C', 'C', '7', '3', '9', '5', '4', '4', 'B', '2', '3', 'A', 'B', 'B', '4', '6', 'C', 'B', '4', 'D', '7', 'A', '9', '2', 'E', 'B', '1', '8', 'E', 'C', '9', '6', '4', '5', 'C', 'D', '3', 'F', 'E', 'B', '9', 'E', 'E', '4', '7', '9', '5', 'C', '7', '3', '1', '6', '7', '0', 'C', 'D', '6', '2', 'F', '4', '5', 'B', 'F', 'B', '8', 'C', '2', '5', '5', '0', '2', '6', 'C', '1', '6', '0', '4', '0', '4', 'F', '1', 'C', 'D', '9', '2', '5', 'E', '6', 'A', 'B', 'A', 'D', 'B', 'E', '5', '6', 'F', 'C', '7', '0', '7', '8', '2', '6', '2', 'F', '4', 'A', '1', '2', '9', '9', 'A', '6', 'E', 'E', 'D', 'A', '7', '2', '6', 'D', 'B', '7', '0', '8', '2', 'B', '5', '5', '3', '3', 'F', '5', '9', 'E', 'C', '7', '7', 'F', '5', '4', '8', 'D', '2', '1', 'B', '9', '1', '2', '2', '2', 'A', 'E', 'A', 'A', 'C', '7', 'A', 'A', '2', '9', '7', '0', '4', '1', '3', '1', '8', '2', '0', 'D', '6', '7', '8', '6', '7', '2', '9', 'B', 'F', '5', '5', '1', '8', 'F', '6', 'F', 'F', '2', '1', 'A', '1', 'C', 'C', 'F', 'D', '5', '6', '3', 'B', '0', 'A', '4', '8', 'F', '1', 'D', '4', 'F', '5', '2', '9', '1', '2', 'B', '8', 'B', '4', '0', '1', '5', '5', 'C', 'D', 'B', '2', '2', '3', '2', 'E', '6', '5', '2', '3', 'E', 'C', '7', 'D', 'D', '1', 'F', 'A', 'B', '1', 'F', 'D', '1', 'D', 'D', 'D', 'D', 'E', '7', '4', '5', '0', 'E', 'A', '5', '8', '8', '2', 'A', '0', '1', 'D', '2', '9', '6', '1', 'A', '9', 'B', 'B', '0', '7', 'D', '9', '3', '1', 'F', '7', 'D', '9', 'B', '8', '2', '4', '6', '4', 'D', '6', '7', 'D', '9', 'A', '4', 'E', '4', 'E', 'F', '6', '2', 'B', '8', 'D', 'A', 'B', 'B', '1', '5', '5', '4', '6', '9', '1', '7', 'C', '0', 'F', 'C', '9', '4', '3', '1', 'B', '3', 'F', 'F', '7', '0', '3', '0', '5', '9', 'F', 'E', '4', 'B', 'B', 'B', '5', '2', '1', '1', '2', 'E', '0', 'D', '3', 'C', '2', 'C', '1', '4', '7', 'F', '0', '8', '5', '9', '2', '9', '5', 'E', '6', 'A', 'C', 'F', '8', '3', 'E', 'F', 'B', '8', 'D', '0', '1', '1', '3', 'D', '6', '5', '7', '1', 'E', '7', 'E', 'B', 'B', '1', 'E', 'D', 'F', '4', 'C', '0', 'C', '6', '6', '2', '7', '6', 'D', 'F', '7', 'A', '1', '4', '9', 'C', 'C', '2', '9', 'C', '3', '0', 'C', 'C', 'C', '4', 'B', 'F', '7', '7', 'B', 'C', '3', 'C', 'F', '5', 'C', 'F', 'F', '6', '6', 'D', '1', '3', 'E', 'A', 'C', '8', 'A', 'F', 'D', 'C', 'C', 'D', 'D', '9', 'A', '2', 'D', '5', '7', 'A', '4', 'C', '8', '4', 'A', '8', '7', '8', 'A', '3', '3', 'A', 'F', '2', '1', '0', 'A', '4', 'B', '8', '7', '8', 'B', 'F', 'C', '3', 'A', '1', '9', 'A', 'F', '3', '0', 'C', '1', 'E', '9', '7', 'F', '4', 'F', '3', '1', '8', '2', '3', 'D', 'F', '8', '9', '3', '2', '0', 'A', '3', 'C', 'E', 'D', 'B', '8', '8', 'A', '5', '0', 'D', '7', '5', 'B', '5', '8', 'A', '6', '8', 'C', '6', '4', '9', '8', '7', '5', '0', 'E', 'E', '6', 'A', '1', '0', 'B', '8', '9', '7', 'B', '3', '3', '6', 'F', '7', '1', '4', 'E', '7', 'E', '4', 'E', '1', 'D', 'B', '0', '7', '2', '9', '5', 'E', '9', '6', 'B', '1', '4', '1', 'D', '4', '1', '9', '4', '6', 'B', '0', '3', 'D', 'B', 'B', '9', 'B', '2', 'B', '4', 'C', 'B', 'E', 'D', '6', '7', 'D', '1', 'E', 'E', '4', '1', '5', '0', '2', 'E', '3', 'C', 'C', '3', 'B', 'A', '6', 'B', 'A', '6', '7', '7', '6', '2', 'E', 'E', '2', '9', 'F', '5', '4', 'C', '4', 'E', '8', '8', '8', 'D', 'C', 'B', 'E', 'F', '6', '2', 'E', '2', '3', '9', '8', 'F', '7', 'B', '1', '9', '3', 'D', '3', '6', 'B', '3', '1', 'D', '8', '5', '6', '1', '5', '5', '3', '1', '7', 'E', 'D', '7', 'D', 'B', '4', '4', '4', 'D', '4', '2', 'B', 'A', 'A', 'E', '9', 'A', '7', '0', 'B', '6', '3', '6', 'C', '3', '6', '0', 'A', 'E', '9', '1', 'E', '2', 'A', 'C', 'F', '5', 'A', 'A', '0', '1', '0', '2', '4', 'A', 'F', 'B', 'C', 'F', '2', 'C', 'B', '7', '2', '1', '6', '4', '0', '4', '7', '3', 'B', 'F', '2', '8', '6', '9', 'F', '8', '3', 'B', '0', 'B', 'A', '2', '7', '8', '0', '7', '4', '6', 'A', '8', '4', '3', 'B', 'D', '0', 'E', 'B', '5', 'B', '6', 'B', '0', 'A', '9', 'F', 'D', 'F', '5', 'A', '0', 'F', '3', '7', '0', 'A', '2', 'E', '5', '8', '9', '9', '2', 'A', '9', '3', '7', 'C', '9', 'E', 'A', 'C', 'F', '2', '4', '2', '2', 'D', '7', '8', 'B', '0', 'A', '9', '6', '5', '8', 'C', '6', 'C', '7', '8', 'A', '1', '4', 'D', '9', 'B', 'E', '8', 'A', 'B', 'B', '5', 'D', '2', 'F', 'F', '4', '5', '9', '4', 'A', 'E', '4', '8', '7', '5', '2', '3', '4', '7', 'C', '9', '7', 'D', '1', 'F', '8', 'B', '6', '7', '1', 'C', '6', '9', '9', '3', 'F', '3', '9', '5', '5', '0', '6', '0', '7', '0', '6', 'D', '9', 'E', '8', '4', '0', 'A', '0', 'D', '3', 'C', '4', 'B', 'F', '7', 'C', '7', 'D', '6', '1', '5', 'C', '0', '3', '3', '0', '2', '2', 'D', '6', '7', '4', 'E', '9', '4', 'F', '4', '8', '1', '7', 'F', '1', '9', '5', '9', 'C', '6', 'F', 'A', '1', '3', 'B', 'E', 'F', 'F', 'C', '5', 'E', '6', '5', 'D', '2', 'D', '2', '5', '3', '8', '6', '1', 'D', '7', '6', '5', 'B', '3', '5', '7', '4', '8', '8', 'A', '0', '4', 'D', 'A', '9', '4', 'B', 'D', '9', '5', '6', 'B', 'F', '6', '1', '3', '3', '0', 'E', 'B', '6', '8', '8', '1', '8', 'F', 'E', 'D', '1', 'D', '5', '7', '6', '7', '0', '9', 'E', '5', 'F', '9', 'B', '7', 'F', '6', '9', 'A', '8', 'B', '9', '7', 'F', '7', '1', '3', '8', '9', '5', '7', 'D', '7', 'A', 'D', '6', 'C', '5', 'C', '7', 'D', 'C', '2', 'F', '3', 'B', '2', '1', '0', 'B', 'D', '3', 'F', '6', '6', '6', 'B', '9', '1', '2', '8', 'C', '9', '1', '2', 'F', 'A', 'B', '1', '2', 'F', 'E', 'D', '2', '7', '8', 'B', 'D', 'A', 'D', '0', '4', '4', 'B', 'D', '8', 'F', '1', '1', '6', '5', '9', 'F', '3', '5', 'B', 'E', 'B', '8', '4', '6', 'D', 'C', '2', 'B', '5', '7', '8', '1', '0', 'B', 'A', '9', 'E', '8', 'E', 'B', 'E', '4', 'F', '4', '1', '1', 'B', '4', '6', 'A', 'C', '8', '0', '8', '4', '4', 'A', '4', '4', '0', 'A', '5', 'F', '2', 'B', 'E', 'A', '8', 'D', '1', '4', 'F', '9', '6', 'F', '0', '4', '6', '8', '8', '7', '6', '0', 'E', '2', 'F', '3', '1', 'F', '3', '8', '0', 'D', '3', 'C', 'B', 'F', 'C', 'A', '0', '1', 'D', 'A', '8', '1', '1', '6', '8', 'D', 'E', 'B', '2', '9', '1', '4', 'B', 'B', 'C', 'E', '7', '1', '9', '3', '7', '5', '0', 'B', 'C', '8', '9', 'A', '6', 'D', 'A', 'B', '7', 'C', 'A', '1', 'E', '2', '4', 'C', 'D', '9', '5', '7', 'F', 'D', '0', '6', '7', 'B', '1', '2', '6', 'C', '2', '4', '1', 'F', '1', '2', '1', '4', '2', '0', '0', '0', '5', '5', '7', '9', 'C', '3', 'E', '7', '6', 'D', '1', 'A', '8', 'E', '8', 'E', '9', '7', '0', 'E', '4', '3', '9', 'E', 'B', '2', '6', 'B', '7', 'E', 'E', '6', '2', 'D', '6', '0', 'E', '7', 'E', '9', '9', '4', '8', '5', 'C', '3', '6', 'A', '2', '2', '5', 'E', '8', 'C', '8', '0', '3', '4', '3', 'C', '7', 'B', '5', '3', 'F', 'F', 'A', '5', '8', '2', 'A', 'E', 'C', '2', '2', '3', '6', 'A', 'F', '1', '6', '5', 'F', 'D', '4', 'D', '2', '4', '4', '5', 'B', '0', '6', '5', '4', '8', '1', '2', '8', 'F', '3', 'E', 'B', 'E', '6', 'D', 'C', '4', 'F', '3', '1', 'F', '9', '5', '7', 'C', '1', '4', 'D', 'A', '6', '8', 'F', '2', '6', '0', '4', '6', 'A', '3', 'F', '6', 'A', '6', 'C', 'D', '9', 'E', 'F', '6', '6', '7', '3', '8', 'E', 'D', '8', '9', '4', 'E', '4', '7', 'C', '1', 'C', 'A', '2', '5', 'F', '4', 'F', '2', '4', 'E', 'D', 'A', 'B', 'D', 'D', 'A', '7', '0', '2', '0', '3', '8', 'F', 'C', '6', '1', '7', '6', 'A', '4', 'A', 'F', '5', 'A', '5', '5', 'D', '7', 'A', '6', 'E', '7', 'C', '2', '5', '0', '0', '2', '6', '8', 'C', 'C', 'C', '5', '6', 'E', '9', '2', '0', '9', '3', '7', '6', '7', 'C', '8', '0', '2', 'A', 'A', '0', '4', '9', 'B', '3', '2', 'B', 'D', '1', 'B', 'F', '1', '8', '2', 'F', 'D', 'F', '0', '4', 'D', 'A', '8', 'E', 'B', '0', '2', '8', 'E', '4', '0', '7', 'B', '2', 'C', 'B', '0', '0', '3', '2', '7', '9', '4', '9', '9', 'C', 'A', '8', 'F', 'D', 'B', '5', '7', '8', '8', 'A', 'D', '2', '0', 'D', 'D', '0', 'F', '5', '3', '8', 'D', 'D', '4', 'B', 'B', '7', 'B', 'B', '4', '7', 'A', 'C', '5', '5', '8', 'B', '4', 'F', '9', 'D', 'E', 'B', 'B', 'A', '6', 'A', '5', '9', 'D', '4', 'F', '0', '2', '1', 'F', '0', 'D', 'C', '1', 'B', '8', '3', '9', '4', '2', '9', '7', '4', '3', '9', '5', '0', '3', '3', 'C', 'C', '2', 'A', '7', 'C', '8', 'F', 'F', '3', 'B', 'E', 'B', '2', 'E', '0', 'D', '1', '0', '4', '4', '8', '8', '0', '3', 'D', '5', '6', 'B', '7', '9', '7', '0', '7', 'A', '9', 'D', 'D', 'E', '9', '6', 'D', '8', '3', '5', '1', '8', 'E', '4', '8', '3', '2', 'F', 'F', '9', '8', 'A', '2', '0', 'F', 'E', '9', '7', 'B', '6', '8', 'A', 'A', '7', 'C', '9', '8', 'F', 'E', 'D', 'C', '8', '2', '7', 'A', 'A', '5', '7', '9', 'F', '7', '7', '7', 'B', '9', '7', '5', '5', '3', 'D', '3', '2', 'C', '4', '0', '1', '4', '1', 'B', 'B', '4', '3', '1', 'A', 'A', '2', 'A', '1', 'E', 'D', '5', '6', '8', '2', '6', '2', 'B', '5', '6', 'E', '4', '8', '8', '4', '3', '3', '8', '8', 'A', '0', '2', '9', '4', '6', '3', '3', '0', '0', '6', '8', 'E', '4', 'B', 'A', '2', '0', 'C', 'A', 'D', '4', '7', '1', '1', 'E', 'A', '5', 'B', '8', 'B', '1', 'A', '0', '5', '9', '0', 'C', 'A', 'F', '1', '6', '4', '8', '8', '7', '9', '6', '6', 'D', 'A', '2', 'B', 'F', 'A', 'D', 'F', 'B', '9', '6', '3', 'E', '3', 'D', '4', '1', '1', 'E', '0', 'F', 'D', 'A', '5', 'E', '8', 'F', '0', '6', '0', '8', '9', '8', 'A', '8', 'B', '3', '9', '0', '5', '4', '0', '3', '9', 'E', '8', '1', 'C', 'A', '5', 'D', '4', 'C', 'E', '9', 'C', '3', 'F', '6', '3', '7', 'D', 'E', '7', 'F', '4', 'E', 'F', 'D', 'C', '3', '1', 'A', 'A', '7', '1', '2', 'A', '0', '4', '4', 'A', '3', '8', '0', '0', 'A', '7', '9', '7', '5', '0', '7', 'D', '5', 'F', '7', 'F', '5', '7', 'D', 'C', 'C', 'A', '8', '3', '2', '7', '7', 'A', 'F', '2', '6', 'F', 'D', '2', 'B', 'E', '3', '7', '6', '6', '3', '1', 'A', 'F', '7', '5', '4', '4', '1', '8', 'F', '3', 'E', '2', 'C', 'F', 'A', '1', '8', 'D', 'D', 'B', 'D', '0', '6', '2', '8', '1', '7', '0', '4', 'F', '5', '4', 'A', 'F', '5', 'B', '0', 'C', '5', '4', '5', '0', '2', '6', '5', '2', '4', '2', 'C', '2', '1', 'C', '5', 'D', '1', '8', '6', '7', '4', '1', '8', 'F', 'C', 'B', '5', '1', 'D', 'B', '1', 'E', '6', '9', 'E', '3', '9', '2', 'C', 'C', '7', 'F', '8', 'E', '6', '1', '2', '4', 'D', '1', '7', '8', '0', '9', '0', 'F', 'B', '6', '0', 'C', 'E', '1', 'D', 'E', '6', 'D', '7', '1', '4', '4', 'B', 'C', '8', '6', '1', '7', '5', '5', 'A', '7', '0', '9', '0', '3', '5', '6', '2', 'C', '2', '2', '8', '8', 'B', '9', '0', '8', '0', 'C', '4', 'F', 'E', 'C', 'B', '5', '8', '0', '5', 'B', 'C', '1', 'F', 'D', 'A', '8', '2', 'B', '0', '5', 'D', 'C', '2', '6', '4', '9', '4', 'E', 'A', '2', 'E', '8', '7', '6', '3', '6', '2', '0', '8', '8', 'D', 'D', '2', '2', '5', 'C', '1', '7', 'D', 'A', '1', '8', '3', '4', 'F', '7', '6', '5', 'E', '7', '6', '3', '0', '7', '4', 'D', '0', 'C', '5', '9', '4', '5', 'C', '9', '9', '1', '5', '3', '3', '9', '2', 'E', '2', '9', '6', '7', 'F', 'D', 'C', 'A', 'F', 'D', 'D', '9', 'F', '1', '0', '7', '1', 'F', '9', '9', 'C', '8', '2', 'A', 'D', '2', '6', '4', '6', 'F', '4', '4', '1', 'C', '0', '8', '4', '5', '5', '0', '8', 'A', '9', 'A', '5', '9', '8', 'F', 'F', 'D', '6', 'C', '7', '8', '4', '7', '6', '7', '4', '9', '1', '8', 'D', '0', '5', '1', 'B', 'C', 'C', '6', '7', '2', '2', 'A', '3', 'B', '3', '2', '8', 'E', 'F', 'A', 'A', '4', '6', 'B', '1', '9', '2', '7', '2', '3', 'B', '6', 'E', 'C', '3', '3', 'A', 'E', 'A', 'E', '4', '8', 'B', 'C', 'D', '3', 'E', '2', '7', 'C', 'A', '6', '9', '2', '9', 'F', 'D', '6', 'C', '0', '7', '6', '8', '3', 'A', 'F', '0', '9', 'C', '2', '1', 'D', '1', '1', '0', '4', 'A', '5', '2', '2', '7', '7', '3', '3', '6', 'F', '7', 'B', 'F', '1', '0', '1', '1', '4', '7', 'E', '0', '6', 'D', 'B', '1', '5', '5', '9', '4', 'F', '5', 'E', '0', '9', '1', '1', '1', '3', '5', '9', 'E', '4', '4', '7', '1', '8', '0', '1', '5', '0', 'D', '3', 'D', '2', '8', '4', 'B', 'D', 'D', 'D', '8', '7', 'F', 'E', '4', 'B', '2', '4', 'C', '1', 'B', '5', 'B', '6', '7', '3', '2', '3', '1', '9', 'C', '7', '0', 'F', 'D', '3', '7', 'A', 'C', 'D', 'F', 'C', '6', '4', 'C', '8', '2', '2', '9', '0', 'F', '2', '7', '1', '3', '9', '4', 'A', '3', '6', '0', '4', '8', 'B', '7', '5', 'C', '8', 'D', 'C', '8', '3', 'C', 'E', 'D', '0', '0', 'C', '7', '0', '7', '9', '3', 'A', '6', '2', '8', 'E', 'E', 'C', '8', '6', '6', '3', '8', 'C', '3', 'B', '8', '3', '5', 'F', 'A', 'D', 'A', '1', 'F', '9', 'D', 'C', 'A', 'B', 'D', '9', 'E', '8', 'D', '3', '5', '4', 'D', '5', '6', '2', '1', '2', 'B', '9', '3', 'C', 'D', '1', '8', '4', '2', '8', '4', '7', '9', '6', '0', '0', 'D', '1', '2', '3', '4', 'A', '8', '0', 'D', '0', 'D', '4', 'E', 'F', 'B', 'D', '5', 'D', '0', '5', 'D', '1', '9', 'A', '5', '7', '6', 'A', '4', 'C', 'A', '6', 'F', '6', '4', 'F', '8', '5', '9', 'E', '2', '4', '1', '7', 'A', 'A', 'E', '7', '7', '8', 'D', 'E', '1', 'E', 'E', 'C', '2', 'E', '6', '6', 'A', '1', '6', '2', '0', '6', 'F', '3', '3', '2', '3', 'B', '9', 'A', '0', 'C', 'F', 'A', '8', '5', 'A', '7', 'A', '0', '1', '0', '3', 'F', 'C', '2', '7', '2', 'A', 'D', 'D', '7', '1', '5', 'C', 'F', '2', '7', 'C', '8', 'C', '2', '3', 'A', 'F', 'E', '4', '3', '9', '2', '7', 'B', '5', '8', '4', 'E', 'B', 'B', 'E', '9', 'B', '0', 'B', 'B', 'B', 'C', 'E', 'A', '8', '5', '4', 'B', '5', '3', 'B', '6', 'F', '2', '4', 'C', '5', 'F', 'D', '8', '5', 'B', 'F', '1', '3', '7', '5', 'B', 'D', 'E', '6', '4', 'C', 'E', '7', '7', '1', '2', 'F', '4', '9', 'C', '0', 'C', '4', '1', 'A', '4', 'D', 'C', 'A', 'A', 'C', 'F', 'F', '8', 'D', '5', '5', 'C', '7', '1', '6', '4', 'F', '8', 'B', 'A', 'D', 'A', 'C', '5', 'F', 'D', 'F', '5', '5', '7', 'F', '7', '6', 'C', 'A', '9', '0', '7', '7', '8', 'C', '8', '1', 'E', '8', '1', 'D', '2', '3', '7', '7', 'D', '8', 'B', 'B', '8', 'C', '3', 'C', 'A', '1', '3', 'D', '8', '6', 'F', '3', '0', 'A', '2', '7', '0', 'D', 'A', '1', '6', '9', '8', '4', 'D', '2', '1', '0', '4', 'B', 'F', 'D', '9', '9', '5', '2', '8', '0', 'C', '6', '2', '3', 'E', '1', '5', '0', '9', '2', '2', '8', '0', '9', '0', '7', '3', '0', 'A', 'D', '5', '2', '9', '2', '1', 'F', '0', 'E', 'A', 'B', 'A', 'B', 'B', 'E', 'D', '5', '9', '7', '0', '1', '4', '8', '2', '3', '0', '9', '7', '4', 'B', '0', '9', '6', '8', '0', '9', 'B', 'F', 'B', '2', '0', 'C', '6', '0', '6', 'E', '5', '5', 'E', '0', 'C', 'D', '2', '1', '8', 'F', '0', '2', '3', '4', '7', 'C', '1', 'F', '1', '1', '9', '1', '9', '7', '1', '3', '8', '1', 'E', '0', 'A', '9', '6', '1', '0', '1', '1', 'E', '0', '4', '1', 'C', 'F', 'E', '8', 'B', '1', '0', 'E', 'A', '4', '6', 'F', '9', '4', '8', '4', '4', '2', '5', 'E', 'B', 'F', 'B', '5', '8', '2', '9', 'C', '5', 'A', '7', 'B', 'A', '4', 'A', '4', '2', '1', 'F', '8', 'B', '0', '0', 'B', '2', 'B', '7', '2', '9', '2', 'F', 'B', 'A', 'E', '8', '3', '3', '3', 'A', '8', '9', '3', '4', '9', '2', '1', 'C', '2', 'D', 'F', 'C', '0', '9', 'B', '8', '0', '6', 'D', '0', 'A', '6', '6', 'F', '2', '6', '7', '4', 'D', '9', 'B', '6', 'F', '3', '0', 'D', '7', 'D', 'F', 'E', '9', 'C', '6', '9', 'D', '3', '8', '2', '5', '6', '8', '5', '5', 'F', '0', '1', 'D', '1', '6', '4', '4', '8', '0', 'E', 'F', '4', '5', 'C', '5', '9', 'A', '5', 'A', '5', 'B', '4', 'E', 'C', '6', '3', 'B', '7', '5', 'F', 'B', 'B', '4', '6', '0', 'F', '3', '8', 'D', '5', 'B', '4', '2', '7', 'E', 'B', '3', '4', '5', '4', '7', '7', '1', 'C', 'F', '5', '0', '8', '2', '2', 'A', '5', '4', 'D', 'D', '4', 'F', '6', '9', '3', '4', '5', 'E', 'E', 'F', '3', 'D', 'B', 'C', '5', '0', 'E', '7', 'B', '0', '9', '1', 'C', 'B', '3', '5', 'C', '1', '9', '0', '5', '5', 'D', 'E', 'F', 'C', '2', '0', 'E', 'F', 'E', '8', '2', 'D', '3', '4', '8', '9', '8', '6', '1', '8', 'B', 'C', '2', 'C', '9', 'E', '2', '9', '3', '4', 'A', '6', '4', '9', 'B', '3', '6', 'B', 'E', '1', '6', 'B', 'A', '5', 'F', '4', 'E', '2', '4', '0', 'F', '6', '1', '2', 'E', '9', '5', '5', '7', 'C', '6', '9', '2', '9', 'F', '8', 'C', 'F', 'E', '5', '8', '8', '9', 'D', '3', '7', '8', 'D', 'B', 'E', '4', 'E', 'B', '5', 'E', '2', 'A', '6', '6', 'D', 'E', 'D', '6', 'B', '3', '7', 'F', 'D', '8', 'F', '0', '1', 'A', '8', '3', '2', '5', '2', '3', 'A', '5', '8', 'A', 'A', '7', '1', 'E', 'D', '4', 'A', 'B', '6', '7', 'A', '3', '4', '6', '0', '0', '1', '9', '0', '0', 'A', 'D', 'E', '6', '1', 'E', 'D', '6', '9', '5', '9', 'C', '6', '7', '2', 'C', 'D', '9', 'C', 'B', '1', '4', '7', 'D', '5', '5', '9', 'A', 'E', '6', 'E', 'C', '2', '1', 'F', '1', '9', 'C', '5', '1', 'A', 'C', '4', '4', '4', '9', 'D', 'F', 'F', '5', '4', '3', '5', '0', '6', '2', 'F', '9', 'C', '0', 'E', '6', '8', 'F', '2', '4', 'C', '6', 'F', 'B', '8', '4', '6', 'D', '5', '5', '3', 'F', '6', 'E', '6', '0', '2', 'D', 'C', '3', '2', '8', '3', 'C', '2', 'D', '5', '9', '5', 'C', '3', '7', 'B', '7', 'E', '2', 'C', '4', '1', 'E', '9', '8', '8', '1', '0', '0', '4', '8', 'A', '2', 'E', '0', '2', '5', 'E', '2', 'B', 'C', '6', '6', '9', 'B', '9', '8', '7', '5', '9', '0', '9', '4', '8', '8', 'B', 'E', 'B', '2', '2', '6', '6', 'E', '9', '1', '7', 'F', '9', 'E', '5', '2', '8', 'D', 'E', '6', 'B', '5', '8', '0', '0', '4', 'F', 'F', '2', '7', 'C', '4', '6', 'A', 'C', '6', 'D', '2', 'B', '5', '5', 'A', '0', 'F', 'D', '5', 'E', 'A', '4', '6', '6', '8', '7', '0', '4', '5', '6', 'D', 'A', '4', '7', '1', '1', 'D', '0', 'F', '3', '0', '1', '0', '9', 'B', 'F', 'C', 'F', 'A', 'A', '0', 'D', 'B', '0', '1', '3', '0', 'F', 'D', 'C', '8', '5', '0', '5', '6', '0', 'A', '3', '6', '2', 'E', '0', 'B', 'C', '5', 'C', 'C', 'F', '7', 'E', '4', '0', 'B', '3', '8', '0', 'E', 'A', 'B', '1', '7', '3', 'C', '3', '8', '2', '3', '5', '7', 'B', 'A', 'F', '7', '8', 'E', '9', '8', 'B', '6', 'D', 'C', 'D', 'F', 'B', '9', '6', '8', '8', '7', 'B', 'B', 'D', '4', 'B', '3', '6', '1', '6', 'B', '9', 'D', '3', '9', 'A', '4', '0', '6', 'C', '5', 'C', 'E', 'A', '0', '0', 'E', 'C', '9', '8', 'C', 'F', '7', '4', 'F', '7', '7', '4', '1', '5', '9', '3', '5', 'C', 'F', '3', '4', 'C', 'A', '4', '3', 'C', 'E', '9', '5', 'C', '4', '8', '3', 'C', '8', 'C', 'F', 'E', '7', '5', 'D', '5', '8', '3', 'B', 'E', '1', '1', 'D', '6', '2', 'A', '0', 'C', '7', '7', 'F', '5', '2', '7', 'B', '1', '9', '7', '9', '7', '2', 'F', 'E', 'E', '7', '4', 'A', 'A', '9', '5', '8', 'D', '0', '5', 'E', 'D', 'F', '6', 'A', '3', 'E', 'F', 'C', '2', '2', '1', '3', '6', 'A', '5', '3', '9', '8', 'F', 'A', '9', '9', 'A', 'F', '9', 'F', 'E', '1', '7', '6', 'F', '2', '4', 'D', '4', '9', '5', '7', '8', 'F', 'B', 'B', '5', 'E', 'F', '9', '6', 'F', '5', '8', 'B', 'E', 'D', '4', '4', '6', '8', '3', '7', '3', '6', 'D', '5', '6', '9', '1', 'A', '5', '2', '7', '2', '9', 'D', '7', 'E', 'A', '9', '1', '9', '8', '2', '8', 'E', '7', 'D', 'C', '1', '8', '0', 'E', 'A', '2', 'A', '8', '6', 'E', '4', '4', 'D', 'D', 'D', 'E', 'E', 'E', '3', 'C', 'D', '5', 'E', '7', '5', '7', '2', 'D', '5', '7', 'A', '9', '2', '3', '0', 'E', 'D', '7', '1', 'C', 'C', '4', '7', '3', '1', '0', '2', 'D', '8', 'F', '5', '5', '9', '7', '9', '6', 'F', 'A', 'D', '6', '4', '7', '6', '0', '9', '6', '2', '5', 'B', '6', 'E', 'D', '5', 'B', 'A', '1', 'A', 'F', '6', '6', '7', 'B', '1', 'B', 'E', 'D', '4', 'E', '0', '3', '7', '8', 'F', 'B', '7', 'A', 'F', 'F', '0', '1', '8', 'C', 'D', 'D', 'E', '5', 'B', '7', 'E', '8', '1', 'A', 'F', '9', '0', 'F', 'B', 'F', '5', 'C', 'A', '2', 'D', '6', 'C', 'C', 'E', '4', 'B', '6', '4', '0', '9', 'A', '5', 'F', 'B', '3', 'D', '7', '9', 'F', '0', '1', '3', 'A', 'B', '1', '1', 'B', 'A', 'F', 'F', 'E', 'A', '8', 'A', '7', '8', 'A', 'E', 'D', 'F', '2', 'A', '3', 'C', 'F', 'D', 'A', 'D', 'B', 'F', '1', 'A', '4', 'F', '9', 'E', '5', '9', '4', 'D', '6', '6', '1', 'D', '7', 'E', '8', 'A', '9', '9', 'A', 'B', '0', '3', '1', '7', '5', 'E', 'D', '0', '7', 'F', 'B', '7', '7', '3', '0', 'A', '8', '8', 'D', '4', 'C', 'D', '1', '3', 'D', '0', '2', '2', 'F', 'F', '7', 'B', '5', 'A', '9', '2', 'F', '6', '3', 'C', '6', 'E', '8', '4', 'F', '1', '2', 'C', 'B', '2', '5', '1', 'C', 'C', 'B', 'D', '4', 'F', 'B', '0', '4', '8', '9', 'F', '8', '6', '4', 'A', 'F', 'C', '2', '4', 'E', '2', '3', '6', '5', 'A', '9', '6', '5', '4', 'F', '3', 'A', '2', '1', '6', '6', 'D', '0', '7', '0', 'E', '2', '0', '8', 'D', 'F', '3', '4', 'E', '1', '2', '1', '3', '1', '6', 'F', '8', 'E', '6', '5', '8', 'A', 'C', '2', '8', '6', '8', '2', '3', '6', '3', '6', 'A', '1', '7', 'B', '9', '5', '3', 'D', '1', '7', '5', 'D', '3', '0', 'F', '7', '1', '9', '0', 'D', '4', 'F', '2', 'A', '6', 'F', '7', '4', '3', 'D', '9', '8', '5', 'B', '9', 'F', '6', 'F', '7', '9', '1', '2', '6', '6', '1', '0', 'F', 'C', '9', 'D', '2', '3', '1', '9', '8', 'A', '9', '4', '9', '2', 'B', '9', 'E', '4', 'A', 'B', 'A', 'B', '1', '5', '0', '8', 'B', '3', 'D', '3', '0', '5', '2', 'F', 'D', 'B', '9', '0', 'D', '9', '3', '2', '9', '8', '6', 'A', '9', 'D', 'E', 'E', '0', '8', '6', '0', 'D', 'E', '5', '0', 'C', 'F', '2', 'D', '1', '4', '0', '3', '5', '6', '5', 'D', '7', 'C', '8', 'E', '3', 'F', 'D', '3', '3', '7', '4', '5', '5', '7', '6', 'C', 'C', '4', '0', '1', '4', '0', '6', '5', '7', 'F', '1', '5', '3', '2', '3', '2', '3', '2', 'E', '5', 'B', '0', '9', '2', '2', 'E', 'C', '7', 'B', 'E', '9', 'C', '8', '6', '2', '0', '9', '3', 'E', '2', '6', '4', 'E', '7', 'A', '2', '1', 'D', 'C', '2', '8', '8', '3', '8', '4', 'D', 'E', '7', 'A', '3', '7', '9', '6', 'D', 'D', '6', 'F', '8', '0', '3', '8', '4', '5', '7', 'B', '1', 'B', '4', '6', '5', '7', 'D', 'A', 'B', '2', 'D', '2', '2', 'B', 'B', 'E', '2', '0', 'A', 'D', '3', 'C', 'B', '9', '9', '6', '9', '2', '6', '8', 'D', 'D', '9', '8', '5', 'B', '4', '8', 'D', '0', 'E', 'E', '4', 'A', '7', '5', '7', 'C', '5', '9', '9', 'B', 'C', '1', '5', 'F', 'A', '4', 'E', 'B', '2', '0', 'A', 'A', 'A', '5', '4', '6', '8', '0', 'B', '3', '2', '1', 'F', '5', '1', '9', 'F', '2', '2', '2', '7', '8', 'B', 'A', 'C', '0', 'E', '9', '0', '4', '2', '3', '6', '8', '5', '1', '9', '2', 'A', 'A', '6', '0', '3', '3', 'D', '3', '8', 'A', 'B', 'C', '6', '6', '5', '8', '9', '1', 'A', 'C', '4', 'F', '1', '5', '3', '1', '5', 'C', 'C', '0', 'C', 'D', 'D', '4', 'C', '2', 'C', '4', '2', '4', '7', 'F', '0', '0', '5', '6', '9', '7', 'E', '5', 'A', 'D', '9', '1', 'A', 'C', 'A', '7', '1', '5', 'B', '5', '6', 'E', 'C', '5', '4', 'E', '3', '3', '1', '6', '6', '8', 'A', '1', 'D', '5', '3', 'E', '6', '6', 'D', '8', '1', '6', 'C', '5', 'E', '8', '2', 'F', 'A', '8', 'F', 'C', '7', 'F', 'C', 'A', '9', '9', '4', 'F', '9', 'A', 'F', '5', '1', 'B', '7', 'D', '7', '7', '1', '7', '8', '5', '2', '2', 'C', '6', '4', 'D', '7', '5', 'E', '7', 'D', '4', '8', 'A', 'B', '1', 'B', 'A', '9', '0', '4', 'B', '8', '7', '6', 'B', 'C', 'D', '4', '0', 'B', 'F', '8', 'E', '7', '9', '7', 'A', '2', 'C', '0', 'B', '5', '1', '3', 'B', 'A', 'A', '2', 'A', 'D', 'F', '3', '1', 'A', '1', '0', 'B', '4', 'D', 'D', '8', '7', '2', 'E', '8', 'E', '4', '6', 'D', '5', '6', '4', 'F', 'A', '5', '4', 'C', '8', 'A', 'B', 'E', '0', '9', '7', '3', '3', '6', '9', '7', '9', '9', 'D', '8', '4', 'C', '8', '9', 'A', '5', 'F', 'A', 'C', 'A', '7', 'F', 'D', 'D', '6', 'F', '4', 'E', 'A', 'A', 'B', '2', 'F', '5', '8', '0', 'D', '8', 'E', '4', 'C', 'E', 'A', '1', '4', '7', '0', '1', '5', 'E', '9', 'C', '0', 'F', 'A', '4', 'C', 'F', '5', 'B', 'E', 'E', '8', '5', '3', '3', '4', 'D', '5', 'A', 'E', 'F', '1', '5', 'F', 'F', '2', '2', '7', '4', '6', 'A', 'C', 'B', '3', '9', '1', 'A', 'B', '2', '7', '8', 'A', '7', '2', '4', '1', 'E', '8', '6', '1', '8', '1', 'D', 'E', 'F', '0', 'D', 'C', 'A', 'E', '2', '3', 'E', 'A', '1', '9', '0', '8', '2', '7', '8', '4', 'E', '3', 'D', 'E', '2', 'B', 'F', 'B', '4', 'D', '9', '1', 'E', '8', 'E', '8', '4', 'A', '1', '8', '9', 'F', '1', '9', '3', '5', '7', '1', '8', '5', '1', '6', '6', '0', '9', 'C', '9', '0', 'C', '1', 'A', '1', '2', 'E', '6', '3', '5', 'D', 'E', '5', 'A', '3', '8', 'F', '3', '3', '5', '8', 'B', '5', 'D', 'A', 'C', '5', 'F', 'B', '2', 'B', 'E', 'F', 'F', 'C', '9', 'C', '0', '2', '0', '3', '7', '3', 'E', '9', '9', 'A', '3', '6', 'A', '4', '3', 'C', 'C', 'D', '8', 'B', '5', '8', 'D', '8', 'E', '2', 'B', '1', 'F', 'F', '0', 'D', '0', '2', 'E', 'D', 'C', '2', '4', '6', '9', '2', '8', '8', '4', '0', '9', '2', '4', '8', 'A', '8', '8', '1', '5', '5', 'A', '3', '2', '9', 'F', '1', 'C', '5', 'B', '1', 'C', '5', '3', '8', '8', 'E', 'A', 'D', 'E', 'C', 'C', '8', '3', '0', '9', 'D', '0', '2', '1', '6', '9', 'D', 'B', 'E', '5', 'E', 'C', 'C', '5', 'C', 'B', '2', '9', 'A', 'D', 'E', '8', '7', 'F', '3', 'B', '2', 'F', 'F', '0', '1', 'F', 'A', '7', 'F', 'C', 'D', '2', 'E', 'E', '7', '7', 'A', '7', '6', 'E', 'D', '1', '5', 'D', 'A', '0', '9', '2', '3', 'D', '5', '3', 'D', 'E', '6', '9', '0', '8', '8', '8', 'E', '7', '2', 'F', 'A', 'D', '4', '0', '9', 'C', 'C', 'E', '4', 'E', '1', 'D', 'F', '8', '7', '1', '7', '8', '1', '3', '5', '1', 'A', '3', '6', 'B', '3', 'B', 'F', 'A', 'A', '5', '6', '3', 'D', 'F', 'A', 'E', '4', '9', '8', '6', '6', '3', '8', 'D', 'E', 'A', 'E', '7', '9', '8', 'F', 'B', 'B', '3', '4', '1', 'C', '7', '0', '8', '5', '3', '5', '0', '2', 'B', '4', '8', '3', 'E', 'A', '7', '8', 'E', '7', '5', 'E', 'E', '8', '8', 'A', '9', 'D', '2', '0', '9', '3', '5', '6', 'C', '0', '9', 'B', '5', 'D', '4', 'E', 'B', 'F', '4', '3', '3', '1', '5', 'E', '1', 'C', '2', '5', '8', '3', 'C', '9', 'E', '5', '0', 'F', '5', 'D', 'C', 'B', '4', '4', '6', '2', 'F', '7', '4', '0', 'D', 'A', 'C', 'B', '7', '0', 'E', '9', 'C', '2', '2', '3', 'B', 'A', '6', '7', '8', '0', 'D', 'F', 'A', 'D', '7', 'F', '7', '0', '9', 'E', '2', '7', '0', '3', '2', '9', '5', 'F', '1', '5', 'B', 'D', '7', '6', '5', 'C', '8', '7', 'A', '0', '8', '6', 'A', '6', '7', '7', 'C', 'D', '8', '9', '1', '5', 'B', '0', '0', 'E', 'B', 'E', '5', 'F', '4', 'A', 'B', 'E', '0', '6', 'F', 'A', '7', '5', '4', '1', 'D', '7', '9', 'D', 'E', '9', '0', '0', '6', '7', '7', '6', 'E', '2', '1', 'C', '6', '4', 'F', 'F', 'A', '2', 'D', 'A', '3', 'A', '1', '2', 'E', 'F', '2', '1', '1', 'E', '4', '2', '2', 'C', '3', '2', 'B', '9', 'C', '7', '3', '2', 'C', 'C', '2', 'A', '2', 'E', 'E', '6', '2', 'F', '2', 'A', '2', 'E', '4', '8', 'E', '5', '2', '8', '0', '3', '9', 'B', '1', 'C', '1', 'B', '4', '7', '9', '5', '5', 'F', 'A', '7', 'B', '6', 'A', '3', 'D', '4', '3', 'C', '1', '2', '3', '4', 'D', 'E', '2', '4', 'A', 'E', '6', '7', '9', '9', '7', 'A', '8', 'C', '0', '9', 'D', 'B', '2', 'A', 'D', '6', '8', 'A', '4', '9', 'C', '4', '0', '0', '8', '1', 'B', '9', '5', '6', '5', 'E', '3', '3', '6', 'A', '0', 'F', '7', '4', '6', 'B', 'A', 'D', 'F', '2', 'C', '6', '7', 'D', '9', 'E', '0', '4', 'B', '0', 'E', '9', '3', '4', 'A', 'D', '2', 'F', '2', 'D', '6', 'A', 'F', '4', 'A', '2', 'F', '6', '0', 'A', 'A', '8', 'E', 'F', '0', 'A', '1', 'A', '9', '8', 'C', '7', '3', 'A', 'A', '7', 'A', 'C', 'C', '7', '2', 'E', '8', '6', '5', '8', '4', '7', 'D', 'F', '4', '3', '4', '8', 'B', '8', '6', '3', '0', '9', '6', '9', '6', '5', 'F', '8', 'A', '1', '7', 'E', '9', '6', 'A', '1', '9', 'E', '2', '4', '4', '3', '8', '9', 'E', 'D', '3', 'B', 'A', '2', 'A', 'A', 'C', '9', '4', '8', 'D', 'D', '1', '9', '9', 'B', '7', '0', 'F', 'A', '0', 'E', '3', '6', 'F', 'D', '6', '2', '5', 'D', '3', 'E', '0', '2', '0', '0', '3', 'C', '2', '8', '1', '0', '3', '8', '5', '1', 'D', 'B', '0', 'C', '2', '1', '6', 'C', 'F', '1', '6', '6', '9', 'C', 'F', '6', '0', 'F', 'A', '1', 'B', '8', '8', 'C', '4', 'F', '3', '1', '8', 'A', 'A', 'C', '2', '0', '6', 'E', '2', '8', '7', '2', '2', 'F', '0', '2', 'B', '3', '8', '8', '6', '6', '2', '4', '9', '5', '1', '1', 'B', '5', '4', 'E', 'E', '7', '4', '5', '8', '3', '7', '7', 'F', 'C', '1', 'E', 'A', 'B', 'A', 'F', '5', '3', 'F', '6', '3', '2', '6', 'F', '1', '9', 'D', '9', '9', 'D', 'E', '2', '0', '5', '9', '2', 'D', '8', 'F', '7', '8', 'B', 'F', 'A', '4', 'A', 'A', '6', 'D', '1', '4', '4', '0', 'F', '8', 'E', 'F', '3', '5', 'A', '3', '1', 'D', '0', '0', 'B', 'D', '6', '0', '6', '3', 'B', 'E', 'E', 'D', '4', '3', 'F', '1', 'A', 'B', '7', '7', '8', 'B', 'C', 'B', 'F', '8', '1', '2', '4', '7', '9', 'D', '2', '7', '7', '8', '1', '7', '9', '4', '4', '3', '0', '6', 'C', '1', '8', '9', '9', 'E', '6', 'D', 'E', '0', 'C', '5', '0', '6', '6', '2', 'C', 'A', '6', 'A', '6', '3', '1', 'C', '7', '2', '9', 'A', 'F', '9', 'C', '1', '8', 'B', '4', 'D', '6', 'F', '9', 'D', '3', 'F', 'D', '7', 'C', '4', 'A', 'A', '6', '4', '0', 'E', '9', '0', '9', 'C', '6', 'D', '0', '9', '2', 'D', 'F', 'A', '2', '4', 'D', 'F', '3', '0', '3', 'F', '0', '3', '2', '0', '1', '6', '8', '7', '2', '8', '4', 'F', '4', '6', '6', '8', 'E', '8', '1', '3', '0', 'C', '2', '7', 'B', '7', 'F', '7', '9', 'C', '6', '6', 'C', 'D', '3', '8', '4', '2', 'B', 'E', '9', '8', '8', '4', 'C', '8', 'D', 'F', 'B', '0', '3', '8', 'F', '3', '8', 'F', '0', '5', 'A', '5', '0', '5', 'D', 'C', '1', '2', '2', 'D', '1', 'F', '1', '2', 'D', '3', '6', '4', 'A', 'F', '1', 'F', '6', '3', '3', 'E', '1', '4', 'D', 'B', '9', '9', '4', '2', 'C', 'F', '3', '1', '3', '5', '5', 'B', 'F', '3', 'B', 'B', '7', 'E', 'D', '5', '0', '2', '7', 'F', '1', '9', '0', '3', 'E', 'B', '8', '9', '3', '3', '3', '2', 'F', 'A', 'B', '7', 'B', 'E', '9', 'E', 'A', '9', 'F', 'C', '9', 'A', '7', '0', '4', '9', '7', '0', '1', '6', '2', '2', 'A', '3', '3', 'F', '8', '5', 'D', 'E', 'B', '1', '0', '4', '5', '4', 'B', '7', '2', 'D', '4', 'F', 'E', '8', '8', '1', '5', '6', '6', '0', 'F', '4', '0', '4', '2', '2', 'C', 'B', 'C', '9', '7', 'E', '3', '6', 'A', '3', '7', '5', '4', 'B', '5', 'E', 'E', 'F', '8', '0', '3', 'B', '8', '1', '6', '8', '6', 'D', '3', '9', '8', 'E', '5', '9', '9', '0', 'D', 'A', 'F', 'F', 'B', 'A', '5', '4', '1', 'B', '9', 'C', 'E', '5', '0', '6', '6', '4', '6', 'B', '7', 'F', 'E', '3', '2', '4', '5', '8', '6', 'D', '2', 'B', '7', '7', '7', '4', 'E', '8', '6', '9', '5', 'E', '1', '9', 'E', '1', 'E', '7', '4', '1', '8', '0', '5', '6', '4', '7', '6', '1', '4', '1', '5', '0', '2', '4', '2', 'A', 'D', '1', '0', 'D', '9', '7', '0', '1', 'F', 'E', 'B', 'A', '8', 'B', '2', '6', '1', '8', '8', '7', '0', '4', 'E', '5', 'F', '2', '3', '7', '5', '8', '2', '7', '1', 'D', 'B', '1', '2', '1', '9', 'D', 'A', '3', '9', '0', '7', '4', '8', '3', '2', '8', 'B', 'E', 'F', 'E', '0', 'C', '7', '0', 'D', 'A', 'E', 'D', 'A', 'B', '8', 'B', '7', 'C', '2', '7', '3', '3', 'E', '6', '5', 'B', '4', 'E', '8', '9', '2', 'F', 'F', '5', 'A', '3', '9', 'E', '0', '2', '0', 'D', 'C', 'C', 'B', 'C', 'B', 'F', '7', '9', 'F', '2', '3', 'E', 'E', 'F', '8', 'B', 'B', '4', 'D', '4', '3', '2', '4', 'B', 'A', 'D', 'C', '1', 'D', 'A', '9', 'D', 'A', 'C', 'C', '0', 'B', 'A', '1', 'E', 'C', '0', '8', 'A', '0', '5', 'B', '6', 'A', 'A', '1', '9', '5', '1', '5', 'A', '6', '5', 'B', '9', 'D', 'D', 'F', '7', '5', '7', 'E', 'D', '7', 'E', 'F', '6', 'F', '7', 'F', 'C', 'C', 'E', '9', 'A', 'D', '4', '6', '4', 'A', '8', '0', 'E', 'A', '9', '8', '2', 'F', 'D', '4', '0', '0', '3', 'D', 'B', 'B', 'B', 'E', '2', 'D', 'E', '1', '8', '3', 'F', 'F', '1', '0', 'E', 'D', 'C', '2', '2', 'D', '3', '7', '0', 'A', '4', '5', '2', '6', '2', '2', 'A', '0', '2', 'D', '8', '7', 'F', '1', 'A', '2', 'B', 'A', '8', 'E', '9', '1', 'D', '7', 'E', '9', '9', '5', '8', '1', 'E', 'B', '6', '6', 'A', '0', 'C', '1', '2', 'D', 'F', 'F', '4', '9', '8', 'A', '8', '1', 'C', 'A', 'A', 'A', 'B', 'B', '5', 'A', 'A', 'D', '1', '8', '8', '2', '4', '2', 'E', 'D', '3', '1', '7', '8', '4', '1', '7', 'F', '0', '2', 'D', '8', '8', 'F', 'B', 'B', '9', '0', '5', '6', 'E', '8', '0', 'C', '0', 'E', 'E', 'E', 'E', '2', '1', '4', 'D', '7', 'E', '4', 'D', '2', 'C', '7', '7', '6', '2', '0', 'C', '7', 'C', '0', 'E', 'D', '9', '8', 'A', '6', '2', 'F', '6', '9', 'C', '8', 'B', '3', 'D', '5', '9', 'A', '3', 'D', 'E', '4', 'D', '6', 'D', 'E', '1', '3', '2', 'E', '4', '6', '5', '1', 'A', '2', 'C', 'D', '5', '3', 'C', '1', '0', '6', 'A', '9', '7', '9', '1', '7', '7', '3', 'A', '2', 'D', '4', '6', '1', 'F', '4', '9', '7', '5', 'D', '3', '7', '4', '7', '4', '8', '3', '1', 'C', 'A', '7', 'F', 'F', 'A', '5', 'C', 'A', '0', '9', '0', '9', '4', '2', '6', '4', 'E', 'C', 'E', '3', '4', '5', 'A', '6', 'D', 'F', '3', '4', '1', '7', 'D', 'D', '5', 'C', 'B', '2', '8', 'B', '9', '5', '1', '4', 'E', '0', 'F', '4', 'D', 'F', 'A', 'E', '7', 'E', '4', '5', '3', '0', '0', '4', 'C', 'D', 'C', '2', '9', '6', '8', 'D', 'F', '7', '0', '3', 'D', 'C', '1', '8', '4', 'B', 'E', 'A', '9', '8', '0', 'D', '8', '4', '0', '9', 'B', 'A', 'E', '5', 'B', '4', '3', 'C', '8', '8', '6', 'A', '0', 'A', '1', 'C', '8', '6', '2', '5', '7', 'B', '2', 'D', '5', 'B', '1', '6', 'D', 'B', 'D', 'E', '8', 'A', '3', 'C', '7', '0', '8', 'E', '1', '4', 'E', '6', 'E', 'F', '3', 'A', '6', 'F', '8', 'F', 'C', 'E', '4', '4', '3', '8', '6', 'F', '8', '8', 'A', '6', 'C', '8', '5', '1', '5', '5', '0', '7', '7', '0', '1', '9', '3', 'D', 'D', 'F', '1', '1', 'A', '3', '7', '1', '9', '9', 'C', 'F', '2', '3', '3', '4', '4', '9', 'F', '9', '0', '6', '0', '7', 'C', 'A', 'C', '4', 'C', '8', 'D', '0', '4', '7', '6', 'D', '1', 'D', '6', 'D', 'D', '5', 'E', '6', '3', 'F', '8', 'B', '9', 'C', 'F', '2', '9', '7', '6', '7', '1', 'D', '3', '1', '2', '9', 'D', '5', '9', '7', 'E', '3', 'F', 'E', 'F', 'B', '8', '7', '1', '2', 'F', '9', 'A', '6', '0', '0', '1', '0', '1', 'E', '8', 'A', '8', '6', '4', '8', 'B', 'E', '2', '2', '4', '2', '7', 'E', 'B', 'C', 'C', '6', '1', 'C', 'F', '8', 'B', 'C', '2', 'F', '3', '9', '1', 'F', '2', 'E', 'B', '2', '3', '2', '6', '3', 'B', '3', '0', '3', 'F', '3', 'F', '6', '0', 'D', 'E', 'D', 'B', 'A', 'A', '3', '1', '6', 'A', '7', 'A', 'C', '6', '2', '6', '5', '8', '7', '2', 'B', 'F', '7', 'D', 'B', '0', '8', '1', '3', 'C', '7', 'E', '2', 'B', '7', '1', 'A', '6', 'B', 'F', '2', 'A', '2', '4', '3', '3', '1', '2', '4', '7', '1', '1', '5', '7', 'E', '5', '5', 'E', 'C', 'A', '7', 'A', 'E', '4', 'D', 'F', '9', 'B', '9', 'C', '4', '6', '3', 'A', '7', '6', '8', '3', '6', '6', 'D', 'D', 'C', '6', '7', 'B', '0', 'D', '2', '4', '0', 'E', '5', '0', 'E', '4', '4', 'A', '0', '7', 'D', '2', '1', '0', '4', '1', 'B', '1', '2', '2', 'C', '3', '1', '6', 'D', 'A', 'C', '8', '5', 'E', 'B', '4', 'E', '7', '1', '4', 'C', 'B', '3', '8', 'E', 'D', '2', '1', '9', 'D', '2', '4', 'D', '4', '3', '8', '8', '7', 'B', '5', '0', 'B', '5', '6', '6', '0', '5', '2', '9', '7', 'D', 'E', 'F', '8', 'D', '4', 'F', '9', 'B', '3', '7', 'E', '4', 'B', '0', '5', '0', 'A', '3', '7', '8', '4', 'B', '5', 'D', 'D', '1', '7', '6', '1', 'B', '7', '7', '6', '7', 'B', '9', '9', '2', '9', 'D', '9', '0', '2', '5', 'E', 'B', 'A', 'E', '8', '5', '2', '7', 'F', 'F', '1', '4', '4', '1', '6', 'E', 'B', '0', 'B', '1', 'A', 'A', '2', '6', '8', 'E', '9', '7', '6', '0', 'D', '7', '9', '3', 'F', '2', 'D', '6', 'D', '2', '3', 'A', '6', 'F', 'D', 'F', 'C', 'C', '0', 'E', '9', '8', '7', '9', '5', '3', '9', 'F', 'B', '7', 'E', '4', '5', '7', 'F', 'E', '9', '8', '6', '3', 'E', '3', '3', '7', '9', '0', '2', '4', '4', '5', 'E', '5', '9', '2', '0', '4', '9', '1', 'B', '2', 'E', '9', '6', '9', 'F', '9', '0', '8', '4', 'C', 'F', '2', '4', 'C', 'C', 'D', '4', '6', 'D', '1', 'E', 'B', '6', 'F', '1', 'B', 'D', 'A', 'D', '7', '2', '4', '1', 'A', 'A', 'E', '5', '4', 'C', 'C', '6', '5', '8', '2', '4', 'A', '5', '1', 'E', '1', '1', 'A', '5', '0', 'B', '4', 'E', '0', '0', '8', 'B', '6', '6', '9', '0', 'C', '2', '4', '1', '6', '2', '6', '0', '0', 'A', 'D', '7', '7', '7', '1', 'C', 'D', '0', '8', 'F', 'F', '4', '7', '9', '2', 'E', 'C', '0', 'C', 'C', '2', 'F', '0', 'E', '3', 'E', '0', 'D', 'A', 'F', 'C', 'E', 'A', '9', 'D', '7', '6', '9', '7', '2', '8', '3', '2', '7', 'C', 'A', '0', '3', '2', '6', '1', 'B', '7', '8', 'C', 'D', '6', 'B', '5', '5', '8', 'B', '1', '2', '7', '9', '4', 'B', '8', '2', '0', '9', 'C', '1', '9', 'C', '0', '2', '7', 'C', '7', 'D', '6', 'E', '3', '1', 'C', '4', '7', '0', '8', '0', '3', '4', 'A', '4', '2', '9', '1', '8', '4', 'D', '5', '2', '3', 'A', '4', '2', '6', 'D', 'C', 'F', '2', 'A', '1', 'B', 'F', '5', '6', '1', '7', '6', '1', '0', '2', 'F', 'A', 'E', 'F', 'C', 'E', 'D', '8', 'E', 'B', '2', '1', 'A', '9', '2', '0', '8', 'D', '9', 'A', 'D', 'C', '7', 'A', 'A', 'B', 'F', 'C', '2', '3', 'D', '2', 'D', 'D', 'A', 'C', '7', '3', '9', '0', '5', 'F', '9', 'D', '4', 'E', 'B', 'A', '0', '6', '4', 'B', '2', '5', 'C', '1', 'D', '8', '8', 'F', 'A', '5', 'E', '0', '8', 'F', '7', '7', '1', 'F', '1', 'E', 'C', 'C', '5', 'B', 'B', 'F', 'B', '9', 'E', '8', '8', 'E', '3', '0', '3', '4', '1', 'C', '2', '9', 'F', '1', '4', '5', '3', '2', '6', '4', 'D', '7', '0', 'D', 'E', '2', 'A', '1', '1', '1', 'D', '7', 'F', '3', 'E', '9', '0', '2', 'D', '2', 'C', 'F', '0', '1', '1', '1', '6', 'E', '4', 'A', '2', 'B', 'C', 'C', 'F', '1', '8', '0', '2', 'B', '7', '1', '1', '5', '6', 'F', '9', 'D', '2', '1', '8', '6', 'B', '4', '3', '0', '6', '5', 'E', 'F', 'B', 'D', 'A', 'E', '5', 'C', '6', 'E', '6', '7', '5', '6', '0', '8', '4', '6', 'E', 'F', '5', '9', 'A', 'D', '6', '8', '5', 'F', '9', '9', '5', 'B', '9', 'D', '7', '3', '4', '4', '0', 'E', 'C', '8', '5', '4', '2', '3', '5', '0', '4', 'C', 'F', 'C', 'D', '9', '9', 'F', '4', 'E', '4', '0', '4', '5', 'D', '9', '6', 'D', '8', '7', '6', '7', 'B', '0', '1', '6', 'F', 'B', '6', 'C', '7', '2', 'B', 'C', 'D', 'C', 'D', '1', 'E', '4', '9', 'F', '8', '6', 'F', '7', '1', 'D', '0', 'A', 'C', '5', '6', '5', '0', '5', '1', '3', '9', 'F', 'F', '9', '5', 'B', '9', 'F', '6', 'B', '1', 'D', '9', '3', '5', '8', 'F', '6', '8', '1', '3', '9', '0', 'E', '3', '1', 'F', '7', '8', 'D', '2', '3', 'C', '5', '4', '2', 'A', 'B', '7', 'D', 'F', '1', '2', '3', '8', '4', '5', '0', '8', '5', '7', '3', 'B', 'C', '2', '0', 'B', 'A', '2', 'D', 'C', '7', '3', 'A', '9', '2', 'D', '8', '9', 'F', 'A', '8', '6', 'B', '3', 'F', '9', '1', '2', '5', '1', 'C', '9', 'F', '5', '4', '5', 'E', '3', '9', '3', '6', 'B', 'B', '3', 'C', '1', 'F', '1', '1', '8', 'B', 'C', '4', 'D', 'D', 'B', '1', '4', '7', '2', '7', '9', '6', 'C', '2', '5', 'A', 'D', 'A', '5', '1', '0', 'A', '3', '1', '3', '1', '3', '5', '0', 'E', '1', 'B', '9', 'D', 'D', '5', '9', '7', 'E', '7', 'E', '7', '9', 'D', 'A', '6', '3', '3', '9', '7', 'F', '3', '8', '0', 'E', 'E', '5', '5', '4', 'E', '0', '9', 'B', 'B', '4', '3', 'D', '8', '5', '4', '3', '9', '1', '7', 'D', 'D', '5', '8', 'B', 'B', '9', '3', '2', '0', '3', '3', 'C', 'D', '1', '6', '8', 'B', 'D', '4', '5', 'E', '7', 'F', 'A', 'E', '1', '1', '4', '4', '9', '2', '8', '0', '2', '6', '6', 'B', 'F', 'A', '9', 'A', '5', '8', '6', '3', 'E', 'D', 'A', '5', 'A', '9', '6', 'D', '0', '7', '3', '1', '8', '5', 'A', '5', 'E', '9', 'D', 'F', '9', '2', 'B', '7', 'F', 'B', '3', '1', '0', 'F', 'B', '4', '5', '1', 'D', '7', 'B', '8', '7', 'F', '1', '2', 'F', 'B', '4', 'B', 'C', '6', 'D', 'C', 'C', '7', '3', 'B', 'C', '0', 'A', '0', 'A', '8', '3', 'B', 'F', 'A', '3', 'B', '4', '0', '6', 'A', '6', 'D', 'F', 'F', '9', '9', 'A', 'D', '3', 'C', '2', '9', '9', 'E', '5', 'E', '5', '9', 'B', '5', '9', '3', '9', 'C', '0', '5', '1', '0', 'B', 'D', 'E', '1', '2', '0', '8', '2', 'D', 'C', '5', '9', 'C', 'F', '1', 'E', '6', 'C', '3', '6', 'D', 'C', '5', '6', '5', '5', '3', '1', '4', 'A', '4', '6', '5', 'C', '4', '6', '9', '4', 'F', 'E', 'D', '3', '3', '3', '7', '1', 'C', '5', 'B', '3', '7', '7', '4', '2', '1', '9', '3', 'F', 'F', '8', '8', '3', '5', '9', '1', 'B', '0', '4', '9', '7', '7', '5', '5', '6', 'F', '8', '5', 'E', '3', '6', '1', '6', '7', '0', '8', 'B', 'D', '9', '0', 'B', '1', 'B', 'A', 'D', '6', '2', '3', 'A', 'A', 'E', '1', 'B', '5', 'C', '1', '4', '5', 'C', '9', '2', '4', 'F', 'A', 'F', '0', 'F', '9', '8', 'C', '8', 'C', 'A', '3', '8', 'B', '9', '1', '3', '7', '2', '9', 'A', 'E', 'F', 'A', '2', '8', 'E', 'F', '5', '1', '6', '4', '0', '3', 'B', 'C', '5', 'F', 'F', 'A', 'A', 'A', '0', '8', '5', 'F', 'B', '1', 'E', 'C', '2', '1', 'F', 'B', '3', '7', '1', '5', 'F', 'C', 'B', '4', 'F', '0', 'F', '7', 'E', '1', '2', '1', '9', '6', 'E', '3', '8', '3', '4', 'F', 'D', '5', '1', 'E', 'A', '7', '9', '6', '3', '4', 'E', 'F', 'E', '3', '6', '3', '6', 'F', '2', 'B', '2', '7', '4', 'C', '4', 'E', '2', 'C', '7', '6', '4', 'F', '0', 'D', 'B', '0', '3', '9', 'C', '5', '3', 'F', 'B', '7', '3', '8', '0', '8', '9', 'C', '5', '8', 'A', '0', '7', 'E', 'C', '3', '6', 'D', 'B', 'C', 'C', '5', '4', 'D', '9', '2', '0', '1', '2', 'A', 'A', '6', '3', 'E', '0', '1', 'F', '5', 'D', 'F', '7', 'A', '1', '3', 'E', '6', '9', 'C', '1', '4', 'C', '1', '4', '5', 'F', '0', '2', '5', '9', '5', 'A', 'F', '5', 'F', 'F', 'C', 'E', '4', '7', '8', 'B', '5', 'B', 'E', 'D', '6', 'A', '8', '7', '8', '7', '8', 'F', '7', 'F', '7', '6', 'B', '5', 'F', 'A', '9', 'A', '7', '4', '5', '8', 'A', '0', '5', 'D', '0', '3', '1', '8', '2', 'D', '6', '7', '6', 'E', '1', '9', '7', '1', '6', 'D', 'B', '6', 'A', '3', 'F', 'E', '9', '8', '4', 'E', '3', 'B', 'A', '0', '3', '1', '3', 'D', '1', '7', 'F', 'A', '6', '4', '3', 'B', 'E', '1', 'F', '7', '7', 'F', 'E', '6', '3', '3', '5', '0', '7', '9', '3', 'D', 'C', '0', 'C', 'E', '1', '5', '6', '2', '8', 'B', '6', 'A', '3', '3', '2', '3', '6', 'D', '3', 'F', 'D', '0', '3', '1', '5', '7', 'B', '0', '0', '3', 'D', 'F', '9', '8', 'C', '7', '2', 'A', '3', '3', '1', '2', '8', '0', '0', 'C', '2', 'E', '1', 'A', '1', 'B', '2', 'F', 'C', '7', '7', 'B', '8', '6', '3', '0', '0', '5', '0', '4', '6', 'B', 'E', 'D', 'A', '5', '1', 'F', 'B', '6', 'F', 'D', '3', 'B', '8', 'B', '1', '6', 'B', 'D', '8', '2', '1', 'B', '7', '7', 'E', '0', '3', '4', '9', '7', '1', 'A', '9', 'D', '3', '9', '5', 'F', '5', '0', 'B', '9', '4', '7', 'A', '8', 'A', 'A', '0', 'E', 'F', '2', '4', 'E', '4', '5', '2', 'A', 'A', 'B', 'E', '2', 'B', '3', 'D', '6', '5', 'E', '1', '6', 'E', 'E', '9', 'E', '5', 'F', '8', '7', '1', 'C', '2', '8', '2', '8', '5', 'C', 'D', 'E', 'E', 'F', 'D', 'A', '0', '4', '0', 'F', 'E', '9', 'C', 'A', '6', 'B', '1', 'B', '4', '2', '4', '6', 'C', '0', 'C', '4', '3', 'D', 'B', '4', '0', '8', '1', '8', '7', '5', '4', 'F', '5', '8', '1', '1', '7', '4', 'F', '9', 'D', 'C', '7', '2', '9', '6', '9', '3', '2', '6', '1', 'D', '7', '0', 'A', '6', '5', 'F', 'F', '2', '2', '1', 'A', 'A', '5', '7', '8', '4', '7', 'F', 'B', 'F', '8', '0', 'B', 'C', '9', 'B', 'B', 'C', 'B', '8', '8', '8', '2', '5', '7', '9', '0', '2', 'B', '4', '4', '7', '6', '8', 'F', '8', 'B', '0', '7', '2', 'C', '7', '1', '5', '3', 'B', '8', 'A', 'C', 'C', '7', '0', '1', '0', '5', '2', 'C', '4', '9', '8', '8', 'A', '0', '7', '8', 'D', 'B', '5', '1', '8', 'A', '3', '3', '2', '7', 'B', '0', '5', '1', '3', '7', '8', 'F', '4', 'C', 'C', 'F', '1', 'C', '9', 'B', '9', '6', '8', '2', '8', '1', 'E', '0', '9', 'E', '6', '4', '0', 'E', '1', 'B', 'D', '0', 'F', '5', '8', '8', 'E', '4', 'E', '4', '7', '9', '9', 'D', 'E', '2', 'D', 'D', 'E', '2', 'E', '9', '9', '3', '9', '7', '9', 'F', '9', '0', 'B', '2', 'F', '8', 'E', 'F', '5', '1', '8', '5', '1', 'B', '9', 'A', '8', '8', '4', '4', '8', 'B', 'E', 'D', 'C', 'F', '2', '2', 'B', 'F', '2', '8', 'E', '2', '9', '8', '6', 'C', '3', 'F', '0', 'F', '3', 'B', '5', 'B', '3', '4', '3', '5', '0', '2', '5', '8', '1', 'B', '6', 'A', '1', 'D', '9', '5', '0', '8', '7', 'E', '3', '0', '5', 'E', '7', '4', '6', '0', '8', 'C', 'E', '9', 'C', '0', 'B', '4', 'F', '6', '5', '8', 'E', 'B', '2', 'D', '8', 'C', '2', '6', 'B', '5', '0', '4', '2', '5', '7', '9', 'E', '4', '2', '2', 'E', '0', 'B', 'D', 'F', 'C', '9', 'D', 'C', 'E', '0', '8', 'B', 'B', '1', '8', 'C', 'E', '9', '8', '0', '4', '0', '5', '6', 'D', '4', '2', 'E', '3', '1', '5', 'B', '8', '8', 'D', '0', '5', '0', 'C', 'D', '6', '2', 'B', '0', 'E', '7', '8', '9', '9', 'E', '4', '7', 'E', '8', '5', '6', '0', '8', 'C', '6', '2', 'A', '8', '4', 'D', 'B', '6', '8', '5', '5', '5', 'C', '7', 'E', '9', '6', 'A', '1', '8', '3', '7', '3', '8', '8', '1', '9', '5', '6', 'B', 'F', 'A', '5', 'F', 'E', '9', '1', '9', '8', '1', 'A', '3', '8', '3', 'C', '7', 'A', 'A', 'E', '3', '3', '4', 'A', '0', '7', 'F', 'B', '7', '3', '0', 'D', '2', '0', 'D', '8', '0', 'E', '8', '2', '2', 'A', '9', '0', 'E', '4', '8', '2', '3', '3', '6', 'A', 'B', '1', '4', '1', '9', '0', '4', '0', '5', '1', '8', '5', '4', '6', '4', '3', '3', '3', '5', 'F', 'F', '2', '9', 'E', '4', 'C', '5', '1', '0', '7', '9', '8', 'E', '3', '0', '9', '3', '9', '3', 'B', '9', '6', 'E', '8', 'E', '5', 'B', 'A', '2', 'B', 'E', '7', '3', '0', '4', '9', 'A', 'B', '5', '7', 'A', '4', '0', '6', '7', '6', 'D', '4', 'D', '6', '4', '4', '7', '7', '5', 'C', '9', '4', 'C', '3', '5', '6', '1', '8', '3', 'D', 'D', '9', '3', '4', '8', 'E', 'A', '5', 'B', '5', '5', 'A', 'A', 'E', '4', '4', '3', 'D', '4', '8', '2', 'C', 'C', '5', '3', '3', 'E', '6', '0', '4', '4', '9', '9', 'F', '0', 'C', 'B', '3', '4', 'C', '9', '3', '3', '9', 'D', '3', '3', '3', '6', '6', 'E', '6', '4', '1', '4', '9', '0', 'E', '0', 'E', '0', '3', '2', '7', '2', 'D', 'B', 'E', '7', 'A', '3', '7', 'E', 'F', '4', 'B', '1', 'B', 'B', 'B', 'D', '5', '4', 'A', '0', '4', '2', '7', '5', '8', '4', 'C', '9', 'B', '9', '0', '0', '2', '4', '6', '9', 'C', '2', '3', 'C', '4', '4', '9', '7', 'C', '4', '0', '3', '9', '1', '5', '3', '9', '0', '9', 'B', 'F', '2', '1', 'F', 'C', '0', '1', 'B', '9', 'C', '1', '2', 'D', '1', '5', 'E', '6', '3', '9', 'A', '4', 'E', '0', 'A', 'D', 'A', '5', '0', 'C', '3', 'B', 'F', '5', '9', '8', '2', '9', '5', 'E', '3', '1', '8', '7', 'E', '1', 'A', 'B', '6', 'B', 'D', 'B', '4', '7', '1', '8', '4', 'B', '7', '0', '0', '7', '6', '3', '2', 'B', '1', 'B', '8', 'F', '0', '2', '0', '4', 'D', '1', 'F', '7', '2', '0', 'C', 'D', 'C', 'A', '4', 'D', '4', 'C', 'E', '4', '5', 'B', '7', 'C', 'D', 'D', '9', '1', '7', 'B', '8', 'D', '8', 'A', '6', 'E', '0', '2', 'E', '7', 'F', '8', 'D', 'C', '6', 'E', 'E', '7', '7', '1', '8', '3', '9', '9', 'D', '4', '6', '8', 'C', 'B', '7', 'B', '7', 'B', '3', 'C', 'B', 'A', '0', '1', '5', 'B', '1', 'B', '9', 'F', 'F', 'D', '6', 'F', 'F', 'A', 'B', '6', '4', 'B', '3', '8', '6', 'B', '3', '4', '7', '4', '2', '7', 'F', '9', '7', 'B', '7', '8', 'A', '2', '1', '1', '8', 'A', '3', '4', '4', 'F', 'B', '2', 'A', '0', 'B', '2', 'A', 'D', '9', '5', '6', '7', '2', '5', 'E', 'B', '8', '5', '7', '1', 'B', '9', '8', '0', '4', 'B', '4', '9', 'C', '9', 'D', '6', '1', '6', 'A', '3', '2', 'D', 'A', '0', '1', '5', 'D', '1', 'F', '2', '2', 'B', 'A', '0', '0', '8', '8', 'B', 'F', '4', '1', '4', '0', '3', '5', '7', 'D', '5', '6', '7', '0', '1', '3', '2', 'E', '3', '4', '8', '9', '9', 'E', '0', '9', '8', '6', 'D', '8', '9', '7', 'F', 'C', 'E', 'F', '7', '6', '1', '3', '5', 'D', '9', 'C', '6', '5', '4', '0', 'E', '9', 'F', '5', 'D', 'D', '5', '8', '3', 'D', 'E', 'F', '2', '7', '3', '4', '9', '6', 'A', 'B', '6', 'F', '8', 'D', '1', 'F', '8', '0', '0', 'B', '0', '5', 'F', '2', '9', 'C', '3', 'E', '7', '8', 'B', 'F', '3', 'C', '1', 'C', '5', '1', '8', 'E', '9', '8', 'B', '3', '4', '1', '2', '1', '2', '1', '0', 'C', '2', 'D', 'B', 'E', '9', '2', 'C', '5', 'C', '8', '5', 'C', '9', '8', '6', 'D', '5', '2', '8', '8', '3', '2', 'A', '0', 'E', '7', '9', 'B', 'A', '2', '2', '1', 'D', '5', 'E', 'D', 'C', '3', 'B', 'D', '4', 'C', '3', 'F', 'E', 'F', '0', '9', 'F', '8', 'B', '0', '5', 'B', '7', '3', '3', 'A', '1', '7', '3', '2', '8', '8', '8', '6', '7', '6', '6', 'F', 'C', 'D', '5', '4', 'D', '9', 'F', 'D', 'A', '9', '2', '8', '4', 'B', 'A', '9', '2', 'B', '4', 'F', 'B', '2', 'D', '7', 'D', 'D', 'C', '2', '4', '2', '7', 'E', 'F', '8', 'F', '7', '8', '3', '7', '3', '6', 'A', '0', '8', '7', '1', '8', '3', '4', '0', '5', 'D', '6', 'C', '2', '0', '0', 'C', '4', '4', '2', '0', '0', '6', '1', '7', '3', 'F', '9', 'D', '1', '3', 'E', 'A', '4', '6', '0', 'A', '6', 'A', '3', '6', 'A', 'E', '4', '5', 'D', '5', 'D', '4', '4', '8', '8', 'F', '2', '7', 'A', '7', 'E', 'C', '2', '3', 'F', '5', 'B', '4', 'C', '1', 'E', 'F', 'F', 'C', 'F', '7', '3', '7', '9', '7', '2', 'A', '6', 'C', '8', '2', 'B', '3', 'C', '3', 'D', '1', '3', 'F', 'C', '1', '6', 'F', '0', '2', '3', 'E', '5', '3', '8', '8', 'B', 'E', '9', 'B', 'F', '1', '7', '3', 'A', '6', '5', '9', '5', '5', 'D', '2', '9', 'B', '7', '9', '1', '6', '3', '4', '5', '8', 'F', '2', '2', 'E', '0', '9', '6', 'E', '0', '2', '9', '3', 'D', '8', '2', '0', '3', 'F', '1', 'D', 'F', '5', '6', 'F', '6', '8', '3', 'F', '0', 'F', 'A', 'F', '4', 'B', '1', '7', 'C', '0', '8', '0', 'E', 'D', 'F', '9', '6', 'C', 'B', '3', '6', '2', '0', 'A', '4', 'B', '6', 'B', '9', 'E', '0', '2', '5', '6', '9', '8', 'D', '4', '0', 'D', '3', '9', 'A', '0', 'B', '4', '1', '5', 'B', '4', 'D', '7', '9', '2', '2', '6', 'A', 'E', '5', '3', 'C', 'D', '9', '4', 'B', 'E', '8', '4', 'C', '8', '3', 'C', '2', '9', 'B', 'D', '3', 'C', '5', '6', '7', 'D', '1', '9', '4', 'D', 'D', 'F', '0', '8', '3', '1', '0', '3', '2', '2', 'A', '7', 'F', 'F', 'C', '1', 'A', 'F', 'D', '0', 'F', '9', '3', 'A', '5', '2', '1', '5', 'C', 'E', 'F', 'C', '1', 'E', 'A', '4', '6', 'F', '5', '8', '4', 'E', '2', '6', '2', '5', 'C', '0', '1', '8', 'A', 'D', '8', 'D', '8', '2', 'C', 'A', 'E', '2', '1', '7', '8', '3', '0', '0', '5', '1', '4', 'A', '3', 'B', '3', '2', '1', '7', '0', '2', '8', '1', '6', '8', '0', 'E', '4', 'B', '0', 'E', '5', 'C', 'C', '2', '1', 'A', '1', '2', 'F', '2', 'F', '7', '8', '5', '6', 'D', '5', '4', 'E', '8', '4', '6', '7', '1', '6', 'F', '3', '0', '9', 'F', '8', '8', 'E', 'F', '4', '4', '1', '3', '8', '5', '3', '2', '5', 'F', '0', 'C', '2', '0', 'E', 'B', '5', 'B', 'D', '7', '6', '0', '7', 'A', '0', 'D', 'D', '6', 'A', '4', '8', '2', 'D', '8', 'A', '4', '6', '7', '4', 'C', '2', '2', '7', '1', '9', 'C', 'A', '3', '7', '6', 'F', '0', 'A', 'B', '8', 'E', '0', 'C', 'A', 'A', 'E', '6', 'D', 'E', '4', '5', '4', 'D', '5', 'C', 'D', '7', '1', '3', 'E', '9', '9', '6', 'B', 'B', '2', '1', '9', '2', '7', '8', '1', '7', 'B', '3', '3', '0', '0', '5', '6', 'D', 'A', '4', '7', 'B', '7', '1', '0', '1', '0', '0', '0', '8', '8', '1', '7', '1', '8', '2', '6', '8', 'A', 'F', '2', 'E', 'F', '8', 'A', '5', '4', '7', 'F', '3', '3', '7', '7', '0', '3', 'B', '6', 'C', '3', '4', '3', 'C', '0', '0', '2', '1', '4', '2', '3', 'A', '4', 'F', 'D', 'C', 'B', '0', 'C', '4', '8', 'C', '6', '6', '5', '4', '2', '8', '5', '7', 'E', '9', '0', '5', 'C', '1', '8', '9', '7', 'B', '0', '9', '7', '8', '2', '9', '1', '1', 'B', 'B', '0', '2', '4', '8', '4', '9', '9', '3', 'C', 'B', '6', '7', 'A', 'E', 'A', '6', '4', '8', 'A', 'B', '4', 'C', '3', 'C', 'F', 'B', '2', '8', 'E', '8', 'C', '4', '8', '4', 'E', '9', '2', 'B', '7', '9', '8', 'F', '8', '1', '8', 'E', '8', 'F', 'D', '3', '7', 'D', '2', '4', '5', '9', 'F', 'C', '0', '0', '3', 'F', '0', '4', '8', '4', '3', '2', 'A', 'A', 'B', '2', '3', '4', '1', 'C', 'A', 'E', '8', 'E', 'E', '7', '3', '2', 'F', 'B', '8', '9', '1', '0', 'B', '2', '9', 'E', '2', '7', 'C', '3', '2', 'E', 'A', '0', '1', 'C', '0', '2', 'C', '6', '7', '4', 'B', 'E', 'D', 'A', '3', '4', '9', 'D', 'A', 'B', 'E', '6', '6', '5', '1', '7', '1', 'F', 'C', '9', 'A', '8', '4', '1', 'A', '3', '4', '1', '6', '2', 'E', 'C', '2', '4', '2', 'D', 'F', '0', 'B', '7', '6', 'B', 'D', '5', '9', 'C', '4', 'B', 'B', 'A', '2', '2', 'C', '9', '5', '9', 'F', '5', '9', '7', '6', '7', 'C', '6', '9', 'E', '1', 'A', 'A', '8', '6', 'B', '8', 'B', 'D', 'D', 'A', '4', '6', 'D', 'E', 'C', 'A', 'A', '2', 'A', '5', '0', '4', '9', 'A', '7', 'B', '9', '7', 'D', '9', 'D', '8', '5', '0', 'B', '1', '8', 'F', 'E', '2', '1', 'B', '5', '1', 'F', '1', '6', '9', 'B', '3', '3', 'C', '5', '5', 'C', '6', '7', 'E', '8', 'A', '9', '6', 'F', '1', 'E', '6', 'A', '0', 'C', 'F', 'F', '4', 'C', 'A', 'A', '3', '1', '1', '4', 'C', '4', 'A', '5', '9', '0', '6', 'D', 'A', '8', 'D', 'F', 'C', '1', 'C', '0', '9', '6', '6', '3', 'C', 'A', 'B', '5', '0', 'D', 'E', 'D', 'A', '4', '8', 'D', 'C', 'C', 'A', '9', '3', '6', '5', '3', '1', 'D', '7', 'C', 'B', 'E', '0', '8', 'E', '0', '7', '9', '1', '3', 'F', '7', '1', 'F', '1', 'A', '7', 'C', 'D', '4', '6', 'A', '6', 'A', '8', '8', 'A', '1', '7', '7', '7', '2', '8', 'D', '8', '3', 'F', 'F', '7', 'E', 'C', 'E', '3', '0', 'D', 'F', '2', 'E', '1', '6', 'F', '5', '8', '3', 'C', 'F', '4', '8', '5', '4', '2', '9', '3', 'E', 'A', '8', '8', 'F', '9', 'B', '7', '8', '0', 'E', 'E', '6', '0', '2', '2', '2', 'B', '2', '5', 'D', 'B', 'E', 'F', '2', '5', '2', 'C', 'C', 'A', 'D', '7', '1', '3', 'B', 'B', '1', 'D', '4', '0', '6', '5', '5', 'D', '5', '6', '3', '9', '0', '5', '0', '5', '9', 'F', '2', '3', 'F', 'A', 'D', '9', 'B', '0', '3', 'F', '8', '4', 'F', 'E', 'E', '2', '6', '9', '7', '1', '9', '0', 'B', '7', '2', '7', '6', '5', '2', '5', 'A', 'F', '3', 'F', '5', '3', 'F', '9', '6', 'A', '8', '4', 'C', '5', '1', '1', 'C', '9', '4', '1', 'D', 'F', 'B', '9', 'E', 'B', '2', 'A', 'B', '3', '0', 'E', 'A', 'C', 'B', '9', '9', 'F', '9', 'C', 'A', 'E', '0', '3', 'C', 'C', '9', '4', 'B', 'A', 'D', '5', '8', 'B', '6', 'A', '0', '6', '3', 'F', 'D', '1', 'B', '3', '6', 'D', 'F', '4', '6', '9', '5', '8', 'C', '8', '6', '6', 'F', '0', 'A', 'F', '0', '9', 'D', '6', 'A', 'F', 'C', 'E', '7', 'B', '3', 'A', '2', '8', 'C', '8', '5', 'C', '0', '4', 'F', '6', 'F', 'D', '0', 'B', '3', '1', 'B', '9', '6', '4', '9', '6', 'C', '3', '2', 'F', 'A', 'F', '8', '6', '0', 'C', '4', 'F', 'E', 'D', 'A', '0', '0', '9', 'F', '7', '1', '7', 'B', '8', 'D', 'F', 'E', 'C', 'B', '8', 'B', '4', 'B', '9', '9', '4', 'D', 'B', 'C', '0', 'C', 'B', '1', '4', '2', '9', 'A', '8', 'F', '0', '6', '9', '4', '2', 'F', 'B', '7', '0', '9', '8', '9', '3', 'C', '2', '9', '2', '2', '6', '0', 'B', '5', '0', 'C', '4', '0', '1', '4', '3', '4', 'D', 'B', 'B', '9', '2', '1', '9', '7', '1', 'B', '7', '2', '5', '5', '5', 'B', '7', '9', '1', '4', '1', '8', '9', '4', 'B', 'C', '9', 'F', 'E', '4', 'A', '0', '5', 'B', '5', '4', '4', '3', '1', 'C', '6', 'D', '6', '0', '2', 'B', 'D', '1', '3', '6', 'D', 'E', '8', '6', '1', '5', 'D', '5', 'F', '6', 'A', 'F', 'B', '3', '2', '1', 'C', 'E', 'E', '0', 'C', '5', 'B', 'D', 'D', 'F', '4', '4', 'B', 'E', 'E', '3', '0', 'D', 'F', 'D', '7', '5', '1', 'C', '2', '2', '2', '2', 'C', '7', '3', 'A', '7', '8', '0', 'D', 'D', 'F', '4', 'B', '5', 'E', '0', '7', 'E', 'C', '2', 'D', '1', 'B', 'F', 'A', '5', '0', '9', '8', 'A', '0', '4', 'E', '5', 'D', '4', 'A', 'C', '2', 'F', '1', '8', '2', 'C', '6', '8', '8', '0', 'F', '5', 'B', '7', '2', 'E', '1', '2', '7', '6', '4', '2', '2', 'F', 'F', '4', '4', '1', 'E', '4', '3', 'B', '9', '7', 'C', 'D', 'F', 'A', '6', '6', 'C', '5', '4', 'A', '6', 'A', '1', '1', '4', '3', 'F', '5', '0', '7', '7', '0', '7', '8', '6', 'F', 'C', '5', '4', '8', '9', 'C', '1', '9', 'B', 'D', 'E', '9', 'B', 'F', 'C', '2', '0', '3', '5', 'D', '5', 'E', '8', '2', '2', '3', '0', 'A', 'E', '7', '4', '5', 'A', 'C', '5', '2', '5', 'E', 'F', 'F', 'D', '7', 'B', 'C', '0', '7', '7', '7', '8', 'F', '0', 'A', '7', 'E', 'B', 'A', '9', 'E', '6', 'D', 'E', '8', 'E', 'A', 'F', 'F', 'A', '9', '2', '1', '0', '3', '9', '0', '1', 'C', '2', '5', 'D', '4', '3', '2', '6', '6', '1', '1', '7', 'A', '1', 'F', 'C', 'C', '6', '2', 'F', '6', '6', '0', 'B', 'A', 'A', '0', '8', '2', 'E', '3', 'F', '3', 'B', '5', '8', '1', 'B', '9', '8', '8', '1', '6', '1', '9', '4', 'B', '9', '5', 'D', '7', '1', '3', '5', 'E', 'C', 'E', '6', '7', '8', 'F', '6', '3', '0', 'C', '1', '3', 'F', '9', 'F', 'B', '6', 'F', 'B', '6', '0', '9', 'A', 'F', 'F', 'A', '2', '2', 'E', '0', 'A', 'A', 'F', 'E', '7', 'C', '6', '5', '6', '9', 'E', 'A', 'C', 'B', '4', 'E', 'D', '5', '8', '9', '4', 'A', '2', '1', '3', '3', 'F', 'F', 'F', '7', '4', '8', 'D', 'C', '8', '3', 'E', '7', '2', 'B', '2', '5', '4', 'A', '8', '2', 'D', '4', 'D', '7', 'F', '3', 'D', 'C', 'C', '7', '8', '2', 'A', '6', '7', '8', '9', '7', 'F', '1', 'E', '9', '1', '5', 'C', '2', '3', '8', 'D', '6', '8', '5', '2', '4', 'A', 'C', '3', 'A', '0', 'A', '1', '9', 'C', '1', '5', 'A', '2', 'A', 'E', 'D', 'F', 'B', '1', 'F', 'C', '4', '0', 'C', '2', '1', '9', '7', '3', 'E', '5', '0', 'D', '0', '9', 'D', '9', '5', '9', '7', 'E', '6', 'A', '7', '8', 'A', '3', '6', 'E', 'D', '9', '1', '5', '0', 'A', 'E', 'D', '3', '5', 'C', 'A', 'E', '4', 'A', '8', '9', 'A', '3', '0', '7', '0', '8', 'C', '0', '4', '6', 'A', '8', 'B', '6', 'A', 'E', '5', '6', 'B', 'F', 'A', 'E', 'C', 'F', '4', 'D', '3', 'B', '5', 'D', '1', '6', '5', '6', '2', '8', '2', '7', '0', '5', 'D', '2', '4', '3', 'D', '4', 'B', 'A', 'A', '0', '2', '7', '8', '7', '2', '9', '2', '7', 'E', 'A', 'C', 'F', '0', 'C', '3', 'B', 'E', 'F', '5', 'D', 'F', '5', '2', 'D', 'B', '8', 'A', 'B', 'F', 'A', 'A', '3', '6', 'E', '0', '4', 'B', '3', '5', '3', 'E', '7', '1', 'B', 'D', 'A', '3', '7', '9', '7', '4', 'A', '2', '0', 'E', '4', '3', '6', 'F', 'B', 'F', '5', '7', '4', 'F', '2', 'A', 'B', '1', '8', '5', '7', '8', '9', 'C', '8', 'F', 'F', '0', '5', '3', '2', '1', '7', '3', 'D', 'C', 'B', 'A', '8', '1', '0', 'C', '5', '3', '2', '6', '7', '9', '6', '4', '5', '0', '0', '1', '5', '3', '2', '6', '7', 'B', '8', '4', '4', '8', '0', '3', '2', 'F', '1', 'C', '5', 'F', '4', 'C', 'C', '9', 'C', '9', 'D', 'D', 'C', '0', 'D', '4', '0', '9', '7', 'C', 'F', '6', '8', 'A', '0', 'F', '4', 'B', '6', 'E', '1', '4', '7', 'C', 'D', 'F', '9', 'D', 'A', 'C', 'E', '3', '2', 'E', '9', '7', 'C', '4', '1', 'A', '4', '6', '3', '3', 'E', 'D', '5', 'A', '8', '1', '1', '4', 'E', 'D', '5', 'E', '5', '8', '2', '3', 'A', '5', 'F', '7', '1', '7', 'E', 'F', '8', '1', '0', '3', 'C', '9', '5', '7', '2', 'A', 'D', 'F', '7', 'C', 'C', '6', 'F', '4', '6', '9', '3', '1', 'A', 'D', '1', '9', 'E', '0', 'B', 'C', '2', '8', '6', '4', 'E', 'F', '3', '8', '4', '5', 'C', '4', '4', '9', '6', '0', '3', '3', '1', 'D', '8', '4', 'C', '2', 'E', '4', '7', '2', '1', '5', '1', 'C', 'D', 'B', 'C', '2', 'F', 'D', 'B', 'C', '5', '0', '2', '9', '6', 'E', 'A', '4', 'E', 'D', 'C', '5', '9', '3', '0', '9', '5', 'B', 'C', 'A', '4', '4', '2', '4', 'C', '7', '5', 'B', '7', 'D', '4', '7', 'E', 'D', '5', '4', 'C', 'D', '1', '5', 'D', 'C', '9', 'F', '4', '8', 'E', '6', '7', '7', 'A', '4', 'A', 'C', 'B', 'E', 'C', '3', '9', '7', '9', 'D', '6', 'F', '9', '2', 'A', 'C', 'F', '0', '5', '1', '0', '6', '3', 'B', '3', '0', 'F', '6', '5', 'B', '6', '6', '9', 'F', 'A', '3', 'F', 'B', 'E', 'B', 'C', 'F', '6', '5', 'B', '7', '4', '8', 'B', '1', '7', 'C', 'B', 'B', '6', '1', 'D', '6', '8', '8', 'B', 'C', '7', 'A', 'E', '4', '1', 'C', '5', '7', '2', '1', 'C', 'A', '2', '6', '1', 'F', '9', '6', '5', 'C', '2', '3', '7', 'A', '5', 'D', '5', 'A', '4', '9', 'D', '5', '2', '5', '9', 'F', 'A', 'D', 'D', '8', '8', '0', '6', '0', 'D', '6', 'A', 'C', '0', '6', 'E', 'B', '0', '3', 'C', '0', '3', '2', '5', 'D', '9', '4', 'B', '6', '3', '1', '4', '9', '6', '7', '6', '0', 'A', '5', '6', 'A', 'B', '5', 'A', '1', '4', '9', '0', '4', '2', 'B', '8', '4', 'A', '8', 'F', '7', '0', '1', 'D', '6', '7', '2', '7', '9', '4', '9', 'A', 'F', '8', '0', '7', 'A', 'A', '0', 'D', 'F', '3', '0', '3', '7', '8', '0', '7', 'C', '3', '6', '5', '2', '1', '6', 'B', '6', 'D', 'D', '5', '4', '5', 'E', '4', 'B', '0', 'A', '8', '5', '5', 'B', 'F', '7', '1', 'F', '9', 'E', '4', '8', '2', 'A', '2', '7', 'C', 'E', 'F', '7', '1', 'C', '1', 'E', 'D', '6', '3', '3', '1', 'F', '4', 'F', 'C', 'E', '5', '0', '1', '2', '7', '9', '8', '2', 'E', '7', '2', 'A', '2', '8', '6', '7', '8', 'C', 'D', 'F', 'C', '3', '6', 'A', 'A', '1', 'A', 'B', 'E', '2', '4', '8', 'D', '6', '7', 'C', '1', '8', 'E', '9', 'E', '9', '3', 'A', 'E', 'D', '0', 'C', 'E', 'F', '2', '8', '8', '0', 'A', '7', 'D', 'D', '1', 'E', 'E', '3', '5', '7', 'C', '4', 'D', '2', '4', '7', 'D', 'C', '3', '9', '8', 'E', 'A', '6', 'A', '7', '0', '1', '4', '3', '2', 'D', '1', '9', 'F', 'E', 'C', '4', 'F', '0', 'B', '5', 'A', '7', '2', '6', 'D', 'C', '1', '6', '0', '0', '8', '6', '6', '9', 'B', '6', '4', 'E', '3', '2', '8', 'D', '6', '6', '4', 'F', '6', 'D', '4', '3', '9', 'E', '5', 'D', '2', 'A', '0', '0', '0', '2', '9', 'A', '0', '9', 'E', 'B', '9', '9', '7', '0', 'C', '1', '6', '1', 'C', '9', '6', 'A', '4', '2', 'D', 'E', 'A', 'E', 'D', 'A', '5', '5', 'E', 'D', 'E', 'C', 'D', 'D', 'F', '4', '9', '1', '0', '2', '7', '8', '2', 'A', '4', '7', '7', '0', 'C', '4', '6', 'C', 'B', 'A', 'A', 'F', 'B', '6', '9', '4', '9', 'D', '1', '3', '9', 'A', '2', '6', '8', 'D', '9', '2', 'F', 'B', 'F', '6', '1', 'B', '0', 'D', '1', 'F', 'D', '1', '3', '6', 'B', '1', '8', '0', '6', 'D', '0', '3', '6', 'A', '3', 'F', '6', '3', '6', '5', 'D', '7', '2', 'A', '2', 'E', '0', '6', '6', 'D', '4', '4', '6', 'D', '9', '7', '4', '1', 'B', '7', '0', 'E', '9', '7', '7', 'D', '9', 'E', '8', 'A', '9', '4', '8', 'C', 'C', '7', 'C', 'D', '8', '4', '4', 'A', 'E', 'D', '7', '1', '3', '6', 'B', '8', '8', 'D', '5', '2', '8', '0', '8', 'A', '6', '1', '7', '8', '1', '1', 'F', '3', 'D', '9', '3', '0', '8', 'F', '3', '4', '6', 'B', '4', '1', '2', '4', 'B', '9', 'D', 'F', '8', '2', 'D', 'E', 'A', '2', 'D', '2', 'B', '8', '3', 'A', 'D', 'B', '9', '9', 'C', '4', 'E', 'D', '3', '6', '4', '0', '4', '4', '2', '1', '3', '2', '4', '7', '4', 'D', 'D', '9', 'F', 'E', 'A', '3', '7', 'A', 'B', 'B', '3', 'F', '8', '0', 'E', '2', '1', 'D', '6', 'B', 'C', '8', '8', 'D', '8', '0', 'A', 'D', '2', '4', 'D', '9', 'D', '9', '9', '8', '0', 'A', '7', '8', '3', '6', '3', '9', '5', 'A', '4', '5', '4', '3', '0', 'F', '9', '2', '8', 'C', '4', 'E', 'D', 'A', '4', '8', '7', 'B', 'E', 'A', 'F', '1', '1', 'D', '5', '1', '2', '3', 'A', '8', 'C', 'A', '2', 'F', '5', 'D', '9', 'D', '2', '7', '5', 'F', '1', '6', 'B', '6', 'A', '2', '6', 'C', '6', 'E', '9', '3', '2', '4', '5', '6', '3', '0', '9', '2', 'E', '9', '9', 'F', '5', '7', '9', '4', 'C', '9', '4', '1', 'C', '6', '1', '9', '2', 'B', 'C', '4', '8', '5', 'B', '8', '8', 'F', '6', '0', 'E', '8', '2', 'E', '4', '6', '8', 'C', '6', 'D', '6', '5', 'A', '7', '7', 'F', '4', '1', 'A', '9', '8', 'C', '5', '4', '5', 'C', 'C', 'C', 'E', '8', '4', '6', '0', 'E', 'E', '5', 'B', '5', 'C', 'B', '4', 'B', '3', '7', 'A', '5', 'A', '6', 'D', 'D', 'D', '4', '0', 'F', '9', '5', '6', '7', 'D', '7', 'A', '7', 'E', 'D', 'D', '2', 'E', '3', 'E', '4', '8', '5', '5', '0', 'E', 'F', 'D', 'C', 'A', '7', 'A', '6', 'D', 'D', '9', '9', 'A', 'A', '4', '3', '1', 'E', 'C', '1', '5', '9', '2', '3', '6', 'F', '3', '4', '4', 'E', 'D', '5', 'F', '3', '0', '1', 'A', '2', '1', 'D', '5', '5', 'C', 'D', '1', '5', '3', '3', 'C', 'D', '9', '0', '9', '6', '0', '6', 'B', 'E', '0', '9', '5', 'C', '4', 'F', '9', 'F', '8', '8', '1', '5', 'F', 'B', 'C', 'E', 'C', '4', '6', '7', '1', '1', '3', '1', '4', '9', '3', '5', 'E', 'B', 'C', '3', '7', 'C', 'E', '7', '1', 'D', '1', 'C', '6', 'D', '4', '8', '4', 'B', '5', 'F', 'F', '1', '2', 'E', 'E', '0', 'E', '0', '6', '8', 'D', '9', '3', '9', 'C', '7', '0', '1', '8', 'F', '8', 'A', '7', 'F', '0', '2', 'C', '8', 'C', '4', '8', '0', 'C', '7', '1', '3', '6', 'B', '8', '9', '4', '2', '5', 'E', '6', '1', '2', '3', '0', '3', 'A', 'B', 'A', 'D', '6', '4', 'E', 'F', '1', 'D', 'C', '3', '9', 'F', 'C', '4', '0', 'B', 'A', 'D', '1', '2', 'E', '4', '6', '4', '7', '3', '5', '7', '0', '9', '1', '4', '5', '3', 'E', '6', '6', '5', '6', '0', '9', '3', '9', '6', 'D', 'B', 'E', '0', '5', '0', '4', '6', 'E', 'F', 'D', 'C', 'D', '9', 'D', '6', '6', 'B', 'C', '5', '8', 'D', '4', 'B', '7', '5', '0', '2', 'A', 'E', '7', 'D', 'C', '7', '1', 'C', '6', 'B', '2', '9', '9', '1', '5', '8', 'A', '2', '8', '0', '0', 'C', 'E', '2', 'F', '0', 'B', 'D', 'B', '2', 'E', 'E', '0', '1', '5', '3', '9', '5', '1', '7', 'F', '6', 'E', '2', 'F', '2', '2', '8', 'C', 'B', 'C', '0', '0', 'A', '1', '4', 'A', 'D', 'F', '7', '7', 'B', 'D', '9', '4', '7', '7', '9', '1', '4', '9', '3', 'A', '1', '9', 'F', 'D', '5', 'B', '6', '1', '4', '3', '9', '7', '4', '8', 'E', '0', 'B', '1', 'C', '3', '5', '7', 'C', 'C', 'C', '2', '3', 'D', '9', 'C', '1', '7', '6', '3', '9', '2', 'B', 'F', 'D', 'C', 'E', '1', '6', '0', '4', '7', 'B', '0', '1', '4', 'D', 'E', '2', '8', 'B', '5', 'E', 'D', '7', '4', '9', '5', '9', 'B', 'B', '0', 'D', '9', 'A', 'A', '3', '3', 'B', '9', 'D', 'D', '5', '8', '4', '2', '5', 'A', '3', '6', '4', '4', 'E', '9', '8', '5', '8', '9', '6', 'B', '6', '8', '0', '8', '6', 'E', '1', 'E', '4', 'E', '3', '6', '4', '2', 'A', '7', 'C', 'F', 'C', '0', '4', '0', '3', 'C', 'C', 'C', '9', 'E', '7', '5', '2', '9', 'D', '5', 'B', '1', '2', 'C', 'C', '1', '4', '3', '0', '9', '9', '6', '4', '6', '8', '2', '8', '8', '8', '6', '9', 'E', '7', '2', '1', 'B', '3', '5', '1', '0', '1', 'F', '2', 'A', '0', '6', 'B', 'D', 'E', '8', '2', '2', '2', 'E', 'A', '5', 'F', '1', 'A', '1', '9', '4', '1', '9', '9', '8', '6', '2', 'F', '7', '5', '6', 'C', '3', '5', '3', '1', '5', '3', 'B', '7', '1', '8', 'F', '8', '7', 'B', 'F', '1', '8', '1', '6', 'F', '1', '5', '6', 'C', '8', 'E', 'F', '0', '7', 'C', '1', '8', '7', '2', '6', '0', 'A', '0', 'E', 'A', 'B', '2', '8', '4', 'B', '5', 'B', '2', '4', '6', 'D', 'A', '7', '3', '5', 'D', '7', 'B', 'A', 'B', '4', '7', '9', '0', '9', 'D', 'B', '6', '7', '8', '5', '9', '0', '4', '5', 'E', '7', '0', 'C', '9', 'D', '0', '4', '9', 'B', '4', '0', 'B', '6', '2', '3', '9', '1', '5', '3', '1', 'F', '0', '9', 'E', '0', 'B', '8', '4', 'B', 'B', '1', 'B', '9', '1', 'B', '6', '6', '3', '2', 'B', 'D', '9', '7', '9', 'C', '8', '5', 'F', '2', '0', '9', '0', 'C', '0', 'F', '9', '3', 'C', 'B', '6', '5', 'B', '7', 'B', 'E', '1', 'A', '3', 'C', '4', '3', 'E', '0', '5', '2', 'F', 'D', 'E', '9', '9', 'C', 'D', '8', '1', '6', '8', 'E', '0', '0', 'D', '2', '7', 'D', '3', '6', '0', 'A', '4', '4', '9', 'C', '0', 'D', 'C', '9', '5', 'E', '4', '7', '1', '0', 'D', '6', 'B', 'C', '6', 'E', '2', '1', '4', '0', 'E', 'D', '6', '2', 'C', '2', '9', 'A', 'F', 'A', 'D', '1', '2', '4', '7', '7', '4', 'A', 'B', '0', 'D', '9', 'B', '9', 'B', '6', 'A', '1', '8', '1', '1', 'F', '7', 'D', '7', 'C', '1', '8', '2', '7', 'D', 'C', '1', '2', '6', '0', 'C', '1', 'F', '1', 'E', 'E', 'A', '6', '2', 'B', '4', '3', 'E', '4', 'D', '9', 'C', 'E', '7', '3', 'C', '4', '7', '4', '2', '6', '6', '3', 'A', 'E', '1', '9', '5', '4', 'D', '6', '4', '9', '5', '5', '3', '7', '5', 'E', 'B', 'E', 'C', '0', '3', '4', 'E', 'E', '5', 'B', 'F', '8', '7', 'F', '2', 'F', '9', 'F', '3', 'D', '1', '5', 'C', '3', '3', 'F', 'B', '6', '6', '3', '3', '0', '2', '7', 'F', '7', '3', '4', '6', 'B', '0', 'E', '6', 'E', 'E', '7', '0', '9', 'C', '8', '0', 'B', '2', '6', '3', '4', '9', 'F', 'E', '0', '8', '0', '1', '7', '3', '9', '7', '1', 'D', '0', 'A', '6', '1', '4', '9', '9', 'C', '1', '3', 'E', 'A', '4', '3', '6', '5', '5', 'A', '8', 'E', 'E', '1', '8', '1', 'B', '6', 'E', 'B', '2', '1', 'A', '0', '3', '4', '1', '5', '7', '3', 'A', '6', '5', '1', '7', 'E', '0', '7', 'E', '9', '9', 'B', 'B', '8', '0', 'B', '9', '7', '8', '1', '9', '7', 'B', '4', '3', '7', '6', 'A', '4', '9', 'D', '4', 'E', '9', 'A', 'C', 'B', 'C', '0', '5', 'C', 'A', '9', '8', 'B', '7', '0', '9', '4', 'F', '9', 'C', 'B', '4', 'D', '6', '7', '9', '6', '1', 'F', 'E', '2', '2', '8', 'B', '8', 'C', 'E', 'A', '2', '5', '0', 'E', 'B', '5', '3', '6', 'A', '7', '3', '6', 'F', '7', '5', 'D', '6', '2', 'A', '4', '9', '7', '7', '2', '4', 'B', '0', '5', '5', '5', 'F', '8', 'E', '7', '8', '7', '8', '2', '4', 'E', 'D', '8', 'A', '3', 'C', 'A', '2', '9', '0', 'B', '0', '8', 'C', '0', '6', 'F', '6', '9', '0', 'A', '4', '6', '7', 'A', 'C', '4', '8', '9', 'A', '5', '7', '7', 'E', '8', '1', 'A', '7', '0', '9', '0', '1', 'E', '5', 'A', 'B', 'E', '5', '7', 'E', '9', '0', 'A', '6', '5', '9', '4', '5', '1', '9', 'F', 'F', '5', 'A', '3', '6', 'E', 'E', '1', '0', '2', 'E', 'D', '3', '2', '9', 'E', '0', '8', '2', '5', 'C', 'D', '6', '4', 'F', 'C', '9', '4', '5', '0', 'E', '6', '5', 'C', '5', 'A', 'A', '1', '6', '8', '8', '8', '3', 'D', '8', '2', 'A', '4', 'E', 'B', 'B', '6', '2', '1', 'D', 'D', '9', 'C', '3', 'E', 'E', '9', '3', '2', 'D', 'B', '7', 'B', '3', '5', '7', 'D', 'A', 'A', 'B', 'C', '7', '9', '5', '2', '6', '4', '3', '3', '6', '2', '9', 'B', '8', 'B', '7', '7', '3', '5', 'F', '1', 'A', 'D', '0', '4', '0', '3', 'D', 'F', '0', '6', 'B', '1', 'C', '4', 'A', '8', 'D', '3', '4', '0', 'B', '4', '2', '1', 'E', '0', '0', 'E', '6', '7', 'C', '4', '7', '3', 'C', 'F', '0', '7', 'B', '2', '6', '5', '0', 'C', '7', 'B', 'A', '0', '4', 'C', '9', 'C', 'D', '1', '0', '3', '6', '2', 'E', '5', '5', 'B', '7', '6', 'E', '8', '5', '4', 'D', '3', '1', '3', '0', '8', 'F', 'B', 'C', 'C', '7', '9', 'C', '2', '8', '6', 'C', '9', 'B', '4', 'A', '2', '7', '5', 'B', '4', '8', 'A', 'B', '6', '1', 'F', '7', 'D', '8', 'F', 'B', '7', '9', '6', '8', '0', '8', '7', '8', '9', 'C', 'E', '1', 'A', '9', 'D', '8', '6', '8', '3', '4', '9', 'E', '6', '7', '0', 'B', '6', 'C', '5', 'E', 'E', '1', '7', '1', '9', '8', 'A', '1', 'F', '3', 'E', '9', 'A', 'A', '0', '6', '7', 'F', 'B', '9', 'B', '4', 'C', '6', 'B', 'F', '3', 'F', 'C', '6', '7', 'D', '5', 'F', 'E', '5', '8', 'C', '3', 'B', '5', 'B', 'A', '4', 'F', 'F', '9', 'F', 'A', 'B', 'B', 'E', 'E', '7', '3', 'D', 'B', '1', 'F', 'B', '6', 'A', '3', '6', '8', '3', '0', 'A', 'F', 'B', '1', '8', 'F', '0', '4', '4', 'E', 'D', '9', 'F', 'C', '9', 'E', 'C', '4', 'D', 'B', 'B', '8', '4', '1', '3', '0', 'E', '6', 'A', '3', '0', '6', 'E', '5', 'D', 'A', '6', '0', 'F', '0', '6', '7', '3', '0', 'B', 'B', '2', '4', 'C', 'B', '4', 'D', '0', '1', '9', '7', '9', '4', '7', '5', '1', '3', 'A', '8', '0', '1', '9', '2', 'C', '7', 'C', 'C', '0', '6', '8', '6', 'D', '0', 'D', '6', '0', '5', 'F', '9', 'E', '5', '7', '1', '6', '2', '9', '3', '9', '3', '2', 'D', '9', '9', '9', '2', 'E', '9', 'A', '9', 'A', '7', 'F', 'D', 'C', 'E', '1', '4', '4', '3', '8', '1', 'D', 'C', '1', '2', 'F', 'F', '7', '4', '2', '7', 'B', '6', '4', 'D', '8', 'E', '7', 'C', 'C', '0', '1', '5', '6', '6', '8', 'E', 'B', '3', 'A', 'B', '8', '1', '2', '7', '5', 'F', '0', 'A', 'A', '0', '6', 'F', '1', '2', '5', 'B', '4', '5', '1', 'B', 'E', '2', '0', '5', '2', '2', 'C', '2', '6', '1', 'F', 'C', 'D', '4', '1', '8', '5', 'E', '0', '5', 'A', '7', '0', 'F', '6', '6', '1', 'F', 'D', '4', 'B', '7', 'F', '5', '3', '1', '6', '7', '4', '5', 'D', '6', 'C', '1', '6', '2', 'E', '4', 'A', '5', 'D', '4', '3', '5', 'D', 'B', '1', 'F', 'D', '0', 'F', '5', '2', 'F', 'C', '2', '6', '0', '3', '2', '6', '3', 'A', '2', 'D', 'D', '8', '2', 'C', '2', 'A', '9', '9', '7', '7', 'D', 'C', '9', 'A', 'B', '1', 'B', '2', '7', '9', 'C', '3', '0', '3', '5', 'E', 'E', '2', '5', 'E', '3', 'E', '7', '5', 'A', 'E', '2', '0', '0', '7', 'D', '3', 'A', '9', '6', '3', '9', '5', '0', '9', '6', 'E', 'E', '8', '1', '2', 'B', '2', '5', '0', '7', 'E', 'F', 'C', '6', '3', 'A', '2', '2', '3', 'D', '1', '2', '6', 'F', '8', '4', '8', 'D', 'D', '4', '8', '3', '8', '7', '0', '2', 'B', '9', '1', '8', 'C', 'B', '8', '8', '8', 'E', '5', 'C', '0', '0', 'C', '6', '1', '4', '4', 'A', '4', '4', 'E', '9', '5', '2', '7', '6', '4', '0', 'B', '8', '6', '9', 'A', '6', '4', '5', '9', 'F', 'C', '4', '3', '0', '8', '9', '8', 'D', 'F', 'B', '6', '8', '2', 'C', '2', 'B', '3', '6', '9', '8', 'E', '7', 'C', '2', 'A', '8', 'F', '1', '5', 'A', 'C', 'D', 'D', '7', '1', '8', '0', 'C', 'D', 'A', 'C', 'E', '4', '7', 'A', '9', 'F', '5', '3', 'F', 'F', '4', '6', 'B', 'D', '2', 'D', 'D', '3', '8', '6', '4', 'F', '3', '3', '5', '7', '1', 'B', '4', '6', '6', '0', 'F', '1', 'E', '9', '5', '5', '7', '0', '4', '3', 'E', 'D', 'B', '3', '5', '8', '9', 'B', '4', '8', '6', '0', '1', '2', '1', '6', 'D', '6', '8', 'D', '0', '0', '3', '6', 'E', 'C', '1', '4', 'F', '2', '3', '7', '3', '2', '6', '2', '2', '3', '6', '7', '7', '5', '5', 'F', 'E', '2', '6', '3', '2', '3', 'E', '8', '3', '9', 'E', 'A', '4', 'A', 'C', 'D', '4', '8', '9', '7', '1', '9', '5', 'E', '8', '0', '2', '5', 'D', '4', '8', '5', 'D', '9', '4', 'B', '0', '9', '9', 'E', 'F', '4', '3', '3', 'A', '8', 'A', '0', '8', '8', 'B', '5', '6', '9', '1', 'D', '7', 'F', '4', '8', 'D', '5', '7', '3', '5', '2', '7', 'D', '0', 'B', '7', 'A', 'F', 'B', 'D', '7', '2', '4', 'F', '8', '5', '3', 'D', '1', 'D', 'C', '6', '2', '7', 'D', 'F', '7', 'B', '5', 'B', '2', 'D', '8', '5', '3', 'D', 'A', 'D', '0', '2', '6', '0', 'A', '6', '2', 'E', 'C', '2', '9', '7', 'C', 'B', '3', 'D', 'B', 'C', '8', '2', 'F', 'C', '8', '1', 'B', '7', 'D', 'A', '8', '5', '5', '5', '6', '6', '2', '9', '8', 'C', 'E', '1', '0', '4', 'F', '7', '7', 'F', '0', '6', '8', 'A', 'A', '6', '9', 'A', 'B', '2', '4', '7', '5', '6', '3', '5', '1', '3', 'C', '9', '3', 'D', '7', '5', '3', '5', '3', '4', '7', '2', '3', 'A', '6', '8', '2', '5', '8', '8', 'A', 'D', '5', 'E', '4', 'B', '1', '5', 'F', '2', 'F', '8', 'E', 'B', '0', '8', '1', '7', '9', 'F', '9', '2', 'E', '0', 'F', 'E', '0', 'B', 'B', '7', 'F', 'F', '8', 'A', '8', '8', 'C', '9', '4', 'D', '8', '5', '9', '2', 'E', 'C', 'C', '8', '7', 'E', '5', '5', '8', '7', '6', 'D', 'D', '4', '6', '9', '1', '9', '5', 'D', '2', 'F', '8', 'D', '8', '4', '7', '7', '1', 'E', 'A', '2', 'B', '3', '3', '8', '2', 'F', '5', 'C', '2', 'C', 'D', '6', '9', '6', '4', '9', '5', 'E', 'E', '3', '7', '1', '4', 'D', '9', '6', '4', 'B', 'E', '2', 'D', 'C', 'C', '7', '8', 'C', '9', '5', 'F', 'B', 'D', '1', 'C', 'B', 'F', '1', '2', '2', '0', '1', 'F', 'A', '6', '9', '4', '9', '7', '7', '8', 'B', 'C', 'A', '0', '3', 'A', 'A', 'C', '2', 'C', '1', '5', '5', '2', '3', '0', 'F', '7', 'E', '0', '9', '6', '1', 'F', 'E', 'C', '2', '9', '2', '3', 'A', 'C', '0', '3', 'E', 'F', '4', '6', '4', '6', '6', '9', '8', '0', '3', 'C', '7', 'C', '2', '2', '4', 'B', 'E', '1', '4', '0', '9', '1', 'D', '8', '1', '4', '5', 'B', '4', '3', '7', '8', '1', '9', 'A', 'C', '0', '9', '3', '2', 'F', '9', '8', 'A', 'C', '6', 'F', 'B', 'B', 'E', '7', 'F', 'B', 'B', '0', '0', '5', '2', '0', '2', '6', 'A', 'E', '5', '2', '5', 'A', 'F', 'C', '4', 'E', 'B', 'E', '1', '7', '6', '5', 'D', 'D', 'A', '1', 'B', '6', '2', '6', '1', 'A', 'A', '7', '3', '4', '7', '8', '5', '2', 'A', 'D', '9', 'D', '2', 'D', 'F', '4', 'F', '3', '5', '8', 'E', '0', '7', 'E', 'D', '7', '7', '2', 'F', '9', '9', '8', '3', 'A', '5', '4', '8', 'C', '0', '4', 'B', '9', 'E', '1', '3', '3', 'B', '0', 'B', 'B', 'A', '2', '5', '7', 'F', '9', '5', '0', '1', 'D', '6', '9', '6', '3', 'F', '7', 'D', '9', 'E', '9', 'E', '4', 'A', 'B', 'F', '3', 'B', 'E', 'D', '1', '2', '5', '5', '7', '7', 'B', 'C', '5', 'B', '7', '6', '0', 'F', 'E', 'E', '1', '0', 'D', '0', 'A', '0', '8', '6', '9', 'C', 'F', 'A', 'B', '5', '5', 'B', 'A', 'E', '6', 'C', '3', 'B', '8', '6', 'C', '0', '4', 'A', '8', '5', 'A', '1', '9', '9', 'C', '5', '1', '1', '0', 'C', 'C', '6', 'B', '5', '4', 'C', '7', '2', '9', '4', '7', '6', 'E', '0', '0', '9', '8', '1', '2', '7', 'F', 'D', '4', '4', '2', '4', '5', '0', '5', '1', 'C', 'E', '0', 'B', 'A', '5', '5', 'C', '2', 'F', 'D', '8', '5', 'D', '0', '5', 'C', 'F', 'E', 'A', '6', 'E', 'A', '9', '5', 'C', 'F', '2', '4', '7', '1', '5', 'D', '7', 'D', '6', 'D', '6', '8', '2', 'D', '9', '5', '1', 'A', '4', 'B', 'F', '2', 'A', '1', '1', '6', '8', 'D', '2', '9', 'B', 'E', '5', '1', 'B', 'E', '7', '4', '1', '9', '4', '0', 'B', '9', 'E', '0', '4', '9', '9', 'F', '0', '4', '6', '4', 'F', '4', '1', 'D', '5', 'B', '7', 'A', 'F', '4', '5', '4', '4', '7', '6', '5', 'A', '9', '9', 'B', 'A', '0', 'B', '8', '3', '2', '0', 'A', 'E', '6', 'A', 'E', '0', 'F', 'B', '3', '0', '6', '8', '6', '2', '2', 'E', '2', '6', 'B', '9', '2', 'C', '0', '7', '9', '5', '9', '5', '2', '6', '3', 'C', 'C', 'F', '1', 'C', '1', '6', '2', '8', '7', '1', 'F', '9', '0', 'E', '5', '9', 'A', 'C', '7', 'B', '5', '7', '7', '3', '4', 'D', 'E', 'A', 'D', 'A', 'B', '6', '3', '2', 'F', 'C', '2', '0', '3', 'F', 'A', 'E', 'D', 'D', '5', '6', '7', '8', '0', '8', '5', '8', '3', '9', '4', 'B', 'B', 'A', '1', '2', '5', '9', '8', '3', '7', '4', 'E', '0', 'F', '6', '8', 'A', '2', '6', '0', 'E', 'D', 'D', '4', '1', '3', '8', 'C', '5', 'F', '0', '2', '7', '8', 'A', '0', '7', 'C', '6', '3', 'A', '5', '0', '4', '9', 'F', '0', '3', '3', '7', 'E', 'F', 'A', '6', '1', '4', '5', '4', '7', '2', '3', '0', 'A', '2', '7', '1', '7', '3', '4', '2', 'F', '6', '7', '7', '0', '7', '4', '5', 'E', '5', '8', 'C', '3', '9', '9', '1', '3', '0', '6', '8', 'F', '6', '9', '5', '1', '0', '1', '2', 'E', '9', 'E', 'A', '6', 'D', '1', 'B', '5', '5', '9', '5', 'F', 'B', '3', '6', '2', 'B', '9', '7', 'D', 'E', 'A', 'B', 'E', '8', 'F', 'A', '7', '7', '7', '8', 'E', '5', '7', 'B', '4', 'D', '6', 'F', 'A', 'C', '1', '6', '5', '5', '0', '8', 'F', 'C', '9', '0', '5', '7', '0', 'E', '2', 'F', '7', '1', 'A', '2', 'B', '9', 'A', 'A', '7', '8', 'E', '4', 'A', '2', '0', '4', '3', '9', '3', '8', 'C', 'F', '7', '9', 'D', 'A', '6', 'F', '4', '2', 'D', '4', '3', 'D', '8', 'D', '1', '3', '1', 'B', '4', '4', '6', 'F', '2', '8', '7', 'A', '5', 'B', '0', '7', '0', 'E', 'F', 'D', 'C', 'D', 'B', '2', '5', '2', 'D', '8', '6', '9', '3', '0', '6', '4', '6', '3', 'B', '3', 'B', '7', '5', '8', '7', '9', '0', '8', 'C', '9', '3', '7', '8', '2', '9', '2', '9', 'F', '5', '9', 'C', 'B', 'F', '5', 'C', 'C', '3', '8', '1', 'E', 'C', '5', '9', '0', 'C', '8', '8', '7', '6', '8', 'E', '8', '2', 'F', '8', 'D', 'F', 'F', 'B', 'D', '5', '4', '8', '1', '1', '9', '5', '8', 'A', '5', '6', '7', '2', '3', 'E', '6', 'A', '7', '6', 'C', '4', 'F', 'E', '9', '4', '4', '4', 'B', '0', 'E', '2', '2', '8', 'E', 'F', '8', '8', '3', '3', '8', 'A', 'F', '1', 'A', 'C', 'C', 'B', 'B', 'C', '9', '5', '6', 'D', '4', 'B', '5', '9', '4', '0', '0', '7', '6', 'C', 'F', '7', 'E', '3', 'D', '7', 'A', '0', '1', '9', '2', 'F', '4', '0', 'C', '3', '6', '2', 'F', 'F', 'C', '9', '2', '1', '1', 'C', '7', 'F', '9', 'B', 'A', '8', '6', 'D', '3', '0', '7', '6', '9', '2', '4', '9', 'E', '7', 'B', '7', 'C', '5', 'D', '7', '9', '1', '6', 'C', 'B', 'B', 'C', '2', '7', '4', '0', 'E', '0', '5', '6', '4', '6', 'A', '7', '3', '5', '3', '7', '4', '8', '6', '6', '7', 'A', '7', '6', '8', '1', 'A', '7', '4', 'B', '4', 'E', '9', 'B', '0', '0', 'B', '6', '8', 'A', 'F', '0', 'E', 'F', 'F', '7', '8', 'B', '2', '6', 'A', 'B', '3', '8', 'A', 'A', '2', '2', '4', '3', 'C', '6', 'B', '8', '6', 'E', 'F', '0', '4', '1', 'A', '9', '9', 'C', 'A', 'C', '0', '5', 'C', 'E', '0', 'F', '2', '8', 'E', '4', '7', 'B', 'D', '6', '0', 'B', '8', '2', 'C', '9', 'D', 'A', 'A', '1', '3', 'F', 'B', 'A', '5', '6', '4', 'B', 'D', '4', 'B', '1', '1', 'D', 'E', '5', '4', 'B', '5', '3', 'B', '9', '0', '3', '1', 'A', '8', '5', '5', 'D', '5', '9', '4', 'F', 'B', 'A', '2', '0', '0', '1', '7', 'F', 'F', 'F', 'C', 'B', '6', 'E', '2', 'A', '5', '9', 'C', '4', 'D', '8', '5', 'E', 'C', 'F', 'F', 'D', 'E', '1', '6', '3', '4', '4', 'A', '2', 'A', 'C', '3', '0', '5', 'F', '3', '9', 'F', '0', 'D', 'A', '0', 'F', 'E', '5', 'C', '9', '9', '1', '8', '3', 'E', '8', 'C', '7', '2', '7', '8', 'F', '8', '2', 'A', '9', '1', '3', '3', 'A', '0', '4', '8', 'B', '0', 'A', '3', 'E', 'B', '6', 'B', 'E', '2', 'B', '2', 'F', '3', '0', '1', 'D', 'C', 'C', '1', 'E', '1', '9', '0', 'A', '6', '4', '9', '3', 'F', 'B', '2', '3', '2', '8', '7', '8', 'A', 'A', '7', '7', 'F', 'B', '5', '4', '9', '4', 'F', '2', '6', 'D', '1', '2', '2', '2', 'C', 'F', '1', '0', '6', 'A', '2', 'B', 'D', 'F', 'A', 'D', 'A', 'C', '6', 'C', '2', '9', 'A', 'B', 'E', '7', 'E', '6', '2', 'B', '4', '0', '9', 'D', '6', '3', '8', '6', 'C', '4', 'F', 'B', '8', '7', 'B', '5', '1', '5', '2', 'C', '2', 'F', '3', '8', 'C', '6', '7', '7', '9', '0', 'D', '1', 'A', 'A', 'A', 'E', 'B', '6', 'B', 'C', '8', 'B', 'C', '8', 'F', '4', '5', '2', 'C', '5', '2', 'D', 'E', '9', '1', '2', '1', '1', '2', '3', '7', '3', 'D', '0', 'C', '4', '0', 'A', '8', 'D', '7', 'E', '5', '3', '8', '4', '7', 'A', '9', '7', 'D', 'C', 'F', 'F', '2', '1', '5', 'A', '5', '2', 'B', '7', '0', 'A', 'B', '7', 'D', '9', '9', '5', 'E', 'C', '0', '1', '0', '5', '8', 'A', '8', 'F', 'B', 'C', '8', 'D', '3', 'D', 'D', 'B', '8', '7', '4', 'A', '3', 'E', '8', 'E', 'D', '6', '2', '4', 'F', 'B', '9', 'E', 'A', 'B', 'E', '3', 'F', '3', '7', '7', '0', 'A', '8', '9', '0', 'B', 'C', '8', '1', 'D', '9', '7', '5', '0', '7', '9', '2', '4', '3', 'E', '3', '4', '1', '9', '5', 'C', '5', '2', '6', 'A', '4', '2', '2', 'D', '8', 'A', '6', 'B', 'A', 'E', '7', 'B', 'D', '3', '4', 'F', '5', 'C', 'A', '7', '2', 'E', '4', 'C', '4', 'F', 'E', '8', '7', '4', 'C', '2', '9', '5', '5', 'A', '4', 'B', '9', 'F', 'A', 'B', 'C', 'D', 'F', 'D', '9', '3', '0', '9', 'F', 'F', 'A', '7', 'A', '1', '1', '8', '6', 'B', 'D', '7', '5', 'F', '8', '6', 'B', 'B', 'D', '8', '0', 'F', 'F', 'D', '3', '1', '2', '6', '6', '9', 'E', '2', 'C', 'A', '2', '7', '7', 'F', 'E', '6', '1', 'B', '0', 'E', '0', 'E', '5', 'E', '7', '9', '9', 'B', 'E', '0', 'F', '4', 'E', '0', '5', 'A', '5', 'F', 'B', 'A', '8', '8', 'D', '5', '7', '2', '8', '4', '2', 'F', 'F', '1', 'B', '6', '9', 'C', '0', 'D', '0', 'C', '1', '1', 'B', '0', 'E', '2', 'D', '9', 'B', '4', '6', 'C', '7', 'C', 'D', '7', '7', '1', '2', '8', '4', 'F', '6', 'C', 'D', 'E', 'D', 'A', '7', '1', 'B', 'C', '0', '2', 'A', '2', '9', '7', '0', '7', '8', '6', '1', 'D', 'B', 'E', 'C', 'D', '4', '5', 'E', '9', 'E', 'D', '8', '9', '3', '2', '3', 'E', 'F', 'D', '4', 'B', '8', 'B', '8', 'C', '7', 'B', 'A', 'C', '2', '7', '0', '3', 'E', '8', '5', '4', 'B', '1', 'D', '6', '8', 'D', 'C', '1', '1', '6', '7', 'E', '9', '6', '3', '4', '3', 'D', 'A', 'C', 'C', '3', '6', '7', 'E', '4', 'F', 'B', 'F', 'D', '1', 'D', '9', 'C', 'D', '6', '6', '9', '4', '6', '7', 'A', '0', '5', 'F', '7', '4', '5', '4', 'C', '6', '6', 'E', '7', '3', '7', '1', '6', 'A', '3', 'E', 'F', 'E', 'E', '2', '2', 'D', 'E', '6', '1', '8', '8', '2', 'B', '0', 'E', '8', 'F', '8', 'F', '8', 'A', 'F', 'D', '5', '6', '5', '5', '0', '4', '4', 'D', '9', 'A', 'D', '0', '9', 'F', 'D', 'A', 'E', 'A', 'E', 'B', 'B', '2', 'F', 'D', '5', '0', '0', '2', 'C', '3', '7', '6', 'F', '7', '0', '0', 'E', '7', '7', '8', 'C', '5', '1', '5', '7', '7', '6', '1', 'B', '0', '6', '2', 'F', '7', '5', '6', '2', '0', 'E', '1', '0', '1', 'E', '7', '0', '8', 'E', '0', '7', '2', 'C', '9', 'C', '7', '2', 'C', 'E', '8', '5', '8', 'E', '2', 'C', '5', 'E', '0', 'C', '6', '7', 'C', '2', '7', '1', 'C', '0', '0', 'B', '8', 'F', '9', '5', 'A', 'F', '0', 'A', '6', 'D', 'F', '1', 'D', 'E', 'C', '0', 'A', '1', '8', 'A', '1', '7', '3', '7', 'E', 'F', 'E', '4', '1', '6', '9', '4', 'C', 'D', '6', '6', 'E', 'E', '1', '8', '1', 'A', 'B', '5', '2', 'B', 'B', '6', 'E', '7', 'C', '6', '0', '7', '3', '0', '5', '1', 'F', '2', 'C', 'A', '7', 'E', 'D', 'A', 'D', '5', '6', '8', '1', '0', 'F', '9', '6', '7', 'B', '8', 'D', 'C', 'E', 'D', '3', '8', 'F', '1', 'A', '0', '4', 'C', '9', 'B', '6', '1', 'D', '6', '4', 'E', '4', '7', '2', 'F', '2', 'E', 'F', 'A', '4', 'B', '1', 'C', '8', 'D', '8', '6', '6', '7', 'D', 'A', '6', '6', '4', 'A', '8', 'C', 'D', 'A', '7', 'B', 'F', '2', 'A', 'C', '2', '4', 'B', 'E', 'A', '0', '6', '6', '7', 'E', '5', '2', 'F', 'A', '6', '1', 'E', '2', '5', '3', '4', '1', '8', '1', '2', 'E', '0', '7', 'D', 'C', '3', '8', 'E', '7', '1', '1', '8', 'B', '4', 'C', 'E', '1', 'B', 'F', '3', '6', '5', '6', 'B', '6', 'F', 'F', 'F', '1', 'A', '0', 'C', '6', 'C', '1', 'A', 'B', '3', '8', 'F', '0', '8', 'E', '2', '0', '7', '9', '0', 'B', '1', '6', '7', '7', '9', '1', '2', '0', 'B', '0', 'C', '7', '7', '8', 'A', 'E', '6', '0', '1', 'D', '7', 'D', 'C', '2', '3', '6', '7', '0', '7', 'C', '3', '1', 'B', '7', '4', '0', '0', 'C', 'F', '4', '9', 'B', '1', '0', '9', '8', 'C', '2', 'B', '6', '8', '2', 'A', 'F', 'F', 'A', '8', '3', 'D', '8', '2', '9', 'C', '9', 'A', '0', 'D', 'B', '7', '4', '5', '2', 'D', '0', 'B', '2', 'D', '7', '2', '5', '7', '1', '0', '9', '8', 'D', '8', 'F', 'C', '1', '3', 'E', 'C', 'A', '0', 'B', 'B', '8', '5', 'E', 'C', '0', '9', '0', '7', 'D', 'C', '0', 'F', '9', '2', 'A', '9', 'B', 'E', '8', 'C', '7', '9', 'A', 'D', 'B', 'D', '4', '0', '8', '0', '9', '7', '7', '8', '2', 'B', '9', '4', '9', '5', 'B', 'B', '6', 'F', '3', '2', '9', 'D', '2', 'D', '6', '4', 'D', '9', '1', '9', '5', '4', '7', '8', '0', '0', 'E', '3', 'B', 'D', '5', 'E', '3', '7', '3', '9', 'C', '3', '1', '3', '6', '9', 'F', 'F', 'C', 'A', '8', 'E', 'D', 'F', '7', '4', 'F', '3', '7', '1', 'F', 'E', 'E', '7', 'C', '7', '8', '7', '6', 'A', '3', 'B', '4', '2', 'F', '6', '1', '3', '0', '5', 'A', '3', '2', '3', 'C', '9', '0', '7', '9', '8', 'C', '5', '9', '4', '3', 'D', 'D', 'B', '3', 'D', 'F', '2', 'B', '5', '3', 'B', '6', '5', '8', '0', '2', '8', '8', '5', '5', '8', 'B', 'E', 'E', 'B', 'D', '4', '8', '5', 'B', '0', 'A', '6', 'A', 'A', '0', 'C', '9', '1', '5', '7', 'A', 'A', '3', 'D', 'C', '3', 'C', '7', '8', '7', 'E', '5', 'C', 'C', '2', '7', 'E', '7', '7', '3', 'E', 'A', 'E', '4', 'B', 'A', '9', '4', '0', 'F', 'B', '4', '4', 'E', '3', '0', '6', 'E', '8', 'D', '4', 'D', 'B', '7', '0', 'A', '3', '9', 'C', 'C', 'F', '0', 'B', '9', 'D', '7', 'B', 'C', '8', 'E', 'B', '0', 'E', 'F', '1', '0', 'E', 'A', '9', '8', 'D', 'E', '8', '5', '5', 'B', '6', 'C', '8', 'E', '4', '7', 'F', '3', '3', '3', 'D', '9', 'C', '6', '3', '8', '4', 'D', '3', 'E', '5', '5', '3', '8', '0', '4', '0', '6', 'F', '9', 'E', '7', '4', '1', 'B', '7', '7', '4', 'B', '1', '6', '2', 'F', '7', '5', 'D', '2', '7', '3', '7', '0', 'B', '6', '9', '2', '7', 'F', '7', '8', '3', 'F', '6', '7', '8', 'A', 'A', 'B', 'B', '7', 'A', '3', '3', '5', 'C', '8', 'E', '1', '2', '8', 'C', 'F', '0', '3', 'F', '3', 'A', '6', '2', 'F', 'E', 'D', 'E', 'D', '9', '4', '8', '6', '7', 'D', 'F', 'F', '2', '2', 'B', '2', '9', '4', 'A', '7', '8', 'D', 'E', '4', 'B', '3', '0', '5', '8', '3', '2', 'E', 'F', '9', 'B', '5', '7', '1', 'C', 'B', 'E', 'E', '7', 'D', '2', '0', 'E', '4', '3', '1', '4', '6', '7', 'A', '2', 'C', 'B', 'D', 'E', '5', '8', 'F', '6', 'C', 'E', 'E', 'F', 'E', 'F', 'A', 'B', 'A', '9', '0', '2', 'B', '8', '3', 'D', '7', '1', 'F', 'F', 'E', '4', 'D', '8', 'D', 'C', '1', '7', 'B', 'D', '6', 'C', '3', '6', '9', 'C', '8', 'C', 'C', 'C', '5', '5', 'D', '6', '3', '4', '6', '3', '5', '5', 'A', 'F', '7', 'E', 'B', 'E', '0', '9', '8', '7', 'B', 'F', 'B', '2', '3', '9', '0', 'C', '5', 'D', '9', 'A', '8', '1', '7', '3', '3', 'B', 'A', '4', '3', '5', '3', 'A', '8', 'F', '5', '1', '4', '8', '4', 'E', 'C', 'B', 'D', '8', '4', '3', 'F', 'A', 'A', '1', '4', 'B', '0', '1', 'F', '5', '7', '4', 'A', 'F', '2', 'B', 'C', 'D', 'D', 'C', '3', 'C', '4', 'B', '3', '8', '2', '1', '8', 'B', 'A', 'B', 'A', '9', '5', 'D', '2', '4', '8', '0', '4', '0', '4', 'F', '2', '6', '8', 'F', '3', '1', '4', '8', '0', '0', '1', 'C', '5', '1', '6', 'D', '3', '0', 'E', 'E', 'D', 'E', 'F', '6', 'F', '6', '1', '9', 'A', 'F', '2', '5', '6', 'F', 'E', '1', '4', '5', '5', 'C', '2', '6', '2', 'F', 'D', '7', 'B', '5', '8', '1', '0', '1', '7', '6', '6', 'E', '6', '4', 'F', 'B', 'E', 'A', 'F', '6', '0', '1', '5', '4', '9', '6', 'F', '2', 'B', '7', '7', 'B', '5', '9', '0', 'D', 'A', '5', '6', '7', '4', '4', 'E', '7', 'B', '2', '0', '5', '9', '5', '3', 'C', 'D', 'C', '6', 'E', 'D', 'E', 'D', '8', '6', 'C', '0', 'F', 'B', 'E', 'D', 'D', '7', 'C', '5', '0', '9', 'B', '6', 'E', '5', '1', 'E', '3', 'B', 'B', '3', '8', '1', 'B', '4', '8', 'E', '0', 'A', '9', '9', '4', '2', '3', 'B', '1', '4', '4', '2', 'A', 'B', 'E', 'C', 'C', '2', '5', '5', 'E', 'F', '3', '6', 'C', 'F', '3', '7', '8', '0', 'A', '5', 'F', '9', '6', '4', '8', 'C', '1', 'F', '6', 'D', '8', 'E', '1', 'C', 'E', '3', 'A', '0', 'E', '8', '8', '4', 'B', '0', '5', '5', 'C', 'B', '8', '9', '7', 'E', '0', '2', 'F', '3', '3', '3', '9', 'E', 'B', 'F', '6', '3', '2', 'B', '0', '5', '0', 'E', '2', '1', '9', '9', '3', 'D', '1', 'A', 'F', 'F', '9', '6', 'D', 'A', '6', '7', '4', 'D', '1', '1', 'E', 'F', 'A', 'B', '9', '9', 'A', 'B', '2', '1', 'B', '2', 'E', '7', '3', 'B', '8', '8', '1', '3', 'C', '2', '6', 'E', '1', 'A', '8', 'F', '7', 'B', '8', '4', '4', 'F', '3', 'D', '8', '7', 'C', '4', '1', '7', 'D', '3', 'A', '8', 'D', '1', '5', 'E', '4', '9', 'A', '8', '2', '2', '0', 'E', '5', '8', '1', 'F', 'C', 'F', '5', '5', 'D', '2', '3', 'B', 'D', 'B', 'B', 'C', '5', '2', 'B', '9', '6', '9', 'D', '9', '9', '8', '4', '4', 'C', 'E', '5', '6', '2', '1', '5', 'C', '0', 'A', 'B', '4', 'E', '0', '4', '7', '0', 'B', '8', 'E', 'F', 'B', '8', '2', '2', '1', 'C', 'A', 'E', 'C', '7', '7', '5', 'F', '0', 'F', 'B', '0', 'E', '2', '2', '6', 'E', '6', '6', '9', '8', '0', 'C', 'C', '1', '2', '5', 'C', 'A', '4', '8', '3', '2', '1', '0', '7', '8', '2', '3', '6', '2', 'D', 'D', '1', '1', '7', '7', 'B', '7', 'B', '2', '5', '0', 'C', 'D', 'E', 'B', '7', 'D', '6', 'D', '0', 'E', 'C', '6', '4', '7', 'B', 'E', '1', 'B', 'D', '1', '2', '1', '4', '5', '1', '5', 'E', '6', 'E', 'C', '7', '1', 'D', 'D', '5', 'D', '8', '1', 'B', '9', '6', '6', '7', '6', '3', 'C', '6', '1', 'C', '1', '9', 'F', 'E', '4', '3', '8', '5', 'C', '5', 'B', '4', '6', '1', 'C', '9', '7', '2', '4', '6', '9', 'D', 'B', '4', '9', 'F', '2', '0', 'A', 'A', '0', '5', '5', '6', '0', 'F', 'A', 'B', '4', '8', '1', '8', '0', '4', '2', 'D', 'D', 'F', '9', 'C', '4', '7', 'E', '9', '8', '8', 'F', '6', '0', '6', '2', '2', 'C', '1', '6', '5', '9', 'F', 'E', 'F', '2', 'E', '5', '5', '2', 'C', '8', 'F', '4', '8', '6', '6', 'C', '2', '5', 'D', 'F', '9', 'B', '9', 'F', '3', '2', '0', '6', '5', '3', '1', '3', 'D', 'E', '3', 'B', 'A', '0', '4', '8', 'D', 'C', '4', 'D', '9', '1', 'F', '0', '4', '7', '6', 'E', 'F', '0', '4', 'C', 'C', '8', '3', '3', '6', 'C', '6', '3', '1', 'D', '4', 'C', '1', '1', '8', '0', '1', 'F', '5', 'C', '7', 'F', '9', '1', 'B', 'B', 'B', 'F', '1', 'C', '6', '0', '2', '5', '4', '2', 'C', '8', 'C', 'E', 'C', '6', '0', '3', 'E', 'A', '8', 'C', '6', '4', '1', '2', 'D', 'A', 'A', '1', '8', 'D', 'F', '0', 'B', '9', 'A', '8', 'C', '0', 'A', '0', 'B', '5', 'A', 'D', '9', '9', '1', '0', '7', '6', 'A', '8', '5', '9', 'F', '0', '0', 'F', '9', 'A', '2', '4', '0', '5', 'A', 'A', '7', '8', '5', '6', 'E', '1', '5', '0', 'E', '3', 'A', '6', '1', '6', '7', 'A', '2', 'E', 'D', 'D', 'A', '0', '0', '7', '2', '8', '3', 'C', '1', '9', '3', '6', '5', '6', 'D', '7', '3', '4', '6', '7', '4', '9', '0', '9', '6', '3', '4', 'A', '7', 'C', '1', '7', '8', 'A', '1', 'D', 'A', '4', '4', '0', 'A', '6', 'D', 'E', 'F', '7', 'D', '2', '3', '3', 'D', '5', 'C', '7', '9', '3', '9', 'C', '3', '0', 'F', '7', '5', '6', 'C', 'B', '5', '1', '2', 'B', '4', '5', '7', '2', '1', 'A', 'B', '9', '3', '3', 'D', '1', 'F', '6', 'E', 'C', 'D', 'E', '2', '7', '0', 'B', '4', 'D', '9', '2', '4', 'C', '0', '9', '9', 'A', 'D', '9', 'B', '0', '6', 'A', 'F', 'B', 'D', '9', 'B', 'D', '7', 'C', 'A', '4', 'B', '7', '1', 'C', '2', '5', '1', '7', 'F', '6', '0', '1', '5', 'E', '5', '0', '9', '7', 'A', '8', '5', 'E', 'A', '5', 'C', 'C', '2', '4', '0', '8', 'F', '3', '3', 'A', '1', '5', 'D', '3', 'F', 'C', 'E', '2', '7', 'D', 'C', 'C', '8', '2', '1', '3', '1', '7', '6', '9', '6', '4', '2', '4', '9', '1', '6', 'D', '4', '5', '4', '1', '2', '3', 'F', 'E', '2', 'F', 'E', '9', 'A', '5', '9', '0', 'A', '6', 'C', '1', '6', 'F', 'D', '8', 'C', '2', 'C', '7', 'A', '0', '8', 'D', '6', '0', 'C', '5', '7', '1', '0', 'B', '2', 'E', '2', 'B', '2', '1', '2', '2', '5', '7', '7', 'B', '4', 'C', '9', '5', 'D', '6', '4', 'E', 'E', '0', 'F', 'C', '2', '2', '8', '2', 'D', 'B', 'A', '7', 'C', 'A', 'C', 'A', 'B', 'E', 'B', 'C', '1', 'A', '0', '9', '9', '3', '4', '4', 'D', '9', '5', '6', 'A', '3', '9', '9', 'B', '9', '1', '4', '3', 'C', '4', '2', '2', '0', 'E', '3', '3', 'E', '4', '2', 'C', '1', '3', '2', 'D', '6', '0', '9', 'A', '2', '7', '4', '7', '5', '7', 'A', 'A', 'C', '2', 'E', 'C', '3', 'E', '4', 'F', '5', '7', '2', '2', '5', '8', '7', 'B', '8', '1', '1', 'E', '9', '1', '5', '0', '3', 'F', 'B', '3', 'E', 'A', '4', '0', '4', '2', 'A', 'E', '7', '4', '8', '2', 'F', '5', '8', 'D', '4', 'C', '1', 'F', 'C', 'B', 'C', '1', '5', '0', 'C', '0', '7', 'E', '7', '6', 'A', '3', '7', '9', '4', '4', 'D', '7', 'D', '7', '6', '3', '3', '6', '4', 'E', '7', '7', 'F', 'D', '4', 'B', '3', 'D', '7', '0', 'A', '8', 'E', '5', '4', 'E', 'E', '7', '7', '4', 'B', '8', '0', '0', 'F', 'B', '2', '4', '0', '6', 'D', '6', '4', 'C', '1', 'D', 'F', 'C', '8', '6', '2', '4', '1', '2', '0', 'A', '2', '8', 'F', 'A', 'D', 'C', '8', '8', 'A', '1', '1', 'B', 'A', '3', '0', 'F', 'C', '1', '8', '5', 'F', '1', 'B', 'A', '2', '8', 'D', '2', 'B', '4', 'B', 'D', '0', '6', 'A', '5', '0', 'A', '6', '2', '0', '2', 'F', '7', '3', 'C', '5', 'B', '9', '8', 'A', 'B', 'F', '4', '8', 'E', 'B', 'D', '9', '3', '3', '3', 'D', 'D', '3', '1', '6', 'B', 'A', '8', '5', '1', 'E', 'A', 'A', '8', 'C', '6', 'F', '7', '5', 'A', '9', '2', '0', 'E', '3', '6', '4', 'B', 'B', '8', '1', 'E', '1', '1', 'D', '9', 'C', '3', '9', '0', 'D', '3', '7', 'C', '6', '3', '7', '4', 'A', '9', 'B', 'C', '4', 'E', '0', 'D', 'D', '3', '1', '7', 'D', 'C', '5', '6', '7', 'F', '1', '9', '9', 'A', 'B', 'A', '9', '5', '5', '5', 'D', '9', '2', 'B', 'B', '8', 'F', 'A', '1', 'B', '9', 'D', 'E', '3', '7', '7', 'F', '0', 'B', 'D', '4', '8', '5', '2', '6', 'A', 'F', '0', '4', '9', 'E', '3', '9', '7', 'C', 'A', '3', 'B', 'F', '7', '4', '8', '7', '8', 'D', 'E', '6', '4', '6', '1', '5', '6', '8', 'F', '5', '8', 'E', '1', 'F', '4', 'D', '0', 'F', '8', 'B', '5', '0', '9', '8', '5', 'F', '2', '2', 'F', '1', '6', '5', '6', '8', '9', '1', 'B', '9', '2', '9', '7', '7', '0', '8', '3', '0', '1', '9', '9', 'F', 'A', 'B', '1', '3', '1', '6', 'F', '8', '9', '4', '4', 'B', '8', 'B', '0', 'B', '9', '5', 'E', 'C', '9', 'C', '4', 'A', '0', 'A', '5', '7', '7', '6', 'A', '9', '5', '7', '4', 'A', 'E', '6', '7', 'D', 'B', '7', '0', '2', '0', 'C', 'B', '4', '3', 'A', 'B', '0', 'B', 'E', 'A', 'B', '5', 'D', 'D', 'C', '4', '0', '5', '5', '9', '9', '3', 'C', '4', '0', 'F', '6', '0', 'E', 'D', 'E', '0', '5', '9', 'D', '6', '5', '0', 'B', 'C', '5', '8', 'D', '0', 'D', 'A', '1', 'C', 'B', 'C', 'D', 'F', 'E', '8', 'E', 'D', '1', 'E', '4', 'A', '8', 'F', '4', 'D', 'C', '2', '3', 'A', 'B', 'F', '1', '4', '1', '8', 'E', 'E', '9', '5', '6', '2', '3', 'E', 'A', '7', '6', '2', 'F', 'C', '6', '6', '8', 'B', '8', '3', 'A', '2', '6', '6', '2', '1', '8', 'D', 'F', '9', '7', 'D', 'E', '7', 'C', '5', '0', '3', 'C', 'E', '7', 'E', '4', '2', 'C', 'B', 'A', '3', '3', '6', '7', '6', '5', 'C', 'D', '1', 'A', 'D', 'D', 'C', 'F', 'F', '5', 'B', '8', '9', 'C', 'B', '5', '3', 'E', 'E', '1', '9', '3', '8', 'A', 'F', '4', '7', 'F', '2', '2', '9', 'C', '0', 'E', 'D', '8', '3', '9', '8', 'F', '7', '6', '8', '6', '8', 'A', '6', '3', '1', '7', '8', '7', '0', '1', 'A', 'D', 'A', '3', 'B', 'F', '1', '2', '9', 'E', '6', '3', 'B', 'D', '9', '2', '6', 'B', '3', '3', '1', 'D', '4', '6', 'B', 'E', '7', 'A', 'D', '2', 'B', '2', 'D', '8', '5', 'A', '7', 'D', 'A', 'D', '3', 'D', '4', '1', 'E', 'F', '0', 'A', '2', '5', '0', '4', 'C', 'E', '4', '3', 'D', 'F', '9', 'F', '0', 'D', 'A', 'A', '1', '3', '7', 'A', 'D', '8', 'C', '4', 'D', '6', '4', '7', 'A', '0', '8', 'B', '7', '4', 'F', '2', '0', 'A', 'D', 'A', 'E', '0', '5', '0', '5', '0', '1', 'E', 'D', '5', '0', '7', '7', '3', '8', '0', '0', 'E', 'D', '8', '4', '8', '8', 'C', '3', '1', '8', '7', '2', '4', '7', '5', '9', '3', '8', '3', '7', '6', '9', '8', '2', '2', '3', '4', 'B', 'F', '9', '6', '7', '8', 'F', 'D', '6', '1', '7', 'F', 'D', 'B', 'F', 'B', 'D', '9', '6', '2', 'F', '6', '4', '8', 'A', '6', 'A', '8', '6', '4', '3', 'E', '7', '7', '4', '9', '5', '0', 'C', '5', '0', 'E', '1', '6', '0', '2', '4', '8', '5', 'C', 'B', '7', '7', 'C', '5', '3', '4', 'B', '1', 'B', '2', 'C', '9', 'E', '5', 'F', 'B', '7', '2', '9', '8', '7', '3', '1', '0', 'D', '9', 'A', '6', '2', '4', 'A', 'C', 'B', 'F', 'C', '7', '0', '2', '2', '1', 'B', '2', 'E', 'A', 'B', '9', 'A', '8', '3', '5', '9', 'E', '4', '1', 'A', '4', 'B', 'A', '2', '5', '3', 'F', 'A', '7', 'D', '3', '3', '1', '3', 'F', '0', 'C', '0', '6', 'B', '3', '7', '3', '2', '2', '4', '6', '3', '0', '5', 'D', 'A', '8', '0', '0', '2', '1', '8', 'E', '8', '3', '2', '4', '1', 'A', '1', '0', '7', '2', 'C', '6', 'B', 'F', 'A', '9', '9', '2', '2', 'F', 'F', 'B', '4', '0', 'A', '9', '3', 'A', '8', '4', '3', '0', '0', '6', '9', 'E', '3', 'E', 'E', 'F', '1', '2', '6', '4', '4', '7', '2', 'D', 'C', 'D', '5', '9', 'B', '2', 'E', '6', 'C', 'C', 'B', '9', 'B', 'C', 'B', '7', '7', '8', '9', '7', '5', 'B', 'F', '0', '0', '2', '4', '9', 'A', '1', '4', '3', 'B', 'F', '3', '4', '3', 'C', 'A', '3', '7', '9', '2', 'D', 'C', '6', '1', '1', '5', '9', '4', 'D', 'C', '8', '2', '2', '7', '7', '4', '1', '7', '3', '8', '4', 'D', 'E', '4', 'B', 'F', 'B', 'B', 'C', '9', 'D', '0', '5', 'F', '4', '9', '0', '3', '6', '1', '4', 'A', '5', '5', '1', '9', 'B', '6', 'D', 'D', '9', '1', 'F', 'F', '0', 'D', '3', '8', '9', '7', '4', '5', '7', '3', '2', 'A', 'D', 'C', '3', '5', 'C', 'C', '8', 'C', '5', '0', '1', '5', '9', '8', 'A', 'E', '5', '3', '0', '0', 'D', '7', 'E', '4', '4', '4', '6', 'A', '2', 'C', 'A', '9', 'E', 'E', '6', '0', 'A', '6', 'E', 'B', '2', 'A', 'D', 'E', '9', 'E', 'C', '0', '5', '6', 'C', 'D', '6', 'B', '2', 'D', '9', 'D', 'B', '3', '2', 'A', '6', '0', '4', '9', '5', 'F', 'C', 'A', '6', '7', 'B', '5', '5', 'B', '0', 'D', '7', '5', '3', '3', '1', '9', 'C', '4', '2', '1', '7', '3', '4', '2', '2', '1', '3', 'B', '0', '3', '5', '7', '2', 'D', '1', '3', 'D', '3', '7', 'B', '9', '8', 'F', 'D', '8', 'F', '4', 'E', '8', 'A', 'B', 'A', '3', '3', '1', 'C', '9', 'E', 'F', 'D', '0', 'A', 'A', '4', '2', '2', '9', '6', '4', '1', '9', '0', 'C', '9', '6', '8', 'A', '5', '7', 'E', 'A', '3', 'F', 'A', '1', 'A', '6', 'C', '7', 'E', 'D', '3', '2', '8', '2', 'D', 'E', '7', 'D', '6', 'A', '0', '5', 'D', 'E', '1', '8', '5', '4', '4', 'C', '2', '8', '1', 'C', '5', '0', '5', 'D', '5', '0', '7', '3', 'E', '7', '2', 'A', '6', '1', 'B', '7', 'B', 'E', '8', '8', 'D', 'B', 'B', '8', '9', '1', '8', '7', 'D', 'A', '1', '7', '2', 'B', 'D', '8', '0', '0', 'D', 'C', '1', '8', '9', '3', 'C', '2', 'B', 'A', '4', '6', '3', 'C', '7', '8', '8', '2', 'D', '0', '4', '6', 'D', '0', 'F', 'F', '0', '6', '9', '7', '7', '0', 'D', '1', 'C', 'C', 'D', '3', 'E', 'B', '8', '1', '7', '6', 'D', '2', '9', '6', '0', '5', '7', '4', '8', '2', '5', '2', '1', '2', '5', 'C', 'F', '6', '6', '4', '9', 'B', 'D', '5', '1', 'A', 'D', '8', '9', '7', '2', 'D', '1', '7', '0', 'A', '3', '5', 'E', '1', 'C', '2', '4', '9', 'F', '7', '3', '9', '4', '4', '9', 'D', 'D', 'B', '7', 'D', 'F', '5', 'E', 'E', '3', '3', '7', 'C', '5', '6', '3', 'E', '5', '6', '9', 'F', '0', 'F', 'F', 'D', '0', '8', '5', '2', 'A', '4', '5', '7', '6', '8', 'C', 'A', 'A', '0', '3', 'F', '3', '2', '9', 'B', '3', 'D', 'E', 'C', 'D', 'C', '3', 'F', 'F', 'E', '2', 'A', 'F', 'A', 'D', 'E', '1', '2', '9', '6', 'E', '6', '4', '9', '4', '3', 'D', 'C', '0', '3', '3', '0', 'A', '3', '6', 'C', '6', '3', '8', 'E', '0', '3', '6', '3', '4', 'D', '4', '5', '8', '0', '1', '1', '9', '0', '2', '3', 'B', 'E', 'E', '8', 'C', '3', 'B', '4', 'F', '5', '4', 'A', '4', '3', '9', 'D', '5', '2', 'D', 'D', 'F', '9', 'D', '4', '5', '0', '0', '7', '6', '8', '8', '5', 'B', 'F', '4', '4', 'E', '9', 'B', '2', '4', '7', '3', '1', '8', '9', 'D', 'B', 'E', '2', '8', 'D', '2', 'F', 'E', '0', '6', '6', '7', 'F', '8', '4', 'E', 'B', 'E', '4', 'E', '2', 'F', '7', 'F', '2', '2', '0', '1', '6', '4', 'B', 'D', '8', 'A', 'B', '4', '4', '4', '9', 'D', 'A', 'A', '5', 'B', '1', '8', 'F', 'C', 'C', '8', '4', '2', '8', 'E', '0', '6', '1', '6', '8', '1', '9', '5', '8', 'A', '3', '4', '4', '0', '7', '0', 'A', '3', '5', '6', 'C', '2', 'D', '6', '0', 'B', 'F', '2', '0', '8', '7', '2', '9', 'E', 'D', 'B', '7', '3', '5', 'C', '1', 'B', '8', '9', 'B', 'E', '5', '7', '6', '2', '3', 'E', 'A', 'B', '8', 'E', '9', '2', 'A', '7', '9', '3', 'A', 'E', 'B', '0', 'B', '5', '8', 'E', 'C', 'E', 'B', 'A', 'C', 'E', '6', 'B', 'F', '3', '5', 'A', '3', '0', '4', '8', 'E', '6', '1', 'B', 'B', '6', '9', 'D', 'B', 'C', '7', '0', '8', 'B', 'D', '7', '9', '2', 'C', 'E', '3', '9', 'E', 'B', '9', '7', '1', '4', '6', 'F', '2', '8', '4', '7', '5', 'E', 'E', 'F', '3', 'D', 'E', '4', 'B', '2', '5', '5', '5', 'F', '2', '1', '9', 'D', '2', '2', 'B', 'A', 'A', 'F', '8', '7', '7', '5', '8', 'D', 'A', '2', '5', 'D', 'E', '2', '1', '8', 'D', '5', '7', '7', '2', '6', 'C', '4', '7', 'A', '1', '0', '8', 'B', '4', 'E', '7', 'B', '9', '6', '0', 'A', 'A', 'A', '2', 'E', 'E', '3', '7', 'D', 'C', 'A', 'C', '5', '4', '5', '2', '7', '6', '9', '3', '5', 'A', '8', '8', 'F', 'C', 'E', '0', 'C', '6', 'B', '6', '0', '2', 'E', '2', '2', '9', '4', '8', '3', '1', '0', 'A', '5', '6', 'C', '9', 'E', 'A', '8', 'E', '9', '6', 'A', '7', 'C', 'D', 'A', 'F', 'E', '5', 'B', '8', '7', 'B', '9', 'F', 'F', 'C', '3', '3', '7', '7', '2', '0', '8', 'C', '7', 'A', '5', '5', '7', 'C', 'B', 'E', '9', 'B', '3', 'B', 'A', 'E', '5', 'E', '2', '0', 'F', 'B', '1', 'F', '8', 'A', '4', 'B', 'B', '3', '9', '3', 'B', 'E', '4', '4', '7', '4', '6', '3', 'F', 'F', 'D', '1', '7', '6', 'A', '4', '8', 'D', '7', '2', '9', 'F', '3', 'C', 'E', 'A', '7', '4', 'A', '1', '0', '9', 'F', '0', '2', '8', 'A', '3', '5', 'C', '9', '3', '0', 'D', 'B', '7', '4', 'E', 'E', '2', 'B', '7', '2', 'A', '6', '2', 'C', 'B', '3', '9', '2', '3', '7', 'A', '1', 'E', '0', 'F', '0', 'E', '0', '7', '9', '8', '3', '5', '7', '3', '4', 'A', '4', 'D', '3', '2', '0', 'A', '2', '2', '1', 'B', '0', '4', '5', '5', '9', 'D', '0', 'B', '3', '9', '6', 'B', 'F', 'F', '3', 'E', '8', '2', '0', '6', 'D', '0', 'E', '7', 'D', 'F', '8', 'D', '1', '0', '8', '2', 'C', '6', '8', 'C', 'E', '6', '5', '8', '2', '9', 'C', '5', '3', '2', 'C', '6', '2', '5', '2', '2', 'D', '2', '7', '3', 'A', 'A', 'F', '1', '6', 'D', '4', 'B', '2', 'E', '1', '4', 'D', '8', '3', '9', 'C', '6', '3', '4', '2', '9', '6', '2', '2', 'B', '5', '1', 'C', 'A', 'A', '8', 'C', '4', '5', '3', 'F', '4', '9', 'E', '0', '1', 'C', '0', 'C', '2', '0', '2', 'E', 'A', '6', '4', 'D', '5', '1', '6', '6', 'B', '6', '1', '3', '0', '9', 'D', '9', '9', 'E', '7', '3', '9', 'B', '0', 'D', '9', '2', 'E', '1', '3', '3', '4', 'D', 'F', 'A', '1', '5', 'C', 'D', '9', '5', 'D', 'E', '6', '4', 'D', 'B', 'A', '7', '7', '4', '1', 'A', '5', '2', '7', '4', 'B', '9', 'A', '6', 'D', '6', '9', '4', '5', 'D', '8', '6', 'F', '6', 'F', '5', '2', '7', '1', 'A', 'D', '6', '3', 'F', 'F', '4', 'D', '3', 'E', 'F', 'E', '8', 'C', '2', '0', 'B', '1', 'A', '5', 'E', 'D', '5', '7', '4', '6', 'E', 'B', '5', '1', '4', 'D', '0', 'F', '5', '8', 'A', '0', 'F', '2', 'C', 'C', '1', 'D', '8', '9', 'E', 'F', '9', 'A', '3', 'D', '9', 'F', '6', 'A', 'F', 'C', 'E', '6', '3', 'D', 'D', '6', '0', '8', '1', 'D', '0', '0', 'C', '7', '5', 'D', '8', 'D', '1', '1', '7', 'D', '0', 'A', 'B', 'B', '7', 'B', '2', '7', '7', '8', '7', 'A', '3', '8', '4', '5', '0', 'E', 'D', '6', '0', 'D', 'E', '4', 'E', 'F', 'B', 'E', 'B', 'A', 'A', '5', 'B', 'F', 'E', '9', '0', 'C', 'A', 'D', '6', 'E', '7', 'D', '6', '9', '2', '2', '9', 'A', '5', 'D', '2', 'E', '2', '1', '2', '2', 'A', 'A', '9', '0', 'C', '1', '8', '4', '5', '7', '5', '9', '2', '8', 'A', '0', 'A', '8', 'F', 'C', 'C', 'C', '7', '0', 'C', 'D', '9', '0', '3', '4', 'C', '8', '1', '5', 'B', '4', '9', '8', 'A', '7', '5', 'C', 'B', '3', 'F', '3', '9', '4', 'E', '4', '0', '0', '5', '5', 'A', 'C', '8', 'A', '1', '4', '6', '0', 'A', '0', '0', '4', '1', 'A', '3', 'F', '8', '4', '3', '7', '3', '1', '5', 'F', '1', 'F', '9', '8', 'B', '5', '8', '1', '8', '9', '8', '7', 'C', 'E', '1', 'D', 'F', '1', '7', '4', 'E', 'F', 'B', 'C', 'F', '8', '5', '8', '0', 'A', '7', '6', '1', '6', '2', 'D', 'F', '1', '6', '0', '0', 'D', 'C', '1', 'D', '1', '3', 'C', '3', '7', '9', '9', 'D', '8', '1', '7', 'B', '8', 'A', '8', '7', '6', 'B', 'F', '5', 'D', '0', '7', '7', '2', '0', '4', '5', '0', '7', '1', '6', 'C', 'F', '0', '8', '6', '8', '2', '9', '1', '4', '4', '8', '6', '6', '3', '1', '4', 'D', '4', 'A', 'F', 'D', '5', '3', '2', '7', '0', 'C', 'D', '5', '5', '8', 'E', '4', '9', '4', '4', '7', 'A', '3', '5', '3', '8', '0', '5', '3', '0', 'B', 'D', '5', '1', '6', 'A', 'F', '0', '5', 'E', '6', '9', '8', 'B', 'A', '7', 'A', '5', '3', 'D', '6', 'C', 'A', '9', 'A', '5', 'F', '9', 'A', 'D', 'C', '7', '6', 'E', 'F', 'C', '4', '5', '4', '6', '9', '1', '0', '8', '8', '8', 'D', 'D', '3', '5', '2', 'B', 'A', 'C', '0', 'C', 'B', '9', 'F', '0', 'A', '6', '7', 'D', '4', '5', '5', 'E', 'C', '3', '7', '9', 'F', '1', '2', '2', '4', '4', '7', '6', 'F', 'C', '4', '1', '3', 'A', '3', '1', '6', '8', '2', '7', 'B', 'E', 'C', '8', 'A', '7', 'C', 'F', 'E', '8', '4', '7', 'E', 'F', '8', '8', 'F', '0', 'F', 'E', 'B', 'A', 'B', '4', '8', '3', 'B', 'C', '1', '4', 'D', '7', '4', '5', '6', '3', '0', '8', 'A', 'C', '9', '9', 'C', 'E', '5', '2', 'F', 'B', 'B', 'A', 'F', 'D', '1', '7', '1', '5', '1', '9', '6', '0', '4', 'B', 'F', '5', '5', '2', '3', '0', '3', 'C', 'F', 'F', 'A', '0', '5', '9', 'E', 'F', '1', '2', 'F', '5', '2', 'D', '3', '5', '3', 'E', '8', 'D', 'C', '0', 'F', 'D', 'B', '8', '5', 'B', '5', 'B', 'D', 'F', 'F', '8', '0', 'F', '9', 'E', 'D', 'B', 'D', '3', '0', 'B', '2', 'A', 'D', '6', '0', '0', 'D', 'A', '4', '2', '7', '0', 'C', '3', '1', '6', '7', '1', '3', 'E', '1', 'A', 'E', '7', '9', '3', '4', '7', '8', '7', '3', 'E', '2', 'F', '5', '1', 'D', '0', '3', 'F', '1', '0', '7', 'E', '2', 'D', 'D', 'C', '5', '7', '3', 'F', '1', 'E', '5', 'C', '2', '5', '8', '5', 'A', 'A', '6', '8', '3', '3', '3', '4', 'B', '0', '4', 'C', '0', '7', '6', '8', '9', '4', '3', '9', 'C', '6', 'A', '9', '7', 'A', '1', 'A', 'D', 'D', '6', 'F', '3', '2', '1', '3', '6', 'E', '6', '0', 'E', 'D', '4', 'B', '9', 'A', 'E', '3', '7', 'F', 'B', '0', 'B', '0', '9', 'F', '1', 'C', '6', '2', '1', 'E', '2', '9', 'B', 'D', 'E', 'F', 'E', '6', 'D', '9', '1', 'D', 'B', 'B', 'B', '3', '4', '5', 'E', '2', '4', 'D', '2', 'D', '8', 'C', 'B', 'D', '2', '2', 'D', 'D', 'E', 'A', '0', 'A', 'B', 'D', '1', 'A', '4', '9', '1', '7', '7', '7', '9', 'E', '5', 'E', '9', 'A', 'B', 'F', '1', '1', '3', '9', '1', 'F', '4', 'C', 'B', 'A', 'F', '1', '4', '2', '8', 'D', 'C', 'D', '0', '2', 'B', '3', 'A', 'B', 'B', '4', 'A', 'A', '3', '1', '9', '0', '7', 'C', '6', '7', '5', '4', 'D', '0', '9', 'A', '7', 'E', '1', '2', '0', 'D', '2', 'E', '0', '4', '5', 'C', '1', 'F', '1', '7', 'C', 'B', 'E', 'C', '9', '2', '4', 'B', 'A', 'D', 'B', '6', 'F', '9', 'D', '0', '5', '0', '2', '8', '5', 'A', 'D', 'E', '6', '3', '2', '1', '4', '5', '8', '4', '5', '4', '4', '2', 'D', '6', 'F', 'F', '6', 'E', '4', '8', '4', '8', '8', '5', '0', 'D', 'F', '5', '4', '1', '1', '2', 'A', '0', '3', 'B', '1', '4', '1', '0', 'F', 'C', 'E', '9', 'D', '6', '2', '8', '6', '3', '4', '8', '6', 'D', '9', '6', 'F', '9', '9', '1', '5', '3', 'A', 'C', '9', 'B', '8', '0', '5', '1', 'D', 'D', '0', '5', 'E', '3', '4', '4', '1', 'B', 'B', '7', '8', 'B', '8', '6', 'A', 'B', '6', 'D', '2', 'D', 'C', '4', '6', '5', 'C', '0', 'A', '8', 'E', 'A', '6', '4', '5', 'C', '2', '4', '0', '7', 'E', '1', '9', 'C', 'E', 'F', '9', '6', '5', '1', 'D', '0', '6', 'E', 'E', 'C', 'F', 'F', '6', 'C', '0', 'D', '6', '2', 'F', '4', '3', '3', '0', '3', 'D', '0', '3', 'C', 'F', 'D', '3', '7', '3', '9', 'E', '6', 'C', 'E', '5', '4', '3', '6', 'D', '0', '2', '8', '9', '0', '8', 'A', 'D', '3', 'B', '4', '3', '3', 'B', '5', 'D', 'C', 'F', 'B', '1', 'D', 'E', 'D', 'A', '0', '6', '4', 'D', '9', 'B', '1', '9', 'B', '5', 'E', '8', 'B', '0', 'E', '6', '7', '1', '7', '1', '5', 'B', '4', '4', 'D', 'D', 'B', '1', '4', 'A', 'B', 'E', '1', '0', '8', '0', '4', 'B', '0', '3', '8', '0', '4', '4', '3', 'A', '1', 'A', 'E', '4', 'E', '4', '5', '4', '6', 'F', 'B', '4', '4', 'F', 'E', 'F', '3', '1', 'E', 'A', '7', 'C', 'E', 'A', 'B', '1', '7', 'E', '0', '7', '1', '6', '2', '9', '8', '8', '8', '1', '7', '0', 'E', '1', '8', 'B', '4', 'E', '1', '0', 'D', '5', 'A', '8', '5', '7', '1', '4', '8', '1', 'D', 'B', 'B', '2', '9', 'E', 'B', '2', 'B', '0', '3', 'E', '4', 'D', '6', 'D', '7', 'F', 'D', '4', '1', '7', 'A', '3', 'E', '7', 'C', 'C', 'E', '9', 'F', '6', 'F', '8', 'F', 'C', '9', '2', '3', '6', '0', 'A', 'E', 'F', '0', '3', '6', '3', '4', '8', '8', '9', '5', 'E', '4', '7', '1', '8', '3', '1', '9', '6', 'A', 'C', '3', 'C', 'D', 'B', '7', '1', '3', '2', '2', 'C', '6', '0', 'F', '7', 'B', '0', 'C', '3', 'B', '8', '9', '4', 'B', '8', 'F', '6', 'F', '3', '3', 'A', 'F', '2', '8', '0', '7', '0', 'F', '1', 'F', '3', '4', '8', '8', 'F', '9', 'A', '5', '3', 'B', '1', 'B', 'D', '9', '6', '7', 'B', '3', '8', '6', 'E', 'C', '4', 'A', 'B', 'B', '8', '9', '9', '7', '3', 'B', '4', 'E', 'C', 'C', '4', '7', '3', '8', 'D', '7', '7', '8', 'B', '5', '5', 'D', 'B', 'B', 'A', 'C', '7', '4', '5', 'B', '4', '0', 'C', '2', '3', '2', '1', '5', 'A', '3', '3', 'C', '1', '7', '4', '8', 'D', '5', 'B', 'C', 'D', 'C', 'B', 'E', 'D', '6', '8', 'C', '4', '6', 'F', 'D', '3', '1', 'B', 'B', '8', '3', 'D', '8', 'B', 'A', 'C', '6', '0', '9', '9', 'C', '8', '9', '1', 'B', 'A', '3', '2', '7', '1', 'C', 'E', '6', 'E', 'A', '3', 'B', '6', 'F', 'F', '0', 'B', '2', 'A', 'E', 'B', '8', 'E', '7', '6', 'F', 'C', 'F', '4', '6', '6', '4', '0', '6', '3', 'B', 'F', 'B', '3', '9', '1', '6', 'A', 'D', '4', '9', '2', '5', '2', 'F', 'C', '5', 'E', '3', '6', '6', '9', '7', '9', 'F', '5', '6', 'E', '3', '0', '0', '2', '8', 'B', 'D', '6', '8', '2', '1', '6', '4', '2', '5', '8', '8', '1', '1', '7', '9', '5', '5', 'D', '2', '3', '6', 'B', '5', 'E', '2', '3', 'F', '2', '9', 'D', '8', '0', 'F', '7', 'B', '6', '4', '2', '4', '9', '9', '3', 'B', '1', '0', '2', 'C', 'C', '5', '0', '1', '7', '7', 'E', '1', 'D', '9', 'C', '8', 'D', '1', 'D', '7', '1', '9', '5', 'D', '4', 'D', '2', '9', '9', '3', '9', 'F', '3', '8', '7', 'B', 'B', '2', 'A', '4', '7', '5', 'F', '9', '0', 'E', '1', '7', '1', 'F', '9', 'F', '5', '3', 'E', '5', '2', '0', '4', '8', '3', '1', '9', '7', '2', 'A', 'A', 'D', '4', '7', '0', 'C', '3', '7', 'E', 'B', 'C', '1', 'D', '4', '8', '9', '8', '9', '1', 'F', '8', '4', '2', '6', 'B', '4', '5', '0', 'C', '7', '0', '9', '6', '4', 'D', '0', 'A', '4', '8', 'E', '9', 'C', '9', '5', 'A', 'C', 'D', 'C', 'C', 'F', 'C', 'C', '6', '9', 'A', '5', 'F', '6', 'A', '2', '9', 'B', '1', '5', '6', 'C', '5', 'B', 'F', '6', 'C', '3', '3', 'B', '0', 'F', '5', '0', 'F', '1', '3', '4', '2', 'F', '8', '8', 'D', '3', 'A', '3', '2', '3', 'B', '2', 'B', '2', '0', 'E', '5', '6', '9', '2', '5', '7', 'F', 'E', 'C', 'D', '3', '2', 'F', 'F', '2', '4', '3', '3', '0', '7', '7', '2', '3', 'A', 'B', '8', 'A', '5', '4', '7', '1', '5', '8', '8', '5', 'B', 'E', '7', 'A', '7', '6', '7', 'B', 'C', '4', 'D', '9', '4', 'C', '2', 'B', 'A', 'C', '0', 'B', '3', 'A', 'C', '4', '7', '6', '0', 'B', 'A', '2', 'D', 'A', '3', '4', '7', '0', '8', '4', '6', '5', 'F', '4', '6', 'B', 'A', '4', '0', '1', 'D', '2', 'C', '9', '2', 'B', '9', '0', '3', 'F', '1', 'E', '2', '3', '1', 'D', 'B', '0', 'E', 'A', '9', 'C', 'C', '2', '3', 'C', 'B', 'D', 'D', '9', 'B', 'B', '2', '3', '5', '7', '4', '6', '2', 'F', 'F', '2', 'C', '3', '5', '3', 'B', 'A', '1', '6', 'A', 'E', '8', 'C', '2', '6', '5', '8', '7', 'F', '8', '1', 'A', '5', 'C', 'B', '1', 'E', 'A', '2', '8', '1', '4', '0', '8', '7', '7', 'A', 'C', '7', 'E', '0', '2', '1', '7', 'E', 'D', '4', 'C', '6', 'D', '6', 'E', '8', 'D', 'D', 'D', '2', '8', '2', 'E', 'E', '1', '8', 'C', 'C', '6', '0', '1', 'E', '4', 'F', '2', '7', '3', '9', 'E', '6', 'C', '1', 'C', 'A', 'C', '2', '2', 'C', '9', 'B', '1', 'C', '2', 'F', '1', 'F', '6', '0', 'C', '5', 'D', 'A', 'A', 'C', '0', 'D', 'D', '4', 'A', '6', 'D', '3', '8', 'F', '6', '4', 'E', 'D', 'A', 'D', '5', '6', '1', '4', 'E', '0', '6', 'D', 'C', 'E', '9', '5', '8', '3', 'A', 'E', '7', 'F', '0', '5', 'A', '6', 'C', 'A', 'A', '0', '9', 'A', '9', 'A', '4', 'B', 'E', '4', '9', '7', '3', '7', '6', '9', '7', '8', 'E', '6', '8', 'E', 'E', 'B', '9', '0', 'E', '3', '6', '8', 'B', '1', 'E', '0', '0', 'B', 'B', '0', '8', '3', '0', '2', 'F', 'F', 'C', '8', 'C', '5', 'D', 'E', 'E', 'F', '7', 'C', '0', '3', '8', '1', '3', '2', 'B', '9', 'F', '5', 'B', '5', '3', '9', '4', '1', '4', '7', 'A', 'B', 'B', 'A', '7', '0', '7', 'B', '3', 'A', '7', '5', 'B', '4', '1', '0', '9', '4', 'C', '3', 'E', '7', '9', 'E', '3', 'B', '3', 'B', '5', '4', 'E', '3', '1', 'C', '8', '8', 'B', '2', '5', '2', '7', 'D', '9', '4', '2', 'D', 'C', 'E', '3', 'F', 'D', 'B', 'D', '0', '5', '9', '9', 'B', '3', 'F', 'C', '0', 'E', 'E', '5', 'E', '8', 'B', '4', 'E', '5', '1', 'D', '0', '7', 'B', '7', '7', '0', '6', '9', '3', 'F', '9', 'E', '6', '1', 'D', '7', 'D', 'D', '5', '0', 'F', 'C', 'A', '8', '2', '2', 'C', '9', '1', 'B', '3', 'C', '7', '4', 'B', '4', 'F', '0', '2', '1', 'A', 'A', 'F', 'F', 'E', '4', 'C', 'A', '5', 'C', '7', 'D', 'A', '0', 'D', '7', 'A', 'C', '2', '0', 'D', '3', '2', '0', '5', '6', '1', '9', '7', '7', '7', '4', 'C', 'D', '4', '1', '9', 'D', '6', '1', 'A', '1', 'F', '2', 'A', 'F', '2', 'C', '7', '0', 'C', '4', '1', '4', '9', 'B', 'C', '1', '3', '7', '6', '7', '5', 'C', '7', '0', '7', 'A', '4', '1', '2', 'E', '9', 'E', 'E', 'E', '4', 'D', 'F', 'D', 'C', '3', '6', 'E', 'D', 'F', 'D', 'D', 'E', '0', '2', '0', '7', '8', '2', '3', '0', 'C', '0', '8', 'F', 'C', 'F', '2', '1', '6', 'E', 'A', '9', 'F', 'E', 'C', '3', 'C', 'B', 'A', '1', '9', 'B', '5', '4', '7', '7', 'F', '9', '6', 'C', '1', 'E', 'F', '3', '3', 'C', 'D', '2', '5', 'B', '2', '5', '7', '8', '8', 'C', 'B', 'D', 'F', 'E', '6', 'F', 'D', 'C', '6', 'D', 'D', '5', 'D', '6', '1', '8', '7', '0', 'A', '3', '4', '7', '7', '4', '7', '0', 'E', 'B', 'B', '4', 'A', '4', '5', 'D', 'B', '2', '7', 'E', '2', 'C', 'C', 'A', '8', '2', 'E', 'F', '8', '4', '8', '9', 'C', 'E', '5', 'A', '0', '8', '8', '2', 'C', 'D', '4', '0', '5', '6', '2', '5', '2', 'E', 'E', '3', '8', '1', '1', '5', '6', '3', 'E', 'B', '9', 'E', 'E', 'A', 'B', '6', 'B', '9', 'E', '6', '4', '0', 'D', '2', '9', 'D', '0', '7', '9', 'B', 'B', '3', '9', '5', '3', 'C', 'C', '2', '3', 'D', '3', 'D', '7', 'C', '3', 'C', 'D', '4', '2', '8', '4', '0', '3', 'C', '1', '3', '1', '9', '2', 'A', 'B', 'F', '2', 'B', '4', 'A', 'E', '3', '2', 'E', 'F', '7', '0', 'F', 'E', '0', '0', '1', '6', 'F', 'C', 'E', '2', 'B', '4', '8', '9', '6', 'B', 'F', 'D', '5', 'B', '5', '0', '2', '0', '8', '4', 'E', 'D', 'B', '9', '2', 'B', 'B', 'A', '9', '6', '8', 'D', '6', '3', '7', 'A', '6', 'B', '2', '1', '3', '6', '8', '8', 'F', '0', '2', '6', 'B', 'F', '5', '4', '3', 'A', 'A', '1', 'C', '4', 'D', '7', '5', 'D', '1', '0', 'E', '6', '3', '2', 'E', '0', '9', 'B', '2', '8', 'C', '8', '1', 'E', 'B', '4', '0', 'F', '2', 'E', '9', '6', 'F', '5', '0', 'D', 'D', '6', '0', '6', 'C', 'F', '4', '5', 'D', '5', 'F', 'B', 'B', 'C', '9', 'F', '2', '9', '2', 'A', '6', '5', 'D', '8', 'D', 'C', 'A', '0', '9', 'A', 'B', '2', 'A', '1', 'E', '2', '0', '4', 'C', '2', '6', '5', 'D', '3', '9', '3', 'C', 'A', '7', '0', 'C', 'D', '5', '2', 'E', '2', 'F', '4', '2', '9', '9', '3', '4', 'D', 'F', '4', 'D', '9', '1', 'F', '9', '4', '0', '9', 'D', '1', 'A', '7', '8', '8', '6', '9', 'A', '1', '8', '2', '0', 'A', '1', '8', '6', '1', '4', '9', '3', 'B', '0', '3', '9', 'A', '3', '2', 'A', '4', '5', '9', '7', 'B', 'F', 'A', 'A', '2', 'B', '6', '6', '0', '5', '8', '6', 'C', '2', 'F', '9', 'C', 'B', 'A', 'B', 'F', 'E', 'D', '5', '6', 'E', 'C', 'C', '7', '3', '9', '6', '9', '8', '4', '7', 'B', '4', '0', '9', '7', '5', '5', '2', 'D', 'E', 'C', '4', '9', '5', 'A', '3', '3', '5', '3', 'D', '5', '1', '1', 'F', '3', '5', '7', 'E', '7', 'B', 'A', '0', '1', 'D', 'B', 'D', '6', 'B', 'D', '6', 'A', '8', 'B', '2', '0', '5', 'B', 'B', 'B', '5', '5', '4', '7', '0', 'F', '6', 'F', '0', '1', '1', '5', 'E', '9', 'C', 'E', '9', '1', '0', 'A', 'A', 'B', '7', 'B', 'F', '0', '7', 'F', '0', 'F', '4', 'B', '8', '6', 'D', '3', '7', '8', 'A', '1', '1', '9', '0', 'C', '1', '5', '6', 'A', 'B', '7', 'D', 'B', '9', '5', 'A', 'A', '8', '4', '3', 'C', 'A', '8', '6', '9', '0', 'C', 'D', '3', 'B', '8', 'E', '9', '1', 'F', '9', '4', '4', 'D', 'B', '7', '8', '5', '6', 'D', '1', 'D', '1', '4', '1', 'C', 'E', '8', '0', 'B', 'D', '4', '2', '3', '7', '6', '9', '3', '2', '7', '7', '6', '3', 'C', '0', 'C', '9', '5', '1', '9', '9', '6', 'F', 'F', '8', 'A', '4', '3', 'E', 'E', '5', '7', 'C', '5', 'A', '8', '3', 'D', '3', '9', '7', '9', '5', '0', '3', 'C', 'A', 'B', '1', '4', '1', '1', 'B', '5', 'A', '1', '7', 'F', '6', 'B', '9', '6', 'D', '4', '0', '6', 'A', '8', 'B', 'E', 'C', '9', '6', 'F', 'A', '2', 'E', 'C', '4', '0', 'E', '4', 'D', '8', '8', '0', 'A', '6', '4', 'C', 'E', '1', 'D', 'F', '3', '2', '6', 'D', '2', '1', '7', '1', '3', 'F', 'D', '7', '4', '0', '2', 'C', '5', 'E', '5', '1', '1', 'D', '7', 'F', '9', '5', 'C', '8', 'C', 'F', '0', '4', '9', '1', '4', 'C', '8', '4', '2', 'A', 'A', '5', '7', '4', 'B', '2', 'D', '5', 'E', '1', '2', '4', '9', 'D', '5', 'A', '2', '0', 'A', 'B', '0', 'C', '7', 'A', 'A', '4', '1', '7', '7', 'B', '8', '2', 'C', '4', '8', '2', '6', 'C', '5', 'B', 'A', '3', '5', 'F', '4', 'C', '5', '9', '0', '9', 'B', 'E', '8', '3', '2', '3', 'A', 'E', '5', '3', '4', '3', '0', '4', 'C', '4', '6', '4', 'F', '7', '9', '4', 'C', '2', '0', '4', '2', '8', '0', '5', '1', 'D', 'B', '3', '9', '7', 'D', '0', '3', 'F', 'D', '4', '0', 'F', '8', 'D', 'F', '8', '3', 'A', 'A', 'C', '8', '9', '8', '9', '4', '5', 'B', '0', '8', 'B', '6', '8', '7', '6', '6', '7', '6', 'F', 'D', 'B', 'E', '9', '9', '0', '5', 'F', '9', '4', 'F', '8', 'C', '2', '8', '2', 'C', 'D', 'F', 'F', 'A', '6', '5', 'D', '4', 'C', 'F', '2', 'A', '4', 'A', 'E', '6', '6', 'C', '6', 'F', '6', '2', '8', '3', '4', '5', 'E', '4', 'C', 'B', '8', '1', 'A', '6', 'F', '1', '6', '6', 'E', 'C', '8', '5', '3', '0', 'A', '2', '7', 'F', '6', '8', '9', '9', 'A', '3', '6', 'E', 'E', 'E', '5', '4', '0', 'F', '2', '0', '8', 'A', '3', 'A', '1', '6', '9', '4', '3', '4', 'A', '8', '9', 'D', 'D', '2', 'F', '6', '3', '3', '2', '6', '6', 'C', 'A', '5', 'D', '0', 'D', '2', '3', 'C', '4', '4', '5', '3', '8', '6', 'B', 'F', 'B', 'D', 'D', 'C', '9', '2', 'E', '8', 'A', 'B', '6', '5', 'B', 'C', 'B', 'D', '8', '2', '9', '8', '3', '9', '6', 'F', 'A', '2', '5', '3', '0', '4', '2', '2', '2', 'D', 'A', 'D', '6', '4', '1', 'B', 'B', '7', '6', '7', 'A', '4', '1', 'F', 'B', '8', 'D', '9', '6', 'F', 'B', 'C', '8', '0', '2', '3', '6', '8', '6', '9', '1', '7', '7', '4', 'C', 'A', '0', '5', 'F', '5', '2', 'F', '9', 'C', '1', '8', 'B', '1', '4', 'B', '9', '0', 'A', 'A', '3', '1', '5', '6', '1', '5', '2', 'B', '0', 'E', '6', '8', '9', 'A', 'E', '7', '2', 'F', '6', '0', '5', '6', '6', '5', '5', '5', 'E', '7', '1', '6', 'A', '4', 'D', '0', 'D', '2', 'C', '1', '5', 'B', '2', 'F', '6', '0', '7', 'A', 'D', '0', '4', 'E', 'D', 'F', '4', '8', '4', '4', '1', '1', '2', '5', '7', '1', '5', '6', 'B', '9', '9', 'B', '0', '4', 'E', '7', '1', '1', '2', '5', 'D', '5', '3', 'D', '6', '1', '9', '6', 'D', 'B', 'B', 'B', 'B', 'B', '7', 'B', 'D', '2', '3', '5', 'C', '9', '1', 'F', '8', 'F', 'E', 'F', '5', '0', 'E', 'F', '7', '7', 'F', 'B', 'E', '5', 'C', '0', 'E', 'B', 'B', '7', '3', '1', 'E', '0', 'A', '9', 'A', '0', '8', '1', '3', 'B', 'D', '4', 'F', 'D', 'A', 'F', 'B', '8', '7', 'E', 'B', 'E', '1', 'E', '5', '3', '1', 'A', '0', '4', '2', '5', 'F', '8', '8', '0', '8', '8', 'A', 'A', '3', 'F', '3', '7', 'D', 'C', '2', '5', 'E', 'E', 'D', '7', 'F', '7', 'B', 'D', '5', '9', '3', 'A', '5', 'D', '9', 'D', 'C', 'F', 'E', '9', '7', '3', '7', '6', '4', '7', '7', '4', '7', '1', '9', '7', '3', 'A', 'C', 'C', '6', 'A', 'F', '3', '8', '9', 'A', '4', 'C', 'C', '2', '6', '7', '8', 'A', 'E', 'C', '6', 'D', 'C', '7', '3', 'F', 'F', '4', '7', '1', '8', 'C', '3', 'F', '2', 'B', '4', 'F', '5', '5', '4', '8', '4', 'B', 'B', '5', '5', '2', 'C', 'D', 'F', 'B', '8', '4', '5', 'C', '3', 'A', 'D', 'B', '7', 'B', '5', '1', 'E', '9', '9', '7', '9', '0', '8', '6', '3', '7', '5', 'D', '6', '4', '7', 'A', '2', 'B', 'D', '6', 'A', '0', '4', 'D', '1', 'D', '8', '8', 'E', 'A', '3', '8', '3', '0', '9', 'B', 'B', 'E', 'E', 'E', 'C', 'C', '4', '8', '6', '0', 'D', '5', '9', '2', '6', '6', '5', '6', '9', '0', '4', '5', '1', '9', 'E', '6', '0', '2', '8', 'F', 'F', 'E', 'C', 'C', '2', '5', '3', '8', 'E', '1', '8', '4', '8', '6', 'D', 'E', '8', 'C', '3', '9', 'D', 'F', '2', '8', '7', '8', '0', 'B', '6', '6', '1', '7', '8', '1', '1', '0', 'B', '3', '1', 'D', '3', '7', 'B', '3', 'F', '5', '8', '0', '1', '4', '1', '5', '0', 'D', '4', 'D', '3', '1', '7', '4', '8', '6', '7', 'A', '4', '1', '4', '8', '1', '5', '2', 'A', '9', 'A', '0', '3', '1', '3', '4', '6', '9', 'F', 'F', 'E', 'A', '2', 'C', '5', '0', '9', 'B', '9', '5', '9', 'F', '1', 'A', 'C', '2', 'F', 'B', '5', '1', 'B', '2', '3', '5', 'B', '2', '3', 'C', '2', 'E', '3', 'F', '7', '5', '6', 'A', 'D', '7', '2', 'C', '3', 'B', '7', 'D', 'C', 'B', 'D', '8', '4', 'B', '9', 'E', 'D', 'E', 'F', '7', 'A', 'C', '6', '6', '6', '6', 'A', '5', 'C', '5', 'A', '3', '1', 'E', '2', '2', '2', '6', 'D', 'A', '3', 'F', '7', 'D', 'E', '4', '3', '9', '2', 'D', 'F', 'A', 'B', 'A', 'E', 'E', '2', '3', '1', 'B', '3', '3', '0', 'F', 'F', 'D', '0', '5', '3', 'B', '5', 'F', 'B', '5', 'D', '4', '6', '4', '6', 'E', '1', '7', '3', '5', '6', '9', 'B', '8', '7', '9', '2', 'E', '9', 'A', '8', 'F', 'D', '9', 'E', 'B', 'F', 'F', '6', '2', '5', 'B', '6', '9', 'C', '4', '8', '6', 'B', '8', '7', '8', '3', '5', '9', 'F', '5', 'F', '7', 'F', '6', '2', '3', 'C', '5', '3', '4', '7', '6', '2', 'E', 'B', '4', 'D', '7', '0', '3', 'D', 'D', '3', 'B', '6', '7', '0', '7', 'A', 'E', '4', '1', 'F', 'D', 'D', 'F', '6', '2', '4', '7', 'F', '4', '1', '3', '8', 'C', 'E', 'F', 'F', 'C', '4', '1', '4', 'A', '4', 'D', '3', '6', 'F', '7', '4', '5', '1', '9', 'D', 'A', '0', 'A', '1', '5', '4', '6', 'A', '8', '8', '4', '6', 'F', 'F', '8', 'D', 'C', '3', '7', '9', 'D', '1', 'C', 'F', 'D', '2', '0', '8', '6', '3', '6', 'A', 'F', 'B', '5', 'F', '8', '7', '6', '3', 'B', 'F', '9', '5', 'C', '1', '4', '8', '9', '4', '9', '8', '9', '4', 'A', '2', '2', 'D', 'C', '5', '5', '9', '1', '8', 'A', '6', '2', '6', 'A', '1', '6', 'F', '2', 'F', '5', 'F', '4', 'D', 'E', 'E', '1', '6', '9', '1', '6', '2', 'A', '7', 'B', 'E', 'B', '0', '0', '8', '1', 'B', 'B', '4', '9', '0', 'C', '2', '9', '8', '3', '1', 'F', '5', '4', 'F', '8', '1', '6', '8', '5', '4', 'E', '4', 'F', '6', 'C', '4', '2', '1', '5', 'D', 'E', '4', 'B', '0', '2', '7', '9', 'C', 'C', '5', 'B', '1', '7', 'A', '2', '9', 'F', '5', 'F', '5', '7', '3', '4', '5', '0', '9', 'F', '3', '1', '3', '5', 'D', '8', '3', '8', '4', '1', 'D', '0', 'F', '5', 'B', 'F', '8', 'B', '6', '0', '6', '4', '6', 'E', '3', '1', '5', '2', '4', '8', 'C', '5', '3', 'E', '4', 'E', 'A', '3', 'E', '6', '5', '2', 'A', '1', 'C', '3', '8', '2', '3', '8', '1', 'E', '2', 'C', 'E', '5', '3', 'E', 'B', '0', '3', '1', 'E', '4', 'C', '9', '2', 'B', '7', '8', 'C', 'E', 'F', '3', 'E', '9', 'D', 'C', '8', '4', '4', 'F', 'E', 'B', '6', '5', '7', '6', 'F', 'C', '3', '7', '1', 'F', '8', 'D', 'C', '3', '6', '8', '3', '3', '6', '2', '7', 'E', '9', 'F', '1', 'A', 'F', 'D', 'A', '2', '8', 'A', 'F', 'E', '0', 'F', '8', '7', 'A', '8', '6', '9', '7', '4', 'B', 'E', '0', 'E', '4', 'D', '0', 'C', '2', '0', 'D', 'F', '7', '0', '9', '9', '8', 'B', '0', '4', '0', '1', '4', 'D', '9', 'C', 'E', '0', '5', '4', '2', '9', 'E', 'B', '6', '9', 'D', '6', '4', '4', '0', 'A', '9', 'A', '5', 'C', '4', 'A', 'C', '3', 'A', 'A', '9', 'B', '6', '8', '4', 'B', '4', 'D', 'E', 'B', '6', 'A', 'E', '5', '4', '1', '1', '5', '0', '8', '8', 'F', '2', '1', 'A', 'F', '4', '2', '6', '6', '1', 'F', '0', '4', '7', '5', '2', '1', '5', '6', 'C', '3', 'E', 'F', '1', 'A', 'D', '1', '1', '1', '4', 'B', 'E', 'F', 'D', '4', 'E', '7', '6', '5', '1', 'C', '4', '2', 'D', '2', '9', 'B', 'F', '0', '5', 'C', '2', '3', '0', '2', '0', '4', '2', '2', '4', '0', 'F', 'C', '0', '5', '5', 'C', '2', '4', '5', '3', 'B', '0', 'F', 'E', 'E', 'B', '3', 'B', '4', 'F', '2', 'B', 'A', 'A', '5', 'D', '6', '0', 'E', '0', 'D', 'A', 'E', '8', 'F', 'D', '8', '8', 'B', '8', '2', 'B', '6', '9', 'F', '4', '4', '3', '8', '3', 'D', '8', '9', '6', '5', '1', 'D', '6', 'A', '3', '6', 'C', 'B', '9', 'A', '8', 'B', '8', '5', '6', '7', '6', '8', 'B', '4', 'D', '5', '1', '8', '9', '1', 'E', 'F', '9', '2', 'E', '8', 'F', 'A', '6', '8', 'A', 'D', '5', 'D', 'D', 'D', 'E', '0', '7', '4', 'F', '3', 'D', '9', '8', '1', 'D', '8', '2', '9', 'F', 'D', 'D', '5', '4', '3', '2', '0', 'F', 'B', '4', '2', '7', '3', '1', '8', 'F', '6', '2', '6', 'E', '9', '2', '0', 'D', '1', 'F', '4', '7', '8', '6', '6', 'A', '7', 'D', '2', '8', '4', 'E', '9', '1', '2', 'C', '4', '3', 'C', 'E', '2', 'D', '8', 'C', '6', 'C', 'A', '7', 'F', '3', '3', '7', '1', '6', '3', '5', '0', '3', '8', 'C', 'F', '1', '8', '2', '7', '0', 'B', '3', 'B', '8', '8', '5', 'C', '1', '4', '9', '0', '1', 'D', 'F', 'E', '3', 'E', '9', '7', 'C', 'E', 'A', '4', '3', 'D', 'A', 'B', '9', '6', '8', '4', 'C', 'B', '5', 'E', '3', '4', '5', 'E', '8', '7', '5', 'E', '0', 'A', '6', 'D', 'F', '0', 'F', '6', 'B', '3', 'A', '7', 'E', 'B', '5', 'D', '9', '9', '3', '8', '9', 'E', 'E', '9', '3', '0', '7', '9', 'F', 'D', '3', '2', 'A', '2', 'C', 'B', 'F', '0', '1', 'B', 'B', '5', '5', '0', '2', '9', '5', '2', 'B', 'A', 'A', '3', '9', '0', '0', '1', '3', '0', '9', 'D', 'A', 'A', '1', 'F', '2', 'A', '6', '6', 'C', '0', 'E', '5', '5', 'B', 'B', 'E', '5', 'F', '1', 'A', 'C', '7', '5', 'C', '9', '5', '6', '8', 'A', 'A', '5', 'E', 'E', '4', '9', 'F', '9', '2', '0', '0', '4', '6', '0', '1', '4', 'E', '7', 'D', '8', '6', '2', '6', '6', '5', 'B', '3', '0', '5', '6', '5', '1', '2', '1', '2', '0', 'B', '4', 'A', '9', '6', '4', 'E', '9', '3', 'C', 'A', 'D', '3', '6', 'E', '6', 'F', 'B', '8', 'B', '7', '0', '3', 'B', '4', '8', '0', '0', '3', '8', '0', '1', '7', '8', 'C', '5', '3', '2', '9', 'C', '0', 'C', '1', '4', 'E', 'A', '7', 'F', 'C', '9', '4', 'E', '0', '5', '9', '6', '3', 'E', '3', '0', '3', '4', '4', '9', '4', 'F', '5', '4', '3', '6', '5', '3', '9', 'C', '8', '7', '2', 'F', '9', '9', '5', '6', '4', 'F', 'D', '1', 'D', 'D', '0', 'E', '5', '1', '3', '1', 'D', 'D', '4', 'E', '0', '3', '2', '6', '9', '5', 'F', '3', '3', '4', 'C', 'E', 'C', 'D', '2', '0', 'C', 'D', '8', '1', '1', 'C', '1', 'E', 'A', '9', 'B', 'E', 'F', 'D', 'C', 'D', 'F', '1', '8', '5', '9', 'A', '9', 'B', '1', 'C', 'D', '8', '9', 'A', '1', '9', '3', '6', 'A', '5', 'E', 'F', 'D', '1', '3', '6', 'A', '4', 'A', '0', '0', '1', '5', '4', '7', '1', 'A', '6', '4', '6', 'B', 'C', 'A', '4', 'D', 'A', '3', 'B', '8', '5', 'E', '7', '7', '0', 'B', '7', 'D', '8', '0', '3', '4', '6', '3', '0', 'D', '1', '4', 'D', 'D', '8', '3', 'C', '4', 'C', '8', 'F', 'E', '4', '8', 'D', 'D', '3', '0', '6', '7', 'F', '2', '5', 'C', '0', '7', '7', '4', '3', '4', '9', 'D', '9', '8', '0', '7', '1', '7', 'C', '3', '4', 'E', '7', 'D', '9', '1', '0', 'D', '1', 'A', 'D', 'D', 'B', '6', 'A', 'C', '4', '6', 'F', '2', '8', '8', 'B', 'B', '5', '3', 'C', 'E', 'A', '1', '0', '3', 'F', '0', 'A', 'B', '1', 'F', '2', '8', '2', '1', '6', '0', '6', '1', '7', '2', '9', 'B', 'A', '4', '0', '7', '7', '5', '2', '9', 'C', '6', '8', '1', 'E', '7', 'D', '6', '5', '1', 'A', 'C', 'C', '7', 'B', 'D', '1', 'A', '8', 'B', '6', '6', 'D', 'A', '8', '7', '9', '2', '3', '1', '3', 'A', '0', '9', '1', '5', '8', 'C', 'C', 'C', '2', '0', '0', '6', 'E', 'C', 'A', '9', '4', 'C', '3', 'A', '2', '1', '2', 'B', '4', 'B', '7', '3', '7', 'C', '9', '6', '9', 'C', '6', 'D', 'B', '5', '7', '0', 'B', '7', 'E', '0', 'A', '4', '4', '3', '0', '9', '9', 'A', '7', '2', 'E', 'C', 'B', '5', '7', '1', 'C', 'A', 'A', '7', 'B', 'F', 'C', '5', 'C', 'F', '5', '8', 'E', '9', 'D', '6', 'D', 'E', '3', '0', 'A', '4', '2', 'F', 'D', 'D', '1', 'A', 'B', 'C', '8', 'A', 'D', 'F', 'C', '8', '1', 'F', 'F', '6', '8', 'D', '2', 'E', 'C', 'E', '9', '4', '2', 'B', 'C', 'A', '4', '0', '9', '6', '4', '3', '7', '3', '3', '0', '2', '0', 'F', 'C', '5', '6', '9', '8', '1', '1', '1', '8', 'D', '8', 'D', '0', 'A', '1', 'F', '5', 'F', '3', '0', '7', '5', 'B', '3', 'F', 'D', '1', '4', 'F', 'C', '7', '0', '2', '3', '7', '8', '6', '9', '1', 'A', 'C', '6', '7', '3', '0', '2', '3', '5', 'D', '5', 'E', '6', '7', 'C', '8', '6', '0', '9', '9', '2', '8', 'E', '2', '2', '7', '2', '4', '5', 'B', '8', '4', '4', 'E', '8', 'F', '6', 'E', '9', '2', 'C', 'D', '2', '0', '7', '6', '4', '8', 'C', 'D', '4', 'E', '5', 'A', '1', 'E', '4', '6', 'E', '8', 'E', '0', '5', '8', 'F', 'C', 'F', '0', '4', 'F', '7', 'D', 'E', '8', '2', '5', 'B', 'A', '6', '1', 'C', '5', 'C', '2', '0', 'E', 'D', 'C', '1', '3', '2', 'C', '8', '3', 'A', 'E', '1', '6', '2', 'B', '6', 'A', 'D', '0', '7', 'A', 'D', '4', '3', '4', '9', '2', '2', '1', '5', '1', '4', 'D', 'B', 'A', 'B', 'F', '5', 'C', 'D', 'E', '4', 'C', '7', '4', 'E', 'E', '6', '2', 'B', 'D', '4', '1', '5', '2', '9', 'B', '0', 'F', 'A', '0', 'D', '7', '3', 'D', '8', '5', '1', 'D', '7', '2', '5', '5', '8', 'F', '1', '7', '9', '5', 'B', '8', '2', '7', '2', 'E', '8', 'F', 'F', 'F', '2', 'A', 'D', '9', 'E', '9', '5', '4', 'D', '6', 'F', 'F', '9', '7', '5', 'F', '0', '8', '4', '1', '6', '8', '5', '2', 'A', 'B', 'F', '2', 'D', '8', '1', 'D', 'A', 'A', '5', '2', 'B', 'B', '4', '5', '2', 'F', '3', 'A', 'A', 'F', '6', '7', '8', 'E', '7', 'C', '0', '4', '1', '7', '6', 'C', 'A', 'D', '5', '6', 'D', 'B', 'D', '1', 'C', 'B', '9', '3', 'B', '1', 'B', '7', '4', 'F', '8', '5', 'B', '7', 'A', 'F', '5', 'C', '4', 'E', 'E', '0', '3', '1', '2', '3', 'A', '1', '7', '3', '8', '0', '1', '6', '9', '9', '8', '4', '0', 'F', '2', '1', '3', '0', 'F', 'E', '2', 'D', 'C', 'D', '3', '5', '0', 'C', '7', 'D', 'C', 'C', '0', '0', 'A', 'D', '0', 'E', 'D', 'F', '9', '1', '2', '9', 'E', '7', 'C', '2', 'E', '6', 'A', '6', '5', 'D', '2', 'C', '3', 'B', '0', '6', '2', '3', 'B', '2', 'E', '7', '4', '9', '1', '6', 'A', '3', '5', '7', '0', 'D', '0', 'C', '9', '8', '1', 'E', 'D', 'B', '0', '2', '8', 'D', '9', 'F', '1', '8', '9', '0', '0', 'A', 'A', '2', '0', '5', '3', '9', 'F', 'F', 'A', '3', 'E', '7', '7', 'F', '3', '6', 'D', 'C', '8', '4', '6', 'D', '1', 'B', '4', '8', '0', '2', 'B', '5', '8', '1', '2', '4', '1', 'A', 'E', 'D', '8', 'B', 'A', 'A', 'A', 'E', 'F', '5', 'F', 'D', 'A', '5', 'A', '4', 'D', 'D', '5', '1', 'E', '2', '5', '2', '0', '7', 'E', 'F', 'C', '1', '0', 'B', '5', '1', '4', '7', '8', '3', '6', '1', 'E', 'C', 'A', '4', '1', '2', 'F', 'B', '8', '6', 'B', 'E', '9', 'D', '8', 'B', '4', '8', 'F', '8', '5', '4', 'C', '1', '6', 'C', '5', '8', '1', '6', '7', '2', 'C', 'C', '5', '3', 'A', '0', 'C', '9', '4', 'A', '2', 'F', 'B', '7', '4', '6', 'F', '2', '6', 'B', 'F', 'C', '6', '2', 'A', 'D', 'D', '1', 'B', 'B', '0', '9', '9', '8', '3', '8', 'C', '4', '2', '9', '1', '0', '2', '7', '8', '6', '5', '7', '8', 'E', '7', 'A', '1', '0', '4', 'C', '3', 'C', 'D', '4', '4', '1', 'D', 'C', '5', '1', 'C', 'B', '5', '2', 'B', '6', '1', '6', '6', '4', 'C', 'D', '7', 'C', '7', '1', 'A', '5', 'B', 'A', 'F', 'D', 'D', '5', 'E', 'B', 'A', 'D', '6', 'A', '9', 'A', '6', 'B', '5', '3', '8', '0', 'C', 'A', 'B', 'A', 'D', '7', '1', '0', 'B', '1', 'F', 'B', '9', '8', '1', '4', 'F', '8', '7', 'F', '5', 'D', '5', '9', '5', '1', 'D', '9', '0', 'A', '1', '7', '4', '2', '4', 'C', '6', '6', '8', '3', '9', '8', '0', 'A', '8', 'D', 'C', '1', '6', '9', '7', 'A', 'E', '6', '3', '8', '8', '4', 'F', '6', 'F', 'B', 'A', '8', '5', '3', '9', 'E', '9', 'E', 'E', '6', 'B', 'D', '8', 'E', 'C', 'C', '6', 'D', '4', 'F', '1', 'A', '2', '8', 'B', '0', 'B', '2', 'D', '4', 'B', 'C', '8', 'C', '2', '4', '0', 'A', 'F', 'B', 'E', '1', 'C', '0', '2', 'B', 'D', 'A', 'E', 'B', '9', '0', '9', '1', 'D', 'F', '6', 'B', '7', 'A', '0', '0', 'A', '6', 'C', 'F', '6', 'A', '5', '9', '3', 'B', 'B', '2', '5', 'C', '7', 'D', '6', 'D', 'F', '1', 'A', 'D', '6', 'C', 'B', 'C', '2', '1', 'E', 'B', 'F', '2', '5', '7', 'C', '8', '1', '2', 'B', '1', '9', 'E', 'B', '2', '1', '5', 'A', 'D', '0', '0', '6', '1', '7', 'A', 'D', '0', '8', 'D', '2', '0', '0', 'D', '2', '8', '5', 'F', 'A', '0', 'A', '6', '2', 'A', 'C', 'D', '5', 'D', '3', 'D', 'F', '3', '5', '5', '8', '8', 'D', '6', '3', '4', 'A', '1', '9', '8', 'D', '3', '7', 'B', '9', '5', '8', '9', '0', '8', '6', '8', 'D', 'D', 'E', 'D', '5', 'C', '2', 'F', '4', 'C', 'C', '1', 'A', '8', '4', '2', 'C', 'A', '0', '6', '9', '4', 'F', 'A', '8', '5', 'F', '0', '5', '1', '7', 'F', '1', '9', '1', '0', 'F', 'C', 'C', 'D', '1', '4', '2', 'A', 'E', 'B', '5', '6', '0', 'D', 'B', 'F', '6', '0', 'C', '3', 'F', 'A', '1', '6', 'B', '2', '9', 'B', '1', '9', '3', '7', 'E', 'A', 'A', '2', 'C', 'B', '7', '4', 'B', '0', '7', 'A', '6', '9', '5', 'F', 'E', 'A', 'E', '5', '1', '9', 'F', '4', 'F', '8', '1', 'C', '8', 'F', 'B', '0', '8', '4', 'D', '0', 'D', 'F', '6', '6', '7', 'C', '2', '4', 'E', '3', 'F', 'E', '6', 'F', 'A', 'F', '8', '0', 'A', 'E', '9', '8', '3', 'E', '9', 'F', 'E', 'C', '6', '5', '8', 'D', 'D', '1', '4', '9', 'A', '9', '8', '3', 'F', '1', '6', 'C', 'B', '5', 'D', '6', '6', '6', 'D', '5', '9', 'A', 'F', 'C', '0', 'E', '7', '5', '2', '2', '3', '3', 'B', '7', '1', '2', '4', '9', 'F', 'E', '5', 'B', '9', 'C', 'E', '1', '9', '6', 'B', '1', '8', '9', 'F', 'E', '7', '9', '4', 'B', 'A', 'B', 'C', 'D', 'D', 'B', 'D', '0', '5', '8', 'F', 'D', '2', '2', '1', 'C', '0', '2', '7', '6', 'E', '2', '8', 'B', 'D', '3', '4', 'D', 'C', 'A', 'A', 'B', 'E', '8', 'A', 'A', '1', 'D', 'C', '4', '9', '7', 'F', 'B', 'E', '9', '3', '1', '7', 'E', '4', '6', '7', '4', 'B', '8', '6', '6', '9', 'B', 'C', '4', 'C', '2', '1', '7', '4', '6', '2', 'F', '7', '7', '5', '4', 'E', '9', 'C', '3', 'A', '7', 'F', '1', '3', 'C', '7', '9', 'E', '2', '8', '8', '0', 'A', '4', '1', '8', '2', 'A', '9', 'D', '0', '0', '1', '2', '0', 'D', 'C', 'B', 'E', 'D', '4', '5', '9', '6', '3', '5', 'E', 'B', 'E', '5', '3', '8', '9', 'B', '7', 'C', 'E', 'F', '4', '9', '2', 'B', '2', 'E', '6', 'C', '8', 'B', '0', '0', 'D', 'E', 'C', '3', '9', 'F', 'D', 'F', 'D', '2', '4', '5', '4', '3', '0', '8', '9', '7', '4', '8', '9', '8', '4', '7', '8', '4', '7', '8', '3', 'A', 'E', 'A', '0', '9', '9', 'B', 'D', '3', '7', '6', 'A', '7', '5', '4', '8', '6', 'F', '3', '4', '9', 'C', '8', '8', 'A', 'E', 'C', '5', 'D', 'E', '5', 'D', 'A', '0', 'E', '1', 'E', 'D', '7', '6', '2', 'F', '9', '3', 'B', '3', 'C', 'A', '8', '4', '4', 'A', '1', '6', 'F', '9', '0', '1', 'C', '3', '9', '6', '6', '3', '4', '0', '7', '1', '2', 'E', '8', 'C', '1', 'F', 'B', 'D', '7', 'C', '2', '5', '9', 'C', '7', '7', 'D', '2', '6', 'B', '1', 'A', '3', '7', '5', '3', '6', 'C', '0', '8', '5', '8', '5', '9', '3', '5', 'F', 'B', '0', 'D', 'F', 'E', '5', '5', 'D', 'B', 'D', '4', '8', 'E', '3', '1', 'B', '9', '5', 'D', '8', '6', '8', '0', '3', 'D', '0', '9', '2', 'C', '2', '4', 'B', '3', '5', '7', '6', '3', '4', 'F', 'B', 'F', '0', '1', 'C', '6', 'C', 'B', '3', 'A', '6', '0', 'E', 'B', '6', 'E', '1', '5', '3', 'E', 'C', 'E', 'E', 'F', 'C', 'E', 'F', '4', '8', 'A', '4', '7', '3', '8', '4', '4', '7', 'E', 'F', '3', '6', '2', '1', 'F', '0', '8', '1', '8', '5', '2', '3', '7', '8', 'B', 'E', '9', '3', '8', '4', 'F', '4', 'B', '6', 'E', '2', '9', '5', 'B', '3', '7', '7', 'B', 'D', 'C', '6', '8', '3', '4', 'C', '7', 'C', '0', '2', '0', 'A', '2', '6', '6', '3', '9', 'F', '4', 'C', 'B', '2', '9', '9', 'A', 'D', 'C', '5', '0', 'E', '5', 'F', 'E', '5', '7', 'C', '9', 'A', '0', 'F', '2', '6', 'D', '6', '4', 'C', 'C', '6', '3', '1', 'E', 'F', '5', '7', '8', '9', 'D', 'F', 'C', '4', 'D', 'E', 'C', '9', '8', 'F', '1', '5', '9', '9', 'E', '0', '5', '4', '4', '4', '5', 'C', '4', '8', 'A', '6', 'A', 'E', '5', '4', '9', '9', '8', '1', '7', '1', '0', '5', '6', 'C', 'A', '2', '4', '8', 'A', '2', 'C', 'B', '9', '4', '3', 'B', 'F', 'F', 'D', '6', '0', '0', '9', '9', '9', '3', '4', '3', 'D', 'F', '7', 'D', '0', '9', '1', '2', '0', '8', '6', '7', 'E', '0', '3', '2', 'C', '4', '4', '4', '6', '0', '1', 'E', 'A', 'A', 'A', '9', '1', '9', 'B', '1', 'C', '6', '5', '3', '4', '9', '3', '6', '7', '9', '5', '4', 'B', 'E', 'F', '4', 'A', '3', '1', 'E', 'D', '4', '2', '8', 'D', 'D', 'F', '4', '2', 'A', '2', '4', '6', '7', 'A', 'A', 'C', '6', '0', '1', '2', '1', '4', '0', 'F', '1', '7', '5', '5', 'F', 'E', '0', '2', '3', '8', '4', '8', 'B', '6', '3', 'A', '6', '6', '4', 'D', '0', '3', '9', '1', '3', 'C', '1', '7', '6', 'D', '4', '8', 'B', 'C', 'A', 'E', '0', '0', 'E', '7', '6', 'A', 'C', 'B', 'B', '6', 'A', '1', '2', 'B', '1', '1', 'A', '5', '6', '1', '6', 'D', '1', 'C', '1', '8', '5', '2', '6', 'D', '5', 'F', '4', 'D', 'F', 'A', '8', '5', 'A', 'C', 'F', 'E', '4', '4', '1', '4', '7', '8', 'F', 'C', 'D', '9', '6', '2', 'C', '5', '6', '8', 'F', 'D', 'A', '2', '4', '6', '2', '1', '8', '1', 'D', '3', 'C', '9', 'D', '3', '1', '6', '9', '5', '8', '4', '8', 'E', 'B', '6', '1', 'C', '5', '2', '5', '6', '9', 'B', '4', 'C', '9', '4', '2', 'A', '9', '9', 'D', '4', 'C', 'E', '4', '8', '3', '7', 'B', '3', '3', 'C', 'B', '8', 'A', '5', '6', 'F', '8', '1', 'D', '4', '8', 'B', '1', 'B', '6', '2', '2', '8', 'B', 'D', '6', '7', '9', '4', '7', '5', '2', 'A', 'B', '3', 'B', 'D', 'D', 'E', '5', '0', 'C', 'B', 'B', '4', 'E', 'F', 'A', '9', '4', '9', 'B', 'D', 'E', '5', '4', '8', '8', '0', '0', 'A', '2', 'F', 'B', 'E', '2', 'B', 'E', '5', 'C', '6', 'D', '7', '3', '5', '1', '8', '2', 'C', '6', '4', '5', '2', '3', 'F', 'C', 'E', 'E', '4', '7', '9', '8', '4', '4', 'C', '9', '8', 'C', 'A', '4', 'B', 'A', '2', '2', '1', 'B', 'B', '9', '8', '1', '0', 'B', 'D', 'D', '7', '0', '3', 'D', '0', '2', 'B', '1', '5', '3', '9', '3', '8', 'F', '5', '0', '9', 'D', '5', 'D', 'F', '7', '3', 'A', '9', 'F', '0', '9', 'B', '6', '1', '6', 'A', 'F', '9', '0', '1', 'B', 'D', 'F', '0', 'C', '6', '7', '5', '9', 'A', '5', '4', 'B', '6', '6', '8', '0', 'B', '7', '8', '5', '4', 'D', '5', '0', 'D', '8', 'E', 'D', 'D', '7', '1', '4', 'E', '9', 'A', '9', '0', 'E', '5', '5', '8', '4', '3', 'A', 'F', '0', 'E', 'C', '5', 'B', 'C', 'C', 'A', '3', '5', '8', '8', '5', '0', '9', '6', '5', '5', '4', 'C', '0', '6', 'F', 'B', '9', '2', 'C', '0', 'C', '8', 'B', '9', 'A', 'E', '9', '6', 'A', '7', 'B', '7', '0', '2', '2', 'A', '3', 'E', '7', '2', '8', '3', '4', 'E', '2', '0', '8', '1', '2', 'C', '1', '4', '4', 'F', 'B', '3', 'F', '8', '1', '2', '3', '1', 'E', '7', '6', '5', '8', '8', '8', '5', '2', '0', 'A', '0', '9', '1', '0', '6', 'E', 'B', '7', 'D', '8', 'E', 'A', 'A', 'C', 'B', 'F', '5', 'A', 'B', 'F', '2', '3', '1', '1', '2', '0', '8', '4', '6', 'C', '5', '8', 'E', 'E', '3', '3', '1', '2', '1', '9', '1', '9', '3', '9', 'B', '6', '3', '4', '4', '5', '6', '3', 'B', '2', '1', 'D', '0', 'B', 'B', '4', '5', '4', 'D', 'C', '0', '8', '1', 'C', '0', '7', 'A', '7', '2', '1', '4', 'B', '3', '8', 'D', '4', '4', '7', '6', '4', '5', 'B', '3', '3', '1', 'F', '2', '9', '9', 'C', 'E', '5', 'F', '4', 'F', 'F', 'F', '5', 'D', '8', '5', '4', '4', 'B', '4', 'F', '7', '6', '2', '4', '3', 'E', '8', 'E', '7', 'E', '1', '3', '5', '6', 'A', '9', 'B', 'D', '4', 'A', 'A', 'F', '4', '2', 'C', '1', 'B', '8', 'A', '6', '6', 'A', '7', '9', '3', '1', 'E', '9', '6', 'F', '0', 'C', 'A', '4', '3', '0', '9', '3', 'A', '0', '0', 'C', '9', '6', 'C', 'A', '4', '6', '2', '5', '9', '7', '2', '5', '1', '3', 'A', '1', '0', '7', '4', 'C', '7', '4', '9', '2', '3', '5', '0', '1', 'D', '2', '9', '6', 'B', 'E', 'E', 'A', '5', '9', '5', '0', 'C', 'D', '4', '9', '8', '5', '8', '7', 'B', 'D', '6', '6', '0', '6', 'A', 'E', '3', '6', 'D', '4', '4', 'C', 'C', '0', '9', '1', 'A', '3', 'E', '6', '2', '0', '8', '5', 'A', '1', '8', '7', '4', '9', '3', 'E', 'F', 'B', '7', 'C', 'E', 'E', '0', '8', '9', '6', '9', '4', '0', 'D', '0', 'C', '7', 'C', 'E', '5', '1', 'E', '8', '4', '4', '0', '5', '3', '3', '2', '3', '1', '5', '0', 'C', 'A', '7', '5', '6', '2', '3', '6', '6', '2', '5', 'E', 'A', '2', 'E', '9', '8', '8', 'F', '4', '8', 'A', '5', 'D', '2', '5', 'E', 'D', '2', '3', '7', 'F', '2', 'F', 'C', 'A', '0', 'D', 'D', 'C', '4', '1', '0', '2', 'F', 'F', '0', 'A', '8', 'F', '7', '7', '2', '7', '9', '3', '5', '4', 'E', '6', 'B', '8', '7', 'E', '9', 'C', '5', '0', '6', '7', '2', '4', '7', 'E', 'B', 'D', 'B', 'C', '1', 'F', 'E', 'A', '0', '5', '8', '2', 'C', '5', 'B', '3', '7', '5', 'C', '4', 'B', 'F', '5', '8', '1', 'A', '0', '5', '8', '0', '8', '4', '0', '5', '0', '4', 'E', '3', '2', 'C', 'C', '5', 'C', '9', '0', '5', 'B', 'D', '4', 'E', '1', '9', '2', '7', 'F', '5', '9', '1', 'C', 'C', '6', 'C', '4', '5', 'C', 'F', '9', '2', '7', '9', 'C', '3', '3', 'A', '8', 'F', '7', 'A', '1', '1', 'A', '3', '0', '5', '4', '0', '1', 'B', '7', 'B', '1', '1', '2', '8', '3', '7', '9', '6', '2', '9', 'B', 'D', 'A', 'B', 'E', 'A', '4', 'C', 'C', '2', 'D', 'C', 'C', 'B', '6', 'A', '1', '7', '5', 'A', 'C', '6', '3', 'F', '6', '5', 'E', 'C', '1', 'D', 'E', 'A', '1', 'D', 'D', 'F', '2', '9', 'C', 'F', '7', 'D', 'A', '7', '9', '6', '1', 'D', '4', 'D', '3', '2', 'C', 'B', 'C', '2', '4', '9', 'E', 'F', '5', '2', 'D', 'F', '8', '4', '7', '7', 'B', 'E', 'A', '6', '5', '3', '9', '0', '0', '6', 'C', '1', '7', 'D', '5', 'B', '7', '2', '4', '1', '4', 'D', 'D', 'E', 'A', '7', '6', '0', 'A', '9', '8', '3', 'D', 'B', '5', '0', '0', '5', 'A', 'C', '8', 'E', 'B', 'B', '4', '9', 'B', 'B', '9', '2', '5', '4', 'F', '2', 'C', 'C', '2', '1', 'C', '8', 'B', 'A', '7', '2', '3', '9', 'F', '1', '6', 'A', '1', '1', '7', '2', 'E', '8', 'B', '8', '1', '5', '7', '4', 'B', 'E', '6', 'C', 'C', 'E', 'C', '3', 'F', '1', '7', '8', '3', '4', 'D', '4', '2', '7', '9', '1', '7', '7', 'D', 'E', '3', '3', '6', '8', '2', '7', '5', '8', 'C', 'D', '4', 'B', 'A', 'C', 'D', 'B', '2', '9', '3', '9', 'E', 'A', 'B', '5', '0', '0', 'C', 'C', '9', '6', '5', '0', 'E', 'E', '4', '3', 'B', 'D', 'C', 'D', 'F', '6', '3', '8', 'B', '8', '9', '5', 'B', '3', '0', '3', '5', '9', 'C', '8', '4', '9', '7', '0', 'D', '3', 'D', 'C', '6', '0', '0', 'F', '4', '3', '9', '3', '6', 'E', 'D', '8', 'B', 'F', '3', '5', '5', '5', 'D', 'E', '1', 'B', '3', 'E', '4', '3', 'D', '8', 'B', 'E', '8', '7', '3', '2', '4', 'F', '6', 'F', '2', '0', '9', '1', '6', 'F', '2', '4', '4', '2', '5', 'B', '2', 'F', 'B', '5', '1', 'D', '3', '5', '1', '4', 'E', 'A', 'E', 'C', 'E', 'F', '0', 'B', '2', '3', 'A', 'C', 'E', 'B', '4', '5', '2', 'B', '4', '8', '0', '2', 'A', 'D', '8', 'F', 'E', 'B', '0', '2', '1', 'F', '2', '4', '9', 'C', '0', '5', 'F', 'A', 'E', '2', 'F', '6', 'F', '5', 'A', '9', '0', 'E', 'B', 'A', '1', 'A', '2', '7', '7', '1', 'C', '5', 'C', 'E', '5', 'A', 'F', 'D', '7', '6', 'A', '1', 'B', '0', '8', '1', 'C', '6', '1', 'B', 'A', '1', '6', '4', '2', 'A', '7', 'A', '1', '6', '2', 'B', '1', 'E', 'A', '1', '7', '9', '5', '1', '9', 'A', '8', 'F', '7', 'C', '7', 'A', '5', '1', '2', 'E', '5', 'D', '9', 'E', '2', '1', 'C', 'B', 'E', '9', '8', '4', '9', 'C', '5', 'F', '6', '6', 'A', '4', '7', 'A', 'C', '9', '0', 'F', '5', '3', '7', '4', '0', '8', '1', 'A', '8', '2', '3', '4', '9', 'C', '2', '2', '4', 'A', '9', 'C', '2', 'F', 'A', 'D', 'E', '8', 'A', 'A', 'E', 'D', '7', 'B', '3', 'B', '1', '7', '7', '7', '1', 'A', 'B', '6', 'D', 'C', 'A', 'B', '8', 'E', 'F', '7', '5', '7', '7', 'A', 'C', '2', '1', 'D', '8', 'D', 'E', 'B', 'B', '4', 'C', '9', 'B', '2', 'F', 'C', '4', '2', '9', '0', 'E', '0', '5', 'B', '4', '4', 'D', 'D', '3', 'F', '1', 'A', '7', '6', '9', '5', 'E', 'B', '1', '0', '8', 'C', 'C', '9', '2', 'C', '7', '5', '3', '9', '1', 'E', 'E', 'B', 'E', 'B', '0', 'C', '2', '3', 'C', '9', '4', '6', '7', '7', '5', '1', 'A', 'A', 'C', '9', '2', '3', '7', '4', '3', '5', '2', 'B', 'D', 'B', '6', '9', 'D', '2', 'C', '4', '0', '4', '3', '5', '0', 'E', 'A', '1', 'C', '7', '8', '7', 'E', 'E', 'D', 'E', 'A', 'E', '3', 'A', 'D', '6', '9', 'F', '3', 'A', '9', '1', '4', '0', '3', 'D', '6', '4', 'B', '0', 'A', 'D', '8', 'C', '4', '2', '5', '5', '0', '2', '4', '8', '0', '4', '5', '9', '1', '1', '2', '1', '5', '5', 'E', '0', '6', '0', 'E', 'C', '9', 'E', '3', 'D', 'F', 'D', 'D', '6', 'F', 'F', '3', 'C', 'D', 'E', '9', '2', '6', 'D', '4', '1', '3', '8', '3', '3', 'F', '3', 'B', '0', 'B', 'F', '3', '1', '6', '6', '7', 'F', 'D', '4', 'B', '9', 'D', '3', 'B', 'B', '9', '5', 'C', 'F', '1', '9', 'E', '0', '8', 'B', '8', 'A', '2', 'D', 'F', '1', '9', '7', '4', 'D', '6', 'E', 'D', 'A', 'F', '0', '0', '3', '6', '2', 'E', '0', 'C', 'C', 'F', 'A', 'C', 'C', 'B', '1', 'D', 'B', 'F', '3', 'C', '5', '3', 'A', '7', '8', 'C', 'F', 'E', '8', 'E', '4', 'B', '4', '0', 'D', 'C', '8', 'B', '5', 'E', 'D', '1', '9', '2', 'B', '8', '3', '9', '8', 'C', 'E', '1', '9', '3', '5', '7', '8', 'D', '7', '5', '7', 'B', 'B', 'F', 'A', '4', 'B', 'D', '2', 'B', 'F', 'A', 'E', 'E', 'F', '5', 'A', '1', '6', '6', 'B', '1', '9', '3', '4', 'C', '8', 'E', 'C', 'D', '9', '2', '6', 'A', '6', 'B', 'F', 'F', '3', 'E', 'D', '1', 'D', '4', '5', 'E', '6', '7', 'F', 'D', '8', '0', '9', 'E', 'F', 'C', '2', '4', '5', '0', '7', '9', '0', '4', '0', '9', '7', '2', '4', '4', '3', 'D', 'E', '8', 'D', 'E', 'E', 'A', 'B', '6', '2', '0', 'B', '0', 'F', 'D', '7', '5', '4', '0', 'C', '3', '4', '0', 'D', '1', 'F', '1', '2', 'C', '9', 'C', 'D', '6', '9', '6', '8', 'E', '8', 'C', '2', 'F', 'D', 'B', '0', '3', '4', 'C', '7', 'C', '7', 'A', 'C', 'E', '5', '8', 'C', '6', '5', '0', '9', '6', '8', 'D', '5', '4', '0', 'C', '0', 'A', 'D', 'A', 'F', '6', 'B', 'E', 'D', '8', 'E', '5', 'B', 'D', 'B', 'B', '6', 'E', '5', '3', '8', '4', '5', '5', 'E', 'B', '3', '7', '6', 'E', '1', '2', '7', '3', '4', 'E', '7', '1', 'B', 'D', '2', 'B', '8', '8', 'F', '9', '2', 'C', '7', '4', '1', 'E', 'C', 'E', '8', '1', '2', 'A', '2', '8', '3', '9', '2', '4', 'A', '7', '3', '5', 'E', 'F', 'B', '7', 'F', 'C', '3', 'D', '3', 'B', '8', 'E', 'E', '2', '3', 'B', '0', '0', '8', '5', 'D', '3', '5', 'D', 'C', '9', '7', 'B', '2', 'B', 'E', 'A', '5', '2', 'E', '7', '9', 'D', '1', '3', '7', '3', '5', '5', '2', '5', 'F', '0', '3', 'E', '8', 'B', '9', '8', '2', '7', '4', '3', '4', '7', '8', '1', '1', '6', '8', 'A', 'E', '0', 'F', 'E', 'A', 'E', '2', '9', '3', 'C', '6', '4', '3', '6', 'B', '6', '4', 'B', 'F', '4', 'A', '9', '2', 'B', 'F', '1', '6', '3', '7', '6', 'A', '5', '9', 'D', '9', 'E', '8', 'C', '1', '5', '5', 'B', '0', '9', 'C', '9', 'E', '0', '4', '4', 'E', 'E', 'B', '0', 'F', '5', 'A', '2', '7', '7', '4', '1', '6', '6', '3', 'F', 'F', 'D', 'D', '2', '0', '6', '2', '3', 'B', '9', '4', '6', 'C', '5', '1', 'C', '8', 'B', '4', '0', '0', '2', '8', '5', 'A', '2', '3', 'F', '0', '5', '3', '7', 'C', 'B', 'D', '2', '2', '5', 'F', 'A', '5', '1', 'C', '3', 'A', 'D', '8', 'C', '6', '3', '5', '2', '3', '7', 'C', '1', 'A', 'B', 'C', '7', '5', '4', 'D', '2', 'E', 'D', '3', '0', '9', '3', 'C', '5', '4', 'F', '1', '3', '3', 'E', 'C', 'A', 'C', 'A', '1', '9', 'B', '2', '6', 'C', '1', '5', '7', '3', '4', '2', '6', 'C', 'A', '1', 'E', '6', '5', 'D', '8', '9', 'F', '7', '6', 'E', 'A', 'E', '1', '4', '9', 'F', '3', 'F', '1', 'C', '5', 'C', '2', '0', '7', 'A', 'D', 'A', 'F', '8', '6', 'E', 'E', '6', 'E', '4', 'C', '1', '3', '4', '4', '1', 'C', 'A', '4', 'D', '6', 'E', 'E', '5', 'E', 'F', '5', '3', '5', '0', '7', 'B', 'F', 'D', '5', 'E', '7', '3', 'A', 'E', 'E', '2', '7', '2', '1', '4', 'F', '5', '0', 'E', 'A', '3', '4', '4', 'D', 'D', '3', '9', 'B', '4', 'F', 'D', '8', '3', 'B', 'D', '9', '9', 'E', '7', 'A', '6', 'D', '5', '3', '5', '5', '4', '9', 'F', '9', 'A', 'B', '8', 'E', '6', '8', '4', '3', '6', '9', '2', 'C', 'E', '3', '4', '4', 'A', 'C', 'B', '7', '6', 'E', '7', '7', 'F', 'F', '6', 'F', '2', '7', '8', '9', 'A', '6', '4', '8', 'A', 'B', '2', 'F', '4', '6', '6', '4', '6', '1', '1', 'D', '2', '2', '0', '6', '1', '8', '7', 'E', 'C', '3', 'C', '0', '6', '8', '8', 'E', '4', 'C', '6', '3', 'B', 'E', 'C', '9', '6', '6', 'B', '0', 'C', '6', '0', 'E', '5', 'D', '4', '9', '2', 'D', '9', '9', '0', '9', 'A', '4', '4', 'D', 'B', '6', '0', '7', '3', '7', '8', '6', '1', 'C', 'E', '8', '3', 'A', '7', '1', '4', 'F', 'B', '4', '4', '7', '8', '4', '3', '3', '7', '3', '0', '2', '2', 'E', '0', '2', '8', '0', 'A', 'B', '4', 'A', 'F', '7', '9', '7', '7', '1', '3', '2', '8', '0', 'E', '6', 'F', 'E', '9', '4', '2', '9', '4', '4', '8', 'F', '4', 'A', '7', '3', '1', '8', '9', '3', 'E', 'D', '6', 'B', '8', 'F', 'B', 'B', '3', '6', 'C', '9', '6', '1', 'B', '4', 'F', '3', 'A', '7', '2', '0', 'D', '4', 'B', '1', '2', '8', '0', '9', '1', 'F', '4', 'C', '3', 'A', '0', '8', '3', '3', 'A', '9', '6', 'A', 'E', '3', '1', '6', '8', '9', 'A', '8', '9', '1', '3', '4', '2', '5', '8', '0', '7', '6', '9', 'F', '2', '8', '5', '1', 'E', '1', 'E', 'D', '2', '4', 'F', 'C', 'F', '1', '7', 'A', 'A', 'C', '3', 'C', '9', '6', '7', '1', '5', 'E', '3', 'A', '8', '5', '2', '5', '3', 'B', '9', '9', 'A', '1', '0', 'D', 'B', 'B', 'B', 'B', 'A', 'D', 'E', '1', 'B', '5', 'D', 'E', 'E', '6', 'B', '7', 'B', '2', 'B', 'D', '8', 'A', '8', '3', '5', 'E', 'D', 'C', 'A', '6', 'C', 'D', 'A', 'E', 'D', '9', '6', '7', '2', 'B', '0', 'A', '5', '3', '4', '3', 'D', '0', '0', 'A', '9', '2', '5', 'D', '4', 'B', '5', '7', 'F', '1', '4', '4', 'C', '5', '8', 'C', '0', 'F', '4', 'C', 'B', '7', 'D', 'C', '6', '1', 'D', 'B', '4', '7', '8', 'C', 'D', 'C', '1', '1', 'D', '5', 'F', '4', '7', '4', 'A', '6', '4', '5', '2', 'D', '4', '5', 'A', '4', '6', '3', 'B', '3', '9', '3', 'C', '1', '3', '9', '0', 'D', '1', '0', '5', '5', '6', '9', '8', 'D', '0', '2', '2', 'B', '7', 'F', '5', '2', 'F', '7', 'D', '7', 'F', '4', '9', '6', 'C', '7', 'D', '6', '1', '2', '6', '4', 'A', 'F', 'B', '4', 'D', '0', '5', '2', 'A', 'B', '7', 'E', '9', '0', '4', '4', 'F', '4', 'C', '8', 'E', '2', '2', '3', '3', '9', '8', 'D', '0', 'F', 'D', '5', 'D', '6', '5', '7', 'C', 'C', '8', '4', '0', '5', '1', '7', '0', 'A', '7', '7', '9', '9', '4', '4', '4', '4', 'E', 'C', 'D', '7', '3', '9', '2', '9', 'E', 'A', 'E', 'B', '1', '6', '6', 'C', 'F', 'D', '8', '7', '9', 'D', 'C', '0', 'B', '3', '7', 'C', '4', 'A', '2', '4', 'A', '0', 'A', '0', '2', 'C', '7', 'A', 'B', '6', '7', '2', '4', '5', 'E', 'B', '8', '3', 'A', 'D', '8', '7', '3', '1', '8', '8', '3', '5', 'A', '8', 'B', '4', '2', 'D', 'C', 'C', 'F', '7', '6', '4', '6', 'F', '6', '9', 'D', '4', '8', 'C', 'B', '5', '9', 'F', 'B', '1', '6', 'F', '8', '5', 'C', 'D', '3', '6', '2', '0', '1', '4', '4', 'E', 'E', '8', 'C', '3', '0', '1', '7', '8', '3', '5', '7', 'B', 'C', 'D', '3', '1', '0', 'F', 'A', '4', '9', '5', '8', 'B', '7', '8', '6', '6', 'F', '0', '3', '6', '8', '7', '2', '3', '4', '8', '9', '8', 'E', '4', '3', '3', 'D', 'C', '6', 'D', '5', '3', '1', '9', 'B', '5', '1', '5', 'D', 'B', 'E', '8', '0', '7', '2', '5', '6', 'D', 'A', 'D', 'B', '3', '2', '6', 'A', 'A', 'C', 'D', '7', '3', '0', 'F', 'B', '5', 'A', 'D', '5', 'D', '4', 'F', '6', 'D', 'B', '2', '4', '6', '1', '0', '6', '7', '0', '6', 'F', '8', '5', 'D', '8', '6', '6', '0', '4', '6', 'E', 'A', '2', '8', '5', '9', '9', '3', 'E', '8', '8', '2', 'E', 'D', '6', 'B', '9', 'F', '0', '7', '2', '6', '2', '8', 'A', 'A', '8', 'B', 'D', '5', '2', '5', 'B', '7', '9', '0', 'C', 'D', '6', '6', '0', '3', '7', '8', 'D', '6', 'A', '5', 'D', '3', 'F', 'B', '6', '2', '9', '4', 'F', 'B', 'A', '1', 'C', 'B', '9', '4', '0', 'C', '6', 'A', '6', '6', '9', 'B', '1', 'C', '7', '9', '2', '6', '8', 'F', '1', 'A', '6', '5', 'E', '1', '4', '9', '7', '9', '7', 'D', '5', '3', 'C', 'E', '2', '7', 'B', 'D', '0', '0', 'B', '0', '0', '4', '8', '0', 'E', '7', '9', '4', '6', 'C', 'A', '4', '9', '9', '4', 'B', '5', '6', 'D', '8', '0', 'A', 'D', 'F', '7', 'F', '9', '2', 'D', 'B', '2', 'F', 'C', 'D', '8', '1', 'C', 'F', '7', 'E', 'D', 'E', '7', 'F', 'A', '9', '0', '6', '2', '4', '4', '8', 'C', '2', '3', 'A', '6', 'B', '8', '2', 'B', 'B', '5', 'A', '0', '4', 'C', '2', '8', 'F', '9', '6', '1', '1', '8', 'B', '3', '2', '5', '0', 'B', 'F', '7', '7', 'A', '2', 'C', 'A', 'A', '4', '4', '5', 'D', '5', '3', '4', 'B', 'B', '3', '6', '2', 'E', '0', '1', '4', '4', 'C', '5', 'D', 'E', '1', '2', '1', '2', 'A', 'C', 'D', '1', '8', 'C', 'C', '0', 'A', 'E', '1', 'B', '0', '6', 'E', '7', 'A', 'A', '7', '2', '3', '4', '6', '6', 'C', 'B', 'D', '8', '6', '5', '3', '4', 'C', 'D', '1', '0', 'E', 'F', '2', '4', '5', 'A', '3', '0', 'B', '7', 'E', '3', 'A', '9', 'B', '3', 'F', '7', '6', '4', '7', '7', 'E', 'D', 'E', 'C', '2', 'B', 'B', '4', '3', '1', 'A', 'A', 'E', '8', 'E', '9', '7', '0', 'D', 'D', '2', '5', 'A', 'E', '9', 'F', 'A', '1', 'F', 'A', 'B', '9', 'C', '4', '9', 'C', 'E', 'E', 'D', 'D', '3', 'D', '5', '7', '9', '2', '1', '4', 'A', '4', 'C', '4', '2', '6', '6', '2', 'A', '5', '4', '2', 'A', '8', '2', 'B', '6', 'D', 'D', '4', '0', '6', '1', 'D', '7', '8', 'F', 'B', '8', '9', '6', '1', '1', '8', 'B', 'A', '7', 'A', '2', '8', '4', '7', '9', 'A', '5', '4', '6', '7', '0', '4', '4', '2', 'D', '3', 'F', '8', 'F', 'D', 'E', '6', '8', '2', 'C', '4', 'E', 'A', '7', '8', 'C', '4', 'F', '7', '9', 'C', '5', 'F', 'E', '6', 'C', 'A', 'E', 'E', '6', 'E', '8', '1', 'D', '6', '3', 'F', 'A', 'E', '6', '7', '6', '0', '1', '9', '2', 'C', 'D', '1', '3', '9', 'C', '6', '1', '1', '6', '3', '0', 'B', '5', '9', 'D', '9', 'B', '9', '8', '0', '0', '1', 'E', '2', '6', 'C', 'A', '1', '9', '5', '5', '7', '4', '9', 'D', 'D', 'F', 'C', '1', '0', '5', '6', 'D', '3', '2', '2', 'A', '0', '6', '1', 'C', '0', '5', 'F', '8', 'E', '5', '2', '9', 'D', '0', '2', '2', '7', '0', 'A', 'C', '3', '2', 'B', '0', 'E', '0', 'A', '9', '7', '0', '6', 'E', '1', 'D', '5', '4', 'A', '5', '3', '8', '3', '4', '5', '9', 'D', 'D', '2', '4', 'A', '4', 'E', '5', '5', 'E', '3', 'A', 'F', '5', 'D', '0', '6', 'A', '9', '9', '4', '0', '7', 'F', 'F', '5', '9', '5', '3', 'B', '9', '1', '8', '0', '2', '1', '1', '3', '3', '0', 'B', '2', 'A', 'A', '7', '3', 'B', '9', '6', '8', '6', '3', '1', '5', '9', '6', '9', '8', 'E', '9', '8', 'A', 'B', '8', '5', '8', 'A', '3', '2', 'A', '8', 'E', 'F', 'C', '6', '0', '3', '9', '7', 'F', '2', 'A', '1', '6', 'A', '3', '7', '5', 'F', 'A', 'C', '7', '4', 'E', '8', 'F', '4', 'B', '8', '0', '0', 'B', '1', '6', 'F', '9', 'C', '8', '4', 'E', 'B', 'C', '2', 'B', '3', '3', '1', '7', '6', '0', '2', '7', '6', '3', '8', 'D', '9', '2', '4', '9', 'E', 'C', '5', '9', '4', 'A', '4', 'E', 'B', 'A', '2', '5', 'E', 'A', '2', '8', 'D', '5', '6', '4', '3', '6', '8', 'D', '3', 'B', 'B', '9', 'A', '3', 'F', '7', '5', '6', 'E', 'D', '0', '5', '5', '3', '4', '7', '4', '8', 'F', '0', 'D', '8', '8', '7', '2', '3', 'D', '5', '2', '9', '5', '0', '8', '7', '9', 'F', '9', '0', '1', 'B', 'B', '7', 'A', '8', '7', '4', 'D', '3', 'E', '4', 'F', '6', '7', 'C', '2', 'A', '9', '3', 'C', 'D', '2', '2', '2', '6', '1', '2', 'E', '9', 'C', 'F', 'D', '3', 'A', 'D', '2', 'E', '5', 'A', '9', '6', '9', '1', 'B', '0', '2', '4', '0', '9', '3', 'D', '6', '0', 'D', '3', 'C', '9', '5', 'D', '9', '2', '1', '9', 'B', '1', 'B', '2', '3', '9', '7', 'B', 'D', '3', '0', '4', '9', '8', '9', 'B', '3', '4', '3', '8', '3', '6', 'E', '4', '8', '4', '4', '6', '9', 'B', '9', '4', '6', 'B', '9', '3', '9', '4', '0', '5', '6', '5', 'A', '8', 'D', 'F', '2', '1', '0', 'A', 'D', 'D', '7', 'D', 'C', '8', 'D', '1', '8', '3', '9', '2', '5', 'E', '2', '4', '4', 'F', '9', 'C', '5', '6', 'C', '6', 'B', 'A', '9', 'E', '2', '9', 'D', '1', '9', '3', 'B', '7', 'D', 'A', '6', '4', 'A', '5', '9', 'C', 'A', 'A', '3', '6', '3', 'E', '7', '3', 'F', 'D', 'E', 'A', 'A', '5', '0', 'D', '1', 'F', '2', '4', '1', '4', '2', 'D', '6', 'A', '9', 'E', 'D', 'B', 'C', 'B', 'B', '7', 'F', 'C', '6', '2', 'D', 'D', '9', 'C', 'C', '0', 'D', 'E', 'F', '8', '5', '8', '6', 'D', 'D', '9', '9', '9', '5', '2', '6', '4', '1', '1', '2', '1', '7', 'A', '2', '3', 'C', '0', '0', '1', '0', '9', '3', '3', '2', '7', '0', '3', 'B', 'B', '6', '7', 'A', 'F', 'E', '4', '6', 'F', 'B', '9', '1', 'D', '3', 'D', 'F', 'A', '4', '4', '6', 'A', 'E', 'F', '3', '7', '3', '3', 'B', '0', '1', 'A', '4', 'C', '3', '8', '8', '6', 'C', 'D', '8', '9', '4', '5', 'F', '1', '6', 'B', 'C', 'B', '3', 'A', 'B', 'E', 'B', '4', 'E', '9', '6', '8', 'B', '6', 'B', '0', '6', '5', '6', '2', 'D', '1', '7', 'F', '3', '3', 'A', 'F', '4', '9', '5', 'F', 'B', 'B', 'E', 'D', '3', '4', '1', 'B', '8', 'F', 'E', '1', 'D', 'C', '0', '8', '1', '1', '8', '0', 'F', '4', 'F', '4', '0', '8', 'C', '5', 'E', '8', '4', '7', 'A', '3', 'F', 'D', '9', 'A', 'F', '4', 'F', '1', 'B', 'D', '7', '6', '2', '7', '4', '4', '0', '7', '1', '9', '4', '6', 'D', '9', 'E', 'C', '7', '1', 'B', 'F', '8', '6', 'A', 'B', '8', 'C', 'C', '1', '4', '4', 'D', 'B', '7', '1', '7', 'D', '1', '3', '8', '6', '7', 'E', '3', '9', '4', '1', '5', '0', '5', '1', 'B', '8', '4', '8', 'B', '2', '8', 'C', '8', '6', '5', '2', '5', 'F', 'F', 'B', '8', '7', '4', '2', 'F', 'F', '0', '0', '9', 'B', 'F', '1', '5', '9', '2', '3', '3', '0', '3', '3', '4', '3', '7', '6', '9', '8', '2', 'F', '4', 'D', '2', 'E', '7', '1', '4', 'D', '7', '9', 'F', '3', 'B', '1', '9', 'F', '9', '4', '3', '6', '2', '1', '8', '2', '7', 'C', '9', '4', 'E', 'A', '8', '2', '7', 'F', '5', '0', 'A', 'D', '0', '0', '7', '2', 'B', '1', '3', 'F', 'C', '4', '7', '6', '8', '3', '3', '9', 'E', '7', '5', '7', '2', 'C', '2', '1', '9', '4', 'F', 'D', 'A', 'A', '7', 'A', '7', '1', '3', '8', 'A', '8', 'D', '8', '1', 'B', '1', 'D', '1', '9', '9', 'F', 'B', '7', '4', '4', '9', 'D', '3', 'F', 'E', '9', '8', '8', 'A', 'A', '4', 'F', '9', 'B', '4', 'A', 'B', '4', 'E', '6', 'C', '9', 'D', 'F', '8', '9', '7', 'A', '9', '0', '5', 'F', '4', 'F', 'F', '6', 'A', '5', 'A', 'D', '8', '4', '7', '7', '5', 'C', '6', '2', 'F', '0', '9', 'D', 'C', '2', '6', 'D', '1', '7', '8', '0', '8', '5', '7', '3', 'B', '7', '6', '8', '8', 'F', 'D', '1', 'D', '0', 'B', '1', 'A', 'D', '0', 'E', 'F', '5', '9', 'F', 'C', '6', 'E', 'C', 'A', 'F', '2', 'D', '4', 'C', 'F', '5', '5', '6', '2', '9', 'D', '9', '7', '3', '3', '8', '2', '1', '0', '1', '7', 'B', 'D', 'D', '0', '4', 'A', '4', '2', 'E', '4', '5', '2', '5', '1', 'E', 'C', '9', 'B', '0', 'A', '5', '9', '6', '9', 'B', '0', '9', '3', '1', '6', 'B', 'F', '1', 'D', '0', '5', '1', '3', '3', 'F', '2', 'E', '5', '8', 'A', '0', '0', '0', 'E', 'E', '4', '5', '2', '2', '9', '4', '2', '5', '9', 'E', '7', '5', 'A', 'C', 'F', '1', 'C', 'E', '3', 'E', '6', 'A', '4', '0', '2', '4', '3', '0', 'F', '7', 'D', 'D', '0', 'E', 'F', 'C', '3', '0', '0', '7', '3', '2', 'F', 'D', '0', '2', '5', '2', '8', '5', 'F', '5', '9', '9', 'A', '5', '6', '4', 'B', '0', '5', '8', '3', 'D', '9', '9', '4', '1', '7', '0', 'B', '0', '5', '6', '6', 'A', 'F', '1', '6', '7', '1', 'D', '4', '2', '0', 'E', '2', '6', '8', 'B', '1', '9', '2', '4', '8', 'B', 'F', '9', 'B', '0', 'D', 'B', 'C', '9', '6', 'F', 'E', '5', '4', '7', 'F', '2', 'B', '5', 'C', '1', 'C', '5', 'D', 'D', '5', '6', 'B', '7', '7', '9', '6', '0', '5', '8', 'B', 'E', 'F', '8', 'A', '3', 'D', '7', 'C', 'D', '4', 'B', '5', '1', 'E', '4', '5', '6', 'B', '1', 'F', 'B', '1', '4', '8', '7', '7', 'C', 'C', 'B', '2', '5', '1', 'C', 'D', 'B', '3', 'A', 'F', '8', '6', '4', 'F', '1', 'D', '6', 'D', 'E', 'B', '2', 'C', '3', 'F', 'C', '9', 'C', 'F', '6', 'E', '3', '1', '5', '3', 'C', 'B', 'E', '1', 'A', '8', 'C', 'B', 'A', 'B', 'E', 'C', 'A', '7', 'D', '7', '3', 'A', '1', '5', '6', '4', '3', 'C', '5', 'D', '2', 'D', 'C', 'F', 'A', '1', '4', '0', 'E', '5', '3', '4', '5', 'F', '3', '8', 'C', '4', '8', 'B', '6', '3', '0', '4', '6', '0', '9', 'F', '9', '8', '3', '6', '1', '8', 'E', '3', '7', '6', '8', 'C', 'C', '7', 'B', 'D', '3', 'C', '5', '8', 'E', 'C', '3', '6', '9', '4', '1', '5', '9', 'B', '6', 'B', '9', '5', '6', '8', 'A', '7', 'F', '3', '7', 'A', 'E', '3', '8', '1', '4', '5', '8', '8', '4', '4', '8', 'A', 'A', '7', 'E', 'B', 'A', 'E', 'D', '9', '6', '3', 'D', '3', '5', '6', 'B', '6', '8', '8', '9', 'D', '0', 'A', '2', '2', 'E', '7', 'A', '5', '4', '6', 'D', 'B', 'E', '0', '6', '6', '9', '7', 'F', '8', '0', 'D', 'A', '0', 'D', '4', '7', '5', '1', 'C', '0', 'C', '8', 'D', '6', 'D', '5', 'D', 'E', '3', 'B', 'A', '0', '2', '5', '0', 'A', '7', '2', 'E', '6', '0', 'D', 'F', '9', '7', '9', '3', 'F', 'A', '3', 'D', '3', '9', '5', '0', 'F', '9', 'A', '7', 'F', 'F', '2', '9', '2', 'B', '7', 'E', '8', '8', '4', '5', 'C', '5', '5', '9', 'B', '4', 'B', '9', '6', 'B', '9', '9', '7', '5', '1', '7', '5', '1', '8', 'A', 'A', '7', 'B', '7', '2', '2', '7', '3', 'D', '9', '1', '0', '2', '2', 'E', '8', 'F', '9', '3', 'D', '6', '8', '2', 'C', '7', '3', '2', '9', '7', '6', '1', '6', 'A', '0', 'D', '1', 'B', '7', '5', '9', 'D', '9', 'D', 'D', 'C', '2', '3', '3', 'A', '2', 'E', '6', '2', '5', '2', '0', '2', '8', '7', '4', '2', '5', 'D', '8', 'D', '9', 'A', 'B', '3', '3', '8', 'D', '0', '1', '7', 'C', 'C', '0', '2', '5', '0', 'C', '8', '2', '5', '4', 'F', 'B', '9', '7', 'B', '6', '4', 'A', '5', '7', 'E', 'F', '7', '5', '6', 'A', '4', 'B', '6', '5', 'D', 'C', '9', '7', '4', 'F', '6', 'C', '1', 'C', '9', '0', '1', 'A', '2', '5', '9', '5', 'D', '6', '8', '4', '1', '5', '6', 'C', '0', '8', 'F', '2', 'B', '6', '1', 'B', '5', 'C', '3', 'E', '5', '9', 'F', '5', '7', '6', 'E', '9', 'C', 'F', 'E', '1', '8', '4', '3', '9', '9', 'F', '5', '9', '5', '7', 'C', '0', 'A', '7', 'B', 'E', '1', 'E', '4', '0', '2', 'E', '7', '2', 'D', '5', '4', '4', '0', 'F', 'A', '2', '9', 'D', '3', 'C', 'D', '2', '0', '0', 'A', '6', 'A', 'E', 'B', '8', 'D', '4', '7', '4', 'C', '5', 'F', '8', '8', '7', '1', '2', 'F', '4', '7', '4', '7', '4', '3', 'E', 'D', 'C', '4', '3', 'E', '9', 'C', '8', 'A', '5', '0', '8', '9', '9', 'E', '9', '7', '7', '5', 'B', '8', '7', '9', 'F', 'B', '9', '4', '0', '3', '7', '0', '3', 'C', '5', 'A', 'F', 'E', 'F', '6', 'C', '4', 'A', '4', '9', '7', 'C', 'E', '6', 'B', 'A', '5', 'B', 'F', 'F', '2', '1', '9', '6', 'F', '6', '5', 'F', '0', 'C', '5', '4', 'D', '7', '3', 'E', '3', '0', '0', '2', 'E', '0', '2', '9', '1', '7', '2', 'B', '7', '7', '8', 'F', 'D', 'F', '9', '7', '5', '8', '7', '9', '0', '7', '2', 'B', '2', 'C', '0', '5', 'D', '2', 'E', '6', '1', 'A', '6', 'E', '5', '2', '4', 'A', '5', 'C', 'A', 'F', '5', '6', '9', '9', 'D', '2', '8', '3', 'F', '7', 'B', '3', 'A', '5', 'E', '5', 'C', 'B', '7', '7', '2', 'D', '8', 'F', 'B', '8', '9', '1', 'E', '6', '6', 'F', 'D', '5', '0', '2', '2', 'C', 'C', '5', '6', '9', 'A', '0', '3', '3', 'B', 'F', 'D', '1', '2', 'D', 'C', '0', 'C', 'C', '9', 'C', 'E', 'E', 'B', 'E', 'F', 'F', '3', '9', '4', '5', '5', '5', '0', 'D', 'C', 'D', '5', '9', 'A', '2', '3', '0', 'C', 'F', '3', '3', '8', '9', '9', '7', 'A', '2', '0', '8', '6', '4', 'F', '4', '9', '9', 'E', 'D', '7', 'F', 'E', '4', 'B', '4', '8', '3', '1', '3', '9', '0', '0', '2', '7', 'B', '4', '7', '8', '5', '6', '4', 'A', '8', '6', 'C', '3', '3', '4', 'C', 'B', 'C', '7', '8', '5', 'A', 'B', 'F', 'E', '8', '8', 'B', 'C', 'E', '0', '1', '2', '7', 'E', '8', '6', 'A', 'D', '6', '0', 'E', '2', '9', '9', 'E', '9', '6', '1', 'E', '6', 'E', '2', 'E', 'F', '4', 'D', 'F', '0', '7', 'C', '3', '3', '1', '2', 'D', 'A', 'C', '9', '2', '7', '1', '8', 'E', '7', 'C', '0', '7', '0', '7', '0', '3', 'B', '5', 'C', '7', 'C', '4', '4', 'F', '2', '5', '5', '4', '9', '5', 'F', 'A', '0', '7', '4', '6', '5', 'A', '5', '4', '5', '7', '0', '9', '7', '1', 'B', 'F', '0', '7', '7', '0', 'C', '7', '9', 'F', 'A', '4', 'B', 'B', '7', '1', '8', '4', '9', '5', 'C', '1', '4', '3', '6', '3', '2', '0', 'C', '0', '1', '4', '2', '0', '5', 'D', '3', '8', '1', '7', '9', '8', 'D', 'C', 'C', '8', 'D', '3', '6', '4', 'C', '5', '6', '8', '4', 'A', '5', '0', '0', '6', 'B', '1', 'B', '8', '0', '8', '9', '7', '5', 'F', '9', '7', '0', '3', '4', '3', '0', '0', '7', 'F', '3', '1', '8', '0', 'C', '2', '9', 'D', 'C', 'D', '7', '0', 'A', 'E', '9', '8', 'A', '2', '2', '8', '6', 'A', 'B', '5', 'D', '8', 'B', '4', 'C', '3', '3', 'A', '4', 'B', '0', 'E', '5', 'F', 'F', '3', 'A', '9', '8', '2', '8', 'D', '6', '6', '4', 'B', 'F', '1', '9', '4', '2', '9', 'B', '4', '3', 'C', '4', '3', '2', 'E', 'D', '7', 'A', 'D', '7', 'B', '0', 'C', 'B', '1', '5', '5', '5', '3', '6', '2', 'A', 'A', '3', 'A', 'B', '4', '9', '4', '0', '5', 'C', '9', '1', '0', 'E', '5', 'C', 'A', '3', '5', 'B', 'A', 'B', '1', '9', '7', '7', 'C', '8', '1', 'C', '7', '8', '7', '4', '6', 'E', '3', '0', 'C', 'F', '3', 'C', '0', '1', '3', '3', 'B', 'D', 'F', '7', '8', '2', 'B', '2', 'C', '8', '8', '8', '5', '7', '7', '7', '5', '9', 'F', 'B', 'B', 'A', '2', 'D', 'F', 'A', '7', 'D', '2', '2', '1', 'E', '3', '7', '1', 'E', 'A', '9', 'E', '8', 'F', '7', 'F', '3', '0', '8', '6', '6', '2', 'F', 'B', 'A', '5', 'D', '3', 'C', '5', '6', 'B', 'C', 'C', '9', '5', 'C', '1', '6', '3', '2', 'B', '9', '7', 'A', '0', '0', '5', '6', '1', '5', 'F', 'E', 'B', '4', 'B', '2', '6', '2', 'D', '3', '8', 'E', '5', 'D', '9', '0', 'D', '5', '3', '8', 'E', '0', 'C', 'E', 'A', '4', '0', '0', '7', 'C', 'F', '4', '3', 'B', '9', '3', '6', '4', 'E', '8', 'E', 'D', 'B', '0', 'C', '4', 'D', '5', 'F', '3', '9', '5', 'D', 'F', 'E', '7', 'A', '7', '1', '3', '8', '2', '4', 'B', 'E', '8', '5', 'C', '8', 'B', 'A', '5', 'C', '4', '0', '7', '7', 'F', '7', 'D', '6', '5', '1', '3', '3', 'C', '8', '5', '9', 'F', 'E', '3', 'C', 'B', 'B', 'E', '5', '6', '1', 'E', '0', '4', '2', 'D', '2', '5', '1', '7', 'C', '7', '6', '5', 'F', 'B', '3', 'D', '6', '1', '5', '7', '0', '1', '3', '9', '7', 'B', 'C', '4', '8', 'E', 'A', 'B', '2', 'B', '0', '1', '9', '0', '1', 'C', 'C', '8', 'E', 'B', '1', '0', '6', '3', '7', 'D', 'C', '5', '5', 'B', '9', 'C', '5', '1', '7', 'A', '5', '3', 'B', 'F', '9', '3', '7', 'B', 'B', '5', '7', '1', 'B', '9', '5', '9', '0', '2', '2', '1', '4', 'A', '6', 'F', 'D', '7', 'D', '0', '5', 'D', 'E', 'A', '3', '5', '1', '4', '8', '0', '4', 'A', 'E', 'B', '5', '0', '8', '9', 'C', 'B', '6', '1', '4', '9', '5', '1', '7', 'E', '7', '1', 'E', 'A', 'D', 'F', '1', '2', '1', '0', 'F', 'D', '6', '3', 'D', '7', 'B', 'D', '4', 'B', 'B', 'D', '7', 'B', '2', '2', '5', '2', 'A', '2', '4', 'D', '4', 'C', 'C', '3', '4', 'E', 'F', 'F', '3', 'E', '1', 'B', 'A', '0', '1', 'A', 'E', '4', 'D', '2', '4', '5', '2', '2', 'D', '9', '9', '4', 'A', '7', '0', 'E', 'D', 'E', 'F', '4', '6', 'D', '5', '0', '0', '3', 'B', '1', '9', 'A', '3', '7', '0', '3', '8', 'C', 'B', '8', '4', '2', '0', 'A', '9', 'B', 'B', '1', '2', 'A', 'F', '1', '6', '1', '2', '3', 'F', 'B', 'C', 'E', '8', 'E', '5', 'E', '6', '4', 'A', '1', '2', '4', 'F', 'B', 'C', '6', '6', '1', 'E', '8', '4', 'E', '8', '3', '4', '5', 'B', '9', '3', 'F', '6', '5', 'E', '4', '1', '0', '1', '3', '8', 'F', 'C', '4', 'F', '9', '3', '6', '9', '9', '8', 'B', 'C', 'E', 'F', 'F', '7', '8', '5', '1', '0', 'B', 'D', 'F', 'B', '9', '4', 'A', '8', 'A', '5', '1', '6', '6', '0', '5', '6', '0', '2', 'E', '0', '5', 'D', '3', 'C', '5', 'D', 'E', 'B', 'F', '0', '4', '4', '8', '6', '0', 'E', '4', '0', 'D', 'F', '1', '5', '7', '1', '5', '4', 'C', '5', '1', '3', 'D', 'D', 'F', '0', 'B', '3', '9', '8', '2', '9', 'C', 'F', '1', '1', 'E', 'D', '0', '8', 'E', '9', '3', 'D', '6', 'F', 'F', '5', '8', '4', '9', '9', '4', '4', '5', '1', '7', 'A', '4', 'F', '4', '3', '3', 'D', 'B', '9', '3', '0', 'D', 'D', '7', '5', '4', '5', '7', '6', '0', 'D', '5', 'A', 'F', 'E', 'E', 'A', '4', '6', 'D', 'A', '4', '6', '5', '6', 'B', '5', 'B', '3', 'C', '4', '4', 'A', '1', '4', 'D', 'B', '4', '6', '4', 'C', 'D', 'F', '4', '8', '4', '0', '8', 'A', '1', '9', '2', 'B', 'B', '2', '9', 'E', 'B', '3', 'D', 'A', '6', 'D', '4', '6', '5', '5', 'A', '3', '4', '8', 'A', 'C', 'E', 'F', '6', 'D', 'D', '3', 'F', '6', '0', '2', '8', '8', '3', '4', '0', 'B', '8', '0', 'E', 'E', '5', 'E', '9', '7', '6', '6', '3', '6', '7', '3', '1', 'B', 'D', 'D', '1', 'B', 'B', '9', '7', 'F', 'A', '6', 'D', 'B', '0', '7', '9', 'A', 'C', 'D', '9', '4', '4', '8', 'A', '1', 'F', 'E', 'F', '4', '6', 'C', 'A', '3', '3', 'B', 'A', '8', '1', '2', '2', 'C', 'C', '9', '9', 'C', '1', 'C', 'E', '2', '1', 'E', '9', 'D', 'D', '7', '9', '4', 'C', 'E', '2', 'A', 'D', '1', 'D', '1', '1', '5', '5', '1', '1', 'E', 'C', '6', '3', '3', '9', '2', 'E', 'A', 'D', '6', '4', '3', '2', 'E', '7', '2', '0', '2', 'E', 'B', 'A', '4', 'F', '6', '8', '2', '4', '0', '5', '0', '7', '7', '5', 'C', '6', '8', '3', '8', 'B', 'D', '6', '4', '2', 'C', 'D', '1', 'C', '9', 'F', '7', '7', 'D', 'D', '7', '8', 'A', '1', 'A', '8', '2', '9', 'B', '3', '5', 'A', '8', '5', '2', '6', '4', '4', 'D', '5', '8', '8', '8', 'A', '7', '0', '6', '5', 'C', '2', '6', 'B', '7', '7', 'F', '5', 'B', '8', '0', 'A', '7', '2', 'B', 'D', '9', 'A', '2', 'F', 'F', '7', 'C', 'C', 'D', '4', '8', 'D', '3', '0', '8', '0', 'E', 'D', '5', 'C', '7', 'E', 'C', '6', '6', 'A', '6', '1', 'C', 'A', '0', 'C', 'C', '6', 'B', 'A', '4', '1', '7', '7', 'B', '5', 'D', 'F', '8', '4', '8', '4', '6', 'D', '4', 'D', '5', 'D', '5', 'A', '9', '2', 'C', '7', '6', '9', '6', 'E', 'F', 'A', 'F', 'C', 'B', 'E', 'A', '8', '6', 'A', '1', 'C', '3', '9', '5', '2', '9', '9', 'E', '5', '8', '4', 'B', '7', 'E', '3', '0', '8', 'F', 'C', 'F', '8', 'C', 'D', 'F', '5', '5', '3', 'F', '5', '2', '4', '4', 'F', '5', '4', '6', '6', 'D', '5', '3', 'B', 'A', '1', '9', '7', '9', '6', 'F', 'A', '6', '3', '1', '3', 'C', '8', '4', '9', 'D', '9', '7', 'A', '4', 'C', 'F', '1', '0', '5', 'B', '1', '0', 'E', 'A', '4', '9', 'C', 'D', 'F', 'C', '2', 'D', '2', 'C', '3', '6', '4', 'F', '3', 'C', '4', 'C', '1', '7', 'C', 'B', 'D', 'F', '3', '7', 'F', '1', '3', 'B', 'E', '4', '9', 'E', '5', '2', '5', '0', '9', '5', '7', '3', '1', '2', 'A', '3', '6', '3', '7', '0', 'B', 'E', '4', '4', '1', '4', 'E', 'D', 'D', '9', '2', 'E', 'F', '1', 'F', '2', '6', 'E', '3', 'A', '8', 'B', 'F', '7', 'D', '9', 'E', 'F', '0', 'F', '5', 'A', 'C', '9', '9', 'A', '0', 'A', '2', 'A', 'E', '5', 'F', 'B', 'D', 'E', '4', '5', 'B', 'D', 'B', '2', '7', '3', '8', '0', '0', 'E', '0', 'F', '3', '0', '0', '3', '5', '5', 'E', 'F', '7', 'B', '7', 'C', 'E', '6', '4', '9', 'E', '6', '5', '5', 'A', 'E', '1', '5', 'B', '1', '3', 'E', 'A', '5', '1', 'F', '9', '5', 'F', '2', '2', 'D', 'B', '7', '1', '3', '9', '2', '8', 'F', 'C', '6', 'F', 'A', 'D', '4', '7', '5', 'E', '0', 'B', 'E', 'E', 'C', '0', '7', 'D', '0', '7', '3', '0', '2', '4', 'E', '9', 'F', '0', '2', 'C', 'F', '4', 'E', 'D', '0', '5', '4', 'A', '6', '2', 'B', 'F', '7', 'F', '1', '2', '5', '5', 'D', 'B', '8', '8', '4', 'C', 'A', 'F', 'E', '4', 'A', '8', '5', 'D', 'B', '4', 'D', '5', 'E', '5', '4', '3', '4', '0', 'B', '0', '9', '7', '5', '8', '1', 'B', 'B', '3', '2', 'B', 'F', '4', '5', '9', '5', 'E', '0', '0', 'B', 'A', '2', '5', '1', 'D', 'D', 'A', '1', '6', '7', 'C', '4', 'F', 'A', '3', 'B', '9', 'A', '0', '1', 'A', 'C', 'E', 'C', 'D', '3', '2', '7', 'A', 'C', 'D', '4', '6', '8', '7', '8', '2', 'F', '8', '4', 'E', '1', 'D', '6', 'A', '2', 'A', '6', 'F', '4', '1', '9', 'E', 'A', '5', '6', '2', 'E', '4', 'B', '3', 'E', '8', '9', '5', '9', 'D', '4', '4', '6', 'E', '2', '7', 'C', 'B', '2', '9', '9', 'E', '8', '8', '6', 'C', '3', '6', '6', 'F', '0', 'F', 'B', 'D', 'C', '1', '6', '7', '8', 'E', 'F', '7', '3', '9', '6', '5', 'B', '7', 'D', 'D', '6', '5', 'C', 'F', '2', 'A', 'A', '6', '6', '5', '1', 'D', '0', '0', 'E', 'B', '5', 'B', '5', 'C', '2', '9', 'D', 'D', '7', 'E', 'C', 'F', '1', '4', '1', 'E', '1', 'D', '8', '3', '4', '7', '9', '9', 'A', '7', 'A', '4', '1', 'B', '7', 'C', 'D', '6', '7', '2', 'A', '6', 'D', 'B', 'F', 'A', '9', 'D', '9', 'A', 'C', 'F', '4', '7', 'D', '5', '9', '9', '6', '2', '7', '1', '0', '9', '6', '1', 'C', 'F', '3', 'D', 'F', '9', 'A', '4', '0', '2', '5', 'B', '0', 'E', '9', 'F', 'C', '3', '4', '9', 'E', 'A', 'E', 'F', '0', '3', 'A', '6', '4', '5', '5', '5', '9', '9', 'F', 'E', 'C', '8', '5', '3', '1', '4', 'B', '3', '0', '1', '3', 'E', '0', 'B', '7', 'D', 'F', 'C', 'D', '1', '9', 'B', 'E', '6', '7', '0', '3', 'F', 'F', 'D', '5', '0', '9', 'B', '3', '9', '2', 'B', '9', 'D', '6', 'B', '4', 'A', '9', 'A', '6', '0', '6', '3', 'C', 'C', 'D', '8', '1', 'E', '2', '4', '4', '4', '7', 'C', '8', 'E', 'B', 'D', '1', '1', '5', '9', 'C', '5', '3', 'A', '2', '2', 'B', '2', '8', '4', '4', '7', '8', '0', '0', '1', 'B', '1', '8', '8', 'C', '0', 'F', '2', '1', 'A', 'C', 'A', '9', '4', '5', '5', '3', '1', '7', 'D', '4', 'C', '0', '3', '7', 'A', 'A', '6', '2', '8', '5', 'F', '1', 'F', '5', 'D', '8', '1', 'D', '3', '7', 'D', 'F', '1', 'F', '7', '4', 'F', 'A', 'F', '3', 'D', '4', '9', 'C', '6', '5', 'D', 'F', 'D', '3', '7', 'D', '2', '9', '6', '0', 'D', '7', '0', 'E', '0', '0', 'D', 'F', '4', '4', 'C', '7', '0', '3', '8', '0', '2', '0', '5', '2', 'C', '4', 'A', 'A', '5', '0', 'F', 'C', '1', '9', 'D', '8', 'D', 'B', 'B', '8', 'C', '7', 'F', '1', 'F', '5', '1', 'D', '1', '4', 'B', 'C', 'A', '5', '8', 'F', '6', '2', '6', '9', '2', 'F', '0', 'E', 'E', '2', 'F', '0', 'A', '7', '6', 'F', '9', '0', '7', '6', '0', 'C', '2', 'C', '1', '2', '5', 'E', 'F', '7', '4', '1', 'D', 'D', '6', '4', '1', '4', 'E', '6', 'B', '7', '4', 'D', 'A', '1', '3', '2', 'B', 'A', 'C', '6', '5', '0', 'D', 'F', '4', '6', 'D', 'F', 'E', '8', 'F', '7', '3', '8', 'D', 'A', 'B', '8', '4', 'D', 'F', 'A', '4', '4', '1', 'E', '3', '8', 'D', '4', '3', '8', 'C', '1', '8', '3', '8', '3', '8', '4', '1', '8', 'C', '2', '7', 'A', 'C', '4', '8', '7', '2', '7', '4', '1', '8', '6', 'D', '8', 'C', 'B', 'D', 'A', '4', '2', 'A', '1', '7', 'C', '1', '3', 'A', 'F', 'B', 'B', '7', 'A', '4', 'B', '8', '5', '1', 'D', '0', '1', '9', '3', 'F', '5', '7', '1', 'C', 'E', 'D', 'F', 'C', 'C', 'C', 'E', 'F', '1', 'A', '3', 'D', '4', 'B', '8', '2', '2', '2', 'A', 'A', '7', 'C', 'F', 'F', 'C', 'F', 'E', '8', 'A', 'E', '7', '0', '1', '6', '2', '2', '9', 'E', '8', '5', 'E', '1', '1', '6', 'B', '6', '2', '2', '6', '0', '5', '7', '1', '5', 'F', '2', 'D', 'C', 'B', '7', 'D', '9', '4', 'D', 'E', '0', 'D', '8', '3', 'B', '8', 'B', 'E', 'A', 'A', '2', '9', '8', '2', '7', '6', '4', 'F', 'D', '7', 'C', '8', '6', '1', 'B', 'D', 'A', 'A', 'C', '4', 'E', '7', '2', '6', '2', 'C', '3', 'B', '0', 'F', '2', 'A', 'E', '2', '4', '6', '8', '6', '6', '4', 'A', 'A', 'F', '3', '0', 'F', 'D', 'D', 'A', '6', '1', '0', 'E', '3', '9', '7', 'D', 'F', '2', 'A', '6', '4', '1', 'F', '9', 'F', 'C', '0', '2', '9', '6', '9', 'F', '8', '1', '0', 'E', 'B', 'C', 'B', '6', 'D', '9', 'B', 'F', 'D', 'C', '5', 'B', 'A', 'B', '5', '6', 'A', '9', '0', 'E', '0', 'C', '3', '7', '9', '6', '3', 'F', 'F', 'D', '0', '1', 'B', '0', 'D', '7', '2', '8', 'A', '0', '2', '8', 'C', 'F', '2', 'E', 'C', '5', '0', '5', 'F', 'E', '3', '2', '6', '8', 'B', 'E', '5', '7', '3', '0', 'B', '5', 'F', '0', 'D', '3', 'D', '5', 'F', 'D', 'C', '9', '7', 'B', '4', '6', '1', 'E', '3', 'B', 'C', '2', '2', '9', 'A', 'E', '6', 'D', 'A', '2', '2', '7', '7', 'E', '6', '0', 'E', 'A', '6', '0', 'C', '8', '3', '1', 'A', '5', '1', '5', 'B', 'F', 'B', '7', '2', '4', '1', '7', '6', '6', '0', '4', '0', 'C', '8', '7', '9', 'F', 'B', '7', 'F', '4', 'A', 'A', '1', '0', 'D', '8', 'B', '4', '8', '6', 'F', '3', '5', 'A', 'B', 'F', '3', '7', '7', '6', '1', 'B', '2', '3', '8', 'B', 'F', 'F', '1', '7', '5', '4', 'C', 'C', 'D', 'C', '9', '1', 'D', 'A', '7', '0', 'F', '7', '6', '7', '8', '5', '2', '1', '5', '5', '5', '5', '4', 'E', '8', 'B', '1', '3', 'F', '5', '2', 'C', '8', 'C', '4', 'F', '9', 'C', '6', '6', '2', 'D', '6', '3', 'A', '9', '8', 'D', 'C', 'C', '9', '2', '3', '9', '7', '9', '8', 'E', '6', '0', 'E', '9', '9', '0', '8', 'B', '9', 'C', '2', 'B', 'F', '9', '4', '2', 'A', 'D', '4', '7', '5', 'E', '1', '2', 'C', '1', '7', '8', '4', 'A', 'B', '0', 'A', '9', '9', '4', '8', '9', '7', '3', '5', '1', 'C', '5', 'B', '3', '4', '8', '3', 'C', '9', '5', 'E', '6', '8', '5', '0', '1', '1', '1', 'D', '5', 'F', '7', 'A', '3', 'E', '7', '4', 'F', '2', '7', 'A', '7', '3', '2', 'D', '2', 'F', '6', '3', 'C', '3', 'F', '4', 'D', '0', '2', '3', '8', '3', '5', '1', '2', '3', '7', 'C', 'E', '9', '4', '8', '4', '2', 'F', '1', 'C', '4', '0', '6', 'E', '4', 'D', 'C', '4', '2', 'E', '8', 'C', '1', '4', '1', '3', '5', '0', '9', '6', '7', '3', '3', 'C', '0', '7', '2', 'D', '4', '3', '2', '1', 'F', '2', '3', 'F', '5', '6', '8', '6', '8', '6', 'B', '5', '0', '0', 'D', '5', 'D', '9', '3', 'B', '9', '1', 'D', 'A', '6', '5', '5', '6', '3', '7', '2', '9', '6', '4', '2', '4', 'B', '1', '7', 'D', '4', 'A', 'B', '6', '8', '3', '2', '5', 'E', '2', '7', 'A', '9', '3', '8', 'C', 'A', 'D', '3', '6', 'A', '0', '5', '6', '1', 'E', '1', '7', '2', '9', '7', 'B', '0', 'E', '8', 'A', 'D', 'F', '4', 'B', '2', '7', '0', '6', '2', 'C', 'B', '4', '1', '7', '8', '2', 'F', 'F', 'B', '5', 'B', '7', '6', 'E', '6', '3', '6', '6', 'D', 'B', '5', 'D', '3', '2', '9', '2', 'A', '6', 'D', '0', 'C', '7', 'D', '4', '3', 'F', 'A', '5', 'D', '8', '5', '7', '3', '8', 'E', 'C', '0', 'B', '0', 'C', 'E', 'A', '6', '8', '6', 'A', 'C', '5', 'E', '2', '1', 'B', 'F', '3', 'D', '7', 'D', '7', 'B', 'D', '3', 'C', '3', 'F', '8', '3', '4', '3', 'A', '8', 'B', '4', '7', 'C', 'F', '8', 'B', '5', '4', '9', '7', '9', 'D', 'A', 'C', 'A', 'A', '0', '3', '3', '5', '8', '4', '1', 'B', '1', 'C', '2', '2', '0', '2', 'C', '8', '5', 'D', '9', '4', '5', '3', '2', '8', 'D', 'A', '0', '0', '5', 'D', 'B', '2', 'E', '9', '2', '4', '8', 'D', 'D', '5', 'D', 'F', 'B', '8', '6', '4', '4', '5', '7', '9', '1', '9', '7', 'A', '0', 'E', '3', '4', '8', 'C', 'E', '7', 'C', '8', '4', '0', '9', '7', '2', '0', '4', '9', 'C', '9', '9', 'E', '0', 'C', '3', 'B', 'A', '7', '6', '0', '9', 'B', 'E', '6', '9', '5', '9', 'C', '1', '7', '6', '1', '8', 'E', '0', 'C', 'F', '8', '1', '4', '5', 'C', 'D', '6', 'F', 'E', 'A', '5', '1', 'F', 'D', 'D', 'D', 'F', '1', '6', '2', '8', 'E', 'A', '3', 'F', '4', 'A', '4', 'D', '4', '0', '9', 'A', '4', '4', 'D', '2', '3', '0', '9', '8', 'F', '2', 'B', '2', '1', '7', 'B', '5', '5', 'A', 'D', '6', '6', 'E', '5', '0', '5', '0', '1', 'F', '4', 'C', 'B', 'A', '6', 'F', '8', '9', 'C', '1', '4', '2', '8', '2', '7', 'A', 'A', 'D', '9', '6', '2', '0', 'C', 'E', '9', '1', '2', '9', 'F', 'C', '5', '2', 'D', 'B', '5', '1', 'A', '1', '4', 'E', '0', 'E', 'B', '1', '1', 'C', '4', '6', 'F', 'F', '9', 'A', '2', '4', 'E', '6', '4', '3', '4', '8', 'A', '0', 'C', '4', 'F', '5', '6', 'D', '1', '0', '4', 'F', '4', '4', 'F', 'B', '0', 'B', 'D', 'D', '5', '5', 'D', 'A', 'B', 'C', 'A', '8', '9', '7', '7', '5', '8', '2', 'D', '1', 'B', 'E', '3', '9', '3', '9', 'F', '1', 'B', 'C', 'A', '9', '9', 'E', '9', '7', 'F', '4', 'A', '2', '8', '0', 'D', 'E', 'C', '5', '0', '7', '8', '4', 'D', '5', '2', '7', '4', '0', '8', 'E', 'C', 'A', '0', 'F', 'D', '2', '9', '0', '3', 'E', '4', 'A', 'D', 'A', '6', '7', 'C', '1', '7', '5', '9', 'B', 'C', '5', '4', '4', '5', 'C', 'C', '3', 'F', '9', 'A', '9', 'E', 'E', 'B', '1', '4', '6', 'B', 'B', '9', '8', 'A', '9', '0', '9', '7', 'C', '0', '6', '2', 'E', '8', 'D', '4', 'B', '3', '4', '5', '2', '2', '5', '0', 'C', 'C', 'D', '4', '6', 'A', '4', 'B', '6', '6', '7', '6', 'C', '1', '2', '7', 'E', '0', 'B', 'C', '9', '1', 'B', 'B', 'F', '5', '3', '6', '5', '9', '8', '0', '5', '6', 'E', 'F', '1', '1', '1', '5', 'B', '1', '7', 'B', 'B', '9', '3', 'D', '8', '7', '6', 'F', '8', 'F', '3', '2', '2', '5', '3', '8', '3', '9', '2', 'F', '7', 'F', '6', '4', 'D', 'A', '7', '3', 'F', 'F', '7', '0', '1', '3', 'A', 'E', 'F', '0', '5', '1', '1', '8', 'F', 'C', 'A', 'D', 'A', 'C', 'C', '5', 'B', '0', 'F', 'E', 'E', 'D', '7', '5', 'B', 'D', '1', 'C', 'B', 'C', '7', '3', 'A', '2', '8', '7', 'E', 'D', '8', '0', '1', 'D', '1', 'C', 'D', 'C', '9', '5', 'A', '5', '5', '3', '1', '2', '2', '1', 'E', '4', 'F', '0', 'C', '8', 'B', '2', 'B', '9', '3', '7', '9', '6', '6', '9', 'C', 'D', '6', '1', '4', '1', '7', 'B', '4', '8', '4', 'B', '5', '0', '8', '0', 'D', 'F', '5', 'D', '0', 'D', '2', '1', '7', '9', '2', '8', '8', '0', 'F', '8', '1', '8', '5', 'A', '1', 'E', '1', '4', '0', 'C', 'B', '6', '3', 'A', '1', '1', '9', '6', '3', '1', '6', '8', 'F', '8', 'E', 'B', '6', 'E', '8', 'F', '3', '9', 'D', 'F', 'D', '6', 'C', '2', '0', '8', '7', 'B', 'D', '3', '9', '6', '6', '1', 'E', 'D', 'C', 'D', 'B', '8', 'F', '1', 'A', '2', 'E', '7', '7', 'E', '9', '8', '2', 'B', 'C', '9', '9', '8', 'D', '1', '6', '4', '1', 'B', 'F', '4', '9', '1', '3', 'A', 'D', '6', '4', '8', '5', 'D', '7', 'D', 'C', '6', '6', '8', 'C', '5', 'E', 'F', '0', '9', '3', 'D', 'B', '9', 'D', '4', '9', '6', 'D', 'A', '0', '2', '3', '2', '5', '9', 'E', '0', '9', '3', 'F', '9', '7', '8', '8', 'B', 'A', '5', 'A', '1', 'C', 'F', '0', '6', '8', '9', '6', 'E', 'F', '5', '1', '9', '0', '9', 'B', 'D', '2', '6', '3', '1', 'D', 'D', '7', 'F', '8', '1', '6', 'A', '4', 'A', 'D', 'B', '3', '7', 'F', 'F', '0', '0', 'D', '6', '1', 'E', '3', '0', 'D', 'F', '7', '7', '1', '2', 'A', 'C', 'D', '3', 'E', '0', '5', '9', '3', 'C', '8', '8', 'A', '0', 'C', 'E', 'A', 'B', '0', 'F', 'B', '7', 'A', 'D', '3', 'B', 'B', '7', 'F', 'B', '8', 'B', '3', '6', 'B', 'B', 'F', '4', '8', '5', '6', '2', '5', 'E', '4', '2', 'D', 'D', '0', '1', '0', '2', '0', '3', '6', '7', '0', '5', '8', 'C', '0', '3', 'A', 'E', '6', '1', 'F', '9', 'F', 'C', 'D', '0', '1', 'A', 'A', '0', '9', 'F', '9', '5', '3', 'A', '3', '6', 'C', 'D', 'B', '8', '1', 'A', '1', 'B', '7', '4', '1', '8', '2', 'B', 'B', '2', '9', '9', '6', '2', '1', '5', '8', 'D', '0', 'E', '0', '5', '5', '1', 'B', '3', 'F', '5', '7', '6', '8', '5', 'A', '5', 'A', '0', 'E', '5', '9', '0', '6', '8', 'D', 'C', '1', '2', '5', 'D', '2', '3', '5', '6', 'C', '5', 'C', '9', '2', 'C', '8', 'A', 'D', '1', '4', 'D', '2', 'A', '8', 'D', '0', '8', 'F', 'E', '5', '4', '3', '4', 'F', '5', '7', '5', '3', '8', 'C', '1', '2', '6', '4', '0', '9', '1', 'E', '1', '0', '6', '4', 'E', 'B', 'C', '8', 'C', '4', '4', '5', 'A', 'F', '6', 'F', 'A', '3', '9', 'A', '6', 'D', 'D', '1', '9', 'F', '4', '6', '3', '3', '9', 'D', 'E', '1', '3', '0', '5', '5', '1', '3', '9', '1', '7', '7', 'F', 'B', 'A', '9', 'B', 'E', 'B', '3', 'A', '5', 'E', '3', 'F', 'C', '6', 'B', 'C', 'B', 'A', '0', '1', '0', '1', '8', '1', 'D', '8', '8', '0', '5', '9', 'E', '0', '6', '2', 'F', '9', 'D', '0', 'B', '1', '0', 'B', '5', 'D', '4', 'A', 'C', '1', 'A', '4', '8', '3', '5', '9', '7', '4', 'E', '5', 'F', 'F', '5', '1', '8', 'A', '3', '1', '9', '9', '0', '7', 'E', 'F', '9', '5', '0', '4', '7', '5', '1', '4', '6', '1', '3', '3', '7', 'B', 'A', 'B', 'E', 'C', '5', 'F', '6', '3', 'A', '7', 'A', 'B', '7', '3', '1', '0', 'B', '6', '6', 'F', 'D', 'A', 'A', 'E', 'D', '9', '3', 'E', 'D', '9', 'A', '1', '2', '9', 'C', 'A', 'B', '4', 'F', '8', '4', '2', 'E', 'D', '5', '1', 'D', '6', '9', 'F', '8', '8', '2', '9', '4', '0', 'D', 'F', 'C', '8', '4', 'D', '6', '7', '9', '1', 'C', 'A', '3', '8', '8', '0', 'B', '1', '7', 'D', '2', '8', 'E', 'D', '4', '1', '1', '8', '0', '4', 'F', '9', '8', 'B', 'A', '2', '4', '8', '9', 'B', '8', '2', '6', 'E', '4', 'B', 'D', 'E', 'C', '3', '9', '3', 'F', '8', '3', '0', '6', '2', '6', '8', '8', 'A', 'E', '4', '4', 'B', '0', '9', '6', '0', '2', 'A', 'C', 'E', '7', '7', '5', '2', '1', '0', 'F', 'D', 'E', '3', 'F', '4', 'C', '4', '4', 'C', '9', '4', 'D', '5', 'D', 'F', 'A', '5', '2', '8', '6', '0', '2', 'B', '0', 'A', '3', '3', 'E', '7', '7', 'A', 'E', '2', 'A', 'E', '6', 'F', '2', 'D', 'B', '9', '6', 'E', 'A', 'E', 'E', '7', 'D', '2', 'F', '1', '2', '8', '5', '4', '5', 'D', '0', '2', '2', 'A', '2', 'D', '6', '3', 'A', 'D', '4', '5', 'F', '7', '4', '0', 'C', 'B', '7', 'A', 'C', 'B', '6', '1', '3', '7', '7', 'C', '1', 'B', '0', '1', '9', 'A', 'F', 'F', '8', '3', '4', '2', '3', '6', '3', 'D', '8', '8', 'E', '9', '2', 'A', 'B', '7', '6', '4', '3', '9', '7', 'A', '9', '6', '2', 'C', 'B', 'E', '6', '6', '9', '8', 'B', '2', '5', '3', 'C', '3', '1', '9', 'C', '3', '0', '6', 'F', '5', '3', 'D', '9', '7', '3', 'B', '6', 'B', '0', '4', '8', 'D', '2', 'B', '2', 'A', '3', 'F', 'A', 'A', 'B', '4', '6', '9', 'F', '9', 'E', '5', 'D', '6', 'F', '4', '6', 'C', '6', 'D', 'D', '0', '5', '7', 'C', '4', '1', '1', '1', '6', '0', 'B', '7', '3', 'A', '8', 'D', '5', '4', 'E', '0', '2', 'A', 'C', '7', '1', '3', '9', '6', 'B', '7', '0', '4', '3', 'B', '1', '2', '9', 'D', 'D', '6', 'F', '5', '0', '6', '9', '8', '8', '5', 'C', '9', 'E', '8', '4', '4', 'A', 'F', '9', '1', 'D', '7', '3', '9', '4', '9', '5', '7', 'E', '0', 'F', 'D', '2', 'B', '7', '1', 'A', '9', '2', '0', 'B', '2', '5', 'B', 'E', '0', 'B', 'E', '3', 'B', '7', 'F', '8', 'A', '5', 'D', 'C', '5', 'E', '6', '3', '9', '7', '4', '0', 'E', '9', '8', 'E', '9', 'D', 'C', '1', '1', '8', '5', '3', 'C', '4', 'A', 'A', '2', 'B', '9', '5', '9', '1', '7', '2', 'B', '7', '0', '1', '4', '4', '9', '1', 'D', '9', '2', 'C', 'B', 'A', '0', '7', 'A', '4', '5', '4', '0', '2', 'F', 'B', '8', '8', '6', '6', '6', 'C', '3', 'A', 'A', '7', '0', '4', 'B', 'B', '7', 'F', 'F', '1', '4', '2', 'E', 'C', 'D', '3', '4', 'F', 'F', '2', '2', '1', '7', '9', 'C', 'D', 'B', 'B', '2', '9', '1', '0', '8', '7', '0', '0', '8', 'F', '0', '7', '4', '9', '5', 'D', 'A', '2', '8', 'B', '5', '7', 'E', 'F', 'D', 'B', '8', '6', '2', '5', '8', '4', 'B', '1', '2', '9', '7', 'D', 'E', '2', 'D', 'B', '0', 'A', '7', 'D', '7', '3', 'F', 'E', '5', 'F', 'D', 'C', '1', 'F', '4', '1', '6', 'A', '4', 'A', 'C', 'D', '8', '8', '7', '0', '3', 'F', '9', 'D', '7', '1', '4', '9', '8', 'B', '7', 'D', '6', 'F', 'A', 'B', 'A', 'C', '0', '9', '4', 'D', '5', 'D', '9', '5', 'E', 'D', '1', '2', 'F', '5', '9', 'C', 'C', '8', '6', 'F', '3', '4', '6', 'E', '4', '3', '9', 'D', '7', 'C', '9', 'F', '7', 'F', 'D', 'B', 'D', '9', '3', 'C', 'C', 'C', '3', 'E', '2', '0', 'C', '5', 'D', '5', '1', '3', 'A', '3', 'D', 'D', 'E', '5', '4', 'B', '7', '2', 'C', 'B', '7', '8', 'F', 'B', '1', '1', 'F', 'C', '7', '9', '4', '1', '3', 'D', '6', 'C', 'D', 'D', '5', '7', 'E', '9', 'F', '3', 'A', 'C', 'B', '2', '3', '7', '9', 'B', '8', 'A', '9', '9', '2', 'F', '8', '3', 'C', '1', '3', '1', '0', 'C', 'C', 'F', '8', '9', '2', 'E', 'A', '3', '0', 'E', '2', '0', '3', '1', '4', 'F', '9', 'E', 'D', 'F', 'C', '1', 'F', 'F', '1', 'B', '3', '4', '8', '9', '1', 'B', 'F', '7', '8', '3', 'D', 'D', '3', '7', '0', 'D', 'A', 'C', 'B', '4', '0', 'D', '3', 'C', '0', '0', 'B', 'F', '5', '2', '8', 'B', 'E', '7', 'E', '7', '6', '2', '0', '7', '1', 'E', '0', 'C', '9', 'C', 'A', 'F', '8', '6', '4', '2', 'B', '5', '7', 'D', 'D', '6', 'E', '2', 'F', '7', '1', 'E', '9', '4', '6', 'B', '8', '0', '0', '4', 'D', '4', 'A', 'B', 'B', 'D', '3', '2', 'D', '9', 'C', 'B', '4', '4', '6', '9', '7', 'D', '4', 'F', '2', 'A', 'C', '5', 'B', 'C', '7', '8', '5', '7', 'A', '0', '4', '2', 'B', 'F', 'F', '3', '5', '1', 'A', '4', '9', '2', 'E', '7', 'C', '0', '8', '0', 'B', '6', '1', 'E', '1', 'A', 'E', '0', '5', '4', 'F', '9', '1', 'F', '9', 'F', '0', '1', 'B', '1', 'F', 'C', '6', '4', '5', '8', '2', '1', 'B', '0', 'E', 'F', '6', 'A', '0', '3', '8', '7', '2', 'A', '9', '5', '9', '7', 'C', '8', '4', '5', '2', 'D', '4', '8', '4', '2', '6', '2', '2', '0', '9', '3', 'B', '5', '5', 'A', 'F', '7', 'B', '0', '6', '1', '7', '8', '1', '2', 'B', 'A', '6', 'A', '2', '1', 'A', 'A', '1', '1', '3', '5', 'C', 'D', '5', '7', '4', '1', 'D', '3', '1', '6', '0', 'B', 'B', '5', 'D', 'A', '4', 'B', '4', '0', '8', '3', '7', '2', '5', 'E', 'C', 'C', '0', '6', 'B', '8', '4', 'F', '0', '6', '2', '2', '4', '2', 'C', 'D', '3', '1', '4', '4', 'F', '3', 'C', '4', '0', '7', '0', '9', '2', 'A', '5', '3', '9', '1', '6', '9', '3', 'F', 'B', '6', '2', 'C', '1', 'E', 'B', '0', 'A', 'C', '6', '8', 'E', 'C', 'C', '9', 'F', '5', '4', '8', 'A', '0', 'C', '5', '4', 'D', 'E', '6', '7', '0', '5', '7', '9', '5', 'C', 'F', 'D', '8', 'D', 'C', '6', 'B', '2', '7', '6', '8', 'A', 'B', 'E', '2', '9', '9', '4', 'E', '2', 'E', '1', 'F', '4', '0', '2', '9', 'F', '1', '0', 'E', 'A', '6', '8', '7', '1', '2', '4', '0', '9', '8', '2', 'C', 'D', '3', '0', '7', '7', 'D', '7', '8', '2', '8', 'A', '2', '0', '2', 'B', '2', '4', '8', '1', '5', '1', '6', '5', '1', '9', '9', '7', '8', 'B', 'A', '4', '3', '1', 'F', 'F', '1', 'D', 'C', '3', 'B', 'B', '5', '1', 'D', '5', '1', '0', 'F', '0', '3', 'C', 'F', '6', '9', 'D', 'C', 'A', '2', '1', 'B', 'F', 'C', '0', 'E', '9', 'C', '4', '1', 'F', '6', '8', '5', '8', '8', 'B', '8', '5', '5', 'F', 'E', '2', '0', '2', '3', '3', 'B', 'C', '8', '5', '6', '8', '6', 'B', '7', '4', 'B', '6', '3', 'B', '9', '5', '5', '9', 'B', '9', '6', '7', 'C', '7', 'B', 'C', '0', '3', '5', 'A', '2', 'B', 'C', '3', 'C', 'D', 'A', '9', '7', '0', 'F', '4', '7', 'B', '8', 'E', '0', 'A', '8', '6', '8', '4', 'A', '1', 'F', '9', 'E', 'A', '1', 'D', 'B', '2', '2', '8', '4', 'B', 'F', '7', '3', '6', '0', '1', 'B', 'D', 'E', '5', 'C', '1', 'C', '0', '2', '7', '9', 'D', '4', '6', '1', '2', 'C', 'F', '0', '7', '5', 'B', '6', '1', 'E', 'C', 'D', 'F', '8', '5', '6', '0', 'E', '3', '7', '9', 'B', '7', '1', '6', '7', 'A', '1', '2', 'A', '0', '2', 'E', '4', 'C', 'F', '0', '0', '1', 'C', 'E', '3', '6', 'E', '4', '8', 'F', '4', 'D', 'F', 'E', '6', '8', 'B', 'C', 'E', '2', '4', '6', 'A', 'C', 'C', '2', 'F', 'B', 'D', '1', 'B', '4', '6', 'D', '7', '3', '5', '9', '2', '5', '4', '6', 'D', 'D', '4', '2', '4', '0', 'A', '1', '1', 'C', 'A', '6', 'E', '2', '3', '7', 'C', 'A', '8', '7', '5', 'F', '2', '1', '2', 'E', 'A', '9', 'E', '2', '8', '0', 'A', '4', '7', '5', '0', '1', 'B', '6', '0', '5', '1', '9', 'F', '2', '1', '0', 'A', '7', 'D', '7', '2', '9', '7', 'B', 'F', '5', '6', '0', 'F', 'B', '3', '0', '0', 'F', '8', '5', '1', '5', '2', '9', '7', '2', '9', '0', '5', '8', 'C', '6', 'D', 'A', 'C', '6', 'C', '5', '9', '7', '6', '9', '6', 'E', 'F', '6', '2', 'F', '6', '6', '5', 'E', 'A', 'C', 'B', '8', '1', '5', '3', '1', '4', '4', '1', 'C', 'C', 'F', 'D', '3', '5', '4', '3', '5', '5', 'C', 'C', '1', '4', '2', 'C', 'E', '5', '2', 'C', '2', '3', '6', '9', 'F', '0', '7', '6', '3', 'C', '1', '7', 'F', 'B', 'A', '4', 'F', '0', '6', '1', '8', '1', '5', 'C', '2', 'E', 'E', '7', '2', 'C', '9', 'C', 'E', '0', 'E', '8', 'D', 'D', 'E', '7', '8', 'C', '9', 'A', '9', '5', '5', '2', 'D', 'A', 'C', '4', '7', '9', 'F', '7', '9', '0', 'A', '8', '2', 'A', '9', 'E', 'E', '0', 'D', '0', '4', '8', '2', '9', '4', 'D', 'F', '5', 'D', 'E', 'F', '4', '1', '7', '8', '9', 'B', '3', 'A', '4', '1', 'B', '5', 'C', '8', '0', '7', '7', 'F', 'E', '0', 'A', '6', '5', '8', 'F', 'E', '7', '8', '4', '1', 'B', 'F', 'C', 'B', '0', '9', 'C', '2', '2', '5', 'C', '2', 'B', '9', 'B', '6', '0', '7', 'B', 'C', 'A', 'E', '3', 'F', '4', 'A', '0', 'E', 'F', '6', '2', 'E', '0', '7', 'F', '6', 'B', 'C', '6', '7', '4', '9', '5', '0', 'F', '2', 'B', 'B', '5', '1', 'A', '8', '4', '6', '6', 'C', '4', 'E', '8', '5', '3', 'E', 'F', '3', '3', 'A', '9', '9', '1', '8', 'C', 'A', 'A', 'F', 'D', 'D', 'C', '3', '7', '6', 'D', '9', '3', '6', 'D', '0', '6', '3', '4', '7', '5', '8', '9', 'F', 'F', '6', '9', '7', '6', 'F', '1', '4', 'A', 'E', 'A', 'E', '6', '5', '8', 'D', '6', '4', '4', '7', 'E', '6', 'A', 'D', 'E', '8', 'E', 'E', 'A', '6', 'D', '6', '9', '1', 'F', '8', '0', 'E', 'D', 'E', '1', 'D', 'B', '8', 'D', 'E', '8', '9', '8', '9', '4', 'D', 'D', '2', 'F', 'C', 'C', '7', '5', '8', '7', '9', 'D', '5', '5', '7', 'B', 'A', 'C', '7', '9', '4', 'A', 'A', '3', '0', 'B', '2', '4', '6', '1', '0', '9', '7', 'F', 'F', '3', '6', 'D', 'C', 'E', '4', 'B', 'E', '3', '0', 'B', 'D', '7', '2', 'D', '4', 'C', 'C', '3', '6', '3', '1', '4', 'A', 'C', 'C', '0', 'E', '7', 'E', 'C', 'D', 'C', '9', 'F', 'A', '0', '6', 'D', 'A', 'B', 'C', '9', '3', '8', '6', 'B', 'F', '5', 'E', 'A', 'F', 'F', '9', '2', '6', 'E', '8', '2', '5', 'C', '9', '7', '2', '5', '5', 'B', 'C', 'D', '6', 'A', '2', '8', 'D', '5', '8', '0', '2', '7', 'B', 'E', '7', '0', 'A', '7', 'F', 'A', '7', '8', '4', 'D', '2', 'E', 'F', '5', 'A', '8', '7', 'B', '7', 'A', '0', 'E', '7', '3', '0', '0', 'F', 'D', 'E', 'D', '8', '2', '9', 'F', 'F', '7', 'C', 'F', '5', 'B', '1', 'F', '1', 'B', '8', 'E', '1', 'B', '5', '1', '2', '8', '9', 'B', '9', '4', 'D', '9', '1', '2', '1', '6', 'F', '0', '1', '1', '1', '0', '0', 'E', '2', '1', 'E', '6', '9', 'B', '6', '1', '5', '5', 'E', '1', 'F', 'A', 'A', '3', 'C', '3', 'C', '2', 'B', 'E', '9', 'A', '4', '3', 'F', 'D', '8', '1', 'A', 'C', '6', '8', '0', '4', 'B', 'F', 'D', '4', '1', '2', '6', 'A', '2', '2', 'A', '8', 'F', '6', '0', 'E', 'F', '3', 'A', '7', '6', '8', '2', '3', '2', '2', 'B', 'B', 'C', '3', '3', '4', '5', 'B', '9', '5', '0', '2', '8', 'C', '9', 'C', 'A', '0', '5', '3', '9', '9', '1', '2', 'B', '9', '0', '4', '2', '2', '7', 'E', 'F', 'C', '1', 'C', '9', '0', 'B', '6', '6', 'B', 'F', 'B', '9', 'D', 'B', '9', 'D', '7', '2', '5', '8', '3', 'B', 'F', 'F', 'B', '8', 'A', '6', '7', 'F', 'B', '8', 'E', '2', '6', '2', '5', '9', '6', '5', '1', 'C', '3', 'B', '7', 'A', '8', 'C', '7', 'C', '9', 'E', 'F', '2', 'A', 'D', 'B', '4', '3', '9', 'E', 'D', 'C', '3', '1', 'E', '4', '0', 'D', '6', 'C', '2', 'C', '4', '3', '8', 'F', '2', '6', 'A', 'E', 'B', '0', 'F', '7', '7', '7', 'C', '9', '6', '4', '1', '6', '0', '1', '4', 'B', 'F', '5', '2', '6', '0', '9', 'D', 'F', 'A', '5', '7', '2', '5', 'F', '0', 'F', '5', '9', '7', '4', 'E', '6', '0', '5', '3', '8', '6', '9', '1', '5', 'D', 'E', 'C', 'B', 'E', 'B', '2', 'D', 'C', '3', '0', '8', '4', '2', 'A', '7', '5', '6', 'C', '1', 'A', 'E', '5', '0', '9', '7', '4', '4', 'B', '5', '0', 'E', 'B', '1', 'E', 'A', '0', 'F', 'D', '0', '0', 'B', '1', '6', 'D', 'E', '5', '5', 'B', '7', 'E', '0', '6', '2', 'E', '5', 'B', '5', 'F', 'B', '0', 'C', 'A', '4', '2', '2', '7', 'E', '8', 'E', '3', 'D', 'C', 'C', '3', 'D', '3', 'F', '2', 'B', '3', 'B', 'D', '1', 'D', '9', '3', '7', '5', 'C', 'F', '1', 'C', '9', '5', '7', 'A', '1', '7', 'F', 'A', '8', '5', '6', '0', '2', '2', '2', '4', 'C', '0', 'F', '6', '6', 'B', '9', '7', 'E', 'A', 'A', '3', '4', '5', '6', 'B', 'E', '4', '5', '0', '5', '2', '7', 'F', '9', 'C', '6', 'B', '5', '5', 'F', 'C', '2', '3', '5', 'B', '6', 'A', '6', 'D', '8', 'A', 'F', 'B', '0', '8', '3', 'D', '8', '1', 'D', 'B', 'A', '7', '3', '7', 'D', '2', 'C', 'C', 'F', 'B', '0', '3', 'A', '5', '2', '0', '8', '9', 'A', '3', 'C', '8', '6', '9', '6', '4', 'F', '2', 'E', 'D', 'D', '5', '4', '9', 'B', 'E', '6', '9', '7', '3', '8', '7', '2', 'F', 'E', 'D', '1', '9', '0', '8', 'F', 'B', 'F', '7', '3', 'D', 'F', '8', 'E', 'B', 'D', 'D', 'C', '5', 'F', '5', '4', '8', 'E', '6', '5', 'C', '1', '2', '4', '5', '0', '6', '2', '6', '2', '7', '4', '0', 'B', '3', 'D', 'A', '1', 'D', 'B', 'E', '5', 'E', '3', 'A', 'A', 'D', '3', 'C', '1', '9', '5', 'C', '6', 'E', '3', '3', '7', 'D', '2', '4', 'F', 'C', '4', 'A', '2', '2', 'D', '6', '4', '9', 'C', '7', 'F', '1', '5', 'C', '6', '7', 'D', '5', '9', '3', '1', 'B', '5', 'D', '5', '2', '4', '8', 'D', '1', '1', 'C', '2', '6', '2', '7', '7', 'C', '2', '3', '9', '1', '8', '4', 'E', 'E', '5', '6', 'D', '3', '1', 'A', '5', '3', 'B', '7', '7', '7', '4', 'E', '2', 'C', 'E', 'D', 'E', '5', '9', 'C', '7', 'E', '8', 'C', '4', 'E', 'F', '2', '1', 'D', '2', '3', 'C', '2', '3', '0', '5', '4', '6', '4', '6', '0', '8', '2', '4', '5', 'C', '7', '6', '6', '0', 'D', 'C', '9', '9', '7', '0', 'A', '2', 'A', '1', '6', '7', 'E', '5', '1', 'B', 'F', '4', 'C', '7', '6', '1', 'A', 'A', '3', '7', 'A', '7', 'B', '9', '2', '1', 'E', '4', '6', '0', '1', '2', '1', '5', '8', 'E', 'C', '4', 'B', '7', '7', 'A', '7', '4', 'B', 'B', '7', '9', '8', '4', 'F', '6', '7', 'E', '9', '7', '9', 'E', 'E', '6', '7', '2', '5', '1', '0', 'A', '5', '1', 'A', '7', '6', '0', 'F', 'B', '6', '1', '4', 'D', 'D', '3', '0', '9', '9', '4', '8', '7', 'C', 'F', '8', '5', '4', '4', '3', 'C', 'C', '0', 'B', '8', 'F', 'C', '6', '3', 'F', 'F', '6', '3', '7', '2', '4', '5', '1', 'E', 'C', 'B', '2', 'E', 'D', '5', 'D', 'C', 'E', '1', '4', '9', 'C', '4', 'A', '3', 'D', '5', '5', 'D', 'C', '4', '5', '5', '5', '1', 'C', '6', '9', 'F', '6', '0', '2', '9', 'D', 'C', '1', 'D', '0', '6', '3', 'C', 'A', 'C', '2', '6', 'A', '7', '4', '6', 'A', '7', '5', '9', 'F', '1', 'B', '7', '6', 'E', '2', '2', 'C', '7', '1', '8', '8', '6', 'C', '7', 'F', 'D', '0', '5', '4', '4', 'F', 'D', '7', '1', '8', 'C', '0', '1', '6', '2', 'C', '3', '4', '8', 'A', '5', 'F', '8', '4', '4', '2', 'A', 'F', '0', '0', '1', '2', 'B', 'E', '9', '2', '2', '0', 'D', 'E', 'F', '7', 'C', 'C', '6', '5', '1', 'B', 'B', 'F', '2', '2', '4', '5', 'D', '0', '6', '7', 'F', '8', '2', '0', 'D', '0', '6', '9', 'B', 'D', '7', 'C', '6', '7', '5', '2', '2', '7', 'A', 'F', '8', '5', 'B', 'B', '7', '3', '3', '9', 'F', '3', '7', '3', 'A', 'A', '2', 'E', '9', 'A', '4', 'D', '9', '6', 'F', '4', 'D', '2', '4', '9', 'A', 'A', '8', 'E', '6', '0', '9', '1', '1', 'E', 'C', '8', '0', '4', '4', 'B', '1', '1', '1', '6', 'D', '4', 'B', 'F', '0', '9', '4', '2', '2', 'A', '9', 'E', '3', 'D', '3', '1', 'B', '2', '3', '7', '5', '6', '9', '2', '2', '6', 'D', 'E', 'B', '5', 'C', '6', '8', 'C', '1', '6', 'B', '0', '6', '3', '9', 'A', '1', '1', '9', '0', '8', 'B', '6', '1', '8', '2', '5', 'F', '5', '3', 'F', '4', 'B', 'B', '8', '8', 'F', '9', '1', '0', 'E', '0', '0', 'B', '9', '0', 'F', '1', 'C', 'E', '3', 'F', 'F', 'D', 'C', 'C', '5', '9', '3', '7', '2', '9', 'D', '4', 'C', 'D', '7', '8', '1', '4', '7', '5', 'D', 'D', '0', '5', '6', 'E', '6', '5', '7', '7', 'B', 'F', 'D', '7', 'D', '4', 'E', '3', '4', '2', '0', 'E', '5', 'D', 'F', '8', 'E', '6', '6', 'F', 'B', 'D', '9', '7', '6', 'B', '0', '3', 'A', '5', '2', 'F', '8', 'D', '7', '9', 'B', 'F', 'A', '4', 'A', '5', '4', '2', '1', '6', 'C', 'F', 'B', '8', 'B', '5', '6', '4', '2', '4', '7', 'A', '8', '6', '4', '7', '8', 'B', '7', 'F', 'C', '5', '5', '0', '3', 'B', '8', '5', '5', '7', '6', 'A', '2', '3', 'B', 'D', 'B', 'C', '2', '9', '2', 'E', '3', '5', '0', '6', '6', '6', '8', '8', 'D', 'A', 'E', '3', '3', '1', '4', '1', '5', '2', 'C', '7', '5', '8', '0', '0', 'E', 'E', '8', '4', '5', 'C', '8', '9', '9', '0', '6', '2', '0', '5', '5', '8', 'B', 'E', '1', '9', '7', 'B', '9', '1', '4', 'F', '6', '3', 'A', 'F', '5', '4', '3', '8', 'D', '8', '1', 'B', 'F', '7', '2', 'B', '1', 'D', '6', 'C', '6', '3', 'E', 'D', '3', 'A', 'A', '7', '8', '9', '0', '7', '6', '0', 'B', '7', 'B', 'E', '6', '3', 'F', '5', 'C', '0', 'B', '9', '7', '9', '0', '2', '8', 'C', 'C', '8', 'D', '8', '7', '8', 'A', '2', 'A', 'D', '4', '2', '9', '5', 'A', 'E', '2', '8', 'E', '6', '4', 'E', 'C', 'C', 'E', '9', '7', 'D', '7', 'B', 'A', 'C', '6', 'C', 'D', '0', 'B', '8', '7', '7', '6', '8', '2', '3', 'D', 'D', '8', '0', '2', '8', '9', '9', 'F', '1', '6', '1', 'E', '7', 'B', 'E', 'A', 'F', '8', 'F', '3', '9', 'D', 'F', 'E', '1', '0', '2', 'E', '4', '5', 'A', '2', '4', 'A', 'A', 'E', '4', '7', '6', 'B', 'E', '4', 'F', '2', '7', 'D', '1', '4', '0', '3', '2', 'D', '2', 'D', 'E', 'B', 'B', '5', '5', 'F', 'D', 'C', '0', 'E', 'F', '0', 'B', '6', '2', '5', '9', '5', 'A', 'B', '0', 'D', 'E', '4', '7', '1', '4', '8', 'C', 'F', '2', '8', 'B', 'B', '5', '2', 'F', 'C', '9', 'D', '8', '1', '2', '2', '0', '2', '1', '1', 'B', 'E', '6', '7', 'E', 'C', '2', '5', 'A', 'C', 'D', '1', 'C', '4', 'C', 'E', '0', '6', 'B', '7', 'B', '3', 'E', '5', 'C', 'B', 'A', '4', '6', '4', 'D', 'C', '5', 'F', '5', '3', '2', '4', '0', '8', 'A', '0', '1', 'B', '0', '4', '3', '7', '1', '3', 'E', 'D', 'B', '0', '2', '7', 'F', '7', '0', '0', '4', '8', 'C', '1', '1', 'A', 'E', '6', '9', '8', '7', '0', '8', 'A', '6', 'A', 'C', 'F', 'E', '4', 'B', 'E', 'C', '1', 'B', 'B', '6', '8', 'A', '9', '4', '9', '6', '6', '3', 'A', '2', '3', 'F', '1', '1', '7', '9', '8', 'E', '6', 'B', 'E', '7', '4', 'B', '8', 'B', '4', 'C', '1', 'C', '6', 'E', '9', 'E', '8', '2', '2', '1', '5', '2', '5', '5', 'B', 'C', 'E', 'E', '7', 'B', '6', 'E', '2', '3', '8', 'C', 'D', '7', '4', '4', 'D', '7', '1', '8', '5', 'F', '8', '3', 'C', '3', '9', '0', 'E', 'B', '2', 'F', '6', '7', '7', '7', '2', '6', '9', 'E', 'C', '8', '0', '3', 'F', 'C', '4', '6', '3', '0', 'B', '3', '1', '9', '3', '5', '1', '4', '3', 'A', 'A', 'B', '9', 'D', '8', '9', '7', '5', 'B', '2', '5', '7', 'D', 'E', 'B', 'C', '3', '7', 'A', '0', '3', 'C', 'A', 'B', '6', 'E', 'E', '7', 'C', '3', 'F', '6', 'E', 'F', '4', '5', 'E', 'D', '2', '7', 'B', 'D', 'F', '0', '0', '0', 'F', '2', '9', 'E', 'F', '6', '9', '8', '5', 'C', '6', '8', 'F', 'C', '2', 'E', '5', '6', '7', '8', '1', '2', 'D', '3', 'A', 'E', '7', '3', 'B', '7', '9', 'F', '1', '8', 'D', '7', 'B', '7', '4', '8', '8', '1', '5', 'C', 'A', 'D', '7', '6', '5', 'E', 'A', 'D', '9', '4', '9', '7', 'E', '9', '8', '1', 'F', '9', 'B', '2', 'D', '4', 'C', '0', '1', '6', '1', 'E', '2', '8', '9', '7', '5', 'C', '4', 'D', 'F', '1', '0', 'D', '2', '9', '9', '7', '1', 'D', '3', '6', '2', 'C', 'F', 'E', 'B', 'A', '5', 'D', '9', 'B', 'A', '8', '2', 'B', '3', 'D', '3', '3', '3', '4', '6', '7', 'A', '9', 'F', '5', 'C', 'D', 'E', '8', '5', '4', '6', 'B', 'A', '8', 'D', '9', 'B', 'C', '4', 'F', '0', 'D', 'C', '8', '4', '0', 'D', 'B', 'D', '8', '5', 'A', '1', '5', 'A', '0', '1', '6', 'E', 'B', '0', '7', '8', '6', '3', '5', '7', 'A', '0', '2', 'D', 'D', '9', 'E', 'A', 'B', '4', 'F', '2', 'B', '8', '3', 'B', '3', 'C', '9', '4', '7', '0', '3', 'F', 'C', 'D', '4', '4', 'B', '9', 'E', '0', '2', '9', '3', '6', 'B', '3', '5', 'B', 'C', '1', 'F', '3', 'E', '8', 'B', '5', '0', '4', 'E', '3', 'E', '6', '3', 'B', '8', '9', '0', '5', '6', 'F', 'C', 'D', 'C', '7', '8', 'D', '7', 'F', '4', 'C', '8', '8', '5', '2', '2', '8', '5', '5', 'E', '7', '2', '6', 'C', '6', 'F', '9', '7', 'B', 'E', '5', '2', '3', '5', '4', 'E', '7', '3', '1', '4', '3', '1', 'E', '0', '0', '2', 'F', '2', '4', '5', 'B', '6', '6', 'A', '4', 'C', 'B', '6', '5', '9', 'F', 'E', '4', 'F', '5', '3', '8', '4', '6', 'A', 'E', 'F', '4', 'B', '8', '3', 'D', '8', '8', 'E', 'A', '2', 'C', 'E', 'B', 'D', '7', '5', 'B', 'A', '6', 'C', '0', '7', '9', 'D', '5', 'E', '5', '6', '4', '0', '9', '1', '3', 'B', '3', '0', 'E', 'C', 'B', '5', '5', 'A', '6', 'F', 'A', '1', '6', '9', '2', 'A', '0', '7', 'C', 'E', 'E', 'E', '6', '5', 'F', '9', 'D', 'E', '3', '3', '7', 'E', '0', 'A', '3', 'E', '9', 'D', '2', '0', '4', '8', '8', '3', 'C', '8', 'E', '6', '9', 'E', '1', '7', '5', '0', 'F', 'B', '5', '1', '4', 'F', 'F', '7', 'D', '2', 'F', '9', '1', 'E', 'C', '6', '2', 'B', '7', '1', '1', '9', 'A', '4', '6', '5', '3', 'D', 'B', '3', '8', 'D', '5', '4', '3', '5', '4', 'D', '0', '2', 'B', '2', '1', 'D', 'B', '6', 'A', '4', '3', '7', 'B', '6', 'D', '2', 'D', '9', '0', 'F', '8', 'F', 'D', '9', 'B', '8', 'E', '0', '6', '5', 'C', '0', '2', '2', 'E', 'C', '4', '6', 'C', '0', 'D', 'F', '6', '1', '5', 'F', '4', '4', 'B', '6', 'F', '2', '9', '0', '5', 'E', '8', '2', 'A', '0', '4', '0', '0', '7', 'D', '0', 'F', 'D', 'D', '4', '8', 'D', '7', 'E', '1', '3', '2', 'D', 'E', 'B', '9', '2', 'C', '9', '3', '0', '5', '6', '0', '4', 'C', '2', 'F', 'E', '2', '9', '7', 'C', 'B', 'A', 'C', '7', 'C', '1', '0', '4', 'A', '7', '2', '0', '3', '0', '3', 'E', 'B', 'F', '0', '4', '1', '0', 'A', 'A', '1', 'B', 'C', '8', '3', '3', '6', '5', 'F', '0', 'F', 'B', 'D', '9', '4', '6', '4', '7', '5', '2', '1', '7', '8', '3', '2', '8', '1', 'D', '7', '0', '8', 'B', 'A', 'E', '8', '1', '0', 'B', '8', 'B', '0', '5', '5', 'F', '8', 'E', '0', '9', '5', '2', '3', 'C', 'A', 'E', '4', '1', 'A', '8', 'D', 'A', '9', '9', '2', 'D', '2', '3', 'C', '9', 'C', 'C', '8', 'F', '0', '7', 'B', 'F', '2', '5', 'F', '3', '8', 'F', '4', 'C', '0', 'A', '3', '0', '2', 'D', '1', 'F', '9', '8', 'C', '4', 'B', '8', '3', '0', '2', 'C', 'D', '7', '9', '9', '2', 'E', '2', 'C', '3', '8', '1', '9', '5', 'B', 'D', '3', '1', '0', '0', 'E', '1', '3', '8', 'A', 'F', '4', '1', '6', 'E', 'E', '6', 'E', '6', 'E', '1', '8', 'F', '2', '6', '7', '8', '8', 'A', '5', '1', '9', 'C', '8', '9', '4', 'C', 'B', '8', '9', 'E', '9', '4', 'B', 'A', '9', '1', '8', '2', '5', 'F', '0', '3', 'A', '5', '3', 'B', 'A', '8', 'C', '6', 'E', '8', 'E', '5', '9', 'F', 'D', 'A', '3', '3', '3', '4', '2', 'A', 'F', '1', '2', '9', 'B', 'E', '6', '9', 'C', '4', '1', '9', '1', '5', '9', '4', '3', '0', 'C', 'D', 'B', 'B', 'F', '3', 'D', 'E', 'A', 'E', '8', '9', 'B', 'D', 'D', '7', 'E', 'B', 'D', '9', 'B', 'E', 'A', '5', '2', '4', 'D', 'E', '8', '6', '7', '1', '1', 'C', '5', 'F', 'F', '9', 'C', 'A', 'D', '2', 'A', 'A', '2', '0', '3', 'E', '1', 'E', '8', 'D', '7', 'D', '0', '1', '0', 'D', '6', '1', '5', 'F', '2', '8', '6', 'F', 'C', '7', 'B', '0', '5', 'A', '3', 'F', '9', 'E', '0', 'E', '7', 'B', '3', '8', '0', '4', 'A', 'D', 'C', 'D', 'E', 'A', 'B', 'A', '5', 'D', '2', 'B', '1', '0', '5', 'F', '2', 'A', '5', 'C', 'C', '0', '7', 'B', '6', '5', '6', 'D', 'E', '3', '2', '0', '7', '3', 'C', 'D', '7', '7', 'F', '7', '8', 'B', 'C', '6', '2', '4', 'C', '2', '9', 'F', '0', 'B', '6', '1', 'D', '1', 'F', 'F', '4', '0', '0', 'E', '4', '5', '2', '3', 'B', '1', '2', '9', '7', 'A', '1', '0', '7', '4', '3', 'D', 'F', '7', '0', '2', 'C', '8', 'C', '1', 'B', '1', 'F', 'E', 'C', '8', '6', '5', '4', 'F', '6', '2', '6', 'F', '2', 'A', '4', '4', '0', '5', '2', 'F', 'D', '7', '8', '8', '1', '9', '8', '3', '3', '3', 'C', '5', '7', 'F', 'A', 'A', '8', '7', '8', '5', '4', '8', '5', 'E', '9', '4', 'A', '1', '2', '6', '6', '3', 'A', '0', '2', '8', '9', '4', '9', '6', '6', '5', '7', '9', 'E', '1', 'D', '9', 'E', '6', '6', '9', '9', '3', 'B', '9', 'A', 'C', '7', '1', '8', '9', '3', '5', 'C', '4', '4', 'C', '5', '4', '9', 'E', '6', '8', '7', 'E', 'B', '5', '1', '4', 'B', '3', '7', '5', 'A', 'B', '6', '8', 'A', '0', '9', 'A', '7', '4', '0', '0', 'A', '1', '5', '1', '0', '1', '6', '6', '7', 'D', 'C', '3', 'E', 'C', '1', 'D', 'B', '4', '8', 'D', 'C', '6', '7', 'E', '3', '4', '3', 'B', '3', 'E', '7', 'E', '0', '2', '3', '3', 'A', 'B', 'B', 'A', '1', '7', 'E', '5', '0', 'A', '0', '2', '5', 'E', '1', 'A', '3', 'E', '1', '3', 'D', 'C', '9', '3', '0', '7', '8', '7', '7', '4', 'C', 'E', '4', '6', 'F', '5', '6', '0', 'C', '3', 'F', 'A', '3', 'D', 'D', '3', 'E', '1', 'E', '3', 'B', '2', 'F', 'E', '5', '5', 'F', 'C', '3', '1', '2', '5', '4', '2', 'B', '2', '8', '9', '9', '3', '3', 'E', 'E', '0', 'E', '8', '6', 'C', 'D', '3', 'D', '4', 'B', '1', '6', 'D', '6', '2', '0', '7', '9', '2', '4', '0', '3', '6', '0', '7', 'E', '5', '9', '4', '0', 'A', '2', '7', '5', '8', '8', 'F', '8', 'B', '9', 'F', 'B', '6', '9', 'D', 'D', '2', 'A', '2', '3', 'E', '9', '8', '6', 'C', '5', '4', '1', 'E', 'D', '9', '8', '8', '1', '6', '9', 'A', 'B', 'D', '2', '1', 'F', '1', 'D', '1', 'B', '0', 'A', 'A', '8', 'C', '2', '8', '5', 'A', '6', 'D', '3', '7', '9', '1', '1', '9', '6', 'F', '1', 'A', '7', '2', '6', 'E', '1', '5', '2', 'B', '1', '5', 'C', '5', 'D', 'B', '2', '6', '9', 'B', '8', 'E', 'D', 'A', '5', '0', '5', '8', '9', 'D', '5', '7', 'D', '0', '1', 'A', '0', '4', '1', '6', 'E', '9', '1', '4', '7', '6', 'F', '3', '3', '9', 'F', '0', 'B', '7', '5', '2', '5', '2', '0', '5', 'B', 'E', 'A', '9', '9', '5', '1', '4', '0', 'A', '8', 'B', 'C', 'C', 'B', 'E', 'D', '6', '8', 'E', '4', 'A', '7', 'F', '7', '2', 'D', 'D', '7', '4', '4', '1', '8', 'A', '4', '2', '5', 'F', 'E', 'E', '4', '3', 'F', '3', '5', '0', 'F', 'C', '5', 'A', '2', '4', '9', 'A', 'C', '5', 'E', '8', '1', 'F', 'B', 'C', 'C', '5', 'E', '0', '2', '6', '0', '7', '2', 'C', '9', '4', '9', 'D', '8', '4', '5', 'B', '4', '8', 'C', '6', 'B', 'B', 'C', 'C', '3', 'A', 'C', '2', 'D', '7', '7', '5', '7', '0', '6', '0', '2', '4', 'F', '9', '1', '7', 'E', '4', '4', 'C', '8', '5', 'D', '0', '2', '7', 'C', 'B', '3', '4', '4', '1', 'F', '3', 'F', '2', '5', '6', 'C', '8', '7', '7', '2', 'A', '6', '9', 'F', '9', '2', '4', '6', '5', '6', '2', '2', '8', '8', '2', '3', '1', '3', '9', 'C', '9', 'E', 'E', 'C', '2', 'B', '9', '8', '7', '4', '4', '2', '9', '0', '4', '2', '9', '7', '9', 'E', '6', 'E', 'F', 'A', '4', '9', 'A', 'D', '8', '3', '6', 'C', '6', '3', 'A', '5', '2', 'B', '3', '0', '0', '3', 'A', 'E', '2', 'F', '3', 'D', 'E', '3', '5', '6', '2', 'B', '6', 'C', '6', '6', '7', 'B', '2', '0', '7', '5', '3', '8', '6', '9', '3', '5', 'E', 'B', '0', 'C', '5', '7', '1', '1', '1', '1', '7', '2', '1', 'E', '6', '3', '0', 'F', 'A', 'A', '0', 'D', 'C', '5', '9', '8', 'B', '8', '2', '4', '8', 'A', 'E', '7', 'E', '3', '2', 'F', 'F', 'A', '5', 'B', '7', '8', '2', '8', '7', 'B', 'E', '2', '3', 'D', '1', 'A', '5', '2', '7', '9', '8', '2', '8', '8', '7', '9', '4', '4', '9', '3', '8', '1', '8', 'D', '1', '3', '4', 'B', 'F', '7', '1', '8', '7', '1', '5', '3', '6', 'C', 'C', '8', 'C', '4', 'C', '9', '8', '4', '9', '0', '6', 'E', '7', 'C', '0', '6', '7', '5', 'B', 'D', '6', '2', '1', '8', 'C', 'D', '3', '4', '1', '5', '1', 'F', 'A', '6', 'E', '2', '9', '0', '7', 'D', 'D', 'E', '8', 'C', '4', '9', '8', 'A', '7', '4', '2', 'D', '4', 'D', '7', '8', '2', 'D', 'D', '6', '8', 'B', '1', '2', '4', '0', '7', '3', 'E', '0', '0', '8', 'A', 'F', '9', '5', 'E', '0', '4', 'A', 'C', 'C', '7', 'D', '7', '8', 'B', '7', 'B', '2', 'A', 'D', 'F', 'C', 'A', 'A', '9', 'E', '0', 'E', '5', '2', '4', '1', 'D', '3', '2', '4', 'D', '5', 'B', '6', '8', 'D', '7', '4', '2', '7', 'C', '6', '5', '1', '0', '6', 'F', 'B', '6', '5', '4', 'C', '7', '1', '4', '1', '9', '8', '1', 'E', '0', '5', '0', 'C', '7', 'A', 'C', 'A', '0', '8', 'A', '7', '6', 'F', '2', 'F', '8', 'A', '1', '1', 'D', '4', 'D', '1', '7', '8', '7', '5', '1', '4', '2', 'D', '4', '1', '8', 'F', '3', '8', '4', 'D', '4', '9', '1', '1', 'F', 'D', 'F', 'F', '8', '2', 'D', '0', 'D', '9', '9', 'F', 'D', 'A', 'D', 'A', 'B', '2', 'D', 'B', '8', '2', '6', '0', '5', '2', '6', 'C', 'D', 'C', '2', 'A', '3', '7', 'B', 'D', '9', '4', 'C', '2', 'C', '1', '2', 'B', '0', 'A', '3', '6', '2', 'A', '7', '0', '9', '8', '5', 'A', '9', '4', '2', '0', 'E', '4', 'E', '8', '9', '4', '8', '6', 'F', '5', 'A', 'F', 'C', '7', '4', '8', '8', '3', 'F', '1', 'C', '5', 'F', '8', '1', '2', 'E', 'A', '7', 'A', '4', '7', '8', '9', '1', 'B', '0', '9', 'E', 'D', '4', 'F', '8', '5', 'C', 'F', '0', '8', 'F', '0', '5', '5', 'B', 'F', '8', 'B', 'F', 'A', '4', '0', '3', 'F', '9', 'F', '0', '4', '1', 'E', 'F', '2', 'F', '1', '7', 'D', 'D', 'F', '9', '2', 'A', '7', 'A', '8', 'B', '4', 'F', '4', '9', 'E', 'D', 'F', '5', '9', 'C', '9', '9', '8', 'A', 'A', 'C', 'C', '8', 'F', 'F', '0', 'A', '8', '8', 'F', '5', '9', '3', '4', 'A', 'B', 'F', 'F', '1', '4', '1', 'D', '6', '2', '3', 'D', '2', '9', '2', 'E', 'A', 'E', '8', '3', '2', '6', 'A', '6', '5', 'E', '6', 'E', 'E', '7', '1', '1', '0', 'C', 'E', '6', '3', '6', '2', '7', 'D', '6', '4', '3', '0', '1', 'D', 'C', '0', '4', 'C', '4', '7', '1', 'F', 'A', '6', 'D', 'A', '8', 'E', 'A', '2', 'E', '6', '6', 'A', '3', '7', 'A', 'C', '7', '4', '7', '8', 'D', 'C', 'F', '6', 'C', 'C', '3', 'B', '4', '0', '9', '2', '8', '2', '9', '0', '3', 'B', '1', '0', 'C', 'E', '4', '2', '1', 'B', '8', 'E', '3', '9', 'B', '6', 'F', '9', '6', '7', '0', 'D', '7', 'E', '1', '7', '5', '9', 'D', '1', '5', 'E', '3', 'F', 'D', '4', '3', 'C', 'D', 'E', 'D', '5', '5', '4', 'F', '7', 'D', 'C', '9', '7', '3', 'E', 'E', '0', '3', '3', '5', 'A', '9', 'B', '8', '8', '9', '7', '3', '5', '0', 'A', 'C', 'C', '6', 'E', '6', 'A', 'F', '8', '7', '8', 'F', 'E', 'F', '3', 'E', '1', 'D', '4', '2', 'B', 'E', '1', '9', '9', '3', 'A', 'B', 'A', 'F', '0', '9', '1', 'E', '9', 'F', '6', 'E', '0', '3', '9', 'F', 'D', '1', '8', '5', 'A', 'E', '4', 'A', 'E', 'E', 'B', 'F', '3', 'F', 'D', 'E', 'B', 'F', '3', '8', 'A', '5', '0', 'A', 'B', '3', '2', 'C', '7', '2', '0', 'B', '4', '3', '7', '9', '6', '8', '2', '8', '0', 'B', '2', '3', '7', 'F', 'A', '6', 'C', 'B', '7', 'F', 'C', '5', 'B', 'A', '4', '6', 'C', '3', 'A', '1', '2', 'E', 'B', '1', '3', '7', 'B', '4', '6', 'A', '6', 'E', 'B', 'D', '7', 'B', '8', '4', '0', '2', 'D', '1', '5', 'E', '3', 'E', '8', 'E', '8', 'D', 'A', '8', 'A', '3', '1', '9', 'F', '7', '6', '6', '2', '4', '8', '5', '0', 'B', '1', 'D', '6', '8', '9', '1', 'C', '1', '8', 'F', '4', 'C', '5', '9', '1', '2', '4', '2', '9', 'B', '1', 'C', 'C', '7', 'E', 'D', '3', '3', 'E', 'A', '2', 'E', '5', '1', '5', '6', '8', '8', '1', '4', '2', '8', 'F', 'F', '5', 'B', 'F', '9', 'C', 'E', 'A', 'C', 'D', '8', '3', 'E', 'C', '3', '3', '0', '5', '7', 'F', '2', '4', '6', 'F', '3', '7', '2', '8', 'B', '3', '0', 'F', '4', 'E', '1', 'C', 'C', 'F', '9', 'F', 'A', '7', '4', '6', 'A', 'E', 'A', 'B', '7', 'D', 'B', 'B', '4', '2', 'E', 'F', 'E', '7', '8', '1', 'E', 'F', '6', '1', 'B', 'A', '3', 'C', '8', '6', '8', '2', 'F', 'A', '7', '4', 'F', '6', '1', '5', '2', 'F', '7', 'D', '0', 'B', '3', '4', '8', '9', 'D', '0', '9', '1', '1', '2', 'D', 'D', '4', '4', 'E', 'D', '3', 'B', 'C', '8', 'F', '9', '3', '0', '4', 'F', 'C', 'A', '3', '2', 'A', '7', '7', 'C', '2', '6', '8', '9', '7', 'C', '3', '6', '6', '9', 'C', '0', '8', 'C', 'F', '4', '4', '6', '2', 'F', '1', '5', '3', '9', '6', '6', 'E', '3', '3', 'A', 'A', 'B', 'D', '9', 'C', 'D', 'E', '7', '2', '9', '8', '2', 'C', '7', 'F', 'D', 'E', 'D', 'C', '3', 'B', '6', '5', 'F', '1', 'D', '7', '0', '1', '2', '4', '6', 'A', '5', '5', '0', '0', '6', '7', '6', '2', '2', '9', '3', '5', '4', 'D', '9', '8', 'B', '0', '7', 'A', '0', 'F', '6', '9', '0', '0', 'D', '0', 'D', '7', 'D', 'C', '7', '9', 'F', '2', '7', 'C', '7', 'A', '2', 'B', '6', '6', '2', 'E', '5', 'D', 'A', 'A', '7', 'D', '8', 'E', 'A', '1', '9', '9', 'D', '2', 'A', '2', 'E', '3', 'C', 'A', '0', 'C', '5', '4', '1', '7', '0', 'D', '4', '9', '9', 'B', 'A', 'D', '8', 'B', '4', 'A', '5', 'E', '6', 'A', '1', '9', 'B', '5', '2', 'F', '3', 'F', '7', '6', '4', 'D', 'E', 'E', '8', '6', '0', '7', '0', '6', '5', '5', '7', 'B', '0', '6', 'C', '6', '0', 'F', 'B', '5', '5', '7', '8', '3', '0', '4', 'D', '3', 'C', '4', '6', '6', '5', '2', '5', 'A', '4', '1', '1', '1', '2', '3', '2', '8', 'E', '5', 'F', '5', '4', 'B', '0', '6', '6', '4', '0', '8', '8', '2', '2', 'E', 'C', '9', '8', 'D', '9', 'F', 'C', '4', '4', '4', 'E', 'E', '7', 'B', 'B', 'B', '2', '3', '6', '2', '0', '5', '8', '9', '0', '2', '9', '0', '0', 'A', '8', '9', 'A', 'B', '5', '7', 'B', '9', '9', '0', '4', 'F', 'A', '7', '2', '9', '4', '7', '7', 'A', '9', 'A', '3', '8', '5', '2', 'C', 'D', '9', '7', '9', '5', '9', 'D', 'B', '3', '7', '9', '8', '4', '4', '3', '6', 'D', '5', 'F', '6', '5', 'A', 'F', '2', 'F', '1', '5', 'A', '7', '3', '1', '9', '9', '4', 'C', 'E', '5', '4', 'F', 'B', '0', '8', 'A', '8', 'D', 'D', '9', '2', '9', '7', '4', 'A', '9', 'B', '8', 'D', '3', '4', '8', 'A', '1', 'C', '7', '8', '2', '3', '4', 'C', '9', 'E', 'F', 'F', '6', '0', '0', '5', 'F', '3', '9', '4', '3', 'F', 'C', '6', '1', '9', 'E', '7', 'E', '6', 'B', '4', 'C', 'F', '3', 'D', '0', '4', '9', 'F', 'F', '5', 'A', '4', 'A', '9', '5', '8', '0', '8', '6', 'B', '7', 'F', 'C', 'D', 'E', '9', '1', 'A', 'F', '9', 'D', '6', '8', '4', 'F', '3', '6', 'B', '8', '0', '2', 'D', 'F', '8', '2', 'B', 'A', '8', 'A', '0', '6', 'F', 'F', 'F', 'B', 'A', 'E', '2', '1', '6', 'C', '4', '4', '7', '5', 'A', 'E', 'C', '6', 'B', '5', '2', '8', '6', '5', '5', 'C', 'A', '0', '4', '3', '6', '7', 'F', 'F', '6', '7', '1', '2', '2', '0', 'B', '0', 'D', '0', 'E', '2', '3', 'A', '6', '6', 'A', 'D', 'A', 'B', 'A', 'F', '6', '1', 'C', '9', 'B', '9', '6', '4', '5', 'D', '8', '6', '5', 'D', 'D', '7', '6', '2', 'E', '1', '7', '6', 'B', 'F', 'C', 'B', 'B', 'E', 'E', '2', 'E', '6', 'D', 'C', '9', 'D', '6', 'A', 'A', '7', '4', '5', '6', 'D', 'F', '2', '9', 'B', '1', '9', '7', '8', '8', '9', '0', 'B', '8', 'B', '5', 'E', 'E', '0', 'E', '7', '4', '7', '1', 'F', '6', '2', 'A', 'D', '7', '0', '6', '7', '8', '4', 'A', '2', 'D', '6', '1', '2', '8', '7', 'A', 'F', 'E', '4', '1', 'B', 'D', '4', '1', 'D', 'B', 'A', '3', '7', '3', '0', '4', '9', '7', '6', '4', 'F', '6', '7', '5', '3', '5', '6', '1', 'D', 'A', '9', '9', 'F', 'D', '2', '0', '5', '7', 'F', 'F', 'B', '3', '6', '1', '9', 'B', 'C', '6', '9', 'A', '4', 'B', '4', '9', '3', '7', 'D', 'A', '6', '4', '6', '6', '9', 'C', 'D', '8', 'E', '2', 'B', '8', '5', 'B', 'F', 'B', '8', '7', 'E', '8', 'E', 'D', 'F', '7', 'C', '9', '5', 'B', '1', '9', '2', '9', 'E', 'C', '2', '9', '8', '4', 'F', '8', '1', '7', '6', 'B', '7', 'F', '9', 'D', 'B', '1', '5', '4', 'A', '3', '2', 'B', '5', '4', '8', '4', 'E', '7', '9', '6', 'B', 'F', '2', '3', '8', 'C', '8', '8', 'C', '8', 'C', 'E', 'B', '3', '1', '5', 'E', '1', 'B', '0', 'F', '6', '5', 'C', 'F', 'F', 'B', '5', 'A', '0', '4', '0', '9', '9', '5', '8', '2', '2', 'A', 'C', '6', '5', 'A', '3', '6', '5', '4', 'F', '8', '9', 'D', '3', '5', '5', '5', '1', 'B', '2', '9', '7', '5', 'A', '3', '9', '6', '1', '3', '4', '3', '9', '3', 'F', '2', '1', '5', '6', '3', '7', 'B', 'C', 'C', 'A', '9', 'B', '9', 'C', '0', '3', '5', 'C', 'D', '5', 'B', 'F', '1', 'C', '1', '9', '6', 'F', '2', '0', 'B', 'C', '8', '1', '0', '2', 'B', '6', '3', '5', '9', '7', '6', '4', '2', 'D', '7', '7', '0', '3', 'D', '6', '3', 'B', '5', 'F', '4', '7', '0', '6', 'F', '5', 'B', '3', 'B', '7', 'D', 'E', '4', '8', '0', '6', '9', 'E', 'A', '9', 'F', '9', '5', '0', '0', 'E', '4', '5', '9', '0', 'F', '4', '2', '7', '3', '5', '0', '8', '3', 'B', '4', 'A', '9', 'D', '8', '0', 'B', '5', '8', '9', '2', 'B', '1', 'A', 'E', '6', '2', '6', '4', '5', 'A', '8', '7', 'F', 'B', 'F', 'A', '3', '0', 'B', '3', '2', 'D', 'F', '5', '8', 'F', 'A', '4', 'E', 'A', 'E', '2', 'B', '6', '2', '5', '6', '4', 'A', '8', 'E', 'B', '5', 'D', '1', 'F', 'A', '2', 'D', 'E', 'D', '6', '8', 'B', '7', '9', '7', 'D', 'B', '6', '6', '7', '2', '1', 'D', '6', 'E', '3', 'C', '6', 'A', '2', '3', 'B', '1', 'A', '0', '5', '0', '2', '1', 'E', 'F', '0', '6', 'F', '6', 'C', 'F', '9', '3', 'D', '6', '2', 'C', '5', 'C', 'C', '4', '1', 'D', '6', '6', 'D', '1', 'D', '2', '5', 'F', '8', 'D', 'E', '6', '0', '7', '2', 'E', '6', '9', '4', 'D', 'E', '1', '8', 'D', 'A', '8', 'F', '5', '4', '9', '6', '5', '2', 'C', 'B', 'F', 'A', '1', '2', '6', '7', '2', 'E', '8', '4', '2', 'A', '8', 'A', '1', '4', 'E', '4', '8', '2', '6', 'C', 'C', '4', '6', 'E', 'D', '7', 'D', '3', 'F', 'E', '7', '0', 'D', '6', '6', '7', '0', 'C', '6', '7', 'A', '3', 'B', 'D', 'A', '3', 'E', '7', 'D', '8', '9', 'E', '0', 'C', '7', 'B', 'A', '2', '9', '5', 'D', 'A', '9', '6', '9', '8', '0', '9', '6', '7', '2', 'F', 'B', 'F', 'D', 'F', '8', '5', '0', '2', 'E', '1', '3', '6', '0', '4', '4', '3', '3', '1', '7', '6', 'E', 'B', '9', '9', '4', 'E', 'F', 'B', '8', '2', 'F', '6', '9', '3', '1', 'D', '5', 'D', 'B', 'C', '2', 'B', 'B', 'D', 'E', '2', 'B', '8', 'B', 'F', '4', '1', '4', 'F', 'A', '3', '3', '7', 'F', '8', '2', 'F', '1', '7', 'D', '2', '5', 'F', '1', '4', 'F', '9', '6', 'D', '1', '3', 'E', '1', 'C', 'F', '2', '5', '8', '1', '1', '0', 'A', '4', 'F', '4', '7', '5', 'F', '8', 'A', '7', 'B', '5', '3', 'C', 'B', '5', '0', 'E', '6', 'C', '7', 'D', '1', '0', '6', '4', 'B', '2', 'A', '2', 'C', 'F', 'E', 'A', 'B', '6', '7', 'B', '5', '5', '0', '6', 'D', 'C', '8', '4', '8', '0', '6', '1', 'A', '8', 'F', '2', 'D', '1', '2', '0', '0', '6', '5', '3', '6', 'B', '5', '2', '9', '0', '7', '3', '1', 'A', '7', 'B', '5', '1', '9', '4', '5', '4', 'B', '0', '9', 'A', 'C', '8', 'A', '3', 'D', 'B', 'C', '7', 'C', '7', '3', '6', '6', 'F', '2', '8', '5', '3', 'B', 'A', '7', 'E', '2', 'F', 'E', '4', '9', '1', '6', '7', 'C', '5', '8', '7', '7', '1', 'C', '5', '9', '2', '9', '4', 'B', '3', '3', 'E', '4', '1', 'E', '2', 'A', '2', '9', 'C', 'B', '4', 'A', '4', '9', '3', 'F', '8', '6', '8', 'C', '9', '7', '0', '7', '0', 'F', '4', 'C', 'D', 'D', '2', '7', '8', 'E', 'C', '3', 'F', '0', '8', 'C', '0', 'B', 'E', '7', 'A', '8', '2', '1', '7', '5', '4', '4', 'C', '7', 'D', '0', 'A', '5', 'A', 'D', '1', '9', '1', '3', '2', '3', '2', '5', '6', '8', '1', '3', 'F', 'B', 'E', '1', 'D', '8', 'D', 'A', '9', '0', '2', '7', '9', '1', '5', '2', '7', 'B', '9', 'A', '3', '6', '8', '3', 'E', '8', 'E', '4', 'A', '6', 'B', '6', '1', 'A', '9', 'C', '1', '8', '5', '8', '8', 'E', '0', '0', '3', 'A', '5', '4', '9', 'A', '9', '3', 'A', 'C', 'B', '4', 'B', '7', 'E', '5', '2', '5', '0', '1', '1', 'C', 'D', 'A', '2', '2', '3', '2', '1', 'B', '8', '2', '8', 'D', '9', 'E', 'F', '7', '4', 'F', 'D', '6', 'A', '9', 'B', 'C', '6', '0', '8', '6', 'A', '5', '3', '4', '2', '0', '3', '7', 'F', 'E', '9', '2', 'A', '1', '6', '5', '1', '4', '5', '2', 'A', '6', '1', '7', 'F', '4', '1', '5', '6', '1', '0', '3', '0', '8', '5', '5', '4', '8', '4', '7', 'D', '7', '2', 'D', '1', '2', '2', '5', 'B', '8', '8', 'F', '7', 'E', '8', '5', '9', '4', '3', '1', 'A', 'B', 'F', 'A', '1', '4', 'A', '9', 'B', 'C', '6', '7', '0', '8', '7', '4', 'E', '8', '7', '0', '1', '4', 'A', '7', '1', 'D', '2', '3', '1', '2', '4', 'E', 'C', '0', '5', 'B', 'E', '4', 'E', '1', 'A', 'A', '0', 'F', 'C', 'D', 'E', '3', '2', 'D', 'E', 'C', '1', '2', '7', '0', '6', 'C', '7', '1', '9', '0', '7', 'E', '7', '2', 'B', '5', '7', '8', '1', 'A', '9', '7', '9', '0', '6', '7', 'C', '5', 'B', 'E', '4', '0', '1', '5', '6', 'F', '4', '4', '5', '8', 'C', '5', '9', '5', '4', 'D', '9', '7', '9', '6', '7', '2', 'A', '5', '3', '1', '0', 'E', 'D', '5', '4', '5', '9', 'D', '3', '5', 'C', 'E', '2', 'E', '8', '1', '4', '9', 'C', 'A', 'E', 'C', '1', '7', 'B', '6', '2', '6', '2', '1', '3', '8', '4', 'E', 'D', '8', 'C', '8', '6', 'A', '5', '3', 'A', 'F', '7', '9', 'E', 'E', 'B', '4', 'B', '8', '8', '9', '4', '8', 'C', '0', '9', '6', '9', '3', '6', '4', '1', '8', '6', '9', '9', '7', '8', '7', 'D', '8', 'E', 'C', '1', 'D', 'B', '8', 'B', 'E', '9', 'E', 'E', '1', '0', 'D', '6', 'E', '5', '6', '2', '6', '2', '5', 'C', '6', '4', 'A', 'D', '1', 'E', '6', '7', '6', 'F', '3', '6', '2', '3', '5', '9', 'B', '3', 'E', 'A', '9', 'E', 'E', '6', '4', 'A', 'E', 'D', '2', 'B', '5', 'B', 'C', '3', '3', 'F', '7', 'E', '2', 'E', '0', '5', '9', '7', 'E', 'C', '2', 'A', '8', 'D', 'B', '8', '6', 'E', 'E', 'D', '0', '2', 'B', '2', '2', 'A', 'C', '6', '6', '3', 'C', '2', 'A', '2', 'A', '1', '1', '4', '8', 'B', '0', '5', 'E', '9', '8', 'C', '4', '3', '2', '2', 'A', '7', 'B', 'E', '7', '5', '6', 'C', '7', '7', '9', '1', '0', '9', 'E', 'B', '4', '6', '7', 'F', 'B', 'C', 'B', '8', '0', '6', '2', '2', '2', 'E', 'A', '8', '5', '6', '0', 'C', 'C', 'C', '7', '9', '9', 'C', '6', '7', '8', '9', 'D', '6', '4', '2', '2', '0', '1', '5', '0', 'B', 'D', 'E', '8', '9', '4', 'C', '9', 'B', '2', 'D', '2', '4', '4', '4', '7', 'C', '5', 'B', 'C', 'F', '3', '5', '9', 'B', 'B', '0', 'E', '2', '1', '5', '4', '6', '7', '7', 'C', '4', '8', '9', '9', '5', '4', '6', 'B', 'E', '9', '8', '1', '7', '2', '4', '7', 'B', 'E', 'E', '9', '7', '2', 'F', '6', '1', '3', '3', 'F', '8', '9', 'F', '0', '4', '6', '9', '1', 'B', 'B', '4', 'B', 'F', '1', 'C', 'C', '1', '3', '1', '5', 'E', '9', 'D', 'C', '7', 'D', 'D', '6', 'A', '2', 'F', 'D', 'F', 'D', '4', 'F', '8', '4', '1', 'C', 'A', '4', 'E', 'B', '6', '1', '6', 'F', '8', '8', 'E', '3', 'D', '0', '0', '9', '6', '1', '0', '5', '7', 'E', '0', '8', '9', '1', 'F', 'C', '8', 'C', '4', '2', '8', '0', '8', 'D', '7', '8', '4', '8', 'C', '3', '8', '2', '0', '1', '3', '2', '1', '6', '0', '2', '1', 'A', '7', 'B', '1', '1', '1', 'C', '6', '0', '0', 'F', '3', '0', '2', '3', 'D', '4', 'C', '5', 'A', 'E', '3', '7', '3', 'B', '8', 'E', 'C', 'B', '0', 'E', '0', '2', 'F', '0', '9', '8', '0', '1', '7', 'A', 'C', 'C', '5', '7', '1', 'D', 'B', '5', '3', 'D', '5', 'D', '5', 'B', 'F', '4', 'E', '9', 'B', '0', 'C', 'D', '1', 'A', '5', 'E', '3', '6', '1', '9', 'C', '8', 'F', 'E', '7', '3', '9', 'A', '8', 'E', '9', '1', '3', '6', '6', 'E', '2', 'E', 'B', '4', '2', '1', 'F', 'E', '8', '4', '0', '3', 'E', 'B', '0', '5', '7', 'F', '7', '0', 'A', '3', 'C', '3', 'A', '6', '6', '2', '5', '0', '8', '5', '7', 'A', 'E', 'F', 'F', '7', '9', 'C', '9', 'D', 'F', 'D', 'A', '9', 'E', 'A', '9', '8', '5', '9', 'A', '5', '1', '0', '7', 'D', '7', 'E', '8', 'B', 'D', '1', '3', '0', '7', 'B', 'E', 'B', '9', '2', 'A', '0', '1', '3', 'C', '6', 'B', '9', 'B', '9', '0', '6', 'A', '3', '0', '6', '7', '1', '1', 'E', '5', '1', '3', '0', 'F', '4', '9', 'F', 'E', '6', 'E', 'E', '5', '2', '6', '6', '5', '5', 'A', 'B', '7', '1', '6', '0', '7', 'E', '4', '6', 'E', 'D', '2', '7', 'C', 'E', '5', 'D', '1', '3', '3', '8', 'A', 'D', 'B', '3', 'D', '9', 'B', '8', 'B', '0', 'E', '4', '0', 'C', '5', 'D', '7', '7', 'A', 'D', '7', '7', 'E', '2', 'B', '1', '3', '5', '2', 'E', '3', '8', '3', 'C', 'A', '0', 'D', '0', '0', '0', 'E', 'A', '7', '6', '2', 'A', 'B', '2', '7', 'C', '4', '5', '3', '2', '7', 'C', '7', 'C', '1', '6', '7', '0', '1', '9', 'B', '0', 'F', '3', 'C', '6', '0', 'B', '7', 'E', '0', '6', '0', 'B', '6', '0', '7', '1', '6', 'A', 'B', '3', 'D', 'D', '0', '6', '7', '1', '1', 'F', '1', '8', '6', 'F', '1', '0', 'A', 'C', 'D', 'B', 'F', '2', '0', 'A', '3', '7', 'D', '4', 'D', '6', '3', 'A', 'E', '5', 'E', 'C', '9', 'F', 'A', '8', '0', '2', '0', '4', '7', '9', '3', '8', '7', 'B', 'E', '0', '9', 'F', 'A', '1', '5', 'F', '7', 'D', '8', 'F', '5', '5', '9', '1', '5', '3', '1', '1', '2', 'C', 'E', '4', 'C', '1', '2', 'E', 'B', '6', 'C', 'D', '4', '9', 'E', '3', '4', '3', '5', '3', 'B', 'D', 'E', 'C', '7', 'D', '9', '3', '9', '1', '4', '0', '2', '7', '8', '5', '6', '9', 'F', '2', '3', 'F', '6', '0', '8', 'E', 'C', '0', '8', '9', 'E', '5', '3', '3', '5', 'C', 'A', 'F', '9', '3', '6', '3', '8', 'F', '6', '5', 'B', '3', '1', '1', 'E', 'D', '8', '7', 'A', 'A', '4', '9', '8', '8', '7', '9', 'F', '5', '6', '5', '0', '5', 'C', '0', '2', '7', '9', '7', '2', '9', '6', 'C', '7', 'D', 'A', '5', '0', '6', 'C', '7', '0', '8', '6', '8', '4', '6', 'D', '0', '5', '3', '5', '7', '6', '1', 'F', '2', '3', 'F', 'B', '2', '7', '0', 'C', '5', '6', '8', 'D', '8', 'F', 'D', 'F', '6', '8', '0', '9', '3', '1', '0', '3', '7', '7', '9', 'A', '2', '0', 'A', '6', 'C', 'E', '4', '4', '2', '9', '8', 'E', 'B', '9', '6', 'B', '4', 'E', '5', '3', 'C', 'D', 'F', 'C', '3', 'A', '0', '2', '7', '6', '8', '9', '6', '5', '3', 'D', 'B', 'D', 'E', 'F', '1', '9', 'C', '8', '0', 'A', '7', 'B', '2', 'C', '3', '7', '3', 'F', 'D', '3', 'B', 'F', 'C', '2', '3', 'E', 'C', '0', 'B', 'A', '3', 'A', 'B', '9', '0', '0', 'D', '3', '8', '1', '3', 'F', '0', '1', '2', '9', 'E', 'A', '0', 'A', '2', '0', '2', '7', 'D', '6', '8', '3', '8', '4', '5', '4', '8', 'E', 'F', 'B', '3', '5', 'C', '0', '5', '1', '2', '5', '3', 'D', 'E', '7', '7', '2', 'A', 'E', 'C', '1', 'C', '1', '5', '5', '5', 'B', 'C', '3', '7', '7', 'E', '1', 'C', 'C', '1', 'E', '8', 'B', '9', '6', 'C', 'A', '5', '7', '2', 'D', '1', '7', '0', '0', '4', '0', '2', 'A', '5', '9', '0', '1', '2', 'E', 'C', '0', 'D', '2', 'E', '2', 'D', '3', '1', '0', 'A', 'A', '7', '0', 'B', 'F', '8', 'B', 'B', '4', 'D', 'E', '9', 'A', 'E', '7', 'A', '1', '0', 'A', 'F', 'B', 'E', '4', 'E', '6', '0', 'C', '6', '4', '0', 'A', '6', '6', 'D', '4', '4', '5', 'B', '6', 'A', '9', 'F', '7', 'E', 'C', 'B', 'B', '7', 'B', 'E', 'E', '4', 'C', '0', 'D', '6', '3', 'C', '1', '7', '9', '5', '2', '2', 'F', 'E', 'E', '4', 'D', 'A', '0', 'B', '1', '0', 'B', '9', '6', '1', '2', '0', '4', '7', '9', 'F', 'F', '5', 'F', '2', '2', '1', 'B', '7', '6', '7', '2', '4', '6', '9', '7', '3', 'A', '1', '6', '7', '1', '4', '0', '7', '5', '7', 'F', '1', 'D', 'D', '0', 'E', '6', '0', '1', 'F', '3', 'D', '7', '2', '8', '3', '8', 'B', '8', 'A', '0', '5', 'F', '9', '7', '8', 'F', '9', '5', 'B', '0', '1', '3', '0', 'E', '6', 'F', '6', '7', 'E', '6', '0', '6', 'B', 'D', 'F', 'C', 'B', '0', '8', '5', '4', '3', '4', '4', 'B', 'C', '8', '8', '6', '4', '1', 'E', '6', '8', 'F', 'D', 'B', 'F', 'F', '9', '0', '0', '2', 'A', 'B', '6', '2', '9', '7', 'F', 'C', 'F', 'F', 'C', 'C', '5', '6', '7', 'A', '3', '7', '7', '9', 'A', '1', '6', 'B', '6', '9', '3', '4', '5', '3', 'C', '2', 'D', '6', '2', '0', '8', 'A', 'A', '9', 'D', '2', '4', '4', 'A', '0', '1', 'C', '6', '9', '6', 'C', '7', '9', 'C', 'F', '5', '1', '2', '0', '1', '4', '4', 'D', '8', '4', '7', '3', 'B', '6', '4', 'D', 'F', '5', '6', '7', '4', 'A', '3', '3', '9', '8', '1', '4', 'E', 'C', 'D', 'A', '5', '4', 'D', '9', '1', 'A', 'F', 'E', 'B', 'D', '8', '6', 'A', '5', 'F', 'A', 'B', 'A', 'F', '3', 'D', '0', '0', '3', '9', '9', 'B', '9', '1', 'A', '8', '9', '6', '5', 'F', 'A', 'D', '8', '9', '4', 'A', '2', '1', 'A', '6', 'F', 'B', 'F', '7', 'D', '6', 'E', '7', '5', '8', '0', '3', '1', '2', 'B', 'F', '5', '7', '9', '1', '6', 'C', '4', 'F', '2', '5', '7', 'C', '7', '2', '8', '4', 'F', 'F', 'A', 'B', 'A', '7', '3', 'E', '5', '1', '5', 'B', '7', '0', 'A', '2', '9', 'D', '2', '9', '1', 'C', '4', 'C', '7', '8', 'D', '1', '0', '4', '8', '0', 'E', '7', '3', '1', '7', '1', '8', '7', '3', 'E', '7', '6', '2', '9', '6', '6', 'B', '8', 'A', 'B', 'F', '6', '9', '6', 'C', 'A', '7', '6', '9', '5', '3', 'E', 'A', '4', '2', 'F', 'C', '2', '3', '0', '5', 'E', 'D', '6', '4', '7', 'D', '1', '8', 'A', 'A', '6', '4', '6', '6', '0', '3', '6', '0', '0', '4', 'D', 'C', 'B', '9', 'F', 'E', '5', '6', 'B', 'C', '2', '4', '1', '4', '3', '4', '8', '0', '5', 'C', 'D', '4', '6', '1', '1', 'D', '0', '9', '9', '1', 'F', '7', '8', '7', '7', '1', '2', '1', '6', 'C', '1', 'E', 'B', 'A', '8', 'C', '5', '9', '7', 'B', 'C', '7', '6', 'B', 'E', '1', '6', '0', 'E', 'A', 'C', 'D', 'C', '2', 'D', '7', '2', '8', 'D', '5', 'A', 'D', 'B', '6', '6', 'B', '7', '1', '5', '5', '8', '7', 'E', '1', '6', 'D', '4', '0', '5', 'C', '3', '9', '6', 'A', '6', 'E', 'F', 'C', 'A', '3', '5', '0', 'F', '5', '3', '9', '9', 'E', '3', '5', 'E', 'E', '3', 'B', 'F', 'E', 'C', 'B', '2', 'C', 'B', '7', '7', 'D', '1', '3', 'B', 'A', '8', '4', 'F', '9', '0', 'C', '0', 'D', 'D', 'A', '8', '5', '9', '9', '2', '4', '6', '1', '8', '4', 'D', '8', 'E', 'B', '6', 'E', '6', '9', '5', 'C', 'F', '0', '6', 'A', 'B', '4', 'F', '0', '2', '3', 'F', '2', 'E', '3', '4', 'B', 'B', '1', 'E', '3', '5', '2', '6', '8', 'F', 'F', '5', 'A', '5', '1', '6', '3', 'D', 'F', '3', 'F', '2', 'B', 'F', '4', 'B', '2', 'B', 'C', '9', 'C', '2', 'C', '2', '2', '4', '2', 'D', '2', '3', '4', 'F', 'E', 'C', 'C', 'C', '9', '9', '9', '9', 'A', '7', '3', '7', 'D', '6', 'C', '6', '6', 'B', '1', '6', '2', '6', '8', '1', '6', '5', '4', '3', 'C', 'E', '5', '7', '5', 'B', 'B', 'A', '1', '3', '5', '1', '7', '5', '5', '3', '4', '1', '9', '3', '4', 'A', '0', '1', '6', 'A', 'F', 'A', '2', '1', '3', '2', 'F', '1', '2', 'F', 'F', 'E', '3', '5', '0', 'A', '4', 'E', '0', '4', 'D', '8', '1', '6', 'F', 'F', 'E', 'B', '1', '0', '5', '7', '1', 'C', 'E', '6', 'B', '4', 'A', '8', '5', '2', '0', 'D', 'B', '3', '6', 'D', '7', 'F', '6', '9', 'D', 'A', '1', '0', '1', 'C', '0', '3', '5', '1', 'C', '5', 'F', '4', 'D', 'A', '7', 'A', '7', '8', 'F', '6', '0', 'D', '4', '7', '7', '1', 'C', '7', '9', 'B', 'A', '6', 'D', 'F', 'B', '0', 'B', 'B', '7', 'E', '4', '7', 'B', 'D', '4', 'C', '0', 'D', '4', '9', '3', 'E', 'E', '0', 'B', '1', '5', '3', 'D', 'E', '7', '0', '1', '8', '1', 'D', '7', '4', 'C', '8', 'D', '3', 'A', '6', 'B', '7', '2', '6', '7', '3', 'F', '4', 'A', '5', '6', 'D', 'A', '6', 'B', 'C', 'F', '0', '2', '9', '0', '8', 'E', '2', 'B', 'B', 'D', 'A', 'A', '2', '4', 'C', '2', '7', 'A', '8', '0', '3', '0', '9', '9', '6', '4', '6', 'E', '0', '5', '8', '2', 'F', '2', '9', '9', '0', '1', '0', '7', '9', '0', '4', '7', 'B', 'A', 'B', '9', '0', '0', 'D', 'D', '9', '8', 'F', '8', '5', '1', 'A', 'B', '3', 'C', 'B', '6', '5', '0', '9', '3', '9', 'E', '6', '4', '5', '6', 'B', 'D', '1', '0', 'B', 'E', '3', '5', '4', 'C', 'C', 'A', '7', '3', 'F', 'C', '7', 'E', 'E', '1', '7', 'C', '2', 'C', '9', '9', 'E', '2', '0', '5', 'B', '3', '3', '9', '5', '0', '5', '8', '7', '2', 'D', '7', '4', 'E', '3', '2', '7', 'A', '2', '1', 'D', '8', '3', '3', '9', 'B', 'B', '4', '9', '5', 'B', '3', '3', '1', 'A', '4', '7', 'A', '0', '1', 'D', '1', 'F', '0', '5', '7', '4', '8', '6', '6', '8', '6', 'D', '9', '7', 'E', 'F', '6', '6', 'B', 'F', '1', '7', '2', '3', '3', 'C', '4', 'F', '9', '5', '6', '3', '3', '1', '8', 'D', 'C', 'A', '2', '5', '0', '5', 'B', '1', 'A', 'C', 'F', 'B', '1', 'E', '9', 'C', '5', '8', 'C', 'B', '8', '6', '2', '1', '1', '4', '1', '8', '7', '8', '5', '1', '9', 'B', 'B', '0', '1', '6', '9', 'B', '9', 'B', 'C', '5', 'D', '9', '8', '5', 'C', 'A', '1', '8', 'A', 'F', '8', '6', 'C', 'F', 'F', '4', '9', 'D', '2', '3', '1', 'C', '3', 'A', '4', '5', '9', '6', '1', '8', 'D', 'D', 'B', '9', 'D', 'D', '9', '9', '1', '0', 'C', 'F', '4', '8', 'A', 'B', 'D', '9', '9', '1', '0', '1', 'D', '4', 'D', '9', 'C', '0', '3', 'F', 'A', '4', 'F', 'A', 'F', '5', 'B', '7', '0', 'A', 'E', 'B', '1', 'F', 'E', '3', 'F', 'E', '9', '9', 'C', 'D', '9', '3', '6', 'E', '5', 'B', '0', '2', '2', '6', 'C', '1', 'C', '7', 'D', 'D', '6', '8', '7', '2', '6', '2', 'C', 'D', '7', '0', '7', 'E', '8', 'D', 'F', 'D', '1', '3', 'B', 'A', '2', '7', '8', 'A', 'C', 'D', '0', 'E', '4', 'B', 'A', '0', '4', '4', '8', '9', '6', '0', 'B', 'F', '8', '0', '0', '5', 'F', '4', 'A', '0', '6', '5', 'B', 'D', '4', '3', 'C', 'A', '5', 'D', 'A', '1', '6', 'C', '8', 'F', '2', 'B', 'D', '5', '8', '7', '2', '9', '8', 'E', 'F', 'D', 'A', 'C', 'E', '7', '0', '7', '2', '1', '2', '8', '7', '0', '9', '4', '2', 'F', 'C', '1', '2', '9', '6', 'D', '2', '9', 'A', 'F', 'B', 'B', '3', '6', 'E', '9', 'B', 'B', 'F', 'F', '8', '2', '9', 'D', '1', 'C', '2', '5', '0', 'E', 'C', 'D', 'E', 'F', '3', '2', 'A', '1', '5', '3', '1', 'A', 'E', '8', '2', 'D', '4', 'D', '2', '3', '2', 'A', '9', '7', '6', '3', 'E', '4', '7', '0', 'E', 'C', '7', '8', '9', 'F', '1', 'C', '2', '6', 'E', '9', 'B', 'C', '2', 'C', '8', 'A', '9', '9', 'A', 'F', '6', '9', '1', 'E', '5', 'A', 'E', '3', '8', '6', 'C', 'C', '6', '2', '1', '8', '1', '6', 'F', '1', '0', '6', 'B', '3', '6', 'B', '0', '4', 'A', '3', 'F', '9', '8', '2', 'D', '3', '3', 'B', 'C', '8', 'B', 'D', '7', '8', '1', 'C', '1', '9', 'B', '4', '5', '2', '6', 'D', '0', '2', '0', 'E', '5', 'C', '1', 'E', '7', '2', '5', '7', '2', 'F', 'D', '0', '0', '9', 'A', 'F', '4', '1', '8', 'B', '7', '8', '8', '6', '9', 'F', '5', '0', 'D', 'D', '0', 'E', 'C', '0', 'B', 'C', '2', '8', 'F', '9', '1', 'B', 'B', 'D', 'D', '9', '5', '5', '6', '0', '0', '9', '7', '2', '2', '6', '9', '0', '2', 'E', 'F', 'C', 'A', 'E', 'A', 'E', '6', '8', 'E', 'F', '7', '8', '0', '0', '7', 'E', 'D', '0', 'B', '1', '4', '9', '7', '8', '8', 'F', 'F', 'D', 'B', '5', 'F', '8', '3', 'C', '2', '3', '5', '8', '2', '7', '6', 'D', '4', '7', 'F', '1', 'F', '6', '1', 'F', '8', 'C', 'A', '5', '3', 'A', 'C', 'C', '2', '4', '0', '5', '0', '9', 'E', '8', '4', '3', '3', 'D', '7', '1', 'E', '4', 'F', '1', '4', '7', 'C', '5', '3', '8', '4', 'B', 'A', '5', '5', 'B', 'B', '0', '8', '6', '3', '1', '2', 'F', 'B', 'E', 'A', '5', '8', 'D', 'C', '4', 'E', '9', 'D', 'D', 'F', '9', 'D', '2', '6', 'A', '1', 'A', 'E', '6', 'C', '7', '1', 'C', '0', 'C', '3', '6', '6', '9', '9', 'D', 'B', '3', 'F', '4', '4', '8', '0', '2', 'B', '6', '9', 'F', 'E', '4', '3', '5', '6', '8', '2', '0', '7', 'E', '9', '5', 'B', 'E', 'E', '3', '0', 'D', '9', 'C', 'D', '4', '0', '2', 'A', '6', 'D', '9', 'A', 'D', 'D', '1', '9', 'D', '9', '2', '1', 'C', '7', '5', '9', '9', '6', '4', 'E', '3', '9', 'D', '3', '8', 'F', 'E', 'B', '5', '6', '7', '6', '5', '4', '9', '5', 'E', 'B', 'C', '8', '8', 'D', '7', '8', 'E', '5', 'E', 'A', '4', 'C', '4', 'E', '4', 'D', '3', 'D', '4', '1', '1', '2', '7', 'A', 'A', 'C', '1', 'E', '5', 'C', '9', 'A', '8', '4', 'E', '8', '5', '9', '4', '5', '5', 'E', 'B', 'E', '1', '3', 'A', '9', 'E', '8', 'A', '1', 'B', 'F', 'C', 'E', '6', '9', '8', '0', '0', '3', '1', '8', 'D', 'F', '7', 'F', '0', '7', '3', '9', 'B', 'B', '7', 'F', '4', '2', '0', 'A', 'C', '3', '1', '6', '1', '3', '1', '6', 'B', '5', 'C', '7', 'F', 'B', '8', '4', 'D', '2', '2', '4', 'B', '1', '4', '5', '5', '8', 'C', '5', '5', '2', '9', 'D', '4', 'B', 'D', '3', '6', '7', '2', '9', '2', '5', '5', '0', 'B', '8', 'C', 'A', '7', '2', '1', 'A', 'A', '4', 'C', '7', 'B', '9', '3', '4', '0', '1', '5', 'F', 'E', '2', '1', '9', '8', '7', '9', '1', '9', '2', 'C', 'A', '6', 'B', '2', 'A', '4', '6', '7', '3', '7', 'A', '9', '7', 'F', 'F', '1', '1', '0', 'B', 'D', '4', '0', '3', 'A', '7', '2', '3', '4', '6', 'F', '8', 'B', '3', '2', 'A', 'A', 'E', '1', 'B', '2', '7', '5', '3', 'B', 'B', '1', '1', '8', '7', 'A', '0', '0', '9', 'B', 'D', '7', 'E', '6', 'E', 'D', '8', '8', '4', 'D', '3', 'D', '1', '1', '3', '3', '3', '9', '2', '7', '0', '8', '6', '9', 'E', '4', '7', '1', '4', '1', '1', '5', 'C', '4', '6', 'E', 'A', 'E', '3', 'A', '7', '8', '0', '7', '8', 'B', '4', 'F', 'E', '1', 'E', '9', '1', 'C', 'C', '8', 'B', '4', '7', '8', 'B', 'B', 'B', '8', '4', '1', 'D', '4', 'F', '3', 'B', '0', '9', '8', '6', 'B', 'C', '5', 'A', '9', '9', '3', '6', '8', '1', '9', 'D', '4', '8', '3', 'F', 'A', 'C', 'F', 'D', '5', '4', '2', 'D', 'B', 'D', 'B', '2', '1', 'F', '6', '8', '0', 'F', '0', 'D', 'C', '2', 'F', 'F', '7', '5', '4', 'B', 'B', '5', 'B', 'C', 'B', '0', 'B', '8', 'A', '5', '6', 'D', '8', '5', '4', 'C', '5', 'A', '5', '8', '5', '6', 'F', '6', '3', '8', '8', 'D', '2', '3', 'D', '1', '7', '8', '9', 'E', '1', '8', 'F', '4', '0', '1', 'D', 'D', 'E', '4', '6', '1', '5', '4', '8', 'B', '0', 'F', 'E', '3', 'C', 'A', 'A', '8', 'A', 'B', 'F', 'B', '1', '5', '1', '1', '8', 'B', '4', '6', '5', '3', 'A', '3', 'E', '1', '3', 'C', '7', 'F', 'E', '2', '2', '4', 'F', 'F', '1', '2', 'C', 'A', '4', 'C', '5', '0', 'A', '2', '8', '5', '8', '9', 'F', '8', '3', 'D', 'A', 'F', '4', 'B', '1', '9', '4', '3', '5', 'F', 'E', '8', 'B', '3', 'A', '8', '0', '5', 'C', 'A', '7', '4', 'B', '5', 'E', '4', 'C', '5', '2', '8', '9', 'D', 'F', '0', '0', '4', 'A', '6', '9', '0', '4', '4', 'F', 'D', 'F', 'E', '9', '6', '4', '2', '6', 'A', '2', 'C', 'F', 'C', 'B', '7', 'B', 'B', '5', 'F', 'D', '0', '9', '7', '8', 'E', '9', '5', '8', 'C', '1', '7', '0', '1', '4', '6', '7', '9', '3', '8', 'A', '8', '4', 'A', '4', '7', 'C', '4', '4', 'E', '2', '6', 'B', '6', '5', 'D', '5', 'F', 'D', 'A', '0', 'D', 'F', 'A', '1', 'B', '9', 'E', 'F', '1', '4', '2', '1', '7', '8', 'C', '2', 'A', 'F', '0', 'A', '0', 'A', '0', '4', 'A', 'B', 'A', 'C', '1', 'E', 'F', 'A', 'E', 'C', 'F', 'C', '5', '1', '6', '0', 'B', '3', 'B', '5', 'A', '7', '5', '3', '0', '4', 'B', '7', '7', '1', 'F', '9', '3', '6', '7', 'A', 'F', 'F', '8', '8', '8', '1', 'F', '6', 'F', '2', 'F', 'B', '3', '2', '3', 'A', 'A', 'C', '9', 'A', '5', '1', '1', 'B', 'C', '4', 'A', '2', '1', '6', 'F', '7', '3', 'C', '9', '9', '3', '8', '0', '5', '2', 'F', '6', '7', '0', '0', '2', '6', '7', '9', '1', '3', 'B', 'C', 'D', '3', '2', '3', '7', '4', 'E', 'C', '0', '7', 'C', '0', '6', 'B', '3', '8', 'E', 'B', 'F', '9', 'E', 'C', '7', '6', 'E', 'F', 'F', '7', 'B', '8', '4', '3', '0', 'A', '2', '7', '0', 'E', 'C', 'F', '1', '8', '3', 'F', '3', '3', 'F', '7', '8', '3', '2', 'B', '2', '4', '7', '6', '9', '0', 'F', '1', 'F', '5', 'B', '0', 'E', '2', 'C', '8', 'B', '9', '5', '8', '4', '2', 'E', '9', '9', 'F', '2', 'C', '0', '5', '8', '2', '5', '5', 'B', 'F', 'A', 'F', 'C', '4', 'E', 'E', '1', 'A', 'B', 'B', '6', 'C', '6', '8', 'E', '9', '9', '9', 'C', 'A', 'E', '9', 'E', 'D', '3', '0', 'E', 'A', '1', '0', 'D', '1', 'A', '9', 'D', '6', '1', '9', 'A', '1', '3', 'C', 'D', '7', '7', '9', 'C', '8', '8', 'B', '9', '2', 'C', 'B', '6', 'B', '4', '6', '8', '2', '5', '4', '8', '8', '8', 'E', '8', 'B', '4', '9', '2', '7', 'F', '2', '2', '3', 'B', 'D', 'C', 'D', '6', 'A', 'C', '9', '5', 'A', 'A', 'F', '9', '8', '4', '2', 'A', 'E', 'A', 'F', '7', '3', '0', '2', 'F', '5', 'C', '3', 'D', '6', '6', '0', '2', '6', '5', 'A', 'D', '5', 'C', '0', '8', '0', '5', 'C', 'E', '8', '4', 'E', 'D', '1', '2', 'F', '3', '5', '0', 'B', '3', '8', 'E', '2', '1', 'A', '7', '2', '7', 'E', 'A', 'B', '0', 'F', 'D', '2', 'C', '5', '8', 'E', '5', '6', '0', 'C', '4', '0', '6', 'E', '8', '9', 'C', '1', '2', 'A', '4', '1', 'F', 'B', 'B', '6', '1', 'F', 'E', '5', '6', '0', '6', '8', 'D', 'E', 'D', 'A', '0', '2', '3', '3', 'E', '7', 'E', 'F', '9', '0', 'D', '4', '9', '5', '7', '1', '5', 'E', '0', '5', '0', '9', 'C', '9', '0', '5', '6', '6', '6', '4', '6', '9', '3', '1', 'C', 'C', 'B', 'B', '9', '0', '9', '6', '1', 'A', 'A', 'F', '0', '3', '8', '2', '4', '3', '6', 'C', '8', '6', 'D', '9', '9', '9', '3', 'C', '9', 'A', '9', '4', '3', '2', 'A', '3', '5', '7', 'B', 'F', 'F', '4', '7', '0', '7', '3', 'C', 'F', 'E', '7', '9', 'E', '2', '8', '7', '0', '9', 'E', 'D', 'D', 'D', 'D', 'F', '8', 'B', '4', '3', '2', '5', '6', '1', 'F', '0', 'A', '3', 'A', 'A', '6', 'A', 'C', '8', '0', '0', '7', 'F', 'E', '4', 'B', 'A', 'B', 'F', 'A', 'F', 'C', '9', 'C', '8', 'E', '8', '9', '2', '8', '9', 'A', 'A', '1', 'B', 'D', '1', '5', 'F', '0', '1', '7', '4', 'A', '7', '5', 'D', '7', '1', '3', '3', '8', '1', 'B', 'D', 'E', '2', '7', '2', 'D', '1', '3', '5', '0', '9', 'E', '0', 'E', '0', 'B', '6', '3', 'C', '9', 'D', '3', '6', '9', '0', '1', '2', '7', '4', '3', 'D', '4', '6', 'B', '7', 'A', '5', 'A', 'D', '1', 'B', '3', '6', '7', '1', 'B', 'B', '8', 'E', 'A', '2', '0', '7', '9', 'B', 'E', '6', 'B', '5', 'D', '5', 'E', '7', 'F', 'B', 'C', '1', 'C', '3', 'C', 'E', 'E', '0', '6', '6', '6', 'A', 'E', '9', '3', '3', '7', '8', '0', 'C', '0', 'D', 'B', 'C', '6', 'E', '3', 'D', '0', 'F', '1', '0', '6', 'A', '8', '2', '1', 'F', 'D', 'E', '6', '0', '4', '8', 'E', 'E', '4', '1', '4', '6', 'D', '0', '3', '1', 'E', '1', '1', '5', 'B', '8', 'B', 'D', '4', '1', 'C', 'F', '3', '0', '4', 'D', '6', 'F', '9', '3', 'A', 'D', 'B', '2', '8', 'F', '0', '6', '9', 'F', '3', '2', 'C', 'B', '3', 'A', '8', '8', '8', '2', 'D', 'A', '1', '3', '3', '7', '2', 'B', '6', '0', 'F', 'D', 'B', '7', '2', 'B', '0', '3', '3', 'F', '6', '1', '1', 'C', 'F', 'C', 'C', '2', '5', '2', 'F', 'B', '8', 'A', '5', '0', 'B', '8', '6', '5', '9', '0', '6', 'B', '4', 'E', 'C', '5', '2', 'A', '3', 'D', 'F', 'E', 'A', 'C', '9', '8', '7', 'D', '3', 'A', 'F', '5', '0', '1', 'D', '8', 'A', 'F', 'D', '0', '7', '9', 'F', '8', '1', 'C', '3', '5', '0', '3', '5', '0', '4', '1', 'B', 'C', 'E', 'C', '5', 'A', 'B', 'E', '6', '4', '1', '1', 'C', '4', 'A', '9', '1', 'B', '1', '7', '0', 'D', '6', 'E', 'E', 'F', '6', '7', '3', '7', '1', 'A', '8', 'B', 'D', '4', 'E', 'B', '0', 'B', '4', 'F', '2', '0', 'E', '8', '7', 'A', '5', '1', '9', '7', 'A', '3', '8', '5', '1', 'B', 'A', '7', 'F', '5', 'C', '4', '8', 'E', 'B', '5', '0', '5', '2', '1', '2', 'A', '1', '1', 'D', '6', '7', 'D', 'E', '8', '8', '8', 'A', 'C', 'E', '1', '2', 'D', 'D', 'D', '5', '9', '1', 'B', 'A', '8', 'F', 'B', '4', '8', '1', 'D', '3', 'A', '5', '4', 'A', '3', 'D', '8', '0', '7', 'A', 'B', '6', '4', 'F', 'D', '5', '4', '0', 'E', '3', '6', '6', 'D', '0', 'B', '4', '3', 'D', '4', '8', '9', '0', 'F', '4', '5', '7', '4', '7', 'F', '5', 'D', '9', '3', '7', 'E', '6', '5', '3', '3', '2', '5', 'D', '4', '2', 'D', '4', 'B', 'C', '5', '8', 'A', 'C', 'A', '6', 'C', 'B', '7', '2', '0', 'B', '5', '1', '4', 'E', '3', 'B', 'C', '8', '7', '7', 'D', 'C', '7', '6', 'B', 'E', '2', '7', '0', 'D', 'F', '1', '9', '5', '3', 'A', '2', 'F', 'E', 'D', '3', 'A', '0', '8', '0', '8', 'F', 'D', 'E', 'D', 'A', '7', 'F', 'A', '1', 'F', '1', '0', 'A', '6', '3', 'D', '0', 'A', 'D', '6', '1', '0', 'A', 'F', '9', '0', '3', '0', '0', 'C', '2', 'C', '5', 'F', '7', '6', '9', '8', '6', 'C', 'C', 'E', 'E', '5', '4', '8', '6', '6', 'F', '5', '0', '4', '5', '7', 'F', '1', 'F', '3', 'F', '4', 'F', 'F', '3', 'B', 'D', '8', '7', '1', 'D', '1', '5', 'A', '4', 'C', '2', '9', 'A', '5', 'C', '4', 'A', 'C', '6', 'E', 'D', '6', 'A', 'B', 'E', '3', '6', '1', '2', '2', 'C', '8', '7', '6', 'C', 'A', '6', 'C', '3', '9', '6', '9', '6', 'D', '2', 'A', '7', 'A', 'B', '7', '9', 'B', '9', 'F', '1', '5', 'A', '8', 'D', '1', 'A', 'E', '8', 'B', 'B', 'A', '5', '6', '2', 'B', '9', '1', 'D', '5', 'B', 'F', '1', '6', '3', '8', '5', 'F', '4', '6', '5', 'A', '0', 'E', '7', '7', '8', '5', '0', 'D', '9', '8', '3', '7', '5', '8', 'B', '7', '1', 'B', 'C', '8', '9', 'C', '2', 'F', '0', 'B', '7', 'B', 'F', '6', '9', '9', '5', 'D', 'D', '2', '7', 'A', 'E', '4', '6', '1', '2', '3', 'B', 'E', 'E', '7', '1', 'E', '4', '8', '1', 'E', 'F', '6', 'B', '8', 'C', '4', 'A', '7', 'B', 'B', 'E', '5', '9', 'F', '5', '4', 'B', '6', '5', 'F', '9', '8', '4', '1', 'C', '3', '2', '1', 'C', 'E', 'A', 'A', 'A', 'E', '2', 'F', '8', '7', 'A', 'E', '5', '4', 'A', 'E', '9', 'A', '9', 'E', '3', 'A', '4', '2', '2', '8', 'F', 'F', '3', 'D', '8', 'D', '3', 'F', '4', '2', '0', '2', '3', 'E', '8', '7', '8', '0', 'A', '8', '0', '2', '2', '4', '4', '3', 'E', 'C', '0', '8', '5', '5', 'F', '7', 'A', 'C', '9', '1', 'E', '9', '9', '1', 'F', 'E', '5', 'B', '8', 'F', '2', '2', '4', '5', '2', '0', '3', 'B', '3', '2', '5', '0', 'F', '7', 'C', 'E', '1', '5', '7', '9', '9', '3', 'F', '1', '0', '2', 'E', '7', 'F', 'B', 'B', 'E', 'B', '8', 'C', 'E', '3', 'D', '7', '2', 'A', 'F', 'E', 'F', '1', 'D', '8', '4', 'E', 'A', '5', '8', '1', 'E', '5', '3', '4', 'E', 'F', '8', '6', '5', '9', '8', '0', '0', '0', 'E', '9', 'F', '3', 'F', '2', '2', '9', '5', '0', '1', '3', 'E', '8', '9', '5', '8', 'F', '9', '4', 'A', '0', '1', 'B', '5', 'F', 'A', '2', '3', 'A', '8', 'D', '7', '8', '0', '8', '5', '3', 'E', '3', 'F', 'E', '4', 'A', '5', '6', '3', '0', '9', '1', '0', '0', '7', '4', '4', 'E', '0', '7', '8', '5', '7', '7', '3', '6', 'B', '8', '5', 'A', 'A', 'A', 'D', '5', '8', 'F', 'F', '7', '8', '0', '6', '8', '2', '8', '9', '3', '3', 'F', '2', 'F', '7', '2', '9', 'F', 'B', 'E', '6', '5', 'C', '8', 'C', '5', '4', 'F', '3', '2', '2', '3', 'C', '0', 'A', '9', '3', '2', 'A', '1', '2', '4', '4', '3', 'C', 'A', '0', '0', '4', '4', '0', '4', '4', 'B', '5', '5', '3', '0', 'C', 'E', 'D', 'D', '0', 'F', '9', 'C', '1', '5', '2', '3', 'F', '6', 'D', '2', '3', '2', '4', '3', '8', 'E', 'E', '4', '6', '1', '5', 'E', 'D', 'B', '7', 'F', '0', 'A', 'C', 'F', '4', '6', 'E', '2', '2', '1', '7', 'D', 'E', '6', '2', '6', '9', 'D', '2', '2', '5', '0', '0', '5', '8', 'F', 'B', 'F', 'E', 'E', 'D', '6', 'B', '9', '0', '5', 'F', '9', '0', '2', '9', '9', '1', '1', '3', '3', '6', '5', '7', '8', 'B', 'D', '5', '4', '8', '6', '5', '5', '6', '1', '2', 'A', '0', 'E', '3', '5', '8', '9', 'F', 'D', '6', 'A', '3', 'B', 'E', '8', 'E', '9', '9', 'D', 'B', 'C', '8', '5', 'B', 'E', 'C', 'D', '6', '0', '3', '4', 'A', '2', '9', '9', 'B', 'D', '2', 'A', '8', '2', '4', '8', '7', '4', 'F', 'E', '1', 'C', 'B', '8', '1', 'E', '9', 'B', 'E', 'D', 'E', 'B', '0', '4', '8', '3', 'A', 'B', 'A', '0', 'C', '0', 'D', 'A', 'A', '6', '4', '6', '2', '6', '9', '1', '1', 'B', 'A', '8', '9', '7', '3', 'E', '5', 'E', '3', 'E', '6', '2', 'F', '2', 'A', 'D', 'D', 'A', '2', '2', 'F', 'B', 'B', '8', 'D', '0', 'F', '5', '5', 'C', '9', '4', '3', '0', '7', '7', '8', 'D', 'B', 'B', '3', '1', '5', 'F', 'A', 'F', 'B', '7', '2', 'A', '2', '3', 'A', '9', '5', '7', '7', '2', '2', 'A', '9', '5', 'E', '3', '3', '3', '2', '2', '2', 'C', 'D', 'C', 'B', '1', '2', 'A', '8', '9', '1', 'D', '3', '0', '0', '8', '2', 'F', '8', '8', '7', '8', '3', 'F', 'A', '3', '7', 'C', 'C', '3', 'F', '7', 'F', 'E', '5', '6', '8', '6', '3', '6', 'F', '5', 'D', 'B', 'A', '1', 'D', 'E', 'D', '8', 'E', 'C', '9', 'C', '2', 'E', '1', 'A', 'E', 'E', '6', 'B', 'E', 'A', 'A', '7', '3', '7', '0', '6', '6', '7', 'B', 'A', '8', '8', 'F', 'D', 'B', 'C', 'B', '1', '3', '9', '7', 'D', 'F', 'B', 'E', 'A', '8', '3', 'A', 'E', 'F', '8', '0', 'D', 'F', 'B', '2', '1', 'D', 'E', 'D', 'E', '0', '7', '1', '3', '7', '7', 'D', '7', 'A', '3', 'A', '2', '0', '4', '1', 'B', '0', '9', '8', 'A', 'D', 'F', 'B', '3', '5', 'C', '1', '8', 'F', 'A', 'C', '1', '8', '5', 'D', '3', 'A', '8', 'C', 'E', 'D', 'E', 'A', '7', '7', 'D', 'E', '2', '7', '9', 'E', 'C', 'F', '0', '8', '5', 'B', '8', 'A', '7', '8', '6', '9', 'A', 'D', '3', '0', '5', 'D', '5', '7', '9', '6', 'D', '2', 'E', 'C', '3', 'F', 'B', '2', '2', '1', 'F', '9', 'D', 'C', '3', '0', 'F', '4', 'B', 'F', 'A', '8', 'C', 'A', '8', 'D', '0', '6', '6', '6', '3', 'E', '9', '1', 'A', '5', '0', '6', '6', 'F', '1', '7', 'E', 'A', '3', 'A', '2', 'A', '7', '2', 'B', 'F', '7', '5', '8', '2', 'D', '2', '6', '8', '3', 'C', '5', '1', '0', '4', '3', 'C', '1', '2', 'F', 'F', 'C', 'E', 'A', '0', 'A', '9', '4', 'B', '1', '2', '9', '7', 'F', '9', '6', 'F', '4', '5', '5', 'E', '7', '1', '1', 'D', '1', 'D', '4', '3', '0', '7', '5', '7', '4', '8', 'E', 'B', '7', 'B', '8', 'C', '4', '0', '8', 'A', '0', '9', '1', '8', 'E', '1', 'E', 'D', '1', '3', '5', '1', '0', '9', '2', '9', 'C', '5', '0', '1', '4', 'A', 'F', '6', 'D', '7', '3', '4', 'A', '7', '7', '5', '9', 'D', '3', 'F', 'D', '7', '1', 'C', 'F', '6', '7', '3', 'A', '0', '0', '3', 'C', '5', '5', '9', '7', 'C', '1', 'B', 'D', '3', '0', '0', '6', '5', 'C', '8', '8', 'D', '1', 'E', 'D', '3', '7', '8', '5', 'A', '3', 'A', '8', '5', 'F', 'F', '4', '4', '9', 'D', '0', 'C', '4', '7', '8', '7', 'D', '5', '1', 'C', 'C', '5', '2', '5', '7', 'B', 'F', 'C', 'F', 'D', 'F', '5', 'A', '5', '7', 'D', 'E', '5', 'B', 'A', '2', 'F', 'E', 'D', 'D', '3', '3', 'F', 'F', 'F', '3', 'E', '9', 'C', 'D', 'E', '8', '0', '0', '0', 'A', 'E', 'B', 'A', '5', 'E', 'B', '9', '4', 'A', 'A', '0', '9', '9', '3', '8', '3', 'F', '1', '4', '9', '3', 'C', 'D', 'D', '6', '7', '8', '8', 'E', '2', '6', '2', '1', '1', 'B', '5', '8', 'C', '0', '7', 'D', '7', 'E', 'F', 'D', 'A', 'D', '8', '2', '4', '2', 'D', 'C', 'A', '0', '1', '7', '2', '3', '3', 'E', 'E', 'B', 'B', 'B', '7', '6', '2', 'F', '7', '1', '0', 'D', 'F', 'E', '9', 'A', '2', '9', '0', 'F', '9', '5', '2', '2', '6', 'A', 'C', 'C', '2', '2', 'B', '7', 'E', '0', '7', '7', '9', 'D', 'E', '4', '2', '7', '5', '5', '2', '7', '3', '5', '9', '5', '6', '2', 'A', '7', 'E', 'E', '7', '6', 'F', '3', '0', '2', 'C', 'B', '8', '7', '4', '1', 'D', 'C', '8', '5', 'B', '9', '6', 'B', 'D', '2', 'D', '0', '0', 'C', '1', 'A', '2', '4', '0', 'A', '9', '0', 'F', '4', 'F', '7', '9', '0', 'C', '4', '3', '5', 'C', 'A', '6', 'F', '9', '0', '1', 'E', '7', 'C', '7', 'D', '2', '1', '8', '3', '6', '5', 'F', '3', '0', 'B', 'B', '7', 'F', '3', '4', 'E', '9', 'B', '5', '0', 'B', 'E', '1', 'D', '1', '0', 'C', '3', '3', '7', 'C', 'F', 'D', 'E', '0', 'D', '3', '2', 'C', '7', '9', 'A', '0', '7', '3', '3', 'E', 'F', 'D', 'B', '3', '2', 'D', '6', '7', 'E', '8', '9', '4', '7', 'D', '4', '3', '7', '8', 'C', '0', 'E', '5', '7', '9', '8', '5', '2', '1', '5', '3', '1', '0', '1', '1', 'C', 'F', 'D', '5', '5', 'E', '0', '7', 'D', '2', 'C', '7', '2', 'C', '8', '3', 'E', '8', 'B', 'B', 'B', 'D', '4', '1', 'F', 'D', 'C', 'D', '0', '3', 'C', '9', 'A', 'F', '6', 'D', 'B', 'F', '0', 'D', 'C', 'B', '8', '8', '0', '1', '4', '0', 'C', 'E', 'C', 'A', 'F', '6', '5', '4', 'A', 'E', 'E', '7', '8', 'D', '5', '1', 'E', 'A', '7', '1', '2', '1', 'C', 'D', '5', '0', '7', '1', '1', 'C', '8', '6', 'D', '1', 'B', '5', '1', 'C', 'D', 'C', 'D', 'E', '8', 'A', '2', 'B', 'B', '3', 'F', '0', 'C', '4', '5', 'D', '8', 'B', 'D', '7', '5', '7', '4', 'A', 'F', 'A', 'E', '7', '7', 'A', 'F', '0', 'B', 'F', '8', '4', '3', 'E', '0', 'C', '7', '3', 'A', 'C', '0', 'C', 'F', 'C', '6', '2', 'F', '6', '9', 'E', '0', 'D', '3', '4', '8', 'E', 'F', '0', 'E', '8', 'A', '5', '6', '1', 'F', 'B', '2', '1', '9', '2', 'C', '7', '4', '6', '5', 'D', '6', '9', '8', '0', 'C', '4', '0', '6', '1', 'A', 'B', '1', '1', 'A', '0', 'F', 'D', 'B', '9', '3', 'B', '6', '3', '1', '3', '8', '0', '9', '5', 'E', 'E', '1', 'D', '6', 'F', '5', 'F', '8', '3', 'C', 'D', 'E', '4', 'D', '9', '2', '4', '4', '8', '8', '1', 'B', '5', '5', 'A', '8', '1', 'D', '8', '0', '3', '3', 'F', 'A', '3', '4', 'B', '0', '2', 'A', 'B', '5', 'E', 'D', '5', '7', '3', 'A', '0', 'C', 'B', 'F', '8', '7', '8', '2', '1', '9', 'C', 'A', '5', '1', '2', '8', 'D', '2', '9', 'F', '1', 'E', '3', 'D', '6', '9', 'F', '8', '7', '9', '4', '8', '4', '2', '7', 'D', 'E', 'F', '5', 'D', 'D', 'F', 'A', '1', 'D', '7', '9', '2', '5', '4', '2', 'B', '6', '1', '6', '4', 'C', 'D', 'C', '5', 'B', '5', '4', '1', 'F', '0', '2', '5', '0', '8', 'A', 'A', '6', 'B', '1', '1', '2', '0', '3', '3', '8', '1', '5', '0', 'D', '4', '0', '3', '7', '2', 'A', '9', '6', '1', 'B', 'E', '5', 'B', '6', '4', '4', '3', 'D', 'E', '6', 'E', 'B', '7', '0', 'D', 'C', '0', '4', '1', 'A', 'D', 'F', '8', '0', '1', '5', '1', '6', 'C', '4', '5', '0', 'F', '7', '0', 'A', '9', '6', 'B', 'E', 'A', '6', '2', '3', 'B', '5', 'A', '8', 'F', 'C', '0', '6', '5', 'C', 'D', '0', '2', '7', '2', 'C', '2', '6', '8', '0', '6', '0', '7', '9', '2', 'D', 'B', 'B', '9', '8', 'F', '7', '0', '8', 'A', 'E', '1', '4', '0', 'A', '2', '7', '2', '1', 'F', 'A', '6', '1', '4', '2', 'F', 'D', '0', '3', '6', '5', '4', 'F', '4', 'C', '3', '3', '6', 'B', '5', '8', '8', '0', '9', '3', '6', '5', '7', '9', '5', '2', '4', '5', '5', 'F', 'D', 'C', 'C', '1', '8', '2', '6', '7', 'E', 'E', '7', 'B', 'C', 'F', '3', '1', '3', 'E', 'D', '5', '2', '1', '7', '8', '9', 'F', 'B', '9', '8', 'B', 'C', 'C', '5', '6', 'F', '5', 'C', '9', 'A', '5', '7', '3', 'B', 'B', 'E', 'B', 'B', 'B', '4', '0', '3', '8', '9', '5', '2', '7', '9', 'E', '3', 'C', 'F', '3', '2', '4', '0', 'D', '7', '0', '3', 'E', 'C', '3', '7', '1', '2', '7', '3', 'A', '0', '0', '5', 'C', '9', '9', '8', 'F', '3', '0', 'C', '7', '3', 'E', 'F', '2', 'A', '6', 'D', '6', '4', '1', '3', '8', '9', 'E', '3', '7', '4', '0', '9', '6', '6', 'C', '3', 'D', '1', '1', '9', 'E', 'A', 'E', 'D', '8', 'E', 'C', '8', 'C', 'E', '1', '0', '9', 'B', '2', 'D', '2', '3', '0', '3', '5', '7', '8', '0', 'A', '8', '4', 'F', 'B', '0', '1', 'D', '3', '3', '4', '3', 'E', '3', 'B', 'E', '5', '8', '6', 'A', '7', '7', '5', 'F', '1', 'E', '8', '6', 'A', '8', '1', '0', '3', '0', 'F', '3', 'D', 'B', '6', 'A', 'E', 'B', '6', '2', '6', 'E', 'E', '3', 'D', '8', '9', 'C', 'B', '4', 'D', 'E', '8', 'A', 'E', '7', '7', '0', 'A', '5', 'A', '4', 'C', 'F', '3', 'C', '1', 'C', '5', '2', 'F', '4', 'C', 'E', '2', 'A', '3', '7', '0', '3', 'C', 'D', '1', '4', '1', '4', '7', '1', '7', '0', 'A', 'B', '9', 'E', '1', '9', 'A', '2', '1', '2', 'B', '7', 'D', 'D', '5', '8', '6', '0', '6', 'B', 'A', 'B', 'C', 'B', '0', '6', 'F', '8', 'A', 'E', 'A', '8', '5', '0', 'D', '7', '8', '1', 'A', '2', '6', '0', '7', 'D', '6', '0', '4', '8', '4', '8', '0', '7', '8', 'D', 'C', 'F', 'D', 'F', '9', 'B', '9', 'D', 'E', '9', '3', 'A', '8', 'D', '8', '3', '3', '7', '3', 'E', 'F', '7', '8', '4', '7', '9', 'D', '1', 'E', '6', 'E', 'B', 'E', 'A', '9', 'C', '0', '6', '0', '1', '2', '0', 'C', '5', 'E', '6', 'C', '0', 'F', 'C', '4', '7', '7', '8', 'B', 'A', 'C', 'A', '6', '4', '2', '7', 'D', '0', '9', 'F', '8', 'A', '4', 'A', '6', '2', '2', '5', 'F', 'B', '2', '8', '7', '7', '2', 'C', '9', '5', '6', 'C', '5', 'C', '8', '8', 'C', '2', '2', 'E', '6', '0', '8', '0', '0', '0', 'C', '1', '6', 'D', 'F', '9', '1', 'A', 'B', '4', '9', '6', 'D', '0', '9', '6', '5', '7', '3', '4', 'D', 'A', '8', 'F', '1', '0', '6', 'D', '4', 'F', '5', 'F', '5', '4', '3', '5', 'E', '1', '0', '0', '8', '3', 'A', 'E', '3', '5', '1', '4', 'E', 'A', 'D', 'F', '1', '2', '9', '2', 'E', '7', '8', 'A', 'B', '6', '8', 'B', '5', '3', '2', 'A', '1', '1', 'C', '7', 'E', '0', 'E', 'C', '1', '8', '1', '5', '5', '8', '9', 'E', '4', 'C', '1', 'B', 'D', '2', 'C', '7', '6', 'D', 'D', 'C', '5', 'D', '0', 'D', '2', 'C', '2', '5', '4', 'C', 'D', 'A', '7', 'F', '3', 'F', 'C', '8', '3', '9', 'C', 'C', 'D', '2', 'C', '4', '9', 'B', 'D', 'D', 'F', '5', '8', 'D', 'B', 'E', '4', '1', 'F', 'C', 'F', '9', '9', '5', '5', '8', '5', '5', '0', '4', '9', '2', 'B', 'C', '7', '4', '9', 'A', '1', '1', '3', 'D', '5', 'E', '2', 'A', '0', '1', 'C', '5', '5', 'C', 'E', 'E', '5', 'A', 'D', '3', '0', '3', 'A', 'D', 'C', '5', '4', '0', 'B', '9', '1', '9', '0', 'C', 'D', '0', '0', '9', 'B', 'D', '0', '9', '2', 'A', '2', '6', '7', 'C', 'A', '6', '9', '5', '9', 'B', '7', 'A', '8', '9', 'C', '6', 'A', '4', '5', 'B', '2', 'C', '9', '0', '4', '8', '6', '8', '9', '5', '4', '7', '1', '3', '1', '1', 'E', 'A', 'F', '3', 'B', '9', 'D', '7', '0', '7', '2', 'B', '2', '4', '6', 'A', '6', 'C', 'F', '1', 'C', 'D', '0', '2', '3', '5', '2', '2', '5', 'E', '2', 'F', '0', '0', '8', 'C', 'F', '8', '4', '1', 'E', 'C', '8', '0', '2', '5', '6', 'B', '4', 'C', '5', '9', 'B', '7', '1', '9', 'D', 'D', 'B', 'D', '1', 'C', '8', 'C', 'A', '2', '5', '0', '0', '6', '2', 'C', 'A', 'A', 'D', '8', 'A', 'E', '9', '8', '9', 'B', '3', 'B', 'A', 'E', '9', 'B', '6', '4', '1', '6', '3', '6', 'C', 'D', 'F', 'E', 'C', '7', 'C', '0', '8', 'F', 'D', 'F', 'B', 'E', 'C', '7', 'F', '2', 'E', 'F', '2', '7', '8', '7', '1', 'A', 'D', '5', '2', '2', '8', 'D', 'B', '7', 'B', 'C', 'B', '1', '2', 'C', '0', '3', '6', 'F', 'A', '1', '0', 'B', '7', '3', 'C', '1', '6', 'A', 'B', '4', 'F', 'B', '9', '6', '4', '5', 'A', 'E', '3', 'D', '8', '8', 'E', 'D', 'B', 'C', 'F', '0', '5', '4', '1', 'F', '3', '8', '3', 'A', '3', '6', 'A', '2', '6', '2', '9', 'F', 'D', '9', 'D', '2', '5', '5', '5', '3', '7', 'B', 'D', '3', 'A', '1', '2', 'A', '0', '2', '9', '4', '8', '1', 'A', '9', '2', 'D', 'F', '2', 'D', '2', '1', '5', '9', 'B', 'E', '5', 'B', '6', 'F', '2', 'C', '8', 'E', '2', '6', '0', '5', '3', '4', '3', 'C', '4', 'B', '7', 'B', '9', '4', 'F', '5', '6', '3', 'C', 'A', '5', 'B', '5', 'A', 'F', '7', 'A', '8', 'A', '8', '1', '3', 'C', 'E', 'B', '4', '8', 'D', 'A', '4', '0', '4', '4', '6', 'E', 'E', 'E', '3', '5', '9', '8', '7', '6', 'F', '4', '6', 'B', 'B', '3', '8', '1', '8', 'C', 'B', '1', '5', '0', '3', '4', 'B', 'D', '3', '8', '1', 'D', 'B', '8', 'A', 'A', '6', 'D', 'E', '1', '5', '7', '2', 'E', '5', 'C', '4', '6', 'A', 'B', 'B', 'B', '8', '4', '4', 'E', '0', '5', 'A', 'C', '3', 'C', '5', '5', 'F', 'C', '0', '9', '5', '6', '7', 'C', '5', 'D', '7', '4', '5', '1', '1', 'B', '4', '0', 'E', '1', 'E', '6', '0', '1', 'F', 'F', '9', '8', 'A', '7', '3', '6', '3', '7', '4', '7', '3', 'C', '6', '0', '9', 'A', 'A', '5', 'E', '7', 'A', '8', '3', '4', '8', '5', '3', '7', '8', '0', '2', '2', '9', '4', '8', '9', 'D', 'B', 'B', 'A', 'C', 'D', '2', '1', '6', '2', 'A', '1', '8', 'E', '6', 'E', '7', '5', 'F', '4', 'C', 'F', '5', 'B', 'F', 'B', '1', '4', '1', 'F', 'C', 'D', '2', '5', '8', 'D', '6', '4', 'A', 'D', 'F', '9', '7', '5', '3', '8', '6', 'E', '9', 'C', '4', 'F', '9', '3', '4', '7', '0', 'B', '6', '4', '0', '4', '3', 'F', 'E', '0', 'A', '2', '3', '1', '8', 'F', 'A', 'D', '9', 'A', '7', '0', '1', '9', 'C', 'C', '1', '2', 'A', 'F', 'B', '0', 'A', '9', 'B', '6', 'D', '4', '4', 'B', '5', 'F', '0', 'D', '2', 'C', '2', '7', '1', '3', '9', '8', '7', '3', 'C', '5', '2', 'F', '8', 'D', '5', 'D', '4', 'B', 'A', '9', '2', '8', '0', '0', '0', '3', 'D', '8', 'D', '3', 'E', '5', 'A', '6', '4', 'F', '8', '3', '4', '7', 'F', 'C', 'D', '5', '3', '9', '1', '9', '1', 'D', '7', 'F', '9', 'E', 'A', '0', '7', 'F', 'B', 'F', '5', '8', 'A', 'A', '8', '2', 'A', 'C', '3', '1', '9', 'D', 'D', '4', 'A', 'B', '5', '9', '9', 'E', '2', 'F', '2', '2', '0', '3', '3', 'A', '1', '5', '1', 'A', 'C', '7', 'A', 'C', '8', 'C', '1', '0', '4', '5', 'F', 'C', 'C', 'E', '6', '1', 'B', '0', 'E', '4', '9', '2', 'A', '1', 'E', '8', '2', 'B', 'C', '3', 'C', 'A', 'B', '3', '0', '5', '7', 'A', '7', 'F', 'A', '3', '4', 'D', '3', '4', '6', '1', '9', '2', '4', 'A', 'A', 'D', '1', 'B', '9', '4', '2', '0', 'F', 'E', '3', '8', '3', '2', '4', 'F', 'E', 'A', 'E', 'B', '4', '6', '6', 'D', 'B', '7', '8', 'C', 'E', 'B', '8', '7', '9', 'C', '8', 'D', '5', '6', 'C', '4', 'B', 'B', '5', 'E', '3', '6', '6', '1', '7', 'D', 'E', '9', 'F', '3', 'A', 'C', 'B', '3', 'D', '7', 'D', '9', '3', '5', '4', 'F', '6', '2', 'D', '3', '4', '1', '6', 'B', 'C', '1', 'C', '7', 'A', 'A', 'E', '1', 'E', '2', '8', 'E', '4', '9', '5', '0', '4', '3', '8', '0', 'D', '0', '0', 'A', '8', '6', '8', '4', 'A', '3', '5', '1', '9', 'D', '7', '1', '6', '5', 'B', 'B', 'C', '0', '9', 'C', '2', 'C', 'C', '7', '9', 'C', '7', '0', 'A', '0', '4', '4', '4', '9', '2', 'D', 'E', '5', '4', 'E', '3', 'A', 'E', '4', 'A', '3', '9', 'C', '4', '7', '3', '6', '9', '0', '9', '8', 'A', 'E', 'B', 'F', 'B', 'E', 'A', '8', '2', '1', 'F', 'D', '6', 'C', 'D', '2', '4', '5', '7', '1', 'A', 'B', '6', '0', '3', '2', 'F', 'C', '4', 'B', 'B', '0', '1', '2', '6', 'D', '1', 'B', 'D', 'D', '0', 'D', 'A', 'D', 'F', 'D', '1', 'A', '4', '5', 'B', 'B', '7', 'B', '0', '7', '4', 'C', '9', '3', 'D', '8', '7', '4', 'D', '4', '2', '2', 'E', '3', '6', '3', '0', '7', '4', '6', 'D', '9', 'F', 'B', '7', 'E', 'A', 'E', 'A', '9', '2', '0', 'D', 'F', '7', '4', '2', '1', 'E', '0', '0', '3', 'D', '6', 'C', '3', '9', '1', '1', '7', '4', '4', '5', '9', 'D', '5', 'B', '5', '6', 'D', 'C', 'C', '3', '7', '6', '0', '5', 'C', '1', '1', 'B', 'E', '4', '0', '4', '9', '6', '3', 'D', 'A', 'C', '8', '6', '0', 'A', '0', '9', 'D', '1', '5', '3', '3', 'A', 'D', '5', '6', '7', 'D', '6', '0', '6', '9', 'B', 'A', '9', '3', 'E', 'F', '6', 'E', 'C', '8', 'D', 'C', 'B', '2', 'E', '9', '2', 'B', '1', '7', '9', '2', 'C', '6', 'A', '6', 'C', '7', '8', 'F', '3', '9', '9', '7', '7', '9', '4', '5', 'B', 'F', '8', 'D', '7', 'F', '4', '5', 'D', '1', '2', 'C', '8', '5', 'E', '5', '5', '7', '7', '1', 'F', '4', '1', 'F', 'B', '3', '2', '4', '4', '3', 'D', '1', '6', '2', '7', '8', '5', '5', '6', 'C', '4', '3', '5', 'C', '5', '6', '5', '5', '0', '7', '8', '6', '1', '6', 'A', '6', '6', '4', 'B', 'F', '3', 'D', 'A', '0', 'F', 'B', '3', '2', '8', '0', '4', 'F', '7', '4', 'B', '5', 'A', '6', 'D', '0', '6', 'B', '1', '4', 'F', '3', '8', '2', 'B', '0', 'D', 'A', '6', 'F', 'D', '3', '1', '9', '2', '5', '1', '0', '1', 'B', '3', '6', '2', 'A', 'B', 'D', 'D', '4', 'D', '7', 'B', '3', '7', 'D', 'F', '9', 'F', 'A', '9', '7', '4', 'E', '0', 'A', 'D', 'B', '6', '3', '7', '8', '3', '4', '1', '6', '9', '3', '9', '7', '5', 'D', 'A', '9', 'F', '9', '5', '0', '7', '4', '1', 'B', 'E', '2', '1', 'F', '5', '0', 'F', 'B', '8', '4', '0', '5', 'C', '5', 'E', 'B', '9', '6', 'D', '2', 'F', '8', '7', '3', '0', 'C', '8', 'B', 'F', '4', '6', '4', '2', '4', '1', 'A', '2', '0', '1', 'E', 'E', '1', '0', 'E', '8', '4', '0', '3', '0', 'D', '6', '3', 'E', '8', '4', '6', '8', 'D', '7', '0', '7', 'E', '6', 'B', 'C', 'E', '5', 'A', 'F', 'E', '0', '0', '5', '0', '5', 'C', 'D', 'C', 'F', '3', 'E', 'A', '8', '2', 'D', '0', 'F', '9', 'F', '3', '5', '3', '5', '8', 'E', 'C', '7', 'C', 'C', 'B', 'C', '7', 'F', 'B', '1', '4', '5', '7', '8', '4', '3', '8', 'A', 'F', '7', '3', '0', 'F', 'B', '1', 'C', 'C', 'F', '0', 'E', 'E', '1', '3', '9', 'E', '0', '8', 'B', 'D', '8', 'C', '2', 'C', 'A', 'A', 'E', '7', '0', '8', 'D', '6', '0', '2', 'B', 'C', 'E', '8', '7', 'A', '9', 'E', 'B', 'F', '9', 'C', '5', 'C', '8', 'B', '1', '9', 'B', '9', '5', '0', '5', '7', '6', '6', 'A', '4', 'F', '3', 'C', 'C', '5', '7', 'F', '2', '3', 'C', '4', 'D', 'C', '4', '7', '3', 'D', 'F', 'D', '2', '8', 'C', 'A', 'B', '8', '8', 'C', '4', 'F', '7', 'D', 'E', 'C', '9', '4', '5', 'A', 'B', '2', '3', '1', '3', '6', '8', 'B', 'E', '5', '1', 'F', '6', 'C', 'F', '6', 'F', 'A', 'A', 'F', '9', '7', '7', '4', 'A', 'A', '3', 'D', 'F', '2', '6', 'C', '3', '1', '7', '2', 'A', '2', '0', 'F', '9', '0', '0', 'E', 'B', '8', '3', 'F', '8', '6', '3', 'A', '2', '3', '9', 'E', '5', '3', 'A', '2', '8', 'C', '0', 'D', '2', 'D', 'F', 'F', 'F', 'E', '6', 'D', '8', 'B', '4', '7', '4', '3', 'C', '4', '5', '4', '8', '1', 'A', '5', '3', 'D', '8', '8', '0', '0', '6', '0', 'C', '4', '4', '9', '1', 'F', '4', '1', 'D', '0', 'F', 'B', '7', 'D', 'C', '4', 'A', 'B', 'C', 'E', 'E', '5', '4', '8', '4', 'B', '5', '0', 'D', '8', '6', '7', '6', '3', '3', '7', '8', '6', '7', '6', '3', '1', 'C', '1', '9', '1', '3', '3', 'F', '3', '9', '5', '4', 'D', 'A', '8', '0', '0', 'F', 'E', '4', 'F', 'A', '4', 'D', '1', '0', '8', 'F', '6', 'B', 'F', 'A', '3', '4', '1', '3', '6', 'D', '9', '1', '3', 'B', '0', '9', '5', '0', 'F', '3', 'E', '8', '8', '2', 'A', 'F', '4', '8', '6', '0', 'D', '1', '1', '2', 'E', '7', '2', 'E', '5', '7', 'A', '4', '9', '8', '5', '0', 'A', '0', 'F', '7', '0', '3', '5', '6', 'A', '5', '1', '4', '4', '6', 'C', '3', 'B', '6', 'C', '4', 'A', '6', '4', '3', '1', 'E', '8', 'E', '5', '8', '0', '4', '7', '9', '8', '3', '3', '7', '3', 'C', 'F', '9', '2', '3', 'F', 'D', '3', 'A', 'A', 'D', '3', '2', '4', 'E', 'A', '3', '6', '5', 'E', 'A', '1', 'C', 'C', '7', 'D', 'E', '6', '9', '0', '4', 'B', 'D', 'F', '6', '9', '8', 'A', '3', '8', '4', 'E', '1', '4', 'C', '8', 'B', '8', '9', 'C', 'E', '3', 'B', '7', '8', '0', 'C', '5', '2', '7', '6', '0', '0', '4', 'F', '8', '4', 'A', '1', '8', 'F', 'C', 'D', 'C', '7', '5', '7', 'E', '2', 'A', '1', 'E', '2', 'C', '6', 'C', 'E', '4', '4', '0', '9', '4', '4', '2', 'C', '1', '8', '9', '1', '6', 'C', 'E', '6', '1', '1', '4', 'B', '2', '5', 'C', '7', 'D', '6', '5', '0', '5', 'D', '0', '0', '3', 'F', 'B', 'A', 'A', 'A', 'E', '8', '0', 'D', '2', '9', 'C', '6', '6', '8', 'E', '0', '0', 'E', '1', '8', '9', '4', 'C', '7', '9', '7', 'B', '6', 'C', '1', 'E', 'B', '8', '4', 'A', '2', 'D', '0', '3', 'A', '4', '8', 'A', 'D', 'E', '8', '7', '7', '2', '6', '1', '8', '8', '0', '5', '9', 'E', 'B', '5', 'B', '3', '2', 'A', '0', '4', 'A', 'A', '2', '4', '1', '2', '8', '7', '5', '7', 'F', '3', 'F', '1', '4', '1', '6', '6', '0', '8', '8', 'B', '9', '9', '9', 'D', 'C', '4', '9', 'F', '7', 'A', '9', '2', 'F', 'B', 'A', '3', 'C', 'F', '5', '6', '5', 'E', '2', '7', 'E', 'B', '8', '3', 'F', 'B', 'A', '1', 'A', '5', '4', '8', 'C', 'B', '5', '3', 'B', '8', '8', '3', 'D', '4', 'B', '5', 'D', '5', '7', '0', 'E', '8', 'D', '1', '5', '7', '9', '4', 'D', 'F', '6', 'F', 'A', '3', '2', 'F', '8', 'B', 'F', 'E', '9', 'D', 'C', '7', 'E', '2', '3', 'D', '8', 'D', 'A', '7', 'E', '2', 'A', 'C', 'B', 'E', '9', 'F', 'B', 'E', 'F', '5', '3', '0', '3', 'E', '9', '8', '3', '7', 'B', '8', '8', '6', 'B', 'F', 'B', '3', 'E', '5', '4', '1', '9', '9', '8', '4', '1', '2', 'A', '5', '2', '3', '7', '4', 'B', '6', '7', '0', '5', 'B', 'A', 'A', '7', '1', '7', '9', '1', 'A', '7', 'B', '7', 'F', 'B', '3', '5', '0', 'B', '0', '4', 'C', '4', 'A', 'A', '0', '4', '5', '7', 'F', '3', 'D', 'D', 'E', 'A', '9', '7', 'E', '4', '2', '7', 'B', '1', '5', 'D', '7', '0', '0', 'F', '3', '6', '9', 'A', 'F', 'B', '1', '4', 'D', '3', 'E', '8', 'A', 'A', '5', 'E', '1', '2', '6', '1', 'B', '5', 'A', '4', '2', '7', '6', 'A', '9', '5', '4', 'C', '2', '4', '0', '6', 'F', 'E', '5', '1', '2', 'A', '3', 'C', 'E', '8', '1', '6', 'E', '8', '4', '1', '7', 'D', 'A', 'A', '0', 'B', '1', '4', 'A', '5', 'F', '9', '8', '0', '2', '2', '5', '1', '0', '1', 'D', '5', 'D', '6', '4', 'A', '9', 'E', '8', '1', 'E', '1', '2', 'B', '7', '6', 'C', 'D', 'E', '6', 'C', '9', 'F', '7', '1', 'F', '3', 'C', 'B', '0', 'F', '0', '2', 'B', '8', '3', '7', 'D', '5', '3', '3', '9', 'B', 'D', '0', 'B', 'C', '8', '6', '7', '6', 'D', '6', '0', '0', 'C', '8', 'A', '4', '4', 'B', '4', '7', '1', '6', 'E', '9', 'E', '9', '6', '4', '5', 'F', '7', '3', '5', 'D', 'B', 'A', '8', '3', 'A', 'D', 'B', '1', 'A', '9', 'D', 'D', '8', 'B', '5', '9', '2', '7', '5', '4', '8', 'E', 'C', 'C', '9', '0', '5', '7', '9', '5', '8', 'E', 'A', 'D', 'A', 'E', '8', 'E', '6', '4', '3', '0', '2', '1', 'F', '2', 'B', '3', 'B', '0', '7', 'A', '0', '1', '1', 'E', '5', 'D', '8', 'A', '4', '1', 'E', 'F', '0', 'C', '6', '2', '2', '8', 'B', '8', 'D', '2', '2', '2', '9', '2', '9', '5', 'D', 'A', '7', 'B', 'C', '8', '6', '6', 'F', 'A', 'A', '1', 'B', '3', '4', '3', '8', 'B', 'D', '6', '1', 'E', 'D', 'A', '0', 'A', 'E', 'E', '4', 'D', '9', '0', 'A', 'F', '5', 'A', '8', '9', 'E', 'E', '5', '8', '8', '1', '4', 'A', 'C', '4', '7', '5', 'B', '9', 'B', '1', 'B', '2', '9', '8', '8', 'D', '4', 'D', '6', '7', '5', 'D', '0', '8', 'C', '9', '2', 'E', '6', '9', '0', '7', '9', 'C', '3', 'D', '2', '8', '6', '7', '1', 'E', 'A', 'C', '6', 'C', 'F', 'E', '2', '5', '2', 'E', 'F', '1', '6', '1', '7', '5', '1', 'E', '5', '5', '5', 'D', 'A', '6', '3', 'F', '5', 'E', '0', '1', '2', '9', 'F', '7', '9', '2', '9', '3', 'E', '0', 'C', 'B', 'C', '7', '1', '9', '4', 'B', 'F', '1', 'A', 'D', '4', 'A', '1', '6', '0', '2', 'A', '6', 'E', 'E', '5', '3', '4', '9', 'F', 'E', '6', '4', '5', '5', 'B', 'E', '5', '1', 'C', 'B', 'D', '8', 'C', '7', '8', '6', '5', '8', '2', '3', '0', 'F', '7', '9', '3', 'F', '7', 'C', 'C', '5', '1', '7', '4', '5', 'F', 'E', 'F', 'B', '0', '3', '7', '2', '7', '1', '2', 'E', '3', 'B', '7', '7', '7', '1', '4', '1', 'A', 'C', '1', '3', 'C', '4', 'A', '5', '3', 'A', '3', 'C', '7', 'D', 'E', 'E', 'F', '2', '2', '2', 'D', '6', '0', '6', '3', '8', '5', '7', '1', '8', '7', '6', '5', '1', 'A', '8', '5', 'A', '2', '2', 'E', '5', '0', 'E', 'C', '7', 'A', '6', '5', '3', 'F', 'C', 'A', '6', 'D', 'B', '7', '4', '1', '9', '6', '4', '0', 'E', '3', '2', '3', 'D', '3', 'A', 'E', '8', 'B', '0', 'D', '3', '6', '7', 'C', 'A', 'F', 'C', 'C', 'D', '1', '9', 'B', '3', '3', '2', '9', '0', '4', '8', 'E', 'E', '4', '3', '9', '2', '5', '5', '7', 'C', 'B', 'F', '8', 'C', 'E', 'F', 'C', '3', '1', '4', '2', '3', '7', '5', '5', '9', '4', 'D', '5', '5', '0', 'C', '9', 'F', '4', '7', '9', '4', '6', 'F', '5', '7', 'C', '5', 'B', '2', '3', 'E', '3', 'B', '4', '0', 'E', 'A', 'C', '6', 'E', '5', '4', '3', 'F', '4', 'E', '9', 'B', '1', 'C', '2', '2', '5', '2', '3', 'A', '6', 'E', '9', 'C', '7', '7', '3', 'D', '5', '2', 'E', '7', '0', '7', '9', 'F', '1', '9', 'C', '0', '8', '0', 'F', '7', '4', '6', 'A', 'B', '3', '0', 'C', 'B', 'D', 'C', '1', 'A', 'B', 'F', 'F', '6', '1', '4', 'F', '3', '4', '4', '3', '2', '2', 'A', 'C', 'A', '5', '7', '3', 'E', '3', 'E', '7', '8', '9', '0', '3', 'E', '0', 'E', '8', '4', '2', '9', '9', '0', '8', '0', 'F', 'D', '2', '6', '6', 'B', 'B', '4', 'A', '1', '2', 'F', 'C', '6', '4', 'B', 'E', '4', '7', '2', '7', '9', 'B', '1', '8', '0', 'B', 'D', 'F', '6', 'A', 'D', '0', 'B', '1', 'C', 'E', 'A', 'A', '9', '8', '9', 'E', '5', 'A', '3', '1', '7', '6', 'C', '9', '4', '0', 'C', '7', 'F', '3', '8', 'C', '8', '1', 'D', '1', 'A', '4', 'E', '5', '1', '3', 'A', '1', 'F', 'D', '8', '8', '7', '3', '9', 'D', '4', '8', '6', 'F', '3', '5', '1', '7', '2', 'F', 'B', 'B', '2', '0', '8', 'C', 'E', 'D', 'C', '6', 'C', 'C', '7', '2', 'F', '7', 'C', 'C', '5', '6', 'C', 'E', 'E', '5', '0', '8', '3', '8', '8', '0', 'E', '7', '8', 'A', '4', 'E', 'E', 'B', 'E', 'E', '5', '6', 'C', '6', '3', '0', '5', '3', '9', 'B', 'B', '1', 'A', 'B', 'A', '5', '9', 'A', '0', '4', '9', '1', '5', 'B', 'F', 'B', '4', '8', 'C', 'E', '5', '3', '5', 'C', '5', '2', '7', '0', '3', '8', '0', 'C', '8', 'B', '0', 'C', '9', 'A', 'C', 'B', 'F', '3', '7', '0', '6', '0', 'A', '7', '9', 'C', 'E', '8', 'E', '8', '6', '3', '7', '7', '5', '7', '0', '9', '8', '4', '1', '2', 'B', '4', 'D', '2', '9', 'D', 'C', '5', 'B', 'C', '7', 'A', '1', '9', 'C', '8', 'C', 'A', '3', 'E', 'B', '4', 'A', '6', '7', '9', 'E', '1', '2', '3', '2', '8', 'C', '2', 'C', '4', '8', '7', 'C', 'A', '2', '0', 'D', '2', '7', '5', '1', '3', '7', '7', '2', '4', '0', 'B', 'C', 'A', '5', '3', '5', '3', '2', '2', 'A', 'F', '1', 'B', '2', '7', '1', '5', '6', '3', 'F', '7', 'E', 'B', 'E', '2', 'F', '8', '8', 'D', 'C', 'F', '2', '7', 'D', '6', 'C', '8', '9', 'F', '8', 'C', '3', 'D', '0', 'B', '7', '3', '5', 'B', '4', '8', 'F', '1', '6', '8', '9', '7', '4', 'E', '7', 'A', 'E', '4', 'F', '8', '5', '3', '9', 'F', 'A', 'A', '2', '8', '2', 'D', '4', '1', '0', 'C', 'A', 'C', '4', '0', '3', '2', 'A', '0', 'E', '0', '2', 'F', '0', '0', 'D', 'B', 'E', 'A', 'E', '1', 'D', 'E', '6', '7', '7', 'F', '0', '3', '5', 'C', '9', '2', '7', '5', '3', 'C', '7', '5', 'E', '1', '6', '9', 'B', 'F', '0', '0', 'E', '9', '2', '4', '7', '8', '6', '0', '8', '4', 'D', 'E', '2', '5', '1', '9', '4', '9', '2', '2', '1', '6', 'A', 'D', '9', 'F', '7', 'C', '5', '4', 'B', '6', 'D', '4', 'A', '7', 'A', '2', '7', '9', 'D', '1', 'F', '3', 'A', 'D', '0', 'B', '3', 'A', 'D', 'A', '3', 'A', '9', 'E', 'D', '5', 'F', 'A', 'A', 'B', '4', 'C', 'A', '3', 'A', '0', '7', '7', '7', 'B', 'C', '8', '0', '0', 'A', '3', '8', '6', 'C', '0', '1', '9', 'A', 'C', '8', 'D', '8', '7', 'F', 'E', '5', 'D', '7', '3', '6', '1', '4', '5', 'D', '0', '1', '4', '5', 'A', 'A', '1', 'E', 'E', 'E', 'F', '3', '2', '9', '0', '0', 'F', '4', 'F', 'B', 'A', '3', '1', '5', 'E', '8', '5', '5', '5', 'E', '9', '6', 'F', '9', '3', 'E', '6', '6', '3', 'F', '1', 'C', 'B', 'E', '7', '9', '0', '9', 'F', 'D', '6', 'D', '6', '2', 'C', 'A', '5', '5', '4', '7', '4', '3', '1', '9', 'E', 'C', '6', 'B', 'D', 'F', 'F', '5', 'E', '4', '9', '5', '3', '8', '0', 'F', 'C', '9', '5', 'C', '8', 'F', 'B', '5', 'C', '1', '4', '6', '1', '7', '6', 'D', 'B', '0', '8', '3', '3', '5', 'D', '2', '4', 'C', '9', 'B', 'A', 'F', 'A', '7', '4', '7', '2', '0', '6', 'D', 'F', '3', '2', 'F', 'F', '0', 'A', 'C', 'C', 'D', 'B', 'E', '1', '2', '1', 'A', '2', 'C', 'B', '7', '9', 'B', 'F', '7', '9', '7', '8', 'B', 'D', '4', '4', '3', 'F', '0', '3', '3', 'E', 'F', '9', '1', '1', '4', 'C', 'E', '9', '0', 'C', '6', '8', 'F', '5', '0', '9', 'E', 'A', '9', '8', 'E', '0', '6', '1', 'E', 'F', '1', '8', '6', '7', '0', 'E', 'C', 'D', 'D', 'A', '1', 'C', 'D', '0', '3', '1', '6', '0', '3', 'A', 'E', '3', '7', '9', '8', '9', '4', 'A', '2', 'F', 'D', '9', 'B', 'B', 'B', '7', 'E', 'C', '4', 'A', 'F', 'C', '7', 'F', 'B', 'C', 'F', '6', '9', 'C', '1', '4', '8', '8', '1', 'E', 'D', '0', 'F', '5', 'E', '4', '6', '1', '4', 'C', '4', '8', '6', '1', '8', 'B', 'A', '9', 'D', 'D', 'F', '2', '6', 'C', 'C', '9', '0', 'B', '3', '7', '1', 'C', '0', 'B', 'B', 'C', '8', '7', 'B', 'C', '8', '1', 'F', '8', 'F', '8', '1', '4', 'D', '8', '6', '3', 'C', 'D', '4', 'C', '4', '3', 'D', 'D', '0', '4', 'D', '4', '1', '2', '8', 'A', '7', '8', 'B', '6', '1', 'E', 'E', '4', '2', '1', '6', '4', '5', 'D', 'C', '1', '0', 'B', 'F', '6', '3', '0', 'D', 'D', 'C', 'B', '1', 'C', '9', '9', 'D', '7', 'B', 'B', '3', '8', '9', '0', 'C', '0', '6', '2', '7', '9', '3', '4', '5', 'D', 'E', '6', '3', '4', '0', '9', '4', '8', '8', '5', '5', 'C', 'F', '6', '9', '6', '6', '9', '5', '4', '8', '0', '1', '4', '8', '0', '1', '5', '9', 'D', 'F', 'F', '4', '4', 'C', 'E', '4', '2', '3', '6', '8', '0', '9', '3', '0', 'B', '0', 'E', '1', '5', '1', 'F', '1', '1', 'E', '0', '2', '1', 'D', '0', 'F', 'E', 'D', '0', 'E', '6', '3', '2', 'A', 'F', 'E', '5', '5', '4', '0', 'F', 'B', '3', 'D', '6', 'F', '3', 'D', '0', '4', 'D', '6', '0', '8', 'D', '4', '2', '8', '8', '8', '2', '6', '7', '7', 'B', '7', 'E', '6', '7', 'A', '6', '8', '8', '0', 'D', '5', 'D', '9', '6', '9', '2', '8', '7', 'E', 'D', '4', '4', 'F', '0', 'F', '0', '0', '5', '1', '2', 'F', '8', '6', '2', '4', '3', '6', '5', '1', '7', 'B', '6', 'C', '8', '6', 'A', '7', '1', '5', '6', 'E', 'B', 'D', '5', '0', 'E', 'E', '5', 'F', '6', '1', '8', 'B', '5', '5', '1', '7', 'F', 'C', 'B', '6', '5', 'C', '3', 'C', 'D', '0', '6', '6', '1', '1', '2', '7', '4', '8', '6', 'F', '9', '4', '7', '2', '2', 'E', '3', 'A', '7', 'D', '2', 'C', '5', '3', '5', 'E', 'F', '2', '9', '5', '4', '4', '0', '1', 'A', '6', 'E', '4', '3', '3', '4', '6', 'E', 'D', 'A', '8', '0', '1', '0', '8', '3', '0', '6', 'C', '3', '5', 'A', '8', 'E', '7', '4', '2', '4', '3', 'F', '6', 'A', '0', '1', 'A', 'C', '8', '2', '4', '2', '9', 'D', 'B', 'F', '6', '5', '9', '1', 'A', 'C', '0', 'F', '3', 'B', 'C', '2', 'E', '7', '1', '3', '2', '5', '5', '9', '3', '5', '5', 'A', '1', '6', '6', 'E', 'C', '2', 'A', '5', 'F', '0', 'B', '5', '5', '1', 'E', '9', 'C', '9', 'B', '6', '4', '4', '0', 'B', '1', '7', '5', '3', 'C', '0', 'F', 'C', '0', 'D', 'E', 'F', '3', '2', '7', '0', '5', '0', '7', '5', '6', '2', 'B', '2', '2', '6', '2', '4', '6', 'D', '6', '6', '2', 'A', '8', '9', '5', '5', 'D', '2', '1', '3', '1', 'A', '8', '7', '2', 'F', 'C', '9', '4', 'D', 'C', 'E', 'F', '2', '0', '3', '4', '9', 'E', 'F', 'B', '7', '8', 'B', '2', '1', '2', '0', '9', '2', 'F', '6', '4', 'C', '5', '2', '8', '8', '6', '3', '1', '0', '8', 'A', 'B', '2', 'B', 'A', 'C', '5', '3', '3', 'F', 'A', '8', '5', 'F', 'D', '3', '0', '3', '6', 'B', '2', '7', 'C', '6', 'C', 'A', '8', 'C', 'F', '0', 'B', '5', 'A', '3', 'C', '3', '5', '8', '8', '4', '6', '1', 'A', 'C', '1', 'D', '1', 'B', 'F', '4', '5', '0', '1', '4', '1', 'F', '1', 'B', '1', 'C', 'F', '9', 'D', '0', '0', '1', 'A', '1', 'C', '1', 'B', '1', 'A', '2', '6', 'F', '6', '4', '1', '4', 'F', '8', '8', '8', 'F', '4', '5', '2', '7', 'E', '8', 'B', 'E', '0', '2', '9', 'E', '1', 'E', '1', '6', 'E', 'E', 'F', '6', '3', 'C', '6', '6', 'A', '0', '6', 'E', '1', '3', '7', '4', '4', 'A', '3', 'D', 'F', '5', '0', '3', '3', '7', '7', '1', '6', 'E', '7', '3', '7', '6', 'B', '5', '3', 'A', 'C', 'C', 'A', '6', '0', 'D', 'D', '6', 'B', '3', 'C', '5', '1', '2', 'D', 'D', '1', '8', '5', '7', '9', '3', '9', 'D', '7', '6', 'F', '9', '4', '0', '2', '7', 'C', '2', 'D', '7', 'F', '8', 'C', 'E', '4', 'A', '5', 'C', '1', 'A', 'C', 'B', '4', 'B', '8', 'F', 'F', '5', '4', '2', '6', 'C', 'E', '4', 'C', '3', 'F', 'C', '5', '8', 'A', '0', '8', '6', 'B', '0', '5', '7', 'C', '8', '7', 'F', '2', '0', '3', '3', '2', 'C', '4', 'F', '3', '0', '7', 'D', '8', '0', '0', '2', '6', '9', '4', '7', '6', 'D', '4', 'E', '9', '9', 'D', '5', 'F', '6', '7', 'E', '8', '7', 'E', '8', '8', '5', 'C', '9', 'B', 'D', '5', '3', 'D', '0', 'C', '5', 'A', '6', '4', 'C', 'C', '4', 'D', 'E', '7', '5', 'A', 'C', 'F', '9', '8', '6', 'A', '9', '7', '8', 'A', 'A', 'C', '3', 'A', '8', 'C', 'E', '8', '8', '6', '4', '3', 'C', '1', '8', '5', 'A', '6', '6', '4', 'F', '7', 'B', '7', '0', 'C', 'F', '5', '7', '4', 'B', '2', '6', 'F', '2', 'F', 'D', '2', '0', 'C', 'B', '3', '9', 'E', '2', '4', '8', '6', 'D', '2', '9', '3', '2', '5', '7', '2', '2', '7', '3', '6', '4', '8', '1', '2', '6', '5', '6', '6', '8', 'F', '4', 'E', '2', 'C', '8', '1', '0', 'E', '7', 'E', 'A', '9', 'D', 'B', 'A', 'A', '6', '4', '8', '8', '9', 'B', '8', '4', '8', '4', '7', 'A', 'C', '2', '7', 'B', '7', '9', 'A', 'D', 'C', 'C', 'A', '2', '7', '7', '3', '8', '6', 'B', 'B', 'E', '4', '9', '1', 'C', '3', '8', '1', '5', '5', 'F', 'B', 'E', 'D', '1', 'A', '6', '0', 'E', 'D', '6', 'C', '6', 'F', 'A', '8', 'A', 'D', 'C', '1', 'D', '3', 'F', '3', 'A', 'A', '0', 'A', 'E', '7', '9', '6', '7', '0', 'B', '8', 'C', 'C', '9', 'B', 'B', '0', 'E', 'C', '7', '2', 'A', '7', '6', '5', '5', 'A', 'D', 'B', 'A', 'D', '6', '6', 'D', '2', 'B', '7', '2', '3', '2', 'C', '9', 'A', 'E', '1', '5', '0', '4', 'B', 'A', '6', '0', '9', 'C', '3', '1', '6', 'B', '6', '0', '7', 'D', 'E', 'E', '9', '3', 'A', '4', '8', 'F', '2', '0', 'D', 'E', '3', 'C', '5', 'C', '4', '2', '4', '7', '8', '0', '8', 'E', '8', '4', 'C', 'D', 'B', '7', 'B', '7', 'C', '9', 'F', '5', '4', '1', 'A', 'A', 'F', '5', '0', '7', '6', '9', 'E', '4', 'C', 'A', 'E', '7', '4', '1', 'B', '8', '9', '7', '3', 'A', 'C', 'C', '2', '2', 'A', '3', '2', 'E', '3', 'F', '9', '1', '2', '6', '8', 'C', '7', 'F', 'E', '0', '6', 'B', '8', '2', '4', '1', 'D', 'F', 'A', '2', 'B', '8', '9', 'B', '6', '4', '0', '5', 'D', '6', '2', '3', '1', '3', '3', '1', 'C', 'E', 'C', '4', '6', '3', '4', '7', 'D', 'A', '6', 'C', 'D', '5', '1', '4', '2', 'A', '6', '4', '1', '9', 'F', 'F', 'B', '3', '7', '1', 'C', '4', '8', 'E', '3', '6', 'E', '2', '6', '9', '3', '6', '4', '8', '8', '7', '3', 'F', 'A', '7', '7', '2', '4', 'F', '8', 'E', '8', '3', '8', 'F', '6', '6', '6', 'C', 'E', '9', '2', '2', '5', '6', 'B', '4', '0', 'D', 'F', '2', '4', '5', 'C', 'B', 'B', 'F', 'A', '3', 'D', '1', '7', 'B', '7', '3', 'F', 'F', '7', 'B', 'C', '4', '4', '3', 'B', '6', '5', '2', '1', 'E', '8', '6', '4', 'F', '0', '0', 'D', '0', '2', '5', '5', 'D', 'B', '8', '1', '5', 'C', '3', 'F', 'C', 'D', '7', '5', '5', '6', '3', '9', '5', 'B', '1', '4', '8', '9', 'F', '4', '5', 'F', '3', '9', 'C', 'A', '8', '2', '9', '9', '0', 'E', 'B', '2', '1', '7', '2', 'E', 'E', '6', 'C', '8', 'B', 'C', 'E', '2', '6', 'B', 'A', 'D', '2', '9', 'A', '5', 'B', 'D', '8', '5', '7', 'D', '0', 'A', '7', 'D', '8', '0', '8', '3', 'D', 'F', '9', '8', '4', 'C', '7', 'D', '0', '5', '7', '4', 'C', 'F', 'D', '2', 'B', '1', '8', '0', '7', '8', '1', 'C', 'F', 'B', '7', '8', 'D', '6', '2', 'C', 'B', 'D', '3', '4', 'A', '3', '8', '8', '9', '7', '1', 'B', '8', '4', '7', 'B', 'F', '9', '1', 'E', 'E', '2', 'B', '1', 'F', '0', 'E', '2', 'D', '0', '4', 'E', '0', 'E', '6', 'A', '4', '4', '0', '2', '7', '8', 'D', '7', '2', '0', '2', 'C', 'B', '9', '5', '0', '4', '5', 'C', '0', '3', '9', 'D', '4', 'D', '3', '8', '1', 'B', '5', '2', '8', '7', '3', '5', '9', 'C', '6', '5', 'B', 'A', 'A', '4', 'E', '4', '3', '4', '6', 'B', '1', '7', '9', '6', 'E', 'F', '4', '2', '2', '4', 'E', 'C', '3', '9', '8', '2', '9', 'C', 'C', '5', '0', '4', '9', 'C', '4', '3', 'D', 'F', '7', '8', '3', '5', '0', '2', '1', 'A', 'B', '8', '3', '1', '0', 'C', '1', '5', '8', '6', '8', '0', 'B', 'B', '4', '7', '2', '8', 'D', 'B', '2', 'E', 'E', 'F', 'A', '7', '2', 'F', '5', 'C', '8', 'B', 'A', '5', 'D', 'C', 'C', 'E', '3', 'B', '1', 'C', '2', '1', 'F', '3', 'C', 'C', '2', '3', 'B', '6', '6', '2', '2', '9', '8', '0', 'E', 'F', 'C', '8', '2', '7', '6', '4', '5', 'A', 'D', '8', 'D', '5', '8', 'E', 'D', '0', 'D', '3', '4', '0', '6', 'C', '0', 'F', '7', '0', '3', '0', '8', 'F', '6', '8', 'B', 'B', '4', '8', '0', '6', '2', '7', 'A', '0', 'D', '9', 'E', '5', '7', '5', 'D', 'D', '3', 'B', '4', '8', '3', '1', '9', '2', 'B', 'D', '7', '5', '4', '1', '0', 'B', 'F', 'D', '2', 'B', 'F', '6', '4', '7', '0', '6', '6', 'C', '5', 'C', '6', '0', '2', '2', 'F', 'E', '1', '3', 'C', '5', 'F', '3', '6', '9', '8', 'B', '8', 'D', '9', 'F', 'F', 'C', '4', '5', '3', '9', '8', 'F', '6', 'B', '1', 'A', 'E', '2', '7', '5', '5', '3', 'F', '0', '1', 'D', '1', 'A', '7', '8', '7', '3', '8', 'B', '2', 'B', 'A', '6', '6', '0', '9', '3', 'A', '2', 'B', '5', 'E', '3', '7', 'D', 'D', 'F', '2', '2', '9', '2', 'F', 'A', '8', '4', 'D', 'C', '0', '0', 'B', 'B', 'E', 'E', '3', 'C', 'B', 'A', '1', 'C', 'D', '2', '0', '9', 'E', 'E', '8', '8', '7', 'F', 'F', '8', 'B', '5', '4', '0', 'C', '3', '7', '9', '7', 'E', 'C', 'D', '2', 'B', '8', '0', '7', '1', '4', '4', '9', '2', '0', '7', '9', '4', '0', '9', 'A', '0', 'B', 'F', '5', '1', '5', '0', '1', 'D', '1', '7', '2', '9', '6', 'F', '0', '5', '6', 'E', '1', '3', 'C', 'D', '8', '1', '5', 'C', 'E', '0', '8', '6', '2', '9', 'F', 'B', '0', '2', '1', '9', 'E', 'F', 'F', 'B', 'B', '2', 'B', '9', '6', 'B', '7', '0', 'D', 'D', '6', '4', '4', 'E', 'C', 'A', '9', 'D', 'F', '5', '5', 'F', 'A', '2', '1', 'E', '2', '7', 'A', '5', '0', 'A', '8', 'E', '1', 'F', '3', '6', 'C', 'F', 'B', 'B', '4', '5', 'A', 'A', 'A', 'F', '5', '0', 'A', 'E', '8', 'E', '4', '5', '4', '2', '7', 'E', '3', 'D', '9', '2', '6', 'E', '7', '4', '6', 'A', '6', '2', 'D', '7', '6', 'B', 'F', 'D', '0', '0', '6', 'C', '5', '5', '3', '4', '9', 'B', '6', 'A', 'B', 'D', '4', 'D', '4', '5', '1', '7', '0', '5', 'A', '1', 'F', '1', '1', 'B', '9', '1', '0', '5', '8', '2', 'B', '1', '1', 'A', '4', '2', '0', '3', '8', 'E', '9', 'E', 'F', '5', 'E', '4', 'A', '4', 'E', '5', 'B', '5', '1', '2', '5', 'E', 'E', 'D', '9', '6', 'D', 'D', '8', '4', '1', '0', 'D', '8', 'C', '6', '9', 'A', '6', '7', 'D', '6', '6', 'B', 'B', '2', '1', '8', '7', '9', '0', '0', 'D', 'C', '0', '6', 'B', '5', '7', '8', '4', '2', '9', '3', 'D', '8', '6', '6', '2', 'D', 'B', 'B', '8', '5', 'C', '0', '5', '8', '4', 'A', 'B', '8', '6', '2', 'E', '2', '8', '1', '2', '4', '5', '2', '8', 'A', '1', 'A', '1', '9', 'F', '8', '6', '1', '1', '6', '0', '3', 'E', '5', '7', '9', '8', 'B', 'D', '2', '2', '6', '7', 'E', '6', 'C', 'E', 'A', '4', '0', 'C', 'E', 'E', '7', '9', '5', 'E', '0', 'E', 'C', '1', '2', '7', '6', '5', '8', '2', '9', '2', '1', '9', 'F', 'A', 'E', 'F', '5', 'E', '8', 'D', '0', 'B', '3', '6', '0', '0', 'A', '9', 'D', 'A', '2', 'C', '3', '0', 'E', '3', 'C', '5', 'F', '5', 'B', '8', 'C', '1', '1', '1', '4', '0', '2', '6', '8', '5', '3', '3', '5', '5', '4', '8', 'D', '2', '4', '2', '7', '1', 'E', '4', '9', '2', '5', '2', '7', '4', '1', 'C', '6', '4', 'A', '5', '7', 'B', '1', 'F', 'E', 'F', 'C', '3', '8', 'F', '2', '3', '5', '0', '9', '3', 'D', '0', 'A', '5', '7', '0', 'A', '9', '8', '1', 'B', 'A', 'E', '1', '4', '7', '6', '0', 'B', '0', '9', '8', '7', '1', '4', 'B', 'B', '0', '3', '5', 'B', '7', '9', 'F', '0', 'A', 'D', '0', 'B', '4', '7', 'D', 'E', '4', '5', 'E', 'F', '1', 'F', 'D', '3', '0', 'A', '8', '3', '6', 'A', '0', '5', '6', 'D', '2', '2', '1', '0', '5', '0', '4', '9', '0', 'F', '6', '3', '2', 'F', 'B', '0', '2', 'F', '6', 'A', 'A', '1', '3', '4', 'A', 'E', 'D', 'E', '5', 'C', '4', '0', '8', 'D', '9', '0', '9', '7', '6', 'E', '3', '8', 'A', 'C', '6', '3', '5', 'A', 'C', '2', '1', '3', '9', 'C', '7', '8', 'B', 'D', '4', 'B', '4', '2', '8', '8', 'C', '2', 'B', 'D', 'E', '1', 'B', 'B', '9', '5', '3', '1', '3', '9', 'F', '2', '3', '1', '9', 'D', 'B', 'B', '5', '1', '3', '3', '5', '3', '7', '5', 'F', 'A', '0', '8', '4', '6', '1', '2', '6', '1', 'B', '8', '7', 'C', 'D', 'C', '2', '4', 'F', '6', '3', '4', 'F', '3', '1', '1', '0', '0', 'F', '0', 'C', 'F', 'F', '9', '8', '2', 'D', '5', '9', 'D', '7', 'C', '3', '8', '7', '9', 'A', '5', '3', '9', '4', 'C', '4', 'A', 'B', '9', '3', 'D', '2', 'D', '7', 'D', '8', '7', 'A', '5', 'C', 'E', '4', 'E', 'F', '1', '3', 'B', 'D', 'D', 'F', 'E', '3', '7', 'F', '2', '7', 'D', 'E', '6', '9', '8', 'F', '3', '3', 'C', '4', 'A', 'D', '3', '2', '9', 'D', 'D', 'C', 'C', '2', '6', '4', '1', '7', '1', 'D', '5', '7', 'F', '1', '7', 'C', '7', '7', 'F', '0', 'A', 'D', 'C', '4', '6', 'C', '3', 'E', 'E', '0', '9', 'F', '9', '7', '6', '6', '2', 'A', '3', 'B', '2', 'C', 'C', 'C', '5', 'C', 'F', '4', 'E', '2', '2', '7', '7', 'A', '1', '1', '8', '0', '8', '8', 'D', '4', '5', '8', 'D', 'A', '1', '9', 'F', '4', 'E', '4', '8', '4', '4', '0', 'D', '1', 'C', '3', '0', 'A', '6', '6', '8', 'D', '7', '1', '6', '7', '3', '9', '5', '2', '8', 'D', '5', '1', '0', '9', 'E', 'F', 'E', '9', 'F', '2', '4', 'F', 'C', 'B', '1', '6', 'C', '3', '4', 'A', '5', 'F', '2', 'D', '7', 'D', 'A', '3', 'C', 'D', '4', '2', '8', '2', 'A', 'E', '9', 'F', 'D', '0', 'A', '9', 'A', '9', '5', 'E', '3', 'F', '8', '1', '5', '7', '5', '7', 'E', '7', 'A', '3', 'F', '1', '2', '0', '9', '8', '9', 'C', 'D', 'D', '9', 'F', 'A', 'A', 'E', 'C', '1', '2', '8', 'B', 'A', '5', '4', '1', '1', '7', 'A', '1', '6', '8', '1', '5', 'A', 'F', 'B', '1', '5', '7', '7', 'C', 'E', '7', 'E', '2', '2', 'B', '3', '7', '0', '3', 'C', 'F', 'A', 'F', '4', '5', '7', 'F', 'E', '4', '8', 'E', 'C', '9', '5', 'C', '1', '6', 'C', 'C', 'F', '8', 'A', 'A', '6', 'D', '3', 'E', '8', '3', '8', 'B', 'F', '4', 'F', 'B', 'F', '0', 'D', '2', '7', 'B', 'C', 'D', 'A', '3', '1', '6', '8', 'F', '0', '2', '0', '8', 'F', 'E', 'C', '1', 'F', 'A', '0', 'B', '0', '9', '0', '4', 'A', '7', '4', 'B', '2', '5', '8', '5', '7', '0', '7', 'A', '8', 'E', '1', 'A', '2', 'C', 'B', '8', '2', 'B', '1', '1', 'A', '1', '0', '2', '4', 'C', '9', 'D', '9', 'A', '9', 'A', 'B', '9', '6', '7', 'F', '1', '4', 'A', '1', '4', 'A', '9', 'E', '8', '2', '0', '4', 'C', 'D', 'D', '7', 'E', '1', 'F', '4', '1', 'B', '4', '6', 'A', '9', '7', '0', '7', 'D', 'B', 'F', '3', '6', '5', '7', 'C', '6', '0', '3', '2', '6', '2', '4', 'A', '9', '5', 'A', '7', '4', 'A', '5', '5', 'C', 'F', '1', 'C', 'B', '0', '9', 'F', '1', '5', 'B', '8', '1', '0', '6', '4', 'A', 'A', 'F', '6', '7', '3', 'A', '1', '7', '9', '2', 'A', '6', 'D', '7', 'D', '2', '4', 'B', 'F', '0', '2', 'E', '5', '9', '0', '5', '5', '7', '4', '7', '2', '2', '3', 'A', '9', 'C', 'C', '2', 'A', '6', 'A', 'B', 'B', '1', '9', '6', '9', 'F', '8', '1', 'D', '6', 'E', '9', 'B', '4', 'C', '5', 'F', '8', '4', 'D', '9', 'F', '2', 'B', '2', 'D', '5', '0', 'F', '0', '7', '4', '5', '2', '0', '7', '0', '2', '4', 'D', '0', '9', '6', '8', '8', '9', '1', 'B', '5', '4', 'A', 'B', '7', '5', '4', '7', '6', '8', 'E', 'F', '6', 'C', '0', 'F', '5', 'A', '2', '0', '7', 'A', '4', '7', 'D', '1', '3', 'E', '3', '4', 'A', '3', '8', '5', 'A', 'E', '9', '7', '2', '1', 'F', 'A', 'B', 'D', '1', '1', 'F', '9', 'E', '7', 'A', 'F', '9', 'B', 'F', '7', '9', '5', '4', 'F', '2', 'A', '5', '1', '5', '3', 'A', 'C', '4', '2', '7', '6', '7', 'C', '3', '9', 'C', '2', '4', '0', 'B', '8', 'D', 'E', '4', '4', 'F', '8', '3', '5', '6', '8', '3', '1', 'A', '3', '6', 'B', 'B', '6', '5', '7', 'D', '0', '6', '9', '9', 'D', 'C', '9', 'E', 'D', '3', 'C', '5', 'E', '6', '1', 'A', '2', 'C', 'A', '2', 'C', 'C', '8', '5', '9', 'D', '3', '5', '3', '0', 'E', '6', '2', '3', '5', '9', '7', '4', 'F', '3', 'B', '2', '2', '7', '0', 'E', '1', '7', 'A', '4', 'E', '8', 'A', 'B', 'C', '9', 'B', 'C', 'D', 'B', '0', '8', 'C', '1', 'D', '2', 'E', '5', '9', 'F', '9', '8', 'C', '2', '4', 'B', '9', '9', 'D', 'D', 'A', '1', '3', '6', 'B', '6', 'C', '0', '6', 'E', '7', 'A', '6', '4', '3', '8', '6', 'B', 'B', '5', '4', '0', '1', 'E', 'B', '6', '5', '9', 'C', '1', '9', '0', '4', '0', 'F', '4', '3', 'B', 'E', 'D', 'A', '0', '8', '1', 'F', 'D', '4', '0', '4', '8', 'E', '9', '5', 'F', '3', '2', '3', '4', '4', '8', 'D', '7', 'F', 'B', '8', '8', 'A', 'B', '3', '3', 'A', '3', '2', '6', '6', '1', '1', 'A', 'C', '4', 'B', 'D', '6', 'F', 'B', 'C', 'B', 'D', '1', '9', '8', 'D', 'D', '4', '0', '4', '2', 'D', 'B', '6', 'F', 'E', '1', '5', '7', 'D', '6', '0', 'A', '2', 'C', 'A', '9', 'D', '6', '9', '7', 'C', 'A', 'F', '6', '7', '9', '2', '1', '5', '8', '6', '1', 'D', 'D', 'E', '5', '5', '0', 'E', '2', 'B', 'C', '8', '4', 'A', '6', '9', '5', 'E', '9', '4', 'C', '3', '9', 'A', '7', 'B', '6', '0', 'F', 'C', '0', '8', '8', '9', 'D', 'E', '7', '2', '4', '6', '7', '7', '1', 'C', 'D', '3', '6', 'C', 'B', '5', 'B', 'C', '2', 'B', '4', 'E', '6', 'D', '5', '9', '8', 'A', 'D', '3', '6', 'F', 'A', '8', '3', '2', '0', 'D', '8', '0', '7', '5', 'B', '5', '4', '6', '0', 'C', 'A', '9', '8', '1', 'E', 'D', '1', '6', 'D', '6', '0', 'B', '7', '9', '1', '8', 'D', '8', '6', 'F', '2', 'B', '7', '4', '6', '3', '6', '9', 'F', 'B', '2', 'C', '5', '2', '1', '3', '7', 'C', '8', 'B', '7', '9', 'A', 'F', '1', '2', 'F', '9', '1', 'B', 'B', 'A', 'F', '9', 'E', 'E', '0', '6', '5', '9', '3', '5', 'D', '7', 'C', 'E', '6', '7', '2', '4', 'E', '2', '8', '0', 'C', '4', '7', '3', 'E', '5', '7', 'C', '4', '5', 'B', '8', '3', 'A', '7', '6', 'B', 'B', '5', 'B', '6', 'D', '7', '3', '4', '2', '3', '2', '7', '4', '8', '3', 'B', 'C', '9', 'F', 'D', '4', 'F', '1', '8', 'B', '6', 'F', '6', 'C', '6', '8', 'B', '1', 'E', '3', '1', '0', '3', 'A', '8', '9', 'A', '5', '3', 'F', '9', '7', 'B', '3', '8', '7', '0', 'A', '4', 'A', '8', 'E', '7', 'A', '9', '4', 'A', '2', '9', '3', '4', '8', 'F', 'B', 'D', 'A', 'E', 'C', 'E', '3', '2', '6', 'A', 'F', '6', '3', 'F', 'F', '1', '6', 'E', '9', '3', 'B', 'E', '0', 'A', '5', '9', '6', '0', '9', '5', 'A', '3', 'D', '0', '2', '3', '5', '7', '8', '7', 'F', 'A', '1', '3', '1', '5', '1', '4', 'D', '3', '2', '7', '2', 'F', '8', '5', 'A', 'E', '0', '4', 'C', '4', '6', 'F', '2', 'D', 'D', '4', 'E', 'E', 'E', '5', 'C', 'C', '4', 'D', '1', '1', '5', '0', 'C', 'D', 'E', '0', '9', '1', '0', '2', 'D', '6', '7', '1', '0', '4', '9', 'A', '7', 'D', 'B', '7', '7', 'D', '1', 'B', '6', '4', '3', '8', '9', 'C', '9', '1', '7', 'E', '7', '4', '8', 'A', '9', '8', 'E', '7', '5', '8', '0', '4', 'F', '5', '0', '8', '0', '7', 'C', '3', '7', '6', '0', 'F', 'F', '1', '5', '0', 'C', '3', '7', '1', '4', '9', '4', '5', '9', 'B', '8', '5', 'E', '5', '0', '1', 'B', 'F', '6', '2', 'E', '4', '7', 'F', 'C', 'C', '9', 'C', '2', '7', 'A', 'C', '5', '0', '3', '1', '1', '0', 'F', '4', '2', '3', 'F', '6', 'F', 'F', '4', 'E', '8', '1', '3', '8', '4', '7', '3', '0', '5', 'A', '7', '4', '3', 'E', '5', '0', 'C', 'F', '0', 'E', 'E', 'C', 'B', 'A', '5', '5', '6', '8', '2', '3', 'E', '5', 'B', '8', '7', '9', '6', '3', '7', '9', 'B', 'F', '2', '3', 'E', '2', '4', '9', 'D', '9', 'C', 'E', 'C', '2', '3', '1', '3', 'F', '1', '9', '0', 'D', '8', '0', '5', '5', '0', 'A', 'E', '2', '8', '6', '3', '5', '0', '3', '0', '2', '5', '3', '9', '7', 'F', '2', 'D', '2', 'E', 'E', '8', 'C', '8', 'E', 'A', 'A', '7', '6', '6', 'B', '2', '6', '3', '5', '4', '2', '9', '8', '2', '8', '7', '4', '8', '0', 'A', '2', '3', '7', '4', '9', 'F', '1', '9', '1', '6', 'C', 'A', '3', '6', '7', '4', '2', '1', '8', '5', 'A', '4', '8', '3', 'C', '4', '2', '2', '7', 'C', '2', '0', '3', 'E', '7', '7', '5', '6', '8', '9', 'B', '6', '7', 'E', '0', '7', '6', '9', '9', '9', '5', '0', 'B', '7', 'D', '5', '1', 'A', 'A', '8', '9', '2', '4', '6', '8', 'D', 'E', '6', '1', 'B', 'B', 'A', 'A', '1', '7', 'A', 'C', '3', '7', '2', '1', '6', 'C', 'D', '5', 'A', '0', '6', '9', '9', '9', '8', 'E', '3', '1', '4', 'B', 'F', 'D', '3', 'B', '2', '0', '1', '5', 'D', '9', '7', '7', 'D', 'D', 'E', 'E', '1', '8', '9', '3', '2', 'E', '7', '8', '5', '1', '8', '5', 'B', '5', '8', '2', 'C', '9', '6', '9', 'C', '5', 'B', '9', '7', '2', 'A', '7', 'F', '3', '9', 'B', '9', 'E', 'A', '6', 'B', '9', '1', 'F', '5', '2', '2', '1', 'D', 'D', 'E', 'F', 'E', '7', '0', 'C', '4', '1', '9', '6', '6', 'C', '4', 'E', '8', 'D', '7', 'E', '3', '7', 'A', '7', 'D', 'E', '2', '4', '4', 'B', '9', '9', 'D', '0', '9', '5', '2', '5', 'A', 'B', '9', '8', '4', '1', '6', 'F', 'C', '4', 'E', 'F', '2', 'A', 'F', 'F', '2', '5', '7', '4', '0', '0', '3', '0', 'B', '9', 'F', 'B', '0', '2', 'A', 'E', '9', '4', 'F', '9', '6', '0', '0', '3', '2', '1', '6', '6', 'F', '3', 'D', 'C', '3', '7', '1', '7', '5', 'B', '1', '9', '2', 'F', '3', 'F', '0', '3', 'F', '8', '9', '6', 'A', '4', '4', '8', 'E', '1', 'F', 'B', '2', 'E', 'A', 'D', '0', '7', 'A', '0', '6', '3', '8', 'E', 'E', '2', '2', '6', '6', '6', 'F', '1', '1', 'F', '6', 'C', '3', '0', '4', 'E', '1', '8', '0', '6', '8', '2', '2', '9', '8', '9', 'D', 'C', '2', 'E', 'D', '1', 'C', '0', '0', 'A', '6', 'C', '2', '1', 'B', '8', '5', '5', 'E', '7', 'D', '5', 'C', '3', '8', '2', '4', 'A', '6', '2', '6', 'B', '8', '3', '7', '4', '0', 'A', '6', '8', '1', '7', 'A', '2', '3', 'D', 'F', 'C', '6', 'F', '4', 'D', 'A', 'C', 'E', 'A', 'B', 'F', '7', 'E', 'E', '1', '7', 'E', '6', '8', 'D', '7', '8', 'B', '2', '2', '4', '8', '3', '9', 'B', '6', '7', '1', 'B', 'B', '5', 'B', 'D', '4', '9', '0', 'C', 'B', '8', '1', '3', 'C', 'E', '2', '0', '3', '6', '7', 'B', '7', '3', '6', 'F', 'C', '9', '9', '4', 'B', '4', '9', '9', 'F', '0', '4', '5', '1', '2', 'E', '4', '5', '7', 'A', '6', '2', 'D', 'D', 'D', '1', '8', '8', '6', 'C', '4', 'B', '5', 'B', '5', 'D', 'E', '2', '8', 'E', '8', '5', 'A', '4', '6', 'B', '9', '1', 'B', '1', '5', '7', '0', '6', '3', '9', 'D', '0', '5', 'F', '9', '6', 'E', 'B', '8', 'B', 'B', '5', 'F', '6', 'E', 'A', 'E', '3', '0', '9', 'E', '9', 'C', 'F', '1', '8', '9', 'D', '1', 'A', 'A', '2', '5', '1', '8', '3', 'C', '6', 'C', '5', 'A', '4', 'E', 'C', 'E', 'E', 'B', '8', 'D', '2', '8', '3', '8', 'C', 'E', 'E', 'F', '1', '3', '9', 'F', '7', 'C', '1', '6', '9', '3', 'C', '3', 'C', 'D', 'A', '2', 'F', '5', 'D', '9', '5', '6', '3', '8', '3', '9', 'F', '2', '3', 'F', 'A', '4', 'C', '3', '5', '5', '3', 'D', 'C', '7', '4', '3', '0', '0', 'C', '3', '9', '0', '9', '9', '6', '7', 'E', '8', '3', '4', '0', '4', 'C', '5', 'B', '2', '0', '3', '2', '9', 'D', '1', 'A', '2', '2', '9', 'C', '4', '4', '9', '0', 'B', '2', 'F', '1', '4', 'D', 'C', '8', 'B', 'B', 'E', '3', 'C', '9', '9', '9', '8', '8', 'F', '7', '1', 'A', '0', '4', 'B', 'C', 'B', 'B', '3', '7', '3', '7', 'A', 'B', '5', 'E', 'B', '8', '1', 'A', 'C', 'F', '5', '6', '4', 'F', 'D', 'C', 'D', '3', 'B', '4', 'A', '6', 'C', 'D', '4', '2', 'A', '9', 'A', 'E', '8', '8', '3', 'D', '4', 'E', '5', 'B', '9', 'F', '6', 'E', '5', 'A', '0', '8', 'B', '3', '1', '9', '6', '7', '3', 'A', 'D', 'A', '7', 'D', '6', '5', 'A', 'E', '4', '2', '2', 'C', 'F', '2', '6', '2', 'E', '9', '5', '3', '6', '9', 'E', 'F', '5', '4', '0', '3', '3', '6', '9', '9', '7', '9', '8', '3', 'E', '3', 'C', 'E', '3', 'D', 'C', '8', '8', '5', 'C', '7', '9', '4', '1', '3', '4', '8', '5', '1', '2', '0', '0', 'F', 'E', '4', '0', 'A', '1', 'E', 'E', '5', '4', 'A', '7', '5', '8', '3', '6', '0', 'E', '6', '6', 'E', 'D', 'C', '5', '2', '6', '6', 'C', 'D', 'B', '7', 'A', '8', '5', 'F', '7', '0', '6', 'E', '8', 'D', '3', 'C', '8', '6', 'B', '1', '4', 'C', 'F', '7', '1', '5', '2', '9', 'C', 'C', '8', '6', '8', '4', 'A', 'B', 'D', '5', 'A', '4', 'C', 'D', 'C', 'E', '3', 'A', '6', 'F', 'A', '0', '8', '8', 'B', '7', '7', 'A', '8', '8', 'A', '1', '0', '7', '3', '1', '9', 'B', 'C', '7', 'B', 'C', 'B', '1', '2', 'B', '5', 'C', '4', '7', '5', '9', '7', 'D', '4', 'F', '4', 'E', 'E', 'F', '8', 'B', '3', 'B', '1', '1', 'B', 'E', 'F', '9', '2', '3', '3', 'D', 'D', 'C', '5', '9', 'F', '8', '8', 'A', 'E', '6', 'D', 'E', 'D', '1', 'F', 'A', 'E', '8', 'F', '5', 'F', 'C', '3', '5', '0', 'B', '2', 'C', '6', '0', '5', 'A', '3', '7', '8', '9', '6', 'A', 'A', '8', '8', '4', '0', '3', 'E', '3', 'D', '1', '0', '5', '3', '2', '3', 'E', 'E', '1', 'A', 'B', '4', 'C', 'F', 'B', '2', '4', '4', 'D', '8', 'E', '3', 'B', '7', 'C', '5', 'C', 'F', '4', 'E', 'C', '9', 'E', '0', 'F', '3', '0', '8', '5', 'D', '9', '9', '0', 'B', '6', '5', 'E', '5', '1', '7', '3', '4', '7', 'B', 'D', 'B', '9', '5', '9', 'A', '2', '2', '4', '1', '5', '8', '6', 'D', 'E', 'B', 'D', 'A', 'E', '9', 'B', 'B', '3', '4', '9', '3', 'B', '6', '4', '6', '2', '6', '2', '1', '1', 'A', 'F', '4', '7', '0', '0', '5', '6', '5', '1', '8', '4', 'A', 'B', '3', '2', '5', '2', 'D', '6', 'E', 'A', '8', 'A', '9', '6', '6', '7', '0', '2', 'E', 'B', '0', '4', '6', '2', '9', 'A', '4', '2', 'B', 'E', 'E', 'B', 'C', 'E', '5', '1', 'F', 'E', '6', 'F', '7', 'E', '9', '9', '7', '7', 'C', '6', '7', 'D', '3', 'E', 'F', '9', 'A', 'B', 'E', '3', 'E', '5', '1', '2', '8', 'D', 'A', '5', '7', 'D', '6', '1', '3', '9', 'C', '8', 'D', '2', '3', '1', '2', '7', '1', 'E', 'A', '9', '3', '8', '2', '8', '6', '9', '5', '2', 'C', '4', 'B', '8', 'F', '5', 'A', 'B', 'D', '1', 'F', '2', '0', '5', '4', 'C', 'F', 'E', '9', '4', 'B', '6', '8', 'F', '2', '8', 'E', 'B', '0', '5', 'E', 'E', 'C', '3', '2', 'F', '6', '8', '0', 'B', '2', '5', '2', '9', '2', '7', '1', '8', '3', '4', '4', 'B', 'E', 'A', '8', 'A', 'E', '3', '8', 'E', '3', '1', 'B', 'F', '4', '4', '7', '1', '7', '0', '9', '5', '6', '6', 'B', '9', '1', '4', 'F', 'F', 'E', 'F', 'C', '2', 'C', '9', 'F', '2', 'E', '0', '6', 'A', '5', 'E', '4', '9', 'C', 'D', '2', '1', '4', '7', 'C', '8', '4', '6', '8', 'B', '3', 'C', '9', 'D', '5', 'C', '1', '5', '3', 'A', 'C', 'F', '4', 'F', 'C', '0', '3', 'D', '9', '4', 'A', '9', '6', 'C', '9', 'B', '3', '9', '2', 'B', '5', 'A', '4', '2', '1', 'E', '7', '5', 'C', '0', 'C', '4', 'E', '1', 'C', '9', '8', 'B', '8', '3', '5', '7', 'A', 'A', '8', '6', '3', '6', 'E', 'D', '0', '3', '5', 'E', 'C', '8', '7', 'B', '2', '5', 'D', '2', '4', '1', 'E', '0', 'C', '2', '8', 'A', '5', '5', 'B', 'F', 'A', 'A', 'D', '4', '6', '2', '1', '2', 'C', 'A', 'C', '2', 'F', '3', '3', '7', '5', '6', '3', '7', '9', 'A', 'B', '4', '0', '5', '7', '3', '0', '6', '7', '6', '0', '3', '0', 'C', '1', '3', 'F', 'A', 'F', 'B', '9', '0', '9', '9', '9', 'B', 'A', 'C', 'C', 'B', '9', '7', '2', 'C', '2', '9', '6', '4', '3', '4', '5', '9', 'D', 'D', '1', 'B', 'B', '5', 'E', '9', '6', '5', '5', '7', 'B', 'E', '1', 'F', 'B', 'F', '5', '2', '0', '2', '6', 'C', '5', 'D', '1', 'D', '4', 'A', '2', 'A', 'E', 'C', '1', '6', '5', '9', '5', '2', 'B', '8', '3', 'E', '8', 'D', '9', '2', '2', '3', 'B', '3', '4', '3', '4', 'F', '0', '8', '5', '0', '5', '2', '5', 'A', 'B', '8', '1', '6', '5', 'A', '3', 'A', 'A', 'F', '8', 'E', '2', '6', '0', '8', '8', '2', '5', '4', 'A', '3', '8', '6', '9', 'D', '7', '5', '3', '0', '0', 'C', 'F', '7', '1', '9', '0', '1', '2', '2', 'B', '4', '7', '5', 'D', '4', '3', 'F', 'C', '3', '0', '1', 'C', '8', 'E', '7', 'C', '5', 'E', '2', '7', 'C', '2', 'E', '8', 'C', 'C', '5', 'F', '8', '4', '6', '3', 'D', '0', 'D', '7', '9', '6', '6', '6', '0', '1', '3', '9', 'A', '7', '3', '3', 'B', '1', 'D', '6', '2', 'D', 'B', 'E', '5', '9', '3', '5', 'F', 'E', '0', 'F', '5', 'D', '8', 'E', 'A', 'B', '6', '0', '0', '2', '1', '2', '4', '9', 'D', 'F', 'F', 'D', '3', '9', 'B', '7', '7', '5', '8', '6', '8', '0', '5', '2', 'B', 'F', '9', '1', 'E', '3', '0', '4', 'E', '9', 'B', '9', '5', '3', 'E', 'D', '7', '2', '0', '8', '4', 'A', '9', '6', 'E', 'E', '3', '5', '1', '5', '0', '3', 'D', '7', 'A', '3', '8', 'B', 'D', '1', '7', 'E', '1', '1', '2', 'C', '8', '6', '7', '5', 'A', '5', 'C', 'D', '6', '0', '0', '1', '4', '0', '7', '0', '8', 'B', '6', '4', '6', 'D', '3', '2', '7', 'B', 'F', '5', 'F', 'B', '2', 'F', '0', '8', '9', '3', '6', '5', '0', '5', 'B', '5', '3', '8', 'A', '3', '4', '4', '3', '7', '1', '1', 'C', '2', 'E', '2', '2', '2', '8', 'A', '5', '3', '2', '5', '1', '1', '5', '7', '9', 'A', 'B', 'F', '0', 'C', '2', '7', '9', '0', 'C', 'C', 'E', 'F', 'D', '5', '3', 'B', 'A', '6', 'C', '3', 'B', '6', '9', '0', '4', '4', '8', '8', '4', '7', '9', 'C', '1', '7', '8', 'A', '3', 'A', '3', '7', '4', '5', '5', 'C', '5', '5', '7', 'C', '6', 'B', 'B', 'A', 'A', 'F', 'D', 'C', '6', 'A', '4', '1', '1', '7', '1', '8', '6', 'F', 'B', '0', 'B', '2', 'C', 'D', '8', '0', 'F', '8', '0', 'C', '9', 'D', 'D', '8', '1', 'B', '6', '6', '9', 'B', '5', '4', '8', 'A', '2', 'A', '0', '2', '1', '0', 'A', 'D', 'B', 'F', '9', '1', '7', '5', '4', 'A', '7', '9', 'F', 'A', '5', 'A', '6', '5', 'F', '4', '9', '1', '5', '5', 'C', 'A', 'E', 'C', 'F', '4', '4', 'C', 'C', '8', '9', '2', 'E', 'D', 'D', 'C', 'F', '6', 'E', '3', 'B', 'B', '7', '8', '8', '8', 'A', '6', 'B', 'A', 'D', 'E', '8', '4', 'D', '7', 'F', '8', '5', '2', '8', 'F', '4', '7', '2', '4', 'D', '8', 'B', '9', '0', '7', 'D', '0', '5', '6', '4', '2', '7', 'D', '8', '9', 'D', 'D', 'E', '2', '3', '8', '6', 'F', '5', 'C', 'A', '8', '2', 'B', '0', 'B', 'B', 'A', '7', 'E', '4', 'A', '4', '9', '9', 'F', '5', 'A', '0', 'B', '5', '8', '1', '5', '2', 'D', 'F', 'B', '5', 'D', '5', 'F', 'B', '5', '5', 'A', '4', '9', 'E', 'D', '7', '9', '5', 'D', '1', '5', 'E', '9', '3', '6', 'B', '5', 'C', '1', 'F', '4', '6', '7', '6', 'B', '6', '3', '6', '7', '2', '5', 'B', '9', 'F', 'D', '6', 'E', '6', '4', 'D', '5', '0', '6', 'D', 'D', '9', 'C', 'A', '4', 'F', '4', '5', 'E', '2', '5', '0', '5', '9', '1', 'C', '8', 'A', '7', 'F', '0', '9', '3', 'E', 'F', '4', '1', '5', 'B', 'E', 'E', '9', 'A', '3', 'C', '3', 'B', '2', '5', '9', '1', 'A', 'D', '2', '7', 'E', 'D', 'B', '8', 'B', '8', 'E', 'A', 'C', '0', '2', '4', '8', '4', '7', 'E', 'E', '3', '5', '9', 'D', '9', 'E', '4', '2', 'B', 'A', 'C', 'F', '3', '9', '7', '0', '6', 'C', 'A', '8', 'B', '1', 'F', 'C', '9', 'A', '5', '8', '6', '4', 'D', 'B', 'C', '8', 'D', '9', 'E', 'F', '1', 'F', '0', '5', '4', '0', '0', '8', '3', 'E', '1', '8', '2', '9', '5', 'B', 'C', '9', '9', 'F', 'B', '1', '6', 'F', '5', 'F', '3', 'A', '5', 'B', '9', '0', '7', '6', '0', '5', '5', '8', 'D', 'B', '2', '0', 'B', '3', 'D', '2', '1', 'B', 'B', '1', 'E', '8', 'F', '3', '8', '3', 'D', 'D', 'D', 'C', 'F', '3', 'D', '2', 'D', '5', '6', 'F', '5', 'F', '3', '1', 'D', '5', '5', 'F', 'C', '3', '2', '9', '3', 'B', '3', '3', 'E', '2', '1', '2', '8', '6', '4', '9', '0', '5', 'F', 'A', '3', '2', '9', '7', '9', 'D', 'F', 'A', '5', 'B', '9', '8', '5', '4', '3', 'F', 'E', '2', '1', '5', '6', 'E', '5', '6', 'C', 'E', '4', 'F', 'D', '1', '0', 'F', 'F', '5', '2', '4', '6', 'A', '0', '2', '5', '4', '5', '4', '9', 'B', '5', '5', 'B', 'E', 'E', 'D', '6', '2', '6', '3', '1', '3', 'C', 'F', 'E', '3', 'C', 'A', 'C', '6', 'D', '9', '2', '9', '4', '1', 'D', '0', '1', 'E', 'B', '6', '0', '6', 'C', '1', 'C', '1', '8', '3', 'D', '2', '0', '9', 'C', '2', 'F', '0', 'F', '3', 'F', '6', '0', '8', 'D', '7', '4', '0', '0', 'D', '7', '1', '4', '1', 'E', 'B', 'A', 'C', '8', '1', '8', '1', 'D', 'F', 'D', 'A', '0', '3', 'A', 'C', '8', '0', '0', '4', '8', '6', '8', 'F', 'D', '9', '6', '2', '1', 'A', '1', 'F', '9', 'D', '9', 'A', '0', 'D', 'E', 'F', '6', '6', 'C', '1', 'C', '3', '1', '9', 'E', '3', '7', 'A', '5', 'B', 'F', '5', '9', '8', '0', '2', 'C', 'A', '1', 'E', '5', 'C', '9', '4', '7', '1', 'E', 'A', 'F', '5', '1', 'B', 'A', '2', '2', '6', '5', '1', '7', '3', '8', '5', '0', '8', '6', '9', 'B', '2', 'F', '6', 'F', 'E', 'F', 'D', 'F', '1', '1', '7', '5', 'D', '6', 'D', 'A', '8', '3', 'A', '6', '8', '5', 'D', 'C', '4', '5', 'C', 'C', '9', '9', '4', '9', '4', '7', '2', '1', '6', '5', 'F', 'C', '5', '7', '7', '3', '6', '2', '3', '0', '2', 'A', 'A', 'F', 'C', '4', '8', 'C', 'B', '6', '5', '1', '0', 'E', '6', 'D', 'C', '2', '2', 'D', '0', '0', '5', '5', '1', '1', 'A', 'C', '9', 'E', '5', '2', 'D', '9', '1', '0', '2', '5', '8', 'F', 'F', '5', '5', '5', '2', 'F', '2', '9', '4', 'E', '0', '7', 'C', '0', '2', '1', '7', 'C', '9', '6', '2', 'B', '3', 'E', 'B', '2', '0', 'B', '2', 'E', 'F', '1', 'B', 'F', 'F', 'D', 'D', '4', 'F', '9', 'F', 'B', '9', 'B', '5', 'B', '4', '8', '7', 'F', '5', '2', '5', '4', 'D', '7', '4', '3', '8', '4', '7', '2', '4', 'E', 'C', '5', 'A', 'A', '3', 'D', 'B', '8', '0', '4', 'E', '7', '0', '3', '9', '2', '9', '3', '6', 'F', 'D', '3', '1', '4', '1', 'B', '7', '7', 'F', '1', 'D', '0', 'B', '1', '3', '2', 'F', '9', 'C', '0', '1', '4', '6', '4', 'E', 'E', '0', '3', '4', '7', '0', 'A', 'B', 'C', '0', '8', 'D', '8', 'D', '7', '7', 'B', 'D', '8', '2', '7', '6', '4', 'F', '0', 'F', '2', '2', '1', '6', '6', '3', '5', '7', 'A', '9', 'C', '0', 'A', 'A', 'F', 'F', 'A', '1', '4', '3', 'A', '0', 'D', '1', '5', 'F', '2', 'D', '2', 'B', 'B', '6', 'A', '4', '0', '4', '9', 'C', '9', 'B', '9', '7', '5', '2', '2', '1', '6', '9', '4', '4', 'A', 'B', '0', '2', '5', '6', 'E', 'B', 'E', 'C', '9', '3', '9', '6', '5', 'D', '2', '3', '3', 'E', '2', '4', '8', 'C', 'A', 'D', 'D', '1', '9', 'C', '5', '1', '6', '9', '2', '7', '7', '6', '7', '8', '9', 'C', 'E', '3', '1', 'B', 'F', '0', '0', 'E', '3', '5', 'B', 'C', 'F', '0', '0', '1', '2', 'D', '3', 'E', '0', '4', '1', '5', 'C', '9', 'D', 'E', '1', 'F', '3', 'C', 'E', '5', 'D', '2', 'F', '6', 'C', 'E', '3', '7', '9', '0', '5', '9', 'D', 'D', '4', '0', '6', '7', '5', '7', '6', '6', '6', '3', 'F', '8', '4', '4', 'F', '1', '6', 'C', '4', 'D', '5', 'E', '5', 'B', 'D', '3', 'E', '3', 'C', 'F', 'F', '9', 'F', 'A', 'B', '4', 'C', '5', '6', 'E', 'B', 'D', '1', '0', '4', '1', '7', 'F', 'F', '5', 'F', '2', '8', '5', '2', '7', '2', '6', '0', 'E', '9', 'F', 'B', 'C', 'D', 'D', '8', '9', '9', '0', 'A', '8', '1', '1', 'A', 'E', '8', '9', 'A', 'E', '5', '4', '7', '6', '4', '6', 'C', 'F', '6', '1', '1', 'A', '7', 'E', '0', '3', '6', 'E', 'E', 'F', '7', 'B', 'C', '9', '3', '3', 'E', '8', '0', '5', 'E', '0', '2', 'F', '4', '4', '1', '7', '9', 'C', '4', '1', '6', 'E', '3', '6', '4', '5', '4', 'C', 'B', '1', '3', '8', 'B', '2', 'C', '6', 'E', 'C', 'B', 'E', 'D', 'E', '9', 'A', 'A', 'C', '0', 'E', '8', 'B', '2', '5', 'D', 'E', 'D', '1', 'C', '5', 'A', '5', '2', '9', '2', '8', '2', '3', 'B', '9', '9', 'B', '5', 'C', '6', '7', '7', 'D', '8', '6', 'D', 'F', '4', '5', '6', '5', 'B', 'C', '3', '1', 'C', '5', '5', 'C', '5', '2', 'F', '1', 'E', '9', 'A', '6', 'D', 'D', '8', '3', 'F', 'E', 'D', '3', '2', 'F', 'C', 'C', '4', '3', 'F', 'B', '0', '5', '6', '6', 'A', 'C', '1', '4', '2', '9', '9', '6', '0', 'D', '5', '8', 'B', '3', '1', '4', '7', '4', 'C', '1', '3', '9', '9', '8', '5', '3', 'C', '1', '7', '9', 'F', '8', 'A', '7', 'A', '8', 'B', 'C', '3', '3', 'B', '3', 'A', '3', 'E', '1', '5', '4', '1', '8', '4', '4', 'C', 'F', '2', '4', 'B', '3', '1', 'F', '8', '0', '7', '8', 'C', 'D', '6', '4', '8', '3', 'E', 'D', '5', 'D', '2', 'A', 'E', '7', 'E', '2', 'A', 'C', 'D', '9', '8', 'E', 'A', '7', '3', 'A', '1', 'B', '7', 'C', 'D', 'F', '2', 'C', '3', '4', 'E', '2', '3', '1', 'B', 'A', '7', '6', '8', '6', '1', 'F', '6', '3', '4', '3', '9', 'A', 'C', 'D', '1', 'B', 'C', '1', 'A', '4', 'F', '8', '4', '8', 'B', '3', '6', '7', 'E', 'D', '3', '9', '6', 'C', '9', 'D', '8', '1', 'E', '0', '5', '1', '4', '6', '9', '3', '7', '4', '7', '7', '6', 'E', '3', '2', 'C', '3', '7', '1', 'C', '6', '1', 'A', 'A', '1', '8', '8', '4', '0', 'C', '7', '5', '7', '1', 'C', 'E', 'A', '2', '5', '7', '2', 'D', 'C', '8', '1', '0', '0', 'A', '6', '2', '4', 'D', 'D', 'A', '4', '2', 'C', '4', '5', '6', 'C', '1', '9', 'D', '4', '0', '6', 'E', 'E', '3', '5', '6', 'C', '4', '6', '5', '6', 'E', '4', '9', 'D', '7', '4', '6', '0', 'C', 'A', '7', '2', '4', '5', '7', '5', 'C', 'A', '4', 'F', 'F', '9', 'C', 'E', '9', '4', '5', '1', '4', '6', 'C', 'A', '1', 'A', 'A', '8', '1', '8', '9', '4', '6', '2', '2', 'C', '7', '3', '3', '1', '4', '8', '4', '1', 'D', 'E', '7', '3', '5', '6', '9', '9', 'A', 'D', '6', '2', '2', '7', 'B', '4', '4', 'C', '2', 'C', '3', 'B', '7', 'E', 'B', '1', '0', 'D', 'E', 'E', '2', '6', '1', 'E', '6', '4', '1', 'C', 'A', '6', '4', 'F', 'A', '3', '0', 'D', 'E', '1', '4', '9', 'B', 'C', '7', '3', '1', 'C', 'A', 'D', '5', 'D', '7', '7', '6', '4', '5', 'D', '4', '9', '0', 'C', 'D', '6', '8', 'F', 'F', '6', '6', 'C', 'D', '2', '3', '2', '3', '0', 'C', 'F', 'F', '8', '0', '5', '4', 'D', '9', 'F', '9', '7', '3', 'E', 'F', '5', '1', '1', '2', 'E', 'B', 'E', 'C', 'C', '8', '2', 'C', '8', '1', '1', 'A', 'E', 'D', 'C', '8', '0', 'E', 'A', '3', 'F', 'C', '4', '6', '1', 'C', '2', '6', '5', '8', 'D', '3', '2', '8', '8', '6', '8', '2', '2', '5', '4', '8', '7', '9', 'C', '9', '3', '2', 'C', '0', '2', '9', '9', '6', '0', '7', '5', '9', '0', 'F', '2', '0', '6', '8', '4', '4', 'B', 'A', '2', '5', '8', 'C', '0', 'E', '0', '1', 'B', '1', 'F', '2', 'B', 'E', '0', '6', 'C', '4', 'B', 'A', '0', 'D', '2', 'F', 'E', '6', '0', 'D', 'F', '6', '3', '1', '4', '2', 'A', '9', '3', 'B', '5', '3', '8', '2', 'C', '9', '6', 'A', '4', 'F', '5', 'B', '8', '9', '8', '2', '7', '7', 'C', 'D', '4', '8', '4', 'D', '8', 'F', 'C', 'A', '6', 'B', 'E', '0', '1', '6', 'E', '7', 'A', '0', '7', '3', 'E', '3', 'F', '8', 'F', '8', '9', 'A', '0', '1', '9', '7', '2', '7', '4', '9', 'B', 'E', 'C', '9', '6', '5', 'B', 'E', '6', '3', '7', '8', 'C', '6', 'C', '3', '7', '9', 'D', 'A', '2', '2', '5', 'C', 'B', '3', '5', '1', 'D', '5', '1', 'F', '7', 'A', '4', '1', '4', '5', '9', '6', '2', '2', '3', '1', '5', '3', '6', 'E', '7', 'E', 'B', 'C', 'C', '8', 'C', '9', 'C', '2', '5', 'A', '0', '9', '4', '2', 'D', '9', '3', '9', '2', '0', 'E', '3', '4', '2', 'A', '2', 'A', '4', 'D', 'A', '8', 'D', 'D', 'C', '9', 'F', '0', '3', 'F', 'F', 'F', 'C', '3', '5', '4', 'A', '3', '6', '4', 'F', '7', '9', '6', '7', 'D', '5', '0', 'A', 'B', '4', '3', '7', 'C', '9', '1', 'D', '9', '0', 'D', '4', 'C', 'A', '4', '8', 'E', 'E', '2', '5', 'E', '4', '2', 'E', '8', '3', '3', 'B', '9', 'E', '5', '4', '4', 'A', '5', '5', '3', '5', '7', 'A', 'A', 'A', '8', '9', 'F', '8', '5', '9', 'A', '8', '3', '1', '5', '3', '3', '1', '8', '3', 'A', '6', '4', 'C', '0', '2', 'E', 'A', 'F', 'C', 'A', 'D', '2', '2', 'C', '4', 'F', 'D', 'C', '6', '5', 'A', '0', 'A', '3', '7', 'B', '6', 'C', '8', '6', 'D', 'F', 'B', '0', '7', '6', '1', '8', 'C', 'E', '1', 'B', 'F', 'A', '1', '7', 'F', '9', '9', '1', '2', 'F', '7', '2', 'B', '1', '0', '2', '6', '6', 'C', '9', '7', '0', '1', '7', 'F', 'D', '8', 'B', '2', 'E', '4', 'D', '7', 'D', '6', '4', '4', '7', '3', '7', '2', '0', 'A', 'C', 'D', '0', '0', '0', '7', 'C', 'B', '8', '9', '0', '1', 'F', '8', '2', '6', '6', '8', 'B', 'F', '3', '8', '1', '9', 'B', 'C', '1', 'D', '4', 'E', '5', '9', 'E', '4', 'D', '9', '8', '5', 'D', '9', '9', '7', 'B', '9', 'A', '0', '5', '3', '8', 'E', '7', '6', '7', 'B', '4', '6', '6', '4', '2', '2', 'F', 'B', '8', '0', '4', '5', '8', '6', '9', '6', '6', 'F', '0', 'B', '7', '2', '2', '2', '4', 'C', 'A', 'C', '4', 'A', 'D', 'B', '8', 'E', 'B', '2', 'E', 'E', '4', 'D', '0', 'C', '4', '7', 'D', '9', 'B', 'E', '8', '9', 'B', '8', 'A', '6', 'A', 'B', '2', '4', '8', '2', 'E', '6', '8', 'D', '3', 'E', '3', '2', '0', '5', '2', '1', '9', '8', 'C', 'A', '5', '0', 'F', '6', '8', 'C', 'A', '6', '4', 'E', 'B', '0', '0', '3', 'A', '9', '5', 'C', 'E', '8', '8', 'A', '0', '5', 'E', '9', '0', '8', 'B', '5', '9', 'A', 'B', '9', 'D', '8', '8', '0', '1', 'F', '1', '4', '6', 'F', '3', '6', 'F', 'B', '3', '1', 'F', '7', 'F', '7', 'C', '0', '5', '0', '0', '5', '9', '6', 'A', '2', 'C', '8', '3', 'A', 'C', '3', '3', '2', '3', 'A', 'B', 'F', 'F', '3', '2', 'B', '2', '3', '3', 'E', 'E', 'F', '2', '0', '4', '6', 'F', 'A', '4', '9', '3', '5', 'F', '2', '7', '0', '4', '9', '6', '8', '1', 'F', 'B', '3', '1', '6', '2', 'C', '5', '6', 'C', 'F', 'A', 'A', 'B', '5', '6', '3', 'E', 'F', '2', '4', 'C', 'C', '5', '6', '2', '6', '1', 'F', 'B', 'A', 'C', '6', 'E', '0', 'B', '1', 'A', 'B', 'F', '0', '9', '2', '1', 'E', 'E', 'D', '5', 'B', '1', '5', 'C', '3', '9', '6', '5', '6', 'B', 'F', 'E', 'C', 'D', '3', '9', '5', 'B', 'C', '4', '6', 'A', '8', '9', '0', '1', '5', 'E', 'F', '3', 'A', 'F', 'A', 'F', '7', '5', '2', 'C', 'A', 'B', 'F', '4', 'C', '8', '7', '2', 'F', 'A', 'B', '5', '6', '6', '0', '8', 'A', '9', '6', '5', 'D', '0', '9', 'A', '0', '7', 'F', '1', 'E', 'E', '8', '4', 'E', '0', '9', '7', 'A', '9', '0', '7', '2', '7', '2', 'B', '2', 'E', 'E', '5', 'D', 'F', 'D', '5', '8', '0', '4', '5', 'B', 'D', '5', '9', '3', '5', '8', 'C', '9', '9', '2', '7', '3', '4', '8', '4', 'E', '7', '4', '4', 'E', '1', '5', '4', '8', 'D', '2', '5', '7', 'A', '4', '4', '6', 'D', 'C', 'A', '2', 'F', '1', '6', '6', '9', 'B', '3', '4', '6', '4', '9', 'F', '5', '6', '3', 'F', 'F', '8', 'D', 'D', 'D', '8', 'E', '7', 'B', '4', 'B', '9', '7', '9', 'C', 'E', '4', '3', '9', '1', 'D', 'F', '2', '4', 'A', 'C', '3', 'A', '7', '1', '9', 'C', '7', 'F', '4', '7', '3', 'F', '4', '3', '3', 'D', 'C', '1', '0', 'F', '5', '6', '3', '8', '6', 'F', '9', '8', '3', '5', 'F', '7', '4', '9', 'D', '5', '0', '1', '0', '8', '5', '4', 'F', '3', '8', '4', '3', 'F', '4', '8', 'A', '0', '8', 'E', '4', '3', 'A', 'A', '1', '8', 'A', '6', '3', '7', '0', '9', '1', 'A', '7', '3', 'B', '6', '8', 'B', '3', '4', '9', '1', '1', '5', '6', '2', '9', '4', '6', 'F', '8', '7', '4', 'D', '4', 'A', 'C', 'B', '7', 'F', '5', '8', 'D', '6', '9', '2', '9', 'B', '6', 'F', 'A', '0', '6', 'C', '5', '2', 'F', 'E', '2', '8', '5', '9', 'F', '9', 'A', 'A', 'D', '1', '8', 'E', 'A', 'C', '7', '8', 'B', '4', '6', 'C', 'D', 'A', '6', '2', 'D', '1', 'D', '5', '4', 'C', 'A', '9', 'D', '3', '2', 'F', 'F', 'D', '4', '8', '8', 'E', '2', '6', '7', '1', '8', '6', '3', '1', '6', '0', 'A', 'E', 'B', '9', '8', '0', 'C', 'B', 'B', '5', 'D', '0', '5', '3', '4', 'A', 'C', '8', 'C', '4', '9', 'A', '5', 'A', '1', 'A', '5', '9', 'B', '0', '8', '9', '0', '1', 'A', '1', '8', 'B', 'A', 'C', '4', '3', '8', 'C', 'F', '9', '3', '9', '8', '7', '8', '4', '1', 'E', '9', '9', 'A', 'F', '1', '9', 'A', '8', '4', 'C', '9', '3', 'B', 'C', 'C', '1', '6', '4', '0', '6', '6', 'F', '9', '6', 'B', '2', '3', '4', 'B', 'F', '9', 'E', 'E', '7', '1', 'A', 'B', '8', 'A', '6', '4', 'A', '2', 'D', 'B', 'A', 'C', 'E', 'E', 'A', '3', 'B', '2', '0', '3', '5', '4', 'E', 'A', 'B', '9', '6', 'F', '0', '4', 'A', '7', 'D', '0', 'A', '5', '8', 'E', '7', '2', 'E', '2', 'F', '3', '0', '4', 'A', '6', '8', '4', '0', '9', 'D', '4', '6', '5', 'D', '1', '7', '9', '4', '9', 'F', '5', '1', '4', '9', '7', '0', '6', '0', '4', '7', '8', '4', '5', '1', '5', '6', '1', '2', '9', '5', 'F', '4', '5', 'E', '0', '9', '2', '0', '7', '6', 'E', '2', 'E', 'E', 'E', '0', 'E', '0', '4', '5', '3', '6', '6', 'D', '7', '9', '3', '6', '3', '5', 'D', '1', 'A', '7', '3', 'B', '4', '2', 'F', 'C', '6', '5', 'D', '3', '2', '6', 'C', '4', '7', '0', '9', 'C', '6', 'C', '9', '4', '8', '3', 'A', 'B', 'C', 'B', 'C', 'A', 'F', 'E', '7', '9', '4', '2', '7', 'E', 'A', 'C', '9', '0', '5', '5', '5', 'C', '4', 'C', '9', '7', '7', 'D', '7', '0', '2', '6', '7', '3', 'F', '7', 'E', '3', '9', '8', '1', 'B', '3', 'B', '1', '9', '1', 'D', 'B', '0', 'B', '3', '7', '4', 'D', '4', 'F', '1', '3', '5', '4', 'C', '1', 'F', '8', 'B', '4', '7', 'A', '5', '0', '1', '0', '3', 'F', '7', 'C', '5', '7', 'F', '9', 'C', 'A', 'F', '3', '9', '2', 'A', '9', '2', 'F', '2', '8', 'F', 'D', 'E', '2', '8', '9', '0', '2', 'D', 'C', '4', 'F', '2', 'C', 'C', 'C', '2', '2', '1', 'E', '8', '7', 'C', 'B', '0', 'C', '5', 'F', 'A', '5', '3', '7', 'A', '7', 'F', '3', 'B', '0', 'C', '4', '7', '7', '6', '9', '1', 'D', '0', '3', '9', '1', '3', 'E', '2', '3', '1', '4', '5', '7', '3', '1', '9', '4', 'F', '1', 'A', '7', '5', '8', 'E', '3', '2', 'C', '4', '3', '4', 'A', '5', 'C', '2', '7', '7', 'A', 'D', 'B', 'C', '8', '2', '2', '6', '2', '4', 'A', 'C', 'F', '3', 'E', 'B', 'E', '1', 'E', '6', '3', '5', '5', '8', 'D', 'F', '0', '0', 'E', 'B', '6', '3', '4', '1', '8', '2', '7', '0', 'A', '4', '9', 'A', 'E', '5', '8', 'D', '4', '1', '9', '7', '1', '7', '2', '9', 'F', 'E', 'E', '8', 'B', 'F', '6', '8', '7', '7', 'D', '0', 'F', 'A', '8', 'A', 'F', 'F', 'D', 'E', 'E', 'E', '7', '3', '1', '0', '3', 'F', 'C', '3', 'B', '8', '8', '5', '7', '4', 'C', '9', 'B', 'E', 'B', '8', 'A', '3', '4', 'C', 'A', '5', 'C', '3', 'F', '1', '1', 'A', '7', '0', '5', '1', '1', 'D', '5', 'D', '6', '8', 'E', '9', 'F', 'B', '5', 'C', 'D', 'E', '3', '7', '9', '9', 'D', '8', '3', '0', '3', '1', '2', 'A', 'F', 'B', '1', '5', '1', 'D', 'D', '9', '4', '4', '0', '5', 'C', '1', '7', '0', '7', '6', 'B', 'C', '0', '9', 'A', '7', '2', 'D', '1', '8', 'C', 'C', '7', '7', '9', 'E', '3', '0', 'B', '5', 'D', '0', '9', 'F', '8', '4', 'E', '2', '3', '4', 'D', 'C', 'B', '5', 'C', '6', 'E', '0', 'A', '7', 'E', '3', '1', '5', '4', 'A', '7', '5', '9', '0', '8', '7', '8', '5', '8', '9', 'D', 'B', '3', 'D', '3', '7', '6', 'F', 'D', 'A', '9', '1', '5', '6', '2', 'D', '8', '7', 'B', '7', '7', 'E', '6', 'B', 'D', 'B', '8', '9', '5', '6', 'A', 'F', 'A', '6', 'F', '3', '5', 'A', '3', 'C', '4', '5', '9', 'E', 'B', '4', '2', 'B', '6', 'F', '6', 'D', 'E', '6', '2', 'A', 'B', '7', 'E', 'F', '5', '4', 'D', '9', 'D', 'E', '6', '1', '5', '5', '9', '5', '2', '5', 'F', 'C', '0', '3', 'C', '4', '0', '1', '2', '3', '1', '8', '8', 'E', '9', 'F', 'D', '2', 'C', '3', 'A', '5', '3', '9', '0', '9', '1', '9', 'F', '5', 'D', '9', '1', '3', 'F', 'B', 'C', 'F', '8', '5', '3', '4', 'B', 'E', '6', 'C', '7', 'E', '0', 'A', '0', '1', '6', '3', 'D', 'C', '5', 'F', '7', '9', '3', '5', 'A', 'B', 'A', 'B', 'A', 'F', '3', '2', '9', '8', '8', '9', '0', '6', '1', '2', '2', '6', 'C', '0', '5', '4', '3', '1', 'A', '6', '6', 'A', '3', 'A', '9', 'C', '8', '9', '3', 'D', 'D', 'D', 'D', 'E', '8', '6', '1', '9', 'E', '9', '2', '6', '1', 'E', '5', 'F', '4', 'A', '4', '2', '0', '6', 'B', 'D', '4', '9', 'D', '5', 'E', '2', '9', '2', 'E', '1', 'A', '2', '6', '2', '0', '9', '7', '5', '2', '3', '6', '7', 'F', 'B', '5', '7', '5', '0', '5', '6', '6', 'C', '6', '3', '4', '0', '2', 'B', 'A', '8', '6', 'E', '7', '4', 'E', '6', '2', '6', '0', 'C', '5', 'C', '0', '3', '5', '5', 'A', 'F', 'D', '9', 'B', 'C', 'F', '9', '9', '1', 'D', 'E', 'B', '2', 'E', '1', 'E', 'B', '9', 'B', '0', '3', '2', 'C', 'C', '2', '9', 'B', 'C', '5', 'A', '2', '1', 'A', '5', '7', 'A', '2', '6', '4', '4', 'D', '6', 'F', '8', '6', 'E', '2', 'A', 'C', '4', 'E', 'A', 'E', '4', '6', 'E', '9', '3', '5', '5', '7', '6', '5', 'E', '9', 'B', 'F', 'B', 'D', 'E', 'E', '6', '0', 'E', '1', '4', '7', '6', '4', '3', 'D', 'E', '5', '4', '5', 'B', '2', '4', '8', 'F', 'F', '3', '4', '1', '5', '4', '7', '7', '9', '2', '9', '4', '1', '0', 'E', '9', 'C', 'C', '2', '1', '2', '7', '8', '1', '3', '2', '7', '4', 'B', 'B', '9', 'D', '3', '2', '5', '4', 'C', '0', 'B', 'E', '6', '8', '0', '3', 'F', '1', 'B', '1', '8', '6', '9', '4', '1', '5', '0', 'A', 'C', '0', 'C', '7', '0', '5', '8', '2', 'A', 'F', '7', 'C', '4', 'E', '0', '3', 'F', '5', '2', 'C', 'D', '7', '2', 'B', '8', '9', '2', 'D', 'B', 'E', '7', '3', 'D', '9', '1', '8', '7', '9', 'A', '6', '2', 'E', 'F', '9', 'B', '2', '6', '6', '8', '3', 'D', '7', 'B', '4', '8', '1', '7', '6', '7', '6', '8', '9', '5', '9', '0', '0', '0', 'B', 'B', '9', '2', '3', 'F', '2', 'A', 'E', '8', 'B', '4', 'C', '2', '5', '2', '3', 'E', 'E', '7', '9', '3', '0', 'E', '7', '9', 'D', 'F', 'A', 'C', '0', 'F', '2', 'E', 'B', '3', 'D', '0', 'A', '6', 'B', '1', '0', '6', '7', '6', '3', 'F', '8', 'D', '2', '3', 'A', 'A', '0', '1', '0', '1', '1', 'F', 'E', '4', '1', '7', '8', '1', 'B', '4', '6', 'F', '0', '8', '7', 'F', 'A', 'E', 'A', '8', '4', '4', '9', 'F', '1', 'B', '7', '2', '8', '2', '4', 'B', '1', 'E', 'F', '5', 'E', '2', '9', '5', 'B', '5', '6', 'E', 'B', '9', '7', 'B', 'E', 'A', '1', '0', 'F', 'D', '4', '8', '2', '5', '7', '6', 'F', '7', '5', '4', 'F', 'A', '8', '7', '9', 'A', '6', '1', 'E', '1', '9', '5', '8', '2', 'D', '4', 'E', 'A', '6', '2', '5', '0', 'A', '0', 'E', 'A', 'A', 'E', 'A', '0', '8', 'C', '1', '6', '7', 'B', '1', 'A', '0', 'C', 'C', 'E', '2', 'C', '8', '2', '9', '1', 'B', 'E', 'A', 'D', '1', '1', '8', '2', '7', '4', '0', '7', 'A', '7', 'F', '7', '0', '7', '7', '1', 'D', '5', '0', 'D', '7', '3', 'A', '6', 'F', '7', '6', 'C', 'E', 'D', '2', '3', '0', '1', 'C', 'D', '4', 'E', 'A', 'E', 'F', 'F', '9', '1', '8', '5', '7', '7', 'C', 'F', '6', 'A', '5', '6', '0', 'E', '6', '5', 'A', '5', '2', '4', '4', '1', 'B', '7', '0', '2', '3', 'F', '6', '5', 'A', '4', '3', '2', '8', '0', '7', 'B', '1', '5', 'B', '6', 'D', '5', '3', 'C', '1', '9', 'E', 'F', '0', 'D', '2', '7', 'B', 'A', '3', '8', '6', '6', '2', '4', 'A', '9', '7', 'F', 'D', '1', 'F', '9', 'A', 'C', '4', '3', 'C', 'B', '7', '1', '0', 'D', '7', '8', '6', '6', 'A', 'B', '0', 'B', 'C', 'B', '7', '1', '8', '0', 'A', 'C', '1', '2', '0', '9', 'B', '7', '7', '1', '6', '0', 'D', '0', '0', '1', '7', '0', '1', '1', '4', '9', 'D', '2', '7', '3', '1', 'A', '5', '4', '2', '3', 'B', 'E', '1', '6', '2', '4', '0', 'C', 'C', '7', 'B', '4', '7', '3', '7', 'E', '3', 'D', 'A', '7', 'F', '5', '5', 'D', '7', '2', '9', '9', 'F', '5', '9', '7', 'C', 'F', '6', '7', '0', '9', '1', '0', '8', 'D', '6', '8', '2', 'D', '2', 'C', '5', 'A', '0', '3', 'F', '1', '3', '1', 'C', 'F', '8', '7', 'C', '0', 'F', 'F', '5', 'D', '6', 'F', '5', '1', '4', 'B', 'C', '2', 'F', '6', '7', '4', 'D', 'E', 'D', 'F', 'F', '7', 'B', '7', '4', 'D', '1', 'D', 'C', '9', '7', 'E', '9', 'A', 'E', '5', '7', 'C', '6', '0', '8', '2', '4', 'E', 'A', '1', '8', '5', '2', '0', 'F', '7', '8', 'B', '6', 'F', 'A', 'A', '3', '6', 'C', '9', 'C', '5', '2', 'C', 'B', '1', 'F', 'D', '9', '1', '4', 'B', '0', '7', 'D', 'D', 'A', '4', '6', '6', '4', 'D', 'F', 'A', '4', '0', '0', '6', 'D', '1', 'B', 'A', '8', '3', 'F', 'F', '4', '5', '1', '1', 'E', '8', '2', '7', '5', 'C', '0', '9', '3', 'A', '7', '5', 'C', '5', '2', 'F', 'F', '9', 'E', 'C', '2', 'F', 'F', '7', '4', 'A', '8', '3', 'A', 'E', '2', 'E', '6', '7', '8', 'D', 'D', '3', '5', '1', 'F', '2', '0', 'C', '5', '6', 'B', '5', '4', 'D', '7', '9', 'B', '2', 'C', '5', '8', 'A', '6', 'A', '9', '5', 'E', '6', 'E', '7', 'B', 'E', '9', '2', 'E', '4', '0', 'C', '5', '5', 'F', 'C', 'F', '4', '9', '8', 'F', 'E', '7', 'E', '7', 'A', '3', '8', '1', '2', 'D', '8', '8', '0', 'D', '5', '6', '6', 'A', '4', 'A', '4', '9', '1', '2', 'D', '4', '6', '4', '9', '0', '8', 'C', 'A', 'C', 'F', '4', 'F', '5', '8', '3', '6', 'D', 'E', '1', '5', '1', '2', '3', 'E', '8', 'A', '5', 'A', '6', '1', '6', '8', '4', '4', '7', 'B', 'C', '6', '8', '4', '9', 'E', 'F', '1', 'A', '8', '1', 'B', 'D', '7', '8', '0', '0', '2', 'E', '7', 'A', 'A', '0', '0', 'C', '1', 'B', 'F', '4', '6', '3', 'A', 'E', 'F', '1', 'F', 'D', 'E', '0', '4', 'E', '7', 'B', 'C', '1', '7', '7', 'D', '9', 'E', '3', '5', '8', 'F', '7', 'A', '4', '3', 'F', '0', 'E', '1', '2', 'D', 'E', '9', '1', '5', '3', 'F', '7', '5', 'D', 'F', '0', '9', '8', '8', '5', 'E', '9', 'B', '6', '0', '0', 'F', '6', 'C', 'F', 'B', '8', '9', 'A', '3', 'D', '2', 'D', '1', '4', 'A', '7', 'A', 'B', '0', 'C', '7', 'C', '6', '8', '9', '8', 'B', 'D', '2', '5', 'F', '4', '8', '9', '2', '0', 'C', '8', 'E', 'D', 'B', 'E', '8', 'A', '3', '5', 'A', '1', 'E', 'A', '7', 'F', '5', '4', 'F', '3', '3', '8', '9', '5', '2', '5', 'F', 'F', '5', '8', 'D', 'E', 'C', '7', 'A', '3', '0', 'C', 'E', '7', '8', 'A', 'F', '4', 'B', '8', 'E', '1', 'B', 'A', 'F', '8', 'B', '0', '9', 'F', 'E', 'E', '1', '3', 'B', 'A', '9', '6', 'A', 'C', '0', '3', '7', 'A', '6', '3', 'F', '2', '8', 'F', '5', 'C', '9', '7', '8', '6', 'C', '5', '1', '2', '4', '6', '3', '6', '5', 'E', 'D', 'F', 'F', '4', '9', '7', '9', '6', '8', 'C', '5', '5', '7', '3', 'B', '6', '1', '9', '4', '2', 'B', '6', 'C', 'E', '6', 'B', 'E', 'B', '2', '6', '6', '0', '0', 'B', 'C', '6', '3', '0', 'D', '0', '5', 'D', '9', '9', '6', 'C', '5', '7', 'A', 'B', 'D', 'F', '2', 'B', 'B', 'B', 'E', 'A', '6', '0', 'B', 'C', '6', 'B', 'F', '4', '2', 'E', '7', 'D', '3', 'B', '2', '0', '5', '5', 'F', 'E', '1', '3', 'F', 'F', 'F', 'F', '7', 'E', 'A', '8', 'E', '2', 'C', 'B', '3', 'A', '8', 'C', 'B', 'A', '9', '5', 'A', 'D', 'F', '6', 'A', 'F', 'C', '9', '0', 'F', '5', 'D', '0', 'F', 'D', 'B', '0', '5', 'B', 'B', '5', 'A', '6', 'F', '3', '6', 'E', '0', '7', '4', '2', 'E', 'B', '0', 'A', '7', '7', '8', '5', '3', '9', '1', '2', 'D', '1', '4', 'F', 'E', 'E', '6', 'F', '3', 'D', '5', 'D', 'B', '7', '1', '8', 'F', 'A', 'E', 'F', '3', '6', '9', '2', '8', 'D', 'B', 'C', '1', '0', '0', '3', '9', 'C', 'B', '0', 'F', 'C', '3', 'E', 'F', 'E', 'E', 'D', '5', '9', '2', '9', '5', 'B', '0', '7', '1', '5', 'D', '8', 'A', '1', 'E', '3', '2', '7', '7', 'A', '8', 'C', '2', '9', '4', 'C', 'E', 'C', 'E', 'E', '5', 'C', 'B', '0', '4', '1', '5', 'D', '9', '2', '1', 'D', '3', '2', '7', '4', 'E', '5', '7', 'B', '2', '9', '4', 'C', 'C', 'D', 'F', '6', '5', '4', 'E', '1', '9', '9', '2', '8', '8', '8', '1', '8', 'C', '7', '9', '3', 'B', '7', 'B', '8', '0', '4', 'B', '2', 'B', 'B', 'D', 'F', 'C', 'F', '3', '9', '2', 'F', 'C', '5', 'A', 'D', '4', '6', 'D', 'E', '6', '4', '2', 'A', 'A', '9', '8', '8', '3', '8', 'F', 'C', '1', '0', 'B', '0', 'C', 'B', 'B', 'C', 'B', 'A', '5', '8', 'C', 'D', '8', '0', '5', '0', '0', '6', 'A', '9', 'B', 'E', '6', '8', '2', 'E', '2', '8', 'D', 'C', '6', '1', 'A', 'D', 'B', '0', 'B', 'B', '7', '6', 'C', 'E', 'A', 'C', '6', '6', 'C', 'B', '6', 'B', '3', 'F', 'F', 'D', '7', 'D', '3', '9', '1', 'D', 'E', '2', '0', 'C', '4', '1', '5', '9', 'C', '3', '9', '9', '4', 'E', 'E', '3', 'D', '7', '7', 'D', '1', '7', '8', '0', '8', '3', 'E', '0', 'C', 'E', '1', '7', '9', '9', 'F', 'E', '7', 'D', '1', '7', '6', 'C', 'B', 'D', '2', 'F', 'E', '5', '6', 'B', 'E', '7', '6', '6', '2', '2', '7', 'E', 'F', 'A', '0', '5', '5', '3', '2', 'B', '0', '2', '9', 'B', 'C', 'F', 'D', '8', '8', 'F', 'B', '0', 'D', 'E', '3', '5', '7', '5', '1', '5', '7', '6', '0', 'C', '2', '1', 'F', '3', '7', '7', '3', '2', '3', '8', '6', '2', 'E', '1', 'B', '1', '6', '9', '8', 'A', '2', '9', 'A', 'B', 'F', '7', 'D', 'C', 'D', 'E', '3', 'C', '4', '2', '3', '1', 'D', '0', '0', '6', '1', '1', 'C', '5', '6', '6', '3', '5', 'B', 'E', '4', 'D', 'B', '7', '3', '2', '6', '4', 'C', '7', 'D', '7', '4', 'D', '3', 'C', 'F', '5', 'D', 'D', 'A', '9', '9', '7', '3', '1', '3', '5', '8', '5', 'E', 'E', '7', '1', '0', '9', '4', '2', 'B', 'A', '5', 'A', '3', 'C', '0', 'E', '7', 'A', '5', 'A', '3', '9', 'B', '4', '7', 'B', '0', '3', '2', 'C', '5', '6', '7', '9', 'B', '6', '1', '6', 'A', '9', 'B', '2', '2', '6', '1', '6', '7', '6', '3', '6', 'C', '8', 'E', 'D', '2', 'B', '9', 'A', '3', '2', '5', '2', '6', '0', '1', 'A', 'F', '9', 'E', '3', '6', '4', 'E', 'B', '0', '4', '0', 'F', '5', '6', 'D', 'B', '2', 'D', '7', '1', '6', '8', 'D', '2', '1', '9', '6', '4', '7', 'D', '0', '6', '7', '1', '8', '5', '9', '8', '2', '4', 'A', 'E', 'F', '5', '3', 'C', '7', '1', '6', '1', '4', 'F', 'B', '3', 'D', '0', '8', 'E', '7', '6', '6', 'E', 'B', '9', 'F', '7', 'E', 'F', '1', 'E', '4', '8', '8', '4', '6', '5', '9', 'C', 'C', 'D', '0', '2', '1', '8', 'D', 'C', '0', 'B', '0', '3', 'E', '0', '4', '0', '5', '9', 'A', '0', '7', '5', '4', '2', '5', '2', 'C', '8', 'F', '4', '5', '8', 'D', '4', '6', '5', '3', 'B', '8', '2', 'A', '3', 'C', '1', 'E', 'B', '6', '0', 'D', '9', 'E', '2', 'F', '6', '5', '2', '9', 'C', '4', '9', 'F', '2', 'B', '4', 'C', '3', '3', 'E', '3', 'E', 'D', '7', '6', '4', '3', '4', 'D', 'B', '2', 'A', 'D', '5', 'A', '4', 'A', '7', 'D', 'A', 'B', '8', 'F', 'C', '1', '7', 'D', '8', '5', '1', 'D', '8', '3', '7', '7', '0', '6', 'F', '2', '6', '7', '2', '2', '5', '5', 'A', '4', 'F', 'F', 'B', '7', '1', 'B', '4', 'E', 'C', '0', 'D', 'F', 'E', '3', 'B', '7', '4', 'E', 'B', 'F', '9', 'E', '9', 'E', 'A', '8', 'F', '3', '5', 'C', 'B', 'E', '6', 'C', '3', '6', '7', '4', 'A', '1', 'F', '2', '2', '4', 'C', '2', '2', '2', 'B', 'E', 'C', 'C', '3', '6', 'F', 'B', 'C', 'F', 'A', '1', 'F', 'C', '0', '3', '7', '7', 'A', '9', 'C', 'A', 'D', 'A', '1', 'E', '9', '1', '8', '7', 'C', 'B', 'F', 'C', '6', '1', 'B', 'B', '8', '9', 'F', '3', 'B', 'B', 'C', '7', '9', '4', '7', '4', '1', 'F', '9', '1', '5', '2', 'C', '9', '6', '4', '1', '9', '3', 'E', 'A', 'A', 'E', 'A', 'B', 'F', '5', '1', '3', '5', 'B', 'E', 'C', '6', '2', '8', '5', 'B', '9', '8', 'E', '9', 'E', '8', '7', '7', '1', 'A', '6', 'E', 'B', '2', '7', '8', 'B', 'C', 'C', 'D', 'F', '8', '1', 'D', '3', 'E', 'D', '3', '9', '1', '4', '6', '1', '4', '5', 'C', 'B', '5', 'A', '9', 'D', '4', '7', '6', '4', '6', '4', 'B', '8', 'D', '1', '8', '3', '3', '0', 'E', '2', '1', 'B', 'F', '4', '0', 'D', '1', 'C', '7', '9', 'C', 'E', '2', '4', '6', '7', 'D', 'E', '8', '5', '6', 'C', 'D', '6', 'F', '2', '2', 'C', '5', '2', '3', '6', 'B', 'C', '2', 'C', '9', '7', 'B', '8', '3', 'B', '2', '6', '8', 'F', '1', 'B', '0', 'C', 'C', 'C', '3', '8', '6', '1', 'B', 'B', 'D', '8', '1', 'F', 'C', '5', 'D', 'F', '4', 'C', 'B', '2', '3', '7', '7', 'A', 'A', 'E', '2', '8', '0', 'B', '7', '5', 'E', '2', '0', '1', '9', '3', '4', 'D', '8', '9', '5', 'A', '8', '6', 'B', 'E', '1', '1', '4', '8', 'E', 'B', '1', '7', '6', '9', 'E', '7', 'A', 'B', 'D', '2', '9', '0', 'A', '4', '8', '7', 'E', 'C', '5', 'F', '1', '0', '4', 'E', '3', '4', 'A', '1', 'D', '8', '3', 'B', '3', 'D', '8', '9', '1', 'A', 'C', '2', 'F', '4', '1', 'E', '3', '5', '1', 'A', '9', 'C', '6', '6', '2', 'D', '3', '7', '7', '2', 'A', 'F', '5', 'B', '6', '3', '6', '4', 'C', '2', '9', '4', 'F', '1', '5', '7', 'F', 'A', 'C', '7', '2', '2', '2', '6', 'A', 'D', '0', '7', '8', 'C', '7', '7', '4', 'F', 'E', 'A', 'F', 'A', 'D', '3', 'B', '2', 'F', '0', '2', 'C', 'F', 'F', 'C', '9', 'F', '2', '9', 'B', 'B', 'F', '5', '7', '5', '0', '7', 'F', 'B', '6', '7', '8', 'D', 'E', '4', 'C', 'A', 'E', 'C', '9', 'F', 'F', '9', 'B', '5', '8', '6', '1', '6', 'A', '6', '6', '0', '4', '5', 'F', 'E', 'F', '0', 'D', '0', '4', '1', 'F', 'C', 'A', '2', '3', '2', 'B', '3', '9', '5', 'F', '8', 'E', '1', '1', '1', '6', '8', '8', '8', '5', '4', '1', 'F', '3', 'B', '0', '2', 'C', '6', 'E', 'D', '5', '3', 'A', 'E', '5', '9', '6', '6', '4', '9', '1', '4', '9', 'D', '5', '2', '6', 'F', 'E', 'C', '2', '4', '8', '5', '5', 'E', 'E', 'C', '8', '8', '1', '2', 'F', '1', '2', '9', '3', 'C', '3', '1', 'B', 'D', '0', '8', '2', 'D', '2', '1', 'A', 'D', '2', '6', '5', 'C', '0', '6', 'B', 'C', '1', '5', 'D', 'A', '2', '0', 'D', '2', '4', '1', '0', 'B', '6', '3', 'A', 'D', '5', 'F', '1', '5', '3', 'B', 'B', 'E', '9', 'B', 'E', '6', '7', 'B', 'D', '9', '3', '7', '3', '3', '6', '4', 'D', 'B', 'B', '2', '1', 'F', '7', 'A', '3', 'D', '1', '8', '4', '3', 'F', '0', '0', 'F', '6', '7', 'A', '2', '5', 'A', '7', '9', 'B', '1', '9', '1', '5', '9', '0', '4', '9', '6', '8', '0', '2', 'C', 'D', 'E', 'D', '8', '5', '6', '8', '0', '8', '4', '8', '1', '0', '2', '2', 'A', '0', 'D', '2', '4', '0', '0', 'C', '3', '5', '2', 'B', '8', '2', '0', '1', 'E', '6', 'E', '5', '5', 'C', '2', '1', '1', 'B', 'F', '1', 'C', '4', '7', '7', '6', '2', 'F', 'C', 'F', '1', 'F', '2', '5', 'E', '2', 'A', '6', 'F', '6', '6', '6', 'F', 'B', '5', '5', '0', '5', '3', '1', 'C', 'F', '9', 'D', '4', 'E', 'B', 'A', 'A', 'E', '8', 'C', '8', '7', 'C', 'A', '5', '5', 'B', '7', '0', 'A', '6', '1', 'D', 'C', '6', 'C', 'A', '5', '8', 'A', '8', 'A', 'B', '9', '3', '6', '6', '5', '3', 'A', '9', 'A', 'A', '9', '9', '3', '6', '8', '7', '6', 'C', 'C', '3', 'A', 'B', '6', '3', '0', '0', 'C', '8', 'D', '3', '7', '7', 'A', 'C', '2', '7', '9', '5', '9', '5', 'C', 'C', '5', 'E', '2', '2', 'D', '8', '6', '6', '7', '2', '7', '3', 'F', 'C', 'C', '4', '5', 'A', '6', '1', '0', '7', '5', '8', 'A', '5', '6', '9', '9', 'B', '0', '6', '0', 'B', '3', 'C', '8', '0', '6', '6', '0', '2', '6', '6', 'E', '9', '2', '7', 'D', 'E', '1', 'D', '0', 'F', 'E', '7', '6', '1', 'F', '3', 'D', '2', 'E', 'E', 'B', '5', 'D', '0', '8', '9', '4', '7', 'D', '7', '6', '7', '3', 'F', '7', '4', '1', '8', '8', 'E', 'D', '5', '5', 'B', '0', '2', '9', 'B', 'C', '7', '0', '5', 'C', '5', '8', 'A', '1', 'B', '3', '0', 'C', '6', 'D', '4', '8', 'D', '0', '8', 'A', '8', '7', 'D', 'C', '4', 'A', '3', '9', '2', 'A', 'B', 'A', 'F', '6', 'D', '3', '0', '0', '5', '4', '1', '9', '7', '8', 'E', 'A', '5', '0', '5', '7', 'A', '4', '4', '5', '0', '7', '5', 'D', '4', 'A', '8', 'F', '9', 'D', '2', '1', 'D', '6', '7', '0', 'E', '4', '6', 'D', 'F', 'D', '9', '0', 'A', '0', '9', '2', '8', '9', 'C', '9', 'E', 'E', 'D', 'E', '7', '2', 'D', '4', 'F', '7', '9', '0', 'E', 'E', '0', '4', '5', '6', '8', '4', 'B', '1', '5', '9', 'C', '9', 'E', 'D', '6', '2', 'F', '7', '7', 'A', '0', 'E', '9', '5', '9', 'D', 'F', 'F', '7', 'A', '7', '2', '4', 'C', '3', 'F', '9', 'D', '4', '7', 'F', 'B', '8', 'C', '2', 'E', 'D', '9', '9', '5', 'C', 'C', '6', 'F', '8', '3', 'E', '6', '2', 'A', 'D', '9', 'F', 'F', '8', '5', '2', 'F', '9', 'B', '2', '2', 'A', '5', '5', '5', 'E', '3', '5', '2', '1', '2', '8', '3', '9', 'C', '1', '9', 'A', '3', '8', '5', '9', 'C', '5', '0', 'F', '2', '8', '0', 'B', '6', '1', 'B', 'B', '4', '3', 'A', '3', 'D', '5', 'E', 'E', '0', '1', 'F', '7', 'C', '6', '9', '4', '5', 'A', 'D', 'C', 'C', '0', '0', '7', 'A', 'E', '9', '3', 'E', '0', '9', '5', 'B', 'E', '0', '4', 'E', 'C', '9', 'B', '5', '5', 'F', '4', 'D', 'F', 'C', '0', 'D', 'A', '6', '7', '5', '3', 'B', '1', 'A', '2', '0', '4', '7', '9', '3', '7', '8', '0', 'D', '1', 'F', '9', '6', '4', '7', '4', 'B', '4', '0', '2', '0', '7', '9', '5', 'C', 'F', '6', '9', 'A', 'E', 'D', 'E', 'E', 'D', '1', '7', 'D', 'F', '7', '1', 'A', '5', '8', 'E', 'F', 'E', '4', '3', 'B', 'A', '9', '9', '8', '4', 'E', '3', 'D', '3', '4', 'C', '0', 'B', '3', '1', 'E', '8', 'D', '1', '1', '6', '4', '1', 'A', '7', '0', '7', 'F', '3', '9', '0', '1', 'F', '0', '0', 'E', 'D', 'D', '0', 'D', '1', '1', '6', 'D', '8', '2', 'B', 'F', '6', '0', 'E', '8', '8', '1', '5', 'C', 'A', '1', 'F', 'B', '8', '6', 'A', '2', '1', 'B', '0', 'F', '5', '4', '6', '9', '5', '1', '9', '2', 'B', '7', 'E', 'F', 'F', '6', 'F', '7', '8', 'A', '6', 'F', 'B', '4', 'D', '8', '0', '2', '2', 'C', '2', '7', 'F', 'F', '6', '2', '5', '9', 'B', '4', '3', '4', '6', '1', '9', '4', '2', '6', '8', '0', '3', 'D', '5', '2', '5', 'F', '5', '5', 'E', '4', 'E', 'D', 'B', '9', '4', '4', 'C', 'A', '1', 'A', '1', 'D', 'D', 'C', '8', '8', '9', '2', '6', '1', 'A', 'D', 'B', '8', '2', 'E', 'E', 'B', '0', 'B', '1', '1', '8', '5', 'B', '8', 'A', '3', '9', '3', 'F', 'D', 'E', '3', '2', '2', '7', '5', 'E', 'D', 'A', 'D', '1', '7', '9', 'F', '0', '2', '0', '0', '7', 'E', '2', '7', '6', '1', '2', '4', '3', 'C', '2', 'D', '4', '2', '0', '5', '4', '0', '9', 'B', 'D', '0', '4', 'F', '7', '3', 'F', 'D', 'D', '3', '6', 'D', '3', '0', 'D', '2', '4', 'E', '9', '6', '8', '7', 'F', '1', '9', 'B', '8', '8', '7', 'C', '8', 'C', '1', 'F', '2', 'F', '0', 'B', 'F', '8', '9', '6', '4', '5', '9', '7', '8', '2', '0', '1', '8', '9', '1', '8', '5', 'F', '3', '7', '4', 'F', '0', '1', '8', '0', '6', 'D', 'F', '6', '2', 'D', 'F', '2', 'A', 'B', 'B', '6', 'C', '3', '8', '4', 'E', 'D', '7', 'C', 'A', 'F', '2', 'E', 'B', 'F', '4', '6', '8', '8', 'A', 'F', '1', '9', 'A', 'E', '3', '7', '5', '7', 'D', '4', 'D', '4', '6', '4', '3', '6', 'C', 'F', '4', 'B', '6', '0', '3', '1', 'E', '3', '6', 'F', '7', '6', 'B', 'A', '1', '4', 'C', '4', '0', '8', '1', 'C', 'C', 'E', 'E', '8', 'B', 'D', 'D', '4', '1', '9', '1', '0', '3', '5', '0', 'B', '6', '7', 'E', '0', '3', '8', 'F', '4', '5', '8', 'F', '3', '2', '2', 'B', 'C', 'E', '2', '4', 'F', '2', '4', '6', 'C', 'F', 'E', '9', 'C', '2', '0', '3', 'E', 'B', 'A', '1', '5', '8', '3', '4', '5', '9', 'A', '3', 'F', '4', '5', '0', 'B', '9', '5', '5', 'A', '5', '1', '5', '5', '1', 'E', '6', '7', '7', '4', '4', '7', '3', '0', 'E', '0', '7', '9', '7', '4', '4', '2', '0', 'C', '2', '4', 'F', '5', 'E', '0', '2', 'D', 'F', '5', '3', 'C', 'F', '7', '7', 'D', 'D', '2', '2', '3', '5', 'B', '3', 'F', '9', '0', '3', '8', 'A', '2', 'D', '1', '5', '0', 'B', '6', '2', '3', '4', '0', '7', '6', 'F', '4', 'C', '8', '6', '1', '0', 'A', '9', '7', '7', '3', 'F', 'C', '7', 'B', '7', '3', '1', '9', '3', 'A', '8', 'F', 'B', 'E', 'B', 'D', 'E', 'E', 'E', '5', '3', '1', '8', 'C', '1', '5', 'C', '9', '0', '8', 'F', 'F', '1', 'E', '6', '9', 'A', '1', 'E', '6', 'D', '9', '7', '4', 'A', '6', '3', '1', 'E', '0', '2', '4', 'E', '9', '0', '5', '7', '2', 'D', 'D', 'E', '7', '6', '7', 'E', '3', '3', '2', '9', 'C', 'E', '4', '2', '7', '1', '0', '6', '7', 'F', 'D', '8', '9', '7', '1', '4', '5', 'E', '4', '0', 'E', 'C', '2', 'F', 'F', 'A', 'F', '0', 'C', 'B', '0', '1', 'B', '8', 'D', '2', 'E', '9', 'D', 'F', '3', '9', '5', 'A', '3', 'F', '9', 'E', '5', 'D', '1', '5', 'A', '6', '1', '7', 'E', 'E', 'A', 'F', '4', 'A', '0', 'A', '3', '2', '5', '8', 'C', 'B', 'D', '3', '0', 'E', 'E', '6', '0', '5', 'F', '1', '1', 'D', 'D', 'B', 'E', 'C', '0', 'F', '8', '9', 'D', 'D', '1', '1', '7', '2', 'B', '9', 'D', '6', 'C', 'A', '9', 'D', '4', '6', 'B', '2', 'B', '6', '4', '7', 'C', '4', 'C', '8', '7', '9', '0', '2', '6', 'F', '2', 'E', '2', 'E', 'F', '3', '8', '7', 'D', 'B', 'B', 'E', 'D', '8', 'E', '6', 'A', 'D', 'E', '6', 'A', 'B', '1', 'D', '7', 'E', 'B', '9', '4', 'B', 'C', '0', '5', 'B', '9', '6', '3', 'C', '5', '6', 'B', '6', '1', '6', '9', '9', '8', '3', '8', '1', 'B', 'F', 'B', '6', '5', '0', '5', '9', 'E', 'B', '0', '6', 'B', '0', '8', '6', '9', 'E', 'F', '9', 'D', '8', 'E', '7', '4', '2', '8', '1', 'B', '1', '8', 'C', 'F', 'D', '9', '7', '5', '0', '8', '3', '2', '6', '5', '2', '7', '0', '5', '4', '5', '5', '7', '3', '1', 'E', '9', 'C', '8', 'E', 'C', 'D', '6', '6', '7', '8', '3', '9', '9', 'B', '5', '0', '2', '7', 'C', '3', '3', 'A', '6', 'C', '3', 'B', 'A', '5', '3', '7', '1', '0', '4', '0', '4', '9', '8', 'F', '6', 'A', 'A', '8', 'B', 'D', '3', '3', '7', '8', '0', 'D', '4', 'B', '4', 'B', '9', '1', '8', 'B', '0', 'A', 'A', 'F', '1', 'F', 'E', '7', '1', '4', 'E', '3', '3', '0', '9', 'D', 'B', '7', 'C', 'F', '4', '7', '8', 'A', 'B', '4', '0', 'E', 'D', '3', '7', '6', 'E', '8', 'F', 'D', 'E', '0', '6', 'D', '9', '3', '4', '1', 'D', 'A', 'D', '9', 'D', '6', 'D', '0', 'D', '6', '7', '1', '0', 'E', 'A', 'B', '8', '6', 'C', 'D', '5', 'D', '7', '8', '1', '5', 'B', 'B', 'E', 'D', 'C', '8', '7', '7', '2', 'F', '1', 'A', '7', '7', '6', '9', '4', '9', 'E', 'C', '6', '7', '6', '5', '1', 'C', 'A', '6', 'F', 'D', '4', '4', 'B', '6', '3', 'C', '1', 'C', '7', '9', 'C', '4', '5', 'C', '2', '8', 'C', '4', 'A', 'E', '5', '8', 'C', 'D', 'C', '1', '6', '1', '6', 'B', '1', '5', 'D', '8', '0', '2', 'F', '2', '3', 'A', '6', '1', 'F', 'A', '8', '9', '1', 'B', 'F', 'E', 'A', '3', '0', 'F', '7', 'D', '9', '2', 'C', 'D', 'D', '8', 'B', 'E', '8', '7', '4', '5', '4', 'A', '1', '0', '7', '8', 'E', 'B', 'D', '0', 'E', '6', '6', '5', 'C', '1', '2', '5', '4', '7', '5', '3', 'E', '9', 'E', '7', 'B', 'F', 'A', '5', '9', '2', 'F', '3', '1', 'C', 'C', '2', 'A', 'F', '7', 'D', '9', '9', '5', 'C', '1', 'F', 'B', '6', '1', '8', '6', '2', 'D', '0', 'A', '0', '7', '3', '6', 'E', 'B', '8', '7', 'E', 'A', '3', '1', '1', '1', '0', '8', '5', '1', 'A', 'E', 'B', 'B', '2', '9', '2', '2', '7', 'E', '1', 'E', '4', 'A', '3', '6', '0', 'D', '6', 'F', 'D', '1', '9', 'A', '3', '8', '3', '4', 'D', '9', 'F', 'B', '1', 'B', '8', '5', '0', 'B', '1', '7', 'A', 'B', 'E', 'D', '4', 'B', 'E', 'B', '3', 'C', '3', '7', '5', '5', '6', '6', 'A', '2', '2', '8', 'A', '9', '5', '5', '0', '7', 'B', '8', '9', 'A', '1', 'F', 'E', '3', '5', 'D', 'C', '8', 'B', 'F', '8', '4', 'F', '0', 'F', '2', 'E', '3', '4', 'C', '7', '0', '3', '0', 'D', '7', 'F', '8', 'F', 'D', '9', 'F', '3', 'C', 'B', 'E', '2', '2', '5', '7', 'B', 'B', 'E', '7', '1', '3', '4', 'E', 'B', '9', '9', '3', '7', 'C', '3', 'A', '3', 'B', '4', 'A', 'C', '4', '7', '2', 'D', 'A', 'F', '9', 'F', 'C', '0', '6', '6', 'C', '9', '5', 'A', 'C', '2', '3', '4', '6', '6', 'B', 'A', '0', 'B', '8', 'E', 'E', '0', '9', '5', 'C', 'C', '7', '5', 'F', '6', '6', 'D', '2', '6', 'A', 'C', '0', '7', 'F', '5', '7', 'D', 'F', '9', 'B', '0', 'B', '6', 'A', '1', '2', 'A', 'E', 'A', 'B', 'D', 'D', 'C', '0', '9', '5', '0', 'E', 'E', '0', 'E', '8', '3', '0', 'D', '4', 'C', 'C', '7', '7', '1', '9', '9', 'C', '8', 'F', '5', 'F', 'C', '4', '5', '5', '9', '1', 'E', '1', '0', '0', 'A', '0', '6', 'B', '5', '1', '7', '9', '8', 'D', '0', '7', 'E', '6', 'F', 'B', 'E', '5', '2', 'B', 'B', '1', '4', '2', '8', '3', '8', '0', '4', '2', 'B', '6', 'E', '1', '1', 'C', '4', 'C', '5', '9', '0', 'E', '8', '2', 'C', '5', '8', '7', '9', 'D', 'F', 'E', '1', '4', '4', '5', 'F', '0', 'C', '1', '7', '8', '8', '4', '5', 'D', '0', '8', '3', '9', 'D', '3', '0', '0', 'F', 'D', '0', '4', 'C', '2', '0', 'B', 'F', '9', '0', '7', '4', '8', '1', 'D', 'A', '6', 'D', '8', '3', '6', '3', '6', '8', '9', '7', 'E', 'A', '3', '1', '6', '8', 'D', '5', '3', '5', 'D', '0', '7', '1', '6', 'E', '6', '6', '7', '4', '8', '0', 'A', '0', 'D', 'E', '0', '0', '4', '9', '0', 'C', 'A', '3', 'C', '9', 'F', '7', '2', '5', '4', '9', '6', 'F', 'F', '6', 'D', '3', 'F', 'D', '6', '2', '4', 'E', '5', 'C', 'C', '4', '2', '8', '3', 'A', '6', '0', '8', 'E', '2', '1', '6', '4', '4', '8', '1', '1', 'C', 'C', '1', '7', '0', '2', 'C', '6', '0', 'C', '7', '9', 'E', '8', 'C', '1', '4', 'E', '6', 'F', 'C', '2', '7', 'C', '4', '2', 'D', 'B', '9', '4', '6', '2', '6', '8', 'D', 'D', 'E', 'C', 'C', '0', '4', '5', 'B', '9', '2', '3', 'E', 'A', '7', 'C', '6', '6', '3', '3', '4', '1', '4', 'E', 'A', 'E', '0', 'A', '7', 'D', '6', 'B', '8', '9', '2', 'A', 'B', '1', '3', 'C', 'E', 'E', '5', '1', '8', '5', '2', '3', '0', 'D', '9', 'D', 'B', '6', '5', '4', 'F', '1', '1', 'A', 'D', '6', 'E', '8', 'C', '0', 'E', '5', '8', 'F', '6', '1', 'B', '8', '1', 'E', 'F', '8', 'B', '6', '5', '6', '3', 'E', '5', '9', 'B', '7', '4', '3', 'A', '5', '6', '5', '3', '2', 'B', 'F', 'E', 'E', 'D', 'A', '4', '0', 'A', 'D', '9', 'B', '7', '5', '9', 'C', '7', '1', '5', '1', '9', 'A', 'B', '5', '3', 'C', 'C', '1', 'D', 'B', 'D', 'E', 'B', '8', '7', '9', '3', '3', '5', 'E', '8', '1', '6', 'F', '7', '3', '8', 'A', 'F', 'B', '6', 'D', '4', 'E', '7', 'D', '1', '6', '3', '2', 'C', '4', '8', '2', '1', '6', '3', '6', 'F', '3', 'E', 'E', 'B', 'B', '1', '2', '7', 'F', '0', '9', '8', '6', 'D', '2', '2', 'D', '2', '6', 'A', '7', '5', '7', '5', '3', 'C', '4', '8', 'B', '2', 'D', 'B', '9', '3', 'B', 'F', 'B', 'C', '7', 'B', '4', '2', '8', 'E', 'B', '0', '9', '0', '0', 'D', '7', '9', 'F', '4', '5', '7', '2', '3', 'D', '3', '4', '9', 'C', '5', '8', '7', '7', '1', 'E', '2', '2', 'C', 'C', '3', '1', 'F', 'F', 'A', '5', 'D', 'D', '6', '5', '8', '6', 'F', '9', 'F', 'C', 'E', 'C', 'C', 'A', '8', '7', '6', '2', '0', '8', 'A', '4', '8', 'C', '5', '9', '3', 'C', 'E', '5', 'C', 'F', 'A', 'C', 'D', '0', 'E', 'F', '9', '4', '8', '6', 'F', '4', 'A', '6', '3', '8', 'F', '4', 'E', '4', '9', '7', '7', 'F', '5', 'B', 'F', 'F', '0', 'F', 'D', '5', '3', 'A', 'D', 'E', '0', '0', 'F', '1', '9', 'D', '5', 'B', '6', 'A', 'D', '3', 'E', '3', '7', '3', 'B', '8', 'D', '3', '6', 'E', 'E', '7', '4', '1', '0', 'B', '5', '1', '6', 'C', '9', '6', 'B', '4', '7', '5', '3', '6', '7', '6', '0', '2', '2', '3', 'A', '5', '7', '7', '2', '3', '7', '7', '5', '1', '2', 'C', '0', '6', 'B', 'F', 'D', 'F', '2', '9', '3', 'A', '1', 'A', 'D', '0', 'F', '4', '9', '8', '5', 'F', 'B', '5', '5', '5', 'F', '6', '9', '1', '8', 'C', '8', '7', '3', 'C', '8', 'A', 'D', '8', '2', 'E', '1', 'D', 'C', 'D', '6', '1', 'D', '5', 'E', '8', 'F', 'D', '0', '8', '9', '3', 'F', 'B', 'D', '4', '3', '8', '7', '2', 'E', '4', '4', 'E', 'E', '9', '0', '4', '9', 'B', 'D', '3', '7', 'F', '5', '4', '6', 'D', '2', 'D', '6', '8', '8', 'E', 'C', 'D', 'A', '6', '5', '2', 'C', 'D', '0', '4', 'B', '2', 'A', 'D', '0', '2', '6', '9', '9', '3', '7', '1', '4', '3', '4', '1', '1', '6', '2', '1', 'B', '8', '3', '4', 'F', '8', '2', 'E', '8', '7', '6', '5', '5', 'B', '7', 'A', 'B', '1', '9', '6', 'F', '4', '6', '5', '7', '8', '9', 'F', 'F', 'A', 'F', 'E', '0', '9', '4', 'A', 'F', '7', '3', 'F', 'E', '7', 'D', 'D', '4', '0', '9', '9', 'E', '0', '4', '1', '4', '4', 'B', 'D', '5', 'D', '2', '4', '7', '6', '6', '8', 'E', 'F', 'B', '8', '3', '9', '7', 'A', '8', '8', '9', 'F', '5', '8', '2', '9', '0', '9', '5', 'D', '2', 'B', 'F', 'B', '9', '4', 'C', '1', '1', 'D', 'B', '1', 'D', 'D', '5', '4', 'F', 'B', 'C', '5', 'A', '0', '0', 'B', 'F', '2', 'D', 'F', '6', 'F', '9', '0', 'E', 'A', 'D', '4', 'A', '1', '2', '5', 'E', '1', '6', '4', '6', 'B', 'A', '0', 'E', '1', 'D', 'F', 'F', '2', '5', 'C', '5', 'A', '5', '9', '6', 'D', 'B', 'A', '8', 'F', '7', 'E', 'C', 'E', '5', '0', 'F', '1', 'B', '7', 'C', 'D', '4', 'D', '3', '3', '6', 'C', 'D', 'C', '8', 'E', 'C', '9', 'A', '2', '5', 'B', '8', '7', '5', '3', '8', '8', 'F', '6', '0', 'A', '3', 'A', '9', 'A', '7', '4', 'A', '9', 'B', 'D', '9', '0', '1', '3', '7', 'A', '8', '2', '4', '7', 'B', '1', '1', 'F', '0', '2', '9', 'A', 'E', '2', '4', 'F', 'B', 'F', '2', '6', 'A', '3', 'C', '2', 'F', '2', 'F', 'B', 'B', 'B', '4', 'F', 'F', 'D', '9', 'E', 'A', 'B', '5', '0', '4', 'A', 'E', '5', 'E', '1', 'A', 'D', 'C', 'A', 'B', '9', 'D', 'A', '0', '7', '0', 'A', 'F', '0', '9', '1', 'A', '3', '9', 'B', '4', '3', '1', '7', '6', 'B', '5', 'E', 'E', '2', '4', 'B', '2', 'A', '2', 'E', '1', 'D', '9', '7', '7', '9', '3', 'D', '9', '6', 'A', '9', '9', 'A', '7', '6', '5', '8', 'E', 'F', '8', '1', '8', 'E', '0', '1', '0', '4', 'B', 'D', '7', '1', 'E', '6', 'F', 'B', '6', 'D', '5', '3', '6', '6', '2', 'B', 'F', '0', '1', 'F', '9', '8', '2', '4', 'F', 'C', '4', 'B', '0', 'E', 'A', '9', '1', '0', '3', '1', '8', '4', '0', '8', 'A', '0', 'F', '4', 'A', '6', 'A', '1', '3', 'A', 'F', '5', 'F', 'B', 'F', '0', '6', 'D', 'F', '7', '4', '5', '6', '6', '2', '9', '4', 'C', 'A', 'D', 'F', 'A', 'E', '2', '1', 'B', '7', '0', '6', 'F', 'E', '8', '9', '6', '6', '4', 'F', '6', 'B', 'D', '6', '9', '0', 'E', '1', '7', 'C', '4', 'E', 'A', 'F', 'C', '1', '1', 'E', '5', 'B', '2', '4', '4', 'D', '9', 'F', '9', '9', '0', '9', '7', 'E', '2', '5', 'D', '9', 'D', '7', '0', '9', '1', '1', '5', '4', 'C', 'C', '7', 'F', '2', 'E', '8', '4', 'D', 'E', '8', '9', '7', 'A', '6', '0', 'A', '8', 'E', '2', 'D', 'F', 'F', '5', '8', '4', 'B', '9', 'B', 'E', 'C', '8', 'C', 'E', 'F', 'C', '5', '8', '6', '0', 'C', '2', '7', '8', 'B', '6', '0', '7', '0', '6', '4', '6', '3', '2', 'D', 'E', 'F', '7', '4', '7', '7', 'D', 'A', '8', 'C', 'B', '0', '1', 'D', '1', '5', '0', '7', 'C', '6', '2', '9', 'E', '0', '2', 'A', '3', 'B', '7', '6', '5', '1', '7', '8', '3', '8', 'B', '1', '7', '0', '1', 'C', '7', '7', '9', '2', 'E', 'C', 'A', '3', '3', '2', '4', 'F', 'A', '7', '4', '0', '8', 'D', '4', 'C', 'A', 'A', 'A', '4', '7', 'A', '1', '3', 'A', '8', 'D', '5', 'F', '5', 'F', '0', '9', 'D', 'B', '6', '7', '6', '6', 'D', 'F', '5', '5', '6', '0', '8', '5', '2', '2', '3', 'C', '0', '7', 'B', 'C', '9', '7', '6', 'E', '7', 'C', '5', 'D', '8', '2', '9', '6', '0', 'D', '1', '4', '4', '7', '2', '2', '9', '9', '2', '4', '1', 'C', '1', '5', '7', 'F', '8', '1', 'C', '1', '8', '9', '0', '6', '5', 'E', 'D', 'B', '8', 'A', '5', '1', '6', '6', 'D', '7', 'F', '2', 'B', '4', '5', 'D', '5', '7', '3', 'A', '6', 'D', '6', 'F', '6', '2', '9', '4', '1', '5', 'B', '6', '6', '0', 'C', '9', '5', 'C', 'C', 'D', '3', '3', '3', 'B', '2', 'D', '4', '6', 'E', '2', 'A', '7', 'F', '4', '3', 'F', 'A', 'A', 'D', '9', '1', 'B', '0', '7', '9', 'A', '0', 'B', '1', 'C', '4', '5', '6', '8', 'C', '3', 'A', '6', 'D', 'F', '5', '0', '2', '1', '3', '8', '4', '8', '5', '6', '3', '5', '0', 'C', '2', 'C', 'B', '7', 'C', '6', '7', '6', '1', 'E', '3', '3', 'F', '2', 'A', 'D', 'B', '9', '9', 'F', '0', '9', '0', '7', '9', 'C', 'B', '5', 'F', '8', 'B', 'D', '4', '9', 'A', '7', '0', 'E', 'E', '4', '2', '4', '6', '1', '3', 'C', '8', 'E', 'F', '5', '3', '0', 'A', 'C', '7', 'C', '1', 'B', '1', 'B', 'B', '7', '3', 'F', '3', '3', '1', 'E', '5', '8', 'E', '8', '2', '4', '0', '4', '8', '5', 'E', '9', 'F', '7', '3', '9', 'A', '9', 'E', '8', '2', '9', '4', '1', '9', 'A', 'A', '8', 'B', 'D', 'C', '5', '9', '3', '8', '9', '0', 'D', '8', 'D', '9', '2', '2', 'C', '8', 'B', '2', '1', 'B', 'F', '7', 'A', '5', '9', '7', 'E', 'F', 'A', '2', 'F', '4', '8', '9', 'B', '7', '3', '5', '9', 'D', 'B', 'E', '4', '4', 'E', '4', 'A', 'D', '2', '5', '6', 'D', '4', '1', '0', '8', '4', 'E', '6', 'F', 'F', '0', '3', '1', 'F', '6', '7', '8', '0', '2', '1', '8', '1', 'A', 'C', 'D', '8', 'A', '5', '2', '2', 'C', '8', '6', 'B', 'C', '4', '1', '0', '0', 'B', '7', '4', '7', '8', '9', 'F', 'C', '0', '4', 'A', 'E', '9', '6', '2', 'D', 'F', '0', '2', '7', '5', 'F', '3', '7', '7', '7', '4', 'C', '7', 'D', '9', '3', '0', 'C', '7', '5', 'B', 'C', 'A', 'A', 'D', '6', '3', '7', '7', 'F', '7', 'E', 'C', 'C', '1', '2', 'E', '9', 'B', 'F', '6', '4', '4', '2', 'A', 'A', 'D', '8', '0', '2', '1', '0', '1', '5', 'D', '9', '0', '8', 'B', '9', 'B', 'C', '3', 'D', 'C', 'E', 'E', '3', 'C', '3', 'B', 'C', '5', '2', '8', '8', '6', 'F', '5', '9', '0', '9', 'F', '4', '1', 'E', '2', 'B', '2', '2', '2', '4', '7', 'D', 'B', '9', '1', 'E', 'E', '2', '7', '0', 'E', '7', '3', 'E', 'F', '2', '7', 'A', 'C', '5', '6', '9', '9', '6', 'B', 'D', 'C', 'D', '8', '7', 'C', '9', '1', 'F', '2', 'E', 'F', '2', 'B', 'E', '6', '7', '9', 'F', '4', '0', '7', 'D', '8', '9', 'A', '8', '0', 'B', 'D', '7', '4', 'F', '4', '7', '9', '5', '9', '7', '6', '7', '4', '3', 'E', 'B', 'F', '9', '1', 'C', '5', '2', '1', 'B', '0', '7', '0', '0', '4', 'A', '9', '2', '2', '7', '7', 'B', '1', 'D', '2', '0', '3', 'A', '2', 'C', '7', '4', 'D', '3', '1', '8', '4', '3', '5', 'F', '1', '3', '0', '1', 'C', '7', '9', '0', '6', '9', '7', 'A', '0', 'D', '0', '7', '9', 'B', '4', '6', '3', 'B', '2', '3', '4', '8', 'F', 'C', 'D', '4', '0', 'B', 'E', 'D', '6', 'A', '7', '3', '4', '1', 'A', '0', '7', '2', '0', '1', '9', 'E', '6', '3', 'A', 'E', 'E', '6', '3', 'C', 'F', '8', '1', '9', '8', '0', 'B', '5', '6', '8', 'F', 'B', 'E', '4', '2', '9', '9', 'A', 'C', '6', 'E', '1', '4', '9', '2', '5', '1', '5', '2', 'A', 'A', '6', '9', '2', '7', '1', 'E', '1', '3', '5', 'C', '6', '9', '7', 'A', '6', '4', 'B', 'E', '2', '8', '6', '1', 'C', 'F', '4', '3', '9', 'D', 'C', 'A', 'E', '0', '4', '7', '1', 'A', '4', '0', '9', 'E', '9', 'C', 'B', 'B', '2', '1', '9', 'B', 'A', 'E', '9', '4', 'E', 'D', '8', '2', '0', '0', '6', '2', 'B', '8', '4', '3', '2', '5', '5', '9', 'B', 'D', '6', 'E', '9', '0', 'B', 'E', 'C', '3', 'F', 'D', 'F', '8', '6', 'B', '8', '0', 'F', '7', '6', '5', '2', '7', '8', '7', '3', 'C', 'F', '0', '0', 'C', '7', '8', '9', 'C', 'C', 'E', '1', '7', 'F', 'E', '3', '9', '7', 'F', '9', 'A', '7', '8', '6', '1', '3', 'B', '4', 'A', '3', 'F', '0', 'E', '4', '8', '8', '7', '2', '0', '1', 'F', '0', 'C', '5', '6', '5', '1', 'A', '3', 'A', 'A', 'C', 'F', 'F', '4', '2', 'C', 'E', '8', '0', 'A', 'C', '8', '8', 'B', '4', '4', 'E', '7', 'C', '6', '3', '4', '6', '6', '8', 'A', 'D', '2', '8', '9', 'B', '2', '2', '9', 'A', 'A', '9', '7', 'F', 'C', '2', 'C', 'D', '3', '9', '7', '0', 'F', '9', 'A', 'A', '6', '5', 'D', 'B', '4', '8', '6', '1', '0', 'B', 'B', 'D', '2', 'F', 'B', 'C', '6', '9', '4', '7', '9', '8', 'D', '8', '7', 'F', '8', '5', '2', '6', '9', '8', '3', '5', '8', '3', '9', 'D', '0', '4', '9', '5', 'B', 'B', 'D', '6', '4', '8', 'A', '2', 'E', '8', '8', '1', '4', '3', 'C', 'E', '7', 'C', '2', '4', '4', '7', '9', '0', '9', 'D', '5', '3', '3', '4', '5', '0', 'E', '4', 'C', 'A', '9', '3', '6', 'D', '3', '7', '5', '0', 'C', '6', '6', '7', '0', '7', 'B', 'C', '8', 'B', '0', '4', '3', '8', 'F', '7', 'C', '5', '5', 'A', '3', '7', 'B', '5', '5', '4', 'A', '6', '0', '0', 'D', 'A', 'D', '1', 'D', '7', '0', '9', '5', 'A', 'C', 'F', '0', 'E', '0', '7', '8', '7', 'E', 'D', '8', '9', '3', 'D', 'F', '6', '0', 'D', 'B', 'E', 'C', '4', 'A', 'D', '4', 'F', '1', 'B', '3', '1', '4', '3', '7', 'B', '7', '5', 'C', 'E', '8', '5', 'D', '8', '3', 'F', 'F', '4', 'A', 'A', '1', 'D', 'C', '9', '8', 'B', '7', 'E', '2', '0', '9', '8', 'D', '6', '8', 'B', 'F', 'E', 'B', '7', '5', '1', 'E', '6', 'B', 'B', '1', '1', '5', '8', '3', 'E', 'E', 'F', '2', 'A', '2', '4', '8', '7', 'D', '2', '3', '2', '8', 'C', 'F', 'C', 'B', 'E', '0', 'F', '1', 'F', 'D', 'E', '7', '3', 'A', 'A', '1', '5', '7', '6', '8', '6', '5', '9', 'F', 'C', 'C', '7', 'D', 'C', '7', 'E', 'C', '6', 'C', '2', '5', 'B', '0', 'C', '4', '6', '0', 'F', '8', 'C', 'D', '6', 'B', '6', '8', '2', 'B', '2', 'D', 'E', 'A', '6', 'D', 'F', '8', '9', 'E', 'A', 'D', '4', '3', '5', 'B', 'C', '4', '9', 'E', 'A', 'B', 'F', '3', '0', 'F', 'E', '0', '0', 'B', '2', '1', 'F', '4', 'F', 'B', 'A', 'D', '8', 'A', '2', 'D', 'D', '2', 'E', 'A', 'B', '5', '9', '4', 'D', 'D', '7', '3', 'C', '6', '9', 'F', 'C', '5', '4', '1', '4', '5', '9', '0', '2', 'D', '6', '8', 'C', 'A', 'E', 'D', 'E', 'A', '7', '5', '6', 'F', '4', 'A', '9', '5', '4', '2', '0', '7', '0', 'C', '2', 'A', '4', '6', '6', '7', '3', 'E', 'B', '5', 'C', 'B', '8', '6', '8', '6', 'A', '4', 'D', '6', '5', '8', '0', '5', '6', '3', '6', '0', 'C', '5', 'D', '6', '9', 'D', '9', '6', '1', 'B', '0', '1', '3', '5', '6', 'C', '9', 'C', '3', 'D', '1', 'B', 'B', 'A', 'D', 'A', '4', 'F', 'E', '6', '0', 'C', '8', '1', '5', '4', 'A', 'C', '7', '7', '8', 'C', '3', 'B', '0', '3', 'B', 'D', '6', '9', '2', '5', 'E', '5', 'F', '9', '1', 'E', 'B', '0', 'E', 'E', 'B', 'B', '4', '5', '3', '4', 'E', '4', 'D', '1', '9', '7', '0', '1', 'A', 'D', '1', '9', '1', '3', 'F', 'A', '0', 'A', 'A', 'F', 'A', 'A', 'D', 'D', 'F', 'F', 'C', 'D', '2', '7', 'A', '6', '3', '3', 'D', 'D', 'B', '9', 'E', '1', 'C', '3', '0', '2', 'F', '9', 'C', 'F', '8', '3', '5', 'D', 'C', '4', '0', '3', '8', '3', 'F', '5', 'D', '9', '5', 'F', 'C', '9', 'B', 'B', 'F', '2', 'B', 'B', '8', 'E', 'D', '1', 'C', '8', '5', '8', '3', '5', '8', 'C', '5', 'E', '5', '8', 'F', 'A', '4', '1', '9', '3', '5', '3', 'D', '2', '3', '1', '6', '0', 'D', '5', 'E', '3', '7', '1', '8', 'B', 'F', '9', '9', '8', '7', '8', 'D', 'C', 'C', '0', '1', '4', 'B', '8', '1', 'C', '6', 'F', 'F', 'B', '6', 'C', '3', 'D', '5', '9', 'F', 'C', '9', '7', '4', '9', 'F', '7', '6', 'D', '3', '9', 'B', '5', 'E', '3', '1', '4', '7', '2', 'B', '9', 'F', '8', 'E', '7', '8', '5', '7', 'C', '6', '7', 'D', '9', '3', '3', 'E', '7', 'A', '3', 'D', '0', '8', '1', '0', '3', 'A', 'A', 'E', '4', '4', '3', 'D', '0', '3', '9', 'A', '9', '9', '8', '5', 'F', '1', '8', '0', '6', '4', '9', '1', '6', 'D', 'A', '6', '5', 'D', 'F', 'D', '7', 'B', 'F', 'E', 'D', '3', 'D', 'F', '0', '5', '2', '0', 'D', '2', '4', '7', '2', 'F', '6', '9', 'B', '1', 'C', '2', 'C', '5', 'D', '7', '6', '2', '8', '1', 'F', '4', '0', '7', '8', '1', 'E', 'A', 'C', '3', '8', '8', '3', '6', 'E', 'B', '5', '2', 'D', '2', 'B', 'D', '7', '1', 'D', 'A', '8', 'F', 'A', '7', '1', 'E', 'E', 'A', 'C', '6', '8', '6', '0', '8', 'E', 'F', '0', '6', '5', '8', '2', 'E', '9', '8', '0', '1', '3', 'D', '0', 'A', '3', 'E', 'D', 'B', 'C', '4', 'A', '3', '5', 'A', 'A', 'C', 'F', '5', '1', 'B', '6', 'C', '6', '2', 'E', 'A', 'E', 'C', 'C', 'B', '5', 'F', '8', '7', 'F', '3', '0', 'F', 'E', '0', '2', '1', '0', '5', '7', 'A', 'F', '7', '2', '1', 'E', 'F', 'E', '1', 'B', '0', 'A', '1', '6', '9', '7', '5', '4', '9', 'D', 'F', 'F', '4', '0', '2', '7', '8', '7', 'A', '1', '8', '4', 'E', 'C', 'F', '3', 'C', '7', '9', '5', '3', '5', 'D', 'F', '1', 'A', '2', '1', '0', '4', '1', '3', '9', 'C', '6', '5', 'E', '2', '8', 'A', 'A', '4', '3', 'E', '8', '3', '7', 'D', '8', 'A', 'E', '7', '6', '9', 'A', '1', '2', '9', 'B', '9', '1', '7', 'E', 'E', '5', 'E', 'B', '6', 'B', 'D', 'E', '7', '4', 'F', 'C', '6', 'F', 'B', '4', '1', '1', 'F', 'F', '8', 'D', '2', '8', '8', '0', '8', '2', 'E', '6', '0', '3', 'F', 'C', 'D', 'E', 'A', '2', '0', '9', '2', '0', '4', '5', '4', '5', 'C', 'D', '3', '8', '1', '6', 'C', 'E', 'C', '2', '9', 'D', '8', '5', '5', 'E', 'B', '1', 'A', '1', '6', '7', '9', 'C', '6', '3', '3', '1', '3', 'A', '8', '4', '2', 'B', 'D', 'A', '8', 'C', '3', '2', '5', 'A', 'A', 'B', '9', '6', 'F', '6', '0', 'B', 'D', '7', '8', '2', '5', 'B', '2', '2', '4', '0', '0', '4', '3', 'F', '3', '1', '1', '6', '6', '2', '1', '2', 'E', 'E', '8', '9', 'F', '8', '4', 'B', '9', 'D', 'C', '0', 'F', '1', 'D', 'B', 'D', 'D', 'D', '9', 'F', 'F', 'E', 'E', '2', '4', '7', '2', 'D', '8', 'A', '2', 'A', '8', 'A', '6', '1', 'A', '2', '0', 'B', 'A', '1', 'B', '1', '6', 'B', '7', '4', 'F', 'A', '5', '8', '7', '6', '1', 'E', 'F', 'D', '9', '7', '3', '9', 'C', '2', '4', 'A', '7', 'D', '4', '8', '2', 'D', '4', 'E', 'C', '8', '0', '6', '8', '4', 'A', '1', 'D', '6', 'F', '6', '1', 'A', '7', '6', 'D', '9', 'F', '7', '6', '6', '5', '4', 'A', 'A', '6', '2', 'F', '1', '0', 'D', '0', '2', 'F', '0', '9', '1', '9', '5', '2', 'D', 'D', 'D', '6', 'A', 'F', '4', '8', 'D', 'F', '7', '9', 'D', '3', '9', 'D', 'E', '1', 'D', '3', '6', '2', '1', '6', 'E', 'C', '7', '2', 'F', '8', '2', '0', '7', '3', 'A', '4', 'E', 'A', '4', '6', 'C', '3', '8', '2', 'A', '8', '8', 'A', '4', 'C', '2', 'F', '5', '6', 'F', '6', '1', '0', '7', '6', '7', '5', '4', 'B', '4', 'C', '7', '2', '3', '7', '4', 'C', 'E', '9', '3', 'C', 'E', 'D', '6', 'B', '0', '0', '6', 'F', '1', '2', 'B', 'E', '7', 'E', '7', 'A', '2', 'D', '1', 'E', 'E', '7', 'C', '5', 'B', '1', '0', 'B', 'D', '4', '4', '7', '4', '2', 'C', '1', '3', 'B', 'C', '7', 'C', '6', '1', 'E', '5', 'B', '2', 'B', '5', '6', '2', 'D', 'A', '1', '5', 'E', '3', '3', '1', '6', '7', 'F', '5', '9', '5', '3', '8', 'F', '5', 'E', 'F', '8', '6', 'D', '0', '4', '2', 'D', '1', '7', '1', 'C', 'F', '2', 'F', 'A', '6', '6', 'B', 'E', 'D', '1', '9', '6', '3', 'C', '2', '4', '2', '3', '5', 'A', '5', 'D', '3', '2', 'A', '7', 'D', 'C', '9', '3', '6', '1', 'A', '0', '7', '4', 'D', '1', '1', 'E', '6', '4', 'C', 'E', 'D', '2', '3', '1', '1', '7', '6', 'A', '0', '7', '8', '8', '2', '3', 'D', '4', '6', '3', '7', '8', '2', 'A', 'E', '7', '3', '4', 'C', '6', 'A', 'C', '0', '7', '8', 'C', '1', '8', '5', '0', '1', '0', '8', '1', '0', 'D', '6', '8', '9', '1', '6', '8', 'E', 'B', 'F', '3', 'C', 'F', 'D', '7', '5', 'E', 'B', '3', '0', '6', '2', '3', '5', '7', '5', 'A', '6', '4', 'B', '8', '5', 'C', 'A', 'E', 'D', 'B', 'E', 'C', 'E', 'B', '3', 'A', 'D', 'B', '6', 'F', '9', '0', 'B', '4', 'A', '1', 'F', '8', 'E', 'A', 'A', 'C', '6', 'C', '4', 'E', 'E', '8', '3', '6', '1', 'F', '6', 'C', 'E', '1', '7', 'F', '4', '7', '6', '5', 'F', '1', '7', 'C', '3', 'E', 'C', '0', '4', '2', '8', '3', 'B', '7', 'B', 'D', '0', 'C', 'C', '0', 'C', '2', 'A', '8', '8', '2', 'A', 'D', 'B', '5', 'E', '4', '3', '1', '1', '6', '4', '8', '8', '6', '7', 'C', 'C', 'A', '0', '0', '4', 'F', 'D', '1', 'B', 'F', '8', '2', 'C', '1', 'D', '7', '9', 'A', 'F', '7', '7', 'C', '4', '6', '4', 'A', '3', 'E', '7', '8', 'C', '2', '1', '0', 'B', '0', 'F', 'C', 'B', '2', '2', 'C', '7', 'B', '3', 'A', '8', '3', '4', 'D', '8', '0', '5', '3', '8', '3', 'F', '9', 'E', 'B', 'C', '5', '1', '2', '6', 'D', '9', '2', 'D', 'E', 'B', 'C', '3', '6', 'A', 'D', '7', '7', 'A', '9', 'D', '9', '2', '9', '0', '3', '3', 'E', '7', 'E', '1', '4', 'D', '9', 'E', 'E', '7', 'E', '4', '8', '0', 'D', '6', '2', '1', 'E', 'C', 'C', 'D', '0', 'C', '5', '0', '8', '8', '4', 'F', 'C', 'F', '5', 'D', '3', '8', '7', '4', '9', '2', '3', '4', '5', '2', '2', '8', 'A', 'A', '8', '0', '2', 'E', 'C', 'F', '8', '8', '5', 'A', '9', '6', 'B', '5', 'B', '6', '9', '9', '5', 'A', '4', '4', '7', '4', 'C', '5', '8', '0', '7', '7', 'F', '5', 'A', 'D', '9', '0', 'E', '0', '8', '2', 'F', '0', 'A', '4', '1', '2', 'F', 'E', 'B', '8', '8', '3', 'D', '5', 'D', '4', 'B', 'B', 'D', 'A', '8', 'E', '9', 'D', '6', 'C', 'C', '1', '3', '1', 'D', '7', 'A', 'E', '1', 'B', '2', '4', '3', '0', 'F', 'C', '5', '2', '7', '9', '0', '8', '1', 'D', 'B', 'C', '6', '4', 'F', '9', '8', 'E', '7', '1', '0', '5', 'A', '2', 'B', '8', '3', 'F', '0', '3', '3', 'D', '8', '4', 'A', '5', '5', 'E', 'A', '1', '1', '3', '4', 'E', '4', 'A', '4', 'C', '4', 'B', '6', '2', '7', '8', '8', '2', '7', '9', 'D', 'C', '6', 'E', '1', 'F', '3', '4', 'F', '0', '3', 'D', 'C', '1', '2', '8', '9', '4', '5', '7', '7', 'E', 'C', '4', 'C', 'F', 'C', '7', 'C', '0', '0', 'D', '4', 'B', '7', 'E', 'B', '4', '6', '3', 'D', 'D', '3', 'D', '9', '5', 'E', '2', '3', '5', '7', '8', 'D', '8', 'C', '2', 'C', '6', '1', '4', 'B', 'E', '6', 'A', 'A', '3', 'D', 'A', 'C', '0', 'D', 'A', '3', 'E', 'C', '9', '2', 'C', '1', '9', 'A', '2', 'F', '7', 'E', 'B', '4', 'A', '7', '4', '7', '2', '4', '5', '5', 'C', 'D', 'A', '1', '4', '4', 'F', '0', '6', 'E', 'E', '3', 'D', 'D', 'F', '2', '0', '6', '0', '8', '4', '8', '6', '6', '1', 'C', '0', 'C', 'B', '7', '3', 'F', 'A', '3', '9', '1', '2', '1', 'A', '6', 'E', '7', '8', 'B', '6', '3', '6', 'D', '2', '4', '4', '3', '3', 'B', 'A', 'C', 'C', 'A', '2', '7', 'E', '6', '7', 'B', '2', 'A', '0', '3', '1', '7', 'A', 'F', '5', 'E', 'E', '7', 'A', 'E', 'A', '6', '1', 'E', '8', 'E', '2', 'F', '4', 'D', '1', 'D', 'B', '6', 'D', '3', '6', 'D', '1', 'E', '9', '0', '3', '3', '9', '8', '2', 'C', '9', '1', '5', '9', 'D', '7', 'B', '5', 'F', 'F', '4', '9', '3', 'E', '4', '1', 'D', '0', '4', 'B', '6', '4', '1', '2', 'D', '3', '7', 'F', '9', '7', 'F', 'C', '7', '6', 'D', 'C', '4', 'C', 'D', 'B', '7', '1', 'F', 'E', '1', '7', '2', 'C', 'C', '1', '2', 'B', 'D', '2', '4', 'D', '3', '9', 'B', '6', 'D', '7', '6', '6', '9', '1', '0', '0', 'B', 'C', '3', '3', 'B', '8', '5', 'C', '5', '1', 'D', 'B', '6', 'D', '7', '6', 'E', '2', 'A', 'A', '6', '0', 'B', 'F', '0', '4', 'E', '1', 'D', '0', 'D', '5', '8', '8', 'A', '7', '9', '6', '4', '1', 'D', 'B', 'C', '4', '7', '8', '7', 'B', '3', '0', '5', 'B', 'E', '9', '0', 'E', '6', '1', '8', '1', '6', '5', 'E', '1', 'E', '3', '8', 'C', '6', 'F', '4', 'E', '3', '6', 'C', '4', 'A', '0', '9', 'E', 'C', 'A', 'B', '8', 'E', 'B', 'B', '7', 'C', 'E', '0', '1', '0', '0', '9', '5', '5', 'D', '6', '4', '4', '9', '2', 'D', '4', '1', '2', '0', '8', '1', 'D', '8', '6', '3', 'B', '3', '4', '5', '5', '0', 'E', 'B', '7', '5', 'E', 'C', 'D', '1', '1', '2', '1', 'F', 'A', 'F', 'D', '5', 'B', '0', '2', '8', 'B', '1', '6', '9', 'C', 'A', 'D', '4', '9', '4', 'D', 'D', 'C', 'C', '3', '7', '8', '9', '0', 'A', '6', 'E', '2', 'F', '6', '9', '1', 'E', 'E', '1', '8', '5', '6', 'D', '3', 'D', 'E', '6', '2', '6', '9', '0', 'A', '7', 'C', '3', '8', '8', '8', '5', '4', '5', '6', 'F', '9', '0', 'C', '5', '6', '4', '1', '1', '8', '7', 'A', '3', 'F', '5', '9', 'F', '6', '2', '3', '5', '1', '6', '5', '7', 'F', '4', '1', '7', '5', '2', 'A', 'D', '2', 'D', '5', 'E', '4', 'B', '1', '5', 'E', '1', 'A', 'E', 'D', '8', 'F', '1', '5', '2', 'B', '7', '1', '5', 'D', '9', '5', 'A', '1', '5', '0', '6', '8', '9', 'A', '3', '7', '5', '9', '8', '4', '8', '9', '8', 'D', '3', '8', '5', 'D', '9', '6', '1', '5', '4', 'E', '9', '4', '3', '9', '2', 'F', 'E', '3', 'E', 'F', '2', '9', '9', '3', 'B', 'D', '4', '6', 'B', '1', 'E', 'E', 'B', 'E', '3', '6', 'A', '5', '6', '8', 'D', '9', '2', 'D', 'A', 'C', 'C', 'C', '7', 'C', '1', '4', 'B', 'E', '1', '1', 'C', '9', '1', '7', 'D', '4', 'D', '9', 'C', '4', 'F', '4', '1', '7', '6', '5', 'A', '5', '3', '2', '8', '1', '6', '9', 'A', '2', 'E', '0', '6', '7', '2', 'F', '9', '5', '9', '0', '8', 'D', '0', 'A', '9', 'A', 'D', '5', '4', '3', '9', 'C', '4', 'B', 'A', '8', 'C', '8', 'E', '4', '3', '9', 'D', '9', '0', '7', 'B', '0', '1', 'B', 'B', '0', '0', '1', '3', '4', '8', '1', '3', '6', '7', '8', '9', 'A', 'A', '3', '4', '5', '2', '9', '1', '2', 'D', '1', '1', 'E', '1', 'A', 'B', '3', 'D', '2', '8', '9', 'A', '8', 'E', 'E', 'B', '0', '1', 'A', 'F', '2', 'F', '5', 'A', '8', '3', '0', 'A', '1', '2', 'B', 'C', 'D', 'B', 'C', '6', '6', 'F', '0', '0', '5', '5', 'E', '9', '0', '6', 'E', '0', 'E', '6', '3', '1', '3', '3', 'A', 'F', '3', '9', 'A', 'C', 'B', '1', 'B', '0', '7', 'F', 'A', 'A', 'F', '9', '6', '6', '9', '5', 'C', '0', '0', '9', 'B', '7', '2', '8', '2', 'D', 'D', 'E', 'F', '2', '4', '3', '2', '8', '8', '1', '2', 'E', 'A', 'A', 'A', 'D', '3', 'C', 'C', '1', 'E', 'D', '6', 'D', 'F', '1', 'A', 'C', 'F', '6', 'F', 'D', '3', '7', '7', '8', 'C', 'B', 'B', '4', '1', 'F', 'E', '3', '5', '9', '5', 'A', '2', '9', '9', '4', '7', '6', 'C', 'B', '1', 'E', '6', '5', '6', '5', '6', 'E', '4', 'A', 'E', '4', 'E', 'C', '7', 'A', '1', '1', '2', 'C', '4', 'C', '9', '4', '0', '9', '2', '3', '6', '2', '2', 'C', '9', '4', '9', '8', 'E', '7', 'B', '2', '1', '8', 'D', '7', '8', 'F', '6', 'F', '4', 'F', '3', '9', 'B', 'D', '2', '7', 'A', 'B', '6', 'E', '0', '9', 'B', 'F', '3', '8', '1', 'C', 'A', '9', '6', 'C', '6', '6', 'A', '8', 'F', '0', 'C', '8', 'F', '0', '4', '7', 'E', '0', 'D', 'F', 'D', 'F', '1', 'A', 'D', 'A', 'D', 'D', 'C', '7', '7', 'B', '2', '1', 'D', '1', '5', 'E', '8', '3', '9', '2', '3', '3', 'F', '8', '5', '2', '3', '9', '9', 'D', '1', '5', 'F', '9', 'C', 'E', '6', 'D', '3', '3', '8', '3', '4', '4', 'C', 'A', 'D', '4', '3', 'A', '5', '9', '1', '1', '2', '2', 'C', '4', '8', '8', 'B', '2', '2', '2', '0', 'A', '3', '4', 'D', '8', '2', '1', '5', 'C', '3', 'F', '4', '4', 'A', '7', '0', 'E', '1', '2', '4', '9', '6', '9', 'F', '8', '1', '6', '7', '5', 'B', 'F', '0', '1', '0', '5', '8', '7', '7', '9', '0', '3', '3', 'F', '2', '3', 'D', 'B', 'E', '9', '6', '7', 'B', 'F', '2', 'A', 'E', 'E', 'F', '2', 'B', 'C', '1', 'F', 'F', '9', '7', 'A', 'F', 'E', '5', '7', '5', '7', 'C', '0', '9', 'E', 'F', '0', 'B', '3', '3', 'F', '7', '2', 'E', '2', '6', '0', 'C', '5', 'C', '5', '7', '2', 'B', '6', 'A', '8', '7', '1', '8', 'A', '1', '6', '3', 'A', 'D', 'C', '5', '0', 'E', 'E', '7', 'E', '2', '1', '0', '8', '9', '7', 'F', '6', '6', '3', '7', 'F', 'D', '2', 'C', 'E', 'F', '8', '7', '2', '1', '3', '8', '3', '5', 'C', '1', 'D', '6', 'D', 'C', '4', 'D', '5', '1', '3', 'F', 'B', '2', '4', '0', '0', '0', 'B', '6', '4', 'B', 'D', '2', 'D', 'F', 'D', '0', '3', 'F', 'C', 'F', '3', 'E', 'C', '9', '1', '6', '8', '6', '8', 'B', 'E', '1', '2', 'D', '8', '5', '7', 'C', '9', 'D', '4', '2', 'E', '5', 'E', '5', '7', '1', '7', 'E', '5', 'B', '0', '3', '5', 'C', 'E', '1', 'B', '9', 'D', '0', 'B', '9', 'B', '5', '5', 'A', '5', 'B', '7', 'A', '3', '6', '3', '1', 'A', 'E', '9', 'E', 'F', '9', '1', '0', '1', 'A', '2', '5', '4', 'F', '4', '0', 'D', '7', '7', 'A', '8', '4', 'D', '3', 'D', '4', '7', '5', '9', 'D', '3', 'E', '5', '1', '0', '2', '7', 'E', 'A', '8', '1', '8', '3', 'A', '5', 'D', 'D', 'C', '4', 'F', '7', '9', 'F', '8', '0', '2', '2', 'A', '1', 'E', 'F', '6', '2', 'A', '4', '8', '3', '4', '2', 'B', '6', '3', '0', 'D', '5', '1', '7', 'D', '0', 'E', 'F', '4', '5', '5', 'D', '8', 'C', 'E', '9', '9', '8', '0', 'F', '1', 'A', '8', 'B', '6', '5', '7', 'A', 'A', 'C', 'B', '0', '6', 'C', '9', '0', 'B', 'E', 'A', 'A', 'E', '9', '5', 'C', '0', '8', '4', '2', 'E', '6', '9', '3', '0', 'A', '6', '5', '7', '8', 'E', '7', 'D', '3', '5', '2', '1', '8', '3', 'E', '9', '2', 'C', '2', 'B', '8', 'C', '4', '3', '6', 'B', 'D', 'D', 'C', '2', '5', '3', 'C', 'F', '4', '7', 'E', '9', 'F', '1', '3', '7', '7', '0', 'E', '8', '0', 'E', '1', 'B', 'E', '9', '6', '5', '3', '8', '2', 'D', '7', 'B', '7', 'A', '3', '9', 'C', 'B', 'D', 'E', '6', 'F', '2', '4', 'C', '3', '1', '4', '9', '5', '4', 'E', 'E', 'B', '1', '6', '5', '8', '3', 'D', '4', '4', '9', 'A', '7', '8', '1', '8', '4', 'A', 'C', '8', 'C', 'C', 'F', '8', '5', '4', 'F', '1', '8', '4', '5', 'C', 'E', '1', 'D', 'D', 'F', 'C', 'C', '8', '5', '4', 'E', '9', 'F', '7', '7', 'E', '0', 'B', 'C', '9', 'C', 'A', 'B', '5', '6', '2', 'A', 'A', 'E', '0', '8', '4', 'D', '7', 'C', '7', '9', '3', 'F', '2', '3', '7', 'F', '6', '8', '5', 'B', 'D', '4', 'B', 'A', 'D', '2', 'F', '6', 'C', '1', '3', '8', 'A', '1', 'E', '0', 'E', '8', 'C', 'B', '4', 'D', 'F', '7', '3', '8', '4', '1', '9', '8', '4', 'F', 'D', '8', '5', 'C', '2', 'C', '6', '9', 'B', '2', '9', 'E', 'A', '8', '3', '1', 'E', '6', '3', '3', '7', '6', 'F', '6', '0', '8', '5', '6', '0', 'B', 'E', '7', 'C', 'A', 'E', 'A', 'A', '2', 'F', '2', '7', '3', '9', 'C', 'A', '9', 'D', '0', 'C', '7', 'B', '8', 'E', '0', '5', 'A', 'F', 'E', '8', '8', '3', '9', '1', '0', '4', 'D', '9', 'F', '7', '0', 'B', '0', 'C', '2', '9', '0', 'A', '0', '5', '9', '9', 'B', '2', 'F', 'D', 'D', '8', 'E', 'B', 'C', '1', '6', 'C', '0', '4', 'B', '6', '4', '4', 'F', '5', '1', 'E', '6', '1', '0', 'B', '2', 'F', '6', '8', '1', '2', 'F', '7', '1', '5', '1', '4', 'F', '0', 'B', 'C', 'C', '8', 'B', '6', 'E', 'F', 'D', '6', '2', 'D', '8', 'A', '2', '6', '2', '6', 'E', 'A', 'A', 'A', '8', 'A', '4', '5', '2', 'D', '8', 'B', 'E', '8', 'E', 'F', '0', '1', 'B', '6', '0', 'E', '1', '0', 'B', 'F', '4', '9', 'B', 'B', 'D', '2', '5', '1', 'F', '0', '6', '3', '4', '5', '1', 'A', 'D', '6', 'A', 'D', 'A', '3', 'D', '4', '6', 'F', '9', '1', '0', '9', '6', '6', '6', '1', 'D', '2', 'D', '6', 'F', 'B', '8', '2', '4', 'B', '0', 'F', '2', '1', '4', '5', '0', '3', '9', '4', 'A', '8', '1', 'D', '5', 'C', 'B', '5', 'C', '8', 'D', '6', '1', 'A', 'B', '1', '3', '0', '6', '1', 'C', '2', '0', '7', 'E', '7', '7', '9', '1', '7', 'F', '6', '0', '0', '0', '2', 'D', 'E', '9', '7', '4', 'B', '2', '3', '3', 'F', '9', '4', '5', '2', 'C', 'F', '9', '5', '0', '3', '0', '6', 'A', 'D', 'E', '4', '2', 'D', '8', 'B', 'A', '9', '5', '6', '2', '2', 'E', '9', 'A', '4', '6', '0', '6', '6', '3', '7', '7', 'D', '8', '2', 'D', '2', 'A', 'E', 'E', 'F', 'D', '6', 'C', '6', '6', 'B', 'F', '2', '8', '0', 'D', 'F', '5', '8', '3', 'E', '4', 'E', 'F', 'D', '4', 'D', 'A', 'F', 'C', 'C', 'D', 'E', '2', 'F', 'D', '6', '2', 'E', '6', '4', 'B', 'B', '2', 'C', 'F', '2', '8', 'F', '6', '9', 'F', '3', 'A', '1', '8', '8', 'D', '0', 'C', 'D', 'F', 'C', '0', '2', '9', '1', 'C', 'D', 'C', 'B', 'B', '8', '4', 'F', 'F', 'B', 'C', '0', 'D', 'A', '0', '7', 'E', '8', '9', '3', 'B', '2', '1', 'E', 'E', 'F', 'D', '8', '0', '6', 'B', 'A', '2', '6', 'C', 'E', 'A', 'A', 'A', '5', '1', '2', 'D', '3', 'C', '0', 'C', '8', 'E', '1', '2', '5', 'C', '3', 'D', 'B', 'B', 'C', '9', '9', '0', 'A', 'F', 'E', '7', '9', '2', 'F', '0', '8', 'C', '6', 'D', 'F', 'D', '1', 'F', '3', '3', '2', '6', '6', '3', '9', '0', 'E', '3', 'B', 'E', '3', '9', '3', '7', '0', 'A', '1', '3', '1', 'F', '2', 'E', 'E', 'D', 'F', 'B', '7', '2', '5', '3', 'C', 'A', 'B', 'D', 'E', '5', '5', '3', '7', 'A', '9', '9', 'D', '2', '3', '8', 'E', '4', 'B', '9', '6', '6', '1', 'F', 'A', 'F', '7', '6', 'D', '0', '8', '8', '8', 'D', 'A', 'E', 'B', 'F', '3', '1', '2', 'F', '4', '4', '9', '3', '0', '9', 'E', '2', 'E', '8', '8', 'E', '4', '5', '7', '8', '2', '6', '2', '2', '2', '1', 'A', '4', '5', '8', '6', '4', '0', '1', 'C', 'D', '8', '2', '3', '8', '8', '0', '4', '8', '3', 'F', '9', '4', 'A', '8', '4', '7', 'A', 'E', '1', '9', 'A', 'E', '7', '8', 'A', '6', '2', 'B', '8', '3', '1', 'F', 'D', 'D', '7', '1', 'B', '1', '4', 'B', 'C', 'C', '2', '2', '3', '4', '5', '1', '5', 'C', '2', '1', '8', '9', 'E', 'F', '8', '0', 'A', '0', '6', '1', 'B', '9', 'D', '6', '5', '6', 'F', '3', 'E', '6', '0', '5', '8', 'B', '1', '7', '8', '7', '4', '1', '1', '2', '6', '9', 'C', '5', '1', 'C', '3', '8', '0', '3', '1', '8', '9', '3', 'A', 'D', 'F', '5', 'C', '7', '1', '6', '8', '2', '4', 'E', 'E', '4', 'E', 'F', '3', 'E', '5', '6', '0', 'B', '5', '6', 'B', 'B', 'D', '0', '1', 'C', '2', 'A', '4', 'C', 'D', '1', 'D', '0', 'E', 'B', 'E', 'A', 'F', '3', '4', '6', '0', 'E', '0', 'B', 'E', '0', '9', '4', 'F', 'E', '5', '9', '2', '6', '7', '4', 'F', '5', 'D', '8', '8', 'B', 'D', '7', '9', '2', '1', '5', '5', '7', 'A', 'C', 'C', 'B', 'C', '8', 'A', '3', '8', 'E', '2', 'D', '9', '7', '3', '1', '3', '2', 'F', 'A', 'E', '8', '9', 'D', 'D', '9', '7', 'F', 'A', 'B', 'C', '0', 'A', '3', '6', 'B', '5', '1', 'D', '5', '5', '1', 'B', '6', 'B', '9', '2', '0', 'E', '6', '6', '3', '1', 'B', '4', '6', '9', '5', '8', '2', 'C', 'D', '3', 'B', 'B', '7', 'A', '2', 'C', 'F', '2', '1', '3', '5', '6', '0', 'D', '3', '5', '2', '2', '1', 'A', '5', 'C', '1', 'E', 'A', '0', '8', '8', 'A', '3', 'F', 'D', '6', '2', '9', '2', 'F', '7', 'D', 'E', '3', '3', '9', '2', '8', '5', 'D', 'A', '2', '8', '5', '8', 'C', '7', '5', 'A', '9', '3', '9', 'A', '8', '0', '7', '7', '3', 'F', 'F', '6', '6', '0', '4', '5', '1', 'F', 'E', 'A', '7', '2', 'F', '4', '9', '1', '2', '2', '9', '6', '8', 'A', 'E', '3', '7', '3', 'B', '0', 'B', '2', '3', '2', '6', '0', '9', '1', '3', 'F', '4', '0', 'E', '8', '8', '8', '9', 'E', '9', 'E', '0', '9', '7', '7', '5', '4', 'D', '1', 'D', 'D', '7', '4', '2', '2', '3', 'E', '2', 'F', '4', '9', 'B', '9', 'D', '1', 'B', 'C', 'E', '2', 'B', '1', '5', '1', '9', '0', '8', '4', '5', '2', '5', 'C', '2', '5', 'E', '8', 'B', '8', 'D', '1', '9', 'A', 'A', 'B', '3', '4', 'B', '0', '2', 'C', '2', '3', '2', 'A', '0', 'D', '3', 'D', '9', '3', '0', 'B', 'F', '1', 'E', '0', 'B', '4', '3', '4', '9', '1', '2', 'A', '8', 'D', '3', '5', 'B', 'C', '6', '6', 'D', 'A', '5', '2', '7', '4', 'D', 'D', '6', 'B', 'C', '5', 'E', 'E', '3', '5', '3', '8', '8', '9', 'E', '0', 'D', '7', '5', '3', 'D', 'D', '1', 'C', '6', '9', '8', '2', '1', '3', '9', 'A', '6', 'E', 'F', '1', 'E', 'E', '2', '1', '2', '0', '1', 'A', 'B', 'F', '7', 'B', '0', '4', '5', '9', '4', 'F', '8', '0', '2', 'D', 'C', '6', '2', '2', '8', 'B', 'B', 'A', '7', '8', '0', 'F', '1', '2', 'E', 'A', '9', '2', '9', '9', 'A', '6', 'F', 'D', 'A', '4', 'A', '9', '1', '9', '2', 'F', 'B', '0', '5', '3', '0', '3', '7', '4', '2', '0', '8', '6', '1', 'F', 'D', '0', '8', '9', 'E', '6', 'A', 'F', 'F', '1', 'A', '0', 'A', 'E', 'F', 'E', '5', '0', '6', '8', '7', '3', '9', '7', 'E', '1', '4', '8', '9', 'F', '4', '3', '7', '7', '7', '6', 'C', '4', '7', '9', '0', 'C', 'E', '4', '0', '3', '2', '1', 'B', '7', '3', '7', '2', '7', 'F', '0', '9', '9', '6', 'C', '7', '9', 'F', 'E', '0', '3', '8', 'F', '0', 'D', '8', '2', '4', 'E', 'D', '1', 'A', '6', '8', 'C', '5', 'E', '3', 'F', '1', '4', '0', '5', '4', 'D', 'D', '7', 'E', 'F', '9', 'D', '6', '0', 'E', '8', 'A', 'D', 'B', 'E', '1', 'B', 'F', '4', '0', '7', 'E', '6', 'F', '6', 'C', '8', '5', '4', 'C', '5', 'D', 'A', '8', '6', '6', '4', '1', '0', '2', '3', 'D', '0', '2', '6', '0', 'A', '5', '8', 'B', '4', 'D', '8', '8', '6', '5', 'C', '3', '8', 'C', 'B', 'B', 'C', '1', '4', 'E', '9', '8', '4', '9', 'D', 'B', 'A', '3', 'F', 'F', 'E', '2', 'F', '8', '2', '0', '7', 'A', '2', 'E', 'E', 'E', '5', '2', '6', '7', '9', '6', '8', '5', 'B', '6', 'F', 'D', 'E', '9', 'B', '9', 'B', '7', 'B', '1', '5', '7', '4', '1', '5', 'D', '3', '7', '2', 'C', 'C', '8', '3', 'C', '1', '7', '1', '0', '4', 'B', 'F', '7', '7', 'B', '3', 'D', 'D', '2', 'D', '3', '3', 'B', 'F', '2', 'C', 'F', 'F', '1', 'A', 'B', 'B', '5', 'F', '9', '7', '7', '2', '0', 'C', '2', '6', '5', '8', 'B', '6', 'B', '2', 'F', '2', '6', 'C', 'F', '0', '7', '0', '9', '8', '9', 'C', '5', '0', 'F', '6', '6', '3', '1', '3', 'B', 'C', 'E', 'A', '9', '0', 'A', '2', 'B', '0', 'F', 'E', 'F', 'B', '3', 'B', '7', '1', '1', 'A', '1', '2', 'F', 'A', '9', '1', 'C', 'F', 'F', '6', '2', 'F', '3', '7', 'A', 'B', 'C', '3', 'F', '7', '4', '5', '6', 'C', '2', '7', '1', 'A', 'E', 'D', '8', 'A', 'F', '7', '2', '8', '1', 'D', '5', '4', '5', 'C', '1', '4', '6', '3', 'F', '5', 'A', 'D', 'B', 'B', 'F', '6', '3', 'A', 'C', '4', 'C', 'B', '5', '1', '9', '1', 'F', '1', 'A', '2', '3', '9', '2', '6', '3', 'E', '0', '9', 'F', '3', '7', 'A', '6', 'D', '7', '9', 'B', '9', 'A', 'E', 'B', 'D', 'B', 'C', 'C', '8', 'D', 'E', '1', '2', '7', '3', 'D', 'D', '8', '4', 'A', '3', '7', '9', '5', '7', 'D', '6', '2', '5', '9', '3', 'B', '4', '6', '6', '9', '1', '1', 'F', 'A', '7', 'B', '0', '8', 'C', '0', 'D', '8', 'A', 'F', 'C', 'C', 'D', 'C', '6', 'E', '9', 'E', '4', '8', '1', '1', 'D', '4', '1', 'A', '0', '7', '1', '4', '9', '3', 'C', '9', 'E', '7', 'A', '8', '3', '9', 'A', 'D', '5', '7', '5', 'E', 'D', '3', 'F', '2', 'E', '2', '4', '0', '3', '4', '6', '1', '5', '7', 'C', '9', 'B', 'C', '9', '3', '9', '5', '7', 'D', 'E', '6', '0', 'F', '8', 'E', 'D', 'E', '4', '3', '0', 'B', 'A', '0', '0', 'E', '9', '3', '6', 'E', '7', '2', '1', 'D', 'F', '9', '7', '0', 'A', 'E', 'A', 'D', '7', 'A', 'D', '7', '9', 'D', 'E', '3', 'D', '7', 'B', '5', 'E', '5', '5', '8', 'E', '5', 'D', '0', 'C', '1', '3', 'B', '0', 'C', '0', '3', '3', 'E', 'C', 'B', '6', 'B', 'E', '2', 'C', '7', 'E', '7', 'D', '6', '3', 'D', 'C', '0', '9', '6', 'F', '5', 'B', 'C', 'D', '5', 'B', 'F', '8', '2', 'D', 'B', 'D', '0', '3', '4', '3', '7', 'A', '5', '1', '9', 'D', '7', '7', '4', 'A', 'C', '5', 'B', 'B', '9', 'A', 'D', '7', 'E', 'D', '4', '5', 'B', '4', '1', '3', 'F', '6', '7', '5', '7', '8', '5', '2', '6', '6', '3', 'A', '1', '6', 'D', '0', '1', 'D', 'E', '2', '3', 'D', '5', 'B', 'A', '6', 'D', '9', '8', '4', 'A', '9', 'B', '6', 'F', '2', 'F', 'A', '5', '4', '7', '2', 'D', 'A', 'D', '3', '8', '6', '2', 'F', '1', 'B', 'F', 'D', '7', '6', '4', 'E', '6', '9', '1', 'E', '7', '9', '4', 'C', 'A', '6', '0', '1', '9', 'C', '9', '4', 'B', '9', 'A', '0', 'D', 'F', '0', '8', 'B', '9', 'D', 'C', '6', '8', '6', '1', 'D', '4', 'C', 'F', 'D', '0', '8', '0', '2', 'A', 'E', 'C', '4', 'E', 'C', '9', 'D', '2', '2', '4', 'B', 'C', 'C', '2', 'C', 'F', '4', '8', 'E', 'B', '3', '6', '0', '7', '4', '0', '0', 'E', 'D', 'F', '2', 'A', 'D', '3', 'C', 'A', '8', '7', 'F', '0', '4', '9', '5', '5', '6', '3', '8', 'F', '1', '3', '4', '9', '5', '1', 'F', 'F', '0', '9', 'E', '7', '7', 'A', 'E', '1', '9', '4', '2', '0', '2', 'E', '2', 'A', '8', 'F', 'F', '5', 'D', '0', '1', '3', '0', '0', '6', 'C', '4', 'C', 'F', '6', '0', 'E', '3', 'E', '8', '9', '7', '6', '3', 'D', '5', '8', 'D', '4', '3', '4', '0', '4', '6', 'D', '1', '3', 'C', '2', '5', 'C', '0', '2', '8', '4', '9', 'E', '2', 'E', '8', 'E', 'A', '3', 'D', '3', 'F', 'F', '4', '5', 'F', '5', '0', '4', '2', 'D', '1', 'A', '6', '5', 'E', 'E', 'D', '0', 'F', '9', 'C', '7', 'A', 'D', 'D', '9', '0', '2', '6', '6', '6', '2', '2', '3', '4', '7', '8', 'F', 'A', 'B', '9', '3', 'D', '1', 'C', '4', '6', '3', 'C', '6', '7', '4', 'A', '2', '2', 'D', '2', '5', 'E', 'F', '7', 'D', '4', 'C', 'A', 'E', '4', '4', '1', 'F', 'C', 'A', '5', '8', '5', '2', 'E', '8', 'C', 'B', '9', 'E', '7', 'A', '7', '4', 'F', 'A', '9', '7', '9', '0', 'B', '6', '0', 'D', 'A', '7', 'F', 'B', 'D', '5', 'E', 'E', '7', '1', '4', 'C', '2', '5', '5', 'F', 'C', 'B', '8', '9', '9', 'C', '3', '4', '1', '1', '5', '9', '1', '0', '7', 'F', '2', '9', 'F', 'A', '8', '7', 'D', '5', 'B', '0', 'E', '1', 'D', 'E', 'B', '4', '9', '5', 'F', '5', '2', '2', 'C', '3', '4', '6', 'A', '9', 'A', '1', 'F', '1', 'C', 'C', 'B', 'F', '9', '2', 'E', '7', '1', 'A', '9', '2', '6', '8', 'E', '0', '7', '6', '7', '7', '2', 'B', 'C', 'F', '5', 'E', '0', '3', 'D', 'A', '4', '0', 'F', 'F', 'F', '8', '7', 'F', '8', 'F', '1', '8', '1', 'D', '1', '3', 'F', '6', '6', 'F', '3', '2', 'E', 'D', '8', '8', '1', '9', '1', 'B', '0', '0', 'F', '6', 'E', 'E', 'C', '5', '8', '5', '9', 'B', 'F', '1', 'F', '5', 'A', '3', '8', 'F', 'C', 'C', 'B', '2', '0', '7', 'C', 'D', '7', '6', '0', 'A', 'B', 'F', '5', '7', '8', '3', '0', 'D', '7', 'E', '1', '6', '6', 'A', '9', 'C', '5', 'C', 'C', '2', '2', '3', '9', '9', 'C', '2', 'C', '2', 'E', 'A', '7', 'C', '6', 'C', 'E', 'F', 'E', '7', 'F', '7', 'F', '2', 'E', 'E', 'E', '5', '5', 'A', '5', 'D', 'B', '5', '0', 'F', '7', '1', '7', '3', 'C', 'A', '2', '9', '6', '5', '5', 'B', '7', 'A', 'F', '0', '7', '1', 'B', '1', 'D', 'D', '6', '0', 'E', '2', 'D', '1', 'B', '3', '2', '4', 'F', 'E', '5', '4', '9', 'D', 'A', '0', '9', '9', '3', '1', 'C', '7', 'C', '9', 'A', '9', 'D', 'D', '5', '1', '2', '6', 'B', '7', 'D', '7', '7', '3', 'C', 'C', '9', '9', '4', '3', 'E', 'C', '4', '0', '5', '2', 'B', 'C', 'E', '5', 'D', '3', 'C', 'B', '6', 'E', '7', '1', '7', 'D', '3', 'F', '6', 'A', '3', '9', 'C', 'A', 'F', '2', '5', 'E', '6', 'F', '2', 'D', '8', '0', '1', '2', '9', '0', 'B', '8', '5', 'D', '6', '4', '9', '8', 'A', '7', '4', '2', '1', '9', '3', '0', '0', 'D', '0', 'A', '0', '4', '1', '3', '3', 'F', 'B', 'C', '2', 'B', 'A', 'C', 'E', '4', '9', 'D', 'C', '2', '5', '1', '7', '4', '6', 'C', 'A', '2', '4', '0', '9', '0', '8', 'C', '3', '2', 'F', '3', '3', '5', '4', '7', '2', '1', '3', 'C', 'F', 'A', 'F', 'C', '5', '3', '4', 'D', '9', 'F', '2', '1', '6', '6', '6', '0', '0', '5', '2', '0', '2', '8', '1', '0', '3', '8', '7', '9', '2', 'A', '4', 'B', 'F', 'D', '4', 'C', 'F', '4', '2', 'D', '5', 'F', '2', 'A', 'C', '9', '3', '2', '5', '7', '2', '2', '3', '9', 'A', '2', '5', 'B', 'D', 'E', 'C', '8', '2', '7', '3', '9', 'C', 'B', 'B', 'C', 'C', 'A', '8', '3', 'F', '2', 'C', 'C', '9', 'A', '7', 'C', 'F', 'A', '4', '6', '9', 'F', '8', '4', 'F', '5', '0', '1', '6', 'C', '5', '2', 'E', '3', '8', '5', 'A', '6', 'A', '2', 'E', 'C', '7', '1', '4', '6', '9', 'C', '5', '5', '8', 'D', '1', 'A', '8', '7', '1', '4', '1', '0', '5', '5', '8', 'E', '3', 'A', '4', '2', '0', '8', 'F', 'A', 'C', 'D', '8', '0', 'F', 'E', '8', '8', '0', '9', '2', 'B', '5', 'A', 'C', 'F', 'B', 'A', 'D', 'B', 'A', 'C', 'A', '8', '5', '5', '7', '2', '0', 'E', '2', 'E', '8', '2', '7', '2', '2', 'D', 'C', '7', '3', 'F', 'A', '5', '5', 'D', '4', '4', 'E', '2', '5', 'F', '3', 'A', 'B', 'D', '4', '5', '6', 'C', '1', 'D', 'E', '8', 'F', 'F', '8', 'B', '6', 'F', 'B', '9', 'B', '8', '9', 'A', '5', '6', '2', 'C', '0', '5', 'C', 'D', '0', 'B', '3', 'A', '8', '6', '3', '9', 'A', '2', 'B', 'F', 'C', 'C', 'A', '7', '8', '0', '0', '7', '4', '6', '9', 'A', '3', 'F', '1', '0', '8', 'E', '4', 'A', '1', '7', '2', '8', 'D', 'A', '7', '1', 'C', 'A', '3', 'F', '6', 'A', 'E', 'F', 'D', '2', 'A', '8', 'B', 'B', '0', '8', '6', '9', '1', 'E', '6', '9', '7', '8', '2', '0', '6', 'C', '8', 'E', 'E', 'B', '2', '3', '6', '0', '3', '2', 'B', '9', '8', '3', 'F', 'E', '1', 'C', '6', '0', 'D', '7', 'F', '1', '2', '4', '7', '2', '3', 'A', '5', '8', 'C', 'E', 'F', '0', '9', '7', '0', 'E', 'B', '9', '4', '5', '8', '6', '1', '1', 'E', '9', '9', '4', 'A', '7', '0', '5', '9', '3', '5', '6', '2', 'D', '1', '4', 'A', 'C', '2', '1', 'F', '0', '3', '8', 'B', 'A', '3', '3', '1', '8', '5', '8', '3', 'C', '1', 'D', 'F', '8', '2', '0', '8', 'F', '8', '3', 'C', 'F', '7', 'D', '5', 'F', 'E', '1', '2', '1', 'B', '7', '8', '4', 'F', '0', '0', '8', 'E', 'B', '6', 'C', 'D', '6', 'A', 'C', 'F', '7', 'B', '1', '0', '7', '2', '5', '1', '5', '9', 'B', 'D', '0', '5', '5', 'E', '1', 'C', '4', '2', 'B', '0', '1', '4', '1', '4', 'C', '1', '8', 'F', '7', 'A', 'B', '1', '7', '4', '5', '0', '6', '1', '9', 'D', '8', '7', '5', '4', 'C', '3', 'A', 'A', 'D', '5', '8', '5', '9', 'D', 'A', '5', '6', '3', 'E', '0', '8', '8', '1', 'A', '2', 'A', 'A', '4', 'B', 'B', 'D', '4', '9', 'D', 'A', '3', 'A', '9', 'D', 'F', '3', 'A', '0', '7', '0', '6', 'B', '2', 'A', 'A', '7', '8', '2', '5', '5', 'D', 'B', '6', '1', 'D', '1', '5', '5', 'D', '0', '6', '8', '9', '4', 'B', '0', 'F', 'F', 'F', '1', '7', '0', '8', '1', 'B', '5', 'A', '7', '7', '9', '4', 'D', '2', '6', '4', '8', 'D', '7', '8', 'D', 'B', '4', '7', '3', 'C', 'B', '1', '3', '2', '2', '9', '4', '7', 'C', '4', 'A', '3', '6', 'B', 'F', '9', 'F', '2', '3', '9', '6', '0', '1', '2', 'A', '4', '7', 'B', '1', '7', '7', '1', '0', '0', '0', '2', '9', '0', '4', 'B', '2', '9', '4', 'C', '7', '9', '8', 'E', 'D', 'A', '6', '5', '1', 'B', 'E', 'F', '9', 'B', '8', '9', '9', 'F', '1', '4', '7', '3', '0', 'D', '1', '7', '1', '7', '2', '0', 'D', '6', '1', '7', 'A', '6', 'E', 'C', '0', 'E', '8', '5', '6', 'A', '2', '8', '4', '5', '7', '0', 'F', '0', '7', '2', '8', 'A', '4', '5', 'A', '3', '0', '6', 'C', '3', '1', '7', '6', 'B', '4', '0', 'B', 'A', '5', '1', '9', '2', '2', '1', '1', '8', '7', '0', '7', '5', '2', 'A', 'D', '8', '2', 'C', '6', 'E', '6', 'A', 'C', '2', '4', 'C', 'F', '6', '1', '3', 'A', '1', 'B', 'C', '9', '0', '8', 'E', '2', 'C', '8', '8', 'E', 'A', 'F', 'A', 'C', 'C', '4', 'C', '0', '1', '0', 'F', '8', 'C', 'C', '6', '9', 'F', 'A', '7', '1', '6', '6', '3', '7', '9', 'B', '2', '8', 'C', '6', '2', 'B', 'A', 'D', '4', '1', 'A', '2', '5', '3', '8', '7', '0', '3', '9', '7', 'A', '9', '2', '7', 'E', 'F', '4', 'C', '5', '6', '4', '0', 'C', 'A', '0', 'E', '7', '6', 'D', '5', '0', '0', '9', '9', '7', '0', '1', 'D', '1', '0', '7', '9', '6', 'A', '7', '7', '2', '6', '9', '6', '2', '6', '1', 'C', '2', '0', '7', '0', '3', '2', 'D', 'E', '1', '7', 'A', '7', '6', 'F', '1', '1', 'A', '3', '5', 'F', '4', 'F', '8', '9', 'D', 'A', 'B', 'B', 'F', '3', '5', '3', '0', 'E', '5', 'E', '0', 'C', 'B', 'B', '0', '0', '1', '6', '9', 'A', '6', '7', '4', '5', '8', 'D', 'D', 'E', '2', 'D', 'E', 'A', '0', '0', '2', 'D', '8', 'B', '3', 'D', 'F', '5', '3', '6', 'A', '4', '6', '6', 'F', 'F', '2', '9', '2', 'A', '8', 'F', 'A', '1', 'A', 'B', '0', 'F', 'C', '5', '1', 'E', 'D', '4', '4', 'C', '9', '8', 'A', '5', '4', 'B', '5', 'E', 'B', 'D', 'F', '1', '2', '5', '4', 'F', '9', '1', 'B', 'A', 'D', '5', '4', '3', '2', 'C', '6', 'B', 'B', '9', 'A', '0', 'E', 'B', '6', '5', '7', 'E', '1', '5', '5', '4', 'E', '1', '8', 'C', '8', 'E', 'C', 'E', '6', '0', 'D', 'F', '2', '3', '6', 'A', 'A', '9', 'E', '3', '8', '9', '8', '1', 'B', 'F', '7', '8', 'E', '3', '6', '8', '7', 'E', '3', '3', '2', 'C', '5', 'E', 'E', 'D', '8', '7', 'A', 'A', '8', '7', '8', '8', 'C', '5', 'D', 'F', '8', '0', '7', 'D', '8', '9', 'D', '3', 'F', 'C', '7', '9', '4', 'D', '1', '9', '7', 'D', '4', '1', '4', '4', '4', '0', '4', 'C', '6', 'A', '2', '5', '5', 'C', '2', '7', '1', 'B', '6', '6', 'D', 'F', '3', 'C', '2', 'E', 'F', 'C', '6', '3', '7', 'E', 'C', '6', 'D', '0', 'C', 'C', '5', '9', '2', '1', '4', '8', 'C', '8', 'E', 'F', '4', '5', 'B', '6', '0', 'F', '9', '4', 'A', 'C', 'B', '9', '9', '1', '7', 'A', 'B', 'F', '8', 'D', 'B', 'D', 'C', 'C', '2', '0', '4', 'C', 'C', '8', '8', '1', '8', 'F', 'B', '5', 'F', '5', '3', '3', '6', 'C', 'C', 'D', 'B', 'E', 'E', '1', '7', '2', 'C', '8', '8', '8', '6', '3', '4', 'F', '3', '4', '1', 'E', '3', '3', '8', 'B', '8', '6', 'F', 'F', '5', '6', 'C', '9', '9', 'A', 'E', '0', '4', '6', 'B', '0', 'E', 'A', '4', '2', '8', 'C', '8', 'C', 'B', '2', '3', 'D', '6', 'E', 'B', '2', '7', '0', 'F', '3', 'B', 'A', '9', 'E', '2', '3', 'C', '2', 'F', 'C', 'D', '9', 'B', 'D', '9', '6', 'B', 'C', '9', '4', '9', 'F', '3', '6', '2', 'F', '5', '0', '2', '8', '9', '7', '0', 'A', '4', '2', 'D', 'D', '3', '2', '4', 'B', '8', 'B', '8', '2', 'B', '7', '6', 'A', '5', 'E', 'A', 'E', '8', '3', '2', '1', '2', '4', 'A', '7', 'E', '1', 'C', 'D', '1', '6', '2', '9', 'B', 'B', '2', '8', 'A', '0', '3', '0', '7', '5', '1', '4', '6', 'C', '1', '7', '0', '9', 'D', '4', '6', 'D', 'F', '5', '6', '8', '8', '8', 'C', 'A', '5', '4', 'E', 'D', '3', 'A', 'B', '1', 'F', 'A', '8', 'B', '0', '8', 'F', '5', 'C', 'F', '6', '2', 'F', '6', 'B', 'C', '3', 'B', 'F', '5', 'F', '3', '5', '4', 'C', 'B', 'E', 'C', '4', '9', '3', '8', '0', 'A', '7', 'A', '7', 'C', '1', 'A', '3', 'E', '4', '6', 'B', 'E', '7', '3', 'E', 'E', '2', 'F', 'E', 'C', '2', 'C', '7', '8', 'A', 'F', '3', '8', '1', '1', 'B', '4', '9', '6', '2', '7', '3', '3', '2', 'E', 'C', '0', 'D', '1', '2', '5', 'E', '9', 'D', 'A', '7', '9', '6', '9', '7', '7', '2', '4', '5', '6', '4', 'B', '1', '3', 'B', 'C', 'A', '8', '1', '9', '4', 'C', 'E', 'D', '7', 'D', '8', '0', '9', '6', '4', '0', '4', '9', '4', '6', 'B', '3', '8', '1', 'F', 'A', 'E', 'C', '7', '1', 'A', 'D', '5', '4', 'A', 'F', 'B', '6', '9', '4', '9', 'B', 'A', '1', 'D', '1', '2', '7', '0', 'D', '8', '1', '6', 'F', '9', '8', '4', 'F', 'D', 'A', 'E', '6', '7', 'A', 'B', '9', '8', 'A', 'F', 'B', 'A', '5', 'F', 'B', '3', '4', '6', '6', '2', 'F', 'A', '3', '1', 'B', '1', '4', '7', '5', '5', '6', 'D', 'D', '6', 'C', 'D', 'D', '4', '8', 'F', '9', '5', 'A', '1', 'D', '3', '2', '7', 'D', '2', '3', '4', '6', '1', 'F', '0', '5', 'A', 'E', 'C', 'D', 'A', '6', '9', '5', '0', '2', 'E', 'F', '1', '9', 'C', 'F', 'A', 'A', '5', '3', '6', '0', 'B', '6', '8', '3', '1', '0', 'C', '0', '0', 'C', 'B', '3', 'C', 'E', '0', 'A', 'D', '9', '8', 'C', '7', 'A', 'B', '0', '2', 'C', '4', '9', '6', 'A', '6', 'C', '5', 'D', '9', '4', '7', '6', 'D', '5', 'E', 'A', 'A', '2', '8', '2', '9', '1', '7', '2', 'A', '8', '6', '8', '3', '7', '7', '5', 'C', 'D', '8', '7', 'E', 'D', '1', '8', '8', '1', '3', 'F', 'B', 'D', '7', '9', '1', '0', '4', '3', '5', '7', '2', '0', '0', '6', '9', '4', 'B', '2', '4', 'D', '5', '3', '8', '7', '8', '5', '9', '7', 'B', '1', 'B', 'F', '3', 'C', '3', 'D', 'E', '8', '4', 'F', 'D', 'F', '0', '0', '1', '7', 'F', 'C', '9', '5', 'F', '5', '1', 'D', '0', '0', '5', 'F', '2', 'E', 'C', '4', '5', '5', 'A', '9', '2', '3', '6', 'A', '5', '3', '4', 'E', 'F', '7', '5', 'F', 'C', 'F', '7', '8', '7', 'B', 'B', '0', '9', '9', '2', 'A', 'B', 'B', '5', '2', 'A', 'D', 'D', 'C', 'D', 'D', '6', '1', 'D', 'F', '8', '4', '9', '2', '1', 'F', '2', '2', '5', '0', '0', 'C', 'F', 'D', '5', '5', 'C', '1', '5', 'D', '1', 'A', '0', '3', '0', 'C', 'E', 'F', 'E', '3', '2', 'C', '1', 'B', 'E', '6', '8', '4', '5', 'F', 'D', 'E', 'A', '8', 'E', 'A', '0', '5', '1', '4', 'D', '7', 'B', '5', '9', '1', '6', 'C', '1', '2', '3', 'A', '8', 'D', 'A', 'F', 'E', '7', '4', '2', 'C', 'F', 'B', '4', 'E', '5', '8', '7', 'F', 'B', '3', '4', '6', '9', 'B', 'F', '5', '5', '7', 'C', 'A', 'C', '7', '1', '8', 'F', '2', '0', '0', 'D', '9', '9', 'A', '9', '8', '4', '9', 'D', 'D', 'E', '4', 'D', '6', '3', '9', '7', '6', '5', '4', 'F', '5', 'D', '8', 'E', '5', '2', '2', 'B', '8', '5', '0', '3', '2', '0', '8', 'B', '4', '8', 'F', 'A', '0', '6', 'D', '6', 'C', 'D', '1', '4', '1', 'F', '5', '3', '4', '4', '2', '5', '9', '9', '2', '6', 'B', '1', 'D', 'A', '1', '6', 'E', 'E', '7', 'D', 'A', 'B', '0', '1', 'E', '4', 'B', '7', '2', '1', 'E', '9', 'F', '2', 'B', 'E', 'C', '8', '9', 'A', '9', 'F', 'D', '4', 'A', 'A', 'E', '4', 'F', 'F', '2', 'C', '8', 'B', 'A', '4', 'E', '9', 'D', '3', '2', 'A', '7', '1', 'D', 'C', 'D', 'F', '9', 'F', '1', 'D', 'B', 'B', '7', 'F', '2', '5', '2', '5', '8', '7', '4', '1', '8', '8', '7', '7', '5', '8', '1', 'A', 'D', 'A', '8', 'A', 'F', 'C', '8', 'D', '4', '9', '8', 'E', '5', '8', '0', 'C', '2', '0', 'F', '3', '4', '4', '3', '2', 'F', '5', '1', '7', '9', '9', 'D', 'A', '2', '9', '3', '4', '1', 'B', '9', '0', '7', 'D', '1', '3', 'F', '9', 'D', 'A', '7', '1', '5', '6', 'E', '6', 'F', '2', '5', 'D', 'B', '4', 'A', '2', 'E', 'A', 'E', 'F', '8', '1', '5', '0', 'F', '0', '1', 'F', '1', '8', '7', 'D', 'E', '7', 'A', '7', 'F', '8', 'B', '0', 'C', '6', '1', '2', 'B', '3', '3', '0', '1', '9', 'B', '5', '7', 'E', '1', '5', 'F', '2', '5', 'B', '7', 'E', '9', '9', '0', '7', 'D', '5', 'E', '3', 'C', 'F', '4', '3', '1', '3', 'A', '6', '2', 'D', 'B', 'E', 'F', '7', 'B', 'F', '2', '9', 'D', '5', '3', '3', 'D', '9', '6', '2', '9', 'A', '6', 'C', '4', '9', 'B', '7', '0', 'B', '6', '7', '8', '6', 'F', 'B', '7', '7', '1', '1', '2', 'D', 'E', 'B', '0', '9', '2', 'E', '0', '8', '9', '6', '7', 'D', '5', 'A', '4', '0', '6', '2', 'E', '5', 'F', 'A', 'D', 'A', '0', '7', 'F', 'C', '3', 'B', 'C', 'E', 'B', '7', '2', '3', '5', 'B', '2', '7', 'A', '7', '9', '9', '3', 'F', '4', '4', '0', '8', 'E', 'D', 'C', 'C', 'E', '3', 'E', 'B', '1', '0', 'D', '3', '5', 'D', '7', '7', '4', '7', '5', 'E', '8', '4', '9', 'F', 'B', '2', '3', '1', 'B', 'B', 'B', 'B', '0', '7', 'F', '7', '3', '2', 'E', '8', '5', '9', '4', '1', '1', 'F', '6', 'E', '0', 'F', '8', '0', 'E', '8', '7', 'B', '7', '3', '4', '8', 'E', '7', '2', '5', '2', '1', 'C', '6', 'D', '1', '4', 'B', 'B', 'C', 'F', '3', '7', '8', '8', 'A', 'D', '5', 'E', '3', '6', 'E', '8', '2', '8', '8', 'C', '8', 'D', '8', '7', 'A', 'D', '2', 'D', '3', '0', '1', '8', '7', 'B', '3', '2', 'D', '6', '0', '8', '7', '3', 'C', '9', '7', '2', '0', '2', '4', '2', 'F', 'C', '1', 'D', '5', '3', 'B', 'F', '9', '3', '6', '3', '7', 'D', '0', 'D', 'A', '3', '3', 'A', 'B', '1', '7', '0', '5', '6', '6', '2', '4', 'E', '1', '6', '5', 'F', 'F', 'C', '3', 'B', '6', '0', 'E', 'B', '1', '2', '9', '5', '1', 'A', '0', '0', '9', 'F', '3', '9', '1', '1', 'E', '9', '1', '0', 'D', '1', 'B', '4', 'D', 'C', 'B', '9', 'E', '0', '1', '1', '7', '2', 'A', '0', 'F', 'C', 'D', 'B', '6', 'A', '0', 'D', 'C', 'C', '0', '9', '8', '8', '7', '9', 'B', '0', 'B', 'D', '7', '0', 'E', '5', '4', '1', '9', '8', 'A', 'A', '3', '5', '7', 'E', 'A', '0', 'D', '3', 'C', '3', '5', 'F', '3', '8', '2', '3', '7', '9', 'B', '2', '8', '7', '4', 'D', '5', '2', 'D', 'F', '2', '7', 'C', '8', '9', '9', 'C', '6', '5', '3', 'B', '4', '4', 'C', '9', 'E', 'A', '8', '7', '1', '1', 'F', 'E', '7', '5', '0', '0', '7', 'D', 'A', '5', '8', 'D', 'E', 'F', 'D', '3', '9', '1', '8', '8', 'A', 'D', '5', 'D', 'A', 'F', '1', 'A', '2', '2', '8', '7', '7', '8', 'E', '5', '2', 'D', 'C', '8', '2', 'C', 'D', '9', '7', 'F', 'A', '2', '5', 'C', 'E', 'B', 'C', 'F', 'F', '8', '4', '0', 'E', 'F', 'C', '0', 'B', '2', 'F', 'F', '6', 'C', '8', 'B', '8', '4', '8', '0', 'C', '8', '7', 'A', 'E', '8', '7', '8', '4', 'E', '7', 'D', 'E', '1', 'C', '2', 'F', 'D', 'E', '1', '6', 'C', 'C', '2', 'A', '3', '8', '4', '8', '6', 'D', '4', '9', 'A', '1', 'B', 'B', '7', 'B', '4', 'F', 'C', '3', 'B', '0', '4', 'B', 'B', '7', '5', '8', '4', '1', '4', '8', '0', 'F', '3', 'D', '9', 'C', '9', '1', '4', 'E', '4', 'A', '2', 'B', 'D', '2', '7', '4', '3', '1', '5', '7', '9', 'A', 'F', '4', 'F', 'B', 'E', 'C', 'F', '8', '7', '1', '5', '9', 'F', '3', 'C', '7', '5', '9', '2', '8', '8', '6', 'F', '5', '9', '2', '5', '4', '5', '5', '5', '1', '2', 'B', '8', 'A', '7', '3', 'B', '0', '2', '0', '9', 'F', '2', '7', '8', '2', '3', '1', '4', '4', '0', '1', 'E', 'E', 'A', 'D', '0', 'E', 'A', '4', 'C', 'C', '7', 'A', 'F', 'A', '6', '4', 'F', '7', 'E', 'B', '2', '0', '8', '4', 'F', '1', '9', '8', '9', '9', '7', 'C', '7', '3', '8', '2', '4', '6', 'A', '4', 'B', '4', '1', '0', '2', '5', '7', 'C', 'A', 'B', 'D', '9', '6', '9', '2', 'D', '1', 'B', 'E', '7', '6', 'C', '8', 'C', 'C', '7', '7', '9', '6', '6', '9', '6', '7', 'F', 'B', '5', '7', 'C', 'A', 'A', '0', '5', 'F', '9', '7', 'D', '5', 'A', 'B', '6', '6', '9', 'F', '2', '0', 'F', 'E', '7', '1', '5', '6', 'E', 'C', '6', '6', 'E', '5', 'D', 'E', '7', '9', 'A', '8', '9', 'D', 'D', 'F', '4', '1', '0', 'E', '2', 'A', '8', '9', '3', 'C', '6', '3', '4', 'E', '5', '9', '8', '7', '6', '7', '7', '3', '6', '0', 'F', '2', '5', '7', '3', 'C', 'D', 'F', '9', 'C', '1', '9', '0', '5', '3', '3', '1', 'C', '7', '2', '4', '5', '5', 'F', '2', 'E', 'C', 'F', 'C', '2', '7', 'D', '8', 'C', 'A', 'E', 'D', 'D', 'D', 'B', 'D', '0', '6', '2', '2', 'C', '3', 'E', 'F', 'B', 'A', 'B', '9', '8', '0', 'B', '2', '5', 'D', 'A', 'E', 'A', 'F', '4', '1', 'B', '0', '5', '6', '2', '0', '1', '0', '9', '4', '0', 'B', 'E', '5', 'E', '9', 'F', 'E', 'F', 'B', '7', 'B', 'D', 'B', '4', 'D', '3', 'B', 'B', 'D', '1', 'F', 'C', '7', '4', '0', '6', 'E', 'E', '9', '8', '0', 'B', '2', 'B', 'D', 'A', '0', '3', 'E', 'E', '5', '6', 'A', '9', '0', 'E', '1', '8', 'B', '6', '0', 'E', 'A', '0', '0', '4', '1', '1', 'B', '4', '3', 'A', '6', 'B', '6', 'B', 'E', '0', 'B', '2', '3', '3', '6', 'C', 'B', '1', 'E', 'A', 'D', '6', '9', '8', 'F', '8', 'B', '8', '4', '0', '6', '6', 'F', '7', 'D', '9', '8', '5', 'A', '2', '8', 'A', 'F', '1', '4', 'A', '1', '4', 'A', '8', 'A', '5', '3', '9', '9', '5', 'D', '5', '5', '1', '5', 'B', '8', '6', '8', 'F', '7', '7', '6', 'B', '7', 'A', 'A', 'E', 'D', 'B', '4', 'D', 'A', '6', '6', 'D', '2', '6', '5', 'C', '1', 'D', '5', '5', '9', '6', '1', '7', '5', 'D', '5', 'D', '4', 'C', 'C', 'C', '0', '5', '0', '2', 'A', '4', '2', '5', 'B', '3', '3', '4', '8', '9', '3', '3', 'D', '9', '6', '3', 'F', '8', 'F', '4', '9', '6', '3', '5', '7', 'D', '5', '1', 'E', 'E', '8', '9', '9', '8', 'F', '8', 'B', '8', 'C', '5', 'F', '4', 'C', '0', '7', 'F', 'C', '3', '7', 'C', '2', 'F', 'F', 'F', '3', '0', '1', '5', '2', '0', 'C', '8', 'E', 'E', '1', '7', '0', '3', 'C', '7', 'E', '7', '5', '4', '2', '0', '0', 'F', '3', '2', '0', '4', '8', '7', '5', 'A', 'A', '0', 'E', 'F', '8', '7', '0', '1', '1', 'B', 'F', '2', '0', 'B', '3', 'A', '5', 'A', '7', '8', 'C', '2', '1', '1', 'A', '3', 'A', '1', 'D', '7', '1', '0', 'C', '0', 'E', '0', '6', '6', 'F', '4', '9', '1', 'C', 'B', 'C', '6', '7', 'C', '5', '2', '7', '5', 'F', 'F', 'F', 'F', '1', 'A', 'D', 'D', 'D', '6', 'A', 'C', '4', '8', '0', '5', '0', 'D', 'C', '3', 'E', '0', 'F', 'C', '7', '1', '0', '1', 'E', '8', 'C', '0', '5', '7', 'E', 'B', 'F', '1', 'A', 'F', '4', '0', 'E', 'E', 'D', '1', 'F', 'F', 'E', 'A', 'F', 'B', '2', 'F', '2', '4', 'F', '5', '4', '7', 'D', '2', '2', '8', '1', 'B', 'C', 'F', '7', 'C', '0', '4', '7', '1', 'E', '7', 'E', 'B', '8', 'C', 'F', '7', '1', '9', '5', '2', 'A', '5', 'A', '4', 'E', 'D', '6', 'D', '5', '8', '9', '5', '1', '2', 'C', '4', '2', 'C', '3', 'B', 'C', '2', '9', '6', 'F', 'D', '0', 'C', '6', 'D', '6', '4', 'F', 'C', '3', '7', 'C', '5', '9', 'E', 'C', '2', '0', 'E', '8', 'C', '3', '5', '5', '8', '9', 'A', 'C', '9', '1', '6', 'D', '5', '8', '6', 'C', '4', '3', '2', '5', 'C', 'F', 'F', '6', 'B', 'E', '4', '2', '5', '6', '1', 'B', 'C', 'E', '6', '6', '1', '4', '0', '7', '6', '9', 'E', '9', 'B', '3', 'E', 'C', '5', '8', 'A', '0', '9', 'D', 'A', 'D', '6', 'A', '2', 'C', 'C', '8', '7', '9', '6', 'C', '0', 'D', 'B', '7', '0', 'C', 'F', 'F', '4', 'C', '4', '8', 'C', 'B', 'F', 'D', 'B', '4', 'B', '7', '8', 'F', '9', 'B', 'E', '1', 'A', 'D', '3', '2', '4', 'D', '3', '2', '2', '7', 'C', '4', 'E', '1', '6', '4', '0', 'E', '5', '1', 'E', '7', '9', '5', 'C', '8', 'E', '5', 'C', 'B', 'D', '0', '5', '6', 'B', '2', '7', 'F', 'B', 'F', '4', 'D', '3', 'C', '1', 'D', '1', 'E', '5', 'B', 'E', 'E', 'E', '8', 'D', 'B', 'D', 'B', '5', 'C', '4', '9', '4', 'A', '4', '4', 'E', '7', '9', '6', 'A', 'D', 'A', 'A', '7', '0', 'E', 'F', 'F', '3', 'F', '1', '0', 'D', 'B', 'E', 'C', 'F', 'B', '2', '2', '5', '4', '6', '4', 'C', '1', '0', 'D', 'C', 'D', 'A', '4', '7', '6', 'C', '5', '9', '1', '1', '4', '6', 'C', '7', '5', '8', 'E', '3', '2', '5', 'A', '4', 'C', '9', 'D', 'C', '2', '5', '9', '2', '0', 'B', '3', '6', 'B', 'D', '1', '4', 'D', 'C', '7', '4', '2', 'E', 'C', 'F', '8', 'B', '8', 'D', 'E', '5', '5', '4', '7', '5', 'D', 'C', 'E', '0', 'E', '2', 'E', '8', '6', '5', '5', 'C', '7', 'C', '4', 'B', '0', 'D', 'A', 'B', 'E', 'E', 'B', '8', '4', '8', 'B', '2', '4', '2', 'A', '1', 'F', '6', 'D', '0', '4', '2', '7', '4', 'E', 'D', 'F', '1', '7', '1', '6', '6', 'B', 'E', '0', 'A', 'B', 'E', '2', '8', '4', '1', '5', '8', 'F', '3', '2', '1', 'F', '6', '5', '8', '7', 'B', '7', 'A', '2', '0', 'D', 'C', '3', 'A', 'C', '6', 'C', '5', '6', '4', 'D', 'E', '7', '9', 'D', '9', 'A', '2', 'E', '0', 'C', '3', '5', 'F', 'E', '2', 'A', '6', '4', 'A', '0', '7', 'C', '3', 'F', '3', 'A', 'F', '9', '9', '3', 'A', '2', '4', 'C', 'A', '6', 'C', '7', 'B', '6', '2', '7', 'D', 'C', '0', 'C', '8', '5', '4', 'C', 'F', '9', 'E', '4', 'F', '1', 'F', '0', '4', 'C', '3', '3', '3', '2', 'C', '3', '1', '4', '1', '4', 'F', 'B', 'B', '9', 'B', '4', 'E', '8', 'C', '1', '1', '4', 'D', '6', 'F', '4', 'B', '9', '6', '3', 'C', '3', 'B', '2', '9', '0', '9', '6', '7', '1', '6', '9', 'C', 'C', 'A', '5', '8', 'F', 'C', '0', '3', 'A', '2', 'B', 'C', '6', '3', 'E', '3', 'D', '2', '4', 'E', '2', 'A', '2', '4', 'B', '6', 'C', '3', '7', 'A', '6', '0', 'B', 'A', '7', 'D', '3', '9', 'B', '7', 'B', '8', '3', 'A', '9', '5', '4', '4', 'E', 'A', 'F', 'B', 'D', 'B', '5', '3', '5', 'D', 'C', '4', 'C', 'A', '4', '8', '4', 'E', '2', '1', 'B', 'D', '5', 'E', 'B', '7', '2', 'F', 'D', 'C', '3', '5', '3', '9', 'B', 'E', 'E', '4', 'E', 'F', '1', 'E', '7', 'C', '9', 'C', '2', '6', '3', 'D', '6', '6', '0', 'C', 'F', '4', '8', 'B', '6', '6', 'F', '2', 'D', 'F', 'C', '6', '2', '9', '4', '4', 'E', '8', '2', '1', 'A', '7', '5', '6', 'E', '4', '2', '2', '5', '9', 'B', '4', 'D', 'D', '0', '8', '6', '7', '6', 'D', 'D', 'A', 'A', 'D', '0', '0', '4', '8', 'F', 'C', 'F', 'B', '9', '3', 'E', '4', '3', '5', 'D', '9', '0', '6', 'F', 'A', 'F', 'E', '1', '5', '0', 'E', 'E', 'F', 'B', '9', 'E', '8', '5', '4', '4', 'A', '0', 'C', '5', 'F', '7', 'C', 'F', 'C', '5', 'A', '8', '6', '3', '9', '1', 'B', '8', 'F', 'F', '1', '4', '8', '5', '6', '3', '4', '7', 'B', '6', 'C', '4', '5', 'E', '0', '7', 'B', 'F', 'B', 'F', '5', '2', '5', 'E', 'B', '9', '2', '1', '2', '4', 'E', '6', 'A', '8', '8', '7', '4', 'E', '4', 'E', '3', 'F', '4', '4', 'C', '2', '4', '8', 'C', '8', 'B', '5', '5', '4', '3', '5', '8', '7', '3', '3', '1', '2', '6', 'E', '7', 'E', '9', 'C', '3', '5', '0', '1', '0', '9', 'C', '5', 'D', '6', '3', 'B', '4', '7', 'E', '3', '3', '3', 'A', 'A', 'B', '8', '8', '4', 'E', '3', '0', '5', '6', 'F', 'A', '1', '2', 'F', '6', 'D', '3', '3', '5', 'B', 'B', 'E', '1', 'A', '4', '6', '9', '0', 'B', '5', 'C', '2', 'E', '7', 'A', 'E', 'B', '4', '6', '6', 'D', 'D', '9', '6', 'C', '6', '5', '1', '6', 'C', 'B', '3', '2', '4', 'F', 'C', 'F', '5', '4', '7', 'D', '4', '6', '7', '4', '4', '6', '1', '6', 'D', '9', '7', 'C', '0', '2', '1', '0', '3', '5', '0', '8', '4', '1', 'E', 'D', '3', 'C', '4', 'E', '0', 'F', 'D', '0', 'F', '0', 'C', '0', 'E', '1', 'A', 'F', 'E', '4', 'B', 'F', 'E', 'E', '7', '3', '9', '4', 'D', 'B', '1', 'A', '6', '2', '9', '3', '7', '2', '9', 'A', '8', '5', '6', '1', 'E', 'A', 'B', '5', '5', '2', 'F', '4', 'C', 'D', '1', '0', '8', '7', '9', '9', '4', '7', '0', '2', 'D', 'E', '7', '4', 'E', '7', '9', 'D', 'C', '1', '5', 'B', '0', '9', 'C', '0', 'E', '8', '2', '2', '0', '9', '0', '6', '5', 'A', '1', '5', '2', '8', 'A', '2', '9', 'F', '4', '3', '5', 'A', 'D', 'F', 'B', '4', '5', '8', '0', 'F', '7', '0', 'B', '5', '7', 'D', '5', '1', '3', 'D', 'B', 'B', 'E', 'B', 'B', 'A', 'C', '1', 'F', '3', '9', 'F', '2', 'E', 'B', '5', 'A', '5', '6', 'A', 'F', 'E', 'F', 'E', 'F', '8', 'C', '3', 'E', '3', '5', '5', '5', '1', '9', '8', 'A', 'D', 'D', 'C', '4', '8', '4', '9', '5', 'D', 'A', 'C', '6', '9', '9', 'F', 'A', '4', '4', '7', 'D', '4', '0', 'B', '0', 'D', 'C', '8', 'E', 'E', 'D', 'F', '6', '1', 'E', 'B', '7', '5', '7', '3', '5', 'D', '7', '5', '5', '7', 'B', '9', '4', '8', 'E', 'C', 'A', 'D', '4', 'E', 'E', 'B', '2', 'F', '0', '5', '8', '0', '0', '5', 'F', '2', 'E', '3', '2', '5', '9', '8', '7', '4', '8', '7', '3', '8', '4', 'E', 'F', '1', '8', '5', '9', '8', '8', 'E', 'B', 'F', 'E', '1', '6', 'E', '1', 'D', 'D', 'F', 'C', 'C', '1', '7', '4', '5', '1', 'F', '6', '7', '3', '5', 'B', 'A', '0', '9', '0', '8', 'A', '9', '4', '8', '7', '9', 'E', '6', '6', 'A', '2', '7', '8', '3', '2', 'E', '0', 'D', '7', '2', 'A', 'E', 'B', '0', '3', '6', '3', '9', '8', '6', 'A', '5', '3', '2', 'E', '7', '5', '7', '8', 'A', '1', 'D', 'A', '1', '5', '1', '5', 'C', 'A', '1', 'E', '6', '8', 'D', 'F', 'F', 'F', '9', '6', '3', 'C', '3', '4', '5', '1', '0', '1', 'A', '8', 'A', '5', '9', 'F', '6', '2', '1', '1', '7', 'F', 'F', '3', 'D', 'B', 'D', 'C', '8', 'D', 'B', 'B', '4', 'B', 'F', 'D', 'F', 'A', '9', 'F', '5', '3', 'B', '1', 'C', 'F', '6', '0', 'E', '9', '0', '8', '0', '7', 'C', 'D', '5', '1', '2', '8', 'F', '7', '4', '9', '5', 'C', '5', '3', '5', '1', 'D', 'B', '7', '0', '3', '7', 'F', '0', '8', '8', 'E', '2', 'A', '9', '5', 'B', 'E', 'B', '8', '1', 'B', '2', '5', '0', '2', 'A', '6', 'F', '2', '6', '6', '1', '3', '2', '9', '4', '1', '6', '3', 'E', '0', 'E', '4', '2', 'C', '4', '6', '5', '2', '5', '2', '6', '4', '9', 'C', 'D', '9', '0', '4', 'F', 'E', '6', 'C', '1', 'E', 'B', '4', 'E', '7', '8', '2', '8', '5', 'F', '0', '2', '6', '8', 'E', '3', '5', '0', '7', '1', '7', 'C', '1', 'D', '9', 'F', '8', '3', 'A', '3', '9', '6', '5', '3', '5', '2', '9', '6', 'E', '6', '0', 'E', 'D', '6', '5', 'E', 'F', '3', '7', '0', '9', '1', '5', 'A', '4', '6', 'B', 'B', '4', 'D', '4', '5', 'A', '7', '1', '2', '3', '0', '7', 'C', 'A', '5', 'B', '2', '1', '5', 'D', '8', '4', '1', 'C', '3', '4', 'D', 'B', '2', '8', '6', '7', '1', 'E', '4', '6', '2', '8', '7', '7', 'E', '0', '1', 'B', '1', '6', 'B', 'C', 'D', '1', '4', 'B', '8', 'F', 'C', '5', 'D', 'A', '6', '3', '5', 'E', '6', 'B', '6', '1', '0', '8', '9', '1', '1', '9', '6', '3', '4', 'A', 'B', 'D', '1', 'B', 'B', 'E', '6', '7', 'E', 'C', 'C', 'B', 'F', '3', 'A', 'C', 'B', 'B', '0', '8', 'C', 'D', '7', 'E', 'E', 'E', '0', '5', '5', '7', 'B', '1', '8', '9', '7', '9', '6', '0', '6', '7', '2', '9', 'C', '7', '3', '8', 'B', 'F', '8', 'F', '5', 'E', '7', '0', 'A', 'E', 'C', 'C', 'F', 'C', '8', 'A', '4', 'C', '2', 'E', 'D', '9', '3', '7', '9', 'A', 'D', 'A', '2', 'F', '4', 'B', 'D', '1', '3', 'C', 'D', '6', '1', '9', 'D', '6', 'B', '5', '1', '7', '7', '1', 'D', '9', '4', '7', '2', 'F', 'D', '9', '7', '1', '2', '8', '2', '9', '1', 'A', 'D', '0', '0', 'E', '3', '3', '1', '2', '5', 'B', '8', '2', '9', '9', '2', '9', '8', '5', '5', 'A', 'C', '5', '7', '8', '9', '7', '8', 'A', 'A', 'C', '7', 'E', '7', '9', '4', '4', '2', '8', '1', '0', '6', '3', 'D', 'A', '9', '6', 'E', 'A', 'F', '3', '7', 'C', '8', 'D', '0', '0', '0', '5', 'A', '4', 'B', '0', '7', 'A', '7', '0', '9', '3', 'F', '4', 'F', 'F', '5', 'C', 'E', '3', '4', '9', '8', '9', '2', 'D', 'D', '8', '0', 'D', '3', 'D', 'B', 'B', '1', '6', '3', '2', '8', '0', '5', '8', 'E', '6', '7', 'C', 'F', '2', '4', '5', 'C', '6', 'A', '4', 'C', '9', '9', '3', '7', '4', 'A', 'F', '0', 'F', '6', '7', 'F', '1', '5', '1', 'F', '1', '1', 'C', 'F', 'B', '5', '3', '6', '8', 'A', '2', '6', '3', '0', '5', '0', '0', '7', 'A', '1', 'F', '7', 'A', '6', '1', '3', '0', '3', '3', '0', '2', 'E', '7', '4', '3', 'D', '5', '7', '0', '1', '5', '1', 'F', '4', 'E', 'B', '0', 'F', '5', '8', '1', '9', '7', '2', '2', 'F', '5', 'D', '2', '0', 'A', '7', '2', 'E', '8', '9', '1', '0', '0', '9', '1', '5', 'E', 'F', '1', 'D', '8', 'D', '7', 'B', '0', 'F', '4', '0', 'B', '5', 'C', '8', 'A', '8', '8', '4', '3', '9', 'F', '3', '2', 'F', '8', '5', 'F', 'C', '4', '2', '5', '3', 'B', '1', '0', '4', 'A', '9', '7', '2', '2', '0', 'D', 'C', '5', 'D', 'A', '0', 'D', 'F', 'D', '4', '1', '5', '2', 'A', '1', '5', '5', 'A', '1', 'F', '6', 'A', '9', '9', 'C', '1', 'B', '4', 'A', 'A', '7', 'F', 'D', 'E', '7', '5', '5', 'C', '7', '8', 'E', 'B', '3', 'D', 'C', '3', '8', '1', 'F', '1', 'B', '4', '6', '7', 'C', '0', '2', 'A', '2', 'B', '8', '3', 'F', 'A', '4', 'B', '9', 'C', '4', '4', '6', '2', '4', 'A', '7', 'A', '2', 'A', 'D', '3', '3', '6', '9', 'D', '7', 'A', '1', '2', 'E', '7', '7', 'F', 'E', '9', '8', 'F', '2', '9', '1', '3', '8', 'F', 'C', '3', '4', 'C', 'C', 'C', '8', '6', '1', '3', 'C', '8', 'A', 'D', 'C', '2', 'A', 'A', '3', 'F', '0', 'A', 'A', '7', '5', '7', 'E', 'F', '8', '6', '3', 'A', 'E', '7', '6', '4', '4', '8', '1', 'E', 'B', '2', '8', '3', '5', 'B', 'A', '7', '7', '0', '5', '9', 'F', 'F', 'D', '3', 'B', 'F', '1', 'B', '6', 'E', '2', '9', '8', '7', '4', 'A', 'B', '3', '6', '6', '5', 'C', '0', '7', '3', '0', '3', '1', '1', '6', 'A', '2', '7', '1', 'B', 'A', 'A', 'F', 'F', 'E', '3', 'E', '7', 'E', '2', '0', '9', 'B', '1', 'A', '3', '7', '8', '8', '5', 'B', 'A', 'B', '9', '6', '5', '9', '6', '0', '6', '0', 'D', '5', '1', '9', '4', '9', '3', 'F', '9', 'D', '3', '7', '1', '1', 'E', 'C', '0', '6', 'C', '1', 'C', 'F', '6', '0', '4', '4', '2', '1', '0', 'F', '8', '3', 'D', 'B', 'B', 'D', '1', 'B', '1', '8', '9', '8', '4', 'F', '2', '2', 'B', 'C', '7', '2', '1', 'F', '9', '5', 'E', 'C', '8', 'A', 'B', 'D', '8', '0', '8', 'D', '5', 'A', 'F', 'C', '0', '7', '1', '8', 'E', 'D', '8', '2', '2', 'A', '4', 'E', '6', '0', '4', 'A', '6', '7', 'A', '7', '0', '3', 'A', '2', '2', '8', '2', 'A', '1', 'A', 'B', '1', '0', '0', '2', 'C', 'D', 'B', 'B', '5', 'F', '8', '6', 'F', '5', 'B', 'F', 'D', '9', 'A', 'E', '4', '0', 'E', '4', 'A', '8', '8', '0', 'D', '1', 'A', '7', 'A', 'A', '2', '4', '8', 'F', '3', '8', '3', 'B', 'F', '9', '3', 'F', '1', '1', 'F', 'E', '8', '7', '0', 'B', '0', 'D', '4', 'B', 'D', '1', 'D', '2', '0', 'C', '6', 'E', 'B', '0', 'F', '4', 'C', 'C', 'F', 'B', 'E', 'A', 'C', 'F', '3', '9', '8', '9', '7', 'A', 'C', '9', '7', '5', '1', '1', '9', 'D', 'B', '2', '7', 'C', '3', '9', '6', 'C', 'E', '5', '5', 'D', 'B', '2', '0', '1', '6', 'D', '6', '1', '2', 'D', 'C', '3', '5', 'B', '2', 'B', '4', 'C', 'A', 'F', '1', '4', 'F', 'D', '5', 'C', 'F', '7', 'E', '6', 'C', 'F', '1', '6', '6', '7', 'F', 'A', '3', 'D', 'C', '2', '6', 'C', '5', '6', 'E', 'C', '8', '3', 'E', 'F', '5', '6', 'B', 'E', 'C', '3', 'C', '5', 'B', 'F', '6', 'B', '8', '9', '1', '8', '4', 'E', '2', '6', 'E', '9', '2', 'C', 'D', '2', '0', '7', '9', 'A', 'F', 'D', '4', '7', 'A', 'F', '4', '8', '9', '6', '0', 'A', '8', 'D', '2', 'A', '9', '8', 'D', '9', 'A', '9', '5', '7', '7', 'C', 'A', '7', '3', '7', '1', '0', 'B', '1', '5', 'B', '7', 'B', '8', '8', 'C', 'E', '3', '7', 'A', 'E', '8', '2', 'D', 'B', '4', 'C', '8', '5', '9', '8', '3', 'C', 'F', '8', '7', '8', '6', 'F', '4', 'E', '2', 'F', 'D', '1', '4', '5', '5', '5', '6', '4', 'E', '8', 'A', 'A', '0', '5', 'E', '6', 'A', '4', 'A', '0', '7', '3', 'E', '4', '4', '7', '0', '6', 'E', 'A', '3', '2', 'E', '4', '6', '0', 'B', 'B', '6', '4', '9', '1', '3', 'E', '0', '2', 'A', 'D', '0', 'D', '1', '0', 'B', '9', '3', '5', 'A', '6', 'E', '0', '5', '4', '3', 'E', '8', '3', '2', '9', 'B', '3', '5', '0', '1', '6', '1', 'D', '8', '5', '6', '0', '7', 'C', 'A', 'E', '5', 'A', '5', 'E', 'C', '3', '8', '2', 'A', '5', 'A', 'B', '8', 'D', '0', '4', '5', '6', '4', 'C', '2', '5', '7', '8', '9', '3', 'A', '2', '5', 'D', 'A', 'F', '3', '0', '7', '7', '6', 'C', 'C', 'C', '1', '5', '1', '4', 'A', '3', 'A', 'C', 'F', '6', '8', 'B', '6', '7', '3', '3', 'F', '2', 'A', '8', 'A', '9', '6', 'B', 'B', '9', '6', '4', 'B', '3', '1', '0', '8', '9', '5', '1', '7', 'D', 'F', '0', 'E', 'A', '6', '2', 'B', 'B', '3', '3', 'D', '8', 'D', 'B', 'A', '4', '8', '1', 'F', 'F', 'A', 'F', '8', '6', '1', '5', 'C', '2', 'D', '0', '2', 'E', '0', '5', '0', '5', '0', 'B', 'E', 'C', 'D', '0', 'F', '4', '7', 'A', '9', '0', 'E', '7', 'D', '8', 'D', 'A', 'A', 'F', '9', '9', '2', '7', 'D', 'B', '6', 'E', 'C', '3', '8', '0', '4', '7', '4', '5', '2', 'F', '6', '1', '0', '9', 'F', '3', 'D', '4', 'F', '5', '2', '3', '5', 'B', 'F', '7', '6', '9', '7', '0', '9', 'A', 'B', '2', '7', '5', '2', '5', '2', '8', '9', 'C', 'E', '5', '7', 'C', '5', '2', '1', 'A', '3', '8', 'F', '3', 'B', '0', '1', '0', 'A', 'E', '0', '0', 'E', 'B', 'B', '7', 'C', '9', 'C', '6', 'D', 'C', '1', '4', '5', '7', '1', '2', 'A', '6', '7', '6', '3', 'C', 'B', '7', '6', '9', 'F', '2', '8', 'E', '3', '9', 'B', '4', 'C', '9', 'C', 'D', '3', '8', 'A', 'C', '2', '4', '6', '5', 'A', 'F', 'E', 'C', '7', '9', '1', '6', 'B', '1', 'F', '5', 'C', 'C', 'C', 'B', 'C', '0', 'A', 'C', '1', '8', 'F', '5', 'F', 'C', 'B', '3', '1', '3', '2', '9', '3', 'B', '9', 'E', 'A', '5', '8', '2', '0', '3', '3', '5', 'B', '9', '1', '4', '7', '8', 'B', 'B', 'E', '9', 'A', 'B', '8', '9', '7', 'A', 'D', '7', 'B', 'E', '6', '9', 'A', '8', '2', 'F', '2', 'F', 'D', '2', '2', '4', '0', 'B', '2', '5', '6', '5', 'C', 'F', 'A', 'F', '0', 'A', '5', '3', 'A', 'A', '6', '6', 'E', '7', 'D', 'D', 'C', '7', '5', 'F', '6', 'A', '1', 'A', '0', 'A', 'C', '1', '3', '4', '1', '4', '6', '1', 'C', 'D', '1', 'D', 'F', '7', 'A', '0', 'A', 'D', '2', 'E', '7', 'F', 'D', 'D', 'C', '4', 'E', '6', '6', '3', 'B', '5', '1', '6', '4', '0', '4', 'E', 'C', '6', '7', 'C', 'F', '8', '6', '0', '3', 'D', '2', '6', '3', '9', '0', 'A', '7', '7', '7', 'A', 'E', 'B', '4', '7', 'D', '4', '1', '6', '4', '7', 'E', 'E', '6', '8', '7', 'C', '4', '4', '3', '0', '4', 'E', '7', 'C', '7', '8', '4', 'B', '4', '4', '3', 'B', '0', 'D', 'B', '2', 'A', '4', '8', '5', 'E', 'D', '2', '0', '6', '6', 'E', '2', '5', '2', '9', '2', '0', '1', '1', 'D', '1', '7', 'A', 'B', '0', '0', '0', '4', '5', 'B', '3', '7', '1', 'A', '9', 'E', '2', 'B', '3', '6', '6', '4', '2', '1', 'B', '5', 'A', '4', '0', 'B', '4', '8', '0', 'F', '2', 'F', '5', '6', '7', 'E', '5', '4', 'C', '5', 'C', '6', 'A', '9', 'C', '2', 'C', 'A', '6', 'A', 'F', '6', 'B', '8', 'B', '1', '0', 'F', '5', '3', 'A', '4', 'A', '3', 'A', '1', 'B', 'C', '9', '1', '5', '7', '1', '1', 'D', '6', '2', 'D', 'C', 'B', '5', 'A', '8', '0', '7', '7', 'A', '5', '7', 'B', '5', '5', '0', '1', 'B', 'C', 'E', '1', 'D', 'A', 'A', '2', '4', '2', '3', '6', '4', 'D', '7', 'C', 'F', '5', 'E', 'F', '8', '5', '3', '0', 'D', 'C', 'F', 'B', '7', '5', '5', '9', '7', '0', 'A', '6', '8', '2', 'B', '6', 'C', '4', '0', 'A', '9', '4', 'A', 'D', 'C', '6', '1', '7', '5', '6', 'D', '8', 'D', '4', 'B', 'A', '0', '6', '1', 'D', '0', '9', '3', '4', 'F', 'E', 'B', '7', '6', 'D', '2', 'B', '9', 'D', '0', '8', '0', '5', 'D', '4', '9', '3', '8', '9', 'B', '0', '1', '2', 'A', 'C', 'A', '8', 'D', 'C', 'C', '6', '6', '2', '8', '7', '5', 'A', '0', '8', 'D', '9', 'C', '7', '3', '0', '2', '6', '8', '6', '1', '6', '0', '5', '6', '4', '7', '9', '6', '5', '9', '7', '2', '0', '0', '5', 'B', '1', '1', '0', 'F', 'C', '7', '9', '3', '8', '1', '0', 'F', 'F', 'D', '6', 'F', '3', 'B', '4', '5', '8', '4', '4', '8', '1', '1', '0', '7', '8', 'C', '5', '2', 'D', '5', 'F', 'D', 'F', 'F', '8', '0', 'D', '4', 'A', '6', '6', '5', '3', '0', 'E', 'D', '9', '8', 'A', 'B', 'C', '9', '0', '6', 'A', '6', 'A', '0', '5', '5', 'B', '9', 'C', 'D', '0', 'F', '0', 'D', '2', 'F', '6', '7', 'B', '7', '7', 'E', 'E', '8', '3', '2', 'C', 'D', 'B', '8', '7', 'C', 'D', '7', 'F', '9', 'A', '5', '8', '6', 'B', '9', '4', 'C', '8', '3', 'B', 'E', '4', '9', '6', '1', '0', '7', '3', 'E', '1', '5', 'E', '2', '8', '9', 'B', '5', '4', 'B', '8', '3', '8', '1', 'C', 'E', 'B', '7', 'F', 'C', 'F', 'C', '0', '4', 'E', '1', '9', 'F', '6', 'D', '4', 'C', '5', '0', '1', '5', '4', '5', '3', '2', '9', '1', '0', '9', 'B', '7', 'E', 'E', 'B', 'E', '1', 'F', '3', 'E', '2', 'F', 'E', '6', 'D', '7', '7', '2', 'A', '6', '4', 'B', 'D', 'E', '9', '8', '2', 'F', 'A', 'C', '5', '8', '7', 'C', '2', 'A', '4', 'F', '5', '9', '7', '2', '6', '4', '1', 'A', '5', '6', '0', '6', 'F', 'F', 'E', '9', '4', 'C', '2', '8', 'A', '4', '2', '9', 'B', '5', '2', 'F', 'A', '0', '8', 'E', '6', '4', '4', 'D', 'B', 'C', '3', '3', '6', '6', 'F', '4', 'F', '4', '9', '8', 'E', 'A', '3', '9', '5', 'E', 'C', '0', '1', '4', '9', 'B', '8', '4', '5', '7', 'E', 'A', '8', '5', 'C', '8', '8', '4', '9', 'E', '2', '5', 'A', '9', '5', '0', 'F', 'D', 'C', 'E', '2', '2', 'E', '0', '6', 'E', '5', 'E', 'C', '6', '9', '6', '6', '1', '6', 'E', 'B', '2', '4', '5', 'C', 'E', '7', 'E', 'A', 'C', 'F', 'B', '6', '3', 'B', '7', 'D', 'A', 'E', '3', '0', 'B', '8', '2', '5', 'B', '9', '9', '4', '5', '4', 'B', '4', 'F', '7', 'C', '3', '9', '7', 'F', '8', '7', 'A', 'C', 'F', '2', '2', 'C', 'D', 'A', '5', 'C', '7', '0', 'B', '8', '9', '0', '2', '7', 'C', '2', '8', '5', 'B', '5', '0', 'F', 'A', 'D', '9', '5', '8', '0', 'B', '5', '0', '9', '2', '1', '1', '4', 'F', '6', '2', '7', '3', 'D', 'D', '3', 'E', '1', 'C', '7', '7', '0', 'E', '0', '9', '6', 'C', '3', '5', '1', '1', 'D', 'D', '7', 'C', '3', '4', '0', 'A', '0', '5', '3', '0', '2', 'E', 'B', '7', '7', '1', '4', '6', '4', '0', 'D', 'E', '4', 'B', '7', 'A', 'C', 'B', '7', '2', '4', '2', '3', '7', 'C', '0', '4', 'B', 'D', '9', '4', 'F', '3', '4', 'F', 'D', 'E', 'B', '4', '2', '4', 'B', '5', 'C', '7', '9', '9', 'A', '8', 'B', '9', 'F', '6', '6', '7', 'B', '7', '0', 'E', '4', '2', '2', '4', '8', 'E', '5', 'A', 'A', '7', '6', '4', 'D', '9', '7', 'F', '1', 'E', 'A', '7', '3', '2', '8', 'E', 'B', '8', 'B', '6', '4', '4', '6', 'C', '9', '3', '0', '5', '2', 'F', 'B', '1', '7', '7', '8', 'B', '9', '6', 'F', 'B', '1', '8', 'A', '3', '1', '1', 'B', 'D', '8', '6', 'D', 'F', 'C', '7', '2', 'B', 'C', 'A', '9', '8', '3', '5', 'D', '0', 'F', 'F', '9', 'B', '7', '6', '5', 'B', '7', '6', '8', '4', '0', '8', 'D', '2', '1', '2', 'F', '9', '1', '3', 'E', 'E', '8', 'C', '0', 'F', '1', '5', '7', '0', 'B', '8', 'F', 'E', '4', 'B', 'C', 'F', 'E', '9', 'E', '0', '4', '5', '6', 'F', '0', '6', 'B', '3', 'C', '2', '1', 'A', '2', '7', 'B', '2', 'B', 'A', '2', '0', '7', 'D', '2', '6', '0', 'F', '3', 'B', '6', 'F', 'B', '1', '6', '6', 'D', 'B', '4', '4', '3', 'D', '7', '9', 'F', 'A', '8', '7', '5', '4', '2', 'C', 'B', '7', '3', '1', '3', '9', 'F', '8', 'B', 'F', 'E', '8', '1', '6', '9', '4', '3', '2', '1', 'A', '2', 'A', '5', 'A', '9', '5', '8', '7', '0', 'C', 'A', 'B', 'B', 'D', 'D', '0', '8', '6', '1', '2', '1', '5', '0', 'C', '2', '6', '0', '4', '7', '7', '3', '4', '4', '8', 'D', '2', '3', '0', 'B', '5', 'E', '0', '5', '7', '4', 'A', '5', 'A', '1', 'E', '9', 'B', '1', '6', '3', '8', '1', 'F', 'D', '7', 'D', '9', '6', '5', '3', '3', '1', '5', 'E', '9', 'D', '6', '1', '1', '1', '6', '9', '7', 'C', '2', '9', '7', 'E', '3', '5', '1', '9', '4', '6', 'A', '3', 'B', '6', 'D', '9', 'E', '6', 'F', 'F', '1', 'E', '4', 'A', 'D', '9', 'B', '2', 'A', '6', 'F', '3', 'E', '5', '5', '4', '4', 'D', 'C', '0', 'D', 'B', '1', '5', '0', 'C', '5', '6', 'C', '8', '4', 'A', '2', '9', 'A', '0', '8', 'A', 'A', '5', 'D', 'D', 'C', '8', '6', 'E', 'A', 'D', '7', 'F', '3', '5', '6', 'F', 'D', 'E', '8', '4', '8', 'B', '1', '0', '9', 'C', '1', '3', '2', '9', '9', 'A', '6', 'E', 'B', '5', 'C', '4', 'B', '8', '3', '9', 'B', '3', '7', '7', '9', '1', '6', '2', '8', '2', '2', '3', 'E', '6', '7', '4', 'F', '0', '9', '9', '0', '8', '5', '3', '7', '1', '3', '0', '2', 'F', '0', '7', '9', '5', '3', 'F', '2', 'D', '6', '2', '8', '9', 'E', 'E', 'F', 'A', 'A', '5', '4', '3', '2', '7', '2', '5', '0', '4', 'C', 'C', '5', 'A', 'B', '1', '0', '2', 'F', '1', '9', '9', '1', '1', '3', '8', '9', '9', '7', '0', '7', '6', '9', '9', '6', 'B', 'A', '3', '7', '6', 'D', '4', '1', '5', '0', 'B', '3', 'D', '9', '6', 'B', 'C', 'B', '7', 'B', '4', 'F', 'F', '4', '7', '4', '8', '9', '1', 'B', '4', '5', 'A', '6', '7', 'E', '7', 'F', '9', 'F', '5', '3', '6', '5', 'C', '2', '4', '5', '5', 'D', '4', '8', 'C', '3', '6', 'E', '8', '0', '6', '0', '7', 'B', '0', 'B', '9', '7', 'E', '4', '0', '9', 'D', 'C', 'F', 'E', 'B', 'D', 'D', 'B', 'D', 'E', '1', '8', '4', 'C', '3', '3', '9', '3', '6', '9', '0', 'C', '8', 'E', '7', '0', '4', 'A', '9', '5', 'B', '5', 'B', 'A', '2', '3', 'F', '3', '5', '2', '0', 'D', 'C', '5', '4', 'C', '7', '0', '4', 'F', '0', 'C', 'E', '2', '7', 'B', 'A', 'C', 'C', '0', 'A', 'E', '3', 'B', '0', '6', 'C', '4', 'A', '4', '2', '8', 'E', '5', '2', 'E', 'F', '3', '8', '4', '4', '5', 'E', 'A', '2', 'F', '1', '3', '9', '9', 'D', '6', 'D', '6', '8', '4', '5', '7', '0', 'C', 'B', '5', 'E', '3', 'A', 'C', 'B', '8', 'B', '2', '6', 'B', 'D', '2', '8', '0', '3', '9', '8', 'F', 'C', 'D', '1', 'C', '0', '5', '2', '2', 'E', '9', 'B', '5', '0', 'B', '5', '0', '0', 'C', 'D', '4', '2', 'F', '5', '8', 'D', 'A', '8', '5', '9', '3', '3', '6', '0', '2', '8', 'D', '2', 'E', '3', 'F', '3', '2', '4', '4', 'B', '2', 'A', '7', 'A', 'F', '9', 'D', '7', 'C', '9', 'B', '3', 'B', '7', 'C', 'F', '3', '7', 'A', '5', '0', '1', '5', '9', '3', '8', '3', '4', '1', '9', 'D', '2', 'C', 'A', 'E', '7', 'D', 'D', 'D', 'F', 'D', '7', '4', 'C', '5', 'B', '2', '3', '5', '0', 'A', '8', '8', 'D', '3', 'C', '7', '1', 'B', 'E', '6', '0', '5', '7', '3', '5', '0', 'D', '1', 'E', 'A', 'C', 'E', 'C', '3', '8', '1', '1', 'B', '6', 'A', 'D', 'A', 'C', 'F', '1', '5', '1', '4', 'B', '4', '8', '0', '6', '3', 'F', '3', '0', '4', 'E', 'E', 'D', '8', '3', '3', '8', 'E', '3', 'C', '3', '2', '2', 'D', '5', 'E', 'E', 'A', '2', '1', 'E', '6', '9', '6', 'D', 'F', '6', '6', 'C', 'E', '6', 'A', 'C', '1', 'E', 'D', '2', '1', '8', 'C', 'E', '7', '8', '0', 'D', 'B', '3', '7', '3', '8', '4', '0', 'A', 'B', '1', 'E', '5', 'A', '2', 'F', '8', 'E', '2', '6', '9', '9', '1', 'C', '5', '2', 'E', 'C', '4', '3', '5', '3', '5', '4', '6', '7', '1', '1', '6', '4', '7', 'C', '7', '6', 'E', '4', 'E', 'E', '0', '3', '3', '1', '0', '4', '7', '7', 'C', 'F', 'F', '3', 'C', '0', '6', '0', '2', '1', 'E', 'B', '7', 'A', '6', '0', '9', '0', '4', '9', '6', '2', '7', 'C', '3', '2', 'A', '2', 'B', '9', 'A', 'B', '9', 'C', '0', '1', 'A', '3', 'A', '0', 'E', 'C', 'B', 'E', 'F', 'F', '4', 'C', '5', '9', 'E', 'B', 'F', '6', 'B', 'B', 'F', '5', '0', '6', '4', '3', '2', 'A', '0', '7', '6', 'F', 'A', '8', 'B', '4', 'C', '7', '7', '2', 'D', '1', '8', 'E', 'F', '3', '5', 'D', '3', '3', '2', '9', '8', '8', 'C', '5', '9', '3', '5', 'A', '7', '1', '5', '6', 'B', '1', '6', 'D', 'E', '8', '2', 'B', '1', 'F', '3', '2', '7', 'A', '3', '0', '5', '5', '2', '2', '7', 'C', 'F', 'E', 'A', 'D', '3', 'C', '7', '0', '3', 'E', '7', '3', '5', 'F', '1', '3', 'F', '8', '6', '3', '7', 'E', 'B', '2', 'D', 'A', '2', 'D', '2', 'E', '5', '6', 'E', 'C', 'F', '4', '8', 'B', '0', 'A', '0', '2', 'D', '5', 'C', '0', 'A', 'B', '3', 'A', '7', 'E', 'D', '8', '1', '0', 'C', '6', '4', '8', 'C', '9', '8', '0', '9', '9', '2', 'F', 'E', 'E', 'B', '9', '9', 'E', 'D', '2', 'E', '0', 'C', 'C', 'F', 'F', '0', '0', 'C', '8', 'E', 'F', '7', '3', 'E', '6', 'D', 'D', 'A', 'C', '8', '6', '2', '4', '0', '8', '3', '9', 'E', '2', 'A', '9', '3', 'C', '5', '5', '9', '3', 'C', '3', '6', '3', 'B', 'F', '7', '6', '1', '2', '1', 'A', '0', 'C', 'C', '7', '7', '7', '4', '9', '5', '7', '2', '5', 'C', '5', 'E', '4', 'B', 'C', '3', '5', 'B', 'C', 'F', '4', '1', '2', 'B', '1', 'B', '0', '5', '2', 'C', '9', 'C', 'A', '0', 'A', '2', 'B', '3', 'F', 'A', 'D', 'A', '0', '7', 'D', '4', '7', '4', 'D', 'D', 'D', '0', 'C', 'C', '2', 'C', 'E', '8', '5', '3', 'D', 'A', '4', '3', '8', '5', 'C', '2', '0', '2', '0', '2', '4', '3', 'E', '5', '1', '9', 'A', '1', '9', 'D', '8', 'D', '9', '3', '4', '6', 'C', 'E', 'E', '3', 'E', 'D', 'A', '0', '2', '9', '3', '8', '3', '9', '9', '6', 'D', 'C', '5', 'C', '3', 'A', 'C', 'F', '5', 'C', '6', 'A', 'F', '0', 'A', '0', '5', 'D', 'E', '2', 'C', '7', '1', '0', 'D', '5', 'C', '7', '5', 'D', 'C', 'D', '2', 'D', 'F', '9', '1', '5', 'D', '7', '6', '7', '9', '3', '3', '7', '9', 'D', '6', 'F', 'C', 'B', '9', '0', '7', 'A', '3', '0', '8', '9', '3', '1', 'E', '0', '5', '5', '1', 'E', 'F', '0', 'B', '7', '3', '5', 'F', 'C', 'D', 'C', '9', 'C', '8', 'C', '8', '4', '1', '3', '1', '4', 'F', '2', '9', 'C', '9', 'B', '0', '6', 'B', 'D', '4', '1', '0', 'E', 'D', '8', '8', '2', 'A', 'C', '9', '1', '1', 'C', '0', '6', '2', 'B', 'B', '2', 'A', 'E', '9', '1', '7', '3', '7', '1', 'D', '0', 'E', '6', '0', 'D', 'E', '4', 'A', 'A', '9', '8', '0', '0', '2', '6', 'F', 'C', 'B', 'E', '3', '1', 'A', '7', '9', '3', 'A', '7', '1', '1', 'E', 'A', 'F', '3', 'A', '3', '7', '0', '4', '8', 'E', 'B', 'B', 'F', 'A', '5', '7', 'D', '0', '7', '2', '9', 'B', 'D', 'D', '8', '0', '2', 'F', 'D', 'B', 'D', '2', '0', '9', 'F', 'F', '5', '8', 'E', 'B', 'C', '0', '7', '8', '9', 'F', 'A', '8', 'D', 'F', '3', '5', '1', '4', '1', 'C', 'F', '1', '1', '5', 'E', 'C', '5', '8', 'F', '9', '9', '5', '2', '4', '2', '4', 'B', '0', '3', 'E', '5', '5', '7', '4', '3', 'B', '1', 'A', '2', '8', '2', '5', '7', 'F', '4', '3', 'B', '6', '4', 'B', 'B', '3', '4', 'D', 'F', '3', '9', '7', '5', '7', 'A', '1', '8', '5', '8', 'A', '2', '1', 'E', 'C', 'B', '4', '8', '1', 'C', '7', '1', '2', '3', '7', 'E', '9', '9', '8', 'F', '8', '6', 'D', '3', 'A', 'F', '1', 'B', '9', 'D', 'B', '0', '6', '3', 'D', 'E', '3', 'A', '0', 'B', '6', 'B', '8', '9', '3', 'F', '7', '7', '8', '0', '4', 'B', 'E', '3', 'F', 'C', '9', 'E', '6', 'F', '9', '3', 'E', '6', 'A', '6', 'E', '5', '9', 'F', 'B', 'B', 'A', '7', '0', '9', 'D', 'E', '9', 'C', '7', 'D', 'D', 'D', 'C', '2', '6', '3', '2', 'D', '1', '3', '0', '2', '0', '4', 'B', '4', '5', 'C', '1', '6', '1', '8', '5', '5', '7', '5', '6', '7', 'C', 'B', 'D', '2', 'E', '9', '7', '1', 'D', '1', '0', '9', 'F', '5', 'B', '2', '1', 'E', '5', 'A', '3', 'A', '0', '3', 'F', 'D', '0', 'E', 'D', 'F', 'D', 'B', 'B', 'F', '3', '2', 'F', '0', 'B', '9', 'E', '5', '9', '7', '8', '8', 'C', '3', '9', 'A', 'B', '7', 'A', '9', '2', 'A', '8', 'C', '7', 'D', '8', 'E', 'B', 'C', '2', '7', '5', '7', 'D', 'C', '1', '3', 'D', '0', 'E', '1', 'A', '9', '3', 'D', '5', '3', 'B', 'B', '4', '3', '3', 'F', 'C', '1', '4', 'F', 'F', 'D', '3', '8', 'B', 'B', 'F', '8', 'B', '6', 'B', '4', '7', 'B', '2', '0', '7', '6', 'C', '6', '7', '8', '3', '0', '1', '9', 'E', 'A', '5', 'C', 'D', '9', '6', 'A', '1', '4', 'C', '2', 'D', '2', 'F', 'B', 'C', '3', '4', '0', '9', '1', '5', '6', 'C', '1', 'B', '6', 'E', 'F', '7', 'D', '2', '1', '2', '8', 'A', 'C', '0', 'E', 'B', '6', '0', '5', '5', '1', '7', 'C', 'D', '5', '3', '5', '8', '6', '0', '5', 'D', 'C', '8', '3', '0', 'D', 'D', '0', '5', '8', '3', '9', '0', 'C', '6', 'F', 'C', '3', 'F', 'C', '0', 'B', '8', '3', '4', '2', '2', 'B', '4', 'B', '2', '3', '8', '0', 'A', '3', 'D', '4', 'C', '9', '5', 'B', '6', '2', 'D', '6', '6', '8', '6', '9', '1', '6', '8', '5', '0', '1', '7', '5', 'A', 'A', 'A', 'B', 'D', '7', 'D', '0', '3', '3', 'B', 'F', '6', 'B', '2', 'C', 'D', 'E', '5', '4', '6', '7', '3', 'E', '8', '0', 'A', '4', '7', '2', 'B', '8', 'A', '2', '9', '0', 'C', 'B', 'F', 'B', '8', '3', '1', '1', '8', 'B', 'A', 'C', 'F', 'A', 'A', 'A', 'E', '7', '4', '0', 'B', 'F', '8', '8', '8', 'E', '7', 'E', '7', 'F', '8', 'C', '1', 'A', '8', 'E', 'C', '6', 'F', 'F', '2', 'C', '4', '9', '5', 'F', '7', 'B', 'F', 'F', '5', '8', '1', '6', '7', 'F', 'C', '8', '0', '5', '9', '7', '1', 'E', '2', '6', '5', '0', '7', 'C', '7', 'F', '1', '5', 'C', '1', 'D', '8', 'E', 'F', '8', 'E', '8', '7', '9', '1', 'E', '3', 'B', 'D', '7', '9', '1', 'F', 'C', 'A', '8', '2', '1', 'B', 'B', '9', 'C', '7', 'D', '4', '5', '8', 'C', 'D', 'F', '3', 'A', '7', '8', '4', 'C', 'D', 'A', 'F', 'F', '5', '0', '3', 'D', 'B', 'F', '9', 'D', 'C', '4', 'D', 'C', 'B', 'A', 'F', '4', '3', '6', '6', '2', '7', '7', 'A', '5', 'A', 'E', '7', '1', '5', '7', '8', 'E', '7', 'C', '6', '0', '3', 'C', 'E', 'A', '8', 'A', 'A', '1', '0', '8', '9', '4', 'A', 'A', '4', '4', '9', 'B', '5', 'C', '4', '0', 'C', '3', 'B', '8', 'A', '3', 'F', 'E', '5', 'C', '1', '8', 'D', '1', '2', 'B', '7', '9', 'F', 'B', '4', '2', '8', '2', 'F', '9', 'B', '7', '5', 'B', '3', 'C', 'C', '1', 'C', '4', '9', '6', '7', 'A', '1', '9', '7', '7', '2', '6', 'B', 'E', '0', 'F', '0', '8', '8', '1', '4', '1', 'A', '4', '3', '6', '9', '8', 'A', 'A', '2', 'F', 'F', '3', '7', 'A', '9', 'E', 'C', 'A', '1', '0', 'E', '4', 'D', 'B', 'C', '1', 'A', '7', 'C', '1', 'B', 'F', '6', '2', '1', '4', 'C', '6', '2', '4', '5', '6', '2', 'E', 'D', '9', 'A', '7', 'C', '0', 'B', '2', '8', '5', 'E', '8', 'C', 'E', '1', 'A', 'E', 'C', '3', '0', 'C', 'C', '5', 'F', '6', 'A', '0', 'A', '9', 'E', 'B', '8', 'C', '6', 'C', 'E', 'D', '9', 'F', '3', 'C', 'E', '3', '4', 'B', '4', '4', 'E', '3', 'C', '2', '8', 'F', 'E', 'D', 'B', 'D', 'C', '8', 'A', '9', '7', 'D', 'F', 'A', 'B', '8', '2', 'B', 'D', 'E', '1', '3', 'F', '2', '3', '6', 'C', '3', 'F', '3', 'F', '9', 'B', 'C', '0', '0', '8', 'C', 'F', '9', '3', '9', '3', 'A', 'B', '4', 'C', '2', '6', '8', 'B', '3', 'C', '9', '4', '2', '7', 'D', '8', 'D', 'C', 'F', '2', '9', '7', 'F', '3', '2', 'C', '1', '6', '7', '4', '6', '8', 'A', '8', '6', '0', 'C', '6', 'E', '9', '6', '7', '6', '0', '3', 'C', '4', '6', '1', 'D', 'B', 'F', '8', '0', '6', '7', '6', '6', 'F', '4', '2', 'C', '0', 'B', '4', '0', '9', '2', 'E', 'A', 'E', 'C', 'A', '7', 'F', '6', '0', 'B', '9', '3', '4', 'E', '1', '8', '9', 'A', '7', '5', '3', '8', '2', '4', '1', '4', '7', 'E', 'B', '7', 'D', '3', '1', 'E', 'B', 'B', '7', 'F', 'B', '1', '6', '4', '5', 'B', 'D', '0', 'D', 'B', '8', '5', 'E', '0', '6', 'B', '2', '5', 'C', '7', '4', 'C', '0', 'F', '8', '4', 'E', 'B', 'B', 'F', '6', '0', '3', 'B', '3', '1', '6', '9', 'E', 'F', 'B', '0', 'B', '4', '0', 'D', '2', '1', '4', 'E', '6', '2', '9', '9', 'A', '2', 'E', 'F', 'A', '7', '2', '5', '1', '1', '3', '7', '4', '7', 'E', '6', '0', '7', 'E', '2', 'D', 'E', 'B', 'C', '7', 'F', '6', '3', 'E', 'F', 'C', 'B', '3', '2', '0', 'F', '5', '6', '8', '6', '8', '7', 'E', '9', '5', '0', '4', '7', '7', '0', 'A', 'D', 'C', '0', '4', '6', '2', 'D', 'F', '4', 'E', 'D', '3', '8', '0', '6', 'B', '2', 'A', '6', '9', '0', 'A', '4', '0', '5', 'B', 'F', 'E', 'B', '0', '8', 'C', '5', '4', '8', '6', 'E', 'D', 'A', '0', '3', '2', 'C', 'B', '5', '2', '3', '1', '7', 'C', 'F', 'F', '0', '9', '2', '7', '4', '7', 'E', 'D', 'D', 'B', 'B', '5', 'B', '9', '6', '5', '4', '9', '7', '8', 'A', '3', '9', 'C', '0', '7', 'E', 'D', 'A', 'D', '6', '3', 'B', 'C', 'B', 'E', 'C', '3', '2', '2', 'E', 'E', '5', 'B', '2', '0', 'D', '6', 'F', '8', 'A', '7', 'F', 'C', 'B', '6', 'A', '7', 'D', 'A', 'C', '4', '1', 'F', 'F', '7', '8', '6', '8', '2', 'D', 'A', 'B', '3', '8', '2', '3', '7', 'B', 'E', 'F', 'D', 'E', 'B', '5', '1', '9', '7', '8', 'B', '0', 'A', 'C', 'C', 'E', 'C', 'C', '9', '8', 'E', 'E', '5', 'D', '1', '3', 'B', '9', 'C', 'E', 'F', 'A', '0', '8', '2', 'F', '3', '8', '1', 'D', 'B', 'E', '5', '9', 'A', 'E', '9', 'C', '1', '1', '3', 'D', '2', '3', 'B', '9', '0', '8', 'C', '2', 'E', '7', '5', 'C', '4', '3', '3', 'F', 'B', 'F', '7', 'A', 'D', 'F', '1', 'C', 'D', '6', '2', '3', 'F', 'F', '4', 'F', 'A', 'B', 'E', '8', '7', 'E', '4', '3', 'C', '2', '2', '6', '7', '0', '4', '7', '3', '0', 'F', '0', '6', '4', '0', 'F', '9', 'D', '4', '8', '3', 'C', '1', 'D', 'D', 'C', 'E', '3', '5', 'F', 'E', '4', '4', '6', 'A', 'D', '6', '0', '7', 'C', 'D', '7', 'B', '4', '8', 'F', '0', '4', 'C', '0', '2', '0', '6', '6', 'C', '8', '0', 'F', '2', 'F', 'B', 'B', '6', 'D', 'B', 'D', 'C', '1', 'B', '1', 'D', '5', '2', 'E', '2', '0', '2', '1', 'D', '6', 'A', '8', 'B', '8', '2', 'D', '2', '9', '5', '5', '5', '8', '9', 'C', '3', '3', 'C', 'A', 'F', '3', 'B', '2', '4', '2', 'F', '9', '2', 'B', '9', '0', 'B', '2', '9', '0', '8', '2', '0', 'F', '6', '4', '2', 'F', '1', '9', 'B', 'D', 'F', '5', '8', 'F', 'B', '8', 'A', '4', '2', '3', '2', '0', '0', 'F', '0', '9', '6', '2', '9', '1', 'D', 'D', '3', '3', '7', '7', '7', '1', '2', 'D', '6', '3', 'F', '6', 'D', '7', 'C', 'F', 'C', '2', '5', 'A', '9', 'D', '8', '0', '4', '4', '8', 'D', '6', '7', 'F', '6', 'C', '1', '4', 'D', '1', '5', 'D', '8', '1', '4', '0', '3', '9', '8', '7', 'E', 'A', 'A', '8', '7', 'B', 'E', 'F', 'C', '6', 'E', 'E', '2', '6', '7', '8', '1', 'B', '6', '0', 'A', '7', '4', '7', '5', '5', '3', '3', '3', '6', 'A', '0', '2', '9', 'F', '8', 'E', 'D', 'B', '6', '3', 'A', 'D', '2', '0', 'B', '9', '0', '9', '2', 'C', '7', 'A', 'B', '4', 'A', 'A', 'B', '9', '2', 'A', '7', '2', '0', 'A', '7', '0', 'D', 'C', '3', 'D', '6', '9', 'B', 'E', '0', '7', 'D', '1', '1', '0', '2', '4', 'F', '6', '0', '6', '1', 'B', '6', '5', 'F', '9', '7', 'C', '8', '9', '8', '8', 'F', 'B', '8', '6', '4', 'A', '5', '8', 'F', '6', '2', 'B', '7', 'D', '2', '4', '0', 'D', '4', '3', '1', '1', '7', 'A', 'F', '7', '1', '4', 'B', '1', '4', 'D', 'E', '4', '7', '6', '0', '2', 'E', 'B', '4', '8', 'D', 'D', '1', '3', 'B', 'D', '8', 'D', '8', '8', 'F', '3', 'B', '3', 'C', 'E', 'F', '1', 'A', '8', '9', 'D', 'E', '7', 'A', '0', '1', '2', '2', '8', '3', 'A', 'E', 'A', '0', 'D', 'C', '5', '8', '5', '1', 'B', 'E', '5', '0', '3', '2', 'B', '7', '9', '2', 'E', '8', '9', '8', 'E', '7', '2', 'B', '1', '4', '5', 'A', 'C', '6', '0', 'A', 'B', 'B', 'B', '1', '2', '1', '2', '2', '4', '3', '9', '0', 'D', 'A', 'D', 'E', '3', '8', '4', '0', 'F', '2', '9', '0', '3', '0', 'E', 'B', '5', 'E', 'D', '8', 'A', 'B', 'A', '1', 'D', 'A', '1', 'F', '3', '0', 'E', '5', '9', '6', 'A', 'A', '3', '5', '5', '7', '3', 'D', '5', '2', 'D', 'D', 'D', 'E', 'B', '6', 'A', 'A', 'A', 'C', '6', 'C', 'D', '4', '2', 'E', 'D', '2', 'B', 'B', 'D', 'A', 'E', '1', 'F', '8', 'F', 'E', 'B', '2', 'E', '9', '1', '9', '7', '9', 'B', '6', 'F', '5', '0', 'A', 'A', 'A', '9', '2', '0', '5', 'E', '7', '6', 'C', '4', 'C', '6', '4', 'F', '5', '9', '0', '5', '6', 'F', 'F', 'C', '7', 'E', 'A', '2', '3', 'D', '1', 'B', '3', '8', '7', 'B', '2', '3', 'B', 'C', 'B', '6', '1', '0', '2', '4', '8', 'B', '1', 'E', 'C', '6', '3', '9', '1', '2', '9', 'B', 'C', '9', '4', 'A', '4', 'A', '6', 'B', '2', '3', '9', '9', '6', '9', '2', '7', 'C', 'A', '2', 'C', '9', '7', 'F', 'B', 'B', 'E', 'D', '3', '4', '0', '5', '5', 'D', 'A', '1', '8', 'F', '8', '3', '2', 'A', '0', 'F', '4', '2', '8', '4', '8', '8', '8', '5', 'E', '5', '2', 'D', '3', 'A', '6', 'B', 'F', '7', '2', 'E', '5', '4', '8', '5', '4', 'B', 'D', '6', '7', '8', '6', '8', 'C', '0', '2', '0', '9', '5', '8', '7', 'F', 'F', 'C', '3', 'B', '6', '5', '9', 'B', '2', 'A', '1', '5', 'A', '6', '7', '9', 'C', 'B', '1', 'F', 'A', '9', '6', 'E', '7', '4', '9', 'D', '0', 'C', 'A', 'A', 'A', '8', '7', '7', '9', 'D', '3', 'B', 'A', '2', '9', '8', '4', '7', '0', '0', 'C', 'C', '3', '3', '4', '0', '5', '7', 'F', '6', 'E', '0', '3', 'D', '4', '7', '1', 'F', '3', '4', '4', '3', '6', '6', '7', 'D', 'E', '9', '0', '6', 'C', '7', '7', 'B', '9', '3', '0', 'A', '7', '5', 'B', 'F', 'F', '2', '2', 'F', 'C', '0', '4', '3', '6', '3', '5', '6', 'E', '8', '6', 'F', '9', '3', '9', '6', '1', 'F', '0', '3', '9', '1', 'D', 'B', '7', '3', 'D', '1', '8', '4', '9', 'B', '6', '1', 'F', '8', 'E', '6', '0', 'A', '6', 'F', 'C', '9', '1', 'A', '0', '3', 'A', '3', '9', '2', 'C', 'F', '8', '6', '4', '2', '0', '8', 'F', '3', '3', 'C', 'E', '6', '4', '1', '7', 'E', '8', '7', '4', 'D', 'E', '2', '5', '3', '2', '9', '8', '7', '3', '7', 'E', '5', 'F', '8', '6', '2', '1', 'D', '5', '7', 'D', 'A', 'A', '5', 'B', 'F', 'B', '1', '5', '3', 'B', 'F', 'E', '2', '1', 'C', '8', '2', 'D', 'B', 'F', '2', 'F', 'F', '0', 'C', '3', '3', 'A', '2', '4', '9', '4', 'C', '5', 'E', '7', '8', '8', '1', 'D', 'D', '1', 'F', '9', 'C', '1', '4', '3', 'C', 'E', 'C', '7', '5', 'E', 'A', '2', 'F', '0', '4', '7', '0', '5', '6', '7', '7', '6', '9', '6', 'B', '5', 'E', '2', '8', 'C', 'C', '5', '8', '3', '8', 'F', 'A', 'B', '9', 'D', 'F', '0', '1', '9', 'F', 'F', 'C', '8', 'A', '5', '9', '3', '0', 'E', 'B', 'A', '5', '9', '5', 'B', '4', '2', 'D', '0', '4', 'F', '0', '0', '8', '9', '8', 'C', 'F', '8', '8', 'E', '5', 'C', '8', '7', '6', 'E', '3', '9', 'D', '3', 'C', 'D', 'F', '9', '6', '6', '7', '7', '9', 'C', '1', 'B', 'E', 'F', '3', '8', 'A', '2', '2', '8', '0', '4', '0', 'B', '8', '0', 'E', '0', 'B', '5', '1', 'C', '4', '3', '1', '3', '5', '4', '6', '9', '1', 'A', '8', '1', 'D', 'A', '1', 'A', '3', '2', '0', '5', '0', '2', '2', 'A', '5', 'C', '3', '3', '4', 'D', '3', 'C', 'F', 'D', 'B', '3', 'C', 'F', '5', '8', 'E', '6', '8', '8', '5', '2', '9', 'A', '1', 'E', '2', 'F', '9', '2', 'C', '6', 'B', '0', 'E', '1', 'B', '0', '7', 'F', 'F', '2', 'B', '6', 'B', 'C', '9', '4', 'D', '3', 'C', 'B', '9', '2', 'D', '2', '5', 'C', 'A', '6', 'D', 'C', '5', '8', 'B', 'C', '0', '2', 'D', 'E', 'D', '1', 'A', 'D', 'A', '0', '5', '7', '2', '3', '8', 'B', '7', '5', '2', '3', '1', '7', 'B', 'E', '0', '8', '3', 'D', '1', '2', '2', 'B', '4', 'D', 'D', '9', 'D', '7', 'E', '7', '8', '3', '1', '9', 'B', '7', '3', '2', '1', '2', '9', '2', '3', '2', 'F', '0', '9', '1', 'C', 'C', '9', 'D', '6', 'A', 'E', 'F', 'C', '0', '6', '0', 'B', '2', '1', '3', '6', '5', '1', '9', '2', '6', '0', '5', '2', '1', '6', 'A', 'C', '6', 'B', 'F', '8', '6', 'E', 'E', '7', 'A', 'F', 'C', 'B', 'D', '6', '1', '6', '8', '7', '6', 'F', 'A', 'B', '0', '5', '6', '4', '5', 'B', '5', '4', 'D', '9', '3', 'B', 'B', 'D', '9', 'E', '8', '3', '4', 'F', 'E', '9', '3', '3', '1', '7', '3', '4', 'A', '6', 'B', '1', '5', '8', '0', 'B', '8', '1', '0', '7', 'F', '5', '7', '4', '5', '0', 'D', 'A', '5', '2', '6', 'E', '7', 'B', '2', 'C', 'A', '3', '9', '6', 'A', 'C', '0', '4', '1', '2', '2', '2', 'C', '6', 'C', 'B', '1', '0', '7', '0', '8', 'B', '3', '7', 'E', '3', '9', 'E', 'E', '3', '3', 'F', '6', 'A', '1', '2', '2', 'B', '5', '9', 'F', 'E', 'F', '2', 'E', 'E', 'E', '1', '2', 'B', '2', '1', '7', 'A', '3', 'A', '8', '1', '0', '9', 'F', '0', 'A', 'E', '3', 'F', 'C', '8', '2', '4', '0', '3', 'A', '5', '0', '7', '9', 'E', 'A', '7', '5', '1', 'F', '8', '8', '9', '2', 'B', '1', '5', '6', '4', '9', '8', '0', '8', 'E', 'B', '1', '2', 'A', '0', '4', '7', '7', '7', 'F', '6', '1', 'A', 'E', '3', '9', 'A', '4', '6', 'A', '4', 'A', 'D', '8', '8', '5', '8', 'D', 'F', '3', '5', 'F', '4', '2', '5', 'C', '2', '6', 'E', '8', '6', '0', '2', 'D', '6', '2', 'E', '7', '8', 'B', 'A', '7', '2', '4', 'B', '6', '4', '5', '1', 'A', '7', '7', 'B', 'E', 'D', '0', '0', '1', 'F', '1', '9', '4', 'C', '6', '5', 'C', 'C', '2', '1', '7', '0', 'F', '5', '1', '2', 'C', 'C', 'C', '5', '7', '5', '9', 'F', '5', 'C', 'F', 'D', '5', '6', '6', 'A', 'E', 'F', '3', 'B', 'E', '1', 'F', '1', '9', 'F', '3', 'E', '5', 'A', 'D', 'E', 'E', '6', '9', '7', '1', '1', 'F', '5', '7', '1', 'C', 'D', '0', '7', 'E', '8', '2', 'B', '0', '4', 'B', '8', '8', 'E', '6', '4', '7', '5', 'C', '4', '2', '2', '2', '1', 'F', '7', '1', 'E', '6', '7', '0', '3', '3', '7', 'F', '2', '9', 'F', 'C', '7', 'B', '8', '2', 'B', '8', '7', '4', '7', 'D', '8', 'F', 'F', 'A', '7', '0', '7', '6', '4', '3', '6', '7', 'E', '3', '5', 'E', 'F', 'B', '4', '1', '8', 'B', 'C', '3', '1', 'D', 'F', '3', '6', 'B', '4', 'B', '1', 'C', 'E', '7', '6', '8', '1', '5', '7', 'A', '4', '9', '0', 'C', '6', 'C', '9', 'B', 'F', '1', 'A', 'D', 'D', '1', '6', 'C', 'E', '7', 'A', 'E', '3', '3', 'B', '1', '3', 'C', 'E', 'E', 'E', '6', '2', '4', '4', 'B', '4', '0', '7', 'D', 'B', '7', 'C', 'B', 'E', '8', '9', '1', 'A', 'A', '9', '1', '8', 'C', 'C', 'F', '6', 'F', '7', '9', '7', 'D', '6', '9', '6', 'D', '9', '4', 'C', '8', '4', '2', '2', 'C', 'C', '7', '4', '2', 'B', '2', '3', 'E', '4', 'D', 'C', '8', 'B', '1', '4', '1', '4', '7', '2', 'D', '7', '2', '8', '2', '6', '2', 'D', '0', '3', 'D', 'D', '1', '2', '4', '1', '3', '8', '4', '3', 'E', '5', '5', '8', 'B', '9', '8', '1', 'B', 'F', '6', '6', '1', '4', 'C', 'E', '0', '0', 'A', '1', '4', '7', '9', 'E', 'B', 'D', '8', '2', '1', '0', 'D', '0', '7', 'F', '8', '8', 'E', '4', 'C', 'F', 'D', '0', '3', '0', '2', 'A', '3', '0', '7', '2', '3', '0', 'D', '9', 'E', 'F', 'C', '2', '9', 'A', '8', 'C', '5', 'C', 'D', '1', 'E', '2', 'F', 'F', '8', '1', 'D', '1', '5', '0', '5', '2', 'A', 'A', '0', '4', '2', 'B', 'D', '5', 'A', 'D', 'D', '2', 'B', '7', 'E', '1', '0', '0', '9', 'F', 'A', '0', '7', 'A', '6', '9', '6', 'A', '6', '7', '2', '9', 'A', '1', '1', '3', 'F', 'E', 'F', '6', '6', '2', '2', '2', 'A', 'D', 'C', 'B', 'F', '3', '2', 'C', '9', '2', '9', '1', '8', 'A', 'F', '8', '4', '0', '5', '4', '7', '0', '7', '5', '5', 'A', '4', '3', '2', '8', '4', 'D', '9', '3', 'F', '3', 'D', '4', 'C', '9', 'F', 'F', '7', '6', '5', '2', '3', 'D', '9', 'F', 'E', '3', 'E', '1', '5', '4', '9', '6', 'F', '1', 'B', 'D', '5', '1', 'D', '6', '2', '9', 'B', '7', '1', '6', 'D', '5', '0', '4', 'A', '0', 'C', '4', '7', '2', '2', '5', '5', 'E', '0', '0', '3', '8', '3', '3', 'D', '3', '7', 'F', '7', 'F', '2', 'F', 'E', 'C', 'A', '8', '6', '3', '8', 'F', '4', '2', '6', '3', 'B', '7', '4', '9', 'F', '0', '8', 'D', 'D', 'A', '7', '3', '8', '3', '9', 'A', '8', '5', '2', '0', '1', '7', '3', '7', '8', '3', 'C', '7', 'A', '0', 'A', '3', '1', 'D', '2', '7', '2', 'C', 'E', '3', 'F', '0', '8', 'A', 'C', '0', '4', '2', 'A', '1', '9', '7', '1', 'F', 'B', '8', '0', '6', 'C', '1', '8', '2', '3', '1', 'E', '1', '9', '1', '0', 'F', 'F', 'B', '1', 'F', '6', '9', '0', 'C', '1', 'C', '9', '4', 'F', '1', '9', '5', '5', '4', '4', '6', 'E', '8', '4', '0', 'E', '9', '2', 'B', 'A', '3', 'E', '7', 'F', 'A', '0', 'A', '0', '3', '6', '8', 'B', '0', '4', 'F', '5', '8', 'F', '9', 'D', '4', 'F', '9', '5', '0', '2', 'C', '0', 'F', 'E', 'B', '0', '4', '0', '4', '3', '7', 'C', '3', '8', '0', 'F', 'D', '2', '0', 'F', '5', 'A', '5', 'E', '5', '9', '0', 'B', '5', '7', 'F', 'F', 'A', '1', '8', '9', '7', '0', '0', '1', '8', '0', '9', 'A', '6', '4', '5', '0', '2', '2', '0', 'D', '0', '9', '8', 'E', 'E', '8', 'D', 'D', '9', 'C', 'F', '0', 'D', 'D', 'E', 'C', 'A', 'C', '7', '4', 'E', '7', 'E', 'B', 'B', 'D', '1', 'F', 'D', '8', 'B', '2', '0', 'B', '8', '9', '0', '3', '9', '1', 'E', '1', '2', 'B', 'A', '4', '5', 'C', '5', 'B', '4', '2', '0', '5', 'F', '7', 'C', '3', 'E', '8', '7', '9', '3', 'B', 'B', '9', '1', '7', '5', '2', '4', 'F', '5', '9', '7', '3', 'D', '6', 'D', '1', '1', '8', '7', 'D', '1', '5', '2', 'F', '9', '0', '5', '4', 'B', '6', 'D', '0', '7', '3', 'D', '2', 'D', '2', 'D', '8', 'C', '2', '0', 'E', '3', 'A', '4', '5', '0', 'D', '2', '7', 'E', '9', 'C', '5', '8', '1', '8', 'A', '7', '2', '1', 'A', '3', 'E', '4', 'A', '3', 'C', 'A', '9', '4', 'A', '9', '4', '7', 'E', '7', '5', '1', 'E', '0', '5', 'C', 'E', '9', 'C', '6', '0', '0', '1', 'C', 'C', '0', '8', 'E', '1', '1', 'D', '4', '7', 'D', '5', 'D', 'A', 'C', '4', '5', '8', 'F', '0', 'B', '5', 'A', '3', '1', '4', '8', 'E', '5', '0', 'E', '4', 'E', '8', '9', '3', '4', '9', '3', 'C', '1', '9', '1', '8', 'F', 'F', '8', 'B', 'D', '7', '7', '5', 'E', '9', '1', 'B', '4', 'B', 'B', '6', '1', '5', '1', 'A', 'A', '2', '0', '2', '5', '9', '6', 'C', 'A', '3', '5', 'F', '9', '6', '6', '6', '0', '4', '7', 'F', '5', '5', 'B', 'E', '6', 'E', '5', '9', 'C', '5', 'A', '0', 'F', 'A', 'E', '6', 'C', '7', '5', 'E', '7', '5', '3', '9', '9', '9', 'D', '3', 'C', '1', '5', 'F', '6', 'F', '4', '6', '2', '7', 'B', 'A', '3', '4', '7', '1', '1', '7', '8', '2', '1', 'B', 'C', '1', '1', '0', '9', '4', '7', '4', '2', 'A', '0', '3', '8', '2', '8', '3', '9', 'D', 'A', '5', '0', '0', '6', 'E', '9', '0', 'A', '4', 'F', '1', '5', 'B', 'F', 'E', 'D', '3', 'E', '8', 'A', '1', '9', '7', '8', 'F', '4', '0', '3', '7', '7', '6', '8', 'E', '3', '0', '3', '3', '1', '4', '3', 'A', 'B', '5', '4', '3', 'C', '0', 'F', 'A', 'D', 'B', '3', 'F', '1', '2', 'B', '5', '0', '8', '4', '0', '2', 'B', 'E', '6', '2', 'F', 'F', '9', '1', '4', 'B', 'C', '4', 'B', '1', 'A', 'F', 'C', '8', '3', '2', '8', 'E', '2', '3', '8', '7', 'A', '7', '7', '5', 'F', '5', '8', '4', 'F', 'F', '7', '8', 'B', '5', '3', 'A', '2', '8', '7', '6', '6', 'B', 'E', '4', 'A', 'C', '8', '1', '6', 'A', '1', '0', '7', '2', '2', '4', '6', 'E', '5', 'A', '3', '5', 'E', 'D', 'F', '5', 'D', '0', '1', 'F', 'C', '1', '5', 'D', '0', '6', 'B', 'E', 'C', '1', 'C', '4', '7', '8', '1', '2', '0', '4', 'B', 'E', '6', 'E', '2', 'B', '2', '9', 'D', '9', 'B', '8', '4', '5', 'A', '0', '6', '2', 'B', 'D', 'A', 'F', '9', '3', '3', '8', '3', '7', '9', '6', 'E', '5', '7', '8', 'C', '6', '4', '1', '7', 'F', '9', '7', 'D', '2', '1', 'C', 'C', '7', '2', '3', '4', '9', 'E', '3', 'B', 'E', '2', 'D', '3', '7', '5', '6', '6', '1', '5', '7', 'A', '8', '3', '6', 'D', '0', '2', 'E', '4', '0', 'F', 'A', '2', 'A', '6', '6', '8', 'B', 'C', '6', '1', 'B', '3', 'B', 'C', '3', '7', '8', '2', '1', '7', '5', '1', '7', '4', 'E', 'A', '2', 'F', 'D', 'B', '7', '2', '6', '2', '6', '1', '7', '0', '8', '0', '2', '5', 'B', 'E', 'F', '8', '7', 'A', 'E', '0', 'D', 'F', '5', '0', '8', '5', '2', '7', '1', '9', '8', 'D', 'C', '0', 'A', 'E', '5', '9', '1', '6', 'A', 'A', '6', '7', '8', 'D', '8', '4', '9', '9', '5', 'F', '2', '1', '3', '0', 'B', 'A', 'D', 'A', '7', '0', 'B', '7', '1', '5', 'E', 'C', 'C', '1', 'A', 'D', 'D', 'E', '0', '3', '7', '9', '8', '6', '9', '2', '6', 'E', '1', '9', '1', 'C', '3', 'C', 'C', '3', 'B', 'E', 'E', '2', '5', '9', '0', 'F', 'C', '9', '5', 'F', 'B', 'C', 'C', '3', '3', '3', '5', '9', '9', '2', '4', '0', '9', 'E', '2', 'C', '3', 'D', '6', '2', 'D', '8', '0', 'A', '2', 'D', '6', '4', 'B', '7', '1', '4', '1', '3', '6', '2', '6', '9', 'C', 'A', '9', 'A', '7', '8', '2', '1', '8', '4', 'E', 'C', 'C', 'C', 'B', '1', 'C', '0', '1', '0', '9', '5', '5', '1', '7', 'B', 'A', '5', 'F', '4', '2', '5', 'D', 'C', '0', 'C', '9', 'D', '6', '2', '2', '1', 'F', '8', 'F', 'C', 'F', '5', 'C', '0', '3', '4', '9', '6', 'B', '1', '8', '0', '8', '6', '8', 'F', '5', '6', '6', '6', '4', 'E', 'A', '3', 'F', 'B', '3', 'B', 'C', '2', 'E', '1', '3', 'F', 'F', '7', 'F', '1', '8', '2', '0', '8', 'E', '8', '5', '2', 'B', '9', '3', '4', '1', '2', '3', '7', '5', '5', 'F', '8', '4', '9', 'C', '6', '6', '6', '8', 'F', 'F', '1', '7', 'C', '7', 'F', '9', '2', '0', '6', 'B', '3', '1', '2', 'B', 'A', '2', 'F', '4', 'D', 'E', '9', '7', '7', '9', '3', '9', '6', '1', '8', 'F', '2', 'A', '0', '2', '1', '4', 'C', 'E', 'A', 'C', '0', 'B', '3', 'E', '2', 'C', '2', '1', 'D', 'B', '9', '2', '0', 'A', 'D', 'D', 'C', '9', '2', 'A', '0', '4', '9', 'C', 'A', '3', 'C', '8', 'C', 'A', 'A', '5', '8', '9', '3', '7', '5', '4', '9', 'A', '9', '5', 'F', '1', 'D', '9', 'A', '4', 'F', '9', '9', '9', 'C', 'F', '2', 'E', '9', '5', 'F', 'B', 'A', 'B', 'D', 'D', '4', 'A', 'B', 'D', '5', '4', '9', '8', '7', '3', '6', '6', 'A', '1', 'C', '2', 'B', 'E', 'D', '4', '9', '2', 'D', '6', '3', '5', '0', '8', 'A', 'B', '1', '0', '0', 'C', 'D', '9', '8', 'D', '9', '5', 'F', '7', 'F', 'B', '6', '3', '8', '3', 'B', '7', 'A', 'F', '6', 'E', '3', '3', 'D', '9', '0', '2', 'F', 'F', 'A', '9', 'F', '2', '1', 'F', '7', '6', '3', '0', '5', 'D', 'C', '6', '0', 'B', 'A', 'E', 'E', '3', 'B', 'C', '5', '6', '6', '3', 'A', '8', '0', '8', 'B', '3', '2', 'F', 'C', 'C', '8', '0', 'A', '6', '2', '5', 'E', '2', '8', '5', '4', 'E', '6', '0', '3', '4', '9', '9', '9', '5', 'F', '5', '6', '6', 'F', 'C', '8', '1', '6', '8', '6', 'F', '0', '6', 'D', '9', '7', 'B', 'B', '3', 'B', 'A', '5', 'D', 'E', 'E', '6', 'E', '3', '7', '1', '8', 'E', 'C', 'C', '5', '0', '4', '2', '9', 'B', '5', 'B', 'C', '4', '8', '3', 'D', '3', '7', '3', '9', 'E', 'B', 'A', '2', 'D', 'B', '2', '5', 'F', 'C', 'D', 'F', '9', '4', 'D', '7', 'F', '8', 'D', 'D', '4', '1', 'E', '5', 'F', 'D', 'E', '4', '0', '0', '7', 'F', 'A', '7', '4', '6', '4', 'C', 'C', '1', '1', '5', '8', 'A', '0', '1', '2', '9', '0', 'A', '7', '1', '6', '6', 'A', 'F', 'F', '6', 'D', '4', 'D', 'F', 'B', '5', 'C', 'D', '0', '2', 'E', 'C', '3', '0', '3', 'E', '5', 'D', '8', '6', '6', '1', '5', 'D', '1', '4', 'D', '3', '3', 'D', '8', '4', 'E', '4', '3', 'C', '0', '1', 'B', 'E', '5', '7', 'E', '2', 'D', '5', '6', '6', '1', '4', '1', '5', 'C', 'C', '9', 'D', '0', '0', 'C', 'C', 'D', 'B', '9', 'A', '8', '9', '3', 'C', '5', '7', '3', '5', 'A', '3', '6', '8', '8', 'F', 'B', 'C', '7', '8', '2', '0', '3', '5', 'E', '3', 'B', '7', '0', '4', 'E', '0', '8', '9', '3', '6', 'E', '2', '6', 'C', 'E', '4', '1', 'B', '5', '8', 'B', 'D', 'F', '3', '5', '2', 'E', 'E', 'A', '8', 'F', '3', 'A', '3', '8', '4', '8', '0', 'C', '2', '5', '9', '8', '8', '5', 'F', '2', 'B', 'C', 'E', '8', 'E', 'B', 'C', 'F', '9', 'F', '8', '4', '7', 'E', '3', 'A', 'F', '6', '0', '5', 'F', '8', 'E', 'B', 'F', '3', 'A', '8', '2', '6', '1', '1', '3', '8', '7', '8', '2', 'C', '7', '3', '2', '6', 'E', '4', 'B', 'D', 'D', '6', '3', 'B', 'D', '4', 'F', 'A', '3', '0', 'E', '6', '3', 'B', 'A', '0', '9', '5', '0', '3', '7', 'E', '2', '5', '7', 'E', '4', '9', '7', '5', 'C', '1', '5', '6', '8', '9', '9', '4', 'E', '8', '8', '7', '3', '1', '3', 'F', 'A', '5', 'E', '0', '8', 'F', 'A', '4', '8', '9', '6', 'B', 'D', 'D', 'E', '3', '1', 'C', '3', 'A', '9', '1', 'F', '6', 'C', 'E', 'E', 'C', '8', 'F', '4', 'B', 'C', '1', '0', '3', 'E', 'A', '2', '7', '4', 'A', 'C', '0', '9', '2', '2', 'C', '6', '3', '2', '5', '4', '7', '8', '1', 'F', 'C', '3', '9', 'E', '0', 'F', 'C', '5', '6', '6', '5', '4', '8', '7', '5', '6', '1', '7', '7', '3', 'D', '8', 'E', '6', '7', '9', 'A', 'F', 'F', '9', '4', '0', '9', '1', '0', 'E', '2', 'A', 'D', '3', 'C', 'C', '6', 'F', 'B', '0', '0', 'E', '7', '6', 'A', '5', '8', '5', 'C', '4', '4', 'A', '5', '4', 'E', '0', '8', 'F', '1', '9', 'B', '4', '8', '4', '8', 'C', 'E', 'A', '3', '4', 'F', '5', 'A', 'F', 'E', '7', 'B', '7', 'C', 'B', 'D', '8', '8', 'F', '1', 'B', '6', 'D', '6', '6', '7', 'B', '6', '4', '0', '4', 'A', 'B', '1', '2', 'F', '0', 'D', 'C', 'F', '6', 'F', '1', '3', '9', '9', '2', '2', '6', 'B', '1', '3', '3', '0', 'E', '7', '5', 'A', 'C', 'D', '2', 'B', 'B', 'E', '7', '5', '3', 'F', 'D', 'E', '2', 'B', '5', '6', 'F', 'E', '3', '3', '7', '3', '2', '1', 'C', '4', '3', 'D', '2', '0', '6', 'C', 'A', '6', '5', 'D', 'F', '0', '6', '1', 'B', 'F', 'A', '7', '1', 'B', 'B', '2', '6', 'C', '0', '6', 'F', '8', 'D', 'B', 'D', '9', '0', 'B', 'C', 'D', '9', 'D', 'F', 'F', 'E', '5', 'B', '8', 'A', '4', '1', 'C', 'D', '2', 'F', '3', '2', '4', '1', '1', 'C', 'E', 'E', '0', 'E', '4', '4', '6', 'F', '4', 'E', 'C', '3', 'A', '3', '7', '9', 'C', '7', '2', '3', '5', '9', 'C', '7', '2', '2', '3', 'F', 'F', 'B', '2', '4', 'B', 'E', 'F', '6', 'F', 'A', 'C', '4', '7', '9', 'C', '5', 'F', '8', '4', '6', '1', 'D', 'E', 'C', '9', '6', '6', '2', '0', '4', '4', '2', '9', 'F', '4', 'A', '5', 'E', 'F', '8', '7', 'B', 'D', '9', 'F', '6', '4', 'B', 'C', 'A', '9', 'A', '5', 'E', '2', '2', '3', 'D', 'F', 'B', 'E', 'E', '8', 'D', 'B', '8', '8', 'B', '8', 'E', '0', '9', '2', '0', 'B', 'E', '6', '2', 'D', '1', 'C', 'A', '5', '5', 'E', 'E', 'E', '1', 'C', '5', '6', '7', 'D', '6', '2', 'D', '4', '2', '0', 'F', '1', 'E', 'C', 'B', '2', 'B', 'E', '0', '6', '1', 'B', 'B', '3', 'A', 'A', '3', 'C', 'C', '7', '9', '0', '5', '6', '0', '0', '3', '5', 'A', 'E', '2', 'F', '6', 'E', '3', '5', '3', '3', '3', '5', '9', '1', '8', '8', 'F', 'A', '2', 'A', 'B', 'B', '8', '2', 'F', '6', '8', '6', '7', '4', 'F', '3', '6', '9', 'B', 'E', '1', 'F', '5', '0', 'F', '2', '1', '5', 'E', '2', 'E', 'F', '3', '4', '5', '1', 'E', '4', '7', '2', 'B', '2', '9', '6', '5', '5', '6', '3', 'E', 'F', '4', '6', 'B', 'B', 'C', '0', '7', 'B', '4', '8', '1', 'B', 'E', '9', '4', '9', '1', 'A', '2', '8', '8', '3', '7', '8', 'E', 'C', '2', '7', 'D', 'F', '7', 'C', '8', '9', 'D', 'D', 'A', 'F', 'E', 'D', 'D', '4', '9', '9', '1', 'B', '6', '5', 'B', 'F', 'E', '7', 'F', 'E', '3', '0', '6', '8', 'D', '2', 'A', 'E', 'A', 'D', '8', '7', 'A', '1', '2', '5', 'B', '6', '0', 'B', '4', 'B', '7', '3', '4', 'A', 'D', '0', '2', '8', '9', '4', '2', '6', '1', '9', '9', '5', '3', 'C', '0', '0', 'F', 'A', 'B', '6', '8', '7', '5', '2', 'B', 'A', '0', '9', 'A', '5', 'B', 'E', '7', '6', 'C', '4', '0', '2', '8', '5', 'B', '9', '0', '8', '0', '2', '6', 'F', 'A', 'D', '6', '3', '9', '4', 'F', '8', 'A', 'A', '0', '8', 'D', '8', '9', '6', '5', '2', 'E', 'D', '2', '5', 'C', 'C', 'E', 'A', 'C', '0', '8', '5', '3', '3', '5', '1', '6', '7', '1', '7', 'F', '4', 'E', '4', '4', '0', '7', '8', 'F', '3', '9', 'A', '3', 'B', 'C', '3', 'D', '2', '4', '4', '6', '6', 'F', '2', '0', 'E', '2', '9', '5', 'D', '9', '4', '7', '5', '2', '5', '1', '3', 'B', '5', 'F', 'D', 'A', '1', '0', '9', '4', '6', 'A', '3', '4', '0', '1', '2', '2', 'C', 'E', '4', '3', '0', 'B', '7', 'B', '2', 'A', '4', '2', '2', '2', '1', '2', '6', 'D', 'F', '2', '0', 'F', '7', '5', '6', '9', '8', '9', 'A', 'C', '1', 'C', 'D', 'F', 'A', '5', '7', '7', '2', 'E', '5', '2', '3', '3', '8', 'B', '9', '5', '0', '0', '4', '2', 'A', 'A', '6', '2', '4', '3', 'C', 'C', '4', '4', '5', '5', '0', '5', 'B', '2', '3', '3', 'D', 'D', 'A', 'C', '9', '5', 'E', '3', '5', 'C', 'A', 'E', '4', '6', 'A', '9', '7', '1', '3', 'B', 'E', 'B', '5', '0', 'D', 'E', '8', '0', '3', '4', '4', '4', '2', '4', '9', 'E', '5', '2', 'A', '8', '5', 'A', '3', '7', 'A', '3', '3', 'D', '9', '3', '1', '6', 'B', 'D', 'B', 'B', 'F', 'F', '9', 'F', '2', '5', '2', 'C', 'B', 'D', 'B', '3', '8', '6', 'C', '1', '0', 'A', '8', '8', 'E', 'A', 'C', '7', '1', 'B', '0', 'F', '6', 'B', '9', '2', '8', 'B', 'D', '6', '3', 'B', '8', 'A', 'B', '2', '8', '4', '4', 'F', 'D', '7', 'F', '2', '4', 'F', 'C', 'B', 'F', 'D', '9', '3', '9', '3', 'C', 'D', '7', 'C', 'A', '8', '3', '7', 'F', '4', '3', 'C', 'E', '3', 'C', '3', 'F', '3', '5', '1', 'D', '9', 'B', 'A', '8', '0', '5', 'E', '7', '9', 'C', 'E', 'D', '2', 'E', '4', 'D', '0', 'C', 'C', '2', '7', 'B', '2', '3', '5', '6', '3', '7', 'A', 'A', 'F', '0', 'F', 'D', 'E', 'C', 'B', '3', '8', '4', '3', '2', '7', 'C', '2', '1', '5', 'C', '5', 'A', '7', '4', 'A', '6', 'D', '3', '7', '9', '6', '7', 'B', 'A', 'C', '1', '5', 'B', '7', '2', '0', '2', '3', '6', '7', 'E', '2', '4', '2', '6', '8', '3', '3', 'A', '1', '9', '5', 'C', '4', '6', 'C', 'B', 'A', '5', 'B', '1', '8', 'A', '0', '3', '7', '7', '4', '3', '1', '9', '2', 'B', 'D', 'E', '9', '1', '4', 'F', '3', 'A', '0', '6', 'F', 'A', 'E', 'A', '0', '0', '3', '7', 'E', '2', '5', '1', 'A', 'C', '0', 'E', '6', '1', '8', '7', 'E', '4', '5', '7', 'E', '9', '0', 'A', '2', 'C', 'E', '1', '2', '9', '4', '2', '0', 'A', 'F', '1', 'C', 'C', '8', '0', '6', '6', '1', '4', 'C', 'A', '5', 'B', '7', 'F', 'D', 'A', '8', 'A', '9', '1', '5', 'F', '2', '4', '6', 'E', '3', '2', 'D', '6', '1', '8', '5', 'D', '9', '6', '4', '8', 'A', '6', 'A', 'F', 'C', '6', '9', '0', '7', '1', '5', '6', 'A', '6', 'A', '3', 'F', '8', 'B', '7', 'E', 'F', 'F', '4', '8', '4', 'D', '4', 'A', '4', 'C', '2', '8', 'A', 'A', '4', '1', 'F', '5', 'F', '3', '7', '6', '6', '5', '2', '1', 'D', 'D', '4', '6', '2', '5', 'C', '7', '4', 'C', '5', '8', 'A', '8', '6', '6', 'D', 'F', '6', '6', '6', '9', 'A', '7', '3', '5', '5', 'B', '2', '0', 'E', '5', '9', '3', '1', 'B', 'F', 'D', 'A', '3', '1', '2', '7', '7', 'A', 'F', 'D', '2', 'A', '3', 'F', '0', 'B', 'A', 'B', '9', 'A', '1', '7', 'B', '4', 'C', 'F', 'C', '3', 'B', 'E', '1', 'F', '7', 'E', 'D', 'F', 'B', '1', 'E', '3', '0', 'F', '9', 'B', '0', 'C', '1', 'F', 'C', '7', '0', 'F', 'F', '8', '1', 'F', 'F', '2', 'C', '4', '5', '7', 'E', '6', '4', '6', '1', '0', 'F', '5', '0', 'D', '7', 'F', '0', '5', '5', '9', '1', '4', '8', '2', '7', '1', '9', '0', '1', '0', 'B', '9', '1', '8', '8', '1', '7', '5', '9', '6', '0', '6', 'E', 'F', 'A', '0', 'A', 'F', '1', 'D', '8', '7', '9', '3', 'C', '5', '6', 'F', '1', '5', '9', 'F', '0', '1', '1', 'B', 'E', 'C', '4', '5', '7', '7', '6', '8', 'B', '3', '1', '9', '7', '5', 'E', '8', '2', '0', '7', '2', 'B', '5', 'E', '9', '3', 'C', 'C', 'C', 'A', 'B', '0', '8', '6', 'E', '7', 'A', '4', 'E', '7', 'B', 'A', 'D', '0', 'C', 'F', '9', '5', '4', '2', 'F', 'C', 'F', '9', 'C', '1', 'F', '1', 'D', '6', 'F', 'E', '1', '9', '1', '6', '5', '4', '8', 'B', '0', 'E', '9', '0', 'F', '7', '7', '3', 'B', '5', '2', 'C', 'C', '2', '4', '9', '6', 'F', '7', '8', 'B', '3', '4', '7', 'D', '2', 'E', 'D', '6', '7', '5', '3', '8', 'E', '7', 'E', '9', '7', '0', 'E', 'D', '2', 'D', 'C', '4', '9', '0', '0', 'F', '6', 'E', '9', 'B', 'E', '5', '1', '9', '0', 'A', '4', 'B', '2', '4', '4', '4', '7', '1', '6', 'F', '4', '9', '1', '1', 'D', '3', '1', '9', 'D', '3', 'A', '7', '0', 'F', '5', '9', 'C', 'D', 'A', 'E', '9', 'A', '0', 'A', 'C', '9', 'E', 'D', '1', '4', '3', 'D', '1', 'E', 'F', 'B', 'C', 'E', '7', 'D', '2', '0', '1', '2', '7', 'E', '1', '2', '8', '9', '9', 'B', '2', '6', '7', '5', '9', 'A', '7', '3', '6', '9', '3', '9', '2', 'D', '9', 'F', '1', 'F', '2', '7', 'D', '0', '2', '2', 'C', 'B', '5', '1', 'E', '1', '2', 'D', '7', '4', 'E', '2', 'B', '1', '7', '7', '7', '9', '5', 'B', 'F', 'E', '0', '1', '0', '7', '2', 'A', '5', '5', 'D', '3', '0', '7', '2', '1', 'C', '3', '5', 'E', '6', 'F', '6', '1', 'C', '2', '9', 'A', '2', '4', 'A', '9', 'E', '7', '3', 'B', '7', '0', '7', '8', '4', 'F', 'E', 'D', '0', '1', '8', '7', '9', '5', 'B', '4', 'D', '0', 'A', '3', 'C', 'B', '6', '6', '2', 'F', '2', '4', '0', '3', '7', '2', '5', '2', '9', 'A', '1', 'B', 'B', '9', '5', '0', '0', 'D', '4', '0', 'B', 'A', 'A', '3', 'C', '9', '1', '6', '9', '8', 'B', '8', '8', 'E', '3', '5', 'F', 'D', 'A', '4', 'D', '8', '7', '5', '0', '2', '1', '0', '2', 'D', '7', 'F', '4', '8', '5', 'A', 'C', '2', '4', 'B', '5', '8', '9', 'C', 'E', 'E', 'A', 'E', '9', '4', 'D', '3', '9', 'D', 'A', '4', 'E', 'D', '0', 'B', '4', 'A', 'A', 'C', 'D', '8', 'C', '9', '6', '9', '8', '2', '3', 'E', '4', 'E', 'C', 'B', '4', '3', '3', '9', 'E', '5', 'F', 'B', 'E', 'B', '3', 'F', '6', 'F', '7', '5', '0', '6', '9', '6', '8', '7', 'E', 'F', 'A', '7', '6', 'B', '6', '0', '0', 'C', '5', '9', '5', '9', '7', '8', 'F', '4', 'F', 'C', '5', '6', '9', '4', 'A', '0', 'F', 'C', '7', 'D', '4', '6', 'F', 'C', '0', '7', '2', 'F', 'A', 'A', '7', 'A', '0', 'C', '2', '1', 'A', '6', 'E', '6', 'C', '0', '7', 'C', '6', '4', '6', '2', '9', '9', '8', '4', 'E', '2', 'A', '9', 'D', '5', '1', 'C', '8', 'B', '4', '6', '5', '1', '6', '9', '2', 'D', '1', '5', 'A', 'A', '2', '2', '5', '4', '9', '8', '2', 'F', 'E', 'B', 'D', '2', '8', 'C', 'B', 'A', 'F', 'E', '7', 'C', 'D', '3', '7', '4', '3', '1', 'A', 'E', 'E', 'D', 'B', '5', 'D', 'D', 'F', '3', '8', 'A', '0', '0', '5', '4', 'C', '1', '9', '3', 'B', 'E', '7', '6', 'F', '3', 'A', '5', 'C', '2', 'F', '7', '2', '1', '9', '5', '9', '6', 'F', 'F', '3', '2', 'E', 'C', '8', '3', 'F', '1', 'A', '3', '1', '7', 'C', '9', '7', '0', '7', '8', 'F', 'A', 'E', '6', 'E', 'D', 'B', 'F', '3', '3', 'E', '6', '3', '5', 'B', '7', 'C', '3', '5', '7', 'E', '4', '2', '1', '0', '6', 'D', 'A', 'D', '2', '1', 'F', '9', 'E', 'B', 'F', '3', '6', '2', 'B', 'C', '4', '0', 'E', 'F', 'E', 'D', 'E', '1', '4', 'D', '7', '4', 'E', '3', '4', 'A', 'D', '7', '1', '2', 'B', '8', '6', '1', '6', '6', 'E', '3', '7', 'B', '4', '3', '9', 'D', '4', '0', '1', '6', '7', '5', '1', '9', 'D', '1', 'C', 'F', 'E', '4', '8', '3', '7', '5', 'B', '3', '2', '2', 'A', '0', '7', 'A', '3', '3', '3', 'F', 'E', '2', 'D', '3', '2', '8', '4', '2', '0', '1', '7', 'D', '1', '8', 'B', '8', '4', 'F', 'F', '8', '2', '3', 'A', '0', '3', '0', '1', '3', '4', '4', 'C', 'A', '3', '2', '0', 'E', '8', 'B', '7', '8', 'E', '1', 'C', '0', 'A', '4', 'B', '4', '9', '6', '2', 'E', 'E', 'D', '0', 'E', '2', '9', '6', '1', 'D', '1', '8', 'E', 'C', '3', '1', '3', '6', '6', '4', '5', '7', 'A', '6', 'A', '3', '6', 'C', '8', 'D', '9', '2', 'F', '9', '1', '1', '8', 'E', '3', '9', '1', '3', '3', '4', 'F', '9', 'D', '2', '7', 'A', '0', 'C', '9', '1', '8', 'D', '4', '1', '3', '5', '9', 'E', '1', '1', '2', '5', '5', 'B', '5', 'F', '9', '6', '0', '2', 'F', '8', '0', '1', 'F', 'A', 'D', '5', '8', '6', '8', '9', 'E', '9', '3', '5', '0', '4', 'D', 'B', 'B', '3', 'C', '8', '6', '3', '0', '7', '0', 'E', '2', '0', 'C', '8', '6', 'F', 'F', 'B', '2', 'A', '3', 'D', 'D', '5', '2', '9', '4', '9', 'E', 'D', '9', '8', '3', '2', '0', 'A', 'D', '0', 'A', 'F', '3', '7', 'D', 'B', '9', 'B', 'F', '2', 'D', '1', 'C', '9', '4', 'D', 'F', 'B', 'A', '2', '0', '4', '7', '9', 'B', '1', 'E', '9', '0', '2', 'E', '2', '8', '9', '7', '8', '8', 'F', '6', '0', '0', 'E', '6', '9', 'D', '1', 'B', 'E', '9', 'B', '2', '7', '5', 'B', 'E', 'C', 'B', '9', '2', '1', '8', 'E', 'C', '9', 'F', '4', '3', 'F', 'F', '3', '1', '1', '3', 'E', 'C', '4', 'A', 'F', '3', '1', '3', '2', 'B', '1', '0', '4', '2', '1', 'B', 'C', '6', '0', '9', '2', '8', '0', '0', 'A', 'F', '6', '7', '9', 'B', '7', '2', '9', 'A', '1', '7', '3', 'A', '8', 'D', 'B', '1', '9', '8', '8', '2', '4', 'E', '1', '3', 'F', '8', 'C', 'B', 'D', '0', 'E', 'C', '4', 'A', 'C', '7', '3', '2', '3', 'B', '6', '4', '0', '1', '9', '5', '9', 'C', 'F', '1', '1', '5', '8', 'E', 'F', '4', 'D', '9', '9', '4', '6', 'F', 'E', 'F', '4', 'D', 'D', '4', 'A', '5', 'B', 'B', '2', '9', '2', '2', '0', '9', 'A', '0', '6', '2', '5', '7', '0', '0', '4', '2', '0', 'A', '9', '5', '9', 'C', '8', '9', 'C', 'F', '0', '2', '0', 'D', '2', '7', '8', '3', '0', 'D', '7', '3', 'A', '0', '5', '3', '7', '0', 'B', '2', '1', '9', 'E', '5', '7', '3', '2', '8', '0', '0', 'C', 'D', '7', '9', '5', 'A', 'B', '1', '4', '7', 'A', '7', 'E', '2', '5', 'A', 'D', 'E', '4', 'A', '1', 'B', '7', 'D', '4', 'F', '3', 'D', '6', '5', '7', '9', '8', '8', '7', '2', '6', '3', '3', 'E', 'F', 'F', 'C', 'D', '9', 'B', '5', '0', 'D', '9', '6', 'F', '8', '3', '2', '8', 'B', '7', '1', '3', 'F', 'E', '9', '4', 'F', 'F', 'F', '9', '1', 'C', '3', '1', '9', '4', '7', '3', 'F', '7', '2', 'E', '8', 'B', '0', 'C', '2', '4', '1', '3', 'C', '6', '6', '5', '9', 'C', '3', '6', 'F', 'F', '8', '0', '5', 'B', '4', '5', '1', 'F', 'F', 'D', 'B', '9', 'F', '1', 'C', 'A', 'E', '8', '7', '5', '8', '8', '2', 'F', 'D', '0', '8', '9', 'C', '9', '2', '3', '9', '9', '0', 'B', '7', '8', '0', 'A', '3', 'F', 'B', 'D', 'B', '3', 'B', '6', 'F', 'F', 'C', 'F', '9', 'B', 'B', 'B', '5', 'C', 'B', '3', '7', '5', '3', '9', '7', '9', '9', 'C', 'F', 'B', 'D', 'F', '3', '2', '1', '0', 'C', '8', 'C', '7', '0', '6', '3', 'B', 'A', 'A', '7', '3', 'B', 'C', '5', '8', '8', '1', '3', '9', 'B', 'D', 'F', '6', '4', '7', '3', 'F', '2', '5', '5', '0', '1', '0', '3', '4', '2', 'F', 'B', 'A', '8', '8', '5', 'C', 'C', '3', '9', '5', '8', '2', '9', '9', 'C', '8', '4', 'D', '7', 'C', 'C', '8', 'B', '1', 'F', '2', '8', '1', 'F', '8', '9', '8', '9', '6', '7', '4', 'B', '2', 'B', '2', '7', '5', '7', 'A', 'E', '8', 'E', '8', '5', 'B', '0', '9', 'A', '1', '0', 'E', '6', '1', '8', 'D', 'B', '5', '1', '4', '2', '7', '6', '1', '2', '8', '1', '0', 'B', '3', '3', '1', 'D', '9', '4', '1', 'A', '0', 'D', '4', '2', '6', '5', 'F', '8', '2', '5', 'D', '5', 'C', 'F', '2', '7', 'B', 'E', '8', 'F', '2', 'C', '9', 'B', '9', 'C', 'F', 'E', 'D', '8', '5', 'C', '3', '1', '4', 'E', '4', 'F', 'C', '5', '1', 'F', 'D', '4', 'B', '6', 'C', 'F', '7', 'A', '4', 'C', '5', '1', '7', '6', '6', '9', 'A', '3', '9', 'A', 'B', 'D', 'E', 'F', '3', 'D', '4', '9', '0', '2', '1', 'A', 'A', '8', 'A', '6', '4', 'F', '7', '5', '5', '6', '5', '6', '8', '4', 'E', 'F', '2', '5', 'D', '2', '4', '8', 'A', '0', 'D', 'E', 'E', 'B', '1', '1', 'A', 'E', 'E', '9', '2', 'C', '0', '2', 'B', 'A', '4', 'E', '7', 'C', '5', '5', '6', '7', 'F', '5', '3', '8', '0', '3', 'C', '2', 'D', '4', 'A', 'B', 'C', '8', 'E', 'E', '7', '1', '7', 'E', 'D', 'B', 'A', '8', '4', 'C', '2', '7', '1', 'F', '5', '1', '1', '1', 'F', '8', 'C', '4', 'D', 'D', '5', '9', 'D', 'D', '0', '2', 'C', 'F', 'B', '7', '3', '2', '2', '5', 'E', '4', '2', '5', '5', '4', '0', '8', '0', 'C', '4', '1', '3', 'D', '9', '9', '6', 'A', '3', 'A', '9', '3', 'C', '1', '5', '7', '9', '0', '3', '4', 'A', '8', '7', 'D', '1', 'E', '8', '4', 'B', '4', 'D', '9', 'A', '8', 'B', '0', '6', '9', '5', '9', 'E', 'A', '4', '3', 'E', '6', '7', '7', '3', '1', '2', '5', '3', '2', '6', '0', '9', 'E', '7', '5', '3', '4', 'A', 'B', '6', '4', 'C', '0', 'C', '8', 'A', '5', '8', 'F', 'E', 'F', 'B', 'F', '2', '6', '0', '0', 'E', '5', '0', '4', '4', 'F', 'B', 'B', 'C', 'F', 'D', '9', '8', 'A', '6', '4', 'E', 'F', 'C', '1', 'A', '4', '6', 'E', 'F', '6', '1', 'F', 'A', 'B', '1', 'D', 'E', 'F', 'B', 'F', '0', '4', '1', '5', '9', '2', '7', '9', 'D', 'D', 'C', '8', 'F', '7', '8', '2', '5', '2', '3', '5', '2', '1', '1', '1', '8', '9', '8', 'F', 'F', 'E', '6', 'E', '0', 'A', '9', '8', '4', '8', 'C', '3', '8', 'C', 'C', 'B', '5', 'E', '9', '8', '2', '4', 'E', '3', 'F', '9', '7', '6', '1', '5', '6', 'C', 'C', 'A', '7', '6', 'A', '8', 'B', '5', 'C', '2', '0', 'E', 'F', '0', 'D', '3', 'F', 'A', '0', 'E', '0', '9', '7', '5', 'F', '9', 'C', 'C', '6', '6', '8', '6', '8', 'A', '8', '1', '1', 'B', 'C', 'F', '2', '2', '7', 'F', 'A', '8', '2', '4', 'D', 'D', '1', 'C', '8', '3', '1', '6', '5', '6', '0', 'F', '5', '3', 'B', '8', '7', '7', '3', '2', '1', '3', 'E', '5', '7', '7', '1', '0', '9', '7', 'C', '5', '7', 'B', '9', '7', 'D', 'A', '4', 'B', '2', 'C', '5', '7', 'C', 'B', 'F', '7', '1', '2', 'B', '7', '4', 'C', 'D', 'D', '6', 'B', 'B', '6', '4', 'A', 'F', 'F', '8', '7', '3', 'B', '4', '4', 'A', '1', '0', 'E', 'F', 'F', 'C', '7', 'F', 'F', '5', '0', '5', 'B', 'C', '7', '3', 'C', 'F', '9', '0', 'E', '6', 'B', '0', 'C', '8', '9', '2', '6', 'A', 'C', 'D', '1', 'D', '7', '0', '7', '5', '8', '2', '2', 'C', '0', 'A', '8', '5', 'D', '2', 'B', '8', 'F', 'A', 'B', '7', '8', '3', '2', '8', '4', 'F', 'A', 'E', 'E', '4', '2', '3', '3', 'A', 'A', 'C', '9', '2', 'E', '0', 'C', 'B', 'F', 'D', '6', 'C', '6', '9', '0', 'A', '6', 'E', '2', '7', 'F', '2', '3', '9', 'D', '3', 'F', '7', '3', '6', '1', '0', '6', '5', '7', '7', 'F', '6', '2', 'F', '5', 'F', '3', 'C', '1', '8', '9', '1', '0', 'C', '3', '0', '3', 'F', 'A', '2', '8', 'F', 'F', 'B', 'D', '6', '0', '1', 'C', 'A', '8', 'E', '6', '3', 'C', '2', 'D', 'C', 'B', '9', '9', 'B', 'C', '6', 'C', '9', '8', 'C', 'A', '5', '1', '2', '8', '0', '6', '0', 'B', '9', '0', 'E', '0', 'B', '6', 'B', '8', 'F', '3', 'F', '0', 'B', 'A', '5', 'F', 'A', 'E', '4', '4', '6', '2', '0', 'F', '8', '7', '3', 'C', '1', '0', 'B', 'F', 'F', '9', '8', '5', 'A', '5', '2', '2', '3', '3', '1', '7', 'E', '6', '0', 'D', '9', 'A', 'B', '4', 'C', '3', '1', '5', '4', '9', 'D', '6', '6', '7', 'B', '5', '7', 'A', '9', 'D', 'A', '1', '3', 'F', '3', '5', '7', 'F', 'F', 'A', '7', '7', '8', 'C', '5', 'B', 'A', 'D', '1', '4', 'B', '2', '7', '8', '4', '6', '9', 'C', '8', '7', '0', '7', 'E', '1', '1', '7', '3', 'D', '1', 'B', 'B', 'F', '3', 'A', '0', 'C', '4', 'D', 'A', 'B', 'D', '6', '2', '6', 'C', 'E', 'B', '3', '2', 'E', '6', '2', '1', '7', '4', 'E', '1', '2', '2', 'E', '0', '1', 'A', 'C', 'A', '9', '9', 'C', '8', '2', '2', 'D', '0', 'B', 'C', '1', '1', '9', '4', '1', 'A', '4', '9', '8', '3', '4', '3', '6', '9', '9', '7', 'E', '9', '3', 'A', '2', '8', 'A', '3', '7', '5', '9', '2', 'D', 'D', '7', '6', 'E', 'A', '1', '8', '6', '9', 'A', '9', '2', '6', 'F', '6', 'F', '4', '1', '0', '1', '7', 'E', '0', 'E', 'F', 'B', '4', '9', 'C', 'F', 'C', 'C', 'F', 'C', 'C', 'F', '2', '0', 'D', '0', '7', 'D', '0', '1', '0', 'F', '9', 'A', '4', '0', 'E', 'D', '0', '5', '1', 'F', 'D', 'D', 'C', 'B', 'A', '9', 'E', '9', '2', 'C', '2', 'C', 'E', '8', '5', 'B', '9', '2', '5', '6', '4', '2', 'A', '2', '1', 'D', '2', '0', 'F', '1', '0', '6', '1', '9', 'F', '0', 'B', '5', '2', 'A', '0', 'C', 'A', '5', '2', '3', 'F', '1', '4', '4', '8', 'B', '7', '8', '8', '8', 'C', '9', '4', '7', '5', 'D', '0', 'E', '5', '5', 'C', '9', 'E', 'C', '9', '5', 'E', '0', '8', '6', '3', 'A', 'D', '3', 'E', 'F', '7', '8', 'A', 'B', 'B', '0', '7', '3', 'E', '3', '5', 'A', 'C', '2', '6', '7', 'D', '5', 'D', 'C', 'D', '6', 'C', '3', 'D', 'E', 'E', 'C', '7', '4', 'E', '1', '5', '4', '2', '3', '2', 'A', '1', 'D', '3', '3', '0', 'C', 'D', '0', 'B', '5', '4', 'A', '3', '5', '8', '1', '4', '1', 'A', 'C', '6', '6', 'D', '6', 'D', '4', 'E', 'E', '4', '5', 'A', 'A', 'A', '8', '5', '3', 'A', '5', '1', '8', '2', '7', '7', '1', '0', 'D', 'B', 'E', '4', '8', 'B', '4', '5', '5', 'C', '6', '6', '9', '9', '2', '2', '0', 'F', 'D', 'C', '4', '1', '9', 'A', '4', '3', '9', '7', 'D', '1', '5', 'A', 'A', '1', '3', '2', '1', 'E', '6', '3', 'A', '0', 'C', '9', '7', '0', 'D', 'D', '8', 'A', '6', '0', 'D', 'A', '3', 'A', '0', '9', 'F', '8', 'A', '9', 'B', '2', 'A', '3', '0', '9', '7', '2', '4', 'B', '2', '3', '6', '3', '8', '1', '2', 'D', 'E', 'F', '2', '5', 'F', 'B', '5', '1', 'B', 'D', '4', 'E', 'F', '8', '1', '6', '2', '2', 'E', '2', 'E', 'D', 'B', '8', '0', '4', '9', '4', '0', '7', '2', '4', '0', '9', '2', '4', '3', '1', '7', 'A', 'E', '1', 'C', '1', 'D', 'F', '0', 'D', '5', 'B', '5', 'B', 'D', '1', '0', '7', '6', '6', 'B', '1', '7', '5', '9', '1', '0', '3', 'F', '7', '6', '5', '3', '5', 'C', '3', 'D', 'D', '9', '1', '8', '4', 'F', '3', 'E', '4', '5', '4', '7', '6', '5', 'D', '7', '4', '6', 'D', 'F', '5', '3', 'B', '6', '3', '2', 'A', 'C', '4', '6', 'E', '7', '9', 'F', '9', '3', '6', '8', '5', 'D', '0', '6', 'A', 'C', '8', '6', '2', '8', 'D', 'B', '9', '6', '5', '4', 'E', '6', 'D', '0', '9', 'D', '3', '2', 'F', 'D', '1', 'E', '3', '3', 'E', '3', '9', '2', '8', 'F', '9', '0', '9', 'E', '4', 'E', 'F', 'E', '0', '8', '0', '7', '0', '0', 'D', '5', '5', '9', 'C', '5', 'B', '4', 'B', '6', '9', 'F', '8', '7', 'E', 'E', 'B', 'A', '9', '3', '6', '0', '5', 'F', 'F', '8', '0', '3', '8', '9', '6', 'C', '9', 'C', '6', 'C', 'C', '5', '7', '2', 'E', '3', '9', '0', '6', '2', 'A', 'F', '4', '9', '0', 'B', '4', 'F', '6', 'D', 'F', '5', 'E', '3', '2', '4', '9', '5', '9', '8', 'E', 'F', '2', '0', '6', 'B', '7', 'A', '0', '1', '6', 'C', '5', 'A', '1', '7', '0', 'D', 'F', '7', '2', 'E', '2', '2', '3', 'D', 'C', '7', '8', 'C', '8', '4', '0', '3', '3', 'C', '5', '5', 'D', '1', '2', '2', '5', 'B', 'C', '3', '5', '8', '2', 'C', 'F', 'C', 'C', 'A', '7', '1', '9', '5', 'B', '3', '2', '3', 'D', 'C', '7', '4', '0', '0', '3', 'C', '6', '8', '2', 'B', 'F', '5', 'D', '8', '4', '0', 'F', 'E', '5', '5', '6', '6', 'C', 'D', '1', 'F', '1', '3', 'C', 'B', '9', 'E', '0', '0', 'D', '5', '3', '5', '7', 'A', 'E', '0', '6', '4', '1', 'B', 'A', '2', '9', 'B', '8', 'C', '1', 'C', 'C', 'C', '3', '5', '8', '6', '8', '6', '7', 'C', 'D', '3', '8', '2', '3', '9', 'C', '2', 'D', 'E', '5', '1', '0', 'C', 'F', 'F', 'F', '4', '9', 'B', '3', 'C', '5', '6', '2', '4', '1', '6', 'B', '7', 'A', 'A', 'E', 'D', 'C', 'B', 'A', 'D', '4', '1', '9', '7', '3', '7', 'F', 'E', 'B', 'D', '0', '0', '3', '3', '0', '3', '7', 'C', 'F', '3', 'F', 'D', '7', '1', 'D', 'C', 'A', '2', '0', '9', '4', 'C', 'D', '0', '6', '7', 'D', '3', 'A', 'C', 'F', 'E', '7', 'F', 'C', 'B', '7', 'E', '8', 'B', '5', '0', '5', '0', '0', '6', '4', 'C', 'A', '4', '9', '3', 'D', '0', '7', '9', '0', '1', 'A', 'E', '9', '2', '7', '8', '7', '9', '0', 'E', 'B', 'A', 'A', '0', 'B', 'F', '3', '2', '6', '8', '3', 'F', '5', '9', '9', 'F', 'B', '5', '3', '8', '0', '8', 'D', '8', 'A', '2', '6', 'F', '8', 'A', '2', 'A', 'B', '3', '9', '1', 'D', '9', 'F', '0', 'C', '1', '5', 'A', '9', '3', 'D', '0', 'C', '4', 'B', '3', 'B', 'C', 'E', 'D', '7', '3', 'F', 'B', '1', 'F', 'C', '7', '4', '1', '0', 'F', 'C', 'E', '9', 'A', 'C', 'C', 'D', 'A', '6', 'A', 'F', '4', 'A', '1', '8', '5', '0', '2', 'B', '8', '5', '6', '3', 'C', '2', '1', '6', 'F', '9', '5', '9', '9', '6', 'D', 'D', 'F', '8', '5', '0', '1', 'C', 'B', '3', '3', '1', '2', '9', '4', 'F', '9', 'C', '2', '0', '8', '2', '8', '5', '7', '7', '7', 'E', '0', '0', '5', '3', 'F', '5', 'E', '9', '9', '4', '0', 'C', '3', '8', '0', 'B', '4', '9', 'C', 'F', 'F', '9', 'B', 'A', 'D', 'C', 'E', '8', '4', 'D', 'A', 'B', 'D', 'B', 'B', 'E', 'D', 'E', '1', 'B', 'F', '6', '8', 'C', '1', '7', 'D', 'C', '2', 'C', '8', '5', '0', '6', '7', '7', 'A', 'C', 'D', '1', '8', '9', '9', 'B', 'D', '4', '0', '5', '3', 'B', 'E', '4', '1', 'D', '1', '5', '9', '4', 'C', '1', '8', '1', '7', '0', 'A', '1', '0', 'C', 'A', 'A', '4', '7', '7', '6', 'E', '0', '8', '4', '5', '6', '9', '4', 'A', 'B', 'D', 'A', '6', 'D', 'C', 'E', '9', '7', '1', '2', '5', 'A', 'D', '3', 'F', 'B', 'A', 'C', '2', 'B', 'E', 'F', '6', '7', 'C', '2', 'E', '4', '7', '0', '9', '7', '5', '6', '3', 'B', 'D', '0', '1', '7', '4', '4', 'C', 'A', '4', 'D', '3', '0', 'E', 'B', 'A', 'D', 'B', '2', '4', '3', 'E', '3', 'A', '0', 'D', 'A', 'F', '8', '6', '0', '7', '7', '6', '1', '6', '8', 'D', '1', 'E', '9', '8', '1', '3', '3', '7', 'D', '0', 'D', '5', 'A', '5', 'D', 'C', '3', 'B', '8', '8', 'D', 'C', '9', 'D', 'A', 'C', '1', '9', '1', '4', 'D', '3', '6', 'F', '2', 'E', '5', 'F', '2', '7', '0', '9', '9', '3', 'E', '3', 'A', 'E', 'D', '9', '9', '6', '4', '2', '4', '1', '6', 'A', '4', '3', 'C', 'C', '6', 'B', 'D', '0', 'D', '0', '5', '7', 'C', 'B', 'C', '2', 'D', 'F', '1', '1', '7', 'F', '9', '4', 'F', '1', '2', '8', '8', '1', '0', '0', '0', '5', '6', 'A', '5', 'B', '3', 'B', 'F', '6', '7', '7', '6', 'C', '4', '6', 'F', '9', 'E', '1', '1', '9', '1', 'C', '8', '2', '1', '3', 'A', '0', '2', '1', 'F', '8', 'B', 'D', '8', '4', 'F', '3', 'A', 'A', '8', '1', '3', 'D', 'F', 'B', 'C', '2', 'C', '9', 'B', 'A', 'F', '1', '7', '1', 'C', 'D', '1', 'C', '1', 'B', '0', '0', '1', 'A', 'C', '6', 'D', '9', 'B', 'F', '3', '7', '5', 'A', 'D', 'A', '6', '9', 'D', 'B', '1', '8', '5', 'D', '4', 'E', '6', 'F', '6', '8', 'E', '7', 'D', '4', '7', '4', 'C', '1', '6', '2', 'B', '7', 'E', '0', 'E', 'D', 'F', '3', '9', '7', '0', 'C', '0', 'D', '2', 'D', 'D', '5', '2', '5', 'E', '3', '5', '6', 'D', 'F', '8', 'B', 'D', '3', 'C', '7', 'A', 'B', '2', 'D', '0', '9', '5', 'E', 'E', '2', 'D', 'E', '7', '0', '4', '2', '2', '2', 'C', 'E', 'D', 'C', 'E', '9', '3', '5', '0', '8', 'D', '7', 'B', 'E', '1', 'D', '3', '6', '5', '8', 'F', '2', '3', '7', '6', '0', 'B', '7', '7', '7', '2', '9', '2', 'B', '5', '3', '6', 'B', '1', '1', 'E', '9', 'C', 'A', '3', '5', 'C', 'D', '1', '6', '1', '1', '2', 'B', 'B', 'E', 'E', '5', 'D', '2', 'C', 'B', '6', '7', '5', '4', '2', 'E', '8', '3', '3', 'C', '4', '5', 'C', '3', '7', 'E', 'C', 'A', '3', 'C', '1', '6', '6', '0', '0', 'E', 'C', 'B', 'D', 'B', 'C', '4', 'D', '1', 'E', 'A', '2', '5', 'C', '3', '1', '6', '6', '6', '3', 'C', '5', '4', 'D', '5', '5', 'A', 'B', '4', '7', '2', '5', 'B', '3', 'B', '6', 'B', 'C', '1', '9', '9', 'F', '0', '5', '7', '2', '4', 'C', '6', '0', 'D', '8', 'C', '8', 'D', 'E', '3', '4', '1', '3', 'D', '3', '2', '6', 'D', '6', 'A', '0', 'C', 'A', 'F', '4', '8', '3', '7', '6', 'E', '1', '1', '5', 'F', '8', '1', 'B', '6', '4', 'B', 'A', '4', '7', '5', '3', '5', 'A', 'F', 'E', '9', '3', '8', 'A', '1', '9', 'F', '7', 'D', '2', 'F', '1', 'F', '1', 'D', 'D', 'E', '6', 'E', 'E', 'A', '3', '6', '6', '3', '9', '1', 'A', '1', '8', '9', '7', '1', '0', '3', '3', 'B', '3', '1', '6', 'B', '4', 'E', 'E', '2', '0', 'D', 'B', 'A', '6', 'E', 'F', '8', '5', '4', '6', 'F', '2', 'A', '8', '1', '9', '4', '1', '1', 'C', '5', 'C', '9', '0', 'F', '7', 'E', '9', '7', 'C', '1', 'F', 'F', 'C', '0', '3', '5', 'E', 'E', '7', '2', '1', '3', '1', '1', '1', 'E', '4', 'C', '7', '1', 'F', 'A', '9', 'B', '3', 'D', 'A', '1', 'C', '3', 'A', '9', 'D', '2', '1', 'F', '8', '2', 'E', '9', '2', '3', 'B', 'E', '1', '1', '1', '1', '7', '3', 'D', '9', '6', '4', 'F', '4', '8', 'A', '0', '2', '3', '7', '0', 'F', '5', 'E', '7', '5', '7', 'B', 'D', '9', '9', '2', '7', '8', 'F', '0', '3', '4', 'D', 'E', '1', 'F', '7', '3', 'C', 'B', 'F', '1', 'F', 'B', 'D', '2', '9', '7', '9', '3', '5', '5', '6', '1', '5', '5', '5', 'A', '1', '8', '9', '2', '1', '1', 'A', '0', 'A', '6', '9', '0', '9', '2', '5', 'A', '8', '1', 'E', 'B', '6', 'A', '8', '6', 'C', '3', 'F', '9', '6', 'B', '7', '6', '0', '8', '5', '7', '1', 'E', 'B', 'E', '6', '5', '9', '2', 'C', 'F', 'D', 'F', 'D', 'E', 'E', '6', '7', '7', '3', 'E', '9', '6', 'C', 'C', '3', '8', '2', '6', 'C', '2', '2', '0', '3', 'D', '5', 'F', '7', '0', 'F', 'F', '0', '0', 'B', 'C', 'C', '0', 'E', 'A', 'B', '8', 'D', 'D', 'F', '6', 'F', 'F', 'C', '0', '2', '5', '9', 'B', 'A', '1', 'D', '6', 'E', '7', 'A', '1', 'A', '7', 'A', '9', '3', '1', '0', '6', '6', 'D', '6', '9', '6', '5', '6', '5', '5', '7', '3', '0', '7', '1', 'B', '5', '8', '5', '0', 'F', 'D', '7', '9', '3', '1', '5', '3', '8', '2', '8', '6', 'A', 'B', '0', 'E', '8', '0', 'B', 'E', '4', '5', '6', '6', 'C', '1', 'D', '2', '5', '5', '9', 'A', '8', '9', '1', '1', '9', '6', '4', 'E', '8', 'A', '4', '5', '2', 'F', 'F', '1', 'B', 'B', 'D', 'C', '6', '2', 'E', '4', '7', 'B', 'A', '5', '1', 'C', 'A', 'E', '8', '8', '4', 'E', 'F', '2', 'E', '7', '9', 'E', '0', '8', 'B', '9', '6', '5', '5', '2', 'B', 'C', '8', 'C', 'E', 'E', 'C', 'F', 'C', '3', 'A', 'E', 'E', '2', '4', '1', '1', '3', '5', '5', '5', '5', 'D', '1', 'B', '3', '5', 'A', '0', 'B', 'B', 'A', '4', 'E', '9', '3', '2', 'E', 'E', 'A', '8', 'A', '3', '9', 'A', 'A', 'C', 'D', '2', '4', '9', '7', '5', 'C', '5', '4', '4', '0', '8', 'F', '2', '9', '8', 'F', '5', '3', 'B', '0', '7', '8', '2', 'C', '7', '3', '4', '1', '6', 'B', '2', '4', '3', '9', '4', '3', '6', '1', '5', '5', 'D', 'D', '7', 'A', '2', '9', '8', 'B', 'A', '1', 'C', 'C', '6', 'C', '9', '8', '6', '5', '7', '3', '1', '3', 'B', '6', 'C', 'F', '8', '8', 'F', '9', '3', '9', '7', '3', '1', 'A', '1', 'B', '9', '9', '6', '1', 'B', '6', 'C', '4', '4', '0', '5', '0', '2', '2', '2', 'F', '7', 'F', '9', '9', 'E', 'A', '0', '5', '0', 'B', '4', 'D', 'C', 'F', '5', 'B', '9', 'B', 'C', '6', '0', 'A', '2', '7', '0', 'C', '3', '8', '6', 'B', '0', '3', 'D', 'E', 'B', 'C', '9', '7', 'C', 'B', '9', 'E', '8', 'B', 'D', '1', '4', '0', 'E', '6', '7', 'D', '2', '2', '9', '3', '2', 'B', 'F', '2', 'F', 'F', '7', '4', 'F', '0', '5', '1', '4', 'F', 'E', 'A', '3', '4', '8', '4', 'A', '7', 'A', '4', 'E', '0', 'D', '3', 'A', 'E', '5', '8', 'A', 'A', 'D', '2', 'C', '1', '7', '1', '9', 'E', '1', '6', 'B', '5', '1', '8', 'E', '9', '9', 'A', '3', '3', '9', 'B', '5', '7', '3', '2', 'E', 'F', '9', 'A', '8', '9', 'C', '4', '8', 'B', 'A', 'E', '4', '4', 'A', '4', 'F', '6', '7', '5', '8', 'C', '6', '6', '2', '5', '3', '2', '7', 'C', 'B', 'B', '3', '2', '0', 'B', '2', 'B', '3', '4', '9', 'C', 'E', '1', '6', '8', 'C', '0', 'C', '2', 'A', '8', 'B', '6', 'C', '9', 'F', 'D', 'F', '5', '6', 'C', '2', 'D', '7', 'C', '7', '4', 'F', '6', 'F', '8', 'F', '4', '2', '6', 'D', '6', '9', 'B', 'D', '5', 'E', '3', '3', '7', '8', '7', '9', '3', 'D', '8', '1', '1', 'D', 'D', '3', '8', '4', '8', 'C', '2', '3', '3', '8', 'F', '8', '4', '8', '9', 'A', '7', '2', '8', '4', '7', '2', '8', '8', 'E', '3', '6', '5', '0', 'C', '4', '9', '6', 'C', '7', '3', '4', 'F', 'B', '8', 'C', 'F', '5', 'E', '2', '3', 'D', '7', 'D', 'F', '0', '9', 'C', 'D', 'F', '2', 'D', '2', 'A', 'A', '7', '3', '8', 'B', '1', '2', 'B', '1', 'C', 'D', '9', '3', 'C', '6', '1', '8', 'C', '9', 'B', 'E', '6', '2', 'B', '5', 'E', '7', '0', '3', '9', '0', '7', 'D', '4', 'D', '7', 'E', '9', '2', '4', 'C', 'D', '8', 'A', 'A', 'C', '1', '7', '1', 'F', 'D', '8', '6', '6', '2', 'D', '8', '2', 'A', '2', '3', '8', '3', 'D', '9', 'B', 'C', 'A', 'F', 'F', '0', '2', '3', 'A', 'C', 'D', '9', 'E', '2', '9', '4', 'B', 'D', '8', '4', '5', 'F', '0', 'F', '2', '6', 'B', '4', '9', '6', '9', '2', '6', 'E', '3', '8', 'B', '3', '9', '8', 'F', '8', 'A', 'D', '5', '8', '2', 'C', '7', 'B', '0', 'A', 'E', '9', 'D', '9', '5', '7', '2', 'F', 'A', 'D', '9', '4', 'E', '3', '8', '1', 'E', '2', '5', '5', 'F', '8', '3', '8', '2', '1', 'F', '9', '9', 'A', 'F', '9', 'D', '4', 'A', '2', '7', '7', '2', '3', 'A', '3', '2', '6', 'C', '2', '9', '5', '8', 'F', '8', '3', '4', '7', '4', '4', 'C', 'C', 'E', '7', '6', '1', 'B', '1', 'B', 'C', 'C', 'D', 'B', 'C', '8', '0', '3', '9', '0', 'F', '8', '2', '1', '9', 'D', '7', '6', '9', '1', '1', '5', 'E', 'B', 'B', 'B', 'F', 'C', 'F', '3', '3', 'C', 'B', 'C', '0', '9', '6', '9', '3', 'D', '2', 'B', '9', 'B', 'B', '0', 'A', '5', 'E', '9', '1', '3', '6', 'A', '6', '3', '9', 'B', '0', '0', '1', '7', 'E', '7', '6', '0', 'D', '9', '7', '9', 'E', '9', '0', '8', 'E', '6', 'A', '6', '7', 'C', 'A', 'D', 'C', '8', 'A', '5', '9', '6', 'D', '0', '8', '1', '8', 'D', 'E', 'C', '3', 'D', '5', '3', '4', 'E', 'D', '1', '0', '2', '1', 'C', '3', '2', '1', '9', '6', '8', '3', '5', 'D', '1', 'F', '7', '4', '5', '9', '5', 'A', '2', '7', 'C', '8', 'C', '3', 'D', 'A', 'D', 'C', 'D', '4', 'C', 'A', 'D', 'D', '2', '6', '6', 'B', '9', '9', 'B', '6', '3', '2', '0', '4', '6', '6', '8', 'A', 'B', '1', 'F', 'E', '8', '3', '8', '4', '8', '2', '3', '4', 'C', 'B', 'A', '5', '3', '9', 'F', '1', '2', '2', '2', '3', 'A', 'D', 'E', '3', '2', 'D', '2', '1', '5', 'C', '1', 'B', '7', '3', 'F', 'A', 'C', '1', '2', '6', '0', '5', '0', '4', 'E', '3', 'F', '5', '1', '3', 'C', '1', 'F', '6', '3', '0', '0', 'B', '4', '5', '1', 'E', '5', 'A', 'F', '6', '2', '2', '7', '5', '7', '3', '5', 'D', 'B', '3', 'A', '2', 'D', 'A', 'F', '1', 'A', '4', '5', '0', 'F', '4', '0', 'F', '8', '3', '4', '1', 'A', 'D', 'A', 'C', 'D', '6', 'A', 'F', '4', 'F', 'C', '5', '7', 'E', 'F', 'F', '7', 'E', '7', '0', 'F', '5', 'F', '1', '3', 'A', '8', '6', 'A', '6', '8', '5', '4', '0', 'F', '1', '1', '5', '2', 'E', 'C', '5', '3', '2', 'C', 'C', '0', '4', '9', '9', '0', '2', 'D', '5', 'B', 'D', 'C', '8', '5', '6', 'B', '3', 'D', 'F', '5', 'B', 'A', 'D', '8', '6', '5', 'D', 'D', 'E', 'D', '8', 'B', '2', '5', '5', '8', 'D', '6', '5', 'C', 'C', '9', 'E', 'E', '3', 'B', '1', 'D', '7', 'A', '9', '6', '5', '1', 'A', 'C', '6', '4', '2', 'A', 'D', '7', 'B', '3', 'B', '5', '7', 'D', '8', 'C', '2', 'D', '9', '4', '7', 'C', '6', '3', '2', '5', 'A', 'D', 'C', '7', '9', 'C', '6', '1', '1', '8', 'E', '6', '1', '3', 'C', '8', 'C', '0', '2', '6', '7', '7', 'A', '4', '7', 'E', 'E', '3', 'F', 'E', '4', '3', 'A', '0', '0', '8', '5', 'E', '5', 'F', 'D', '9', '1', '2', '1', '4', '6', '6', '1', '1', 'F', '3', '7', '1', '7', '7', '8', '7', '6', '6', 'C', '1', 'B', 'C', '4', '0', '8', '3', '6', '0', '9', 'F', '5', '0', '1', '3', '5', 'E', '0', '9', 'A', '4', 'E', 'C', 'E', '4', '6', 'D', '5', '9', 'A', '2', 'F', '8', '1', '2', '7', '7', 'A', 'A', '8', 'D', 'E', 'A', '4', '6', 'D', '4', '6', '5', 'F', '8', '2', 'B', '7', 'A', 'E', '5', '9', '3', 'D', '5', '5', 'F', '4', '6', '1', 'F', 'A', 'F', 'F', '2', 'C', 'A', '0', '6', '9', '0', 'F', '3', '9', 'F', 'E', 'B', '5', 'B', 'A', '9', '8', 'F', '8', 'C', '0', '1', 'C', 'E', '1', '1', '9', '5', '0', '5', 'E', 'D', '2', 'D', '1', 'D', 'D', '1', '0', '1', 'D', '1', '4', '7', '1', '9', 'A', 'D', '1', 'B', 'E', '1', 'E', '9', '0', 'E', 'C', 'E', '6', '9', '7', '9', 'C', '2', 'E', '4', 'B', 'A', '2', 'D', '8', '3', 'F', '8', '0', '7', 'A', 'B', '8', 'A', 'E', '1', '9', 'A', '1', 'E', '4', '2', 'C', 'D', '7', '4', '7', 'D', 'C', '0', '4', '9', 'A', '6', '5', 'E', 'D', 'A', 'F', '4', '1', '2', '3', 'D', '6', '6', 'F', '5', '9', '2', '4', 'E', 'B', '1', '9', '5', 'D', '0', '8', 'A', '0', '3', 'B', '7', '6', '3', '1', 'F', 'E', 'A', '6', '8', '1', '7', 'D', '0', '2', '9', '0', '4', '3', '0', '0', '6', '8', 'E', 'B', '7', '2', '0', 'B', '6', '3', '2', 'A', 'F', '2', '4', '7', '3', '0', 'F', '4', 'C', 'F', '9', 'E', '5', '4', '8', '0', 'F', 'E', 'C', 'E', 'D', 'D', '8', '6', 'E', 'F', 'C', '9', '4', '3', 'F', 'E', '0', '6', 'F', 'C', 'A', 'E', '6', '7', '3', '9', '1', '8', 'C', 'C', 'B', '2', '0', '0', '3', '1', '7', '6', '9', 'E', 'E', '3', '1', '0', 'C', 'E', 'E', '5', 'A', 'E', '9', '4', '4', '9', '4', '5', 'E', '2', '6', '3', 'E', '8', 'B', '6', 'E', '9', '3', '7', '0', 'A', '8', '0', '3', 'E', '4', '1', 'C', '1', 'A', '7', '1', '1', '4', 'F', '3', 'E', 'E', '6', '5', '3', '0', 'A', '1', '4', '4', '3', '4', '0', 'F', 'D', '4', 'E', '1', '8', '0', '4', '6', '7', 'B', '3', 'A', '9', 'E', '0', '7', '3', '5', '6', 'E', '7', '9', '8', '6', 'B', '7', '0', '3', '2', '9', '3', 'E', '9', '8', 'F', '3', 'F', 'A', 'C', 'A', '1', '7', '0', '4', 'E', 'A', 'E', '3', '1', '4', '8', '3', '8', '6', '5', '1', '9', 'E', 'B', 'F', '2', '4', '9', 'B', 'A', 'F', 'B', '7', 'B', 'A', '2', 'D', '6', '9', '7', 'F', 'C', '0', '2', '8', '0', '1', '2', 'F', '1', '7', '2', '7', 'B', '0', '4', 'E', 'A', 'E', '2', 'B', '2', '9', '7', 'C', '9', 'A', 'C', '0', 'D', 'A', '3', 'C', 'A', '5', '3', 'E', '2', '3', '8', 'B', '5', '2', '0', '2', '4', 'A', 'B', '3', '2', 'D', '9', '9', 'D', 'B', '9', '1', '7', '4', 'A', 'D', '0', 'F', 'E', 'E', '6', 'A', '2', 'F', '2', '9', '1', '8', '2', '7', '8', 'D', 'E', '6', 'F', 'B', 'F', '7', '8', '1', '7', '3', '4', '6', '6', '5', '4', '3', '2', '8', '5', 'F', '5', '2', 'C', '1', '3', '2', '5', '2', '6', '1', '2', '8', '7', '7', '2', 'B', 'C', '3', '5', '0', '2', 'B', 'F', '3', 'F', '8', '1', '7', '1', '8', 'B', '9', '2', '2', '5', '3', '8', '9', 'D', '3', '5', '0', '8', '2', 'B', '1', '8', 'D', '0', '9', '5', '5', 'C', 'B', '2', 'B', '1', '4', 'D', 'B', '1', '7', '0', '8', 'D', '6', '3', '9', '8', '8', '7', 'C', '0', '5', 'A', '6', 'E', '7', '6', '9', '0', '8', '2', '2', '4', '3', 'E', '1', 'F', 'B', '7', 'A', 'E', 'F', '8', 'A', 'B', 'B', 'D', '7', 'B', '4', '3', '9', 'C', 'A', '4', '1', '4', '7', '9', '0', 'C', '6', '5', '3', '6', 'A', '3', '9', '1', '1', '1', '0', 'A', '1', 'C', '9', 'F', 'C', 'A', '2', 'F', 'F', '4', '4', 'D', '5', '6', '1', '5', 'B', 'A', 'E', '9', 'E', 'C', '7', '1', 'F', 'A', '8', '0', 'B', '5', 'F', '9', 'F', '2', 'D', 'C', '7', '7', '0', '8', 'A', 'E', '4', '4', 'B', 'A', '5', '8', 'E', 'D', '2', '1', '2', '4', '8', 'F', '0', '3', '8', '0', '6', '2', '8', '6', '4', '6', 'E', 'F', '7', '2', 'A', '4', 'D', 'A', 'E', 'B', '5', '1', '8', '8', '0', '7', '8', '7', '0', '8', 'C', '5', '4', '1', 'F', '8', '0', '7', '1', 'C', '4', '8', '9', '7', '2', 'C', 'D', 'A', '0', '7', 'D', '6', 'C', '3', '2', 'C', 'B', '6', '9', '0', '0', '9', '8', '0', 'D', '8', 'A', 'D', '3', '0', '7', 'D', 'B', 'B', 'E', 'A', '4', '5', 'A', '7', '6', 'F', '5', '7', '9', '1', 'C', '8', 'C', 'F', 'A', '9', 'B', '2', '8', '5', 'E', '5', 'B', 'F', 'B', '0', '2', '5', 'A', '2', 'A', '0', '5', 'C', 'C', '8', '9', '4', '7', 'D', '0', '6', '5', '2', '9', '3', 'A', '8', '6', '4', '5', 'F', '6', '8', '5', 'F', 'B', 'D', 'D', 'E', '3', 'B', '1', 'D', 'A', 'D', '3', '5', 'A', '5', '1', '0', '4', '0', '1', 'D', 'A', 'E', '1', 'F', '8', '3', '1', 'F', '5', '9', '0', '6', '6', 'F', 'A', 'B', '5', '0', 'F', 'B', 'D', 'C', 'B', 'E', 'A', '3', '4', '1', '4', '4', 'B', '9', '9', '8', 'D', '4', '1', '3', '6', 'E', 'B', 'F', '5', '5', 'F', '1', 'C', '9', '9', '6', '7', '3', 'A', '1', '7', '8', '1', '9', '9', 'D', '5', 'A', 'B', '8', '3', '8', '2', '1', '9', '9', '5', 'F', '3', 'F', '8', '0', 'A', 'A', 'E', '7', '8', 'D', '2', 'E', '2', '2', '4', '2', 'F', '7', '2', 'D', '1', '3', '9', '2', '1', '1', 'C', '9', '2', 'E', '2', 'D', 'B', 'E', 'B', '8', '5', '1', 'C', '1', 'A', '7', 'C', 'D', 'C', 'E', '8', 'A', 'E', 'F', '8', 'D', '6', '2', 'A', '6', 'D', '7', '2', '7', 'D', '0', '0', 'C', '8', 'F', 'A', 'F', 'F', '1', 'F', 'F', 'F', 'D', '7', '2', 'E', '9', 'C', '3', '0', '1', '2', '7', 'E', '0', 'D', '0', '9', '5', 'C', '4', '8', 'F', 'C', '6', '7', '3', '1', 'E', 'A', 'A', '3', '0', 'A', '0', '3', '9', '2', 'B', 'A', 'B', 'E', '0', 'C', 'B', '2', 'F', '9', '3', '3', '8', '4', 'A', '5', '3', 'A', '6', 'A', '6', 'F', 'D', '0', '9', 'B', '5', '3', '0', '1', '1', 'C', '7', 'B', '1', 'F', 'F', 'F', '8', '5', 'A', '4', 'E', '1', '2', '7', '2', '5', 'C', '0', '9', '4', '2', '0', '7', 'F', '1', '4', 'A', 'B', '2', '4', '2', 'D', 'A', 'B', '9', 'A', '9', 'F', 'A', 'D', 'B', '9', '3', 'C', '9', 'B', '0', '9', '8', '2', '5', '3', '8', '0', '0', '3', '3', '9', 'B', 'F', '8', '5', '0', 'E', '3', 'B', '0', '8', 'E', 'A', '5', 'E', '9', 'E', '8', 'F', '7', '8', 'A', '3', 'B', '3', 'D', 'B', 'C', '0', 'D', 'F', '2', '4', 'C', '5', 'D', '2', 'D', '3', 'C', '4', '6', 'F', '1', '1', '7', '5', '5', 'A', 'A', 'B', 'A', 'B', 'D', 'D', '1', 'F', '9', '1', 'F', '6', '0', '4', 'F', '1', '4', 'B', 'A', 'B', '9', '0', '9', '3', '4', '2', '0', '7', 'F', '8', 'C', '0', '8', '5', 'A', '7', '0', '1', 'D', 'A', 'B', 'B', '3', 'E', '0', '2', '1', '4', '7', '4', 'A', '0', 'B', '4', '3', '5', '8', 'D', '5', '9', '7', 'D', '7', '2', 'B', '3', 'C', '3', '4', 'A', 'E', '2', '7', 'E', '6', '1', '7', 'C', 'A', 'B', '1', 'D', '1', '6', '5', '5', '9', '5', '4', '2', '6', '9', '5', '3', '6', '2', '5', '7', '4', '2', '4', 'D', 'D', '9', '4', '4', '8', 'D', '1', '0', '5', 'F', '8', 'A', 'A', '4', '4', 'E', '1', 'D', 'F', '6', '5', '9', '8', '7', '3', 'A', '6', '0', '4', '4', 'D', '1', 'F', 'F', '8', '4', '3', '8', '9', 'F', 'D', '3', '9', '2', '3', '2', '2', 'C', '2', 'D', '4', '7', 'C', '3', 'C', '5', 'C', '9', 'C', '4', 'E', '6', '5', '1', '4', '4', '8', '2', '9', '8', 'F', '0', '6', 'E', '9', '5', '4', 'F', '0', '4', '6', '6', '9', '0', '3', 'B', '8', '2', 'E', '7', '8', '2', '0', 'A', 'F', '8', '7', '3', '2', '8', '9', 'F', '7', '0', '8', '2', 'D', '3', 'F', 'C', '2', '6', 'F', '7', 'E', '9', '1', '0', '6', '9', '7', '0', '1', 'A', '3', '7', 'E', 'F', 'C', '8', 'E', 'D', '0', '4', '0', '7', '9', '6', '0', '4', 'F', 'F', 'B', '7', 'F', 'F', '6', '3', '3', '5', '5', '7', '2', '3', '7', 'B', 'D', '2', '5', '1', 'C', 'F', '7', '2', 'A', 'D', '8', '4', 'C', '9', '9', '3', 'B', '7', '9', '2', 'D', 'B', '8', '9', 'C', '8', '2', '1', 'B', 'C', 'C', 'D', '5', '7', '3', '7', 'B', '7', '8', '5', '3', 'A', 'C', '8', '0', '1', '1', 'D', 'F', '8', '4', 'A', 'D', '1', '6', 'A', '2', '0', 'B', '4', 'C', '9', 'C', '1', 'B', 'D', '0', '0', '3', 'A', '7', '4', '0', 'F', '0', '5', 'D', '7', '9', '3', '2', 'E', 'F', '7', '1', '6', '5', '8', 'E', '6', 'C', 'C', '0', 'D', '9', '0', 'B', '2', '9', 'E', '3', '4', 'B', '8', '9', '8', 'F', '7', 'D', 'E', '9', '4', 'B', '7', 'A', '6', '7', 'A', '1', '1', '6', '8', 'B', '9', '9', 'D', '2', '7', '3', 'C', '5', 'E', '2', 'E', 'B', '6', '4', '6', '4', 'B', '8', '6', '6', 'B', 'E', '0', '8', '5', 'B', 'D', '9', '3', 'E', 'B', 'A', '3', '8', 'D', '7', '8', '9', 'B', 'A', '2', '0', 'F', '8', '0', 'E', 'B', 'B', '0', '9', 'E', 'B', '9', '8', '7', 'D', '7', '3', 'D', '0', '7', 'B', 'A', '6', 'C', '9', 'D', 'B', 'E', '1', '6', '0', '2', '6', '3', '8', 'F', 'C', 'E', '5', '3', '1', 'A', '8', '5', '1', 'E', 'C', '9', 'C', 'F', '7', 'A', 'D', 'A', '9', 'D', '2', '1', '1', '4', '3', '8', '9', 'B', 'A', 'C', '4', 'D', '6', 'C', '1', 'E', '3', '2', '8', '4', '7', '1', 'C', 'C', 'E', 'B', '4', '5', 'E', 'C', '4', 'C', '2', '7', 'C', 'F', '5', '2', 'D', 'A', '1', '8', 'D', 'E', '8', 'A', '6', '9', '5', 'B', 'D', '7', 'F', 'E', 'F', 'F', '5', '7', 'E', 'D', 'B', 'A', '3', 'C', '7', 'F', 'E', '9', '5', '6', '8', '9', '3', '3', '2', '9', '7', '0', '4', 'B', 'F', 'D', '8', 'B', '7', 'F', '9', '7', '8', '7', 'E', 'E', 'A', '4', '9', 'B', 'B', '9', '9', 'E', '1', 'A', 'E', '7', '1', '4', 'D', 'D', 'E', '1', 'D', '6', 'B', 'C', '8', '7', '8', '4', '9', '3', '3', 'E', 'A', '3', '1', 'C', '9', 'B', '6', '8', 'C', 'F', '7', 'E', '9', '1', '5', '3', '8', '5', '5', 'B', '0', '1', '5', '6', 'B', 'F', '3', '5', '6', '6', '6', '0', 'A', 'E', '6', '8', '2', '4', '7', 'E', '0', 'F', '3', 'D', '4', 'A', '2', 'E', '5', '5', '7', 'F', '9', '4', '3', '3', '2', '4', '2', '7', 'F', 'B', '2', '8', '1', '0', '3', 'A', 'D', '6', '1', '6', '5', '4', '2', '8', '8', '5', '2', '0', '0', '8', 'A', 'E', 'C', 'A', '5', 'E', 'F', 'E', 'E', '9', 'C', '4', 'D', '5', '3', '6', 'D', '1', '7', '8', '8', '9', '5', 'E', '2', '9', 'B', '7', '4', '0', '7', '4', '4', 'B', '9', 'E', '8', 'A', 'A', '9', 'A', '6', 'A', '9', 'F', '4', '0', 'A', '5', 'C', '9', 'D', '0', 'C', 'B', '3', '2', 'C', '6', '2', '9', 'A', '8', 'E', '9', 'D', 'F', '1', '8', 'D', 'E', 'E', 'E', 'C', 'A', '2', '3', '0', '2', 'F', '8', 'C', 'F', '0', '2', '2', '7', 'D', '8', '4', '6', '7', 'E', '8', '9', '5', '3', '1', 'C', 'F', '7', 'F', '1', '5', '3', '8', '8', 'F', '7', 'B', '5', 'E', '6', 'A', '5', 'E', 'F', '4', '5', 'C', 'F', 'F', 'B', '7', 'E', '7', 'F', '3', 'F', '6', 'C', '6', '7', '4', 'D', '2', 'D', 'B', 'F', 'C', '0', '2', '2', 'C', '4', 'F', 'C', 'E', '5', '1', '7', '7', 'D', '8', 'A', '6', '8', '7', 'A', '0', 'B', 'F', '4', 'D', '9', 'A', 'A', '7', 'E', '6', '8', '1', '2', '4', '1', '4', '6', '1', 'D', '4', '3', '6', 'C', '8', '6', 'B', '9', '7', '1', '8', 'F', '5', 'D', 'E', '5', '7', '1', '5', 'C', '4', '1', 'B', 'B', '7', '9', '2', '4', '9', '0', '4', '5', '4', '9', 'C', 'A', 'C', 'B', '8', 'A', '1', 'C', 'C', '0', 'C', 'A', '0', 'C', 'A', '8', '2', 'B', 'E', '8', '7', '8', '4', 'C', '0', 'B', 'B', '3', 'A', '0', 'D', '6', '8', 'E', 'B', 'E', '3', 'C', '3', '2', '9', 'B', '0', 'E', '7', 'D', 'F', 'E', '4', '5', '0', '8', 'B', '9', 'C', 'D', 'C', '7', '1', 'B', 'E', '6', 'C', 'D', '5', '2', '8', '8', 'B', 'F', 'D', '0', '6', '9', '5', '1', 'E', '4', '1', 'A', 'A', '7', '5', '7', 'C', '0', 'C', '8', 'F', '6', '9', '2', 'C', '0', '8', 'E', '2', '0', '5', 'C', 'F', '8', 'C', '4', 'A', '2', '9', 'E', 'A', '8', 'F', '1', '3', 'C', '4', '5', '7', '2', 'B', '2', 'C', 'E', '9', '9', 'B', 'F', 'B', '7', 'D', '6', 'E', '7', '2', '2', 'C', '2', '0', 'E', '7', '8', '7', '4', 'F', '2', '2', '8', '2', '8', '0', '3', '0', '6', '8', 'D', '3', '9', '5', '8', '1', 'E', '1', 'E', '0', 'B', '2', '5', 'E', '9', '2', '7', '1', '5', 'E', 'D', '7', '9', 'C', '9', 'E', 'E', 'F', 'B', 'D', '6', '1', '8', '6', '8', '5', 'F', '5', '3', '0', '6', '2', 'F', '7', 'A', 'E', 'B', '6', '1', '3', '4', '7', '1', '7', 'B', '8', 'D', '9', 'A', 'F', 'A', '0', 'C', '0', 'B', 'D', '4', 'A', '6', '2', '2', '7', 'B', '1', '3', 'B', 'F', 'A', '7', '3', 'C', 'E', '1', '6', '0', 'A', '8', '7', '2', 'A', '9', '0', 'F', 'E', 'E', 'A', 'D', 'F', 'B', '6', '8', 'B', 'C', 'C', '4', '1', 'E', '2', 'A', '7', 'E', 'F', 'C', '7', '5', 'B', 'F', 'D', '5', '9', 'A', 'B', '1', '6', 'B', '2', '6', '1', 'B', '3', 'D', '6', '3', '9', '8', '7', '5', '8', '5', '4', '7', '0', 'E', '2', 'D', '7', 'F', '3', 'E', 'F', 'F', '0', 'F', 'C', '5', 'B', 'F', '2', '8', 'F', '1', '8', '4', '9', 'B', 'D', '8', '2', '4', '3', '4', 'C', '2', 'D', 'A', 'F', '6', '5', 'D', '4', '2', '5', 'A', '1', '8', '3', '0', '9', 'E', '7', '1', 'A', '6', 'B', '2', '0', '8', 'B', '7', '6', 'F', 'B', '9', '8', '1', 'E', '2', '8', '2', 'A', '3', '8', '9', '4', 'C', 'B', '2', '2', '3', '9', '9', 'E', '4', '1', 'B', '2', 'F', '7', 'F', 'F', 'E', 'D', '3', 'C', '2', '4', '3', 'A', 'B', 'A', 'D', 'B', '2', 'A', 'F', '9', '1', '2', '6', '9', 'E', '6', 'D', '9', 'A', '7', '7', 'D', '4', '2', '4', 'B', '9', 'E', 'F', 'C', 'C', 'B', '4', 'E', '1', '9', '3', '1', '5', '6', '6', 'A', '5', '9', 'D', '2', '5', '9', '7', 'C', 'E', '2', 'B', '8', 'A', 'D', '6', 'D', '3', '8', 'E', '3', '6', 'A', 'D', '1', '3', 'F', '9', '5', '2', 'E', 'A', 'A', 'A', '6', '4', '1', 'C', 'A', '2', '0', 'C', 'D', 'A', 'E', '7', '6', '8', 'B', '5', '1', '0', 'C', '7', '3', '8', '1', '9', '8', '6', 'B', '7', '8', 'E', 'B', '8', '5', 'F', 'D', '1', 'B', 'A', 'F', 'E', '5', '6', 'C', '7', '7', 'E', '7', 'B', '4', '3', '0', '9', '2', 'C', 'E', '6', '8', '1', '7', 'B', '1', 'E', '0', 'C', '7', '4', '8', 'D', 'E', '5', 'E', 'F', '6', 'A', 'A', '0', 'F', 'B', '1', '8', '2', '2', '7', '8', 'B', '4', 'C', '1', '1', 'A', 'D', '5', '1', '9', '6', '1', '5', '6', 'B', '4', '8', 'E', '8', '9', '5', 'C', '0', '3', 'B', 'F', '2', '6', '1', 'D', '7', '6', '4', '4', '4', '4', 'C', 'A', '2', '1', 'C', 'C', '7', '3', '7', 'A', 'C', 'F', 'D', '0', '4', 'B', '7', '7', '8', '8', '6', 'F', 'D', 'F', 'A', '0', 'D', '5', '9', 'E', '5', 'D', 'F', 'D', 'E', '7', 'F', '8', '8', 'C', 'D', 'F', '4', '1', '6', '2', 'E', 'F', 'C', 'F', '4', 'D', '3', '1', '6', 'D', 'E', 'D', 'C', '2', '0', 'C', '6', '6', '2', 'A', '5', '6', '1', '2', '3', '1', 'D', '4', 'D', '4', '4', '8', '5', '9', 'A', 'A', '8', '3', 'A', '2', 'D', '4', '9', '8', '9', 'A', '5', '0', '8', '3', '0', '1', '8', '5', '6', '7', 'D', 'A', 'C', '8', '6', 'E', 'F', '9', 'C', '2', '4', '1', 'F', '6', '8', 'F', '7', '1', 'D', '3', '8', '1', '2', '9', '3', '0', '9', '3', '4', 'D', '9', 'F', '9', '8', '0', '4', '3', 'B', '0', '3', 'E', '0', 'B', 'C', '3', '4', '4', '5', 'E', 'F', 'D', '1', 'C', '4', '3', '2', '3', '4', 'D', '2', '9', '2', '5', 'C', '3', '3', '3', '7', '1', '5', '4', '8', '2', '0', '8', 'F', 'F', '8', '7', 'E', '6', 'C', '9', 'F', 'E', '7', 'C', '9', '1', 'B', 'D', 'E', 'E', '4', '2', '7', '6', 'F', '6', '5', 'A', '4', '7', '5', '0', 'D', '0', '4', 'F', 'D', '2', '6', 'B', 'D', '3', '3', '8', '3', '2', '4', 'C', 'D', 'B', 'E', '3', '9', 'E', 'C', '6', 'C', '6', '8', '5', 'B', '1', 'C', '3', '4', 'C', 'B', '8', '7', '5', '6', '6', 'C', 'D', 'B', 'D', '6', '6', '2', '6', '4', 'B', 'E', 'A', 'C', '6', '7', '4', 'C', '6', '3', 'B', '5', '8', '3', 'F', '1', 'D', '2', 'A', '8', '5', '9', 'E', 'B', '2', 'B', 'C', 'D', 'F', 'A', 'C', '5', 'E', '4', '5', '2', '8', '0', 'D', '9', 'C', '3', 'C', '4', '5', '1', '2', '0', '6', '8', '5', 'A', '4', '0', 'D', 'A', '6', 'D', '3', '6', '7', 'F', '8', '1', '2', 'A', '2', '9', '9', '5', '3', '0', 'B', '5', '8', 'D', '5', '4', '8', 'E', 'D', '9', '5', '4', 'F', 'D', 'E', 'E', '3', '2', '8', '0', 'D', 'B', 'D', 'D', '9', 'B', '2', '3', '1', '7', '3', 'C', '0', 'D', '5', 'C', 'D', '4', '5', '0', 'E', '5', '0', '9', '2', 'A', '7', '2', '6', '5', '6', '5', 'F', '3', 'C', '9', '0', '4', 'F', 'C', 'E', 'C', '1', '5', 'B', 'C', '8', '8', '2', 'F', 'F', 'B', '3', '0', '8', '2', 'A', '3', '5', '0', 'C', '8', '9', '2', '6', '7', '4', 'E', '4', 'E', 'E', '7', '3', '4', 'F', '9', '2', 'F', '7', 'F', '3', '1', '8', '1', 'E', '7', '9', '9', '0', 'C', 'A', '9', 'F', '6', 'D', 'E', 'A', '4', '1', '7', 'E', 'F', '8', '1', 'F', 'C', 'D', 'F', '7', '7', 'E', '9', '6', '8', 'D', 'A', 'F', '4', '2', '6', '6', 'F', 'E', '2', '7', '7', 'D', 'B', 'F', 'D', '1', '7', '6', '9', '7', 'B', 'C', '4', '9', 'E', 'D', 'A', '3', 'D', '5', '8', 'F', '3', '2', '7', 'B', '1', 'A', '4', '6', '6', '1', 'E', '3', '5', '4', '0', 'E', 'A', '7', 'C', 'A', 'E', 'F', 'B', 'F', 'B', '5', '4', '7', 'B', 'D', 'C', 'C', '8', '1', '6', '9', '8', '3', '2', 'B', '6', '0', 'D', 'E', '5', 'D', '0', '7', '4', '9', '9', 'E', '2', '2', 'F', 'F', '5', 'C', '7', '1', 'D', 'C', 'C', '2', '2', 'E', '0', '5', 'C', '9', 'C', '6', 'C', '6', '1', '3', '1', '3', '9', 'C', 'F', '2', 'F', '0', '2', '4', '5', '8', '4', '6', '3', 'E', '5', '2', '2', '7', '3', 'F', 'D', '0', 'D', '6', '0', '2', 'E', '6', 'F', '0', '8', 'A', '0', 'A', 'C', 'D', '7', '4', '6', '5', '4', 'C', '0', '3', '8', 'C', 'C', '4', '1', '2', '2', 'C', '4', 'F', 'B', 'E', 'A', '6', 'C', '1', '9', '5', '5', '2', 'F', '5', '3', '7', '0', 'A', 'F', '0', '0', 'B', '7', '0', '8', '0', 'F', '5', '2', 'F', '2', 'B', '1', '4', '8', 'D', '3', 'E', '8', '5', '3', 'D', '7', 'C', '1', '0', 'B', '8', '1', 'E', '1', '1', '7', 'E', '8', 'C', 'D', '5', 'B', '7', 'E', '6', 'F', 'B', 'C', '1', '1', '8', 'F', '3', '0', 'D', 'B', '5', '1', 'D', '7', '4', '6', 'A', 'E', '9', '0', '0', '2', 'D', '8', 'C', '8', 'F', 'E', 'D', 'C', '9', '4', '7', 'E', 'D', 'F', '5', '3', 'D', '2', '3', '7', '1', 'A', '8', '4', 'D', 'E', 'B', '9', '8', '8', '5', '8', '8', 'C', 'E', 'D', 'E', '4', '6', '7', '3', '8', 'D', 'A', 'D', 'B', '1', '5', '3', '6', '2', 'C', '8', '7', 'C', '0', '8', 'C', '2', '5', 'C', '8', '4', '1', '9', 'D', '4', '8', 'F', '7', '8', 'C', '4', 'E', '2', '5', 'F', 'F', 'B', 'C', '3', '9', '9', 'D', 'C', '6', '3', 'A', 'E', '3', 'D', 'B', '2', 'D', '3', '6', '0', 'F', '8', '3', '1', 'A', '0', '7', 'B', 'A', 'D', '6', '9', '7', 'A', '0', '9', '7', '8', '7', '3', 'C', '6', 'D', '0', '4', '6', 'C', 'B', '3', '4', '8', '6', 'E', '7', '5', 'C', '8', '6', '0', '4', '6', 'D', '7', '4', '5', 'E', '8', '5', '0', 'B', '3', '1', '9', 'F', '6', '0', '2', 'E', 'C', 'F', 'F', '0', '4', '0', '0', '7', 'E', 'A', 'B', 'A', '5', '0', '0', 'F', '0', '0', '7', 'D', '2', '9', 'E', '1', 'D', 'B', '8', '1', '8', 'D', '2', '8', '4', 'D', '0', 'C', 'B', '0', 'A', '7', '8', '6', '3', '2', '8', '8', 'C', '5', 'C', '5', 'D', 'D', '7', 'F', 'E', '8', 'F', 'F', '2', '2', '8', 'F', '0', 'E', '6', '1', '6', '0', 'B', 'D', '3', '2', '6', '8', 'A', '6', '8', 'D', 'B', '0', '1', 'C', '3', '5', 'C', 'B', '1', '8', '2', '9', '0', 'E', 'C', 'B', '8', 'D', 'A', '2', '3', '6', 'C', 'C', '0', '4', '3', '4', '0', 'B', 'F', '9', '6', '3', '6', 'E', '8', '2', '1', '8', '9', '6', '1', 'E', '2', 'B', '3', '7', '1', '5', '9', '0', 'A', '2', 'F', '0', '6', 'C', 'C', 'A', '7', '5', 'E', '9', '0', '9', '8', '3', 'A', 'A', 'F', 'B', '6', '9', '2', 'E', 'D', 'E', '3', 'E', 'D', 'B', '3', '0', 'E', '7', 'D', 'D', '8', 'A', 'C', 'C', 'F', 'E', 'C', 'D', '4', '6', 'F', 'F', 'B', '2', '5', '8', '6', '8', 'B', '1', '7', '4', '8', 'A', 'A', '3', '1', '7', '3', '6', '3', '9', '1', 'B', '3', 'B', 'F', 'D', '3', '9', '2', 'A', '7', '8', '0', '7', 'D', 'D', '3', '4', '4', '2', 'D', '0', 'E', '2', '9', '1', '5', '4', 'C', '0', '1', '7', 'B', 'E', '3', '1', '6', 'C', '0', '5', '3', '4', '5', 'C', '4', 'B', '6', '2', 'A', '1', 'A', 'F', '2', '0', '5', 'E', '5', 'E', 'A', 'A', 'F', '9', '9', '8', 'E', '5', 'B', 'C', 'B', '0', '3', '5', '5', 'C', '6', 'A', 'A', '8', '6', '0', '1', '9', 'D', 'A', '1', '3', '0', '9', 'A', '8', 'B', 'E', '1', '5', '9', '9', '2', 'A', '2', 'E', '0', '0', 'D', 'A', 'F', '7', 'C', 'D', 'D', '6', '0', 'D', 'B', '4', '8', 'F', '1', '3', 'B', 'C', '9', '5', '7', 'E', '8', 'A', 'B', '8', 'B', 'B', 'E', '8', '6', '5', 'D', '6', '5', 'A', '5', '5', 'C', '2', '4', '3', '2', '5', '7', 'A', 'A', '8', '5', '9', '7', 'F', 'D', '7', '6', 'A', 'F', '8', '1', 'C', 'A', '4', 'A', '3', 'C', 'D', '8', '3', '7', '8', '7', '4', '6', 'C', '7', '4', 'E', '0', '6', '0', 'F', '0', '0', 'F', '8', '5', '3', '5', 'C', '7', '1', '8', '8', '1', '0', '8', 'B', 'B', '6', '3', 'B', 'D', '5', '7', 'C', '1', '8', '5', 'E', 'C', '8', '5', '2', 'D', '8', '9', 'E', '9', 'D', '1', '3', '4', '9', '1', '0', '4', '9', '9', '6', 'E', '6', '1', 'E', 'F', 'A', '1', 'D', '8', 'B', 'B', 'A', 'A', 'E', 'C', 'B', '6', '2', '3', '3', '5', 'F', '7', '4', '8', '3', '6', 'F', 'B', '3', 'D', '8', '5', 'A', 'E', 'A', 'F', '3', 'E', '2', '3', '7', 'C', '1', '3', '7', '7', '7', 'B', '1', 'B', 'E', 'C', 'D', 'E', '6', 'D', '9', 'E', 'C', '8', '4', '6', '7', '7', '6', '8', '7', 'A', 'F', '6', '1', '9', 'E', 'E', '7', '4', '0', '0', '2', '1', 'A', '0', '6', 'E', 'C', 'A', '2', '2', '1', '3', '0', '6', '8', '7', '0', '6', '1', '3', '5', 'C', '8', 'F', '9', '0', 'F', 'F', '3', 'F', '8', '0', '6', '3', '2', '2', '1', 'C', '4', 'D', '9', 'D', 'C', '9', 'B', '9', '8', '1', '9', 'C', '4', '2', '8', '2', '2', '1', '1', '2', '0', '7', 'D', 'D', 'F', 'E', 'A', '3', 'B', '1', 'A', 'F', 'B', 'F', 'D', '1', '6', '7', '7', 'C', '2', '7', '0', 'E', 'B', '5', 'E', '4', 'B', '7', '7', '2', '9', 'E', '9', '7', 'F', 'F', '4', '6', 'E', '0', '3', '6', 'E', 'D', '4', 'A', '7', 'E', '7', '1', 'C', '8', '4', 'D', 'C', '7', '7', '2', 'A', 'A', '8', '4', 'D', '8', 'D', 'C', 'D', '2', 'E', '3', 'B', 'D', '6', '6', '3', 'D', 'B', 'E', '3', '1', '5', '2', '2', '8', 'A', '5', 'E', '9', '1', '2', '3', 'A', '6', '3', 'C', '9', '0', '5', '4', '5', 'B', '7', '2', 'D', '1', 'B', 'E', 'C', '3', '9', '2', '1', '2', 'D', '0', 'C', '1', 'D', 'C', 'A', 'E', '9', '5', '8', '3', 'E', '1', '2', '7', '3', 'C', 'D', '7', 'F', 'F', '9', '3', '3', 'A', 'A', 'E', '8', 'A', 'C', '5', '2', '5', '1', '8', '0', 'F', '6', 'E', '7', 'F', '3', '3', '7', 'B', '7', '1', '8', '3', 'A', '2', '6', '6', '8', '1', 'B', 'A', '4', 'A', '8', '3', 'C', '1', '5', '4', 'D', '6', 'B', '3', '2', '8', '0', 'C', '3', '3', 'E', 'F', '8', '2', '9', 'F', 'F', 'E', '4', '3', '2', '1', '3', '9', '6', 'F', '6', '0', '2', '1', 'F', 'E', '4', 'B', '3', '3', 'D', 'D', 'A', '5', '6', '5', '1', '0', '8', 'B', 'B', '2', '2', 'D', '1', 'B', 'C', '8', '9', '5', '7', 'E', '4', '9', 'A', 'C', 'E', '9', '9', '6', 'D', '0', 'E', '2', 'C', 'A', 'C', '6', '3', '3', 'B', '4', '0', '8', '3', '2', '7', '1', 'F', 'A', '7', '0', '2', '4', '1', 'D', '1', '6', '7', '8', 'A', '7', '7', 'A', '5', '7', '0', '8', '3', 'A', '8', '6', 'E', '0', 'D', 'F', '6', 'E', 'C', '7', 'B', 'B', '0', '6', 'F', 'E', '7', '1', '5', 'D', 'C', 'E', 'D', '2', '1', '1', '1', '1', '9', '2', '9', 'D', '7', '5', '6', '9', 'E', 'F', 'C', '2', '1', 'C', 'F', '6', '7', '4', '9', '9', 'C', '9', '1', 'E', '3', '0', 'A', 'A', '5', 'A', 'A', 'E', 'B', '6', 'F', 'D', '5', 'C', 'E', 'D', '9', 'C', '4', '2', 'A', 'D', 'B', 'D', '6', '5', 'D', '3', '3', '6', '3', 'E', 'B', '9', 'E', '8', '0', 'A', 'B', '2', '7', '7', '6', 'C', '3', 'D', '1', '2', '0', 'F', '4', 'A', '9', 'E', 'B', '9', 'C', '8', 'C', '4', '5', '1', '2', 'E', '3', '4', 'D', 'C', 'B', '2', '9', 'A', '9', '7', '2', '5', '1', 'D', '4', '9', 'E', 'C', 'D', '7', 'C', '8', '0', '6', 'F', 'B', '9', '5', '9', 'F', '7', 'E', 'F', '1', '1', 'D', 'E', 'E', '4', 'F', 'A', 'A', '4', '2', '9', '8', '4', '0', '5', 'C', 'E', 'D', '2', '3', '1', '6', 'B', 'E', '1', '1', 'B', 'E', 'F', 'C', '0', '7', 'C', '5', '6', 'E', '3', '6', '0', '1', '5', '4', '1', '0', '3', '5', '3', 'A', '2', '2', 'D', 'B', '5', 'D', 'A', 'F', '5', '2', 'F', '1', '6', 'A', '7', 'C', '7', '1', '0', '4', '7', '8', '8', '5', 'C', 'F', 'B', 'C', '5', 'A', '2', 'E', 'C', '6', '9', '3', '5', '0', '7', 'F', 'E', '6', '8', 'C', '5', '4', 'E', '5', 'A', 'C', 'C', 'A', 'D', '2', 'F', '7', '3', 'D', '9', '9', 'F', '8', '1', '9', '3', '4', '5', '1', 'F', '0', 'B', 'E', 'B', 'F', '3', '4', 'C', '4', 'D', '3', '4', '3', 'F', '5', '5', 'F', 'E', '6', 'E', 'B', '1', 'C', '4', '6', 'F', 'D', '9', 'A', '3', '2', '0', '6', '4', '0', 'F', 'C', '2', '9', '5', 'D', '0', 'C', '1', '0', 'B', '1', '3', 'C', '5', 'D', 'A', 'F', '9', '2', 'E', 'B', '8', '4', 'F', '4', '5', '9', '1', '9', '1', 'F', 'E', '5', '7', '4', '8', 'C', '4', '3', 'A', '5', 'A', '3', '7', '4', '8', '0', '7', '6', 'B', '0', 'F', 'C', '8', '1', '1', '8', '9', 'C', '8', 'F', '2', 'D', 'F', '7', '7', '8', '4', 'A', 'C', 'B', '4', '5', '4', '6', '5', '6', 'E', '1', '5', '3', 'C', '0', 'D', '6', 'F', 'E', 'F', '6', '9', 'B', '5', '7', '8', '8', '2', '1', 'D', '3', '5', '0', '4', '9', '2', 'E', 'D', '0', '0', '4', 'F', 'E', 'C', '8', '6', '5', 'D', '3', '8', '9', '3', '2', '4', 'D', '4', 'F', 'E', 'B', '8', 'F', 'E', '1', '8', '1', '6', '2', 'C', '8', '1', '1', '0', '3', '1', '5', 'B', 'E', '7', '3', '2', 'C', '0', '6', 'C', '0', '4', '4', 'B', '2', '2', '3', 'E', 'A', '8', '5', '2', '1', '8', '5', 'A', 'E', '3', 'C', '2', 'F', '2', '9', '6', '6', '1', 'F', 'F', '0', '6', '3', '6', 'E', 'C', '1', '7', '3', '8', '9', 'D', '2', 'A', 'B', '0', 'F', '9', 'D', '8', '8', 'C', 'D', '9', '0', '2', '2', 'C', 'B', '0', '3', 'F', 'A', '9', '2', '8', '8', '6', '2', '6', '0', 'E', '4', '5', 'A', 'F', 'B', '5', '4', '5', 'E', '7', '7', '7', 'B', 'E', 'C', '7', '1', '9', '7', 'A', 'F', '0', '9', '3', '6', 'F', 'A', 'A', 'F', '4', '8', '5', '5', '2', '6', 'A', 'B', '0', 'A', '7', 'B', '2', '2', 'D', 'F', '6', 'C', '2', '2', '5', '8', '5', '6', 'D', '8', '9', 'B', '9', '5', 'D', '7', '1', 'C', 'D', '5', '7', '2', '7', 'E', '0', '9', '9', '6', '9', '0', '6', '5', '7', '5', 'F', 'C', 'F', 'C', 'D', '8', '0', 'A', 'F', '9', '4', '4', 'E', 'F', '9', '5', '2', 'F', '8', '8', '7', '5', 'C', 'D', '4', '8', '4', '1', 'B', '9', '3', 'F', 'B', '3', '9', '3', '9', '8', '9', 'B', '4', '3', 'A', 'A', '6', '1', '4', 'C', 'D', 'B', 'F', '1', '9', 'C', 'D', '2', 'E', '1', '5', 'E', 'A', '3', '0', '8', '5', '9', '6', '8', 'D', 'F', '4', 'C', 'D', '5', 'B', 'D', '4', '8', 'D', 'E', 'C', 'F', '5', 'F', 'F', 'D', '7', 'B', '5', '9', '8', '6', 'A', '8', 'B', '8', 'B', '4', 'E', '4', 'D', '9', '1', 'C', 'D', '7', '1', 'F', '8', '5', '0', '9', '6', '2', 'E', 'A', '6', '4', '4', 'C', 'B', '4', 'F', '4', '8', '5', '2', '1', '6', '8', 'D', '2', '7', '8', 'A', '1', 'C', '2', 'D', '2', 'C', '6', 'B', '2', 'E', '9', 'C', 'B', '7', '7', 'F', '5', 'D', '3', '1', '5', '3', '9', 'D', '3', '5', '2', 'F', '2', 'E', 'F', '8', 'D', '2', '5', '2', '5', 'E', '3', '8', 'F', '4', 'F', 'C', '5', '9', 'D', '2', '7', '2', '8', 'A', '9', 'F', '4', '3', 'E', '6', 'C', '6', 'C', '9', 'F', '7', '1', '8', '5', '2', '8', 'B', '2', 'B', '1', 'F', '6', 'B', 'B', 'D', '9', '7', 'B', '0', 'D', 'F', '0', '6', 'E', '8', 'A', '3', 'D', '7', 'E', 'F', 'E', 'B', 'B', '2', '5', 'F', 'F', '0', '3', '2', 'B', 'E', '5', 'C', '7', 'B', 'C', 'A', '8', 'E', 'F', '8', 'A', '8', '3', '4', '8', 'C', 'A', '0', '2', 'D', '2', 'A', '1', '1', 'D', 'B', '0', '8', '5', 'A', '8', '7', '0', 'D', 'D', 'B', '7', 'D', '7', '2', 'D', '3', '7', '4', '0', '4', 'D', 'E', '1', '9', 'E', '7', 'F', '5', 'E', 'D', 'E', 'A', '0', '9', '6', '6', '7', '1', '4', 'F', '2', 'E', '4', '4', '6', '1', '7', '4', '6', '5', '2', 'D', 'E', '6', 'D', '6', 'B', '3', '3', '2', 'D', '7', 'F', '2', '8', '9', 'B', 'A', '2', 'A', 'A', '6', '3', 'D', 'A', '5', '4', 'C', '4', '3', 'C', 'B', 'D', 'C', '4', '5', '4', 'C', '0', 'D', '4', '6', '5', '6', 'A', '0', '6', '9', '1', '1', 'E', 'E', '7', '8', 'F', 'D', '3', '4', '8', 'C', '5', 'D', '0', '1', '1', 'D', 'E', '6', '3', '5', '9', '7', '9', '7', 'B', '2', 'E', '5', 'C', 'B', '6', '8', '1', '9', '9', '5', '8', '4', '6', '6', 'A', '5', '2', 'B', '0', '1', '3', '7', '9', '7', 'A', '8', 'E', '3', '7', 'F', 'F', '9', '7', 'F', '5', 'B', 'F', 'A', '6', '9', '7', 'A', '1', '6', '2', '3', '3', '6', '1', 'A', '5', '3', '2', '4', 'A', 'E', 'D', 'D', 'A', 'D', 'D', '1', '4', 'B', 'D', '0', '9', 'D', 'A', '0', '6', '1', '2', 'F', '3', '0', '4', 'F', '3', '9', 'F', 'B', 'E', '4', 'E', 'E', 'F', 'A', '4', '8', 'B', '0', '5', '6', '7', 'E', '4', 'D', 'E', '3', 'B', '3', 'C', '4', 'C', '4', '2', '1', '5', '8', '4', '6', 'A', 'C', '8', '1', '3', '2', '1', '0', '7', '6', '3', '5', 'C', 'B', 'B', 'A', '6', '4', 'F', 'E', 'F', '4', '4', 'E', 'F', 'F', 'E', 'F', 'D', '4', 'D', 'C', 'E', '3', 'D', 'A', '3', '4', '2', 'D', '0', 'B', 'C', 'C', '7', '4', 'B', '2', '2', '2', '7', '6', '1', 'D', '6', '8', 'F', '1', 'E', '9', 'A', '7', 'C', 'F', '6', '3', 'C', 'A', 'F', 'E', '9', 'F', '0', 'C', '5', 'B', '8', 'D', '7', '7', '1', '4', '9', '0', '5', '5', '5', 'A', '4', '1', 'F', 'B', '3', 'B', '3', 'B', '3', '1', '7', '2', 'A', '0', 'D', 'B', 'C', 'B', '7', 'E', 'A', '4', '9', '0', '0', '5', 'E', '3', '4', '6', '7', '2', 'E', 'F', '4', '7', '3', 'E', '6', 'E', '8', '2', '0', '3', 'B', 'E', '4', '5', 'D', '6', '5', '9', 'F', '5', '7', 'B', '9', '9', '8', '1', '0', '9', 'B', '3', '3', '4', 'D', 'E', 'C', 'C', '2', '2', '7', '6', '1', '9', 'F', '9', 'E', 'C', 'D', '6', '6', '0', '0', 'C', 'F', '2', '8', '6', '0', '6', 'F', 'F', '4', '0', 'E', '1', '7', '8', 'A', '1', '4', 'F', 'E', 'B', 'F', 'A', '6', 'F', 'F', '4', '6', '6', '4', '8', 'B', '0', '6', '8', '3', '3', '0', '4', 'E', '0', '9', '9', '1', '5', '9', '8', 'E', '0', '1', 'E', '9', 'C', '6', '6', '2', '4', 'A', '9', '7', '7', 'D', '4', 'D', 'C', '6', '2', '2', 'B', '6', '1', 'F', '3', '6', '1', '4', '1', '3', 'D', '2', '2', '0', '5', 'A', '2', '1', '5', '3', '5', '3', '7', 'C', '2', 'A', '1', '7', 'A', 'F', '7', '9', '0', '6', 'C', '0', '5', '7', '4', '6', '7', 'B', '4', '9', 'E', 'F', '1', '9', '5', 'D', 'B', 'A', '2', '0', 'A', '5', 'D', 'E', '0', '1', 'E', '7', '2', 'B', 'E', '3', 'E', '8', '8', '2', '5', '2', '3', '6', '4', '2', '3', '6', '0', 'B', '4', '0', 'F', 'E', 'C', '8', '4', '7', '4', 'F', 'C', 'E', '5', '0', '4', 'A', '4', '5', 'E', '3', 'C', '1', '1', '5', '1', '8', 'B', 'D', 'A', '6', '8', 'E', 'A', '7', '4', '2', '2', '0', '1', '2', 'C', '7', '2', '5', '6', 'A', '0', '3', '3', 'F', 'D', '9', 'B', '5', '3', '1', '5', '0', 'B', '8', '6', '1', 'C', '8', 'B', '0', '3', 'A', '6', '1', '8', '1', '1', '0', '8', '8', '2', 'F', '8', '7', '9', '7', '9', '5', 'C', '7', 'A', '5', '8', '5', '7', 'E', 'C', 'C', '6', 'F', '3', 'E', 'A', '3', '7', '2', '8', 'F', '2', '0', '2', '0', 'C', 'C', 'B', '9', '2', '1', '0', '4', '3', 'F', '4', 'C', '9', 'A', '0', '7', 'E', '0', 'A', '5', '5', '3', 'E', 'E', 'D', 'A', '9', '7', 'B', 'E', 'C', 'F', '9', 'F', '9', '9', 'F', '8', 'A', '6', '6', 'E', '9', 'A', 'A', '2', '4', '6', '6', '7', '7', 'B', 'C', 'B', '0', 'F', 'B', 'B', '9', '5', '7', '5', '8', 'F', 'C', 'A', '6', 'D', 'B', 'F', 'B', '8', 'D', 'B', 'C', '7', '8', '1', 'F', 'A', '5', 'C', '0', 'F', 'B', 'F', 'F', '2', 'F', '4', '5', 'A', '8', '4', '5', '2', '2', '3', '1', '8', '2', 'F', 'D', '9', '4', '6', '5', '8', '3', 'C', '1', 'A', '6', '3', 'C', 'C', '5', '6', 'E', 'F', 'E', 'A', 'D', '4', 'F', '6', '1', '7', '3', '2', '9', 'C', '0', 'A', 'E', '2', 'F', 'A', 'D', 'C', 'D', '4', 'A', '0', '6', 'B', '7', '0', 'D', 'B', 'E', '5', '9', 'C', '7', '5', '4', '7', '8', '7', 'C', 'D', '2', 'D', '8', '7', 'B', 'B', 'D', '7', '9', '4', 'E', 'F', '4', '3', 'C', '8', 'A', '4', 'C', 'C', '9', '0', '3', '4', '5', '5', '6', 'B', 'D', 'D', 'C', '4', '0', 'A', 'C', 'E', '3', 'C', 'B', 'C', '8', '6', 'C', '7', 'A', '0', 'F', 'E', '0', 'E', '6', '0', 'A', '4', '9', '0', 'E', '6', 'F', '9', 'D', '7', 'D', 'A', '8', '9', 'D', 'E', '8', '6', 'D', 'C', '5', 'D', '1', 'B', '7', '8', 'B', 'E', '0', '1', '4', '9', 'A', '0', 'E', '5', 'B', 'A', '6', '2', '0', '1', 'D', '4', '8', '5', 'E', 'A', 'B', 'D', 'D', 'A', 'F', '5', '6', 'E', '5', 'F', 'B', '4', '6', 'F', 'C', '4', '8', '4', 'B', 'D', '9', 'B', '8', 'C', '3', 'F', 'B', '8', '5', 'E', '3', 'C', '3', 'E', '5', 'F', '5', 'F', 'C', '3', 'B', '1', 'E', '2', 'D', 'A', '1', '5', '5', '0', 'F', 'E', 'F', '9', 'B', '7', '4', '7', '0', '4', '0', '6', 'E', '9', 'B', '0', 'C', 'E', '4', '5', '6', 'A', '8', '9', '0', '0', '7', 'F', '9', '1', 'D', '8', '3', '8', 'A', '0', '2', '2', '8', '4', '3', '3', '8', 'D', 'A', '5', 'E', '1', '4', 'F', '5', '5', '9', 'F', '7', '9', 'F', 'E', 'C', '1', '8', '4', '0', '7', '3', '3', '2', '5', '5', 'C', '0', 'D', 'D', 'A', '9', '2', '9', 'B', 'D', '7', 'D', 'C', '4', '7', 'D', '7', 'E', '9', 'C', '4', 'D', 'D', 'E', 'E', '5', 'E', 'B', 'E', '0', '4', '8', '7', 'F', 'A', 'F', '9', 'B', '3', 'D', 'A', 'C', '7', '3', 'C', '5', '3', '9', 'D', '6', '1', '6', '4', 'B', '5', '3', '8', '4', '2', '2', 'E', 'E', 'D', '1', '1', '2', 'C', 'D', '1', 'F', '1', 'F', '8', '6', 'E', 'E', '1', '1', '6', '5', '6', '5', '9', 'A', '8', '4', '0', '8', 'D', '1', 'B', 'D', '3', '1', 'A', '9', '0', '8', '2', '4', '7', '9', '3', '7', '5', '0', '6', '0', 'E', 'D', '5', 'D', 'B', '7', 'F', '9', '6', '1', '1', 'C', 'B', '0', '4', '5', '1', '3', 'E', '7', '6', 'B', '5', '7', '6', 'F', 'D', '3', '5', 'A', '8', '1', 'E', '7', '4', 'F', '9', 'A', '9', '9', '6', 'E', 'A', '7', '4', '2', 'F', 'C', '3', '7', 'E', 'E', 'E', 'E', 'A', '6', '5', '1', '5', 'A', 'E', '3', '1', 'B', '0', '5', '3', 'F', 'F', '4', 'E', '0', '9', 'F', 'D', '4', 'F', 'F', 'F', '1', 'B', 'E', '6', 'F', 'B', 'C', 'A', '1', 'F', 'C', '8', 'F', '4', 'A', 'B', '1', '2', '4', 'D', '8', '9', '4', '8', 'B', 'E', '3', 'B', '4', '9', '6', '6', 'B', '9', 'D', 'B', '7', '7', '2', 'A', 'E', '0', 'C', '3', '0', '1', '1', '5', '6', '3', 'B', '2', '2', '3', 'F', 'C', '3', 'B', 'F', '9', 'A', 'C', 'A', '7', '6', '1', '4', '5', '4', '8', 'F', 'D', '4', '4', 'E', '0', '2', '1', 'C', '8', 'F', '6', '5', '2', '2', '3', 'B', '0', '7', 'C', '6', '3', 'F', '3', 'C', '8', '0', 'F', '8', '1', '0', '0', 'E', '7', '9', 'B', 'F', '2', 'D', 'B', '6', 'D', '7', 'E', '9', 'C', 'F', '1', 'D', '4', '7', '8', 'B', 'A', '6', '7', '9', '6', '8', 'A', 'D', 'B', 'C', '4', 'A', '4', 'B', 'C', '1', 'D', '3', 'C', 'E', '8', '1', '7', '0', 'A', 'E', '7', 'C', '6', '8', 'C', 'A', '7', 'F', '7', '3', 'D', '4', 'A', 'B', '8', '1', 'D', '5', 'C', '6', '4', '5', 'E', '4', 'A', 'E', '0', '6', '6', 'B', '7', 'B', 'B', '5', '6', '9', 'C', 'B', '5', 'F', 'B', '8', '1', '6', '9', '3', 'A', 'A', 'F', 'C', 'D', '5', '3', '7', '5', 'B', '1', '3', 'F', '8', '6', '0', 'A', '0', '4', 'D', 'F', '4', '3', '0', '6', '8', '4', '1', '1', 'A', 'B', 'D', '9', '2', '9', '1', '4', '6', '1', 'C', 'C', '3', 'E', 'A', 'A', '8', '3', 'D', '9', 'F', 'E', 'E', '8', 'A', 'C', '4', 'A', 'F', 'E', 'C', 'E', 'A', 'A', '7', '2', '1', '9', 'F', '0', '0', '8', '5', 'A', '9', '2', '3', '0', 'D', '7', '9', '8', 'F', '0', '3', '8', '2', '7', '0', 'A', '8', '1', 'D', 'A', '7', '2', 'D', '1', '3', 'A', 'B', '1', '4', '9', '2', '3', '3', '1', '2', 'C', 'B', 'A', '3', 'C', 'F', '1', '5', 'C', 'B', '4', '0', '2', 'A', '3', '2', '5', '4', 'B', 'E', '0', 'D', '9', 'E', '8', '6', '2', '5', '1', '5', '7', 'C', '7', 'A', '4', '3', 'D', '6', 'E', 'F', 'C', '3', 'F', '8', 'E', '2', '5', 'C', '5', 'F', 'E', 'C', '6', '0', '4', '8', '7', '9', '0', 'B', '9', 'A', '8', '9', 'B', '9', '7', '2', 'E', '4', '6', '9', '6', 'B', '9', '1', '0', '9', '2', 'D', '3', '8', '3', '6', '4', 'E', 'F', 'C', '4', '8', '3', '5', '6', '0', '7', '0', 'C', '6', 'B', '5', '6', '9', 'D', 'D', 'C', 'D', 'C', '2', '1', 'B', 'B', '1', '4', '0', '3', '4', '7', '0', '9', '4', '8', '6', 'A', '3', '5', '8', '1', '5', 'F', 'C', '9', '5', 'A', '6', '1', '3', 'D', '8', '0', '6', '8', '7', '4', 'E', 'D', '5', 'E', 'B', 'A', 'F', 'A', '4', 'E', '0', 'E', '2', '5', '8', '6', '3', 'D', '3', 'B', 'E', 'E', 'E', '1', '9', '6', '4', '6', '2', '8', 'E', '8', '7', '6', '0', 'E', 'A', '9', 'D', 'F', 'E', '3', '7', '9', 'E', '3', 'D', '3', '1', '1', 'B', '1', 'B', '0', 'F', '6', 'D', '9', 'C', 'A', '6', '2', 'B', '5', 'A', '2', 'E', '4', '2', 'A', 'D', 'A', 'B', 'D', 'E', '4', '7', '9', '4', '3', '1', 'B', 'D', 'D', '5', 'E', '3', 'A', 'A', '5', '3', '4', 'A', '4', '9', 'B', 'C', 'D', '7', '0', '0', 'B', '1', 'D', '7', 'F', 'B', '9', 'E', 'C', '5', '6', 'B', '0', '2', '9', '6', '5', 'F', '6', '6', '7', 'C', 'A', 'B', '4', '9', '3', '8', '0', '2', '8', '4', '3', '4', '3', '6', 'E', '4', 'B', '1', '1', 'A', '2', '5', '9', '4', '5', '2', '1', '6', 'A', '7', 'C', '7', '5', '1', 'D', '2', '2', '1', '9', 'A', 'A', '8', '5', '2', 'E', '5', 'C', 'F', '7', '6', 'F', '1', '4', 'B', '4', 'A', '5', '1', '9', '6', 'D', 'D', '5', 'C', '8', '6', 'B', 'A', 'D', '1', '3', '7', '9', '7', '9', '1', '2', 'A', 'F', 'A', 'D', '3', '8', 'B', 'C', '5', 'A', '3', '6', 'F', '4', '7', 'E', 'C', '2', '8', '9', '1', '4', '7', '7', '9', 'D', '0', 'D', 'D', 'A', '1', '3', '0', '1', '5', '3', '7', '7', 'F', '2', 'B', '9', 'B', 'D', '2', '3', 'C', '0', '5', '3', 'F', '4', 'F', '2', '5', '6', '0', '5', '3', '8', '7', 'C', 'B', '1', '8', 'A', 'A', 'A', '7', '3', '7', 'A', 'F', '6', 'D', '7', '4', 'C', 'B', '0', 'C', 'B', '2', '7', '3', '4', '2', '5', 'F', 'C', '8', 'E', 'A', 'F', '6', 'F', 'F', '1', '8', '4', '1', 'D', '4', 'E', '9', 'E', 'D', 'D', '2', '6', 'D', '2', '4', '1', '7', 'B', 'F', 'C', '6', 'E', 'C', '3', '0', '4', '0', 'D', 'B', 'C', '6', '7', '6', 'E', 'E', 'D', 'D', '5', '3', '4', '5', 'E', '7', '8', 'E', 'A', '5', '9', '3', '2', '7', '3', 'B', '1', '1', '6', 'D', 'B', 'A', '8', 'E', '4', 'E', '0', 'D', '8', 'E', 'A', 'E', '9', '3', '4', '8', '3', '5', '6', '9', '7', '4', 'F', '2', 'E', 'F', '6', '8', 'A', 'F', 'A', '3', 'B', 'F', '3', 'F', 'C', '2', '6', 'F', 'B', 'E', '3', '5', 'D', '6', 'B', 'D', '0', '9', '5', 'E', '9', '5', '2', 'B', '7', '0', 'D', 'D', 'E', 'B', 'E', 'B', 'E', '0', '3', 'F', '7', 'C', '6', 'D', '1', '3', '3', '3', '4', '3', 'F', 'A', 'B', 'D', 'B', '3', 'E', 'F', '7', '1', '8', 'C', '1', '9', '5', '6', '4', '9', 'C', '5', '7', 'F', '4', 'B', '2', '5', '4', '9', 'D', '6', '3', '3', 'B', '1', '9', '1', '2', '0', 'E', '8', '1', '4', '9', 'C', '7', 'D', '6', 'D', '8', '7', '6', '7', 'F', 'C', '6', 'F', '1', 'A', '3', '2', '7', '9', '1', '5', '7', 'F', '2', '3', '7', 'B', '9', '8', '0', 'C', '4', '0', 'C', '1', '5', 'E', 'F', '6', '2', '7', 'D', '3', '4', '8', '7', 'F', '0', '2', 'B', '9', '1', 'C', 'F', 'B', '0', '4', '8', '0', '6', '5', '9', '9', '3', 'D', '1', '4', '3', 'F', '3', 'F', 'A', '3', '7', 'F', '7', '2', '4', '4', 'A', 'E', '6', '5', '8', '9', '9', '0', 'E', 'E', '5', 'D', '0', '9', '9', '0', 'C', '9', '8', '9', '1', '7', '8', 'F', '0', '3', '6', 'E', '7', '0', '4', '9', 'C', '3', '1', 'D', '4', '5', 'B', '8', 'D', '7', 'B', '6', '8', '3', 'C', 'B', '7', 'D', '6', '2', '3', 'C', '5', '8', '2', '9', '4', '5', '2', '7', 'A', '2', '6', '6', 'E', '3', '4', '0', '3', '2', '5', '1', 'E', '8', 'A', '8', 'B', 'A', '1', '6', '4', '9', '3', '6', '2', '9', '9', '7', '6', '1', 'A', 'C', '2', '3', 'F', 'E', '6', 'D', '1', 'E', '6', '7', '3', '2', '8', '2', '0', '7', 'F', '2', 'D', '4', '5', '4', '3', '0', '8', 'C', '2', '7', 'B', '3', 'A', 'D', '9', 'C', 'B', 'F', 'E', '3', 'E', '9', '5', '6', 'E', '1', '4', 'B', '9', '9', '7', '0', '0', '6', '2', '1', 'D', 'C', '9', '3', '5', '0', 'A', 'E', 'E', '8', '3', 'F', 'C', '5', 'E', '3', '1', '1', 'D', 'B', '3', '1', '8', 'A', 'F', '9', '7', 'E', '2', 'D', '1', '4', '4', '7', '1', '1', '3', '3', '3', 'A', 'A', '3', '2', '4', 'D', 'B', '0', 'B', '5', 'B', 'C', '6', '3', 'D', 'E', '0', '5', 'A', '9', '0', '5', 'E', 'D', '0', 'D', 'D', '5', '1', '4', '2', 'D', '9', '2', 'F', 'E', 'D', '4', '7', '3', 'D', '8', '3', '1', '6', '8', '9', '4', 'B', 'A', '9', '3', '6', 'A', '9', '2', 'F', 'B', 'C', '7', 'C', 'C', 'C', '8', 'F', '8', '9', '3', 'C', '7', '1', '6', 'D', 'E', '1', '6', '0', '2', '2', '4', 'B', '0', '4', '2', '9', '9', '0', 'F', '5', '2', '7', '0', '5', 'C', '6', 'A', '9', '1', '7', '3', '2', '5', '5', '9', 'A', '8', '8', '4', 'F', '4', 'C', 'F', '2', '4', '9', '8', '6', 'C', '8', '1', '6', 'D', '6', 'A', '5', '6', '9', '8', '0', '2', '5', '1', '3', '9', '0', 'E', 'E', '1', 'E', 'F', '5', '2', 'D', 'C', 'B', 'F', 'F', '8', '3', '7', 'C', '3', '1', '7', 'E', '3', 'A', '4', '6', '3', '5', '0', '4', 'C', '3', '8', '6', '4', '5', '5', 'A', '2', 'A', '6', 'F', '0', 'A', 'B', '3', '3', 'E', '3', '5', 'C', 'C', '1', '3', 'D', 'D', '3', 'B', '9', '0', 'D', '8', 'A', '0', '5', '2', '0', '0', 'B', '1', 'A', 'E', 'C', 'C', '9', '3', 'C', '3', 'A', '0', 'A', 'B', '5', 'D', '8', '6', '3', '1', 'E', '4', '3', '3', 'E', 'C', '9', '2', '1', '1', '4', 'D', '0', '3', '7', 'D', '2', '8', 'A', '8', '5', '0', 'E', 'D', '0', '2', 'D', '7', 'D', 'C', 'F', '1', 'E', 'B', 'C', '1', 'E', '7', '3', 'F', 'D', 'B', 'C', '5', 'C', '4', 'E', 'E', 'B', 'F', 'E', '8', '7', '0', '7', '5', 'F', '0', 'C', '9', '2', 'D', '2', 'E', '3', 'E', 'A', '0', 'F', '8', '9', 'B', '1', 'D', '1', 'D', 'B', 'F', 'C', '4', 'B', 'E', 'D', '8', 'B', '3', 'F', '4', '1', '9', '1', '2', '5', '7', '3', '8', '1', 'B', '2', '9', 'F', 'A', 'F', 'E', '9', '7', '9', '3', '3', '5', 'C', '9', '4', '3', 'D', '9', '9', '1', 'F', '3', '7', 'B', 'A', '3', '1', '2', 'A', '2', '5', '2', '8', 'E', '7', '2', '6', '0', '7', '1', '7', '8', 'D', '1', '8', 'C', '3', '3', '0', '9', '5', 'D', 'F', '1', 'C', '6', '5', '5', 'F', 'D', '0', 'E', 'C', '3', '4', 'A', '7', '6', '6', 'D', '2', 'A', 'B', '9', 'E', '2', '3', '3', 'B', '0', '6', 'A', '6', 'F', '5', 'B', '4', '5', '9', '1', '5', '0', 'E', '2', '9', 'A', '5', '4', '4', 'F', '6', '6', '3', '9', 'E', 'D', '1', '9', '3', '6', '2', '3', 'B', '6', '1', '0', 'B', '0', '4', 'C', 'D', 'C', '0', '8', '5', '4', '3', '9', '6', '0', '1', 'F', '1', 'C', 'D', '6', '8', 'F', 'D', '0', '1', 'F', '1', 'A', '9', '6', 'C', '6', 'B', '4', 'D', '0', 'D', 'B', '3', '3', '8', '5', '5', 'E', 'D', 'C', '3', '2', 'B', '4', '7', '8', 'D', '1', '8', '6', '2', '2', '2', 'E', '0', '5', '0', 'B', '8', '6', '5', '1', '5', '1', '5', '3', 'B', '9', 'F', '0', '9', 'B', 'E', '8', '1', '0', 'C', 'C', 'C', 'C', 'B', 'F', '3', '6', 'C', 'B', '4', '6', '3', '1', '5', '5', '7', 'B', 'F', '6', '6', 'C', 'E', '1', '4', 'A', '3', '6', '1', '9', '8', '8', 'C', 'B', 'C', '0', 'B', 'F', '1', '1', 'D', 'A', '9', 'C', 'B', '3', '5', 'B', 'A', '9', '6', '0', '6', '6', 'E', '2', 'B', '4', '7', '9', '8', 'C', '1', '7', '8', '0', 'F', 'C', '1', 'C', '3', '2', '6', 'D', '2', 'A', '7', 'D', '2', 'B', 'E', 'F', '5', 'D', 'F', 'E', '7', 'E', 'A', '6', '7', 'F', '7', '3', '6', '2', 'B', '4', '0', 'C', 'E', '3', '9', '8', '2', 'D', '6', 'A', '7', 'D', '6', '0', '4', '9', '5', '0', '9', '6', '3', 'F', 'D', '5', '9', 'C', '2', '4', 'E', '9', '1', '8', '5', '8', 'E', '4', 'A', 'E', 'B', '4', 'C', '1', '2', '1', '4', '3', '3', 'B', '6', '0', 'A', '2', 'A', '1', '2', '4', '9', 'D', '7', '3', '3', '7', '4', '4', 'B', '9', 'F', '5', '9', '6', 'C', 'A', 'B', '8', '1', '6', '2', 'A', '2', 'C', '9', '1', '0', '1', '9', '9', '0', '7', '1', 'B', '1', '0', '5', '8', 'D', '5', 'E', '0', '7', 'C', 'F', '9', '8', 'B', '8', '2', '9', '1', 'A', '1', '4', '6', 'B', 'A', 'F', '3', 'E', '4', 'D', '4', 'E', 'F', 'A', 'F', 'E', '0', 'F', '4', '6', '2', 'A', 'C', 'A', '9', 'B', 'B', 'C', '9', '2', 'A', 'C', 'F', '3', '3', 'A', '8', '8', '9', 'E', '6', '9', 'A', 'B', '7', 'A', 'F', '1', '9', 'A', 'B', '6', 'B', 'B', 'E', '4', '9', '1', 'F', 'E', '3', '0', '2', 'A', '7', '0', 'F', 'C', '0', '7', '9', 'D', '1', '3', '3', '6', '6', '1', '4', '5', '0', '6', '4', '6', '1', 'A', 'E', 'F', '5', '9', '5', 'E', '4', '4', '4', '6', 'F', 'B', '8', '5', '5', '3', '9', 'E', '0', 'A', '7', 'E', '0', '5', '3', '9', '5', 'A', '3', '0', '7', '3', '7', '7', '5', '3', 'C', '1', '2', 'D', '3', 'D', 'A', '6', 'A', 'A', '1', '1', '5', '0', 'D', '7', '2', 'A', '1', 'E', '3', '1', '8', '1', '8', 'E', '6', '7', '5', 'B', 'B', '2', 'C', '9', '6', '7', '7', 'A', '1', '9', '2', '6', '4', '2', '0', 'F', '0', 'B', 'C', 'B', 'C', '9', 'D', '3', '4', '8', 'B', '7', 'B', '7', '7', '3', 'E', '0', '2', '2', 'A', 'F', '8', '4', 'B', '5', '5', 'B', '0', 'F', '7', 'C', 'D', 'E', '6', 'F', '9', '3', '2', '5', 'D', '7', '1', 'D', 'E', 'B', '2', '9', '1', '4', '0', '7', '2', '3', '8', '8', '7', '7', 'F', '0', '7', '0', 'A', '8', '4', 'F', '1', '0', '8', '6', '4', 'E', '6', 'A', '8', 'A', '0', 'F', '7', '1', '9', '6', '5', '7', '9', '1', 'D', '3', 'B', 'F', '1', '8', 'D', '4', '4', 'F', 'C', '0', '9', 'F', 'B', 'C', '4', 'E', 'E', 'E', 'E', 'E', '2', '7', '5', '9', '3', '9', '0', '0', '5', '4', '5', '3', '6', 'A', 'B', 'B', 'A', '9', 'E', '3', 'B', 'A', '0', '9', '9', '1', '4', 'E', '1', '0', 'A', '6', '6', '8', 'F', '5', 'D', 'C', '0', 'D', '5', '5', 'F', '3', '5', 'D', '2', 'B', 'E', '3', 'E', '2', 'A', '3', '3', '8', 'D', '8', '5', '9', 'B', '4', '2', 'F', '0', '4', '7', 'A', 'E', '0', '3', '0', '4', '8', '3', '5', 'F', '9', 'C', '1', '6', 'B', '1', 'F', 'D', 'B', '7', '4', '8', '2', '1', 'F', 'D', '0', 'E', 'C', 'D', 'B', '2', 'C', '2', 'D', '8', '9', '6', '2', '2', '7', 'C', 'A', 'C', 'F', '7', '2', 'B', '9', 'A', 'F', 'D', 'D', '4', '2', 'D', '1', 'E', '2', 'A', 'B', 'F', '3', 'D', '5', '0', '1', 'C', '3', 'F', 'E', '9', '0', '1', '2', 'B', '9', 'B', '1', '0', '2', '7', '7', 'B', '6', '4', '9', 'A', '2', '5', 'F', 'A', '2', 'F', 'C', 'E', 'D', '7', '9', '5', 'E', 'F', '3', 'D', 'A', 'F', 'D', '9', '9', '5', '3', 'D', '5', '6', '5', '8', '9', '0', 'F', '9', 'B', '2', '3', 'B', 'E', '3', '6', '2', 'A', '0', 'D', 'E', '5', '8', 'F', '9', '8', 'A', '1', 'B', 'D', '0', 'A', '2', 'A', '8', '9', 'D', 'C', '6', 'D', '6', '7', 'E', '6', '7', 'E', '0', '7', '7', 'A', 'E', '7', '0', '5', 'F', '2', 'B', '1', '0', '5', '5', '9', '8', '7', '4', '6', '1', '3', '2', '6', '0', '4', 'B', '2', 'C', '6', '2', '7', '5', '7', '9', 'C', '8', '5', '9', 'C', 'B', 'D', '2', '5', 'A', '3', '2', 'B', 'E', 'C', 'B', 'E', '8', '6', 'B', 'E', 'D', 'B', '0', '6', 'A', 'F', '8', 'C', '2', '3', '2', '4', '9', 'C', 'C', 'F', 'A', '4', '6', 'F', '6', '4', 'D', '6', '8', '9', '3', 'E', 'B', 'D', '7', '2', 'A', '5', '8', '6', '5', 'B', '5', 'F', 'B', 'C', '8', 'B', '2', '0', '5', 'C', 'A', 'D', 'C', '6', '2', '9', 'E', 'F', 'F', 'F', '6', '8', '5', 'F', '1', 'B', '5', 'A', '9', 'A', 'E', '4', '3', '6', 'F', '7', '1', '1', '0', '0', 'F', '8', '1', '1', '6', 'C', '4', '4', '2', '0', '2', '2', '3', 'B', 'A', '2', 'B', 'A', '4', '4', 'D', 'A', '9', '8', '4', 'D', 'D', '6', 'B', '2', '7', '3', 'A', '8', '3', 'B', 'C', 'D', '7', '5', 'A', 'A', '3', 'A', 'A', '0', '3', '1', '3', 'C', '3', '8', 'C', '8', 'A', 'B', '2', 'B', '9', '1', '6', '0', 'D', '8', 'F', '2', 'B', '8', '8', '1', '1', 'A', 'E', '7', 'A', '7', '5', '7', '2', '8', '0', '5', '0', 'E', '5', '1', 'F', 'A', 'B', 'C', '3', '3', '8', '5', '3', '8', '7', 'F', 'E', 'C', '1', 'C', 'F', '8', '6', '4', '7', '5', '5', '6', '2', 'A', '7', 'D', 'F', '8', '3', 'E', '1', '8', '9', '3', 'A', 'A', 'F', '9', '5', '4', 'A', '0', '6', '1', '9', '9', '3', '2', 'C', 'F', 'E', '9', '4', 'C', '2', '7', '0', '1', '1', '4', 'C', '4', '1', '7', 'A', '4', 'B', '7', 'E', 'B', '1', 'F', '0', '5', '9', '7', '4', '3', 'C', '9', '5', '8', '2', '9', 'E', '2', '0', '7', '3', '1', 'D', 'E', 'F', 'F', '0', '9', '3', '3', '8', 'D', '7', 'C', '9', '9', 'D', 'C', 'F', 'F', '4', '7', 'F', '4', 'F', 'B', '3', '7', '5', '6', '2', '0', '5', '8', '2', '8', 'B', 'B', 'A', '8', 'C', '0', 'A', 'A', 'A', '8', 'A', '5', '6', '6', '9', 'B', '0', '9', '6', '8', '0', '7', 'E', 'A', '4', '8', 'A', '9', 'B', '4', '9', 'D', 'C', 'C', 'C', '8', '6', '8', 'B', '9', 'B', '8', '4', '0', '3', '6', 'C', 'F', '7', 'E', '4', 'C', 'E', 'E', 'F', 'C', 'A', '5', '8', '1', '4', '7', 'E', 'D', 'A', '7', '7', 'C', 'A', '5', '1', 'C', '5', '2', '3', '4', '1', '6', 'E', 'B', '2', '9', '8', '9', '7', 'F', '4', '3', 'E', '0', '5', 'A', '6', 'C', 'A', '2', 'F', 'F', '9', '6', 'D', '4', '4', 'F', '2', '5', '5', '4', '5', '6', '1', 'D', '8', 'C', '9', '9', 'E', '0', 'E', '9', 'C', 'C', '6', 'E', 'F', '9', '6', '2', '0', 'E', 'C', '0', '1', 'F', 'D', '3', 'C', 'D', 'A', '2', '2', 'A', 'F', '4', '6', '9', 'E', '0', '0', '2', 'E', '4', 'C', 'E', '4', '4', 'A', '5', 'C', 'C', '2', '5', 'B', '7', 'C', '8', '7', 'A', '4', '0', '2', '1', '0', '1', '0', '7', 'C', '7', '5', '5', '8', '0', 'A', 'D', 'A', '9', '1', '0', 'A', '2', '4', 'F', 'B', '3', '9', 'E', '3', 'D', '4', '9', 'F', '1', '2', 'A', 'A', '5', '7', '7', '1', 'D', '6', '9', 'E', '4', '3', '2', '5', '8', '3', 'F', '6', 'D', 'F', '1', 'E', '6', 'D', 'B', '1', '2', '3', '6', 'F', '4', 'D', '5', '1', 'B', 'E', '3', '9', '2', 'A', '4', '2', '6', '7', '5', 'E', '1', '7', '1', '9', '4', '6', 'E', 'A', '7', 'E', '4', 'D', 'B', '4', '3', 'B', 'E', '4', '1', '1', '7', '3', 'A', '6', 'C', '6', '8', '1', '8', '2', '9', '4', '5', '9', 'B', 'D', '5', '0', 'E', '2', 'A', '5', 'B', '7', '9', 'B', '5', '0', 'F', '9', 'C', '1', '7', '8', '5', '6', 'F', '9', 'F', '2', 'B', '7', 'B', '9', '5', 'F', '6', '6', '4', '4', 'C', '8', '3', '6', 'C', '7', '8', '2', 'D', '4', '8', '3', '6', '5', '5', '5', '6', '9', '5', '7', '8', '5', '6', '2', '4', 'F', '2', '3', '6', '2', 'C', '0', 'D', 'D', '9', '0', '4', '8', '1', 'D', '4', 'F', 'B', '2', 'C', 'A', '6', '9', '5', 'F', '2', '5', 'D', '6', '8', '9', '2', '1', '2', 'E', 'E', '9', 'D', 'B', '9', '3', '7', 'D', '7', 'E', '6', '0', 'D', '3', 'F', 'A', '5', 'D', '3', '6', 'E', '5', '9', '0', '8', 'D', '2', 'D', 'D', '0', 'F', '0', 'C', '5', '7', '2', 'C', '4', '3', 'F', '2', '2', '3', '9', '9', '3', 'E', 'B', '0', 'A', '4', 'C', 'E', '8', '1', 'E', '7', '1', '6', '3', '4', 'F', '5', 'E', '7', '5', 'A', 'F', '6', '9', '1', '1', '5', '3', '2', '7', '5', '8', 'E', 'D', '7', 'E', 'F', '9', '8', '1', '6', 'B', 'D', '4', 'A', 'B', 'F', '4', '8', 'D', 'C', '7', 'F', 'F', '6', '7', '2', '8', 'E', 'F', 'C', '0', '6', '0', 'B', '2', '8', '5', 'C', 'E', '2', '2', 'C', '1', '1', '5', 'F', 'A', '7', '4', '6', 'B', '7', 'B', '6', 'F', '6', '7', '1', 'C', '7', '3', 'D', 'B', '2', 'B', 'C', '7', 'E', '3', '2', '4', '7', '8', '9', 'B', '9', '0', 'F', '5', 'E', '4', '7', '7', 'B', '7', '4', '7', 'F', 'B', '9', '4', '4', 'A', '2', 'C', '3', '2', 'B', '8', 'A', '3', '9', '3', '1', '9', '8', 'D', 'A', '2', 'B', '7', 'F', '8', 'D', '4', 'D', 'F', 'E', 'C', '0', '8', '6', '6', '3', '7', 'F', 'E', 'E', '9', '5', 'C', 'C', 'F', '9', '7', 'B', '0', '0', '7', '2', '0', '3', 'A', '1', '5', '9', 'A', '5', '1', '4', '8', 'E', '2', '2', 'A', '0', '6', '2', '1', '0', '4', 'F', 'D', '9', 'A', '6', '4', '4', '2', '3', 'B', 'A', 'D', '5', '7', '4', '8', 'D', '5', 'A', '3', 'C', 'D', '2', '9', '2', 'D', 'F', 'C', '7', '7', 'D', 'D', 'E', '0', '6', '7', '6', '7', '1', '2', '5', '0', '2', 'F', 'E', 'E', '6', '0', '1', 'B', 'E', 'A', '1', 'E', 'C', '8', '2', 'A', 'D', '2', '1', 'F', '5', 'B', '7', '8', '6', '6', 'A', 'A', '9', '1', '7', '1', '9', '0', '6', '8', '4', '0', 'A', '5', '1', 'A', 'E', '7', 'A', '1', 'B', 'F', 'A', '2', 'C', 'F', 'F', 'F', 'B', '2', '3', 'A', 'E', 'C', 'C', '7', 'C', 'B', '5', '1', '7', '5', '4', '8', 'E', '1', '1', '7', 'E', 'A', 'D', 'A', '3', '6', '9', 'C', '8', 'E', '0', '0', '5', '0', 'B', '3', '4', 'A', 'D', '5', 'C', 'E', '9', '5', '6', 'F', 'C', '1', 'D', '1', 'D', 'A', '0', '2', 'A', '2', '6', '2', 'D', 'D', '5', '2', 'C', 'D', '5', '4', '1', '9', '4', '1', '2', '9', '5', 'C', '2', 'D', '4', '9', 'C', '7', 'B', 'D', '9', 'E', '5', '8', 'D', '6', 'A', 'E', '0', '6', '8', 'A', 'B', 'E', 'F', 'B', 'B', 'F', 'D', 'F', '3', 'E', 'F', '5', '0', 'D', '6', '9', '7', 'D', '6', 'F', '3', '2', '5', '9', 'C', 'E', '6', '6', '8', '4', 'E', '1', 'E', 'D', 'C', '9', '6', '1', '0', 'C', 'F', '6', 'F', '3', 'D', 'F', '9', 'A', 'D', '3', '0', '5', 'F', 'D', '4', 'C', '2', 'F', '4', 'A', 'E', '6', 'F', '9', '7', '2', '5', '6', 'B', '9', 'D', 'A', '8', '7', 'B', '5', '2', '7', '8', 'C', 'F', 'F', '2', '0', 'B', '5', 'F', 'C', '9', '1', 'F', 'F', 'E', '2', '0', '2', 'F', 'F', '4', '9', '0', 'B', '9', '9', 'C', '2', 'B', 'C', '2', '4', 'C', 'F', 'D', 'D', '3', '2', 'F', '1', 'C', 'B', 'B', '4', 'D', 'F', '0', '0', '6', 'C', '5', '4', 'D', 'D', 'B', '1', '2', '6', 'E', '5', '4', '0', '0', 'C', '9', '1', '1', '6', 'A', 'B', '2', '4', '6', '7', '2', '2', 'E', 'F', '4', '6', '3', 'F', 'F', '1', '4', 'B', '1', 'D', '4', 'C', '9', 'E', '6', 'C', 'A', 'A', '7', '3', 'D', 'C', '0', 'D', 'E', '6', '9', '9', '5', '8', 'E', '4', '0', '3', '1', 'B', 'B', '7', '0', 'B', '5', 'F', 'E', 'B', 'E', '3', 'C', 'F', '0', 'B', '2', '0', '2', 'B', '5', '3', 'C', 'E', '3', '1', '4', '7', 'F', 'D', '9', 'F', 'B', 'A', '8', '3', 'A', '9', '0', 'B', '0', '7', '1', '0', '9', '2', 'B', '7', '8', 'F', '3', 'F', '6', '0', '6', '3', '4', 'B', '1', '8', 'F', '4', 'B', 'A', '1', 'C', '3', 'F', 'F', 'F', '4', 'F', '9', 'F', '5', '3', '3', '0', '7', 'B', '7', '1', '6', '1', 'B', '3', '1', 'F', '3', '0', 'E', 'E', '0', 'A', '3', 'C', 'F', '1', 'B', 'E', '9', 'E', '6', '0', 'A', '8', '9', '6', '0', 'F', 'E', '4', 'D', '2', 'E', '1', 'F', '2', '4', 'A', '0', '9', 'F', '0', '7', '1', 'C', 'A', '3', '4', '8', 'A', 'B', '1', '5', '5', '7', '9', 'C', 'A', 'F', '5', 'D', 'B', 'D', '7', '6', 'E', 'E', '6', '1', '4', '3', 'D', 'B', 'C', '5', '3', '8', '3', '1', 'B', 'A', '9', '9', '5', '1', '3', 'D', '9', '8', 'A', '3', '7', '6', 'B', '9', '1', '6', '8', 'F', 'C', '9', '3', '3', 'B', 'C', '0', '0', '5', '0', '6', 'C', '2', 'C', '1', '3', 'A', '1', '0', '0', '8', 'F', '7', '8', '8', 'D', 'A', '4', '4', '8', 'E', '8', '3', '6', 'D', 'B', 'B', 'E', '3', '3', '0', '3', '4', 'C', '4', '1', '8', '4', '3', '1', 'C', 'F', '7', 'E', '4', 'E', 'D', 'B', '0', '3', '5', '7', '8', 'E', 'D', '7', 'E', '3', 'D', 'D', 'A', '3', 'D', '2', 'A', '5', 'F', '3', '3', '0', 'D', '0', '7', '2', '9', '2', '2', 'F', '0', '5', '9', 'F', 'F', 'D', 'B', '2', '5', 'F', 'C', '2', '1', '6', '1', 'B', '9', 'F', '4', 'F', '8', 'E', '6', '9', '2', '0', '8', 'E', 'F', '6', '0', '4', '3', '5', 'A', 'B', 'F', 'C', '3', '5', '6', '2', 'F', 'A', 'B', 'C', 'F', '4', '2', '4', '8', '7', '4', 'A', 'F', '8', 'A', '5', '5', '6', '9', '0', '5', '7', 'E', '7', '8', '2', '3', '2', '9', 'A', 'E', '2', 'D', 'C', 'F', 'F', '1', '8', 'A', '3', 'D', 'D', '4', 'D', '4', '8', '2', 'D', '4', '6', '7', 'D', '6', '5', '3', '3', 'B', '3', '1', 'A', 'B', '7', 'F', '4', 'F', 'F', '1', '3', 'E', '4', '0', '2', '0', 'D', '9', 'A', '7', 'E', 'E', 'B', '2', '9', '1', '6', '6', 'A', 'F', '2', '9', 'F', 'A', 'A', '8', '6', '5', '9', 'D', '8', '0', 'C', '4', 'B', 'E', '7', '3', 'B', 'F', '4', 'D', 'C', 'B', 'C', '9', '4', '2', '0', '6', 'A', 'E', '7', 'C', '8', 'D', '8', 'E', 'A', '3', 'D', '2', 'F', '7', '5', '3', '0', 'E', '9', '8', 'A', 'B', '3', '7', '4', '2', 'B', '4', 'F', '4', '0', '5', 'E', '2', '4', '4', 'E', '5', '4', '6', '8', '8', '8', '9', '6', '9', 'F', '3', '7', '9', '7', '8', '7', 'B', '7', 'C', '0', '7', '9', 'B', '3', '9', '6', '3', 'A', '6', '7', '3', '9', '6', 'E', 'F', '9', '1', 'D', '0', 'A', '6', '0', 'F', '4', '2', '7', '5', '2', '8', 'D', 'A', '1', '5', '5', 'D', '3', 'B', '3', '9', '3', '1', '4', '2', '0', '7', 'F', '6', 'F', 'A', '6', '5', '1', '5', '9', 'B', '2', '0', '5', 'B', 'D', '8', '3', '0', '4', 'A', '0', '7', 'E', 'C', '8', '2', '0', '2', 'F', 'F', '4', '4', '1', '8', 'D', '7', '5', '5', 'A', 'C', '0', '3', '2', 'F', '0', '0', 'C', '9', 'B', 'C', '2', 'A', '5', '7', 'D', '6', '6', '0', '3', 'E', 'A', '8', 'E', '2', '7', 'E', 'C', '5', 'E', 'F', '0', '8', '7', '4', '8', '2', '5', '6', '8', 'B', '1', '7', '7', '6', 'E', '6', '9', '6', 'D', '8', '5', 'F', '7', '3', '8', '0', '4', '1', '8', 'F', '7', '8', '3', '5', 'B', '5', 'A', '6', '1', '7', 'A', 'E', 'A', 'A', '0', '3', '1', 'D', '9', '5', '6', '1', 'D', '9', '5', '4', '6', '7', '7', 'F', 'C', '5', '9', 'F', 'B', '6', '7', 'F', 'C', 'D', 'C', 'E', '5', '9', '7', '4', '6', '4', '6', 'E', '5', '3', '4', 'F', '7', 'D', 'B', '1', '2', '3', 'B', 'F', 'F', '1', '1', 'E', '6', 'A', '9', '2', 'E', 'B', '5', 'F', '2', 'D', 'B', 'B', 'F', '7', '2', '4', '4', '7', '8', 'F', '9', '3', '1', '5', 'C', '1', '4', 'C', '0', '2', '1', 'C', '6', 'F', '7', '2', '7', '9', 'D', '7', 'D', '3', 'D', '5', '4', '6', '3', '7', '2', 'C', '3', 'B', '7', '9', 'B', '4', '6', '7', '7', '0', '4', 'E', '7', '2', 'B', 'B', 'B', 'B', 'E', 'A', '6', '5', '3', '6', '7', 'E', '0', '2', '8', '8', 'D', 'A', '0', '1', '2', '3', '5', '7', '0', 'B', 'D', 'D', 'A', '9', '1', '5', 'E', 'C', 'D', 'F', '7', '3', '7', '0', '9', '8', 'A', '6', '2', '9', '2', 'C', '1', 'F', 'C', '4', '9', '9', 'C', '1', '7', 'D', '4', 'F', '4', '9', 'E', 'C', '5', 'F', '0', '1', 'D', '4', '0', '3', 'D', 'B', '8', '9', 'A', '8', '7', '5', '0', '3', 'C', '9', 'B', '5', 'F', '2', 'A', 'E', '6', 'C', '7', '4', 'E', 'D', '4', 'E', '4', '4', '9', 'A', '9', '6', '8', '1', 'E', '9', '0', '5', '4', 'F', '0', '7', '5', '2', '6', '6', '2', 'D', 'E', 'F', '9', 'D', '7', '8', '5', '3', 'E', '1', 'B', 'C', '1', '0', 'C', 'C', '8', 'E', '1', '6', 'B', '6', '6', '5', 'C', '7', 'B', '0', '4', 'A', '2', '0', '6', '2', 'B', 'A', '6', '8', 'F', 'B', '0', 'F', 'E', '2', 'C', 'C', '9', '6', '9', '5', '5', '7', '4', '8', '2', '0', '5', 'E', '6', '8', 'B', '4', 'C', '1', '9', '7', '5', '4', 'B', '5', '8', 'C', '6', '7', '7', '3', 'A', 'F', 'A', 'C', '7', 'E', '9', '6', '8', 'A', '8', '7', '8', '9', 'F', '3', '3', 'A', 'A', '9', 'E', '4', 'C', 'F', 'A', '6', '5', '4', 'F', '9', 'E', '8', '5', 'D', 'B', 'A', '3', '0', 'C', 'F', 'B', '8', '5', '4', 'E', '6', 'C', 'E', 'B', '3', 'C', '1', 'A', '0', '4', 'C', '7', '7', 'E', 'C', '7', '3', '8', '4', '1', 'A', '7', 'E', 'B', '6', '1', '7', '9', '3', '8', '3', '4', '0', '1', 'E', '7', 'A', 'D', '5', 'A', 'B', 'F', 'C', '6', '1', '6', '5', '0', 'A', '7', '8', 'E', 'E', '3', '6', 'B', 'E', '7', '6', '4', 'A', '8', '5', '4', '3', '5', 'B', '3', 'D', '6', 'E', '3', '6', '9', '1', 'D', '4', '3', 'E', '6', 'A', '4', '2', 'B', 'D', '9', '1', '7', 'E', '6', '7', '7', '3', '4', '3', 'F', '2', 'E', 'D', '2', '1', 'B', '5', 'D', 'E', '3', 'F', 'F', '1', '8', '2', 'F', '6', '8', '7', '0', '8', 'E', '4', 'E', 'E', 'C', '6', 'C', 'F', '6', '5', '3', 'D', 'C', '7', '9', 'E', 'D', '4', '7', '6', '9', 'C', '7', 'D', '5', '2', '4', '5', '7', '8', '0', '3', '6', 'A', '8', '4', 'E', '5', '0', 'A', '4', 'C', 'E', '4', '3', '1', '5', 'A', 'F', 'F', 'C', 'E', '7', '1', '2', '0', '5', 'A', '3', 'F', 'B', 'D', 'B', 'A', '9', '6', 'B', 'A', '5', '8', '4', '0', '6', 'B', '4', '6', 'A', '0', '5', '3', 'B', 'D', 'D', '1', 'E', '2', '3', '2', 'E', 'F', '4', 'B', 'B', '8', '7', 'C', '6', '2', '0', '5', 'C', '9', '0', '5', 'B', 'A', 'B', '0', '3', '6', '0', '1', '2', '9', '0', '2', '1', '1', '2', '6', '7', '1', 'D', '8', '0', '5', '3', 'B', '1', '6', 'E', '3', 'B', 'D', '4', 'B', '3', '6', 'F', '4', '7', '0', '5', '7', 'E', '2', '2', 'E', 'C', '5', 'B', '7', '8', 'E', 'E', 'C', '2', '5', 'C', 'D', 'E', '8', '3', '6', '1', '0', 'A', 'D', '1', '7', '6', 'C', '0', 'E', '1', '9', '6', '2', 'B', 'D', '4', '8', 'B', 'C', '3', '2', 'A', '0', '0', 'B', '9', '8', '2', '1', 'C', '1', 'C', '4', '4', 'E', 'F', 'B', '6', '6', '6', '7', '8', '2', 'A', '2', 'B', '9', '4', '7', 'D', '5', '7', '5', '4', '2', '8', 'F', '6', '0', '8', '4', '9', '9', 'A', '8', 'C', '4', 'D', 'B', 'A', '4', 'A', '8', '5', 'B', '3', '5', '2', 'A', 'C', 'A', 'B', 'A', 'C', '8', '3', 'E', 'B', '8', '8', 'F', '9', '3', '4', 'B', '6', '3', '8', 'E', '4', '3', 'F', '6', '9', 'E', 'C', '5', '7', '4', 'F', 'B', '6', '0', '6', 'D', '7', 'D', '7', '0', '5', '4', 'D', '0', '4', '3', '9', '5', 'C', '3', '4', 'C', '4', '1', '9', '5', '0', 'F', 'A', 'E', '0', '8', '6', 'C', '4', '4', '3', '3', '7', '4', '9', '7', 'D', '4', 'B', 'E', '5', 'E', '0', 'F', '5', '9', '6', 'D', '0', 'B', '1', '0', 'B', 'B', '0', '8', '7', '5', '9', 'B', 'B', 'D', '7', '1', '3', 'C', '4', 'C', 'C', '4', '7', '0', '4', 'C', '0', '7', '8', '3', '8', '3', '2', '2', '7', '4', 'C', '4', 'E', 'B', '1', '0', '3', '6', 'F', 'B', '0', '2', '1', '3', '2', 'C', 'D', '5', 'A', '5', '9', '0', '0', '8', '5', 'A', '1', 'B', 'C', '0', '8', 'A', 'E', '5', 'E', 'A', 'B', 'C', 'C', 'C', 'F', 'D', 'E', '7', 'B', 'D', 'B', '4', 'A', '5', '2', '0', '7', 'D', '8', '0', 'E', '7', '8', 'B', 'F', 'F', '0', 'F', '8', 'D', '8', '9', 'A', '6', '8', 'B', '9', 'E', '9', 'D', '4', 'B', 'F', 'A', 'A', '6', 'D', 'A', '3', '7', '8', 'F', '0', '7', '8', '3', '2', 'C', '1', '7', '0', 'D', '2', '3', 'E', '4', '6', 'E', '8', '1', '9', '4', '8', '9', '9', 'A', 'F', '5', '1', 'C', 'C', '2', 'D', '9', 'F', 'F', 'B', '5', 'A', '6', '1', 'A', '0', 'E', '9', '7', '2', '7', '0', '8', 'B', '9', 'A', '8', 'E', '1', '8', '0', '5', 'F', '6', '5', 'B', '8', '2', '4', 'F', '1', '6', '0', '8', 'C', '4', 'A', '0', 'B', '9', '2', 'E', '6', '0', 'E', 'E', '4', '6', 'D', '5', '5', '0', '3', 'C', '3', 'C', 'E', 'C', '3', '5', 'E', '6', '5', '9', '7', '6', 'F', 'E', '8', '1', 'D', 'B', 'A', 'F', '3', 'D', '4', '1', '3', '1', 'A', 'E', 'D', '3', '4', '5', '7', '4', '4', '6', '3', '2', '7', 'B', 'D', 'C', '7', '2', '2', 'D', '0', '9', '0', '1', '2', 'A', '4', 'E', '6', '8', 'C', 'B', '5', 'D', 'C', '3', '1', 'D', '2', 'F', 'F', 'B', 'E', 'F', '2', 'F', '5', 'E', '5', '9', '0', 'E', 'B', 'A', '0', '7', 'D', '1', 'D', '0', '3', '5', '6', 'A', 'C', 'F', '1', '2', '9', '4', '3', 'C', 'A', '9', '6', '4', '3', 'C', '4', '3', 'B', 'E', '3', '6', '2', '4', '8', 'F', '0', '2', '6', 'C', '9', '7', '3', '3', '3', '3', '6', 'A', 'D', 'B', '9', 'A', '4', '9', '4', 'C', 'C', '0', '8', '3', '0', '0', 'F', '4', 'D', 'F', 'F', '6', '2', '0', 'A', '5', '9', '4', '0', '3', 'C', '5', '0', 'F', '3', '9', 'C', 'B', 'E', 'E', '5', '3', '9', 'C', 'D', '3', 'B', 'C', '7', 'F', '1', '6', '8', '3', 'E', 'E', '5', 'C', 'E', '6', 'C', '7', '4', '0', 'B', '1', 'E', '8', 'B', 'E', 'F', 'B', '7', '2', '9', '8', '1', 'E', '0', '7', 'C', 'B', '1', '8', '3', 'D', '1', '5', '6', 'E', 'D', '9', '7', '0', '5', 'F', '6', '3', '9', '4', '2', '1', 'C', 'B', '5', '4', 'D', '8', 'D', '4', '1', 'C', 'B', '9', '7', 'F', '9', 'B', 'A', '3', '9', 'E', '9', 'B', '2', 'F', '2', 'C', 'B', '4', '8', '1', 'F', '1', '4', '9', 'D', '0', '5', '0', '7', 'B', 'A', '9', '1', 'F', '4', '4', '0', 'A', '2', '0', '7', '9', '1', '5', 'D', '4', '2', 'A', '2', '9', '6', '1', '6', '8', 'A', '2', 'F', '9', '7', '6', 'E', '4', '4', 'E', '4', '9', 'C', 'A', 'C', '2', 'C', '3', '7', '7', '9', '4', '5', 'B', '6', 'B', '7', 'A', '4', '7', '0', 'D', '7', '8', '3', '5', '4', '9', '0', '5', '3', 'E', '7', '6', 'E', 'D', 'C', 'C', '8', '9', '1', 'C', '3', '5', '0', 'F', '8', '5', 'E', 'B', '8', 'D', '7', 'B', '5', 'D', '8', '0', '7', '7', 'A', '7', 'D', '5', 'A', '0', 'B', '9', '7', 'A', 'C', '3', 'C', 'E', 'D', 'D', 'F', '3', 'D', 'A', '3', '6', '8', '7', 'B', '4', 'F', '8', 'C', 'B', '1', 'C', '4', '9', 'E', 'A', '9', 'E', '3', 'E', 'E', '3', 'D', '0', 'B', '6', '8', '8', '5', '9', '3', 'D', '2', '4', 'A', 'C', '6', 'B', '0', '4', '5', '8', '0', 'C', '8', 'D', 'E', '3', '4', 'D', '1', '7', 'B', '5', 'C', 'A', 'E', 'F', '2', '5', 'D', '7', '4', 'C', '6', '6', '6', '2', '2', '5', 'F', 'C', '9', '4', '6', 'C', '1', '0', 'B', 'D', 'A', 'E', '1', 'A', '5', '2', '1', '0', 'D', '9', 'C', '4', '5', '4', '3', 'D', 'A', 'D', '4', 'A', '8', 'A', '6', '7', '7', 'E', 'E', '2', '0', '5', 'C', '9', '4', '6', '2', '2', 'E', '6', '0', 'A', 'C', 'E', 'F', 'D', '0', 'D', 'E', 'C', 'D', '9', '4', 'C', '7', 'E', 'F', 'C', '4', '1', '9', '4', 'D', '6', '5', '3', '6', '8', 'D', 'D', 'F', 'E', '8', '0', '1', '2', 'B', 'E', '1', 'E', '1', 'E', '3', '2', 'C', 'F', '3', '9', '3', 'C', 'F', 'E', '0', '4', '3', 'F', 'B', '0', '8', '3', '2', '3', 'F', 'A', '2', '1', 'D', 'D', '6', '6', '8', '8', '1', '7', '3', 'B', '8', 'B', '8', '1', 'D', '4', '4', 'A', 'D', '4', 'D', '9', '6', 'C', '5', 'C', 'D', '2', '6', 'D', 'D', '3', '0', '2', 'A', '6', 'E', '9', 'F', '1', '1', '7', '0', '4', '4', '3', 'D', '0', '4', '1', '2', '1', '5', 'E', '4', '4', '7', 'C', 'C', 'D', 'E', '6', '9', 'F', '3', '9', 'A', 'F', 'F', 'B', '3', '5', 'B', '2', '2', '7', 'A', 'C', 'B', '2', '8', '4', '6', '9', 'B', 'C', 'B', '1', '8', '2', '4', '0', '0', 'B', 'B', '3', '4', '0', '1', 'D', '3', '6', '2', 'E', '2', '1', 'E', '4', 'D', '8', '0', '5', '8', 'B', 'A', 'F', '4', '4', 'D', 'E', 'D', 'D', '1', '2', '7', 'B', 'E', '7', 'E', '8', '5', 'E', '2', 'E', '6', '6', 'B', '2', '5', '4', 'F', '3', 'A', '1', 'F', 'A', 'F', 'F', 'D', 'F', '9', 'A', '8', '9', '1', '8', '5', 'E', 'D', '8', 'A', '5', 'B', '5', 'A', '8', 'D', 'D', '6', '0', 'A', '7', 'D', '6', '2', 'F', '1', 'F', 'B', '7', 'E', '0', 'B', '6', '2', 'A', 'F', 'D', '6', '5', '9', '1', 'C', '3', 'C', 'B', '7', 'E', '1', 'E', '6', 'B', 'C', 'F', '7', 'A', '0', '7', 'D', '0', '0', '8', 'A', '9', '4', 'E', 'E', '2', '4', 'E', '4', '5', '4', '8', '4', 'C', '0', '6', '7', '8', '6', 'A', 'D', 'D', '4', 'A', '2', 'A', '8', '0', 'C', 'A', '9', 'E', '7', '3', '1', '0', 'C', '4', 'A', '1', '0', '9', 'A', '3', '8', '0', '3', '6', 'F', 'B', '6', '7', '5', 'C', 'D', '7', '2', '1', '0', '2', 'A', 'D', '5', '8', '1', 'C', 'B', '6', '9', '6', '8', 'A', '5', '3', 'C', 'E', 'A', '8', 'A', '5', '9', 'A', '7', '1', 'F', 'F', 'B', 'F', '4', '9', '5', '2', '8', '8', 'A', 'C', '9', '2', '8', 'F', '6', 'C', '4', 'F', '1', 'B', '2', '2', '3', '9', '1', '9', '0', 'C', 'B', '7', '6', '9', '9', 'D', 'A', '2', 'D', '9', 'D', '5', '0', 'F', '9', 'B', 'D', '2', 'B', 'B', '1', '5', '7', '0', '5', '7', 'A', '7', '3', '1', '5', '6', '9', '2', 'D', 'E', 'B', 'A', '2', 'C', '4', '8', 'E', '1', '4', 'E', '2', '3', '4', 'F', '0', '5', 'D', 'D', '9', '2', '2', '8', '8', '2', 'B', 'C', '4', '4', '0', 'A', '8', 'F', '5', '0', '2', '9', 'D', '3', '6', '4', '9', '1', 'B', '8', 'E', '7', '9', '0', '2', 'E', '6', '4', 'D', '9', 'D', 'A', 'B', '6', '8', 'F', '0', '3', '4', 'F', 'B', 'A', '0', '3', '6', 'F', '0', 'A', '6', 'E', '6', 'F', '7', 'F', '7', '8', 'C', '9', '5', '6', '8', 'C', '1', '4', '5', '1', 'C', 'A', 'D', '0', '0', '6', 'E', 'D', 'D', 'A', 'B', 'A', '2', 'A', 'C', 'D', '0', 'C', '8', 'F', '2', 'E', '7', '3', '6', 'C', 'A', 'E', '9', '5', '5', 'A', '6', '5', '7', '7', '6', 'A', '1', 'E', 'A', 'D', 'B', '6', '5', 'C', '6', '1', '6', '0', '6', 'A', 'B', '1', '9', '2', '0', '6', '4', 'D', 'B', '0', '7', '8', '3', '1', '6', '8', 'C', 'C', 'F', '1', 'E', '7', 'B', '8', 'C', '5', '5', 'B', 'C', 'C', '0', 'A', '6', 'E', 'D', '1', 'F', '7', 'F', '3', 'B', '1', '7', '4', '5', '1', '9', '4', 'D', 'E', 'D', '3', 'B', '4', '2', '0', 'C', 'A', '7', '1', '0', 'C', '2', 'C', 'D', 'B', 'C', 'C', '3', '0', 'D', '7', 'E', '1', '2', 'F', 'A', '3', '2', 'F', 'D', '2', 'B', '7', 'B', '3', '2', '5', '4', '9', '9', '3', '9', '3', 'E', '1', 'C', '7', '3', '8', '7', 'C', '2', '1', '7', 'A', '4', 'B', '8', '1', 'C', '4', '3', 'E', 'D', '3', 'F', '2', 'C', 'B', '7', 'F', '0', '2', '8', 'C', 'F', '8', '5', '0', '0', '3', '5', 'E', '0', 'F', '3', 'C', '9', 'A', 'C', '1', '1', '8', 'B', '2', 'B', '7', '0', '1', '6', '9', '7', '0', 'C', 'B', '6', '0', 'F', 'B', '8', '9', 'B', 'A', '9', '2', '8', 'F', '1', '8', 'B', '8', 'D', 'E', '6', '7', 'A', 'E', 'F', '1', 'B', '4', '7', '9', 'B', '8', 'E', '4', '4', '1', '3', 'B', 'B', 'B', '3', '0', '5', '5', '2', '6', 'A', 'C', '7', '0', '7', '9', '3', 'F', 'A', '6', 'C', 'B', 'F', 'B', 'C', '3', '4', '7', 'A', '0', 'A', '7', 'C', 'D', '6', '4', 'C', 'B', 'D', '1', '5', 'D', 'C', 'B', 'B', 'D', 'A', 'B', '5', 'F', 'B', 'F', '0', '3', '8', 'F', '0', '7', '6', 'B', '8', '3', 'B', 'F', '2', '5', 'A', '0', 'B', 'B', '3', '0', '3', 'F', 'B', 'A', '5', '5', 'C', 'D', '7', 'E', 'C', 'E', 'E', '7', '0', '6', 'F', '4', '2', '1', '3', '1', '5', 'D', '8', '3', '3', '7', 'D', 'E', 'D', 'F', '6', 'E', 'A', 'E', 'A', '4', '7', '1', 'E', '1', 'A', '9', 'D', 'E', '5', 'F', 'A', 'F', 'D', '0', '8', 'C', '2', '5', '8', '7', 'C', 'C', '4', 'A', 'F', '7', '9', 'D', 'B', '4', 'E', 'E', '5', '1', '4', 'A', '6', '7', '7', '6', '5', '4', '8', '7', '1', '4', '4', 'D', '6', '4', '7', 'C', '8', '1', '9', 'A', 'E', 'F', '2', '0', '9', '4', '2', '4', '6', '1', 'B', 'E', 'E', '4', '4', 'E', 'C', 'C', '7', '1', '3', '7', '6', 'C', '6', '5', '9', 'C', '9', '6', '4', '0', 'E', '1', '3', '4', '3', '9', 'B', '7', '1', 'F', 'F', '7', '3', 'A', '3', 'C', '6', 'B', '5', '6', '5', '2', 'F', '8', '7', '5', 'D', 'B', '9', '6', '8', '3', 'A', '6', '2', 'A', '1', '9', '1', '0', 'A', '1', '2', '7', '3', '3', '8', '9', '3', 'D', 'E', 'F', '9', '0', 'D', 'F', 'E', 'B', 'D', '9', '6', 'A', '4', '0', '9', 'A', '9', 'F', '2', '3', '9', '1', 'B', '2', 'D', '9', 'E', '7', 'E', 'E', '2', '6', '6', '2', 'E', 'B', 'B', 'E', '3', '4', '4', '3', '6', 'B', '9', '8', '2', 'C', '0', '2', 'D', '5', '4', 'F', 'B', 'A', '7', '1', '5', 'E', '6', '3', 'E', '8', 'E', '3', '1', '4', '7', 'F', '8', 'C', '0', '2', '4', 'E', 'B', '6', 'D', 'F', 'E', '8', '4', '2', '4', 'E', 'B', 'F', 'C', '7', '7', '6', 'E', '7', '7', 'E', '4', '2', 'A', '1', '9', '1', 'C', '7', 'D', '5', '5', '8', '9', '6', '6', 'D', '8', '5', '8', '6', '5', 'D', '2', '2', 'B', '0', 'A', '4', '7', '4', '8', 'E', '9', '4', '1', '2', 'D', 'F', '7', 'D', '3', '1', '0', 'A', '5', '4', 'F', '0', '7', '7', '1', '0', '0', 'B', 'F', '3', 'F', '3', 'E', '9', 'E', 'B', '2', 'F', '8', '9', '3', 'B', '3', '6', '6', '2', '3', 'C', 'E', '7', '4', '4', '3', 'D', '6', 'B', '8', 'B', '8', 'C', 'B', '8', '8', '5', '9', 'B', '3', '4', 'E', 'F', 'D', 'B', '6', 'D', '4', '8', '4', '1', 'C', 'B', '3', 'B', '6', 'D', '8', '1', '5', '1', 'A', 'D', '1', 'F', 'E', 'F', '2', 'C', '9', '6', '0', '7', '9', '6', '1', '8', 'D', '1', '5', '6', '6', 'F', '8', '9', '3', '0', '8', '9', 'A', 'A', '5', '7', '5', '1', 'D', 'C', '2', '7', 'C', 'E', '5', '2', '8', 'E', '8', '1', '6', '8', 'E', '7', '7', '3', '0', '5', 'A', '6', '7', '0', '5', '5', '5', '6', '8', '0', '8', '0', 'D', '5', '4', 'C', '2', '7', 'A', '5', '6', 'E', '7', 'D', '6', 'D', '0', '9', '4', 'C', 'C', '8', '9', 'D', '9', '5', '9', '3', '3', '3', '9', 'D', 'C', '0', 'E', '3', '1', 'D', 'F', '1', 'C', '8', 'F', '2', 'B', '7', '9', '8', 'E', '6', '4', '1', 'A', '4', '9', '2', '8', '0', '5', 'A', 'B', 'E', '8', 'A', '5', '7', '5', '0', 'C', 'F', '5', '1', 'B', '1', '2', '6', 'A', 'E', '6', 'E', 'E', '4', 'D', '9', '4', '3', 'A', 'A', '7', '8', 'C', 'D', 'D', '9', '6', '1', 'B', '4', '8', '9', '8', 'D', 'D', 'C', '9', '3', '6', 'A', '6', '8', '7', '1', 'C', 'B', '5', '5', '6', '9', 'C', 'A', '3', 'E', 'D', 'B', '0', '1', '5', 'C', 'D', 'E', 'B', '2', '2', 'E', 'B', '4', '7', '9', '7', '4', '3', '7', '0', 'C', '6', '4', '1', '0', '5', 'F', '3', '6', 'F', '4', 'B', 'A', '5', '5', 'C', '0', '7', 'F', '6', '0', 'A', '2', 'B', 'F', '7', '8', '2', 'D', '0', '0', 'F', 'E', '9', '3', '6', '6', 'B', 'A', '2', '3', 'A', 'D', '7', '1', '5', '1', '7', 'F', 'B', '2', 'A', '9', '7', '5', 'A', '8', 'B', 'E', 'A', '7', 'D', '1', '8', 'F', '4', '7', 'E', '7', '5', 'C', '0', '6', 'C', '4', '0', '8', '8', '7', 'C', '5', '1', '0', '5', 'A', '5', '0', 'A', 'D', '3', 'D', 'D', '0', 'C', 'B', '1', '6', '5', 'E', '3', '4', 'D', 'B', '2', '9', '9', 'F', '8', '2', '9', '8', '2', '5', '4', '6', 'C', 'B', 'A', 'C', '3', 'C', '8', '9', '5', 'E', '6', '9', '8', '3', 'A', 'A', 'D', '4', '8', '0', '6', '2', 'C', 'E', '6', 'F', '6', 'B', 'D', '7', 'A', '5', '1', '6', '0', 'B', '2', 'D', 'E', 'B', 'D', '0', 'F', 'C', '6', 'F', '9', '5', '2', 'A', 'A', 'C', '1', '7', 'A', '1', '9', '8', 'A', '3', 'C', 'A', 'F', 'B', 'E', 'B', 'A', '9', '6', '4', '3', '5', 'F', '9', '9', '2', '7', 'F', '1', '9', '4', '5', '9', 'E', 'E', '5', '0', '5', 'F', '2', '0', 'B', 'F', '7', 'E', 'C', 'C', '5', 'D', 'B', '9', '4', '8', '0', '7', '4', '3', '1', 'F', '5', 'C', '8', '6', '7', '4', '4', '4', '4', 'D', '5', '2', 'D', '2', '1', '6', '3', 'B', 'D', 'D', '5', '1', 'E', 'A', '9', '3', '2', '9', '8', '4', '7', 'A', '4', '3', '5', '5', 'D', 'A', '3', '2', '7', '4', '3', 'E', 'B', '7', 'B', '4', '7', 'C', '7', 'A', '9', '7', '0', 'F', '0', '4', 'E', '4', '0', 'F', '0', '5', '0', '1', '3', '9', '8', '2', '1', '8', '9', 'B', '8', 'D', 'C', '4', '6', '6', '4', 'D', 'D', 'E', '1', '6', '7', '8', 'F', 'F', 'F', '4', 'D', '5', '2', 'E', '4', '0', '0', 'C', 'A', '2', 'C', '3', '0', '4', '1', 'E', '2', '5', 'D', 'F', 'C', 'B', 'A', '4', '3', '7', 'A', 'D', '0', '1', '4', 'B', '1', '3', '6', '5', 'B', '4', '2', '8', '2', 'C', '7', 'A', '5', 'F', '3', 'C', 'C', '3', 'E', 'D', '4', 'C', '5', '4', 'E', '7', '9', '7', 'B', 'C', '9', '1', 'B', 'E', '1', 'F', '9', 'A', 'D', '9', 'B', 'F', '7', '7', '0', '7', 'E', 'A', '3', '9', 'E', '8', 'F', 'E', '7', 'A', '0', 'C', 'C', 'D', '7', 'C', 'F', 'E', '1', '1', '6', '0', '9', 'B', '6', 'C', 'D', '2', 'C', '3', 'C', '1', 'D', 'F', 'A', '0', 'E', 'C', '3', 'E', 'F', 'F', 'B', 'D', '2', '7', '0', 'D', '5', '2', 'D', '5', '3', '3', '7', 'C', 'D', 'D', '5', 'D', 'C', '6', '9', 'A', '5', '6', 'D', '2', '0', 'C', '1', '2', 'A', '9', 'C', 'B', '2', 'F', '9', '9', '0', '4', '1', 'E', 'B', 'C', 'F', 'A', 'C', 'D', '3', 'F', '3', '3', 'E', 'D', '3', '9', 'A', 'F', 'A', '9', '3', '4', '2', '7', 'F', '9', '6', '0', 'A', 'B', 'F', '4', '6', '4', '6', 'C', '9', '4', 'E', '1', '8', 'D', 'E', '1', '5', '1', '3', '0', 'F', '1', '5', '0', 'F', 'C', 'C', 'B', 'F', '4', '5', '6', 'C', '9', 'A', 'F', 'D', '1', 'B', '7', '6', '8', '8', '7', '1', '0', '9', '0', '5', 'D', '9', 'D', '9', '4', '5', '4', 'A', '9', 'A', '1', '8', 'A', '8', '2', 'D', 'B', '3', 'A', '9', '6', 'F', '4', '0', 'C', '0', '9', '1', 'E', 'E', 'D', '4', '7', 'D', '2', '7', '9', '9', '5', 'F', 'D', '6', '2', 'A', '2', 'F', 'D', 'B', '7', 'D', '5', '8', '6', 'D', '5', '9', 'B', '3', 'E', '8', '8', 'F', 'A', 'B', 'F', 'F', 'E', '0', 'D', 'C', 'D', 'E', '7', '8', '7', '7', 'E', 'B', '5', '5', '9', '8', '7', '1', 'E', 'A', '5', 'C', '4', '4', '7', 'A', '2', '8', 'D', 'D', '7', '6', 'D', 'A', '0', 'F', '4', '4', '5', 'E', '6', '4', '2', '6', '0', '9', '9', 'E', '6', '7', '5', '5', '5', 'D', '2', '6', 'A', '1', 'F', 'E', '5', '3', '4', '1', '3', '7', 'B', 'B', '4', '3', 'C', 'D', 'E', '1', '0', '2', '2', '8', '1', '4', '1', '9', '7', 'B', '7', '8', '8', 'F', 'B', 'A', '7', '2', '9', '8', '5', '3', 'D', '2', '7', '9', '2', 'C', 'F', '2', '4', 'B', '3', 'C', '7', '6', '2', 'E', 'C', '2', 'A', 'C', 'A', '4', 'E', 'F', '5', '8', '4', '4', '9', '7', 'E', 'A', '0', 'A', '0', '9', '3', '2', '0', '4', '7', 'F', 'A', 'A', '8', '9', '0', 'C', '5', 'A', 'F', '4', '8', '4', '3', 'B', '9', 'A', 'B', '9', '7', 'F', 'A', '3', '0', '6', 'F', 'B', 'A', 'A', 'B', 'C', '5', '5', 'E', '0', 'E', 'D', 'E', '4', 'F', '3', 'B', '6', '3', '9', '8', 'F', 'E', 'C', '3', 'A', '3', '0', 'E', '7', '0', '6', '4', '4', '0', 'E', '7', 'D', '7', '8', '6', 'F', 'A', 'F', '2', 'F', '4', '5', 'E', '8', 'F', '7', '3', '2', 'A', '7', '9', 'F', 'F', '3', '6', '9', '3', '0', '5', 'D', '9', 'D', '4', '5', '9', '2', 'A', '3', '6', '4', '3', '7', '1', '3', '3', 'F', 'C', 'D', 'E', 'D', '6', '4', '9', 'F', '6', '4', 'A', 'A', 'C', '9', '2', 'E', '6', 'F', '7', '6', '3', 'C', '0', 'C', 'C', 'E', 'F', '8', 'E', '7', 'C', '7', 'E', '8', '6', '8', '1', 'D', 'D', '0', '7', '2', 'E', '6', 'A', 'F', '5', 'C', 'B', 'E', '2', '8', '8', 'F', 'A', 'E', '8', 'B', '8', '1', '6', 'A', '0', 'A', '6', 'B', '6', '6', '4', 'B', '7', 'F', '4', '6', 'A', '3', '8', '2', 'A', 'F', '2', '8', '0', 'B', '8', '8', 'F', 'E', '8', '8', '9', '4', 'E', '3', '7', 'A', '1', '7', '7', '4', '2', '2', '2', '8', '0', 'D', '5', '9', '6', '5', '7', '6', 'C', '9', 'E', 'D', 'C', '2', '6', '5', '1', '9', '7', 'D', '3', 'E', '8', 'C', '8', '6', '4', '4', '2', '1', '4', '3', '2', '6', 'B', '1', 'B', '4', 'E', '2', '3', '6', 'C', 'D', 'C', 'C', 'E', '1', 'C', 'C', '9', '7', '7', '6', '9', '5', '3', 'E', '4', '9', '6', '8', '2', '9', '9', 'E', 'C', '3', '3', '6', '5', '0', 'E', '8', 'C', '1', '0', 'A', 'B', '2', '7', 'A', '6', 'A', '4', 'E', 'A', 'D', 'D', '5', '7', '1', 'A', '4', '0', '1', 'E', 'F', '9', 'D', 'B', 'A', '4', '5', 'D', 'A', 'B', '8', 'B', '4', 'F', '1', 'F', 'E', 'D', '9', '4', 'F', '6', 'A', '8', '1', '9', '4', '5', '7', 'A', 'B', '0', '5', '4', '8', '0', 'F', '9', '5', 'E', '3', '9', '3', 'C', '1', '9', 'E', 'D', 'F', '6', '6', 'F', 'D', '3', '6', '6', 'D', 'E', '2', 'F', 'E', '9', '4', '2', '9', '0', '8', 'C', '0', 'F', '4', '8', '8', 'B', '6', '4', '0', '5', 'E', 'B', 'B', '6', 'B', '1', '9', '7', 'D', '0', '3', '9', '6', '4', 'F', '7', '3', '8', '3', '1', '4', '6', '8', 'B', '5', '3', '1', '5', '8', '4', '2', '3', 'B', '1', 'F', '8', 'A', '2', 'A', 'C', 'D', '2', '9', 'C', '7', 'B', 'E', '7', '9', '1', 'A', 'E', '3', '4', 'F', 'B', '2', 'C', 'F', 'B', '1', '9', 'D', '5', '8', '7', 'F', '5', '7', '9', '6', '9', '5', '5', 'A', 'D', 'B', '6', '4', 'F', '9', 'F', '6', '8', '3', '9', 'C', '6', '0', '2', '7', '9', 'D', '5', '1', 'C', 'B', '2', '4', '2', '7', '3', '1', '4', '1', '5', '9', '1', '9', '5', '7', '6', '9', '7', 'A', '0', 'D', '3', '6', 'E', '3', '2', '2', 'C', '0', 'D', 'F', '0', '6', 'A', '2', '8', '4', 'D', '1', 'A', '5', 'B', 'A', 'B', 'C', 'F', '6', '6', '9', 'B', 'B', '2', '9', '4', '7', '7', 'E', 'F', '2', '6', '2', 'B', 'F', '3', 'C', '3', 'B', '8', '3', '7', '7', '3', 'D', '8', 'C', '3', '5', 'E', 'D', '7', '8', 'D', '4', '8', 'C', '4', '2', '5', 'F', 'D', '2', 'D', 'C', '2', '8', 'A', '2', '9', '4', '1', '3', '1', '9', 'F', '6', 'A', '6', 'E', 'A', 'F', 'B', 'D', '8', '1', '8', 'E', '6', 'A', '0', '3', '0', 'E', '9', 'B', '6', 'E', '8', '1', '2', '3', '0', 'C', 'C', '5', '0', 'B', '0', '3', '2', 'E', '2', 'D', '3', 'A', '2', '1', 'C', '1', '9', '8', 'B', '5', '1', '8', '0', '6', '2', '6', '4', '7', '1', '2', '7', '8', '0', 'F', 'C', '0', '8', '3', '9', '7', '4', '0', '7', '2', '9', '6', '0', '5', '9', '5', 'D', '4', '2', '6', '8', 'B', 'F', '3', '2', '1', '0', 'E', '1', '4', '1', '6', '5', '3', '1', 'E', 'D', 'E', '8', '8', 'D', '3', 'B', 'B', '1', 'E', 'C', '3', '8', '5', '6', '9', 'E', '8', 'C', '9', 'F', '1', 'B', '4', 'B', '9', '6', '9', '1', 'F', '1', '3', '3', '2', '6', '3', 'F', '3', 'B', 'A', '7', '1', 'D', '2', '3', '3', 'E', '4', '6', '7', '6', '0', '1', 'F', '8', '3', '6', 'D', '8', '2', 'A', '8', '5', '9', '1', '3', '2', '8', 'B', 'B', '2', 'D', 'C', '1', '3', 'A', '5', '2', 'D', '6', '6', '4', 'D', '4', 'A', '4', '2', '3', 'B', 'B', 'C', 'B', 'F', '0', '9', 'F', '9', 'C', '3', '8', 'F', '2', 'E', 'D', 'F', 'C', '4', '0', '7', 'A', 'C', 'D', '1', 'E', 'A', '8', 'B', '9', '9', 'C', '2', 'F', 'E', 'F', 'C', '8', 'F', '2', '3', 'F', 'D', '7', 'A', '2', '7', '2', '7', '0', '5', '0', '7', '7', '6', '7', '4', 'B', '4', 'D', '3', 'B', '3', '5', '1', 'F', '7', 'E', '5', '9', '3', '3', 'D', 'D', '4', 'A', '9', '4', '7', 'D', 'D', '1', '5', '6', 'D', '9', 'C', '3', '3', 'E', '7', '9', 'C', '4', 'E', '9', 'C', '2', '9', '0', 'E', 'A', 'C', '7', 'D', 'B', 'C', '4', '6', 'C', '4', 'B', '6', 'D', 'C', '4', '7', 'D', '0', '5', '8', '3', 'D', 'F', 'B', '0', '9', 'A', '5', 'F', '0', '7', '1', '1', '5', '9', '4', '1', 'A', '3', 'A', '1', '6', '3', 'D', '5', 'E', '9', '1', '7', 'F', 'C', '2', '3', 'E', '1', 'A', 'D', 'B', '5', 'E', 'C', '3', 'A', 'E', 'C', '3', 'B', '7', 'F', '9', '1', 'D', '4', '3', '7', '5', 'E', '1', '2', 'B', '7', 'D', 'D', '6', '7', 'A', '7', 'A', 'E', '3', '1', '0', '2', 'C', '1', 'D', 'A', '4', '4', '3', '4', '8', 'D', '3', '2', 'E', '3', 'F', 'F', 'B', '8', '9', '2', '6', '1', '8', '6', '9', '4', '3', 'B', '1', 'C', '5', '4', 'B', '6', 'B', '8', 'B', '4', '1', 'D', '6', '7', '1', '2', '9', '7', '2', '5', '7', '3', '6', '2', '5', 'A', '3', '5', 'F', 'A', 'B', '7', '5', '9', '6', 'A', '3', '2', '5', 'F', 'D', '8', '9', 'E', 'E', 'A', '9', '7', '5', 'F', '4', '4', '6', '8', 'F', 'D', 'B', '0', '2', '3', 'F', 'B', '2', 'C', '2', '0', '6', '9', '9', '4', '9', 'D', '2', '5', 'C', '0', '6', 'A', 'C', '6', '3', '0', '6', '5', '3', '2', 'B', '4', '4', 'E', '1', '7', '8', '3', 'E', '3', '8', '5', 'C', '2', '8', '9', '1', '5', '4', 'D', 'B', '1', '8', '2', 'D', '3', 'C', '0', '4', '8', '7', 'E', '4', 'E', 'A', 'F', '4', 'F', '3', 'E', '2', 'D', '0', '4', '1', '7', '9', 'D', '6', '3', '7', 'F', '4', 'E', 'C', '1', '3', 'D', '8', '4', 'D', 'F', '8', '0', '3', '8', '5', 'F', '7', 'E', 'C', '8', '6', '2', '5', '6', '6', '5', 'D', 'F', '8', 'D', 'D', 'F', '0', '4', '0', 'F', '1', '5', '6', 'B', '7', 'E', '2', 'D', '3', 'C', 'F', 'C', '0', '2', 'D', 'B', 'E', 'D', 'A', '1', '6', '6', '5', '1', 'F', '5', 'F', 'C', '9', 'D', '2', '5', '4', '3', 'C', 'A', '4', '5', '6', '2', 'B', '6', 'D', '6', '0', '7', '6', '8', '6', 'A', '5', '0', 'F', 'C', '8', 'E', '9', '9', '6', '6', '1', '1', 'E', 'B', '3', '7', '8', 'C', '3', '9', 'B', '6', 'D', 'F', 'A', '4', '6', '3', '2', '0', '0', 'C', 'A', '9', 'C', '4', 'B', 'A', '7', '8', '0', '6', 'D', 'F', 'A', '7', '9', '5', 'E', '6', '0', '0', '7', 'A', 'D', '4', '4', '0', '9', '3', '6', '9', '9', 'F', '0', '3', 'D', '8', '9', 'C', '2', 'B', '0', '1', 'B', '3', '0', 'C', '2', 'C', '1', '6', '1', '3', 'C', '0', 'E', '4', '6', 'D', 'C', '9', 'B', '0', '5', '4', '9', '4', 'F', '7', '8', '8', '4', '5', '1', '2', 'E', 'D', '9', '1', '0', '2', '7', 'E', '6', '6', '3', 'B', 'E', 'A', '7', 'D', '0', 'C', '3', '5', 'A', '7', '6', '1', '7', '9', 'F', '6', '7', '9', '9', 'D', '7', '8', '3', '7', 'C', 'D', 'D', 'A', '2', 'F', '5', 'B', 'D', '6', 'A', '4', '9', '0', '6', '6', '7', '0', '7', '7', 'F', '9', '2', '1', 'B', '0', 'C', 'D', '4', '5', 'A', 'A', 'A', '9', '7', '9', '8', '4', '7', 'C', '6', '1', '3', '1', 'E', '4', 'E', '5', 'F', '7', '4', 'C', '9', '4', 'E', '0', '4', '6', '0', '0', '4', '1', '0', '6', 'C', 'E', '3', '1', 'E', '2', 'A', '4', 'C', 'B', '3', 'C', 'A', 'E', 'C', 'F', '9', '6', 'E', 'D', 'E', '3', 'C', '1', '9', '4', '9', '8', '5', 'D', 'C', '5', '7', '2', '2', '2', '3', '8', '0', '9', 'F', 'F', '1', '5', '8', '5', '3', '6', '0', 'F', '5', 'E', '1', '1', '6', 'E', '3', '2', '3', 'E', '8', '3', '7', '3', 'B', '8', 'F', 'F', '7', '9', '9', 'D', 'D', 'D', '8', '2', 'E', '1', 'F', '7', '8', '8', '8', '5', '9', 'C', '8', 'C', '3', 'D', '1', 'A', '7', 'B', 'A', '6', '8', '1', 'D', 'B', 'C', '6', 'C', '2', 'F', '3', 'F', '7', '3', '7', '1', 'B', '0', '6', 'D', '4', 'E', '5', '4', '4', 'D', '1', 'D', 'A', 'E', 'F', 'F', '1', '0', '7', '0', '5', 'E', '6', '7', '4', 'A', '3', '9', 'E', '1', '4', 'A', '2', '2', 'A', '2', 'D', '1', 'A', 'A', 'F', 'F', '1', '0', 'E', '0', '6', '8', '0', '8', 'B', 'A', '5', '7', '2', 'F', 'E', 'B', '8', '7', 'E', '6', 'B', '1', '7', '5', 'A', '9', '8', 'A', 'A', '8', '8', 'C', 'F', 'E', '4', '5', '7', '5', '4', '0', 'B', '0', '9', '4', '7', '3', 'A', '6', '8', 'C', '2', '9', 'B', 'A', '5', 'A', '6', '8', '8', '6', 'C', 'D', '4', '9', '7', '9', '6', 'F', '9', 'C', 'F', '8', '6', '3', 'B', '1', '1', '1', '5', 'E', 'B', 'A', 'B', '7', '6', '4', 'C', 'F', 'F', '0', '8', 'F', '6', '5', '4', '4', 'D', '9', 'A', 'F', '1', 'C', '2', '4', '6', 'F', 'B', '8', '1', 'E', '5', '2', '4', '7', '5', 'B', '1', 'E', 'C', '8', '0', 'E', 'E', 'A', '6', '1', 'E', '9', '2', '3', '3', 'F', 'B', '4', 'C', '3', '1', '2', '8', '5', '9', 'E', 'C', 'A', '3', '1', 'D', 'A', 'F', '5', '4', 'A', 'F', 'E', '7', '0', '6', '4', 'C', '3', 'A', '1', '1', '0', '8', '8', '1', '2', '8', '0', 'F', 'C', '5', '6', '4', '9', '4', '5', '6', '5', '2', 'F', '0', '8', '7', 'D', 'B', 'A', '4', '4', '7', 'C', 'D', 'A', '9', '6', '9', 'F', 'F', '4', '4', 'C', '1', '3', 'A', '8', '7', 'B', 'D', 'B', 'C', 'C', '5', '2', '9', '1', '7', '1', '7', '3', 'D', '3', '8', 'B', 'C', '8', '1', '3', '6', '0', '8', '8', 'C', 'A', '5', '5', 'C', '7', 'F', '2', 'E', '0', 'C', 'F', '9', 'D', '9', '9', '4', 'C', '9', '0', 'B', 'A', '0', '4', 'A', '8', '0', 'B', 'F', 'A', '6', 'D', 'C', '8', '3', 'E', '4', 'B', 'F', 'E', '2', '5', '3', '0', '3', '0', '0', 'D', '3', '6', 'D', '0', 'E', '1', '4', 'A', '0', '8', '0', 'E', 'F', '8', '3', '9', 'C', 'D', '1', '1', 'D', 'A', '8', '1', '1', '7', '2', 'C', '6', 'B', '6', '0', 'B', 'A', 'B', '8', 'D', '6', '5', '3', 'C', '7', '4', '6', 'B', '0', 'D', '1', '1', '0', '3', '9', '3', '8', '7', '5', '4', '2', '0', 'D', 'A', '1', '4', '3', '5', '1', 'E', 'C', '1', 'B', 'B', '6', '7', 'A', '3', '1', 'B', '1', 'B', 'A', '1', '9', '7', '9', 'A', '7', 'D', 'B', '5', '5', '8', '3', 'D', '2', 'B', '3', '4', 'B', 'D', 'B', 'E', 'D', '0', '8', '8', '9', '3', 'E', '1', '8', 'A', '4', 'D', '8', '7', '9', '5', 'D', '8', '5', '1', '2', '1', 'A', 'B', '8', '7', '8', 'E', '1', '9', '3', '9', '4', '4', '9', '7', '5', '3', 'D', '4', '6', '6', 'E', '7', 'D', 'A', 'B', 'F', 'B', 'D', '3', 'A', '0', 'F', '3', 'F', '8', '9', '8', 'E', '7', '9', '0', '8', 'B', '1', '2', 'A', '8', '7', 'A', '4', '8', 'C', '9', '6', 'D', '5', 'B', 'A', '1', '2', '2', 'B', '7', '9', '9', '5', '4', 'B', '6', 'A', '1', '5', '8', '3', 'F', '1', '3', '3', '6', '7', 'C', '5', '4', 'B', '5', 'A', '3', '6', 'C', '1', 'E', '4', '4', '0', 'F', 'E', 'C', 'E', 'E', '2', 'D', 'C', 'E', 'D', '5', '1', '2', 'B', '6', '4', '9', 'D', '0', '4', '6', '9', '7', '7', '1', '4', '3', '9', '2', '5', '6', 'E', '6', '1', '1', '0', '1', 'D', '7', 'E', '3', '1', '8', '1', '0', '0', '5', '1', '0', 'B', 'F', 'E', 'C', 'E', 'C', '2', '6', 'F', 'C', '8', 'D', 'D', '1', '3', '4', '8', 'E', '7', 'D', 'B', '6', 'B', '8', '0', '4', 'A', '0', '6', '3', 'F', '3', '4', '3', '8', '5', 'C', '3', 'F', '1', '7', '2', 'D', '2', '8', 'B', '1', '1', '0', 'F', '6', 'E', 'A', 'E', '6', '5', '2', '9', '5', '5', '7', 'E', '8', '2', '4', '3', '0', 'B', '2', 'B', '5', 'F', '4', 'D', 'D', 'A', '8', '8', '6', '3', 'F', 'E', '1', '7', '3', 'C', 'D', '0', '8', '6', '0', 'C', '1', 'B', '7', '3', 'D', '7', 'D', '3', 'A', '9', 'B', 'B', '2', 'B', 'D', '7', '0', 'B', '7', '5', '5', '0', '7', 'F', '2', '5', '6', '0', '2', '2', '7', '2', '5', '4', '7', '3', '9', '3', '8', '6', 'F', 'D', '8', '5', 'A', 'E', '8', '9', '1', 'A', 'D', '3', '4', 'B', '0', '4', 'A', '1', '6', 'C', '6', 'C', '7', 'D', 'A', '6', '4', '4', 'E', 'D', 'C', 'D', '4', 'F', 'C', '1', '2', 'C', '9', 'C', '5', 'F', '1', 'E', 'C', 'D', '8', '5', 'E', '5', 'F', '1', '8', 'A', '3', '1', 'C', '2', 'B', 'C', '2', 'F', 'F', '9', '3', '6', 'B', '3', '8', 'D', '2', '7', 'F', '6', 'B', 'E', '8', '6', '4', 'B', '7', '5', '0', '2', '9', '9', 'C', '4', 'D', '6', '5', '2', 'C', '8', '3', 'D', '7', '7', 'C', '1', '8', 'A', '5', 'B', '9', 'F', '8', '4', 'C', '1', '9', '5', 'E', '8', '6', 'E', '2', 'B', '1', '5', '5', 'B', '2', 'E', 'F', '3', 'D', 'A', 'A', '9', '8', '7', 'F', 'F', '5', '6', '2', '3', '3', 'F', 'C', '0', '7', '5', '9', '5', '3', '7', 'C', '6', 'F', '6', 'B', '0', '9', 'C', '9', '5', '5', '0', '8', '5', '1', 'B', '8', '4', 'C', '1', '1', '7', '8', '1', '6', '1', '3', 'E', '5', 'E', '7', 'C', '3', '8', 'D', '5', 'D', '8', 'D', 'D', '1', '2', 'F', 'B', '0', '4', '0', 'D', '0', '5', 'C', '3', '2', 'B', '5', 'A', '6', '2', '6', 'B', '8', '8', '1', '5', 'A', 'C', '5', '8', '5', '2', 'B', '5', 'B', 'D', 'F', '5', 'E', '8', '0', '9', 'E', 'C', 'B', '2', '4', '3', '6', '1', 'F', '5', '6', 'C', '0', 'F', '7', 'A', '8', '7', '2', '6', '7', '0', '4', '7', '9', '3', 'F', 'A', '2', '6', '7', '3', 'D', '9', '8', 'C', '5', 'D', 'B', 'E', '0', '8', 'D', '3', 'D', 'D', '3', '7', '0', '4', 'F', 'A', '9', '8', '1', '2', 'B', 'D', 'C', '1', '9', '2', '2', 'E', 'A', '7', '4', 'D', 'A', '5', '9', '0', '6', '2', '0', 'B', '1', '9', '8', 'F', '0', '8', 'C', '2', 'D', 'A', 'A', '0', '0', '4', 'E', '2', '5', 'D', 'A', '1', '8', 'C', '3', '4', '0', 'D', 'C', '0', 'E', '8', '2', 'A', 'E', '3', '8', '3', 'D', '4', '3', 'C', '1', 'E', '7', '7', 'E', '7', 'E', 'E', '9', 'D', '7', '3', '1', 'F', '7', 'E', '9', 'B', '8', '7', '1', '2', 'B', 'E', 'F', '7', '0', 'A', '7', 'F', '5', 'E', '6', '3', '9', 'B', '5', '7', 'A', '1', 'B', 'E', 'E', '2', '1', 'C', '8', 'F', '1', '3', 'B', '2', 'D', '8', '3', 'A', '6', '9', 'F', 'C', 'A', '4', 'C', 'D', '7', '5', '3', '4', '5', '9', 'E', '4', 'E', '9', '3', '5', '9', 'E', 'E', '1', '2', '4', 'D', '5', '4', '1', 'F', '2', 'D', 'D', '1', 'E', '7', '1', 'F', 'A', '6', '3', '5', '5', '8', 'A', '0', 'D', 'A', 'F', 'E', 'C', '3', 'D', '1', 'A', '6', '5', '8', 'D', 'C', '7', '2', '2', '7', '9', '8', 'D', '9', '0', '9', 'A', 'C', '4', '2', '1', '9', '4', '6', '7', 'B', '3', '5', '5', '4', '9', '3', '5', 'D', '1', 'C', '8', 'C', 'F', 'F', 'F', 'B', 'A', '5', '2', '1', 'D', 'E', '4', 'F', '3', '3', 'A', '0', '4', '2', 'A', 'E', '4', '8', '4', 'E', '4', '3', 'B', '1', '8', '7', '8', '7', 'B', 'D', '0', '5', '1', '9', '2', '3', 'D', '1', 'B', '3', '7', '2', '2', '2', '4', '0', '4', 'B', 'E', '1', 'A', '9', 'C', '3', 'D', 'F', 'A', '9', 'A', '3', '1', 'D', '2', '6', '9', '9', '9', 'A', '1', '9', '8', '1', 'E', '1', '1', '2', '8', '4', '7', '6', '3', '4', '5', '4', '0', 'F', '9', '2', '0', 'C', '8', '8', '5', '8', 'D', '1', 'B', '6', '4', 'F', '3', '9', 'E', '2', 'B', '6', '6', 'F', 'D', 'E', '3', '7', '6', '3', '7', '0', '1', '6', '8', '9', 'E', 'E', 'E', '8', '2', '7', 'C', '0', '5', '5', '5', '1', '3', '3', 'B', 'A', '7', '2', '7', 'B', '4', '2', '5', '8', '1', '3', '4', '8', 'F', 'A', '9', 'E', 'D', '8', '0', '3', 'F', '9', '3', '1', 'E', '8', 'F', '6', 'D', '9', '0', 'F', '8', '9', 'C', '4', '7', '8', 'E', '6', 'D', '5', 'C', '0', '5', '6', 'E', '2', 'A', 'F', '6', '1', '4', '2', '6', 'A', '4', '2', '4', 'E', 'E', 'B', '0', 'B', '9', '1', '7', '3', '8', 'C', 'C', '2', '3', '0', '8', '8', 'F', '4', '5', 'B', 'D', '5', 'B', '8', '3', '7', 'A', '8', 'F', 'B', 'A', 'E', '6', '4', '7', '6', 'F', '0', '0', 'F', 'F', 'F', '3', 'B', 'C', 'C', '8', 'B', '8', 'B', 'C', '7', '1', 'D', 'A', '5', 'B', '1', '2', '1', 'F', '3', '8', '2', 'B', 'B', 'D', '0', 'A', 'E', '7', '3', 'F', 'E', 'A', '8', '0', 'E', 'B', '8', '6', '6', '5', '5', '5', '1', 'A', '9', '2', '6', '8', 'B', 'B', 'F', 'E', '8', 'D', '4', '1', 'C', 'E', 'C', '9', 'E', '0', '6', '9', 'F', '4', 'D', 'B', '0', 'B', '0', '1', 'D', '0', 'F', 'D', 'A', 'A', '5', '4', 'D', 'F', '8', 'B', '4', '2', '9', 'A', 'A', 'D', '0', '4', '1', '7', 'A', '9', '9', 'A', '7', '2', '9', '8', '3', 'B', '7', 'F', 'E', '5', '5', 'A', '5', '2', '8', 'E', '5', '0', 'C', '5', '9', '3', '3', 'B', '2', 'F', 'A', '6', 'B', '5', '3', 'E', 'D', '8', 'B', 'E', 'F', '7', 'C', 'B', '9', 'B', 'C', '3', '5', '9', 'A', 'E', 'D', '1', '9', 'F', '5', '7', 'A', 'D', 'A', '6', '0', '6', '5', '3', '7', '1', '3', 'C', '2', 'E', '7', '4', '8', '2', 'A', 'B', 'A', 'A', 'C', 'A', '5', 'F', '5', 'A', 'C', 'A', '3', 'F', '9', 'A', 'B', '4', '4', 'D', 'D', 'F', '1', '1', '2', '9', '1', 'F', '6', '5', '2', 'B', '5', 'D', 'D', '0', '4', '6', 'C', '1', 'E', '1', '8', 'F', 'F', '2', '7', '1', '1', 'B', 'C', 'D', '5', 'D', 'D', 'E', '7', '5', '9', '8', 'C', '9', 'C', 'C', 'C', 'B', '7', '0', '8', 'B', '9', 'C', 'B', 'C', 'E', '6', 'E', 'C', 'E', '5', '9', 'F', 'B', 'C', 'B', '2', '1', 'A', '3', '4', '9', '4', 'F', '1', 'E', '3', '0', '7', 'B', '1', '4', '5', 'B', 'B', '5', '6', '2', '0', '4', '5', '9', '7', '3', '5', '9', '3', 'E', '1', 'D', '0', '5', '4', '3', '5', '9', 'A', '7', '6', '4', 'A', '2', 'A', 'B', '1', '1', 'B', '8', '4', '3', 'B', 'C', '7', '5', '7', 'B', '1', '1', 'B', 'E', '6', '2', '8', '3', '6', 'D', 'F', '1', 'A', 'C', '7', 'A', 'B', '8', '3', '5', '8', 'C', 'A', '1', 'A', '5', '8', '2', '9', 'D', '0', '5', 'C', 'B', '1', '6', '6', '6', '5', '0', '0', 'A', '1', 'B', 'B', 'A', '8', '2', 'A', '6', '8', 'A', '2', '9', '4', '3', 'E', 'E', 'F', '3', '9', '6', 'A', '6', '3', '7', 'A', '3', '8', 'B', '2', '5', '3', '0', '4', '1', '6', 'A', 'C', 'A', '3', '4', '0', 'F', '4', 'A', '2', '0', '9', 'A', '1', '0', '4', '5', '4', 'F', '6', '8', '5', '0', '7', 'B', '7', '8', 'C', '7', 'F', 'F', '2', '5', '5', '6', 'E', '1', '1', '0', 'A', 'E', '7', 'E', '1', 'E', '8', '6', '6', 'A', '2', '0', '7', '8', '4', 'C', '2', 'C', '3', 'D', 'B', '0', '6', '9', '1', '4', '3', 'D', 'B', '4', '0', '5', 'D', 'B', 'D', 'C', 'D', '4', '1', '7', 'E', '6', '0', '6', 'F', 'C', '3', '3', 'E', '0', '0', 'F', '5', '6', 'C', '4', 'D', '3', 'D', 'A', '4', '1', '1', '0', '7', 'E', 'C', 'C', '9', '5', 'E', 'C', '8', 'C', '6', '8', '5', '3', 'D', 'C', '0', '9', '3', 'C', 'D', 'E', '5', '9', 'C', 'A', 'E', '3', 'D', '5', '2', '7', '2', 'F', '4', '3', '5', '4', '1', 'E', 'A', 'A', 'E', '1', 'D', '7', 'A', 'D', '7', '7', '3', '1', '1', 'B', '8', '8', 'F', 'C', '0', 'F', '7', 'E', 'F', '1', 'A', '4', 'D', '5', 'A', 'F', '0', '5', '4', '5', '2', 'D', 'B', '5', '8', 'F', '8', 'F', 'F', '3', '1', 'D', 'E', '4', 'D', 'F', '6', '9', 'A', '6', '8', '4', 'B', 'B', '3', 'B', '0', '4', '1', '0', '3', 'E', 'F', '6', 'F', 'C', '0', '8', '4', 'E', 'A', 'D', '7', '2', '1', '0', 'E', 'A', 'C', 'D', 'A', '6', '9', '9', '8', '6', '2', '6', '2', 'C', 'D', '5', '7', 'B', 'A', '3', '5', '1', '4', '2', '1', '5', '7', 'B', 'A', 'F', 'B', 'F', '6', 'E', 'C', '0', '4', '5', 'E', 'A', 'F', '6', '3', '8', '1', '3', 'F', 'F', '8', 'E', 'F', 'F', 'B', 'D', '3', '8', 'C', '6', 'E', 'C', '1', '0', '0', '5', '0', '3', '7', '0', '0', 'F', '4', '1', '0', '5', '6', '1', 'D', 'F', '9', 'F', '4', '8', 'B', 'A', 'E', 'C', 'D', '9', 'A', 'E', 'B', '7', 'B', '0', '4', 'E', '9', '2', 'C', '8', 'A', 'D', '8', '9', '8', '3', '8', 'F', '5', '7', 'C', 'A', 'A', '4', '2', '7', 'D', 'D', '3', 'A', '0', '3', '1', 'D', '9', 'C', 'B', '3', '6', '1', 'E', '8', 'C', 'F', 'D', 'E', '4', '8', '5', 'F', '7', '4', 'C', '7', '7', '4', '3', '3', '0', '0', '4', 'A', '2', 'E', '8', '3', '1', 'A', '5', 'F', 'E', '5', 'E', '8', 'A', '6', 'D', '6', '2', 'E', 'F', '8', '4', '8', '6', 'A', 'A', '8', '7', '5', '6', '4', '5', '9', '2', '1', '2', '3', '2', '2', '4', '0', '1', '3', '6', '2', 'D', '3', 'E', '9', '0', 'A', '4', '6', 'C', '1', '0', '1', 'E', '4', 'D', 'B', '6', '8', '8', 'D', 'E', '3', '9', '6', '6', '9', '1', '6', '4', '4', 'F', 'E', 'E', 'A', 'B', '4', 'C', '9', 'F', 'B', 'F', '9', 'E', '7', '4', '7', 'E', '9', '1', '7', '9', '1', '8', 'D', 'F', 'D', '1', '4', '2', '9', '6', '3', 'B', '5', '4', '9', '6', 'A', '4', '0', '3', '4', 'C', '6', '4', 'F', 'C', 'F', 'D', 'D', '8', 'F', 'D', '0', '8', 'F', '6', 'F', 'E', 'D', '3', 'D', '2', 'C', '4', '6', '5', '2', '3', 'B', '9', '3', 'F', '3', '0', 'C', '1', 'E', 'C', 'C', '8', 'C', '8', '1', 'C', '6', 'D', '2', 'A', '9', '1', '1', '3', 'C', 'A', '1', '9', 'C', '0', '6', '1', 'C', '1', '6', '4', 'E', 'A', '2', '6', 'B', '3', 'C', '2', '0', 'E', 'A', '5', '4', 'E', 'B', '1', '0', '9', '6', '2', '3', 'E', '1', '4', '3', '9', '5', 'F', '2', '1', 'F', 'D', '3', '3', '1', '1', '5', '6', '2', '0', '3', '5', '4', '3', '1', 'C', '7', 'C', 'A', '0', '3', '4', '1', 'C', '0', '4', '9', 'A', '9', '1', '4', '5', 'A', 'D', '0', '4', '6', '7', '2', '4', '9', 'B', 'D', 'D', 'F', '0', '7', '7', 'B', '7', '0', 'C', '7', 'C', 'A', 'A', '9', 'A', '3', '4', 'F', '1', '6', '6', '4', '7', '1', 'E', 'E', '3', '5', 'E', 'B', '8', '1', '6', '3', 'C', '7', '0', '5', '4', '0', '9', 'E', '2', '8', 'E', 'F', 'D', '8', 'E', 'A', '5', 'D', '9', '0', '0', 'F', '6', '4', '7', '0', '6', 'C', '9', '5', '5', '2', 'E', 'E', 'D', 'D', '5', 'F', '3', 'E', '6', '7', '8', 'B', 'E', '8', '9', '5', '2', 'D', '8', '9', '2', 'F', 'E', 'A', 'A', '7', '6', '2', '6', '0', '1', '9', '4', '4', '6', '3', 'C', 'D', '8', '9', '1', '4', '4', '3', '3', 'A', 'F', 'B', '8', 'E', '8', '0', '2', '4', '8', '1', 'D', 'E', '8', 'D', 'D', 'B', '9', '6', 'C', '7', '3', 'C', '4', '5', 'B', '8', '9', 'F', '2', '0', 'A', 'F', '2', '0', '6', '8', '8', '0', '0', 'B', '9', '9', '4', '7', '1', 'C', 'B', 'D', '1', '5', '3', 'B', 'C', '0', 'F', 'F', '9', '7', 'C', 'A', '3', '9', 'A', '0', '2', '5', 'B', '5', 'D', '6', '7', 'D', 'C', '8', '1', '9', 'E', '4', '4', '2', '7', 'D', '9', 'C', '8', 'F', '0', '6', 'B', '1', '0', 'B', '6', '5', '0', '7', 'B', 'A', 'B', 'E', '0', '1', '4', 'B', '0', 'E', '0', '9', '0', '5', 'F', '0', 'A', 'D', 'E', '3', '4', 'B', '6', 'C', 'D', '0', '7', '0', '3', 'B', 'E', '0', '2', '8', '2', 'B', '4', '7', '6', 'A', '7', 'A', '5', '4', 'C', '7', 'F', 'E', 'E', '4', 'F', '2', '1', 'D', '1', '5', 'A', '2', '7', '8', 'F', '2', 'D', '1', 'A', '6', 'D', '8', 'B', '0', 'D', '3', 'F', 'E', '9', 'B', '0', 'C', '2', '6', '9', '9', 'A', 'B', '0', '6', '0', 'B', 'E', '3', '6', '8', '9', '7', '1', '7', 'A', '8', 'E', 'D', '9', 'F', '3', '5', 'D', '6', '2', '5', 'D', '3', '2', '3', '2', '4', 'F', 'D', '0', 'D', '5', '1', '7', '2', 'E', 'F', '4', '5', 'C', 'F', '7', '8', '8', 'A', 'F', '8', '6', 'F', '9', '5', 'E', '5', 'D', 'E', '4', 'F', '8', '9', 'A', '5', 'D', '3', 'E', '6', '0', '3', 'A', '4', '3', '2', 'B', 'A', '4', '4', '1', '8', '3', 'F', '5', '0', 'C', '0', 'A', 'A', '6', '4', '1', '6', '8', '8', '2', '5', 'A', '1', 'C', 'F', '1', '4', 'E', '2', 'B', '8', 'F', '6', 'E', '2', 'B', '0', '9', 'C', '8', 'D', '1', 'A', '2', '2', 'E', '9', '5', 'D', 'B', '7', 'C', '3', '9', '7', 'C', 'D', 'D', '9', '8', '4', 'D', '0', 'E', 'D', '3', 'E', '3', 'B', '8', '0', '7', '7', 'A', 'B', '4', '4', '9', '6', '1', 'E', 'E', '1', 'D', '5', '9', '4', 'C', 'E', '8', 'A', '4', 'E', '1', '7', 'E', '7', '1', '2', '7', '6', 'E', '7', 'C', '4', 'E', '8', '8', '3', '6', '4', '1', '6', '5', 'D', '7', '8', 'B', 'E', 'A', 'C', '8', 'D', '4', '0', '8', 'E', '8', 'F', 'D', '8', '4', 'C', '9', '6', '4', 'E', 'C', 'B', 'D', '4', 'C', '0', '8', 'E', '2', 'D', '9', '5', 'B', 'B', '1', '0', 'D', '8', 'B', '4', '9', 'E', '9', 'C', '2', 'D', 'F', '7', '1', 'E', '7', '2', '4', '4', '6', '6', '8', 'E', '5', 'D', 'C', '1', '3', 'E', 'F', 'F', '0', 'C', '9', 'D', '8', 'A', '2', 'F', '3', '9', '1', '1', '8', 'D', '3', 'E', '0', '3', '9', 'B', '0', '2', '4', '7', 'F', '2', '7', '1', '7', '5', 'F', 'F', '2', 'C', 'D', 'D', '8', 'D', 'A', '2', '3', '2', 'F', '5', 'B', '1', 'B', '3', '7', '4', '2', '1', '6', '2', '4', '6', '7', '4', '3', 'D', 'B', '9', '3', '1', '2', '0', 'D', '8', 'B', '1', '0', 'C', 'D', '9', '1', '1', '3', '4', '5', '6', '9', '3', '6', '5', '1', 'A', 'A', 'F', '1', 'E', '0', 'E', 'E', '1', '9', '2', 'C', '3', '8', 'B', '8', '6', '8', '0', 'B', '6', '0', 'A', '8', 'F', 'A', 'E', '2', '7', '9', '3', '8', 'B', '9', 'E', '4', 'C', '1', '3', 'B', '3', '4', 'C', 'E', 'B', '7', '3', 'B', 'A', '1', '1', '5', '7', '6', '6', '6', '1', 'A', '9', '7', '9', 'C', '2', 'A', '8', '6', '1', '5', '0', 'B', '8', 'E', '5', '3', 'B', 'C', 'F', '4', '3', 'D', 'E', '0', '5', 'E', 'F', 'B', '1', 'B', '5', 'E', 'C', 'F', '2', 'C', 'A', '5', '1', 'B', 'F', 'F', '9', 'B', '0', '9', '0', 'F', '1', 'A', 'E', 'F', 'B', 'D', '3', '2', '0', 'E', '1', 'B', '4', 'C', '8', '0', '2', '7', '0', '7', '5', '9', 'F', '2', '8', '0', '5', '4', '6', '1', '9', '7', '5', '8', 'B', '7', 'D', '9', '6', '7', '4', '6', '0', 'B', 'D', '7', '9', '2', 'F', 'F', '6', '3', '2', 'E', '2', '2', '7', 'B', 'D', 'F', 'E', '7', '8', 'F', 'B', 'A', 'C', 'B', '1', '8', 'C', 'E', 'B', 'B', '6', '5', '3', '0', 'F', 'E', '6', '4', 'E', '3', '2', 'A', '6', 'C', 'A', '9', '6', 'C', '9', '6', '0', '4', '2', '4', '3', 'A', 'D', 'F', '2', '8', 'E', 'F', 'D', '4', '9', '8', '3', 'C', 'B', '6', '5', '1', '1', '3', 'F', '2', '4', '8', '3', '9', '0', '1', '6', 'F', 'E', '5', '4', 'D', '7', '5', '9', '6', '4', '0', 'F', 'C', '9', 'B', 'D', 'B', '4', 'C', '5', 'A', 'A', 'F', 'E', '1', 'A', '8', 'A', 'C', 'A', 'D', '2', '6', '4', '2', '2', '3', 'D', '3', 'A', 'C', 'B', 'C', 'E', '5', '4', '1', '3', '3', '4', 'C', '2', 'A', '2', 'F', 'E', '5', '7', '5', '7', 'F', '5', '2', '0', '1', '3', 'F', '5', '0', '3', '5', '2', '0', '1', '7', '9', 'E', 'D', '8', '8', 'E', '2', '8', '3', '6', 'C', 'C', 'C', '5', 'F', '4', 'F', 'D', 'F', '3', 'D', 'E', '4', '8', '0', '1', '5', '7', '9', 'B', '1', '3', '1', 'D', '3', '4', 'E', '7', '5', 'B', '7', '0', 'C', '9', 'B', '2', '3', '3', 'E', 'D', '0', '0', '3', '3', '5', 'E', 'B', '9', '9', 'A', 'A', '1', '9', '8', 'B', '2', '6', 'A', '3', '0', 'E', '3', 'B', 'B', 'B', '8', '4', '7', '4', '0', '2', '0', '7', '0', '4', '3', '5', '6', '5', 'C', '6', 'D', '3', 'D', '0', 'F', '7', '0', 'A', '9', '1', '3', 'B', '7', '3', 'F', 'F', '8', '6', '1', 'F', 'E', 'E', '3', '2', '9', 'B', '2', '2', '1', '6', '1', 'F', '1', '4', '2', 'C', '3', 'C', 'A', '4', '6', '0', '3', '1', '5', 'A', 'E', '0', '4', '5', '6', '0', 'D', '0', '4', '1', '9', 'E', '3', 'E', '0', 'C', '8', 'A', '1', 'B', '9', 'D', 'C', '0', '1', '4', '2', '8', '6', '5', 'A', '4', '8', '5', '4', '7', '2', '3', 'A', 'E', 'A', '9', 'D', '8', '2', '7', 'F', 'A', 'A', '4', '9', 'F', '0', 'C', 'C', '6', 'C', '8', '6', 'C', '0', 'A', '0', '4', '7', '5', '8', '1', 'E', 'F', 'F', '9', '3', 'A', 'A', '3', '2', '3', '9', 'F', 'E', 'D', '4', '0', 'D', '4', '4', '4', '5', 'E', '3', 'D', '8', '4', '8', 'C', '6', '5', 'A', '1', 'C', '2', 'A', '0', '9', '0', '1', 'E', 'A', '3', '4', 'F', 'E', '1', '4', 'D', '0', 'A', '2', '4', '0', '6', '0', 'C', '7', 'F', '7', 'F', 'E', 'C', '5', '9', '6', '0', 'B', 'E', '6', '7', '5', 'D', '5', '7', '0', 'D', '9', '4', 'F', '5', 'C', 'B', '7', '2', 'D', 'E', 'A', '7', '0', '9', 'E', 'E', '3', '8', '6', 'D', '4', '2', '1', 'C', 'D', '5', 'B', 'D', '9', '1', '1', 'E', 'A', 'D', '2', 'F', 'A', '3', '4', 'D', '5', 'C', '5', '2', 'E', 'E', '7', '8', 'C', '1', 'F', '0', '1', 'C', 'D', '7', 'D', 'E', 'A', '2', 'B', '8', 'E', '8', 'C', '7', 'C', '4', '4', '0', 'C', 'C', 'B', '6', '1', '8', '1', '5', 'F', '8', 'F', '7', '5', 'A', '3', '4', '3', '3', '8', 'D', 'F', '7', '0', '0', '0', '2', '9', '4', 'C', '3', 'D', '7', '5', 'D', '7', '6', 'E', '0', '6', 'A', '7', '9', 'E', '9', '2', '4', 'B', 'C', 'B', '5', '1', '3', 'B', 'A', 'D', 'D', '1', '9', '3', 'A', '6', '0', '8', 'D', '4', 'E', '0', '4', '7', '1', '7', 'A', '2', '0', '0', '9', '9', '5', '1', 'A', 'D', '8', 'A', 'E', '9', 'D', '2', '5', '5', 'C', '6', '8', 'B', 'A', '8', 'D', 'D', '7', '2', 'F', 'B', '0', '8', '6', 'E', '9', '2', 'E', '8', '5', 'E', '6', '9', '6', '4', 'C', '6', '8', 'C', '5', 'E', '6', '5', 'F', 'D', '1', 'A', 'C', 'A', 'E', '6', '4', '1', '1', '6', 'A', 'D', 'E', 'D', '7', 'B', '7', '0', '3', 'D', 'B', '7', '5', '3', '2', 'E', 'A', '5', 'A', '1', 'E', '1', '0', '2', 'B', '6', '9', 'F', 'F', '5', 'C', '4', '2', '4', '0', '3', 'A', '3', '5', '7', '4', '3', '5', '7', '0', '0', '4', 'E', '1', '0', '5', 'C', 'C', '1', '2', '7', '9', '5', '8', 'B', 'D', 'F', '7', '9', '7', '5', '5', '3', '9', 'A', 'D', '4', '8', 'E', '1', 'F', '1', 'B', '7', '4', 'F', '9', 'C', 'D', 'E', '7', '9', '7', '5', '7', 'D', '6', 'A', 'D', '1', 'E', 'C', 'F', '7', '3', '7', '5', '9', 'A', '7', '5', '2', '5', 'B', '2', 'D', '4', 'E', 'B', '4', '4', '5', '1', 'C', 'A', '1', 'C', '6', 'B', '1', '9', 'E', '4', 'A', '4', '2', '3', 'D', '5', '2', '1', '1', '2', 'B', 'C', '6', 'D', '0', 'F', 'C', 'C', '6', 'D', '0', '0', 'F', '9', 'C', 'F', '9', 'E', 'D', 'B', '8', '3', '4', '8', '2', '7', '7', '6', 'E', '9', '4', 'E', '3', '8', '3', '7', '2', '1', '0', 'C', 'F', 'F', '5', 'A', '1', '0', 'E', 'F', '1', 'F', 'F', '9', 'B', 'C', '4', '5', '3', '5', '2', 'F', '8', 'C', 'D', '6', '3', '8', 'C', '5', 'E', '4', '3', '0', '9', '3', '4', '7', '0', '6', '7', 'C', '1', 'C', 'B', '3', '9', '8', '4', '0', '2', '1', '1', '9', '2', '9', '4', '7', 'D', '0', '3', '0', '5', '7', '0', '3', 'C', 'F', 'A', '6', '2', 'F', '8', 'E', '6', '2', '9', '7', '6', '1', '5', '4', 'E', '5', 'B', '3', '5', '8', '0', 'F', 'B', '8', '0', 'A', '8', '1', 'C', 'F', '8', '9', '3', '5', '4', '2', '2', '0', '5', '2', '1', '1', '6', '2', 'B', 'C', 'E', 'F', '1', '8', '7', 'A', '5', '5', 'F', 'E', '3', '1', 'F', '9', '4', '8', 'A', 'C', '3', 'C', '9', '2', '3', 'B', '5', '4', '3', '4', 'C', '2', 'E', '3', '8', '5', '5', 'B', 'C', '3', 'D', '9', 'C', '3', '8', 'C', '5', '6', 'A', '8', 'A', '0', 'C', '0', '5', 'D', 'C', '0', '8', 'A', '8', '8', '9', 'B', 'D', 'E', '8', '4', '5', '3', 'D', '2', 'F', '0', 'C', '0', '7', '3', '5', 'F', '3', '5', '0', '4', '3', '6', '2', '1', 'E', '6', '3', 'D', 'D', 'E', 'C', '6', '3', '2', 'B', '8', 'A', '6', 'F', 'D', '2', 'C', '6', '6', 'F', '7', '4', '9', '7', '4', '9', 'E', '2', 'C', '2', 'F', '7', '8', '9', '3', '3', 'E', 'A', '9', '1', '0', 'F', '1', '6', 'C', '4', '1', '3', '5', 'D', 'B', '6', '7', 'C', 'C', '8', 'A', '1', '8', 'E', 'D', 'A', '9', 'D', '9', '8', 'D', 'B', '5', 'D', '6', 'C', '4', '5', '8', '2', '1', 'B', '8', '9', '5', '1', '7', '1', '5', 'E', '8', 'F', 'D', 'D', 'D', 'E', 'A', '0', 'B', '3', '9', 'C', '3', '3', '2', 'B', 'A', '7', '1', 'C', 'C', '3', '9', 'F', 'D', '0', 'F', 'B', 'E', '4', 'F', '4', 'E', 'D', 'D', '2', 'A', '4', '1', 'F', '8', '4', '8', '8', '4', '5', '0', '1', 'B', '2', 'A', '6', '4', '1', 'F', 'C', '0', '6', 'D', 'A', '6', '8', 'D', '9', '0', '5', '1', '9', '6', '7', 'F', '0', '9', 'A', 'D', 'C', '8', '1', '5', '0', '5', '0', '4', '3', '7', 'D', 'A', 'E', 'B', 'F', 'F', 'D', '7', '9', '8', '1', '9', '0', '6', '1', '8', '9', '9', '5', '4', '7', 'C', 'D', 'B', '9', '6', '9', '6', 'B', 'D', '8', 'B', '3', 'D', '9', 'A', 'E', 'B', 'A', '7', 'B', '3', 'C', 'F', '1', 'F', 'F', '1', '5', 'C', '5', '9', '1', '4', '7', '6', '5', 'F', '8', 'B', 'A', '0', 'A', 'E', '2', '3', '6', 'E', '4', 'F', '2', '4', 'D', '7', 'B', '7', '2', '5', '6', 'C', '9', '9', 'F', '7', 'D', '6', 'D', 'E', '6', 'B', 'E', 'A', 'E', 'B', '8', '8', 'D', 'A', '1', '1', 'A', 'A', '2', '1', '3', '7', '8', 'B', 'F', 'D', '0', '5', '9', '2', '2', '7', '2', 'B', '4', 'A', 'B', '7', 'D', 'C', 'D', 'B', '7', '5', '3', 'D', 'E', '8', 'E', '8', 'C', 'F', '6', '1', '1', '1', 'F', '0', 'B', '0', 'A', '0', 'D', 'F', '3', '6', '3', '6', 'A', '1', 'E', '6', '7', '7', '2', '2', '9', '4', '6', 'B', '7', 'E', '9', '8', 'F', '2', '3', 'A', 'B', '8', '6', '5', '3', 'B', 'E', 'A', '9', '3', 'E', '4', '2', 'E', '1', '1', '1', 'C', '3', '4', 'B', 'A', '2', 'E', 'C', 'F', '2', '8', '9', '6', '8', '4', '7', '2', '3', '1', '6', 'D', '9', '9', '7', 'E', '0', 'D', '8', '9', 'A', '7', '9', 'A', '1', '4', '6', '9', 'F', '5', 'C', '2', '4', '5', 'B', '6', '7', '2', 'E', 'C', '8', '1', '5', 'B', '5', '8', 'B', 'B', '6', 'C', '3', 'E', 'D', '0', 'A', '0', 'E', '9', 'C', 'F', '3', 'F', '1', 'B', '5', 'D', '8', '8', '6', 'D', 'C', '5', '2', 'C', 'B', '3', '8', '2', 'F', '3', 'F', '1', 'B', 'A', 'D', '4', 'A', '4', '4', '5', '6', '8', '7', '4', '6', '3', 'F', '6', '3', 'C', '6', 'B', 'E', '4', '0', 'D', '6', 'A', '9', '7', 'E', '0', '4', '2', '8', '2', 'D', 'B', '7', '5', '3', '7', '1', '4', '3', 'D', 'B', '4', '4', 'D', '9', '1', '2', 'A', '3', '7', 'E', '9', '4', 'F', '3', '2', 'D', 'F', 'C', 'D', '6', 'F', '2', 'E', '6', 'A', '6', '4', 'F', '4', 'A', '9', '8', '3', '7', 'C', '0', '0', '7', '2', 'D', 'F', 'F', '0', 'A', 'B', '8', '1', 'E', 'B', 'E', '3', 'A', '7', '1', '2', '5', 'C', '7', '4', 'B', 'D', '0', 'D', 'C', '5', '9', 'E', '4', 'D', '4', '2', '0', '4', '9', '7', '5', '0', '1', 'D', '8', '2', 'F', '1', '7', '3', 'F', '0', '4', 'F', '9', '7', 'B', '0', '2', '6', '5', 'E', 'C', '1', '6', '4', '8', 'B', '6', 'E', '6', '8', 'B', '5', '9', '8', 'D', '5', '4', '1', '3', '7', '1', '6', 'C', 'B', '1', '9', 'C', 'F', '9', '8', '4', '8', '5', '5', '1', '2', '7', 'E', '7', '1', '4', '0', 'F', 'A', '0', '4', '2', 'F', '1', '1', 'D', '5', 'F', 'A', '5', '2', '7', 'C', 'F', '6', 'B', '4', '3', 'A', '9', '4', '3', 'C', 'B', '7', '5', 'E', 'D', '8', '3', 'A', 'A', '9', '6', 'D', 'D', '2', '9', '8', 'E', '8', 'A', '4', 'D', '9', '9', '3', 'D', '7', '0', '4', 'B', '9', '2', 'A', 'E', '8', 'A', 'A', '4', '2', '7', '6', '9', '2', '6', '7', '4', '5', 'C', '0', 'A', '2', 'D', 'A', 'A', '6', '6', 'E', '4', '7', '5', '0', '2', '5', '8', '4', '4', 'D', 'F', '3', '7', 'D', 'A', 'E', '1', 'F', '3', '9', '9', 'B', '3', 'D', '6', '9', '3', '8', '8', '6', '7', 'F', 'A', 'F', '2', '6', '3', '7', 'D', '8', '3', '3', '1', 'B', '8', '8', '3', '1', '0', '9', 'E', '7', 'F', '3', '1', '7', '9', '5', 'B', 'D', 'F', '6', '0', '8', 'D', '1', '9', 'B', '3', '1', 'F', 'C', '1', '6', '5', '2', 'A', '8', 'A', '4', '1', '8', '0', '4', '1', '6', '5', 'E', '0', 'F', 'C', 'F', '9', '9', '5', '9', '0', 'C', 'B', 'C', '4', 'D', 'F', '1', '3', '0', '1', 'B', '0', '9', '3', 'A', '5', '4', '2', '2', 'A', '9', 'D', '6', '6', '9', 'F', 'E', '3', 'B', '6', 'D', 'B', 'E', 'C', '3', '8', '4', '4', 'A', '6', 'E', '0', '3', '0', '2', 'D', '6', 'F', '7', '1', '4', '7', 'A', '7', '0', 'C', 'F', 'B', '2', 'A', 'E', 'A', '0', '9', '8', '3', '1', '3', 'B', '1', 'E', 'B', '1', 'E', 'F', '0', '2', '9', 'D', 'E', '5', '5', 'B', '5', 'E', '5', '5', '9', '3', '7', '2', '8', 'D', '6', '2', '3', 'E', '8', '4', 'E', '5', 'F', 'A', '3', '7', '4', '0', 'B', '0', 'D', '0', '3', '2', 'A', '4', 'F', 'F', 'F', '3', '7', '0', '7', '8', '2', '6', '6', '4', '8', '6', '8', '7', '6', 'A', '1', '9', '7', '3', 'A', '1', '9', '0', '7', 'E', '8', '6', 'D', 'E', 'A', '3', '6', 'F', '3', 'A', '4', '2', '8', '0', 'F', 'A', '5', '6', '3', '4', '5', '4', '1', 'E', '1', '3', '0', 'A', 'B', 'D', '3', 'B', '9', '4', '5', '4', '4', 'F', 'E', '7', '4', 'B', '1', '7', 'E', 'F', 'D', '1', 'F', '8', '7', 'D', '8', '4', '3', '4', '2', 'A', '8', 'D', '4', 'E', 'D', '5', '2', 'F', 'F', 'B', '5', '0', 'E', '8', 'A', '1', '5', '9', '6', '9', '3', '3', '7', '7', '0', '2', '6', '9', 'A', '6', '3', '4', '4', 'C', '4', '6', 'F', 'F', '9', '0', 'B', 'B', '3', '1', 'C', '9', '2', '1', '2', '7', '9', 'C', 'C', '2', '5', 'D', '3', 'B', 'D', '6', 'D', '5', '8', '3', '5', '1', '0', '7', '0', 'A', 'D', '8', 'A', '8', '2', '3', '0', 'E', '0', '4', '5', '2', '1', '5', '7', 'F', 'D', '9', '5', 'F', 'D', '9', '7', 'B', 'D', 'B', '4', '9', 'B', 'C', '6', 'A', '6', 'D', '7', '3', '2', 'A', 'C', '1', '1', '5', 'C', '4', '0', '7', 'B', '4', '8', 'F', 'C', '0', 'C', '5', 'E', 'C', '2', '0', 'A', '1', 'E', '3', '5', '4', 'C', '4', '9', '8', '6', 'D', '4', 'F', '3', '9', 'A', '8', '9', '9', 'E', 'D', '0', '1', 'D', 'B', '9', '2', '0', '5', 'D', '1', 'A', 'A', 'F', '9', 'C', 'B', '7', 'F', 'B', '6', '6', 'D', '9', '3', '0', 'B', '6', '7', '0', 'D', '9', '3', '1', '2', 'E', '2', 'A', 'A', '1', '2', '6', '4', '4', '5', '9', '9', '8', '9', '8', 'A', '9', '0', '6', '3', '7', 'B', '9', 'A', 'E', 'C', '0', '9', 'E', 'E', 'B', '5', '2', '8', 'E', '4', 'F', 'B', '9', 'D', 'C', 'F', 'F', '7', '8', 'F', '0', 'C', 'E', '0', 'B', '6', 'D', 'A', 'B', 'A', '9', 'A', 'B', '3', '8', '5', '1', '1', '3', '2', 'A', 'D', 'A', '8', '6', '9', '6', '4', '6', 'C', '3', 'E', 'A', 'F', '9', '9', 'B', '7', 'D', '9', 'A', '4', '7', '5', '1', 'C', '8', '8', '8', '3', '8', 'A', '5', '3', '2', '5', 'C', 'F', '7', '1', 'B', 'C', '2', '7', '5', '6', '0', 'C', 'B', '8', 'D', 'E', 'B', '5', '0', '8', '5', '2', 'B', '0', '7', '2', '3', 'D', 'B', '1', '1', 'F', 'C', '5', '9', '7', 'D', 'D', '2', '7', 'D', '4', '6', '6', 'F', 'E', '4', 'F', '3', '7', 'E', '0', '1', 'D', 'D', 'D', '6', '4', '6', '2', 'E', 'A', 'B', 'C', '3', '3', 'B', '8', 'B', '2', 'A', 'F', 'C', '5', '3', 'B', '2', 'A', '1', 'F', 'B', '2', '6', '7', '6', 'B', 'C', '9', 'D', 'E', '0', '6', '0', 'D', '5', '1', '8', 'E', '6', '6', '0', '6', '4', 'B', '9', '5', 'A', 'D', 'B', '8', '8', 'E', 'A', 'B', '2', 'D', '5', 'F', '8', 'F', 'B', 'B', 'F', '8', '2', '1', 'A', '7', '9', '1', 'C', 'E', '1', '1', '5', 'C', 'F', 'D', 'C', 'B', '3', 'B', '5', '4', 'E', 'B', '5', '9', '5', '7', '5', 'B', '2', '6', 'A', '0', 'F', '6', '9', '7', 'F', '7', '4', '9', '0', '3', 'F', 'B', 'D', '2', '8', '9', 'C', 'F', '3', 'A', '8', 'A', '9', '9', '7', '8', '9', '9', 'C', '6', 'D', 'F', '0', 'F', '8', '5', '9', 'E', '3', '0', '4', '9', '2', 'F', 'C', '2', 'E', 'A', '9', '2', 'F', 'A', 'E', 'C', 'F', 'A', 'A', '3', '3', '6', 'D', 'E', '0', 'B', '3', 'A', 'C', '4', 'D', '8', 'E', 'B', '0', '3', '2', '7', 'C', 'C', '1', 'E', '5', '3', '6', '3', 'A', '3', 'F', '6', 'B', '7', '5', '6', '8', '3', '0', 'B', '9', '2', '8', '2', '7', 'C', '4', '2', '8', 'A', 'C', 'B', 'C', '5', '0', 'B', 'B', 'B', '4', '0', '6', '7', '5', '9', '4', '7', 'A', '0', '2', 'D', '1', 'B', '3', 'F', 'B', 'A', '1', 'A', 'F', '5', '3', '5', '5', 'E', '9', '7', '9', 'B', 'C', 'B', '8', '6', 'D', '9', 'D', '2', '4', '3', '2', '2', '1', '4', 'A', '5', '0', '6', 'C', 'C', '2', '9', '8', '8', 'A', 'A', '3', 'D', '5', '7', '9', '9', '3', 'C', '4', '4', 'B', 'F', '8', 'E', 'A', '5', 'D', 'D', '7', '8', '7', '2', 'E', '2', 'A', 'C', 'A', '9', '8', '7', 'D', '6', 'A', '0', '2', '4', '8', 'E', '2', 'D', 'F', '5', '7', '5', '0', '8', '4', '5', '8', 'B', '4', 'E', 'E', '9', '0', '9', 'B', '2', '9', 'A', '5', '0', '9', 'A', '3', 'E', 'A', 'E', '5', '5', 'E', '4', '9', '8', '3', '7', '0', 'E', 'C', '6', '1', 'A', '8', '9', 'A', 'F', 'F', '2', '3', 'D', '0', '1', '6', '4', 'C', 'B', '5', '0', 'B', '8', '1', '8', 'A', '9', 'C', '8', 'E', '8', '5', '9', '5', 'D', '7', 'C', 'A', 'D', 'D', 'F', '6', 'E', '0', '2', '4', '0', '6', '5', '1', '1', 'B', 'E', '6', 'B', '1', 'D', 'E', '1', '2', 'F', '0', '7', 'A', '3', 'E', '8', '8', '4', 'B', '3', 'F', 'C', '9', '0', '9', 'A', '9', 'E', 'C', '3', '4', '8', 'C', 'C', '4', '2', '0', '6', '4', 'F', 'C', '5', '6', '6', 'A', '8', '4', '4', 'F', 'B', '7', '3', '2', 'D', 'E', '3', '2', '5', '1', 'A', 'C', 'F', '2', 'C', '7', '9', 'A', '7', 'C', '9', '6', 'F', '3', '3', '9', 'B', '1', '6', 'F', 'D', '0', 'C', 'F', '1', '0', '0', '2', '1', '2', '4', 'E', 'F', 'F', '4', '0', 'B', '1', '8', 'D', '4', 'E', '7', 'C', 'A', '3', '2', '7', '8', '9', 'A', '8', 'B', 'D', '6', '3', 'A', 'F', '7', '3', '7', '1', '8', '6', 'B', '7', '4', '5', 'C', '8', 'F', 'F', '9', '5', '2', 'B', '1', '8', 'F', '1', '7', 'E', '7', 'F', 'E', '2', 'A', '0', '0', '4', '7', '2', 'A', '3', 'B', '0', 'B', '1', '8', 'E', '8', 'B', 'A', 'A', '9', '2', '5', '8', '4', 'D', 'A', 'E', 'D', '8', '9', 'C', '6', 'B', '5', '1', 'E', 'C', 'F', '3', 'B', '0', '4', '2', 'B', '3', 'F', '0', '2', 'D', '1', '4', '2', 'C', '9', '7', '6', '3', 'D', 'D', 'C', 'E', '3', 'E', '5', '2', 'C', 'E', 'E', 'B', '1', '9', '9', '0', 'C', 'E', '8', '0', '2', '5', '6', 'E', '4', '0', 'A', 'C', 'A', '1', '2', 'D', '3', '9', '9', 'E', '9', 'C', 'F', 'D', '5', '6', '9', 'E', '9', 'B', 'B', '3', 'C', 'F', '1', 'A', 'A', '3', '1', '9', '1', '3', '8', 'A', 'D', '2', '2', 'A', '4', 'D', 'D', '6', '1', '9', '4', '0', 'C', '9', '8', 'B', '0', '2', '0', '4', '1', 'C', '9', 'C', 'D', 'F', '7', '6', 'A', 'B', 'B', 'D', '9', '7', '9', 'A', 'D', '6', 'C', 'C', 'D', 'B', 'B', '7', '1', '8', '1', '9', 'C', 'D', 'B', '2', '1', '8', 'E', '6', '7', 'C', '0', 'B', '7', '4', '2', 'B', 'B', '9', 'B', 'C', '2', 'D', '6', 'A', 'D', '9', '3', 'E', '4', '1', '5', '5', '8', '0', '0', 'A', '2', '9', '5', '9', '4', '7', 'B', '2', 'B', '4', 'F', '7', '8', '1', '3', '5', '1', '7', 'D', 'C', 'C', '3', '2', '8', 'E', '3', 'D', '2', '1', '2', 'F', 'B', 'E', '9', '4', 'B', '0', '0', '6', '5', '9', 'F', 'A', '3', '3', '3', '0', '2', '0', 'E', '0', '0', '1', '9', 'C', '1', '2', 'D', 'E', '1', '6', 'F', 'F', '7', '5', '9', '4', '3', '8', '4', '2', '4', '2', '0', '6', '2', '5', 'B', '4', 'A', '3', '5', '8', 'D', 'D', '9', '6', '0', 'D', '9', '8', 'E', '8', '8', '9', '2', '7', 'D', '6', 'D', '2', 'B', 'D', 'A', '5', '2', 'F', '7', 'F', '1', 'D', '4', '2', 'C', '4', '4', 'E', '6', '2', '7', '2', '9', '6', '2', '6', '5', '5', 'D', 'C', '8', 'C', '8', '9', 'A', '6', '6', '6', 'E', 'A', '5', '6', '2', '9', 'F', '1', '3', '1', '6', 'F', 'D', 'B', '5', '9', 'D', '5', '4', '9', '2', '6', '2', '3', 'A', 'C', 'B', '9', '0', '9', 'F', 'E', '4', '0', 'F', 'E', '8', '7', 'C', 'B', '5', '3', 'F', '2', '2', '3', '5', 'C', '8', '2', 'E', 'A', 'A', '4', '0', 'D', 'F', '6', '0', '3', '3', '2', 'E', 'A', '2', '4', 'A', 'B', 'D', '7', '4', '3', 'E', 'D', 'C', '4', '6', '1', '6', '7', '4', 'D', 'B', '1', '1', '5', '0', 'A', 'F', '5', '7', '4', 'A', 'C', '7', 'C', '5', 'F', '8', 'A', '7', '8', '2', 'B', 'B', 'E', '1', '6', 'C', '6', 'F', '7', 'A', '7', '9', '0', 'D', '1', 'B', '1', 'A', '0', '2', 'B', '7', '3', 'D', '6', 'C', 'F', 'E', 'C', '0', 'D', '0', '3', '1', '9', '7', 'A', '3', '0', '5', 'E', '9', 'A', '9', '5', 'F', '9', '1', '0', '9', 'E', '2', '9', '8', 'E', 'F', '1', '7', '7', '5', 'A', '6', 'D', 'C', 'F', '1', '6', '9', 'D', 'B', 'B', 'B', '1', '8', 'A', '6', '3', '9', '0', 'E', 'F', 'F', '9', '9', 'B', 'E', '0', '3', '1', 'F', '8', 'A', 'C', 'A', '2', '2', '3', '3', '1', '2', '8', '3', 'A', '0', '7', '7', 'A', '7', '6', '6', '5', '0', 'B', '0', '6', 'B', '3', 'D', '9', '6', '5', '8', 'A', '8', 'F', '0', '8', '7', '0', 'A', '2', 'E', '5', 'F', 'D', 'D', 'D', 'B', '4', 'A', 'E', '8', 'E', 'D', 'B', '9', 'C', 'B', '2', '7', '9', 'F', 'B', '8', '5', '1', 'A', 'D', 'D', 'D', 'F', '7', '4', '5', 'C', '8', '7', '8', 'B', '6', '3', '8', '2', '8', '3', 'B', '6', 'E', 'C', 'D', 'B', 'C', 'C', '7', '4', '3', '1', '8', '7', '9', 'C', '1', '5', '0', 'C', 'A', '8', 'C', 'D', 'E', 'E', 'D', '1', '4', '4', '2', '5', 'D', 'F', 'C', 'E', '7', 'F', '0', 'B', '0', '9', 'A', 'B', 'F', '9', '1', '2', '6', '8', '5', '3', 'D', 'B', '0', '6', 'A', '8', '2', '1', '4', '3', 'A', '3', 'D', '8', 'F', 'D', '2', 'F', '5', 'D', 'B', 'D', 'D', '5', 'F', 'A', '3', 'C', 'F', 'E', '4', '2', '5', 'C', 'C', '5', '6', '4', '9', '8', '4', '6', 'E', '4', 'A', '7', 'A', '0', '5', '1', 'A', '3', '4', '0', '0', '7', '9', '0', 'F', '8', '3', '9', '6', '7', 'F', '6', '6', 'E', 'A', '6', 'D', '8', 'B', '8', '0', '2', '9', '6', 'E', '0', 'A', '9', 'A', '5', '8', 'D', 'A', '9', '2', '3', '7', '4', '4', '8', 'E', '9', '3', 'F', 'F', '4', '2', '9', '8', 'C', '4', '1', '9', '8', 'A', '2', '7', '9', '4', 'F', '9', '5', '5', '6', 'F', '1', '4', '1', '6', '1', '5', '6', '7', '5', '6', 'F', 'C', 'F', '6', '8', 'F', 'C', 'A', '8', 'F', '0', '6', 'E', '5', '0', '2', '5', 'A', 'A', 'E', '4', '9', '8', '0', 'C', '9', '3', 'A', '7', 'F', '9', '8', 'D', 'D', '1', '0', '4', '4', 'E', 'F', '2', '6', '1', 'A', 'E', 'B', 'C', 'A', '5', 'B', '2', '6', 'F', '2', '7', '1', '5', 'D', '0', '9', 'E', 'C', '2', '8', 'A', '2', '8', '4', 'B', 'B', '0', '3', '1', '2', '9', '9', '3', 'A', 'D', 'E', '8', 'D', '0', 'A', '2', '8', '2', '3', '7', 'F', '0', '1', '0', 'D', 'E', '0', '4', '3', 'D', '3', 'D', '0', '0', '5', '4', 'C', '6', '9', '1', 'E', '7', '3', '6', '4', '7', 'C', '8', 'B', 'F', 'C', 'E', '4', 'D', '9', '7', '4', '5', '1', 'C', '0', '3', 'F', 'A', '4', 'A', 'D', 'B', '0', 'A', '5', '3', '9', '3', '7', '0', 'B', 'E', '9', 'C', 'D', '4', '1', '8', '9', 'F', 'C', '8', '3', '8', 'D', '3', '7', '6', 'E', '3', '7', '8', '5', 'B', '6', 'F', 'F', '5', '8', '3', '0', 'D', 'A', '9', '5', '9', 'A', '5', '1', '4', '0', '9', 'B', '0', 'E', 'E', '9', 'B', '3', '5', '3', 'C', '0', 'A', 'C', 'C', 'A', '6', 'E', '0', '2', '1', 'D', 'C', '9', '4', '3', '0', 'B', '6', '7', '8', '5', 'E', '6', 'C', 'D', '3', 'D', 'B', '1', 'A', 'E', '9', 'A', 'B', '1', '3', 'B', 'E', '5', '2', 'E', '5', '1', 'F', '4', 'B', '2', '5', '9', 'D', '4', '7', 'B', '7', '1', 'D', 'A', '0', 'A', 'B', '6', 'D', '9', '9', 'A', 'F', '9', 'B', '4', 'A', 'A', '2', 'A', '7', '9', '3', 'D', 'A', 'E', '6', '9', '0', '4', '2', '6', '3', '9', 'F', 'C', 'A', '3', '1', '3', '3', 'B', 'C', '9', '9', 'C', '7', 'D', 'E', 'C', 'A', '9', '1', '5', '0', 'F', '7', '1', '7', '1', 'D', 'D', '9', '9', 'C', '9', '7', '0', '0', '7', 'E', '6', '4', '4', '3', '1', '6', 'A', '0', 'B', '8', '6', '2', '0', '9', '1', '7', 'D', '8', '3', '6', 'C', '0', '6', 'D', '3', 'F', 'D', '2', '6', '8', 'F', '5', '8', '0', 'D', '6', 'E', '7', '1', '7', '1', '1', '6', '7', 'A', 'A', '4', 'E', 'E', '0', '3', '7', 'B', '4', 'F', '0', '8', 'B', 'F', 'A', 'F', 'F', '2', '6', '7', '8', 'F', '4', '3', '0', '6', '2', 'D', 'F', 'B', 'D', '7', 'E', '2', '3', '5', '5', '4', '0', 'B', '0', 'B', 'E', '3', '5', '4', 'C', '6', '4', 'D', '9', '7', '0', '0', '4', 'F', 'C', '4', '1', 'E', 'C', '4', '2', '8', '5', 'B', '5', '8', 'A', 'F', '4', 'B', 'B', 'F', '0', '1', '0', '5', '9', 'B', '6', 'B', '3', '4', '3', '6', '9', 'F', '1', 'E', 'E', 'A', '8', '5', '7', 'E', '2', '0', 'A', 'D', '3', 'C', 'D', '7', '5', 'B', '4', 'E', 'F', '0', '1', 'D', '6', '1', '6', 'A', 'E', '8', '3', '8', '6', '9', 'F', '0', 'E', 'E', '0', '9', '4', '8', '8', '9', 'B', 'D', 'A', '5', '6', '8', '3', 'C', '0', '5', '3', 'A', '1', '2', 'B', '0', '8', '3', '5', 'B', '8', 'C', '7', '5', '7', '6', '6', '6', '4', 'E', '2', 'F', '0', 'B', 'C', '6', '6', '4', '9', 'F', 'F', 'A', 'E', '8', 'F', 'D', '2', '1', '5', 'B', '7', '1', '1', '1', 'A', '7', '5', '8', '7', '3', '1', '6', 'D', '0', '9', 'D', 'C', 'C', '3', 'C', '0', '2', '1', '4', '3', '3', 'F', '5', '5', 'B', '1', '8', '4', '4', 'C', '3', 'F', '3', 'A', '2', '8', '0', '8', '0', 'F', '8', 'D', '7', 'E', 'B', 'A', 'A', 'B', '8', '4', '0', '6', '5', '2', '9', 'C', 'E', 'B', 'C', '7', '9', '6', 'C', 'A', '2', '6', '5', '3', '5', '3', '2', '3', 'D', 'D', '3', 'A', '9', '8', 'E', 'F', 'A', '3', '7', 'E', '4', 'D', '9', '2', 'C', 'A', '5', '1', '8', 'A', '3', '7', '8', '1', '5', '8', '5', 'B', '4', '3', '4', 'D', 'E', '6', 'C', '2', '7', '9', 'A', '0', '2', '0', 'A', 'B', '3', '3', '1', 'D', '0', 'E', 'C', '9', '2', 'D', '1', 'B', '8', '8', '8', '4', 'C', '6', '5', 'E', '5', '2', '6', '9', '0', '8', '0', 'B', '9', '7', '4', 'A', '8', '3', '7', '8', 'F', '1', '6', '1', '3', 'F', 'C', 'F', 'C', '4', 'F', '3', '4', 'E', '3', '3', 'F', 'B', '0', '0', 'A', '0', '0', 'B', 'B', '1', '4', '7', 'C', '1', '5', 'F', 'A', '1', 'C', '7', 'F', 'D', '5', '7', 'B', '0', 'B', 'C', '9', 'E', 'B', '3', 'C', 'F', '6', '5', '5', '6', '5', 'E', 'C', '3', '7', '8', 'E', '8', '6', 'C', 'A', '1', 'C', '3', '4', '8', 'D', '2', '4', 'B', '8', '0', '4', 'A', '8', '4', 'B', '3', 'B', '0', '4', '2', '5', '6', 'D', '4', '5', '5', 'A', '8', '6', '5', 'D', '4', '2', 'B', 'E', '7', '3', 'A', '5', '4', '5', '0', '8', '7', '1', '1', 'C', '6', '2', 'B', 'C', '7', '9', 'A', 'C', 'C', 'E', '9', 'A', '8', 'B', '7', '6', '9', '5', '3', '8', 'C', '1', 'B', 'F', '0', 'E', '8', '7', '3', '1', '3', '0', 'D', 'D', '0', '6', '0', 'A', '6', '4', 'C', '7', '1', 'E', 'C', '1', '7', '2', '8', 'F', '7', '4', '3', 'C', 'C', 'B', 'A', 'C', '3', '1', '4', '7', '5', 'F', '6', '5', '9', '8', 'E', '5', 'B', 'F', 'C', '1', 'E', '3', 'A', '2', '6', '1', '1', 'B', '6', '1', '7', '2', '2', '1', '3', '4', '5', '8', '5', 'C', 'F', '9', '7', '3', 'B', '4', '1', '1', 'E', 'E', '7', '5', '4', 'C', '2', '5', 'E', '7', '6', 'B', 'B', 'A', 'B', '8', '6', '2', 'C', 'D', 'B', '3', '4', 'A', '2', 'A', '2', '5', 'B', 'F', 'B', '3', '3', 'D', 'D', '0', '3', '5', '4', 'B', '4', '7', '3', 'E', '1', '3', '2', 'B', '1', '8', 'C', '2', '7', 'B', '0', '4', 'B', 'C', 'B', '4', 'E', '0', '7', 'B', 'C', '4', '7', '2', 'F', '5', '8', 'F', 'F', '7', '8', 'A', 'F', '5', '0', '6', 'D', 'F', '2', '6', 'E', '3', 'E', 'D', '1', 'B', '0', '1', '4', '1', '7', 'D', 'A', 'F', '7', '4', '7', 'E', 'C', '1', '0', 'D', 'E', '4', '5', '1', 'C', 'F', 'F', 'B', '2', '5', 'F', '9', '7', '0', '6', 'B', 'E', '8', '0', '7', '6', '8', '8', '6', '1', '1', '1', '9', '7', 'B', 'C', '9', '7', '4', '1', '8', 'C', '4', 'E', 'B', 'E', '2', '2', '8', '5', 'F', '7', '8', '2', '0', '2', '6', '9', '1', '0', 'B', '1', '3', 'D', '1', 'F', 'E', '9', '2', '7', 'A', '1', '0', 'F', '6', 'D', '8', 'D', '8', 'B', 'F', '4', '3', '8', 'B', '2', '7', 'F', '7', '1', 'F', '2', '4', 'E', 'F', 'B', '8', '5', '5', '7', '0', 'D', 'A', 'A', 'E', '4', '2', 'F', 'B', 'F', 'D', '3', 'B', '9', '5', 'D', '7', '0', '3', '1', '2', 'D', 'F', 'B', 'F', '1', 'A', '3', '0', '2', 'E', '7', '9', 'A', '2', '9', '6', '3', '9', '3', '6', '4', 'E', '6', 'C', '4', '9', 'E', '4', '1', '8', '7', '0', 'F', '6', '2', 'B', '3', 'F', '2', '8', '1', 'C', 'C', 'D', '9', 'D', '6', '7', '2', '1', '4', '1', '6', '9', '9', 'F', '9', '5', 'A', '4', 'B', '6', 'C', '6', 'A', 'E', 'C', '5', '5', '7', '7', 'C', 'B', '0', 'B', 'C', '4', '4', '2', 'E', '4', 'F', 'D', 'F', '6', '1', '6', '6', '9', '3', 'B', '0', '5', 'F', '6', 'F', 'D', 'C', '5', 'D', 'C', '8', '8', 'E', '7', '2', 'F', '7', 'D', '9', '4', '5', '8', '0', 'A', '1', '2', 'C', '2', 'F', 'D', '9', 'C', '5', '1', '0', 'B', '8', 'F', '6', '9', '1', '8', 'D', '1', '1', '6', '4', '5', 'C', '1', 'C', 'A', '6', 'A', 'C', 'A', 'D', '7', 'A', '7', 'E', '3', 'A', 'F', 'A', 'A', 'A', '5', '3', '8', '7', '1', 'B', '2', '6', '4', '4', '2', '1', '0', '4', 'A', '7', 'A', '5', 'D', 'D', 'A', '7', 'C', 'F', 'C', 'E', 'C', '3', '0', 'F', '9', 'F', '7', '9', '7', '9', 'C', 'B', '3', 'E', '9', '8', 'E', '2', 'F', 'F', 'C', '8', '9', 'C', 'F', 'A', 'B', 'A', '3', '7', 'C', 'E', 'F', 'D', 'E', '0', 'D', 'D', '2', '9', 'B', '5', '7', '4', '3', 'D', '9', '2', '1', 'B', '7', '2', 'F', '1', '5', 'C', 'F', 'D', '5', '4', '8', 'D', '3', '8', 'A', 'C', '3', 'F', '3', 'C', '8', 'B', 'E', 'C', 'E', '4', '7', '4', '8', 'A', 'A', 'D', '7', '4', '0', '6', 'E', 'D', '6', '2', '9', '5', '7', 'A', '2', 'B', 'B', 'A', '3', 'F', '9', 'D', '8', '3', '0', 'E', '5', '8', 'A', 'D', '5', '6', '8', '2', '9', '8', 'A', 'E', '6', '4', 'C', 'B', 'D', '4', '3', '2', '2', 'E', '7', '4', '6', 'E', 'A', 'F', '4', '4', '5', 'E', 'C', '5', '8', '8', '1', '4', '9', '8', 'B', '0', '1', '8', '4', '1', 'C', 'E', 'D', '7', '1', 'D', '2', '7', '9', '6', '9', '7', 'D', 'D', 'C', '2', '6', '0', '2', '9', 'D', '3', '2', '0', '5', '9', '1', '6', '7', '6', '4', '7', '2', 'F', '1', 'B', '1', '2', '6', '3', '5', '3', '4', '4', '1', '5', 'C', '2', '1', '8', '4', '9', 'E', '4', '9', 'A', 'B', 'E', 'F', '7', '8', '8', 'F', 'C', '8', '5', '9', 'B', '2', '9', 'D', '1', 'C', 'E', '4', 'A', '3', '8', 'F', '4', '5', '7', 'F', '2', '4', '0', '0', '5', 'B', '2', '0', '9', '2', '9', 'A', '0', 'F', '7', 'B', '2', '3', '2', '4', 'D', '4', 'C', '6', '0', '8', '5', 'D', '2', '7', '3', '5', 'C', '6', 'D', '5', '2', '8', '4', '4', 'A', '3', '5', '5', '2', '0', 'E', '3', 'C', 'A', '0', '8', '3', '8', 'A', '7', 'E', 'F', 'E', 'C', 'E', '4', '8', '9', 'F', '1', '5', 'D', '2', '4', '2', '4', 'B', '8', '1', '0', '2', '2', 'E', 'D', 'D', 'F', '0', '3', 'A', 'E', 'B', 'B', '4', '8', '2', '1', '3', '8', '3', '9', '8', 'B', '7', '1', 'A', 'C', 'B', '1', 'D', 'C', '3', '8', '4', '8', 'E', '3', '8', '7', 'A', '1', '9', 'B', '3', 'E', 'E', '7', '0', 'C', 'A', '7', 'A', 'A', '0', '8', '8', '5', '3', '4', '1', 'C', 'D', '7', '5', '1', 'E', 'D', 'B', 'E', 'B', '1', '9', '0', '5', 'C', 'D', '0', 'A', '1', '3', '6', '4', 'E', '2', 'F', '4', '2', '5', '3', 'F', '9', 'E', '4', '7', '8', 'A', 'D', 'D', '2', '7', '8', 'E', '2', '1', '7', '9', 'F', '7', 'C', '4', 'A', 'F', '5', '0', '4', '0', '6', '4', 'F', '0', 'D', '5', '0', 'E', 'E', 'E', '4', '8', 'E', '4', '7', '9', '1', '0', '0', '1', '4', '1', '1', 'D', 'B', 'D', 'A', 'B', '4', '2', '9', 'E', '2', '2', 'C', 'B', 'B', 'F', '1', '2', '4', 'B', '7', '3', '9', 'E', '1', '4', 'F', '6', '7', 'A', 'C', '0', 'D', '5', '6', 'A', 'E', '1', '2', '7', '3', '4', 'E', 'C', 'B', 'B', '1', '9', 'F', '5', '7', '9', '6', '9', '8', '0', '7', '8', '4', '7', 'E', '8', 'E', 'E', '9', '8', '4', '1', 'A', 'E', 'E', '8', '6', '8', '4', 'A', '1', '5', 'E', 'C', '8', '6', 'E', 'F', 'B', '1', '2', '5', '6', 'D', 'C', '3', 'C', '4', '3', '5', 'F', '6', '4', 'D', '6', 'A', 'E', '4', '3', 'F', '7', '2', '9', 'A', '4', 'B', '5', '5', '0', '1', 'D', '4', '6', '4', 'C', '8', '7', 'E', '0', '1', 'E', '0', 'B', 'F', 'A', '4', 'C', '4', '7', '7', '8', 'F', 'E', 'B', '5', '9', '8', '6', 'C', '2', '4', '4', '1', '1', 'C', '1', '8', '6', 'E', '2', '6', '0', '8', '6', '5', '6', 'C', 'B', 'E', '7', '4', '5', 'D', 'A', '3', '6', 'D', '6', 'F', '6', '1', 'A', '1', '1', '8', '9', '9', '2', 'E', 'B', 'B', '3', '0', 'B', '6', '0', 'F', 'F', '5', '7', '6', '6', 'E', '7', '6', '2', '5', 'A', '9', '1', '7', '8', 'E', 'C', '0', '3', '0', 'E', '4', '3', 'E', 'A', '6', '0', '9', 'E', '0', '8', 'A', '4', 'C', 'A', '8', '3', '5', '1', '4', '2', '5', '0', 'B', '1', 'D', '5', '7', '3', 'F', '3', '8', '2', '1', 'A', 'B', '6', 'C', '1', 'D', '9', '1', '5', '2', 'B', 'C', 'B', '6', '2', '4', '1', 'F', 'D', '8', '6', 'A', '4', '2', 'C', 'F', 'A', 'C', 'E', '3', '7', '7', 'B', '3', 'F', '1', '2', 'A', '4', '4', 'E', '6', '2', 'E', '9', 'C', '1', '3', 'D', 'D', '8', '7', '7', 'F', 'F', '9', '0', '2', 'C', 'F', 'D', '6', 'E', '6', '8', '9', 'C', '4', 'B', 'C', '4', '5', '0', '2', 'F', '7', '9', '5', 'C', '3', '1', '4', 'D', '2', '9', 'C', 'F', '3', '4', '5', '3', '0', '7', '0', 'B', 'D', 'A', '8', '8', 'D', '3', '9', 'B', '2', 'A', '9', 'E', 'F', 'E', 'F', 'D', '0', 'C', 'C', 'A', '6', '0', 'E', 'C', 'C', '3', '3', 'B', 'B', '0', '4', '4', 'E', '6', 'B', '1', '0', 'A', 'B', '2', 'A', 'C', '6', 'B', '1', 'F', 'B', 'E', '5', 'E', 'C', '8', 'D', 'C', '8', '0', '8', '8', '5', '2', 'C', '6', '1', 'D', 'B', '8', 'C', '3', '2', 'C', '2', '1', 'E', '4', 'D', '6', '9', '3', '4', '1', '1', '6', 'A', '2', '5', '5', '3', 'E', 'C', '2', '4', '4', '6', 'C', '3', 'A', '6', 'E', '9', '9', '5', '7', '9', 'C', 'C', 'E', 'B', '7', 'B', '8', '1', 'A', '9', '0', '2', 'A', '7', 'D', 'F', '0', '8', 'C', 'F', '6', '4', '2', 'D', 'F', '9', '8', 'D', '5', 'B', 'E', 'C', 'F', '5', 'E', '0', 'F', 'D', '2', '6', '0', '0', '3', '2', '6', 'A', '6', '7', '1', '4', '6', '3', '8', '5', '4', '9', 'F', '5', '4', '9', '4', '7', '6', 'F', 'A', 'F', 'E', '2', '7', '1', '7', 'D', '5', 'E', '4', 'C', '6', '5', '8', '0', 'A', '7', 'F', 'F', '5', 'E', '0', '7', '7', '6', '9', 'E', 'A', '2', '5', '9', 'E', 'F', 'B', '9', 'F', '9', 'D', '7', '1', 'E', 'E', '8', 'F', 'F', 'E', 'A', 'A', '8', '1', '5', '3', '5', '3', '2', 'B', 'C', 'E', '6', 'C', 'A', '2', '6', 'C', '3', 'E', 'A', 'D', '3', '5', '9', '9', '1', 'C', '8', 'E', '4', '1', '5', 'F', '8', '5', 'C', '0', '2', 'C', '0', '0', 'D', '7', '4', '6', 'C', 'D', '3', 'E', '9', '8', '9', '4', 'C', '4', '5', '7', '3', 'E', 'F', 'E', '9', 'B', '1', '1', '5', '9', 'B', '3', '4', '9', 'B', 'A', '5', 'C', '2', '8', '8', '7', '6', '3', '8', 'E', '9', 'D', 'E', '9', '0', '9', '5', '2', '1', '3', 'B', '6', '8', 'A', 'C', '5', '0', '3', '0', '5', 'C', '3', 'A', '7', '1', '6', '4', '9', 'A', 'B', '8', '9', 'C', 'E', '6', 'B', 'A', 'A', '4', '1', 'D', '1', '6', 'E', '9', '4', '4', '0', '8', '0', '7', '2', '8', '9', 'B', '9', 'E', 'F', 'B', 'B', 'B', '1', 'D', '1', '1', 'B', '0', 'B', '5', '7', 'F', '7', 'D', '4', '4', '6', '3', '5', '9', '0', 'D', 'F', '7', '1', '9', '5', 'D', '9', 'A', '3', '9', 'F', '4', 'E', '9', 'D', 'B', 'F', 'B', '4', '2', 'D', 'A', '5', '4', 'C', '0', 'B', '4', '5', '4', '7', '0', '5', 'D', 'A', '3', 'A', 'D', '9', 'C', '6', '6', '1', 'F', 'C', '7', '9', '3', 'C', 'D', 'A', 'B', '7', 'D', '1', '6', '9', '0', '2', '1', 'D', '4', '0', '8', '8', 'B', 'B', '7', 'E', '8', '2', '9', 'C', '7', 'B', 'A', '8', '5', 'D', 'A', 'D', '8', 'C', 'D', '5', 'B', '0', '1', '4', '1', 'A', 'B', 'E', '3', '7', '8', '3', '9', '8', 'D', '2', '1', '6', '6', '9', '2', 'C', '7', 'C', '7', '4', '4', '7', 'D', '1', '7', '8', '6', '7', '9', '1', 'B', '6', '1', '7', '9', '9', 'A', 'D', '2', 'B', '7', 'D', 'D', '4', 'F', '5', 'B', '7', 'A', '8', '3', '6', 'F', '8', '6', '8', 'F', '0', '9', 'C', 'B', '9', 'A', 'D', '7', 'C', '1', '8', 'C', '1', '5', '5', 'B', 'B', 'D', 'C', 'E', 'D', '4', '6', '6', '5', 'E', '9', '7', '4', 'D', '6', 'A', '7', 'E', 'F', '5', 'D', '2', '2', 'D', '4', '8', 'A', '6', '9', '0', '1', 'B', '1', '0', 'D', '9', '9', '5', 'D', 'C', '4', '3', '7', 'F', 'D', '8', '9', '0', 'A', '9', '2', '9', '4', '3', '4', 'A', '4', 'A', '5', '8', '4', '6', 'C', 'E', '2', '9', '8', 'C', '3', '4', 'E', '4', 'E', '8', '3', '5', 'E', '2', '0', '9', 'C', '8', '7', '5', 'B', '9', '8', 'E', '5', '7', 'D', '6', '5', 'F', '5', '4', '2', 'B', 'B', '0', '6', '4', 'E', '6', 'F', 'A', '2', '4', '8', '1', '0', 'F', '1', 'C', '5', 'D', 'F', 'A', '8', '8', 'A', '6', '0', '6', '5', 'E', '6', '4', '1', 'D', '5', 'E', '7', '7', '9', 'B', 'F', '8', '8', 'B', 'F', '0', '0', '8', 'D', 'E', '2', '8', '7', '3', 'F', 'B', '3', '0', '1', '9', '0', '2', 'F', 'B', '0', '5', 'B', 'D', '9', '0', 'C', 'F', 'A', 'E', '5', 'F', '0', '1', 'C', '0', '7', '3', '6', '7', 'B', '2', '6', '5', 'D', '3', 'C', '1', '6', 'A', '4', '2', 'C', 'C', '5', '1', 'F', 'A', '7', '7', 'E', 'E', '2', '9', '0', '9', 'D', '8', '4', '9', 'C', '5', '1', 'B', '6', '2', '8', '0', '9', 'F', '0', '5', '1', 'E', 'A', '5', '3', 'B', '1', 'C', 'A', 'D', '9', 'C', '7', 'B', '7', 'D', '6', '2', '2', 'D', 'F', '1', '9', '3', '6', '5', '8', '4', '2', 'B', 'A', '5', 'C', '4', '1', '7', 'B', '9', '5', 'F', '8', '1', '1', '2', 'C', '7', 'A', 'B', '2', '1', 'C', 'B', 'E', 'A', '9', '3', 'E', 'B', '0', '1', '4', '5', 'F', '8', '2', '1', '3', 'A', '2', '6', 'E', '5', '7', 'C', 'F', 'B', '0', 'C', '7', '6', '2', '9', '2', '8', 'C', '3', '2', 'C', '8', '6', 'D', '0', '9', 'D', '6', '9', '4', '6', '1', '3', '1', '0', 'D', 'E', '8', '2', '3', 'F', 'E', '4', '7', 'D', '3', 'B', '3', '9', '0', 'B', '9', '7', '6', '9', 'B', '0', 'D', '1', 'C', '4', '6', '7', 'B', '9', 'D', 'F', '6', '6', 'C', 'F', '8', '5', '0', '1', 'D', '7', 'B', 'B', '1', 'C', '6', 'B', '3', '5', 'F', '1', 'D', '1', 'B', '8', '9', '8', '0', '1', '7', '3', '4', '1', '9', '4', '0', '6', '3', 'A', 'C', '1', 'E', '1', '7', '9', '5', '5', 'B', '9', '2', 'B', '3', '7', 'F', '4', '1', '6', '9', 'B', '3', '1', '6', 'F', 'D', 'D', '3', '6', 'F', 'F', '7', '1', '3', 'B', '4', '6', '1', '1', '1', 'F', '0', '7', 'A', 'F', '5', 'C', 'A', 'F', 'F', 'C', 'E', 'A', '6', '4', '8', '6', '7', '5', '1', 'E', 'A', '1', '2', '3', '3', 'F', 'C', '3', 'F', 'E', '9', '8', '0', 'E', '4', 'A', '5', 'C', 'B', '5', '9', 'A', 'D', 'C', '2', 'B', '4', '4', 'D', 'E', '8', '5', 'A', 'C', 'A', '0', 'D', '2', '0', '8', '7', 'E', '7', 'A', 'B', '4', '4', '5', 'C', '8', '3', 'A', 'E', '6', 'F', '9', '1', 'B', 'A', '7', '9', '0', '8', '4', '9', 'C', '3', '1', '3', '7', '3', 'E', '5', '4', '9', '6', 'A', '7', 'D', 'B', 'F', 'E', '3', '3', '3', 'A', '7', '7', '1', '3', '5', 'F', '0', 'A', '2', '5', 'D', '2', 'D', '3', 'C', '7', 'A', 'B', '3', 'D', '5', '6', 'F', '2', '2', 'D', '7', 'A', '5', '1', '9', 'C', '1', 'D', '8', 'F', 'B', '9', '8', '1', '8', 'A', '2', '5', '0', '3', 'C', '0', '6', 'A', '8', 'D', 'A', '2', 'E', '3', 'A', 'F', 'A', '2', '8', '6', '9', 'E', 'A', '2', 'A', '5', '9', '7', '5', '7', '9', '8', '7', '9', '1', 'A', '6', '8', '3', '1', 'B', '4', '9', 'D', 'E', '7', 'F', '4', '7', '2', 'F', 'F', '8', '4', 'D', '9', '4', '5', 'D', '7', '7', '9', '2', '1', 'F', 'D', 'D', 'C', '1', '5', 'B', '9', 'D', '0', '9', 'B', 'F', 'C', '3', '7', '2', '0', '0', '3', '1', '5', '8', 'A', '1', '4', 'E', '9', '8', '9', '9', '8', '3', 'D', 'A', '2', 'C', 'D', 'D', 'C', 'A', 'F', 'C', '1', 'E', '2', 'F', '0', '2', '8', '9', '9', '8', '2', 'C', 'F', '8', '0', 'C', '8', '0', '5', '6', '3', '3', '3', 'B', 'E', '5', 'F', 'B', '2', 'C', '2', '1', '3', 'A', '6', '8', 'D', 'D', '3', '4', 'B', 'C', 'E', '1', '6', '8', '8', '9', 'D', '5', '4', '3', '2', 'F', '1', '6', '6', '4', '9', '0', '6', '0', '3', 'B', '0', '7', 'C', 'E', '9', '7', '9', 'D', 'B', '5', 'A', '7', '1', '9', '9', '6', 'E', '7', '7', 'C', '9', '5', '1', '8', 'C', '2', '9', '3', '4', '5', '9', 'F', 'C', 'C', '1', '1', 'D', '8', '2', '5', '0', '6', 'E', '5', 'E', 'B', '1', 'F', '5', '1', '9', 'B', 'A', 'B', '5', 'A', 'A', 'D', '9', '2', '9', '1', '3', 'B', '0', '2', '8', '5', '0', 'F', '2', '7', '2', 'D', '2', '2', 'C', '6', '5', 'C', 'B', '6', '9', 'E', '6', 'A', 'F', '5', '4', '9', '7', 'F', '3', '0', 'F', 'B', '8', 'F', '7', 'B', '9', 'D', '5', '7', '4', '1', '2', '0', '5', 'C', 'D', '2', '0', '4', '4', '3', '3', '9', 'D', '9', '0', '1', '8', 'B', '7', '3', '7', '9', '4', 'C', '9', '2', '8', 'D', '6', '4', '9', 'D', 'C', 'D', '4', '8', 'B', '3', 'F', 'D', '3', '1', '4', '3', '8', 'B', 'F', 'D', '6', '4', '5', '8', '9', '2', '6', '5', '7', 'E', 'A', '4', 'C', 'F', '8', '3', 'B', 'F', '2', 'D', '1', '9', '1', 'A', '1', '0', '2', '3', '8', '6', 'D', '6', '5', '7', '3', '2', '1', '6', 'E', 'C', 'E', '5', '2', 'F', '7', '3', 'B', 'E', 'E', '8', 'B', 'F', '2', 'B', 'F', 'E', 'D', '1', 'B', 'D', 'A', '2', 'D', 'C', 'D', 'E', '5', '0', 'C', 'E', 'C', 'F', 'B', 'F', '0', '9', '0', '7', 'A', '8', 'E', '3', 'F', '8', 'B', '8', '6', 'C', '7', '0', '3', '7', '1', '3', 'C', 'D', 'F', 'A', 'E', '0', 'A', '7', '9', '2', '3', '1', 'F', 'D', 'F', '5', '4', '0', '2', '7', 'F', 'D', '8', 'E', '9', 'A', 'D', '4', 'B', '3', 'A', '6', '6', '9', '7', '8', 'E', 'A', '5', '6', '9', 'D', '1', '0', '7', '9', '1', 'E', '6', '3', 'E', '0', '9', '3', 'F', 'A', '7', 'A', 'E', '5', '6', 'B', '8', 'F', 'B', '0', 'A', 'F', '3', '8', '5', '2', 'A', 'A', 'C', '2', 'E', 'F', '3', 'E', 'D', '1', '4', 'B', '6', '0', 'A', '2', '2', '3', '4', '4', '5', '9', 'E', '0', '7', '6', '9', '0', '5', '3', '0', 'E', 'D', '3', 'D', '8', '2', '4', '6', '4', 'E', 'A', '7', 'B', 'F', '2', 'A', '2', '4', '5', '9', '8', '9', '4', 'D', '9', 'E', 'D', 'D', '1', '5', '6', '1', 'E', '2', '6', '4', '9', 'F', '7', 'E', 'D', '8', 'C', '5', 'C', 'F', '3', '5', '8', '1', 'E', '5', '3', '9', 'D', '7', '5', '9', '7', '2', '8', 'E', '1', 'B', '8', '5', '7', '2', '9', '4', 'E', '3', '0', '6', '6', 'C', 'B', '5', '2', '2', '5', 'F', '3', 'D', '0', 'B', 'A', 'E', 'B', 'D', '7', '4', 'D', '4', '2', 'F', 'B', '3', '3', 'D', '2', '2', 'B', '7', '1', '8', '0', '9', 'C', 'A', 'D', 'F', '5', '7', 'D', '4', '2', 'D', 'D', '4', '1', '4', '3', '3', 'B', '2', '6', '9', 'E', '9', 'A', '6', '0', '2', 'C', '4', '8', '5', 'F', '8', '5', 'F', '4', '7', '2', 'F', '6', '5', 'D', '6', '2', '5', '7', 'E', '6', 'F', '0', 'E', 'D', 'C', 'A', '0', '7', '5', '4', 'B', '2', '0', '4', '6', '0', 'C', '7', 'B', '5', 'F', '8', '5', '7', 'F', '5', 'E', '0', '5', 'A', 'D', '7', 'B', '2', '4', 'B', 'E', 'B', '4', '4', '0', 'E', '1', '3', 'B', 'A', '6', 'B', '4', 'A', '3', '3', '1', '3', 'B', 'C', 'F', '8', '3', 'E', 'D', '6', '5', '5', 'A', '4', 'C', '1', '8', 'B', '6', 'F', '2', '9', '7', '6', '2', '2', '2', '5', 'C', 'C', 'B', 'D', 'F', '0', '7', '8', '0', 'A', 'A', 'D', '6', '4', 'E', 'B', 'F', '8', 'D', 'B', '9', 'B', '9', 'E', '2', '7', 'E', '3', 'B', '0', '5', '7', 'B', '6', 'D', '8', '6', '4', '3', '8', 'B', 'C', 'F', 'F', '8', 'B', '5', '6', 'B', '0', 'C', '7', 'C', '7', '7', '5', '1', '2', 'C', '6', 'E', '2', 'B', '9', '6', '2', 'F', 'A', '7', 'A', '2', 'B', '2', 'D', '7', '8', '3', 'F', '1', '5', 'C', '2', '7', '9', 'B', 'F', 'B', 'B', '3', '2', '1', 'D', 'C', '8', 'B', '9', 'C', 'E', 'A', 'C', 'A', '6', 'A', 'D', 'E', 'B', 'C', '4', 'B', 'F', '4', '8', '4', '2', 'B', '2', '3', '2', 'D', 'F', '5', '5', '5', '3', '3', '5', '5', '0', '8', 'E', 'E', '2', '7', 'E', 'D', '7', '2', 'C', '5', '2', 'B', '8', '3', '8', '0', 'A', '4', '6', '5', 'E', '4', '6', '0', 'B', '5', '5', '3', '9', 'E', '2', 'D', '1', '4', 'D', '3', 'E', '0', 'A', '9', '4', '6', 'A', '3', 'B', 'D', '9', '4', 'E', '2', 'F', 'B', 'C', '2', '3', '7', '5', '1', '8', '4', '5', 'D', '9', '1', '0', '4', '5', 'F', '8', '2', 'C', '9', 'E', '8', '6', '2', 'A', '9', '2', 'D', '1', '0', 'A', '9', '8', 'A', 'A', '5', 'F', '5', '4', '5', 'F', '2', 'C', 'D', 'E', '4', 'B', 'A', 'D', '7', '6', '2', '2', '9', 'D', '7', 'C', 'F', 'E', '9', '9', '1', 'A', '5', 'C', '7', '4', 'D', 'B', 'D', '9', '4', 'F', '0', '1', '2', '2', '0', 'F', '6', 'B', '1', 'E', 'D', '1', '3', '3', '0', '5', 'F', '4', 'C', '8', 'F', 'A', '5', '5', '4', 'C', '0', 'E', 'A', 'F', '3', '3', '5', '9', 'F', 'C', '3', '7', '3', '7', '2', '3', '9', '1', '0', 'C', '5', '7', '4', '6', 'F', '9', 'F', '6', '3', '8', '6', '4', 'A', '4', 'C', '3', 'E', '4', '6', '6', 'A', 'B', '9', 'B', '4', '7', 'A', '3', 'A', 'E', '2', 'A', '0', '4', '7', '3', '1', '5', '0', '8', '4', 'F', 'D', '6', 'C', '1', 'F', 'B', 'E', 'F', 'E', '0', 'F', 'D', '9', 'F', '5', 'F', 'C', '2', 'C', 'C', '5', '4', 'E', '3', '7', 'D', '1', '4', 'D', '5', 'F', '6', 'F', '3', '3', '9', 'F', '3', 'F', '5', 'F', '4', '7', 'A', '7', '2', '4', '3', 'B', 'E', '3', 'A', 'A', '9', '0', 'C', '0', '9', '3', '8', '4', '7', 'D', '6', '2', 'F', '9', '9', '7', '4', 'F', 'D', 'F', '2', '0', '1', '9', '2', 'E', 'C', '1', '3', 'D', '3', 'E', 'A', 'F', 'F', 'D', 'B', '1', '8', 'D', '3', '8', 'F', 'F', 'A', '5', '4', 'E', 'A', '6', 'F', '9', '5', '4', 'D', '6', 'C', '5', '8', '5', '7', '5', '4', '5', 'B', '8', '0', '8', 'B', 'F', 'B', '1', 'A', '8', 'B', 'D', 'D', 'B', '5', 'D', 'B', '4', 'A', 'C', 'F', 'B', '8', '4', '0', '5', 'B', '5', '1', '3', '4', '5', 'E', 'B', 'B', '7', '7', '5', '1', '3', '3', '9', '4', '2', '7', '4', 'F', '4', '5', '4', 'D', '6', '1', 'E', 'B', '2', '1', '3', 'E', '7', '2', '8', '0', 'D', '2', 'E', '7', '3', 'F', '1', '5', 'D', 'D', 'A', '9', '7', '3', '8', '3', 'D', '6', '2', 'B', '1', 'E', 'F', '6', 'C', '8', 'B', '8', '6', 'F', '0', '3', 'D', '8', 'C', 'E', '6', 'D', '7', 'B', 'E', 'C', '2', 'D', '3', '2', 'C', '4', '8', 'F', 'D', '3', 'B', '7', '3', '1', '4', 'D', 'C', 'D', 'C', 'A', '5', 'B', 'E', '3', '8', 'A', 'E', '5', 'F', '0', '3', '1', '3', 'B', 'B', '9', 'F', '8', '0', '1', 'C', '5', 'E', '3', 'D', 'B', 'B', '0', '7', 'C', '8', '1', '3', '2', '2', 'E', '4', '2', '7', '4', 'A', '2', '0', '4', 'A', '7', '1', 'A', '7', '0', '3', '3', '2', '2', '3', '5', '3', '7', 'D', '7', '7', '2', '1', '7', '5', 'B', '9', 'B', 'B', 'F', '0', '3', '9', '5', 'B', 'C', '8', '6', '7', '2', '5', '2', '2', 'C', 'E', 'A', '3', 'C', '5', 'E', 'B', 'C', 'D', '5', '6', '3', '5', '8', '3', '9', '2', '1', '0', 'B', '3', '0', '1', '6', 'C', '8', 'D', 'B', '7', '3', '6', '8', 'D', 'A', '0', '4', 'F', 'C', '2', '6', '1', '3', 'C', '1', '8', '7', 'F', '4', '2', 'F', '0', '1', 'B', '8', 'B', '4', 'A', '4', 'F', '3', 'B', 'F', '0', 'A', '8', 'B', 'A', 'E', '1', 'E', '1', 'A', '2', 'C', 'A', '2', '3', '8', '2', 'F', 'D', '3', 'C', 'A', 'E', '0', 'D', 'D', '6', 'D', 'E', '7', 'F', '5', '7', '1', '4', 'F', '0', 'F', '3', '6', 'F', 'E', 'B', 'E', '0', '6', '8', 'F', '5', '8', '5', 'A', 'E', 'A', 'E', '1', 'E', 'C', 'B', '6', 'A', 'A', '6', '4', '4', '0', 'B', 'C', '9', '4', 'E', '4', '2', '6', 'C', '2', '3', '6', '6', '3', '0', 'D', '0', 'F', '1', 'F', '3', 'A', 'F', '1', 'C', '0', 'F', '8', '0', '1', '1', '1', '7', 'A', '6', '1', 'A', 'A', 'E', 'C', '1', '2', '3', 'F', '3', 'B', 'B', '9', 'E', '9', '9', 'C', '5', '0', 'C', 'D', '4', '0', 'D', '9', '1', 'B', '6', '0', 'F', '0', '8', '1', '0', '9', '9', 'F', '6', 'A', 'C', 'A', 'A', '3', 'F', 'E', 'D', '1', '8', '2', 'C', 'C', 'A', '2', '1', '5', '5', 'C', '8', '8', '9', 'C', '5', 'E', '4', '8', '5', '0', 'D', 'B', '7', '0', '2', 'A', '1', '6', '7', '1', '4', 'B', '7', '4', 'A', 'D', '9', 'F', '4', 'F', 'D', '4', '2', 'F', '2', '3', '3', '4', 'C', 'D', 'D', '9', 'F', '1', '7', 'B', '1', '2', '2', 'E', '4', '8', 'D', 'F', '0', 'E', 'A', '6', '8', '1', '6', '8', '3', '3', 'C', '6', 'C', '7', '4', 'E', 'F', 'E', 'A', 'E', 'B', '8', '5', 'F', 'A', '4', 'E', 'E', '7', 'D', '7', 'E', 'E', '4', '8', '0', 'F', '1', 'A', 'F', 'E', 'A', '5', '3', '5', 'B', '6', '0', '3', '1', '2', '0', '8', '6', 'C', '5', '7', '6', '5', '7', 'E', '0', '6', 'F', '9', '3', '3', '2', '3', '0', 'E', '8', 'D', '5', '0', 'A', '8', '7', 'E', '3', 'E', 'B', 'E', 'D', '6', 'A', 'D', '5', '3', 'F', '0', 'A', 'B', '8', '8', '7', '6', '9', '3', '7', '5', '7', '2', 'C', 'F', '6', '5', 'B', '4', '4', '8', '6', '1', 'C', '0', 'B', 'D', '3', '2', 'B', '4', '8', '6', '2', '7', '7', '0', '9', '3', 'A', '3', '6', 'E', '5', '5', '3', '8', '1', 'B', '8', '0', 'D', 'E', 'B', '9', '8', '6', 'C', 'B', 'D', '8', '8', 'E', '8', 'D', 'B', 'F', 'B', '9', 'B', '2', 'A', '1', '9', '2', '6', 'F', '7', 'D', '4', 'A', 'F', '5', 'E', '5', '9', '0', '7', 'E', '9', '7', '3', '1', 'E', 'B', '7', 'F', '9', '8', '3', '2', '2', '2', 'F', '2', '5', '4', 'F', '2', '8', '6', 'B', '1', 'E', '3', '7', '4', '5', '5', 'A', 'E', '1', 'C', 'D', '3', '5', 'C', '2', '7', '3', '9', '0', '8', 'C', 'B', 'E', '7', 'E', 'F', '4', '8', 'A', 'C', 'A', '3', '7', '2', '4', 'F', '7', '5', 'B', 'C', '6', '6', '5', '8', '8', 'D', '9', 'C', '0', 'B', '7', '5', 'F', 'D', 'C', 'B', '9', '5', 'E', '8', 'F', '8', 'D', '7', 'A', 'C', 'F', '8', '9', 'B', '0', '8', 'C', '4', 'A', '7', '7', 'A', '9', 'E', '2', 'A', '3', '6', '7', 'A', 'A', 'C', '8', 'F', 'C', '8', 'E', '4', 'E', '7', '5', 'E', '9', 'B', '8', 'D', '4', '0', 'B', '7', 'C', '2', '6', '9', '4', 'B', 'F', '6', 'F', 'A', '2', 'B', 'D', 'F', '3', '4', '7', 'F', 'E', 'E', 'F', 'E', '5', 'F', 'A', 'E', 'C', 'A', '3', '3', 'D', 'E', '3', '9', '0', '2', '7', '3', 'B', '5', '0', '5', '9', '4', '7', '1', '9', '4', '5', '5', '0', '5', '5', '6', '0', '5', '0', 'A', 'B', '5', '1', '7', '0', '0', '5', '0', 'D', 'F', '9', 'E', '7', '4', 'D', 'A', '6', '8', 'A', '4', 'B', '3', '2', 'F', '4', '1', '1', '8', '9', 'D', '3', '4', '7', 'E', 'F', '3', '3', '5', 'F', '0', '5', 'C', 'A', 'B', '4', '9', '4', 'F', 'F', 'F', '0', 'E', '3', 'E', '6', '0', '4', 'E', '5', 'D', '5', '7', 'F', '5', '3', 'B', 'C', '3', 'E', '1', 'A', '0', 'B', 'B', '5', '3', '8', 'B', 'F', '5', '5', '0', '6', '2', 'A', '7', '2', 'B', '2', '5', 'E', '3', 'D', 'C', 'D', 'B', 'C', 'E', 'B', '0', '0', '4', '6', 'E', '4', '0', '6', '2', '0', 'D', '8', '3', '3', '9', '0', 'F', '9', 'D', '8', 'D', 'F', '6', 'A', 'B', '2', '9', 'D', '5', '5', '3', 'B', '9', 'E', 'F', 'F', '4', '6', '8', '9', 'D', '1', '2', '7', '4', '2', '0', '0', '7', '5', 'E', '9', '5', '8', '9', '2', '4', '6', 'A', 'C', '6', 'B', '9', 'E', '6', '8', '1', 'A', '7', '0', 'C', '7', '5', '2', 'D', '7', '6', 'E', '3', '0', '8', 'A', 'D', 'A', '6', '4', '3', '8', '3', '1', '8', 'E', 'F', 'E', '9', '3', 'C', '7', '0', '2', '3', '2', '3', 'B', 'F', '5', '3', 'C', '2', '4', '8', '0', 'A', '5', '5', 'C', '2', 'E', '5', '7', '6', '6', 'A', '9', '1', '2', '6', 'D', 'B', 'C', 'D', '0', 'E', '7', '3', '4', '9', 'B', 'A', 'D', '0', '2', 'B', '1', '9', '5', '5', '3', '0', '0', 'F', '8', 'B', '4', '3', '7', '7', '8', '8', 'A', 'B', '3', '3', 'A', 'B', '9', 'B', '0', 'F', 'F', '4', '7', '9', 'D', '6', '7', 'B', 'C', 'F', 'C', 'E', 'C', 'B', '9', 'F', '0', '0', '8', '2', '1', 'C', '7', '9', 'D', '2', 'E', '1', 'E', '4', 'D', '7', 'F', '5', '9', 'A', '0', '6', '8', 'E', '8', '7', '6', '2', '3', '9', '1', 'E', 'F', '6', '6', '2', '2', '9', '9', '8', 'E', '6', '5', 'E', '1', 'C', '4', '6', 'F', '2', '7', 'E', 'F', 'A', '8', '9', 'B', 'B', '8', 'F', 'B', 'E', 'F', '3', 'B', '8', '3', 'A', '2', '6', 'F', '5', '5', '3', 'D', 'E', '0', '9', '8', '7', '5', '4', 'C', '1', '0', '2', '6', '3', 'E', '2', '7', '4', '3', '5', 'E', 'F', '7', '0', 'C', 'E', 'C', 'E', 'B', '1', '0', 'E', 'E', '1', '7', '9', '0', 'A', '6', 'D', '2', 'D', '3', '5', 'D', '8', '6', '8', 'E', 'D', 'D', '2', 'F', '7', '7', '1', '7', '6', 'E', '6', 'F', '0', '7', 'D', '6', 'F', 'A', '2', 'D', '8', '9', '0', '6', '5', '8', '0', 'A', 'B', 'D', '1', '5', '1', 'C', 'B', 'D', 'D', '0', '4', 'E', 'E', '5', '0', '8', '6', '8', '1', 'E', '2', '6', '5', '7', 'F', '9', 'A', 'F', 'A', '0', 'A', '5', '6', '9', 'F', 'B', '3', 'E', '1', '6', '2', 'E', '5', '5', '0', '5', '0', '4', '6', 'A', '1', 'B', '9', '1', '8', 'C', 'D', '1', '0', '9', '6', '9', '7', '4', '6', '8', '8', '4', '8', '1', '2', '2', '8', '4', '1', '8', '6', '4', '6', '6', '7', '7', '9', 'B', '1', '4', '7', '3', '2', 'E', '7', 'C', 'A', '4', '8', 'B', 'B', '4', '4', 'A', '9', '6', 'E', 'B', '6', '4', '5', '4', '0', '9', 'A', 'C', 'D', '1', 'E', '7', '0', '6', '9', '0', 'F', '2', '4', '8', 'D', '0', '6', 'D', '6', '7', '4', '1', '3', '2', '6', '7', '2', '7', '9', '3', '4', '6', 'A', '2', '6', '3', '9', 'C', '9', '5', '4', '3', '8', 'B', '7', 'E', '2', '1', 'F', '8', 'B', '5', '1', '9', '8', '9', '4', 'F', 'A', '4', '0', 'C', 'F', '3', '7', 'B', '6', '8', 'A', '3', 'A', '2', '9', '8', '8', 'E', '8', '8', '7', '7', '5', '5', '4', '0', 'D', '3', '0', '4', 'E', 'D', '6', 'E', 'B', 'B', '7', '9', '5', 'A', 'F', '6', 'C', '7', '8', '4', '6', '4', '2', '3', '6', '2', 'F', '7', '2', '9', '6', '0', '7', '1', '4', '2', '9', 'C', '5', '3', '0', '2', '6', '6', '4', '6', '5', 'E', 'F', '8', 'B', 'D', 'F', '4', '3', '6', '6', '0', '6', '1', '7', '9', '9', 'E', '7', '0', '3', '2', '8', '0', '0', '8', '7', 'C', 'B', '7', '7', '2', '3', '6', '0', '9', 'B', '1', '9', 'E', 'D', 'F', '5', 'C', 'D', 'E', '5', '8', 'B', 'D', '1', '2', 'A', 'A', 'F', '1', '6', '7', 'B', '2', '5', 'E', '9', '5', '4', '3', 'B', 'E', '2', 'B', '9', '8', '3', '8', '4', '8', 'C', '5', '0', '8', '7', '6', '2', 'E', '2', 'D', '0', 'E', 'A', 'E', 'C', '7', '8', '9', 'D', 'A', '3', '5', '1', '8', '9', '9', 'B', 'F', '4', 'C', 'F', '1', 'C', '6', '8', '5', '5', '9', '7', '9', 'B', 'F', '1', 'E', '0', '6', '4', '7', '9', 'D', '2', '9', 'B', 'B', '4', '2', '2', '8', '3', '7', '2', 'E', '1', '9', '9', 'C', '8', 'A', '4', '9', 'B', '7', '1', '3', '1', '3', '4', '3', '7', '6', '8', '6', '8', '0', '7', '2', '1', '5', 'D', '6', 'E', '9', 'D', 'D', 'F', 'D', 'B', 'E', '2', 'D', 'E', '5', '7', 'B', '1', '9', '0', '4', '3', 'A', '5', '5', 'A', '8', '3', 'A', '0', '5', '6', '9', '2', '0', 'C', 'F', '7', '9', 'A', 'D', 'D', 'D', '8', '0', 'F', 'C', '5', 'A', '5', '9', '3', '7', 'D', '6', 'B', '4', 'D', 'D', '7', '0', '5', '2', '4', '2', 'E', 'D', '2', '1', 'D', 'A', '2', 'F', 'D', 'D', '2', '2', '7', '5', 'F', '4', 'D', 'C', '8', '0', '1', '9', 'F', '7', '8', 'C', 'B', '2', '7', '2', 'A', '4', '6', 'B', '7', '8', '7', '5', 'E', '2', 'F', '5', 'E', 'A', 'E', '6', '5', 'F', '6', '9', '8', '4', '8', '5', 'B', '6', '9', '9', '9', '0', '3', 'B', '5', '3', 'C', 'F', '3', 'D', '3', '4', '7', 'A', '5', '8', '6', 'E', 'E', 'C', '0', '1', '1', '0', '1', 'A', '8', '7', '6', 'C', '8', 'B', '4', '4', '4', '3', '7', '3', '3', '7', 'D', '9', 'D', '0', 'A', 'A', '5', '6', '1', '3', 'F', '5', 'C', '1', 'B', '7', '3', '8', '7', '3', '2', 'E', '9', 'E', '0', 'D', '4', '0', '0', '5', '1', 'F', 'C', 'E', 'E', '4', '7', '1', 'A', 'C', '3', '9', 'D', '8', 'C', '5', '3', '8', '3', '1', 'D', '8', '0', 'B', '1', '7', '2', 'E', '6', '5', '8', 'E', '4', 'F', 'C', 'C', '3', '7', '2', '4', 'B', 'E', '2', '8', '6', 'C', '6', '5', '7', 'B', 'F', '5', '5', '8', 'B', '9', '3', 'A', 'F', '5', '0', '1', 'F', 'F', 'F', '6', '6', '0', '4', 'B', '3', '8', '2', '3', '3', '3', '7', 'E', 'B', 'D', '0', '1', '0', '6', '0', '6', '5', '6', '0', '3', '1', '3', '1', '6', '8', 'D', '9', '2', '3', 'F', '0', '3', 'A', 'B', 'C', '1', '1', 'F', 'E', '1', '8', '9', 'F', 'B', '3', '1', '0', '6', 'F', '8', '5', '0', 'A', '6', '7', 'E', 'B', '6', '4', '1', '6', 'B', '7', '0', '4', 'A', '4', 'B', 'B', 'B', '5', 'F', 'C', '9', '3', '6', '9', '0', '9', '0', '4', '5', '0', '4', 'E', 'C', '9', 'D', '4', '1', '4', '5', '5', '7', '2', '1', '0', '5', 'C', '1', 'A', 'D', '5', '5', 'C', '2', 'D', 'D', 'F', 'F', '1', '4', 'C', 'A', '5', 'E', '7', 'D', '4', '5', '4', '5', '5', '0', '3', '2', 'D', '3', 'E', 'E', 'D', 'F', 'E', 'D', 'A', 'D', '5', '9', 'D', 'B', 'E', '2', '5', '1', 'F', 'A', '3', '7', 'A', '0', 'D', '9', '6', 'B', '3', '1', '8', 'C', '2', '1', '6', 'F', '7', '0', '6', '5', '4', '8', '4', '1', '2', '9', 'E', '4', '8', '5', 'C', '4', 'E', '3', 'B', '4', 'D', '8', '3', '1', 'A', '3', '9', 'C', 'E', '6', '3', '0', 'F', '9', '5', '4', 'B', '5', '9', 'C', 'C', '8', 'E', '2', '4', '7', '6', '1', '2', '7', 'A', 'F', '0', '1', '0', 'C', 'C', '7', '6', '6', '0', '9', 'E', '7', '4', 'A', '5', 'F', '4', 'D', '9', 'D', '7', '5', '9', '2', '3', '7', '2', '8', 'A', '5', 'F', '5', '4', 'E', '6', 'D', 'C', '1', '5', 'D', '1', 'E', '1', 'F', '3', '1', '9', '9', '2', '2', '7', 'C', 'F', '1', '5', '9', '8', '0', '5', '5', 'D', '3', '4', '9', 'B', '2', '8', 'C', 'C', '6', '0', '6', '1', 'D', '1', 'C', '5', 'B', '1', '2', 'C', '8', '7', '2', '0', '2', '1', '6', '3', '7', '3', 'F', '0', '1', 'D', 'E', '0', '3', 'C', '5', 'F', '3', '4', '5', '0', '9', '1', 'B', '0', 'D', '8', 'F', '6', '5', '1', '3', '7', '0', '7', '3', '8', '7', '3', 'F', '8', 'A', 'D', '3', '1', '6', '8', '3', 'E', '5', 'A', 'C', '1', '0', 'E', 'F', '7', 'D', '3', '8', 'D', '7', '5', '6', '4', 'E', 'F', '9', 'E', 'D', '7', 'D', '7', 'D', '8', '5', 'B', 'B', '0', '4', 'D', '4', 'E', '2', '4', 'D', 'D', '6', '0', 'D', 'F', '0', '6', '5', 'E', '5', 'B', 'D', '6', '5', '9', 'E', 'B', '1', 'C', 'B', '9', 'D', '7', 'C', 'F', '0', '2', 'C', '7', 'A', 'C', '0', 'B', '6', '3', '8', '2', 'F', '0', '2', '7', '8', '3', '1', '2', '1', 'F', 'C', '0', 'C', '9', '3', 'B', '6', 'D', '2', '9', '2', '5', 'F', 'E', 'A', '1', 'E', '8', '6', 'A', '1', 'D', 'B', '3', 'A', '6', 'A', '6', '2', '4', 'D', 'A', 'B', '2', 'D', '2', '3', '6', 'A', 'A', '4', 'E', '8', 'B', 'F', 'A', '9', 'E', '9', '2', 'A', '6', 'A', '6', '6', '9', 'C', '5', 'D', '6', '8', '5', '9', '7', '0', 'B', '8', '8', 'A', 'D', 'E', '9', 'A', 'F', '5', 'B', '8', 'D', '7', 'D', 'C', 'F', '2', '8', '8', 'F', 'B', 'C', '6', 'E', 'D', '0', '3', '7', '6', '1', '0', '9', '6', 'F', '4', '7', 'F', '3', '2', '5', '8', 'C', 'A', 'C', '6', 'D', 'B', 'E', '1', 'E', '1', 'D', '3', 'C', '3', '7', '0', 'E', 'B', 'D', '8', '9', '2', 'A', '2', 'D', '7', 'A', '6', 'B', 'D', '4', '4', '1', 'E', '3', '7', '5', '9', 'A', '6', 'C', 'A', 'A', '2', 'A', 'B', '7', '9', 'C', 'C', 'F', 'A', 'F', 'E', '8', 'E', 'A', '5', '4', 'A', '0', '4', '2', 'C', '6', '2', '2', 'D', '9', '7', '8', 'A', '6', 'E', '7', 'E', 'C', 'D', '7', 'A', 'C', 'D', '4', 'D', '5', '0', '8', 'D', '0', '1', 'F', '2', '6', '5', 'B', '4', '1', '3', '6', '4', '6', '3', '9', '8', '6', '1', 'E', 'E', '0', 'D', '9', '5', 'A', '2', 'A', '7', 'E', 'A', '2', '8', '1', '8', '4', 'B', '4', '8', '9', '7', '7', '3', 'C', 'A', '1', '4', '3', '5', 'B', 'A', '9', 'A', 'F', '0', '1', '8', 'B', '6', '9', '4', 'A', '0', 'E', 'E', '1', '4', '6', '3', 'F', '9', '5', '4', 'A', 'A', 'B', 'D', '0', '3', '6', '9', '9', 'E', '7', 'C', 'E', '0', 'F', '3', '5', '6', 'F', 'B', 'B', 'B', '9', 'D', '2', 'E', 'D', 'B', '5', '7', '2', '6', '5', '8', 'B', '5', 'B', '9', 'A', 'B', 'C', '0', '6', 'D', '9', '2', '7', '0', '3', 'B', 'E', 'E', 'D', '3', '2', 'B', 'A', '7', '6', '8', '7', '8', 'D', 'C', 'B', '8', 'B', '5', '3', 'F', '6', '5', 'B', '7', '8', '3', 'A', 'D', '8', '7', 'C', '3', 'A', '3', '7', 'C', '3', '1', 'B', 'F', '4', '8', '3', '5', '5', 'D', 'D', '3', '9', '0', 'A', '5', '8', '9', 'B', '8', '8', '5', 'E', 'C', 'A', 'A', '5', 'B', 'A', 'D', '6', '4', 'C', 'A', 'C', '2', 'E', '5', '7', 'D', 'F', '8', 'B', '1', '2', 'C', '5', '6', '7', 'B', '5', '3', '9', '9', '8', 'D', 'F', '4', '9', '1', '9', '8', 'E', 'B', '6', 'A', '4', '8', '7', '1', 'E', '5', '0', 'F', '2', '7', 'F', '3', 'D', '2', '3', '1', 'C', '5', '2', '1', '1', '3', '6', 'E', '0', '1', 'F', '3', '1', '3', '3', 'C', 'C', '9', 'D', '8', 'D', '1', '5', '6', '3', 'C', 'C', '0', '8', 'E', '3', '1', '2', '4', 'E', '4', 'B', '7', '6', 'C', 'E', '8', '0', 'F', '1', '1', '5', 'E', '7', '6', 'E', 'B', '4', '2', 'E', '3', 'E', '7', 'D', 'E', 'C', 'B', 'B', '1', '6', '8', 'B', '0', 'F', '1', '6', '8', '3', '9', '4', '4', '8', '8', 'B', 'E', '5', 'E', '7', '0', 'D', 'E', 'D', '6', 'C', 'C', '5', '7', '3', '2', 'F', 'D', '0', '8', '3', '2', '3', 'F', '2', 'F', 'B', '9', '6', 'E', 'F', '6', '9', 'A', '0', '3', '4', '5', '6', '4', '5', '5', 'F', 'A', '7', '5', '6', '2', '8', '7', 'E', 'E', 'D', 'F', '4', 'F', '5', '5', '9', 'A', 'C', '2', 'B', 'D', 'A', '5', '6', '3', '5', '8', 'C', '7', 'B', '5', '4', '8', '4', '1', '9', 'D', '9', 'C', '6', '1', '1', 'F', 'D', '6', 'B', '2', 'B', 'E', 'B', '0', 'A', 'F', '8', '3', '6', '5', '0', '8', '9', '9', 'E', '6', '5', '6', 'C', 'E', '3', '8', 'D', '8', 'C', 'C', '5', '7', '8', 'C', '4', '4', '3', '9', 'B', '4', 'C', '5', '7', 'D', '6', '5', 'B', '5', '0', '7', '2', 'C', '3', '5', 'F', '5', '0', '0', '5', 'C', 'B', '6', '8', '3', '6', 'C', 'C', '9', '3', 'D', '2', 'F', 'C', '7', 'A', 'D', '7', '0', '6', 'B', '4', 'C', 'A', '2', 'E', '0', '2', '1', '2', '2', '9', 'C', '1', '3', '2', 'D', 'F', 'D', '5', '9', 'A', '1', '1', '8', '7', 'A', '9', '5', '2', '8', '5', 'C', '1', 'B', '4', 'B', '2', '3', 'D', 'E', '2', 'A', '3', '4', '7', '8', '1', '3', '5', '2', '6', '6', 'B', '7', '7', '0', '9', '9', '8', 'B', '8', '1', '7', '7', 'A', '6', '2', '0', '5', '\0' }; ajtcl-16.04/test/ajlite.c000066400000000000000000000033521271074662300152270ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include static const char ServiceName[] = "org.alljoyn.ajlite"; #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) int AJ_Main() { AJ_Status status; AJ_BusAttachment bus; AJ_Initialize(); status = AJ_FindBusAndConnect(&bus, NULL, CONNECT_TIMEOUT); if (status == AJ_OK) { status = AJ_BusRequestName(&bus, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE); } while (status == AJ_OK) { AJ_Message msg; status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status == AJ_OK) { status = AJ_BusHandleBusMessage(&msg); } AJ_CloseMsg(&msg); } return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/base64.c000066400000000000000000000044411271074662300150430ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE TEST_BASE64 #include #include #include #include #include #include uint8_t dbgTEST_BASE64 = 0; static int test(const char* input, const char* output) { AJ_Status status; int inputlen; int outputlen; char encode[1024]; char decode[1024]; inputlen = strlen(input); outputlen = strlen(output); status = AJ_RawToB64((uint8_t*) input, inputlen, encode, sizeof (encode)); if (AJ_OK != status) { AJ_AlwaysPrintf(("FAILED STATUS\n")); return 1; } if (0 != strncmp(output, encode, outputlen)) { AJ_AlwaysPrintf(("FAILED ENCODE\n")); return 1; } status = AJ_B64ToRaw(output, outputlen, (uint8_t*) decode, sizeof (decode)); if (AJ_OK != status) { AJ_AlwaysPrintf(("FAILED STATUS\n")); return 1; } if (0 != strncmp(input, decode, inputlen)) { AJ_AlwaysPrintf(("FAILED DECODE\n")); return 1; } return 0; } int AJ_Main(void) { /* * put your test cases here. */ if (test("This is a test.", "VGhpcyBpcyBhIHRlc3Qu")) { AJ_AlwaysPrintf(("FAILED\n")); } else { AJ_AlwaysPrintf(("PASSED\n")); } return 0; } #ifdef AJ_MAIN int main(void) { return AJ_Main(); } #endif ajtcl-16.04/test/bastress2.c000066400000000000000000000162551271074662300156750ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #define CONNECT_TIMEOUT (1000ul * 200) #define UNMARSHAL_TIMEOUT (1000ul * 5) #define METHOD_TIMEOUT (1000ul * 3) /// globals uint8_t connected = FALSE; uint32_t sessionId = 0ul; AJ_Status authStatus = AJ_ERR_NULL; static const char ServiceName[] = "org.alljoyn.Bus.test.bastress"; static const uint16_t ServicePort = 25; static uint32_t authenticate = TRUE; static const char* const testInterface[] = { "org.alljoyn.Bus.test.bastress", "?cat inStr1s", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { testInterface, NULL }; /** * Objects implemented by the application */ static const AJ_Object AppObjects[] = { { "/sample", testInterfaces }, { NULL } }; #define APP_MY_CAT AJ_APP_MESSAGE_ID(0, 0, 0) /* * Let the application do some work */ void AppDoWork() { AJ_AlwaysPrintf(("AppDoWork\n")); } static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "1234"; #endif /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; default: break; } return status; } void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } AJ_Status AppHandleCat(AJ_Message* msg) { AJ_Status status = AJ_OK; AJ_Message reply; char* partA; char* partB; char* totalString; AJ_AlwaysPrintf(("%s:%d:%s %d\n", __FILE__, __LINE__, __FUNCTION__, 0)); AJ_UnmarshalArgs(msg, "ss", &partA, &partB); totalString = (char*) AJ_Malloc(strlen(partA) + strlen(partB) + 1); if (!totalString) { return AJ_ERR_RESOURCES; } strcpy(totalString, partA); strcpy(totalString + strlen(partA), partB); AJ_MarshalReplyMsg(msg, &reply); AJ_MarshalArgs(&reply, "s", totalString); status = AJ_DeliverMsg(&reply); AJ_Free(totalString); return status; } int AJ_Main() { AJ_Status status; AJ_BusAttachment bus; // you're connected now, so print out the data: AJ_AlwaysPrintf(("You're connected to the network\n")); AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status == AJ_OK) { AJ_AlwaysPrintf(("StartService returned %d\n", status)); connected = TRUE; if (authenticate) { AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); } else { authStatus = AJ_OK; } } else { AJ_AlwaysPrintf(("StartClient returned %d\n", status)); continue; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(); continue; } } if (status == AJ_OK) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_AlwaysPrintf(("Accepting...\n")); AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); if (status == AJ_OK) { AJ_AlwaysPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } else { AJ_AlwaysPrintf(("AJ_BusReplyAcceptSession: error %d\n", status)); } } break; case APP_MY_CAT: status = AppHandleCat(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * don't force a disconnect, be ready to accept another session */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %d", id, reason)); } break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_AlwaysPrintf(("AllJoyn disconnect\n")); AJ_Disconnect(&bus); connected = FALSE; /* * Sleep a little while before trying to reconnect */ AJ_Sleep(10 * 1000); } } return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/certificate.c000066400000000000000000000372441271074662300162500ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE TEST_CERTIFICATE #include #include #include #include #include #include #include #include uint8_t dbgTEST_CERTIFICATE = 1; static const char pem_x509_self[] = { "-----BEGIN CERTIFICATE-----" "MIIBszCCAVmgAwIBAgIJAILNujb37gH2MAoGCCqGSM49BAMCMFYxKTAnBgNVBAsM" "IDdhNDhhYTI2YmM0MzQyZjZhNjYyMDBmNzdhODlkZDAyMSkwJwYDVQQDDCA3YTQ4" "YWEyNmJjNDM0MmY2YTY2MjAwZjc3YTg5ZGQwMjAeFw0xNTAyMjYyMTUxMjNaFw0x" "NjAyMjYyMTUxMjNaMFYxKTAnBgNVBAsMIDdhNDhhYTI2YmM0MzQyZjZhNjYyMDBm" "NzdhODlkZDAyMSkwJwYDVQQDDCA3YTQ4YWEyNmJjNDM0MmY2YTY2MjAwZjc3YTg5" "ZGQwMjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGEkAUATvOE4uYmt/10vkTcU" "SA0C+YqHQ+fjzRASOHWIXBvpPiKgHcINtNFQsyX92L2tMT2Kn53zu+3S6UAwy6yj" "EDAOMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgKit5yeq1uxTvdFmW" "LDeoxerqC1VqBrmyEvbp4oJfamsCIQDvMTmulW/Br/gY7GOP9H/4/BIEoR7UeAYS" "4xLyu+7OEA==" "-----END CERTIFICATE-----" }; static const char pem_prv_1[] = { "-----BEGIN EC PRIVATE KEY-----" "MHcCAQEEIAqN6AtyOAPxY5k7eFNXAwzkbsGMl4uqvPrYkIj0LNZBoAoGCCqGSM49" "AwEHoUQDQgAEvnRd4fX9opwgXX4Em2UiCMsBbfaqhB1U5PJCDZacz9HumDEzYdrS" "MymSxR34lL0GJVgEECvBTvpaHP2bpTIl6g==" "-----END EC PRIVATE KEY-----" }; static const char pem_x509_1[] = { "-----BEGIN CERTIFICATE-----" "MIIBtDCCAVmgAwIBAgIJAMlyFqk69v+OMAoGCCqGSM49BAMCMFYxKTAnBgNVBAsM" "IDdhNDhhYTI2YmM0MzQyZjZhNjYyMDBmNzdhODlkZDAyMSkwJwYDVQQDDCA3YTQ4" "YWEyNmJjNDM0MmY2YTY2MjAwZjc3YTg5ZGQwMjAeFw0xNTAyMjYyMTUxMjVaFw0x" "NjAyMjYyMTUxMjVaMFYxKTAnBgNVBAsMIDZkODVjMjkyMjYxM2IzNmUyZWVlZjUy" "NzgwNDJjYzU2MSkwJwYDVQQDDCA2ZDg1YzI5MjI2MTNiMzZlMmVlZWY1Mjc4MDQy" "Y2M1NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL50XeH1/aKcIF1+BJtlIgjL" "AW32qoQdVOTyQg2WnM/R7pgxM2Ha0jMpksUd+JS9BiVYBBArwU76Whz9m6UyJeqj" "EDAOMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAKfmglMgl67L5ALF" "Z63haubkItTMACY1k4ROC2q7cnVmAiEArvAmcVInOq/U5C1y2XrvJQnAdwSl/Ogr" "IizUeK0oI5c=" "-----END CERTIFICATE-----" }; static const char pem_prv_2[] = { "-----BEGIN EC PRIVATE KEY-----" "MHcCAQEEIIHvXKVlMAUG8NOeJ9SqQg3Op5kXIBRvoHowaLtySxhToAoGCCqGSM49" "AwEHoUQDQgAE79HKpErGIZVLzKvc1gPoCkKQtuc1JP9N9AGXGrvQWOQOSwzg3E82" "4DqEWkvOFEP1GHeagPFIINl6IUvcgISwLA==" "-----END EC PRIVATE KEY-----" }; static const char pem_x509_2[] = { "-----BEGIN CERTIFICATE-----" "MIIBWzCCAQCgAwIBAgIJAN1+gCpX2RyfMAoGCCqGSM49BAMCMCsxKTAnBgNVBAMM" "IGE2NzgyNWUwZjZlYzZmZDlhMWVlYWJkNWMyNTg5Y2Q1MB4XDTE1MDMwMjE0NDYx" "N1oXDTE2MDMwMTE0NDYxN1owKzEpMCcGA1UEAwwgYTY3ODI1ZTBmNmVjNmZkOWEx" "ZWVhYmQ1YzI1ODljZDUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATv0cqkSsYh" "lUvMq9zWA+gKQpC25zUk/030AZcau9BY5A5LDODcTzbgOoRaS84UQ/UYd5qA8Ugg" "2XohS9yAhLAsow0wCzAJBgNVHRMEAjAAMAoGCCqGSM49BAMCA0kAMEYCIQCLChlN" "IoHhS7jbhbV96uyIthGEyJ62YvM+438VFMEHTwIhAOpxvefi7VFHQXhWpNE5KmG5" "zhXQwrpn6D0rMylIZ5/v" "-----END CERTIFICATE-----" }; static const char pem_prv_3[] = { "-----BEGIN EC PRIVATE KEY-----" "MDECAQEEIICSqj3zTadctmGnwyC/SXLioO39pB1MlCbNEX04hjeioAoGCCqGSM49" "AwEH" "-----END EC PRIVATE KEY-----" }; static const char pem_x509_3[] = { "-----BEGIN CERTIFICATE-----" "MIIBWjCCAQGgAwIBAgIHMTAxMDEwMTAKBggqhkjOPQQDAjArMSkwJwYDVQQDDCAw" "ZTE5YWZhNzlhMjliMjMwNDcyMGJkNGY2ZDVlMWIxOTAeFw0xNTAyMjYyMTU1MjVa" "Fw0xNjAyMjYyMTU1MjVaMCsxKTAnBgNVBAMMIDZhYWM5MjQwNDNjYjc5NmQ2ZGIy" "NmRlYmRkMGM5OWJkMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEP/HbYga30Afm" "0fB6g7KaB5Vr5CDyEkgmlif/PTsgwM2KKCMiAfcfto0+L1N0kvyAUgff6sLtTHU3" "IdHzyBmKP6MQMA4wDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiAZmNVA" "m/H5EtJl/O9x0P4zt/UdrqiPg+gA+wm0yRY6KgIgetWANAE2otcrsj3ARZTY/aTI" "0GOQizWlQm8mpKaQ3uE=" "-----END CERTIFICATE-----" }; static const char pem_x509_4[] = { "-----BEGIN CERTIFICATE-----" "MIIBOjCB4aADAgECAgECMAoGCCqGSM49BAMCMCIxDjAMBgNVBAsMBUFkbWluMRAw" "DgYDVQQDDAdNYW5hZ2VyMB4XDTE1MDQyNzAyMTk1OFoXDTE2MDQyNjAyMTk1OFow" "HTEOMAwGA1UECwwFTWVkaWExCzAJBgNVBAMMAlRWMFkwEwYHKoZIzj0CAQYIKoZI" "zj0DAQcDQgAEXhpO6l5w9lARVZklVvYCnqvUnK1sQg+SFKERW9IOae0yUQJAoV5B" "L4YkaN3zQirDZzZefX4gIxIYXeLNLwYr8qMNMAswCQYDVR0TBAIwADAKBggqhkjO" "PQQDAgNIADBFAiA7aDL+XYAmfosrwINWWtwGcFDm1kSb7mw3N7tnXFwBHAIhAKeW" "LfgmobFgXu++LwVFg02BSLuL0IrFAysDcF8w9lxj" "-----END CERTIFICATE-----" }; static const char pem_x509_5[] = { "-----BEGIN CERTIFICATE-----" "MIIBPTCB5KADAgECAgECMAoGCCqGSM49BAMCMCIxDjAMBgNVBAsMBUFkbWluMRAw" "DgYDVQQDDAdNYW5hZ2VyMB4XDTE1MDQyNzAyMjIyOFoXDTE2MDQyNjAyMjIyOFow" "HTEOMAwGA1UECwwFTWVkaWExCzAJBgNVBAMMAlRWMFkwEwYHKoZIzj0CAQYIKoZI" "zj0DAQcDQgAEXhpO6l5w9lARVZklVvYCnqvUnK1sQg+SFKERW9IOae0yUQJAoV5B" "L4YkaN3zQirDZzZefX4gIxIYXeLNLwYr8qMQMA4wDAYDVR0TBAUwAwEB/zAKBggq" "hkjOPQQDAgNIADBFAiEAoT1gFCwUONyeLaiyv4LZFxqMsCnGOYlDejfPBjfdlccC" "ICgI/7pny9QjuqKcX+FKUwqnq6IsOIaodvKNo3GlPe5O" "-----END CERTIFICATE-----" }; static const char pem_x509_6[] = { "-----BEGIN CERTIFICATE-----" "MIIBPjCB5KADAgECAgECMAoGCCqGSM49BAMCMCIxDjAMBgNVBAsMBUFkbWluMRAw" "DgYDVQQDDAdNYW5hZ2VyMB4XDTE1MDQyNzAyMjM1NFoXDTE2MDQyNjAyMjM1NFow" "HTEOMAwGA1UECwwFTWVkaWExCzAJBgNVBAMMAlRWMFkwEwYHKoZIzj0CAQYIKoZI" "zj0DAQcDQgAEXhpO6l5w9lARVZklVvYCnqvUnK1sQg+SFKERW9IOae0yUQJAoV5B" "L4YkaN3zQirDZzZefX4gIxIYXeLNLwYr8qMQMA4wDAYDVR0TBAUwAwIBATAKBggq" "hkjOPQQDAgNJADBGAiEA4Laxe8SunKOjqohe5lFzSUQh3m9O2OdzV3ZKKcclMtEC" "IQCOVhnC7/PLFGXCY1uaJ/4cJvlLtUmLkMZVeYJRN3NSRA==" "-----END CERTIFICATE-----" }; static const char pem_x509_7[] = { "-----BEGIN CERTIFICATE-----" "MIIBQjCB6qADAgECAgECMAoGCCqGSM49BAMCMCIxDjAMBgNVBAsMBUFkbWluMRAw" "DgYDVQQDDAdNYW5hZ2VyMB4XDTE1MDQyNzAyMjQwMloXDTE2MDQyNjAyMjQwMlow" "HTEOMAwGA1UECwwFTWVkaWExCzAJBgNVBAMMAlRWMFkwEwYHKoZIzj0CAQYIKoZI" "zj0DAQcDQgAEXhpO6l5w9lARVZklVvYCnqvUnK1sQg+SFKERW9IOae0yUQJAoV5B" "L4YkaN3zQirDZzZefX4gIxIYXeLNLwYr8qMWMBQwEgYDVR0TAQH/BAgwBgEB/wIB" "ATAKBggqhkjOPQQDAgNHADBEAiB4qUTMHJZMHtSvi9AKPRvG9JwkgFewBYpxvQad" "VbinnAIgWw4KgERCMAqSUbCVsQXGff87OPHrL1M1xsHpomG8Qhs=" "-----END CERTIFICATE-----" }; static const char pem_x509_8[] = { "-----BEGIN CERTIFICATE-----" "MIIBPjCB5KADAgECAgECMAoGCCqGSM49BAMCMCIxDjAMBgNVBAsMBUFkbWluMRAw" "DgYDVQQDDAdNYW5hZ2VyMB4XDTE1MDQyNzAyMjQyMVoXDTE2MDQyNjAyMjQyMVow" "HTEOMAwGA1UECwwFTWVkaWExCzAJBgNVBAMMAlRWMFkwEwYHKoZIzj0CAQYIKoZI" "zj0DAQcDQgAEXhpO6l5w9lARVZklVvYCnqvUnK1sQg+SFKERW9IOae0yUQJAoV5B" "L4YkaN3zQirDZzZefX4gIxIYXeLNLwYr8qMQMA4wDAYDVR0TAQH/BAIwADAKBggq" "hkjOPQQDAgNJADBGAiEA7lU0PJ5/TZgTj8EKiMUGIGsafxqZZVpjeeuC9yGskSwC" "IQCTgDOBsgKA74gf0pKipF7fA0+UDLpwMLQlw8P6YVidHQ==" "-----END CERTIFICATE-----" }; static const char pem_x509_9[] = { "-----BEGIN CERTIFICATE-----" "MIIBiDCCAS+gAwIBAgIBATAKBggqhkjOPQQDAjAiMQ4wDAYDVQQLDAVBZG1pbjEQ" "MA4GA1UEAwwHTWFuYWdlcjAeFw0xNTA0MjcwMjM1MDFaFw0xNjA0MjYwMjM1MDFa" "MCIxDjAMBgNVBAsMBUFkbWluMRAwDgYDVQQDDAdNYW5hZ2VyMFkwEwYHKoZIzj0C" "AQYIKoZIzj0DAQcDQgAEPEPcAowvgJcSAVbZgJp1TjZ84VHtgITq/Ex3ayLMGrJ1" "aqA6+s9eOEYNGqvrZfQHRFcaM7m5MmRDn4J8PT+1oaNWMFQwDAYDVR0TAQH/BAIw" "ADAgBgNVHQ4BAf8EFgQU1Fg51CWrJVEvK0CmpqxH5cugqlgwIgYDVR0jAQH/BBgw" "FoAU1Fg51CWrJVEvK0CmpqxH5cugqlgwCgYIKoZIzj0EAwIDRwAwRAIgXzg72DWx" "EwY6xH6iVLvuqGW9cgBsgp/tPzkPwsmg0kcCIETALRqB6+bcIEgPLa6EG3/7rC44" "ZWyKXae3oh5W2t4k" "-----END CERTIFICATE-----" }; // Identity certificate static const char pem_x509_10[] = { "-----BEGIN CERTIFICATE-----" "MIIB8DCCAZagAwIBAgIBATAKBggqhkjOPQQDAjANMQswCQYDVQQDDAJjbjAeFw0x" "NTA1MjgwMDM3NTNaFw0xNjA1MjcwMDM3NTNaMA0xCzAJBgNVBAMMAmNuMFkwEwYH" "KoZIzj0CAQYIKoZIzj0DAQcDQgAEPEPcAowvgJcSAVbZgJp1TjZ84VHtgITq/Ex3" "ayLMGrJ1aqA6+s9eOEYNGqvrZfQHRFcaM7m5MmRDn4J8PT+1oaOB5jCB4zAMBgNV" "HRMBAf8EAjAAMCwGA1UdDgEB/wQiBCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAADAuBgNVHSMBAf8EJDAigCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAADARBgorBgEEAYLefAEBBAMCAQEwIwYDVR0RAQH/BBkwF6AVBgorBgEE" "AYLefAEEoAcEBWFsaWFzMD0GCisGAQQBgt58AQIELzAtBglghkgBZQMEAgEEIAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAoGCCqGSM49BAMCA0gAMEUC" "IQDyo+zR+1Ba7Nud8X9I53ZF52tNn+ou4zSo9qIiEKmI5wIgTUO3+3HE0NN5uy8c" "aBmsqvqSzEvN/RQqsKXIyRUfQY8=" "-----END CERTIFICATE-----" }; // Security group certificate static const char pem_x509_11[] = { "-----BEGIN CERTIFICATE-----" "MIIBuzCCAWKgAwIBAgIBATAKBggqhkjOPQQDAjANMQswCQYDVQQDDAJjbjAeFw0x" "NTA1MjcwNDAzMzhaFw0xNjA1MjYwNDAzMzhaMA0xCzAJBgNVBAMMAmNuMFkwEwYH" "KoZIzj0CAQYIKoZIzj0DAQcDQgAEPEPcAowvgJcSAVbZgJp1TjZ84VHtgITq/Ex3" "ayLMGrJ1aqA6+s9eOEYNGqvrZfQHRFcaM7m5MmRDn4J8PT+1oaOBsjCBrzAMBgNV" "HRMBAf8EAjAAMCwGA1UdDgEB/wQiBCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAADAuBgNVHSMBAf8EJDAigCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAADARBgorBgEEAYLefAEBBAMCAQIwLgYDVR0RAQH/BCQwIqAgBgorBgEE" "AYLefAEDoBIEEAAAAAAAAAAAAAAAAAAAAAAwCgYIKoZIzj0EAwIDRwAwRAIgaGVf" "HMKMdNPoBegHdikjI+tpNRWeh1rwg4xzKBnftWQCIFA6AK0Zm4cJfCvMw+Dx/rXa" "xqmf9RLcTk6jT96b0wGC" "-----END CERTIFICATE-----" }; static const char pem_prv_12[] = { "-----BEGIN EC PRIVATE KEY-----" "MHcCAQEEINiXjrhr3NNV+NYcS9ZHuWGjOYVmK1l4S03QV+vn1mIIoAoGCCqGSM49" "AwEHoUQDQgAEZFf5jgxNc4wJ2qYcuBHcrWsxOXhMgtvyRMfH2ryM6aQPlioY/dnc" "XbWnsfO2FyE8wsdKLPeENJy+8g6p+RPEig==" "-----END EC PRIVATE KEY-----" }; static const char pem_x509_12[] = { "-----BEGIN CERTIFICATE-----" "MIIB2jCCAYGgAwIBAgIBAjAKBggqhkjOPQQDAjANMQswCQYDVQQDDAJjbjAeFw0x" "NTA3MzEwNjUwMDhaFw0xNjA3MzAwNjUwMDhaMA0xCzAJBgNVBAMMAnR2MFkwEwYH" "KoZIzj0CAQYIKoZIzj0DAQcDQgAEZFf5jgxNc4wJ2qYcuBHcrWsxOXhMgtvyRMfH" "2ryM6aQPlioY/dncXbWnsfO2FyE8wsdKLPeENJy+8g6p+RPEiqOB0TCBzjAJBgNV" "HRMEAjAAMB0GA1UdDgQWBBQWI2DkX/AhybZBGOUP+LEJcNz2yjAfBgNVHSMEGDAW" "gBSqnBbXUz17dBCqTejIv0HoSS/xiTArBgNVHREEJDAioCAGCisGAQQBgt58AQSg" "EgQQAAAAAAAAAAAAAAAAAAAAADAVBgNVHSUEDjAMBgorBgEEAYLefAEBMD0GCisG" "AQQBgt58AQIELzAtBglghkgBZQMEAgEEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAMAoGCCqGSM49BAMCA0cAMEQCIDjCZb6ALBxw+lc7i7oHDNwOQCIU" "BjYqtR4kr4LqdQktAiAfu5+EVXC1hDgK9bc91dy1cv21Pn9cL4FAVFX3xGm4hA==" "-----END CERTIFICATE-----" "" "-----BEGIN CERTIFICATE-----" "MIIBezCCASKgAwIBAgIBATAKBggqhkjOPQQDAjANMQswCQYDVQQDDAJjbjAeFw0x" "NTA3MzEwNjQ3NDlaFw0xNjA3MzAwNjQ3NDlaMA0xCzAJBgNVBAMMAmNuMFkwEwYH" "KoZIzj0CAQYIKoZIzj0DAQcDQgAE2+TD0C9O6nScng1lUl+s6pcrezUBySXVKadH" "7P8vAdvnnGtjSxSLdy/G1XDG/81cWf+W/sZcC+qCSbQg+EW/QqNzMHEwDAYDVR0T" "BAUwAwEB/zAdBgNVHQ4EFgQUqpwW11M9e3QQqk3oyL9B6Ekv8YkwHwYDVR0jBBgw" "FoAUqpwW11M9e3QQqk3oyL9B6Ekv8YkwIQYDVR0lBBowGAYKKwYBBAGC3nwBAQYK" "KwYBBAGC3nwBBTAKBggqhkjOPQQDAgNHADBEAiBVSPvp2t5Uct+Yrj43uC/eyKTb" "BQPY5bGS2yt8iReZ+AIgacrFYDzNnbUu39rtjn85kn3zWasFXmsa8R+mTmlJTFo=" "-----END CERTIFICATE-----" }; #define ASN_OCTETS 0x04 #define ASN_UTF8 0x0C void PrintElement(const char* tag, DER_Element* der, uint8_t type) { size_t i; if (0 == der->size) { return; } AJ_AlwaysPrintf(("%s: ", tag)); for (i = 0; i < der->size; i++) { switch (type) { case ASN_OCTETS: AJ_AlwaysPrintf(("%02X", der->data[i])); break; case ASN_UTF8: AJ_AlwaysPrintf(("%c", (char) der->data[i])); break; } } AJ_AlwaysPrintf(("\n")); } void PrintCertificate(X509Certificate* certificate) { AJ_AlwaysPrintf(("Certificate\n")); PrintElement(" Serial ", &certificate->tbs.serial, ASN_OCTETS); PrintElement(" Issuer OU", &certificate->tbs.issuer.ou, ASN_UTF8); PrintElement(" Issuer CN", &certificate->tbs.issuer.cn, ASN_UTF8); PrintElement(" Subject OU", &certificate->tbs.subject.ou, ASN_UTF8); PrintElement(" Subject CN", &certificate->tbs.subject.cn, ASN_UTF8); AJ_AlwaysPrintf((" Extensions\n")); PrintElement(" SKI ", &certificate->tbs.extensions.ski, ASN_OCTETS); PrintElement(" AKI ", &certificate->tbs.extensions.aki, ASN_OCTETS); PrintElement(" Alias ", &certificate->tbs.extensions.alias, ASN_UTF8); PrintElement(" Group ", &certificate->tbs.extensions.group, ASN_OCTETS); PrintElement(" Digest", &certificate->tbs.extensions.digest, ASN_OCTETS); } AJ_Status ParseCertificate(X509Certificate* certificate, const char* pem, uint8_t verify) { AJ_Status status = AJ_OK; DER_Element der; status = AJ_X509DecodeCertificatePEM(certificate, pem); if (AJ_OK != status) { AJ_Printf("Parse: %s\n", AJ_StatusText(status)); return status; } der.size = certificate->der.size; der.data = certificate->der.data; status = AJ_X509DecodeCertificateDER(certificate, &der); AJ_Printf("Parse: %s\n", AJ_StatusText(status)); if (AJ_OK != status) { return status; } PrintCertificate(certificate); if (verify) { status = AJ_X509SelfVerify(certificate); AJ_Printf("Verify: %s\n", AJ_StatusText(status)); } if (certificate->der.data) { AJ_Free(certificate->der.data); } return status; } int AJ_Main(int ac, char** av) { AJ_Status status = AJ_OK; X509Certificate certificate; AJ_ECCPublicKey pub; AJ_ECCPrivateKey prv; AJ_ECCSignature sig; X509CertificateChain* head; X509CertificateChain* chain; uint8_t buffer[128]; status = AJ_GenerateECCKeyPair(&pub, &prv); AJ_ASSERT(AJ_OK == status); status = AJ_ECDSASign(buffer, sizeof (buffer), &prv, &sig); AJ_ASSERT(AJ_OK == status); status = AJ_ECDSAVerify(buffer, sizeof (buffer), &sig, &pub); AJ_ASSERT(AJ_OK == status); status = ParseCertificate(&certificate, pem_x509_self, 1); status = ParseCertificate(&certificate, pem_x509_1, 0); status = AJ_DecodePrivateKeyPEM(&prv, pem_prv_1); AJ_ASSERT(AJ_OK == status); status = ParseCertificate(&certificate, pem_x509_2, 0); status = AJ_DecodePrivateKeyPEM(&prv, pem_prv_2); AJ_ASSERT(AJ_OK == status); status = ParseCertificate(&certificate, pem_x509_3, 0); status = AJ_DecodePrivateKeyPEM(&prv, pem_prv_3); AJ_ASSERT(AJ_OK == status); status = ParseCertificate(&certificate, pem_x509_4, 0); status = ParseCertificate(&certificate, pem_x509_5, 0); status = ParseCertificate(&certificate, pem_x509_6, 0); status = ParseCertificate(&certificate, pem_x509_7, 0); status = ParseCertificate(&certificate, pem_x509_8, 0); status = ParseCertificate(&certificate, pem_x509_9, 1); status = ParseCertificate(&certificate, pem_x509_10, 1); status = ParseCertificate(&certificate, pem_x509_11, 1); chain = AJ_X509DecodeCertificateChainPEM(pem_x509_12); head = chain; while (head) { PrintCertificate(&head->certificate); head = head->next; } AJ_X509FreeDecodedCertificateChain(chain); return 0; } #ifdef AJ_MAIN int main(int ac, char** av) { return AJ_Main(ac, av); } #endif ajtcl-16.04/test/clientlite.c000066400000000000000000000526411271074662300161200ustar00rootroot00000000000000/* * clientlite.c */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE CLIENTLITE #ifndef TEST_DISABLE_SECURITY #define SECURE_INTERFACE #define SECURE_OBJECT #endif #include #include #include #include #include #include #include #include uint8_t dbgCLIENTLITE = 1; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; /* * The app should authenticate the peer if one or more interfaces are secure * To define a secure interface, prepend '$' before the interface name, eg., "$org.alljoyn.alljoyn_test" */ #ifdef SECURE_INTERFACE static const char testInterfaceName[] = "$org.alljoyn.alljoyn_test"; static const char testValuesInterfaceName[] = "$org.alljoyn.alljoyn_test.values"; #else static const char testInterfaceName[] = "org.alljoyn.alljoyn_test"; static const char testValuesInterfaceName[] = "org.alljoyn.alljoyn_test.values"; #endif #if defined(ANNOUNCE_BASED_DISCOVERY) || defined(NGNS) static const char* testInterfaceNames[] = { testInterfaceName, testValuesInterfaceName, NULL }; #else static const char testServiceName[] = "org.alljoyn.svclite"; #endif /* * Buffer to hold the peer's full service name or unique name. */ #if defined(ANNOUNCE_BASED_DISCOVERY) || defined(NGNS) static char g_peerServiceName[AJ_MAX_NAME_SIZE + 1]; #else static char g_peerServiceName[AJ_MAX_SERVICE_NAME_SIZE]; #endif static const uint16_t testServicePort = 24; static const char* const testInterface[] = { testInterfaceName, "?my_ping inStrs", NULL }; static const char* const testValuesInterface[] = { testValuesInterfaceName, "@int_val=i", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { AJ_PropertiesIface, testInterface, testValuesInterface, NULL }; static const char testObj[] = "/org/alljoyn/alljoyn_test"; /** * Objects implemented by the application */ #ifdef SECURE_OBJECT static AJ_Object ProxyObjects[] = { { "/org/alljoyn/alljoyn_test", testInterfaces, AJ_OBJ_FLAG_SECURE }, { NULL } }; #else static AJ_Object ProxyObjects[] = { { "/org/alljoyn/alljoyn_test", testInterfaces }, { NULL } }; #endif #define PRX_GET_PROP AJ_PRX_MESSAGE_ID(0, 0, AJ_PROP_GET) #define PRX_SET_PROP AJ_PRX_MESSAGE_ID(0, 0, AJ_PROP_SET) #define PRX_MY_PING AJ_PRX_MESSAGE_ID(0, 1, 0) #define PRX_GET_INT AJ_PRX_PROPERTY_ID(0, 2, 0) #define PRX_SET_INT AJ_PRX_PROPERTY_ID(0, 2, 0) #define CONNECT_TIMEOUT (1000 * 200) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (1000 * 10) #define PING_TIMEOUT (1000 * 10) /** * Peer discovery */ #ifdef ANNOUNCE_BASED_DISCOVERY static void handleMandatoryProps(const char* peerName, const char* appId, const char* appName, const char* deviceId, const char* deviceName, const char* manufacturer, const char* modelNumber, const char* defaultLanguage) { AJ_AlwaysPrintf(("Mandatory Properties for %s\n", peerName)); AJ_AlwaysPrintf(("Mandatory property: AppId=\"%s\"\n", (appId == NULL || appId[0] == '\0') ? "N/A" : appId)); AJ_AlwaysPrintf(("Mandatory property: AppName=\"%s\"\n", (appName == NULL || appName[0] == '\0') ? "N/A" : appName)); AJ_AlwaysPrintf(("Mandatory property: DeviceId=\"%s\"\n", (deviceId == NULL || deviceId[0] == '\0') ? "N/A" : deviceId)); AJ_AlwaysPrintf(("Mandatory property: DeviceName=\"%s\"\n", (deviceName == NULL || deviceName[0] == '\0') ? "N/A" : deviceName)); AJ_AlwaysPrintf(("Mandatory property: Manufacturer=\"%s\"\n", (manufacturer == NULL || manufacturer[0] == '\0') ? "N/A" : manufacturer)); AJ_AlwaysPrintf(("Mandatory property: ModelNumber=\"%s\"\n", (modelNumber == NULL || modelNumber[0] == '\0') ? "N/A" : modelNumber)); AJ_AlwaysPrintf(("Mandatory property: DefaultLanguage=\"%s\"\n", (defaultLanguage == NULL || defaultLanguage[0] == '\0') ? "N/A" : defaultLanguage)); } static void handleOptionalProperty(const char* peerName, const char* key, const char* sig, const AJ_Arg* value) { if (strcmp(sig, "s") == 0) { AJ_AlwaysPrintf(("Optional Prop: %s=\"%s\"\n", key, value->val.v_string)); } else { AJ_AlwaysPrintf(("Optional Prop: %s=[Not A String]\n", key)); } } static uint8_t FoundNewTestPeer(uint16_t version, uint16_t port, const char* peerName, const char* objPath) { AJ_AlwaysPrintf(("FoundNewTestPeer: version:%u port:%u name:%s path=%s\n", version, port, peerName, objPath)); if ((strcmp(objPath, testObj) == 0) && (port == testServicePort)) { if (g_peerServiceName[0] == '\0') { strncpy(g_peerServiceName, peerName, AJ_MAX_NAME_SIZE); g_peerServiceName[AJ_MAX_NAME_SIZE] = '\0'; } } return FALSE; } static uint8_t AcceptNewTestPeer(const char* peerName) { AJ_AlwaysPrintf(("AcceptNewTestPeer: name:%s\n", peerName)); if ((strcmp(g_peerServiceName, peerName) == 0)) { return TRUE; } return FALSE; } static const char* testIFaces[] = { "org.alljoyn.alljoyn_test", "org.alljoyn.alljoyn_test.values" }; static AJ_AboutPeerDescription pingServicePeer = { testIFaces, (uint16_t)(sizeof(testIFaces) / sizeof(*testIFaces)), FoundNewTestPeer, AcceptNewTestPeer, NULL, handleMandatoryProps, handleOptionalProperty }; #endif /* * Let the application do some work */ static AJ_Status SendPing(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName, unsigned int num); static int32_t g_iterCount = 0; static void AppDoWork(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName) { AJ_AlwaysPrintf(("AppDoWork\n")); /* * This function is called if there are no messages to unmarshal * Alternate between alljoyn_test ping and Bus ping */ g_iterCount = g_iterCount + 1; if (g_iterCount & 1) { SendPing(bus, sessionId, serviceName, g_iterCount); } else { AJ_BusPing(bus, serviceName, PING_TIMEOUT); } } #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "123456"; #endif // Copied from alljoyn/alljoyn_core/unit_test/AuthListenerECDHETest.cc with // newlines removed static const char pem_prv[] = { "-----BEGIN EC PRIVATE KEY-----" "MHcCAQEEIBiLw29bf669g7MxMbXK2u8Lp5//w7o4OiVGidJdKAezoAoGCCqGSM49" "AwEHoUQDQgAE+A0C9YTghZ1vG7198SrUHxFlhtbSsmhbwZ3N5aQRwzFXWcCCm38k" "OzJEmS+venmF1o/FV0W80Mcok9CWlV2T6A==" "-----END EC PRIVATE KEY-----" }; static const char pem_x509[] = { "-----BEGIN CERTIFICATE-----" "MIIBYTCCAQigAwIBAgIJAOVrhhJOre/7MAoGCCqGSM49BAMCMCQxIjAgBgNVBAoM" "GUFsbEpveW5UZXN0U2VsZlNpZ25lZE5hbWUwHhcNMTUwODI0MjAxODQ1WhcNMjkw" "NTAyMjAxODQ1WjAgMR4wHAYDVQQKDBVBbGxKb3luVGVzdENsaWVudE5hbWUwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAAT4DQL1hOCFnW8bvX3xKtQfEWWG1tKyaFvB" "nc3lpBHDMVdZwIKbfyQ7MkSZL696eYXWj8VXRbzQxyiT0JaVXZPooycwJTAVBgNV" "HSUEDjAMBgorBgEEAYLefAEBMAwGA1UdEwEB/wQCMAAwCgYIKoZIzj0EAwIDRwAw" "RAIgevLUXoJBgUr6nVepBHQiv85CGuxu00V4uoARbH6qu1wCIA54iDRh6wit1zbP" "kqkBC015LjxucTf3Y7lNGhXuZRsL" "-----END CERTIFICATE-----" "-----BEGIN CERTIFICATE-----" "MIIBdTCCARugAwIBAgIJAJTFhmdwDWsvMAoGCCqGSM49BAMCMCQxIjAgBgNVBAoM" "GUFsbEpveW5UZXN0U2VsZlNpZ25lZE5hbWUwHhcNMTUwODI0MjAxODQ1WhcNMjkw" "NTAyMjAxODQ1WjAkMSIwIAYDVQQKDBlBbGxKb3luVGVzdFNlbGZTaWduZWROYW1l" "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEF0nZmkzuK/2CVf7udexLZnlEB5D+" "DBsx3POtsRyZWm2QiI1untDTp0uYp51tkP6wI6Gi5gWxB+86lEIPg4ZpTaM2MDQw" "IQYDVR0lBBowGAYKKwYBBAGC3nwBAQYKKwYBBAGC3nwBBTAPBgNVHRMBAf8EBTAD" "AQH/MAoGCCqGSM49BAMCA0gAMEUCIQDPQ1VRvdBhhneU5e7OvIFHK3d9XPZA7Fw6" "VyeW/P5wIAIgD969ks/z9vQ1yCaVaxmVz63toC1ggp4AnBXqbDy8O+4=" "-----END CERTIFICATE-----" }; static X509CertificateChain* chain = NULL; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; X509CertificateChain* node; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_ECDSA: switch (command) { case AJ_CRED_PRV_KEY: AJ_ASSERT(sizeof (AJ_ECCPrivateKey) == cred->len); status = AJ_DecodePrivateKeyPEM((AJ_ECCPrivateKey*) cred->data, pem_prv); cred->expiration = keyexpiration; break; case AJ_CRED_CERT_CHAIN: switch (cred->direction) { case AJ_CRED_REQUEST: // Free previous certificate chain AJ_X509FreeDecodedCertificateChain(chain); chain = AJ_X509DecodeCertificateChainPEM(pem_x509); if (NULL == chain) { return AJ_ERR_INVALID; } cred->data = (uint8_t*) chain; cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_RESPONSE: node = (X509CertificateChain*) cred->data; while (node) { AJ_DumpBytes("CERTIFICATE", node->certificate.der.data, node->certificate.der.size); node = node->next; } status = AJ_OK; break; } break; } break; default: break; } return status; } #endif static const char PingString[] = "Ping String"; AJ_Status SendPing(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName, unsigned int num) { AJ_Status status; AJ_Message msg; /* * Since the object path on the proxy object entry was not set in the proxy object table above * it must be set before marshalling the method call. */ status = AJ_SetProxyObjectPath(ProxyObjects, PRX_MY_PING, testObj); if (status == AJ_OK) { status = AJ_MarshalMethodCall(bus, &msg, PRX_MY_PING, serviceName, sessionId, 0, METHOD_TIMEOUT); } if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", PingString); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } else { AJ_AlwaysPrintf(("SendPing %s\n", AJ_StatusText(status))); } return status; } AJ_Status SendGetProp(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, PRX_GET_PROP, serviceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalPropertyArgs(&msg, PRX_GET_INT); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } else { AJ_AlwaysPrintf(("SendGetProp %s\n", AJ_StatusText(status))); } return status; } AJ_Status SendSetProp(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName, int val) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, PRX_SET_PROP, serviceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalPropertyArgs(&msg, PRX_SET_INT); } if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "i", val); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } else { AJ_AlwaysPrintf(("SendSetProp %s\n", AJ_StatusText(status))); } return status; } #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } #endif #ifdef MAIN_ALLOWS_ARGS int AJ_Main(int ac, char** av) #else int AJ_Main() #endif { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; AJ_Status authStatus = AJ_ERR_NULL; #ifdef SECURE_INTERFACE uint32_t suites[AJ_AUTH_SUITES_NUM]; size_t numsuites = 0; uint8_t clearkeys = FALSE; #endif #ifdef MAIN_ALLOWS_ARGS #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) ac--; av++; /* * Enable authentication mechanism by command line */ if (ac) { if (0 == strncmp(*av, "-ek", 3)) { clearkeys = TRUE; ac--; av++; } else if (0 == strncmp(*av, "-e", 2)) { ac--; av++; } if (!ac) { AJ_AlwaysPrintf(("-e(k) requires an auth mechanism.\n")); return 1; } while (ac) { if (0 == strncmp(*av, "ECDHE_ECDSA", 11)) { suites[numsuites++] = AUTH_SUITE_ECDHE_ECDSA; } else if (0 == strncmp(*av, "ECDHE_PSK", 9)) { suites[numsuites++] = AUTH_SUITE_ECDHE_PSK; } else if (0 == strncmp(*av, "ECDHE_NULL", 10)) { suites[numsuites++] = AUTH_SUITE_ECDHE_NULL; } ac--; av++; } } #endif #else suites[numsuites++] = AUTH_SUITE_ECDHE_ECDSA; clearkeys = TRUE; #endif #ifdef SECURE_INTERFACE if (numsuites == 0) { /* Default security to ECDHE_NULL, if not explicit elsewhere */ suites[numsuites++] = AUTH_SUITE_ECDHE_NULL; } #endif /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(ProxyObjects); AJ_RegisterObjects(NULL, ProxyObjects); while (TRUE) { AJ_Message msg; if (!connected) { #if defined (ANNOUNCE_BASED_DISCOVERY) status = AJ_StartClientByPeerDescription(&bus, NULL, CONNECT_TIMEOUT, FALSE, &pingServicePeer, testServicePort, &sessionId, g_peerServiceName, NULL); #elif defined (NGNS) status = AJ_StartClientByInterface(&bus, NULL, CONNECT_TIMEOUT, FALSE, testInterfaceNames, &sessionId, g_peerServiceName, NULL); #else status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, testServiceName, testServicePort, &sessionId, NULL, g_peerServiceName); #endif if (status == AJ_OK) { AJ_AlwaysPrintf(("StartClient returned %d, sessionId=%u, serviceName=%s\n", status, sessionId, g_peerServiceName)); AJ_AlwaysPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(&bus))); connected = TRUE; #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) AJ_BusEnableSecurity(&bus, suites, numsuites); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); if (clearkeys) { AJ_ClearCredentials(AJ_GENERIC_MASTER_SECRET | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_THUMBPRINT | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_KEYS | AJ_CRED_TYPE_GENERIC); } status = AJ_BusAuthenticatePeer(&bus, g_peerServiceName, AuthCallback, &authStatus); if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_BusAuthenticatePeer returned %d\n", status)); } #else authStatus = AJ_OK; #endif } else { AJ_AlwaysPrintf(("StartClient returned %d\n", status)); break; } } AJ_AlwaysPrintf(("Auth status %d and AllJoyn status %d\n", authStatus, status)); if (status == AJ_ERR_RESOURCES) { AJ_InfoPrintf(("Peer is busy, disconnecting and retrying auth...\n")); AJ_Disconnect(&bus); connected = FALSE; continue; } if (authStatus != AJ_ERR_NULL) { if (authStatus != AJ_OK) { AJ_Disconnect(&bus); break; } authStatus = AJ_ERR_NULL; AJ_BusSetLinkTimeout(&bus, sessionId, 10 * 1000); } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(&bus, sessionId, g_peerServiceName); continue; } } else { switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_SET_LINK_TIMEOUT): { uint32_t disposition; uint32_t timeout; status = AJ_UnmarshalArgs(&msg, "uu", &disposition, &timeout); if (disposition == AJ_SETLINKTIMEOUT_SUCCESS) { AJ_AlwaysPrintf(("Link timeout set to %d\n", timeout)); } else { AJ_AlwaysPrintf(("SetLinkTimeout failed %d\n", disposition)); } SendPing(&bus, sessionId, g_peerServiceName, 1); } break; case AJ_REPLY_ID(AJ_METHOD_BUS_PING): { uint32_t disposition; status = AJ_UnmarshalArgs(&msg, "u", &disposition); if (disposition == AJ_PING_SUCCESS) { AJ_AlwaysPrintf(("Bus Ping reply received\n")); } else { AJ_AlwaysPrintf(("Bus Ping failed, disconnecting: %d\n", disposition)); status = AJ_ERR_LINK_DEAD; } } break; case AJ_REPLY_ID(PRX_MY_PING): { AJ_Arg arg; AJ_UnmarshalArg(&msg, &arg); AJ_AlwaysPrintf(("Got ping reply\n")); AJ_InfoPrintf(("INFO Got ping reply\n")); status = SendGetProp(&bus, sessionId, g_peerServiceName); } break; case AJ_REPLY_ID(PRX_GET_PROP): { const char* sig; status = AJ_UnmarshalVariant(&msg, &sig); if (status == AJ_OK) { status = AJ_UnmarshalArgs(&msg, sig, &g_iterCount); AJ_AlwaysPrintf(("Get prop reply %d\n", g_iterCount)); if (status == AJ_OK) { g_iterCount = g_iterCount + 1; status = SendSetProp(&bus, sessionId, g_peerServiceName, g_iterCount); } } } break; case AJ_REPLY_ID(PRX_SET_PROP): AJ_AlwaysPrintf(("Set prop reply\n")); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * Force a disconnect */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u\n", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_SESSION_LOST) || (status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_AlwaysPrintf(("AllJoyn disconnect\n")); AJ_AlwaysPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); break; } } AJ_AlwaysPrintf(("clientlite EXIT %d\n", status)); return status; } #ifdef AJ_MAIN #ifdef MAIN_ALLOWS_ARGS int main(int ac, char** av) { return AJ_Main(ac, av); } #else int main() { return AJ_Main(); } #endif #endif ajtcl-16.04/test/codisco.c000066400000000000000000000145171271074662300154070ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include /* Forward Declaration */ static void Print_Connection_Summary(void); static const char* routingNodeName = "org.alljoyn.BusNode"; /* * To exercise LegacyNS code, set a mininum value via AJ_SetMinProtoVersion. * The protocol version for 14.02 is 9, as specified at: * https://git.allseenalliance.org/cgit/core/alljoyn.git/tree/alljoyn_core/inc/alljoyn/AllJoynStd.h?id=v14.02#n33 */ static const uint8_t minRouterProtocolVersion = 9; /* All time values are in milliseconds */ static const uint32_t CONNECT_TIMEOUT = 1000 * 5; /* To stress the underlying target's socket creation, set the value to zero */ static const uint16_t ROUTER_SELECTION_TIMEOUT = 5; /* PAUSE is the delay between connection attempts */ static const uint16_t PAUSE_MAX = 1000 * 4; /* Four seconds */ static const uint16_t PAUSE_MIN = 500 * 1; /* Half-a-second */ /* * If RANDOM_PAUSE is TRUE, then a random value between MIN and MAX is generated * If RANDOM_PAUSE is FALSE, then the average of MIN & MAX is used */ static const uint8_t RANDOM_PAUSE = TRUE; /* * Counters * The total number of connection attempts is the sum of * various pieces, viz. timed out, network error, unexpected error and success. * i. timed out attempts - AJ_ERR_TIMEOUT timeout is returned * ii. network error attempts - AJ_ERR_READ or AJ_ERR_WRITE or * AJ_ERR_CONNECT or AJ_ERR_LINK_DEAD is returned * iii. unexpected error attempts - Any other AJ_ERR_* returned * iv. success attempts - AJ_OK is returned */ static uint32_t num_total_attempts = 0; static uint16_t num_network_error_attempts = 0; static uint16_t num_unexpected_error_attempts = 0; static uint16_t num_timedout_attempts = 0; static uint16_t num_successful_attempts = 0; void AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; AJ_Time discoveryTimer; uint32_t timeTakenForDiscovery = 0; uint16_t timeout = 0; AJ_Initialize(); AJ_Printf("\nAllJoyn Release: %s\n\n", AJ_GetVersion()); AJ_SetMinProtoVersion(minRouterProtocolVersion); /* * Set the selection timeout to a different value from the default. */ AJ_SetSelectionTimeout(ROUTER_SELECTION_TIMEOUT); /* Connect and disconnect forever */ while (TRUE) { AJ_Printf("Attempting to connect to a routing node with prefix: %s ...\n", routingNodeName); AJ_InitTimer(&discoveryTimer); status = AJ_FindBusAndConnect(&bus, routingNodeName, CONNECT_TIMEOUT); timeTakenForDiscovery = AJ_GetElapsedTime(&discoveryTimer, FALSE); num_total_attempts++; if (AJ_ERR_READ == status || AJ_ERR_WRITE == status || AJ_ERR_CONNECT == status || AJ_ERR_LINK_DEAD == status) { num_network_error_attempts++; AJ_Printf("Network failure while connecting to routing node: %s (code: %u)\n", AJ_StatusText(status), status); } else if (AJ_ERR_TIMEOUT == status) { num_timedout_attempts++; AJ_Printf("Timedout while connecting to routing node\n"); /* * Discovery timed out. Check whether the API returned in a timely * manner. See whether the actual duration is off by +/- 500ms. * Delay beyond that is unusual. */ if (500 < abs(CONNECT_TIMEOUT - timeTakenForDiscovery)) { AJ_Printf("WARN: AJ_FindBusAndConnect API did not return in a timely manner. Timeout parameter: %u Actual time elapsed: %u\n", CONNECT_TIMEOUT, timeTakenForDiscovery); } } else if (AJ_OK == status) { num_successful_attempts++; AJ_Printf("Connected to routing node (protocol version = %u). Got unique name - %s\n", AJ_GetRoutingProtoVersion(), AJ_GetUniqueName(&bus)); } else { /* Unexpected failures */ num_unexpected_error_attempts++; AJ_Printf("!!!Unexpected!!! failure when connecting to routing node: %s (code: %u)\n", AJ_StatusText(status), status); } Print_Connection_Summary(); if (RANDOM_PAUSE) { /* Generate random timeout, between PAUSE_MIN and PAUSE_MAX */ AJ_RandBytes((uint8_t*)(&timeout), sizeof(timeout)); timeout = PAUSE_MIN + timeout % (PAUSE_MAX - PAUSE_MIN); } else { /* fixed timeout is the average of PAUSE_MIN and PAUSE_MAX */ timeout = (PAUSE_MIN + PAUSE_MAX) / 2; } AJ_Sleep(timeout); if (AJ_OK == status) { AJ_Disconnect(&bus); AJ_Printf("Disconnected from the routing node. "); } } } static void Print_Connection_Summary(void) { AJ_Printf("\n\t--Connection counters--\n" "\tNumber of successful attempts = %u\n" "\tNumber of timedout attempts = %u\n" "\tNumber of network error attempts = %u\n" "\tNumber of unexpected error attempts = %u\n" "\tTotal Number of attempts = %u\n" "\t-----------------------\n\n", num_successful_attempts, num_timedout_attempts, num_network_error_attempts, num_unexpected_error_attempts, num_total_attempts); } #ifdef AJ_MAIN int main(void) { /* AJ_Main is not expected to return */ AJ_Main(); return 0; } #endif ajtcl-16.04/test/ctrdrbg.c000066400000000000000000000141201271074662300154010ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE CTRDRBG #include #include #include #include #include uint8_t dbgCTRDRBG = 0; typedef struct { uint8_t df; /* Use DF or not */ const char* entropy; /* Entropy input */ const char* nonce; /* Nonce */ const char* personal; /* Personalization string */ const char* reseed; /* Reseed input */ const char* rand; /* Output */ } TEST_CASE; /* * Known answer tests taken from * http://csrc.nist.gov/groups/STM/cavp/ * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip * AES-128 use df, no predication resisitance, no reseed */ static TEST_CASE const testVector[] = { // DF - no reseed { 1, "890eb067acf7382eff80b0c73bc872c6", "aad471ef3ef1d203", "", "", "a5514ed7095f64f3d0d3a5760394ab42062f373a25072a6ea6bcfd8489e94af6cf18659fea22ed1ca0a9e33f718b115ee536b12809c31b72b08ddd8be1910fa3", }, { 1, "c47be8e8219a5a87c94064a512089f2b", "f2a23e636aee75c6", "", "", "5a1650bb6d6a16f6040591d56abcd5dd3db8772a9c75c44d9fc64d51b733d4a6759bd5a64ec4231a24e662fdd47c82db63b200daf8d098560eb5ba7bf3f9abf7", }, // DF - reseed { 1, "0f65da13dca407999d4773c2b4a11d85", "5209e5b4ed82a234", "", "1dea0a12c52bf64339dd291c80d8ca89", "2859cc468a76b08661ffd23b28547ffd0997ad526a0f51261b99ed3a37bd407bf418dbe6c6c3e26ed0ddefcb7474d899bd99f3655427519fc5b4057bcaf306d4", }, { 1, "1ff8f4a85dbf2f6bb2648967419bb270", "b0cdf7bc47ca5f8b", "", "f90699441c1ece41cf1f6a32e4948656", "d9ae8b33f1a10cbf516d97b9ad7baf0d596a081a0ff0f4717674239b9e339354d813b2bb71c10f7d2e34994e0030e4fbfba6438d077c361745993b9d6f669b24", }, // no DF - reseed { 0, "ed1e7f21ef66ea5d8e2a85b9337245445b71d6393a4eecb0e63c193d0f72f9a9", "", "", "303fb519f0a4e17d6df0b6426aa0ecb2a36079bd48be47ad2a8dbfe48da3efad", "f80111d08e874672f32f42997133a5210f7a9375e22cea70587f9cfafebe0f6a6aa2eb68e7dd9164536d53fa020fcab20f54caddfab7d6d91e5ffec1dfd8deaa", }, { 0, "eab5a9f23ceac9e4195e185c8cea549d6d97d03276225a7452763c396a7f70bf", "", "", "4258765c65a03af92fc5816f966f1a6644a6134633aad2d5d19bd192e4c1196a", "2915c9fabfbf7c62d68d83b4e65a239885e809ceac97eb8ef4b64df59881c277d3a15e0e15b01d167c49038fad2f54785ea714366d17bb2f8239fd217d7e1cba", }, }; int AJ_Main(void) { AJ_Status status = AJ_OK; CTR_DRBG_CTX ctx; size_t i; size_t size; uint8_t* d; uint8_t* data; uint8_t* rand; char* hex; for (i = 0; i < ArraySize(testVector); i++) { size_t elen = strlen(testVector[i].entropy) / 2; size_t nlen = strlen(testVector[i].nonce) / 2; size_t plen = strlen(testVector[i].personal) / 2; size_t rlen = strlen(testVector[i].reseed) / 2; size = elen + nlen + plen; data = AJ_Malloc(size); AJ_ASSERT(data); d = data; AJ_HexToRaw(testVector[i].entropy, 2 * elen, d, size); d += elen; AJ_HexToRaw(testVector[i].nonce, 2 * nlen, d, size); d += nlen; AJ_HexToRaw(testVector[i].personal, 2 * plen, d, size); d += plen; AJ_DumpBytes("SEED", data, size); AES_CTR_DRBG_Instantiate(&ctx, data, size, testVector[i].df); AJ_Free(data); if (rlen) { size = rlen; data = AJ_Malloc(size); AJ_ASSERT(data); AJ_HexToRaw(testVector[i].reseed, 2 * rlen, data, size); AES_CTR_DRBG_Reseed(&ctx, data, size); AJ_Free(data); } size = strlen(testVector[i].rand) / 2; data = AJ_Malloc(size); rand = AJ_Malloc(size); AJ_ASSERT(data); AJ_ASSERT(rand); AJ_HexToRaw(testVector[i].rand, 2 * size, rand, size); status = AES_CTR_DRBG_Generate(&ctx, data, size); if (AJ_OK != status) { AJ_AlwaysPrintf(("Generate failed for test #%zu\n", i)); goto Exit; } status = AES_CTR_DRBG_Generate(&ctx, data, size); if (AJ_OK != status) { AJ_AlwaysPrintf(("Generate failed for test #%zu\n", i)); goto Exit; } if (0 != memcmp(data, rand, size)) { AJ_AlwaysPrintf(("Expected failed for test #%zu\n", i)); status = AJ_ERR_SECURITY; goto Exit; } AJ_Free(data); AJ_Free(rand); } // Initialize the core context AJ_RandBytes(NULL, 0); // Get some random data size = 64; rand = AJ_Malloc(size); AJ_ASSERT(rand); hex = AJ_Malloc(2 * size + 1); AJ_ASSERT(hex); for (i = 0; i < 64; i++) { AJ_RandBytes(rand, size); AJ_RawToHex(rand, size, hex, 2 * size + 1, 0); AJ_AlwaysPrintf(("%s\n", hex)); } AJ_Free(rand); AJ_Free(hex); Exit: AJ_AlwaysPrintf(("CTR DRBG test: %s\n", AJ_StatusText(status))); return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/doorsvc.c000066400000000000000000000375141271074662300154450ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE DOORSVC #define SECURE_INTERFACE #define SECURE_OBJECT #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ uint8_t dbgDOORSVC = 1; /* * Modify these variables to change the service's behavior */ static const char ServiceName[] = "org.alljoyn.doorsvc"; static const uint16_t ServicePort = 12345; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; static const char doorIfn[] = "sample.securitymgr.door.Door"; static const char doorObj[] = "/sample/security/Door"; /* * To define a secure interface, prepend '$' before the interface name, eg., "$org.alljoyn.alljoyn_test" */ static const char* const doorInterface[] = { doorIfn, "?Open success>b", "?Close success>b", "?GetState state>b", "!StateChanged state>b", "@State=b", NULL }; static const AJ_InterfaceDescription doorInterfaces[] = { AJ_PropertiesIface, doorInterface, NULL }; static AJ_Object AppObjects[] = { { doorObj, doorInterfaces, AJ_OBJ_FLAG_ANNOUNCED | AJ_OBJ_FLAG_SECURE }, { NULL } }; static AJ_PermissionMember members[] = { { "*", AJ_MEMBER_TYPE_ANY, AJ_ACTION_PROVIDE | AJ_ACTION_OBSERVE, NULL } }; static AJ_PermissionRule rules[] = { { doorObj, doorIfn, members, NULL } }; #define OPEN TRUE #define CLOSED FALSE static boolean_t state = CLOSED; /* * Message identifiers for the method calls this application implements */ #define APP_GET_PROP AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_GET) #define APP_SET_PROP AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_SET) #define APP_OPEN AJ_APP_MESSAGE_ID(0, 1, 0) #define APP_CLOSE AJ_APP_MESSAGE_ID(0, 1, 1) #define APP_GET_STATE AJ_APP_MESSAGE_ID(0, 1, 2) #define APP_STATE_CHANGED AJ_APP_MESSAGE_ID(0, 1, 3) #define APP_STATE AJ_APP_PROPERTY_ID(0, 1, 4) /* * Let the application do some work */ static void AppDoWork() { /* * This function is called if there are no messages to unmarshal */ AJ_InfoPrintf(("do work\n")); } #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.08 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "123456"; #endif static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; default: break; } return status; } #endif /* * Handles a property GET request so marshals the property value to return */ static AJ_Status PropGetHandler(AJ_Message* reply, uint32_t id, void* context) { if (id == APP_STATE) { return AJ_MarshalArgs(reply, "b", state); } else { return AJ_ERR_UNEXPECTED; } } /* * Handles a property SET request so unmarshals the property value to apply. */ static AJ_Status PropSetHandler(AJ_Message* reply, uint32_t id, void* context) { if (id == APP_STATE) { return AJ_UnmarshalArgs(reply, "b", &state); } else { return AJ_ERR_UNEXPECTED; } } #define UUID_LENGTH 16 #define APP_ID_SIGNATURE "ay" static AJ_Status MarshalAppId(AJ_Message* msg, const char* appId) { AJ_Status status; uint8_t binAppId[UUID_LENGTH]; uint32_t sz = strlen(appId); if (sz > UUID_LENGTH * 2) { // Crop application id that is too long sz = UUID_LENGTH * 2; } status = AJ_HexToRaw(appId, sz, binAppId, UUID_LENGTH); if (status != AJ_OK) { return status; } status = AJ_MarshalArgs(msg, "{sv}", AJ_APP_ID_STR, APP_ID_SIGNATURE, binAppId, sz / 2); return status; } static AJ_Status AboutPropGetter(AJ_Message* reply, const char* language) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_GUID theAJ_GUID; AJ_Arg dict; AJ_Arg languageListArray; char machineIdValue[UUID_LENGTH * 2 + 1]; machineIdValue[UUID_LENGTH * 2] = '\0'; /* Here, "en" is the only supported language, so we always return it * regardless of what was requested, per the algorithm specified in * RFC 4647 section 3.4. */ status = AJ_MarshalContainer(reply, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { status = AJ_GetLocalGUID(&theAJ_GUID); if (status == AJ_OK) { AJ_GUID_ToString(&theAJ_GUID, machineIdValue, UUID_LENGTH * 2 + 1); } if (status == AJ_OK) { status = MarshalAppId(reply, &machineIdValue[0]); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_APP_NAME_STR, "s", "doorsvc"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_ID_STR, "s", machineIdValue); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_NAME_STR, "s", "Tester"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MANUFACTURER_STR, "s", "QCE"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MODEL_NUMBER_STR, "s", "1.0"); } //SupportedLanguages if (status == AJ_OK) { status = AJ_MarshalContainer(reply, &dict, AJ_ARG_DICT_ENTRY); if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", AJ_SUPPORTED_LANGUAGES_STR); } if (status == AJ_OK) { status = AJ_MarshalVariant(reply, "as"); } if (status == AJ_OK) { status = AJ_MarshalContainer(reply, &languageListArray, AJ_ARG_ARRAY); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", "en"); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &languageListArray); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &dict); } } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DESCRIPTION_STR, "s", "doorsvc test app"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEFAULT_LANGUAGE_STR, "s", "en"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_SOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_AJSOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &array); } return status; } uint32_t MyBusAuthPwdCB(uint8_t* buf, uint32_t bufLen) { const char* myPwd = "1234"; strncpy((char*)buf, myPwd, bufLen); return (uint32_t)strlen(myPwd); } static const uint32_t suites[] = { AUTH_SUITE_ECDHE_ECDSA, AUTH_SUITE_ECDHE_PSK, AUTH_SUITE_ECDHE_NULL }; #define CONNECT_TIMEOUT (1000 * 1000) #define UNMARSHAL_TIMEOUT (1000 * 5) #ifdef MAIN_ALLOWS_ARGS int AJ_Main(int ac, char** av) #else int AJ_Main() #endif { AJ_Message reply; AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; AJ_Message msg; uint16_t port; char* joiner; AJ_Message signal; uint32_t id, reason; uint32_t disposition, idleTo, probeTo; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); AJ_AboutRegisterPropStoreGetter(AboutPropGetter); while (TRUE) { if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned AJ_OK\n")); AJ_InfoPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_SetIdleTimeouts(&bus, 10, 4); connected = TRUE; #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) AJ_BusEnableSecurity(&bus, suites, ArraySize(suites)); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); AJ_ManifestTemplateSet(rules); AJ_SecuritySetClaimConfig(&bus, APP_STATE_CLAIMABLE, CLAIM_CAPABILITY_ECDHE_NULL, 0); #endif /* Configure timeout for the link to the daemon bus */ AJ_SetBusLinkTimeout(&bus, 60); // 60 seconds } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status && AJ_ERR_LINK_TIMEOUT == AJ_BusLinkStateProc(&bus)) { status = AJ_ERR_READ; } if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(); continue; } } if (status == AJ_OK) { switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_ADD_MATCH): if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_InfoPrintf(("Failed to add match\n")); status = AJ_ERR_FAILURE; } else { status = AJ_OK; } break; case AJ_METHOD_ACCEPT_SESSION: { AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); if (port == ServicePort) { status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } else { status = AJ_ResetArgs(&msg); if (AJ_OK != status) { break; } status = AJ_BusHandleBusMessage(&msg); } } break; case APP_OPEN: AJ_MarshalReplyMsg(&msg, &reply); AJ_MarshalArgs(&reply, "b", TRUE); AJ_DeliverMsg(&reply); if (CLOSED == state) { state = OPEN; AJ_MarshalSignal(&bus, &signal, APP_STATE_CHANGED, msg.sender, msg.sessionId, 0, 0); AJ_MarshalArgs(&signal, "b", state); AJ_DeliverMsg(&signal); AJ_CloseMsg(&signal); } break; case APP_CLOSE: AJ_MarshalReplyMsg(&msg, &reply); AJ_MarshalArgs(&reply, "b", TRUE); AJ_DeliverMsg(&reply); if (OPEN == state) { state = CLOSED; AJ_MarshalSignal(&bus, &signal, APP_STATE_CHANGED, msg.sender, msg.sessionId, 0, 0); AJ_MarshalArgs(&signal, "b", state); AJ_DeliverMsg(&signal); AJ_CloseMsg(&signal); } break; case APP_GET_STATE: AJ_MarshalReplyMsg(&msg, &reply); AJ_MarshalArgs(&reply, "b", state); AJ_DeliverMsg(&reply); break; case APP_GET_PROP: status = AJ_BusPropGet(&msg, PropGetHandler, NULL); break; case APP_SET_PROP: status = AJ_BusPropSet(&msg, PropSetHandler, NULL); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: { AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_InfoPrintf(("Session lost. ID = %u, reason = %u", id, reason)); status = AJ_ERR_SESSION_LOST; } break; case AJ_SIGNAL_SESSION_JOINED: break; case AJ_REPLY_ID(AJ_METHOD_CANCEL_ADVERTISE): case AJ_REPLY_ID(AJ_METHOD_ADVERTISE_NAME): if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } break; case AJ_REPLY_ID(AJ_METHOD_BUS_SET_IDLE_TIMEOUTS): { if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } AJ_UnmarshalArgs(&msg, "uuu", &disposition, &idleTo, &probeTo); AJ_InfoPrintf(("SetIdleTimeouts response disposition=%u idleTimeout=%u probeTimeout=%u\n", disposition, idleTo, probeTo)); } break; default: /* * Pass to the built-in bus message handlers */ status = AJ_BusHandleBusMessage(&msg); break; } // Any received packets indicates the link is active, so call to reinforce the bus link state AJ_NotifyLinkActive(); } /* * Unarshaled messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_LINK_DEAD)) { AJ_InfoPrintf(("AllJoyn disconnect\n")); AJ_InfoPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); connected = FALSE; /* * Sleep a little while before trying to reconnect */ AJ_Sleep(10 * 1000); } } AJ_WarnPrintf(("doorsvc EXIT %d\n", status)); return status; } #ifdef AJ_MAIN #ifdef MAIN_ALLOWS_ARGS int main(int ac, char** av) { return AJ_Main(ac, av); } #else int main() { return AJ_Main(); } #endif #endif ajtcl-16.04/test/ecctest.c000066400000000000000000001112371271074662300154130ustar00rootroot00000000000000/** * @file ecctest.c ECC (elliptic curve cryptography) tests */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include #include /* for the RNG */ #include /* ECDH/ECDSA APIs */ #include /* * Set this variable to print out the standard EC-SPEKE basepoints used in * AllJoyn for ECDHE_SPEKE. */ static const int g_print_speke_basepoints = 0; /* Benchmark support code */ /* Note: For a given processor, more precise timing methods often exist. * Since currently the build system does not tell us the processor, we * use these less precise, but more generic ways to get timing information. */ #define ITERS 100 /* Number of iterations for benchmarks. */ #if __linux #include #endif typedef struct { uint32_t data[9]; } bigval_t; /* Access system counter for benchmarking. */ uint64_t benchmark_time(void) { #if defined _WIN32 return __rdtsc(); #elif defined __linux struct timespec time; clock_gettime(CLOCK_REALTIME, &time); return (int64_t)(time.tv_sec * 1e9 + time.tv_nsec); #endif } /* Print benchmarking result with the corresponding unit */ void bench_print(const char* label, unsigned long long count, unsigned long long num_runs) { const char* unit; unsigned long long result = count / num_runs; #if __linux if (result >= 1e7) { unit = "msec"; result = result / 1e6; } else if (result >= 1e4) { unit = "usec"; result = result / 1e3; } else { unit = "nsec"; } #else unit = "cycles"; #endif AJ_Printf(" %s runs in %*s %10lld %s\n", label, (int)(50 - strlen(label)), " ", result, unit); } /* Field Arithmetic Tests */ int test_fpmul_p256_kat(digit256_tc a, digit256_tc b, digit256_tc c_known, int i) { digit256_t c = { 0, 0, 0, 0 }; digit_t temps[P256_TEMPS]; memset(temps, 0x00, sizeof(temps)); fpmul_p256(a, b, c, temps); if (memcmp(c, c_known, sizeof(c)) == 0) { return 1; } else { AJ_Printf("fpmul test %d failed -- wrong answer.\n", i); return 0; } } int run_fpmul_p256_kats() { int passed = 0; int run = 0; // Known answer tests. c1_known = a*b (mod p256). The product a*b before modular reduction is included for debugging. digit256_tc a1 = { 17719206558549681838UL, 6431396540947310048UL, 11612935573663628158UL, 8718051496037544076UL }; digit256_tc b1 = { 4921253721701162537UL, 17209563459544305479UL, 1017636069198536828UL, 5517976548754532891UL }; digit256_tc c1_known = { 961789641737072625UL, 10225457115821151364UL, 4102039298977734239UL, 1404790894956925208UL }; // a*b = [14274785008760427998UL, 6946299620016575489UL, 13709194129124787162UL, 17909878623608041999UL, 419040080746784108UL, 5344702675657996016UL, 14552306481969204026UL, 2607831686380395122] digit256_tc a2 = { 8844934698490770636UL, 9829389649759050548UL, 15580190479849132290UL, 17766681537739872130UL }; digit256_tc b2 = { 14500914995729698198UL, 6422638149855794201UL, 15664328861594059002UL, 6404777437367841893UL }; digit256_tc c2_known = { 2097716429123545365UL, 17656009607115261235UL, 9344564188714855756UL, 5082079834809801308UL }; // a*b = [1300317245404892040UL, 6008198196536125206UL, 16022114046911353928UL, 5876577119790533637UL, 14048949065398320954UL, 15111932852584245813UL, 1471281526380311976UL, 6168657221845067557] digit256_tc a3 = { 15939615155660301108UL, 7143350094927966522UL, 3883951360218364098UL, 15133662551349039251UL }; digit256_tc b3 = { 18150268098113480338UL, 11312047171767748001UL, 6186193757377372050UL, 8019375174056696995UL }; digit256_tc c3_known = { 11452255603278212989UL, 12257383617576985661UL, 11163574383076909462UL, 1558810016341072940UL }; // a*b = [5776732926367550376UL, 1772296329390911596UL, 9566540135247392647UL, 4895202992860378391UL, 17996356884603099097UL, 9232508218673844893UL, 5182695418892870641UL, 6579075270513827835] digit256_tc a4 = { 14318944385485372598UL, 883375215920048957UL, 13803891150075560442UL, 6611050328294776182UL }; digit256_tc b4 = { 13788568089797780523UL, 14427058084629806332UL, 14551108227132870340UL, 612024294718074594UL }; digit256_tc c4_known = { 4847932808027178217UL, 16808312094030226880UL, 378517564788830623UL, 327361809514739816UL }; // a*b = [4169236071965493906UL, 2577223082178085076UL, 8612931833157935979UL, 17698379716881045988UL, 8647078201883724018UL, 17217140294649640218UL, 14905457703337800644UL, 219340789808369142] digit256_tc a5 = { 6907620683598084025UL, 10652677734757169213UL, 12111960731393070133UL, 18325545720791423845UL }; digit256_tc b5 = { 16421853107984745044UL, 7149540827219402707UL, 7591632485150638734UL, 11078530975399126193UL }; digit256_tc c5_known = { 813005960448587351UL, 15100031179218961217UL, 296293684846639486UL, 5443020030248087442UL }; // a*b = [7766518664827697844UL, 1761751396603640420UL, 4677571217510298465UL, 11145029642123640723UL, 2694824567421187998UL, 4143170301981517467UL, 17398917319244501262UL, 11005743078434454794] digit256_tc a6 = { 10, 0, 0, 0 }; digit256_tc b6 = { 17, 0, 0, 0 }; digit256_tc c6_known = { 170, 0, 0, 0 }; // a*b = 170 = c6_known. product smaller than p256 passed += test_fpmul_p256_kat(a1, b1, c1_known, 1); run++; passed += test_fpmul_p256_kat(a2, b2, c2_known, 2); run++; passed += test_fpmul_p256_kat(a3, b3, c3_known, 3); run++; passed += test_fpmul_p256_kat(a4, b4, c4_known, 4); run++; passed += test_fpmul_p256_kat(a5, b5, c5_known, 5); run++; passed += test_fpmul_p256_kat(a6, b6, c6_known, 6); run++; return (passed == run); } int test_fpadd_p256_kat(digit256_tc a, digit256_tc b, digit256_tc c_known, int i) { digit256_t c; fpadd_p256(a, b, c); if (memcmp(c, c_known, sizeof(c)) == 0) { return 1; } else { AJ_Printf("fpadd test %d failed -- wrong answer.\n", i); return 0; } } int run_fpadd_p256_kats() { int run = 0; int passed = 0; digit256_tc a1 = { 13389093525700345293UL, 9786536739768428856UL, 2828400845031766471UL, 14419212017040060345UL }; digit256_tc b1 = { 14294722422393585579UL, 17460355475368744786UL, 3501978364702603477UL, 3400043727025504347UL }; digit256_tc c1_known = { 9237071874384379256UL, 8800148141427622027UL, 6330379209734369949UL, 17819255744065564692UL }; digit256_tc a2 = { 9046118443709457292UL, 13349558207210907587UL, 7658398902856321151UL, 3862605742198849968UL }; digit256_tc b2 = { 13188724448030810238UL, 8350995109368408207UL, 875478512590890457UL, 16363082593212770616UL }; digit256_tc c2_known = { 3788098818030715915UL, 3253809238574796883UL, 8533877415447211609UL, 1778944265997036263UL }; digit256_tc a3 = { 13389093525700345293UL, 9786536739768428856UL, 2828400845031766471UL, 14419212017040060345UL }; digit256_tc b3 = { 14294722422393585579UL, 17460355475368744786UL, 3501978364702603477UL, 3400043727025504347UL }; digit256_tc c3_known = { 9237071874384379256UL, 8800148141427622027UL, 6330379209734369949UL, 17819255744065564692UL }; digit256_tc a4 = { 10, 0, 0, 0 }; digit256_tc b4 = { 7, 0, 0, 0 }; digit256_tc c4_known = { 17, 0, 0, 0 }; passed += test_fpadd_p256_kat(a1, b1, c1_known, 1); run++; passed += test_fpadd_p256_kat(a2, b2, c2_known, 2); run++; passed += test_fpadd_p256_kat(a3, b3, c3_known, 3); run++; passed += test_fpadd_p256_kat(a4, b4, c4_known, 4); run++; return (run == passed); } int test_fpsub_p256_kat(digit256_tc a, digit256_tc b, digit256_tc c_known, int i) { digit256_t c; fpsub_p256(a, b, c); if (memcmp(c, c_known, sizeof(c)) == 0) { return 1; } else { AJ_Printf("fpsub test %d failed -- wrong answer.\n", i); return 0; } } int run_fpsub_p256_kats() { int run = 0; int passed = 0; digit256_tc a1 = { 11700990786256262891UL, 5637983711336958193UL, 5959611888226728961UL, 11869998447973167452UL }; digit256_tc b1 = { 4819216106114708977UL, 14863724383416041616UL, 12346602459755209691UL, 15988320929136601693UL }; digit256_tc c1_known = { 6881774680141553913UL, 9221003405925435489UL, 12059753502181070885UL, 14328421588251150079UL }; digit256_tc a2 = { 17719206558549681838UL, 6431396540947310048UL, 11612935573663628158UL, 8718051496037544076UL }; digit256_tc b2 = { 4921253721701162537UL, 17209563459544305479UL, 1017636069198536828UL, 5517976548754532891UL }; digit256_tc c2_known = { 12797952836848519301UL, 7668577155112556185UL, 10595299504465091329UL, 3200074947283011185UL }; digit256_tc a3 = { 8844934698490770636UL, 9829389649759050548UL, 15580190479849132290UL, 17766681537739872130UL }; digit256_tc b3 = { 14500914995729698198UL, 6422638149855794201UL, 15664328861594059002UL, 6404777437367841893UL }; digit256_tc c3_known = { 12790763776470624054UL, 3406751499903256346UL, 18362605691964624904UL, 11361904100372030236UL }; digit256_tc a4 = { 17, 0, 0, 0 }; digit256_tc b4 = { 7, 0, 0, 0 }; digit256_tc c4_known = { 10, 0, 0, 0 }; passed += test_fpsub_p256_kat(a1, b1, c1_known, 1); run++; passed += test_fpsub_p256_kat(a2, b2, c2_known, 2); run++; passed += test_fpsub_p256_kat(a3, b3, c3_known, 3); run++; passed += test_fpsub_p256_kat(a4, b4, c4_known, 4); run++; return (run == passed); } int test_fpneg_p256_kat(digit256_tc a, digit256_tc b_known, int i) { boolean_t status = B_FALSE; digit256_t b; memcpy(b, a, sizeof(digit256_t)); status = fpneg_p256(b); if (status == B_TRUE) { if (memcmp(b, b_known, sizeof(b)) == 0) { return 1; } else { AJ_Printf("fpneg test %d failed -- wrong answer.\n", i); return 0; } } else { AJ_Printf("fpneg test %d failed -- function failed.\n", i); return 0; } } int run_fpneg_p256_kats() { int run = 0; int passed = 0; digit256_tc a1 = { 15939615155660301108UL, 7143350094927966522UL, 3883951360218364098UL, 15133662551349039251UL }; digit256_tc b1_known = { 2507128918049250507UL, 11303393983076552389UL, 14562792713491187517UL, 3313081518065545069UL }; digit256_tc a2 = { 18150268098113480338UL, 11312047171767748001UL, 6186193757377372050UL, 8019375174056696995UL }; digit256_tc b2_known = { 296475975596071277UL, 7134696906236770910UL, 12260550316332179565UL, 10427368895357887325UL }; digit256_tc a3 = { 14318944385485372598UL, 883375215920048957UL, 13803891150075560442UL, 6611050328294776182UL }; digit256_tc b3_known = { 4127799688224179017UL, 17563368862084469954UL, 4642852923633991173UL, 11835693741119808138UL }; passed += test_fpneg_p256_kat(a1, b1_known, 1); run++; passed += test_fpneg_p256_kat(a2, b2_known, 2); run++; passed += test_fpneg_p256_kat(a3, b3_known, 3); run++; return (run == passed); } int test_fpequal_p256_kat(digit256_tc a, digit256_tc b, boolean_t are_equal_known, int i) { boolean_t status = B_FALSE; status = fpequal_p256(a, b); if (status == are_equal_known) { return 1; } else { AJ_Printf("fpequal test %d failed -- wrong answer.\n", i); return 0; } } int run_fpequal_p256_kats() { int run = 0; int passed = 0; digit256_tc a1 = { 15939615155660301108UL, 7143350094927966522UL, 3883951360218364098UL, 15133662551349039251UL }; digit256_tc b1 = { 15939615155660301108UL, 7143350094927966522UL, 3883951360218364098UL, 15133662551349039251UL }; boolean_t c1 = B_TRUE; digit256_tc a2 = { 15939615155660301108UL, 7143350094927966522UL, 3883951360218364098UL, 15133662551349039251UL }; digit256_tc b2 = { 15939615155660301108UL, 7143350094927966522UL, 3883951360218364098UL, 15133662551349039252UL }; boolean_t c2 = B_FALSE; digit256_tc a3 = { 0, 4294967296UL, 0, 18446744069414584321UL, }; // p + 1 digit256_tc b3 = { 1, 0, 0, 0 }; // 1 boolean_t c3 = B_FALSE; // Note that fpequal requires inputs be reduced mod p, so these will not be considered equal. passed += test_fpequal_p256_kat(a1, b1, c1, 1); run++; passed += test_fpequal_p256_kat(a2, b2, c2, 2); run++; passed += test_fpequal_p256_kat(a3, b3, c3, 3); run++; return (passed == run); } int test_fpinv_p256_kat(digit256_tc a, digit256_tc b_known, int i) { digit_t temps[P256_TEMPS]; digit256_t b; fpinv_p256(a, b, temps); if (memcmp(b, b_known, sizeof(b)) == 0) { return 1; } else { AJ_Printf("fpinv test %d failed -- wrong answer.\n", i); return 0; } } int run_fpinv_p256_kats() { int run = 0; int passed = 0; digit256_tc a1 = { 6907620683598084025UL, 10652677734757169213UL, 12111960731393070133UL, 18325545720791423845UL }; digit256_tc b1 = { 14025966668329367848UL, 3595156072241463650UL, 15456073631280180716UL, 14150861440201384475UL }; digit256_tc a2 = { 16421853107984745044UL, 7149540827219402707UL, 7591632485150638734UL, 11078530975399126193UL }; digit256_tc b2 = { 5524053351190660477UL, 14052510857214807129UL, 17409895116542148161UL, 5055399665644516158UL }; digit256_tc a3 = { 9046118443709457292UL, 13349558207210907587UL, 7658398902856321151UL, 3862605742198849968UL }; digit256_tc b3 = { 17723950800386319926UL, 12284076655406226634UL, 17109263073168979093UL, 71817302339060736UL }; passed += test_fpinv_p256_kat(a1, b1, 1); run++; passed += test_fpinv_p256_kat(a2, b2, 2); run++; passed += test_fpinv_p256_kat(a3, b3, 3); run++; return (passed == run); } int test_fpdiv2_p256_kat(digit256_tc a, digit256_tc b_known, int i) { digit256_t b; digit_t temps[P256_TEMPS]; fpdiv2_p256(a, b, temps); if (memcmp(b, b_known, sizeof(b)) == 0) { return 1; } else { AJ_Printf("fpdiv2 test %d failed -- wrong answer.\n", i); return 0; } } int run_fpdiv2_p256_kats() { int run = 0; int passed = 0; digit256_tc a1 = { 13188724448030810238UL, 8350995109368408207UL, 875478512590890457UL, 16363082593212770616UL }; digit256_tc b1 = { 15817734260870180927UL, 13398869591538979911UL, 437739256295445228UL, 8181541296606385308UL }; digit256_tc a2 = { 13389093525700345293UL, 9786536739768428856UL, 2828400845031766471UL, 14419212017040060345UL }; digit256_tc b2 = { 6694546762850172646UL, 14116640408886473884UL, 1414200422515883235UL, 16432978043227322333UL }; digit256_tc a3 = { 14294722422393585579UL, 17460355475368744786UL, 3501978364702603477UL, 3400043727025504347UL }; digit256_tc b3 = { 7147361211196792789UL, 17953549776686631849UL, 1750989182351301738UL, 10923393898220044334UL }; passed += test_fpdiv2_p256_kat(a1, b1, 1); run++; passed += test_fpdiv2_p256_kat(a2, b2, 2); run++; passed += test_fpdiv2_p256_kat(a3, b3, 3); run++; return (passed == run); } int run_fp256_tests() { int run = 0; int passed = 0; passed += run_fpmul_p256_kats(); run++; passed += run_fpadd_p256_kats(); run++; passed += run_fpsub_p256_kats(); run++; passed += run_fpneg_p256_kats(); run++; passed += run_fpequal_p256_kats(); run++; passed += run_fpinv_p256_kats(); run++; passed += run_fpdiv2_p256_kats(); run++; if (run != passed) { AJ_Printf("Ran %d Fp tests, %d passed\n", run, passed); } return (run == passed); } /* Curve tests */ int test_curve_basics() { ec_t curve = { 0 }; ecpoint_t P = { 0 }; ecpoint_t P2 = { 0 }; ecpoint_jacobian_t Pj = { 0 }; AJ_Status status; status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { AJ_Printf("ec_getcurve failed\n"); goto Exit; } ec_get_generator(&P, &curve); if (ec_is_infinity(&P, &curve)) { AJ_Printf("ec_is_infinity reports true for output of ec_get_generator\n"); status = AJ_ERR_UNKNOWN; goto Exit; } ec_affine_tojacobian(&P, &Pj); if (ec_is_infinity_jacobian(&Pj, &curve)) { AJ_Printf("ec_is_infinity_jacobian reports true unexpectedly\n"); status = AJ_ERR_UNKNOWN; goto Exit; } ec_toaffine(&Pj, &P2, &curve); if (!fpequal_p256(P.x, P2.x) || !fpequal_p256(P.y, P2.y)) { AJ_Printf("unknown error with point type conversion\n"); status = AJ_ERR_UNKNOWN; goto Exit; } Exit: ec_freecurve(&curve); return (status == AJ_OK); } int ecpoint_jacobian_areequal(ecpoint_jacobian_t* A, ecpoint_jacobian_t* B, ec_t* curve) { ecpoint_t a = { 0 }; ecpoint_t b = { 0 }; ec_toaffine(A, &a, curve); ec_toaffine(B, &b, curve); // Convert to affine & compare if (fpequal_p256(a.x, b.x) && fpequal_p256(a.y, b.y)) { return 1; } return 0; } int ecpoint_areequal(ecpoint_t* A, ecpoint_t* B, ec_t* curve) { if (fpequal_p256(A->x, B->x) && fpequal_p256(A->y, B->y)) { return 1; } return 0; } int test_curve_arith_basics() { ec_t curve = { 0 }; ecpoint_t g = { 0 }; ecpoint_jacobian_t G = { 0 }; ecpoint_jacobian_t anotherG = { 0 }; AJ_Status status; ecpoint_t R2_known = { { 11964737083406719352UL, 13873736548487404341UL, 9967090510939364035UL, 9003393950442278782UL }, { 11386427643415524305UL, 13438088067519447593UL, 2971701507003789531UL, 537992211385471040UL } }; // 2*G ecpoint_t R3_known = { { 18104864246493347180UL, 16629180030495074693UL, 14481306550553801061UL, 6830804848925149764UL }, { 11131122737810853938UL, 15576456008133752893UL, 3984285777615168236UL, 9742521897846374270UL } }; // 3*G ecpoint_jacobian_t R2 = { 0 }; ecpoint_jacobian_t R3 = { 0 }; status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { goto Exit; } /* Test point validation */ ec_get_generator(&g, &curve); if (!ecpoint_validation(&g, &curve)) { AJ_Printf("ec_oncurve failed\n"); status = AJ_ERR_UNKNOWN; goto Exit; } /* Test ec_double_jacobian */ ec_get_generator(&g, &curve); ec_affine_tojacobian(&g, &G); ec_affine_tojacobian(&R2_known, &R2); ec_double_jacobian(&G); // G = 2*G if (!ecpoint_jacobian_areequal(&G, &R2, &curve)) { AJ_Printf("ec_double_jacobian is incorrect\n"); status = AJ_ERR_UNKNOWN; goto Exit; } /* Test ec_add_jacobian with same inputs. */ ec_get_generator(&g, &curve); ec_affine_tojacobian(&g, &G); // G = G ec_affine_tojacobian(&g, &anotherG); // G = G ec_affine_tojacobian(&R2_known, &R2); ec_add_jacobian(&anotherG, &G, &curve); // G = 2*G this add should work properly when the inputs are the same. if (!ecpoint_jacobian_areequal(&G, &R2, &curve)) { AJ_Printf("ec_add_jacobian is incorrect (tested with the same input)\n"); status = AJ_ERR_UNKNOWN; goto Exit; } /* Test ec_add_jacobian with different inputs. */ ec_get_generator(&g, &curve); ec_affine_tojacobian(&g, &G); // G = G ec_affine_tojacobian(&R2_known, &R2); ec_affine_tojacobian(&R3_known, &R3); ec_add_jacobian(&R2, &G, &curve); // G = G + 2*G = 3*G this add works properly when the inputs are the same. if (!ecpoint_jacobian_areequal(&G, &R3, &curve)) { AJ_Printf("ec_add_jacobian is incorrect (tested with different inputs)\n"); status = AJ_ERR_UNKNOWN; goto Exit; } Exit: ec_freecurve(&curve); return (status == AJ_OK); } int test_scalarmul_kat(digit256_t k, digit256_t x, digit256_t y, int i) { ec_t curve = { 0 }; ecpoint_t P = { 0 }; ecpoint_t Q; AJ_Status status; status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { AJ_Printf("ec_getcurve failed %d\n", i); goto Exit; } ec_get_generator(&P, &curve); if (ec_is_infinity(&P, &curve)) { AJ_Printf("invalid generator %d\n", i); status = AJ_ERR_UNKNOWN; goto Exit; } status = ec_scalarmul(&P, k, &Q, &curve); if (status != AJ_OK) { AJ_Printf("ec_scalarmul test %d failed (the function failed)\n", i); goto Exit; } if (!fpequal_p256(x, Q.x) || !fpequal_p256(y, Q.y)) { AJ_Printf("ec_scalarmul test %d returned an incorrect result\n", i); status = AJ_ERR_UNKNOWN; goto Exit; } Exit: ec_freecurve(&curve); return (status == AJ_OK); } int run_scalarmul_kats() { int passed = 0; int run = 0; // Test vectors: (x, y) = k*G (where G is the basepoint) // From http://point-at-infinity.org/ecc/nisttv digit256_t k1 = { 17562291160714782032UL, 13611842547513532036UL, 18446744073709551615UL, 18446744069414584320UL }; digit256_t x1 = { 17627433388654248598UL, 8575836109218198432UL, 17923454489921339634UL, 7716867327612699207UL }; digit256_t y1 = { 3767753221892779530UL, 15290227238617653553UL, 8149286295562117609UL, 12690225778011766885UL }; digit256_t k2 = { 8234495237290528275UL, 6084187275451764UL, 0, 0 }; digit256_t x2 = { 13013376741987594852UL, 7335293150882016018UL, 7890206492658706934UL, 1981025739527209566UL }; digit256_t y2 = { 5672504522216064379UL, 8327131327894173024UL, 4446911187859987120UL, 13828999463473408775UL }; passed += test_scalarmul_kat(k1, x1, y1, 1); run++; passed += test_scalarmul_kat(k2, x2, y2, 2); run++; return (passed == run); } int run_scalarmul_randomized() { digit256_t k1, k2; ecpoint_t g, Q1, Q2, Z1, Z2; int i = 0; int iters = 10; ec_t curve; AJ_Status status; status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { goto Exit; } ec_get_generator(&g, &curve); for (i = 0; i < iters; i++) { /* Choose random k1 in [0, curve order - 1]*/ do { AJ_RandBytes((uint8_t*)k1, sizeof(digit256_t)); } while (!validate_256(k1, curve.order)); /* Choose random k2 in [0, curve order - 1]*/ do { AJ_RandBytes((uint8_t*)k2, sizeof(digit256_t)); } while (!validate_256(k2, curve.order)); /* Compute public keys */ ec_scalarmul(&g, k1, &Q1, &curve); ec_scalarmul(&g, k2, &Q2, &curve); /* Compute shared secret points */ ec_scalarmul(&Q2, k1, &Z1, &curve); ec_scalarmul(&Q1, k2, &Z2, &curve); if (!ecpoint_areequal(&Z1, &Z2, &curve)) { AJ_Printf("Randomized scalarmul test failed\n"); status = AJ_ERR_UNKNOWN; goto Exit; } } Exit: ec_freecurve(&curve); return (status == AJ_OK); } void scalarmul_benchmark() { digit256_t k[ITERS]; ecpoint_t g, Q; int i = 0; ec_t curve; AJ_Status status; uint64_t cycles_start, cycles_end, cycles_total; uint64_t asdf = 0; status = ec_getcurve(&curve, NISTP256r1); if (AJ_OK != status) { goto Exit; } ec_get_generator(&g, &curve); for (i = 0; i < ITERS; i++) { /* Choose random scalars in [0, curve order - 1]*/ do { AJ_RandBytes((uint8_t*)k[i], sizeof(digit256_t)); } while (!validate_256(k[i], curve.order)); } cycles_total = 0; for (i = 0; i < ITERS; i++) { cycles_start = benchmark_time(); ec_scalarmul(&g, k[i], &Q, &curve); cycles_end = benchmark_time(); cycles_total += cycles_end - cycles_start; asdf += Q.x[0]; } if (asdf == 42) { AJ_Printf("Ignore this message.\n"); /* Prevents the above from being optimized out.*/ } bench_print("newecc scalarmul", cycles_total, ITERS); Exit: ec_freecurve(&curve); } void print_digits(char* label, digit256_t a) { size_t i; AJ_Printf("%s{", label); for (i = 0; i < P256_DIGITS; i++) { AJ_Printf("%llu, ", a[i]); } AJ_Printf("\b\b}\n"); } int test_ecdh() { AJ_ECCPublicKey ecpubkeyAlice; AJ_ECCPrivateKey ecprvkeyAlice; AJ_ECCPublicKey ecpubkeyBob; AJ_ECCPrivateKey ecprvkeyBob; AJ_ECCSecret agreedSecret1; AJ_ECCSecret agreedSecret2; AJ_Status status; status = AJ_GenerateECCKeyPair(&ecpubkeyAlice, &ecprvkeyAlice); if (AJ_OK != status) { AJ_Printf("AJ_GenerateECCKeyPair(...) failed with status 0x%08x for Alice's key.\n", (uint32_t)status); goto Exit; } status = AJ_GenerateECCKeyPair(&ecpubkeyBob, &ecprvkeyBob); if (AJ_OK != status) { AJ_Printf("AJ_GenerateECCKeyPair(...) failed with status 0x%08x for Bob's key.\n", (uint32_t)status); goto Exit; } status = AJ_GenerateShareSecret(&ecpubkeyAlice, &ecprvkeyBob, &agreedSecret1); if (AJ_OK != status) { AJ_Printf("AJ_GenerateShareSecret(...) failed with status 0x%08x using Alice's public and Bob's private.\n", (uint32_t)status); goto Exit; } status = AJ_GenerateShareSecret(&ecpubkeyBob, &ecprvkeyAlice, &agreedSecret2); if (AJ_OK != status) { AJ_Printf("AJ_GenerateShareSecret(...) failed with status 0x%08x using Bob's public and Alice's private.\n", (uint32_t)status); goto Exit; } if (0 != memcmp(&agreedSecret1.x, &agreedSecret2.x, KEY_ECC_SZ)) { AJ_Printf("agreed secrets didn't match!\n"); status = AJ_ERR_NO_MATCH; goto Exit; } status = AJ_OK; Exit: return (status == AJ_OK); } void tweak_buffer(uint8_t*pb, size_t cb) { size_t i; for (i = 0; i < cb; i++) { pb[i] ^= (uint8_t)i; } } int test_ecdsa() { AJ_ECCPublicKey ecpubkey; AJ_ECCPrivateKey ecprvkey; AJ_SHA256_Context* sha256ctx; uint8_t rgDataToHash[AJ_SHA256_DIGEST_LENGTH]; uint8_t rgHash[AJ_SHA256_DIGEST_LENGTH]; AJ_ECCSignature ecsig1; AJ_ECCSignature ecsig2; AJ_ECCPublicKey ecpubkey2; AJ_ECCPrivateKey ecprvkey2; AJ_Status status; status = AJ_GenerateECCKeyPair(&ecpubkey, &ecprvkey); if (AJ_OK != status) { AJ_Printf("AJ_GenerateECCKeyPair(...) failed with status 0x%08x.\n", (uint32_t)status); goto Exit; } AJ_RandBytes(rgDataToHash, sizeof(rgDataToHash)); sha256ctx = AJ_SHA256_Init(); AJ_SHA256_Update(sha256ctx, rgDataToHash, sizeof(rgDataToHash)); AJ_SHA256_Final(sha256ctx, rgHash); status = AJ_ECDSASignDigest(rgHash, &ecprvkey, &ecsig1); if (AJ_OK != status) { AJ_Printf("AJ_ECDSASignDigest(...) failed with status 0x%08x.\n", (uint32_t)status); goto Exit; } status = AJ_ECDSASign(rgDataToHash, sizeof(rgDataToHash), &ecprvkey, &ecsig2); if (AJ_OK != status) { AJ_Printf("AJ_ECDSASign(...) failed with status 0x%08x.\n", (uint32_t)status); goto Exit; } status = AJ_ECDSAVerifyDigest(rgHash, &ecsig1, &ecpubkey); if (AJ_OK != status) { AJ_Printf("AJ_ECDSAVerifyDigest(...) failed with status 0x%08x verify digest with signature generated by sign digest.\n", (uint32_t)status); goto Exit; } status = AJ_ECDSAVerify(rgDataToHash, sizeof(rgDataToHash), &ecsig1, &ecpubkey); if (AJ_OK != status) { AJ_Printf("AJ_ECDSAVerify(...) failed with status 0x%08x verify data with signature generated by sign digest.\n", (uint32_t)status); goto Exit; } status = AJ_ECDSAVerifyDigest(rgHash, &ecsig2, &ecpubkey); if (AJ_OK != status) { AJ_Printf("AJ_ECDSAVerifyDigest(...) failed with status 0x%08x verify digest with signature generated by sign data.\n", (uint32_t)status); goto Exit; } status = AJ_ECDSAVerify(rgDataToHash, sizeof(rgDataToHash), &ecsig2, &ecpubkey); if (AJ_OK != status) { AJ_Printf("AJ_ECDSAVerify(...) failed with status 0x%08x verify data with signature generated by sign data.\n", (uint32_t)status); goto Exit; } /* Check and make sure that the the verify code correctly rejects bad signatures. */ status = AJ_GenerateECCKeyPair(&ecpubkey2, &ecprvkey2); if (AJ_OK != status) { AJ_Printf("AJ_GenerateECCKeyPair(...) failed with status 0x%08x.\n", (uint32_t)status); goto Exit; } /* Verify with the wrong public key (should fail). */ status = AJ_ECDSAVerifyDigest(rgHash, &ecsig1, &ecpubkey2); if (AJ_OK == status) { AJ_Printf("AJ_ECDSAVerifyDigest(...) failed with status 0x%08x.\n", (uint32_t)status); status = AJ_ERR_UNKNOWN; goto Exit; } tweak_buffer(rgHash, sizeof(rgHash)); tweak_buffer((uint8_t*)&ecsig2, sizeof(AJ_ECCSignature)); /* Verify with the wrong hash. */ status = AJ_ECDSAVerifyDigest(rgHash, &ecsig1, &ecpubkey); if (AJ_OK == status) { AJ_Printf("AJ_ECDSAVerifyDigest(...) correctly accepted the incorrect hash.\n"); status = AJ_ERR_UNKNOWN; goto Exit; } /* Verify with a corrupted signature. */ status = AJ_ECDSAVerify(rgDataToHash, sizeof(rgDataToHash), &ecsig2, &ecpubkey); if (AJ_OK == status) { AJ_Printf("AJ_ECDSAVerify(...) correctly accepted a tweaked signature.\n"); status = AJ_ERR_UNKNOWN; goto Exit; } status = AJ_OK; Exit: return (status == AJ_OK); } /* These two internal conversion fucntions are here for unit testing. */ void digit256_to_bigval(digit256_tc src, bigval_t* dst); boolean_t bigval_to_digit256(const bigval_t* src, digit256_t dst); int test_conversion() { bigval_t a; digit256_t A; digit256_t B; fpset_p256(1, A); fpset_p256(2, B); digit256_to_bigval(A, &a); a.data[0]++; bigval_to_digit256(&a, A); if (!fpequal_p256(A, B)) { AJ_Printf("Conversion test 1 failed\n"); AJ_Printf("A: %llu %llu %llu %llu\n", A[0], A[1], A[2], A[3]); AJ_Printf("a: %u %u %u %u\n", a.data[0], a.data[1], a.data[2], a.data[3]); AJ_Printf("B: %llu %llu %llu %llu\n", B[0], B[1], B[2], B[3]); return 0; } /* Test with a random value */ AJ_RandBytes((uint8_t*)A, sizeof(digit256_t)); fpset_p256(1, B); fpadd_p256(A, B, B); digit256_to_bigval(A, &a); a.data[0]++; if (a.data[0] == 0) { AJ_Printf("Conversion test will fail, it's OK (problem with test code)\n"); /* happens with very low (2^(-32) probability) */ } bigval_to_digit256(&a, A); if (!fpequal_p256(A, B)) { AJ_Printf("Conversion test 2 failed\n"); AJ_Printf("A: %llu %llu %llu %llu\n", A[0], A[1], A[2], A[3]); AJ_Printf("a: %u %u %u %u\n", a.data[0], a.data[1], a.data[2], a.data[3]); AJ_Printf("B: %llu %llu %llu %llu\n", B[0], B[1], B[2], B[3]); return 0; } return 1; } int test_redp() { ec_t curve = { 0 }; ecpoint_t Q1 = { 0 }; ecpoint_t Q2 = { 0 }; ecpoint_t P1 = { 0 }; ecpoint_t P2 = { 0 }; ecpoint_t R = { 0 }; AJ_Status status; unsigned char point1[18] = "ALLJOYN-ECSPEKE-1"; unsigned char point2[18] = "ALLJOYN-ECSPEKE-2"; unsigned char password[11] = "mypassword"; status = ec_getcurve(&curve, NISTP256r1); if (status != AJ_OK) { goto Exit; } status = ec_REDP1(point1, sizeof(point1), &Q1, &curve); if (status != AJ_OK) { AJ_Printf("REDP-1 failed with pi1, did not return AJ_OK."); goto Exit; } status = ec_REDP1(point2, sizeof(point2), &Q2, &curve); if (status != AJ_OK) { AJ_Printf("REDP-1 failed with pi2, did not return AJ_OK."); goto Exit; } if (g_print_speke_basepoints) { /* Print the standard EC-SPEKE basepoints used in AllJoyn for ECDHE_SPEKE. */ AJ_Printf("REDP-1(ALLJOYN-ECSPEKE-1)\n"); print_digits("x = ", Q1.x); print_digits("y = ", Q1.y); AJ_Printf("REDP-1(ALLJOYN-ECSPEKE-2)\n"); print_digits("x = ", Q2.x); print_digits("y = ", Q2.y); } status = ec_REDP2(password, &Q1, &Q2, &R, &curve); if (status != AJ_OK) { AJ_Printf("REDP-2 failed, did not return AJ_OK."); goto Exit; } /* Make sure precomputed basepoints equal those we computed just now from the two constants. */ ec_get_REDP_basepoints(&P1, &P2, curve.curveid); if (!ecpoint_areequal(&P1, &Q1, &curve)) { status = AJ_ERR_UNKNOWN; AJ_Printf("REDP precomputed basepoints incorrect, point 1 does not match REDP-1(%s).", point1); goto Exit; } if (!ecpoint_areequal(&P2, &Q2, &curve)) { status = AJ_ERR_UNKNOWN; AJ_Printf("REDP precomputed basepoints incorrect, point 2 does not match REDP-1(%s).", point2); goto Exit; } Exit: if (status == AJ_OK) { return 1; } else { return 0; } } // Test the ECDHE_ECSPEKE key generation and agreement functions from aj_crypto_ecc.h int test_ecspeke() { AJ_GUID clientGUID; AJ_GUID serviceGUID; AJ_Status status; AJ_ECCPublicKey pk1, pk2; AJ_ECCPrivateKey sk1, sk2; AJ_ECCSecret secret1, secret2; const uint8_t pw[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; const uint8_t notpw[8] = { 8, 7, 6, 5, 4, 3, 2, 1 }; AJ_CreateNewGUID((uint8_t*)&clientGUID, sizeof(AJ_GUID)); AJ_CreateNewGUID((uint8_t*)&serviceGUID, sizeof(AJ_GUID)); // Create key pairs from matching password status = AJ_GenerateSPEKEKeyPair(pw, sizeof(pw), &clientGUID, &serviceGUID, &pk1, &sk1); if (status != AJ_OK) { AJ_Printf("Failed to generate key pair 1 for ECDHE_SPEKE test\n"); return 0; } status = AJ_GenerateSPEKEKeyPair(pw, sizeof(pw), &clientGUID, &serviceGUID, &pk2, &sk2); if (status != AJ_OK) { AJ_Printf("Failed to generate key pair 2 for ECDHE_SPEKE test\n"); return 0; } // Do key agreement operation status = AJ_GenerateShareSecret(&pk2, &sk1, &secret1); if (status != AJ_OK) { AJ_Printf("Failed to generate shared secret 1 for ECDHE_SPEKE test\n"); return 0; } status = AJ_GenerateShareSecret(&pk1, &sk2, &secret2); if (status != AJ_OK) { AJ_Printf("Failed to generate shared secret 2 for ECDHE_SPEKE test\n"); return 0; } // Shared secrets should be equal if (memcmp(secret1.x, secret2.x, KEY_ECC_SZ) != 0) { AJ_Printf("Shared secrets for ECHDE_SPEKE test do not match\n"); return 0; } // Re-create keypair 2 with a different password status = AJ_GenerateSPEKEKeyPair(notpw, sizeof(notpw), &clientGUID, &serviceGUID, &pk2, &sk2); if (status != AJ_OK) { AJ_Printf("Failed to re-generate key pair 2 for ECDHE_SPEKE test\n"); return 0; } // Re-do key agreement operation status = AJ_GenerateShareSecret(&pk2, &sk1, &secret1); if (status != AJ_OK) { AJ_Printf("Failed to generate shared secret 1 for ECDHE_SPEKE test\n"); return 0; } status = AJ_GenerateShareSecret(&pk1, &sk2, &secret2); if (status != AJ_OK) { AJ_Printf("Failed to generate shared secret 2 for ECDHE_SPEKE test\n"); return 0; } // Shared secrets should no longer be equal if (memcmp(secret1.x, secret2.x, KEY_ECC_SZ) == 0) { AJ_Printf("Shared secrets for ECHDE_SPEKE test match when they shouldn't\n"); return 0; } return 1; } int AJ_Main() { int tests_ran = 0; int passed = 0; AJ_Printf("Running tests...\n"); passed += run_fp256_tests(); tests_ran++; passed += test_curve_basics(); tests_ran++; passed += test_curve_arith_basics(); tests_ran++; passed += run_scalarmul_kats(); tests_ran++; passed += run_scalarmul_randomized(); tests_ran++; passed += test_ecdh(); tests_ran++; passed += test_ecdsa(); tests_ran++; passed += test_conversion(); tests_ran++; passed += test_redp(); tests_ran++; passed += test_ecspeke(); tests_ran++; AJ_Printf(" Ran %d tests, %d passed.\n", tests_ran, passed); AJ_Printf("Running benchmarks...\n"); scalarmul_benchmark(); return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/echo.c000066400000000000000000000050341271074662300146740ustar00rootroot00000000000000/** * @file UART transport Tester */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #define BITRATE B115200 #define AJ_SERIAL_WINDOW_SIZE 4 #define AJ_SERIAL_ENABLE_CRC 1 #define AJ_SERIAL_PACKET_SIZE 104 static uint8_t txBuffer[32]; static uint8_t rxBuffer[32]; void TimerCallbackEndProc(uint32_t timerId, void* context) { AJ_AlwaysPrintf(("TimerCallback %.6d \n", timerId)); exit(0); } #ifdef AJ_MAIN int main() { AJ_Status status; memset(&rxBuffer, 'R', sizeof(rxBuffer)); #ifdef READTEST status = AJ_SerialInit("/dev/ttyUSB0", BITRATE, AJ_SERIAL_WINDOW_SIZE, AJ_SERIAL_ENABLE_CRC, AJ_SERIAL_PACKET_SIZE); #else status = AJ_SerialInit("/dev/ttyUSB1", BITRATE, AJ_SERIAL_WINDOW_SIZE, AJ_SERIAL_ENABLE_CRC, AJ_SERIAL_PACKET_SIZE); #endif AJ_AlwaysPrintf(("serial init was %u\n", status)); uint32_t timerEndProc = 9999; status = AJ_TimerRegister(10000, &TimerCallbackEndProc, NULL, &timerEndProc); AJ_AlwaysPrintf(("Added id %u\n", timerEndProc)); uint16_t echocount = 0; while (1) { snprintf((char*)&txBuffer, sizeof(txBuffer), "echo t %i", ++echocount); #ifdef READTEST uint16_t recv; AJ_SerialRecv(rxBuffer, sizeof(rxBuffer), 2000, &recv); AJ_DumpBytes("Post serial recv", rxBuffer, sizeof(rxBuffer)); #else AJ_Sleep(500); AJ_SerialSend(txBuffer, sizeof(txBuffer)); AJ_AlwaysPrintf(("post serial send\n")); #endif AJ_Sleep(400); } return(0); } #endif ajtcl-16.04/test/marshal_unmarshal_test.c000066400000000000000000004026611271074662300205250ustar00rootroot00000000000000/** * @file * Alljoyn client that marshals and unmarshals different data types. */ /****************************************************************************** * Copyright (c) AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE MARSHAL_UNMARSHAL #include #include #include #ifndef bool /* These tests were written to use stdbool.h, but VS2012 does not support it. */ #define bool int #define false (0) #define true (1) #endif #define CONNECT_ATTEMPTS 10 static const char ServiceName[] = "org.datatypes.test"; static const char ServicePath[] = "/datatypes"; static const uint16_t ServicePort = 25; /* * Buffer to hold the full service name. This buffer must be big enough to hold * a possible 255 characters plus a null terminator (256 bytes) */ static char fullServiceName[AJ_MAX_SERVICE_NAME_SIZE]; /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ uint8_t dbgMARSHAL_UNMARSHAL = 0; /** * The interface name followed by the method signatures. * * See also .\inc\aj_introspect.h */ static const char* const sampleInterface[] = { "org.datatypes.test.interface", /* The first entry is the interface name. */ "?byte inStry", /* Method at index 1. */ "?int inStri", "?unsignedint inStru", "?double inStrd", "?bool inStrb", "?string inStrs", "?uint16 inStrq", "?int16 inStrn", "?uint64 inStrt", "?int64 inStrx", "?struct inStr<(yiudbsqnxt) outStr>(yiudbsqnxt)", "?dictionary inStra{uv}", "?bytearray inStray", "?intarray inStrai", "?unsignedintarray inStrau", "?doublearray inStrad", "?boolarray inStrab", "?stringarray inStras", "?uint16array inStraq", "?int16array inStran", "?uint64array inStrat", "?int64array inStrax", "?arrayofstruct inStra(is)", "?nestedstruct inStr<(y(iu)) outStr>(y(iu))", NULL }; static const char* const paddingInterface[] = { "org.datatypes.test.padding.interface", /* The first entry is the interface name. */ "?paddingtest1 inStr<(yqut) outStr>(yqut)", /* Method at index 1. */ "?paddingtest2 inStr<(yqtu) outStr>(yqtu)", "?paddingtest3 inStr<(yuqt) outStr>(yuqt)", "?paddingtest4 inStr<(yutq) outStr>(yutq)", "?paddingtest5 inStr<(ytqu) outStr>(ytqu)", "?paddingtest6 inStr<(ytuq) outStr>(ytuq)", "?paddingtest7 inStr<(qyut) outStr>(qyut)", "?paddingtest8 inStr<(qytu) outStr>(qytu)", "?paddingtest9 inStr<(uyqt) outStr>(uyqt)", "?paddingtest10 inStr<(tyqu) outStr>(tyqu)", NULL }; /** * A NULL terminated collection of all interfaces. */ static const AJ_InterfaceDescription sampleInterfaces[] = { sampleInterface, paddingInterface, NULL }; /** * Objects implemented by the application. The first member in the AJ_Object structure is the path. * The second is the collection of all interfaces at that path. */ static const AJ_Object AppObjects[] = { { ServicePath, sampleInterfaces }, { NULL } }; /*Service*/ #define BASIC_SERVICE_BYTE AJ_APP_MESSAGE_ID(0, 0, 0) #define BASIC_SERVICE_INT AJ_APP_MESSAGE_ID(0, 0, 1) #define BASIC_SERVICE_UNSIGNED_INT AJ_APP_MESSAGE_ID(0, 0, 2) #define BASIC_SERVICE_DOUBLE AJ_APP_MESSAGE_ID(0, 0, 3) #define BASIC_SERVICE_BOOL AJ_APP_MESSAGE_ID(0, 0, 4) #define BASIC_SERVICE_STRING AJ_APP_MESSAGE_ID(0, 0, 5) #define BASIC_SERVICE_UINT16 AJ_APP_MESSAGE_ID(0, 0, 6) #define BASIC_SERVICE_INT16 AJ_APP_MESSAGE_ID(0, 0, 7) #define BASIC_SERVICE_UINT64 AJ_APP_MESSAGE_ID(0, 0, 8) #define BASIC_SERVICE_INT64 AJ_APP_MESSAGE_ID(0, 0, 9) #define BASIC_SERVICE_STRUCT AJ_APP_MESSAGE_ID(0, 0, 10) #define BASIC_SERVICE_DICT AJ_APP_MESSAGE_ID(0, 0, 11) #define BASIC_SERVICE_BYTE_ARRAY AJ_APP_MESSAGE_ID(0, 0, 12) #define BASIC_SERVICE_INT_ARRAY AJ_APP_MESSAGE_ID(0, 0, 13) #define BASIC_SERVICE_UINT_ARRAY AJ_APP_MESSAGE_ID(0, 0, 14) #define BASIC_SERVICE_DOUBLE_ARRAY AJ_APP_MESSAGE_ID(0, 0, 15) #define BASIC_SERVICE_BOOL_ARRAY AJ_APP_MESSAGE_ID(0, 0, 16) #define BASIC_SERVICE_STRING_ARRAY AJ_APP_MESSAGE_ID(0, 0, 17) #define BASIC_SERVICE_UINT16_ARRAY AJ_APP_MESSAGE_ID(0, 0, 18) #define BASIC_SERVICE_INT16_ARRAY AJ_APP_MESSAGE_ID(0, 0, 19) #define BASIC_SERVICE_UINT64_ARRAY AJ_APP_MESSAGE_ID(0, 0, 20) #define BASIC_SERVICE_INT64_ARRAY AJ_APP_MESSAGE_ID(0, 0, 21) #define BASIC_SERVICE_STRUCT_ARRAY AJ_APP_MESSAGE_ID(0, 0, 22) #define BASIC_SERVICE_NESTED_STRUCT AJ_APP_MESSAGE_ID(0, 0, 23) /*Client*/ #define BASIC_SERVICE_BYTE_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 0) #define BASIC_SERVICE_INT_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 1) #define BASIC_SERVICE_UNSIGNED_INT_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 2) #define BASIC_SERVICE_DOUBLE_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 3) #define BASIC_SERVICE_BOOL_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 4) #define BASIC_SERVICE_STRING_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 5) #define BASIC_SERVICE_UINT16_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 6) #define BASIC_SERVICE_INT16_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 7) #define BASIC_SERVICE_UINT64_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 8) #define BASIC_SERVICE_INT64_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 9) #define BASIC_SERVICE_STRUCT_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 10) #define BASIC_SERVICE_DICT_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 11) #define BASIC_SERVICE_BYTE_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 12) #define BASIC_SERVICE_INT_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 13) #define BASIC_SERVICE_UINT_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 14) #define BASIC_SERVICE_DOUBLE_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 15) #define BASIC_SERVICE_BOOL_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 16) #define BASIC_SERVICE_STRING_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 17) #define BASIC_SERVICE_UINT16_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 18) #define BASIC_SERVICE_INT16_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 19) #define BASIC_SERVICE_UINT64_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 20) #define BASIC_SERVICE_INT64_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 21) #define BASIC_SERVICE_STRUCT_ARRAY_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 22) #define BASIC_SERVICE_NESTED_STRUCT_CLIENT AJ_PRX_MESSAGE_ID(0, 0, 23) /*Service*/ #define BASIC_SERVICE_PADDING_1 AJ_APP_MESSAGE_ID(0, 1, 0) #define BASIC_SERVICE_PADDING_2 AJ_APP_MESSAGE_ID(0, 1, 1) #define BASIC_SERVICE_PADDING_3 AJ_APP_MESSAGE_ID(0, 1, 2) #define BASIC_SERVICE_PADDING_4 AJ_APP_MESSAGE_ID(0, 1, 3) #define BASIC_SERVICE_PADDING_5 AJ_APP_MESSAGE_ID(0, 1, 4) #define BASIC_SERVICE_PADDING_6 AJ_APP_MESSAGE_ID(0, 1, 5) #define BASIC_SERVICE_PADDING_7 AJ_APP_MESSAGE_ID(0, 1, 6) #define BASIC_SERVICE_PADDING_8 AJ_APP_MESSAGE_ID(0, 1, 7) #define BASIC_SERVICE_PADDING_9 AJ_APP_MESSAGE_ID(0, 1, 8) #define BASIC_SERVICE_PADDING_10 AJ_APP_MESSAGE_ID(0, 1, 9) /*Client*/ #define BASIC_CLIENT_PADDING_1 AJ_PRX_MESSAGE_ID(0, 1, 0) #define BASIC_CLIENT_PADDING_2 AJ_PRX_MESSAGE_ID(0, 1, 1) #define BASIC_CLIENT_PADDING_3 AJ_PRX_MESSAGE_ID(0, 1, 2) #define BASIC_CLIENT_PADDING_4 AJ_PRX_MESSAGE_ID(0, 1, 3) #define BASIC_CLIENT_PADDING_5 AJ_PRX_MESSAGE_ID(0, 1, 4) #define BASIC_CLIENT_PADDING_6 AJ_PRX_MESSAGE_ID(0, 1, 5) #define BASIC_CLIENT_PADDING_7 AJ_PRX_MESSAGE_ID(0, 1, 6) #define BASIC_CLIENT_PADDING_8 AJ_PRX_MESSAGE_ID(0, 1, 7) #define BASIC_CLIENT_PADDING_9 AJ_PRX_MESSAGE_ID(0, 1, 8) #define BASIC_CLIENT_PADDING_10 AJ_PRX_MESSAGE_ID(0, 1, 9) struct PaddingStruct { uint8_t byte; uint16_t uint16; uint32_t uint32; uint64_t uint64; }; struct SampleStruct { int intVar; unsigned char byte; int int32; unsigned int uint32; double doubleValue; bool boolValue; char* stringValue; uint16_t uint16; int16_t int16; int64_t int64; uint64_t uint64; }; struct ArrayStruct { int intVar; const char* stringValue; }; /* * Use async version of API for reply */ static uint8_t asyncForm = FALSE; /* All times are expressed in milliseconds. */ #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (1000 * 5) #define SLEEP_TIME (1000 * 2) #define METHOD_TIMEOUT (100 * 10) /*******************************************************************************/ /*******************************************************************************/ /* METHOD CALLS */ /*******************************************************************************/ /*******************************************************************************/ void ByteMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; unsigned char inputByte = 125; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_BYTE_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "y", inputByte); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("ByteMethodCall() resulted in a status of 0x%04x.\n", status)); } void IntMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int inputInt = 100; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_INT_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "i", inputInt); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("IntMethodCall() resulted in a status of 0x%04x.\n", status)); } void UnsignedIntMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; unsigned int inputInt = 4294967201; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_UNSIGNED_INT_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "u", inputInt); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("UnsignedIntMethodCall() resulted in a status of 0x%04x.\n", status)); } void DoubleMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; double inputDouble = -4294967201986; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_DOUBLE_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "d", inputDouble); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("DoubleMethodCall() resulted in a status of 0x%04x.\n", status)); } void BooleanMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; bool inputBool = false; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_BOOL_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "b", inputBool); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("BooleanMethodCall() resulted in a status of 0x%04x.\n", status)); } void StringMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; const char* inputString = "This is a cool string"; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_STRING_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", inputString); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("BooleanMethodCall() resulted in a status of 0x%04x.\n", status)); } void UInt16MethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; uint16_t inputUInt16 = 60500; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_UINT16_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "q", inputUInt16); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("UInt16MethodCall() resulted in a status of 0x%04x.\n", status)); } void Int16MethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; uint16_t inputUInt16 = -15236; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_INT16_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "n", inputUInt16); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Int16MethodCall() resulted in a status of 0x%04x.\n", status)); } void UInt64MethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; uint64_t inputUInt64 = 18446744073709551610ULL; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_UINT64_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "t", inputUInt64); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("UInt64MethodCall() resulted in a status of 0x%04x.\n", status)); } void Int64MethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int64_t inputUInt64 = -92233720368547758LL; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_INT64_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "x", inputUInt64); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Int64MethodCall() resulted in a status of 0x%04x.\n", status)); } void StructMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; struct SampleStruct structData; structData.byte = 254; structData.int32 = -65541; structData.uint32 = 65541; structData.doubleValue = 3.14908765; structData.boolValue = false; structData.stringValue = (char*)"Hello Struct"; structData.uint16 = 65535; structData.int16 = -32768; structData.int64 = -5223372036854775808LL; structData.uint64 = 6223372036854775808ULL; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_STRUCT_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(yiudbsqnxt)", structData.byte, structData.int32, structData.uint32, structData.doubleValue, structData.boolValue, structData.stringValue, structData.uint16, structData.int16, structData.int64, structData.uint64); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("StructMethodCall() resulted in a status of 0x%04x.\n", status)); } void DictionaryMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message dict; AJ_Arg array1; uint32_t key = 1; uint32_t val = 2134; status = AJ_MarshalMethodCall(bus, &dict, BASIC_SERVICE_DICT_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalContainer(&dict, &array1, AJ_ARG_ARRAY); } if (status == AJ_OK) { status = AJ_MarshalArgs(&dict, "{uv}", key, "u", val); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&dict, &array1); } if (status == AJ_OK) { status = AJ_DeliverMsg(&dict); } AJ_InfoPrintf(("DictionaryMethodCall resulted in a status of 0x%04x.\n", status)); } void ByteArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; uint8_t inputArray [5] = { 57, 125, 79, 100, 12 }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_BYTE_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { //status = AJ_MarshalContainer(&msg, &inputArray, AJ_ARG_ARRAY); status = AJ_MarshalArgs(&msg, "ay", inputArray, sizeof(inputArray)); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("ByteArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void IntArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; AJ_Arg array1; int inputArray [5] = { 1552, -1, -547, 101, 5269 }; int i; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_INT_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "i", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array1); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("IntArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void UnsignedIntArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; AJ_Arg array; unsigned int inputArray [5] = { 1552, 1, 5562447, 101, 565269 }; int i; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_UINT_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "u", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("UnsignedIntArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void DoubleArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; double inputArray [5] = { 789.66, 1.0009, 5562447, 175.569, -78.2 }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_DOUBLE_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "d", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("DoubleArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void BoolArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; bool inputArray [5] = { true, true, true, true, false }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_BOOL_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "b", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("BoolArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void StringArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; const char* inputArray [5] = { "Hello", "Hola Amigos", "Alljoyn", "Is Awesome", "IoT :)" }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_STRING_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "s", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("StringArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void UnsignedInt16ArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; uint16_t inputArray [5] = { 1564, 0, 4612, 12546, 125 }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_UINT16_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "q", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("UnsignedInt16ArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void Int16ArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; int16_t inputArray [5] = { 1564, 0, 4612, -13546, -125 }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_INT16_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "n", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("UnsignedInt16ArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void UnsignedInt64ArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; uint64_t inputArray [5] = { 1565151234, 1000000, 4656412, 1221546, 125 }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_UINT64_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "t", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("UnsignedInt64ArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void Int64ArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; int64_t inputArray [5] = { 1564562, 1145550, 4612, -2213546, -12655 }; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_INT64_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 5; ++i) { status = AJ_MarshalArgs(&msg, "x", inputArray[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Int64ArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void StructArrayMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; int i; AJ_Arg array; struct ArrayStruct struct1; struct ArrayStruct struct2; struct ArrayStruct struct3; struct ArrayStruct inputArray [3]; struct1.intVar = 509; struct1.stringValue = "Le First Line"; struct2.intVar = 59; struct2.stringValue = "Le Struct Line"; struct3.intVar = 3409; struct3.stringValue = "Le AllIoT Cool Line"; inputArray[0] = struct1; inputArray[1] = struct2; inputArray[2] = struct3; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_STRUCT_ARRAY_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < 3; i++) { status = AJ_MarshalArgs(&msg, "(is)", inputArray[i].intVar, inputArray[i].stringValue); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("StructArrayMethodCall() resulted in a status of 0x%04x.\n", status)); } void NestedStructMethodCall(AJ_BusAttachment* bus, uint32_t sessionId) { AJ_Status status; AJ_Message msg; uint8_t byte = 110; unsigned int uIntVal = 5894; int intVal = -4512; status = AJ_MarshalMethodCall(bus, &msg, BASIC_SERVICE_NESTED_STRUCT_CLIENT, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(y(iu))", byte, intVal, uIntVal); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("NestedStructMethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding1MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_1, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(yqut)", structP->byte, structP->uint16, structP->uint32, structP->uint64); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding1MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding2MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_2, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(yqtu)", structP->byte, structP->uint16, structP->uint64, structP->uint32); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding2MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding3MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_3, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(yuqt)", structP->byte, structP->uint32, structP->uint16, structP->uint64); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding3MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding4MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_4, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(yutq)", structP->byte, structP->uint32, structP->uint64, structP->uint16); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding4MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding5MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_5, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(ytqu)", structP->byte, structP->uint64, structP->uint16, structP->uint32); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding5MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding6MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_6, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(ytuq)", structP->byte, structP->uint64, structP->uint32, structP->uint16); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding6MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding7MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_7, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(qyut)", structP->uint16, structP->byte, structP->uint32, structP->uint64); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding7MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding8MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_8, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(qytu)", structP->uint16, structP->byte, structP->uint64, structP->uint32); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding8MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding9MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_9, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(uyqt)", structP->uint32, structP->byte, structP->uint16, structP->uint64); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding9MethodCall() resulted in a status of 0x%04x.\n", status)); } void Padding10MethodCall(AJ_BusAttachment* bus, uint32_t sessionId, struct PaddingStruct* structP) { AJ_Status status; AJ_Message msg; status = AJ_MarshalMethodCall(bus, &msg, BASIC_CLIENT_PADDING_10, fullServiceName, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "(tyqu)", structP->uint64, structP->byte, structP->uint16, structP->uint32); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_InfoPrintf(("Padding10MethodCall() resulted in a status of 0x%04x.\n", status)); } /*******************************************************************************/ /*******************************************************************************/ /* APP HANDLERS */ /*******************************************************************************/ /*******************************************************************************/ static AJ_Status AppHandleByte(AJ_Message* msg) { unsigned char value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "y", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_BYTE, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleInt(AJ_Message* msg) { int value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "i", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_INT32, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleUnsignedInt(AJ_Message* msg) { unsigned int value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "u", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_UINT32, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleDouble(AJ_Message* msg) { double value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "d", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_DOUBLE, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleBoolean(AJ_Message* msg) { bool value; AJ_Message reply; AJ_UnmarshalArgs(msg, "b", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "b", value); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleString(AJ_Message* msg) { #define BUFFER_SIZE 256 const char* value; char buffer[BUFFER_SIZE]; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "s", &value); /* We have the arguments. Now do the concatenation. */ strncpy(buffer, value, BUFFER_SIZE); buffer[BUFFER_SIZE - 1] = '\0'; if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_STRING, 0, &buffer, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); #undef BUFFER_SIZE } static AJ_Status AppHandleUInt16(AJ_Message* msg) { uint16_t value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "q", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_UINT16, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleInt16(AJ_Message* msg) { int16_t value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "n", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_INT16, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleUInt64(AJ_Message* msg) { uint64_t value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "t", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_UINT64, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleInt64(AJ_Message* msg) { int64_t value = 0; AJ_Message reply; AJ_Arg replyArg; AJ_UnmarshalArgs(msg, "x", &value); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_InitArg(&replyArg, AJ_ARG_INT64, 0, &value, 0); AJ_MarshalArg(&reply, &replyArg); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleStruct(AJ_Message* msg) { struct SampleStruct structData; AJ_Message reply; AJ_UnmarshalArgs(msg, "(yiudbsqnxt)", &structData.byte, &structData.int32, &structData.uint32, &structData.doubleValue, &structData.boolValue, &structData.stringValue, &structData.uint16, &structData.int16, &structData.int64, &structData.uint64); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(yiudbsqnxt)", structData.byte, structData.int32, structData.uint32, structData.doubleValue, structData.boolValue, structData.stringValue, structData.uint16, structData.int16, structData.int64, structData.uint64); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleDictionary(AJ_Message* msg) { AJ_Message reply; unsigned int key; unsigned int value; AJ_Arg array; AJ_Arg replyArray; AJ_UnmarshalContainer(msg, &array, AJ_ARG_ARRAY); AJ_UnmarshalArgs(msg, "{uv}", &key, "u", &value); AJ_UnmarshalCloseContainer(msg, &array); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &replyArray, AJ_ARG_ARRAY); AJ_MarshalArgs(&reply, "{uv}", key, "u", value); AJ_MarshalCloseContainer(&reply, &replyArray); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleByteArray(AJ_Message* msg) { AJ_Message reply; uint8_t* value; size_t size; AJ_UnmarshalArgs(msg, "ay", (const uint8_t**)&value, &size); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "ay", value, size); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandleIntArray(AJ_Message* msg) { AJ_Message reply; AJ_Status status; int* value = malloc(sizeof(int)); int i; size_t size = 0; AJ_Arg arg1; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { status = AJ_UnmarshalArgs(msg, "i", &value[size]); if (status == AJ_OK) { value = realloc(value, (size + 2) * sizeof(int)); size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "i", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleUnsignedIntArray(AJ_Message* msg) { AJ_Message reply; AJ_Status status; unsigned int* value = malloc(sizeof(unsigned int)); size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { status = AJ_UnmarshalArgs(msg, "u", &value[size]); if (status == AJ_OK) { value = realloc(value, (size + 2) * sizeof(int)); size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "u", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleDoubleArray(AJ_Message* msg) { AJ_Message reply; AJ_Status status; double* value = malloc(1 * sizeof(double)); size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { value = realloc(value, sizeof(double) * (size + 1)); status = AJ_UnmarshalArgs(msg, "d", &value[size]); if (status == AJ_OK) { size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "d", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleBoolArray(AJ_Message* msg) { AJ_Message reply; AJ_Status status; bool* value = malloc(1 * sizeof(bool)); size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { value = realloc(value, sizeof(bool) * (size + 1)); status = AJ_UnmarshalArgs(msg, "b", &value[size]); if (status == AJ_OK) { size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "b", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleStringArray(AJ_Message* msg) { AJ_Message reply; AJ_Status status; char** value = malloc(1 * sizeof(char*)); size_t size = 0; int i; AJ_Arg arg1; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { value = realloc(value, sizeof(char*) * (size + 1)); status = AJ_UnmarshalArgs(msg, "s", &value[size]); if (status == AJ_OK) { size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "s", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleUnsignedInt16Array(AJ_Message* msg) { AJ_Message reply; AJ_Status status; uint16_t* value = malloc(1 * sizeof(uint16_t)); size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { value = realloc(value, sizeof(uint16_t) * (size + 1)); status = AJ_UnmarshalArgs(msg, "q", &value[size]); if (status == AJ_OK) { size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "q", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleInt16Array(AJ_Message* msg) { AJ_Message reply; AJ_Status status; int16_t* value = malloc(1 * sizeof(int16_t)); size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { value = realloc(value, sizeof(int16_t) * (size + 1)); status = AJ_UnmarshalArgs(msg, "n", &value[size]); if (status == AJ_OK) { size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "n", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleUnsignedInt64Array(AJ_Message* msg) { AJ_Message reply; AJ_Status status; uint64_t* value = malloc(1 * sizeof(uint64_t)); size_t size = 0; int i; AJ_Arg arg1; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { value = realloc(value, sizeof(uint64_t) * (size + 1)); status = AJ_UnmarshalArgs(msg, "t", &value[size]); if (status == AJ_OK) { size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "t", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleInt64Array(AJ_Message* msg) { AJ_Message reply; AJ_Status status; int64_t* value = malloc(1 * sizeof(int64_t)); size_t size = 0; int i; AJ_Arg arg1; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { value = realloc(value, sizeof(int64_t) * (size + 1)); status = AJ_UnmarshalArgs(msg, "x", &value[size]); if (status == AJ_OK) { size++; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "x", value[i]); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleStructArray(AJ_Message* msg) { AJ_Message reply; AJ_Status status; struct ArrayStruct* value = malloc(1 * sizeof(struct ArrayStruct)); size_t size = 0; int i; AJ_Arg arg1; status = AJ_UnmarshalContainer(msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK) { status = AJ_UnmarshalArgs(msg, "(is)", &value[size].intVar, &value[size].stringValue); if (status == AJ_OK) { size++; value = realloc(value, sizeof(struct ArrayStruct) * (size + 1)); } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg1); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalContainer(&reply, &arg1, AJ_ARG_ARRAY); if (status == AJ_OK) { for (i = 0; i < size; ++i) { status = AJ_MarshalArgs(&reply, "(is)", value[i].intVar, value[i].stringValue); } } if (status == AJ_OK) { AJ_MarshalCloseContainer(&reply, &arg1); } status = AJ_DeliverMsg(&reply); free(value); return status; } static AJ_Status AppHandleNestedStruct(AJ_Message* msg) { AJ_Message reply; uint8_t byte; unsigned int uIntVal; int intVal; AJ_UnmarshalArgs(msg, "(y(iu))", &byte, &intVal, &uIntVal); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(y(iu))", byte, intVal, uIntVal); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding1(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(yqut)", &byte, &uint16Val, &uint32Val, &uint64Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(yqut)", byte, uint16Val, uint32Val, uint64Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding2(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(yqtu)", &byte, &uint16Val, &uint64Val, &uint32Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(yqtu)", byte, uint16Val, uint64Val, uint32Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding3(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(yuqt)", &byte, &uint32Val, &uint16Val, &uint64Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(yuqt)", byte, uint32Val, uint16Val, uint64Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding4(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(yutq)", &byte, &uint32Val, &uint64Val, &uint16Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(yutq)", byte, uint32Val, uint64Val, uint16Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding5(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(ytqu)", &byte, &uint64Val, &uint16Val, &uint32Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(ytqu)", byte, uint64Val, uint16Val, uint32Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding6(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(ytuq)", &byte, &uint64Val, &uint32Val, &uint16Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(ytuq)", byte, uint64Val, uint32Val, uint16Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding7(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(qyut)", &uint16Val, &byte, &uint32Val, &uint64Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(qyut)", uint16Val, byte, uint32Val, uint64Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding8(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(qytu)", &uint16Val, &byte, &uint64Val, &uint32Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(qytu)", uint16Val, byte, uint64Val, uint32Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding9(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(uyqt)", &uint32Val, &byte, &uint16Val, &uint64Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(uyqt)", uint32Val, byte, uint16Val, uint64Val); return AJ_DeliverMsg(&reply); } static AJ_Status AppHandlePadding10(AJ_Message* msg) { AJ_Message reply; uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; AJ_UnmarshalArgs(msg, "(tyqu)", &uint64Val, &byte, &uint16Val, &uint32Val); if (asyncForm) { AJ_MsgReplyContext replyCtx; AJ_CloseMsgAndSaveReplyContext(msg, &replyCtx); AJ_MarshalReplyMsgAsync(&replyCtx, &reply); } else { AJ_MarshalReplyMsg(msg, &reply); } AJ_MarshalArgs(&reply, "(tyqu)", uint64Val, byte, uint16Val, uint32Val); return AJ_DeliverMsg(&reply); } int AJ_ClientMain(bool padding) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint8_t done = FALSE; uint32_t sessionId = 0; struct PaddingStruct paddingStruct; if (padding) { paddingStruct.byte = 10; paddingStruct.uint16 = 10589; paddingStruct.uint32 = 68254; paddingStruct.uint64 = 9845612; } /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(NULL, AppObjects); /***********************************************************************************************/ /* Int*/ /***********************************************************************************************/ while (!done) { AJ_Message msg; if (!connected) { status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServiceName, ServicePort, &sessionId, NULL, fullServiceName); if (status == AJ_OK) { AJ_InfoPrintf(("StartClient returned %d, sessionId=%u.\n", status, sessionId)); connected = TRUE; AJ_AlwaysPrintf(("Method call %s \n", "Int")); IntMethodCall(&bus, sessionId); } else { AJ_InfoPrintf(("StartClient returned 0x%04x.\n", status)); break; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_REPLY_ID(BASIC_SERVICE_INT_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { int valueReturned = *arg.val.v_int32; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%i'.\n", fullServiceName, "interface", ServicePath, valueReturned)); //done = TRUE; } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ IntMethodCall(&bus, sessionId); } } else { const int valueReturned = 0; if (AJ_UnmarshalArgs(&msg, "y", &valueReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%i)\n", msg.error, valueReturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } //done = TRUE; } /*Byte Method Call*/ AJ_AlwaysPrintf(("Method call %s \n", "Byte")); ByteMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /* Byte*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_BYTE_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { const unsigned char byte = *arg.val.v_byte; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u'.\n", fullServiceName, "interface", ServicePath, byte)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ ByteMethodCall(&bus, sessionId); } } else { const uint8_t value = 0; if (AJ_UnmarshalArgs(&msg, "y", &value) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, value)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } /*Unsigned int method call*/ AJ_AlwaysPrintf(("Method call %s \n", "Unsigned Int")); UnsignedIntMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Unsigned int */ /************************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_UNSIGNED_INT_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { unsigned int uintreturned = *arg.val.v_uint32; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u'.\n", fullServiceName, "interface", ServicePath, uintreturned)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ UnsignedIntMethodCall(&bus, sessionId); } } else { const unsigned int uintreturned = 0; if (AJ_UnmarshalArgs(&msg, "u", &uintreturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, uintreturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } /*Double Method Call*/ AJ_AlwaysPrintf(("Method call %s \n", "Double")); DoubleMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Double*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_DOUBLE_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { double doubleReturned = *arg.val.v_double; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%f'.\n", fullServiceName, "interface", ServicePath, doubleReturned)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ DoubleMethodCall(&bus, sessionId); } } else { const double doubleReturned = 0; if (AJ_UnmarshalArgs(&msg, "u", &doubleReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, doubleReturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } /*Bool Method Call*/ AJ_AlwaysPrintf(("Method call %s \n", "Boolean")); BooleanMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Bool*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_BOOL_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { bool boolReturned = *arg.val.v_bool; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%s'.\n", fullServiceName, "interface", ServicePath, boolReturned ? "TRUE" : "FALSE")); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ BooleanMethodCall(&bus, sessionId); } } else { const bool boolReturned = 0; if (AJ_UnmarshalArgs(&msg, "b", &boolReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%s)\n", msg.error, boolReturned ? "TRUE" : "FALSE")); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } /*String method Call*/ StringMethodCall(&bus, sessionId); AJ_AlwaysPrintf(("Method call %s \n", "String")); break; /***********************************************************************************************/ /*String*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_STRING_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { const char* stringReturned = arg.val.v_string; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%s'.\n", fullServiceName, "interface", ServicePath, stringReturned)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ StringMethodCall(&bus, sessionId); } } else { const char* stringReturned = ""; if (AJ_UnmarshalArgs(&msg, "s", &stringReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%s)\n", msg.error, stringReturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Unsigned Int 16")); UInt16MethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Unsigned Int 16*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_UINT16_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { uint16_t uintReturned = *arg.val.v_uint16; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u'.\n", fullServiceName, "interface", ServicePath, uintReturned)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ UInt16MethodCall(&bus, sessionId); } } else { const uint16_t uintReturned = 0; if (AJ_UnmarshalArgs(&msg, "q", &uintReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, uintReturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Int 16")); Int16MethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Int 16*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_INT16_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { int16_t intReturned = *arg.val.v_int16; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%d'.\n", fullServiceName, "interface", ServicePath, intReturned)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Int16MethodCall(&bus, sessionId); } } else { const int16_t intReturned = 0; if (AJ_UnmarshalArgs(&msg, "n", &intReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, intReturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Unsigned Int 64")); UInt64MethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Unsigned Int 64*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_UINT64_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { uint64_t uintReturned = *arg.val.v_uint64; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%llu'.\n", fullServiceName, "interface", ServicePath, uintReturned)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ UInt64MethodCall(&bus, sessionId); } } else { const uint16_t uintReturned = 0; if (AJ_UnmarshalArgs(&msg, "t", &uintReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%llu)\n", msg.error, uintReturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Int 64")); Int64MethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Int 64*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_INT64_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { AJ_Arg arg; status = AJ_UnmarshalArg(&msg, &arg); if (AJ_OK == status) { int64_t intReturned = *arg.val.v_int64; AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%lld'.\n", fullServiceName, "interface", ServicePath, intReturned)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Int64MethodCall(&bus, sessionId); } } else { const int16_t intReturned = 0; if (AJ_UnmarshalArgs(&msg, "x", &intReturned) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%llu)\n", msg.error, intReturned)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Struct")); StructMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Struct */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_STRUCT_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { struct SampleStruct structData; status = AJ_UnmarshalArgs(&msg, "(yiudbsqnxt)", &structData.byte, &structData.int32, &structData.uint32, &structData.doubleValue, &structData.boolValue, &structData.stringValue, &structData.uint16, &structData.int16, &structData.int64, &structData.uint64); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%d'.\n", fullServiceName, "interface", ServicePath, structData.int32)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ StructMethodCall(&bus, sessionId); } } else { struct SampleStruct structData; if (AJ_UnmarshalArgs(&msg, "(yiudbsqnxt)", &structData.byte, &structData.int32, &structData.uint32, &structData.doubleValue, &structData.boolValue, &structData.stringValue, &structData.uint16, &structData.int16, &structData.int64, &structData.uint64) == AJ_OK) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%lld'.\n", fullServiceName, "interface", ServicePath, structData.int32)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Dictionary")); DictionaryMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Dictionary */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_DICT_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { unsigned int key; unsigned int value; AJ_Arg array; status = AJ_UnmarshalContainer(&msg, &array, AJ_ARG_ARRAY); status = AJ_UnmarshalArgs(&msg, "{uv}", &key, "u", &value); status = AJ_UnmarshalCloseContainer(&msg, &array); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' ' %u'.\n", fullServiceName, "interface", ServicePath, key, value)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ StructMethodCall(&bus, sessionId); } } else { unsigned int key; unsigned int value; AJ_Arg array; status = AJ_UnmarshalContainer(&msg, &array, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "{uv}", &key, "u", &value) == AJ_OK) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' ' %u'.\n", fullServiceName, "interface", ServicePath, key, value)); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_UnmarshalCloseContainer(&msg, &array); } AJ_AlwaysPrintf(("Method call %s \n", "Byte Array")); ByteArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Byte Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_BYTE_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t* array; size_t size; int i; status = AJ_UnmarshalArgs(&msg, "ay", (const uint8_t**)&array, &size); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < size; i++) { AJ_AlwaysPrintf(("Value '%d' %u'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ ByteArrayMethodCall(&bus, sessionId); } } else { uint8_t* array; size_t size; if (AJ_UnmarshalArgs(&msg, "ay", (const uint8_t**)&array, &size) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Int Array")); IntArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Int Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_INT_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; int32_t array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "i", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%d'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %d'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ IntArrayMethodCall(&bus, sessionId); } } else { int* array; size_t size; if (AJ_UnmarshalArgs(&msg, "ai", (const int**)&array, &size) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Unsigned Int Array")); UnsignedIntArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Unsigned Int Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_UINT_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; unsigned int array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "u", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %u'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ UnsignedIntArrayMethodCall(&bus, sessionId); } } else { unsigned int* array; size_t size; if (AJ_UnmarshalArgs(&msg, "au", (const unsigned int**)&array, &size) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%u)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } } AJ_AlwaysPrintf(("Method call %s \n", "Int Array")); DoubleArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Double Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_DOUBLE_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; double array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "d", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%f'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %f'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ DoubleArrayMethodCall(&bus, sessionId); } } else { double array [5]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "d", &array[0]) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "Bool Array")); BoolArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Bool Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_BOOL_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; bool array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "b", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%s'.\n", fullServiceName, "interface", ServicePath, array[0] ? "true" : "false")); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %s'.\n", i, array[i] ? "true" : "false")); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ DoubleArrayMethodCall(&bus, sessionId); } } else { bool array [5]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "b", &array[0]) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "String Array")); StringArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*String Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_STRING_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; char* array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "s", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%s'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %s'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ StringArrayMethodCall(&bus, sessionId); } } else { char* array [5]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "s", &array[0]) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "Unsigned Int 16 Array")); UnsignedInt16ArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Unsigned Int 16 Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_UINT16_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; uint16_t array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "q", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %u'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ UnsignedInt16ArrayMethodCall(&bus, sessionId); } } else { uint16_t array [5]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "q", &array[0]) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "Int 16 Array")); Int16ArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Int 16 Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_INT16_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; int16_t array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "n", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%d'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %d'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Int16ArrayMethodCall(&bus, sessionId); } } else { int16_t array [5]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "n", &array[0]) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "Unsigned Int 64 Array")); UnsignedInt64ArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Unsigned Int 16 Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_UINT64_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; uint64_t array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "t", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %u'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ UnsignedInt64ArrayMethodCall(&bus, sessionId); } } else { uint64_t array [5]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "t", &array[0]) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "Int 64 Array")); Int64ArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Int 64 Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_INT64_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 5; int64_t array [5]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "x", &array[size]); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%d'.\n", fullServiceName, "interface", ServicePath, array[0])); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' %d'.\n", i, array[i])); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Int64ArrayMethodCall(&bus, sessionId); } } else { int64_t array [5]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "n", &array[0]) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "Struct Array")); StructArrayMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Int 64 Array*/ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_STRUCT_ARRAY_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { int arrayLength = 3; struct ArrayStruct array [3]; size_t size = 0; AJ_Arg arg1; int i; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); while (status == AJ_OK || (size < arrayLength)) { status = AJ_UnmarshalArgs(&msg, "(is)", &array[size].intVar, &array[size].stringValue); size++; } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } status = AJ_UnmarshalCloseContainer(&msg, &arg1); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%d' '%s'.\n", fullServiceName, "interface", ServicePath, array[0].intVar, array[0].stringValue)); for (i = 1; i < arrayLength; i++) { AJ_AlwaysPrintf(("Value '%d' '%d' '%s' .\n", i, array[i].intVar, array[i].stringValue)); } } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ StructArrayMethodCall(&bus, sessionId); } } else { struct ArrayStruct array [3]; AJ_Arg arg1; status = AJ_UnmarshalContainer(&msg, &arg1, AJ_ARG_ARRAY); if (AJ_UnmarshalArgs(&msg, "(is)", &array[0].intVar, &array[0].stringValue) == AJ_OK) { AJ_AlwaysPrintf(("Method call returned error %s (%f)\n", msg.error, array[0])); } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } status = AJ_UnmarshalCloseContainer(&msg, &arg1); } AJ_AlwaysPrintf(("Method call %s \n", "Nested Struct Array")); NestedStructMethodCall(&bus, sessionId); break; /***********************************************************************************************/ /*Nested Struct */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_SERVICE_NESTED_STRUCT_CLIENT): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; int intVal; unsigned int uIntVal; status = AJ_UnmarshalArgs(&msg, "(y(iu))", &byte, &intVal, &uIntVal); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %d' '%u'.\n", fullServiceName, "interface", ServicePath, byte, intVal, uIntVal)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ NestedStructMethodCall(&bus, sessionId); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } if (padding) { AJ_AlwaysPrintf(("Method call %s \n", "Padding 1")); Padding1MethodCall(&bus, sessionId, &paddingStruct); break; } else { done = TRUE; break; } /***********************************************************************************************/ /*Padding 1 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_1): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(yqut)", &byte, &uint16Val, &uint32Val, &uint64Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %u' '%u' '%llu'.\n", fullServiceName, "padding", ServicePath, byte, uint16Val, uint32Val, uint64Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding1MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 2")); Padding2MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 2 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_2): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(yqtu)", &byte, &uint16Val, &uint64Val, &uint32Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %u' '%llu' '%u'.\n", fullServiceName, "padding", ServicePath, byte, uint16Val, uint64Val, uint32Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding2MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 3")); Padding3MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 3 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_3): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(yuqt)", &byte, &uint32Val, &uint16Val, &uint64Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %u' '%u' '%llu'.\n", fullServiceName, "padding", ServicePath, byte, uint32Val, uint16Val, uint64Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding3MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 4")); Padding4MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 4 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_4): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(yutq)", &byte, &uint32Val, &uint64Val, &uint16Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %u' '%llu' '%u'.\n", fullServiceName, "padding", ServicePath, byte, uint32Val, uint64Val, uint16Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding4MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 5")); Padding5MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 5 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_5): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(ytqu)", &byte, &uint64Val, &uint16Val, &uint32Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %llu' '%u' '%u'.\n", fullServiceName, "padding", ServicePath, byte, uint64Val, uint16Val, uint32Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding5MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 6")); Padding6MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 6 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_6): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(ytuq)", &byte, &uint64Val, &uint32Val, &uint16Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %llu' '%u' '%u'.\n", fullServiceName, "padding", ServicePath, byte, uint64Val, uint32Val, uint16Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding6MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 7")); Padding7MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 7 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_7): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(qyut)", &uint16Val, &byte, &uint32Val, &uint64Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %u' '%u' '%llu'.\n", fullServiceName, "padding", ServicePath, uint16Val, byte, uint32Val, uint64Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding7MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 8")); Padding8MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 8 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_8): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(qytu)", &uint16Val, &byte, &uint64Val, &uint32Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %u' '%llu' '%u'.\n", fullServiceName, "padding", ServicePath, uint16Val, byte, uint64Val, uint32Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding8MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 9")); Padding9MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 9 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_9): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(uyqt)", &uint32Val, &byte, &uint16Val, &uint64Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%u' %u' '%u' '%llu'.\n", fullServiceName, "padding", ServicePath, uint32Val, byte, uint16Val, uint64Val)); } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding9MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } AJ_AlwaysPrintf(("Method call %s \n", "Padding 10")); Padding10MethodCall(&bus, sessionId, &paddingStruct); break; /***********************************************************************************************/ /*Padding 10 */ /***********************************************************************************************/ case AJ_REPLY_ID(BASIC_CLIENT_PADDING_10): if (msg.hdr->msgType == AJ_MSG_METHOD_RET) { uint8_t byte; uint16_t uint16Val; uint32_t uint32Val; uint64_t uint64Val; status = AJ_UnmarshalArgs(&msg, "(tyqu)", &uint64Val, &byte, &uint16Val, &uint32Val); if (AJ_OK == status) { AJ_AlwaysPrintf(("'%s.%s' (path='%s') returned '%llu' '%u' '%u' '%u'.\n", fullServiceName, "padding", ServicePath, uint64Val, byte, uint16Val, uint32Val)); done = TRUE; } else { AJ_InfoPrintf(("AJ_UnmarshalArg() returned status %d.\n", status)); /* Try again because of the failure. */ Padding10MethodCall(&bus, sessionId, &paddingStruct); } } else { AJ_AlwaysPrintf(("Method call returned error %s\n", msg.error)); } done = TRUE; break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* A session was lost so return error to force a disconnect. */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u\n", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); } if (status == AJ_ERR_SESSION_LOST) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); exit(0); } AJ_AlwaysPrintf(("Basic client exiting with status %d.\n", status)); return status; } int AJ_ServiceMain(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; /* One time initialization before calling any other AllJoyn APIs. */ AJ_Initialize(); /* This is for debug purposes and is optional. */ AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status == AJ_OK) { AJ_InfoPrintf(("StartService returned %d, session_id=%u\n", status, sessionId)); connected = TRUE; } else { continue; } } //if (AJ_OK == status) { status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); //} if (AJ_ERR_TIMEOUT == status) { continue; } if (AJ_OK == status) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); AJ_AlwaysPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } break; case BASIC_SERVICE_BYTE: status = AppHandleByte(&msg); break; case BASIC_SERVICE_INT: status = AppHandleInt(&msg); break; case BASIC_SERVICE_UNSIGNED_INT: status = AppHandleUnsignedInt(&msg); break; case BASIC_SERVICE_DOUBLE: status = AppHandleDouble(&msg); break; case BASIC_SERVICE_BOOL: status = AppHandleBoolean(&msg); break; case BASIC_SERVICE_STRING: status = AppHandleString(&msg); break; case BASIC_SERVICE_UINT16: status = AppHandleUInt16(&msg); break; case BASIC_SERVICE_INT16: status = AppHandleInt16(&msg); break; case BASIC_SERVICE_UINT64: status = AppHandleUInt64(&msg); break; case BASIC_SERVICE_INT64: status = AppHandleInt64(&msg); break; case BASIC_SERVICE_STRUCT: status = AppHandleStruct(&msg); break; case BASIC_SERVICE_DICT: status = AppHandleDictionary(&msg); break; case BASIC_SERVICE_BYTE_ARRAY: status = AppHandleByteArray(&msg); break; case BASIC_SERVICE_INT_ARRAY: status = AppHandleIntArray(&msg); break; case BASIC_SERVICE_UINT_ARRAY: status = AppHandleUnsignedIntArray(&msg); break; case BASIC_SERVICE_DOUBLE_ARRAY: status = AppHandleDoubleArray(&msg); break; case BASIC_SERVICE_BOOL_ARRAY: status = AppHandleBoolArray(&msg); break; case BASIC_SERVICE_STRING_ARRAY: status = AppHandleStringArray(&msg); break; case BASIC_SERVICE_UINT16_ARRAY: status = AppHandleUnsignedInt16Array(&msg); break; case BASIC_SERVICE_INT16_ARRAY: status = AppHandleInt16Array(&msg); break; case BASIC_SERVICE_UINT64_ARRAY: status = AppHandleUnsignedInt64Array(&msg); break; case BASIC_SERVICE_INT64_ARRAY: status = AppHandleInt64Array(&msg); break; case BASIC_SERVICE_STRUCT_ARRAY: status = AppHandleStructArray(&msg); break; case BASIC_SERVICE_NESTED_STRUCT: status = AppHandleNestedStruct(&msg); break; case BASIC_SERVICE_PADDING_1: status = AppHandlePadding1(&msg); break; case BASIC_SERVICE_PADDING_2: status = AppHandlePadding2(&msg); break; case BASIC_SERVICE_PADDING_3: status = AppHandlePadding3(&msg); break; case BASIC_SERVICE_PADDING_4: status = AppHandlePadding4(&msg); break; case BASIC_SERVICE_PADDING_5: status = AppHandlePadding5(&msg); break; case BASIC_SERVICE_PADDING_6: status = AppHandlePadding6(&msg); break; case BASIC_SERVICE_PADDING_7: status = AppHandlePadding7(&msg); break; case BASIC_SERVICE_PADDING_8: status = AppHandlePadding8(&msg); break; case BASIC_SERVICE_PADDING_9: status = AppHandlePadding9(&msg); break; case BASIC_SERVICE_PADDING_10: status = AppHandlePadding10(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u\n", id, reason)); } break; default: /* Pass to the built-in handlers. */ status = AJ_BusHandleBusMessage(&msg); break; } } /* Messages MUST be discarded to free resources. */ AJ_CloseMsg(&msg); if (status == AJ_ERR_READ) { AJ_AlwaysPrintf(("AllJoyn disconnect.\n")); AJ_Disconnect(&bus); connected = FALSE; /* Sleep a little while before trying to reconnect. */ AJ_Sleep(SLEEP_TIME); } } AJ_AlwaysPrintf(("Basic service exiting with status %d.\n", status)); return status; } static void usage(void) { printf("Usage: marshal_unmarshal_test [-h] [-s] [-c]\n\n"); printf("Options:\n"); printf(" -h = Print this help message\n"); printf(" -s = Run the program as a service\n"); printf(" -c = Run the program as a client\n"); printf(" -p = Run padding tests\n"); printf("\n"); } #ifdef AJ_MAIN int main(int argc, char** argv) { int16_t appType = 0; bool paddingTest = false; int i; /* Parse command line args */ for (i = 1; i < argc; ++i) { if (0 == strcmp("-h", argv[i])) { usage(); exit(0); } else if (0 == strcmp("-c", argv[i])) { appType = 1; } else if (0 == strcmp("-s", argv[i])) { appType = 2; } else if (0 == strcmp("-p", argv[i])) { paddingTest = true; } else { AJ_AlwaysPrintf(("Unknown Option %s", argv[i])); usage(); exit(1); } } if (appType == 2) { //#define AJ_MODULE BASIC_SERVICE return AJ_ServiceMain(); } else { if (appType == 1) { //#define AJ_MODULE BASIC_CLIENT return AJ_ClientMain(paddingTest); } else { usage(); } return 0; } } #endif ajtcl-16.04/test/mouse.c000066400000000000000000000175051271074662300151140ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #include #include #define ACCEL_SENSOR_PORT gpioPortA #define ACCEL_SENSOR_PIN 10 #define ACCEL_SELFTEST_PORT gpioPortA #define ACCEL_SELFTEST_PIN 2 #define ACCEL_SLEEP_PORT gpioPortF #define ACCEL_SLEEP_PIN 4 extern int ButtonPushed; static const char ServiceName[] = "org.alljoyn.ajlite"; static const uint16_t ServicePort = 24; static const char* testInterface[] = { "org.alljoyn.ajlite_test", "!ADC_Update >i", "!Gyro_Update >i >i", "!Button_Down >i", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { testInterface, NULL }; /** * Objects implemented by the application */ static const AJ_Object AppObjects[] = { { "/org/alljoyn/ajlite_test", testInterfaces }, { NULL } }; #define APP_ADC_UPDATE_SIGNAL AJ_APP_MESSAGE_ID(0, 0, 0) #define APP_GYROSCOPE_UPDATE_SIGNAL AJ_APP_MESSAGE_ID(0, 0, 1) #define APP_BUTTON_DOWN_SIGNAL AJ_APP_MESSAGE_ID(0, 0, 2) void sendClickSignal(AJ_BusAttachment* bus, int pushed); /* * Let the application do some work */ static void AppDoWork(AJ_BusAttachment* bus) { static int oldX = -1; static int oldY = -1; static int initialized = FALSE; int x, y; ADC_Init_TypeDef init = ADC_INIT_DEFAULT; ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT; if (initialized == FALSE) { /*Turn on accelerometer*/ GPIO_PinModeSet(ACCEL_SENSOR_PORT, ACCEL_SENSOR_PIN, gpioModePushPull, 1); /*Disable sleep*/ GPIO_PinModeSet(ACCEL_SLEEP_PORT, ACCEL_SLEEP_PIN, gpioModePushPull, 1); /*Disable self test*/ GPIO_PinModeSet(ACCEL_SELFTEST_PORT, ACCEL_SELFTEST_PIN, gpioModePushPull, 0); } CMU_ClockEnable(cmuClock_HFPER, true); CMU_ClockEnable(cmuClock_ADC0, true); init.timebase = ADC_TimebaseCalc(0); init.prescale = ADC_PrescaleCalc(4000000, 0); ADC_Init(ADC0, &init); /* Init for single conversion use. */ singleInit.reference = adcRefVDD; //adcRef2V5; singleInit.resolution = adcRes12Bit; singleInit.input = adcSingleInpCh6; /* According to Maui HW design */ ADC_InitSingle(ADC0, &singleInit); ADC_IntClear(ADC0, ADC_IF_SINGLE); ADC_Start(ADC0, adcStartSingle); /* Wait for completion */ while (!(ADC_IntGet(ADC0) & ADC_IF_SINGLE)); x = ADC_DataSingleGet(ADC0); /* According to Maui HW design */ singleInit.input = adcSingleInpCh7; ADC_InitSingle(ADC0, &singleInit); ADC_IntClear(ADC0, ADC_IF_SINGLE); ADC_Start(ADC0, adcStartSingle); /* Wait for completion */ while (!(ADC_IntGet(ADC0) & ADC_IF_SINGLE)); y = ADC_DataSingleGet(ADC0); // send the message if (x != oldX || y != oldY) { AJ_Message msg; oldX = x; oldY = y; AJ_MarshalSignal(bus, &msg, APP_GYROSCOPE_UPDATE_SIGNAL, NULL, 0, 0, 0); AJ_MarshalArgs(&msg, "uu", x, y); AJ_DeliverMsg(&msg); } if (ButtonPushed) { sendClickSignal(bus, ButtonPushed); ButtonPushed = 0; } } static const char PWD[] = "ABCDEFGH"; static uint32_t PasswordFunc(uint8_t* buffer, uint32_t bufLen) { memcpy(buffer, PWD, sizeof(PWD)); return sizeof(PWD) - 1; } void sendClickSignal(AJ_BusAttachment* bus, int pushed) { AJ_Message msg; AJ_MarshalSignal(bus, &msg, APP_BUTTON_DOWN_SIGNAL, NULL, 0, 0, 0); AJ_MarshalArgs(&msg, "u", pushed); AJ_DeliverMsg(&msg); } #define CONNECT_TIMEOUT (1000 * 60) #define UNMARSHAL_TIMEOUT (10) int AJ_Main(void) { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { ButtonPushed = 0; status = AJ_FindBusAndConnect(&bus, NULL, CONNECT_TIMEOUT); if (status != AJ_OK) { AJ_AlwaysPrintf(("AllJoyn failed to connect sleeping for 15 seconds\n")); AJ_Sleep(15 * 1000); continue; } AJ_AlwaysPrintf(("AllJoyn connected\n")); /* * Kick things off by binding a session port */ status = AJ_BusBindSessionPort(&bus, ServicePort, NULL); if (status != AJ_OK) { AJ_AlwaysPrintf(("Failed to send bind session port message\n")); break; } connected = TRUE; } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(&bus); } continue; } switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_BIND_SESSION_PORT): /* * TODO check the reply args to tell if the request succeeded */ status = AJ_BusRequestName(&bus, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE); break; case AJ_REPLY_ID(AJ_METHOD_REQUEST_NAME): /* * TODO check the reply args to tell if the request succeeded */ status = AJ_BusAdvertiseName(&bus, ServiceName, AJ_TRANSPORT_ANY, AJ_BUS_START_ADVERTISING); break; case AJ_REPLY_ID(AJ_METHOD_ADVERTISE_NAME): /* * TODO check the reply args to tell if the request succeeded */ break; case AJ_METHOD_ACCEPT_SESSION: status = AJ_BusReplyAcceptSession(&msg, TRUE); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * Force a disconnect */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_InfoPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_SESSION_LOST) || (status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_AlwaysPrintf(("AllJoyn disconnect\n")); AJ_Disconnect(&bus); connected = FALSE; /* * Sleep a little while before trying to reconnect */ AJ_Sleep(10 * 1000); } } AJ_AlwaysPrintf(("svclite EXIT %d\n", status)); return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/mutter.c000066400000000000000000001644501271074662300153060ustar00rootroot00000000000000/** * @file Marhal/Unmarshal Tester */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include static uint8_t wireBuffer[8 * 1024]; static size_t wireBytes = 0; static uint8_t txBuffer[1024]; static uint8_t rxBuffer[1024]; static AJ_Status TxFunc(AJ_IOBuffer* buf) { size_t tx = AJ_IO_BUF_AVAIL(buf);; if ((wireBytes + tx) > sizeof(wireBuffer)) { return AJ_ERR_WRITE; } else { memcpy(wireBuffer + wireBytes, buf->bufStart, tx); AJ_IO_BUF_RESET(buf); wireBytes += tx; return AJ_OK; } } AJ_Status RxFunc(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { size_t rx = AJ_IO_BUF_SPACE(buf); rx = min(len, rx); rx = min(wireBytes, rx); if (!rx) { return AJ_ERR_READ; } else { memcpy(buf->writePtr, wireBuffer, rx); /* * Shuffle the remaining data to the front of the buffer */ memmove(wireBuffer, wireBuffer + rx, wireBytes - rx); wireBytes -= rx; buf->writePtr += rx; return AJ_OK; } } static const char* const testSignature[] = { "ays", /* 0 */ "a{us}", /* 1 */ "u(usu(ii)qsq)yyy", /* 2 */ "a(usay)", /* 3 */ "aas", /* 4 */ "ivi", /* 5 */ "v", /* 6 */ "v", /* 7 */ "(vvvvvv)", /* 8 */ "uqay", /* 9 */ "a(uuuu)", /* 10 */ "a(sss)", /* 11 */ "ya{ss}", /* 12 */ "yyyyya{ys}", /* 13 */ "(iay)", /* 14 */ "ia{iv}i", /* 15 */ "ay", /* 16 */ "a{s(us)}", /* 17 */ "(yva(yay))", /* 18 */ "d", /* 19 */ "ad" /* 20 */ }; typedef struct { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } TestStruct; typedef struct { int32_t m; int32_t n; } TestInnerStruct; typedef struct { uint32_t u; char* str1; uint32_t v; TestInnerStruct inner; uint16_t q; char* str2; uint16_t r; } TestNestedStruct; #ifndef NDEBUG static AJ_Status MsgInit(AJ_Message* msg, uint32_t msgId, uint8_t msgType) { msg->objPath = "/test/mutter"; msg->iface = "test.mutter"; msg->member = "mumble"; msg->msgId = msgId; msg->signature = testSignature[msgId]; return AJ_OK; } extern AJ_MutterHook MutterHook; #endif static const char* const Fruits[] = { "apple", "banana", "cherry", "durian", "elderberry", "fig", "grape" }; static const char* const Colors[] = { "azure", "blue", "cyan", "dun", "ecru" }; static const double doubleData[] = { 1.111, 2.222, 3.333, 4.444, 5.555, 6.666, 777.777, 888.888 }; static const uint8_t Data8[] = { 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xA1, 0xB1, 0xC2, 0xD3 }; static const uint16_t Data16[] = { 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06 }; static const char* const string_marshalled_after_scalar_array = "string after array"; int AJ_Main() { AJ_Status status; AJ_BusAttachment bus; AJ_Message txMsg; AJ_Message rxMsg; AJ_Arg arg; AJ_Arg array1; AJ_Arg array2; AJ_Arg struct1; AJ_Arg struct2; size_t sz; uint32_t test; uint32_t i; uint32_t j; uint32_t k; uint32_t key; uint32_t len; uint32_t u; int32_t n; uint16_t q; uint8_t y; char* str; char* sig; void* raw; double d; #ifdef EXPANDED_FORM AJ_Arg struct2; int32_t m; uint16_t r; uint32_t v; #endif const size_t lengthOfShortGUID = 16; bus.sock.tx.direction = AJ_IO_BUF_TX; bus.sock.tx.bufSize = sizeof(txBuffer); bus.sock.tx.bufStart = txBuffer; bus.sock.tx.readPtr = bus.sock.tx.bufStart; bus.sock.tx.writePtr = bus.sock.tx.bufStart; bus.sock.tx.send = TxFunc; bus.sock.rx.direction = AJ_IO_BUF_RX; bus.sock.rx.bufSize = sizeof(rxBuffer); bus.sock.rx.bufStart = rxBuffer; bus.sock.rx.readPtr = bus.sock.rx.bufStart; bus.sock.rx.writePtr = bus.sock.rx.bufStart; bus.sock.rx.recv = RxFunc; /* * mutter doesn't connect to an actual daemon. * Hence, to ensure that we don't fail the header validation checks, * manually set the unique name of the Bus. */ strncpy(bus.uniqueName, "DummyNaaaame.N1", lengthOfShortGUID); /* * Set the hook */ #ifndef NDEBUG MutterHook = MsgInit; #else AJ_AlwaysPrintf(("mutter only works in DEBUG builds\n")); return -1; #endif for (test = 0; test < ArraySize(testSignature); ++test) { status = AJ_MarshalSignal(&bus, &txMsg, test, "mutter.service", 0, 0, 0); if (status != AJ_OK) { break; } switch (test) { case 0: status = AJ_MarshalArgs(&txMsg, "ays", Data8, sizeof(Data8), string_marshalled_after_scalar_array); if (status != AJ_OK) { break; } break; case 1: status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (key = 0; key < ArraySize(Fruits); ++key) { #ifdef EXPANDED_FORM AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "us", key, Fruits[key]); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &dict); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "{us}", key, Fruits[key]); if (status != AJ_OK) { break; } #endif } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } break; case 2: #ifdef EXPANDED_FORM status = AJ_MarshalArgs(&txMsg, "u", 11111); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "usu", 22222, "hello", 33333); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &struct2, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "ii", -100, -200); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct2); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "qsq", 4444, "goodbye", 5555); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "yyy", 1, 2, 3); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "u(usu(ii)qsq)yyy", 11111, 22222, "hello", 33333, -100, -200, 4444, "goodbye", 5555, 1, 2, 3); if (status != AJ_OK) { break; } #endif break; case 3: status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (u = 0; u < ArraySize(Fruits); ++u) { #ifdef EXPANDED_FORM status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "us", u, Fruits[u]); if (status != AJ_OK) { break; } status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_BYTE, AJ_ARRAY_FLAG, Data8, u)); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "(usay)", u, Fruits[u], Data8, u); if (status != AJ_OK) { break; } #endif } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } break; case 4: status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (j = 0; j < 3; ++j) { status = AJ_MarshalContainer(&txMsg, &array2, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (k = j; k < ArraySize(Fruits); ++k) { status = AJ_MarshalArgs(&txMsg, "s", Fruits[k]); if (status != AJ_OK) { break; } } status = AJ_MarshalCloseContainer(&txMsg, &array2); if (status != AJ_OK) { break; } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } break; case 5: status = AJ_MarshalArgs(&txMsg, "i", 987654321); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "a(ii)"); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (j = 0; j < 16; ++j) { #ifdef EXPANDED_FORM status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "ii", j + 1, (j + 1) * 100); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "(ii)", j + 1, (j + 1) * 100); if (status != AJ_OK) { break; } #endif } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } status = AJ_MarshalArgs(&txMsg, "i", 123456789); if (status != AJ_OK) { break; } break; case 6: #ifdef EXPANDED_FORM status = AJ_MarshalVariant(&txMsg, "(ivi)"); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "i", 1212121); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "s"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "s", "inner variant"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "i", 3434343); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "v", "(ivi)", 121212121, "s", "inner variant", 3434343); if (status != AJ_OK) { break; } #endif break; case 7: status = AJ_MarshalVariant(&txMsg, "v"); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "v"); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "v"); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "v"); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "s"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "s", "deep variant"); if (status != AJ_OK) { break; } break; case 8: #ifdef EXPANDED_FORM status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "i"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "i", 1212121); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "s"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "s", "variant"); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "ay"); if (status != AJ_OK) { break; } status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_BYTE, AJ_ARRAY_FLAG, Data8, sizeof(Data8))); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "ay"); if (status != AJ_OK) { break; } status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_BYTE, AJ_ARRAY_FLAG, Data8, sizeof(Data8))); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "aq"); if (status != AJ_OK) { break; } status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_UINT16, AJ_ARRAY_FLAG, Data16, sizeof(Data16))); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "s"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "s", "variant2"); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "(vvvvvv)", "i", 121212121, "s", "variant", "ay", Data8, sizeof(Data8), "ay", Data8, sizeof(Data8), "aq", Data16, sizeof(Data16), "s", "variant2"); if (status != AJ_OK) { break; } #endif break; case 9: status = AJ_MarshalArgs(&txMsg, "uq", 0xF00F00F0, 0x0707); if (status != AJ_OK) { break; } len = 5000; status = AJ_DeliverMsgPartial(&txMsg, len + 4); if (status != AJ_OK) { break; } status = AJ_MarshalRaw(&txMsg, &len, 4); if (status != AJ_OK) { break; } for (j = 0; j < len; ++j) { uint8_t temp = (uint8_t)j; status = AJ_MarshalRaw(&txMsg, &temp, 1); if (status != AJ_OK) { break; } } break; case 10: len = 500; u = len * sizeof(TestStruct); status = AJ_DeliverMsgPartial(&txMsg, u + sizeof(u) + 4); if (status != AJ_OK) { break; } status = AJ_MarshalRaw(&txMsg, &u, sizeof(u)); if (status != AJ_OK) { break; } /* * Structs are always 8 byte aligned */ u = 0; status = AJ_MarshalRaw(&txMsg, &u, 4); if (status != AJ_OK) { break; } for (j = 0; j < len; ++j) { TestStruct ts; ts.a = j; ts.b = j + 1; ts.c = j + 2; ts.d = j + 3; status = AJ_MarshalRaw(&txMsg, &ts, sizeof(ts)); if (status != AJ_OK) { break; } } break; case 11: status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } break; case 12: status = AJ_MarshalArgs(&txMsg, "y", 127); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (key = 0; key < ArraySize(Colors); ++key) { AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "ss", Colors[key], Fruits[key]); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &dict); if (status != AJ_OK) { break; } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } break; case 13: status = AJ_MarshalArgs(&txMsg, "y", 0x11); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "y", 0x22); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "y", 0x33); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "y", 0x44); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "y", 0x55); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (key = 0; key < ArraySize(Colors); ++key) { AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "ys", (uint8_t)key, Colors[key]); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &dict); if (status != AJ_OK) { break; } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } break; case 14: status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "i", 3434343); if (status != AJ_OK) { break; } status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_BYTE, AJ_ARRAY_FLAG, Data8, sizeof(Data8))); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } break; case 15: status = AJ_MarshalArgs(&txMsg, "i", 0x1111); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (j = 0; j < 8; ++j) { #ifdef EXPANDED_FORM AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "i", j); if (status != AJ_OK) { break; } if (j == 4) { status = AJ_MarshalVariant(&txMsg, "s"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "s", "This is a variant string"); if (status != AJ_OK) { break; } } else { status = AJ_MarshalVariant(&txMsg, "i"); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "i", j + 200); if (status != AJ_OK) { break; } } status = AJ_MarshalCloseContainer(&txMsg, &dict); if (status != AJ_OK) { break; } #else if (j == 4) { status = AJ_MarshalArgs(&txMsg, "{iv}", j, "s", "This is a variant string"); if (status != AJ_OK) { break; } } else { status = AJ_MarshalArgs(&txMsg, "{iv}", j, "i", j + 200); if (status != AJ_OK) { break; } } #endif } status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "i", 0x2222); if (status != AJ_OK) { break; } break; case 16: status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (i = 0; i < 100; ++i) { status = AJ_MarshalArgs(&txMsg, "y", i); } status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } break; case 17: status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (key = 0; key < ArraySize(Colors); ++key) { #ifdef EXPANDED_FORM AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "s", Colors[key]); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "us", key, Fruits[key]); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &dict); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "{s(us)}", Colors[key], key, Fruits[key]); if (status != AJ_OK) { break; } #endif } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } break; case 18: status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "y", 36); if (status != AJ_OK) { break; } status = AJ_MarshalVariant(&txMsg, "a(ii)"); if (status != AJ_OK) { break; } status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (j = 0; j < 16; ++j) { #ifdef EXPANDED_FORM status = AJ_MarshalContainer(&txMsg, &struct2, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "ii", j + 1, (j + 1) * 100); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct2); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "(ii)", j + 1, (j + 1) * 100); if (status != AJ_OK) { break; } #endif } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (y = 0; y < ArraySize(Fruits); ++y) { #ifdef EXPANDED_FORM status = AJ_MarshalContainer(&txMsg, &struct2, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_MarshalArgs(&txMsg, "y", y); if (status != AJ_OK) { break; } status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_BYTE, AJ_ARRAY_FLAG, Fruits[y], strlen(Fruits[y]))); if (status != AJ_OK) { break; } status = AJ_MarshalCloseContainer(&txMsg, &struct2); if (status != AJ_OK) { break; } #else status = AJ_MarshalArgs(&txMsg, "(yay)", y, Fruits[y], strlen(Fruits[y])); if (status != AJ_OK) { break; } #endif } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&txMsg, &array1); if (status != AJ_OK) { break; } } status = AJ_MarshalCloseContainer(&txMsg, &struct1); if (status != AJ_OK) { break; } break; case 19: status = AJ_MarshalArgs(&txMsg, "d", 1234.5678); if (status != AJ_OK) { break; } break; case 20: status = AJ_MarshalArgs(&txMsg, "ad", doubleData, sizeof(doubleData)); if (status != AJ_OK) { break; } break; } /* Marshal */ if (status != AJ_OK) { AJ_AlwaysPrintf(("Failed %d\n", test)); break; } AJ_AlwaysPrintf(("deliver\n")); AJ_DeliverMsg(&txMsg); status = AJ_UnmarshalMsg(&bus, &rxMsg, 0); if (status != AJ_OK) { break; } switch (test) { case 0: status = AJ_UnmarshalArgs(&rxMsg, "ays", (const void**)&raw, &sz, &str); if (status != AJ_OK) { break; } if (strncmp(str, string_marshalled_after_scalar_array, strlen(string_marshalled_after_scalar_array))) { break; } break; case 1: status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (j = 0; j >= 0; ++j) { if (j & 1) { AJ_AlwaysPrintf(("Skipping dict entry %d\n", j)); status = AJ_SkipArg(&rxMsg); if (status != AJ_OK) { break; } } else { char* fruit; #ifdef EXPANDED_FORM AJ_Arg dict; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "us", &key, &fruit); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal[%d] = %s\n", key, fruit)); status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); if (status != AJ_OK) { break; } #else status = AJ_UnmarshalArgs(&rxMsg, "{us}", &key, &fruit); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal[%d] = %s\n", key, fruit)); #endif } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } break; case 2: #ifdef EXPANDED_FORM status = AJ_UnmarshalArgs(&rxMsg, "u", &u); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %u\n", u)); status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "usu", &u, &str, &v); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %u %s %u\n", u, str, v)); status = AJ_UnmarshalContainer(&rxMsg, &struct2, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "ii", &n, &m); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d %d\n", n, m)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct2); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "qsq", &q, &str, &r); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %u %s %u\n", q, str, r)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", y)); status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", y)); status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", y)); #else { TestNestedStruct ns; uint8_t y1; uint8_t y2; status = AJ_UnmarshalArgs(&rxMsg, "u(usu(ii)qsq)yyy", &u, &ns.u, &ns.str1, &ns.v, &ns.inner.m, &ns.inner.n, &ns.q, &ns.str2, &ns.r, &y, &y1, &y2); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %u (%u %s %u (%d %d) %u %s %u) %d %d %d\n", u, ns.u, ns.str1, ns.v, ns.inner.m, ns.inner.n, ns.q, ns.str2, ns.r, y, y1, y2)); } #endif break; case 3: status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (status == AJ_OK) { #ifdef EXPANDED_FORM status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "us", &u, &str); if (status != AJ_OK) { break; } status = AJ_UnmarshalArg(&rxMsg, &arg); if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } #else size_t tmpLen; uint8_t* data; status = AJ_UnmarshalArgs(&rxMsg, "(usay)", &u, &str, &data, &tmpLen); if (status != AJ_OK) { break; } #endif AJ_AlwaysPrintf(("Unmarshal %d %s\n", u, str)); } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } break; case 4: status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (status == AJ_OK) { status = AJ_UnmarshalContainer(&rxMsg, &array2, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (status == AJ_OK) { status = AJ_UnmarshalArg(&rxMsg, &arg); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %s\n", arg.val.v_string)); } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array2); if (status != AJ_OK) { break; } } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } break; case 5: status = AJ_UnmarshalArgs(&rxMsg, "i", &j); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (status == AJ_OK) { status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "ii", &j, &k); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal[%d] %d\n", j, k)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } } /* * We expect AJ_ERR_NO_MORE */ if (status != AJ_ERR_NO_MORE) { break; } status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "i", &j); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", j)); break; case 6: #ifdef EXPANDED_FORM status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "i", &j); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "s", &str); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %s\n", str)); status = AJ_UnmarshalArgs(&rxMsg, "i", &j); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } #else status = AJ_UnmarshalArgs(&rxMsg, "v", "(ivi)", &j, "s", &str, &j); if (status != AJ_OK) { break; } #endif break; case 7: status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "s", &str); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %s\n", str)); break; case 8: status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "i", &j); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "s", &str); if (status != AJ_OK) { break; } status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArg(&rxMsg, &arg); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Skipping variant\n")); status = AJ_SkipArg(&rxMsg); if (status != AJ_OK) { break; } status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArg(&rxMsg, &arg); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Skipping variant\n")); status = AJ_SkipArg(&rxMsg); if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } break; case 9: status = AJ_UnmarshalArgs(&rxMsg, "uq", &j, &q); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %x\n", j)); AJ_AlwaysPrintf(("Unmarshal %x\n", q)); status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, sizeof(len), &sz); if (status != AJ_OK) { break; } len = *((uint32_t*)raw); AJ_AlwaysPrintf(("UnmarshalRaw %d\n", len)); for (j = 0; j < len; ++j) { uint8_t v; status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, 1, &sz); if (status != AJ_OK) { break; } v = *((uint8_t*)raw); if (v != (uint8_t)j) { status = AJ_ERR_FAILURE; break; } } break; case 10: status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, 4, &sz); if (status != AJ_OK) { break; } len = *((uint32_t*)raw) / sizeof(TestStruct); /* * Structs are always 8 byte aligned */ status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, 4, &sz); if (status != AJ_OK) { break; } for (j = 0; j < len; ++j) { TestStruct* ts; status = AJ_UnmarshalRaw(&rxMsg, (const void**)&ts, sizeof(TestStruct), &sz); if (status != AJ_OK) { break; } if ((ts->a != j) || (ts->b != (j + 1)) || (ts->c != (j + 2)) || (ts->d != (j + 3))) { status = AJ_ERR_FAILURE; break; } } break; case 11: status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArg(&rxMsg, &arg); /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } break; case 12: status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (TRUE) { AJ_Arg dict; char* fruit; char* color; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "ss", &color, &fruit); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal[%s] = %s\n", color, fruit)); status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); if (status != AJ_OK) { break; } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } break; case 13: status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (TRUE) { char* color; #ifdef EXPANDED_FORM AJ_Arg dict; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "ys", &y, &color); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal[%d] = %s\n", y, color)); status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); if (status != AJ_OK) { break; } #else status = AJ_UnmarshalArgs(&rxMsg, "{ys}", &y, &color); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal[%d] = %s\n", y, color)); #endif } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } break; case 14: status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "i", &n); if (status != AJ_OK) { break; } AJ_ASSERT(n == 3434343); status = AJ_UnmarshalArg(&rxMsg, &arg); if (status != AJ_OK) { break; } for (j = 0; j < arg.len; ++j) { uint8_t val = arg.val.v_byte[j]; AJ_AlwaysPrintf(("Unmarhsalled array1[%u] = %u\n", j, val)); AJ_ASSERT(val == Data8[j]); } status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } break; case 15: status = AJ_UnmarshalArgs(&rxMsg, "i", &j); if (status != AJ_OK) { break; } status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (j = 0;; ++j) { AJ_Arg dict; int tmpKey; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "i", &tmpKey); if (status != AJ_OK) { break; } if (tmpKey == 4) { status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal dict entry key=%d variant %s\n", tmpKey, sig)); status = AJ_UnmarshalArgs(&rxMsg, sig, &str); if (status != AJ_OK) { break; } } else { AJ_AlwaysPrintf(("Skipping dict entry key=%d\n", tmpKey)); status = AJ_SkipArg(&rxMsg); if (status != AJ_OK) { break; } } status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); if (status != AJ_OK) { break; } } status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "i", &j); if (status != AJ_OK) { break; } AJ_ASSERT(j == 0x2222); break; case 16: status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (status == AJ_OK) { status = AJ_UnmarshalArgs(&rxMsg, "y", &i); } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } break; case 17: status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } for (j = 0; j >= 0; ++j) { if (j & 1) { AJ_AlwaysPrintf(("Skipping dict entry %d\n", j)); status = AJ_SkipArg(&rxMsg); if (status != AJ_OK) { break; } } else { char* color; char* fruit; #ifdef EXPANDED_FORM AJ_Arg dict; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "s", &color); if (status != AJ_OK) { break; } status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "us", &key, &fruit); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %s => (%d, %s)\n", color, key, fruit)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); if (status != AJ_OK) { break; } #else status = AJ_UnmarshalArgs(&rxMsg, "{s(us)}", &color, &key, &fruit); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %s => (%d, %s)\n", color, key, fruit)); #endif } } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } break; case 18: status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "y", &j); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (status == AJ_OK) { status = AJ_UnmarshalContainer(&rxMsg, &struct2, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "ii", &j, &k); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("Unmarshal[%d] %d\n", j, k)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct2); if (status != AJ_OK) { break; } } /* * We expect AJ_ERR_NO_MORE */ if (status != AJ_ERR_NO_MORE) { break; } status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); if (status != AJ_OK) { break; } while (status == AJ_OK) { size_t tmpLen; uint8_t* data; char buf[20]; #ifdef EXPANDED_FORM status = AJ_UnmarshalContainer(&rxMsg, &struct2, AJ_ARG_STRUCT); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(&rxMsg, "y", &y); if (status != AJ_OK) { break; } status = AJ_UnmarshalArg(&rxMsg, "ay", &data, &tmpLen); if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(&rxMsg, &struct2); if (status != AJ_OK) { break; } #else status = AJ_UnmarshalArgs(&rxMsg, "(yay)", &u, &data, &tmpLen); if (status != AJ_OK) { break; } #endif memcpy(buf, data, tmpLen); buf[tmpLen] = '\0'; AJ_AlwaysPrintf(("Unmarshal %d %s\n", y, buf)); } /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); if (status != AJ_OK) { break; } } status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); if (status != AJ_OK) { break; } break; case 19: memset(&d, 0, sizeof(double)); status = AJ_UnmarshalArgs(&rxMsg, "d", &d); if (d != 1234.5678) { AJ_ErrPrintf(("Double test failure\n")); status = AJ_ERR_FAILURE; } if (status != AJ_OK) { break; } break; case 20: status = AJ_UnmarshalArgs(&rxMsg, "ad", (const void**)&raw, &sz); if (status != AJ_OK) { break; } if (memcmp(raw, doubleData, sz) != 0) { AJ_ErrPrintf(("Double array test failure\n")); status = AJ_ERR_FAILURE; break; } break; } /* Unmarshal */ if (status != AJ_OK) { AJ_AlwaysPrintf(("Failed %d\n", test)); break; } AJ_CloseMsg(&rxMsg); AJ_AlwaysPrintf(("Passed %d \"%s\"\n", test, testSignature[test])); } if (status != AJ_OK) { AJ_AlwaysPrintf(("Marshal/Unmarshal unit test[%d] failed %d\n", test, status)); } return status; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/nvramdump.c000066400000000000000000000052131271074662300157660ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE NVRAMDUMP #include #include #include #include #include uint8_t dbgNVRAMDUMP = 1; extern void AJ_NVRAM_Layout_Print(); AJ_Status DumpNVRAM(); void printhex(uint8_t*x, size_t n) { size_t i; for (i = 0; i < n; i++) { AJ_AlwaysPrintf(("%02X", x[i])); } } AJ_Status DumpNVRAM() { AJ_Status status; uint16_t slot = AJ_CREDS_NV_ID_BEGIN; uint16_t type; AJ_CredField id; uint32_t expiration; AJ_CredField data; AJ_NVRAM_Layout_Print(); AJ_AlwaysPrintf(("Remaining Size %d\n", AJ_NVRAM_GetSizeRemaining())); AJ_AlwaysPrintf(("SLOT | TYPE | ID | EXPIRATION | DATA\n")); for (; slot < AJ_CREDS_NV_ID_END; slot++) { if (!AJ_NVRAM_Exist(slot)) { continue; } id.data = NULL; data.data = NULL; status = AJ_CredentialRead(&type, &id, &expiration, &data, slot); if (AJ_OK == status) { AJ_AlwaysPrintf(("%04X | %04X | ", slot, type)); printhex(id.data, id.size); AJ_AlwaysPrintf((" | %08X | ", expiration)); //printhex(data.data, data.size); AJ_DumpBytes("", data.data, data.size); AJ_AlwaysPrintf(("\n")); AJ_CredFieldFree(&id); AJ_CredFieldFree(&data); } } return AJ_OK; } int AJ_Main() { AJ_Status status = AJ_OK; AJ_Initialize(); //AJ_NVRAM_Clear(); //AJ_AlwaysPrintf(("Clearing NVRAM\n")); status = DumpNVRAM(); AJ_ASSERT(status == AJ_OK); //AJ_DumpPolicy(); return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/nvrampersistencetest.c000066400000000000000000000303771271074662300202560ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include /* Forward Declaration */ AJ_Status CreateTrailOfBreadcrumbs(void); AJ_Status FollowTrailOfBreadcrumbs(void); const int8_t AJTestNvramReadFailure = -1; const int8_t AJTestNvramWriteFailure = -1; char AJTestReadMode[] = { AJ_NV_DATASET_MODE_READ, '\0' }; char AJTestWriteMode[] = { AJ_NV_DATASET_MODE_WRITE, '\0' }; /* * When an item is stored in NVRAM, the number of bytes occupied * equals the size of the item stored itself, plus the overhead to * to store metadata (viz. id and some other information). * * The most accurate way to measure this would be to actually write * an item to the NVRAM and compare the before and after sizes. * * A rough estimate would be the 'visible' size of AJ_NV_DATASET structure. * (the member void* internal, is opaque to the application) */ static const uint16_t estimatedOverheadPerNvramItem = sizeof(AJ_NV_DATASET); static const char sensumManifestum[] = "AllJoyn - The cultissima aditus ad IoT"; /* starting id for trail of crumbs */ static const uint16_t smId = 0x8421; /* id where number of crumbs is stored */ static const uint16_t countId = 0x8193; static uint16_t lengthOfBreadcrumbTrail = 0; int AJ_Main(void) { AJ_Status status = AJ_ERR_INVALID; AJ_NVRAM_Init(); AJ_Printf("\nAllJoyn Release: %s\n\n", AJ_GetVersion()); /* * The very first thing the test application does is to follow the trail of * breadcrumbs, if available. */ status = FollowTrailOfBreadcrumbs(); if (AJ_OK == status) { AJ_Printf("PASS: Successfully read the known message from NVRAM and " "it is as expected. Done with the test.\n"); return status; } else { AJ_Printf("INFO: No old remnants of a previous test run found.\n"); } /* * The very last thing the test application does is to create the trail of * breadcrumbs, to be compared upon start. */ status = CreateTrailOfBreadcrumbs(); if (AJ_OK == status) { AJ_Printf("INFO: Successfully wrote the known message to NVRAM.\n"); AJ_Reboot(); /* Reboot the target, if available */ } else { AJ_Printf("ERROR: CreateTrailOfBreadcrumbs failed: %s (code: %u)\n", AJ_StatusText(status), status); } AJ_Printf("INFO: Completed running the test. Exiting...\n"); return status; } AJ_Status CreateTrailOfBreadcrumbs(void) { uint16_t minNvramSpaceNeeded; uint16_t currentAvailableNvramSpace; uint16_t someNvramId = 0; AJ_NV_DATASET* someDataHandle = NULL; uint8_t sizeOfEachSlice; uint16_t i; size_t numBytesExpectingToWrite; size_t numBytesActuallyWritten; /* * Test program would write (place breadcrumbs) over the NVRAM, anyway. */ AJ_NVRAM_Clear(); currentAvailableNvramSpace = AJ_NVRAM_GetSizeRemaining(); /* * At minimum, the test needs to store: * a. The message itself * b. The number of breadcrumbs in the trail (the mininum value is 1) * (this is essentially the value held by lengthOfBreadcrumbTrail) */ minNvramSpaceNeeded = (estimatedOverheadPerNvramItem + sizeof(sensumManifestum)) + (estimatedOverheadPerNvramItem + sizeof(lengthOfBreadcrumbTrail)); if (currentAvailableNvramSpace < minNvramSpaceNeeded) { AJ_Printf("ERROR: Available NVRAM space (%u bytes) is less than needed (%u bytes).\n", currentAvailableNvramSpace, minNvramSpaceNeeded); return AJ_ERR_RESOURCES; } /* * Any remaining space can be used to add more breadcrumbs. * max_num_bread_crumbs = nvram_size_available / size_occupied_by_each_crumb * * size_occupied_by_each_crumb = estimatedOverheadPerNvramItem + sizeof(id) */ lengthOfBreadcrumbTrail = (currentAvailableNvramSpace - minNvramSpaceNeeded) / (estimatedOverheadPerNvramItem + sizeof(someNvramId)); /* * Create the trail of bread crumbs starting at smId * * Generate a random list of nvram ids, lengthOfBreadcrumbTrail number of * elements. The list should not have any duplicates and should not include * marker ids viz. smId and countId. * * This is necessary to ensure that the trail of breadcrumbs is without * any loops. The simplest way to generate a list of unique nvram ids * would be to divide the available space into equal slices and generate * one id from each slice. * * The starting id is AJ_NVRAM_ID_APPS_BEGIN and the ending id is 0xFFFF. * * There are a total of (lengthOfBreadcrumbTrail + 1) items to * go through, including the starting point smId. */ sizeOfEachSlice = (0xFFFF - AJ_NVRAM_ID_APPS_BEGIN) / lengthOfBreadcrumbTrail; /* The starting point has to be the constant marker, smId */ someNvramId = smId; for (i = 0; i < lengthOfBreadcrumbTrail + 1; i++) { uint8_t randByte; uint16_t startId; uint16_t nextId; void* pointerToData; AJ_RandBytes(&randByte, sizeof(randByte)); startId = AJ_NVRAM_ID_APPS_BEGIN + sizeOfEachSlice * i; nextId = startId + randByte % sizeOfEachSlice; /* Ensure uniqueness of id - no conflicts with well-known markers */ if (smId == nextId || countId == nextId) { nextId += (0 == i % 2) ? -1 : 1; } numBytesExpectingToWrite = (lengthOfBreadcrumbTrail != i) ? sizeof(nextId) : sizeof(sensumManifestum); currentAvailableNvramSpace = AJ_NVRAM_GetSizeRemaining(); someDataHandle = AJ_NVRAM_Open(someNvramId, AJTestWriteMode, numBytesExpectingToWrite); if (NULL == someDataHandle) { /* Cannot proceed any further due to failed breadcrumb access */ return AJ_ERR_NVRAM_WRITE; } pointerToData = (lengthOfBreadcrumbTrail != i) ? (void*) (&nextId) : (void*) sensumManifestum; numBytesActuallyWritten = AJ_NVRAM_Write(pointerToData, numBytesExpectingToWrite, someDataHandle); /* done writing the data, can close the handle */ if (AJ_OK != AJ_NVRAM_Close(someDataHandle)) { AJ_Printf("WARN: For id: %u, AJ_NVRAM_Close did NOT return %s (code: %u)\n", someNvramId, AJ_StatusText(AJ_OK), AJ_OK); } if (AJTestNvramWriteFailure == numBytesActuallyWritten || numBytesExpectingToWrite != numBytesActuallyWritten) { /* Cannot proceed any further due to breadcrumb write failure */ return AJ_ERR_NVRAM_WRITE; } /* * The write has been successful. * * Check whether estimatedOverheadPerNvramItem (rough estimate) is * accurate. Overestimating estimatedOverheadPerNvramItem is fine * (erring on the side on caution). */ if (estimatedOverheadPerNvramItem < currentAvailableNvramSpace - AJ_NVRAM_GetSizeRemaining() - numBytesExpectingToWrite) { AJ_Printf("ERROR: The estimated overhead per NVRAM item (%u bytes) is not accurate. It needs to be increased.\n", estimatedOverheadPerNvramItem); return AJ_ERR_FAILURE; } /* Move to the next breadcrumb */ someNvramId = nextId; } /* * All the items are written. * Write the value of lengthOfBreadcrumbTrail */ someDataHandle = AJ_NVRAM_Open(countId, AJTestWriteMode, sizeof(lengthOfBreadcrumbTrail)); if (NULL == someDataHandle) { return AJ_ERR_NVRAM_WRITE; } numBytesExpectingToWrite = sizeof(lengthOfBreadcrumbTrail); numBytesActuallyWritten = AJ_NVRAM_Write((void*)&lengthOfBreadcrumbTrail, numBytesExpectingToWrite, someDataHandle); /* done writing the data, can close the handle */ if (AJ_OK != AJ_NVRAM_Close(someDataHandle)) { AJ_Printf("WARN: For id: %u, AJ_NVRAM_Close did NOT return %s (code: %u)\n", countId, AJ_StatusText(AJ_OK), AJ_OK); } if (AJTestNvramWriteFailure == numBytesActuallyWritten || numBytesExpectingToWrite != numBytesActuallyWritten) { return AJ_ERR_NVRAM_WRITE; } return AJ_OK; } AJ_Status FollowTrailOfBreadcrumbs(void) { static char scratchPad[sizeof(sensumManifestum)]; uint16_t someNvramId = 0; AJ_NV_DATASET* someDataHandle = NULL; size_t numBytesExpectingToRead; size_t numBytesActuallyRead; uint16_t i; /* * As long as NVRAM wasn't cleared between two successive runs of * the test, it should be possible to read the known data written at * the very end of the test by the previous run. * * The first item to read is the number of breadcrumbs. */ if (1 != AJ_NVRAM_Exist(countId)) { /* cannot find the marker countId */ return AJ_ERR_NVRAM_READ; } someDataHandle = AJ_NVRAM_Open(countId, AJTestReadMode, 0); if (NULL == someDataHandle) { /* cannot open the marker countId */ return AJ_ERR_NVRAM_READ; } numBytesExpectingToRead = sizeof(lengthOfBreadcrumbTrail); numBytesActuallyRead = AJ_NVRAM_Read((void*)&lengthOfBreadcrumbTrail, numBytesExpectingToRead, someDataHandle); if (AJ_OK != AJ_NVRAM_Close(someDataHandle)) { AJ_Printf("WARN: For id: %u, AJ_NVRAM_Close did NOT return %s (code: %u)\n", countId, AJ_StatusText(AJ_OK), AJ_OK); } if (AJTestNvramReadFailure == numBytesActuallyRead || numBytesExpectingToRead != numBytesActuallyRead) { /* could not read from the marker countId */ return AJ_ERR_NVRAM_READ; } /* * Follow the trail of bread crumbs starting at smId */ someNvramId = smId; for (i = 0; i < lengthOfBreadcrumbTrail + 1; i++) { uint8_t isIdPresent = AJ_NVRAM_Exist(someNvramId); void* pointerToData = (lengthOfBreadcrumbTrail != i) ? (void*) &someNvramId : (void*) scratchPad; someDataHandle = (1 == isIdPresent) ? AJ_NVRAM_Open(someNvramId, AJTestReadMode, 0) : NULL; if (NULL == someDataHandle) { /* Cannot proceed any further due to failed breadcrumb access */ return AJ_ERR_NVRAM_READ; } numBytesExpectingToRead = (lengthOfBreadcrumbTrail != i) ? sizeof(someNvramId) : sizeof(sensumManifestum); numBytesActuallyRead = AJ_NVRAM_Read(pointerToData, numBytesExpectingToRead, someDataHandle); /* done reading the data, can close the handle */ if (AJ_OK != AJ_NVRAM_Close(someDataHandle)) { AJ_Printf("WARN: For id: %u, AJ_NVRAM_Close did NOT return %s (code: %u)\n", someNvramId, AJ_StatusText(AJ_OK), AJ_OK); } if (AJTestNvramReadFailure == numBytesActuallyRead || numBytesExpectingToRead != numBytesActuallyRead) { /* Cannot proceed any further due to breadcrumb read failure */ return AJ_ERR_NVRAM_READ; } if (lengthOfBreadcrumbTrail == i) { /* Final crumb where message has been retrieved */ return (0 == strcmp(scratchPad, sensumManifestum)) ? AJ_OK : AJ_ERR_NVRAM_READ; } } return AJ_OK; } #ifdef AJ_MAIN int main(void) { return AJ_Main(); } #endif ajtcl-16.04/test/nvramtest.c000066400000000000000000000712721271074662300160100ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE NVT #include #include #include #include #include #include #include uint8_t dbgNVT = 0; AJ_Status TestNVRAM(); AJ_Status TestCreds(); extern void AJ_NVRAM_Layout_Print(); static uint16_t tid1 = 15; static uint16_t tid2 = 16; static uint16_t tid3 = 17; static uint16_t tid4 = 18; static uint16_t count = 0; #define AJ_NVRAM_REQUESTED AJ_NVRAM_SIZE #define RAND_DATA #define READABLE_LOG typedef enum _AJOBS_AuthType_Test { AJOBS_AUTH_TYPE_MIN_OF_WIFI_AUTH_TYPE = -4, AJOBS_AUTH_TYPE_WPA2_AUTO = -3, AJOBS_AUTH_TYPE_WPA_AUTO = -2, AJOBS_AUTH_TYPE_ANY = -1, AJOBS_AUTH_TYPE_OPEN = 0, AJOBS_AUTH_TYPE_WEP = 1, AJOBS_AUTH_TYPE_WPA_TKIP = 2, AJOBS_AUTH_TYPE_WPA_CCMP = 3, AJOBS_AUTH_TYPE_WPA2_TKIP = 4, AJOBS_AUTH_TYPE_WPA2_CCMP = 5, AJOBS_AUTH_TYPE_WPS = 6, AJOBS_AUTH_TYPE_MAX_OF_WIFI_AUTH_TYPE = 7 } AJOBS_AuthType_Test; typedef enum _AJOBS_State_Test { AJOBS_STATE_NOT_CONFIGURED = 0, AJOBS_STATE_CONFIGURED_NOT_VALIDATED = 1, AJOBS_STATE_CONFIGURED_VALIDATING = 2, AJOBS_STATE_CONFIGURED_VALIDATED = 3, AJOBS_STATE_CONFIGURED_ERROR = 4, AJOBS_STATE_CONFIGURED_RETRY = 5, } AJOBS_State_Test; typedef struct _AJOBS_Info_Test { char ssid[33]; char pc[129]; AJOBS_AuthType_Test authType; AJOBS_State_Test state; } AJOBS_Info_Test; void Randomizer() { do { AJ_RandBytes((uint8_t*) &tid1, sizeof(tid1)); AJ_Sleep(10); AJ_RandBytes((uint8_t*) &tid2, sizeof(tid2)); AJ_Sleep(10); AJ_RandBytes((uint8_t*) &tid3, sizeof(tid3)); AJ_Sleep(10); AJ_RandBytes((uint8_t*) &tid4, sizeof(tid4)); AJ_InfoPrintf(("Randomizer values: %u %u %u %u\n", tid1, tid2, tid3, tid4)); } while (tid1 == 0 || tid2 == 0 || tid3 == 0 || tid4 == 0); } AJ_Status TestCreds() { AJ_Status status = AJ_OK; AJ_GUID localGuid; AJ_GUID remoteGuid; char str[33]; uint32_t exp; AJ_CredField id; AJ_CredField data; int i = 0; AJ_GUID peerGuid; uint8_t secretLen = 24; uint8_t secret[24]; uint32_t expiration = 50898; char hex[100]; AJ_ECCPrivateKey prv1; AJ_ECCPrivateKey prv2; AJ_ECCPublicKey pub1; AJ_ECCPublicKey pub2; AJ_AlwaysPrintf(("Start TestCreds\n")); status = AJ_GetLocalGUID(&localGuid); if (AJ_OK != status) { return status; } AJ_GUID_FromString(&localGuid, str); /* Test delete oldest credential by storing more than MAX_CREDS */ id.data = (uint8_t*) &peerGuid; id.size = sizeof (peerGuid); data.data = id.data; data.size = id.size; memset(id.data, 0, id.size); for (i = 0; i < 2 * AJ_MAX_CREDS; i++) { id.data[0] = i; status = AJ_CredentialSet(AJ_CRED_TYPE_GENERIC, &id, (uint32_t) i, &data); AJ_ASSERT(AJ_OK == status); } AJ_InfoPrintf(("TestCreds() Layout Print\n")); AJ_NVRAM_Layout_Print(); memset(&peerGuid, 1, sizeof(AJ_GUID)); for (i = 0; i < secretLen; i++) { secret[i] = i; } AJ_GUID_ToString(&peerGuid, hex, 100); AJ_AlwaysPrintf(("AJ_CredentialSetPeer guid %s\n", hex)); status = AJ_CredentialSetPeer(AJ_GENERIC_MASTER_SECRET, &peerGuid, expiration, secret, secretLen); memcpy(&remoteGuid, &peerGuid, sizeof(AJ_GUID)); // backup the GUID if (AJ_OK != status) { AJ_AlwaysPrintf(("AJ_CredentialSetPeer failed = %d\n", status)); return status; } AJ_NVRAM_Layout_Print(); AJ_InfoPrintf(("TestCreds() StoreCred() Layout Print\n")); AJ_NVRAM_Layout_Print(); AJ_GUID_ToString(&remoteGuid, hex, 100); AJ_AlwaysPrintf(("AJ_CredentialGetPeer guid %s\n", hex)); data.data = NULL; status = AJ_CredentialGetPeer(AJ_GENERIC_MASTER_SECRET, &remoteGuid, &exp, &data); if (AJ_OK != status) { AJ_AlwaysPrintf(("AJ_CredentialGetPeer failed = %d\n", status)); return status; } if (data.size != secretLen) { AJ_AlwaysPrintf(("no match for secretLen got %d expected %d\n", data.size, secretLen)); AJ_CredFieldFree(&data); return AJ_ERR_FAILURE; } if (secretLen > 0) { if (0 != memcmp(data.data, secret, secretLen)) { AJ_AlwaysPrintf(("no match for secret\n")); AJ_CredFieldFree(&data); return AJ_ERR_FAILURE; } } if (exp != expiration) { AJ_AlwaysPrintf(("no match for expiration got %d expected %d\n", exp, expiration)); AJ_CredFieldFree(&data); return AJ_ERR_FAILURE; } AJ_CredentialDeletePeer(&remoteGuid); AJ_CredFieldFree(&data); if (AJ_ERR_UNKNOWN == AJ_CredentialGetPeer(AJ_GENERIC_MASTER_SECRET, &remoteGuid, NULL, NULL)) { status = AJ_OK; } else { return AJ_ERR_FAILURE; } AJ_InfoPrintf(("TestCreds() Layout Print\n")); AJ_NVRAM_Layout_Print(); AJ_ClearCredentials(0); if (AJ_ERR_UNKNOWN == AJ_CredentialGetPeer(AJ_GENERIC_MASTER_SECRET, &remoteGuid, NULL, NULL)) { status = AJ_OK; } else { return AJ_ERR_FAILURE; } AJ_InfoPrintf(("TestCreds() Layout Print\n")); AJ_NVRAM_Layout_Print(); AJ_AlwaysPrintf(("TestCreds done.\n")); status = AJ_GenerateECCKeyPair(&pub1, &prv1); AJ_ASSERT(AJ_OK == status); status = AJ_CredentialSetECCPublicKey(AJ_ECC_SIG, NULL, 0xFFFFFFFF, &pub1); AJ_ASSERT(AJ_OK == status); status = AJ_CredentialSetECCPrivateKey(AJ_ECC_SIG, NULL, 0xFFFFFFFF, &prv1); AJ_ASSERT(AJ_OK == status); status = AJ_CredentialGetECCPublicKey(AJ_ECC_SIG, NULL, NULL, &pub2); AJ_ASSERT(AJ_OK == status); status = AJ_CredentialGetECCPrivateKey(AJ_ECC_SIG, NULL, NULL, &prv2); AJ_ASSERT(AJ_OK == status); AJ_ASSERT(0 == memcmp((uint8_t*) &pub1, (uint8_t*) &pub2, sizeof (pub1))); AJ_ASSERT(0 == memcmp((uint8_t*) &prv1, (uint8_t*) &prv2, sizeof (prv1))); return status; } AJ_Status TestExist() { AJ_Status status = AJ_OK; #ifdef EXIST_STRESS while (TRUE) { #endif AJ_InfoPrintf(("POSITIVE EXIST STATUS = %u\n", status = AJ_NVRAM_Exist(AJ_LOCAL_GUID_NV_ID))); if (status < 0) { return status; } AJ_InfoPrintf(("NEGATIVE EXIST STATUS = %u\n", status = AJ_NVRAM_Exist(66))); if (status < 0) { return status; } #ifdef EXIST_STRESS } #endif return status; } AJ_Status TestObsWrite() { AJ_Status status = AJ_OK; AJ_NV_DATASET* nvramHandle; AJOBS_Info_Test info; size_t size = sizeof(info); const char* ssid[] = { "abcdefghABCDEFGH", "aaaaaaaa", "bbbbbbbb", "cccccccc", "dddddddd", "eeeeeeee", "ffffffff", "gggggggg", "hhhhhhhh", "iiiiiiii", "jjjjjjjj", "kkkkkkkk", "llllllll", "mmmmmmmm", "nnnnnnnn", "oooooooo", "pppppppp", "qqqqqqqq", "rrrrrrrr", "ssssssss", "", "tttttttt", "uuuuuuuu", "vvvvvvvv", "wwwwwwww", "xxxxxxxx", "yyyyyyyy", "zzzzzzzz", "11111111", "22222222", "33333333", "44444444", "55555555", "66666666", "77777777", "888888888888888888888888888888", "99999999", "aaaa1111", "bbbb2222", "cccc3333", "dddd4444", "TRTESTING123", "eeee5555", "", "TR-TESTING-43" }; char pc[] = "aaaaabbbbbcccccAAAAABBBBBCCCCCzzzzzZZZZZ1111122222"; size_t i; AJ_NVRAM_Layout_Print(); //if( AJ_NVRAM_Exist(AJ_NVRAM_ID_SERVICES_BEGIN + 99)){ //NEGATIVE TEST, ID DOESN'T EXIST //if( AJ_NVRAM_Exist(AJ_NVRAM_ID_SERVICES_BEGIN + 1)){ //PROPERTY STORE DEVICE ID if (AJ_NVRAM_Exist(AJ_NVRAM_ID_APPS_BEGIN)) { //nvramHandle = AJ_NVRAM_Open(100, "r", 0); //NEGATIVE TEST, OPEN INVALID ID //nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_SERVICES_BEGIN, "r", 0); //PROPERTY STORE DEVICE ID nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_APPS_BEGIN, "r", 0); if (nvramHandle != NULL) { int sizeRead = AJ_NVRAM_Read(&info, size, nvramHandle); status = AJ_NVRAM_Close(nvramHandle); AJ_InfoPrintf(("sizeRead: %u, size: %u\n", sizeRead, size)); if (sizeRead != size) { status = AJ_ERR_READ; } else { AJ_InfoPrintf(("Read Info values: state=%d, ssid=%s authType=%d pc=%s\n", info.state, info.ssid, info.authType, info.pc)); } } } //nTest = AJ_NVRAM_Read(&info, size, nvramHandle); //NEGATIVE TEST, READ NULL HANDLE //nTest = AJ_NVRAM_Write(&info, size, nvramHandle); //NEGATIVE TEST, WRITE TO NULL HANDLE for (i = 0; i < ArraySize(ssid); i++) { strncpy(info.ssid, ssid[i], sizeof(info.ssid)); strncpy(info.pc, pc, sizeof(info.pc)); info.authType = 0; info.state = 0; #ifdef OBS_STRESS while (TRUE) { #endif #ifdef SHOW_REWRITES AJ_AlwaysPrintf(("Going to write Info values: state=%d, ssid=%s authType=%d pc=%s\n", info.state, info.ssid, info.authType, info.pc)); #endif //nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_SERVICES_BEGIN, "w", 0); //NEGATIVE TEST, OPEN 0 SIZE //nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_SERVICES_BEGIN, "t", size); //NEGATIVE TEST, INVALID MODE //nvramHandle = AJ_NVRAM_Open(0, "w", size); //NEGATIVE TEST, OPEN 0 ID //nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_SERVICES_BEGIN, "w", size); //PROPERTY STORE DEVICE ID nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_APPS_BEGIN, "w", size); if (nvramHandle != NULL) { int sizeWritten = AJ_NVRAM_Write(&info, size, nvramHandle); status = AJ_NVRAM_Close(nvramHandle); if (sizeWritten != size) { status = AJ_ERR_WRITE; } } //nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_SERVICES_BEGIN, "r", 0); //PROPERTY STORE DEVICE ID nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_APPS_BEGIN, "r", 0); if (nvramHandle != NULL) { int sizeRead = AJ_NVRAM_Read(&info, size, nvramHandle); status = AJ_NVRAM_Close(nvramHandle); if (sizeRead != sizeRead) { status = AJ_ERR_READ; } #ifdef SHOW_REWRITES else { AJ_InfoPrintf(("Read Info values: state=%d, ssid=%s authType=%d pc=%s\n", info.state, info.ssid, info.authType, info.pc)); } #endif } #ifdef NEGATIVE_OPEN nvramHandle = AJ_NVRAM_Open(66, "r", 0); status = AJ_NVRAM_Close(nvramHandle); #endif //AJ_NVRAM_Layout_Print(); #ifdef OBS_STRESS AJ_Sleep(2000); } #endif } AJ_NVRAM_Layout_Print(); return status; } AJ_Status TestNvramWrite() { AJ_NV_DATASET* d1 = NULL; AJ_NV_DATASET* d2 = NULL; AJ_NV_DATASET* d3 = NULL; AJ_NV_DATASET* d4 = NULL; int i = 0; uint16_t cap1, cap2, cap3, cap4 = 0; size_t bytes1, bytes2, bytes3, bytes4 = 0; AJ_Status status = AJ_OK; #ifdef WRITE_STRESS while (TRUE) { #endif cap1 = (tid1 % ((AJ_NVRAM_REQUESTED / 4) - 100)) + 1; cap2 = (tid2 % ((AJ_NVRAM_REQUESTED / 4) - 100)) + 1; cap3 = (tid3 % ((AJ_NVRAM_REQUESTED / 4) - 100)) + 1; cap4 = (tid4 % ((AJ_NVRAM_REQUESTED / 4) - 100)) + 1; d1 = AJ_NVRAM_Open(tid1, "w", cap1); for (i = 0; i < AJ_NVRAM_REQUESTED / 4; i++) { if ((d1->capacity - d1->curPos) >= sizeof(i)) { bytes1 = AJ_NVRAM_Write(&i, sizeof(i), d1); if (bytes1 != sizeof(i)) { return AJ_ERR_FAILURE; } } } AJ_InfoPrintf(("Dataset1 bytes: %u i: %u sizeof(i): %u capacity %u curPos %u\n", bytes1, i, sizeof(i), d1->capacity, d1->curPos)); AJ_InfoPrintf(("LAYOUT AFTER WRITE\n")); AJ_NVRAM_Layout_Print(); if (d1 != NULL) { AJ_NVRAM_Close(d1); AJ_ASSERT(d1); } d2 = AJ_NVRAM_Open(tid2, "w", cap2); AJ_ASSERT(d2); for (i = 0; i < AJ_NVRAM_REQUESTED / 4; i++) { if ((d2->capacity - d2->curPos) >= sizeof(i)) { bytes2 = AJ_NVRAM_Write(&i, sizeof(i), d2); if (bytes2 != sizeof(i)) { return AJ_ERR_FAILURE; } } } AJ_InfoPrintf(("Dataset2 bytes: %u i: %u sizeof(i): %u capacity %u curPos %u\n", bytes2, i, sizeof(i), d2->capacity, d2->curPos)); AJ_InfoPrintf(("LAYOUT AFTER WRITE\n")); AJ_NVRAM_Layout_Print(); if (d2 != NULL) { AJ_NVRAM_Close(d2); AJ_ASSERT(d2); } d3 = AJ_NVRAM_Open(tid3, "w", cap3); AJ_ASSERT(d3); for (i = 0; i < AJ_NVRAM_REQUESTED / 4; i++) { if ((d3->capacity - d3->curPos) >= sizeof(i)) { bytes3 = AJ_NVRAM_Write(&i, sizeof(i), d3); if (bytes3 != sizeof(i)) { return AJ_ERR_FAILURE; } } } AJ_InfoPrintf(("Dataset3 bytes: %u i: %u sizeof(i): %u capacity %u curPos %u\n", bytes2, i, sizeof(i), d2->capacity, d2->curPos)); AJ_InfoPrintf(("LAYOUT AFTER WRITE\n")); AJ_NVRAM_Layout_Print(); if (d3 != NULL) { AJ_NVRAM_Close(d3); AJ_ASSERT(d3); } d4 = AJ_NVRAM_Open(tid4, "w", cap4); AJ_ASSERT(d4); for (i = 0; i < AJ_NVRAM_REQUESTED / 4; i++) { if ((d4->capacity - d4->curPos) >= sizeof(i)) { bytes4 = AJ_NVRAM_Write(&i, sizeof(i), d4); if (bytes4 != sizeof(i)) { return AJ_ERR_FAILURE; } } } AJ_InfoPrintf(("Dataset4 bytes: %u i: %u sizeof(i): %u capacity %u curPos %u\n", bytes2, i, sizeof(i), d2->capacity, d2->curPos)); AJ_InfoPrintf(("LAYOUT AFTER WRITE\n")); AJ_NVRAM_Layout_Print(); if (d4 != NULL) { AJ_NVRAM_Close(d4); AJ_ASSERT(d4); } AJ_InfoPrintf(("LAYOUT AFTER CLOSE - WRITE MODE\n")); AJ_NVRAM_Layout_Print(); #ifdef WRITE_STRESS } #endif return status; } AJ_Status TestNvramRead() { //uint16_t id = 0; AJ_NV_DATASET* d1 = NULL; AJ_NV_DATASET* d2 = NULL; AJ_NV_DATASET* d3 = NULL; AJ_NV_DATASET* d4 = NULL; int i = 0; size_t bytes1, bytes2, bytes3, bytes4 = 0; AJ_Status status = AJ_OK; AJ_NVRAM_Layout_Print(); #ifdef READ_STRESS while (TRUE) { #endif //AJ_InfoPrintf(("LAYOUT AFTER OPEN - READ MODE\n")); //AJ_NVRAM_Layout_Print(); d1 = AJ_NVRAM_Open(tid1, "r", 0); //d1 = AJ_NVRAM_Open(66, "r", 0); //NEGATIVE READ TEST AJ_ASSERT(d1); for (i = 0; i < d1->capacity / 4; i++) { int data1 = 0; bytes1 = AJ_NVRAM_Read(&data1, sizeof(data1), d1); if (bytes1 != sizeof(data1) || data1 != i) { return AJ_ERR_FAILURE; } #ifdef SHOW_READ if (i % 10 == 0) { AJ_InfoPrintf(("Dataset 1 capacity %u curPos %u flash value: %u\n", d1->capacity, d1->curPos, data1)); } #endif } if (d1 != NULL) { AJ_NVRAM_Close(d1); AJ_ASSERT(d1); } d2 = AJ_NVRAM_Open(tid2, "r", 0); AJ_ASSERT(d2); for (i = 0; i < d2->capacity / 4; i++) { int data2 = 0; bytes2 = AJ_NVRAM_Read(&data2, sizeof(data2), d2); if (bytes2 != sizeof(data2) || data2 != i) { return AJ_ERR_FAILURE; } #ifdef SHOW_READ if (i % 10 == 0) { AJ_InfoPrintf(("Dataset 2 capacity %u curPos %u flash value: %u\n", d2->capacity, d2->curPos, data2)); } #endif } if (d2 != NULL) { AJ_NVRAM_Close(d2); AJ_ASSERT(d2); } d3 = AJ_NVRAM_Open(tid3, "r", 0); AJ_ASSERT(d3); for (i = 0; i < d3->capacity / 4; i++) { int data3 = 0; bytes3 = AJ_NVRAM_Read(&data3, sizeof(data3), d3); if (bytes3 != sizeof(data3) || data3 != i) { return AJ_ERR_FAILURE; } #ifdef SHOW_READ if (i % 10 == 0) { AJ_InfoPrintf(("Dataset 3 capacity %u curPos %u flash value: %u\n", d3->capacity, d3->curPos, data3)); } #endif } if (d3 != NULL) { AJ_NVRAM_Close(d3); AJ_ASSERT(d3); } d4 = AJ_NVRAM_Open(tid4, "r", 0); AJ_ASSERT(d4); for (i = 0; i < d4->capacity / 4; i++) { int data4 = 0; bytes4 = AJ_NVRAM_Read(&data4, sizeof(data4), d4); if (bytes4 != sizeof(data4) || data4 != i) { return AJ_ERR_FAILURE; } #ifdef SHOW_READ if (i % 10 == 0) { AJ_InfoPrintf(("Dataset 4 capacity %u curPos %u flash value: %u\n", d4->capacity, d4->curPos, data4)); } #endif } if (d4 != NULL) { AJ_NVRAM_Close(d4); AJ_ASSERT(d4); } AJ_InfoPrintf(("LAYOUT AFTER READ --- END capacity %u curPos %u\n", d4->capacity, d4->curPos)); AJ_NVRAM_Layout_Print(); #ifdef READ_STRESS } #endif return status; } AJ_Status TestNvramDelete() { AJ_Status status = AJ_OK; AJ_NV_DATASET* nvramHandle; if (tid1 % 2 == 1) { #ifndef OBS_ONLY if (AJ_NVRAM_Exist(tid1)) { AJ_ASSERT(AJ_NVRAM_Delete(tid1) == AJ_OK); } AJ_InfoPrintf(("LAYOUT AFTER DELETE 1\n")); AJ_NVRAM_Layout_Print(); if (AJ_NVRAM_Exist(tid2)) { AJ_ASSERT(AJ_NVRAM_Delete(tid2) == AJ_OK); } AJ_InfoPrintf(("LAYOUT AFTER DELETE 2\n")); AJ_NVRAM_Layout_Print(); if (AJ_NVRAM_Exist(tid3)) { AJ_ASSERT(AJ_NVRAM_Delete(tid3) == AJ_OK); } AJ_InfoPrintf(("LAYOUT AFTER DELETE 3\n")); AJ_NVRAM_Layout_Print(); if (AJ_NVRAM_Exist(tid4)) { AJ_ASSERT(AJ_NVRAM_Delete(tid4) == AJ_OK); } AJ_InfoPrintf(("LAYOUT AFTER DELETE 4\n")); AJ_NVRAM_Layout_Print(); #endif if (AJ_NVRAM_Exist(AJ_NVRAM_ID_APPS_BEGIN)) { AJOBS_Info_Test emptyInfo; size_t size = sizeof(AJOBS_Info_Test); memset(&emptyInfo, 0, sizeof(emptyInfo)); AJ_AlwaysPrintf(("Going to write Info values: state=%d, ssid=%s authType=%d pc=%s\n", emptyInfo.state, emptyInfo.ssid, emptyInfo.authType, emptyInfo.pc)); //AJ_NV_DATASET* nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_SERVICES_BEGIN, "w", size); //PROPERTY STORE DEVICE ID nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_APPS_BEGIN, "w", size); if (nvramHandle != NULL) { int sizeWritten = AJ_NVRAM_Write(&emptyInfo, size, nvramHandle); status = AJ_NVRAM_Close(nvramHandle); if (sizeWritten != size) { status = AJ_ERR_WRITE; goto _TEST_NVRAM_DELETE_EXIT; } } //nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_SERVICES_BEGIN, "r", 0); //PROPERTY STORE DEVICE ID nvramHandle = AJ_NVRAM_Open(AJ_NVRAM_ID_APPS_BEGIN, "r", 0); if (nvramHandle != NULL) { int sizeRead = AJ_NVRAM_Read(&emptyInfo, size, nvramHandle); status = AJ_NVRAM_Close(nvramHandle); if (sizeRead != sizeRead) { status = AJ_ERR_READ; } else { AJ_AlwaysPrintf(("Read Info values: state=%d, ssid=%s authType=%d pc=%s\n", emptyInfo.state, emptyInfo.ssid, emptyInfo.authType, emptyInfo.pc)); } } } AJ_InfoPrintf(("LAYOUT AFTER DELETE OBS\n")); AJ_NVRAM_Layout_Print(); } else { AJ_NVRAM_Clear(); AJ_InfoPrintf(("LAYOUT AFTER CLEAR ALL\n")); AJ_NVRAM_Layout_Print(); } return status; _TEST_NVRAM_DELETE_EXIT: AJ_NVRAM_Close(nvramHandle); return status; } AJ_Status TestNVRAMPeek() { AJ_Status status = AJ_OK; AJ_NV_DATASET* handle = NULL; size_t bytes = 0; char buffer[] = "This is a test buffer"; uint8_t buffer_raw[32] = { 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 }; char* ptr; uint8_t* ptr_raw; AJ_AlwaysPrintf(("Testing AJ_NVRAM_Peek()\n")); /* * String pointer data test */ handle = AJ_NVRAM_Open(999, "w", strlen(buffer) + 1); if (handle) { bytes = AJ_NVRAM_Write(buffer, strlen(buffer) + 1, handle); if (bytes != strlen(buffer) + 1) { return AJ_ERR_FAILURE; } } else { return AJ_ERR_FAILURE; } status = AJ_NVRAM_Close(handle); if (status == AJ_OK) { handle = AJ_NVRAM_Open(999, "r", strlen(buffer) + 1); ptr = (char*)AJ_NVRAM_Peek(handle); if (!ptr || (strcmp(ptr, buffer) != 0)) { AJ_ErrPrintf(("Strings do not match: buffer = %s, return = %s\n", buffer, ptr)); return AJ_ERR_FAILURE; } status = AJ_NVRAM_Close(handle); } /* * Raw data pointer test */ handle = AJ_NVRAM_Open(1000, "w", ArraySize(buffer_raw)); if (handle) { bytes = AJ_NVRAM_Write(buffer_raw, ArraySize(buffer_raw), handle); if (bytes != ArraySize(buffer_raw)) { return AJ_ERR_FAILURE; } } status = AJ_NVRAM_Close(handle); if (status == AJ_OK) { handle = AJ_NVRAM_Open(1000, "r", ArraySize(buffer_raw)); ptr_raw = (uint8_t*)AJ_NVRAM_Peek(handle); if (!ptr || (memcmp(buffer_raw, ptr_raw, ArraySize(buffer_raw)) != 0)) { AJ_ErrPrintf(("Raw data does not match\n")); return AJ_ERR_FAILURE; } status = AJ_NVRAM_Close(handle); } AJ_NVRAM_Layout_Print(); AJ_AlwaysPrintf(("Testing AJ_NVRAM_Peek() done\n")); return status; } AJ_Status TestNVRAMBigWrite() { AJ_Status status = AJ_OK; AJ_NV_DATASET* handle = NULL; uint8_t* write_bytes; uint8_t* read_bytes; size_t bytes; int i; uint16_t size = 40000; if (size > AJ_NVRAM_REQUESTED) { AJ_AlwaysPrintf(("Testing big write not possible, NVRAM not big enough\n")); return AJ_OK; } write_bytes = AJ_Malloc(size); read_bytes = AJ_Malloc(size); if (!write_bytes || !read_bytes) { AJ_ErrPrintf(("malloc failed\n")); return AJ_ERR_FAILURE; } memset(write_bytes, 0x54, size); memset(read_bytes, 0x45, size); handle = AJ_NVRAM_Open(1234, "w", size); if (!handle) { AJ_ErrPrintf(("Unable to open big write ID\n")); return AJ_ERR_FAILURE; } bytes = AJ_NVRAM_Write(write_bytes, size, handle); if (bytes != (size_t) size) { AJ_ErrPrintf(("Unable to write big bytes\n")); return AJ_ERR_FAILURE; } status = AJ_NVRAM_Close(handle); if (status != AJ_OK) { AJ_ErrPrintf(("Unable to close big write ID\n")); return AJ_ERR_FAILURE; } handle = AJ_NVRAM_Open(1234, "r", 0); if (!handle) { AJ_ErrPrintf(("Unable to open big read ID\n")); return AJ_ERR_FAILURE; } bytes = AJ_NVRAM_Read(read_bytes, size, handle); if (bytes != (size_t) size) { AJ_ErrPrintf(("Unable to read big bytes\n")); return AJ_ERR_FAILURE; } for (i = 0; i < size; i++) { if (write_bytes[i] != read_bytes[i]) { AJ_ErrPrintf(("big bytes mismatch at offset %d\n", i)); return AJ_ERR_FAILURE; } } status = AJ_NVRAM_Close(handle); if (status != AJ_OK) { AJ_ErrPrintf(("Unable to close big read ID\n")); return AJ_ERR_FAILURE; } AJ_AlwaysPrintf(("Testing Big Write done\n")); return AJ_OK; } AJ_Status TestNVRAM() { uint16_t id = 16; AJ_NV_DATASET* handle = NULL; int i = 0; size_t bytes = 0; AJ_Status status = AJ_OK; AJ_NVRAM_Layout_Print(); { handle = AJ_NVRAM_Open(id, "w", 40 + 5); AJ_NVRAM_Layout_Print(); AJ_ASSERT(handle); for (i = 0; i < 10; i++) { bytes = AJ_NVRAM_Write(&i, sizeof(i), handle); if (bytes != sizeof(i)) { status = AJ_ERR_FAILURE; goto _TEST_NVRAM_EXIT; } } { uint8_t buf[3] = { 11, 22, 33 }; uint8_t buf2[2] = { 44, 55 }; bytes = AJ_NVRAM_Write(buf, sizeof(buf), handle); if (bytes != sizeof(buf)) { status = AJ_ERR_FAILURE; goto _TEST_NVRAM_EXIT; } bytes = AJ_NVRAM_Write(buf2, sizeof(buf2), handle); if (bytes != sizeof(buf2)) { status = AJ_ERR_FAILURE; goto _TEST_NVRAM_EXIT; } } AJ_NVRAM_Close(handle); AJ_InfoPrintf(("TestNVRAM() Layout Print\n")); AJ_NVRAM_Layout_Print(); handle = AJ_NVRAM_Open(id, "r", 0); AJ_ASSERT(handle); for (i = 0; i < 10; i++) { int data = 0; bytes = AJ_NVRAM_Read(&data, sizeof(data), handle); if (bytes != sizeof(data) || data != i) { status = AJ_ERR_FAILURE; goto _TEST_NVRAM_EXIT; } } for (i = 1; i < 6; i++) { uint8_t data = 0; AJ_NVRAM_Read(&data, 1, handle); if (data != i * 11) { status = AJ_ERR_FAILURE; goto _TEST_NVRAM_EXIT; } } AJ_NVRAM_Close(handle); } if (AJ_NVRAM_Exist(id + 1)) { AJ_ASSERT(AJ_NVRAM_Delete(id + 1) == AJ_OK); } // Force storage compaction for (i = 0; i < 12; i++) { if (i == 6) { handle = AJ_NVRAM_Open(id + 2, "w", 100); AJ_ASSERT(handle); status = AJ_NVRAM_Close(handle); if (AJ_OK != status) { goto _TEST_NVRAM_EXIT; } continue; } handle = AJ_NVRAM_Open(id + 1, "w", 200); AJ_ASSERT(handle); status = AJ_NVRAM_Close(handle); if (AJ_OK != status) { goto _TEST_NVRAM_EXIT; } } AJ_InfoPrintf(("Compaction Layout Print\n")); AJ_NVRAM_Layout_Print(); _TEST_NVRAM_EXIT: //AJ_NVRAM_Close(handle); return status; } int AJ_Main() { AJ_Status status = AJ_OK; while (status == AJ_OK) { AJ_AlwaysPrintf(("AJ Initialize\n")); AJ_Initialize(); #ifdef OBS_ONLY AJ_RandBytes(&oRand, sizeof(oRand)); AJ_InfoPrintf(("BEGIN OBSWRITE TEST\n")); status = testObsWrite(); if (oRand % 2 == 0) { AJ_InfoPrintf(("CALLING REBOOT WITHOUT REWRITING TO 0")); #ifdef READABLE_LOG AJ_Sleep(1500); #endif AJ_Reboot(); } AJ_InfoPrintf(("REWRITE OBS TO 0 AND READ TEST\n")); #ifdef READABLE_LOG AJ_Sleep(1500); #endif status = TestNvramDelete(); AJ_Reboot(); #endif AJ_NVRAM_Clear(); AJ_AlwaysPrintf(("TEST LOCAL AND REMOTE CREDS\n")); status = TestCreds(); AJ_ASSERT(status == AJ_OK); #ifdef READABLE_LOG AJ_Sleep(1500); #endif AJ_AlwaysPrintf(("AJ_Main 2\n")); status = TestNVRAM(); #ifdef READABLE_LOG AJ_Sleep(1500); #endif #ifdef RAND_DATA Randomizer(); #endif AJ_InfoPrintf(("\nBEGIN GUID EXIST TEST\n")); status = TestExist(); #ifdef READABLE_LOG AJ_Sleep(1500); #endif AJ_InfoPrintf(("\nBEGIN OBSWRITE TEST\n")); status = TestObsWrite(); #ifdef READABLE_LOG AJ_Sleep(1500); #endif AJ_InfoPrintf(("\nOBSWRITE STATUS %u, BEGIN WRITE TEST\n", status)); #ifdef READABLE_LOG AJ_Sleep(1500); #endif status = TestNvramWrite(); AJ_InfoPrintf(("\nWRITE STATUS %u, BEGIN READ TEST\n", status)); #ifdef READABLE_LOG AJ_Sleep(1500); #endif status = TestNvramRead(); AJ_InfoPrintf(("\nREAD STATUS %u, BEGIN DELETE TEST\n", status)); #ifdef READABLE_LOG AJ_Sleep(1500); #endif status = TestNvramDelete(); AJ_InfoPrintf(("\nDONE\n")); AJ_AlwaysPrintf(("AJ_Main 3\n")); AJ_ASSERT(status == AJ_OK); AJ_AlwaysPrintf(("\nDELETE STATUS %u, NVRAMTEST RUN %u TIMES\n", status, count++)); #ifdef READABLE_LOG AJ_Sleep(3000); #endif status = TestNVRAMPeek(); AJ_InfoPrintf(("\nNVRAM Peek STATUS %u\n", status)); AJ_ASSERT(status == AJ_OK); status = TestNVRAMBigWrite(); AJ_InfoPrintf(("\nNVRAM Big Write STATUS %u\n", status)); AJ_ASSERT(status == AJ_OK); } return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/pcclient.c000066400000000000000000000513671271074662300155710ustar00rootroot00000000000000/* * PROPERTIES_CHANGED.c */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE PROPERTIES_CHANGED #ifndef TEST_DISABLE_SECURITY #define SECURE_INTERFACE #define SECURE_OBJECT #endif #include #include #include #include #include #include #include #include uint8_t dbgPROPERTIES_CHANGED = 0; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; /* * The app should authenticate the peer if one or more interfaces are secure * To define a secure interface, prepend '$' before the interface name, eg., "$org.alljoyn.alljoyn_test" */ #ifdef SECURE_INTERFACE static const char testInterfaceName[] = "$org.alljoyn.alljoyn_test"; static const char testValuesInterfaceName[] = "$org.alljoyn.alljoyn_test.values"; #else static const char testInterfaceName[] = "org.alljoyn.alljoyn_test"; static const char testValuesInterfaceName[] = "org.alljoyn.alljoyn_test.values"; #endif #if defined(ANNOUNCE_BASED_DISCOVERY) || defined(NGNS) static const char* testInterfaceNames[] = { testInterfaceName, testValuesInterfaceName, NULL }; #else static const char testServiceName[] = "org.alljoyn.alljoyn_test.PropertiesChanged"; #endif /* * Buffer to hold the peer's full service name or unique name. */ #if defined(ANNOUNCE_BASED_DISCOVERY) || defined(NGNS) static char g_peerServiceName[AJ_MAX_NAME_SIZE + 1]; #else static char g_peerServiceName[AJ_MAX_SERVICE_NAME_SIZE]; #endif static const uint16_t testServicePort = 789; static const char* const testValuesInterface[] = { testValuesInterfaceName, "@int_val=i", "@str_val=s", "@ro_val>s", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { AJ_PropertiesIface, testValuesInterface, NULL }; static const char testObj[] = "/org/alljoyn/alljoyn_test/PropertiesChanged"; /** * Objects implemented by the application */ #ifdef SECURE_OBJECT static AJ_Object ProxyObjects[] = { { "/org/alljoyn/alljoyn_test/PropertiesChanged", testInterfaces, AJ_OBJ_FLAG_SECURE }, { NULL } }; #else static AJ_Object ProxyObjects[] = { { "/org/alljoyn/alljoyn_test/PropertiesChanged", testInterfaces }, { NULL } }; #endif #define PRX_GET_PROP AJ_PRX_MESSAGE_ID(0, 0, AJ_PROP_GET) #define PRX_SET_PROP AJ_PRX_MESSAGE_ID(0, 0, AJ_PROP_SET) #define PRX_PROP_CHANGED AJ_PRX_MESSAGE_ID(0, 0, AJ_PROP_CHANGED) #define PRX_GET_INT AJ_PRX_PROPERTY_ID(0, 1, 0) #define PRX_SET_INT AJ_PRX_PROPERTY_ID(0, 1, 0) #define CONNECT_TIMEOUT (1000 * 200) #define UNMARSHAL_TIMEOUT (1000 * 5) #define PING_TIMEOUT (1000 * 10) /** * Peer discovery */ #ifdef ANNOUNCE_BASED_DISCOVERY static void handleMandatoryProps(const char* peerName, const char* appId, const char* appName, const char* deviceId, const char* deviceName, const char* manufacturer, const char* modelNumber, const char* defaultLanguage) { AJ_AlwaysPrintf(("Mandatory Properties for %s\n", peerName)); AJ_AlwaysPrintf(("Mandatory property: AppId=\"%s\"\n", (appId == NULL || appId[0] == '\0') ? "N/A" : appId)); AJ_AlwaysPrintf(("Mandatory property: AppName=\"%s\"\n", (appName == NULL || appName[0] == '\0') ? "N/A" : appName)); AJ_AlwaysPrintf(("Mandatory property: DeviceId=\"%s\"\n", (deviceId == NULL || deviceId[0] == '\0') ? "N/A" : deviceId)); AJ_AlwaysPrintf(("Mandatory property: DeviceName=\"%s\"\n", (deviceName == NULL || deviceName[0] == '\0') ? "N/A" : deviceName)); AJ_AlwaysPrintf(("Mandatory property: Manufacturer=\"%s\"\n", (manufacturer == NULL || manufacturer[0] == '\0') ? "N/A" : manufacturer)); AJ_AlwaysPrintf(("Mandatory property: ModelNumber=\"%s\"\n", (modelNumber == NULL || modelNumber[0] == '\0') ? "N/A" : modelNumber)); AJ_AlwaysPrintf(("Mandatory property: DefaultLanguage=\"%s\"\n", (defaultLanguage == NULL || defaultLanguage[0] == '\0') ? "N/A" : defaultLanguage)); } static void handleOptionalProperty(const char* peerName, const char* key, const char* sig, const AJ_Arg* value) { if (strcmp(sig, "s") == 0) { AJ_AlwaysPrintf(("Optional Prop: %s=\"%s\"\n", key, value->val.v_string)); } else { AJ_AlwaysPrintf(("Optional Prop: %s=[Not A String]\n", key)); } } static uint8_t FoundNewTestPeer(uint16_t version, uint16_t port, const char* peerName, const char* objPath) { AJ_AlwaysPrintf(("FoundNewTestPeer: version:%u port:%u name:%s path=%s\n", version, port, peerName, objPath)); if ((strcmp(objPath, testObj) == 0) && (port == testServicePort)) { if (g_peerServiceName[0] == '\0') { strncpy(g_peerServiceName, peerName, AJ_MAX_NAME_SIZE); g_peerServiceName[AJ_MAX_NAME_SIZE] = '\0'; } } return FALSE; } static uint8_t AcceptNewTestPeer(const char* peerName) { AJ_AlwaysPrintf(("AcceptNewTestPeer: name:%s\n", peerName)); if ((strcmp(g_peerServiceName, peerName) == 0)) { return TRUE; } return FALSE; } static const char* testIFaces[] = { "org.alljoyn.alljoyn_test.values" }; static AJ_AboutPeerDescription pingServicePeer = { testIFaces, (uint16_t)(sizeof(testIFaces) / sizeof(*testIFaces)), FoundNewTestPeer, AcceptNewTestPeer, NULL, handleMandatoryProps, handleOptionalProperty }; #endif /* * Let the application do some work */ static void AppDoWork(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName) { AJ_AlwaysPrintf(("AppDoWork\n")); } AJ_Status AppProcessPropertiesChanged(AJ_Message* msg) { AJ_Status status; const char* sendingInterface; AJ_Arg arrayOfChanged; AJ_Arg arrayOfInvalidated; AJ_AlwaysPrintf(("PROPERTIES CHANGED\n")); status = AJ_UnmarshalArgs(msg, "s", &sendingInterface); if (status == AJ_OK) { AJ_InfoPrintf(("interface name: %s\n", sendingInterface)); status = AJ_UnmarshalContainer(msg, &arrayOfChanged, AJ_ARG_ARRAY); } // unmarshal the array of changed properties if (status == AJ_OK) { while (status == AJ_OK) { const char* propName; const char* vsig; AJ_Arg value; AJ_Arg dict; status = AJ_UnmarshalContainer(msg, &dict, AJ_ARG_DICT_ENTRY); if (status != AJ_OK) { break; } status = AJ_UnmarshalArgs(msg, "s", &propName); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("property name: %s\n", propName)); status = AJ_UnmarshalVariant(msg, &vsig); if (status != AJ_OK) { break; } status = AJ_UnmarshalArg(msg, &value); if (status != AJ_OK) { break; } status = AJ_UnmarshalCloseContainer(msg, &dict); } if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(msg, &arrayOfChanged); } } if (status == AJ_OK) { // now the invalidated objects status = AJ_UnmarshalContainer(msg, &arrayOfInvalidated, AJ_ARG_ARRAY); while (status == AJ_OK) { const char* propName; status = AJ_UnmarshalArgs(msg, "s", &propName); if (status != AJ_OK) { break; } AJ_AlwaysPrintf(("invalidated property name: %s\n", propName)); } if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(msg, &arrayOfInvalidated); } } return status; } #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "123456"; #endif // Copied from alljoyn/alljoyn_core/unit_test/AuthListenerECDHETest.cc with // newlines removed static const char pem_prv[] = { "-----BEGIN EC PRIVATE KEY-----" "MHcCAQEEIBiLw29bf669g7MxMbXK2u8Lp5//w7o4OiVGidJdKAezoAoGCCqGSM49" "AwEHoUQDQgAE+A0C9YTghZ1vG7198SrUHxFlhtbSsmhbwZ3N5aQRwzFXWcCCm38k" "OzJEmS+venmF1o/FV0W80Mcok9CWlV2T6A==" "-----END EC PRIVATE KEY-----" }; static const char pem_x509[] = { "-----BEGIN CERTIFICATE-----" "MIIBYTCCAQigAwIBAgIJAOVrhhJOre/7MAoGCCqGSM49BAMCMCQxIjAgBgNVBAoM" "GUFsbEpveW5UZXN0U2VsZlNpZ25lZE5hbWUwHhcNMTUwODI0MjAxODQ1WhcNMjkw" "NTAyMjAxODQ1WjAgMR4wHAYDVQQKDBVBbGxKb3luVGVzdENsaWVudE5hbWUwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAAT4DQL1hOCFnW8bvX3xKtQfEWWG1tKyaFvB" "nc3lpBHDMVdZwIKbfyQ7MkSZL696eYXWj8VXRbzQxyiT0JaVXZPooycwJTAVBgNV" "HSUEDjAMBgorBgEEAYLefAEBMAwGA1UdEwEB/wQCMAAwCgYIKoZIzj0EAwIDRwAw" "RAIgevLUXoJBgUr6nVepBHQiv85CGuxu00V4uoARbH6qu1wCIA54iDRh6wit1zbP" "kqkBC015LjxucTf3Y7lNGhXuZRsL" "-----END CERTIFICATE-----" "-----BEGIN CERTIFICATE-----" "MIIBdTCCARugAwIBAgIJAJTFhmdwDWsvMAoGCCqGSM49BAMCMCQxIjAgBgNVBAoM" "GUFsbEpveW5UZXN0U2VsZlNpZ25lZE5hbWUwHhcNMTUwODI0MjAxODQ1WhcNMjkw" "NTAyMjAxODQ1WjAkMSIwIAYDVQQKDBlBbGxKb3luVGVzdFNlbGZTaWduZWROYW1l" "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEF0nZmkzuK/2CVf7udexLZnlEB5D+" "DBsx3POtsRyZWm2QiI1untDTp0uYp51tkP6wI6Gi5gWxB+86lEIPg4ZpTaM2MDQw" "IQYDVR0lBBowGAYKKwYBBAGC3nwBAQYKKwYBBAGC3nwBBTAPBgNVHRMBAf8EBTAD" "AQH/MAoGCCqGSM49BAMCA0gAMEUCIQDPQ1VRvdBhhneU5e7OvIFHK3d9XPZA7Fw6" "VyeW/P5wIAIgD969ks/z9vQ1yCaVaxmVz63toC1ggp4AnBXqbDy8O+4=" "-----END CERTIFICATE-----" }; static X509CertificateChain* chain = NULL; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; X509CertificateChain* node; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_ECDSA: switch (command) { case AJ_CRED_PRV_KEY: AJ_ASSERT(sizeof (AJ_ECCPrivateKey) == cred->len); if (sizeof (AJ_ECCPrivateKey) != cred->len) { AJ_ErrPrintf(("Credential length mismatch.\n")); status = AJ_ERR_INVALID; break; } status = AJ_DecodePrivateKeyPEM((AJ_ECCPrivateKey*) cred->data, pem_prv); cred->expiration = keyexpiration; break; case AJ_CRED_CERT_CHAIN: switch (cred->direction) { case AJ_CRED_REQUEST: // Free previous certificate chain AJ_X509FreeDecodedCertificateChain(chain); chain = AJ_X509DecodeCertificateChainPEM(pem_x509); if (NULL == chain) { status = AJ_ERR_INVALID; } else { cred->data = (uint8_t*) chain; cred->expiration = keyexpiration; status = AJ_OK; } break; case AJ_CRED_RESPONSE: node = (X509CertificateChain*) cred->data; #ifdef LITE_TEST_BACKCOMPAT status = AJ_X509VerifyChain(node, NULL, 0); #else status = AJ_X509VerifyChain(node, NULL, AJ_CERTIFICATE_IDN_X509); #endif while (node) { AJ_DumpBytes("CERTIFICATE", node->certificate.der.data, node->certificate.der.size); node = node->next; } break; } break; } break; default: break; } return status; } #endif #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } #endif #ifdef MAIN_ALLOWS_ARGS int AJ_Main(int ac, char** av) #else int AJ_Main() #endif { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; AJ_Status authStatus = AJ_ERR_NULL; #ifdef SECURE_INTERFACE uint32_t suites[AJ_AUTH_SUITES_NUM]; size_t numsuites = 0; uint8_t clearkeys = FALSE; #endif #ifdef MAIN_ALLOWS_ARGS #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) ac--; av++; /* * Enable authentication mechanism by command line */ if (ac) { if (0 == strncmp(*av, "-ek", 3)) { clearkeys = TRUE; ac--; av++; } else if (0 == strncmp(*av, "-e", 2)) { ac--; av++; } if (!ac) { AJ_AlwaysPrintf(("-e(k) requires an auth mechanism.\n")); return 1; } while (ac) { if (0 == strncmp(*av, "ECDHE_ECDSA", 11)) { suites[numsuites++] = AUTH_SUITE_ECDHE_ECDSA; } else if (0 == strncmp(*av, "ECDHE_PSK", 9)) { suites[numsuites++] = AUTH_SUITE_ECDHE_PSK; } else if (0 == strncmp(*av, "ECDHE_NULL", 10)) { suites[numsuites++] = AUTH_SUITE_ECDHE_NULL; } ac--; av++; } } #endif #else suites[numsuites++] = AUTH_SUITE_ECDHE_ECDSA; clearkeys = TRUE; #endif #ifdef SECURE_INTERFACE if (numsuites == 0) { /* Default security to ECDHE_NULL, if not explicit elsewhere */ suites[numsuites++] = AUTH_SUITE_ECDHE_NULL; } #endif /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(ProxyObjects); AJ_RegisterObjects(NULL, ProxyObjects); while (TRUE) { AJ_Message msg; if (!connected) { #if defined (ANNOUNCE_BASED_DISCOVERY) status = AJ_StartClientByPeerDescription(&bus, NULL, CONNECT_TIMEOUT, FALSE, &pingServicePeer, testServicePort, &sessionId, g_peerServiceName, NULL); #elif defined (NGNS) status = AJ_StartClientByInterface(&bus, NULL, CONNECT_TIMEOUT, FALSE, testInterfaceNames, &sessionId, g_peerServiceName, NULL); #else status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, testServiceName, testServicePort, &sessionId, NULL, g_peerServiceName); #endif if (status == AJ_OK) { AJ_AlwaysPrintf(("StartClient returned %d, sessionId=%u, serviceName=%s\n", status, sessionId, g_peerServiceName)); AJ_AlwaysPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(&bus))); connected = TRUE; #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) AJ_BusEnableSecurity(&bus, suites, numsuites); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); if (clearkeys) { AJ_ClearCredentials(AJ_GENERIC_MASTER_SECRET | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_THUMBPRINT | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_KEYS | AJ_CRED_TYPE_GENERIC); } status = AJ_BusAuthenticatePeer(&bus, g_peerServiceName, AuthCallback, &authStatus); if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_BusAuthenticatePeer returned %d\n", status)); } #else authStatus = AJ_OK; #endif } else { AJ_AlwaysPrintf(("StartClient returned %d\n", status)); break; } } AJ_AlwaysPrintf(("Auth status %d and AllJoyn status %d\n", authStatus, status)); if (status == AJ_ERR_RESOURCES) { AJ_InfoPrintf(("Peer is busy, disconnecting and retrying auth...\n")); AJ_Disconnect(&bus); connected = FALSE; continue; } if (authStatus != AJ_ERR_NULL) { if (authStatus != AJ_OK) { AJ_Disconnect(&bus); break; } authStatus = AJ_ERR_NULL; AJ_BusSetLinkTimeout(&bus, sessionId, 10 * 1000); } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(&bus, sessionId, g_peerServiceName); continue; } } else { switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_SET_LINK_TIMEOUT): { uint32_t disposition; uint32_t timeout; status = AJ_UnmarshalArgs(&msg, "uu", &disposition, &timeout); if (disposition == AJ_SETLINKTIMEOUT_SUCCESS) { AJ_AlwaysPrintf(("Link timeout set to %d\n", timeout)); } else { AJ_AlwaysPrintf(("SetLinkTimeout failed %d\n", disposition)); } // inform the routing node we want to see these notifications AJ_BusSetSignalRuleSerial(&bus, "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',arg0='#org.alljoyn.alljoyn_test.values'", AJ_BUS_SIGNAL_ALLOW, 0, NULL); } break; case AJ_REPLY_ID(AJ_METHOD_BUS_PING): { uint32_t disposition; status = AJ_UnmarshalArgs(&msg, "u", &disposition); if (disposition == AJ_PING_SUCCESS) { AJ_AlwaysPrintf(("Bus Ping reply received\n")); } else { AJ_AlwaysPrintf(("Bus Ping failed, disconnecting: %d\n", disposition)); status = AJ_ERR_LINK_DEAD; } } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * Force a disconnect */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u\n", id, reason)); } status = AJ_ERR_SESSION_LOST; break; case PRX_PROP_CHANGED: /* * properties changed notification: "sa{sv}as", "interface,changed_props,invalidated_props" */ status = AppProcessPropertiesChanged(&msg); break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_SESSION_LOST) || (status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_AlwaysPrintf(("AllJoyn disconnect\n")); AJ_AlwaysPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); break; } } AJ_AlwaysPrintf(("PROPERTIES_CHANGED EXIT %d\n", status)); return status; } #ifdef AJ_MAIN #ifdef MAIN_ALLOWS_ARGS int main(int ac, char** av) { return AJ_Main(ac, av); } #else int main() { return AJ_Main(); } #endif #endif ajtcl-16.04/test/pcservice.c000066400000000000000000000467501271074662300157530ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE PROPERTIES_CHANGED #ifndef TEST_DISABLE_SECURITY #define SECURE_INTERFACE #define SECURE_OBJECT #endif #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ uint8_t dbgPROPERTIES_CHANGED = 0; /* * Modify these variables to change the service's behavior */ static const char ServiceName[] = "org.alljoyn.alljoyn_test.PropertiesChanged"; static const uint16_t ServicePort = 789; static const uint8_t CancelAdvertiseName = FALSE; static const uint8_t ReflectSignal = FALSE; #define METHOD_TIMEOUT (1000 * 10) /* * An application property to SET or GET */ static int32_t propVal = 123456; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; static const char* const testValuesInterface[] = { #ifdef SECURE_INTERFACE "$org.alljoyn.alljoyn_test.values", #else "org.alljoyn.alljoyn_test.values", #endif "@int_val=i", "@str_val=s", "@ro_val>s", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { AJ_PropertiesIface, testValuesInterface, NULL }; static AJ_Object AppObjects[] = { #ifdef SECURE_OBJECT { "/org/alljoyn/alljoyn_test/PropertiesChanged", testInterfaces, AJ_OBJ_FLAG_ANNOUNCED | AJ_OBJ_FLAG_SECURE }, #else { "/org/alljoyn/alljoyn_test/PropertiesChanged", testInterfaces, AJ_OBJ_FLAG_ANNOUNCED }, #endif { NULL } }; static AJ_PermissionMember members[] = { { "*", AJ_MEMBER_TYPE_ANY, AJ_ACTION_PROVIDE | AJ_ACTION_OBSERVE, NULL } }; static AJ_PermissionRule rules[] = { { "/org/alljoyn/alljoyn_test/PropertiesChanged", "org.alljoyn.alljoyn_test.PropertiesChanged", members, NULL } }; /* * Message identifiers for the method calls this application implements */ #define APP_GET_PROP AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_GET) #define APP_SET_PROP AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_SET) #define APP_PROP_CHANGED AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_CHANGED) /* * Property identifiers for the properies this application implements */ #define APP_INT_VAL_PROP AJ_APP_PROPERTY_ID(0, 1, 0) /* * Send out PropopertiesChanged with different payloads, * based on the number of times AppDoWork has been called. * This should exercise different permutations of properties changing. * int_val: every even count * ro_val: every third count * invalidates str_val: every fifth count */ static void AppDoWork(AJ_BusAttachment* bus, uint32_t sessionId) { /* * This function is called if there are no messages to unmarshal */ AJ_Status status; AJ_Message msg; AJ_Arg array; static uint8_t count = 0; AJ_InfoPrintf(("do work\n")); status = AJ_MarshalSignal(bus, &msg, APP_PROP_CHANGED, NULL, sessionId, 0, METHOD_TIMEOUT); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", testValuesInterface[0]); } // now create the array of dictionary entries and their values if (status == AJ_OK) { status = AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); } if (status == AJ_OK) { if (count % 2 == 0) { status = AJ_MarshalArgs(&msg, "{sv}", "int_val", "i", propVal); } if (count % 3 == 0) { status = AJ_MarshalArgs(&msg, "{sv}", "ro_val", "s", "ro_val mod 4"); } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&msg, &array); } // and one entry in the invalidated property array if (status == AJ_OK) { status = AJ_MarshalContainer(&msg, &array, AJ_ARG_ARRAY); } if (status == AJ_OK) { if (count % 5 == 0) { status = AJ_MarshalArgs(&msg, "s", "str_val"); } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(&msg, &array); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } else { AJ_AlwaysPrintf(("AppDoWork %s\n", AJ_StatusText(status))); } AJ_CloseMsg(&msg); propVal++; count++; } #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "123456"; #endif // Copied from alljoyn/alljoyn_core/unit_test/AuthListenerECDHETest.cc with // newlines removed static const char pem_prv[] = { "-----BEGIN EC PRIVATE KEY-----" "MDECAQEEICCRJMbxSiWUqj4Zs7jFQRXDJdBRPWX6fIVqE1BaXd08oAoGCCqGSM49" "AwEH" "-----END EC PRIVATE KEY-----" }; static const char pem_x509[] = { "-----BEGIN CERTIFICATE-----" "MIIBuDCCAV2gAwIBAgIHMTAxMDEwMTAKBggqhkjOPQQDAjBCMRUwEwYDVQQLDAxv" "cmdhbml6YXRpb24xKTAnBgNVBAMMIDgxM2FkZDFmMWNiOTljZTk2ZmY5MTVmNTVk" "MzQ4MjA2MB4XDTE1MDcyMjIxMDYxNFoXDTE2MDcyMTIxMDYxNFowQjEVMBMGA1UE" "CwwMb3JnYW5pemF0aW9uMSkwJwYDVQQDDCAzOWIxZGNmMjBmZDJlNTNiZGYzMDU3" "NzMzMjBlY2RjMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGJ/9F4xHn3Klw7z" "6LREmHJgzu8yJ4i09b4EWX6a5MgUpQoGKJcjWgYGWb86bzbciMCFpmKzfZ42Hg+k" "BJs2ZWajPjA8MAwGA1UdEwQFMAMBAf8wFQYDVR0lBA4wDAYKKwYBBAGC3nwBATAV" "BgNVHSMEDjAMoAoECELxjRK/fVhaMAoGCCqGSM49BAMCA0kAMEYCIQDixoulcO7S" "df6Iz6lvt2CDy0sjt/bfuYVW3GeMLNK1LAIhALNklms9SP8ZmTkhCKdpC+/fuwn0" "+7RX8CMop11eWCih" "-----END CERTIFICATE-----" }; static X509CertificateChain* chain = NULL; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; X509CertificateChain* node; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_ECDSA: switch (command) { case AJ_CRED_PRV_KEY: AJ_ASSERT(sizeof (AJ_ECCPrivateKey) == cred->len); if (sizeof (AJ_ECCPrivateKey) != cred->len) { AJ_ErrPrintf(("Credential length mismatch.\n")); status = AJ_ERR_INVALID; break; } status = AJ_DecodePrivateKeyPEM((AJ_ECCPrivateKey*) cred->data, pem_prv); cred->expiration = keyexpiration; break; case AJ_CRED_CERT_CHAIN: switch (cred->direction) { case AJ_CRED_REQUEST: // Free previous certificate chain AJ_X509FreeDecodedCertificateChain(chain); chain = AJ_X509DecodeCertificateChainPEM(pem_x509); if (NULL == chain) { return AJ_ERR_INVALID; } cred->data = (uint8_t*) chain; cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_RESPONSE: node = (X509CertificateChain*) cred->data; #ifdef LITE_TEST_BACKCOMPAT status = AJ_X509VerifyChain(node, NULL, 0); #else status = AJ_X509VerifyChain(node, NULL, AJ_CERTIFICATE_IDN_X509); #endif while (node) { AJ_DumpBytes("CERTIFICATE", node->certificate.der.data, node->certificate.der.size); node = node->next; } break; } break; } break; default: break; } return status; } #endif #define UUID_LENGTH 16 #define APP_ID_SIGNATURE "ay" static AJ_Status MarshalAppId(AJ_Message* msg, const char* appId) { AJ_Status status; uint8_t binAppId[UUID_LENGTH]; uint32_t sz = strlen(appId); if (sz > UUID_LENGTH * 2) { // Crop application id that is too long sz = UUID_LENGTH * 2; } status = AJ_HexToRaw(appId, sz, binAppId, UUID_LENGTH); if (status != AJ_OK) { return status; } status = AJ_MarshalArgs(msg, "{sv}", AJ_APP_ID_STR, APP_ID_SIGNATURE, binAppId, sz / 2); return status; } static AJ_Status AboutPropGetter(AJ_Message* reply, const char* language) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_GUID theAJ_GUID; char machineIdValue[UUID_LENGTH * 2 + 1]; machineIdValue[UUID_LENGTH * 2] = '\0'; /* Here, "en" is the only supported language, so we always return it * regardless of what was requested, per the algorithm specified in * RFC 4647 section 3.4. */ status = AJ_MarshalContainer(reply, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { status = AJ_GetLocalGUID(&theAJ_GUID); if (status == AJ_OK) { AJ_GUID_ToString(&theAJ_GUID, machineIdValue, UUID_LENGTH * 2 + 1); } if (status == AJ_OK) { status = MarshalAppId(reply, &machineIdValue[0]); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_APP_NAME_STR, "s", "properties_changed_service"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_ID_STR, "s", machineIdValue); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_NAME_STR, "s", "Tester"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MANUFACTURER_STR, "s", "QCE"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MODEL_NUMBER_STR, "s", "1.0"); } //SupportedLanguages if (status == AJ_OK) { AJ_Arg dict; AJ_Arg languageListArray; status = AJ_MarshalContainer(reply, &dict, AJ_ARG_DICT_ENTRY); if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", AJ_SUPPORTED_LANGUAGES_STR); } if (status == AJ_OK) { status = AJ_MarshalVariant(reply, "as"); } if (status == AJ_OK) { status = AJ_MarshalContainer(reply, &languageListArray, AJ_ARG_ARRAY); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", "en"); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &languageListArray); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &dict); } } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DESCRIPTION_STR, "s", "properties changed test app"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEFAULT_LANGUAGE_STR, "s", "en"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_SOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_AJSOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &array); } return status; } static const uint32_t suites[] = { AUTH_SUITE_ECDHE_ECDSA, AUTH_SUITE_ECDHE_PSK, AUTH_SUITE_ECDHE_NULL }; #define CONNECT_TIMEOUT (1000 * 1000) #define UNMARSHAL_TIMEOUT (1000 * 5) #ifdef MAIN_ALLOWS_ARGS int AJ_Main(int ac, char** av) #else int AJ_Main() #endif { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; uint8_t claim = FALSE; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); AJ_AboutRegisterPropStoreGetter(AboutPropGetter); #ifdef MAIN_ALLOWS_ARGS ac--; av++; if (ac) { #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) if (0 == strncmp(*av, "-claim", 6)) { claim = TRUE; } #endif } #endif while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned AJ_OK\n")); AJ_InfoPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_SetIdleTimeouts(&bus, 10, 4); connected = TRUE; #ifdef SECURE_OBJECT status = AJ_SetObjectFlags("/org/alljoyn/alljoyn_test/PropertiesChanged", AJ_OBJ_FLAG_SECURE, 0); if (status != AJ_OK) { AJ_ErrPrintf(("Error calling AJ_SetObjectFlags.. [%s] \n", AJ_StatusText(status))); return -1; } #endif #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) AJ_BusEnableSecurity(&bus, suites, ArraySize(suites)); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); AJ_ManifestTemplateSet(rules); if (claim) { AJ_SecuritySetClaimConfig(&bus, APP_STATE_CLAIMABLE, CLAIM_CAPABILITY_ECDHE_PSK, 0); } #endif /* Configure timeout for the link to the daemon bus */ AJ_SetBusLinkTimeout(&bus, 60); // 60 seconds } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if ((AJ_ERR_TIMEOUT == status) && (AJ_ERR_LINK_TIMEOUT == AJ_BusLinkStateProc(&bus))) { status = AJ_ERR_READ; } if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(&bus, sessionId); continue; } } if (status == AJ_OK) { switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_ADD_MATCH): if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_InfoPrintf(("Failed to add match\n")); status = AJ_ERR_FAILURE; } else { status = AJ_OK; } break; case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; status = AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); if (AJ_OK != status) { break; } if (port == ServicePort) { status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } else { status = AJ_ResetArgs(&msg); if (AJ_OK != status) { break; } status = AJ_BusHandleBusMessage(&msg); } } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: { uint32_t id, reason; status = AJ_UnmarshalArgs(&msg, "uu", &id, &reason); if (AJ_OK != status) { break; } AJ_InfoPrintf(("Session lost. ID = %u, reason = %u", id, reason)); if (CancelAdvertiseName) { status = AJ_BusAdvertiseName(&bus, ServiceName, AJ_TRANSPORT_ANY, AJ_BUS_START_ADVERTISING, 0); } status = AJ_ERR_SESSION_LOST; } break; case AJ_SIGNAL_SESSION_JOINED: if (CancelAdvertiseName) { status = AJ_BusAdvertiseName(&bus, ServiceName, AJ_TRANSPORT_ANY, AJ_BUS_STOP_ADVERTISING, 0); } break; case AJ_REPLY_ID(AJ_METHOD_CANCEL_ADVERTISE): case AJ_REPLY_ID(AJ_METHOD_ADVERTISE_NAME): if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } break; case AJ_REPLY_ID(AJ_METHOD_BUS_SET_IDLE_TIMEOUTS): { uint32_t disposition, idleTo, probeTo; if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } status = AJ_UnmarshalArgs(&msg, "uuu", &disposition, &idleTo, &probeTo); if (AJ_OK != status) { break; } AJ_InfoPrintf(("SetIdleTimeouts response disposition=%u idleTimeout=%u probeTimeout=%u\n", disposition, idleTo, probeTo)); } break; default: /* * Pass to the built-in bus message handlers */ status = AJ_BusHandleBusMessage(&msg); break; } // Any received packets indicates the link is active, so call to reinforce the bus link state AJ_NotifyLinkActive(); } /* * Unarshaled messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_LINK_DEAD)) { AJ_InfoPrintf(("AllJoyn disconnect\n")); AJ_InfoPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); connected = FALSE; /* * Sleep a little while before trying to reconnect */ AJ_Sleep(10 * 1000); } } AJ_WarnPrintf(("properties_changed_service EXIT %d\n", status)); return status; } #ifdef AJ_MAIN #ifdef MAIN_ALLOWS_ARGS int main(int ac, char** av) { return AJ_Main(ac, av); } #else int main() { return AJ_Main(); } #endif #endif ajtcl-16.04/test/scan-n-con.c000066400000000000000000000424721271074662300157210ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include /* Forward Declaration */ static void wifiScanResultCallback(void* context, const char* ssid, const uint8_t mac[6], uint8_t rssi, AJ_WiFiSecurityType secType, AJ_WiFiCipherType cipherType); static void PrintStats(void); static char* TestAddrStr(uint32_t addr); /* Configurable test knobs */ static const uint8_t RUN_NEGATIVE_TESTS = TRUE; static const uint16_t DELAY_BETWEEN_SCANS = 5000; /* milliseconds */ static const uint16_t DELAY_BETWEEN_ASSOCIATIONS = 15000; /* milliseconds */ static const uint16_t DHCP_TIMEOUT = 1000 * 10; /* in milliseconds */ static const uint16_t DISCOVER_TIMEOUT = 1000 * 3; /* in milliseconds */ /* static globals */ #define AJ_TEST_NUM_MAX_OCTETS_IN_SSID 32 static const char* const secStr[] = { "OPEN", "WEP", "WPA", "WPA2" }; static const char* const ciphStr[] = { "OPEN", "TKIP", "CCMP", "WEP" }; typedef struct { char ssid[AJ_TEST_NUM_MAX_OCTETS_IN_SSID + 1]; uint8_t bssid[6]; uint8_t rssi; AJ_WiFiSecurityType secType; AJ_WiFiCipherType cipherType; } AJ_WiFiScanInfoEntry; static AJ_WiFiScanInfoEntry wifiScanInfo[255]; /* 255 == UINT8_MAX */ static uint8_t numValidScanEntries = 0; /* The intention is to explcitly avoid connecting to any routing node */ static const char routingNodePrefix[] = "test.randhex"; /* counters to keep track of the progress */ typedef struct { uint16_t numSuccessful; uint16_t numTimedout; uint16_t numFailed; } testStats_t; static testStats_t scanStats; static testStats_t associationStats; static testStats_t dhcpStats; static testStats_t discoverStats; static testStats_t disassociationStats; static const uint8_t* sentinelForWifiScanContext = NULL; static uint8_t currentContext = 0; /* an offset value from the above pointer */ void AJ_Main(void) { uint8_t i = 0; AJ_Status status = AJ_ERR_FAILURE; /* the glass is half-empty */ AJ_BusAttachment bus; /* these variables are used when kicking off DHCP */ uint32_t current_ip_address = 0; uint32_t current_subnet_mask = 0; uint32_t current_default_gateway = 0; AJ_Time dhcpTimer; uint32_t timeTakenForDhcp = 0; AJ_Initialize(); AJ_Printf("\nAllJoyn Release: %s\n\n", AJ_GetVersion()); AJ_Printf("INFO: The parameter RUN_NEGATIVE_TESTS is %s\n", (RUN_NEGATIVE_TESTS ? "true" : "false")); AJ_Printf("INFO: The parameter DELAY_BETWEEN_SCANS is %u ms\n", DELAY_BETWEEN_SCANS); AJ_Printf("INFO: The parameter DELAY_BETWEEN_ASSOCIATIONS is %u ms\n", DELAY_BETWEEN_ASSOCIATIONS); AJ_Printf("INFO: The parameter DHCP_TIMEOUT is %u ms\n", DHCP_TIMEOUT); AJ_Printf("INFO: The parameter DISCOVER_TIMEOUT is %u ms\n", DISCOVER_TIMEOUT); /* reset the wifi to start with a clean slate */ status = AJ_ResetWiFi(); if (AJ_OK != status) { AJ_Printf("WARN: AJ_ResetWiFi returned %s (code: %u).\n", AJ_StatusText(status), status); } /* * Repeatedly do the following: * a. scan for access points in the vicinity * b. For each open access point in the returned results: * i. associate using AJ_ConnectWiFi * ii. acquire an ip address using AJ_AcquireIPAddress * iii. perform a short-lived discovery on some random node prefix * using AJ_FindBusAndConnect * iv. disassociate using AJ_DisconnectWiFi * c. For each secured access point in the returned results: * i. Connect to it with intentionally incorrect parameters * (Negative test) */ while (TRUE) { AJ_RandBytes(¤tContext, sizeof(currentContext)); uint8_t currentMaxAps = 0; /* ask for a random number of access points (between 1 and 255) when scanning */ AJ_RandBytes(¤tMaxAps, sizeof(currentMaxAps)); if (currentMaxAps == 0) { currentMaxAps = 1; } /* Reset numValidScanEntries, before every scan attempt. */ numValidScanEntries = 0; status = AJ_WiFiScan((void*) (sentinelForWifiScanContext + currentContext), wifiScanResultCallback, currentMaxAps); if (AJ_OK != status) { if (AJ_ERR_FAILURE == status && 0 != currentMaxAps) { scanStats.numFailed++; } else if (AJ_ERR_RESOURCES == status) { scanStats.numFailed++; } AJ_Printf("Failed to scan: %s (code: %u)\n", AJ_StatusText(status), status); /* No point in attempting to do wifi operations, when scan failed */ continue; } else { /* * A success was returned from AJ_WiFiScan. Were any results * returned after all?? */ if (0 < numValidScanEntries) { scanStats.numSuccessful++; } else { AJ_Printf("WARN: AJ_WiFiScan returned %s (code: %u), but returned ZERO scan results...\n", AJ_StatusText(status), status); scanStats.numFailed++; /* When num of scan results is zero, there is nothing to do */ continue; } } /* numValidScanEntries is an index into the array. */ if (currentMaxAps < numValidScanEntries) { AJ_Printf("WARN: Scan returned more results (%u) than requested (%u).\n", numValidScanEntries, currentMaxAps); } else { AJ_Printf("Wifi scan successful (got %u results).\n", numValidScanEntries); } for (i = 0; i < numValidScanEntries; i++) { if (AJ_WIFI_SECURITY_NONE != wifiScanInfo[i].secType) { /* On some targets, it is not possible to check for 802.11 * authentication failure when security type is WEP. * Hence, run negative tests only for WPA/WPA2-based APs. */ if (RUN_NEGATIVE_TESTS && AJ_WIFI_SECURITY_WEP != wifiScanInfo[i].secType) { /* Run a negative test for wifi association */ AJ_Printf("RUN (negative test): Attempting to associate with %s using a randomly generated passphrase...", wifiScanInfo[i].ssid); char random_passphrase[128 + 1]; AJ_RandHex(random_passphrase, sizeof(random_passphrase), (sizeof(random_passphrase) - 1) / 2); /* Set a random passphrase length based on security type */ uint8_t randomPassphraseLen = 0; /* WPA / WPA2 - assuming min len is 8 and max is 64 */ AJ_RandBytes(&randomPassphraseLen, sizeof(randomPassphraseLen)); randomPassphraseLen = 8 + randomPassphraseLen % (64 - 8 + 1); random_passphrase[randomPassphraseLen] = '\0'; status = AJ_ConnectWiFi(wifiScanInfo[i].ssid, wifiScanInfo[i].secType, wifiScanInfo[i].cipherType, random_passphrase); if (AJ_OK == status) { /* negative test failed */ AJ_Printf("FAIL (negative test): Associated with SSID: %s BSSID: %x:%x:%x:%x:%x:%x Security: %s(%s) Passphrase: %s RSSI: %u ...\n", wifiScanInfo[i].ssid, wifiScanInfo[i].bssid[0], wifiScanInfo[i].bssid[1], wifiScanInfo[i].bssid[2], wifiScanInfo[i].bssid[3], wifiScanInfo[i].bssid[4], wifiScanInfo[i].bssid[5], secStr[wifiScanInfo[i].secType], ciphStr[wifiScanInfo[i].cipherType], random_passphrase, wifiScanInfo[i].rssi); /* negative test failed - don't go any further */ AJ_ASSERT(0); } else { AJ_Printf("Done (negative test).\n"); } status = AJ_DisconnectWiFi(); AJ_Sleep(DELAY_BETWEEN_ASSOCIATIONS); } continue; } else { AJ_Printf("Attempting to associate with SSID: %s BSSID: %x:%x:%x:%x:%x:%x Security: %s(%s) RSSI: %u ...\n", wifiScanInfo[i].ssid, wifiScanInfo[i].bssid[0], wifiScanInfo[i].bssid[1], wifiScanInfo[i].bssid[2], wifiScanInfo[i].bssid[3], wifiScanInfo[i].bssid[4], wifiScanInfo[i].bssid[5], secStr[wifiScanInfo[i].secType], ciphStr[wifiScanInfo[i].cipherType], wifiScanInfo[i].rssi); status = AJ_ConnectWiFi(wifiScanInfo[i].ssid, wifiScanInfo[i].secType, wifiScanInfo[i].cipherType, ""); if (AJ_OK != status) { associationStats.numFailed++; AJ_Printf("Failed to associate : %s (code: %u)\n", AJ_StatusText(status), status); /* * No point in proceeding any further when WiFi association * has failed */ continue; } else { associationStats.numSuccessful++; } AJ_Printf("Successfully associated. Attempting to get IP Address via DHCP...\n"); AJ_InitTimer(&dhcpTimer); status = AJ_AcquireIPAddress(¤t_ip_address, ¤t_subnet_mask, ¤t_default_gateway, DHCP_TIMEOUT); timeTakenForDhcp = AJ_GetElapsedTime(&dhcpTimer, FALSE); if (AJ_OK != status) { if (AJ_ERR_TIMEOUT == status) { dhcpStats.numTimedout++; AJ_Printf("Timedout (%u ms) while trying to get IP Address via DHCP\n", timeTakenForDhcp); /* * Discovery timed out. * Check whether the API returned in a timely manner. * See whether the actual duration is off by +/- 500ms. * Delay beyond that is unusual. */ if (500 < abs(DHCP_TIMEOUT - timeTakenForDhcp)) { AJ_Printf("WARN: AJ_AcquireIPAddress API did not return in a timely manner. Timeout parameter: %u Actual time elapsed: %u\n", DHCP_TIMEOUT, timeTakenForDhcp); } } else { dhcpStats.numFailed++; AJ_Printf("Failed to get IP Address via DHCP : %s (code: %u)\n", AJ_StatusText(status), status); } } else { dhcpStats.numSuccessful++; AJ_Printf("Successfully obtained\n"); AJ_Printf("\tIP Addresss : %s\n", TestAddrStr(current_ip_address)); AJ_Printf("\tSubnet Mask : %s\n", TestAddrStr(current_subnet_mask)); AJ_Printf("\tDefault Gateway: %s\n", TestAddrStr(current_default_gateway)); /* Generate a random name using routingNodePrefix */ char currentRoutingNodeName[32 + 1]; strncpy(currentRoutingNodeName, routingNodePrefix, sizeof(routingNodePrefix)); AJ_RandHex(currentRoutingNodeName + strlen(routingNodePrefix), sizeof(currentRoutingNodeName) - sizeof(routingNodePrefix), (sizeof(currentRoutingNodeName) - sizeof(routingNodePrefix) - 1) / 2); currentRoutingNodeName[32] = '\0'; /* just to be safe */ AJ_Printf("Attempting to discover routing node: %s...", currentRoutingNodeName); status = AJ_FindBusAndConnect(&bus, currentRoutingNodeName, DISCOVER_TIMEOUT); if (AJ_ERR_TIMEOUT == status) { /* this is the expected result */ discoverStats.numTimedout++; AJ_Printf("Done (discovery of routing node).\n"); } else if (AJ_OK != status) { discoverStats.numFailed++; AJ_Printf("Failed to connect to routing node: %s (code: %u)\n", AJ_StatusText(status), status); } else if (AJ_OK == status) { /* * the test attempted to discovery a randomly generated * routing node prefix and it worked - highly unlikely event */ AJ_Printf("FATAL: Was able to discover and connect to routing node with prefix %s. Got unique address %s.", currentRoutingNodeName, AJ_GetUniqueName(&bus)); AJ_ASSERT(0); } } status = AJ_DisconnectWiFi(); if (AJ_OK != status) { disassociationStats.numFailed++; AJ_Printf("Failed to disassociate: %s (code: %u)\n", AJ_StatusText(status), status); } else { disassociationStats.numSuccessful++; AJ_Printf("Disassociated from access point. "); } AJ_Sleep(DELAY_BETWEEN_ASSOCIATIONS); } } PrintStats(); AJ_Sleep(DELAY_BETWEEN_SCANS); } } static void wifiScanResultCallback(void* context, const char* ssid, const uint8_t mac[6], uint8_t rssi, AJ_WiFiSecurityType secType, AJ_WiFiCipherType cipherType) { uint8_t callbackContext = (((uint8_t*) context) - sentinelForWifiScanContext); if (currentContext != callbackContext) { AJ_Printf("WARN: Got wifi callback with context: %u different from current context: %u. Ignoring...\n", callbackContext, currentContext); return; } size_t lengthOfSsid = strlen(ssid); if (AJ_TEST_NUM_MAX_OCTETS_IN_SSID < lengthOfSsid) { AJ_Printf("WARN: Got wifi callback with an ssid %s of length %u (greater than %u). Ignoring...\n", ssid, lengthOfSsid, AJ_TEST_NUM_MAX_OCTETS_IN_SSID); return; } if (0 == lengthOfSsid) { AJ_Printf("WARN: Got wifi callback with an ssid of length ZERO. Ignoring...\n"); return; } if ((AJ_WIFI_SECURITY_NONE == secType && AJ_WIFI_CIPHER_NONE != cipherType) || (AJ_WIFI_SECURITY_WEP == secType && AJ_WIFI_CIPHER_WEP != cipherType) || ((AJ_WIFI_SECURITY_WPA == secType || AJ_WIFI_SECURITY_WPA2 == secType) && (AJ_WIFI_CIPHER_CCMP != cipherType && AJ_WIFI_CIPHER_TKIP != cipherType))) { AJ_Printf("WARN: Got wifi callback with security type: %s and ciphertype: %s. Ignoring...\n", secStr[secType], ciphStr[cipherType]); return; } /* input validation done - store the result */ strncpy(wifiScanInfo[numValidScanEntries].ssid, ssid, lengthOfSsid + 1); wifiScanInfo[numValidScanEntries].ssid[lengthOfSsid + 1] = '\0'; /* Force nul termination */ memcpy(wifiScanInfo[numValidScanEntries].bssid, mac, sizeof(wifiScanInfo[numValidScanEntries].bssid)); wifiScanInfo[numValidScanEntries].rssi = rssi; wifiScanInfo[numValidScanEntries].secType = secType; wifiScanInfo[numValidScanEntries].cipherType = cipherType; /* * All pieces have been copied to this entry, point to the next * the entry so that the next callback copies into that */ numValidScanEntries++; return; } static void PrintStats(void) { AJ_Printf("\n\t--Scan Stats--\n" "\t--------------\n" "\tSuccessful = %u Failed = %u\n", scanStats.numSuccessful, scanStats.numFailed); AJ_Printf("\n\t--Wifi Connect Stats--\n" "\t----------------------\n" "\tSuccessful = %u Failed = %u\n", associationStats.numSuccessful, associationStats.numFailed); AJ_Printf("\n\t--Dhcp Stats--\n" "\t--------------\n" "\tSuccessful = %u Timedout = %u Failed = %u\n", dhcpStats.numSuccessful, dhcpStats.numTimedout, dhcpStats.numFailed); AJ_Printf("\n\t--Discovery Stats--\n" "\t-------------------\n" "\tTimedout = %u Failed = %u\n", discoverStats.numTimedout, discoverStats.numFailed); AJ_Printf("\n\t--Wifi Disconnect Stats--\n" "\t-------------------------\n" "\tSuccessful = %u Failed = %u\n\n", disassociationStats.numSuccessful, disassociationStats.numFailed); } static char bufferToHoldCharsOfIpAddress[17]; static char* TestAddrStr(uint32_t addr) { sprintf((char*)&bufferToHoldCharsOfIpAddress, "%3u.%3u.%3u.%3u", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF) ); bufferToHoldCharsOfIpAddress[16] = '\0'; /* force null termination */ return bufferToHoldCharsOfIpAddress; } ajtcl-16.04/test/sessions.c000066400000000000000000000600731271074662300156300ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SESSIONS /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE SESSIONS #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ uint8_t dbgSESSIONS = 0; #define CONNECT_TIMEOUT (1000ul * 60) #define CONNECT_PAUSE (1000ul * 10) #define UNMARSHAL_TIMEOUT (1000ul * 5) #define METHOD_TIMEOUT (1000ul * 3) /// globals uint8_t connected = FALSE; uint32_t g_sessionId = 0ul; AJ_Status authStatus = AJ_ERR_NULL; uint32_t sendTTL = 0; static const char InterfaceName[] = "org.alljoyn.bus.test.sessions"; static const char ServiceName[] = "org.alljoyn.bus.test.sessions"; static const uint16_t ServicePort = 25; static uint32_t authenticate = TRUE; static const char* const testInterface[] = { InterfaceName, "!Chat >s", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { testInterface, NULL }; /** * Objects implemented by the application */ static const AJ_Object AppObjects[] = { { "/sessions", testInterfaces }, { NULL } }; #define APP_CHAT_SIGNAL AJ_APP_MESSAGE_ID(0, 0, 0) /* * Let the application do some work */ void AppDoWork() { AJ_InfoPrintf(("AppDoWork\n")); } static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "1234"; #endif /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; default: break; } return status; } void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } AJ_Status AppSendChatSignal(AJ_BusAttachment* bus, uint32_t sessionId, const char* chatString, uint8_t flags, uint32_t ttl) { AJ_Status status = AJ_OK; AJ_Message msg; status = AJ_MarshalSignal(bus, &msg, APP_CHAT_SIGNAL, NULL, sessionId, flags, ttl); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", chatString); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_AlwaysPrintf(("TX chat: %s\n", chatString)); return status; } AJ_Status AppHandleChatSignal(AJ_Message* msg) { AJ_Status status = AJ_OK; char* chatString; AJ_UnmarshalArgs(msg, "s", &chatString); AJ_AlwaysPrintf(("RX chat from %s[%u]: %s\n", msg->sender, msg->sessionId, chatString)); return status; } void Do_Connect(AJ_BusAttachment* bus) { while (!connected) { AJ_Status status; AJ_AlwaysPrintf(("Attempting to connect to bus\n")); status = AJ_FindBusAndConnect(bus, NULL, CONNECT_TIMEOUT); if (status != AJ_OK) { AJ_AlwaysPrintf(("Failed to connect to bus sleeping for %lu seconds\n", CONNECT_PAUSE / 1000)); AJ_Sleep(CONNECT_PAUSE); continue; } connected = TRUE; AJ_AlwaysPrintf(("AllJoyn service connected to bus\n")); AJ_AlwaysPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(bus))); } } int AJ_Main() { AJ_Status status; AJ_BusAttachment bus; AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); Do_Connect(&bus); if (authenticate) { AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); } else { authStatus = AJ_OK; } AJ_StartReadFromStdIn(); while (TRUE) { // check for serial input and dispatch if needed. char buf[1024]; AJ_Message msg; // read a line if (AJ_GetCmdLine(buf, 1024) != NULL && strlen(buf) > 0) { char*command; AJ_AlwaysPrintf((">~~~%s\n", buf)); command = strtok(buf, " \r\n"); if (!command) { continue; } if (0 == strcmp("startservice", command)) { uint16_t port = 0; const char* name; AJ_SessionOpts opts; char* token = strtok(NULL, " \r\n"); if (token) { name = token; } else { name = ServiceName; } token = strtok(NULL, " \r\n"); if (token) { port = (uint16_t)atoi(token); } if (port == 0) { port = ServicePort; } token = strtok(NULL, " \r\n"); if (token) { opts.isMultipoint = (0 == strcmp("true", token)); } else { opts.isMultipoint = 0; } token = strtok(NULL, " \r\n"); if (token) { opts.traffic = atoi(token); } else { opts.traffic = 0x1; } token = strtok(NULL, " \r\n"); if (token) { opts.proximity = atoi(token); } else { opts.proximity = 0xFF; } token = strtok(NULL, " \r\n"); if (token) { opts.transports = atoi(token); } else { opts.transports = 0xFFFF; } status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, TRUE, port, name, AJ_NAME_REQ_DO_NOT_QUEUE, &opts); AJ_BusAddSignalRule(&bus, "Chat", InterfaceName, AJ_BUS_SIGNAL_ALLOW); } else if (0 == strcmp("find", command)) { char* namePrefix = strtok(NULL, " \r\n"); if (!namePrefix) { AJ_AlwaysPrintf(("Usage: find \n")); continue; } status = AJ_BusFindAdvertisedName(&bus, namePrefix, AJ_BUS_START_FINDING); } else if (0 == strcmp("cancelfind", command)) { char* namePrefix = strtok(NULL, " \r\n"); if (!namePrefix) { AJ_AlwaysPrintf(("Usage: cancelfind \n")); continue; } status = AJ_BusFindAdvertisedName(&bus, namePrefix, AJ_BUS_STOP_FINDING); } else if (0 == strcmp("find2", command)) { char* namePrefix = strtok(NULL, " \r\n"); uint16_t transport = 0; char* token = strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } if (!namePrefix || !transport) { AJ_AlwaysPrintf(("Usage: find2 \n")); continue; } status = AJ_BusFindAdvertisedNameByTransport(&bus, namePrefix, transport, AJ_BUS_START_FINDING); } else if (0 == strcmp("cancelfind2", command)) { char* namePrefix = strtok(NULL, " \r\n"); uint16_t transport = 0; char* token = strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } if (!namePrefix || !transport) { AJ_AlwaysPrintf(("Usage: cancelfind2 \n")); continue; } status = AJ_BusFindAdvertisedNameByTransport(&bus, namePrefix, transport, AJ_BUS_STOP_FINDING); } else if (0 == strcmp("requestname", command)) { char* name = strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: requestname \n")); continue; } status = AJ_BusRequestName(&bus, name, AJ_NAME_REQ_DO_NOT_QUEUE); } else if (0 == strcmp("releasename", command)) { char* name = strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: releasename \n")); continue; } status = AJ_BusReleaseName(&bus, name); } else if (0 == strcmp("advertise", command)) { uint16_t transport = 0xFFFF; char* token = NULL; char* name = strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: advertise [transports]\n")); continue; } token = strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } status = AJ_BusAdvertiseName(&bus, name, transport, AJ_BUS_START_ADVERTISING, 0); } else if (0 == strcmp("canceladvertise", command)) { uint16_t transport = 0xFFFF; char* token = NULL; char* name = strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: canceladvertise [transports]\n")); continue; } token = strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } status = AJ_BusAdvertiseName(&bus, name, transport, AJ_BUS_STOP_ADVERTISING, 0); } else if (0 == strcmp("bind", command)) { AJ_SessionOpts opts; uint16_t port = 0; char* token = strtok(NULL, " \r\n"); if (token) { port = (uint16_t)atoi(token); } if (port == 0) { AJ_AlwaysPrintf(("Usage: bind [isMultipoint] [traffic] [proximity] [transports]\n")); continue; } token = strtok(NULL, " \r\n"); if (token) { opts.isMultipoint = (0 == strcmp("true", token)); } else { opts.isMultipoint = 0; } token = strtok(NULL, " \r\n"); if (token) { opts.traffic = atoi(token); } else { opts.traffic = 0x1; } token = strtok(NULL, " \r\n"); if (token) { opts.proximity = atoi(token); } else { opts.proximity = 0xFF; } token = strtok(NULL, " \r\n"); if (token) { opts.transports = atoi(token); } else { opts.transports = 0xFFFF; } status = AJ_BusBindSessionPort(&bus, port, &opts, 0); } else if (0 == strcmp("unbind", command)) { uint16_t port = 0; char* token = strtok(NULL, " \r\n"); if (token) { port = (uint16_t) atoi(token); } if (port == 0) { AJ_AlwaysPrintf(("Usage: unbind \n")); continue; } status = AJ_BusUnbindSession(&bus, port); } else if (0 == strcmp("join", command)) { AJ_SessionOpts opts; uint16_t port = 0; char* name = strtok(NULL, " \r\n"); char* token = strtok(NULL, " \r\n"); if (token) { port = (uint16_t)atoi(token); } else { port = 0; } if (!name || (port == 0)) { AJ_AlwaysPrintf(("Usage: join [isMultipoint] [traffic] [proximity] [transports]\n")); continue; } token = strtok(NULL, " \r\n"); if (token) { opts.isMultipoint = (0 == strcmp("true", token)); } else { opts.isMultipoint = 0; } token = strtok(NULL, " \r\n"); if (token) { opts.traffic = (uint8_t)atoi(token); } else { opts.traffic = 0x1; } token = strtok(NULL, " \r\n"); if (token) { opts.proximity = (uint8_t)atoi(token); } else { opts.proximity = 0xFF; } token = strtok(NULL, " \r\n"); if (token) { opts.transports = (uint16_t)atoi(token); } else { opts.transports = 0xFFFF; } status = AJ_BusJoinSession(&bus, name, port, &opts); } else if (0 == strcmp("leave", command)) { char* sessionIdStr = strtok(NULL, "\r\n"); uint32_t sessionId = 0; if (sessionIdStr) { sessionId = (uint32_t)atoi(sessionIdStr); } if (sessionId == 0) { AJ_AlwaysPrintf(("Usage: leave \n")); continue; } status = AJ_BusLeaveSession(&bus, sessionId); } else if (0 == strcmp("addmatch", command)) { char* ruleString = strtok(NULL, "\r\n"); if (!ruleString) { AJ_AlwaysPrintf(("Usage: addmatch \n")); continue; } status = AJ_BusSetSignalRule(&bus, ruleString, AJ_BUS_SIGNAL_ALLOW); } else if (0 == strcmp("removematch", command)) { char* ruleString = strtok(NULL, "\r\n"); if (!ruleString) { AJ_AlwaysPrintf(("Usage: removematch \n")); continue; } status = AJ_BusSetSignalRule(&bus, ruleString, AJ_BUS_SIGNAL_DENY); } else if (0 == strcmp("sendttl", command)) { int32_t ttl = 0; char* token = strtok(NULL, " \r\n"); if (token) { ttl = atoi(token); } if (ttl < 0) { AJ_AlwaysPrintf(("Usage: sendttl \n")); continue; } sendTTL = ttl; } else if (0 == strcmp("schat", command)) { char* chatMsg = strtok(NULL, "\r\n"); if (!chatMsg) { AJ_AlwaysPrintf(("Usage: schat \n")); continue; } status = AppSendChatSignal(&bus, 0, chatMsg, AJ_FLAG_SESSIONLESS, sendTTL); } else if (0 == strcmp("chat", command)) { char* sessionIdString = strtok(NULL, " \r\n"); char*chatMsg; uint32_t session = g_sessionId; if (sessionIdString != NULL) { if (sessionIdString[0] != '#') { session = atol(sessionIdString); } } chatMsg = strtok(NULL, "\r\n"); if (chatMsg) { status = AppSendChatSignal(&bus, session, chatMsg, 0, sendTTL); } } else if (0 == strcmp("cancelsessionless", command)) { uint32_t serialId = 0; char* token = strtok(NULL, " \r\n"); if (token) { serialId = (uint32_t)atoi(token); } if (serialId == 0) { AJ_AlwaysPrintf(("Invalid serial number\n")); AJ_AlwaysPrintf(("Usage: cancelsessionless \n")); continue; } status = AJ_BusCancelSessionless(&bus, serialId); } else if (0 == strcmp("exit", command)) { break; } else if (0 == strcmp("help", command)) { //AJ_AlwaysPrintf(("debug - Set debug level for a module\n")); AJ_AlwaysPrintf(("startservice [name] [port] [isMultipoint] [traffic] [proximity] [transports] - Startservice\n")); AJ_AlwaysPrintf(("requestname - Request a well-known name\n")); AJ_AlwaysPrintf(("releasename - Release a well-known name\n")); AJ_AlwaysPrintf(("bind [isMultipoint] [traffic] [proximity] [transports] - Bind a session port\n")); AJ_AlwaysPrintf(("unbind - Unbind a session port\n")); AJ_AlwaysPrintf(("advertise [transports] - Advertise a name\n")); AJ_AlwaysPrintf(("canceladvertise [transports] - Cancel an advertisement\n")); AJ_AlwaysPrintf(("find - Discover names that begin with prefix\n")); AJ_AlwaysPrintf(("find2 - Discover names that begin with prefix by specific transports\n")); AJ_AlwaysPrintf(("cancelfind - Cancel discovering names that begins with prefix\n")); AJ_AlwaysPrintf(("cancelfind2 - Cancel discovering names that begins with prefix by specific transports\n")); AJ_AlwaysPrintf(("join [isMultipoint] [traffic] [proximity] [transports] - Join a session\n")); AJ_AlwaysPrintf(("leave - Leave a session\n")); AJ_AlwaysPrintf(("chat - Send a message over a given session\n")); AJ_AlwaysPrintf(("schat - Send a sessionless message\n")); AJ_AlwaysPrintf(("cancelsessionless - Cancel a sessionless message\n")); AJ_AlwaysPrintf(("addmatch - Add a DBUS rule\n")); AJ_AlwaysPrintf(("removematch - Remove a DBUS rule\n")); AJ_AlwaysPrintf(("sendttl - Set default ttl (in ms) for all chat messages (0 = infinite)\n")); AJ_AlwaysPrintf(("exit - Exit this program\n")); AJ_AlwaysPrintf(("\n")); continue; } else { AJ_AlwaysPrintf(("Unknown command: %s\n", command)); continue; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(); continue; } } if (status == AJ_OK) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_AlwaysPrintf(("Accepting...\n")); AJ_UnmarshalArgs(&msg, "qus", &port, &g_sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); if (status == AJ_OK) { AJ_AlwaysPrintf(("Accepted session session_id=%u joiner=%s\n", g_sessionId, joiner)); } else { AJ_AlwaysPrintf(("AJ_BusReplyAcceptSession: error %d\n", status)); } } break; case AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION): { uint32_t replyCode; if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } else { status = AJ_UnmarshalArgs(&msg, "uu", &replyCode, &g_sessionId); if (replyCode == AJ_JOINSESSION_REPLY_SUCCESS) { AJ_AlwaysPrintf(("Joined session session_id=%u\n", g_sessionId)); status = AJ_BusAddSignalRule(&bus, "Chat", InterfaceName, AJ_BUS_SIGNAL_ALLOW); } else { AJ_AlwaysPrintf(("Joine session failed\n")); } } } break; case APP_CHAT_SIGNAL: status = AppHandleChatSignal(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * don't force a disconnect, be ready to accept another session */ break; case AJ_SIGNAL_FOUND_ADV_NAME: { char* name; char* namePrefix; uint16_t transport; AJ_UnmarshalArgs(&msg, "sqs", &name, &transport, &namePrefix); AJ_AlwaysPrintf(("FoundAdvertisedName name=%s, namePrefix=%s\n", name, namePrefix)); } break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_SESSION_LOST) || (status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_AlwaysPrintf(("AllJoyn disconnect\n")); AJ_AlwaysPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); connected = FALSE; /* * Sleep a little while before trying to reconnect */ AJ_Sleep(10 * 1000); Do_Connect(&bus); } } AJ_StopReadFromStdIn(); return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/sessionslite.c000066400000000000000000000657431271074662300165170ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SESSIONS_LITE #include #include #include uint8_t dbgSESSIONS_LITE = 0; #define CONNECT_TIMEOUT (1000ul * 60) #define CONNECT_PAUSE (1000ul * 10) #define UNMARSHAL_TIMEOUT (1000ul * 5) #define METHOD_TIMEOUT (1000ul * 3) /// globals uint8_t connected = FALSE; uint32_t g_sessionId = 0ul; AJ_Status authStatus = AJ_ERR_NULL; uint32_t sendTTL = 0; static const char InterfaceName[] = "org.alljoyn.bus.test.sessions"; static const char ServiceName[] = "org.alljoyn.bus.test.sessions"; static const uint16_t ServicePort = 25; static uint32_t authenticate = TRUE; /* * Command array: * Put the commands you would like to execute into this * array with the last element being NULL */ static const char* commands[] = { "wait 1000", "startservice org.alljoyn.samples 27", "advertise org.alljoyn.samples 27", "wait 1000", "wait 1000", NULL }; static const char* const testInterface[] = { InterfaceName, "!Chat >s", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { testInterface, NULL }; /** * Objects implemented by the application */ static const AJ_Object AppObjects[] = { { "/sessions", testInterfaces }, { NULL } }; #define APP_CHAT_SIGNAL AJ_APP_MESSAGE_ID(0, 0, 0) /* * Let the application do some work */ void AppDoWork() { //AJ_AlwaysPrintf(("AppDoWork\n")); } static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "1234"; #endif /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; default: break; } return status; } void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } AJ_Status AppSendChatSignal(AJ_BusAttachment* bus, uint32_t sessionId, const char* chatString, uint8_t flags, uint32_t ttl) { AJ_Status status = AJ_OK; AJ_Message msg; status = AJ_MarshalSignal(bus, &msg, APP_CHAT_SIGNAL, NULL, sessionId, flags, ttl); if (status == AJ_OK) { status = AJ_MarshalArgs(&msg, "s", chatString); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } AJ_AlwaysPrintf(("TX chat: %s\n", chatString)); return status; } AJ_Status AppHandleChatSignal(AJ_Message* msg) { AJ_Status status = AJ_OK; char* chatString; AJ_UnmarshalArgs(msg, "s", &chatString); AJ_AlwaysPrintf(("RX chat from %s[%u]: %s\n", msg->sender, msg->sessionId, chatString)); return status; } void Do_Connect(AJ_BusAttachment* bus) { while (!connected) { AJ_Status status; AJ_InfoPrintf(("Attempting to connect to bus\n")); status = AJ_FindBusAndConnect(bus, NULL, CONNECT_TIMEOUT); if (status != AJ_OK) { AJ_InfoPrintf(("Failed to connect to bus sleeping for %lu seconds\n", CONNECT_PAUSE / 1000)); AJ_Sleep(CONNECT_PAUSE); continue; } connected = TRUE; AJ_BusAddSignalRule(bus, "Chat", InterfaceName, AJ_BUS_SIGNAL_ALLOW); AJ_InfoPrintf(("AllJoyn service connected to bus\n")); AJ_InfoPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(bus))); } } /* * Returns the partial length of str that does not contain any * characters in not */ int notInStr(char*str, const char*not) { int size = 0; int idx1 = 0; if (str == NULL) { return size; } while (str[idx1] != '\0') { int idx2 = 0; while (not[idx2] != '\0') { if (str[idx1] == not[idx2]) { return size; } idx2++; } idx1++; size++; } return size; } /* * Returns the partial length of str that only contains characters from 'in' */ int inStr(char*str, const char*in) { int size = 0; int idx1 = 0; int flag = 0; if (str == NULL) { return size; } while (str[idx1] != '\0') { int idx2 = 0; while (in[idx2] != '\0') { if (str[idx1] == in[idx2]) { flag = 1; } else { idx2++; } } if (flag == 1) { size++; idx1++; flag = 0; } else { return size; } } return size; } /* * Tokenize a string into parts separated by 'delim' */ char*aj_strtok(char*str, const char*delim) { static char*nextLocation = 0; int currentTokenLength; int nextTokenLength; /* NULL given so set location to the string */ if (str == NULL) { str = nextLocation; } if (str != NULL) { nextLocation = str; /* Location is NULL, return 0 */ } else if (!nextLocation) { return 0; } /* * Get the length of the next token and * the length of string where there is not a token * and move the location and str pointers to those * two locations. */ currentTokenLength = inStr(nextLocation, delim); nextTokenLength = notInStr(str, delim); /* Get current token */ str = nextLocation + currentTokenLength; /* Update for the next token */ nextLocation = str + nextTokenLength; /* location and str are the same so there was no token */ if (nextLocation == str) { //nextLocation = 0; return nextLocation = 0; } /* if next location is valid: * set the start to zero (end of str) * and increment (to get rid of space) */ if (*nextLocation) { *nextLocation = 0; nextLocation++; } else { nextLocation = 0; } return str; } int AJ_Main() { AJ_Status status; AJ_BusAttachment bus; int i; AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); Do_Connect(&bus); if (authenticate) { AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); } else { authStatus = AJ_OK; } i = 0; while (commands[i] != NULL) { AJ_AlwaysPrintf(("%s\n", commands[i])); i++; } i = 0; while (TRUE) { // check for serial input and dispatch if needed. char buf[1024]; AJ_Message msg; // read a line if (commands[i] != NULL) { char*command; strcpy(buf, commands[i]); AJ_AlwaysPrintf((">~~~%s\n", buf)); command = aj_strtok(buf, " \r\n"); i++; if (0 == strcmp("startservice", command)) { uint16_t port = 0; const char* name; AJ_SessionOpts opts; char* token = aj_strtok(NULL, " \r\n"); if (token) { name = token; } else { name = ServiceName; } token = aj_strtok(NULL, " \r\n"); if (token) { port = (uint16_t)atoi(token); } if (port == 0) { port = ServicePort; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.isMultipoint = (0 == strcmp("true", token)); } else { opts.isMultipoint = 0; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.traffic = atoi(token); } else { opts.traffic = 0x1; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.proximity = atoi(token); } else { opts.proximity = 0xFF; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.transports = atoi(token); } else { opts.transports = 0xFFFF; } status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, TRUE, port, name, AJ_NAME_REQ_DO_NOT_QUEUE, &opts); AJ_BusAddSignalRule(&bus, "Chat", InterfaceName, AJ_BUS_SIGNAL_ALLOW); } else if (0 == strcmp("find", command)) { char* namePrefix = aj_strtok(NULL, " \r\n"); if (!namePrefix) { AJ_AlwaysPrintf(("Usage: find \n")); continue; } status = AJ_BusFindAdvertisedName(&bus, namePrefix, AJ_BUS_START_FINDING); } else if (0 == strcmp("cancelfind", command)) { char* namePrefix = aj_strtok(NULL, " \r\n"); if (!namePrefix) { AJ_AlwaysPrintf(("Usage: cancelfind \n")); continue; } status = AJ_BusFindAdvertisedName(&bus, namePrefix, AJ_BUS_STOP_FINDING); } else if (0 == strcmp("find2", command)) { char* namePrefix = aj_strtok(NULL, " \r\n"); uint16_t transport = 0; char* token = aj_strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } if (!namePrefix || !transport) { AJ_AlwaysPrintf(("Usage: find2 \n")); continue; } status = AJ_BusFindAdvertisedNameByTransport(&bus, namePrefix, transport, AJ_BUS_START_FINDING); } else if (0 == strcmp("cancelfind2", command)) { char* namePrefix = aj_strtok(NULL, " \r\n"); uint16_t transport = 0; char* token = aj_strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } if (!namePrefix || !transport) { AJ_AlwaysPrintf(("Usage: cancelfind2 \n")); continue; } status = AJ_BusFindAdvertisedNameByTransport(&bus, namePrefix, transport, AJ_BUS_STOP_FINDING); } else if (0 == strcmp("requestname", command)) { char* name = aj_strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: requestname \n")); continue; } status = AJ_BusRequestName(&bus, name, AJ_NAME_REQ_DO_NOT_QUEUE); } else if (0 == strcmp("releasename", command)) { char* name = aj_strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: releasename \n")); continue; } status = AJ_BusReleaseName(&bus, name); } else if (0 == strcmp("advertise", command)) { uint16_t transport = 0xFFFF; char* token = NULL; char* name = aj_strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: advertise [transports]\n")); continue; } token = aj_strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } status = AJ_BusAdvertiseName(&bus, name, transport, AJ_BUS_START_ADVERTISING, 0); } else if (0 == strcmp("canceladvertise", command)) { uint16_t transport = 0xFFFF; char* token = NULL; char* name = aj_strtok(NULL, " \r\n"); if (!name) { AJ_AlwaysPrintf(("Usage: canceladvertise [transports]\n")); continue; } token = aj_strtok(NULL, " \r\n"); if (token) { transport = (uint16_t)atoi(token); } status = AJ_BusAdvertiseName(&bus, name, transport, AJ_BUS_STOP_ADVERTISING, 0); } else if (0 == strcmp("bind", command)) { AJ_SessionOpts opts; uint16_t port = 0; char* token = aj_strtok(NULL, " \r\n"); if (token) { port = (uint16_t)atoi(token); } if (port == 0) { AJ_AlwaysPrintf(("Usage: bind [isMultipoint] [traffic] [proximity] [transports]\n")); continue; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.isMultipoint = (0 == strcmp("true", token)); } else { opts.isMultipoint = 0; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.traffic = atoi(token); } else { opts.traffic = 0x1; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.proximity = atoi(token); } else { opts.proximity = 0xFF; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.transports = atoi(token); } else { opts.transports = 0xFFFF; } status = AJ_BusBindSessionPort(&bus, port, &opts, 0); } else if (0 == strcmp("unbind", command)) { uint16_t port = 0; char* token = aj_strtok(NULL, " \r\n"); if (token) { port = (uint16_t) atoi(token); } if (port == 0) { AJ_AlwaysPrintf(("Usage: unbind \n")); continue; } status = AJ_BusUnbindSession(&bus, port); } else if (0 == strcmp("join", command)) { AJ_SessionOpts opts; uint16_t port = 0; char* name = aj_strtok(NULL, " \r\n"); char* token = aj_strtok(NULL, " \r\n"); if (token) { port = (uint16_t)atoi(token); } else { port = 0; } if (!name || (port == 0)) { AJ_AlwaysPrintf(("Usage: join [isMultipoint] [traffic] [proximity] [transports]\n")); continue; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.isMultipoint = (0 == strcmp("true", token)); } else { opts.isMultipoint = 0; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.traffic = (uint8_t)atoi(token); } else { opts.traffic = 0x1; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.proximity = (uint8_t)atoi(token); } else { opts.proximity = 0xFF; } token = aj_strtok(NULL, " \r\n"); if (token) { opts.transports = (uint16_t)atoi(token); } else { opts.transports = 0xFFFF; } status = AJ_BusJoinSession(&bus, name, port, &opts); } else if (0 == strcmp("leave", command)) { uint32_t sessionId = (uint32_t)atoi(aj_strtok(NULL, "\r\n")); if (sessionId == 0) { AJ_AlwaysPrintf(("Usage: leave \n")); continue; } status = AJ_BusLeaveSession(&bus, sessionId); } else if (0 == strcmp("addmatch", command)) { char* ruleString = aj_strtok(NULL, "\r\n"); if (!ruleString) { AJ_AlwaysPrintf(("Usage: addmatch \n")); continue; } status = AJ_BusSetSignalRule(&bus, ruleString, AJ_BUS_SIGNAL_ALLOW); } else if (0 == strcmp("removematch", command)) { char* ruleString = aj_strtok(NULL, "\r\n"); if (!ruleString) { AJ_AlwaysPrintf(("Usage: removematch \n")); continue; } status = AJ_BusSetSignalRule(&bus, ruleString, AJ_BUS_SIGNAL_DENY); } else if (0 == strcmp("sendttl", command)) { int32_t ttl = 0; char* token = aj_strtok(NULL, " \r\n"); if (token) { ttl = atoi(token); } if (ttl < 0) { AJ_AlwaysPrintf(("Usage: sendttl \n")); continue; } sendTTL = ttl; } else if (0 == strcmp("schat", command)) { char* chatMsg = aj_strtok(NULL, "\r\n"); if (!chatMsg) { AJ_AlwaysPrintf(("Usage: schat \n")); continue; } status = AppSendChatSignal(&bus, 0, chatMsg, AJ_FLAG_SESSIONLESS, sendTTL); } else if (0 == strcmp("chat", command)) { char* sessionIdString = aj_strtok(NULL, " \r\n"); char*chatMsg; uint32_t session = g_sessionId; if (sessionIdString != NULL) { if (sessionIdString[0] != '#') { session = (long)atoi(sessionIdString); } } chatMsg = aj_strtok(NULL, "\r\n"); status = AppSendChatSignal(&bus, session, chatMsg, 0, sendTTL); } else if (0 == strcmp("cancelsessionless", command)) { uint32_t serialId = 0; char* token = aj_strtok(NULL, " \r\n"); if (token) { serialId = (uint32_t)atoi(token); } if (serialId == 0) { AJ_AlwaysPrintf(("Invalid serial number\n")); AJ_AlwaysPrintf(("Usage: cancelsessionless \n")); continue; } status = AJ_BusCancelSessionless(&bus, serialId); } else if (0 == strcmp("exit", command)) { break; } else if (0 == strcmp("help", command)) { //AJ_AlwaysPrintf(("debug - Set debug level for a module\n")); AJ_AlwaysPrintf(("startservice [name] [port] [isMultipoint] [traffic] [proximity] [transports] - Startservice\n")); AJ_AlwaysPrintf(("requestname - Request a well-known name\n")); AJ_AlwaysPrintf(("releasename - Release a well-known name\n")); AJ_AlwaysPrintf(("bind [isMultipoint] [traffic] [proximity] [transports] - Bind a session port\n")); AJ_AlwaysPrintf(("unbind - Unbind a session port\n")); AJ_AlwaysPrintf(("advertise [transports] - Advertise a name\n")); AJ_AlwaysPrintf(("canceladvertise [transports] - Cancel an advertisement\n")); AJ_AlwaysPrintf(("find - Discover names that begin with prefix\n")); AJ_AlwaysPrintf(("find2 - Discover names that begin with prefix by specific transports\n")); AJ_AlwaysPrintf(("cancelfind - Cancel discovering names that begins with prefix\n")); AJ_AlwaysPrintf(("cancelfind2 - Cancel discovering names that begins with prefix by specific transports\n")); AJ_AlwaysPrintf(("join [isMultipoint] [traffic] [proximity] [transports] - Join a session\n")); AJ_AlwaysPrintf(("leave - Leave a session\n")); AJ_AlwaysPrintf(("chat - Send a message over a given session\n")); AJ_AlwaysPrintf(("schat - Send a sessionless message\n")); AJ_AlwaysPrintf(("cancelsessionless - Cancel a sessionless message\n")); AJ_AlwaysPrintf(("addmatch - Add a DBUS rule\n")); AJ_AlwaysPrintf(("removematch - Remove a DBUS rule\n")); AJ_AlwaysPrintf(("sendttl - Set default ttl (in ms) for all chat messages (0 = infinite)\n")); AJ_AlwaysPrintf(("exit - Exit this program\n")); AJ_AlwaysPrintf(("\n")); continue; } else if (0 == strcmp("wait", command)) { char* token = aj_strtok(NULL, " \n\r"); if (token) { AJ_AlwaysPrintf(("Sleeping...\n")); AJ_Sleep((uint16_t)atoi(token)); AJ_AlwaysPrintf(("Done\n")); } } else { AJ_AlwaysPrintf(("Unknown command: %s\n", command)); continue; } } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(); continue; } } if (status == AJ_OK) { switch (msg.msgId) { case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_AlwaysPrintf(("Accepting...\n")); AJ_UnmarshalArgs(&msg, "qus", &port, &g_sessionId, &joiner); status = AJ_BusReplyAcceptSession(&msg, TRUE); if (status == AJ_OK) { AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", g_sessionId, joiner)); } else { AJ_InfoPrintf(("AJ_BusReplyAcceptSession: error %d\n", status)); } } break; case AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION): { uint32_t replyCode; if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } else { status = AJ_UnmarshalArgs(&msg, "uu", &replyCode, &g_sessionId); if (replyCode == AJ_JOINSESSION_REPLY_SUCCESS) { AJ_InfoPrintf(("Joined session session_id=%u\n", g_sessionId)); AJ_BusAddSignalRule(&bus, "Chat", InterfaceName, AJ_BUS_SIGNAL_ALLOW); } else { AJ_InfoPrintf(("Joined session failed\n")); } } } break; case APP_CHAT_SIGNAL: status = AppHandleChatSignal(&msg); break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * don't force a disconnect, be ready to accept another session */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_InfoPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } break; case AJ_SIGNAL_FOUND_ADV_NAME: { char* name; char* namePrefix; uint16_t transport; AJ_UnmarshalArgs(&msg, "sqs", &name, &transport, &namePrefix); AJ_AlwaysPrintf(("FoundAdvertisedName name=%s, namePrefix=%s\n", name, namePrefix)); } break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_AlwaysPrintf(("AllJoyn disconnect\n")); AJ_AlwaysPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); connected = FALSE; /* * Sleep a little while before trying to reconnect */ AJ_Sleep(10 * 1000); Do_Connect(&bus); } } return 0; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/shatest.c000066400000000000000000000163641271074662300154410ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include int AJ_Main(void); typedef struct { const char* msg; /* input message - ascii */ const char* dig; /* output digest - hex string */ } TEST_SHA; static TEST_SHA sha256test[] = { { "abc", "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD" }, { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1" }, }; typedef struct { const char* key; /* input key (for hmac) - hex string */ const char* seed; /* input message - ascii */ const char* expected; /* output digest - hex string */ } TEST_PRF; static TEST_PRF prftest[] = { { /* Shortest allowable key is 24 bytes */ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "Hi There", "0AB50319EFE5E73DF3327DCE552DBF1C4EF6EC0C4192230057B5194E6C277609" "A453979FD1D25F922DF3A2D296599CECB3ED0FED975C8CBBD9E791B354C744C1" "B09C5C7F586071CFB5EA25F20450E330DB2FB305FF812DFD8FC987F8EFACE01D" "65DB64DF21DD6C194D3BAFE6AECBE791A8263B1E59E877B96EB7C4961DB3DC6A" "058CE104B96D321783728BBE8EB9DB49EC20098A0BB1CF12E6D4D60B26776576" "EA0FFA170040EA1CA79E25701D976A5C3F43EF28AB6606F2E807EB4BF193604C" "BF450C7CDCEE536D" }, { "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665", "what do ya want for nothing?", "62C00DD5EB0752876B03B235BCDA99F3D3922650606760A89CDCDDC7BBF7A2B1" "9321586328DFECCAFD43919EA5FA44967DFAE9B69D90AF00CC417C647CACB5CD" "5D6FB8288781C2176FC32F85B663ACC30EF0C425FC8A19746093D0CAEC2289C7" "288652EF213FD670FC629424D38FEF486287DC505C47E38890E0565F9437DAA3" "129136E24A745F4DA00B40107E0FE9F94C754D02A081D29C72441CC229EEDC13" "A0D297CA86F2C479E485575D5264AE15212A24FC93C278E6AB10B45BED28F3D2" "67A2A18D5735F40E" }, { /* Longest allowable key is 128 bytes */ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "Test Using Larger Than Block-Size Key - Hash Key First", "707F5855E679CF2B8647D83E1F5B5C50CC7841C47F84F962F69250480C50FEC0" "69D2F8D92D35ECAE7F893F7A959FF837104750C6C8887873D8D5800DFE134426" "AEE5DD6A109AD8B74038AA134C712E8C9B573BDF01AA572A4AA44A5F412087EF" "B756770F9F136092F04B7380FBB30F6442088CFB9A9727471A26DA441F90A894" "7EA7E12C02485B57B5A1BA5C63046387CA2A41FB2C7103FCF2863A1271B4CE81" "FFB4007CC3203DDB465F0664562974094BDD288A013B372F2388070B446D8465" "45AD2309776A7B65" }, { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "This is a test using a larger than block-size key and a larger t" "han block-size data. The key needs to be hashed before being use" "d by the HMAC algorithm.", "956BBE25A75C5A30F88FA7A7CECEDC04124C1FFE3AE172758D73757A4A442708" "DCEBC685BCDD6F28DF7422F3F99D2087F477E954FC8CADF54476522CE439700A" "267E7AAC6615D90F0DACFB5FAAD582C6BFD4A326BAFD75C40DB615274EB40710" "08656461BAC11FEFDBC4B4E1BBFAF62D9423ADD1E66196C7DDF9430BAA56D5A0" "5A6ECD43922F8B982F98C3A41CA46C7122F4AD34F34EA42F471D453F61FEF6F6" "B47B1E06F8A5C8B7573C4D1A370EF540B3BC82D3056F5E308945E7F7019AABCE" "E9BBA1A576D5C2F1" }, }; int AJ_Main(void) { uint32_t i; AJ_Status status; AJ_AlwaysPrintf(("SHA256 unit test START\n")); for (i = 0; i < ArraySize(sha256test); i++) { AJ_SHA256_Context* ctx; const uint8_t* msg; const char* expected; uint32_t mlen; uint8_t digBuf[AJ_SHA256_DIGEST_LENGTH]; char digStr[AJ_SHA256_DIGEST_LENGTH * 2 + 1]; memset(&ctx, 0, sizeof(ctx)); msg = (const uint8_t*) sha256test[i].msg; expected = sha256test[i].dig; mlen = (uint32_t)strlen((char*)msg); ctx = AJ_SHA256_Init(); AJ_SHA256_Update(ctx, msg, mlen); status = AJ_SHA256_Final(ctx, digBuf); if (AJ_OK != status) { AJ_AlwaysPrintf(("SHA final failure for test #%u\n", i)); goto ErrorExit; } AJ_RawToHex(digBuf, AJ_SHA256_DIGEST_LENGTH, digStr, AJ_SHA256_DIGEST_LENGTH * 2 + 1, 0); if (strcmp(expected, digStr) != 0) { AJ_AlwaysPrintf(("SHA verification failure for test #%u\nexpected: %s\nactual: %s\n", i, expected, digStr)); goto ErrorExit; } AJ_AlwaysPrintf(("Passed and verified SHA test #%u\n", i)); } AJ_AlwaysPrintf(("SHA256 unit test PASSED\n")); AJ_AlwaysPrintf(("PRF unit test START\n")); for (i = 0; i < ArraySize(prftest); i++) { const char* expected; uint8_t key[128]; uint8_t randBuf[200]; char randStr[200 * 2 + 1]; const uint8_t* inputs[4]; uint8_t lengths[4]; expected = prftest[i].expected; AJ_HexToRaw(prftest[i].key, 0, key, sizeof(key)); inputs[0] = key; inputs[1] = inputs[2] = inputs[3] = (uint8_t*)prftest[i].seed; lengths[0] = strlen((char*)prftest[i].key) / 2; lengths[1] = lengths[2] = lengths[3] = (uint8_t)strlen((char*)inputs[1]); AJ_Crypto_PRF_SHA256(inputs, lengths, 4, randBuf, sizeof(randBuf)); AJ_RawToHex(randBuf, sizeof(randBuf), randStr, sizeof(randStr), 0); if (strcmp(expected, randStr) != 0) { AJ_AlwaysPrintf(("PRF verification failure for test #%u\nexpected: %s\nactual: %s\n", i, expected, randStr)); goto ErrorExit; } AJ_AlwaysPrintf(("Passed and verified PRF test #%u\n", i)); } AJ_AlwaysPrintf(("PRF unit test PASSED\n")); return 0; ErrorExit: AJ_AlwaysPrintf(("Crypto unit test FAILED\n")); return 1; } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/siglite.c000066400000000000000000000334551271074662300154260ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #define AJ_MODULE SIGLITE #ifndef TEST_DISABLE_SECURITY #define SECURE_INTERFACE #endif #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ uint8_t dbgSIGLITE = 0; #ifdef SECURE_INTERFACE static const char testInterfaceName[] = "$org.alljoyn.alljoyn_test"; static const char testValuesInterfaceName[] = "$org.alljoyn.alljoyn_test.values"; #else static const char testInterfaceName[] = "org.alljoyn.alljoyn_test"; static const char testValuesInterfaceName[] = "org.alljoyn.alljoyn_test.values"; #endif #if defined (NGNS) || defined (ANNOUNCE_BASED_DISCOVERY) static const char* testInterfaceNames[] = { testInterfaceName, NULL }; #else static const char testServiceName[] = "org.alljoyn.svclite"; static const uint16_t testServicePort = 24; #endif static const uint32_t NumPings = 10; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; /* * The app should authenticate the peer if one or more interfaces are secure * To define a secure interface, prepend '$' before the interface name, eg., "$org.alljoyn.alljoyn_test" */ static const char* const testInterface[] = { testInterfaceName, "?my_ping inStrs", "?delayed_ping inStrs", "?time_ping u >q", "!my_signal >a{ys}", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { testInterface, NULL }; /** * Objects implemented by the application */ static const AJ_Object ProxyObjects[] = { { "/org/alljoyn/alljoyn_test", testInterfaces }, { NULL } }; #define PRX_MY_PING AJ_PRX_MESSAGE_ID(0, 0, 0) #define PRX_DELAYED_PING AJ_PRX_MESSAGE_ID(0, 0, 1) #define PRX_TIME_PING AJ_PRX_MESSAGE_ID(0, 0, 2) #define PRX_MY_SIGNAL AJ_PRX_MESSAGE_ID(0, 0, 3) static AJ_Status SendSignal(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName); /* * Let the application do some work */ #define PINGS_PER_CALL 10 static AJ_Status AppDoWork(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName) { static uint32_t pings_sent = 0; uint32_t pings = 0; AJ_Status status = AJ_OK; while (pings_sent < NumPings && pings++ < PINGS_PER_CALL && status == AJ_OK) { status = SendSignal(bus, sessionId, serviceName); ++pings_sent; } return status; } #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "123456"; #endif // Copied from alljoyn/alljoyn_core/unit_test/AuthListenerECDHETest.cc with // newlines removed static const char pem_prv[] = { "-----BEGIN EC PRIVATE KEY-----" "MHcCAQEEIBiLw29bf669g7MxMbXK2u8Lp5//w7o4OiVGidJdKAezoAoGCCqGSM49" "AwEHoUQDQgAE+A0C9YTghZ1vG7198SrUHxFlhtbSsmhbwZ3N5aQRwzFXWcCCm38k" "OzJEmS+venmF1o/FV0W80Mcok9CWlV2T6A==" "-----END EC PRIVATE KEY-----" }; static const char pem_x509[] = { "-----BEGIN CERTIFICATE-----" "MIIBYTCCAQigAwIBAgIJAOVrhhJOre/7MAoGCCqGSM49BAMCMCQxIjAgBgNVBAoM" "GUFsbEpveW5UZXN0U2VsZlNpZ25lZE5hbWUwHhcNMTUwODI0MjAxODQ1WhcNMjkw" "NTAyMjAxODQ1WjAgMR4wHAYDVQQKDBVBbGxKb3luVGVzdENsaWVudE5hbWUwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAAT4DQL1hOCFnW8bvX3xKtQfEWWG1tKyaFvB" "nc3lpBHDMVdZwIKbfyQ7MkSZL696eYXWj8VXRbzQxyiT0JaVXZPooycwJTAVBgNV" "HSUEDjAMBgorBgEEAYLefAEBMAwGA1UdEwEB/wQCMAAwCgYIKoZIzj0EAwIDRwAw" "RAIgevLUXoJBgUr6nVepBHQiv85CGuxu00V4uoARbH6qu1wCIA54iDRh6wit1zbP" "kqkBC015LjxucTf3Y7lNGhXuZRsL" "-----END CERTIFICATE-----" "-----BEGIN CERTIFICATE-----" "MIIBdTCCARugAwIBAgIJAJTFhmdwDWsvMAoGCCqGSM49BAMCMCQxIjAgBgNVBAoM" "GUFsbEpveW5UZXN0U2VsZlNpZ25lZE5hbWUwHhcNMTUwODI0MjAxODQ1WhcNMjkw" "NTAyMjAxODQ1WjAkMSIwIAYDVQQKDBlBbGxKb3luVGVzdFNlbGZTaWduZWROYW1l" "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEF0nZmkzuK/2CVf7udexLZnlEB5D+" "DBsx3POtsRyZWm2QiI1untDTp0uYp51tkP6wI6Gi5gWxB+86lEIPg4ZpTaM2MDQw" "IQYDVR0lBBowGAYKKwYBBAGC3nwBAQYKKwYBBAGC3nwBBTAPBgNVHRMBAf8EBTAD" "AQH/MAoGCCqGSM49BAMCA0gAMEUCIQDPQ1VRvdBhhneU5e7OvIFHK3d9XPZA7Fw6" "VyeW/P5wIAIgD969ks/z9vQ1yCaVaxmVz63toC1ggp4AnBXqbDy8O+4=" "-----END CERTIFICATE-----" }; static X509CertificateChain* chain = NULL; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; X509CertificateChain* node; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_ECDSA: switch (command) { case AJ_CRED_PRV_KEY: AJ_ASSERT(sizeof (AJ_ECCPrivateKey) == cred->len); status = AJ_DecodePrivateKeyPEM((AJ_ECCPrivateKey*) cred->data, pem_prv); cred->expiration = keyexpiration; break; case AJ_CRED_CERT_CHAIN: switch (cred->direction) { case AJ_CRED_REQUEST: // Free previous certificate chain AJ_X509FreeDecodedCertificateChain(chain); chain = AJ_X509DecodeCertificateChainPEM(pem_x509); if (NULL == chain) { return AJ_ERR_INVALID; } cred->data = (uint8_t*) chain; cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_RESPONSE: node = (X509CertificateChain*) cred->data; while (node) { AJ_DumpBytes("CERTIFICATE", node->certificate.der.data, node->certificate.der.size); node = node->next; } status = AJ_OK; break; } break; } break; default: break; } return status; } #endif #define CONNECT_TIMEOUT (1000 * 200) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (100 * 10) static AJ_Status SendSignal(AJ_BusAttachment* bus, uint32_t sessionId, const char* serviceName) { AJ_Status status; AJ_Message msg; status = AJ_MarshalSignal(bus, &msg, PRX_MY_SIGNAL, serviceName, sessionId, 0, 0); if (status == AJ_OK) { AJ_Arg arg; status = AJ_MarshalContainer(&msg, &arg, AJ_ARG_ARRAY); status = AJ_MarshalCloseContainer(&msg, &arg); } if (status == AJ_OK) { status = AJ_DeliverMsg(&msg); } return status; } void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; } #ifdef MAIN_ALLOWS_ARGS int AJ_Main(int ac, char** av) #else int AJ_Main() #endif { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; AJ_Status authStatus = AJ_ERR_NULL; /* * Buffer to hold the peer's full service name or unique name. */ #if defined (NGNS) || defined (ANNOUNCE_BASED_DISCOVERY) char peerServiceName[AJ_MAX_NAME_SIZE + 1]; #else char peerServiceName[AJ_MAX_SERVICE_NAME_SIZE]; #endif #ifdef SECURE_INTERFACE uint32_t suites[16]; size_t numsuites = 0; uint8_t clearkeys = FALSE; #endif #ifdef MAIN_ALLOWS_ARGS #ifdef SECURE_INTERFACE ac--; av++; /* * Enable authentication mechanism by command line */ if (ac) { if (0 == strncmp(*av, "-ek", 3)) { clearkeys = TRUE; ac--; av++; } else if (0 == strncmp(*av, "-e", 2)) { ac--; av++; } if (!ac) { AJ_AlwaysPrintf(("-e(k) requires an auth mechanism.\n")); return 1; } while (ac) { if (0 == strncmp(*av, "ECDHE_ECDSA", 11)) { suites[numsuites++] = AUTH_SUITE_ECDHE_ECDSA; } else if (0 == strncmp(*av, "ECDHE_PSK", 9)) { suites[numsuites++] = AUTH_SUITE_ECDHE_PSK; } else if (0 == strncmp(*av, "ECDHE_NULL", 10)) { suites[numsuites++] = AUTH_SUITE_ECDHE_NULL; } ac--; av++; } } #endif #endif /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(ProxyObjects); AJ_RegisterObjects(NULL, ProxyObjects); while (TRUE) { AJ_Message msg; if (!connected) { #if defined (NGNS) || defined (ANNOUNCE_BASED_DISCOVERY) status = AJ_StartClientByInterface(&bus, NULL, CONNECT_TIMEOUT, FALSE, testInterfaceNames, &sessionId, peerServiceName, NULL); #else status = AJ_StartClientByName(&bus, NULL, CONNECT_TIMEOUT, FALSE, testServiceName, testServicePort, &sessionId, NULL, peerServiceName); #endif if (status == AJ_OK) { AJ_AlwaysPrintf(("StartClient returned %d, sessionId=%u, serviceName=%s\n", status, sessionId, peerServiceName)); AJ_AlwaysPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(&bus))); connected = TRUE; #ifdef SECURE_INTERFACE AJ_BusEnableSecurity(&bus, suites, numsuites); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); if (clearkeys) { AJ_ClearCredentials(AJ_GENERIC_MASTER_SECRET | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_THUMBPRINT | AJ_CRED_TYPE_GENERIC); AJ_ClearCredentials(AJ_GENERIC_ECDSA_KEYS | AJ_CRED_TYPE_GENERIC); } status = AJ_BusAuthenticatePeer(&bus, peerServiceName, AuthCallback, &authStatus); if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_BusAuthenticatePeer returned %d\n", status)); } #else authStatus = AJ_OK; #endif AJ_BusAddSignalRule(&bus, "my_signal", testInterfaceName, AJ_BUS_SIGNAL_ALLOW); } else { AJ_AlwaysPrintf(("StartClient returned %d\n", status)); break; } } if (authStatus != AJ_ERR_NULL) { if (authStatus != AJ_OK) { AJ_Disconnect(&bus); break; } authStatus = AJ_ERR_NULL; } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (status == AJ_ERR_TIMEOUT) { status = AppDoWork(&bus, sessionId, peerServiceName); continue; } if (status == AJ_OK) { switch (msg.msgId) { case PRX_MY_SIGNAL: AJ_AlwaysPrintf(("Received my_signal\n")); status = AJ_OK; break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: /* * Force a disconnect */ { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_AlwaysPrintf(("Session lost. ID = %u, reason = %u", id, reason)); } status = AJ_ERR_SESSION_LOST; break; default: /* * Pass to the built-in handlers */ status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_SESSION_LOST) || (status == AJ_ERR_READ) || (status == AJ_ERR_WRITE) || (status == AJ_ERR_LINK_DEAD)) { AJ_AlwaysPrintf(("AllJoyn disconnect\n")); AJ_AlwaysPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); connected = FALSE; } } AJ_AlwaysPrintf(("siglite EXIT %d\n", status)); return status; } #ifdef AJ_MAIN #ifdef MAIN_ALLOWS_ARGS int main(int ac, char** av) { return AJ_Main(ac, av); } #else int main() { return AJ_Main(); } #endif #endif ajtcl-16.04/test/sigtest.c000066400000000000000000000256761271074662300154560ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include static const uint16_t SIG_LEN_MAX = 65000; static const uint16_t SIG_LEN_MIN = 100; /* * Generate a random signal length between SIG_LEN_MIN and SIG_LEN_MAX, * if RANDOM_SIGNAL_LENGTH is TRUE. If RANDOM_SIGNAL_LENGTH is FALSE, * then fix the length of signal as average of SIG_LEN_MIN and SIG_LEN_MAX. */ static const uint8_t RANDOM_SIGNAL_LENGTH = TRUE; static const char DaemonName[] = "org.alljoyn.BusNode"; static const char ServiceName[] = "org.alljoyn.LargeSignals"; static const uint16_t ServicePort = 42; static uint8_t g_prop_ok_to_send = FALSE; static AJ_BusAttachment g_bus; static uint32_t g_sessionId = 0; static const char* const testInterface[] = { "org.alljoyn.LargeSignals", "!large_signal >u >ay", "@ok_to_send=b", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { testInterface, AJ_PropertiesIface, NULL }; /** * Objects implemented by the application */ static const AJ_Object ProxyObjects[] = { { "/org/alljoyn/LargeSignals", testInterfaces }, { NULL } }; #define APP_MY_SIGNAL AJ_APP_MESSAGE_ID(0, 0, 0) #define APP_GET_PROP AJ_APP_MESSAGE_ID(0, 1, AJ_PROP_GET) #define APP_SET_PROP AJ_APP_MESSAGE_ID(0, 1, AJ_PROP_SET) #define APP_BOOL_VAL_PROP AJ_APP_PROPERTY_ID(0, 0, 1) static const uint32_t CONNECT_TIMEOUT = 1000 * 200; static const uint32_t UNMARSHAL_TIMEOUT = 100 * 5; #define ARRAY_SIZE 10000 static const uint8_t byte_array[ARRAY_SIZE]; static uint8_t g_error = 0; /* set property handler */ AJ_Status AppHandleSetProp(AJ_Message* replyMsg, uint32_t propId, void* context) { AJ_Status status = AJ_ERR_UNEXPECTED; uint32_t prop_val = 0; status = AJ_UnmarshalArgs(replyMsg, "b", &prop_val); AJ_Printf("\tDEBUG: Received the property %s\n", (0 == prop_val) ? "FALSE" : "TRUE"); g_prop_ok_to_send = prop_val; return status; } void HandleSignal(AJ_Message*msg) { uint32_t number = 0; uint32_t length = 0; uint32_t bytesUnmarshalled; size_t sz; void* raw = NULL; uint8_t firstByte = 0; uint8_t lastByte = 0; AJ_Status status = AJ_UnmarshalArgs(msg, "u", &number); if (AJ_OK == status) { status = AJ_UnmarshalRaw(msg, (const void**)&raw, sizeof(bytesUnmarshalled), &sz); if (AJ_OK != status) { AJ_Printf("ERROR: UnmarshalRaw 1st call status is %s \n", AJ_StatusText(status)); g_error = 1; } else { length = *((uint32_t*)raw); } } if (AJ_OK == status) { uint32_t bytesToBeFetched = length; uint32_t count = 0; while (0 != bytesToBeFetched) { raw = NULL; status = AJ_UnmarshalRaw(msg, (const void**)&raw, bytesToBeFetched, &sz); if (AJ_OK != status) { AJ_Printf("UnmarshalRaw status is %s \n", AJ_StatusText(status)); AJ_Printf("Bytes to be fetched: %u, actual bytes fetched: %u \n", bytesToBeFetched, (uint32_t)sz); } else { /* * Read the first byte. We need the first byte and the * last byte of the array. */ if (count == 0) { firstByte = *((uint8_t*) raw); } bytesToBeFetched -= sz; count++; } } /* Read the last byte here. */ lastByte = *((uint8_t*) raw + sz - 1); if (firstByte != lastByte) { AJ_Printf("ERROR: Integrity check failed. first element != last element. \n"); g_error = 1; } AJ_Printf("============> Received my_signal # %u, length %u, firstByte %u, lastByte %u\n", number, length, firstByte, lastByte); } } static AJ_Status SendSignal(AJ_BusAttachment* bus, uint32_t sessionId, char* fullServiceName) { AJ_Status status = AJ_OK; AJ_Message msg; static uint32_t current_signal_number = 0; uint32_t array_size = 0; uint16_t random = 0; uint32_t i = 0; int remaining = 0; uint8_t data = 0; status = AJ_MarshalSignal(bus, &msg, APP_MY_SIGNAL, fullServiceName, sessionId, 0, 0); if (AJ_OK == status) { status = AJ_MarshalArgs(&msg, "u", current_signal_number); if (RANDOM_SIGNAL_LENGTH) { AJ_RandBytes((uint8_t*)&random, sizeof(random)); if (random == 0) { random = 1; } array_size = SIG_LEN_MIN + random % (SIG_LEN_MAX - SIG_LEN_MIN); } else { array_size = (SIG_LEN_MIN + SIG_LEN_MAX) / 2; } AJ_Printf("\tDEBUG: Size of array (in signal payload) is %u\n", array_size); /* * Raw Marshaling of an array involves: * a. Marshaling of length of array (uint32_t) * b. Marshaling of the array itself */ status = AJ_DeliverMsgPartial(&msg, sizeof(uint32_t) + array_size); if (AJ_OK != status) { AJ_Printf("ERROR: DeliverMsgPartial returned: %s.\n", AJ_StatusText(status)); return status; } status = AJ_MarshalRaw(&msg, &array_size, sizeof(uint32_t)); if (AJ_OK != status) { AJ_Printf("ERROR: AJ_MarshalRaw of array_size returned %s.\n", AJ_StatusText(status)); return status; } /* Marshal raw the data. it will keep sending the data partially. */ AJ_RandBytes(&data, sizeof(data)); /* Marshal the first data byte separately. */ status = AJ_MarshalRaw(&msg, &data, 1); if (AJ_OK != status) { AJ_Printf("ERROR: Marshaling of first byte returned %s.\n", AJ_StatusText(status)); return status; } if (ARRAY_SIZE < (array_size - 2)) { for (i = 0; i < (array_size - 2) / ARRAY_SIZE; i++) { status = AJ_MarshalRaw(&msg, byte_array, ARRAY_SIZE); if (AJ_OK != status) { AJ_Printf("ERROR: 1 Marshaling element (index: %d) failed. Got status: %s.\n", i, AJ_StatusText(status)); break; } } } if (0 != (array_size - 2) % ARRAY_SIZE) { remaining = (array_size - 2) % ARRAY_SIZE; status = AJ_MarshalRaw(&msg, byte_array, remaining); if (AJ_OK != status) { AJ_Printf("ERROR: 2 Marshaling element (index: %d) failed. Got status: %s.\n", i, AJ_StatusText(status)); } } /* fill the last byte with data */ status = AJ_MarshalRaw(&msg, &data, 1); if (AJ_OK != status) { AJ_Printf("ERROR: Marshaling last element returned %s.\n", AJ_StatusText(status)); return status; } } if (AJ_OK == status) { status = AJ_DeliverMsg(&msg); if (AJ_OK == status) { AJ_Printf("Signal sent successfully.\n"); } current_signal_number++; } return status; } static void AppDoWork(char* fullServiceName) { if (g_prop_ok_to_send) { if (AJ_OK != SendSignal(&g_bus, g_sessionId, fullServiceName)) { AJ_Printf("ERROR: Sending signal failed.\n"); } else { g_prop_ok_to_send = FALSE; } } else { AJ_Printf("Nothing to do at the moment. \n"); } } void AJ_Main(void) { AJ_Status status = AJ_OK; uint8_t connected = FALSE; /* * Buffer to hold the full service name. The buffer size must be AJ_MAX_SERVICE_NAME_SIZE. */ char fullServiceName[AJ_MAX_SERVICE_NAME_SIZE]; AJ_Initialize(); AJ_PrintXML(ProxyObjects); AJ_RegisterObjects(ProxyObjects, NULL); while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartClientByName(&g_bus, DaemonName, CONNECT_TIMEOUT, 0, ServiceName, ServicePort, &g_sessionId, NULL, fullServiceName); if (AJ_OK == status) { AJ_Printf("StartClient returned %s, sessionId=%u\n", AJ_StatusText(status), g_sessionId); AJ_Printf("Connected to Daemon: %s\n", AJ_GetUniqueName(&g_bus)); connected = TRUE; } else { AJ_Printf("StartClient returned %s\n", AJ_StatusText(status)); break; } } status = AJ_UnmarshalMsg(&g_bus, &msg, UNMARSHAL_TIMEOUT); if ((AJ_ERR_TIMEOUT != status) && (AJ_OK != status)) { AJ_Printf("ERROR: UnmarshalMsg returned %s \n", AJ_StatusText(status)); } if (AJ_ERR_TIMEOUT == status) { AppDoWork(fullServiceName); continue; } if (AJ_OK == status) { switch (msg.msgId) { case APP_MY_SIGNAL: HandleSignal(&msg); status = AJ_OK; break; case APP_SET_PROP: status = AJ_BusPropSet(&msg, AppHandleSetProp, NULL); break; case AJ_SIGNAL_SESSION_LOST: AJ_Printf("Session Lost \n"); status = AJ_ERR_READ; break; default: AJ_Printf("Default: msg id is %u\n", msg.msgId); status = AJ_BusHandleBusMessage(&msg); break; } } /* * Messages must be closed to free resources */ if (status == AJ_OK) { status = AJ_CloseMsg(&msg); if (status != AJ_OK) { AJ_Printf("Close message failed \n"); AJ_Disconnect(&g_bus); connected = FALSE; break; } } if ((AJ_ERR_READ == status) || (status == AJ_ERR_WRITE) || g_error) { AJ_Printf("AllJoyn disconnect %s \n", AJ_StatusText(status)); AJ_Printf("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&g_bus)); AJ_Disconnect(&g_bus); connected = FALSE; break; } } AJ_Printf("sigtest exiting with status: %s\n", AJ_StatusText(status)); } #ifdef AJ_MAIN int main(void) { /* We are not expecting AJ_Main to return */ AJ_Main(); return 0; } #endif ajtcl-16.04/test/svclite.c000066400000000000000000000471401271074662300154330ustar00rootroot00000000000000/** * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ /** * Per-module definition of the current module for debug logging. Must be defined * prior to first inclusion of aj_debug.h */ #define AJ_MODULE SVCLITE #ifndef TEST_DISABLE_SECURITY #define SECURE_INTERFACE #define SECURE_OBJECT #endif #include #include #include #include #include #include #include #include #include #include #include /** * Turn on per-module debug printing by setting this variable to non-zero value * (usually in debugger). */ uint8_t dbgSVCLITE = 1; /* * Modify these variables to change the service's behavior */ static const char ServiceName[] = "org.alljoyn.svclite"; static const uint16_t ServicePort = 24; static const uint8_t CancelAdvertiseName = FALSE; static const uint8_t ReflectSignal = FALSE; /* * An application property to SET or GET */ static int32_t propVal = 123456; /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; /* * To define a secure interface, prepend '$' before the interface name, eg., "$org.alljoyn.alljoyn_test" */ static const char* const testInterface[] = { #ifdef SECURE_INTERFACE "$org.alljoyn.alljoyn_test", #else "org.alljoyn.alljoyn_test", #endif "?my_ping inStrs", "?delayed_ping inStrs", "?time_ping u >q", "!my_signal >a{ys}", NULL }; static const char* const testValuesInterface[] = { #ifdef SECURE_INTERFACE "$org.alljoyn.alljoyn_test.values", #else "org.alljoyn.alljoyn_test.values", #endif "@int_val=i", "@str_val=s", "@ro_val>s", NULL }; static const AJ_InterfaceDescription testInterfaces[] = { AJ_PropertiesIface, testInterface, testValuesInterface, NULL }; static AJ_Object AppObjects[] = { #ifdef SECURE_OBJECT { "/org/alljoyn/alljoyn_test", testInterfaces, AJ_OBJ_FLAG_ANNOUNCED | AJ_OBJ_FLAG_SECURE }, #else { "/org/alljoyn/alljoyn_test", testInterfaces, AJ_OBJ_FLAG_ANNOUNCED }, #endif { NULL } }; static AJ_PermissionMember members[] = { { "*", AJ_MEMBER_TYPE_ANY, AJ_ACTION_PROVIDE | AJ_ACTION_OBSERVE, NULL } }; static AJ_PermissionRule rules[] = { { "/org/alljoyn/alljoyn_test", "org.alljoyn.alljoyn_test", members, NULL } }; /* * Message identifiers for the method calls this application implements */ #define APP_GET_PROP AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_GET) #define APP_SET_PROP AJ_APP_MESSAGE_ID(0, 0, AJ_PROP_SET) #define APP_MY_PING AJ_APP_MESSAGE_ID(0, 1, 0) #define APP_DELAYED_PING AJ_APP_MESSAGE_ID(0, 1, 1) #define APP_TIME_PING AJ_APP_MESSAGE_ID(0, 1, 2) #define APP_MY_SIGNAL AJ_APP_MESSAGE_ID(0, 1, 3) /* * Property identifiers for the properies this application implements */ #define APP_INT_VAL_PROP AJ_APP_PROPERTY_ID(0, 2, 0) /* * Let the application do some work */ static void AppDoWork() { /* * This function is called if there are no messages to unmarshal */ AJ_InfoPrintf(("do work\n")); } #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) static const char psk_hint[] = ""; /* * The tests were changed at some point to make the psk longer. * If doing backcompatibility testing with previous versions (14.06 or before), * define LITE_TEST_BACKCOMPAT to use the old version of the password. */ #ifndef LITE_TEST_BACKCOMPAT static const char psk_char[] = "faaa0af3dd3f1e0379da046a3ab6ca44"; #else static const char psk_char[] = "123456"; #endif // Copied from alljoyn/alljoyn_core/unit_test/AuthListenerECDHETest.cc with // newlines removed static const char pem_prv[] = { "-----BEGIN EC PRIVATE KEY-----" "MDECAQEEICCRJMbxSiWUqj4Zs7jFQRXDJdBRPWX6fIVqE1BaXd08oAoGCCqGSM49" "AwEH" "-----END EC PRIVATE KEY-----" }; static const char pem_x509[] = { "-----BEGIN CERTIFICATE-----" "MIIBuDCCAV2gAwIBAgIHMTAxMDEwMTAKBggqhkjOPQQDAjBCMRUwEwYDVQQLDAxv" "cmdhbml6YXRpb24xKTAnBgNVBAMMIDgxM2FkZDFmMWNiOTljZTk2ZmY5MTVmNTVk" "MzQ4MjA2MB4XDTE1MDcyMjIxMDYxNFoXDTE2MDcyMTIxMDYxNFowQjEVMBMGA1UE" "CwwMb3JnYW5pemF0aW9uMSkwJwYDVQQDDCAzOWIxZGNmMjBmZDJlNTNiZGYzMDU3" "NzMzMjBlY2RjMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGJ/9F4xHn3Klw7z" "6LREmHJgzu8yJ4i09b4EWX6a5MgUpQoGKJcjWgYGWb86bzbciMCFpmKzfZ42Hg+k" "BJs2ZWajPjA8MAwGA1UdEwQFMAMBAf8wFQYDVR0lBA4wDAYKKwYBBAGC3nwBATAV" "BgNVHSMEDjAMoAoECELxjRK/fVhaMAoGCCqGSM49BAMCA0kAMEYCIQDixoulcO7S" "df6Iz6lvt2CDy0sjt/bfuYVW3GeMLNK1LAIhALNklms9SP8ZmTkhCKdpC+/fuwn0" "+7RX8CMop11eWCih" "-----END CERTIFICATE-----" }; static X509CertificateChain* chain = NULL; static AJ_Status AuthListenerCallback(uint32_t authmechanism, uint32_t command, AJ_Credential* cred) { AJ_Status status = AJ_ERR_INVALID; X509CertificateChain* node; AJ_AlwaysPrintf(("AuthListenerCallback authmechanism %08X command %d\n", authmechanism, command)); switch (authmechanism) { case AUTH_SUITE_ECDHE_NULL: cred->expiration = keyexpiration; status = AJ_OK; break; case AUTH_SUITE_ECDHE_PSK: switch (command) { case AJ_CRED_PUB_KEY: cred->data = (uint8_t*) psk_hint; cred->len = strlen(psk_hint); cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_PRV_KEY: cred->data = (uint8_t*) psk_char; cred->len = strlen(psk_char); cred->expiration = keyexpiration; status = AJ_OK; break; } break; case AUTH_SUITE_ECDHE_ECDSA: switch (command) { case AJ_CRED_PRV_KEY: AJ_ASSERT(sizeof (AJ_ECCPrivateKey) == cred->len); status = AJ_DecodePrivateKeyPEM((AJ_ECCPrivateKey*) cred->data, pem_prv); cred->expiration = keyexpiration; break; case AJ_CRED_CERT_CHAIN: switch (cred->direction) { case AJ_CRED_REQUEST: // Free previous certificate chain AJ_X509FreeDecodedCertificateChain(chain); chain = AJ_X509DecodeCertificateChainPEM(pem_x509); if (NULL == chain) { return AJ_ERR_INVALID; } cred->data = (uint8_t*) chain; cred->expiration = keyexpiration; status = AJ_OK; break; case AJ_CRED_RESPONSE: node = (X509CertificateChain*) cred->data; while (node) { AJ_DumpBytes("CERTIFICATE", node->certificate.der.data, node->certificate.der.size); node = node->next; } status = AJ_OK; break; } break; } break; default: break; } return status; } #endif static AJ_Status AppHandlePing(AJ_Message* msg) { AJ_Message reply; AJ_Arg arg; AJ_UnmarshalArg(msg, &arg); AJ_MarshalReplyMsg(msg, &reply); /* * Just return the arg we received */ AJ_MarshalArg(&reply, &arg); AJ_InfoPrintf(("Handle Ping\n")); return AJ_DeliverMsg(&reply); } /* * Handles a property GET request so marshals the property value to return */ static AJ_Status PropGetHandler(AJ_Message* replyMsg, uint32_t propId, void* context) { if (propId == APP_INT_VAL_PROP) { return AJ_MarshalArgs(replyMsg, "i", propVal); } else { return AJ_ERR_UNEXPECTED; } } /* * Handles a property SET request so unmarshals the property value to apply. */ static AJ_Status PropSetHandler(AJ_Message* replyMsg, uint32_t propId, void* context) { if (propId == APP_INT_VAL_PROP) { return AJ_UnmarshalArgs(replyMsg, "i", &propVal); } else { return AJ_ERR_UNEXPECTED; } } #define UUID_LENGTH 16 #define APP_ID_SIGNATURE "ay" static AJ_Status MarshalAppId(AJ_Message* msg, const char* appId) { AJ_Status status; uint8_t binAppId[UUID_LENGTH]; uint32_t sz = strlen(appId); if (sz > UUID_LENGTH * 2) { // Crop application id that is too long sz = UUID_LENGTH * 2; } status = AJ_HexToRaw(appId, sz, binAppId, UUID_LENGTH); if (status != AJ_OK) { return status; } status = AJ_MarshalArgs(msg, "{sv}", AJ_APP_ID_STR, APP_ID_SIGNATURE, binAppId, sz / 2); return status; } static AJ_Status AboutPropGetter(AJ_Message* reply, const char* language) { AJ_Status status = AJ_OK; AJ_Arg array; AJ_GUID theAJ_GUID; char machineIdValue[UUID_LENGTH * 2 + 1]; machineIdValue[UUID_LENGTH * 2] = '\0'; /* Here, "en" is the only supported language, so we always return it * regardless of what was requested, per the algorithm specified in * RFC 4647 section 3.4. */ status = AJ_MarshalContainer(reply, &array, AJ_ARG_ARRAY); if (status == AJ_OK) { status = AJ_GetLocalGUID(&theAJ_GUID); if (status == AJ_OK) { AJ_GUID_ToString(&theAJ_GUID, machineIdValue, UUID_LENGTH * 2 + 1); } if (status == AJ_OK) { status = MarshalAppId(reply, &machineIdValue[0]); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_APP_NAME_STR, "s", "svclite"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_ID_STR, "s", machineIdValue); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEVICE_NAME_STR, "s", "Tester"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MANUFACTURER_STR, "s", "QCE"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_MODEL_NUMBER_STR, "s", "1.0"); } //SupportedLanguages if (status == AJ_OK) { AJ_Arg dict; AJ_Arg languageListArray; status = AJ_MarshalContainer(reply, &dict, AJ_ARG_DICT_ENTRY); if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", AJ_SUPPORTED_LANGUAGES_STR); } if (status == AJ_OK) { status = AJ_MarshalVariant(reply, "as"); } if (status == AJ_OK) { status = AJ_MarshalContainer(reply, &languageListArray, AJ_ARG_ARRAY); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "s", "en"); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &languageListArray); } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &dict); } } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DESCRIPTION_STR, "s", "svclite test app"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_DEFAULT_LANGUAGE_STR, "s", "en"); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_SOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } if (status == AJ_OK) { status = AJ_MarshalArgs(reply, "{sv}", AJ_AJSOFTWARE_VERSION_STR, "s", AJ_GetVersion()); } } if (status == AJ_OK) { status = AJ_MarshalCloseContainer(reply, &array); } return status; } static const uint32_t suites[] = { AUTH_SUITE_ECDHE_ECDSA, AUTH_SUITE_ECDHE_PSK, AUTH_SUITE_ECDHE_NULL }; #define CONNECT_TIMEOUT (1000 * 1000) #define UNMARSHAL_TIMEOUT (1000 * 5) #ifdef MAIN_ALLOWS_ARGS int AJ_Main(int ac, char** av) #else int AJ_Main() #endif { AJ_Status status = AJ_OK; AJ_BusAttachment bus; uint8_t connected = FALSE; uint32_t sessionId = 0; uint8_t claim = FALSE; /* * One time initialization before calling any other AllJoyn APIs */ AJ_Initialize(); AJ_PrintXML(AppObjects); AJ_RegisterObjects(AppObjects, NULL); AJ_AboutRegisterPropStoreGetter(AboutPropGetter); #ifdef MAIN_ALLOWS_ARGS ac--; av++; if (ac) { #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) if (0 == strncmp(*av, "-claim", 6)) { claim = TRUE; } #endif } #endif while (TRUE) { AJ_Message msg; if (!connected) { status = AJ_StartService(&bus, NULL, CONNECT_TIMEOUT, FALSE, ServicePort, ServiceName, AJ_NAME_REQ_DO_NOT_QUEUE, NULL); if (status != AJ_OK) { continue; } AJ_InfoPrintf(("StartService returned AJ_OK\n")); AJ_InfoPrintf(("Connected to Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_SetIdleTimeouts(&bus, 10, 4); connected = TRUE; #ifdef SECURE_OBJECT status = AJ_SetObjectFlags("/org/alljoyn/alljoyn_test", AJ_OBJ_FLAG_SECURE, 0); if (status != AJ_OK) { AJ_ErrPrintf(("Error calling AJ_SetObjectFlags.. [%s] \n", AJ_StatusText(status))); return -1; } #endif #if defined(SECURE_INTERFACE) || defined(SECURE_OBJECT) AJ_BusEnableSecurity(&bus, suites, ArraySize(suites)); AJ_BusSetAuthListenerCallback(&bus, AuthListenerCallback); AJ_ManifestTemplateSet(rules); if (claim) { AJ_SecuritySetClaimConfig(&bus, APP_STATE_CLAIMABLE, CLAIM_CAPABILITY_ECDHE_PSK, 0); } #endif /* Configure timeout for the link to the daemon bus */ AJ_SetBusLinkTimeout(&bus, 60); // 60 seconds } status = AJ_UnmarshalMsg(&bus, &msg, UNMARSHAL_TIMEOUT); if (AJ_ERR_TIMEOUT == status && AJ_ERR_LINK_TIMEOUT == AJ_BusLinkStateProc(&bus)) { status = AJ_ERR_READ; } if (status != AJ_OK) { if (status == AJ_ERR_TIMEOUT) { AppDoWork(); continue; } } if (status == AJ_OK) { switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_ADD_MATCH): if (msg.hdr->msgType == AJ_MSG_ERROR) { AJ_InfoPrintf(("Failed to add match\n")); status = AJ_ERR_FAILURE; } else { status = AJ_OK; } break; case AJ_METHOD_ACCEPT_SESSION: { uint16_t port; char* joiner; AJ_UnmarshalArgs(&msg, "qus", &port, &sessionId, &joiner); if (port == ServicePort) { status = AJ_BusReplyAcceptSession(&msg, TRUE); AJ_InfoPrintf(("Accepted session session_id=%u joiner=%s\n", sessionId, joiner)); } else { status = AJ_ResetArgs(&msg); if (AJ_OK != status) { break; } status = AJ_BusHandleBusMessage(&msg); } } break; case APP_MY_PING: status = AppHandlePing(&msg); break; case APP_GET_PROP: status = AJ_BusPropGet(&msg, PropGetHandler, NULL); break; case APP_SET_PROP: status = AJ_BusPropSet(&msg, PropSetHandler, NULL); if (status == AJ_OK) { AJ_InfoPrintf(("Property successfully set to %d.\n", propVal)); } else { AJ_InfoPrintf(("Property set attempt unsuccessful. Status = 0x%04x.\n", status)); } break; case AJ_SIGNAL_SESSION_LOST_WITH_REASON: { uint32_t id, reason; AJ_UnmarshalArgs(&msg, "uu", &id, &reason); AJ_InfoPrintf(("Session lost. ID = %u, reason = %u", id, reason)); if (CancelAdvertiseName) { status = AJ_BusAdvertiseName(&bus, ServiceName, AJ_TRANSPORT_ANY, AJ_BUS_START_ADVERTISING, 0); } status = AJ_ERR_SESSION_LOST; } break; case AJ_SIGNAL_SESSION_JOINED: if (CancelAdvertiseName) { status = AJ_BusAdvertiseName(&bus, ServiceName, AJ_TRANSPORT_ANY, AJ_BUS_STOP_ADVERTISING, 0); } break; case AJ_REPLY_ID(AJ_METHOD_CANCEL_ADVERTISE): case AJ_REPLY_ID(AJ_METHOD_ADVERTISE_NAME): if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } break; case AJ_REPLY_ID(AJ_METHOD_BUS_SET_IDLE_TIMEOUTS): { uint32_t disposition, idleTo, probeTo; if (msg.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_FAILURE; } AJ_UnmarshalArgs(&msg, "uuu", &disposition, &idleTo, &probeTo); AJ_InfoPrintf(("SetIdleTimeouts response disposition=%u idleTimeout=%u probeTimeout=%u\n", disposition, idleTo, probeTo)); } break; case APP_MY_SIGNAL: AJ_InfoPrintf(("Received my_signal\n")); status = AJ_OK; if (ReflectSignal) { AJ_Message out; AJ_Arg arg; AJ_MarshalSignal(&bus, &out, APP_MY_SIGNAL, msg.sender, msg.sessionId, 0, 0); AJ_MarshalContainer(&out, &arg, AJ_ARG_ARRAY); AJ_MarshalCloseContainer(&out, &arg); AJ_DeliverMsg(&out); AJ_CloseMsg(&out); } break; default: /* * Pass to the built-in bus message handlers */ status = AJ_BusHandleBusMessage(&msg); break; } // Any received packets indicates the link is active, so call to reinforce the bus link state AJ_NotifyLinkActive(); } /* * Unarshaled messages must be closed to free resources */ AJ_CloseMsg(&msg); if ((status == AJ_ERR_READ) || (status == AJ_ERR_LINK_DEAD)) { AJ_InfoPrintf(("AllJoyn disconnect\n")); AJ_InfoPrintf(("Disconnected from Daemon:%s\n", AJ_GetUniqueName(&bus))); AJ_Disconnect(&bus); connected = FALSE; /* * Sleep a little while before trying to reconnect */ AJ_Sleep(10 * 1000); } } AJ_WarnPrintf(("svclite EXIT %d\n", status)); return status; } #ifdef AJ_MAIN #ifdef MAIN_ALLOWS_ARGS int main(int ac, char** av) { return AJ_Main(ac, av); } #else int main() { return AJ_Main(); } #endif #endif ajtcl-16.04/test/uart_randombuffer.c000066400000000000000000000065271271074662300174730ustar00rootroot00000000000000/** * @file UART transport Tester */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #define B115200 111520 #define BITRATE B115200 #define AJ_SERIAL_WINDOW_SIZE 4 #define AJ_SERIAL_ENABLE_CRC 1 #define LOCAL_DATA_PACKET_SIZE 100 #define AJ_SERIAL_PACKET_SIZE LOCAL_DATA_PACKET_SIZE #define RANDOM_BYTES_MAX 5000 #ifdef ECHO static uint8_t txBuffer[RANDOM_BYTES_MAX]; #endif static uint8_t rxBuffer[RANDOM_BYTES_MAX]; int AJ_Main() { AJ_Status status; status = AJ_SerialInit("/dev/ttyUSB1", BITRATE, AJ_SERIAL_WINDOW_SIZE, AJ_SERIAL_PACKET_SIZE); AJ_AlwaysPrintf(("serial init was %u\n", status)); uint16_t txlen; uint16_t rxlen; int i = 0; #ifdef ECHO while (1) { AJ_AlwaysPrintf(("Iteration %d\n", i++)); status = AJ_SerialRecv(rxBuffer, RANDOM_BYTES_MAX, 5000, &rxlen); if (status == AJ_ERR_TIMEOUT) { continue; } if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_SerialRecv returned %d\n", status)); exit(1); } AJ_Sleep(rand() % 5000); status = AJ_SerialSend(rxBuffer, rxlen); if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_SerialSend returned %d\n", status)); exit(1); } AJ_Sleep(rand() % 5000); } #else txlen = 0; while (1) { AJ_AlwaysPrintf(("Iteration %d\n", i++)); txlen = rand() % 5000; for (int i = 0; i < txlen; i++) { txBuffer[i] = rand() % 256; rxBuffer[i] = 1; } status = AJ_SerialSend(txBuffer, txlen); if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_SerialSend returned %d\n", status)); exit(1); } AJ_Sleep(rand() % 5000); status = AJ_SerialRecv(rxBuffer, txlen, 50000, &rxlen); if (status != AJ_OK) { AJ_AlwaysPrintf(("AJ_SerialRecv returned %d\n", status)); exit(1); } if (rxlen != txlen) { AJ_AlwaysPrintf(("Failed: length match rxlen=%d txlen=%d.\n", rxlen, txlen)); exit(-1); } if (0 != memcmp(txBuffer, rxBuffer, rxlen)) { AJ_AlwaysPrintf(("Failed: buffers match.\n")); exit(-1); } } #endif return(0); } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/uartbigsmall.c000066400000000000000000000063431271074662300164500ustar00rootroot00000000000000/** * @file UART transport Tester */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #define BITRATE B115200 #define AJ_SERIAL_WINDOW_SIZE 4 #define AJ_SERIAL_ENABLE_CRC 1 #define LOCAL_DATA_PACKET_SIZE 100 #define AJ_SERIAL_PACKET_SIZE LOCAL_DATA_PACKET_SIZE + AJ_SERIAL_HDR_LEN static uint8_t txBuffer[1600]; static uint8_t rxBuffer[1600]; void TimerCallbackEndProc(uint32_t timerId, void* context) { AJ_AlwaysPrintf(("TimerCallbackEndProc %.6d \n", timerId)); #ifdef READTEST if (0 == memcmp(txBuffer, rxBuffer, sizeof(rxBuffer))) { AJ_AlwaysPrintf(("Passed: buffers match.\n")); } else { AJ_AlwaysPrintf(("FAILED: buffers mismatch.\n")); exit(-1); } #endif exit(0); } #ifdef AJ_MAIN int main() { AJ_Status status; memset(&txBuffer, 'T', sizeof(txBuffer)); memset(&rxBuffer, 'R', sizeof(rxBuffer)); int blocks; int blocksize = LOCAL_DATA_PACKET_SIZE; for (blocks = 0; blocks < 16; blocks++) { memset(txBuffer + (blocks * blocksize), 0x41 + (uint8_t)blocks, blocksize); } #ifdef READTEST status = AJ_SerialInit("/dev/ttyUSB0", BITRATE, AJ_SERIAL_WINDOW_SIZE, AJ_SERIAL_ENABLE_CRC, AJ_SERIAL_PACKET_SIZE); #else status = AJ_SerialInit("/dev/ttyUSB1", BITRATE, AJ_SERIAL_WINDOW_SIZE, AJ_SERIAL_ENABLE_CRC, AJ_SERIAL_PACKET_SIZE); #endif AJ_AlwaysPrintf(("serial init was %u\n", status)); uint32_t timerEndProc = 9999; status = AJ_TimerRegister(20000, &TimerCallbackEndProc, NULL, &timerEndProc); AJ_AlwaysPrintf(("Added id %u\n", timerEndProc)); #ifdef READTEST //Read small chunks of a packet at one time. for (blocks = 0; blocks < 16 * 4; blocks++) { fflush(NULL); AJ_SerialRecv(rxBuffer + (blocks * blocksize / 4), blocksize / 4, 2000, NULL); AJ_Sleep(200); } AJ_DumpBytes("Post serial recv", rxBuffer, sizeof(rxBuffer)); #else AJ_Sleep(500); AJ_SerialSend(txBuffer, sizeof(txBuffer)); // for (blocks = 0 ; blocks < 16; blocks++) { // AJ_SerialSend(txBuffer+(blocks*blocksize), blocksize); // } AJ_AlwaysPrintf(("post serial send\n")); #endif while (1) { usleep(1000); } return(0); } #endif ajtcl-16.04/test/uartfuzztest.c000066400000000000000000000157131271074662300165550ustar00rootroot00000000000000/** * @file UART transport Tester */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #define B115200 111520 #define BITRATE B115200 static uint8_t* txBuffer; static uint8_t* rxBuffer; /** * Busy-wait if there is a crash, then we can check the stack with a debugger */ void HardFault_Handler(void) { assert(0); while (1); } #ifdef AJ_DEBUG_SERIAL_TARGET #define AJ_DebugDumpSerialRX(a, b, c) AJ_DumpBytes(a, b, c) #define AJ_DebugDumpSerialTX(a, b, c) AJ_DumpBytes(a, b, c) #else #define AJ_DebugDumpSerialRX(a, b, c) #define AJ_DebugDumpSerialTX(a, b, c) #endif /** * byte-aligned structures that mimic the wire-protocol */ #pragma pack(1) typedef struct __packetStart { uint8_t boundary; uint8_t ack : 4; uint8_t seq : 4; uint8_t type : 4; uint8_t : 4; uint8_t len[2]; } PacketStart; typedef struct __packetHeader { PacketStart start; uint8_t tag[4]; } PacketHeader; typedef struct __packetNegotiate { PacketHeader header; uint16_t packetSize; uint8_t : 4; uint8_t protoVersion : 2; uint8_t windowSize : 2; } PacketNegotiate; typedef struct __packetTail { uint8_t CRC[2]; uint8_t boundaryEnd; } PacketTail; #pragma pack() /** * For every byte in the buffer buf, * with a P(percent/100) chance, write a random byte */ void RandFuzzing(uint8_t* buf, uint32_t len, uint8_t percent) { uint32_t pos = 0; uint8_t* p = (uint8_t*)buf; while (pos++ < len) { uint8_t roll = rand() % 256; if (percent > ((100 * roll) / 256)) { *p = rand() % 256; } ++p; } } /** * Given a buffer of fixed length, randomly pick a way to corrupt the data (or not.) */ void FuzzBuffer(uint8_t* buf, uint32_t len) { size_t offset; uint8_t test = rand() % 32; PacketStart* ps = (PacketStart*)buf; PacketHeader* ph = (PacketHeader*)buf; uint16_t packetLen = (ps->len[0] << 8) | ps->len[1]; AJ_AlwaysPrintf(("FuzzBuffer: Before case %i Tag:%c%c%c%c Ack:%i Seq:%i Type:%X Len:%i\n" , test, ph->tag[0], ph->tag[1], ph->tag[2], ph->tag[3], ps->ack, ps->seq, ps->type, packetLen)); switch (test) { case 0: case 1: /* * Protect fixed header from fuzzing */ offset = sizeof(PacketStart); RandFuzzing(buf + offset, len - offset, 5); break; case 2: /* * fuzz the payload */ offset = sizeof(PacketStart); RandFuzzing(buf + offset, packetLen, 10); break; case 3: /* * change the sequence number */ ps->seq = rand() % 16; break; case 4: /* * change the ack number */ ps->ack = rand() % 16; break; case 5: /* * change the type field of the packet */ ps->type = rand() % 16; break; case 6: /* * change the length field of the packet */ ps->len[0] = rand() % 256; ps->len[1] = rand() % 256; packetLen = (ps->len[0] << 8) | ps->len[1]; break; case 7: /* * Fuzz the entire message */ RandFuzzing(buf, len, 1 + (rand() % 10)); break; // case 8: // not ready yet. // /* // * Protect Negotiate packet header from fuzzing // */ // offset = sizeof(PacketNegotiate); // RandFuzzing(buf + offset, len - offset, 5); // break; default: /* * don't fuzz anything */ break; } AJ_AlwaysPrintf(("FuzzBuffer: After case %i Tag:%c%c%c%c Ack:%i Seq:%i Type:%X Len:%i\n" , test, ph->tag[0], ph->tag[1], ph->tag[2], ph->tag[3], ps->ack, ps->seq, ps->type, packetLen)); AJ_DebugDumpSerialTX("FuzzBuffer", buf, len); __AJ_TX(buf, len); } int AJ_Main() { AJ_Status status; while (1) { int windows = 1 << (rand() % 3); // randomize window width 1,2,4 int blocksize = 50 + (rand() % 1000); // randomize packet size 50 - 1050 AJ_AlwaysPrintf(("Windows:%i Blocksize:%i\n", windows, blocksize)); txBuffer = (uint8_t*) AJ_Malloc(blocksize); rxBuffer = (uint8_t*) AJ_Malloc(blocksize); memset(txBuffer, 0x41, blocksize); memset(rxBuffer, 'r', blocksize); #ifdef READTEST status = AJ_SerialInit("/dev/ttyUSB0", BITRATE, windows, blocksize); #else status = AJ_SerialInit("/dev/ttyUSB1", BITRATE, windows, blocksize); #endif AJ_AlwaysPrintf(("serial init was %u\n", status)); if (status != AJ_OK) { continue; // init failed perhaps from bad parameters, start the loop again } // Change the buffer transmission function to one that fuzzes the output. AJ_SetTxSerialTransmit(&FuzzBuffer); #ifdef READTEST AJ_Sleep(2000); // wait for the writing side to be running, this should test the queuing of data. // try to read everything at once int i = 0; while (1) { AJ_SerialRecv(rxBuffer, blocksize, 50000, NULL); } AJ_DumpBytes("Post serial recv", rxBuffer, blocksize); AJ_Sleep(500); #else AJ_Sleep(5000); int i = 0; while (1) { // change the packet to be sent every time through the loop. memset(txBuffer, 0x41 + (i % 26), blocksize); memset(rxBuffer, 0x41 + (i % 26), blocksize); AJ_SerialSend(txBuffer, blocksize); ++i; if (i % 20 == 0) { AJ_AlwaysPrintf(("Hit iteration %d\n", i)); break; } AJ_SerialRecv(rxBuffer, blocksize, 5000, NULL); } AJ_AlwaysPrintf(("post serial send\n")); #endif // clean up and start again AJ_SerialShutdown(); AJ_Free(txBuffer); AJ_Free(rxBuffer); } return(0); } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/test/uarttest.c000066400000000000000000000065541271074662300156410ustar00rootroot00000000000000/** * @file UART transport Tester */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #include #include #include #include #include #define B115200 111520 #define BITRATE B115200 #define AJ_SERIAL_WINDOW_SIZE 4 #define AJ_SERIAL_ENABLE_CRC 1 #define LOCAL_DATA_PACKET_SIZE 100 #define AJ_SERIAL_PACKET_SIZE LOCAL_DATA_PACKET_SIZE static uint8_t txBuffer[1600]; static uint8_t rxBuffer[1600]; void TimerCallbackEndProc(uint32_t timerId, void* context) { AJ_AlwaysPrintf(("TimerCallbackEndProc %.6d \n", timerId)); #ifdef READTEST if (0 == memcmp(txBuffer, rxBuffer, sizeof(rxBuffer))) { AJ_AlwaysPrintf(("Passed: buffers match.\n")); } else { AJ_AlwaysPrintf(("FAILED: buffers mismatch.\n")); exit(-1); } #endif exit(0); } int AJ_Main() { AJ_Status status; memset(&txBuffer, 'T', sizeof(txBuffer)); memset(&rxBuffer, 'R', sizeof(rxBuffer)); int blocks; int blocksize = LOCAL_DATA_PACKET_SIZE; for (blocks = 0; blocks < 16; blocks++) { memset(txBuffer + (blocks * blocksize), 0x41 + (uint8_t)blocks, blocksize); } #ifdef READTEST status = AJ_SerialInit("/dev/ttyUSB0", BITRATE, AJ_SERIAL_WINDOW_SIZE, AJ_SERIAL_PACKET_SIZE); #else status = AJ_SerialInit("/dev/ttyUSB1", BITRATE, AJ_SERIAL_WINDOW_SIZE, AJ_SERIAL_PACKET_SIZE); #endif AJ_AlwaysPrintf(("serial init was %u\n", status)); #ifdef READTEST AJ_Sleep(2000); // wait for the writing side to be running, this should test the queuing of data. // try to read everything at once int i = 0; //for ( ; i < 10000; ++i) { while (1) { AJ_SerialRecv(rxBuffer, sizeof(rxBuffer), 50000, NULL); } /* //Read small chunks of a packet at one time. for (blocks = 0 ; blocks < 16*4; blocks++) { AJ_SerialRecv(rxBuffer+(blocks*blocksize/4), blocksize/4, 2000, NULL); // AJ_Sleep(200); } */ AJ_DumpBytes("Post serial recv", rxBuffer, sizeof(rxBuffer)); AJ_Sleep(500); #else AJ_Sleep(5000); int i = 0; while (1) { AJ_SerialSend(txBuffer, sizeof(txBuffer)); ++i; if (i % 500 == 0) { AJ_AlwaysPrintf(("Hit iteration %d\n", i)); } } AJ_AlwaysPrintf(("post serial send\n")); #endif while (1) { AJ_StateMachine(); } return(0); } #ifdef AJ_MAIN int main() { return AJ_Main(); } #endif ajtcl-16.04/tools/000077500000000000000000000000001271074662300137715ustar00rootroot00000000000000ajtcl-16.04/tools/ajuncrustify.cfg000066400000000000000000002453651271074662300172170ustar00rootroot00000000000000# Copyright AllSeen Alliance. All rights reserved. # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # Uncrustify 0.61 # # General options # # The type of line endings newlines = auto # auto/lf/crlf/cr # The original size of tabs in the input input_tab_size = 8 # number # The size of tabs in the output (only used if align_with_tabs=true) output_tab_size = 8 # number # The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) string_escape_char = 92 # number # Alternate string escape char for Pawn. Only works right before the quote char. string_escape_char2 = 0 # number # Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. # If true (default), 'assert(x<0 && y>=3)' will be broken. # Improvements to template detection may make this option obsolete. tok_split_gte = false # false/true # Control what to do with the UTF-8 BOM (recommend 'remove') utf8_bom = remove # ignore/add/remove/force # If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8 utf8_byte = false # false/true # Force the output encoding to UTF-8 utf8_force = false # false/true # # Indenting # # The number of columns to indent per level. # Usually 2, 3, 4, or 8. # DJM # indent_columns = 8 # number indent_columns = 4 # number # The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. # For FreeBSD, this is set to 4. Negative value is absolute and not increased for each ( level indent_continue = 0 # number # How to use tabs when indenting code # 0=spaces only # 1=indent with tabs to brace level, align with spaces # 2=indent and align with tabs, using spaces when not on a tabstop # DJM # indent_with_tabs = 1 # number indent_with_tabs = 0 # number # Comments that are not a brace level are indented with tabs on a tabstop. # Requires indent_with_tabs=2. If false, will use spaces. indent_cmt_with_tabs = false # false/true # Whether to indent strings broken by '\' so that they line up indent_align_string = false # false/true # The number of spaces to indent multi-line XML strings. # Requires indent_align_string=True indent_xml_string = 0 # number # Spaces to indent '{' from level indent_brace = 0 # number # Whether braces are indented to the body level indent_braces = false # false/true # Disabled indenting function braces if indent_braces is true indent_braces_no_func = false # false/true # Disabled indenting class braces if indent_braces is true indent_braces_no_class = false # false/true # Disabled indenting struct braces if indent_braces is true indent_braces_no_struct = false # false/true # Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. indent_brace_parent = false # false/true # Indent based on the paren open instead of the brace open in '({\n', default is to indent by brace. indent_paren_open_brace = false # false/true # Whether the 'namespace' body is indented indent_namespace = false # false/true # Only indent one namespace and no sub-namepaces. # Requires indent_namespace=true. indent_namespace_single_indent = false # false/true # The number of spaces to indent a namespace block indent_namespace_level = 0 # number # If the body of the namespace is longer than this number, it won't be indented. # Requires indent_namespace=true. Default=0 (no limit) indent_namespace_limit = 0 # number # Whether the 'extern "C"' body is indented indent_extern = false # false/true # Whether the 'class' body is indented # DJM # indent_class = false # false/true indent_class = true # false/true # Whether to indent the stuff after a leading base class colon indent_class_colon = false # false/true # Whether to indent the stuff after a leading class initializer colon indent_constr_colon = false # false/true # Virtual indent from the ':' for member initializers. Default is 2 indent_ctor_init_leading = 2 # number # Additional indenting for constructor initializer list indent_ctor_init = 0 # number # False=treat 'else\nif' as 'else if' for indenting purposes # True=indent the 'if' one level indent_else_if = false # false/true # Amount to indent variable declarations after a open brace. neg=relative, pos=absolute indent_var_def_blk = 0 # number # Indent continued variable declarations instead of aligning. indent_var_def_cont = false # false/true # True: force indentation of function definition to start in column 1 # False: use the default behavior indent_func_def_force_col1 = false # false/true # True: indent continued function call parameters one indent level # False: align parameters under the open paren indent_func_call_param = false # false/true # Same as indent_func_call_param, but for function defs indent_func_def_param = false # false/true # Same as indent_func_call_param, but for function protos indent_func_proto_param = false # false/true # Same as indent_func_call_param, but for class declarations indent_func_class_param = false # false/true # Same as indent_func_call_param, but for class variable constructors indent_func_ctor_var_param = false # false/true # Same as indent_func_call_param, but for templates indent_template_param = false # false/true # Double the indent for indent_func_xxx_param options indent_func_param_double = false # false/true # Indentation column for standalone 'const' function decl/proto qualifier indent_func_const = 0 # number # Indentation column for standalone 'throw' function decl/proto qualifier indent_func_throw = 0 # number # The number of spaces to indent a continued '->' or '.' # Usually set to 0, 1, or indent_columns. indent_member = 0 # number # Spaces to indent single line ('//') comments on lines before code indent_sing_line_comments = 0 # number # If set, will indent trailing single line ('//') comments relative # to the code instead of trying to keep the same absolute column indent_relative_single_line_comments = false # false/true # Spaces to indent 'case' from 'switch' # Usually 0 or indent_columns. indent_switch_case = 0 # number # Spaces to shift the 'case' line, without affecting any other lines # Usually 0. indent_case_shift = 0 # number # Spaces to indent '{' from 'case'. # By default, the brace will appear under the 'c' in case. # Usually set to 0 or indent_columns. indent_case_brace = 4 # number # Whether to indent comments found in first column indent_col1_comment = false # false/true # How to indent goto labels # >0 : absolute column where 1 is the leftmost column # <=0 : subtract from brace indent # DJM # indent_label = 1 # number indent_label = -4 # number # Same as indent_label, but for access specifiers that are followed by a colon # DJM # indent_access_spec = 1 # number indent_access_spec = -2 # number # Indent the code after an access specifier by one level. # If set, this option forces 'indent_access_spec=0' indent_access_spec_body = false # false/true # If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) indent_paren_nl = false # false/true # Controls the indent of a close paren after a newline. # 0: Indent to body level # 1: Align under the open paren # 2: Indent to the brace level indent_paren_close = 0 # number # Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren indent_comma_paren = false # false/true # Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren indent_bool_paren = false # false/true # If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones indent_first_bool_expr = false # false/true # If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) indent_square_nl = false # false/true # Don't change the relative indent of ESQL/C 'EXEC SQL' bodies indent_preserve_sql = false # false/true # Align continued statements at the '='. Default=True # If FALSE or the '=' is followed by a newline, the next line is indent one tab. indent_align_assign = true # false/true # Indent OC blocks at brace level instead of usual rules. indent_oc_block = false # false/true # Indent OC blocks in a message relative to the parameter name. # 0=use indent_oc_block rules, 1+=spaces to indent indent_oc_block_msg = 0 # number # Minimum indent for subsequent parameters indent_oc_msg_colon = 0 # number # If true, prioritize aligning with initial colon (and stripping spaces from lines, if necessary). # Default is true. indent_oc_msg_prioritize_first_colon = true # false/true # If indent_oc_block_msg and this option are on, blocks will be indented the way that Xcode does by default (from keyword if the parameter is on its own line; otherwise, from the previous indentation level). indent_oc_block_msg_xcode_style = false # false/true # If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is relative to a msg keyword. indent_oc_block_msg_from_keyword = false # false/true # If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is relative to a msg colon. indent_oc_block_msg_from_colon = false # false/true # If indent_oc_block_msg and this option are on, blocks will be indented from where the block caret is. indent_oc_block_msg_from_caret = false # false/true # If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is. indent_oc_block_msg_from_brace = false # false/true # # Spacing options # # Add or remove space around arithmetic operator '+', '-', '/', '*', etc # DJM # sp_arith = ignore # ignore/add/remove/force sp_arith = add # ignore/add/remove/force # Add or remove space around assignment operator '=', '+=', etc # DJM # sp_assign = ignore # ignore/add/remove/force sp_assign = add # ignore/add/remove/force # Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign sp_cpp_lambda_assign = ignore # ignore/add/remove/force # Add or remove space after the capture specification in C++11 lambda. sp_cpp_lambda_paren = ignore # ignore/add/remove/force # Add or remove space around assignment operator '=' in a prototype # DJM # sp_assign_default = ignore # ignore/add/remove/force sp_assign_default = add # ignore/add/remove/force # Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. sp_before_assign = ignore # ignore/add/remove/force # Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. sp_after_assign = ignore # ignore/add/remove/force # Add or remove space in 'NS_ENUM (' sp_enum_paren = ignore # ignore/add/remove/force # Add or remove space around assignment '=' in enum # DJM # sp_enum_assign = ignore # ignore/add/remove/force sp_enum_assign = add # ignore/add/remove/force # Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. sp_enum_before_assign = ignore # ignore/add/remove/force # Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. sp_enum_after_assign = ignore # ignore/add/remove/force # Add or remove space around preprocessor '##' concatenation operator. Default=Add sp_pp_concat = add # ignore/add/remove/force # Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. sp_pp_stringify = add # ignore/add/remove/force # Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'. sp_before_pp_stringify = ignore # ignore/add/remove/force # Add or remove space around boolean operators '&&' and '||' # DJM # sp_bool = ignore # ignore/add/remove/force sp_bool = add # ignore/add/remove/force # Add or remove space around compare operator '<', '>', '==', etc # DJM # sp_compare = ignore # ignore/add/remove/force sp_compare = add # ignore/add/remove/force # Add or remove space inside '(' and ')' # DJM # sp_inside_paren = ignore # ignore/add/remove/force sp_inside_paren = remove # ignore/add/remove/force # Add or remove space between nested parens: '((' vs ') )' # DJM # sp_paren_paren = ignore # ignore/add/remove/force sp_paren_paren = remove # ignore/add/remove/force # Add or remove space between back-to-back parens: ')(' vs ') (' sp_cparen_oparen = ignore # ignore/add/remove/force # Whether to balance spaces inside nested parens sp_balance_nested_parens = false # false/true # Add or remove space between ')' and '{' # DJM # sp_paren_brace = ignore # ignore/add/remove/force sp_paren_brace = add # ignore/add/remove/force # Add or remove space before pointer star '*' # DJM # sp_before_ptr_star = ignore # ignore/add/remove/force sp_before_ptr_star = remove # ignore/add/remove/force # Add or remove space before pointer star '*' that isn't followed by a variable name # If set to 'ignore', sp_before_ptr_star is used instead. sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force # Add or remove space between pointer stars '*' sp_between_ptr_star = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a word. sp_after_ptr_star = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a qualifier. sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by a func proto/def. sp_after_ptr_star_func = ignore # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by an open paren (function types). sp_ptr_star_paren = ignore # ignore/add/remove/force # Add or remove space before a pointer star '*', if followed by a func proto/def. # DJM # sp_before_ptr_star_func = ignore # ignore/add/remove/force sp_before_ptr_star_func = remove # ignore/add/remove/force # Add or remove space before a reference sign '&' # DJM # sp_before_byref = ignore # ignore/add/remove/force sp_before_byref = remove # ignore/add/remove/force # Add or remove space before a reference sign '&' that isn't followed by a variable name # If set to 'ignore', sp_before_byref is used instead. sp_before_unnamed_byref = ignore # ignore/add/remove/force # Add or remove space after reference sign '&', if followed by a word. # DJM # sp_after_byref = ignore # ignore/add/remove/force sp_after_byref = add # ignore/add/remove/force # Add or remove space after a reference sign '&', if followed by a func proto/def. # DJM # sp_after_byref_func = ignore # ignore/add/remove/force sp_after_byref_func = add # ignore/add/remove/force # Add or remove space before a reference sign '&', if followed by a func proto/def. # DJM # sp_before_byref_func = ignore # ignore/add/remove/force sp_before_byref_func = remove # ignore/add/remove/force # Add or remove space between type and word. Default=Force sp_after_type = force # ignore/add/remove/force # Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('. sp_before_template_paren = ignore # ignore/add/remove/force # Add or remove space in 'template <' vs 'template<'. # If set to ignore, sp_before_angle is used. # DJM # sp_template_angle = ignore # ignore/add/remove/force sp_template_angle = add # ignore/add/remove/force # Add or remove space before '<>' sp_before_angle = ignore # ignore/add/remove/force # Add or remove space inside '<' and '>' # DJM # sp_inside_angle = ignore # ignore/add/remove/force sp_inside_angle = remove # ignore/add/remove/force # Add or remove space after '<>' sp_after_angle = ignore # ignore/add/remove/force # Add or remove space between '<>' and '(' as found in 'new List();' sp_angle_paren = ignore # ignore/add/remove/force # Add or remove space between '<>' and a word as in 'List m;' # DJM # sp_angle_word = ignore # ignore/add/remove/force sp_angle_word = add # ignore/add/remove/force # Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add sp_angle_shift = add # ignore/add/remove/force # Permit removal of the space between '>>' in 'foo >' (C++11 only). Default=False # sp_angle_shift cannot remove the space without this option. sp_permit_cpp11_shift = false # false/true # Add or remove space before '(' of 'if', 'for', 'switch', and 'while' # DJM # sp_before_sparen = ignore # ignore/add/remove/force sp_before_sparen = add # ignore/add/remove/force # Add or remove space inside if-condition '(' and ')' # DJM # sp_inside_sparen = ignore # ignore/add/remove/force sp_inside_sparen = remove # ignore/add/remove/force # Add or remove space before if-condition ')'. Overrides sp_inside_sparen. sp_inside_sparen_close = ignore # ignore/add/remove/force # Add or remove space before if-condition '('. Overrides sp_inside_sparen. sp_inside_sparen_open = ignore # ignore/add/remove/force # Add or remove space after ')' of 'if', 'for', 'switch', and 'while' # DJM # sp_after_sparen = ignore # ignore/add/remove/force sp_after_sparen = add # ignore/add/remove/force # Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' # DJM # sp_sparen_brace = ignore # ignore/add/remove/force sp_sparen_brace = add # ignore/add/remove/force # Add or remove space between 'invariant' and '(' in the D language. sp_invariant_paren = ignore # ignore/add/remove/force # Add or remove space after the ')' in 'invariant (C) c' in the D language. sp_after_invariant_paren = ignore # ignore/add/remove/force # Add or remove space before empty statement ';' on 'if', 'for' and 'while' sp_special_semi = ignore # ignore/add/remove/force # Add or remove space before ';'. Default=Remove sp_before_semi = remove # ignore/add/remove/force # Add or remove space before ';' in non-empty 'for' statements sp_before_semi_for = ignore # ignore/add/remove/force # Add or remove space before a semicolon of an empty part of a for statement. sp_before_semi_for_empty = ignore # ignore/add/remove/force # Add or remove space after ';', except when followed by a comment. Default=Add sp_after_semi = add # ignore/add/remove/force # Add or remove space after ';' in non-empty 'for' statements. Default=Force sp_after_semi_for = force # ignore/add/remove/force # Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). # DJM # sp_after_semi_for_empty = ignore # ignore/add/remove/force sp_after_semi_for_empty = remove # ignore/add/remove/force # Add or remove space before '[' (except '[]') sp_before_square = ignore # ignore/add/remove/force # Add or remove space before '[]' sp_before_squares = ignore # ignore/add/remove/force # Add or remove space inside a non-empty '[' and ']' sp_inside_square = ignore # ignore/add/remove/force # Add or remove space after ',' # DJM # sp_after_comma = ignore # ignore/add/remove/force sp_after_comma = add # ignore/add/remove/force # Add or remove space before ',' sp_before_comma = remove # ignore/add/remove/force # Add or remove space between an open paren and comma: '(,' vs '( ,' sp_paren_comma = force # ignore/add/remove/force # Add or remove space before the variadic '...' when preceded by a non-punctuator sp_before_ellipsis = ignore # ignore/add/remove/force # Add or remove space after class ':' # DJM # sp_after_class_colon = ignore # ignore/add/remove/force sp_after_class_colon = add # ignore/add/remove/force # Add or remove space before class ':' # DJM # sp_before_class_colon = ignore # ignore/add/remove/force sp_before_class_colon = add # ignore/add/remove/force # Add or remove space after class constructor ':' sp_after_constr_colon = ignore # ignore/add/remove/force # Add or remove space before class constructor ':' sp_before_constr_colon = ignore # ignore/add/remove/force # Add or remove space before case ':'. Default=Remove sp_before_case_colon = remove # ignore/add/remove/force # Add or remove space between 'operator' and operator sign sp_after_operator = ignore # ignore/add/remove/force # Add or remove space between the operator symbol and the open paren, as in 'operator ++(' sp_after_operator_sym = ignore # ignore/add/remove/force # Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' sp_after_cast = ignore # ignore/add/remove/force # Add or remove spaces inside cast parens sp_inside_paren_cast = ignore # ignore/add/remove/force # Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' sp_cpp_cast_paren = ignore # ignore/add/remove/force # Add or remove space between 'sizeof' and '(' sp_sizeof_paren = ignore # ignore/add/remove/force # Add or remove space after the tag keyword (Pawn) sp_after_tag = ignore # ignore/add/remove/force # Add or remove space inside enum '{' and '}' sp_inside_braces_enum = ignore # ignore/add/remove/force # Add or remove space inside struct/union '{' and '}' sp_inside_braces_struct = ignore # ignore/add/remove/force # Add or remove space inside '{' and '}' # DJM # sp_inside_braces = ignore # ignore/add/remove/force sp_inside_braces = add # ignore/add/remove/force # Add or remove space inside '{}' # sp_inside_braces_empty = ignore # ignore/add/remove/force sp_inside_braces_empty = add # ignore/add/remove/force # Add or remove space between return type and function name # A minimum of 1 is forced except for pointer return types. sp_type_func = ignore # ignore/add/remove/force # Add or remove space between function name and '(' on function declaration # DJM # sp_func_proto_paren = ignore # ignore/add/remove/force sp_func_proto_paren = remove # ignore/add/remove/force # Add or remove space between function name and '(' on function definition # DJM # sp_func_def_paren = ignore # ignore/add/remove/force sp_func_def_paren = remove # ignore/add/remove/force # Add or remove space inside empty function '()' # DJM # sp_inside_fparens = ignore # ignore/add/remove/force sp_inside_fparens = remove # ignore/add/remove/force # Add or remove space inside function '(' and ')' # DJM # sp_inside_fparen = ignore # ignore/add/remove/force sp_inside_fparen = remove # ignore/add/remove/force # Add or remove space inside the first parens in the function type: 'void (*x)(...)' sp_inside_tparen = ignore # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)' sp_after_tparen_close = ignore # ignore/add/remove/force # Add or remove space between ']' and '(' when part of a function call. sp_square_fparen = ignore # ignore/add/remove/force # Add or remove space between ')' and '{' of function # DJM # sp_fparen_brace = ignore # ignore/add/remove/force sp_fparen_brace = add # ignore/add/remove/force # Java: Add or remove space between ')' and '{{' of double brace initializer. sp_fparen_dbrace = ignore # ignore/add/remove/force # Add or remove space between function name and '(' on function calls # DJM # sp_func_call_paren = ignore # ignore/add/remove/force sp_func_call_paren = remove # ignore/add/remove/force # Add or remove space between function name and '()' on function calls without parameters. # If set to 'ignore' (the default), sp_func_call_paren is used. sp_func_call_paren_empty = ignore # ignore/add/remove/force # Add or remove space between the user function name and '(' on function calls # You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. sp_func_call_user_paren = ignore # ignore/add/remove/force # Add or remove space between a constructor/destructor and the open paren # DJM # sp_func_class_paren = ignore # ignore/add/remove/force sp_func_class_paren = remove # ignore/add/remove/force # Add or remove space between 'return' and '(' sp_return_paren = ignore # ignore/add/remove/force # Add or remove space between '__attribute__' and '(' sp_attribute_paren = ignore # ignore/add/remove/force # Add or remove space between 'defined' and '(' in '#if defined (FOO)' sp_defined_paren = ignore # ignore/add/remove/force # Add or remove space between 'throw' and '(' in 'throw (something)' sp_throw_paren = ignore # ignore/add/remove/force # Add or remove space between 'throw' and anything other than '(' as in '@throw [...];' sp_after_throw = ignore # ignore/add/remove/force # Add or remove space between 'catch' and '(' in 'catch (something) { }' # If set to ignore, sp_before_sparen is used. sp_catch_paren = ignore # ignore/add/remove/force # Add or remove space between 'version' and '(' in 'version (something) { }' (D language) # If set to ignore, sp_before_sparen is used. sp_version_paren = ignore # ignore/add/remove/force # Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) # If set to ignore, sp_before_sparen is used. sp_scope_paren = ignore # ignore/add/remove/force # Add or remove space between macro and value sp_macro = ignore # ignore/add/remove/force # Add or remove space between macro function ')' and value sp_macro_func = ignore # ignore/add/remove/force # Add or remove space between 'else' and '{' if on the same line # DJM # sp_else_brace = ignore # ignore/add/remove/force sp_else_brace = add # ignore/add/remove/force # Add or remove space between '}' and 'else' if on the same line # DJM # sp_brace_else = ignore # ignore/add/remove/force sp_brace_else = add # ignore/add/remove/force # Add or remove space between '}' and the name of a typedef on the same line sp_brace_typedef = ignore # ignore/add/remove/force # Add or remove space between 'catch' and '{' if on the same line sp_catch_brace = ignore # ignore/add/remove/force # Add or remove space between '}' and 'catch' if on the same line sp_brace_catch = ignore # ignore/add/remove/force # Add or remove space between 'finally' and '{' if on the same line sp_finally_brace = ignore # ignore/add/remove/force # Add or remove space between '}' and 'finally' if on the same line sp_brace_finally = ignore # ignore/add/remove/force # Add or remove space between 'try' and '{' if on the same line sp_try_brace = ignore # ignore/add/remove/force # Add or remove space between get/set and '{' if on the same line sp_getset_brace = ignore # ignore/add/remove/force # Add or remove space between a variable and '{' for C++ uniform initialization sp_word_brace = add # ignore/add/remove/force # Add or remove space between a variable and '{' for a namespace sp_word_brace_ns = add # ignore/add/remove/force # Add or remove space before the '::' operator # DJM # sp_before_dc = ignore # ignore/add/remove/force sp_before_dc = remove # ignore/add/remove/force # Add or remove space after the '::' operator # DJM # sp_after_dc = ignore # ignore/add/remove/force sp_after_dc = remove # ignore/add/remove/force # Add or remove around the D named array initializer ':' operator sp_d_array_colon = ignore # ignore/add/remove/force # Add or remove space after the '!' (not) operator. Default=Remove sp_not = remove # ignore/add/remove/force # Add or remove space after the '~' (invert) operator. Default=Remove sp_inv = remove # ignore/add/remove/force # Add or remove space after the '&' (address-of) operator. Default=Remove # This does not affect the spacing after a '&' that is part of a type. sp_addr = remove # ignore/add/remove/force # Add or remove space around the '.' or '->' operators. Default=Remove sp_member = remove # ignore/add/remove/force # Add or remove space after the '*' (dereference) operator. Default=Remove # This does not affect the spacing after a '*' that is part of a type. sp_deref = remove # ignore/add/remove/force # Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove sp_sign = remove # ignore/add/remove/force # Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove sp_incdec = remove # ignore/add/remove/force # Add or remove space before a backslash-newline at the end of a line. Default=Add sp_before_nl_cont = add # ignore/add/remove/force # Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' sp_after_oc_scope = ignore # ignore/add/remove/force # Add or remove space after the colon in message specs # '-(int) f:(int) x;' vs '-(int) f: (int) x;' sp_after_oc_colon = ignore # ignore/add/remove/force # Add or remove space before the colon in message specs # '-(int) f: (int) x;' vs '-(int) f : (int) x;' sp_before_oc_colon = ignore # ignore/add/remove/force # Add or remove space after the colon in immutable dictionary expression # 'NSDictionary *test = @{@"foo" :@"bar"};' sp_after_oc_dict_colon = ignore # ignore/add/remove/force # Add or remove space before the colon in immutable dictionary expression # 'NSDictionary *test = @{@"foo" :@"bar"};' sp_before_oc_dict_colon = ignore # ignore/add/remove/force # Add or remove space after the colon in message specs # '[object setValue:1];' vs '[object setValue: 1];' sp_after_send_oc_colon = ignore # ignore/add/remove/force # Add or remove space before the colon in message specs # '[object setValue:1];' vs '[object setValue :1];' sp_before_send_oc_colon = ignore # ignore/add/remove/force # Add or remove space after the (type) in message specs # '-(int)f: (int) x;' vs '-(int)f: (int)x;' sp_after_oc_type = ignore # ignore/add/remove/force # Add or remove space after the first (type) in message specs # '-(int) f:(int)x;' vs '-(int)f:(int)x;' sp_after_oc_return_type = ignore # ignore/add/remove/force # Add or remove space between '@selector' and '(' # '@selector(msgName)' vs '@selector (msgName)' # Also applies to @protocol() constructs sp_after_oc_at_sel = ignore # ignore/add/remove/force # Add or remove space between '@selector(x)' and the following word # '@selector(foo) a:' vs '@selector(foo)a:' sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force # Add or remove space inside '@selector' parens # '@selector(foo)' vs '@selector( foo )' # Also applies to @protocol() constructs sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force # Add or remove space before a block pointer caret # '^int (int arg){...}' vs. ' ^int (int arg){...}' sp_before_oc_block_caret = ignore # ignore/add/remove/force # Add or remove space after a block pointer caret # '^int (int arg){...}' vs. '^ int (int arg){...}' sp_after_oc_block_caret = ignore # ignore/add/remove/force # Add or remove space between the receiver and selector in a message. # '[receiver selector ...]' sp_after_oc_msg_receiver = ignore # ignore/add/remove/force # Add or remove space after @property. sp_after_oc_property = ignore # ignore/add/remove/force # Add or remove space around the ':' in 'b ? t : f' #DJM # sp_cond_colon = ignore # ignore/add/remove/force sp_cond_colon = add # ignore/add/remove/force # Add or remove space before the ':' in 'b ? t : f'. Overrides sp_cond_colon. sp_cond_colon_before = ignore # ignore/add/remove/force # Add or remove space after the ':' in 'b ? t : f'. Overrides sp_cond_colon. sp_cond_colon_after = ignore # ignore/add/remove/force # Add or remove space around the '?' in 'b ? t : f' # DJM # sp_cond_question = ignore # ignore/add/remove/force sp_cond_question = add # ignore/add/remove/force # Add or remove space before the '?' in 'b ? t : f'. Overrides sp_cond_question. sp_cond_question_before = ignore # ignore/add/remove/force # Add or remove space after the '?' in 'b ? t : f'. Overrides sp_cond_question. sp_cond_question_after = ignore # ignore/add/remove/force # In the abbreviated ternary form (a ?: b), add/remove space between ? and :.'. Overrides all other sp_cond_* options. sp_cond_ternary_short = ignore # ignore/add/remove/force # Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. sp_case_label = ignore # ignore/add/remove/force # Control the space around the D '..' operator. sp_range = ignore # ignore/add/remove/force # Control the spacing after ':' in 'for (TYPE VAR : EXPR)' (Java) sp_after_for_colon = ignore # ignore/add/remove/force # Control the spacing before ':' in 'for (TYPE VAR : EXPR)' (Java) sp_before_for_colon = ignore # ignore/add/remove/force # Control the spacing in 'extern (C)' (D) sp_extern_paren = ignore # ignore/add/remove/force # Control the space after the opening of a C++ comment '// A' vs '//A' sp_cmt_cpp_start = ignore # ignore/add/remove/force # Controls the spaces between #else or #endif and a trailing comment sp_endif_cmt = ignore # ignore/add/remove/force # Controls the spaces after 'new', 'delete', and 'delete[]' sp_after_new = ignore # ignore/add/remove/force # Controls the spaces before a trailing or embedded comment sp_before_tr_emb_cmt = ignore # ignore/add/remove/force # Number of spaces before a trailing or embedded comment sp_num_before_tr_emb_cmt = 0 # number # Control space between a Java annotation and the open paren. sp_annotation_paren = ignore # ignore/add/remove/force # # Code alignment (not left column spaces/tabs) # # Whether to keep non-indenting tabs align_keep_tabs = false # false/true # Whether to use tabs for aligning align_with_tabs = false # false/true # Whether to bump out to the next tab when aligning align_on_tabstop = false # false/true # Whether to left-align numbers align_number_left = false # false/true # Whether to keep whitespace not required for alignment. align_keep_extra_space = false # false/true # Align variable definitions in prototypes and functions align_func_params = false # false/true # Align parameters in single-line functions that have the same name. # The function names must already be aligned with each other. align_same_func_call_params = false # false/true # The span for aligning variable definitions (0=don't align) align_var_def_span = 0 # number # How to align the star in variable definitions. # 0=Part of the type 'void * foo;' # 1=Part of the variable 'void *foo;' # 2=Dangling 'void *foo;' align_var_def_star_style = 0 # number # How to align the '&' in variable definitions. # 0=Part of the type # 1=Part of the variable # 2=Dangling align_var_def_amp_style = 0 # number # The threshold for aligning variable definitions (0=no limit) align_var_def_thresh = 0 # number # The gap for aligning variable definitions align_var_def_gap = 0 # number # Whether to align the colon in struct bit fields align_var_def_colon = false # false/true # Whether to align any attribute after the variable name align_var_def_attribute = false # false/true # Whether to align inline struct/enum/union variable definitions align_var_def_inline = false # false/true # The span for aligning on '=' in assignments (0=don't align) align_assign_span = 0 # number # The threshold for aligning on '=' in assignments (0=no limit) align_assign_thresh = 0 # number # The span for aligning on '=' in enums (0=don't align) align_enum_equ_span = 0 # number # The threshold for aligning on '=' in enums (0=no limit) align_enum_equ_thresh = 0 # number # The span for aligning struct/union (0=don't align) align_var_struct_span = 0 # number # The threshold for aligning struct/union member definitions (0=no limit) align_var_struct_thresh = 0 # number # The gap for aligning struct/union member definitions align_var_struct_gap = 0 # number # The span for aligning struct initializer values (0=don't align) align_struct_init_span = 0 # number # The minimum space between the type and the synonym of a typedef align_typedef_gap = 0 # number # The span for aligning single-line typedefs (0=don't align) align_typedef_span = 0 # number # How to align typedef'd functions with other typedefs # 0: Don't mix them at all # 1: align the open paren with the types # 2: align the function type name with the other type names align_typedef_func = 0 # number # Controls the positioning of the '*' in typedefs. Just try it. # 0: Align on typedef type, ignore '*' # 1: The '*' is part of type name: typedef int *pint; # 2: The '*' is part of the type, but dangling: typedef int *pint; align_typedef_star_style = 0 # number # Controls the positioning of the '&' in typedefs. Just try it. # 0: Align on typedef type, ignore '&' # 1: The '&' is part of type name: typedef int &pint; # 2: The '&' is part of the type, but dangling: typedef int &pint; align_typedef_amp_style = 0 # number # The span for aligning comments that end lines (0=don't align) align_right_cmt_span = 0 # number # If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment align_right_cmt_mix = false # false/true # If a trailing comment is more than this number of columns away from the text it follows, # it will qualify for being aligned. This has to be > 0 to do anything. align_right_cmt_gap = 0 # number # Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) align_right_cmt_at_col = 0 # number # The span for aligning function prototypes (0=don't align) align_func_proto_span = 0 # number # Minimum gap between the return type and the function name. align_func_proto_gap = 0 # number # Align function protos on the 'operator' keyword instead of what follows align_on_operator = false # false/true # Whether to mix aligning prototype and variable declarations. # If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. align_mix_var_proto = false # false/true # Align single-line functions with function prototypes, uses align_func_proto_span align_single_line_func = false # false/true # Aligning the open brace of single-line functions. # Requires align_single_line_func=true, uses align_func_proto_span align_single_line_brace = false # false/true # Gap for align_single_line_brace. align_single_line_brace_gap = 0 # number # The span for aligning ObjC msg spec (0=don't align) align_oc_msg_spec_span = 0 # number # Whether to align macros wrapped with a backslash and a newline. # This will not work right if the macro contains a multi-line comment. align_nl_cont = false # false/true # # Align macro functions and variables together align_pp_define_together = false # false/true # The minimum space between label and value of a preprocessor define align_pp_define_gap = 0 # number # The span for aligning on '#define' bodies (0=don't align, other=number of lines including comments between blocks) align_pp_define_span = 0 # number # Align lines that start with '<<' with previous '<<'. Default=true align_left_shift = true # false/true # Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) align_oc_msg_colon_span = 0 # number # If true, always align with the first parameter, even if it is too short. align_oc_msg_colon_first = false # false/true # Aligning parameters in an Obj-C '+' or '-' declaration on the ':' align_oc_decl_colon = false # false/true # # Newline adding and removing options # # Whether to collapse empty blocks between '{' and '}' nl_collapse_empty_body = false # false/true # Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' nl_assign_leave_one_liners = false # false/true # Don't split one-line braced statements inside a class xx { } body # DJM # nl_class_leave_one_liners = false # false/true nl_class_leave_one_liners = true # false/true # Don't split one-line enums: 'enum foo { BAR = 15 };' nl_enum_leave_one_liners = false # false/true # Don't split one-line get or set functions nl_getset_leave_one_liners = false # false/true # Don't split one-line function definitions - 'int foo() { return 0; }' nl_func_leave_one_liners = false # false/true # Don't split one-line C++11 lambdas - '[]() { return 0; }' nl_cpp_lambda_leave_one_liners = false # false/true # Don't split one-line if/else statements - 'if(a) b++;' nl_if_leave_one_liners = false # false/true # Don't split one-line OC messages nl_oc_msg_leave_one_liner = false # false/true # Add or remove newlines at the start of the file nl_start_of_file = ignore # ignore/add/remove/force # The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' nl_start_of_file_min = 0 # number # Add or remove newline at the end of the file nl_end_of_file = ignore # ignore/add/remove/force # The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') nl_end_of_file_min = 0 # number # Add or remove newline between '=' and '{' nl_assign_brace = ignore # ignore/add/remove/force # Add or remove newline between '=' and '[' (D only) nl_assign_square = ignore # ignore/add/remove/force # Add or remove newline after '= [' (D only). Will also affect the newline before the ']' nl_after_square_assign = ignore # ignore/add/remove/force # The number of blank lines after a block of variable definitions at the top of a function body # 0 = No change (default) nl_func_var_def_blk = 0 # number # The number of newlines before a block of typedefs # 0 = No change (default) nl_typedef_blk_start = 0 # number # The number of newlines after a block of typedefs # 0 = No change (default) nl_typedef_blk_end = 0 # number # The maximum consecutive newlines within a block of typedefs # 0 = No change (default) nl_typedef_blk_in = 0 # number # The number of newlines before a block of variable definitions not at the top of a function body # 0 = No change (default) nl_var_def_blk_start = 0 # number # The number of newlines after a block of variable definitions not at the top of a function body # 0 = No change (default) nl_var_def_blk_end = 0 # number # The maximum consecutive newlines within a block of variable definitions # 0 = No change (default) nl_var_def_blk_in = 0 # number # Add or remove newline between a function call's ')' and '{', as in: # list_for_each(item, &list) { } nl_fcall_brace = ignore # ignore/add/remove/force # Add or remove newline between 'enum' and '{' # DJM # nl_enum_brace = ignore # ignore/add/remove/force nl_enum_brace = remove # ignore/add/remove/force # Add or remove newline between 'struct and '{' # DJM # nl_struct_brace = ignore # ignore/add/remove/force nl_struct_brace = remove # ignore/add/remove/force # Add or remove newline between 'union' and '{' # DJM # nl_union_brace = ignore # ignore/add/remove/force nl_union_brace = remove # ignore/add/remove/force # Add or remove newline between 'if' and '{' # DJM # nl_if_brace = ignore # ignore/add/remove/force nl_if_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'else' # DJM # nl_brace_else = ignore # ignore/add/remove/force nl_brace_else = remove # ignore/add/remove/force # Add or remove newline between 'else if' and '{' # If set to ignore, nl_if_brace is used instead nl_elseif_brace = ignore # ignore/add/remove/force # Add or remove newline between 'else' and '{' # DJM # nl_else_brace = ignore # ignore/add/remove/force nl_else_brace = remove # ignore/add/remove/force # Add or remove newline between 'else' and 'if' nl_else_if = ignore # ignore/add/remove/force # Add or remove newline between '}' and 'finally' # DJM # nl_brace_finally = ignore # ignore/add/remove/force nl_brace_finally = remove # ignore/add/remove/force # Add or remove newline between 'finally' and '{' # DJM # nl_finally_brace = ignore # ignore/add/remove/force nl_finally_brace = remove # ignore/add/remove/force # Add or remove newline between 'try' and '{' # DJM # nl_try_brace = ignore # ignore/add/remove/force nl_try_brace = remove # ignore/add/remove/force # Add or remove newline between get/set and '{' # DJM # nl_getset_brace = ignore # ignore/add/remove/force nl_getset_brace = remove # ignore/add/remove/force # Add or remove newline between 'for' and '{' # DJM # nl_for_brace = ignore # ignore/add/remove/force nl_for_brace = remove # ignore/add/remove/force # Add or remove newline between 'catch' and '{' # DJM # nl_catch_brace = ignore # ignore/add/remove/force nl_catch_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'catch' # DJM # nl_brace_catch = ignore # ignore/add/remove/force nl_brace_catch = remove # ignore/add/remove/force # Add or remove newline between '}' and ']' nl_brace_square = ignore # ignore/add/remove/force # Add or remove newline between '}' and ')' in a function invocation nl_brace_fparen = ignore # ignore/add/remove/force # Add or remove newline between 'while' and '{' # DJM # nl_while_brace = ignore # ignore/add/remove/force nl_while_brace = remove # ignore/add/remove/force # Add or remove newline between 'scope (x)' and '{' (D) nl_scope_brace = ignore # ignore/add/remove/force # Add or remove newline between 'unittest' and '{' (D) nl_unittest_brace = ignore # ignore/add/remove/force # Add or remove newline between 'version (x)' and '{' (D) nl_version_brace = ignore # ignore/add/remove/force # Add or remove newline between 'using' and '{' nl_using_brace = ignore # ignore/add/remove/force # Add or remove newline between two open or close braces. # Due to general newline/brace handling, REMOVE may not work. nl_brace_brace = ignore # ignore/add/remove/force # Add or remove newline between 'do' and '{' # DJM # nl_do_brace = ignore # ignore/add/remove/force nl_do_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'while' of 'do' statement # DJM # nl_brace_while = ignore # ignore/add/remove/force nl_brace_while = remove # ignore/add/remove/force # Add or remove newline between 'switch' and '{' # DJM # nl_switch_brace = ignore # ignore/add/remove/force nl_switch_brace = remove # ignore/add/remove/force # Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. # Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. nl_multi_line_cond = false # false/true # Force a newline in a define after the macro name for multi-line defines. nl_multi_line_define = false # false/true # Whether to put a newline before 'case' statement # DJM # nl_before_case = false # false/true nl_before_case = true # false/true # Add or remove newline between ')' and 'throw' nl_before_throw = ignore # ignore/add/remove/force # Whether to put a newline after 'case' statement nl_after_case = false # false/true # Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. nl_case_colon_brace = ignore # ignore/add/remove/force # Newline between namespace and { # DJM # nl_namespace_brace = ignore # ignore/add/remove/force nl_namespace_brace = remove # ignore/add/remove/force # Add or remove newline between 'template<>' and whatever follows. nl_template_class = ignore # ignore/add/remove/force # Add or remove newline between 'class' and '{' # DJM # nl_class_brace = ignore # ignore/add/remove/force nl_class_brace = remove # ignore/add/remove/force # Add or remove newline after each ',' in the class base list nl_class_init_args = ignore # ignore/add/remove/force # Add or remove newline after each ',' in the constructor member initialization nl_constr_init_args = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a function definition # DJM # nl_func_type_name = ignore # ignore/add/remove/force nl_func_type_name = remove # ignore/add/remove/force # Add or remove newline between return type and function name inside a class {} # Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. # DJM # nl_func_type_name_class = ignore # ignore/add/remove/force nl_func_type_name_class = remove # ignore/add/remove/force # Add or remove newline between function scope and name in a definition # Controls the newline after '::' in 'void A::f() { }' nl_func_scope_name = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a prototype # DJM # nl_func_proto_type_name = ignore # ignore/add/remove/force nl_func_proto_type_name = remove # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' # DJM # nl_func_paren = ignore # ignore/add/remove/force nl_func_paren = remove # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the definition # DJM # nl_func_def_paren = ignore # ignore/add/remove/force nl_func_def_paren = remove # ignore/add/remove/force # Add or remove newline after '(' in a function declaration nl_func_decl_start = ignore # ignore/add/remove/force # Add or remove newline after '(' in a function definition nl_func_def_start = ignore # ignore/add/remove/force # Overrides nl_func_decl_start when there is only one parameter. nl_func_decl_start_single = ignore # ignore/add/remove/force # Overrides nl_func_def_start when there is only one parameter. nl_func_def_start_single = ignore # ignore/add/remove/force # Add or remove newline after each ',' in a function declaration nl_func_decl_args = ignore # ignore/add/remove/force # Add or remove newline after each ',' in a function definition nl_func_def_args = ignore # ignore/add/remove/force # Add or remove newline before the ')' in a function declaration nl_func_decl_end = ignore # ignore/add/remove/force # Add or remove newline before the ')' in a function definition nl_func_def_end = ignore # ignore/add/remove/force # Overrides nl_func_decl_end when there is only one parameter. nl_func_decl_end_single = ignore # ignore/add/remove/force # Overrides nl_func_def_end when there is only one parameter. nl_func_def_end_single = ignore # ignore/add/remove/force # Add or remove newline between '()' in a function declaration. nl_func_decl_empty = ignore # ignore/add/remove/force # Add or remove newline between '()' in a function definition. nl_func_def_empty = ignore # ignore/add/remove/force # Whether to put each OC message parameter on a separate line # See nl_oc_msg_leave_one_liner nl_oc_msg_args = false # false/true # Add or remove newline between function signature and '{' nl_fdef_brace = ignore # ignore/add/remove/force # Add or remove newline between C++11 lambda signature and '{' nl_cpp_ldef_brace = ignore # ignore/add/remove/force # Add or remove a newline between the return keyword and return expression. nl_return_expr = ignore # ignore/add/remove/force # Whether to put a newline after semicolons, except in 'for' statements nl_after_semicolon = false # false/true # Java: Control the newline between the ')' and '{{' of the double brace initializer. nl_paren_dbrace_open = ignore # ignore/add/remove/force # Whether to put a newline after brace open. # This also adds a newline before the matching brace close. nl_after_brace_open = false # false/true # If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is # placed between the open brace and a trailing single-line comment. nl_after_brace_open_cmt = false # false/true # Whether to put a newline after a virtual brace open with a non-empty body. # These occur in un-braced if/while/do/for statement bodies. nl_after_vbrace_open = false # false/true # Whether to put a newline after a virtual brace open with an empty body. # These occur in un-braced if/while/do/for statement bodies. nl_after_vbrace_open_empty = false # false/true # Whether to put a newline after a brace close. # Does not apply if followed by a necessary ';'. nl_after_brace_close = false # false/true # Whether to put a newline after a virtual brace close. # Would add a newline before return in: 'if (foo) a++; return;' nl_after_vbrace_close = false # false/true # Control the newline between the close brace and 'b' in: 'struct { int a; } b;' # Affects enums, unions, and structures. If set to ignore, uses nl_after_brace_close nl_brace_struct_var = ignore # ignore/add/remove/force # Whether to alter newlines in '#define' macros nl_define_macro = false # false/true # Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' nl_squeeze_ifdef = false # false/true # Add or remove blank line before 'if' nl_before_if = ignore # ignore/add/remove/force # Add or remove blank line after 'if' statement nl_after_if = ignore # ignore/add/remove/force # Add or remove blank line before 'for' nl_before_for = ignore # ignore/add/remove/force # Add or remove blank line after 'for' statement nl_after_for = ignore # ignore/add/remove/force # Add or remove blank line before 'while' nl_before_while = ignore # ignore/add/remove/force # Add or remove blank line after 'while' statement nl_after_while = ignore # ignore/add/remove/force # Add or remove blank line before 'switch' nl_before_switch = ignore # ignore/add/remove/force # Add or remove blank line after 'switch' statement nl_after_switch = ignore # ignore/add/remove/force # Add or remove blank line before 'do' nl_before_do = ignore # ignore/add/remove/force # Add or remove blank line after 'do/while' statement nl_after_do = ignore # ignore/add/remove/force # Whether to double-space commented-entries in struct/enum nl_ds_struct_enum_cmt = false # false/true # Whether to double-space before the close brace of a struct/union/enum # (lower priority than 'eat_blanks_before_close_brace') nl_ds_struct_enum_close_brace = false # false/true # Add or remove a newline around a class colon. # Related to pos_class_colon, nl_class_init_args, and pos_class_comma. nl_class_colon = ignore # ignore/add/remove/force # Add or remove a newline around a class constructor colon. # Related to pos_constr_colon, nl_constr_init_args, and pos_constr_comma. nl_constr_colon = ignore # ignore/add/remove/force # Change simple unbraced if statements into a one-liner # 'if(b)\n i++;' => 'if(b) i++;' nl_create_if_one_liner = false # false/true # Change simple unbraced for statements into a one-liner # 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' nl_create_for_one_liner = false # false/true # Change simple unbraced while statements into a one-liner # 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' nl_create_while_one_liner = false # false/true # # Positioning options # # The position of arithmetic operators in wrapped expressions pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of assignment in wrapped expressions. # Do not affect '=' followed by '{' pos_assign = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of boolean operators in wrapped expressions pos_bool = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of comparison operators in wrapped expressions pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of conditional (b ? t : f) operators in wrapped expressions pos_conditional = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of the comma in wrapped expressions pos_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of the comma in the class base list pos_class_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of the comma in the constructor initialization list pos_constr_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of colons between class and base class list pos_class_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of colons between constructor and member initialization pos_constr_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force # # Line Splitting options # # Try to limit code width to N number of columns code_width = 0 # number # Whether to fully split long 'for' statements at semi-colons ls_for_split_full = false # false/true # Whether to fully split long function protos/calls at commas ls_func_split_full = false # false/true # Whether to split lines as close to code_width as possible and ignore some groupings ls_code_width = false # false/true # # Blank line options # # The maximum consecutive newlines nl_max = 0 # number # The number of newlines after a function prototype, if followed by another function prototype nl_after_func_proto = 0 # number # The number of newlines after a function prototype, if not followed by another function prototype nl_after_func_proto_group = 0 # number # The number of newlines after '}' of a multi-line function body nl_after_func_body = 0 # number # The number of newlines after '}' of a multi-line function body in a class declaration nl_after_func_body_class = 0 # number # The number of newlines after '}' of a single line function body nl_after_func_body_one_liner = 0 # number # The minimum number of newlines before a multi-line comment. # Doesn't apply if after a brace open or another multi-line comment. nl_before_block_comment = 0 # number # The minimum number of newlines before a single-line C comment. # Doesn't apply if after a brace open or other single-line C comments. nl_before_c_comment = 0 # number # The minimum number of newlines before a CPP comment. # Doesn't apply if after a brace open or other CPP comments. nl_before_cpp_comment = 0 # number # Whether to force a newline after a multi-line comment. nl_after_multiline_comment = false # false/true # The number of newlines after '}' or ';' of a struct/enum/union definition nl_after_struct = 0 # number # The number of newlines after '}' or ';' of a class definition nl_after_class = 0 # number # The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. # Will not change the newline count if after a brace open. # 0 = No change. nl_before_access_spec = 0 # number # The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. # 0 = No change. nl_after_access_spec = 0 # number # The number of newlines between a function def and the function comment. # 0 = No change. nl_comment_func_def = 0 # number # The number of newlines after a try-catch-finally block that isn't followed by a brace close. # 0 = No change. nl_after_try_catch_finally = 0 # number # The number of newlines before and after a property, indexer or event decl. # 0 = No change. nl_around_cs_property = 0 # number # The number of newlines between the get/set/add/remove handlers in C#. # 0 = No change. nl_between_get_set = 0 # number # Add or remove newline between C# property and the '{' nl_property_brace = ignore # ignore/add/remove/force # Whether to remove blank lines after '{' eat_blanks_after_open_brace = false # false/true # Whether to remove blank lines before '}' eat_blanks_before_close_brace = false # false/true # How aggressively to remove extra newlines not in preproc. # 0: No change # 1: Remove most newlines not handled by other config # 2: Remove all newlines and reformat completely by config nl_remove_extra_newlines = 0 # number # Whether to put a blank line before 'return' statements, unless after an open brace. nl_before_return = false # false/true # Whether to put a blank line after 'return' statements, unless followed by a close brace. nl_after_return = false # false/true # Whether to put a newline after a Java annotation statement. # Only affects annotations that are after a newline. nl_after_annotation = ignore # ignore/add/remove/force # Controls the newline between two annotations. nl_between_annotation = ignore # ignore/add/remove/force # # Code modifying options (non-whitespace) # # Add or remove braces on single-line 'do' statement mod_full_brace_do = ignore # ignore/add/remove/force # Add or remove braces on single-line 'for' statement mod_full_brace_for = ignore # ignore/add/remove/force # Add or remove braces on single-line function definitions. (Pawn) mod_full_brace_function = ignore # ignore/add/remove/force # Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. # GLN # mod_full_brace_if = ignore # ignore/add/remove/force mod_full_brace_if = add # ignore/add/remove/force # Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. # If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. mod_full_brace_if_chain = false # false/true # Don't remove braces around statements that span N newlines mod_full_brace_nl = 0 # number # Add or remove braces on single-line 'while' statement mod_full_brace_while = ignore # ignore/add/remove/force # Add or remove braces on single-line 'using ()' statement mod_full_brace_using = ignore # ignore/add/remove/force # Add or remove unnecessary paren on 'return' statement mod_paren_on_return = ignore # ignore/add/remove/force # Whether to change optional semicolons to real semicolons mod_pawn_semicolon = false # false/true # Add parens on 'while' and 'if' statement around bools mod_full_paren_if_bool = false # false/true # Whether to remove superfluous semicolons mod_remove_extra_semicolon = false # false/true # If a function body exceeds the specified number of newlines and doesn't have a comment after # the close brace, a comment will be added. mod_add_long_function_closebrace_comment = 0 # number # If a namespace body exceeds the specified number of newlines and doesn't have a comment after # the close brace, a comment will be added. mod_add_long_namespace_closebrace_comment = 0 # number # If a switch body exceeds the specified number of newlines and doesn't have a comment after # the close brace, a comment will be added. mod_add_long_switch_closebrace_comment = 0 # number # If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after # the #endif, a comment will be added. mod_add_long_ifdef_endif_comment = 0 # number # If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after # the #else, a comment will be added. mod_add_long_ifdef_else_comment = 0 # number # If TRUE, will sort consecutive single-line 'import' statements [Java, D] mod_sort_import = false # false/true # If TRUE, will sort consecutive single-line 'using' statements [C#] mod_sort_using = false # false/true # If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] # This is generally a bad idea, as it may break your code. mod_sort_include = false # false/true # If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. mod_move_case_break = false # false/true # Will add or remove the braces around a fully braced case statement. # Will only remove the braces if there are no variable declarations in the block. mod_case_brace = ignore # ignore/add/remove/force # If TRUE, it will remove a void 'return;' that appears as the last statement in a function. mod_remove_empty_return = false # false/true # # Comment modifications # # Try to wrap comments at cmt_width columns cmt_width = 0 # number # Set the comment reflow mode (default: 0) # 0: no reflowing (apart from the line wrapping due to cmt_width) # 1: no touching at all # 2: full reflow cmt_reflow_mode = 0 # number # Whether to convert all tabs to spaces in comments. Default is to leave tabs inside comments alone, unless used for indenting. cmt_convert_tab_to_spaces = false # false/true # If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. # Default is true. cmt_indent_multi = true # false/true # Whether to group c-comments that look like they are in a block cmt_c_group = false # false/true # Whether to put an empty '/*' on the first line of the combined c-comment cmt_c_nl_start = false # false/true # Whether to put a newline before the closing '*/' of the combined c-comment cmt_c_nl_end = false # false/true # Whether to group cpp-comments that look like they are in a block cmt_cpp_group = false # false/true # Whether to put an empty '/*' on the first line of the combined cpp-comment cmt_cpp_nl_start = false # false/true # Whether to put a newline before the closing '*/' of the combined cpp-comment cmt_cpp_nl_end = false # false/true # Whether to change cpp-comments into c-comments cmt_cpp_to_c = false # false/true # Whether to put a star on subsequent comment lines cmt_star_cont = false # false/true # The number of spaces to insert at the start of subsequent comment lines cmt_sp_before_star_cont = 0 # number # The number of spaces to insert after the star on subsequent comment lines # DJM # cmt_sp_after_star_cont = 0 # number cmt_sp_after_star_cont = 1 # number # For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of # the comment are the same length. Default=True # DJM # cmt_multi_check_last = true # false/true cmt_multi_check_last = false # false/true # The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. # Will substitute $(filename) with the current file's name. cmt_insert_file_header = "" # string # The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. # Will substitute $(filename) with the current file's name. cmt_insert_file_footer = "" # string # The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. # Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. # Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } cmt_insert_func_header = "" # string # The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. # Will substitute $(class) with the class name. cmt_insert_class_header = "" # string # The filename that contains text to insert before a Obj-C message specification if the method isn't preceded with a C/C++ comment. # Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. cmt_insert_oc_msg_header = "" # string # If a preprocessor is encountered when stepping backwards from a function name, then # this option decides whether the comment should be inserted. # Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. cmt_insert_before_preproc = false # false/true # # Preprocessor options # # Control indent of preprocessors inside #if blocks at brace level 0 (file-level) pp_indent = ignore # ignore/add/remove/force # Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) pp_indent_at_level = false # false/true # Specifies the number of columns to indent preprocessors per level at brace level 0 (file-level). # If pp_indent_at_level=false, specifies the number of columns to indent preprocessors per level at brace level > 0 (function-level). # Default=1. pp_indent_count = 1 # number # Add or remove space after # based on pp_level of #if blocks pp_space = ignore # ignore/add/remove/force # Sets the number of spaces added with pp_space pp_space_count = 0 # number # The indent for #region and #endregion in C# and '#pragma region' in C/C++ pp_indent_region = 0 # number # Whether to indent the code between #region and #endregion pp_region_indent_code = false # false/true # If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level. # 0: indent preprocessors using output_tab_size. # >0: column at which all preprocessors will be indented. pp_indent_if = 0 # number # Control whether to indent the code between #if, #else and #endif. pp_if_indent_code = false # false/true # Whether to indent '#define' at the brace level (true) or from column 1 (false) pp_define_at_level = false # false/true # You can force a token to be a type with the 'type' option. # Example: # type myfoo1 myfoo2 # # You can create custom macro-based indentation using macro-open, # macro-else and macro-close. # Example: # macro-open BEGIN_TEMPLATE_MESSAGE_MAP # macro-open BEGIN_MESSAGE_MAP # macro-close END_MESSAGE_MAP # # You can assign any keyword to any type with the set option. # set func_call_user _ N_ # # The full syntax description of all custom definition config entries # is shown below: # # define custom tokens as: # - embed whitespace in token using '' escape character, or # put token in quotes # - these: ' " and ` are recognized as quote delimiters # # type token1 token2 token3 ... # ^ optionally specify multiple tokens on a single line # define def_token output_token # ^ output_token is optional, then NULL is assumed # macro-open token # macro-close token # macro-else token # set id token1 token2 ... # ^ optionally specify multiple tokens on a single line # ^ id is one of the names in token_enum.h sans the CT_ prefix, # e.g. PP_PRAGMA # # all tokens are separated by any mix of ',' commas, '=' equal signs # and whitespace (space, tab) # # You can add support for other file extensions using the 'file_ext' command. # The first arg is the language name used with the '-l' option. # The remaining args are file extensions, matched with 'endswith'. # file_ext CPP .ch .cxx .cpp.in # ajtcl-16.04/tools/whitespace.py000066400000000000000000000311541271074662300165030ustar00rootroot00000000000000#!/usr/bin/python # Copyright AllSeen Alliance. All rights reserved. # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # import sys, os, fnmatch, re, filecmp, difflib, textwrap import hashlib, pickle, time from subprocess import Popen, STDOUT, PIPE whitespacedb = '.whitespace.db' def main(argv = None): start_time = time.clock() dir_ignore = ["build", "dist", ".git", ".repo", "external", ".sconf_temp" ] file_ignore_patterns = ['\.#.*'] file_patterns = ['*.c', '*.h', '*.cpp', '*.cc', '*.ino'] valid_commands = ["check", "detail", "fix", "off"] uncrustify_config = None required_uncrustify_version = "0.61" unc_suffix = ".uncrustify" wscfg = None xit = 0 sha_hash = hashlib.sha1() whitespace_db = {} whitespace_db_updated = False run_ws_check = True uncfile = None # Try to load the whitespace.db file. The file is dictionary of key:value # pairs where the key is the name of a file that has been checked by the WS # checker and the value is a sha1 blob calculated for the file. specified # for the key if the key is not found (i.e. a new file or first time this # script has been run) then the key will be added. If the file fails the WS # check it will be removed from the dictionary. If the file is new or the # calculated hash has changed the WS checker will check the file to see if # it complies with the WS rules. if os.path.exists(whitespacedb): f = open(whitespacedb, 'r') try: whitespace_db = pickle.load(f) except pickle.UnpicklingError: os.remove(whitespacedb) finally: f.close() if argv is None: argv=[] if len(argv) > 0: wscmd = argv[0] else: wscmd = valid_commands[0] if len(argv) > 1: wscfg = os.path.normpath(argv[1]) if wscmd not in valid_commands: print "\'" + wscmd + "\'" + " is not a valid command" print_help() sys.exit(2) # If config specified in command line then use that, otherwise search for it if wscfg: uncrustify_config = wscfg else: uncrustify_config = find_config() # Cannot find config file if not uncrustify_config: print "Unable to find a config file" print_help() sys.exit(2) # Specified config file is invalid if not os.path.isfile(uncrustify_config): print uncrustify_config + " does not exist or is not a file" print_help() sys.exit(2) #Verify uncrustify install and version version = get_uncrustify_version() if version != required_uncrustify_version: print ("You are using uncrustify v" + version + ". You must be using uncrustify v" + required_uncrustify_version ) print "(Or, run SCons with 'WS=off' to bypass the whitespace check)" sys.exit(2) if wscmd == 'off': return 0 # Get a list of source files and apply uncrustify to them for srcfile in locate(file_patterns, file_ignore_patterns, dir_ignore): f = open(srcfile, 'rb') uncfile = None filesize = os.path.getsize(srcfile) sha_digest = None try: # Compute the sha tag for the file the same way as git computes sha # tags this prevents whitespace changes being ignored. sha_hash.update("blob %u\0" % filesize) sha_hash.update(f.read()) sha_digest = sha_hash.hexdigest() finally: f.close() if sha_digest != None: try: if whitespace_db[srcfile] == sha_digest: run_ws_check = False else: whitespace_db[srcfile] = sha_digest run_ws_check = True whitespace_db_updated = True except KeyError: whitespace_db[srcfile] = sha_digest run_ws_check = True whitespace_db_updated = True if run_ws_check: uncfile = srcfile + unc_suffix # Run uncrustify and generate uncrustify output file p = Popen( [ "uncrustify", "-c", uncrustify_config, srcfile, ], stdout=PIPE, stderr=STDOUT ) output = p.communicate()[0] if p.returncode: print "error exit, uncrustify -c %s %s" % ( uncrustify_config, srcfile ) print output print "whitespace check is not complete" del whitespace_db[srcfile] xit=2 break # check command if wscmd == valid_commands[0]: # If the src file and the uncrustify file are different # then print the filename if not filecmp.cmp(srcfile, uncfile, False): print srcfile del whitespace_db[srcfile] xit=1 # detail command if wscmd == valid_commands[1]: # If the src file and the uncrustify file are different # then diff the files if not filecmp.cmp(srcfile, uncfile, False): print '' print '******** FILE: ' + srcfile print '' print '******** BEGIN DIFF ********' fromlines = open(srcfile, 'U').readlines() tolines = open(uncfile, 'U').readlines() diff = difflib.unified_diff(fromlines, tolines, n=0) sys.stdout.writelines(diff) print '' print '********* END DIFF *********' print '' del whitespace_db[srcfile] xit=1 # fix command if wscmd == valid_commands[2]: # If the src file and the uncrustify file are different # then print the filename so that the user can see what will # be fixed if not filecmp.cmp(srcfile, uncfile, False): print srcfile del whitespace_db[srcfile] # run uncrustify again and overwrite the non-compliant file with # the uncrustify output p = Popen( [ "uncrustify", "-c", uncrustify_config, "--no-backup", srcfile, ], stdout=PIPE, stderr=STDOUT ) output = p.communicate()[0] if p.returncode: print "error exit, uncrustify -c %s --no-backup %s" % ( uncrustify_config, srcfile ) print output print "whitespace check is not complete" del whitespace_db[srcfile] xit=2 break # remove the uncrustify output file if os.path.exists(uncfile): try: os.remove(uncfile) except OSError: print "Unable to remove uncrustify output file: " + uncfile # end srcfile loop if uncfile and os.path.exists(uncfile): try: os.remove(uncfile) except OSError: print "Unable to remove uncrustify output file: " + uncfile # write the whitespace_db to a file so it is avalible next time the whitespace # checker is run. if whitespace_db_updated: try: f = open(whitespacedb, 'w') try: pickle.dump(whitespace_db, f) finally: f.close() except IOError: pass return xit # Return the uncrustify version number def get_uncrustify_version( ): version = None try: # run the uncrustify version command output = Popen(["uncrustify", "-v"], stdout=PIPE).communicate()[0] except OSError: # OSError probably indicates that uncrustify is not installed, # so bail after printing helpful message print ("It appears that \'uncrustify\' is not installed or is not " + "on your PATH. Please check your system and try again.") print "(Or, run SCons with 'WS=off' to bypass the whitespace check)" sys.exit(2) else: # extract version from output string p = re.compile('^uncrustify (\d.\d{2})') m = re.search(p, output) version = m.group(1) return version # Command line argument help def print_help( ): prog = 'whitespace.py' print textwrap.dedent('''usage: %(prog)s [-h] [command] [uncrustify config] Apply uncrustify to C++ source files (.c, .h, .cc, .cpp), recursively, from the present working directory. Skips 'stlport', 'build', 'alljoyn_objc', 'ios', 'external', '.git', and '.repo' directories. Note: present working directory is presumed to be within, or the parent of, one of the AllJoyn archives. Script will automatically locate the uncrustify config file in build_core, or alternatively, the user may specify one. Enables users to see which source files are not in compliance with the AllJoyn whitespace policy and fix them as follows: check - prints list of non-compliant files (default) detail - prints diff of non-compliant files fix - modifies (fixes) non-compliant files Note that all files generated by uncrustify are removed. positional arguments: command options: check(default) | detail | fix uncrustify config specify an alternative uncrustify config (default=none) optional arguments: -h, --help show this help message and exit Examples: Get a list of non-compliant files using the alljoyn uncrustify config: >python %(prog)s --OR-- >python %(prog)s check Get a list of non-compliant files using your own uncrustify config: >python %(prog)s check r'myconfig.cfg' (note: use raw string) Get a diff of non-compliant files using the alljoyn uncrustify config: >python %(prog)s detail Fix non-compliant files using the alljoyn uncrustify config: >python %(prog)s fix''' % { 'prog': prog } ) # Search for the uncrustify config file def find_config( ): tgtdir = "build_core" cfgname = "ajuncrustify.cfg" ajcfgrelpath = os.path.join(tgtdir, "tools", "conf", cfgname) ajcfgpath = None foundit = 0 DIRDEPTHMAX = 6 # Limit directory search to depth DIRDEPTHMAX curdir = os.path.abspath(os.curdir) for i in range(DIRDEPTHMAX): if tgtdir in os.listdir(curdir): foundit = 1 break else: curdir = os.path.abspath(os.path.join(curdir, "..")) if foundit == 1 and os.path.exists(os.path.join(curdir, ajcfgrelpath)): ajcfgpath = os.path.join(curdir, ajcfgrelpath) return ajcfgpath # Recurse through directories and locate files that match a given pattern def locate(file_patterns, file_ignore_patterns, dir_ignore_patterns, root=os.curdir): for path, dirs, files in os.walk(os.path.abspath(root)): # Remove unwanted dirs for dip in dir_ignore_patterns: for dyr in dirs: if dyr == dip: dirs.remove(dyr) # Remove unwanted files files_dict = {} for filename in files: files_dict[filename] = True for filename in files: for fip in file_ignore_patterns: if re.search(fip, filename) != None: del files_dict[filename] # Collect the filtered list filtered_files = [] for filename in files_dict.keys(): filtered_files.append(filename) # Filter the remainder using our wanted file pattern list for pattern in file_patterns: for filename in fnmatch.filter(filtered_files, pattern): yield os.path.join(path, filename) if __name__ == "__main__": if len(sys.argv) > 1: sys.exit(main(sys.argv[1:])) else: sys.exit(main()) #end ajtcl-16.04/unit_test/000077500000000000000000000000001271074662300146475ustar00rootroot00000000000000ajtcl-16.04/unit_test/.gitignore000066400000000000000000000000251271074662300166340ustar00rootroot00000000000000ajtcltest libgtest.a ajtcl-16.04/unit_test/ARDPTest.cc000066400000000000000000000145251271074662300165530ustar00rootroot00000000000000/****************************************************************************** * * * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #ifdef AJ_ARDP #include #include #include #include #define ARDP_FLAG_SYN 0x01 /**< Control flag. Request to open a connection. Must be separate segment. */ #define ARDP_FLAG_ACK 0x02 /**< Control flag. Acknowledge a segment. May accompany message */ #define ARDP_FLAG_EACK 0x04 /**< Control flag. Non-cumulative (extended) acknowledgement */ #define ARDP_FLAG_RST 0x08 /**< Control flag. Reset this connection. Must be separate segment. */ #define ARDP_FLAG_NUL 0x10 /**< Control flag. Null (zero-length) segment. Must have zero data length */ #define ARDP_FLAG_VER 0x40 /**< Control flag. Bits 6-7 of flags byte. Current version is (1) */ #define ARDP_FLAG_SDM 0x0001 /**< Sequenced delivery mode option. Indicates in-order sequence delivery is in force. */ #define ARDP_SYN_HEADER_SIZE 28 #define FLAGS_OFFSET 0 #define HLEN_OFFSET 1 #define SRC_OFFSET 2 #define DST_OFFSET 4 #define DLEN_OFFSET 6 #define SEQ_OFFSET 8 #define ACK_OFFSET 12 #define TTL_OFFSET 16 #define LCS_OFFSET 20 #define ACKNXT_OFFSET 24 #define SOM_OFFSET 28 #define FCNT_OFFSET 32 #define RSRV_OFFSET 34 #define SEGMAX_OFFSET 16 #define SEGBMAX_OFFSET 18 #define DACKT_OFFSET 20 #define OPTIONS_OFFSET 24 #define SYN_RSRV_OFFSET 26 static const char TestHelloData[] = "HELLO"; static enum { Connecting = 0, Connected = 1, Disconnecting = 2 } State; static uint16_t local_port; static uint8_t ConnectedResponse[] = { ARDP_FLAG_SYN | ARDP_FLAG_ACK | ARDP_FLAG_VER, // flags 0x0E, // HLEN 0x00, 0x00, // local port 0xFF, 0xFF, // remote port 0x00, 0x06, // DLEN 0x00, 0x00, 0x00, 0x00, // SEQ 0x00, 0x00, 0x00, 0x00, // ACK 0x00, 0x5D, // segmax == 93 0x11, 0x58, // segbmax == 4400 0x00, 0x00, 0x00, 0x64, // 100 == ack timeout 0x00, 0x01, // options 0x00, 0x00, // padding? 'H', 'E', 'L', 'L', 'O', '\0' }; static AJ_Status AJ_ARDP_UDP_Send(void* context, uint8_t* txbuf, size_t len, size_t* sent, uint8_t confirm) { switch (State) { case Connecting: EXPECT_EQ(*(txbuf + 0), ARDP_FLAG_SYN | ARDP_FLAG_VER); EXPECT_EQ(*(txbuf + HLEN_OFFSET), ARDP_SYN_HEADER_SIZE >> 1); local_port = ntohs(*((uint16_t*) (txbuf + SRC_OFFSET))); EXPECT_EQ(*((uint16_t*) (txbuf + DST_OFFSET)), 0); EXPECT_EQ(*((uint16_t*) (txbuf + DLEN_OFFSET)), htons(sizeof(TestHelloData))); // we will need to acknowledge the response memcpy(ConnectedResponse + ACK_OFFSET, txbuf + SEQ_OFFSET, sizeof(uint32_t)); EXPECT_EQ(*((uint32_t*) (txbuf + ACK_OFFSET)), 0); EXPECT_EQ(*((uint16_t*) (txbuf + SEGMAX_OFFSET)), htons(UDP_SEGMAX)); EXPECT_EQ(*((uint16_t*) (txbuf + SEGBMAX_OFFSET)), htons(UDP_SEGBMAX)); EXPECT_EQ(*((uint32_t*) (txbuf + DACKT_OFFSET)), htonl(UDP_DELAYED_ACK_TIMEOUT)); EXPECT_EQ(*((uint16_t*) (txbuf + OPTIONS_OFFSET)), htons(ARDP_FLAG_SIMPLE_MODE | ARDP_FLAG_SDM)); EXPECT_EQ(*((uint16_t*) (txbuf + SYN_RSRV_OFFSET)), 0); EXPECT_EQ(len, sizeof(TestHelloData) + ARDP_SYN_HEADER_SIZE); EXPECT_TRUE(0 == memcmp(txbuf + ARDP_SYN_HEADER_SIZE, TestHelloData, sizeof(TestHelloData))); State = Connected; break; case Connected: // now check the ack going back out EXPECT_EQ(*(txbuf + 0), ARDP_FLAG_ACK | ARDP_FLAG_VER); EXPECT_EQ(*(txbuf + HLEN_OFFSET), 18); EXPECT_EQ(*((uint16_t*) (txbuf + SRC_OFFSET)), htons(local_port)); EXPECT_EQ(*((uint16_t*) (txbuf + DST_OFFSET)), 0); break; case Disconnecting: EXPECT_EQ(*(txbuf + FLAGS_OFFSET), (ARDP_FLAG_RST | ARDP_FLAG_ACK | ARDP_FLAG_VER)); EXPECT_EQ(*(txbuf + HLEN_OFFSET), (uint8_t)(ARDP_HEADER_SIZE >> 1)); EXPECT_EQ(*((uint16_t*) (txbuf + DLEN_OFFSET)), 0); EXPECT_EQ(*((uint32_t*) (txbuf + TTL_OFFSET)), ARDP_TTL_INFINITE); EXPECT_EQ(*((uint32_t*) (txbuf + SOM_OFFSET)), 0); EXPECT_EQ(*((uint16_t*) (txbuf + FCNT_OFFSET)), 0); EXPECT_EQ(*((uint16_t*) (txbuf + RSRV_OFFSET)), 0); break; } *sent = len; return AJ_OK; } static AJ_Status AJ_ARDP_UDP_Recv(void* context, uint8_t** data, uint32_t* recved, uint32_t timeout) { *data = ConnectedResponse; *recved = sizeof(ConnectedResponse); return AJ_OK; } class ARDPTest : public testing::Test { public: virtual void SetUp() { AJ_ARDP_InitFunctions(&AJ_ARDP_UDP_Recv, &AJ_ARDP_UDP_Send); } virtual void TearDown() { } }; void SendBackConnected() { uint8_t rxData[1024]; AJ_Status status; AJ_IOBuffer buf; *((uint16_t*) (ConnectedResponse + DST_OFFSET)) = htons(local_port); AJ_IOBufInit(&buf, rxData, sizeof(rxData), AJ_IO_BUF_RX, NULL); status = AJ_ARDP_Recv(&buf, sizeof(rxData), 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); EXPECT_TRUE(0 == memcmp(TestHelloData, buf.readPtr, sizeof(TestHelloData))); } TEST_F(ARDPTest, TestSynAck) { State = Connecting; AJ_Status status = AJ_ARDP_Connect((uint8_t*) TestHelloData, sizeof(TestHelloData), NULL, NULL); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); // simulate an accepted connect request SendBackConnected(); // now maybe do some send and receive State = Disconnecting; AJ_ARDP_Disconnect(TRUE); } #endif ajtcl-16.04/unit_test/BusAttachmentTest.cc000066400000000000000000000223071271074662300205640ustar00rootroot00000000000000/****************************************************************************** * * * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include extern "C" { #include #include } static const char* serviceName = "org.alljoyn.thinclient.test.theoffice"; static const uint16_t servicePort = 1984; // The expectation is that there is a daemon running on the same machine. // Hence, we should be able to discover and connect to it within 1.5 seconds. static const uint16_t connectTimeout = 1500; // We expect to receive replies very quickly from the local daemon. static const uint16_t unmarshalTimeout = 250; static AJ_BusAttachment testBus; class BusAttachmentTest : public testing::Test { public: virtual void SetUp() { AJ_Status status = AJ_ERR_FAILURE; AJ_Initialize(); // Connect to the bus status = AJ_FindBusAndConnect(&testBus, NULL, connectTimeout); // No point in continuing with any further tests, if we // cannot connect to the daemon. So ASSERT. ASSERT_EQ(AJ_OK, status) << "Unable to connect to the daemon. " << "The status returned is " << AJ_StatusText(status); if (AJ_OK == status) { AJ_AlwaysPrintf(("Connected to the bus. The unique name is %s\n", AJ_GetUniqueName(&testBus))); } } virtual void TearDown() { // Disconnect from the bus AJ_Disconnect(&testBus); } }; // Helper function to test: RequestName and ReleaseName apis. // It returns the 'disposition' in the reply to the method call. uint32_t RequestReleaseNameTestHelper(const uint32_t method, const char* name, const uint32_t flags) { // Initialized to an invalid value // (valid values are 1, 2, 3, 4 - See DBus spec) uint32_t returnValue = 0; AJ_Status status = AJ_ERR_FAILURE; switch (method) { case AJ_METHOD_REQUEST_NAME: status = AJ_BusRequestName(&testBus, name, flags); EXPECT_EQ(AJ_OK, status) << "Call to AJ_BusRequestName was not successful " << "when invoked with name: " << name << " and flags 0x" << std::hex << flags << ". Got status " << AJ_StatusText(status); break; case AJ_METHOD_RELEASE_NAME: status = AJ_BusReleaseName(&testBus, name); EXPECT_EQ(AJ_OK, status) << "Call to AJ_BusReleaseName was not successful " << "when invoked with name: " << name << ". Got status " << AJ_StatusText(status); break; } // Given the message loop nature of the code, we need to wait // until we get a reply for the call that we made and then check // that result. We could get other notifications from // the bus during this wait. // However, we don't want to wait indefinitely and hence we // need some kind of a time out. // Also once we get what we are waiting for, there is no point // in waiting any further. bool yetToReceiveReplyInterestedIn = true; AJ_Time timer; AJ_InitTimer(&timer); const uint16_t loopTimeoutValue = 500; // five hundred milliseconds while (yetToReceiveReplyInterestedIn && AJ_GetElapsedTime(&timer, TRUE) < loopTimeoutValue) { AJ_Message msg; status = AJ_UnmarshalMsg(&testBus, &msg, unmarshalTimeout); EXPECT_EQ(AJ_OK, status) << "Unable to unmarshal a message with in " << unmarshalTimeout << "ms. Got status " << AJ_StatusText(status); if (AJ_OK != status) { // No point continuing the test if we are unable to unmarshal. break; } uint32_t disposition = 0; switch (msg.msgId) { case AJ_REPLY_ID(AJ_METHOD_REQUEST_NAME): EXPECT_EQ(AJ_MSG_METHOD_RET, msg.hdr->msgType) << "The response to RequestName method " << "call was not a method return."; status = AJ_UnmarshalArgs(&msg, "u", &disposition); EXPECT_EQ(AJ_OK, status) << "Unable to unmarshal args from " << "RequestName reply msg."; returnValue = disposition; yetToReceiveReplyInterestedIn = false; break; case AJ_REPLY_ID(AJ_METHOD_RELEASE_NAME): EXPECT_EQ(AJ_MSG_METHOD_RET, msg.hdr->msgType) << "The response to ReleaseName method " << "call was not a method return."; status = AJ_UnmarshalArgs(&msg, "u", &disposition); EXPECT_EQ(AJ_OK, status) << "Unable to unmarshal args from " << "ReleaseName reply msg."; returnValue = disposition; yetToReceiveReplyInterestedIn = false; break; default: // Any other message sent from the bus should be handled // as a bus message. status = AJ_BusHandleBusMessage(&msg); EXPECT_EQ(AJ_OK, status) << "The bus message was not handled " << "correctly. Got status " << AJ_StatusText(status); break; } status = AJ_CloseMsg(&msg); EXPECT_EQ(AJ_OK, status) << "Unable to close message. Got status " << AJ_StatusText(status); } return returnValue; } static const uint32_t DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1; static const uint32_t DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2; static const uint32_t DBUS_REQUEST_NAME_REPLY_EXISTS = 3; static const uint32_t DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4; TEST_F(BusAttachmentTest, RequestName) { // Request names that are already taken EXPECT_EQ(DBUS_REQUEST_NAME_REPLY_IN_QUEUE, RequestReleaseNameTestHelper(AJ_METHOD_REQUEST_NAME, AJ_DBusDestination, AJ_NAME_REQ_REPLACE_EXISTING)) << "Did not get 'in queue' while requesting an already existing name: " << AJ_DBusDestination; EXPECT_EQ(DBUS_REQUEST_NAME_REPLY_EXISTS, RequestReleaseNameTestHelper(AJ_METHOD_REQUEST_NAME, AJ_BusDestination, AJ_NAME_REQ_ALLOW_REPLACEMENT | AJ_NAME_REQ_DO_NOT_QUEUE)) << "Did not get 'name already exists' while requesting an already existing name: " << AJ_BusDestination; // Request a new name that is not taken uint32_t disposition = RequestReleaseNameTestHelper(AJ_METHOD_REQUEST_NAME, serviceName, 0x0); EXPECT_EQ(DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER, disposition) << "Unable to request a well-known name: " << serviceName; if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER == disposition) { // Request the same name again EXPECT_EQ(DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER, RequestReleaseNameTestHelper(AJ_METHOD_REQUEST_NAME, serviceName, 0x0)) << "Did not get 'name already owner' while requesting an already requested name:" << serviceName; } } static const uint32_t DBUS_RELEASE_NAME_REPLY_RELEASED = 1; static const uint32_t DBUS_RELEASE_NAME_REPLY_NON_EXISTENT = 2; static const uint32_t DBUS_RELEASE_NAME_REPLY_NOT_OWNER = 3; TEST_F(BusAttachmentTest, ReleaseName) { // Release a non-existent name const char* nonExistentName = "org.freeedesktop.DBus"; EXPECT_EQ(DBUS_RELEASE_NAME_REPLY_NON_EXISTENT, RequestReleaseNameTestHelper(AJ_METHOD_RELEASE_NAME, nonExistentName, 0x0)) << "Did not get 'name non existent' when tried to release the name: " << nonExistentName; // Release a name for which we are not an owner EXPECT_EQ(DBUS_RELEASE_NAME_REPLY_NOT_OWNER, RequestReleaseNameTestHelper(AJ_METHOD_RELEASE_NAME, AJ_BusDestination, 0x0)) << "Did not get 'name not owner' when tried to release the name: " << AJ_BusDestination; // Request and Release a unique name uint32_t disposition = RequestReleaseNameTestHelper(AJ_METHOD_REQUEST_NAME, serviceName, 0x0); EXPECT_EQ(DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER, disposition) << "Unable to request a well-known name: " << serviceName; if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER == disposition) { // release the name EXPECT_EQ(DBUS_RELEASE_NAME_REPLY_RELEASED, RequestReleaseNameTestHelper(AJ_METHOD_RELEASE_NAME, serviceName, 0x0)) << "Unable to release the well-known name: " << serviceName; } } ajtcl-16.04/unit_test/DiscoveryTest.cc000066400000000000000000000274111271074662300177720ustar00rootroot00000000000000/****************************************************************************** * * * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include extern "C" { #include #include } class DiscoveryTest : public testing::Test { public: virtual void SetUp() { AJ_Initialize(); } virtual void TearDown() { } }; TEST_F(DiscoveryTest, DiscoverValidBusNodeName) { // Attempt to discover a valid bus node name that is being advertised. AJ_Service service; AJ_Service newService = { 0, 0, 0, 0, 0x0100007f, 1234, 0, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&newService); AJ_Status status = AJ_Discover("org.alljoyn.BusNode", &service, 5000, 5000); AJ_InitRoutingNodeResponselist(); EXPECT_EQ(AJ_OK, status) << "Unable to discover routing node. Got status " << AJ_StatusText(status); } TEST_F(DiscoveryTest, DiscoverInValidBusNodeName) { // Attempt to discover an invalid bus node name that is not being advertised. AJ_Service service; AJ_InitRoutingNodeResponselist(); AJ_Status status = AJ_Discover("org.alljoyn.BusNodezzzz", &service, 5000, 5000); EXPECT_EQ(AJ_ERR_TIMEOUT, status) << "Able to discover invalid routing node. Got status " << AJ_StatusText(status); } TEST_F(DiscoveryTest, SelectPriority) { // Select between two routing nodes with different priorities. AJ_Service service; AJ_Service serviceHighScore = { 0, 0, 0, 0, 0x0100007f, 1234, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowScore = { 0, 0, 0, 0, 0x0200007f, 5678, 0, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceHighScore); AJ_AddRoutingNodeToResponseList(&serviceLowScore); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceHighScore.priority, service.priority) << "Wrong priority selected from the response list"; EXPECT_EQ(serviceHighScore.ipv4, service.ipv4) << "Wrong ipv4 address selected from the response list"; } TEST_F(DiscoveryTest, UpdatePriority) { // Select between two routing nodes with different priorities. AJ_Service service; AJ_Service serviceHighScore = { 0, 0, 0, 0, 0x0100007f, 1234, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowScore = { 0, 0, 0, 0, 0x0100007f, 5678, 0, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceLowScore); AJ_AddRoutingNodeToResponseList(&serviceHighScore); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceHighScore.priority, service.priority) << "Priority not updated in response list"; } TEST_F(DiscoveryTest, SelectProtocolVersion) { // Select between two routing nodes with different protocol versions. AJ_Service service; AJ_Service serviceOldProtocol = { 0, 0, 0, 0, 0x0100007f, 0, 11, { 0, 0, 0, 0 } }; AJ_Service serviceNewProtocol = { 0, 0, 0, 0, 0x0200007f, 5678, 12, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceOldProtocol); AJ_AddRoutingNodeToResponseList(&serviceNewProtocol); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceNewProtocol.priority, service.priority) << "Wrong priority selected from the response list"; EXPECT_EQ(serviceNewProtocol.ipv4, service.ipv4) << "Wrong priority selected from the response list"; } TEST_F(DiscoveryTest, UpdateProtocolVersion) { // Select between two routing nodes with different protocol versions. AJ_Service service; AJ_Service serviceOldProtocol = { 0, 0, 0, 0, 0x0100007f, 1234, 11, { 0, 0, 0, 0 } }; AJ_Service serviceNewProtocol = { 0, 0, 0, 0, 0x0100007f, 5678, 12, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceOldProtocol); AJ_AddRoutingNodeToResponseList(&serviceNewProtocol); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceNewProtocol.priority, service.priority) << "Priority not updated in the response list"; EXPECT_EQ(serviceNewProtocol.pv, service.pv) << "Protocol version not updated in the response list"; EXPECT_EQ(serviceNewProtocol.ipv4, service.ipv4) << "Wrong priority selected from the response list"; } TEST_F(DiscoveryTest, ExhaustSelection) { // Select from the response list until there are no more responses available. AJ_Service service; AJ_Service serviceHighScore = { 0, 0, 0, 0, 0x0100007f, 1234, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowScore = { 0, 0, 0, 0, 0x0200007f, 5678, 0, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceHighScore); AJ_AddRoutingNodeToResponseList(&serviceLowScore); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); status = AJ_SelectRoutingNodeFromResponseList(&service); status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_ERR_END_OF_DATA, status) << "Response list was not exhausted after all nodes were selected"; } TEST_F(DiscoveryTest, SelectPriorityListFullVarious) { // Select correct routing node after adding best priority to a list that is full of various priorities AJ_Service service; AJ_Service serviceHigherScore = { 0, 0, 0, 0, 0x0100007f, 1234, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore1 = { 0, 0, 0, 0, 0x0200007f, 2345, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore2 = { 0, 0, 0, 0, 0x0300007f, 3456, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore3 = { 0, 0, 0, 0, 0x0400007f, 4567, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore4 = { 0, 0, 0, 0, 0x0500007f, 5678, 0, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceLowerScore2); AJ_AddRoutingNodeToResponseList(&serviceLowerScore3); AJ_AddRoutingNodeToResponseList(&serviceLowerScore4); AJ_AddRoutingNodeToResponseList(&serviceLowerScore1); AJ_AddRoutingNodeToResponseList(&serviceHigherScore); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceHigherScore.ipv4, service.ipv4) << "Wrong ipv4 address selected from the response list"; } TEST_F(DiscoveryTest, SelectPriorityListFullEqual) { // Select correct routing node after adding best priority to a list that is full of equal priorities AJ_Service service; AJ_Service serviceHigherScore = { 0, 0, 0, 0, 0x0100007f, 1234, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore1 = { 0, 0, 0, 0, 0x0200007f, 5678, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore2 = { 0, 0, 0, 0, 0x0300007f, 5678, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore3 = { 0, 0, 0, 0, 0x0400007f, 5678, 0, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceLowerScore2); AJ_AddRoutingNodeToResponseList(&serviceLowerScore3); AJ_AddRoutingNodeToResponseList(&serviceLowerScore1); AJ_AddRoutingNodeToResponseList(&serviceHigherScore); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceHigherScore.ipv4, service.ipv4) << "Wrong ipv4 address selected from the response list"; } TEST_F(DiscoveryTest, SelectPriorityListFullDoNotEvict) { // Select correct routing node after attempting to add lesser score to a list that is full of various priorities AJ_Service service; AJ_Service serviceHigherScore = { 0, 0, 0, 0, 0x0100007f, 1234, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore1 = { 0, 0, 0, 0, 0x0200007f, 2345, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore2 = { 0, 0, 0, 0, 0x0300007f, 3456, 0, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore3 = { 0, 0, 0, 0, 0x0400007f, 4567, 0, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceLowerScore2); AJ_AddRoutingNodeToResponseList(&serviceLowerScore1); AJ_AddRoutingNodeToResponseList(&serviceHigherScore); AJ_AddRoutingNodeToResponseList(&serviceLowerScore3); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceHigherScore.ipv4, service.ipv4) << "Wrong ipv4 address selected from the response list"; } TEST_F(DiscoveryTest, SelectProtocolVersionListFullEqual) { // Select correct routing node after adding better protocol version to a list that is full of equal protocol versi AJ_Service service; AJ_Service serviceHigherScore = { 0, 0, 0, 0, 0x0100007f, 6789, 12, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore1 = { 0, 0, 0, 0, 0x0200007f, 5678, 11, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore2 = { 0, 0, 0, 0, 0x0300007f, 5678, 11, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore3 = { 0, 0, 0, 0, 0x0400007f, 5678, 11, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceLowerScore2); AJ_AddRoutingNodeToResponseList(&serviceLowerScore3); AJ_AddRoutingNodeToResponseList(&serviceLowerScore1); AJ_AddRoutingNodeToResponseList(&serviceHigherScore); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceHigherScore.ipv4, service.ipv4) << "Wrong ipv4 address selected from the response list"; } TEST_F(DiscoveryTest, SelectProtocolVersionPriorityListFullEqual) { // Select correct routing node after adding better protocol version and priority to a list that is full of equal protocol versi AJ_Service service; AJ_Service serviceHigherScore = { 0, 0, 0, 0, 0x0100007f, 1234, 12, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore1 = { 0, 0, 0, 0, 0x0200007f, 5678, 11, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore2 = { 0, 0, 0, 0, 0x0300007f, 5678, 11, { 0, 0, 0, 0 } }; AJ_Service serviceLowerScore3 = { 0, 0, 0, 0, 0x0400007f, 5678, 11, { 0, 0, 0, 0 } }; AJ_InitRoutingNodeResponselist(); AJ_AddRoutingNodeToResponseList(&serviceLowerScore2); AJ_AddRoutingNodeToResponseList(&serviceLowerScore3); AJ_AddRoutingNodeToResponseList(&serviceLowerScore1); AJ_AddRoutingNodeToResponseList(&serviceHigherScore); AJ_Status status = AJ_SelectRoutingNodeFromResponseList(&service); EXPECT_EQ(AJ_OK, status) << "Unable to select any routing node from the response list "; EXPECT_EQ(serviceHigherScore.ipv4, service.ipv4) << "Wrong ipv4 address selected from the response list"; } ajtcl-16.04/unit_test/MutterTest.cc000066400000000000000000001475141271074662300173120ustar00rootroot00000000000000/** * @file Marhal/Unmarshal Unit Test */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include extern "C" { #include #include #include #include #include #ifndef NDEBUG extern AJ_MutterHook MutterHook; #endif } static uint8_t wireBuffer[16 * 1024]; static size_t wireBytes = 0; static uint8_t txBuffer[1024]; static uint8_t rxBuffer[1024]; static AJ_Status TxFunc(AJ_IOBuffer* buf) { size_t tx = AJ_IO_BUF_AVAIL(buf);; if ((wireBytes + tx) > sizeof(wireBuffer)) { return AJ_ERR_WRITE; } else { memcpy(wireBuffer + wireBytes, buf->bufStart, tx); AJ_IO_BUF_RESET(buf); wireBytes += tx; return AJ_OK; } } AJ_Status RxFunc(AJ_IOBuffer* buf, uint32_t len, uint32_t timeout) { size_t rx = AJ_IO_BUF_SPACE(buf); rx = min(len, rx); rx = min(wireBytes, rx); if (!rx) { return AJ_ERR_READ; } else { memcpy(buf->writePtr, wireBuffer, rx); /* * Shuffle the remaining data to the front of the buffer */ memmove(wireBuffer, wireBuffer + rx, wireBytes - rx); wireBytes -= rx; buf->writePtr += rx; return AJ_OK; } } static const uint32_t ZERO_SECONDS = 0; // Array of test signatures // Each test case will use a particular index into this array // to get the message signature. static const char* testSignature[] = { "a{us}", "u(usu(ii)qsq)yyy", "a(usay)", "aas", "ivi", "v", "v", "(vvvv)", "uqay", "a(uuuu)", "a(sss)", "ya{ss}", "yyyyya{ys}" }; #ifndef NDEBUG static AJ_Status MsgInit(AJ_Message* msg, uint32_t msgId, uint8_t msgType) { msg->objPath = "/test/mutter"; msg->iface = "test.mutter"; msg->member = "mumble"; msg->msgId = msgId; msg->signature = testSignature[msgId]; return AJ_OK; } #endif static const char* const Fruits[] = { "apple", "banana", "cherry", "durian", "elderberry", "fig", "grape" }; static const char* const Colors[] = { "azure", "blue", "cyan", "dun", "ecru" }; static const uint8_t Data8[] = { 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xA1, 0xB1, 0xC2, 0xD3 }; static const uint16_t Data16[] = { 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06 }; // Variables common to all tests static AJ_BusAttachment testBus; static AJ_Message txMsg; static AJ_Message rxMsg; static AJ_Arg arg; static AJ_Arg array1; static AJ_Arg array2; static AJ_Arg struct1; static AJ_Arg struct2; class MutterTest : public testing::Test { public: virtual void SetUp() { /* random offset for the buffer to force different alignments */ uint8_t random_offset = 0; AJ_RandBytes(&random_offset, 1); random_offset = random_offset % 8; std::cout << "\tINFO: The random offset for this test is " << (unsigned int) random_offset << std::endl; testBus.sock.tx.direction = AJ_IO_BUF_TX; testBus.sock.tx.bufSize = sizeof(txBuffer) - random_offset; testBus.sock.tx.bufStart = txBuffer + random_offset; testBus.sock.tx.readPtr = txBuffer; testBus.sock.tx.writePtr = txBuffer; testBus.sock.tx.send = TxFunc; testBus.sock.rx.direction = AJ_IO_BUF_RX; testBus.sock.rx.bufSize = sizeof(rxBuffer); testBus.sock.rx.bufStart = rxBuffer; testBus.sock.rx.readPtr = rxBuffer; testBus.sock.rx.writePtr = rxBuffer; testBus.sock.rx.recv = RxFunc; /* * MutterTest doesn't connect to an actual daemon. * Hence, to ensure that we don't fail the header validation checks, * manually set the unique name of the Bus. */ const size_t lengthOfShortGUID = 16; strncpy(testBus.uniqueName, "DummyNaaaame.N1", lengthOfShortGUID); #ifndef NDEBUG MutterHook = MsgInit; #endif } virtual void TearDown() { #ifndef NDEBUG MutterHook = NULL; #endif } }; typedef struct { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } MutterTestStruct; TEST_F(MutterTest, ArrayofDict) { AJ_Status status = AJ_ERR_FAILURE; //Index of "a{us}" in testSignature[] is 0 status = AJ_MarshalSignal(&testBus, &txMsg, 0, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t key = 0; key < ArraySize(Fruits); ++key) { AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "us", key, Fruits[key]); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &dict); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } if (AJ_OK == status) { status = AJ_MarshalCloseContainer(&txMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { uint32_t key; status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t i = 0; i < ArraySize(Fruits); ++i) { char* fruit; AJ_Arg dict; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "us", &key, &fruit); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal[%d] = %s\n", key, fruit)); status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } AJ_Arg dict; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status); /* * We expect AJ_ERR_NO_MORE */ if (status == AJ_ERR_NO_MORE) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, BasicTypesAndNestedStruct) { uint32_t u; uint32_t v; int32_t n; int32_t m; uint16_t q; uint16_t r; uint8_t y; char* str; AJ_Status status = AJ_ERR_FAILURE; //Index of "u(usu(ii)qsq)yyy" in testSignature[] is 1 status = AJ_MarshalSignal(&testBus, &txMsg, 1, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalArgs(&txMsg, "u", 11111); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "usu", 22222, "hello", 33333); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalContainer(&txMsg, &struct2, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "ii", -100, -200); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &struct2); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "qsq", 4444, "goodbye", 5555); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "yyy", 1, 2, 3); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalArgs(&rxMsg, "u", &u); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "usu", &u, &str, &v); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalContainer(&rxMsg, &struct2, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "ii", &n, &m); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct2); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "qsq", &q, &str, &r); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "y", &y); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "y", &y); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "y", &y); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, ArrayOfStructofBasicTypeStringandByteArray) { char* str; AJ_Status status = AJ_ERR_FAILURE; //Index of "a(usay)" in testSignature[] is 2 status = AJ_MarshalSignal(&testBus, &txMsg, 2, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t u = 0; u < ArraySize(Fruits); ++u) { status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "us", u, Fruits[u]); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_BYTE, AJ_ARRAY_FLAG, Data8, u)); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } if (AJ_OK == status) { status = AJ_MarshalCloseContainer(&txMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { uint32_t u; status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); for (uint32_t i = 0; i < ArraySize(Fruits); ++i) { status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "us", &u, &str); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArg(&rxMsg, &arg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); } /* * We expect AJ_ERR_NO_MORE */ status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_ERR_NO_MORE == status) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, ArrayOfArrayofString) { uint32_t count = 3; AJ_Status status = AJ_ERR_FAILURE; //Index of "aas" in testSignature[] is 3 status = AJ_MarshalSignal(&testBus, &txMsg, 3, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t j = 0; j < count; ++j) { status = AJ_MarshalContainer(&txMsg, &array2, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t k = j; k < ArraySize(Fruits); ++k) { status = AJ_MarshalArgs(&txMsg, "s", Fruits[k]); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_MarshalCloseContainer(&txMsg, &array2); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } if (AJ_OK == status) { status = AJ_MarshalCloseContainer(&txMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t j = 0; j < count; ++j) { status = AJ_UnmarshalContainer(&rxMsg, &array2, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t k = j; k < ArraySize(Fruits); ++k) { status = AJ_UnmarshalArg(&rxMsg, &arg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %s\n", arg.val.v_string)); } /* * We expect AJ_ERR_NO_MORE */ status = AJ_UnmarshalArg(&rxMsg, &arg); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_ERR_NO_MORE == status) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array2); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } /* * We expect AJ_ERR_NO_MORE */ status = AJ_UnmarshalContainer(&rxMsg, &array2, AJ_ARG_ARRAY); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_ERR_NO_MORE == status) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, IntegerandVariant) { char* sig; uint32_t count = 16; AJ_Status status = AJ_ERR_FAILURE; //Index of "ivi" in testSignature[] is 4 status = AJ_MarshalSignal(&testBus, &txMsg, 4, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalArgs(&txMsg, "i", 987654321); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "a(ii)"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t i = 0; i < count; ++i) { status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "ii", i + 1, (i + 1) * 100); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } if (AJ_OK == status) { status = AJ_MarshalCloseContainer(&txMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_MarshalArgs(&txMsg, "i", 123456789); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { uint32_t k; uint32_t l; status = AJ_UnmarshalArgs(&rxMsg, "i", &k); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %d\n", k)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (uint32_t i = 0; i < count; ++i) { status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "ii", &k, &l); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal[%d] %d\n", k, l)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } /* * We expect AJ_ERR_NO_MORE */ status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_ERR_NO_MORE == status) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "i", &k); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %d\n", k)); } status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, StructofInteger_VariantandInteger) { char* str; char* sig; uint32_t j; AJ_Status status = AJ_ERR_FAILURE; //Index of "v" in testSignature[] is 5 status = AJ_MarshalSignal(&testBus, &txMsg, 5, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalVariant(&txMsg, "(ivi)"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "i", 1212121); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "s"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "s", "inner variant"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "i", 3434343); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArgs(&rxMsg, "i", &j); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "s", &str); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %s\n", str)); status = AJ_UnmarshalArgs(&rxMsg, "i", &j); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, DeepVariant) { char* str; char* sig; AJ_Status status = AJ_ERR_FAILURE; //Index of "v" in testSignature[] is 6 status = AJ_MarshalSignal(&testBus, &txMsg, 6, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalVariant(&txMsg, "v"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "v"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "v"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "v"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "s"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "s", "deep variant"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "s", &str); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %s\n", str)); status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, StructofVariants) { char* str; char* sig; uint32_t j; AJ_Status status = AJ_ERR_FAILURE; //Index of "(vvvv)" in testSignature[] is 7 status = AJ_MarshalSignal(&testBus, &txMsg, 7, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalContainer(&txMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "i"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "i", 1212121); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "s"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArgs(&txMsg, "s", "variant"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "ay"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_BYTE, AJ_ARRAY_FLAG, Data8, sizeof(Data8))); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalVariant(&txMsg, "aq"); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalArg(&txMsg, AJ_InitArg(&arg, AJ_ARG_UINT16, AJ_ARRAY_FLAG, Data16, sizeof(Data16))); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalContainer(&rxMsg, &struct1, AJ_ARG_STRUCT); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "i", &j); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal %d\n", j)); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArgs(&rxMsg, "s", &str); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArg(&rxMsg, &arg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalVariant(&rxMsg, (const char**)&sig); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); AJ_AlwaysPrintf(("Unmarshal variant %s\n", sig)); status = AJ_UnmarshalArg(&rxMsg, &arg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalCloseContainer(&rxMsg, &struct1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, IntegerandArrayofInteger) { uint32_t len; uint32_t j; uint16_t q; void* raw; size_t sz; AJ_Status status = AJ_ERR_FAILURE; //Index of "uqay" in testSignature[] is 8 status = AJ_MarshalSignal(&testBus, &txMsg, 8, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalArgs(&txMsg, "uq", 0xF00F00F00, 0x070707); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); len = 5000; status = AJ_DeliverMsgPartial(&txMsg, len + 4); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalRaw(&txMsg, &len, 4); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (j = 0; j < len; ++j) { uint8_t n = (uint8_t)j; status = AJ_MarshalRaw(&txMsg, &n, 1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalArgs(&rxMsg, "uq", &j, &q); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, sizeof(len), &sz); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); len = *((uint32_t*)raw); for (j = 0; j < len; ++j) { uint8_t v; status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, 1, &sz); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); v = *((uint8_t*)raw); EXPECT_EQ(v, (uint8_t)j); } status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, ArrayOfStructs) { void* raw; size_t sz; AJ_Status status = AJ_ERR_FAILURE; //Index of "a(uuuu)" in testSignature[] is 9 status = AJ_MarshalSignal(&testBus, &txMsg, 9, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { size_t len = 500; uint32_t u = len * sizeof(MutterTestStruct); status = AJ_DeliverMsgPartial(&txMsg, u + sizeof(u) + 4); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalRaw(&txMsg, &u, sizeof(u)); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); /* * Structs are always 8 byte aligned */ u = 0; status = AJ_MarshalRaw(&txMsg, &u, 4); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (size_t j = 0; j < len; ++j) { MutterTestStruct ts; ts.a = j; ts.b = j + 1; ts.c = j + 2; ts.d = j + 3; status = AJ_MarshalRaw(&txMsg, &ts, sizeof(ts)); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, 4, &sz); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); len = *((uint32_t*)raw) / sizeof(MutterTestStruct); /* * Structs are always 8 byte aligned */ status = AJ_UnmarshalRaw(&rxMsg, (const void**)&raw, 4, &sz); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); for (size_t j = 0; j < len; ++j) { MutterTestStruct* ts; status = AJ_UnmarshalRaw(&rxMsg, (const void**)&ts, sizeof(MutterTestStruct), &sz); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); // Check the contents of the struct EXPECT_EQ(j, ts->a); EXPECT_EQ((j + 1), ts->b); EXPECT_EQ((j + 2), ts->c); EXPECT_EQ((j + 3), ts->d); } status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, ArrayOfStructofStrings) { AJ_Status status = AJ_ERR_FAILURE; //Index of "a(sss)" in testSignature[] is 10 status = AJ_MarshalSignal(&testBus, &txMsg, 10, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_MarshalCloseContainer(&txMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); status = AJ_UnmarshalArg(&rxMsg, &arg); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status); /* * We expect AJ_ERR_NO_MORE */ if (AJ_ERR_NO_MORE == status) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); } } } TEST_F(MutterTest, ByteAndDictionaryEntries) { AJ_Status status = AJ_ERR_FAILURE; //Index of "ya{ss}" in testSignature[] is 11 status = AJ_MarshalSignal(&testBus, &txMsg, 11, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { uint8_t in_byte = 0; AJ_RandBytes(&in_byte, 1); status = AJ_MarshalArgs(&txMsg, "y", in_byte); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal a byte into the message."; status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal array start into the message."; for (size_t key = 0; key < ArraySize(Colors); key++) { AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal dict start."; status = AJ_MarshalArgs(&txMsg, "ss", Colors[key], Fruits[key]); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal key-value pair."; status = AJ_MarshalCloseContainer(&txMsg, &dict); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal dict end."; } status = AJ_MarshalCloseContainer(&txMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal array end into the message."; status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to deliver message."; status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal message."; uint8_t out_byte = 0; status = AJ_UnmarshalArgs(&rxMsg, "y", &out_byte); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal a byte from the message."; if (AJ_OK == status) { /* The value that was marshaled must match the unmarshaled */ EXPECT_EQ(in_byte, out_byte) << "A byte was marshaled and " << "unmarshaled back. The unmarshaled value " << out_byte << " does NOT match the marshaled value " << in_byte; } status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal the start of array " << "from the message."; for (size_t key = 0; key < ArraySize(Colors); key++) { AJ_Arg dict; char* fruit; char* color; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal dict start."; status = AJ_UnmarshalArgs(&rxMsg, "ss", &color, &fruit); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal key-value pair."; if (AJ_OK == status) { /* verify that what was marshaled in, is unmarshaled out */ EXPECT_STREQ(Colors[key], color) << "The key of dictionary " << "element was marshaled in and" << "unmarshaled out. The unmarshaled " << "value " << color << " does NOT " << "match the marshaled value " << Colors[key]; EXPECT_STREQ(Fruits[key], fruit) << "The value of dictionary " << "element was marshaled in and " << "unmarshaled out. The unmarshaled " << "value " << fruit << " does NOT " << "match the marshaled value " << Fruits[key]; } status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal dict end."; } /* * Now that we have unmarshaled all the entries, there should be * NO MORE */ AJ_Arg dict; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status) << ". After unmarshaling all the dictionary " << "entries, we expect that there are " << "no more entries."; if (AJ_ERR_NO_MORE == status) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal end of the array " << "from the message."; status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to close the message."; } } } TEST_F(MutterTest, MultipleBytesAndDictionaryEntries) { AJ_Status status = AJ_ERR_FAILURE; //Index of "yyyyya{ys}" in testSignature[] is 12 status = AJ_MarshalSignal(&testBus, &txMsg, 12, "mutter.service", 0, 0, 0); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status); if (AJ_OK == status) { /* Marshal five random byte values */ uint8_t in_bytes[5]; AJ_RandBytes(in_bytes, ArraySize(in_bytes)); for (uint8_t i = 0; i < ArraySize(in_bytes); i++) { status = AJ_MarshalArgs(&txMsg, "y", in_bytes[i]); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal a byte into the message."; } status = AJ_MarshalContainer(&txMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal array start into the message."; for (size_t key = 0; key < ArraySize(Colors); key++) { AJ_Arg dict; status = AJ_MarshalContainer(&txMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal dict start."; status = AJ_MarshalArgs(&txMsg, "ys", key, Colors[key]); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal key-value pair."; status = AJ_MarshalCloseContainer(&txMsg, &dict); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal dict end."; } status = AJ_MarshalCloseContainer(&txMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to marshal array end into the message."; status = AJ_DeliverMsg(&txMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to deliver message."; status = AJ_UnmarshalMsg(&testBus, &rxMsg, ZERO_SECONDS); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal message."; for (uint8_t i = 0; i < ArraySize(in_bytes); i++) { uint8_t out_byte = 0; status = AJ_UnmarshalArgs(&rxMsg, "y", &out_byte); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal a byte from the message."; if (AJ_OK == status) { /* The value that was marshaled must match the unmarshaled */ EXPECT_EQ(in_bytes[i], out_byte) << "A byte was marshaled and " << "unmarshaled back. The unmarshaled value " << out_byte << " does NOT match the marshaled value " << in_bytes[i]; } } status = AJ_UnmarshalContainer(&rxMsg, &array1, AJ_ARG_ARRAY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal the start of array " << "from the message."; for (size_t key = 0; key < ArraySize(Colors); key++) { AJ_Arg dict; uint8_t index; char* color; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal dict start."; status = AJ_UnmarshalArgs(&rxMsg, "ys", &index, &color); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal key-value pair."; if (AJ_OK == status) { /* verify that what was marshaled in, is unmarshaled out */ EXPECT_EQ(key, index) << "The key of dictionary element was marshaled " << "in and unmarshaled out. The unmarshaled " << "value " << index << " does NOT match the marshaled value " << key; EXPECT_STREQ(Colors[key], color) << "The value of dictionary " << "element was marshaled in and " << "unmarshaled out. The unmarshaled " << "value " << color << " does NOT match the marshaled value " << Colors[key]; } status = AJ_UnmarshalCloseContainer(&rxMsg, &dict); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal dict end."; } /* * Now that we have unmarshaled all the entries, there should be * NO MORE */ AJ_Arg dict; status = AJ_UnmarshalContainer(&rxMsg, &dict, AJ_ARG_DICT_ENTRY); EXPECT_EQ(AJ_ERR_NO_MORE, status) << " Actual Status: " << AJ_StatusText(status) << ". After unmarshaling all the dictionary " << "entries, we expect that there are no " << "more entries."; if (AJ_ERR_NO_MORE == status) { status = AJ_UnmarshalCloseContainer(&rxMsg, &array1); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to unmarshal end of the array " << "from the message."; status = AJ_CloseMsg(&rxMsg); EXPECT_EQ(AJ_OK, status) << " Actual Status: " << AJ_StatusText(status) << ". Unable to close the message."; } } } ajtcl-16.04/unit_test/SConscript000066400000000000000000000055521271074662300166700ustar00rootroot00000000000000import os import platform Import('env') vars = Variables() vars.Add(PathVariable('GTEST_DIR', 'The path to googletest sources', os.environ.get('GTEST_DIR'), PathVariable.PathIsDir)) vars.Update(env) Help(vars.GenerateHelpText(env)) config = Configure(env) system_gtest = config.CheckHeader('gtest/gtest.h', '<>', 'c++') if env.get('GTEST_DIR'): prevCPPPATH = list(env.get('CPPPATH', [])) env.Prepend(CPPPATH = [ env.Dir('$GTEST_DIR/include') ]) custom_gtest = config.CheckHeader(env.subst('$GTEST_DIR/include/gtest/gtest.h'), '<>', 'c++') env.Replace(CPPPATH = prevCPPPATH) else: custom_gtest = False env = config.Finish() if custom_gtest: gtest_all_path = env.File('$GTEST_DIR/src/gtest-all.cc') elif env['TARG'] in ['linux', 'darwin']: gtest_file = env.FindFile('gtest/src/gtest-all.cc', [ '/usr/src', '/usr/local/src' ]) if gtest_file: gtest_all_path = env.File(gtest_file) if (system_gtest or custom_gtest) and os.path.exists(str(gtest_all_path)): gtest_env = env.Clone() if env['TARG'] == 'win32': # gTest needs different CPPDEFINES as compared to AllJoyn TCL. gtest_env.Append(CPPDEFINES = ['WIN32', '_LIB']) gtest_env.Append(CXXFLAGS = ['/wd4355', '/vmm', '/vmg', '/MDd', '/Od', '/Gd', '/Ob1', '/EHsc']) gtest_env.Append(CFLAGS = ['/wd4355', '/vmm', '/vmg', '/MDd', '/Od', '/Gd', '/Ob1', '/EHsc']) # Microsoft Visual Studio 2012 has a different _VARIADIC_MAX default value. # See: http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx if(env['MSVC_VERSION'] == '11.0' or env['MSVC_VERSION'] == '11.0Exp'): gtest_env.Append(CPPDEFINES = ['_VARIADIC_MAX=10']) # We compile with no rtti, no exceptions and no threads gtest_env.Append(CPPDEFINES = { 'GTEST_HAS_RTTI': '0', 'GTEST_HAS_EXCEPTIONS': '0', 'GTEST_HAS_PTHREAD': '0' }) if custom_gtest: gtest_env.Prepend(CPPPATH = [ gtest_env.Dir('$GTEST_DIR/include') ]) gtest_env.Prepend(CPPPATH = [ os.path.join(gtest_all_path.path, '../..') ]) gtest_obj = gtest_env.StaticObject(target = 'gtest-all', source = [ gtest_all_path ]) gtest_lib = gtest_env.StaticLibrary(target = 'gtest', source = gtest_obj) unittest_env = gtest_env.Clone() unittest_env.Append(LIBPATH = "#dist/lib") unittest_env.Append(LIBS = "ajtcl") # gtest library file is placed in the same directory #unittest_env.Append(LIBPATH = [ gtest_lib.path() ]) unittest_env.Prepend(LIBS = [ gtest_lib ]) objs = [ unittest_env.Object(env.Glob('*.cc')) ] if env['TARG'] == 'win32': unittest_env.Append(LFLAGS=['/NODEFAULTLIB:msvcrt.lib']) unittest_env.Append(LINKFLAGS=['/NODEFAULTLIB:msvcrt.lib']) unittest_prog = unittest_env.Program('ajtcltest', objs) unittest_env.Install('#dist/test', unittest_prog) ajtcl-16.04/unit_test/SecurityTest.cc000066400000000000000000000455111271074662300176330ustar00rootroot00000000000000/* * @file */ /****************************************************************************** * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include #define AJ_MODULE SECURITYTEST extern "C" { #include #include #include #include #include #include #include #include #include #include } #ifndef NDEBUG uint8_t dbgSECURITYTEST = 0; #endif #define CONNECT_TIMEOUT (1000ul * 15) #define UNMARSHAL_TIMEOUT (1000 * 5) #define METHOD_TIMEOUT (1000 * 10) #define PING_TIMEOUT (1000 * 10) /*Interface */ static const char* const Test1_Interface1[] = { "$org.alljoyn.alljoyn_test", "?my_ping inStrs", NULL }; static const AJ_InterfaceDescription Test1_Interfaces[] = { AJ_PropertiesIface, Test1_Interface1, NULL }; static const char testObj[] = "/org/alljoyn/alljoyn_test"; static AJ_Object AppObjects[] = { { testObj, Test1_Interfaces, AJ_OBJ_FLAG_SECURE }, { NULL } }; uint32_t TEST1_APP_MY_PING = AJ_PRX_MESSAGE_ID(0, 1, 0); /* * Default key expiration */ static const uint32_t keyexpiration = 0xFFFFFFFF; static AJ_BusAttachment testBus; static const char ServiceName[] = "org.alljoyn.svclite"; static const uint16_t ServicePort = 24; static char g_ServiceName[AJ_MAX_SERVICE_NAME_SIZE]; class SecurityTest : public testing::Test { public: SecurityTest() { authStatus = AJ_ERR_NULL; } static void AuthCallback(const void* context, AJ_Status status) { *((AJ_Status*)context) = status; ASSERT_EQ(AJ_OK, status) << "Auth callback returns fail " << AJ_StatusText(status); } AJ_Status authStatus; }; /* * Order of certificates is important. * Generated using alljoyn/common/unit_test/CertificateECCTest.cc (CreateIdentityCertificateChain) */ static const char pem_x509_identity[] = { "-----BEGIN CERTIFICATE-----" "MIIBQzCB66ADAgECAgIwMzAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANjbjMwHhcN" "MTYwMjA5MDA0ODM0WhcNMTYwMjA5MDMzNTE0WjAOMQwwCgYDVQQDDANjbjQwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAASCHIVNOJO98Ce7vGy5IQkKgFdLhU4LJpZp" "5UKLZNxYEYTLtPBc1ynq3pty9DVsZ3/dXgzZFLzrA9Ns3tISqXk1ozkwNzAJBgNV" "HRMEAjAAMBUGA1UdJQQOMAwGCisGAQQBgt58AQEwEwYDVR0jBAwwCqAIS5ALPthB" "n0QwCgYIKoZIzj0EAwIDRwAwRAIgay/Z7JMjDVBIaJ8G0rh35fGwK77c0ytA9nVy" "GikbVzECIAjhPpqz9k6z0nlzwsKtOC95JvOC5GD9NHXX96xo5lWZ" "-----END CERTIFICATE-----" "-----BEGIN CERTIFICATE-----" "MIIBSDCB7qADAgECAgIwMzAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANjbjIwHhcN" "MTYwMjA5MDA0ODM0WhcNMTYwMjA5MDMzNTE0WjAOMQwwCgYDVQQDDANjbjMwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQK3bAEiq71WbFCXkIN33HP5n1u8c6cAHB4" "zYkq0mfz4oNBJrJqZfuZWUOJdmyq/ZcFaB+YF8GucmUKMncSlZoAozwwOjAMBgNV" "HRMEBTADAQH/MBUGA1UdJQQOMAwGCisGAQQBgt58AQEwEwYDVR0jBAwwCqAIT9/x" "lYHtWkwwCgYIKoZIzj0EAwIDSQAwRgIhAMTyK7btKTjriyM+Z5IoI96VyUnnfLUl" "yAI94VWoK1nVAiEAyjWDTZikPwWFG7Ma2IDu3A39LWHYjyhes5xMV7oG44Y=" "-----END CERTIFICATE-----" "-----BEGIN CERTIFICATE-----" "MIIBSDCB7qADAgECAgIwMjAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANjbjEwHhcN" "MTYwMjA5MDA0ODM0WhcNMTYwMjA5MDMzNTE0WjAOMQwwCgYDVQQDDANjbjIwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAASvUK0iuLHtZjTTqHB9PEtY6iivCckgKEHu" "Eat6I/blbiQvNYe5AX8taZD6dVntU8Rs30Ua6nQNSYvFIeUm9wV4ozwwOjAMBgNV" "HRMEBTADAQH/MBUGA1UdJQQOMAwGCisGAQQBgt58AQEwEwYDVR0jBAwwCqAIQPGV" "somA/vswCgYIKoZIzj0EAwIDSQAwRgIhANMgbRmi3sEmQplB6fRDx9ijrs5yVx30" "ayowCW26sKSyAiEAwFTh6CwdAgTAJ4X6Yr2SJ0mGkh6EKILIPvoGyARQPNM=" "-----END CERTIFICATE-----" "-----BEGIN CERTIFICATE-----" "MIIBMjCB2aADAgECAgIwMTAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANjbjEwHhcN" "MTYwMjA5MDA0ODM0WhcNMTYwMjA5MDMzNTE0WjAOMQwwCgYDVQQDDANjbjEwWTAT" "BgcqhkjOPQIBBggqhkjOPQMBBwNCAARLrc3K8qbzf5WyHTNHERLFyF5NauTSWOAs" "x6lql+DbGfBFeS6G5XL0akNmxJcRLUma6BKnyll9zj6fEpA5dbvaoycwJTAMBgNV" "HRMEBTADAQH/MBUGA1UdJQQOMAwGCisGAQQBgt58AQEwCgYIKoZIzj0EAwIDSAAw" "RQIgAn13qEfFf3H0MSdvNC/NVgWVBRoJWpZ8IWcC+cf5HqwCIQDSQrb1gop6PeqN" "mTMTCVFSHo33KuSn0Y7Dbpc2N3BpvQ==" "-----END CERTIFICATE-----" }; TEST_F(SecurityTest, CommonPathTest) { EXPECT_FALSE(AJ_CommonPath("", "Signal1", SIGNAL)); EXPECT_FALSE(AJ_CommonPath("", "Method1", METHOD)); EXPECT_FALSE(AJ_CommonPath("", "Property1", PROPERTY)); EXPECT_TRUE(AJ_CommonPath("*", "Signal1", SIGNAL)); EXPECT_TRUE(AJ_CommonPath("*", "Method1", METHOD)); EXPECT_TRUE(AJ_CommonPath("*", "Property1", PROPERTY)); EXPECT_FALSE(AJ_CommonPath("Signal", "Signal1", SIGNAL)); EXPECT_FALSE(AJ_CommonPath("Method", "Method1", METHOD)); EXPECT_FALSE(AJ_CommonPath("Property", "Property1", PROPERTY)); EXPECT_TRUE(AJ_CommonPath("Signal1", "Signal1", SIGNAL)); EXPECT_TRUE(AJ_CommonPath("Method1", "Method1", METHOD)); EXPECT_FALSE(AJ_CommonPath("Property1", "Property1", PROPERTY)); EXPECT_TRUE(AJ_CommonPath("Signal1", "Signal1 ", SIGNAL)); EXPECT_TRUE(AJ_CommonPath("Method1", "Method1 ", METHOD)); EXPECT_FALSE(AJ_CommonPath("Property1", "Property1 ", PROPERTY)); EXPECT_TRUE(AJ_CommonPath("Signal1", "Signal1 >s", SIGNAL)); EXPECT_TRUE(AJ_CommonPath("Method1", "Method1 >s", METHOD)); EXPECT_TRUE(AJ_CommonPath("Method1", "Method1 s", PROPERTY)); EXPECT_FALSE(AJ_CommonPath("Property1", "Property1 s", SIGNAL)); EXPECT_FALSE(AJ_CommonPath("Method1", "Method1>s", METHOD)); EXPECT_FALSE(AJ_CommonPath("Method1", "Method1s", PROPERTY)); EXPECT_TRUE(AJ_CommonPath("Property1", "Property1s", SIGNAL)); EXPECT_FALSE(AJ_CommonPath("Method1", "Method>s", METHOD)); EXPECT_FALSE(AJ_CommonPath("Method1", "Methods", PROPERTY)); EXPECT_FALSE(AJ_CommonPath("Property1", "Propertys", PROPERTY)); EXPECT_FALSE(AJ_CommonPath("Property1", "Property2s", PROPERTY)); EXPECT_TRUE(AJ_CommonPath("Property*", "Property1s", PROPERTY)); EXPECT_FALSE(AJ_CommonPath("Property1*", "Propertynext; ASSERT_TRUE(NULL != intermediate1); intermediate2 = intermediate1->next; ASSERT_TRUE(NULL != intermediate2); leaf = intermediate2->next; ASSERT_TRUE(NULL != leaf); /* This is an Identity certificate */ EXPECT_EQ(AJ_OK, AJ_X509VerifyChain(head, &head->certificate.tbs.publickey, AJ_CERTIFICATE_IDN_X509)); EXPECT_EQ(AJ_ERR_SECURITY, AJ_X509VerifyChain(head, &head->certificate.tbs.publickey, AJ_CERTIFICATE_MBR_X509)); EXPECT_EQ(AJ_ERR_SECURITY, AJ_X509VerifyChain(head, &head->certificate.tbs.publickey, AJ_CERTIFICATE_UNR_X509)); field.data = buffer; field.size = sizeof (buffer); policy.specification = 1; policy.version = 1; policy.acls = &acl; acl.peers = &peer; acl.rules = NULL; acl.next = NULL; peer.type = AJ_PEER_TYPE_FROM_CA; peer.kid.data = NULL; peer.kid.size = 0; peer.group.data = NULL; peer.group.size = 0; peer.next = NULL; /* Store root issuer */ memcpy(&peer.pub, &head->certificate.tbs.publickey, sizeof (AJ_ECCPublicKey)); ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_OK, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); peer.type = AJ_PEER_TYPE_WITH_MEMBERSHIP; ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_OK, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); /* Store intermediate 1 issuer */ peer.type = AJ_PEER_TYPE_FROM_CA; memcpy(&peer.pub, &intermediate1->certificate.tbs.publickey, sizeof (AJ_ECCPublicKey)); ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); EXPECT_EQ(AJ_OK, AJ_PolicyFindAuthority(head)); peer.type = AJ_PEER_TYPE_WITH_MEMBERSHIP; ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); EXPECT_EQ(AJ_OK, AJ_PolicyFindAuthority(head)); /* Store intermediate 2 issuer */ peer.type = AJ_PEER_TYPE_FROM_CA; memcpy(&peer.pub, &intermediate2->certificate.tbs.publickey, sizeof (AJ_ECCPublicKey)); ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); EXPECT_EQ(AJ_OK, AJ_PolicyFindAuthority(head)); peer.type = AJ_PEER_TYPE_WITH_MEMBERSHIP; ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); EXPECT_EQ(AJ_OK, AJ_PolicyFindAuthority(head)); /* Store leaf issuer (non CA) */ peer.type = AJ_PEER_TYPE_FROM_CA; memcpy(&peer.pub, &leaf->certificate.tbs.publickey, sizeof (AJ_ECCPublicKey)); ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyFindAuthority(head)); peer.type = AJ_PEER_TYPE_WITH_MEMBERSHIP; ASSERT_EQ(AJ_OK, AJ_PolicyToBuffer(&policy, &field)); ASSERT_EQ(AJ_OK, AJ_CredentialSet(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL, 0xFFFFFFFF, &field)); ASSERT_EQ(AJ_OK, AJ_PolicyLoad()); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyVerifyCertificate(&head->certificate, &pub)); EXPECT_EQ(AJ_ERR_SECURITY, AJ_PolicyFindAuthority(head)); AJ_X509FreeDecodedCertificateChain(root); AJ_PolicyUnload(); /* Remove policy from keystore */ AJ_CredentialDelete(AJ_POLICY_INSTALLED | AJ_CRED_TYPE_POLICY, NULL); } TEST_F(SecurityTest, RegisterACLTest) { AJ_AuthorisationRegister(AppObjects, AJ_APP_ID_FLAG); AJ_AuthorisationRegister(AJ_StandardObjects, AJ_BUS_ID_FLAG); AJ_AuthorisationRegister(AJ_StandardObjects, AJ_BUS_ID_FLAG); AJ_AuthorisationRegister(AppObjects, AJ_APP_ID_FLAG); AJ_AuthorisationRegister(AJ_StandardObjects, AJ_BUS_ID_FLAG); AJ_AuthorisationRegister(AppObjects, AJ_APP_ID_FLAG); } class SerialNumberTest : public testing::Test { public: SerialNumberTest() { } }; TEST_F(SerialNumberTest, Test1) { AJ_SerialNum prev = { 0, 0 }; uint32_t curr = 0; int i; for (i = 0; i < 64; i++) { curr++; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } for (i = 0; i < 64; i++) { curr--; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } } TEST_F(SerialNumberTest, Test2) { AJ_SerialNum prev = { 0, 0 }; uint32_t curr = 0; int i; for (i = 0; i < 32; i++) { curr += 2; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } for (i = 0; i < 32; i++) { curr -= 2; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } } TEST_F(SerialNumberTest, Test3) { AJ_SerialNum prev = { 0, 0 }; uint32_t curr = 0xFFFFFFFFUL - 32; int i; for (i = 0; i < 64; i++) { curr++; if (curr != 0) { ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); } ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } for (i = 0; i < 64; i++) { curr--; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } } TEST_F(SerialNumberTest, Test4) { AJ_SerialNum prev = { 0, 0 }; uint32_t curr = 0xFFFFFFFFUL - 32; int i; for (i = 0; i < 32; i++) { curr += 2; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } for (i = 0; i < 32; i++) { curr -= 2; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } } TEST_F(SerialNumberTest, Test5) { AJ_SerialNum prev = { 0, 0 }; uint32_t curr = 64; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = curr - 63; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = curr - 1; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x8000UL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x8001UL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x8000UL; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); } TEST_F(SerialNumberTest, Test6) { AJ_SerialNum prev = { 0, 0 }; uint32_t curr; curr = 0x80000001UL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x10UL; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x0UL; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x60000000UL; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = 0xFFFFFFFFUL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x1UL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = 0xFFFFFFFFUL; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x0UL; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x80000001UL; ASSERT_EQ(AJ_ERR_INVALID, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x7FFFFFFFUL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = 0xC0000000UL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); curr = 0x1UL; ASSERT_EQ(AJ_OK, AJ_CheckIncomingSerial(&prev, curr)); } ajtcl-16.04/unit_test/ajtclTest.cc000066400000000000000000000027041271074662300171160ustar00rootroot00000000000000/****************************************************************************** * * * Copyright AllSeen Alliance. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************************/ #include extern "C" { #include #include } /** Main entry point */ int main(int argc, char**argv, char**envArg) { int status = 0; setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); AJ_AlwaysPrintf(("\n Running ajtcl unit test\n")); testing::InitGoogleTest(&argc, argv); status = RUN_ALL_TESTS(); AJ_AlwaysPrintf(("%s exiting with status %d \n", argv[0], status)); return (int) status; } ajtcl-16.04/unit_test/test_report/000077500000000000000000000000001271074662300172215ustar00rootroot00000000000000ajtcl-16.04/unit_test/test_report/ajtcltest-buildbot.conf000066400000000000000000000015341271074662300236720ustar00rootroot00000000000000# # This is buildbot's test_harness configuration for ajtcltest # [Environment] # variable=value ER_DEBUG_ALL=0 # GTest supports the following options, shown with their default value # GTEST_OUTPUT= # None # GTEST_ALSO_RUN_DISABLED_TESTS=0 # No # GTEST_REPEAT=0 # No # GTEST_SHUFFLE=0 # No # GTEST_RANDOM_SEED=0 # default pseudo-random seed # GTEST_BREAK_ON_FAILURE=0 # no break on failures # GTEST_CATCH_EXCEPTIONS=1 # gtest catches exceptions itself GTEST_OUTPUT=xml:ajtcltest.xml [GTestFile] # ajtcltest ajtcltest [TestCases] # Can select individual tests as well as groups. # That is, TestCase selection can look like Foo.Bar=YES, not just Foo=YES. # You can also used negative selection, like *=YES followed by Foo.Bar=NO. *=Yes SecurityTest=NO ajtcl-16.04/unit_test/test_report/runall.sh000077500000000000000000000121331271074662300210550ustar00rootroot00000000000000#!/bin/bash # Copyright AllSeen Alliance. All rights reserved. # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # function Usage() { set +ex echo >&2 " Runs GTest executable ajtcltest Usage: $(basename -- "$0") [ -s -d alljoyn_dist ] [-c configfile ] where -s # start and stop our own AllJoyn-Daemon (default internal transport address, --no-bt) -d alljoyn_dist # path to the build/.../dist tree, used to find cpp/bin/alljoyn-daemon exe, if used -c configfile # name of config file # default 'ajtcltest.conf' " exit 2 } : read commandline options set -e start_daemon=false alljoyn_dist='' configfile='*.conf' while getopts sSc:d: option do case "$option" in ( c ) configfile="$OPTARG" ;; ( d ) alljoyn_dist="$OPTARG" ;; ( s ) start_daemon=true ;; ( S ) start_daemon=false ;; ( \? ) Usage ;; esac done if cygpath -wa . > /dev/null 2>&1 then # found Cygwin, which means Windows : there is no alljoyn-daemon on Windows start_daemon=false fi gtests='' if test "$OPTIND" -gt 0 -a "$OPTIND" -le $# then shift ` expr $OPTIND - 1 ` while test $# -ge 1 do case "$1" in ( *[!a-zA-Z0-9_-]* | '' ) echo >&2 "error, $1: allowed characters are [a-zA-Z0-9_-]" ; Usage ;; ( * ) gtests="$gtests $1" ;; esac shift done fi if test -z "$gtests" then gtests="ajtcltest" fi : check commandline options ckbin() { ckvar=$1 binvar=$2 eval ckval="\$$1" binval=` cd "$ckval/cpp/bin" > /dev/null && pwd ` || : ok if test -z "$binval" then echo >&2 "error, could not find 'cpp/bin' subdirectory in $ckvar=$ckval" exit 2 fi eval $binvar="'$binval'" } # alljoyn_dist if $start_daemon then if test -z "$alljoyn_dist" then echo >&2 "error, -d path is required" Usage fi ckbin alljoyn_dist daemon_bin fi gtest_bin=$( cd "$(dirname -- "$0")/.." > /dev/null && pwd ) if test -z "$gtest_bin" -o "gtest_bin" = / then : unknown error trap exit 2 fi if cygpath -wa . > /dev/null 2>&1 then # found Cygwin, which means Windows : there is no alljoyn-daemon on Windows options='' # gtest_bin needs to be Windows-style because we use pure Windows Python, not Cygwin Python gtest_bin_p="$( cygpath -wa "$gtest_bin" )" # sometimes Windows "home" does not work for keystore tests export USERPROFILE="$( cygpath -wa . )" export LOCALAPPDATA="$USERPROFILE" else : set up alljoyn-daemon options="--print-address" gtest_bin_p="$gtest_bin" # MBUS-1589: remove .alljoyn_keystore, if any export HOME="$PWD" LinuxLibDir="$alljoyn_dist/cpp/lib" if [ -f "$LinuxLibDir/liballjoyn.so" ]; then ls -ld "$LinuxLibDir/liballjoyn.so" export LD_LIBRARY_PATH="$LinuxLibDir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" else echo "warning, liballjoyn.so does NOT exist!" fi fi # MBUS-1589: remove .alljoyn_keystore, if any rm -rf .alljoyn_keystore echo "# runall test plan:" if $start_daemon then ls >/dev/null -ld "$daemon_bin/alljoyn-daemon" || ls >/dev/null -ld "$daemon_bin/alljoyn-daemon.exe" || { echo >&2 "error, alljoyn-daemon exe not found" exit 2 } echo "# $daemon_bin/alljoyn-daemon $options > alljoyn-daemon.log &" fi for i in $gtests do ls >/dev/null -ld "$gtest_bin/$i" || ls >/dev/null -ld "$gtest_bin/$i.exe" || { echo >&2 "error, $i exe not found" exit 2 } c="$( echo "$configfile" | sed -e 's,\*,'$i',g' )" ls >/dev/null -ld "$c" || { echo >&2 "error, configfile $c not found" exit 2 } echo "# python test_harness.py -c $c -t $i -p $gtest_bin_p > $i.log" done : begin export ER_DEBUG_ALL=0 if $start_daemon then : start alljoyn-daemon rm -f alljoyn-daemon.log killall -v alljoyn-daemon || : ok ( set -ex cd "$daemon_bin" pwd date ./alljoyn-daemon $options; xit=$? date set +x echo exit status $xit ) > alljoyn-daemon.log 2>&1 $c.t else echo ' BusAttachmentTest.*=No' | cat $c - > $c.t fi rm -f "$i.log" sleep 5 set -x : run $i date python -u test_harness.py -c $c.t -t $i -p "$gtest_bin_p" > "$i.log" 2>&1 < /dev/null || : exit status is $? / IGNORE IT date set +x tail -1 "$i.log" | grep "exiting with status 0" || xit=1 case "$xit" in 0 ) echo $i PASSED ;; * ) echo $i FAILED, see $i.log for info ;; esac sleep 5 done if $start_daemon then sleep 5 killall -v alljoyn-daemon || : ok sleep 5 fi echo exit status $xit exit $xit ajtcl-16.04/unit_test/test_report/sample.conf000066400000000000000000000014501271074662300213510ustar00rootroot00000000000000# # This is an example test_harness configuration for ajtcl # [TestCases] # Can select individual tests as well as groups. # That is, TestCase selection can look like Foo.Bar=YES, not just Foo=YES. # You can also used negative selection, like *=YES followed by Foo.Bar=NO. *=Yes [Environment] # variable=value ER_DEBUG_ALL=0 # GTest supports the following options, shown with their default value # GTEST_OUTPUT= # None # GTEST_ALSO_RUN_DISABLED_TESTS=0 # No # GTEST_REPEAT=0 # No # GTEST_SHUFFLE=0 # No # GTEST_RANDOM_SEED=0 # default pseudo-random seed # GTEST_BREAK_ON_FAILURE=0 # no break on failures # GTEST_CATCH_EXCEPTIONS=1 # gtest catches exceptions itself [GTestFile] # ajtcltest, or ... ajtcltest ajtcl-16.04/unit_test/test_report/test_harness.py000077500000000000000000000153051271074662300223040ustar00rootroot00000000000000 # Copyright AllSeen Alliance. All rights reserved. # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # import getopt import os import re import sys import subprocess def usage(): print >> sys.stderr, """ Usage: python test_harness.py [ -c config_file ] [ -t gtestfile ] [ -p path_to_gtestfile ] where: config_file: test_harness config file; default: test_harness.conf gtestfile: name of gtest executable file; default: ajtcltest path_to_gtestfile: optional path to directory containing gtestfile """ def main(argv=None): # get commandline options conffile='test_harness.conf' testpath='' gtestfileopt='' if argv is None: argv=[] if len(argv) > 0: try: opts, junk = getopt.getopt(argv, 'c:p:t:') if junk: print >> sys.stderr, 'error, unrecognized arguments ' + str(junk) usage() return 2 for opt, val in opts: if opt == '-c': conffile = val elif opt == '-p': testpath = val elif opt == '-t': gtestfileopt= val except getopt.GetoptError, err: print >> sys.stderr, 'error, ' + str(err) usage() return 2 # initialize dict = [] filter = '' negfilter = '' gtestfile = '' part = '' re_comment = re.compile( r'\s*#.*$' ) re_equals = re.compile( r'\s*=\s*' ) re_lastcolon = re.compile( r':$' ) re_TestCases = re.compile( r'^\[\s*Test\s*Cases\s*\]', re.I ) re_Environment = re.compile( r'^\[\s*Environment\s*\]', re.I ) re_GTestFile = re.compile( r'^\[\s*GTest\s*File\s*\]', re.I ) # read config file one line at a time try: with open( conffile, 'r' ) as fileptr: for line in fileptr: # strip leading and trailing whitespace line = line.strip() line = line.strip('\n') # strip trailing comment (and preceding whitespace), if any line = re_comment.sub( '', line ) # search line for part header if re_TestCases.search( line ): # line ~= [ TestCases ] part = 'TestCases' continue elif re_Environment.search( line ): # line ~= [ Environment ] part = 'Environment' print '[Environment]' continue elif re_GTestFile.search( line ): # line ~= [ GTestFile ] part = 'GTestFile' continue else: # line is none of the above # split line around equals sign (and surrounding whitespace), if any dict = re_equals.split( line, 1 ) if (len(dict) > 1): # line ~= something = something if part == 'TestCases': # Can select individual tests as well as groups. # That is, TestCase selection can look like Foo.Bar=YES, not just Foo=YES. # You can also used negative selection, like *=YES followed by Foo.Bar=NO. d0 = dict[0].split('.',1) if (dict[1].upper() == 'YES' or dict[1].upper() == 'Y'): if (len(d0) > 1): filter = filter + dict[0] + ':' else: filter = filter + dict[0] + '.*' + ':' elif (dict[1].upper() == 'NO' or dict[1].upper() == 'N'): if (len(d0) > 1): negfilter = negfilter + dict[0] + ':' else: negfilter = negfilter + dict[0] + '.*' + ':' elif part == 'Environment': os.putenv(dict[0],dict[1]) print '\t%s="%s"' % ( dict[0], dict[1] ) elif part == 'GTestFile': # the file name might contain = character gtestfile = line elif part == 'GTestFile' and line != '': gtestfile = line else: # line is unusable continue except IOError: print >> sys.stderr, 'error opening config file "%s"' % conffile return 2 # assemble the path to gtestfile to execute command = gtestfile if gtestfileopt != '': command = gtestfileopt if command == '': command = 'ajtcltest' if testpath != '': command = os.path.join( testpath, command ) print '[GTestFile]\n\t%s' % command if not ( os.path.exists( command ) or os.path.exists( command + '.exe' ) ): print >> sys.stderr, 'error, GTestFile="%s" not found' % command return 2 command=[command] # assemble the gtest filter, if any if filter == '' and negfilter == '': pass elif filter != '' and negfilter == '': filter = re_lastcolon.sub( '', filter ) elif filter == '' and negfilter != '': filter = '*' + '-' + re_lastcolon.sub( '', negfilter ) else: filter = re_lastcolon.sub( '', filter ) + '-' + re_lastcolon.sub( '', negfilter) if filter != '': print '[TestCases]\n\t%s' % filter command.append('--gtest_filter=' + filter) print '\ncommand line: %s\n' % ( ' '.join( command ) ) sys.stdout.flush() # execute the gtestfile with filter argument, if any # exit status 0 if no errors, 1 if any tests failed, 2 if system error if subprocess.call(command) == 0: return 0 else: return 1 if __name__ == '__main__': if len(sys.argv) > 1: sys.exit(main(sys.argv[1:])) else: sys.exit(main())