├── .clang-format ├── .editorconfig ├── .github └── workflows │ ├── codeql-analysis.yml │ ├── compile.yml │ └── ndk.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSES ├── BSD-3-Clause ├── GPL-2.0-only.txt └── Linux-syscall-note.txt ├── Makefile ├── README.md ├── asc2log.c ├── bcmserver.c ├── calc-bit-timing ├── can-calc-bit-timing-v2_6_31.c ├── can-calc-bit-timing-v3_18.c ├── can-calc-bit-timing-v4_8.c ├── can-calc-bit-timing-v5_16.c ├── can-calc-bit-timing-v5_19.c ├── can-calc-bit-timing-v6_3.c ├── can-calc-bit-timing.c └── compat.h ├── can-j1939-install-kernel-module.md ├── can-j1939-kickstart.md ├── can-j1939.md ├── can-tc-init-etf.sh ├── canbusload.c ├── candump.c ├── canerrsim.c ├── canfdtest.c ├── canframelen.c ├── canframelen.h ├── cangen.c ├── cangw.c ├── canlogserver.c ├── canplayer.c ├── cansend.c ├── cansequence.c ├── cansniffer.c ├── check_cc.sh ├── cmake ├── aarch64-linux-gnu-clang.cmake ├── aarch64-linux-gnu-gcc.cmake ├── arm-linux-gnueabihf-clang.cmake ├── arm-linux-gnueabihf-gcc.cmake ├── make_uninstall.cmake └── mips-linux-gnu-gcc.cmake ├── fork_test.c ├── include └── linux │ ├── can.h │ ├── can │ ├── bcm.h │ ├── error.h │ ├── gw.h │ ├── isotp.h │ ├── j1939.h │ ├── netlink.h │ ├── raw.h │ └── vxcan.h │ ├── errqueue.h │ ├── kernel.h │ ├── net_tstamp.h │ └── netlink.h ├── isobusfs ├── isobusfs_cli.c ├── isobusfs_cli.h ├── isobusfs_cli_cm.c ├── isobusfs_cli_dh.c ├── isobusfs_cli_fa.c ├── isobusfs_cli_int.c ├── isobusfs_cli_selftests.c ├── isobusfs_cmn.c ├── isobusfs_cmn.h ├── isobusfs_cmn_cm.h ├── isobusfs_cmn_dh.c ├── isobusfs_cmn_dh.h ├── isobusfs_cmn_fa.h ├── isobusfs_cmn_fh.h ├── isobusfs_cmn_va.h ├── isobusfs_create_test_dirs.sh ├── isobusfs_create_test_file.sh ├── isobusfs_srv.c ├── isobusfs_srv.h ├── isobusfs_srv_cm.c ├── isobusfs_srv_cm_fss.c ├── isobusfs_srv_dh.c ├── isobusfs_srv_fa.c ├── isobusfs_srv_fh.c └── isobusfs_srv_vh.c ├── isotpdump.c ├── isotpperf.c ├── isotprecv.c ├── isotpsend.c ├── isotpserver.c ├── isotpsniffer.c ├── isotptun.c ├── j1939_timedate ├── j1939_timedate_cli.c ├── j1939_timedate_cmn.h └── j1939_timedate_srv.c ├── j1939_vehicle_position ├── j1939_vehicle_position_cmn.h └── j1939_vehicle_position_srv.c ├── j1939acd.c ├── j1939cat.c ├── j1939spy.c ├── j1939sr.c ├── lib.c ├── lib.h ├── libj1939.c ├── libj1939.h ├── log2asc.c ├── log2long.c ├── mcp251xfd ├── 99-devcoredump.rules ├── data │ ├── devcoredump-canfd-v5.15.dump │ ├── devcoredump-canfd.dump │ ├── devcoredump-classic-can-v5.15.dump │ ├── devcoredump-classic-can.dump │ ├── registers-canfd-v5.15.dump │ ├── registers-canfd.dump │ ├── registers-classic-can-v5.15.dump │ └── registers-classic-can.dump ├── devcoredump ├── mcp251xfd-dev-coredump.c ├── mcp251xfd-dump-userspace.h ├── mcp251xfd-dump.c ├── mcp251xfd-dump.h ├── mcp251xfd-gen-testdata.sh ├── mcp251xfd-main.c ├── mcp251xfd-regmap.c └── mcp251xfd.h ├── page.theme ├── slcan_attach.c ├── slcand.c ├── slcanpty.c ├── style.css ├── terminal.h └── testj1939.c /.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # clang-format configuration file. Intended for clang-format >= 11. 4 | # 5 | # For more information, see: 6 | # 7 | # Documentation/process/clang-format.rst 8 | # https://clang.llvm.org/docs/ClangFormat.html 9 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 10 | # 11 | --- 12 | AccessModifierOffset: -4 13 | AlignAfterOpenBracket: Align 14 | AlignConsecutiveAssignments: false 15 | AlignConsecutiveDeclarations: false 16 | AlignEscapedNewlines: Left 17 | AlignOperands: true 18 | AlignTrailingComments: false 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | AllowShortBlocksOnASingleLine: false 21 | AllowShortCaseLabelsOnASingleLine: false 22 | AllowShortFunctionsOnASingleLine: None 23 | AllowShortIfStatementsOnASingleLine: false 24 | AllowShortLoopsOnASingleLine: false 25 | AlwaysBreakAfterDefinitionReturnType: None 26 | AlwaysBreakAfterReturnType: None 27 | AlwaysBreakBeforeMultilineStrings: false 28 | AlwaysBreakTemplateDeclarations: false 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BraceWrapping: 32 | AfterClass: false 33 | AfterControlStatement: false 34 | AfterEnum: false 35 | AfterFunction: true 36 | AfterNamespace: true 37 | AfterObjCDeclaration: false 38 | AfterStruct: false 39 | AfterUnion: false 40 | AfterExternBlock: false 41 | BeforeCatch: false 42 | BeforeElse: false 43 | IndentBraces: false 44 | SplitEmptyFunction: true 45 | SplitEmptyRecord: true 46 | SplitEmptyNamespace: true 47 | BreakBeforeBinaryOperators: None 48 | BreakBeforeBraces: Custom 49 | BreakBeforeInheritanceComma: false 50 | BreakBeforeTernaryOperators: false 51 | BreakConstructorInitializersBeforeComma: false 52 | BreakConstructorInitializers: BeforeComma 53 | BreakAfterJavaFieldAnnotations: false 54 | BreakStringLiterals: false 55 | ColumnLimit: 200 56 | CommentPragmas: "^ IWYU pragma:" 57 | CompactNamespaces: false 58 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 59 | ConstructorInitializerIndentWidth: 8 60 | ContinuationIndentWidth: 8 61 | Cpp11BracedListStyle: false 62 | DerivePointerAlignment: false 63 | DisableFormat: false 64 | ExperimentalAutoDetectBinPacking: false 65 | FixNamespaceComments: false 66 | 67 | IncludeBlocks: Preserve 68 | IncludeCategories: 69 | - Regex: ".*" 70 | Priority: 1 71 | IncludeIsMainRegex: "(Test)?$" 72 | IndentCaseLabels: false 73 | IndentGotoLabels: false 74 | IndentPPDirectives: None 75 | IndentWidth: 8 76 | IndentWrappedFunctionNames: false 77 | JavaScriptQuotes: Leave 78 | JavaScriptWrapImports: true 79 | KeepEmptyLinesAtTheStartOfBlocks: false 80 | MacroBlockBegin: "" 81 | MacroBlockEnd: "" 82 | MaxEmptyLinesToKeep: 1 83 | NamespaceIndentation: None 84 | ObjCBinPackProtocolList: Auto 85 | ObjCBlockIndentWidth: 8 86 | ObjCSpaceAfterProperty: true 87 | ObjCSpaceBeforeProtocolList: true 88 | 89 | # Taken from git's rules 90 | PenaltyBreakAssignment: 10 91 | PenaltyBreakBeforeFirstCallParameter: 30 92 | PenaltyBreakComment: 10 93 | PenaltyBreakFirstLessLess: 0 94 | PenaltyBreakString: 10 95 | PenaltyExcessCharacter: 100 96 | PenaltyReturnTypeOnItsOwnLine: 60 97 | 98 | PointerAlignment: Right 99 | ReflowComments: false 100 | SortIncludes: false 101 | SortUsingDeclarations: false 102 | SpaceAfterCStyleCast: false 103 | SpaceAfterTemplateKeyword: true 104 | SpaceBeforeAssignmentOperators: true 105 | SpaceBeforeCtorInitializerColon: true 106 | SpaceBeforeInheritanceColon: true 107 | SpaceBeforeParens: ControlStatementsExceptForEachMacros 108 | SpaceBeforeRangeBasedForLoopColon: true 109 | SpaceInEmptyParentheses: false 110 | SpacesBeforeTrailingComments: 1 111 | SpacesInAngles: false 112 | SpacesInContainerLiterals: false 113 | SpacesInCStyleCastParentheses: false 114 | SpacesInParentheses: false 115 | SpacesInSquareBrackets: false 116 | Standard: Cpp03 117 | TabWidth: 8 118 | UseTab: Always 119 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | 8 | [{CMakeLists.txt,*.cmake}] 9 | indent_style = space 10 | indent_size = 2 11 | tab_width = 2 12 | 13 | [{*.c,*.h}] 14 | indent_style = tab 15 | indent_size = 8 16 | tab_width = 8 17 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '29 21 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v3 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v3 71 | -------------------------------------------------------------------------------- /.github/workflows/compile.yml: -------------------------------------------------------------------------------- 1 | name: native and cross 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-24.04 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | release: 12 | - "ubuntu:20.04" 13 | - "ubuntu:22.04" 14 | - "ubuntu:24.04" 15 | - "ubuntu:rolling" 16 | - "debian:oldstable-slim" 17 | - "debian:stable-slim" 18 | - "debian:testing-slim" 19 | - "debian:unstable-slim" 20 | - "debian:experimental" 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Prepare ${{ matrix.release }} container 26 | env: 27 | release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }} 28 | run: | 29 | podman version 30 | podman run --name stable -di --userns=keep-id:uid=1000,gid=1000 -v "$PWD":/home -w /home ${{ matrix.release }} bash 31 | podman exec -i stable uname -a 32 | podman exec -i stable id 33 | 34 | - name: Update APT Sources List (Ubuntu Only) 35 | if: 36 | startsWith(matrix.release, 'ubuntu:') && matrix.release != 'ubuntu:20.04' 37 | run: | 38 | podman exec -i -u root stable apt update 39 | podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy \ 40 | lsb-release 41 | 42 | podman exec -i -u root stable \ 43 | test -e /etc/apt/sources.list && 44 | podman exec -i -u root stable \ 45 | sed -i -e 's|\(http.*:\)|[arch=amd64] \1|g' /etc/apt/sources.list 46 | 47 | podman exec -i -u root stable \ 48 | test -e /etc/apt/sources.list.d/ubuntu.sources && 49 | podman exec -i -u root stable \ 50 | sed -i -e '/^Components:/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources 51 | 52 | echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs) main restricted universe multiverse" | \ 53 | podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list 54 | echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs)-updates main restricted universe multiverse" | \ 55 | podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list 56 | echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs)-backports main restricted universe multiverse" | \ 57 | podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list 58 | 59 | - name: Add Architecture 60 | if: 61 | matrix.release != 'ubuntu:20.04' 62 | run: | 63 | podman exec -i -u root stable dpkg --add-architecture arm64 64 | podman exec -i -u root stable dpkg --add-architecture armhf 65 | 66 | - name: Install Development Packages 67 | env: 68 | release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }} 69 | run: | 70 | podman exec -i -u root stable apt update 71 | podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt upgrade -o APT::Install-Suggests=false -qy 72 | podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \ 73 | clang \ 74 | cmake \ 75 | gcc \ 76 | gcc-aarch64-linux-gnu \ 77 | gcc-arm-linux-gnueabihf \ 78 | gcc-mips-linux-gnu \ 79 | libgps-dev \ 80 | make 81 | 82 | - name: Install Cross Libs 83 | env: 84 | release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }} 85 | if: 86 | matrix.release != 'ubuntu:20.04' 87 | run: | 88 | podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \ 89 | libgps-dev:arm64 \ 90 | libgps-dev:armhf 91 | 92 | - name: Configure & Build with gcc 93 | env: 94 | cc: gcc 95 | run: | 96 | podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -DENABLE_GPS=ON -B build-${cc} 97 | podman exec -i stable cmake --build build-${cc} 98 | 99 | - name: Configure & Build with clang 100 | env: 101 | cc: clang 102 | run: | 103 | podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -DENABLE_GPS=ON -B build-${cc} 104 | podman exec -i stable cmake --build build-${cc} 105 | 106 | - name: Configure & Build with arm-linux-gnueabihf-gcc 107 | env: 108 | toolchain: arm-linux-gnueabihf-gcc 109 | gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }} 110 | run: | 111 | podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain} 112 | podman exec -i stable cmake --build build-${toolchain} 113 | 114 | - name: Configure & Build with arm-linux-gnueabihf-clang 115 | if: 116 | matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim' 117 | env: 118 | toolchain: arm-linux-gnueabihf-clang 119 | gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }} 120 | run: | 121 | podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain} 122 | podman exec -i stable cmake --build build-${toolchain} 123 | 124 | - name: Configure & Build with aarch64-linux-gnu-gcc 125 | env: 126 | toolchain: aarch64-linux-gnu-gcc 127 | gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }} 128 | run: | 129 | podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain} 130 | podman exec -i stable cmake --build build-${toolchain} 131 | 132 | - name: Configure & Build with aarch64-linux-gnu-clang 133 | if: 134 | matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim' 135 | env: 136 | toolchain: aarch64-linux-gnu-clang 137 | gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }} 138 | run: | 139 | podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain} 140 | podman exec -i stable cmake --build build-${toolchain} 141 | 142 | - name: Configure & Build with mips-linux-gnu-gcc 143 | env: 144 | toolchain: mips-linux-gnu-gcc 145 | run: | 146 | podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain} 147 | podman exec -i stable cmake --build build-${toolchain} 148 | 149 | - name: Configure & Build with gcc (Makefile) 150 | env: 151 | cc: gcc 152 | run: | 153 | podman exec -i stable make CC=${cc} 154 | podman exec -i stable make clean 155 | 156 | - name: Configure & Build with clang (Makefile) 157 | env: 158 | cc: clang 159 | run: | 160 | podman exec -i stable make CC=${cc} 161 | podman exec -i stable make clean 162 | 163 | - name: Show logs 164 | if: ${{ failure() }} 165 | run: | 166 | for log in build-*/CMakeFiles/{CMakeOutput.log,CMakeConfigureLog.yaml}; do \ 167 | if [ -e ${log} ]; then \ 168 | echo "---------------- ${log} ----------------"; \ 169 | cat ${log}; \ 170 | fi; \ 171 | done 172 | -------------------------------------------------------------------------------- /.github/workflows/ndk.yml: -------------------------------------------------------------------------------- 1 | name: NDK 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v4 11 | 12 | - name: CMake and NDK 13 | run: | 14 | cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_WERROR=ON -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -B build 15 | cmake --build build 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.a 3 | *.so 4 | *.so.* 5 | *.o 6 | .ccls-cache 7 | CMakeCache.txt 8 | CMakeFiles/ 9 | cmake_install.cmake 10 | compile_commands.json 11 | tags 12 | /build 13 | 14 | /asc2log 15 | /bcmserver 16 | /can-calc-bit-timing 17 | /canbusload 18 | /candump 19 | /canerrsim 20 | /canfdtest 21 | /cangen 22 | /cangw 23 | /canlogserver 24 | /canplayer 25 | /cansend 26 | /cansequence 27 | /cansniffer 28 | /isobusfs-cli 29 | /isobusfs-srv 30 | /isotpdump 31 | /isotpperf 32 | /isotprecv 33 | /isotpsend 34 | /isotpserver 35 | /isotpsniffer 36 | /isotptun 37 | /j1939acd 38 | /j1939cat 39 | /j1939spy 40 | /j1939sr 41 | /j1939-timedate-cli 42 | /j1939-timedate-srv 43 | /j1939-vehicle-position-srv 44 | /log2asc 45 | /log2long 46 | /mcp251xfd-dump 47 | /slcan_attach 48 | /slcand 49 | /slcanpty 50 | /testj1939 51 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(can-utils LANGUAGES C) 4 | 5 | message(STATUS "CMake version: ${CMAKE_VERSION}") 6 | 7 | include(CheckFunctionExists) 8 | include(CheckSymbolExists) 9 | include(GNUInstallDirs) 10 | 11 | if(NOT CMAKE_BUILD_TYPE) 12 | set(CMAKE_BUILD_TYPE Release) 13 | endif() 14 | 15 | if(CMAKE_EXPORT_COMPILE_COMMANDS STREQUAL "") 16 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "project default" FORCE) 17 | endif() 18 | 19 | # Add an option to enable treating warnings as errors 20 | option(ENABLE_WERROR "Treat all compiler warnings as errors" OFF) 21 | option(ENABLE_GPS "Enable GPS support" OFF) 22 | option(BUILD_SHARED_LIBS "Build shared libraries" ON) 23 | 24 | # Options for controlling targets. These groups correspond to the README. 25 | option(ENABLE_BASIC_TOOLS "Build basic tools" ON) 26 | option(ENABLE_IP_SERVER "Build tools providing CAN access via IP sockets" ON) 27 | option(ENABLE_GATEWAY "Build in-kernel gateway configuration tools" ON) 28 | option(ENABLE_MEASUREMENT "Build measurement tools" ON) 29 | option(ENABLE_ISOTP "Build isotp tools" ON) 30 | option(ENABLE_LOG_FILE "Build log file converter tools" ON) 31 | option(ENABLE_SLCAN "Build slcan tools" ON) 32 | option(ENABLE_MCP251XFD "Build MCP251XFD tools" ON) 33 | 34 | # cmake_dependent_option is only available in CMake 3.22 and later. 35 | if(ANDROID) 36 | set(ENABLE_J1939 OFF) 37 | set(ENABLE_ISOBUSFS OFF) 38 | else() 39 | option(ENABLE_J1939 "Build J1939 tools" ON) 40 | option(ENABLE_ISOBUSFS "Build ISOBUS tools" ON) 41 | endif() 42 | 43 | find_package(PkgConfig REQUIRED) 44 | if(ENABLE_GPS) 45 | pkg_check_modules(GPS REQUIRED libgps) 46 | endif() 47 | 48 | if(ENABLE_WERROR) 49 | add_compile_options(-Werror) 50 | endif() 51 | 52 | add_definitions(-D_GNU_SOURCE) 53 | 54 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses -Wsign-compare") 55 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing") 56 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_RXQ_OVFL=40") 57 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPF_CAN=29") 58 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAF_CAN=PF_CAN") 59 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DN_SLCAN=17") 60 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TIMESTAMPING_OPT_STATS=54") 61 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCLOCK_TAI=11") 62 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_TXTIME=61") 63 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TXTIME=SO_TXTIME") 64 | 65 | include_directories(.) 66 | include_directories(./include) 67 | 68 | check_function_exists(fork HAVE_FORK) 69 | 70 | # List of all programs to be built. 71 | # Each program is expected to have a corresponding source file with the same name. 72 | set(PROGRAMS) 73 | # List of programs to link against can. 74 | set(PROGRAMS_CANLIB) 75 | # List of programs to link against j1939 and can. 76 | set(PROGRAMS_J1939) 77 | 78 | if(ENABLE_BASIC_TOOLS) 79 | list(APPEND PROGRAMS cansniffer) 80 | list(APPEND PROGRAMS_CANLIB 81 | candump 82 | canplayer 83 | cansend 84 | cangen 85 | cansequence 86 | ) 87 | endif() 88 | 89 | if(ENABLE_IP_SERVER AND HAVE_FORK) 90 | list(APPEND PROGRAMS bcmserver) 91 | list(APPEND PROGRAMS_CANLIB canlogserver) 92 | endif() 93 | 94 | if(ENABLE_GATEWAY) 95 | list(APPEND PROGRAMS cangw) 96 | endif() 97 | 98 | if(ENABLE_MEASUREMENT) 99 | list(APPEND PROGRAMS 100 | canfdtest 101 | canerrsim 102 | ) 103 | list(APPEND PROGRAMS_CANLIB canbusload) 104 | 105 | add_executable(can-calc-bit-timing 106 | calc-bit-timing/can-calc-bit-timing.c 107 | ) 108 | install(TARGETS can-calc-bit-timing DESTINATION ${CMAKE_INSTALL_BINDIR}) 109 | endif() 110 | 111 | if(ENABLE_ISOTP) 112 | list(APPEND PROGRAMS 113 | isotpdump 114 | isotpperf 115 | isotprecv 116 | isotpsend 117 | isotpsniffer 118 | isotptun 119 | ) 120 | 121 | if(HAVE_FORK) 122 | list(APPEND PROGRAMS isotpserver) 123 | endif() 124 | endif() 125 | 126 | if(ENABLE_J1939) 127 | list(APPEND PROGRAMS_J1939 128 | j1939acd 129 | j1939cat 130 | j1939spy 131 | j1939sr 132 | testj1939 133 | ) 134 | 135 | add_executable(j1939-timedate-cli 136 | j1939_timedate/j1939_timedate_cli.c 137 | ) 138 | target_link_libraries(j1939-timedate-cli 139 | PRIVATE can j1939 140 | ) 141 | install(TARGETS j1939-timedate-cli DESTINATION ${CMAKE_INSTALL_BINDIR}) 142 | 143 | add_executable(j1939-timedate-srv 144 | j1939_timedate/j1939_timedate_srv.c 145 | ) 146 | target_link_libraries(j1939-timedate-srv 147 | PRIVATE can j1939 148 | ) 149 | install(TARGETS j1939-timedate-srv DESTINATION ${CMAKE_INSTALL_BINDIR}) 150 | endif() 151 | 152 | if(ENABLE_J1939 AND ENABLE_GPS) 153 | add_executable(j1939-vehicle-position-srv 154 | j1939_vehicle_position/j1939_vehicle_position_srv.c 155 | ) 156 | target_link_libraries(j1939-vehicle-position-srv 157 | PRIVATE can j1939 ${GPS_LIBRARIES} 158 | ) 159 | install(TARGETS j1939-vehicle-position-srv DESTINATION ${CMAKE_INSTALL_BINDIR}) 160 | endif() 161 | 162 | if(ENABLE_ISOBUSFS) 163 | add_library(isobusfs EXCLUDE_FROM_ALL 164 | isobusfs/isobusfs_cmn.c 165 | isobusfs/isobusfs_cmn_dh.c 166 | ) 167 | set(PUBLIC_HEADER_ISOBUSFS 168 | isobusfs/isobusfs_cmn.h 169 | isobusfs/isobusfs_cmn_cm.h 170 | ) 171 | set_target_properties(isobusfs PROPERTIES 172 | PUBLIC_HEADER "${PUBLIC_HEADER_ISOBUSFS}" 173 | SOVERSION 0 174 | ) 175 | install(TARGETS isobusfs 176 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 177 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 178 | ) 179 | 180 | add_executable(isobusfs-cli 181 | isobusfs/isobusfs_cli.c 182 | isobusfs/isobusfs_cli_cm.c 183 | isobusfs/isobusfs_cli_dh.c 184 | isobusfs/isobusfs_cli_fa.c 185 | isobusfs/isobusfs_cli_selftests.c 186 | isobusfs/isobusfs_cli_int.c 187 | ) 188 | target_link_libraries(isobusfs-cli 189 | PRIVATE isobusfs can j1939 190 | ) 191 | install(TARGETS isobusfs-cli DESTINATION ${CMAKE_INSTALL_BINDIR}) 192 | 193 | add_executable(isobusfs-srv 194 | isobusfs/isobusfs_srv.c 195 | isobusfs/isobusfs_srv_cm.c 196 | isobusfs/isobusfs_srv_cm_fss.c 197 | isobusfs/isobusfs_srv_dh.c 198 | isobusfs/isobusfs_srv_fa.c 199 | isobusfs/isobusfs_srv_fh.c 200 | isobusfs/isobusfs_srv_vh.c 201 | ) 202 | target_link_libraries(isobusfs-srv 203 | PRIVATE isobusfs can j1939 204 | ) 205 | install(TARGETS isobusfs-srv DESTINATION ${CMAKE_INSTALL_BINDIR}) 206 | endif() 207 | 208 | if(ENABLE_LOG_FILE) 209 | list(APPEND PROGRAMS_CANLIB 210 | asc2log 211 | log2asc 212 | log2long 213 | ) 214 | endif() 215 | 216 | if(ENABLE_SLCAN) 217 | list(APPEND PROGRAMS 218 | slcan_attach 219 | slcand 220 | ) 221 | list(APPEND PROGRAMS_CANLIB slcanpty) 222 | endif() 223 | 224 | if(ENABLE_MCP251XFD) 225 | add_executable(mcp251xfd-dump 226 | mcp251xfd/mcp251xfd-dev-coredump.c 227 | mcp251xfd/mcp251xfd-dump.c 228 | mcp251xfd/mcp251xfd-main.c 229 | mcp251xfd/mcp251xfd-regmap.c 230 | ) 231 | install(TARGETS mcp251xfd-dump DESTINATION ${CMAKE_INSTALL_BINDIR}) 232 | endif() 233 | 234 | list(APPEND PROGRAMS 235 | ${PROGRAMS_CANLIB} 236 | ${PROGRAMS_J1939} 237 | ) 238 | 239 | add_library(can STATIC EXCLUDE_FROM_ALL 240 | lib.c 241 | canframelen.c 242 | ) 243 | 244 | add_library(j1939 STATIC EXCLUDE_FROM_ALL 245 | libj1939.c 246 | ) 247 | target_link_libraries(j1939 248 | PRIVATE can 249 | ) 250 | 251 | foreach(name ${PROGRAMS}) 252 | add_executable(${name} ${name}.c) 253 | 254 | if("${name}" IN_LIST PROGRAMS_J1939) 255 | target_link_libraries(${name} 256 | PRIVATE j1939 can 257 | ) 258 | elseif("${name}" IN_LIST PROGRAMS_CANLIB) 259 | target_link_libraries(${name} 260 | PRIVATE can 261 | ) 262 | endif() 263 | 264 | install(TARGETS ${name} DESTINATION ${CMAKE_INSTALL_BINDIR}) 265 | endforeach() 266 | 267 | add_custom_target(uninstall 268 | "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake" 269 | COMMENT "Add uninstall target" 270 | ) 271 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause: -------------------------------------------------------------------------------- 1 | Copyright (c) . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its 14 | contributors may be used to endorse or promote products derived from this 15 | software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/Linux-syscall-note.txt: -------------------------------------------------------------------------------- 1 | NOTE! This copyright does *not* cover user programs that use kernel 2 | services by normal system calls - this is merely considered normal use 3 | of the kernel, and does *not* fall under the heading of "derived work". 4 | Also note that the GPL below is copyrighted by the Free Software 5 | Foundation, but the instance of code that it refers to (the Linux 6 | kernel) is copyrighted by me and others who actually wrote it. 7 | 8 | Also note that the only valid version of the GPL as far as the kernel 9 | is concerned is _this_ particular version of the license (ie v2, not 10 | v2.2 or v3.x or whatever), unless explicitly otherwise stated. 11 | 12 | Linus Torvalds 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2002-2005 Volkswagen Group Electronic Research 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions, the following disclaimer and 10 | # the referenced file 'COPYING'. 11 | # 2. Redistributions in binary form must reproduce the above copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # 3. Neither the name of Volkswagen nor the names of its contributors 15 | # may be used to endorse or promote products derived from this software 16 | # without specific prior written permission. 17 | # 18 | # Alternatively, provided that this notice is retained in full, this 19 | # software may be distributed under the terms of the GNU General 20 | # Public License ("GPL") version 2 as distributed in the 'COPYING' 21 | # file from the main directory of the linux kernel source. 22 | # 23 | # The provided data structures and external interfaces from this code 24 | # are not restricted to be used by modules with a GPL compatible license. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 37 | # DAMAGE. 38 | # 39 | # Send feedback to 40 | 41 | DESTDIR ?= 42 | PREFIX ?= /usr/local 43 | 44 | MAKEFLAGS := -k 45 | 46 | CFLAGS := -O2 -Wall -Wno-parentheses -Wsign-compare 47 | 48 | HAVE_FORK := $(shell ./check_cc.sh "$(CC)" fork_test.c) 49 | HAVE_LIBGPS := $(shell test -x "`which pkg-config`" && pkg-config --exists libgps && echo 1 || echo 0) 50 | 51 | CPPFLAGS += \ 52 | -I. \ 53 | -Iinclude \ 54 | -DAF_CAN=PF_CAN \ 55 | -DPF_CAN=29 \ 56 | -DSO_RXQ_OVFL=40 \ 57 | -DSCM_TIMESTAMPING_OPT_STATS=54 \ 58 | -DCLOCK_TAI=11 \ 59 | -DSO_TXTIME=61 \ 60 | -DSCM_TXTIME=SO_TXTIME \ 61 | -D_FILE_OFFSET_BITS=64 \ 62 | -D_GNU_SOURCE 63 | 64 | PROGRAMS_CANGW := \ 65 | cangw 66 | 67 | PROGRAMS_J1939_TIMEDATE := \ 68 | j1939-timedate-srv \ 69 | j1939-timedate-cli 70 | 71 | ifeq ($(HAVE_LIBGPS),1) 72 | PROGRAMS_J1939_VEHICLE_POSITION := \ 73 | j1939-vehicle-position-srv 74 | endif 75 | 76 | PROGRAMS_ISOBUSFS := \ 77 | isobusfs-srv \ 78 | isobusfs-cli 79 | 80 | PROGRAMS_ISOTP := \ 81 | isotpdump \ 82 | isotpperf \ 83 | isotprecv \ 84 | isotpsend \ 85 | isotpsniffer \ 86 | isotptun 87 | 88 | ifeq ($(HAVE_FORK),1) 89 | PROGRAMS_ISOTP += \ 90 | isotpserver 91 | endif 92 | 93 | PROGRAMS_J1939 := \ 94 | j1939acd \ 95 | j1939cat \ 96 | j1939spy \ 97 | j1939sr \ 98 | testj1939 99 | 100 | PROGRAMS_SLCAN := \ 101 | slcan_attach \ 102 | slcand 103 | 104 | PROGRAMS := \ 105 | $(PROGRAMS_CANGW) \ 106 | $(PROGRAMS_J1939_TIMEDATE) \ 107 | $(PROGRAMS_J1939_VEHICLE_POSITION) \ 108 | $(PROGRAMS_ISOBUSFS) \ 109 | $(PROGRAMS_ISOTP) \ 110 | $(PROGRAMS_J1939) \ 111 | $(PROGRAMS_SLCAN) \ 112 | asc2log \ 113 | can-calc-bit-timing \ 114 | canbusload \ 115 | candump \ 116 | canerrsim \ 117 | canfdtest \ 118 | cangen \ 119 | cansequence \ 120 | canplayer \ 121 | cansend \ 122 | cansniffer \ 123 | log2asc \ 124 | log2long \ 125 | mcp251xfd-dump \ 126 | slcanpty 127 | 128 | ifeq ($(HAVE_FORK),1) 129 | PROGRAMS += \ 130 | canlogserver \ 131 | bcmserver 132 | endif 133 | 134 | all: $(PROGRAMS) 135 | 136 | clean: 137 | rm -f $(PROGRAMS) *.o mcp251xfd/*.o isobusfs/*.o j1939_timedate/*.o \ 138 | j1939_vehicle_position/*.o 139 | 140 | install: 141 | mkdir -p $(DESTDIR)$(PREFIX)/bin 142 | cp -f $(PROGRAMS) $(DESTDIR)$(PREFIX)/bin 143 | 144 | distclean: clean 145 | rm -f $(PROGRAMS) $(LIBRARIES) *~ 146 | 147 | asc2log.o: lib.h 148 | candump.o: lib.h 149 | cangen.o: lib.h 150 | canlogserver.o: lib.h 151 | canplayer.o: lib.h 152 | cansend.o: lib.h 153 | log2asc.o: lib.h 154 | log2long.o: lib.h 155 | slcanpty.o: lib.h 156 | j1939acd.o: lib.h libj1939.h 157 | j1939cat.o: lib.h libj1939.h 158 | j1939spy.o: lib.h libj1939.h 159 | j1939sr.o: lib.h libj1939.h 160 | testj1939.o: lib.h libj1939.h 161 | isobusfs_srv.o: lib.h libj1939.h 162 | isobusfs_c.o: lib.h libj1939.h 163 | j1939_timedate_srv.o: lib.h libj1939.h 164 | j1939_timedate_cli.o: lib.h libj1939.h 165 | j1939_vehicle_position_srv.o: lib.h libj1939.h 166 | 167 | canframelen.o: canframelen.h 168 | 169 | asc2log: asc2log.o lib.o 170 | canbusload: canbusload.o canframelen.o 171 | candump: candump.o lib.o 172 | cangen: cangen.o lib.o 173 | canlogserver: canlogserver.o lib.o 174 | canplayer: canplayer.o lib.o 175 | cansend: cansend.o lib.o 176 | cansequence: cansequence.o lib.o 177 | log2asc: log2asc.o lib.o 178 | log2long: log2long.o lib.o 179 | slcanpty: slcanpty.o lib.o 180 | j1939acd: j1939acd.o lib.o libj1939.o 181 | j1939cat: j1939cat.o lib.o libj1939.o 182 | j1939spy: j1939spy.o lib.o libj1939.o 183 | j1939sr: j1939sr.o lib.o libj1939.o 184 | testj1939: testj1939.o lib.o libj1939.o 185 | 186 | j1939-timedate-srv: lib.o \ 187 | libj1939.o \ 188 | j1939_timedate/j1939_timedate_srv.o 189 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 190 | 191 | j1939-timedate-cli: lib.o \ 192 | libj1939.o \ 193 | j1939_timedate/j1939_timedate_cli.o 194 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 195 | 196 | j1939-vehicle-position-srv: \ 197 | lib.o \ 198 | libj1939.o \ 199 | j1939_vehicle_position/j1939_vehicle_position_srv.o 200 | $(CC) $(LDFLAGS) $^ $(LDLIBS) $(shell pkg-config --libs libgps) -o $@ 201 | 202 | isobusfs-srv: lib.o \ 203 | libj1939.o \ 204 | isobusfs/isobusfs_cmn.o \ 205 | isobusfs/isobusfs_srv.o \ 206 | isobusfs/isobusfs_srv_cm.o \ 207 | isobusfs/isobusfs_srv_cm_fss.o \ 208 | isobusfs/isobusfs_srv_dh.o \ 209 | isobusfs/isobusfs_srv_fa.o \ 210 | isobusfs/isobusfs_srv_fh.o \ 211 | isobusfs/isobusfs_srv_vh.o \ 212 | isobusfs/isobusfs_cmn_dh.o 213 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 214 | 215 | isobusfs-cli: lib.o \ 216 | libj1939.o \ 217 | isobusfs/isobusfs_cmn.o \ 218 | isobusfs/isobusfs_cli.o \ 219 | isobusfs/isobusfs_cli_cm.o \ 220 | isobusfs/isobusfs_cli_dh.o \ 221 | isobusfs/isobusfs_cli_fa.o \ 222 | isobusfs/isobusfs_cli_selftests.o \ 223 | isobusfs/isobusfs_cli_int.o 224 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 225 | 226 | can-calc-bit-timing: calc-bit-timing/can-calc-bit-timing.o 227 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 228 | 229 | mcp251xfd-dump: mcp251xfd/mcp251xfd-dev-coredump.o mcp251xfd/mcp251xfd-dump.o mcp251xfd/mcp251xfd-main.o mcp251xfd/mcp251xfd-regmap.o 230 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 231 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | SocketCAN logo 3 |

4 | 5 | ### SocketCAN userspace utilities and tools 6 | 7 | This repository contains some userspace utilities for Linux CAN 8 | subsystem (aka SocketCAN): 9 | 10 | #### Basic tools to display, record, generate and replay CAN traffic 11 | 12 | * candump : display, filter and log CAN data to files 13 | * canplayer : replay CAN logfiles 14 | * cansend : send a single frame 15 | * cangen : generate (random) CAN traffic 16 | * cansequence : send and check sequence of CAN frames with incrementing payload 17 | * cansniffer : display CAN data content differences 18 | 19 | #### CAN access via IP sockets 20 | * canlogserver : log CAN frames and serves them 21 | * bcmserver : interactive BCM configuration (remote/local) 22 | * [socketcand](https://github.com/linux-can/socketcand) : use RAW/BCM/ISO-TP sockets via TCP/IP sockets 23 | * [cannelloni](https://github.com/mguentner/cannelloni) : UDP/SCTP based SocketCAN tunnel 24 | 25 | #### CAN in-kernel gateway configuration 26 | * cangw : CAN gateway userspace tool for netlink configuration 27 | 28 | #### CAN bus measurement and testing 29 | * canbusload : calculate and display the CAN busload 30 | * can-calc-bit-timing : userspace version of in-kernel bitrate calculation 31 | * canfdtest : Full-duplex test program (DUT and host part) 32 | * canerrsim : CAN error message simulator 33 | 34 | #### ISO-TP tools [ISO15765-2:2016 for Linux](https://github.com/hartkopp/can-isotp) 35 | * isotpsend : send a single ISO-TP PDU 36 | * isotprecv : receive ISO-TP PDU(s) 37 | * isotpsniffer : 'wiretap' ISO-TP PDU(s) 38 | * isotpdump : 'wiretap' and interpret CAN messages (CAN_RAW) 39 | * isotpserver : IP server for simple TCP/IP <-> ISO 15765-2 bridging (ASCII HEX) 40 | * isotpperf : ISO15765-2 protocol performance visualisation 41 | * isotptun : create a bi-directional IP tunnel on CAN via ISO-TP 42 | 43 | #### J1939/ISOBus tools 44 | * j1939acd : address claim daemon 45 | * j1939cat : take a file and send and receive it over CAN 46 | * j1939spy : spy on J1939 messages using SOC_J1939 47 | * j1939sr : send/recv from stdin or to stdout 48 | * testj1939 : send/receive test packet 49 | 50 | Follow the link to see examples on how this tools can be used: 51 | [Kickstart guide to can-j1939 on linux](https://github.com/linux-can/can-utils/blob/master/can-j1939-kickstart.md) 52 | 53 | #### ISOBus File server tools 54 | * isobusfs-cli : ISOBus file client 55 | * isobusfs-srv : ISOBus file server 56 | 57 | #### Log file converters 58 | * asc2log : convert ASC logfile to compact CAN frame logfile 59 | * log2asc : convert compact CAN frame logfile to ASC logfile 60 | * log2long : convert compact CAN frame representation into user readable 61 | 62 | #### Serial Line Discipline configuration (for slcan driver) 63 | * slcan_attach : userspace tool for serial line CAN interface configuration 64 | * slcand : daemon for serial line CAN interface configuration 65 | * slcanpty : creates a pty for applications using the slcan ASCII protocol 66 | 67 | #### CMake Project Generator 68 | * Place your build folder anywhere, passing CMake the path. Relative or absolute. 69 | * Some examples using a build folder under the source tree root: 70 | * Android : ``cmake -DCMAKE_TOOLCHAIN_FILE=~/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=android-21 -DANDROID_ABI=armeabi-v7a .. && make`` 71 | * Android Studio : Copy repo under your project's ``app`` folder, add ``add_subdirectory(can-utils)`` to your ``CMakeLists.txt`` file after ``cmake_minimum_required()``. Generating project will build Debug/Release for all supported EABI types. ie. arm64-v8a, armeabi-v7a, x86, x86_64. 72 | * Raspberry Pi : ``cmake -DCMAKE_TOOLCHAIN_FILE=~/rpi/tools/build/cmake/rpi.toolchain.cmake .. && make`` 73 | * Linux : ``cmake -GNinja .. && ninja`` 74 | * Linux Eclipse Photon (Debug) : ``CC=clang cmake -G"Eclipse CDT4 - Unix Makefiles" ../can-utils/ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_ECLIPSE_VERSION=4.8.0`` 75 | * To override the base installation directory use: ``CMAKE_INSTALL_PREFIX`` 76 | ie. ``CC=clang cmake -DCMAKE_INSTALL_PREFIX=./out .. && make install`` 77 | 78 | ### Additional Information: 79 | 80 | * [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/html/latest/networking/can.html) 81 | * [Elinux.org CAN Bus Page](http://elinux.org/CAN_Bus) 82 | * [Debian Package Description](https://packages.debian.org/sid/can-utils) 83 | * [J1939 kernel module installation on Debian](can-j1939-install-kernel-module.md) 84 | -------------------------------------------------------------------------------- /calc-bit-timing/can-calc-bit-timing-v2_6_31.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | 3 | #include "compat.h" 4 | 5 | /* 6 | * imported from v2.6.31-rc1~330^2~376 7 | * 8 | * 39549eef3587 can: CAN Network device driver and Netlink interface 9 | * 10 | * cherry-picked for easier integration: 11 | * 61463a30f652 can: make function can_get_bittiming static 12 | * aabdfd6adb80 can: replace the dev_dbg/info/err/... with the new netdev_xxx macros 13 | * 08da7da41ea4 can: provide a separate bittiming_const parameter to bittiming functions 14 | * b25a437206ed can: dev: remove unused variable from can_calc_bittiming() function 15 | */ 16 | 17 | /* 18 | * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix 19 | * Copyright (C) 2006 Andrey Volkov, Varma Electronics 20 | * Copyright (C) 2008-2009 Wolfgang Grandegger 21 | * 22 | * This program is free software; you can redistribute it and/or modify 23 | * it under the terms of the version 2 of the GNU General Public License 24 | * as published by the Free Software Foundation 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program; if not, write to the Free Software 33 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 34 | */ 35 | 36 | /* 37 | * Bit-timing calculation derived from: 38 | * 39 | * Code based on LinCAN sources and H8S2638 project 40 | * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz 41 | * Copyright 2005 Stanislav Marek 42 | * email: pisa@cmp.felk.cvut.cz 43 | * 44 | * Calculates proper bit-timing parameters for a specified bit-rate 45 | * and sample-point, which can then be used to set the bit-timing 46 | * registers of the CAN controller. You can find more information 47 | * in the header file linux/can/netlink.h. 48 | */ 49 | static int can_update_spt(const struct can_bittiming_const *btc, 50 | int sampl_pt, int tseg, int *tseg1, int *tseg2) 51 | { 52 | *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000; 53 | if (*tseg2 < btc->tseg2_min) 54 | *tseg2 = btc->tseg2_min; 55 | if (*tseg2 > btc->tseg2_max) 56 | *tseg2 = btc->tseg2_max; 57 | *tseg1 = tseg - *tseg2; 58 | if (*tseg1 > btc->tseg1_max) { 59 | *tseg1 = btc->tseg1_max; 60 | *tseg2 = tseg - *tseg1; 61 | } 62 | return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); 63 | } 64 | 65 | static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, 66 | const struct can_bittiming_const *btc) 67 | { 68 | struct can_priv *priv = netdev_priv(dev); 69 | long best_error = 1000000000, error = 0; 70 | int best_tseg = 0, best_brp = 0, brp = 0; 71 | int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0; 72 | int spt_error = 1000, spt = 0, sampl_pt; 73 | long rate; 74 | u64 v64; 75 | 76 | /* Use CIA recommended sample points */ 77 | if (bt->sample_point) { 78 | sampl_pt = bt->sample_point; 79 | } else { 80 | if (bt->bitrate > 800000) 81 | sampl_pt = 750; 82 | else if (bt->bitrate > 500000) 83 | sampl_pt = 800; 84 | else 85 | sampl_pt = 875; 86 | } 87 | 88 | /* tseg even = round down, odd = round up */ 89 | for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; 90 | tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { 91 | tsegall = 1 + tseg / 2; 92 | /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ 93 | brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; 94 | /* chose brp step which is possible in system */ 95 | brp = (brp / btc->brp_inc) * btc->brp_inc; 96 | if ((brp < btc->brp_min) || (brp > btc->brp_max)) 97 | continue; 98 | rate = priv->clock.freq / (brp * tsegall); 99 | error = bt->bitrate - rate; 100 | /* tseg brp biterror */ 101 | if (error < 0) 102 | error = -error; 103 | if (error > best_error) 104 | continue; 105 | best_error = error; 106 | if (error == 0) { 107 | spt = can_update_spt(btc, sampl_pt, tseg / 2, 108 | &tseg1, &tseg2); 109 | error = sampl_pt - spt; 110 | if (error < 0) 111 | error = -error; 112 | if (error > spt_error) 113 | continue; 114 | spt_error = error; 115 | } 116 | best_tseg = tseg / 2; 117 | best_brp = brp; 118 | if (error == 0) 119 | break; 120 | } 121 | 122 | if (best_error) { 123 | /* Error in one-tenth of a percent */ 124 | error = (best_error * 1000) / bt->bitrate; 125 | if (error > CAN_CALC_MAX_ERROR) { 126 | netdev_err(dev, 127 | "bitrate error %ld.%ld%% too high\n", 128 | error / 10, error % 10); 129 | return -EDOM; 130 | } else { 131 | netdev_warn(dev, "bitrate error %ld.%ld%%\n", 132 | error / 10, error % 10); 133 | } 134 | } 135 | 136 | /* real sample point */ 137 | bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg, 138 | &tseg1, &tseg2); 139 | 140 | v64 = (u64)best_brp * 1000000000UL; 141 | do_div(v64, priv->clock.freq); 142 | bt->tq = (u32)v64; 143 | bt->prop_seg = tseg1 / 2; 144 | bt->phase_seg1 = tseg1 - bt->prop_seg; 145 | bt->phase_seg2 = tseg2; 146 | bt->sjw = 1; 147 | bt->brp = best_brp; 148 | /* real bit-rate */ 149 | bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1)); 150 | 151 | return 0; 152 | } 153 | 154 | /* 155 | * Checks the validity of the specified bit-timing parameters prop_seg, 156 | * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate 157 | * prescaler value brp. You can find more information in the header 158 | * file linux/can/netlink.h. 159 | */ 160 | static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, 161 | const struct can_bittiming_const *btc) 162 | { 163 | struct can_priv *priv = netdev_priv(dev); 164 | int tseg1, alltseg; 165 | u64 brp64; 166 | 167 | tseg1 = bt->prop_seg + bt->phase_seg1; 168 | if (!bt->sjw) 169 | bt->sjw = 1; 170 | if (bt->sjw > btc->sjw_max || 171 | tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || 172 | bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) 173 | return -ERANGE; 174 | 175 | brp64 = (u64)priv->clock.freq * (u64)bt->tq; 176 | if (btc->brp_inc > 1) 177 | do_div(brp64, btc->brp_inc); 178 | brp64 += 500000000UL - 1; 179 | do_div(brp64, 1000000000UL); /* the practicable BRP */ 180 | if (btc->brp_inc > 1) 181 | brp64 *= btc->brp_inc; 182 | bt->brp = (u32)brp64; 183 | 184 | if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) 185 | return -EINVAL; 186 | 187 | alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; 188 | bt->bitrate = priv->clock.freq / (bt->brp * alltseg); 189 | bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; 190 | 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /calc-bit-timing/can-calc-bit-timing-v3_18.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | 3 | #include "compat.h" 4 | 5 | /* 6 | * imported from v3.18-rc1~52^2~248^2~1 7 | * 8 | */ 9 | 10 | /* 11 | * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix 12 | * Copyright (C) 2006 Andrey Volkov, Varma Electronics 13 | * Copyright (C) 2008-2009 Wolfgang Grandegger 14 | * 15 | * This program is free software; you can redistribute it and/or modify 16 | * it under the terms of the version 2 of the GNU General Public License 17 | * as published by the Free Software Foundation 18 | * 19 | * This program is distributed in the hope that it will be useful, 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | * GNU General Public License for more details. 23 | * 24 | * You should have received a copy of the GNU General Public License 25 | * along with this program; if not, see . 26 | */ 27 | 28 | /* 29 | * Bit-timing calculation derived from: 30 | * 31 | * Code based on LinCAN sources and H8S2638 project 32 | * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz 33 | * Copyright 2005 Stanislav Marek 34 | * email: pisa@cmp.felk.cvut.cz 35 | * 36 | * Calculates proper bit-timing parameters for a specified bit-rate 37 | * and sample-point, which can then be used to set the bit-timing 38 | * registers of the CAN controller. You can find more information 39 | * in the header file linux/can/netlink.h. 40 | */ 41 | static int can_update_spt(const struct can_bittiming_const *btc, 42 | int sampl_pt, int tseg, int *tseg1, int *tseg2) 43 | { 44 | *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000; 45 | if (*tseg2 < btc->tseg2_min) 46 | *tseg2 = btc->tseg2_min; 47 | if (*tseg2 > btc->tseg2_max) 48 | *tseg2 = btc->tseg2_max; 49 | *tseg1 = tseg - *tseg2; 50 | if (*tseg1 > btc->tseg1_max) { 51 | *tseg1 = btc->tseg1_max; 52 | *tseg2 = tseg - *tseg1; 53 | } 54 | return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); 55 | } 56 | 57 | static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, 58 | const struct can_bittiming_const *btc) 59 | { 60 | struct can_priv *priv = netdev_priv(dev); 61 | long best_error = 1000000000, error = 0; 62 | int best_tseg = 0, best_brp = 0, brp = 0; 63 | int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0; 64 | int spt_error = 1000, spt = 0, sampl_pt; 65 | long rate; 66 | u64 v64; 67 | 68 | /* Use CIA recommended sample points */ 69 | if (bt->sample_point) { 70 | sampl_pt = bt->sample_point; 71 | } else { 72 | if (bt->bitrate > 800000) 73 | sampl_pt = 750; 74 | else if (bt->bitrate > 500000) 75 | sampl_pt = 800; 76 | else 77 | sampl_pt = 875; 78 | } 79 | 80 | /* tseg even = round down, odd = round up */ 81 | for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; 82 | tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { 83 | tsegall = 1 + tseg / 2; 84 | /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ 85 | brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; 86 | /* chose brp step which is possible in system */ 87 | brp = (brp / btc->brp_inc) * btc->brp_inc; 88 | if ((brp < btc->brp_min) || (brp > btc->brp_max)) 89 | continue; 90 | rate = priv->clock.freq / (brp * tsegall); 91 | error = bt->bitrate - rate; 92 | /* tseg brp biterror */ 93 | if (error < 0) 94 | error = -error; 95 | if (error > best_error) 96 | continue; 97 | best_error = error; 98 | if (error == 0) { 99 | spt = can_update_spt(btc, sampl_pt, tseg / 2, 100 | &tseg1, &tseg2); 101 | error = sampl_pt - spt; 102 | if (error < 0) 103 | error = -error; 104 | if (error > spt_error) 105 | continue; 106 | spt_error = error; 107 | } 108 | best_tseg = tseg / 2; 109 | best_brp = brp; 110 | if (error == 0) 111 | break; 112 | } 113 | 114 | if (best_error) { 115 | /* Error in one-tenth of a percent */ 116 | error = (best_error * 1000) / bt->bitrate; 117 | if (error > CAN_CALC_MAX_ERROR) { 118 | netdev_err(dev, 119 | "bitrate error %ld.%ld%% too high\n", 120 | error / 10, error % 10); 121 | return -EDOM; 122 | } else { 123 | netdev_warn(dev, "bitrate error %ld.%ld%%\n", 124 | error / 10, error % 10); 125 | } 126 | } 127 | 128 | /* real sample point */ 129 | bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg, 130 | &tseg1, &tseg2); 131 | 132 | v64 = (u64)best_brp * 1000000000UL; 133 | do_div(v64, priv->clock.freq); 134 | bt->tq = (u32)v64; 135 | bt->prop_seg = tseg1 / 2; 136 | bt->phase_seg1 = tseg1 - bt->prop_seg; 137 | bt->phase_seg2 = tseg2; 138 | 139 | /* check for sjw user settings */ 140 | if (!bt->sjw || !btc->sjw_max) 141 | bt->sjw = 1; 142 | else { 143 | /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ 144 | if (bt->sjw > btc->sjw_max) 145 | bt->sjw = btc->sjw_max; 146 | /* bt->sjw must not be higher than tseg2 */ 147 | if (tseg2 < bt->sjw) 148 | bt->sjw = tseg2; 149 | } 150 | 151 | bt->brp = best_brp; 152 | /* real bit-rate */ 153 | bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1)); 154 | 155 | return 0; 156 | } 157 | 158 | /* 159 | * Checks the validity of the specified bit-timing parameters prop_seg, 160 | * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate 161 | * prescaler value brp. You can find more information in the header 162 | * file linux/can/netlink.h. 163 | */ 164 | static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, 165 | const struct can_bittiming_const *btc) 166 | { 167 | struct can_priv *priv = netdev_priv(dev); 168 | int tseg1, alltseg; 169 | u64 brp64; 170 | 171 | tseg1 = bt->prop_seg + bt->phase_seg1; 172 | if (!bt->sjw) 173 | bt->sjw = 1; 174 | if (bt->sjw > btc->sjw_max || 175 | tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || 176 | bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) 177 | return -ERANGE; 178 | 179 | brp64 = (u64)priv->clock.freq * (u64)bt->tq; 180 | if (btc->brp_inc > 1) 181 | do_div(brp64, btc->brp_inc); 182 | brp64 += 500000000UL - 1; 183 | do_div(brp64, 1000000000UL); /* the practicable BRP */ 184 | if (btc->brp_inc > 1) 185 | brp64 *= btc->brp_inc; 186 | bt->brp = (u32)brp64; 187 | 188 | if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) 189 | return -EINVAL; 190 | 191 | alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; 192 | bt->bitrate = priv->clock.freq / (bt->brp * alltseg); 193 | bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; 194 | 195 | return 0; 196 | } 197 | -------------------------------------------------------------------------------- /calc-bit-timing/can-calc-bit-timing-v5_16.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | 3 | #include "compat.h" 4 | 5 | /* 6 | * imported from v5.16-rc1~159^2~104^2~13 7 | * 8 | */ 9 | 10 | /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix 11 | * Copyright (C) 2006 Andrey Volkov, Varma Electronics 12 | * Copyright (C) 2008-2009 Wolfgang Grandegger 13 | */ 14 | 15 | /* Bit-timing calculation derived from: 16 | * 17 | * Code based on LinCAN sources and H8S2638 project 18 | * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz 19 | * Copyright 2005 Stanislav Marek 20 | * email: pisa@cmp.felk.cvut.cz 21 | * 22 | * Calculates proper bit-timing parameters for a specified bit-rate 23 | * and sample-point, which can then be used to set the bit-timing 24 | * registers of the CAN controller. You can find more information 25 | * in the header file linux/can/netlink.h. 26 | */ 27 | static int 28 | can_update_sample_point(const struct can_bittiming_const *btc, 29 | unsigned int sample_point_nominal, unsigned int tseg, 30 | unsigned int *tseg1_ptr, unsigned int *tseg2_ptr, 31 | unsigned int *sample_point_error_ptr) 32 | { 33 | unsigned int sample_point_error, best_sample_point_error = UINT_MAX; 34 | unsigned int sample_point, best_sample_point = 0; 35 | unsigned int tseg1, tseg2; 36 | int i; 37 | 38 | for (i = 0; i <= 1; i++) { 39 | tseg2 = tseg + CAN_SYNC_SEG - 40 | (sample_point_nominal * (tseg + CAN_SYNC_SEG)) / 41 | 1000 - i; 42 | tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); 43 | tseg1 = tseg - tseg2; 44 | if (tseg1 > btc->tseg1_max) { 45 | tseg1 = btc->tseg1_max; 46 | tseg2 = tseg - tseg1; 47 | } 48 | 49 | sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) / 50 | (tseg + CAN_SYNC_SEG); 51 | sample_point_error = abs(sample_point_nominal - sample_point); 52 | 53 | if (sample_point <= sample_point_nominal && 54 | sample_point_error < best_sample_point_error) { 55 | best_sample_point = sample_point; 56 | best_sample_point_error = sample_point_error; 57 | *tseg1_ptr = tseg1; 58 | *tseg2_ptr = tseg2; 59 | } 60 | } 61 | 62 | if (sample_point_error_ptr) 63 | *sample_point_error_ptr = best_sample_point_error; 64 | 65 | return best_sample_point; 66 | } 67 | 68 | int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, 69 | const struct can_bittiming_const *btc) 70 | { 71 | struct can_priv *priv = netdev_priv(dev); 72 | unsigned int bitrate; /* current bitrate */ 73 | unsigned int bitrate_error; /* difference between current and nominal value */ 74 | unsigned int best_bitrate_error = UINT_MAX; 75 | unsigned int sample_point_error; /* difference between current and nominal value */ 76 | unsigned int best_sample_point_error = UINT_MAX; 77 | unsigned int sample_point_nominal; /* nominal sample point */ 78 | unsigned int best_tseg = 0; /* current best value for tseg */ 79 | unsigned int best_brp = 0; /* current best value for brp */ 80 | unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0; 81 | u64 v64; 82 | 83 | /* Use CiA recommended sample points */ 84 | if (bt->sample_point) { 85 | sample_point_nominal = bt->sample_point; 86 | } else { 87 | if (bt->bitrate > 800 * CAN_KBPS) 88 | sample_point_nominal = 750; 89 | else if (bt->bitrate > 500 * CAN_KBPS) 90 | sample_point_nominal = 800; 91 | else 92 | sample_point_nominal = 875; 93 | } 94 | 95 | /* tseg even = round down, odd = round up */ 96 | for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; 97 | tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { 98 | tsegall = CAN_SYNC_SEG + tseg / 2; 99 | 100 | /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ 101 | brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; 102 | 103 | /* choose brp step which is possible in system */ 104 | brp = (brp / btc->brp_inc) * btc->brp_inc; 105 | if (brp < btc->brp_min || brp > btc->brp_max) 106 | continue; 107 | 108 | bitrate = priv->clock.freq / (brp * tsegall); 109 | bitrate_error = abs(bt->bitrate - bitrate); 110 | 111 | /* tseg brp biterror */ 112 | if (bitrate_error > best_bitrate_error) 113 | continue; 114 | 115 | /* reset sample point error if we have a better bitrate */ 116 | if (bitrate_error < best_bitrate_error) 117 | best_sample_point_error = UINT_MAX; 118 | 119 | can_update_sample_point(btc, sample_point_nominal, tseg / 2, 120 | &tseg1, &tseg2, &sample_point_error); 121 | if (sample_point_error > best_sample_point_error) 122 | continue; 123 | 124 | best_sample_point_error = sample_point_error; 125 | best_bitrate_error = bitrate_error; 126 | best_tseg = tseg / 2; 127 | best_brp = brp; 128 | 129 | if (bitrate_error == 0 && sample_point_error == 0) 130 | break; 131 | } 132 | 133 | if (best_bitrate_error) { 134 | /* Error in one-tenth of a percent */ 135 | v64 = (u64)best_bitrate_error * 1000; 136 | do_div(v64, bt->bitrate); 137 | bitrate_error = (u32)v64; 138 | if (bitrate_error > CAN_CALC_MAX_ERROR) { 139 | netdev_err(dev, 140 | "bitrate error %d.%d%% too high\n", 141 | bitrate_error / 10, bitrate_error % 10); 142 | return -EDOM; 143 | } 144 | netdev_warn(dev, "bitrate error %d.%d%%\n", 145 | bitrate_error / 10, bitrate_error % 10); 146 | } 147 | 148 | /* real sample point */ 149 | bt->sample_point = can_update_sample_point(btc, sample_point_nominal, 150 | best_tseg, &tseg1, &tseg2, 151 | NULL); 152 | 153 | v64 = (u64)best_brp * 1000 * 1000 * 1000; 154 | do_div(v64, priv->clock.freq); 155 | bt->tq = (u32)v64; 156 | bt->prop_seg = tseg1 / 2; 157 | bt->phase_seg1 = tseg1 - bt->prop_seg; 158 | bt->phase_seg2 = tseg2; 159 | 160 | /* check for sjw user settings */ 161 | if (!bt->sjw || !btc->sjw_max) { 162 | bt->sjw = 1; 163 | } else { 164 | /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ 165 | if (bt->sjw > btc->sjw_max) 166 | bt->sjw = btc->sjw_max; 167 | /* bt->sjw must not be higher than tseg2 */ 168 | if (tseg2 < bt->sjw) 169 | bt->sjw = tseg2; 170 | } 171 | 172 | bt->brp = best_brp; 173 | 174 | /* real bitrate */ 175 | bt->bitrate = priv->clock.freq / 176 | (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2)); 177 | 178 | return 0; 179 | } 180 | 181 | /* Checks the validity of the specified bit-timing parameters prop_seg, 182 | * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate 183 | * prescaler value brp. You can find more information in the header 184 | * file linux/can/netlink.h. 185 | */ 186 | static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, 187 | const struct can_bittiming_const *btc) 188 | { 189 | struct can_priv *priv = netdev_priv(dev); 190 | unsigned int tseg1, alltseg; 191 | u64 brp64; 192 | 193 | tseg1 = bt->prop_seg + bt->phase_seg1; 194 | if (!bt->sjw) 195 | bt->sjw = 1; 196 | if (bt->sjw > btc->sjw_max || 197 | tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || 198 | bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) 199 | return -ERANGE; 200 | 201 | brp64 = (u64)priv->clock.freq * (u64)bt->tq; 202 | if (btc->brp_inc > 1) 203 | do_div(brp64, btc->brp_inc); 204 | brp64 += 500000000UL - 1; 205 | do_div(brp64, 1000000000UL); /* the practicable BRP */ 206 | if (btc->brp_inc > 1) 207 | brp64 *= btc->brp_inc; 208 | bt->brp = (u32)brp64; 209 | 210 | if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) 211 | return -EINVAL; 212 | 213 | alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; 214 | bt->bitrate = priv->clock.freq / (bt->brp * alltseg); 215 | bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; 216 | 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /calc-bit-timing/can-calc-bit-timing-v5_19.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | 3 | #include "compat.h" 4 | 5 | /* 6 | * imported from v5.19-rc1~159^2~286^2~15 7 | * 8 | */ 9 | 10 | /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix 11 | * Copyright (C) 2006 Andrey Volkov, Varma Electronics 12 | * Copyright (C) 2008-2009 Wolfgang Grandegger 13 | */ 14 | 15 | /* Bit-timing calculation derived from: 16 | * 17 | * Code based on LinCAN sources and H8S2638 project 18 | * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz 19 | * Copyright 2005 Stanislav Marek 20 | * email: pisa@cmp.felk.cvut.cz 21 | * 22 | * Calculates proper bit-timing parameters for a specified bit-rate 23 | * and sample-point, which can then be used to set the bit-timing 24 | * registers of the CAN controller. You can find more information 25 | * in the header file linux/can/netlink.h. 26 | */ 27 | static int 28 | can_update_sample_point(const struct can_bittiming_const *btc, 29 | const unsigned int sample_point_nominal, const unsigned int tseg, 30 | unsigned int *tseg1_ptr, unsigned int *tseg2_ptr, 31 | unsigned int *sample_point_error_ptr) 32 | { 33 | unsigned int sample_point_error, best_sample_point_error = UINT_MAX; 34 | unsigned int sample_point, best_sample_point = 0; 35 | unsigned int tseg1, tseg2; 36 | int i; 37 | 38 | for (i = 0; i <= 1; i++) { 39 | tseg2 = tseg + CAN_SYNC_SEG - 40 | (sample_point_nominal * (tseg + CAN_SYNC_SEG)) / 41 | 1000 - i; 42 | tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); 43 | tseg1 = tseg - tseg2; 44 | if (tseg1 > btc->tseg1_max) { 45 | tseg1 = btc->tseg1_max; 46 | tseg2 = tseg - tseg1; 47 | } 48 | 49 | sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) / 50 | (tseg + CAN_SYNC_SEG); 51 | sample_point_error = abs(sample_point_nominal - sample_point); 52 | 53 | if (sample_point <= sample_point_nominal && 54 | sample_point_error < best_sample_point_error) { 55 | best_sample_point = sample_point; 56 | best_sample_point_error = sample_point_error; 57 | *tseg1_ptr = tseg1; 58 | *tseg2_ptr = tseg2; 59 | } 60 | } 61 | 62 | if (sample_point_error_ptr) 63 | *sample_point_error_ptr = best_sample_point_error; 64 | 65 | return best_sample_point; 66 | } 67 | 68 | int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt, 69 | const struct can_bittiming_const *btc) 70 | { 71 | struct can_priv *priv = netdev_priv(dev); 72 | unsigned int bitrate; /* current bitrate */ 73 | unsigned int bitrate_error; /* difference between current and nominal value */ 74 | unsigned int best_bitrate_error = UINT_MAX; 75 | unsigned int sample_point_error; /* difference between current and nominal value */ 76 | unsigned int best_sample_point_error = UINT_MAX; 77 | unsigned int sample_point_nominal; /* nominal sample point */ 78 | unsigned int best_tseg = 0; /* current best value for tseg */ 79 | unsigned int best_brp = 0; /* current best value for brp */ 80 | unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0; 81 | u64 v64; 82 | 83 | /* Use CiA recommended sample points */ 84 | if (bt->sample_point) { 85 | sample_point_nominal = bt->sample_point; 86 | } else { 87 | if (bt->bitrate > 800 * KILO /* BPS */) 88 | sample_point_nominal = 750; 89 | else if (bt->bitrate > 500 * KILO /* BPS */) 90 | sample_point_nominal = 800; 91 | else 92 | sample_point_nominal = 875; 93 | } 94 | 95 | /* tseg even = round down, odd = round up */ 96 | for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; 97 | tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { 98 | tsegall = CAN_SYNC_SEG + tseg / 2; 99 | 100 | /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ 101 | brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; 102 | 103 | /* choose brp step which is possible in system */ 104 | brp = (brp / btc->brp_inc) * btc->brp_inc; 105 | if (brp < btc->brp_min || brp > btc->brp_max) 106 | continue; 107 | 108 | bitrate = priv->clock.freq / (brp * tsegall); 109 | bitrate_error = abs(bt->bitrate - bitrate); 110 | 111 | /* tseg brp biterror */ 112 | if (bitrate_error > best_bitrate_error) 113 | continue; 114 | 115 | /* reset sample point error if we have a better bitrate */ 116 | if (bitrate_error < best_bitrate_error) 117 | best_sample_point_error = UINT_MAX; 118 | 119 | can_update_sample_point(btc, sample_point_nominal, tseg / 2, 120 | &tseg1, &tseg2, &sample_point_error); 121 | if (sample_point_error >= best_sample_point_error) 122 | continue; 123 | 124 | best_sample_point_error = sample_point_error; 125 | best_bitrate_error = bitrate_error; 126 | best_tseg = tseg / 2; 127 | best_brp = brp; 128 | 129 | if (bitrate_error == 0 && sample_point_error == 0) 130 | break; 131 | } 132 | 133 | if (best_bitrate_error) { 134 | /* Error in one-tenth of a percent */ 135 | v64 = (u64)best_bitrate_error * 1000; 136 | do_div(v64, bt->bitrate); 137 | bitrate_error = (u32)v64; 138 | if (bitrate_error > CAN_CALC_MAX_ERROR) { 139 | netdev_err(dev, 140 | "bitrate error %d.%d%% too high\n", 141 | bitrate_error / 10, bitrate_error % 10); 142 | return -EDOM; 143 | } 144 | netdev_warn(dev, "bitrate error %d.%d%%\n", 145 | bitrate_error / 10, bitrate_error % 10); 146 | } 147 | 148 | /* real sample point */ 149 | bt->sample_point = can_update_sample_point(btc, sample_point_nominal, 150 | best_tseg, &tseg1, &tseg2, 151 | NULL); 152 | 153 | v64 = (u64)best_brp * 1000 * 1000 * 1000; 154 | do_div(v64, priv->clock.freq); 155 | bt->tq = (u32)v64; 156 | bt->prop_seg = tseg1 / 2; 157 | bt->phase_seg1 = tseg1 - bt->prop_seg; 158 | bt->phase_seg2 = tseg2; 159 | 160 | /* check for sjw user settings */ 161 | if (!bt->sjw || !btc->sjw_max) { 162 | bt->sjw = 1; 163 | } else { 164 | /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ 165 | if (bt->sjw > btc->sjw_max) 166 | bt->sjw = btc->sjw_max; 167 | /* bt->sjw must not be higher than tseg2 */ 168 | if (tseg2 < bt->sjw) 169 | bt->sjw = tseg2; 170 | } 171 | 172 | bt->brp = best_brp; 173 | 174 | /* real bitrate */ 175 | bt->bitrate = priv->clock.freq / 176 | (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2)); 177 | 178 | return 0; 179 | } 180 | 181 | /* Checks the validity of the specified bit-timing parameters prop_seg, 182 | * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate 183 | * prescaler value brp. You can find more information in the header 184 | * file linux/can/netlink.h. 185 | */ 186 | static int can_fixup_bittiming(const struct net_device *dev, struct can_bittiming *bt, 187 | const struct can_bittiming_const *btc) 188 | { 189 | const struct can_priv *priv = netdev_priv(dev); 190 | unsigned int tseg1, alltseg; 191 | u64 brp64; 192 | 193 | tseg1 = bt->prop_seg + bt->phase_seg1; 194 | if (!bt->sjw) 195 | bt->sjw = 1; 196 | if (bt->sjw > btc->sjw_max || 197 | tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || 198 | bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) 199 | return -ERANGE; 200 | 201 | brp64 = (u64)priv->clock.freq * (u64)bt->tq; 202 | if (btc->brp_inc > 1) 203 | do_div(brp64, btc->brp_inc); 204 | brp64 += 500000000UL - 1; 205 | do_div(brp64, 1000000000UL); /* the practicable BRP */ 206 | if (btc->brp_inc > 1) 207 | brp64 *= btc->brp_inc; 208 | bt->brp = (u32)brp64; 209 | 210 | if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) 211 | return -EINVAL; 212 | 213 | alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; 214 | bt->bitrate = priv->clock.freq / (bt->brp * alltseg); 215 | bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; 216 | 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /calc-bit-timing/compat.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | 3 | #ifndef _COMPAT_H 4 | #define _COMPAT_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | /* imported from kernel */ 15 | 16 | /* define in-kernel-types */ 17 | typedef __u64 u64; 18 | typedef __u32 u32; 19 | 20 | #define NSEC_PER_SEC 1000000000L 21 | 22 | #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ 23 | #define CAN_CALC_SYNC_SEG 1 24 | #define CAN_SYNC_SEG 1 25 | #define CAN_KBPS 1000 26 | #define KILO 1000UL 27 | 28 | /** 29 | * abs - return absolute value of an argument 30 | * @x: the value. If it is unsigned type, it is converted to signed type first. 31 | * char is treated as if it was signed (regardless of whether it really is) 32 | * but the macro's return type is preserved as char. 33 | * 34 | * Return: an absolute value of x. 35 | */ 36 | #define abs(x) __abs_choose_expr(x, long long, \ 37 | __abs_choose_expr(x, long, \ 38 | __abs_choose_expr(x, int, \ 39 | __abs_choose_expr(x, short, \ 40 | __abs_choose_expr(x, char, \ 41 | __builtin_choose_expr( \ 42 | __builtin_types_compatible_p(typeof(x), char), \ 43 | (char)({ signed char __x = (x); __x < 0 ? -__x:__x; }), \ 44 | ((void)0))))))) 45 | 46 | #define __abs_choose_expr(x, type, other) __builtin_choose_expr( \ 47 | __builtin_types_compatible_p(typeof(x), signed type) || \ 48 | __builtin_types_compatible_p(typeof(x), unsigned type), \ 49 | ({ signed type __x = (x); __x < 0 ? -__x : __x; }), other) 50 | 51 | /* 52 | * min()/max()/clamp() macros that also do 53 | * strict type-checking.. See the 54 | * "unnecessary" pointer comparison. 55 | */ 56 | #define min(x, y) ({ \ 57 | typeof(x) _min1 = (x); \ 58 | typeof(y) _min2 = (y); \ 59 | (void) (&_min1 == &_min2); \ 60 | _min1 < _min2 ? _min1 : _min2; }) 61 | 62 | #define max(x, y) ({ \ 63 | typeof(x) _max1 = (x); \ 64 | typeof(y) _max2 = (y); \ 65 | (void) (&_max1 == &_max2); \ 66 | _max1 > _max2 ? _max1 : _max2; }) 67 | 68 | /** 69 | * clamp - return a value clamped to a given range with strict typechecking 70 | * @val: current value 71 | * @lo: lowest allowable value 72 | * @hi: highest allowable value 73 | * 74 | * This macro does strict typechecking of lo/hi to make sure they are of the 75 | * same type as val. See the unnecessary pointer comparisons. 76 | */ 77 | #define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) 78 | 79 | #define do_div(n, base) ({ \ 80 | uint32_t __base = (base); \ 81 | uint32_t __rem; \ 82 | __rem = ((uint64_t)(n)) % __base; \ 83 | (n) = ((uint64_t)(n)) / __base; \ 84 | __rem; \ 85 | }) 86 | 87 | 88 | /** 89 | * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer 90 | * @dividend: unsigned 64bit dividend 91 | * @divisor: unsigned 32bit divisor 92 | * 93 | * Divide unsigned 64bit dividend by unsigned 32bit divisor 94 | * and round to closest integer. 95 | * 96 | * Return: dividend / divisor rounded to nearest integer 97 | */ 98 | #define DIV_U64_ROUND_CLOSEST(dividend, divisor) \ 99 | ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); }) 100 | 101 | /** 102 | * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder 103 | * @dividend: unsigned 64bit dividend 104 | * @divisor: unsigned 32bit divisor 105 | * @remainder: pointer to unsigned 32bit remainder 106 | * 107 | * Return: sets ``*remainder``, then returns dividend / divisor 108 | * 109 | * This is commonly provided by 32bit archs to provide an optimized 64bit 110 | * divide. 111 | */ 112 | static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) 113 | { 114 | *remainder = dividend % divisor; 115 | return dividend / divisor; 116 | } 117 | 118 | static inline u64 div_u64(u64 dividend, u32 divisor) 119 | { 120 | u32 remainder; 121 | return div_u64_rem(dividend, divisor, &remainder); 122 | } 123 | 124 | static inline u64 mul_u32_u32(u32 a, u32 b) 125 | { 126 | return (u64)a * b; 127 | } 128 | 129 | /* */ 130 | 131 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 132 | 133 | /* we don't want to see these prints */ 134 | #define netdev_err(dev, format, arg...) do { } while (0) 135 | #define netdev_warn(dev, format, arg...) do { } while (0) 136 | #define NL_SET_ERR_MSG_FMT(dev, format, arg...) do { } while (0) 137 | 138 | struct calc_ref_clk { 139 | __u32 clk; /* CAN system clock frequency in Hz */ 140 | const char *name; 141 | }; 142 | 143 | /* 144 | * minimal structs, just enough to be source level compatible 145 | */ 146 | struct can_priv { 147 | struct can_clock clock; 148 | }; 149 | 150 | struct net_device { 151 | struct can_priv priv; 152 | }; 153 | 154 | struct netlink_ext_ack { 155 | u32 __dummy; 156 | }; 157 | 158 | static inline void *netdev_priv(const struct net_device *dev) 159 | { 160 | return (void *)&dev->priv; 161 | } 162 | 163 | #endif /*_COMPAT_H */ 164 | -------------------------------------------------------------------------------- /can-j1939-install-kernel-module.md: -------------------------------------------------------------------------------- 1 | # can-j1939 kernel module installation # 2 | 3 | 4 | 5 | ### Problem 6 | 7 | You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this: 8 | 9 | ```bash 10 | avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939 11 | modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64 12 | ``` 13 | 14 | and also this: 15 | 16 | ```bash 17 | avra@vm-debian:~/can/can-utils$ testj1939 18 | testj1939: socket(j1939): Protocol not supported 19 | ``` 20 | 21 | 22 | 23 | ### Solution 24 | 25 | Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine. 26 | 27 | 28 | 29 | #### 1. Download kernel source #### 30 | 31 | We will download Debian patched kernel 5.8. First update your sources 32 | 33 | ``` 34 | avra@vm-debian:~$ sudo apt update 35 | ``` 36 | 37 | and then look at available Debian patched kernel source packages 38 | 39 | ``` 40 | avra@vm-debian:~$ apt-cache search linux-source 41 | linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches 42 | linux-source - Linux kernel source (meta-package) 43 | linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches 44 | linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches 45 | linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches 46 | linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches 47 | linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches 48 | ``` 49 | 50 | If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this 51 | 52 | ``` 53 | echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list 54 | ``` 55 | 56 | Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours) 57 | 58 | ``` 59 | deb http://security.debian.org/debian-security buster/updates main contrib 60 | deb-src http://security.debian.org/debian-security buster/updates main contrib 61 | 62 | deb http://deb.debian.org/debian/ buster main contrib non-free 63 | deb-src http://deb.debian.org/debian/ buster main contrib non-free 64 | 65 | deb http://deb.debian.org/debian buster-backports main contrib 66 | ``` 67 | 68 | After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package 69 | 70 | ``` 71 | sudo apt install linux-source-5.8 72 | ``` 73 | 74 | and unpack it 75 | ``` 76 | avra@vm-debian:~$ cd /usr/src 77 | avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz 78 | avra@vm-debian:/usr/src$ cd linux-source-5.8 79 | ``` 80 | 81 | 82 | 83 | #### 2. Add can-j1939 module to kernel #### 84 | 85 | First we need some packages for **menuconfig** 86 | 87 | ``` 88 | sudo apt-get install libncurses5 libncurses5-dev 89 | ``` 90 | 91 | copy and use our old configuration to run **menuconfig** 92 | 93 | ``` 94 | avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config 95 | avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig 96 | ``` 97 | 98 | where we enable SAE J1939 kernel module as shown 99 | 100 | ``` 101 | - Networking Support 102 | - Can bus subsystem support 103 | - SAE J1939 104 | ``` 105 | 106 | Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following 107 | ``` 108 | CONFIG_SYSTEM_TRUSTED_KEYS="" 109 | ``` 110 | 111 | and save the file. 112 | 113 | 114 | 115 | #### 3. Compile and install kernel and modules 116 | 117 | We will have to download necessary packages 118 | 119 | ``` 120 | sudo apt install build-essential libssl-dev libelf-dev bison flex 121 | ``` 122 | 123 | compile kernel (using threads to make it faster) 124 | 125 | ``` 126 | avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc) 127 | ``` 128 | 129 | install 130 | 131 | ``` 132 | avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install 133 | avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install 134 | ``` 135 | 136 | and update grub 137 | 138 | ``` 139 | avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub 140 | avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot 141 | ``` 142 | 143 | Check if installation is correct with 144 | 145 | ``` 146 | sudo modprobe can-j1939 147 | ``` 148 | 149 | and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works: 150 | 151 | ``` 152 | sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko 153 | ``` 154 | 155 | If it does then all you need to do is 156 | 157 | ``` 158 | sudo depmod -av 159 | ``` 160 | 161 | reboot once, and **modprobe** command from the above should finally work. 162 | 163 | 164 | 165 | #### 4. Install headers if needed 166 | 167 | You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with 168 | 169 | ``` 170 | nano /usr/include/linux/can.h 171 | ``` 172 | 173 | If in the struct **sockaddr_can** you don’t see **j1939**, then header files did not upgrade and you need to do it manually 174 | 175 | ``` 176 | sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h 177 | sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/ 178 | ``` 179 | 180 | That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy! 181 | -------------------------------------------------------------------------------- /can-j1939-kickstart.md: -------------------------------------------------------------------------------- 1 | # Kickstart guide to can-j1939 on linux 2 | 3 | ## Prepare using VCAN 4 | 5 | You may skip this step entirely if you have a functional 6 | **can0** bus on your system. 7 | 8 | Load module, when *vcan* is not in-kernel 9 | 10 | modprobe vcan 11 | 12 | Create a virtual can0 device and start the device 13 | 14 | ip link add can0 type vcan 15 | ip link set can0 up 16 | 17 | ## First steps with j1939 18 | 19 | Use [testj1939](testj1939.c) 20 | 21 | When *can-j1939* is compiled as module, opening a socket will load it, 22 | __or__ you can load it manually 23 | 24 | modprobe can-j1939 25 | 26 | Most of the subsequent examples will use 2 sockets programs (in 2 terminals). 27 | One will use CAN_J1939 sockets using *testj1939*, 28 | and the other will use CAN_RAW sockets using cansend+candump. 29 | 30 | testj1939 can be told to print the used API calls by adding **-v** program argument. 31 | 32 | ### receive without source address 33 | 34 | Do in terminal 1 35 | 36 | testj1939 -B -r can0 37 | 38 | Send raw CAN in terminal 2 39 | 40 | cansend can0 1823ff40#0123 41 | 42 | You should have this output in terminal 1 43 | 44 | 40 02300: 01 23 45 | 46 | This means, from NAME 0, SA 40, PGN 02300 was received, 47 | with 2 databytes, *01* & *23*. 48 | 49 | now emit this CAN message: 50 | 51 | cansend can0 18234140#0123 52 | 53 | In J1939, this means that ECU 0x40 sends directly to ECU 0x41 54 | Since we did not bind to address 0x41, this traffic 55 | is not meant for us and *testj1939* does not receive it. 56 | 57 | ### receive with source address 58 | 59 | Terminal 1: 60 | 61 | testj1939 -r can0:0x80 62 | 63 | Terminal 2: 64 | 65 | cansend can0 18238040#0123 66 | 67 | Will emit this output 68 | 69 | 40 02300: 01 23 70 | 71 | This is because the traffic had destination address __0x80__ . 72 | 73 | ### send 74 | 75 | Open in terminal 1: 76 | 77 | candump -L can0 78 | 79 | And to these test in another terminal 80 | 81 | testj1939 -B -s can0:0x80 can0:,0x3ffff 82 | 83 | This produces **1BFFFF80#0123456789ABCDEF** on CAN. 84 | 85 | Note: To be able to send a broadcast we need to use, we need to use "-B" flag. 86 | 87 | ### Multiple source addresses on 1 CAN device 88 | 89 | testj1939 -B -s can0:0x90 can0:,0x3ffff 90 | 91 | produces **1BFFFF90#0123456789ABCDEF** , 92 | 93 | ### Use PDU1 PGN 94 | 95 | testj1939 -B -s can0:0x80 can0:,0x12300 96 | 97 | emits **1923FF80#0123456789ABCDEF** . 98 | 99 | Note that the PGN is **0x12300**, and destination address is **0xff**. 100 | 101 | ### Use destination address info 102 | 103 | Since in this example we use unicast source and destination addresses, we do 104 | not need to use "-B" (broadcast) flag. 105 | 106 | The destination field may be set during sendto(). 107 | *testj1939* implements that like this 108 | 109 | testj1939 -s can0:0x80 can0:0x40,0x12300 110 | 111 | emits **19234080#0123456789ABCDEF** . 112 | 113 | The destination CAN iface __must__ always match the source CAN iface. 114 | Specifying one during bind is therefore sufficient. 115 | 116 | testj1939 -s can0:0x80 :0x40,0x12300 117 | 118 | emits the very same. 119 | 120 | ### Emit different PGNs using the same socket 121 | 122 | The PGN is provided in both __bind( *sockname* )__ and 123 | __sendto( *peername* )__ , and only one is used. 124 | *peername* PGN has highest precedence. 125 | 126 | For broadcasted transmissions 127 | 128 | testj1939 -B -s can0:0x80 :,0x32100 129 | 130 | emits **1B21FF80#0123456789ABCDEF** 131 | 132 | Destination specific transmissions 133 | 134 | testj1939 -s can0:0x80,0x12300 :0x40,0x32100 135 | 136 | emits **1B214080#0123456789ABCDEF** . 137 | 138 | It makes sometimes sense to omit the PGN in __bind( *sockname* )__ . 139 | 140 | ### Larger packets 141 | 142 | J1939 transparently switches to *Transport Protocol* when packets 143 | do not fit into single CAN packets. 144 | 145 | testj1939 -B -s20 can0:0x80 :,0x12300 146 | 147 | emits: 148 | 149 | 18ECFF80#20140003FF002301 150 | 18EBFF80#010123456789ABCD 151 | 18EBFF80#02EF0123456789AB 152 | 18EBFF80#03CDEF01234567FF 153 | 154 | The fragments for broadcasted *Transport Protocol* are separated 155 | __50ms__ from each other. 156 | Destination specific *Transport Protocol* applies flow control 157 | and may emit CAN packets much faster. 158 | 159 | First assign 0x90 to the local system. 160 | This becomes important because the kernel must interact in the 161 | transport protocol sessions before the complete packet is delivered. 162 | 163 | testj1939 can0:0x90 -r & 164 | 165 | Now test: 166 | 167 | testj1939 -s20 can0:0x80 :0x90,0x12300 168 | 169 | emits: 170 | 171 | 18EC9080#1014000303002301 172 | 18EC8090#110301FFFF002301 173 | 18EB9080#010123456789ABCD 174 | 18EB9080#02EF0123456789AB 175 | 18EB9080#03CDEF01234567FF 176 | 18EC8090#13140003FF002301 177 | 178 | The flow control causes a bit overhead. 179 | This overhead scales very good for larger J1939 packets. 180 | 181 | ## Advanced topics with j1939 182 | 183 | ### Change priority of J1939 packets 184 | 185 | testj1939 -B -s can0:0x80 :,0x0100 186 | testj1939 -B -s -p3 can0:0x80 :,0x0200 187 | 188 | emits 189 | 190 | 1801FF80#0123456789ABCDEF 191 | 0C02FF80#0123456789ABCDEF 192 | 193 | ### using connect 194 | 195 | ### advanced filtering 196 | 197 | ## dynamic addressing 198 | -------------------------------------------------------------------------------- /can-j1939.md: -------------------------------------------------------------------------------- 1 | # CAN-J1939 on linux 2 | 3 | The [Kickstart guide is here](can-j1939-kickstart.md) 4 | 5 | ## CAN on linux 6 | 7 | See [Wikipedia:socketcan](http://en.wikipedia.org/wiki/Socketcan) 8 | 9 | ## J1939 networking in short 10 | 11 | * Add addressing on top of CAN (destination address & broadcast) 12 | 13 | * Any (max 1780) length packets. 14 | Packets of 9 or more use **Transport Protocol** (fragmentation) 15 | Such packets use different CANid for the same PGN. 16 | 17 | * only **29**bit, non-**RTR** CAN frames 18 | 19 | * CAN id is composed of 20 | * 0..8: SA (source address) 21 | * 9..26: 22 | * PDU1: PGN+DA (destination address) 23 | * PDU2: PGN 24 | * 27..29: PRIO 25 | 26 | * SA / DA may be dynamically assigned via j1939-81 27 | Fixed rules of precedence in Specification, no master necessary 28 | 29 | ## J1939 on SocketCAN 30 | 31 | J1939 is *just another protocol* that fits 32 | in the Berkely sockets. 33 | 34 | socket(AF_CAN, SOCK_DGRAM, CAN_J1939) 35 | 36 | ## differences from CAN_RAW 37 | ### addressing 38 | 39 | SA, DA & PGN are used, not CAN id. 40 | 41 | Berkeley socket API is used to communicate these to userspace: 42 | 43 | * SA+PGN is put in sockname ([getsockname](http://man7.org/linux/man-pages/man2/getsockname.2.html)) 44 | * DA+PGN is put in peername ([getpeername](http://man7.org/linux/man-pages/man2/getpeername.2.html)) 45 | PGN is put in both structs 46 | 47 | PRIO is a datalink property, and irrelevant for interpretation 48 | Therefore, PRIO is not in *sockname* or *peername*. 49 | 50 | The *data* that is [recv][recvfrom] or [send][sendto] is the real payload. 51 | Unlike CAN_RAW, where addressing info is data. 52 | 53 | ### Packet size 54 | 55 | J1939 handles packets of 8+ bytes with **Transport Protocol** fragmentation transparently. 56 | No fixed data size is necessary. 57 | 58 | send(sock, data, 8, 0); 59 | 60 | will emit a single CAN frame. 61 | 62 | send(sock, data, 9, 0); 63 | 64 | will use fragmentation, emitting 1+ CAN frames. 65 | 66 | # Using J1939 67 | 68 | ## BSD socket implementation 69 | * socket 70 | * bind / connect 71 | * recvfrom / sendto 72 | * getsockname / getpeername 73 | 74 | ## Modified *struct sockaddr_can* 75 | 76 | struct sockaddr_can { 77 | sa_family_t can_family; 78 | int can_ifindex; 79 | union { 80 | struct { 81 | __u64 name; 82 | __u32 pgn; 83 | __u8 addr; 84 | } j1939; 85 | } can_addr; 86 | } 87 | 88 | * *can_addr.j1939.pgn* is PGN 89 | 90 | * *can_addr.j1939.addr* & *can_addr.j1939.name* 91 | determine the ECU 92 | 93 | * receiving address information, 94 | *addr* is always set, 95 | *name* is set when available. 96 | 97 | * When providing address information, 98 | *name* != 0 indicates dynamic addressing 99 | -------------------------------------------------------------------------------- /can-tc-init-etf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # Copyright (C) 2022 Pengutronix, Marc Kleine-Budde 4 | # 5 | # This script requires a kernel compiled with the following options: 6 | # 7 | # CONFIG_NET_SCH_PRIO 8 | # CONFIG_NET_SCH_ETF 9 | # CONFIG_NET_CLS_BASIC 10 | # CONFIG_NET_CLS_FW 11 | # CONFIG_NET_EMATCH 12 | # CONFIG_NET_EMATCH_CANID 13 | # 14 | 15 | set -e 16 | 17 | IFACE=${1:-can0} 18 | MARK=${2:-1} 19 | 20 | clear() { 21 | tc -batch - < 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 3. Neither the name of Czech Technical University in Prague nor the 18 | * names of its contributors may be used to endorse or promote 19 | * products derived from this software without specific prior 20 | * written permission. 21 | * 22 | * Alternatively, provided that this notice is retained in full, this 23 | * software may be distributed under the terms of the GNU General 24 | * Public License ("GPL") version 2, in which case the provisions of the 25 | * GPL apply INSTEAD OF those given above. 26 | * 27 | * The provided data structures and external interfaces from this code 28 | * are not restricted to be used by modules with a GPL compatible license. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 41 | * DAMAGE. 42 | * 43 | * Send feedback to 44 | * 45 | */ 46 | 47 | #ifndef CANFRAMELEN_H 48 | #define CANFRAMELEN_H 49 | 50 | #include 51 | 52 | /** 53 | * Frame length calculation modes. 54 | * 55 | * CFL_WORSTCASE corresponds to *worst* case calculation for 56 | * stuff-bits - see (1)-(3) in [1]. The worst case number of bits on 57 | * the wire can be calculated as: 58 | * 59 | * (34 + 8n - 1)/4 + 34 + 8n + 13 for SFF frames (11 bit CAN-ID) => 55 + 10n 60 | * (54 + 8n - 1)/4 + 54 + 8n + 13 for EFF frames (29 bit CAN-ID) => 80 + 10n 61 | * 62 | * while 'n' is the data length code (number of payload bytes) 63 | * 64 | * [1] "Controller Area Network (CAN) schedulability analysis: 65 | * Refuted, revisited and revised", Real-Time Syst (2007) 66 | * 35:239-272. 67 | * 68 | */ 69 | enum cfl_mode { 70 | CFL_NO_BITSTUFFING, /* plain bit calculation without bitstuffing */ 71 | CFL_WORSTCASE, /* worst case estimation - see above */ 72 | CFL_EXACT, /* exact calculation of stuffed bits based on frame 73 | * content and CRC */ 74 | }; 75 | 76 | /** 77 | * Calculates the number of bits a frame needs on the wire (including 78 | * inter frame space). 79 | * 80 | * Mode determines how to deal with stuffed bits. 81 | */ 82 | unsigned can_frame_length(struct canfd_frame *frame, enum cfl_mode mode, int mtu); 83 | unsigned can_frame_dbitrate_length(struct canfd_frame *frame, enum cfl_mode mode, int mtu); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /cansend.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | /* 3 | * cansend.c - send CAN-frames via CAN_RAW sockets 4 | * 5 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of Volkswagen nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * Alternatively, provided that this notice is retained in full, this 21 | * software may be distributed under the terms of the GNU General 22 | * Public License ("GPL") version 2, in which case the provisions of the 23 | * GPL apply INSTEAD OF those given above. 24 | * 25 | * The provided data structures and external interfaces from this code 26 | * are not restricted to be used by modules with a GPL compatible license. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 39 | * DAMAGE. 40 | * 41 | * Send feedback to 42 | * 43 | */ 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | #include 56 | 57 | #include "lib.h" 58 | 59 | static void print_usage(char *prg) 60 | { 61 | fprintf(stderr, 62 | "%s - send CAN-frames via CAN_RAW sockets.\n" 63 | "\n" 64 | "Usage: %s .\n" 65 | "\n" 66 | ":\n" 67 | " #{data} for CAN CC (Classical CAN 2.0B) data frames\n" 68 | " #R{len} for CAN CC (Classical CAN 2.0B) data frames\n" 69 | " #{data}_{dlc} for CAN CC (Classical CAN 2.0B) data frames\n" 70 | " #R{len}_{dlc} for CAN CC (Classical CAN 2.0B) data frames\n" 71 | " ##{data} for CAN FD frames\n" 72 | " #::# for CAN XL frames\n" 73 | "\n" 74 | ":\n" 75 | " 3 (SFF) or 8 (EFF) hex chars\n" 76 | "{data}:\n" 77 | " 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n" 78 | "{len}:\n" 79 | " an optional 0..8 value as RTR frames can contain a valid dlc field\n" 80 | "_{dlc}:\n" 81 | " an optional 9..F data length code value when payload length is 8\n" 82 | ":\n" 83 | " a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n" 84 | "\n" 85 | ":\n" 86 | " 2 hex chars - virtual CAN network identifier (00 .. FF)\n" 87 | ":\n" 88 | " 3 hex chars - 11 bit priority value (000 .. 7FF)\n" 89 | ":\n" 90 | " 2 hex chars values (00 .. FF) which defines canxl_frame.flags\n" 91 | ":\n" 92 | " 2 hex chars values (00 .. FF) which defines canxl_frame.sdt\n" 93 | ":\n" 94 | " 8 hex chars - 32 bit acceptance field (canxl_frame.af)\n" 95 | ":\n" 96 | " 1..2048 ASCII hex-values (optionally separated by '.')\n" 97 | "\n" 98 | "Examples:\n" 99 | " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n" 100 | " 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E /\n" 101 | " 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n" 102 | "\n", 103 | prg, prg); 104 | } 105 | 106 | int main(int argc, char **argv) 107 | { 108 | int s; /* can raw socket */ 109 | int required_mtu; 110 | int mtu; 111 | int enable_canfx = 1; 112 | struct sockaddr_can addr; 113 | struct can_raw_vcid_options vcid_opts = { 114 | .flags = CAN_RAW_XL_VCID_TX_PASS, 115 | }; 116 | static cu_t cu; 117 | struct ifreq ifr; 118 | 119 | /* check command line options */ 120 | if (argc != 3) { 121 | print_usage(argv[0]); 122 | return 1; 123 | } 124 | 125 | /* parse CAN frame */ 126 | required_mtu = parse_canframe(argv[2], &cu); 127 | if (!required_mtu) { 128 | fprintf(stderr, "\nWrong CAN-frame format!\n\n"); 129 | print_usage(argv[0]); 130 | return 1; 131 | } 132 | 133 | /* open socket */ 134 | if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { 135 | perror("socket"); 136 | return 1; 137 | } 138 | 139 | strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1); 140 | ifr.ifr_name[IFNAMSIZ - 1] = '\0'; 141 | ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); 142 | if (!ifr.ifr_ifindex) { 143 | perror("if_nametoindex"); 144 | return 1; 145 | } 146 | 147 | memset(&addr, 0, sizeof(addr)); 148 | addr.can_family = AF_CAN; 149 | addr.can_ifindex = ifr.ifr_ifindex; 150 | 151 | if (required_mtu > (int)CAN_MTU) { 152 | /* check if the frame fits into the CAN netdevice */ 153 | if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { 154 | perror("SIOCGIFMTU"); 155 | return 1; 156 | } 157 | mtu = ifr.ifr_mtu; 158 | 159 | if (mtu == (int)CANFD_MTU) { 160 | /* interface is ok - try to switch the socket into CAN FD mode */ 161 | if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, 162 | &enable_canfx, sizeof(enable_canfx))){ 163 | printf("error when enabling CAN FD support\n"); 164 | return 1; 165 | } 166 | } 167 | 168 | if (mtu >= (int)CANXL_MIN_MTU) { 169 | /* interface is ok - try to switch the socket into CAN XL mode */ 170 | if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, 171 | &enable_canfx, sizeof(enable_canfx))){ 172 | printf("error when enabling CAN XL support\n"); 173 | return 1; 174 | } 175 | /* try to enable the CAN XL VCID pass through mode */ 176 | if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, 177 | &vcid_opts, sizeof(vcid_opts))) { 178 | printf("error when enabling CAN XL VCID pass through\n"); 179 | return 1; 180 | } 181 | } 182 | } 183 | 184 | /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ 185 | if (required_mtu == CANFD_MTU) 186 | cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len)); 187 | 188 | /* CAN XL frames need real frame length for sending */ 189 | if (required_mtu == CANXL_MTU) 190 | required_mtu = CANXL_HDR_SIZE + cu.xl.len; 191 | 192 | /* 193 | * disable default receive filter on this RAW socket This is 194 | * obsolete as we do not read from the socket at all, but for 195 | * this reason we can remove the receive list in the Kernel to 196 | * save a little (really a very little!) CPU usage. 197 | */ 198 | setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); 199 | 200 | if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 201 | perror("bind"); 202 | return 1; 203 | } 204 | 205 | /* send frame */ 206 | if (write(s, &cu, required_mtu) != required_mtu) { 207 | perror("write"); 208 | return 1; 209 | } 210 | 211 | close(s); 212 | 213 | return 0; 214 | } 215 | -------------------------------------------------------------------------------- /check_cc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # check_cc.sh - Helper to test userspace compilation support 4 | # Copyright (c) 2015 Andrew Lutomirski 5 | 6 | CC="$1" 7 | TESTPROG="$2" 8 | shift 2 9 | 10 | if [ -n "$CC" ] && $CC -o /dev/null "$TESTPROG" -O0 "$@"; then 11 | echo 1 12 | else 13 | echo 0 14 | fi 15 | 16 | exit 0 17 | -------------------------------------------------------------------------------- /cmake/aarch64-linux-gnu-clang.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR aarch64) 3 | 4 | set(CMAKE_C_COMPILER clang) 5 | set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu) 6 | -------------------------------------------------------------------------------- /cmake/aarch64-linux-gnu-gcc.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR aarch64) 3 | 4 | set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) 5 | set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu) 6 | -------------------------------------------------------------------------------- /cmake/arm-linux-gnueabihf-clang.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR arm) 3 | 4 | set(CMAKE_C_COMPILER clang) 5 | set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf) 6 | -------------------------------------------------------------------------------- /cmake/arm-linux-gnueabihf-gcc.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR arm) 3 | 4 | set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) 5 | set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf) 6 | -------------------------------------------------------------------------------- /cmake/make_uninstall.cmake: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") 2 | message(FATAL_ERROR 3 | "Cannot find install manifest: \ 4 | ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" 5 | ) 6 | endif() 7 | 8 | file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" files) 9 | string(REGEX REPLACE "[\r\n]" ";" files "${files}") 10 | 11 | foreach(file ${files}) 12 | message(STATUS "Uninstalling ${file}") 13 | if(EXISTS "${file}") 14 | file(REMOVE ${file}) 15 | if (EXISTS "${file}") 16 | message( 17 | FATAL_ERROR "Problem when removing ${file}, \ 18 | please check your permissions" 19 | ) 20 | endif() 21 | else() 22 | message(STATUS "File ${file} does not exist.") 23 | endif() 24 | endforeach() 25 | -------------------------------------------------------------------------------- /cmake/mips-linux-gnu-gcc.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR mips) 3 | 4 | set(CMAKE_C_COMPILER mips-linux-gnu-gcc) 5 | set(CMAKE_C_COMPILER_TARGET mips-linux-gnu) 6 | -------------------------------------------------------------------------------- /fork_test.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2023 Dario Binacchi 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the version 2 of the GNU General Public License 7 | * as published by the Free Software Foundation 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | fork(); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /include/linux/can/bcm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 | /* 3 | * linux/can/bcm.h 4 | * 5 | * Definitions for CAN Broadcast Manager (BCM) 6 | * 7 | * Author: Oliver Hartkopp 8 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. Neither the name of Volkswagen nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * Alternatively, provided that this notice is retained in full, this 24 | * software may be distributed under the terms of the GNU General 25 | * Public License ("GPL") version 2, in which case the provisions of the 26 | * GPL apply INSTEAD OF those given above. 27 | * 28 | * The provided data structures and external interfaces from this code 29 | * are not restricted to be used by modules with a GPL compatible license. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 42 | * DAMAGE. 43 | */ 44 | 45 | #ifndef _UAPI_CAN_BCM_H 46 | #define _UAPI_CAN_BCM_H 47 | 48 | #include 49 | #include 50 | 51 | struct bcm_timeval { 52 | long tv_sec; 53 | long tv_usec; 54 | }; 55 | 56 | /** 57 | * struct bcm_msg_head - head of messages to/from the broadcast manager 58 | * @opcode: opcode, see enum below. 59 | * @flags: special flags, see below. 60 | * @count: number of frames to send before changing interval. 61 | * @ival1: interval for the first @count frames. 62 | * @ival2: interval for the following frames. 63 | * @can_id: CAN ID of frames to be sent or received. 64 | * @nframes: number of frames appended to the message head. 65 | * @frames: array of CAN frames. 66 | */ 67 | struct bcm_msg_head { 68 | __u32 opcode; 69 | __u32 flags; 70 | __u32 count; 71 | struct bcm_timeval ival1, ival2; 72 | canid_t can_id; 73 | __u32 nframes; 74 | struct can_frame frames[]; 75 | }; 76 | 77 | enum { 78 | TX_SETUP = 1, /* create (cyclic) transmission task */ 79 | TX_DELETE, /* remove (cyclic) transmission task */ 80 | TX_READ, /* read properties of (cyclic) transmission task */ 81 | TX_SEND, /* send one CAN frame */ 82 | RX_SETUP, /* create RX content filter subscription */ 83 | RX_DELETE, /* remove RX content filter subscription */ 84 | RX_READ, /* read properties of RX content filter subscription */ 85 | TX_STATUS, /* reply to TX_READ request */ 86 | TX_EXPIRED, /* notification on performed transmissions (count=0) */ 87 | RX_STATUS, /* reply to RX_READ request */ 88 | RX_TIMEOUT, /* cyclic message is absent */ 89 | RX_CHANGED /* updated CAN frame (detected content change) */ 90 | }; 91 | 92 | #define SETTIMER 0x0001 93 | #define STARTTIMER 0x0002 94 | #define TX_COUNTEVT 0x0004 95 | #define TX_ANNOUNCE 0x0008 96 | #define TX_CP_CAN_ID 0x0010 97 | #define RX_FILTER_ID 0x0020 98 | #define RX_CHECK_DLC 0x0040 99 | #define RX_NO_AUTOTIMER 0x0080 100 | #define RX_ANNOUNCE_RESUME 0x0100 101 | #define TX_RESET_MULTI_IDX 0x0200 102 | #define RX_RTR_FRAME 0x0400 103 | #define CAN_FD_FRAME 0x0800 104 | 105 | #endif /* !_UAPI_CAN_BCM_H */ 106 | -------------------------------------------------------------------------------- /include/linux/can/error.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 | /* 3 | * linux/can/error.h 4 | * 5 | * Definitions of the CAN error messages to be filtered and passed to the user. 6 | * 7 | * Author: Oliver Hartkopp 8 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. Neither the name of Volkswagen nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * Alternatively, provided that this notice is retained in full, this 24 | * software may be distributed under the terms of the GNU General 25 | * Public License ("GPL") version 2, in which case the provisions of the 26 | * GPL apply INSTEAD OF those given above. 27 | * 28 | * The provided data structures and external interfaces from this code 29 | * are not restricted to be used by modules with a GPL compatible license. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 42 | * DAMAGE. 43 | */ 44 | 45 | #ifndef _UAPI_CAN_ERROR_H 46 | #define _UAPI_CAN_ERROR_H 47 | 48 | #define CAN_ERR_DLC 8 /* dlc for error message frames */ 49 | 50 | /* error class (mask) in can_id */ 51 | #define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */ 52 | #define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */ 53 | #define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */ 54 | #define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */ 55 | #define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */ 56 | #define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */ 57 | #define CAN_ERR_BUSOFF 0x00000040U /* bus off */ 58 | #define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */ 59 | #define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */ 60 | #define CAN_ERR_CNT 0x00000200U /* TX error counter / data[6] */ 61 | /* RX error counter / data[7] */ 62 | 63 | /* arbitration lost in bit ... / data[0] */ 64 | #define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */ 65 | /* else bit number in bitstream */ 66 | 67 | /* error status of CAN-controller / data[1] */ 68 | #define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */ 69 | #define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */ 70 | #define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */ 71 | #define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */ 72 | #define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */ 73 | #define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */ 74 | #define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */ 75 | /* (at least one error counter exceeds */ 76 | /* the protocol-defined level of 127) */ 77 | #define CAN_ERR_CRTL_ACTIVE 0x40 /* recovered to error active state */ 78 | 79 | /* error in CAN protocol (type) / data[2] */ 80 | #define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */ 81 | #define CAN_ERR_PROT_BIT 0x01 /* single bit error */ 82 | #define CAN_ERR_PROT_FORM 0x02 /* frame format error */ 83 | #define CAN_ERR_PROT_STUFF 0x04 /* bit stuffing error */ 84 | #define CAN_ERR_PROT_BIT0 0x08 /* unable to send dominant bit */ 85 | #define CAN_ERR_PROT_BIT1 0x10 /* unable to send recessive bit */ 86 | #define CAN_ERR_PROT_OVERLOAD 0x20 /* bus overload */ 87 | #define CAN_ERR_PROT_ACTIVE 0x40 /* active error announcement */ 88 | #define CAN_ERR_PROT_TX 0x80 /* error occurred on transmission */ 89 | 90 | /* error in CAN protocol (location) / data[3] */ 91 | #define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* unspecified */ 92 | #define CAN_ERR_PROT_LOC_SOF 0x03 /* start of frame */ 93 | #define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */ 94 | #define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/ 95 | #define CAN_ERR_PROT_LOC_SRTR 0x04 /* substitute RTR (SFF: RTR) */ 96 | #define CAN_ERR_PROT_LOC_IDE 0x05 /* identifier extension */ 97 | #define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */ 98 | #define CAN_ERR_PROT_LOC_ID12_05 0x0F /* ID bits 12-5 */ 99 | #define CAN_ERR_PROT_LOC_ID04_00 0x0E /* ID bits 4-0 */ 100 | #define CAN_ERR_PROT_LOC_RTR 0x0C /* RTR */ 101 | #define CAN_ERR_PROT_LOC_RES1 0x0D /* reserved bit 1 */ 102 | #define CAN_ERR_PROT_LOC_RES0 0x09 /* reserved bit 0 */ 103 | #define CAN_ERR_PROT_LOC_DLC 0x0B /* data length code */ 104 | #define CAN_ERR_PROT_LOC_DATA 0x0A /* data section */ 105 | #define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */ 106 | #define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */ 107 | #define CAN_ERR_PROT_LOC_ACK 0x19 /* ACK slot */ 108 | #define CAN_ERR_PROT_LOC_ACK_DEL 0x1B /* ACK delimiter */ 109 | #define CAN_ERR_PROT_LOC_EOF 0x1A /* end of frame */ 110 | #define CAN_ERR_PROT_LOC_INTERM 0x12 /* intermission */ 111 | 112 | /* error status of CAN-transceiver / data[4] */ 113 | /* CANH CANL */ 114 | #define CAN_ERR_TRX_UNSPEC 0x00 /* 0000 0000 */ 115 | #define CAN_ERR_TRX_CANH_NO_WIRE 0x04 /* 0000 0100 */ 116 | #define CAN_ERR_TRX_CANH_SHORT_TO_BAT 0x05 /* 0000 0101 */ 117 | #define CAN_ERR_TRX_CANH_SHORT_TO_VCC 0x06 /* 0000 0110 */ 118 | #define CAN_ERR_TRX_CANH_SHORT_TO_GND 0x07 /* 0000 0111 */ 119 | #define CAN_ERR_TRX_CANL_NO_WIRE 0x40 /* 0100 0000 */ 120 | #define CAN_ERR_TRX_CANL_SHORT_TO_BAT 0x50 /* 0101 0000 */ 121 | #define CAN_ERR_TRX_CANL_SHORT_TO_VCC 0x60 /* 0110 0000 */ 122 | #define CAN_ERR_TRX_CANL_SHORT_TO_GND 0x70 /* 0111 0000 */ 123 | #define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */ 124 | 125 | /* data[5] is reserved (do not use) */ 126 | 127 | /* TX error counter / data[6] */ 128 | /* RX error counter / data[7] */ 129 | 130 | /* CAN state thresholds 131 | * 132 | * Error counter Error state 133 | * ----------------------------------- 134 | * 0 - 95 Error-active 135 | * 96 - 127 Error-warning 136 | * 128 - 255 Error-passive 137 | * 256 and greater Bus-off 138 | */ 139 | #define CAN_ERROR_WARNING_THRESHOLD 96 140 | #define CAN_ERROR_PASSIVE_THRESHOLD 128 141 | #define CAN_BUS_OFF_THRESHOLD 256 142 | 143 | #endif /* _UAPI_CAN_ERROR_H */ 144 | -------------------------------------------------------------------------------- /include/linux/can/j1939.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ 2 | /* 3 | * j1939.h 4 | * 5 | * Copyright (c) 2010-2011 EIA Electronics 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef _UAPI_CAN_J1939_H_ 13 | #define _UAPI_CAN_J1939_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define J1939_MAX_UNICAST_ADDR 0xfd 20 | #define J1939_IDLE_ADDR 0xfe 21 | #define J1939_NO_ADDR 0xff /* == broadcast or no addr */ 22 | #define J1939_NO_NAME 0 23 | #define J1939_PGN_REQUEST 0x0ea00 /* Request PG */ 24 | #define J1939_PGN_ADDRESS_CLAIMED 0x0ee00 /* Address Claimed */ 25 | #define J1939_PGN_ADDRESS_COMMANDED 0x0fed8 /* Commanded Address */ 26 | #define J1939_PGN_PDU1_MAX 0x3ff00 27 | #define J1939_PGN_MAX 0x3ffff 28 | #define J1939_NO_PGN 0x40000 29 | 30 | /* J1939 Parameter Group Number 31 | * 32 | * bit 0-7 : PDU Specific (PS) 33 | * bit 8-15 : PDU Format (PF) 34 | * bit 16 : Data Page (DP) 35 | * bit 17 : Reserved (R) 36 | * bit 19-31 : set to zero 37 | */ 38 | typedef __u32 pgn_t; 39 | 40 | /* J1939 Priority 41 | * 42 | * bit 0-2 : Priority (P) 43 | * bit 3-7 : set to zero 44 | */ 45 | typedef __u8 priority_t; 46 | 47 | /* J1939 NAME 48 | * 49 | * bit 0-20 : Identity Number 50 | * bit 21-31 : Manufacturer Code 51 | * bit 32-34 : ECU Instance 52 | * bit 35-39 : Function Instance 53 | * bit 40-47 : Function 54 | * bit 48 : Reserved 55 | * bit 49-55 : Vehicle System 56 | * bit 56-59 : Vehicle System Instance 57 | * bit 60-62 : Industry Group 58 | * bit 63 : Arbitrary Address Capable 59 | */ 60 | typedef __u64 name_t; 61 | 62 | /* J1939 socket options */ 63 | #define SOL_CAN_J1939 (SOL_CAN_BASE + CAN_J1939) 64 | enum { 65 | SO_J1939_FILTER = 1, /* set filters */ 66 | SO_J1939_PROMISC = 2, /* set/clr promiscuous mode */ 67 | SO_J1939_SEND_PRIO = 3, 68 | SO_J1939_ERRQUEUE = 4, 69 | }; 70 | 71 | enum { 72 | SCM_J1939_DEST_ADDR = 1, 73 | SCM_J1939_DEST_NAME = 2, 74 | SCM_J1939_PRIO = 3, 75 | SCM_J1939_ERRQUEUE = 4, 76 | }; 77 | 78 | enum { 79 | J1939_NLA_PAD, 80 | J1939_NLA_BYTES_ACKED, 81 | J1939_NLA_TOTAL_SIZE, 82 | J1939_NLA_PGN, 83 | J1939_NLA_SRC_NAME, 84 | J1939_NLA_DEST_NAME, 85 | J1939_NLA_SRC_ADDR, 86 | J1939_NLA_DEST_ADDR, 87 | }; 88 | 89 | enum { 90 | J1939_EE_INFO_NONE, 91 | J1939_EE_INFO_TX_ABORT, 92 | J1939_EE_INFO_RX_RTS, 93 | J1939_EE_INFO_RX_DPO, 94 | J1939_EE_INFO_RX_ABORT, 95 | }; 96 | 97 | struct j1939_filter { 98 | name_t name; 99 | name_t name_mask; 100 | pgn_t pgn; 101 | pgn_t pgn_mask; 102 | __u8 addr; 103 | __u8 addr_mask; 104 | }; 105 | 106 | #define J1939_FILTER_MAX 512 /* maximum number of j1939_filter set via setsockopt() */ 107 | 108 | #endif /* !_UAPI_CAN_J1939_H_ */ 109 | -------------------------------------------------------------------------------- /include/linux/can/netlink.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ 2 | /* 3 | * linux/can/netlink.h 4 | * 5 | * Definitions for the CAN netlink interface 6 | * 7 | * Copyright (c) 2009 Wolfgang Grandegger 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the version 2 of the GNU General Public License 11 | * as published by the Free Software Foundation 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | #ifndef _UAPI_CAN_NETLINK_H 20 | #define _UAPI_CAN_NETLINK_H 21 | 22 | #include 23 | 24 | /* 25 | * CAN bit-timing parameters 26 | * 27 | * For further information, please read chapter "8 BIT TIMING 28 | * REQUIREMENTS" of the "Bosch CAN Specification version 2.0" 29 | * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf. 30 | */ 31 | struct can_bittiming { 32 | __u32 bitrate; /* Bit-rate in bits/second */ 33 | __u32 sample_point; /* Sample point in one-tenth of a percent */ 34 | __u32 tq; /* Time quanta (TQ) in nanoseconds */ 35 | __u32 prop_seg; /* Propagation segment in TQs */ 36 | __u32 phase_seg1; /* Phase buffer segment 1 in TQs */ 37 | __u32 phase_seg2; /* Phase buffer segment 2 in TQs */ 38 | __u32 sjw; /* Synchronisation jump width in TQs */ 39 | __u32 brp; /* Bit-rate prescaler */ 40 | }; 41 | 42 | /* 43 | * CAN hardware-dependent bit-timing constant 44 | * 45 | * Used for calculating and checking bit-timing parameters 46 | */ 47 | struct can_bittiming_const { 48 | char name[16]; /* Name of the CAN controller hardware */ 49 | __u32 tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */ 50 | __u32 tseg1_max; 51 | __u32 tseg2_min; /* Time segment 2 = phase_seg2 */ 52 | __u32 tseg2_max; 53 | __u32 sjw_max; /* Synchronisation jump width */ 54 | __u32 brp_min; /* Bit-rate prescaler */ 55 | __u32 brp_max; 56 | __u32 brp_inc; 57 | }; 58 | 59 | /* 60 | * CAN clock parameters 61 | */ 62 | struct can_clock { 63 | __u32 freq; /* CAN system clock frequency in Hz */ 64 | }; 65 | 66 | /* 67 | * CAN operational and error states 68 | */ 69 | enum can_state { 70 | CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */ 71 | CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */ 72 | CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */ 73 | CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */ 74 | CAN_STATE_STOPPED, /* Device is stopped */ 75 | CAN_STATE_SLEEPING, /* Device is sleeping */ 76 | CAN_STATE_MAX 77 | }; 78 | 79 | /* 80 | * CAN bus error counters 81 | */ 82 | struct can_berr_counter { 83 | __u16 txerr; 84 | __u16 rxerr; 85 | }; 86 | 87 | /* 88 | * CAN controller mode 89 | */ 90 | struct can_ctrlmode { 91 | __u32 mask; 92 | __u32 flags; 93 | }; 94 | 95 | #define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */ 96 | #define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ 97 | #define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ 98 | #define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ 99 | #define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ 100 | #define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ 101 | #define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ 102 | #define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ 103 | #define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ 104 | #define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */ 105 | #define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */ 106 | 107 | /* 108 | * CAN device statistics 109 | */ 110 | struct can_device_stats { 111 | __u32 bus_error; /* Bus errors */ 112 | __u32 error_warning; /* Changes to error warning state */ 113 | __u32 error_passive; /* Changes to error passive state */ 114 | __u32 bus_off; /* Changes to bus off state */ 115 | __u32 arbitration_lost; /* Arbitration lost errors */ 116 | __u32 restarts; /* CAN controller re-starts */ 117 | }; 118 | 119 | /* 120 | * CAN netlink interface 121 | */ 122 | enum { 123 | IFLA_CAN_UNSPEC, 124 | IFLA_CAN_BITTIMING, 125 | IFLA_CAN_BITTIMING_CONST, 126 | IFLA_CAN_CLOCK, 127 | IFLA_CAN_STATE, 128 | IFLA_CAN_CTRLMODE, 129 | IFLA_CAN_RESTART_MS, 130 | IFLA_CAN_RESTART, 131 | IFLA_CAN_BERR_COUNTER, 132 | IFLA_CAN_DATA_BITTIMING, 133 | IFLA_CAN_DATA_BITTIMING_CONST, 134 | IFLA_CAN_TERMINATION, 135 | IFLA_CAN_TERMINATION_CONST, 136 | IFLA_CAN_BITRATE_CONST, 137 | IFLA_CAN_DATA_BITRATE_CONST, 138 | IFLA_CAN_BITRATE_MAX, 139 | IFLA_CAN_TDC, 140 | IFLA_CAN_CTRLMODE_EXT, 141 | 142 | /* add new constants above here */ 143 | __IFLA_CAN_MAX, 144 | IFLA_CAN_MAX = __IFLA_CAN_MAX - 1 145 | }; 146 | 147 | /* 148 | * CAN FD Transmitter Delay Compensation (TDC) 149 | * 150 | * Please refer to struct can_tdc_const and can_tdc in 151 | * include/linux/can/bittiming.h for further details. 152 | */ 153 | enum { 154 | IFLA_CAN_TDC_UNSPEC, 155 | IFLA_CAN_TDC_TDCV_MIN, /* u32 */ 156 | IFLA_CAN_TDC_TDCV_MAX, /* u32 */ 157 | IFLA_CAN_TDC_TDCO_MIN, /* u32 */ 158 | IFLA_CAN_TDC_TDCO_MAX, /* u32 */ 159 | IFLA_CAN_TDC_TDCF_MIN, /* u32 */ 160 | IFLA_CAN_TDC_TDCF_MAX, /* u32 */ 161 | IFLA_CAN_TDC_TDCV, /* u32 */ 162 | IFLA_CAN_TDC_TDCO, /* u32 */ 163 | IFLA_CAN_TDC_TDCF, /* u32 */ 164 | 165 | /* add new constants above here */ 166 | __IFLA_CAN_TDC, 167 | IFLA_CAN_TDC_MAX = __IFLA_CAN_TDC - 1 168 | }; 169 | 170 | /* 171 | * IFLA_CAN_CTRLMODE_EXT nest: controller mode extended parameters 172 | */ 173 | enum { 174 | IFLA_CAN_CTRLMODE_UNSPEC, 175 | IFLA_CAN_CTRLMODE_SUPPORTED, /* u32 */ 176 | 177 | /* add new constants above here */ 178 | __IFLA_CAN_CTRLMODE, 179 | IFLA_CAN_CTRLMODE_MAX = __IFLA_CAN_CTRLMODE - 1 180 | }; 181 | 182 | /* u16 termination range: 1..65535 Ohms */ 183 | #define CAN_TERMINATION_DISABLED 0 184 | 185 | #endif /* !_UAPI_CAN_NETLINK_H */ 186 | -------------------------------------------------------------------------------- /include/linux/can/raw.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 | /* 3 | * linux/can/raw.h 4 | * 5 | * Definitions for raw CAN sockets 6 | * 7 | * Authors: Oliver Hartkopp 8 | * Urs Thuermann 9 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions 14 | * are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of Volkswagen nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * Alternatively, provided that this notice is retained in full, this 25 | * software may be distributed under the terms of the GNU General 26 | * Public License ("GPL") version 2, in which case the provisions of the 27 | * GPL apply INSTEAD OF those given above. 28 | * 29 | * The provided data structures and external interfaces from this code 30 | * are not restricted to be used by modules with a GPL compatible license. 31 | * 32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 35 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 39 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 40 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 42 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 43 | * DAMAGE. 44 | */ 45 | 46 | #ifndef _UAPI_CAN_RAW_H 47 | #define _UAPI_CAN_RAW_H 48 | 49 | #include 50 | 51 | #define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW) 52 | #define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ 53 | 54 | enum { 55 | SCM_CAN_RAW_ERRQUEUE = 1, 56 | }; 57 | 58 | /* for socket options affecting the socket (not the global system) */ 59 | 60 | enum { 61 | CAN_RAW_FILTER = 1, /* set 0 .. n can_filter(s) */ 62 | CAN_RAW_ERR_FILTER, /* set filter for error frames */ 63 | CAN_RAW_LOOPBACK, /* local loopback (default:on) */ 64 | CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ 65 | CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ 66 | CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ 67 | CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */ 68 | CAN_RAW_XL_VCID_OPTS, /* CAN XL VCID configuration options */ 69 | }; 70 | 71 | /* configuration for CAN XL virtual CAN identifier (VCID) handling */ 72 | struct can_raw_vcid_options { 73 | 74 | __u8 flags; /* flags for vcid (filter) behaviour */ 75 | __u8 tx_vcid; /* VCID value set into canxl_frame.prio */ 76 | __u8 rx_vcid; /* VCID value for VCID filter */ 77 | __u8 rx_vcid_mask; /* VCID mask for VCID filter */ 78 | 79 | }; 80 | 81 | /* can_raw_vcid_options.flags for CAN XL virtual CAN identifier handling */ 82 | #define CAN_RAW_XL_VCID_TX_SET 0x01 83 | #define CAN_RAW_XL_VCID_TX_PASS 0x02 84 | #define CAN_RAW_XL_VCID_RX_FILTER 0x04 85 | 86 | #endif /* !_UAPI_CAN_RAW_H */ 87 | -------------------------------------------------------------------------------- /include/linux/can/vxcan.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ 2 | #ifndef _UAPI_CAN_VXCAN_H 3 | #define _UAPI_CAN_VXCAN_H 4 | 5 | enum { 6 | VXCAN_INFO_UNSPEC, 7 | VXCAN_INFO_PEER, 8 | 9 | __VXCAN_INFO_MAX 10 | #define VXCAN_INFO_MAX (__VXCAN_INFO_MAX - 1) 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/linux/errqueue.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _UAPI_LINUX_ERRQUEUE_H 3 | #define _UAPI_LINUX_ERRQUEUE_H 4 | 5 | #include 6 | 7 | struct sock_extended_err { 8 | __u32 ee_errno; 9 | __u8 ee_origin; 10 | __u8 ee_type; 11 | __u8 ee_code; 12 | __u8 ee_pad; 13 | __u32 ee_info; 14 | __u32 ee_data; 15 | }; 16 | 17 | #define SO_EE_ORIGIN_NONE 0 18 | #define SO_EE_ORIGIN_LOCAL 1 19 | #define SO_EE_ORIGIN_ICMP 2 20 | #define SO_EE_ORIGIN_ICMP6 3 21 | #define SO_EE_ORIGIN_TXSTATUS 4 22 | #define SO_EE_ORIGIN_ZEROCOPY 5 23 | #define SO_EE_ORIGIN_TXTIME 6 24 | #define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS 25 | 26 | #define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1)) 27 | 28 | #define SO_EE_CODE_ZEROCOPY_COPIED 1 29 | 30 | #define SO_EE_CODE_TXTIME_INVALID_PARAM 1 31 | #define SO_EE_CODE_TXTIME_MISSED 2 32 | 33 | /** 34 | * struct scm_timestamping - timestamps exposed through cmsg 35 | * 36 | * The timestamping interfaces SO_TIMESTAMPING, MSG_TSTAMP_* 37 | * communicate network timestamps by passing this struct in a cmsg with 38 | * recvmsg(). See Documentation/networking/timestamping.txt for details. 39 | */ 40 | struct scm_timestamping { 41 | struct timespec ts[3]; 42 | }; 43 | 44 | /* The type of scm_timestamping, passed in sock_extended_err ee_info. 45 | * This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0] 46 | * is zero, then this is a hardware timestamp and recorded in ts[2]. 47 | */ 48 | enum { 49 | SCM_TSTAMP_SND, /* driver passed skb to NIC, or HW */ 50 | SCM_TSTAMP_SCHED, /* data entered the packet scheduler */ 51 | SCM_TSTAMP_ACK, /* data acknowledged by peer */ 52 | }; 53 | 54 | #endif /* _UAPI_LINUX_ERRQUEUE_H */ 55 | -------------------------------------------------------------------------------- /include/linux/kernel.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | 3 | #ifndef _LINUX_KERNEL_H 4 | #define _LINUX_KERNEL_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | typedef uint8_t u8; 14 | typedef uint16_t u16; 15 | typedef uint32_t u32; 16 | typedef uint32_t __le32; 17 | 18 | struct mcp251xfd_mem; 19 | 20 | struct regmap { 21 | struct mcp251xfd_mem *mem; 22 | }; 23 | 24 | #define pr_info(...) fprintf(stdout, ## __VA_ARGS__) 25 | #define pr_err(...) fprintf(stderr, ## __VA_ARGS__) 26 | #define pr_warn(...) fprintf(stderr, ## __VA_ARGS__) 27 | #define pr_cont(...) fprintf(stdout, ## __VA_ARGS__) 28 | #define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__) 29 | #define BUILD_BUG_ON(...) 30 | 31 | #define BITS_PER_LONG (sizeof(long) * 8) 32 | 33 | #define ____cacheline_aligned 34 | 35 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 36 | 37 | int regmap_bulk_read(struct regmap *map, unsigned int reg, 38 | void *val, size_t val_count); 39 | 40 | #define SZ_2K 0x00000800 41 | 42 | #define __packed __attribute__((__packed__)) 43 | 44 | #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) 45 | 46 | #define BIT(nr) (UL(1) << (nr)) 47 | 48 | #define __stringify_1(x...) #x 49 | #define __stringify(x...) __stringify_1(x) 50 | 51 | #ifdef __ASSEMBLY__ 52 | #define _AC(X,Y) X 53 | #define _AT(T,X) X 54 | #else 55 | #define __AC(X,Y) (X##Y) 56 | #define _AC(X,Y) __AC(X,Y) 57 | #define _AT(T,X) ((T)(X)) 58 | #endif 59 | 60 | #define _UL(x) (_AC(x, UL)) 61 | #define _ULL(x) (_AC(x, ULL)) 62 | 63 | #define UL(x) (_UL(x)) 64 | #define ULL(x) (_ULL(x)) 65 | 66 | #define GENMASK(h, l) \ 67 | (((~UL(0)) - (UL(1) << (l)) + 1) & \ 68 | (~UL(0) >> (BITS_PER_LONG - 1 - (h)))) 69 | 70 | #define __bf_shf(x) (__builtin_ffsll(x) - 1) 71 | 72 | #define FIELD_PREP(_mask, _val) \ 73 | ({ \ 74 | ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ 75 | }) 76 | 77 | #define FIELD_GET(_mask, _reg) \ 78 | ({ \ 79 | (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ 80 | }) 81 | 82 | #define min_t(type, x, y) ({ \ 83 | type __min1 = (x); \ 84 | type __min2 = (y); \ 85 | __min1 < __min2 ? __min1 : __min2; }) 86 | 87 | #define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC)) 88 | 89 | static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7, 90 | 8, 12, 16, 20, 24, 32, 48, 64}; 91 | 92 | /* get data length from can_dlc with sanitized can_dlc */ 93 | static inline u8 can_dlc2len(u8 can_dlc) 94 | { 95 | return dlc2len[can_dlc & 0x0F]; 96 | } 97 | 98 | #endif /* _LINUX_KERNEL_H */ 99 | -------------------------------------------------------------------------------- /include/linux/net_tstamp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* 3 | * Userspace API for hardware time stamping of network packets 4 | * 5 | * Copyright (C) 2008,2009 Intel Corporation 6 | * Author: Patrick Ohly 7 | * 8 | */ 9 | 10 | #ifndef _NET_TIMESTAMPING_H 11 | #define _NET_TIMESTAMPING_H 12 | 13 | #include 14 | #include /* for SO_TIMESTAMPING */ 15 | 16 | /* SO_TIMESTAMPING gets an integer bit field comprised of these values */ 17 | enum { 18 | SOF_TIMESTAMPING_TX_HARDWARE = (1<<0), 19 | SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1), 20 | SOF_TIMESTAMPING_RX_HARDWARE = (1<<2), 21 | SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3), 22 | SOF_TIMESTAMPING_SOFTWARE = (1<<4), 23 | SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5), 24 | SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6), 25 | SOF_TIMESTAMPING_OPT_ID = (1<<7), 26 | SOF_TIMESTAMPING_TX_SCHED = (1<<8), 27 | SOF_TIMESTAMPING_TX_ACK = (1<<9), 28 | SOF_TIMESTAMPING_OPT_CMSG = (1<<10), 29 | SOF_TIMESTAMPING_OPT_TSONLY = (1<<11), 30 | SOF_TIMESTAMPING_OPT_STATS = (1<<12), 31 | SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13), 32 | SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14), 33 | 34 | SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TX_SWHW, 35 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | 36 | SOF_TIMESTAMPING_LAST 37 | }; 38 | 39 | /* 40 | * SO_TIMESTAMPING flags are either for recording a packet timestamp or for 41 | * reporting the timestamp to user space. 42 | * Recording flags can be set both via socket options and control messages. 43 | */ 44 | #define SOF_TIMESTAMPING_TX_RECORD_MASK (SOF_TIMESTAMPING_TX_HARDWARE | \ 45 | SOF_TIMESTAMPING_TX_SOFTWARE | \ 46 | SOF_TIMESTAMPING_TX_SCHED | \ 47 | SOF_TIMESTAMPING_TX_ACK) 48 | 49 | /** 50 | * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter 51 | * 52 | * @flags: no flags defined right now, must be zero for %SIOCSHWTSTAMP 53 | * @tx_type: one of HWTSTAMP_TX_* 54 | * @rx_filter: one of HWTSTAMP_FILTER_* 55 | * 56 | * %SIOCGHWTSTAMP and %SIOCSHWTSTAMP expect a &struct ifreq with a 57 | * ifr_data pointer to this structure. For %SIOCSHWTSTAMP, if the 58 | * driver or hardware does not support the requested @rx_filter value, 59 | * the driver may use a more general filter mode. In this case 60 | * @rx_filter will indicate the actual mode on return. 61 | */ 62 | struct hwtstamp_config { 63 | int flags; 64 | int tx_type; 65 | int rx_filter; 66 | }; 67 | 68 | /* possible values for hwtstamp_config->tx_type */ 69 | enum hwtstamp_tx_types { 70 | /* 71 | * No outgoing packet will need hardware time stamping; 72 | * should a packet arrive which asks for it, no hardware 73 | * time stamping will be done. 74 | */ 75 | HWTSTAMP_TX_OFF, 76 | 77 | /* 78 | * Enables hardware time stamping for outgoing packets; 79 | * the sender of the packet decides which are to be 80 | * time stamped by setting %SOF_TIMESTAMPING_TX_SOFTWARE 81 | * before sending the packet. 82 | */ 83 | HWTSTAMP_TX_ON, 84 | 85 | /* 86 | * Enables time stamping for outgoing packets just as 87 | * HWTSTAMP_TX_ON does, but also enables time stamp insertion 88 | * directly into Sync packets. In this case, transmitted Sync 89 | * packets will not received a time stamp via the socket error 90 | * queue. 91 | */ 92 | HWTSTAMP_TX_ONESTEP_SYNC, 93 | }; 94 | 95 | /* possible values for hwtstamp_config->rx_filter */ 96 | enum hwtstamp_rx_filters { 97 | /* time stamp no incoming packet at all */ 98 | HWTSTAMP_FILTER_NONE, 99 | 100 | /* time stamp any incoming packet */ 101 | HWTSTAMP_FILTER_ALL, 102 | 103 | /* return value: time stamp all packets requested plus some others */ 104 | HWTSTAMP_FILTER_SOME, 105 | 106 | /* PTP v1, UDP, any kind of event packet */ 107 | HWTSTAMP_FILTER_PTP_V1_L4_EVENT, 108 | /* PTP v1, UDP, Sync packet */ 109 | HWTSTAMP_FILTER_PTP_V1_L4_SYNC, 110 | /* PTP v1, UDP, Delay_req packet */ 111 | HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ, 112 | /* PTP v2, UDP, any kind of event packet */ 113 | HWTSTAMP_FILTER_PTP_V2_L4_EVENT, 114 | /* PTP v2, UDP, Sync packet */ 115 | HWTSTAMP_FILTER_PTP_V2_L4_SYNC, 116 | /* PTP v2, UDP, Delay_req packet */ 117 | HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ, 118 | 119 | /* 802.AS1, Ethernet, any kind of event packet */ 120 | HWTSTAMP_FILTER_PTP_V2_L2_EVENT, 121 | /* 802.AS1, Ethernet, Sync packet */ 122 | HWTSTAMP_FILTER_PTP_V2_L2_SYNC, 123 | /* 802.AS1, Ethernet, Delay_req packet */ 124 | HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ, 125 | 126 | /* PTP v2/802.AS1, any layer, any kind of event packet */ 127 | HWTSTAMP_FILTER_PTP_V2_EVENT, 128 | /* PTP v2/802.AS1, any layer, Sync packet */ 129 | HWTSTAMP_FILTER_PTP_V2_SYNC, 130 | /* PTP v2/802.AS1, any layer, Delay_req packet */ 131 | HWTSTAMP_FILTER_PTP_V2_DELAY_REQ, 132 | 133 | /* NTP, UDP, all versions and packet modes */ 134 | HWTSTAMP_FILTER_NTP_ALL, 135 | }; 136 | 137 | /* SCM_TIMESTAMPING_PKTINFO control message */ 138 | struct scm_ts_pktinfo { 139 | __u32 if_index; 140 | __u32 pkt_length; 141 | __u32 reserved[2]; 142 | }; 143 | 144 | /* 145 | * SO_TXTIME gets a struct sock_txtime with flags being an integer bit 146 | * field comprised of these values. 147 | */ 148 | enum txtime_flags { 149 | SOF_TXTIME_DEADLINE_MODE = (1 << 0), 150 | SOF_TXTIME_REPORT_ERRORS = (1 << 1), 151 | 152 | SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_REPORT_ERRORS, 153 | SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) | 154 | SOF_TXTIME_FLAGS_LAST 155 | }; 156 | 157 | struct sock_txtime { 158 | __kernel_clockid_t clockid;/* reference clockid */ 159 | __u32 flags; /* as defined by enum txtime_flags */ 160 | }; 161 | 162 | #endif /* _NET_TIMESTAMPING_H */ 163 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_cli.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #ifndef ISOBUSFS_CLI_H 5 | #define ISOBUSFS_CLI_H 6 | 7 | #include 8 | #include 9 | 10 | #include "isobusfs_cmn.h" 11 | #include "isobusfs_cmn_cm.h" 12 | 13 | #define ISOBUSFS_CLI_MAX_EPOLL_EVENTS 10 14 | #define ISOBUSFS_CLI_DEFAULT_WAIT_TIMEOUT_MS 1000 /* ms */ 15 | 16 | enum isobusfs_cli_state { 17 | ISOBUSFS_CLI_STATE_CONNECTING, 18 | ISOBUSFS_CLI_STATE_IDLE, 19 | ISOBUSFS_CLI_STATE_NACKED, /* here is NACKed and not what you think */ 20 | ISOBUSFS_CLI_STATE_SELFTEST, 21 | ISOBUSFS_CLI_STATE_WAIT_FS_PROPERTIES, 22 | ISOBUSFS_CLI_STATE_WAIT_CURRENT_DIR, 23 | ISOBUSFS_CLI_STATE_WAIT_CCD_RESP, 24 | ISOBUSFS_CLI_STATE_WAIT_OF_RESP, 25 | ISOBUSFS_CLI_STATE_WAIT_FILE_SIZE, 26 | ISOBUSFS_CLI_STATE_WAIT_FILE, 27 | ISOBUSFS_CLI_STATE_WAIT_VOLUME_STATUS, 28 | ISOBUSFS_CLI_STATE_WAIT_CF_RESP, 29 | ISOBUSFS_CLI_STATE_WAIT_SF_RESP, /* wait for seek file response */ 30 | ISOBUSFS_CLI_STATE_WAIT_RF_RESP, /* wait for read file response */ 31 | ISOBUSFS_CLI_STATE_MAX_WAITING, 32 | 33 | ISOBUSFS_CLI_STATE_CONNECTING_DONE, 34 | ISOBUSFS_CLI_STATE_GET_FS_PROPERTIES_DONE, 35 | ISOBUSFS_CLI_STATE_GET_CURRENT_DIR_DONE, 36 | ISOBUSFS_CLI_STATE_GET_CURRENT_DIR_FAIL, 37 | ISOBUSFS_CLI_STATE_GET_FILE_SIZE_DONE, 38 | ISOBUSFS_CLI_STATE_GET_FILE_DONE, 39 | ISOBUSFS_CLI_STATE_VOLUME_STATUS_DONE, 40 | ISOBUSFS_CLI_STATE_CCD_DONE, 41 | ISOBUSFS_CLI_STATE_CCD_FAIL, 42 | ISOBUSFS_CLI_STATE_OF_DONE, 43 | ISOBUSFS_CLI_STATE_OF_FAIL, 44 | ISOBUSFS_CLI_STATE_CF_DONE, 45 | ISOBUSFS_CLI_STATE_CF_FAIL, 46 | ISOBUSFS_CLI_STATE_SF_DONE, 47 | ISOBUSFS_CLI_STATE_SF_FAIL, 48 | ISOBUSFS_CLI_STATE_RF_CONT, 49 | ISOBUSFS_CLI_STATE_RF_DONE, 50 | ISOBUSFS_CLI_STATE_RF_FAIL, 51 | ISOBUSFS_CLI_STATE_MAX_DONE, 52 | 53 | ISOBUSFS_CLI_STATE_GET_FS_PROPERTIES, 54 | ISOBUSFS_CLI_STATE_GET_CURRENT_DIR, 55 | ISOBUSFS_CLI_STATE_GET_FILE_SIZE, 56 | ISOBUSFS_CLI_STATE_GET_FILE, 57 | ISOBUSFS_CLI_STATE_VOLUME_STATUS, 58 | ISOBUSFS_CLI_STATE_TEST_CLEANUP, 59 | ISOBUSFS_CLI_STATE_TEST_DONE, 60 | ISOBUSFS_CLI_STATE_MAX_ACTIVE, 61 | }; 62 | 63 | struct isobusfs_priv; 64 | 65 | typedef int (*isobusfs_event_callback)(struct isobusfs_priv *priv, 66 | struct isobusfs_msg *msg, void *ctx, 67 | int error); 68 | 69 | struct isobusfs_event { 70 | isobusfs_event_callback cb; 71 | struct timespec timeout; 72 | /* fs_function is needed to identify package type for event 73 | * subscription 74 | */ 75 | uint8_t fs_function; 76 | int fd; 77 | bool one_shot; 78 | void *ctx; 79 | }; 80 | 81 | struct isobusfs_priv { 82 | int sock_ccm; 83 | int sock_nack; 84 | int sock_main; 85 | int sock_bcast_rx; 86 | struct isobusfs_cm_ccm ccm; /* file server status message */ 87 | 88 | bool run_selftest; 89 | 90 | struct sockaddr_can sockname; 91 | struct sockaddr_can peername; 92 | 93 | struct isobusfs_stats stats; 94 | 95 | uint8_t next_tan; 96 | uint8_t cl_buf[1]; 97 | 98 | bool fs_is_active; 99 | struct timespec fs_last_seen; 100 | uint8_t fs_version; 101 | uint8_t fs_max_open_files; 102 | uint8_t fs_caps; 103 | struct isobusfs_buf_log tx_buf_log; 104 | enum isobusfs_cli_state state; 105 | 106 | struct libj1939_cmn cmn; 107 | uint8_t handle; 108 | 109 | uint32_t read_offset; 110 | uint8_t *read_data; 111 | size_t read_data_len; 112 | 113 | bool interactive; 114 | bool int_busy; 115 | 116 | struct isobusfs_event *events; 117 | uint num_events; 118 | uint max_events; 119 | 120 | enum isobusfs_error error_code; 121 | }; 122 | 123 | /* isobusfs_cli_cm.c */ 124 | void isobusfs_cli_ccm_init(struct isobusfs_priv *priv); 125 | int isobusfs_cli_ccm_send(struct isobusfs_priv *priv); 126 | void isobusfs_cli_fs_detect_timeout(struct isobusfs_priv *priv); 127 | int isobusfs_cli_rx_cg_cm(struct isobusfs_priv *priv, struct isobusfs_msg *msg); 128 | int isobusfs_cli_property_req(struct isobusfs_priv *priv); 129 | int isobusfs_cli_volume_status_req(struct isobusfs_priv *priv, 130 | uint8_t volume_mode, 131 | uint16_t path_name_length, 132 | const char *volume_name); 133 | 134 | /* isobusfs_cli_dh.c */ 135 | int isobusfs_cli_ccd_req(struct isobusfs_priv *priv, const char *name, 136 | size_t name_len); 137 | int isobusfs_cli_get_current_dir_req(struct isobusfs_priv *priv); 138 | int isobusfs_cli_rx_cg_dh(struct isobusfs_priv *priv, 139 | struct isobusfs_msg *msg); 140 | int isobusfs_cli_send_and_register_ccd_event(struct isobusfs_priv *priv, 141 | const char *name, 142 | size_t name_len, 143 | isobusfs_event_callback cb, 144 | void *ctx); 145 | int isobusfs_cli_send_and_register_gcd_event(struct isobusfs_priv *priv, 146 | isobusfs_event_callback cb, 147 | void *ctx); 148 | 149 | /* isobusfs_cli_fa.c */ 150 | int isobusfs_cli_rx_cg_fa(struct isobusfs_priv *priv, 151 | struct isobusfs_msg *msg); 152 | int isobusfs_cli_fa_of_req(struct isobusfs_priv *priv, const char *name, 153 | size_t name_len, uint8_t flags); 154 | int isobusfs_cli_fa_cf_req(struct isobusfs_priv *priv, uint8_t handle); 155 | int isobusfs_cli_fa_rf_req(struct isobusfs_priv *priv, uint8_t handle, 156 | uint16_t count); 157 | int isobusfs_cli_fa_sf_req(struct isobusfs_priv *priv, uint8_t handle, 158 | uint8_t position_mode, int32_t offset); 159 | 160 | int isobusfs_cli_send_and_register_fa_of_event(struct isobusfs_priv *priv, 161 | const char *name, 162 | size_t name_len, 163 | uint8_t flags, 164 | isobusfs_event_callback cb, 165 | void *ctx); 166 | int isobusfs_cli_send_and_register_fa_sf_event(struct isobusfs_priv *priv, 167 | uint8_t handle, 168 | uint8_t position_mode, 169 | int32_t offset, 170 | isobusfs_event_callback cb, 171 | void *ctx); 172 | int isobusfs_cli_send_and_register_fa_rf_event(struct isobusfs_priv *priv, 173 | uint8_t handle, 174 | uint16_t count, 175 | isobusfs_event_callback cb, 176 | void *ctx); 177 | int isobusfs_cli_send_and_register_fa_cf_event(struct isobusfs_priv *priv, 178 | uint8_t handle, 179 | isobusfs_event_callback cb, 180 | void *ctx); 181 | 182 | /* isobusfs_cli_selftests.c */ 183 | void isobusfs_cli_run_self_tests(struct isobusfs_priv *priv); 184 | 185 | /* isobusfs_cli_int.c */ 186 | void isobusfs_cli_int_start(struct isobusfs_priv *priv); 187 | int isobusfs_cli_interactive(struct isobusfs_priv *priv); 188 | 189 | /* isobusfs_cli.c */ 190 | int isobusfs_cli_process_events_and_tasks(struct isobusfs_priv *priv); 191 | void isobusfs_cli_prepare_response_event(struct isobusfs_event *event, int sock, 192 | uint8_t fs_function); 193 | int isobusfs_cli_register_event(struct isobusfs_priv *priv, 194 | const struct isobusfs_event *new_event); 195 | 196 | static inline uint8_t isobusfs_cli_get_next_tan(struct isobusfs_priv *priv) 197 | { 198 | return priv->next_tan++; 199 | } 200 | 201 | static inline bool isobusfs_cli_tan_is_valid(uint8_t tan, 202 | struct isobusfs_priv *priv) 203 | { 204 | uint8_t expected_tan = priv->next_tan == 0 ? 255 : priv->next_tan - 1; 205 | 206 | if (tan != expected_tan) { 207 | pr_err("%s: tan %d is not valid, expected tan %d\n", __func__, 208 | tan, expected_tan); 209 | return false; 210 | } 211 | 212 | return true; 213 | } 214 | 215 | #endif /* ISOBUSFS_CLI_H */ 216 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_cli_cm.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "isobusfs_cli.h" 9 | #include "isobusfs_cmn_cm.h" 10 | 11 | 12 | int isobusfs_cli_volume_status_req(struct isobusfs_priv *priv, 13 | uint8_t volume_mode, 14 | uint16_t path_name_length, 15 | const char *volume_name) 16 | { 17 | struct isobusfs_cm_vol_stat_req req; 18 | size_t req_size; 19 | int ret; 20 | 21 | req.fs_function = 22 | isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT, 23 | ISOBUSFS_CM_VOLUME_STATUS_REQ); 24 | 25 | req.volume_mode = volume_mode; 26 | req.name_len = htole16(path_name_length); 27 | req_size = sizeof(req) - sizeof(req.name) + path_name_length; 28 | 29 | memcpy(req.name, volume_name, path_name_length); 30 | 31 | ret = isobusfs_send(priv->sock_main, &req, req_size, &priv->tx_buf_log); 32 | if (ret < 0) { 33 | ret = -errno; 34 | pr_warn("failed to send volume status request: %d (%s)", ret, strerror(ret)); 35 | return ret; 36 | } 37 | 38 | priv->state = ISOBUSFS_CLI_STATE_WAIT_VOLUME_STATUS; 39 | 40 | pr_debug("> tx: volume status request"); 41 | return 0; 42 | } 43 | 44 | 45 | int isobusfs_cli_property_req(struct isobusfs_priv *priv) 46 | { 47 | uint8_t buf[ISOBUSFS_MIN_TRANSFER_LENGH]; 48 | int ret; 49 | 50 | /* not used space should be filled with 0xff */ 51 | memset(buf, 0xff, ARRAY_SIZE(buf)); 52 | buf[0] = isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT, 53 | ISOBUSFS_CM_GET_FS_PROPERTIES); 54 | 55 | /* send property request */ 56 | ret = isobusfs_send(priv->sock_main, buf, sizeof(buf), &priv->tx_buf_log); 57 | if (ret < 0) 58 | return ret; 59 | 60 | priv->state = ISOBUSFS_CLI_STATE_WAIT_FS_PROPERTIES; 61 | 62 | pr_debug("> tx: FS property request"); 63 | return 0; 64 | } 65 | 66 | /* ccm section */ 67 | void isobusfs_cli_ccm_init(struct isobusfs_priv *priv) 68 | { 69 | struct isobusfs_cm_ccm *ccm = &priv->ccm; 70 | 71 | ccm->fs_function = 72 | isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT, 73 | ISOBUSFS_CM_F_FS_STATUS); 74 | ccm->version = 2; 75 | memset(ccm->reserved, 0xFF, sizeof(ccm->reserved)); 76 | } 77 | 78 | /** 79 | * isobusfs_cli_ccm_send - send periodic file server status messages 80 | * @priv: pointer to the isobusfs_priv structure 81 | * 82 | * Returns 0 on success, -1 on errors. 83 | */ 84 | int isobusfs_cli_ccm_send(struct isobusfs_priv *priv) 85 | { 86 | int64_t time_diff; 87 | int ret; 88 | 89 | /* Test if it is proper time to send next status message. */ 90 | time_diff = timespec_diff_ms(&priv->cmn.next_send_time, 91 | &priv->cmn.last_time); 92 | if (time_diff > ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { 93 | /* too early to send next message */ 94 | return 0; 95 | } 96 | 97 | if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { 98 | pr_warn("too late to send next fs status message: %ld ms", 99 | time_diff); 100 | } 101 | 102 | /* Make sure we send the message with the latest stats */ 103 | if (priv->stats.tskey_sch != priv->stats.tskey_ack) 104 | pr_warn("previous message was not acked"); 105 | 106 | /* send periodic file servers status messages. */ 107 | ret = isobusfs_send(priv->sock_ccm, &priv->ccm, sizeof(priv->ccm), 108 | &priv->tx_buf_log); 109 | if (ret < 0) { 110 | pr_err("sendto() failed: %d (%s)", ret, strerror(ret)); 111 | return ret; 112 | } 113 | 114 | pr_debug("> tx: ccm version: %d", priv->ccm.version); 115 | 116 | priv->cmn.next_send_time = priv->cmn.last_time; 117 | timespec_add_ms(&priv->cmn.next_send_time, 2000); 118 | 119 | return 0; 120 | } 121 | 122 | /* detect if FS is timeout */ 123 | void isobusfs_cli_fs_detect_timeout(struct isobusfs_priv *priv) 124 | { 125 | int64_t time_diff; 126 | 127 | if (!priv->fs_is_active) 128 | return; 129 | 130 | time_diff = timespec_diff_ms(&priv->cmn.last_time, 131 | &priv->fs_last_seen); 132 | if (time_diff > ISOBUSFS_FS_TIMEOUT) { 133 | pr_debug("file server timeout"); 134 | priv->fs_is_active = false; 135 | } 136 | } 137 | 138 | /* activate FS status if was not active till now */ 139 | static void isobusfs_cli_fs_activate(struct isobusfs_priv *priv) 140 | { 141 | if (priv->fs_is_active) 142 | return; 143 | 144 | pr_debug("file server detectet"); 145 | priv->fs_is_active = true; 146 | } 147 | 148 | static int isobusfs_cli_rx_fs_status(struct isobusfs_priv *priv, 149 | struct isobusfs_msg *msg) 150 | { 151 | struct isobusfs_cm_fss *fs_status = (void *)msg->buf; 152 | int ret = 0; 153 | 154 | if (msg->len != sizeof(*fs_status)) { 155 | pr_warn("wrong message length: %d", msg->len); 156 | return -EINVAL; 157 | } 158 | 159 | isobusfs_cli_fs_activate(priv); 160 | 161 | priv->fs_last_seen = priv->cmn.last_time; 162 | pr_debug("< rx: fs status: %x, opened files: %d", 163 | fs_status->status, fs_status->num_open_files); 164 | 165 | return ret; 166 | } 167 | 168 | /* process FS properties response */ 169 | static int isobusfs_cli_rx_fs_property_res(struct isobusfs_priv *priv, 170 | struct isobusfs_msg *msg) 171 | { 172 | struct isobusfs_cm_get_fs_props_resp *fs_prop = (void *)msg->buf; 173 | int ret = 0; 174 | 175 | if (priv->state != ISOBUSFS_CLI_STATE_WAIT_FS_PROPERTIES) { 176 | pr_warn("unexpected fs properties response"); 177 | return -EINVAL; 178 | } 179 | 180 | if (msg->len != sizeof(*fs_prop)) { 181 | pr_warn("wrong message length: %d", msg->len); 182 | return -EINVAL; 183 | } 184 | 185 | priv->fs_version = fs_prop->version_number; 186 | priv->fs_max_open_files = fs_prop->max_open_files; 187 | priv->fs_caps = fs_prop->fs_capabilities; 188 | 189 | 190 | pr_debug("< rx: fs properties: version: %d, max open files: %d, caps: %x", 191 | priv->fs_version, priv->fs_max_open_files, priv->fs_caps); 192 | 193 | priv->state = ISOBUSFS_CLI_STATE_GET_FS_PROPERTIES_DONE; 194 | 195 | return ret; 196 | } 197 | 198 | /* function to handle ISOBUSFS_CM_VOLUME_STATUS_RES */ 199 | static int isobusfs_cli_rx_volume_status_res(struct isobusfs_priv *priv, 200 | struct isobusfs_msg *msg) 201 | { 202 | struct isobusfs_cm_vol_stat_res *vol_status = (void *)msg->buf; 203 | int ret = 0; 204 | 205 | if (priv->state != ISOBUSFS_CLI_STATE_WAIT_VOLUME_STATUS) { 206 | pr_warn("unexpected volume status response"); 207 | return -EINVAL; 208 | } 209 | 210 | pr_debug("< rx: volume status: %x, max time before remove %d, error code %d, path name length %d, name %s", 211 | vol_status->volume_status, 212 | vol_status->max_time_before_removal, 213 | vol_status->error_code, 214 | vol_status->name_len, 215 | vol_status->name); 216 | 217 | priv->state = ISOBUSFS_CLI_STATE_VOLUME_STATUS_DONE; 218 | 219 | return ret; 220 | } 221 | 222 | /* Command group: connection management */ 223 | int isobusfs_cli_rx_cg_cm(struct isobusfs_priv *priv, struct isobusfs_msg *msg) 224 | { 225 | int func = isobusfs_buf_to_function(msg->buf); 226 | int ret = 0; 227 | 228 | switch (func) { 229 | case ISOBUSFS_CM_F_FS_STATUS: 230 | return isobusfs_cli_rx_fs_status(priv, msg); 231 | case ISOBUSFS_CM_GET_FS_PROPERTIES_RES: 232 | return isobusfs_cli_rx_fs_property_res(priv, msg); 233 | case ISOBUSFS_CM_VOLUME_STATUS_RES: 234 | return isobusfs_cli_rx_volume_status_res(priv, msg); 235 | default: 236 | pr_warn("unsupported function: %i", func); 237 | return -EINVAL; 238 | } 239 | 240 | return ret; 241 | } 242 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_cli_dh.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "isobusfs_cli.h" 10 | #include "isobusfs_cmn_dh.h" 11 | 12 | /* 13 | * C.2.3.2 Change Current Directory Request 14 | */ 15 | int isobusfs_cli_ccd_req(struct isobusfs_priv *priv, const char *name, 16 | size_t name_len) 17 | { 18 | struct isobusfs_dh_ccd_req *req; 19 | size_t req_len = sizeof(*req) + name_len; 20 | size_t padding_size = 0; 21 | int ret; 22 | 23 | if (name_len > ISOBUSFS_MAX_PATH_NAME_LENGTH) { 24 | pr_warn("path name too long: %i, max is %i", name_len, 25 | ISOBUSFS_MAX_PATH_NAME_LENGTH); 26 | return -EINVAL; 27 | } 28 | 29 | if (req_len < ISOBUSFS_MIN_TRANSFER_LENGH) { 30 | /* Update the buffer size accordingly */ 31 | padding_size = ISOBUSFS_MIN_TRANSFER_LENGH - req_len; 32 | req_len = ISOBUSFS_MIN_TRANSFER_LENGH; 33 | } 34 | 35 | req = malloc(req_len); 36 | if (!req) { 37 | pr_err("failed to allocate memory for ccd request"); 38 | return -ENOMEM; 39 | } 40 | 41 | req->fs_function = isobusfs_cg_function_to_buf(ISOBUSFS_CG_DIRECTORY_HANDLING, 42 | ISOBUSFS_DH_F_CHANGE_CURRENT_DIR_REQ); 43 | req->tan = isobusfs_cli_get_next_tan(priv); 44 | 45 | memcpy(&req->name[0], name, name_len); 46 | req->name_len = name_len; 47 | 48 | if (padding_size) { 49 | /* Fill the rest of the res structure with 0xff */ 50 | memset(((uint8_t *)req) + req_len - padding_size, 0xff, 51 | padding_size); 52 | } 53 | 54 | priv->state = ISOBUSFS_CLI_STATE_WAIT_CCD_RESP; 55 | ret = isobusfs_send(priv->sock_main, req, req_len, &priv->tx_buf_log); 56 | if (ret < 0) { 57 | ret = -errno; 58 | pr_warn("failed to send ccd request: %d (%s)", 59 | ret, strerror(ret)); 60 | goto free_req; 61 | } 62 | 63 | pr_debug("> tx: ccd request for %s", name); 64 | 65 | free_req: 66 | free(req); 67 | 68 | return ret; 69 | } 70 | 71 | static int isobusfs_cli_dh_ccd_res_log(struct isobusfs_priv *priv, 72 | struct isobusfs_msg *msg, void *ctx, 73 | int error) 74 | { 75 | struct isobusfs_dh_ccd_res *res = 76 | (struct isobusfs_dh_ccd_res *)msg->buf; 77 | 78 | if (priv->state != ISOBUSFS_CLI_STATE_WAIT_CCD_RESP) { 79 | pr_warn("invalid state: %i (expected %i)", priv->state, 80 | ISOBUSFS_CLI_STATE_WAIT_CCD_RESP); 81 | return -EINVAL; 82 | } 83 | 84 | if (!isobusfs_cli_tan_is_valid(res->tan, priv)) { 85 | priv->state = ISOBUSFS_CLI_STATE_CCD_FAIL; 86 | } else if (res->error_code != 0) { 87 | pr_warn("ccd failed with error code: %i", res->error_code); 88 | priv->state = ISOBUSFS_CLI_STATE_CCD_FAIL; 89 | } else { 90 | priv->state = ISOBUSFS_CLI_STATE_CCD_DONE; 91 | } 92 | 93 | priv->error_code = res->error_code; 94 | if (!error) 95 | pr_debug("< rx: change current directory response. Error code: %i", 96 | res->error_code); 97 | 98 | return 0; 99 | } 100 | 101 | int isobusfs_cli_send_and_register_ccd_event(struct isobusfs_priv *priv, 102 | const char *name, 103 | size_t name_len, 104 | isobusfs_event_callback cb, 105 | void *ctx) 106 | { 107 | struct isobusfs_event event; 108 | uint8_t fs_function; 109 | int ret; 110 | 111 | ret = isobusfs_cli_ccd_req(priv, name, name_len); 112 | if (ret < 0) 113 | return ret; 114 | 115 | fs_function = 116 | isobusfs_cg_function_to_buf(ISOBUSFS_CG_DIRECTORY_HANDLING, 117 | ISOBUSFS_DH_F_CHANGE_CURRENT_DIR_RES); 118 | 119 | if (cb) 120 | event.cb = cb; 121 | else 122 | event.cb = isobusfs_cli_dh_ccd_res_log; 123 | 124 | event.ctx = ctx; 125 | 126 | isobusfs_cli_prepare_response_event(&event, priv->sock_main, 127 | fs_function); 128 | 129 | return isobusfs_cli_register_event(priv, &event); 130 | } 131 | 132 | /* function to send current directory request */ 133 | int isobusfs_cli_get_current_dir_req(struct isobusfs_priv *priv) 134 | { 135 | struct isobusfs_dh_get_cd_req req; 136 | int ret; 137 | 138 | req.fs_function = isobusfs_cg_function_to_buf(ISOBUSFS_CG_DIRECTORY_HANDLING, 139 | ISOBUSFS_DH_F_GET_CURRENT_DIR_REQ); 140 | req.tan = isobusfs_cli_get_next_tan(priv); 141 | 142 | ret = isobusfs_send(priv->sock_main, &req, sizeof(req), &priv->tx_buf_log); 143 | if (ret < 0) { 144 | ret = -errno; 145 | pr_warn("failed to send current directory request: %d (%s)", 146 | ret, strerror(ret)); 147 | return ret; 148 | } 149 | 150 | priv->state = ISOBUSFS_CLI_STATE_WAIT_CURRENT_DIR; 151 | 152 | pr_debug("> tx: current directory request"); 153 | return 0; 154 | } 155 | 156 | static int isobusfs_cli_dh_current_dir_res_log(struct isobusfs_priv *priv, 157 | struct isobusfs_msg *msg, 158 | void *ctx, int error) 159 | { 160 | struct isobusfs_dh_get_cd_res *res = 161 | (struct isobusfs_dh_get_cd_res *)msg->buf; 162 | char str[ISOBUSFS_MAX_PATH_NAME_LENGTH]; 163 | uint16_t total_space, free_space, str_len; 164 | 165 | if (!isobusfs_cli_tan_is_valid(res->tan, priv)) 166 | pr_warn("invalid tan: %i", res->tan); 167 | 168 | total_space = le16toh(res->total_space); 169 | free_space = le16toh(res->free_space); 170 | str_len = le16toh(res->name_len); 171 | if (str_len > ISOBUSFS_MAX_PATH_NAME_LENGTH) { 172 | pr_warn("path name too long: %i, max is %i", str_len, 173 | ISOBUSFS_MAX_PATH_NAME_LENGTH); 174 | str_len = ISOBUSFS_MAX_PATH_NAME_LENGTH; 175 | } 176 | strncpy(str, (const char *)&res->name[0], str_len); 177 | 178 | priv->state = ISOBUSFS_CLI_STATE_GET_CURRENT_DIR_DONE; 179 | 180 | pr_debug("< rx: current directory response: %s, total space: %i, free space: %i", 181 | str, total_space, free_space); 182 | 183 | return 0; 184 | } 185 | 186 | int isobusfs_cli_send_and_register_gcd_event(struct isobusfs_priv *priv, 187 | isobusfs_event_callback cb, 188 | void *ctx) 189 | { 190 | struct isobusfs_event event; 191 | uint8_t fs_function; 192 | int ret; 193 | 194 | ret = isobusfs_cli_get_current_dir_req(priv); 195 | if (ret < 0) 196 | return ret; 197 | 198 | fs_function = 199 | isobusfs_cg_function_to_buf(ISOBUSFS_CG_DIRECTORY_HANDLING, 200 | ISOBUSFS_DH_F_GET_CURRENT_DIR_RES); 201 | if (cb) 202 | event.cb = cb; 203 | else 204 | event.cb = isobusfs_cli_dh_ccd_res_log; 205 | 206 | event.ctx = ctx; 207 | 208 | isobusfs_cli_prepare_response_event(&event, priv->sock_main, 209 | fs_function); 210 | 211 | return isobusfs_cli_register_event(priv, &event); 212 | } 213 | 214 | /* Command group: directory handling */ 215 | int isobusfs_cli_rx_cg_dh(struct isobusfs_priv *priv, 216 | struct isobusfs_msg *msg) 217 | { 218 | int func = isobusfs_buf_to_function(msg->buf); 219 | int ret = 0; 220 | 221 | switch (func) { 222 | case ISOBUSFS_DH_F_GET_CURRENT_DIR_RES: 223 | return isobusfs_cli_dh_current_dir_res_log(priv, msg, NULL, 0); 224 | case ISOBUSFS_DH_F_CHANGE_CURRENT_DIR_RES: 225 | return isobusfs_cli_dh_ccd_res_log(priv, msg, NULL, 0); 226 | default: 227 | pr_warn("%s: unsupported function: %i", __func__, func); 228 | /* Not a critical error */ 229 | } 230 | 231 | return ret; 232 | } 233 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_cmn_cm.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #ifndef ISOBUSFS_CMN_CM_H 5 | #define ISOBUSFS_CMN_CM_H 6 | 7 | #include "isobusfs_cmn.h" 8 | 9 | /* ISOBUSFS_CM_F_FS_STATUS */ 10 | #define ISOBUSFS_CM_F_FS_STATUS_IDLE_RATE 2000 /* ms */ 11 | #define ISOBUSFS_CM_F_FS_STATUS_BUSY_RATE 200 /* ms */ 12 | #define ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER 5 /* ms */ 13 | /* File Server Status */ 14 | #define ISOBUSFS_FS_SATUS_BUSY_WRITING BIT(1) 15 | #define ISOBUSFS_FS_SATUS_BUSY_READING BIT(0) 16 | 17 | /** 18 | * C.1.2 File Server Status 19 | * struct isobusfs_cm_fss - File Server Status structure 20 | * @fs_function: Function and command (1 byte) 21 | * Bits 7-4: 0b0000 (Command - Connection Management, see B.1) 22 | * Bits 3-0: 0b0001 (Function - File Server Status, see B.2) 23 | * @file_server_status: File Server Status (1 byte) (see B.3) 24 | * Bits 7-2: 000000 (Reserved, send as 000000) 25 | * Bit 1: 1 (Busy writing) 26 | * Bit 0: 1 (Busy reading) 27 | * @num_open_files: Number of open files (1 byte) 28 | * @reserved: Reserved for future use (5 bytes) 29 | * 30 | * Transmission repetition rate: 2 000 ms when the status is not busy, 200 ms 31 | * when the status is busy reading or writing and, 32 | * on change of byte 2, up to five messages per 33 | * second. 34 | * Data length: 8 bytes 35 | * Parameter group number: FS to client, destination-specific or use global address: 0xFF 36 | */ 37 | struct isobusfs_cm_fss { 38 | uint8_t fs_function; 39 | uint8_t status; 40 | uint8_t num_open_files; 41 | uint8_t reserved[5]; 42 | }; 43 | 44 | /** 45 | * C.1.3 Client Connection Maintenance 46 | * struct isobusfs_cm_ccm - Client Connection Maintenance structure 47 | * @fs_function: Function and command (1 byte) 48 | * Bits 7-4: 0b0000 (Command - Connection Management, see B.1) 49 | * Bits 3-0: 0b0000 (Function - Client Connection Maintenance, see B.2) 50 | * @version: Version number (1 byte) (see B.5) 51 | * @reserved: Reserved for future use (6 bytes) 52 | * 53 | * Transmission repetition rate: 2000 ms 54 | * Data length: 8 bytes 55 | * Parameter group number: Client to FS, destination-specific 56 | */ 57 | struct isobusfs_cm_ccm { 58 | uint8_t fs_function; 59 | uint8_t version; 60 | uint8_t reserved[6]; 61 | }; 62 | 63 | /** 64 | * C.1.4 Get File Server Properties 65 | * struct isobusfs_cm_get_fs_props_req - Get File Server Properties structure 66 | * @fs_function: Function and command (1 byte) 67 | * Bits 7-4: 0b0000 (Command - Connection Management, see B.1) 68 | * Bits 3-0: 0b0001 (Function - Get File Server Properties, see B.2) 69 | * @reserved: Reserved, transmit as 0xFF (7 bytes) 70 | * 71 | * Transmission repetition rate: On request 72 | * Data length: 8 bytes 73 | * Parameter group number: Client to FS, destination-specific 74 | */ 75 | struct isobusfs_cm_get_fs_props_req { 76 | uint8_t fs_function; 77 | uint8_t reserved[7]; 78 | }; 79 | 80 | /* File Server Capabilities */ 81 | /* server support removable volumes */ 82 | #define ISOBUSFS_SRV_CAP_REMOVABLE_VOL BIT(1) 83 | /* server support multiple volumes */ 84 | #define ISOBUSFS_SRV_CAP_MULTI_VOL BIT(0) 85 | 86 | /** 87 | * C.1.5 Get File Server Properties Response 88 | * struct isobusfs_get_fs_props_resp - Get File Server Properties Response 89 | * @fs_function: Function and command (1 byte) 90 | * Bits 7-4: 0b0000 (Command - Connection Management, see B.1) 91 | * Bits 3-0: 0b0001 (Function - Get File Server Properties, see B.2) 92 | * @version_number: Version Number (1 byte, see B.5) 93 | * @max_open_files: Maximum Number of Simultaneously Open Files (1 byte, see B.6) 94 | * @fs_capabilities: File Server Capabilities (1 byte, see B.7) 95 | * @reserved: Reserved, transmit as 0xFF (4 bytes) 96 | * 97 | * Transmission repetition rate: In response to Get File Server Properties message 98 | * Data length: 8 bytes 99 | * Parameter group number: FS to client, destination-specific 100 | */ 101 | struct isobusfs_cm_get_fs_props_resp { 102 | uint8_t fs_function; 103 | uint8_t version_number; 104 | uint8_t max_open_files; 105 | uint8_t fs_capabilities; 106 | uint8_t reserved[4]; 107 | }; 108 | 109 | #define ISOBUSFS_VOL_MODE_PREP_TO_REMOVE BIT(1) 110 | #define ISOBUSFS_VOL_MODE_USED_BY_CLIENT BIT(0) 111 | #define ISOBUSFS_VOL_MODE_NOT_USED 0 112 | 113 | /** 114 | * C.1.6 Volume Status Request 115 | * struct isobusfs_cm_vol_stat_req - Volume Status Request structure 116 | * @fs_function: Function and command (1 byte) 117 | * Bits 7-4: 0b0000 (Command - Connection Management, see B.1) 118 | * Bits 3-0: 0b0010 (Function - Removable Media Status, see B.2) 119 | * @volume_mode: Volume Mode (1 byte) (see B.30) 120 | * @name_len: Path Name Length (2 bytes) (__le16, see B.12) 121 | * @name: Volume Name (variable length) (see B.34) 122 | * 123 | * Transmission repetition rate: Upon request 124 | * Data length: Variable 125 | * Parameter group number: Client to FS, specific to the destination 126 | */ 127 | 128 | struct isobusfs_cm_vol_stat_req { 129 | uint8_t fs_function; 130 | uint8_t volume_mode; 131 | __le16 name_len; 132 | char name[ISOBUSFS_MAX_VOLUME_NAME_LENGTH]; 133 | }; 134 | 135 | 136 | enum isobusfs_vol_status { 137 | ISOBUSFS_VOL_STATUS_PRESENT = 0, 138 | ISOBUSFS_VOL_STATUS_IN_USE = 1, 139 | ISOBUSFS_VOL_STATUS_PREP_TO_REMOVE = 2, 140 | ISOBUSFS_VOL_STATUS_REMOVED = 3, 141 | }; 142 | /** 143 | * C.1.7 Volume Status Response 144 | * struct isobusfs_cm_vol_stat_res - Volume Status Response structure 145 | * @fs_function: Function and command (1 byte) 146 | * Bits 7-4: 0b0000 (Command - Connection Management, see B.1) 147 | * Bits 3-0: 0b0010 (Function - Volume Status, see B.2) 148 | * @volume_status: Volume Status (1 byte) (see B.31) 149 | * @max_time_before_removal: Maximum Time Before Volume Removal (1 byte) (see B.32) 150 | * @error_code: Error code (1 byte) (see B.9) 151 | * 0: Success 152 | * 1: Access denied 153 | * 2: Invalid Access 154 | * 4: File, path or volume not found 155 | * 6: Invalid given source name 156 | * 43: Out of memory 157 | * 44: Any other error 158 | * @name_len: Path Name Length (2 bytes) (__le16, see B.12) 159 | * @name: Volume Name (variable length) (see B.34) 160 | * 161 | * Transmission repetition rate: On request and on change of Volume Status 162 | * Data length: Variable 163 | * Parameter group number: FS to client, destination-specific or use global address: FF 16 164 | */ 165 | struct isobusfs_cm_vol_stat_res { 166 | uint8_t fs_function; 167 | uint8_t volume_status; 168 | uint8_t max_time_before_removal; 169 | uint8_t error_code; 170 | __le16 name_len; 171 | char name[ISOBUSFS_MAX_VOLUME_NAME_LENGTH]; 172 | }; 173 | 174 | 175 | #endif /* ISOBUSFS_CMN_CM_H */ 176 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_cmn_dh.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "isobusfs_cmn.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable) 17 | { 18 | struct stat path_stat; 19 | int mode = R_OK; 20 | int ret; 21 | 22 | mode |= writable ? W_OK : 0; 23 | ret = access(path, mode); 24 | if (ret == -1) { 25 | ret = -errno; 26 | pr_err("failed to access path %s, for read %s. %s", path, 27 | writable ? "and write" : "", strerror(ret)); 28 | return ret; 29 | } 30 | 31 | ret = stat(path, &path_stat); 32 | if (ret == -1) { 33 | ret = -errno; 34 | pr_err("failed to get stat information on path %s. %s", path, 35 | strerror(ret)); 36 | return ret; 37 | } 38 | 39 | if (!S_ISDIR(path_stat.st_mode)) { 40 | pr_err("path %s is not a directory", path); 41 | return -ENOTDIR; 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_cmn_dh.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #ifndef _ISOBUSFS_CMN_DH_H 5 | #define _ISOBUSFS_CMN_DH_H 6 | 7 | #include "isobusfs_cmn.h" 8 | 9 | /** 10 | * C.2.2.2 Get Current Directory Request 11 | * struct isobusfs_dh_get_cd_req - Get Current Directory Request structure 12 | * @fs_function: Function and command (1 byte) 13 | * Bits 7-4: 0b0001 (Command - Directory Access, see B.1) 14 | * Bits 3-0: 0b0000 (Function - Get Current Directory, see B.2) 15 | * @tan: Transaction number (1 byte) (see B.8) 16 | * @reserved: Reserved, transmit as 0xFF (6 bytes) 17 | * 18 | * Transmission repetition rate: On request 19 | * Data length: 8 bytes 20 | * Parameter group number: Client to FS, destination-specific 21 | */ 22 | struct isobusfs_dh_get_cd_req { 23 | uint8_t fs_function; 24 | uint8_t tan; 25 | uint8_t reserved[6]; 26 | }; 27 | 28 | /** 29 | * C.2.2.3 Get Current Directory Response 30 | * struct isobusfs_dh_get_cd_res - Get Current Directory Response structure 31 | * @fs_function: Function and command (1 byte) 32 | * Bits 7-4: 0b0001 (Command - Directory Access, see B.1) 33 | * Bits 3-0: 0b0000 (Function - Get Current Directory, see B.2) 34 | * @tan: Transaction number (1 byte) (see B.8) 35 | * @error_code: Error code (1 byte) (see B.9) 36 | * @total_space: Total space (4 bytes) (in units of 512 bytes, see B.11) 37 | * @free_space: Free space (4 bytes) (in units of 512 bytes, see B.11) 38 | * @name_len: Path Name Length (2 bytes) (__le16, see B.12) 39 | * @name: Path Name (variable length) (see B.13) 40 | * 41 | * Transmission repetition rate: In response to Get Current Directory Request message 42 | * Data length: Variable 43 | * Parameter group number: FS to client, destination-specific 44 | */ 45 | struct isobusfs_dh_get_cd_res { 46 | uint8_t fs_function; 47 | uint8_t tan; 48 | uint8_t error_code; 49 | __le32 total_space; 50 | __le32 free_space; 51 | __le16 name_len; 52 | uint8_t name[]; 53 | }; 54 | 55 | /** 56 | * C.2.3.2 Change Current Directory Request 57 | * struct isobusfs_dh_ccd_req - Change Current Directory Request structure 58 | * @fs_function: Function and command (1 byte) 59 | * Bits 7-4: 0b0001 (Command - Directory Access, see B.1) 60 | * Bits 3-0: 0b0001 (Function - Change Current Directory, see B.2) 61 | * @tan: Transaction number (1 byte) (see B.8) 62 | * @name_len: Path Name length (2 bytes) (__le16, see B.12) 63 | * @name: Path Name (variable length) (see B.13) 64 | * 65 | * Transmission repetition rate: On request 66 | * Data length: Variable 67 | * Parameter group number: Client to FS, destination-specific 68 | */ 69 | struct isobusfs_dh_ccd_req { 70 | uint8_t fs_function; 71 | uint8_t tan; 72 | __le16 name_len; 73 | uint8_t name[]; 74 | }; 75 | 76 | /** 77 | * C.2.3.3 Change Current Directory Response 78 | * struct isobusfs_dh_ccd_res - Change Current Directory Response structure 79 | * @fs_function: Function and command (1 byte) 80 | * Bits 7-4: 0b0001 (Command - Directory Access, see B.1) 81 | * Bits 3-0: 0b0001 (Function - Change Current Directory, see B.2) 82 | * @tan: Transaction number (1 byte) (see B.8) 83 | * @error_code: Error code (1 byte) (see B.9) 84 | * 0: Success 85 | * 1: Access denied 86 | * 2: Invalid access 87 | * 4: File, path or volume not found 88 | * 7: Invalid destination name given 89 | * 10: Media is not present 90 | * 13: Volume is possibly not initialized 91 | * 43: Out of memory 92 | * 44: Any other error 93 | * @reserved: Reserved, transmit as 0xFF (5 bytes) 94 | * 95 | * Transmission repetition rate: In response to Change Current Directory Request message 96 | * Data length: 8 bytes 97 | * Parameter group number: FS to client, destination-specific 98 | */ 99 | struct isobusfs_dh_ccd_res { 100 | uint8_t fs_function; 101 | uint8_t tan; 102 | uint8_t error_code; 103 | uint8_t reserved[5]; 104 | }; 105 | 106 | 107 | #endif /* _ISOBUSFS_CMN_DH_H */ 108 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_cmn_va.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #ifndef _ISOBUSFS_CMN_VA_H 5 | #define _ISOBUSFS_CMN_VA_H 6 | 7 | #include "isobusfs_cmn.h" 8 | 9 | /** 10 | * C.5.2.2 Initialize Volume Request 11 | * struct isobusfs_va_init_vol_req - Initialize Volume Request structure 12 | * @fs_function: Function and command (1 byte) 13 | * Bits 7-4: 0b0100 (Command - Volume Access, see B.1) 14 | * Bits 3-0: 0b0000 (Function - Initialize Volume, see B.2) 15 | * @tan: Transaction number (1 byte) (see B.8) 16 | * @space: Space (2 bytes) (see B.11) 17 | * @volume_flags: Volume Flags (1 byte) (see B.29) 18 | * @name_len: Pathname Length (2 bytes) (__le16, see B.12) 19 | * @name: Volume, Path and Filename (variable length) (see B.35) 20 | * 21 | * Transmission repetition rate: On request 22 | * Data length: Variable 23 | * Parameter group number: Client to FS, destination-specific 24 | */ 25 | struct isobusfs_va_init_vol_req { 26 | uint8_t fs_function; 27 | uint8_t tan; 28 | __le16 space; 29 | uint8_t volume_flags; 30 | __le16 name_len; 31 | uint8_t name[]; 32 | }; 33 | 34 | /** 35 | * C.5.2.3 Initialize Volume Response 36 | * struct isobusfs_va_init_vol_res - Initialize Volume Response structure 37 | * @fs_function: Function and command (1 byte) 38 | * Bits 7-4: 0b0100 (Command - Volume Access, see B.1) 39 | * Bits 3-0: 0b0000 (Function - Initialize Volume, see B.2) 40 | * @tan: Transaction number (1 byte) (see B.8) 41 | * @error_code: Error code (1 byte) (see B.9) 42 | * 0: Success 43 | * 1: Access denied 44 | * 4: Volume, path or file not found 45 | * 6: Invalid given source name 46 | * 8: Volume out of free space 47 | * 9: Failure during write operation 48 | * 10: Media is not present 49 | * 11 Failure during read operation 50 | * 12: Function not supported 51 | * 13: Volume is possibly not initialized 52 | * 43: Out of memory 53 | * 44: Any other error 54 | * @reserved: Reserved, transmit as 0xFF (4 bytes) 55 | * 56 | * Transmission repetition rate: In response to Initialize Volume Request message 57 | * Data length: 8 bytes 58 | * Parameter group number: FS to client, destination-specific 59 | */ 60 | struct isobusfs_va_init_vol_res { 61 | uint8_t fs_function; 62 | uint8_t tan; 63 | uint8_t error_code; 64 | uint8_t reserved[4]; 65 | }; 66 | 67 | #endif /* _ISOBUSFS_CMN_VA_H */ 68 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_create_test_dirs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: LGPL-2.0-only 3 | # SPDX-FileCopyrightText: 2023 Oleksij Rempel 4 | 5 | mkdir dir1 6 | mkdir dir1/dir2 7 | mkdir dir1/dir2/dir3 8 | mkdir dir1/dir2/dir3/dir4 9 | mkdir dir1/dir2/dir3/dir5 10 | mkdir MCMC0683 11 | mkdir MCMC0683/msd_dir1/msd_dir2 12 | mkdir MCMC0683/msd_dir1/msd_dir2/~ 13 | mkdir MCMC0683/msd_dir1/msd_dir2/~/~tilde_dir 14 | mkdir dir1/~ 15 | mkdir dir1/~/~ 16 | 17 | echo "hello" > dir1/dir2/file0 18 | 19 | ./isobusfs_create_test_file.sh dir1/dir2/file1k 1024 20 | ./isobusfs_create_test_file.sh dir1/dir2/file1m 1048576 21 | 22 | File and directory names testing 23 | mkdir 'dir1/dir2/special_chars_*?/' 24 | mkdir 'dir1/dir2/unicode_名字' 25 | 26 | # Define the long suffix for the filenames 27 | long_suffix="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop" 28 | 29 | # Loop to create 300 files with long names 30 | for count in {1..300}; do 31 | touch "long_name_${count}_${long_suffix}" 32 | done 33 | 34 | touch dir1/dir2/hidden_file 35 | touch dir1/dir2/readonly_file 36 | touch dir1/dir2/executable_file 37 | touch dir1/dir2/no_read_permission_file 38 | 39 | # Setting permissions 40 | chmod 444 dir1/dir2/readonly_file # Read-only file 41 | chmod +x dir1/dir2/executable_file # Executable file 42 | chmod 000 dir1/dir2/no_read_permission_file # No read permission for anyone 43 | 44 | # Create directories for date problems 45 | mkdir "dir1/dir2/y2000_problem" 46 | mkdir "dir1/dir2/y2038_problem" 47 | mkdir "dir1/dir2/y1979_problem" 48 | mkdir "dir1/dir2/y1980_problem" 49 | mkdir "dir1/dir2/y2107_problem" 50 | mkdir "dir1/dir2/y2108_problem" 51 | 52 | # Change timestamps to reflect specific years 53 | # Year 2000 54 | touch -d '2000-01-01 00:00:00' dir1/dir2/y2000_problem 55 | 56 | # Year 2038 - beyond 19 January 2038, Unix timestamp issue 57 | touch -d '2038-01-20 00:00:00' dir1/dir2/y2038_problem 58 | 59 | # Year 1980 - minimal year supported 60 | touch -d '1979-12-31 23:59:59' dir1/dir2/y1979_problem 61 | touch -d '1980-01-01 00:00:00' dir1/dir2/y1980_problem 62 | 63 | # Year 2107 - max year 1980+127 64 | touch -d '2107-12-31 23:59:59' dir1/dir2/y2107_problem 65 | touch -d '2108-01-01 00:00:00' dir1/dir2/y2108_problem 66 | 67 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_create_test_file.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: LGPL-2.0-only 3 | # SPDX-FileCopyrightText: 2023 Oleksij Rempel 4 | 5 | # Arguments: path to the file and the file size 6 | FILEPATH=$1 7 | FILESIZE=$2 8 | 9 | # Variable to store the increasing number 10 | counter=0 11 | 12 | # XOR pattern (change this to whatever you like) 13 | pattern=0xdeadbeef 14 | 15 | # Calculate the number of iterations needed 16 | let iterations=$FILESIZE/4 17 | 18 | # Use 'dd' command to generate the file with increasing numbers 19 | for ((i=0; i<$iterations; i++)); do 20 | # Print the 32-bit number in binary format to the file 21 | printf "%08x" $((counter ^ pattern)) | xxd -r -p >> $FILEPATH 22 | let counter=counter+1 23 | done 24 | 25 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_srv.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #ifndef ISOBUSFS_SRV_H 5 | #define ISOBUSFS_SRV_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "isobusfs_cmn.h" 13 | #include "isobusfs_cmn_cm.h" 14 | 15 | #define ISOBUSFS_SRV_VERSION 4 16 | #define ISOBUSFS_SRV_MAX_CTRL_SOCKETS 1 17 | #define ISOBUSFS_SRV_MAX_CLIENT_SOCKETS 255 18 | #define ISOBUSFS_SRV_MAX_EPOLL_EVENTS (ISOBUSFS_SRV_MAX_CTRL_SOCKETS + \ 19 | ISOBUSFS_SRV_MAX_CLIENT_SOCKETS) 20 | #define ISOBUSFS_SRV_MAX_OPENED_HANDLES 255 21 | /* 22 | * ISO 11783-13:2021 standard does not explicitly specify a maximum number of 23 | * clients that can be supported on the network. However, the ISO 11783 standard 24 | * is built on top of the SAE J1939 protocol, which has a maximum of 238 25 | * available addresses for nodes. This number is calculated from the available 26 | * address range for assignment to nodes on the network, which includes 127 27 | * addresses in the range 1-127 and 111 addresses in the range 248-254, 28 | * inclusive. Some addresses in the total range (0-255) are reserved for 29 | * specific purposes, such as broadcast messages and null addresses. 30 | * 31 | * The maximum number of 238 nodes includes both clients and servers, so the 32 | * actual number of clients that can be supported will be less than 238. 33 | * 34 | * It is important to note that the practical limit of clients in an ISO 35 | * 11783-13 network could be lower due to factors such as network bandwidth, 36 | * performance constraints of the individual devices, and the complexity of the 37 | * network. 38 | */ 39 | #define ISOBUSFS_SRV_MAX_CLIENTS 237 40 | 41 | enum isobusfs_srv_fss_state { 42 | ISOBUSFS_SRV_STATE_IDLE = 0, /* send status with 2000ms interval */ 43 | ISOBUSFS_SRV_STATE_STAT_CHANGE_1, /* send status with 200ms interval */ 44 | ISOBUSFS_SRV_STATE_STAT_CHANGE_2, /* send status with 200ms interval */ 45 | ISOBUSFS_SRV_STATE_STAT_CHANGE_3, /* send status with 200ms interval */ 46 | ISOBUSFS_SRV_STATE_STAT_CHANGE_4, /* send status with 200ms interval */ 47 | ISOBUSFS_SRV_STATE_STAT_CHANGE_5, /* send status with 200ms interval */ 48 | ISOBUSFS_SRV_STATE_BUSY, /* send status with 200ms interval */ 49 | }; 50 | 51 | struct isobusfs_srv_client { 52 | int sock; 53 | struct timespec last_received; 54 | uint8_t addr; 55 | uint8_t tan; 56 | uint8_t version; 57 | char current_dir[ISOBUSFS_SRV_MAX_PATH_LEN]; 58 | }; 59 | 60 | struct isobusfs_srv_volume { 61 | char *name; 62 | char *path; 63 | bool removable; 64 | bool writeable; 65 | int refcount; 66 | struct isobusfs_srv_client *clients[ISOBUSFS_SRV_MAX_CLIENTS]; 67 | }; 68 | 69 | struct isobusfs_srv_handles { 70 | char *path; 71 | int refcount; 72 | int fd; 73 | off_t offset; 74 | int32_t dir_pos; 75 | DIR *dir; 76 | struct isobusfs_srv_client *clients[ISOBUSFS_SRV_MAX_CLIENTS]; 77 | }; 78 | 79 | struct isobusfs_srv_priv { 80 | /* incoming traffic from peers */ 81 | int sock_in; 82 | /* 83 | * egress only File Server Status broadcast packets with different 84 | * prio 85 | */ 86 | int sock_fss; 87 | /* 88 | * bidirectional socket for NACK packets. 89 | * ISO 11783-3:2018 5.4.5 Acknowledgement 90 | */ 91 | int sock_nack; 92 | struct sockaddr_can addr; 93 | 94 | int server_version; 95 | 96 | /* fs status related variables */ 97 | struct isobusfs_cm_fss st; /* file server status message */ 98 | enum isobusfs_srv_fss_state st_state; 99 | struct isobusfs_stats st_msg_stats; 100 | 101 | /* client related variables */ 102 | struct isobusfs_srv_client clients[ISOBUSFS_SRV_MAX_CLIENTS]; 103 | int clients_count; 104 | struct isobusfs_buf_log tx_buf_log; 105 | 106 | struct libj1939_cmn cmn; 107 | 108 | struct isobusfs_srv_volume volumes[ISOBUSFS_SRV_MAX_VOLUMES]; 109 | int volume_count; 110 | int removable_volumes_count; 111 | const char *default_volume; 112 | /* manufacturer-specific directory */ 113 | char mfs_dir[9]; 114 | uint64_t local_name; 115 | 116 | struct isobusfs_srv_handles handles[ISOBUSFS_SRV_MAX_OPENED_HANDLES]; 117 | int handles_count; 118 | }; 119 | 120 | /* isobusfs_srv.c */ 121 | int isobusfs_srv_send_error(struct isobusfs_srv_priv *priv, 122 | struct isobusfs_msg *msg, enum isobusfs_error err); 123 | int isobusfs_srv_sendto(struct isobusfs_srv_priv *priv, 124 | struct isobusfs_msg *msg, const void *buf, 125 | size_t buf_size); 126 | 127 | /* isobusfs_srv_cm_fss.c */ 128 | void isobusfs_srv_fss_init(struct isobusfs_srv_priv *priv); 129 | int isobusfs_srv_fss_send(struct isobusfs_srv_priv *priv); 130 | 131 | /* isobusfs_srv_cm.c */ 132 | int isobusfs_srv_rx_cg_cm(struct isobusfs_srv_priv *priv, 133 | struct isobusfs_msg *msg); 134 | void isobusfs_srv_remove_timeouted_clients(struct isobusfs_srv_priv *priv); 135 | void isobusfs_srv_init_clients(struct isobusfs_srv_priv *priv); 136 | struct isobusfs_srv_client *isobusfs_srv_get_client( 137 | struct isobusfs_srv_priv *priv, uint8_t addr); 138 | struct isobusfs_srv_client *isobusfs_srv_get_client_by_msg( 139 | struct isobusfs_srv_priv *priv, struct isobusfs_msg *msg); 140 | 141 | /* isobusfs_srv_dh.c */ 142 | int isobusfs_srv_rx_cg_dh(struct isobusfs_srv_priv *priv, 143 | struct isobusfs_msg *msg); 144 | int isobusfs_path_to_linux_path(struct isobusfs_srv_priv *priv, 145 | const char *isobusfs_path, size_t isobusfs_path_size, 146 | char *linux_path, size_t linux_path_size); 147 | int isobusfs_check_current_dir_access(struct isobusfs_srv_priv *priv, 148 | const char *path, size_t path_size); 149 | int isobusfs_convert_relative_to_absolute(struct isobusfs_srv_priv *priv, 150 | const char *current_dir, 151 | const char *rel_path, 152 | size_t rel_path_size, char *abs_path, 153 | size_t abs_path_size); 154 | void isobusfs_srv_set_default_current_dir(struct isobusfs_srv_priv *priv, 155 | struct isobusfs_srv_client *client); 156 | 157 | 158 | /* isobusfs_srv_vh.c */ 159 | int isobusfs_srv_rx_cg_vh(struct isobusfs_srv_priv *priv, 160 | struct isobusfs_msg *msg); 161 | 162 | /* isobusfs_srv_fh.c */ 163 | int isobusfs_srv_rx_cg_fh(struct isobusfs_srv_priv *priv, 164 | struct isobusfs_msg *msg); 165 | 166 | /* isobusfs_srv_fa.c */ 167 | int isobusfs_srv_rx_cg_fa(struct isobusfs_srv_priv *priv, 168 | struct isobusfs_msg *msg); 169 | void isobusfs_srv_remove_client_from_handles(struct isobusfs_srv_priv *priv, 170 | struct isobusfs_srv_client *client); 171 | 172 | 173 | #endif /* ISOBUSFS_SRV_H */ 174 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_srv_cm_fss.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | /* 4 | * This file implements Annex C.1.2 File Server Status according to 5 | * ISO 11783-13:2021. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "isobusfs_srv.h" 20 | 21 | /* 22 | * isobusfs_srv_fss_init - Initialize the file server status structure 23 | * @priv: Pointer to the private data structure of the ISOBUS file server 24 | * 25 | * This function initializes the file server status structure, which 26 | * represents the status of the file server according to Annex C.1.2 27 | * of ISO 11783-13:2021. 28 | */ 29 | void isobusfs_srv_fss_init(struct isobusfs_srv_priv *priv) 30 | { 31 | struct isobusfs_cm_fss *st = &priv->st; 32 | 33 | st->fs_function = 34 | isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT, 35 | ISOBUSFS_CM_F_FS_STATUS); 36 | st->status = 0; 37 | st->num_open_files = 0; 38 | memset(st->reserved, 0xFF, sizeof(st->reserved)); 39 | } 40 | 41 | /* 42 | * isobusfs_srv_fss_get_rate - Get the rate of File Server Status transmission 43 | * @priv: Pointer to the private data structure of the ISOBUS file server 44 | * 45 | * Returns: the transmission rate of the File Server Status messages depending 46 | * on the current state of the file server. 47 | */ 48 | static unsigned int isobusfs_srv_fss_get_rate(struct isobusfs_srv_priv *priv) 49 | { 50 | switch (priv->st_state) { 51 | case ISOBUSFS_SRV_STATE_IDLE: 52 | return ISOBUSFS_CM_F_FS_STATUS_IDLE_RATE; 53 | /* 54 | * On every change of Byte 2 "File Server Status" send max 5 status 55 | * messages per second. 56 | */ 57 | case ISOBUSFS_SRV_STATE_STAT_CHANGE_1: /* fall through */ 58 | case ISOBUSFS_SRV_STATE_STAT_CHANGE_2: /* fall through */ 59 | case ISOBUSFS_SRV_STATE_STAT_CHANGE_3: /* fall through */ 60 | case ISOBUSFS_SRV_STATE_STAT_CHANGE_4: /* fall through */ 61 | case ISOBUSFS_SRV_STATE_STAT_CHANGE_5: 62 | priv->st_state--; 63 | return ISOBUSFS_CM_F_FS_STATUS_BUSY_RATE; 64 | case ISOBUSFS_SRV_STATE_BUSY: 65 | return ISOBUSFS_CM_F_FS_STATUS_BUSY_RATE; 66 | default: 67 | pr_warn("%s:%i: unknown state %d", __func__, __LINE__, 68 | priv->st_state); 69 | } 70 | 71 | /* 72 | * In case something is wrong, fall back to idle rate to not spam the 73 | * bus. 74 | */ 75 | return ISOBUSFS_CM_F_FS_STATUS_IDLE_RATE; 76 | } 77 | 78 | /** 79 | * isobusfs_srv_fss_send - Send periodic File Server Status messages 80 | * @priv: Pointer to the private data structure of the ISOBUS file server 81 | * 82 | * Returns: 0 if the message was sent successfully, a negative error code 83 | * otherwise. 84 | */ 85 | int isobusfs_srv_fss_send(struct isobusfs_srv_priv *priv) 86 | { 87 | unsigned int next_msg_rate; 88 | int64_t time_diff; 89 | int ret; 90 | 91 | /* Test if it is proper time to send next status message. */ 92 | time_diff = timespec_diff_ms(&priv->cmn.next_send_time, 93 | &priv->cmn.last_time); 94 | if (time_diff > ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { 95 | /* too early to send next message */ 96 | return 0; 97 | } 98 | 99 | if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { 100 | pr_warn("too late to send next fs status message: %ld ms", 101 | time_diff); 102 | } 103 | 104 | /* Make sure we send the message with the latest stats */ 105 | if (priv->st_msg_stats.tskey_sch != priv->st_msg_stats.tskey_ack) 106 | pr_warn("previous message was not acked"); 107 | 108 | /* send periodic file servers status messages. */ 109 | ret = send(priv->sock_fss, &priv->st, sizeof(priv->st), MSG_DONTWAIT); 110 | if (ret < 0) { 111 | ret = -errno; 112 | pr_warn("Failed to send FS status message, error code: %d (%s)", 113 | ret, strerror(ret)); 114 | return ret; 115 | } 116 | 117 | pr_debug("> tx FS status: 0x%02x, opened files: %d", 118 | priv->st.status, priv->st.num_open_files); 119 | 120 | /* Calculate time for the next status message */ 121 | next_msg_rate = isobusfs_srv_fss_get_rate(priv); 122 | priv->cmn.next_send_time = priv->cmn.last_time; 123 | timespec_add_ms(&priv->cmn.next_send_time, next_msg_rate); 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_srv_fh.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "isobusfs_srv.h" 9 | 10 | /* Command group: file handling */ 11 | int isobusfs_srv_rx_cg_fh(struct isobusfs_srv_priv *priv, 12 | struct isobusfs_msg *msg) 13 | { 14 | int func = isobusfs_buf_to_function(msg->buf); 15 | int ret = 0; 16 | 17 | switch (func) { 18 | case ISOBUSFS_FH_F_MOVE_FILE_REQ: 19 | case ISOBUSFS_FH_F_DELETE_FILE_REQ: 20 | case ISOBUSFS_FH_F_GET_FILE_ATTR_REQ: 21 | case ISOBUSFS_FH_F_SET_FILE_ATTR_REQ: 22 | case ISOBUSFS_FH_F_GET_FILE_DATETIME_REQ: 23 | default: 24 | isobusfs_srv_send_error(priv, msg, 25 | ISOBUSFS_ERR_FUNC_NOT_SUPPORTED); 26 | pr_warn("%s: unsupported function: %i", __func__, func); 27 | } 28 | 29 | return ret; 30 | } 31 | -------------------------------------------------------------------------------- /isobusfs/isobusfs_srv_vh.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2023 Oleksij Rempel 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "isobusfs_srv.h" 9 | 10 | /* Command group: volume hnadling */ 11 | int isobusfs_srv_rx_cg_vh(struct isobusfs_srv_priv *priv, 12 | struct isobusfs_msg *msg) 13 | { 14 | int func = isobusfs_buf_to_function(msg->buf); 15 | int ret = 0; 16 | 17 | switch (func) { 18 | /* TODO: currently not implemented */ 19 | case ISOBUSFS_VA_F_INITIALIZE_VOLUME_REQ: /* fall through */ 20 | default: 21 | isobusfs_srv_send_error(priv, msg, 22 | ISOBUSFS_ERR_FUNC_NOT_SUPPORTED); 23 | pr_warn("%s: unsupported function: %i", __func__, func); 24 | } 25 | 26 | return ret; 27 | } 28 | -------------------------------------------------------------------------------- /j1939_timedate/j1939_timedate_cmn.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.0-only 2 | // SPDX-FileCopyrightText: 2024 Oleksij Rempel 3 | 4 | #ifndef _J1939_TIMEDATE_H_ 5 | #define _J1939_TIMEDATE_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include "../libj1939.h" 15 | #include "../lib.h" 16 | 17 | /* SAE J1939-71:2002 - 5.3 pgn54528 - Time/Date Adjust - TDA - */ 18 | #define J1939_PGN_TDA 0x0d500 /* 54528 */ 19 | /* SAE J1939-71:2002 - 5.3 pgn65254 - Time/Date - TD - */ 20 | #define J1939_PGN_TD 0x0fee6 /* 65254 */ 21 | 22 | #define J1939_PGN_REQUEST_PGN 0x0ea00 /* 59904 */ 23 | 24 | /* ISO 11783-3:2018 - 5.4.5 Acknowledgment */ 25 | #define ISOBUS_PGN_ACK 0x0e800 /* 59392 */ 26 | 27 | #define J1939_TIMEDATE_PRIO_DEFAULT 6 28 | 29 | #define J1939_TIMEDATE_MAX_TRANSFER_LENGH 8 30 | 31 | struct j1939_timedate_stats { 32 | int err; 33 | uint32_t tskey_sch; 34 | uint32_t tskey_ack; 35 | uint32_t send; 36 | }; 37 | 38 | struct j1939_timedate_msg { 39 | uint8_t buf[J1939_TIMEDATE_MAX_TRANSFER_LENGH]; 40 | size_t buf_size; 41 | ssize_t len; /* length of received message */ 42 | struct sockaddr_can peername; 43 | socklen_t peer_addr_len; 44 | int sock; 45 | }; 46 | 47 | struct j1939_timedate_err_msg { 48 | struct sock_extended_err *serr; 49 | struct scm_timestamping *tss; 50 | struct j1939_timedate_stats *stats; 51 | }; 52 | 53 | /* 54 | * struct time_date_packet - Represents the PGN 65254 Time/Date packet 55 | * 56 | * @seconds: Seconds since the last minute (0-59) with a scaling factor, 57 | * meaning each increment represents 0.25 seconds. 58 | * @minutes: Minutes since the last hour (0-59) with no scaling. 59 | * @hours: Hours since midnight (0-23) with no scaling. 60 | * @month: Current month (1-12) with no scaling. 61 | * @day: Day of the month with a scaling factor, each increment represents 0.25 62 | * day. 63 | * @year: Year offset since 1985, each increment represents one year. 64 | * @local_minute_offset: Offset in minutes from UTC, can range from -125 to 125 65 | * minutes. 66 | * @local_hour_offset: Offset in hours from UTC, can range from -125 to 125 67 | * hours. 68 | * 69 | * This structure defines each component of the Time/Date as described in 70 | * PGN 65254, using each byte to represent different components of the standard 71 | * UTC time and optionally adjusted local time based on offsets. 72 | */ 73 | struct j1939_time_date_packet { 74 | uint8_t seconds; 75 | uint8_t minutes; 76 | uint8_t hours; 77 | uint8_t month; 78 | uint8_t day; 79 | uint8_t year; 80 | int8_t local_minute_offset; 81 | int8_t local_hour_offset; 82 | }; 83 | 84 | #endif /* !_J1939_TIMEDATE_H_ */ 85 | -------------------------------------------------------------------------------- /j1939sr.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2011 EIA Electronics 4 | * 5 | * Authors: 6 | * Kurt Van Dijck 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the version 2 of the GNU General Public License 10 | * as published by the Free Software Foundation 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "libj1939.h" 29 | 30 | /* 31 | * getopt 32 | */ 33 | static const char help_msg[] = 34 | "j1939sr: An SAE J1939 send/recv utility" "\n" 35 | "Usage: j1939sr [OPTION...] SOURCE [DEST]" "\n" 36 | "Options:\n" 37 | " -v, --verbose Increase verbosity" "\n" 38 | " -p, --priority=VAL J1939 priority (0..7, default 6)" "\n" 39 | " -S, --serialize Strictly serialize outgoing packets" "\n" 40 | " -s, --size Packet size, default autodetected" "\n" 41 | "\n" 42 | " SOURCE [IFACE:][NAME|SA][,PGN]" "\n" 43 | " DEST [NAME|SA]" "\n" 44 | ; 45 | 46 | #ifdef _GNU_SOURCE 47 | static struct option long_opts[] = { 48 | { "help", no_argument, NULL, '?', }, 49 | { "verbose", no_argument, NULL, 'v', }, 50 | 51 | { "priority", required_argument, NULL, 'p', }, 52 | { "size", required_argument, NULL, 's', }, 53 | { "serialize", no_argument, NULL, 'S', }, 54 | { }, 55 | }; 56 | #else 57 | #define getopt_long(argc, argv, optstring, longopts, longindex) \ 58 | getopt((argc), (argv), (optstring)) 59 | #endif 60 | static const char optstring[] = "vp:s:S?"; 61 | 62 | /* 63 | * static variables: configurations 64 | */ 65 | static struct { 66 | int verbose; 67 | int sendflags; /* flags for sendto() */ 68 | int pkt_len; 69 | int priority; 70 | int defined; 71 | #define DEF_SRC 1 72 | #define DEF_DST 2 73 | #define DEF_PRIO 4 74 | struct sockaddr_can src, dst; 75 | } s = { 76 | .priority = 6, 77 | .src.can_addr.j1939 = { 78 | .name = J1939_NO_NAME, 79 | .addr = J1939_NO_ADDR, 80 | .pgn = J1939_NO_PGN, 81 | }, 82 | .dst.can_addr.j1939 = { 83 | .name = J1939_NO_NAME, 84 | .addr = J1939_NO_ADDR, 85 | .pgn = J1939_NO_PGN, 86 | }, 87 | }; 88 | 89 | int main(int argc, char **argv) 90 | { 91 | 92 | int ret, sock, opt; 93 | unsigned int len; 94 | struct pollfd pfd[2]; 95 | uint8_t *buf; 96 | 97 | /* argument parsing */ 98 | while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1) 99 | switch (opt) { 100 | case 'v': 101 | ++s.verbose; 102 | break; 103 | case 's': 104 | s.pkt_len = strtoul(optarg, 0, 0); 105 | if (!s.pkt_len) 106 | err(1, "packet size of %s", optarg); 107 | break; 108 | case 'p': 109 | s.priority = strtoul(optarg, 0, 0); 110 | s.defined |= DEF_PRIO; 111 | break; 112 | case 'S': 113 | s.sendflags |= MSG_SYN; 114 | break; 115 | default: 116 | fputs(help_msg, stderr); 117 | exit(1); 118 | break; 119 | } 120 | 121 | if (argv[optind]) { 122 | optarg = argv[optind++]; 123 | ret = libj1939_str2addr(optarg, 0, &s.src); 124 | if (ret < 0) 125 | err(1, "bad address spec [%s]", optarg); 126 | s.defined |= DEF_SRC; 127 | } 128 | if (argv[optind]) { 129 | optarg = argv[optind++]; 130 | ret = libj1939_str2addr(optarg, 0, &s.dst); 131 | if (ret < 0) 132 | err(1, "bad address spec [%s]", optarg); 133 | s.defined |= DEF_DST; 134 | } 135 | 136 | if (!s.pkt_len) { 137 | struct stat st; 138 | 139 | if (fstat(STDIN_FILENO, &st) < 0) 140 | err(1, "stat stdin, could not determine buffer size"); 141 | s.pkt_len = st.st_size ?: 1024; 142 | } 143 | 144 | /* prepare */ 145 | buf = malloc(s.pkt_len); 146 | if (!buf) 147 | err(1, "malloc %u", s.pkt_len); 148 | 149 | sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939); 150 | if (sock < 0) 151 | err(1, "socket(can, dgram, j1939)"); 152 | 153 | if (s.defined & DEF_PRIO) { 154 | ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &s.priority, sizeof(s.priority)); 155 | if (ret < 0) 156 | err(1, "setsockopt priority"); 157 | } 158 | if (s.defined & DEF_SRC) { 159 | s.src.can_family = AF_CAN; 160 | ret = bind(sock, (void *)&s.src, sizeof(s.src)); 161 | if (ret < 0) 162 | err(1, "bind(%s), %i", libj1939_addr2str(&s.src), -errno); 163 | } 164 | 165 | if (s.defined & DEF_DST) { 166 | s.dst.can_family = AF_CAN; 167 | ret = connect(sock, (void *)&s.dst, sizeof(s.dst)); 168 | if (ret < 0) 169 | err(1, "connect(%s), %i", libj1939_addr2str(&s.dst), -errno); 170 | } 171 | 172 | pfd[0].fd = STDIN_FILENO; 173 | pfd[0].events = POLLIN; 174 | pfd[1].fd = sock; 175 | pfd[1].events = POLLIN; 176 | 177 | /* run */ 178 | while (1) { 179 | ret = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), -1); 180 | if (ret < 0) { 181 | if (errno == EINTR) 182 | continue; 183 | err(1, "poll()"); 184 | } 185 | if (pfd[0].revents) { 186 | ret = read(pfd[0].fd, buf, s.pkt_len); 187 | if (ret < 0) 188 | err(1, "read(stdin)"); 189 | if (!ret) 190 | break; 191 | len = ret; 192 | do { 193 | ret = send(pfd[1].fd, buf, len, s.sendflags); 194 | if (ret < 0 && errno != ENOBUFS) 195 | err(1, "write(%s)", libj1939_addr2str(&s.src)); 196 | } while (ret < 0); 197 | } 198 | if (pfd[1].revents) { 199 | ret = read(pfd[1].fd, buf, s.pkt_len); 200 | if (ret < 0) { 201 | ret = errno; 202 | err(0, "read(%s)", libj1939_addr2str(&s.dst)); 203 | switch (ret) { 204 | case EHOSTDOWN: 205 | break; 206 | default: 207 | exit(1); 208 | } 209 | } else { 210 | if (write(STDOUT_FILENO, buf, ret) < 0) 211 | err(1, "write(stdout)"); 212 | } 213 | } 214 | } 215 | 216 | free(buf); 217 | return 0; 218 | } 219 | 220 | -------------------------------------------------------------------------------- /libj1939.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2011 EIA Electronics 4 | * 5 | * Authors: 6 | * Kurt Van Dijck 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the version 2 of the GNU General Public License 10 | * as published by the Free Software Foundation 11 | */ 12 | 13 | /* needed on some 64 bit platforms to get consistent 64-bit types */ 14 | #define __SANE_USERSPACE_TYPES__ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifndef J1939_LIB_H 24 | #define J1939_LIB_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | struct libj1939_cmn { 31 | int epoll_fd; 32 | struct epoll_event *epoll_events; 33 | size_t epoll_events_size; 34 | struct timespec next_send_time; 35 | struct timespec last_time; 36 | }; 37 | 38 | void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr); 39 | extern int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can); 40 | extern const char *libj1939_addr2str(const struct sockaddr_can *can); 41 | 42 | void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn); 43 | 44 | int libj1939_open_socket(void); 45 | int libj1939_bind_socket(int sock, struct sockaddr_can *addr); 46 | int libj1939_connect_socket(int sock, struct sockaddr_can *addr); 47 | int libj1939_socket_prio(int sock, int prio); 48 | int libj1939_set_broadcast(int sock); 49 | int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events); 50 | int libj1939_create_epoll(void); 51 | 52 | int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds, 53 | bool dont_wait); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /log2long.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | /* 3 | * log2long.c - convert compact CAN frame representation into user readable 4 | * 5 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of Volkswagen nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * Alternatively, provided that this notice is retained in full, this 21 | * software may be distributed under the terms of the GNU General 22 | * Public License ("GPL") version 2, in which case the provisions of the 23 | * GPL apply INSTEAD OF those given above. 24 | * 25 | * The provided data structures and external interfaces from this code 26 | * are not restricted to be used by modules with a GPL compatible license. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 39 | * DAMAGE. 40 | * 41 | * Send feedback to 42 | * 43 | */ 44 | 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | 51 | #include "lib.h" 52 | 53 | #define DEVSZ 22 54 | #define TIMESZ 22 /* sizeof("(1345212884.318850) ") */ 55 | #define BUFSZ (DEVSZ + AFRSZ + TIMESZ) 56 | 57 | /* adapt sscanf() functions below on error */ 58 | #if (AFRSZ != 6300) 59 | #error "AFRSZ value does not fit sscanf restrictions!" 60 | #endif 61 | #if (DEVSZ != 22) 62 | #error "DEVSZ value does not fit sscanf restrictions!" 63 | #endif 64 | #if (TIMESZ != 22) 65 | #error "TIMESZ value does not fit sscanf restrictions!" 66 | #endif 67 | 68 | int main(void) 69 | { 70 | static char buf[BUFSZ], timestamp[TIMESZ], device[DEVSZ], afrbuf[AFRSZ]; 71 | static cu_t cu; 72 | int mtu; 73 | 74 | while (fgets(buf, BUFSZ-1, stdin)) { 75 | 76 | if (strlen(buf) >= BUFSZ-2) { 77 | fprintf(stderr, "line too long for input buffer\n"); 78 | return 1; 79 | } 80 | 81 | if (sscanf(buf, "%21s %21s %6299s", timestamp, device, afrbuf) != 3) 82 | return 1; 83 | 84 | mtu = parse_canframe(afrbuf, &cu); 85 | 86 | /* mark dual-use struct canfd_frame - no CAN_XL support */ 87 | if (mtu == CAN_MTU) 88 | cu.fd.flags = 0; 89 | else if (mtu == CANFD_MTU) 90 | cu.fd.flags |= CANFD_FDF; 91 | else { 92 | fprintf(stderr, "read: no valid CAN CC/FD frame\n"); 93 | return 1; 94 | } 95 | 96 | /* with ASCII output */ 97 | snprintf_long_canframe(afrbuf, sizeof(afrbuf), &cu, 98 | (CANLIB_VIEW_INDENT_SFF | CANLIB_VIEW_ASCII)); 99 | 100 | printf("%s %s %s\n", timestamp, device, afrbuf); 101 | } 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /mcp251xfd/99-devcoredump.rules: -------------------------------------------------------------------------------- 1 | ACTION=="add", SUBSYSTEM=="devcoredump", RUN+="/usr/sbin/devcoredump" 2 | -------------------------------------------------------------------------------- /mcp251xfd/data/devcoredump-canfd-v5.15.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-can/can-utils/93a7b2dfd32c72105e9ba480b3d57c9ad6935767/mcp251xfd/data/devcoredump-canfd-v5.15.dump -------------------------------------------------------------------------------- /mcp251xfd/data/devcoredump-canfd.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-can/can-utils/93a7b2dfd32c72105e9ba480b3d57c9ad6935767/mcp251xfd/data/devcoredump-canfd.dump -------------------------------------------------------------------------------- /mcp251xfd/data/devcoredump-classic-can-v5.15.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-can/can-utils/93a7b2dfd32c72105e9ba480b3d57c9ad6935767/mcp251xfd/data/devcoredump-classic-can-v5.15.dump -------------------------------------------------------------------------------- /mcp251xfd/data/devcoredump-classic-can.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-can/can-utils/93a7b2dfd32c72105e9ba480b3d57c9ad6935767/mcp251xfd/data/devcoredump-classic-can.dump -------------------------------------------------------------------------------- /mcp251xfd/devcoredump: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | timestamp=$(date +%+4Y%m%d-%H%M%S) 6 | filename=/var/log/devcoredump-${timestamp}.dump 7 | 8 | cat /sys/${DEVPATH}/data > ${filename} 9 | echo 1 > /sys/${DEVPATH}/data 10 | 11 | echo "devcoredump ${DEVPATH}" | logger 12 | -------------------------------------------------------------------------------- /mcp251xfd/mcp251xfd-dev-coredump.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | // 3 | // Microchip MCP251xFD Family CAN controller debug tool 4 | // 5 | // Copyright (c) 2020, 2021 Pengutronix, 6 | // Marc Kleine-Budde 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "lib.h" 21 | #include "mcp251xfd.h" 22 | #include "mcp251xfd-dump-userspace.h" 23 | 24 | struct mcp251xfd_dump_iter { 25 | const void *start; 26 | const struct mcp251xfd_dump_object_header *hdr; 27 | const void *object_start; 28 | const void *object_end; 29 | }; 30 | 31 | const char * 32 | get_object_type_str(enum mcp251xfd_dump_object_type object_type) 33 | { 34 | switch (object_type) { 35 | case MCP251XFD_DUMP_OBJECT_TYPE_REG: 36 | return "REG"; 37 | case MCP251XFD_DUMP_OBJECT_TYPE_TEF: 38 | return "TEF"; 39 | case MCP251XFD_DUMP_OBJECT_TYPE_RX: 40 | return "RX"; 41 | case MCP251XFD_DUMP_OBJECT_TYPE_TX: 42 | return "TX"; 43 | case MCP251XFD_DUMP_OBJECT_TYPE_END: 44 | return "END"; 45 | default: 46 | return ""; 47 | } 48 | } 49 | 50 | static __attribute__((__unused__)) const char * 51 | get_ring_key_str(enum mcp251xfd_dump_object_ring_key key) 52 | { 53 | switch (key) { 54 | case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD: 55 | return "head"; 56 | case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL: 57 | return "tail"; 58 | case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE: 59 | return "base"; 60 | case MCP251XFD_DUMP_OBJECT_RING_KEY_NR: 61 | return "nr"; 62 | case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR: 63 | return "fifo-nr"; 64 | case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM: 65 | return "obj-num"; 66 | case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE: 67 | return "obj-size"; 68 | default: 69 | return ""; 70 | } 71 | } 72 | 73 | static int 74 | do_dev_coredump_read_reg(const struct mcp251xfd_priv *priv, 75 | const struct mcp251xfd_dump_iter *iter, 76 | struct mcp251xfd_mem *mem) 77 | { 78 | const struct mcp251xfd_dump_object_reg *object; 79 | 80 | for (object = iter->object_start; 81 | (void *)(object + 1) <= iter->object_end; 82 | object++) { 83 | uint32_t reg, val; 84 | 85 | reg = le32toh(object->reg); 86 | val = le32toh(object->val); 87 | 88 | pr_debug("%s: offset=0x%04zx reg=0x%04x - val=0x%08x\n", 89 | __func__, 90 | (void *)object - iter->start, 91 | reg, val); 92 | 93 | if (reg > ARRAY_SIZE(mem->buf)) 94 | return -EINVAL; 95 | 96 | *(uint32_t *)(mem->buf + reg) = val; 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | static int 103 | do_dev_coredump_read_ring(const struct mcp251xfd_priv *priv, 104 | const struct mcp251xfd_dump_iter *iter, 105 | struct mcp251xfd_ring *ring) 106 | { 107 | const struct mcp251xfd_dump_object_reg *object; 108 | 109 | for (object = iter->object_start; 110 | (void *)(object + 1) <= iter->object_end; 111 | object++) { 112 | enum mcp251xfd_dump_object_ring_key key; 113 | uint32_t val; 114 | 115 | key = le32toh(object->reg); 116 | val = le32toh(object->val); 117 | 118 | pr_debug("%s: offset=0x%04zx key=0x%02x: %8s - val=0x%08x\n", 119 | __func__, 120 | (void *)object - iter->start, 121 | key, get_ring_key_str(key), val); 122 | 123 | switch (key) { 124 | case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD: 125 | ring->head = val; 126 | break; 127 | case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL: 128 | ring->tail = val; 129 | break; 130 | case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE: 131 | ring->base = val; 132 | break; 133 | case MCP251XFD_DUMP_OBJECT_RING_KEY_NR: 134 | ring->nr = val; 135 | break; 136 | case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR: 137 | ring->fifo_nr = val; 138 | break; 139 | case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM: 140 | ring->obj_num = val; 141 | break; 142 | case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE: 143 | ring->obj_size = val; 144 | break; 145 | default: 146 | continue; 147 | } 148 | } 149 | 150 | return 0; 151 | } 152 | 153 | static int 154 | do_dev_coredump_read(struct mcp251xfd_priv *priv, 155 | struct mcp251xfd_mem *mem, 156 | const void *dump, size_t dump_len) 157 | { 158 | struct mcp251xfd_dump_iter iter[] = { 159 | { 160 | .start = dump, 161 | .hdr = dump, 162 | }, 163 | }; 164 | 165 | while ((void *)(iter->hdr + 1) <= iter->start + dump_len && 166 | le32toh(iter->hdr->magic) == MCP251XFD_DUMP_MAGIC) { 167 | const struct mcp251xfd_dump_object_header *hdr = iter->hdr; 168 | enum mcp251xfd_dump_object_type object_type; 169 | struct mcp251xfd_ring ring; 170 | size_t object_offset, object_len; 171 | int err; 172 | 173 | object_type = le32toh(hdr->type); 174 | object_offset = le32toh(hdr->offset); 175 | object_len = le32toh(hdr->len); 176 | 177 | if (object_offset + object_len > dump_len) 178 | return -EFAULT; 179 | 180 | iter->object_start = iter->start + object_offset; 181 | iter->object_end = iter->object_start + object_len; 182 | 183 | mcp251xfd_dump_ring_init(&ring); 184 | 185 | pr_debug("%s: hdr=0x%04zx type=0x%08x: %8s - offset=0x%04zx len=0x%04zx end=0x%04zx\n", 186 | __func__, 187 | (void *)iter->hdr - iter->start, 188 | object_type, get_object_type_str(object_type), 189 | object_offset, object_len, object_offset + object_len); 190 | 191 | switch (object_type) { 192 | case MCP251XFD_DUMP_OBJECT_TYPE_REG: 193 | err = do_dev_coredump_read_reg(priv, iter, mem); 194 | break; 195 | case MCP251XFD_DUMP_OBJECT_TYPE_TEF: 196 | case MCP251XFD_DUMP_OBJECT_TYPE_RX: 197 | case MCP251XFD_DUMP_OBJECT_TYPE_TX: 198 | err = do_dev_coredump_read_ring(priv, iter, &ring); 199 | if (err) 200 | return err; 201 | 202 | if (ring.fifo_nr >= ARRAY_SIZE(priv->ring)) 203 | return -EINVAL; 204 | 205 | priv->ring[ring.fifo_nr] = ring; 206 | 207 | break; 208 | case MCP251XFD_DUMP_OBJECT_TYPE_END: 209 | return 0; 210 | default: 211 | return -EINVAL; 212 | } 213 | 214 | if (err) 215 | return err; 216 | 217 | iter->hdr++; 218 | } 219 | 220 | return -EINVAL; 221 | } 222 | 223 | int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv, 224 | struct mcp251xfd_mem *mem, 225 | const char *dump_path) 226 | { 227 | struct stat statbuf; 228 | size_t dump_len; 229 | void *dump; 230 | int fd, err; 231 | 232 | fd = open(dump_path, O_RDONLY); 233 | if (fd < 0) 234 | return -errno; 235 | 236 | err = fstat(fd, &statbuf); 237 | if (err < 0) { 238 | err = -errno; 239 | goto out_close; 240 | } 241 | dump_len = statbuf.st_size; 242 | 243 | dump = mmap(NULL, dump_len, PROT_READ, MAP_SHARED, fd, 0x0); 244 | if (dump == MAP_FAILED) { 245 | err = -errno; 246 | goto out_close; 247 | } 248 | 249 | err = do_dev_coredump_read(priv, mem, dump, dump_len); 250 | 251 | munmap(dump, dump_len); 252 | out_close: 253 | close(fd); 254 | return err; 255 | } 256 | -------------------------------------------------------------------------------- /mcp251xfd/mcp251xfd-dump-userspace.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 2 | * 3 | * Microchip MCP251xFD Family CAN controller debug tool 4 | * 5 | * Copyright (c) 2019, 2020 Pengutronix, 6 | * Marc Kleine-Budde 7 | */ 8 | 9 | #ifndef _MCP251XFD_DUMP_USERSPACE_H 10 | #define _MCP251XFD_DUMP_USERSPACE_H 11 | 12 | #include "mcp251xfd.h" 13 | #include "mcp251xfd-dump.h" 14 | 15 | #define MCP251XFD_DUMP_UNKNOWN (-1U) 16 | 17 | struct mcp251xfd_mem { 18 | char buf[0x1000]; 19 | }; 20 | 21 | struct mcp251xfd_ring { 22 | enum mcp251xfd_dump_object_type type; 23 | const struct mcp251xfd_dump_regs_fifo *fifo; 24 | void *ram; 25 | 26 | unsigned int head; 27 | unsigned int tail; 28 | 29 | u16 base; 30 | u8 nr; 31 | u8 fifo_nr; 32 | u8 obj_num; 33 | u8 obj_size; 34 | }; 35 | 36 | #define MCP251XFD_RING_TEF 0 37 | 38 | struct mcp251xfd_priv { 39 | struct regmap *map; 40 | struct mcp251xfd_ring ring[32]; 41 | }; 42 | 43 | void mcp251xfd_dump_ring_init(struct mcp251xfd_ring *ring); 44 | 45 | void mcp251xfd_dump(struct mcp251xfd_priv *priv); 46 | int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv, 47 | struct mcp251xfd_mem *mem, 48 | const char *file_path); 49 | int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv, 50 | struct mcp251xfd_mem *mem, 51 | const char *file_path); 52 | const char * 53 | get_object_type_str(enum mcp251xfd_dump_object_type object_type); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /mcp251xfd/mcp251xfd-dump.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 2 | * 3 | * mcp251xfd - Microchip MCP251xFD Family CAN controller driver 4 | * 5 | * Copyright (c) 2019, 2020, 2021 Pengutronix, 6 | * Marc Kleine-Budde 7 | */ 8 | 9 | #ifndef _MCP251XFD_DUMP_H 10 | #define _MCP251XFD_DUMP_H 11 | 12 | #define MCP251XFD_DUMP_MAGIC 0x1825434d 13 | 14 | enum mcp251xfd_dump_object_type { 15 | MCP251XFD_DUMP_OBJECT_TYPE_REG, 16 | MCP251XFD_DUMP_OBJECT_TYPE_TEF, 17 | MCP251XFD_DUMP_OBJECT_TYPE_RX, 18 | MCP251XFD_DUMP_OBJECT_TYPE_TX, 19 | MCP251XFD_DUMP_OBJECT_TYPE_END = -1, 20 | }; 21 | 22 | enum mcp251xfd_dump_object_ring_key { 23 | MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD, 24 | MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL, 25 | MCP251XFD_DUMP_OBJECT_RING_KEY_BASE, 26 | MCP251XFD_DUMP_OBJECT_RING_KEY_NR, 27 | MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR, 28 | MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM, 29 | MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE, 30 | __MCP251XFD_DUMP_OBJECT_RING_KEY_MAX, 31 | }; 32 | 33 | struct mcp251xfd_dump_object_header { 34 | __le32 magic; 35 | __le32 type; 36 | __le32 offset; 37 | __le32 len; 38 | }; 39 | 40 | struct mcp251xfd_dump_object_reg { 41 | __le32 reg; 42 | __le32 val; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /mcp251xfd/mcp251xfd-gen-testdata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0 3 | # 4 | # Copyright (c) 2023 Pengutronix, 5 | # Marc Kleine-Budde 6 | 7 | set -x 8 | set -e 9 | 10 | DEV=${1:-can0} 11 | SPI=${2:-$(ethtool -i ${DEV}|sed -ne "s/bus-info: //p")} 12 | 13 | modprobe -r mcp251xfd 14 | modprobe mcp251xfd 15 | 16 | sleep 2 17 | 18 | ip link set ${DEV} down 19 | 20 | sleep 2 21 | rm -vf /var/log/devcoredump-*.dump 22 | 23 | ip link set ${DEV} up type can bitrate 1000000 dbitrate 4000000 fd on restart-ms 1000 berr-reporting off listen-only off loopback on 24 | 25 | ethtool -g ${DEV} || true 26 | ethtool -c ${DEV} || true 27 | 28 | cangen ${DEV} -Di -L8 -I2 -p 10 -g 200 -n 3 29 | 30 | cat /sys/kernel/debug/regmap/${SPI}-crc/registers > data/registers-canfd.dump 31 | 32 | ip link set ${DEV} down 33 | sleep 2 34 | cp -av /var/log/devcoredump-*.dump data 35 | 36 | 37 | ip link set ${DEV} up type can bitrate 1000000 fd off restart-ms 1000 berr-reporting off listen-only off loopback on 38 | 39 | rm -vf /var/log/devcoredump-*.dump 40 | 41 | ethtool -g ${DEV} || true 42 | ethtool -c ${DEV} || true 43 | 44 | cangen ${DEV} -Di -L8 -I2 -p 10 -g 200 -n 7 45 | 46 | cat /sys/kernel/debug/regmap/${SPI}-crc/registers > data/registers-classic-can.dump 47 | 48 | ip link set ${DEV} down 49 | sleep 2 50 | cp -av /var/log/devcoredump-*.dump data 51 | -------------------------------------------------------------------------------- /mcp251xfd/mcp251xfd-main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | // 3 | // Microchip MCP251xFD Family CAN controller debug tool 4 | // 5 | // Copyright (c) 2020, 2021 Pengutronix, 6 | // Marc Kleine-Budde 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "mcp251xfd-dump-userspace.h" 18 | 19 | static void print_usage(char *prg) 20 | { 21 | fprintf(stderr, 22 | "%s - decode chip and driver state of mcp251xfd.\n" 23 | "\n" 24 | "Usage: %s [options] \n" 25 | "\n" 26 | " path to dev coredump file\n" 27 | " ('/var/log/devcoredump-19700101-234200.dump')\n" 28 | " path to regmap register file\n" 29 | " ('/sys/kernel/debug/regmap/spi1.0-crc/registers')\n" 30 | " shortcut to regmap register file\n" 31 | " ('spi0.0')\n" 32 | "\n" 33 | "Options:\n" 34 | " -h, --help this help\n" 35 | "\n", 36 | prg, prg); 37 | } 38 | 39 | int regmap_bulk_read(struct regmap *map, unsigned int reg, 40 | void *val, size_t val_count) 41 | { 42 | memcpy(val, map->mem->buf + reg, 43 | val_count * sizeof(uint32_t)); 44 | 45 | return 0; 46 | } 47 | 48 | void mcp251xfd_dump_ring_init(struct mcp251xfd_ring *ring) 49 | { 50 | memset(ring, 0x0, sizeof(*ring)); 51 | 52 | ring->type = MCP251XFD_DUMP_UNKNOWN; 53 | ring->head = MCP251XFD_DUMP_UNKNOWN; 54 | ring->tail = MCP251XFD_DUMP_UNKNOWN; 55 | ring->nr = (uint8_t)MCP251XFD_DUMP_UNKNOWN; 56 | ring->fifo_nr = (uint8_t)MCP251XFD_DUMP_UNKNOWN; 57 | } 58 | 59 | int main(int argc, char *argv[]) 60 | { 61 | struct mcp251xfd_mem mem = { }; 62 | struct regmap map = { 63 | .mem = &mem, 64 | }; 65 | struct mcp251xfd_priv priv = { 66 | .map = &map, 67 | }; 68 | const char *file_path; 69 | unsigned int i; 70 | int opt, err; 71 | 72 | struct option long_options[] = { 73 | { "help", no_argument, 0, 'h' }, 74 | { 0, 0, 0, 0 }, 75 | }; 76 | 77 | while ((opt = getopt_long(argc, argv, "ei:pq::rvh", long_options, NULL)) != -1) { 78 | switch (opt) { 79 | case 'h': 80 | print_usage(basename(argv[0])); 81 | exit(EXIT_SUCCESS); 82 | break; 83 | 84 | default: 85 | print_usage(basename(argv[0])); 86 | exit(EXIT_FAILURE); 87 | break; 88 | } 89 | } 90 | 91 | file_path = argv[optind]; 92 | 93 | if (!file_path) { 94 | print_usage(basename(argv[0])); 95 | exit(EXIT_FAILURE); 96 | } 97 | 98 | for (i = 0; i < ARRAY_SIZE(priv.ring); i++) 99 | mcp251xfd_dump_ring_init(&priv.ring[i]); 100 | 101 | err = mcp251xfd_dev_coredump_read(&priv, &mem, file_path); 102 | if (err) 103 | err = mcp251xfd_regmap_read(&priv, &mem, file_path); 104 | if (err) { 105 | fprintf(stderr, "Unable to read file: '%s'\n", file_path); 106 | exit(EXIT_FAILURE); 107 | } 108 | 109 | mcp251xfd_dump(&priv); 110 | 111 | exit(EXIT_SUCCESS); 112 | } 113 | -------------------------------------------------------------------------------- /mcp251xfd/mcp251xfd-regmap.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | // 3 | // Microchip MCP251xFD Family CAN controller debug tool 4 | // 5 | // Copyright (c) 2020, 2022, 2023 Pengutronix, 6 | // Marc Kleine-Budde 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "mcp251xfd.h" 19 | #include "mcp251xfd-dump-userspace.h" 20 | 21 | static int 22 | do_mcp251xfd_regmap_read(struct mcp251xfd_priv *priv, 23 | struct mcp251xfd_mem *mem, 24 | const char *file_path) 25 | { 26 | FILE *reg_file; 27 | uint16_t reg; 28 | uint32_t val; 29 | unsigned int n = 0; 30 | int ret, err = 0; 31 | 32 | reg_file = fopen(file_path, "r"); 33 | if (!reg_file) 34 | return -errno; 35 | 36 | while ((ret = fscanf(reg_file, "%hx: %x\n", ®, &val)) != EOF) { 37 | if (ret != 2) { 38 | ret = fscanf(reg_file, "%*[^\n]\n"); 39 | 40 | continue; 41 | } 42 | 43 | if (reg >= ARRAY_SIZE(mem->buf)) { 44 | err = -EINVAL; 45 | goto out_close; 46 | } 47 | 48 | *(uint32_t *)(mem->buf + reg) = val; 49 | 50 | n++; 51 | } 52 | 53 | printf("regmap: Found %u registers in %s\n", n, file_path); 54 | if (!n) 55 | err = -EINVAL; 56 | 57 | out_close: 58 | fclose(reg_file); 59 | 60 | return err; 61 | } 62 | 63 | int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv, 64 | struct mcp251xfd_mem *mem, 65 | const char *file_path) 66 | { 67 | char *tmp; 68 | int err; 69 | 70 | err = do_mcp251xfd_regmap_read(priv, mem, file_path); 71 | if (!err) 72 | return 0; 73 | 74 | /* maybe it's something like "spi0.0" */ 75 | tmp = strchr(file_path, '/'); 76 | if (tmp) 77 | return -ENOENT; 78 | 79 | /* first try literally */ 80 | err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s/registers", file_path); 81 | if (err == -1) 82 | return -errno; 83 | 84 | err = do_mcp251xfd_regmap_read(priv, mem, tmp); 85 | free (tmp); 86 | if (!err) 87 | return 0; 88 | 89 | /* then add "-crc" */ 90 | err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s-crc/registers", file_path); 91 | if (err == -1) 92 | return -errno; 93 | 94 | err = do_mcp251xfd_regmap_read(priv, mem, tmp); 95 | free (tmp); 96 | 97 | return err; 98 | } 99 | -------------------------------------------------------------------------------- /page.theme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | page: <?theme title?> 5 | 6 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: Helvetica Neue, Helvetica, Arial, sans-serif; 3 | } 4 | body { 5 | max-width: 60em; 6 | margin: 0 auto; 7 | color: #111; 8 | } 9 | 10 | pre, code { 11 | font-family: Monaco, Courier New, monospace; 12 | font-size: 11px; 13 | } 14 | 15 | h1 { 16 | color: rgb(43,105,145); 17 | font-weight: bold; 18 | font-size: 40px; 19 | letter-spacing: -1px; 20 | margin-bottom: -5px; 21 | margin: 0; 22 | } 23 | h1 code { 24 | font-size: 32px; 25 | } 26 | 27 | h2 { 28 | color: rgb(43,105,145); 29 | font-weight: bold; 30 | margin-bottom: -5px; 31 | } 32 | h2 code { 33 | font-size: 22px; 34 | } 35 | 36 | h3 { 37 | margin-bottom: -5px; 38 | } 39 | h3 code { 40 | font-size: 16px; 41 | } 42 | 43 | a { 44 | color: blue; 45 | text-decoration: none; 46 | } 47 | a:visited { 48 | color: navy; 49 | } 50 | a:hover { 51 | text-decoration: underline; 52 | } 53 | 54 | pre { 55 | border-width: 1px; 56 | border-color: #777; 57 | border-style: solid; 58 | padding: 0.5em; 59 | background-color: #ccc; 60 | overflow: auto; 61 | color: #000; 62 | font-weight: bold; 63 | } 64 | 65 | p, li { 66 | font-size: 13px; 67 | line-height: 18px; 68 | } 69 | -------------------------------------------------------------------------------- /terminal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | /* 3 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of Volkswagen nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * Alternatively, provided that this notice is retained in full, this 19 | * software may be distributed under the terms of the GNU General 20 | * Public License ("GPL") version 2, in which case the provisions of the 21 | * GPL apply INSTEAD OF those given above. 22 | * 23 | * The provided data structures and external interfaces from this code 24 | * are not restricted to be used by modules with a GPL compatible license. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 37 | * DAMAGE. 38 | * 39 | * Send feedback to 40 | * 41 | */ 42 | 43 | #ifndef TERMINAL_H 44 | #define TERMINAL_H 45 | 46 | /* reset to default */ 47 | 48 | #define ATTRESET "\33[0m" 49 | 50 | /* attributes */ 51 | 52 | #define ATTBOLD "\33[1m" 53 | #define ATTUNDERLINE "\33[4m" 54 | #define ATTBLINK "\33[5m" 55 | #define ATTINVERSE "\33[7m" 56 | #define ATTINVISIBLE "\33[8m" 57 | 58 | /* foreground colors */ 59 | 60 | #define FGBLACK "\33[30m" 61 | #define FGRED "\33[31m" 62 | #define FGGREEN "\33[32m" 63 | #define FGYELLOW "\33[33m" 64 | #define FGBLUE "\33[34m" 65 | #define FGMAGENTA "\33[35m" 66 | #define FGCYAN "\33[36m" 67 | #define FGWHITE "\33[37m" 68 | 69 | /* background colors */ 70 | 71 | #define BGBLACK "\33[40m" 72 | #define BGRED "\33[41m" 73 | #define BGGREEN "\33[42m" 74 | #define BGYELLOW "\33[43m" 75 | #define BGBLUE "\33[44m" 76 | #define BGMAGENTA "\33[45m" 77 | #define BGCYAN "\33[46m" 78 | #define BGWHITE "\33[47m" 79 | 80 | /* cursor */ 81 | 82 | #define CSR_HOME "\33[H" 83 | #define CSR_UP "\33[A" 84 | #define CSR_DOWN "\33[B" 85 | #define CSR_RIGHT "\33[C" 86 | #define CSR_LEFT "\33[D" 87 | 88 | #define CSR_HIDE "\33[?25l" 89 | #define CSR_SHOW "\33[?25h" 90 | 91 | /* clear screen */ 92 | 93 | #define CLR_SCREEN "\33[2J" 94 | 95 | #endif /* TERMINAL_H */ 96 | --------------------------------------------------------------------------------