├── .clang-format ├── .editorconfig ├── .github └── workflows │ ├── codeql-analysis.yml │ └── compile.yml ├── .gitignore ├── LICENSES ├── BSD-3-Clause ├── GPL-2.0-only.txt └── Linux-syscall-note.txt ├── README.md ├── debian ├── .gitignore ├── changelog ├── control ├── copyright ├── rules ├── socketcand.service └── source │ └── format ├── doc └── protocol.md ├── files ├── meson.build ├── socketcand-init.d.in ├── socketcand-rc.d └── socketcand.conf ├── include └── linux │ ├── can.h │ └── can │ ├── bcm.h │ ├── error.h │ ├── isotp.h │ └── raw.h ├── meson.build ├── meson_options.txt ├── socketcand.1 └── src ├── beacon.c ├── beacon.h ├── canctl.c ├── canctl.h ├── meson.build ├── socketcand.c ├── socketcand.h ├── socketcandcl.c ├── state_bcm.c ├── state_control.c ├── state_isotp.c ├── state_nobus.c ├── state_raw.c ├── statistics.c └── statistics.h /.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/dev-tools/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: 1220 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 | # Taken from: 68 | # git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ tools/ \ 69 | # | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ 70 | # | LC_ALL=C sort -u 71 | ForEachMacros: 72 | - '__ata_qc_for_each' 73 | - '__bio_for_each_bvec' 74 | - '__bio_for_each_segment' 75 | - '__evlist__for_each_entry' 76 | - '__evlist__for_each_entry_continue' 77 | - '__evlist__for_each_entry_from' 78 | - '__evlist__for_each_entry_reverse' 79 | - '__evlist__for_each_entry_safe' 80 | - '__for_each_mem_range' 81 | - '__for_each_mem_range_rev' 82 | - '__for_each_thread' 83 | - '__hlist_for_each_rcu' 84 | - '__map__for_each_symbol_by_name' 85 | - '__pci_bus_for_each_res0' 86 | - '__pci_bus_for_each_res1' 87 | - '__pci_dev_for_each_res0' 88 | - '__pci_dev_for_each_res1' 89 | - '__perf_evlist__for_each_entry' 90 | - '__perf_evlist__for_each_entry_reverse' 91 | - '__perf_evlist__for_each_entry_safe' 92 | - '__rq_for_each_bio' 93 | - '__shost_for_each_device' 94 | - '__sym_for_each' 95 | - 'apei_estatus_for_each_section' 96 | - 'ata_for_each_dev' 97 | - 'ata_for_each_link' 98 | - 'ata_qc_for_each' 99 | - 'ata_qc_for_each_raw' 100 | - 'ata_qc_for_each_with_internal' 101 | - 'ax25_for_each' 102 | - 'ax25_uid_for_each' 103 | - 'bio_for_each_bvec' 104 | - 'bio_for_each_bvec_all' 105 | - 'bio_for_each_folio_all' 106 | - 'bio_for_each_integrity_vec' 107 | - 'bio_for_each_segment' 108 | - 'bio_for_each_segment_all' 109 | - 'bio_list_for_each' 110 | - 'bip_for_each_vec' 111 | - 'bond_for_each_slave' 112 | - 'bond_for_each_slave_rcu' 113 | - 'bpf_for_each' 114 | - 'bpf_for_each_reg_in_vstate' 115 | - 'bpf_for_each_reg_in_vstate_mask' 116 | - 'bpf_for_each_spilled_reg' 117 | - 'bpf_object__for_each_map' 118 | - 'bpf_object__for_each_program' 119 | - 'btree_for_each_safe128' 120 | - 'btree_for_each_safe32' 121 | - 'btree_for_each_safe64' 122 | - 'btree_for_each_safel' 123 | - 'card_for_each_dev' 124 | - 'cgroup_taskset_for_each' 125 | - 'cgroup_taskset_for_each_leader' 126 | - 'cpu_aggr_map__for_each_idx' 127 | - 'cpufreq_for_each_efficient_entry_idx' 128 | - 'cpufreq_for_each_entry' 129 | - 'cpufreq_for_each_entry_idx' 130 | - 'cpufreq_for_each_valid_entry' 131 | - 'cpufreq_for_each_valid_entry_idx' 132 | - 'css_for_each_child' 133 | - 'css_for_each_descendant_post' 134 | - 'css_for_each_descendant_pre' 135 | - 'damon_for_each_region' 136 | - 'damon_for_each_region_from' 137 | - 'damon_for_each_region_safe' 138 | - 'damon_for_each_scheme' 139 | - 'damon_for_each_scheme_safe' 140 | - 'damon_for_each_target' 141 | - 'damon_for_each_target_safe' 142 | - 'damos_for_each_filter' 143 | - 'damos_for_each_filter_safe' 144 | - 'damos_for_each_quota_goal' 145 | - 'damos_for_each_quota_goal_safe' 146 | - 'data__for_each_file' 147 | - 'data__for_each_file_new' 148 | - 'data__for_each_file_start' 149 | - 'device_for_each_child_node' 150 | - 'device_for_each_child_node_scoped' 151 | - 'dma_fence_array_for_each' 152 | - 'dma_fence_chain_for_each' 153 | - 'dma_fence_unwrap_for_each' 154 | - 'dma_resv_for_each_fence' 155 | - 'dma_resv_for_each_fence_unlocked' 156 | - 'do_for_each_ftrace_op' 157 | - 'drm_atomic_crtc_for_each_plane' 158 | - 'drm_atomic_crtc_state_for_each_plane' 159 | - 'drm_atomic_crtc_state_for_each_plane_state' 160 | - 'drm_atomic_for_each_plane_damage' 161 | - 'drm_client_for_each_connector_iter' 162 | - 'drm_client_for_each_modeset' 163 | - 'drm_connector_for_each_possible_encoder' 164 | - 'drm_exec_for_each_locked_object' 165 | - 'drm_exec_for_each_locked_object_reverse' 166 | - 'drm_for_each_bridge_in_chain' 167 | - 'drm_for_each_connector_iter' 168 | - 'drm_for_each_crtc' 169 | - 'drm_for_each_crtc_reverse' 170 | - 'drm_for_each_encoder' 171 | - 'drm_for_each_encoder_mask' 172 | - 'drm_for_each_fb' 173 | - 'drm_for_each_legacy_plane' 174 | - 'drm_for_each_plane' 175 | - 'drm_for_each_plane_mask' 176 | - 'drm_for_each_privobj' 177 | - 'drm_gem_for_each_gpuvm_bo' 178 | - 'drm_gem_for_each_gpuvm_bo_safe' 179 | - 'drm_gpuva_for_each_op' 180 | - 'drm_gpuva_for_each_op_from_reverse' 181 | - 'drm_gpuva_for_each_op_reverse' 182 | - 'drm_gpuva_for_each_op_safe' 183 | - 'drm_gpuvm_bo_for_each_va' 184 | - 'drm_gpuvm_bo_for_each_va_safe' 185 | - 'drm_gpuvm_for_each_va' 186 | - 'drm_gpuvm_for_each_va_range' 187 | - 'drm_gpuvm_for_each_va_range_safe' 188 | - 'drm_gpuvm_for_each_va_safe' 189 | - 'drm_mm_for_each_hole' 190 | - 'drm_mm_for_each_node' 191 | - 'drm_mm_for_each_node_in_range' 192 | - 'drm_mm_for_each_node_safe' 193 | - 'dsa_switch_for_each_available_port' 194 | - 'dsa_switch_for_each_cpu_port' 195 | - 'dsa_switch_for_each_cpu_port_continue_reverse' 196 | - 'dsa_switch_for_each_port' 197 | - 'dsa_switch_for_each_port_continue_reverse' 198 | - 'dsa_switch_for_each_port_safe' 199 | - 'dsa_switch_for_each_user_port' 200 | - 'dsa_switch_for_each_user_port_continue_reverse' 201 | - 'dsa_tree_for_each_cpu_port' 202 | - 'dsa_tree_for_each_user_port' 203 | - 'dsa_tree_for_each_user_port_continue_reverse' 204 | - 'dso__for_each_symbol' 205 | - 'elf_hash_for_each_possible' 206 | - 'elf_symtab__for_each_symbol' 207 | - 'evlist__for_each_cpu' 208 | - 'evlist__for_each_entry' 209 | - 'evlist__for_each_entry_continue' 210 | - 'evlist__for_each_entry_from' 211 | - 'evlist__for_each_entry_reverse' 212 | - 'evlist__for_each_entry_safe' 213 | - 'flow_action_for_each' 214 | - 'for_each_acpi_consumer_dev' 215 | - 'for_each_acpi_dev_match' 216 | - 'for_each_active_dev_scope' 217 | - 'for_each_active_drhd_unit' 218 | - 'for_each_active_iommu' 219 | - 'for_each_active_route' 220 | - 'for_each_aggr_pgid' 221 | - 'for_each_and_bit' 222 | - 'for_each_andnot_bit' 223 | - 'for_each_available_child_of_node' 224 | - 'for_each_available_child_of_node_scoped' 225 | - 'for_each_bench' 226 | - 'for_each_bio' 227 | - 'for_each_board_func_rsrc' 228 | - 'for_each_btf_ext_rec' 229 | - 'for_each_btf_ext_sec' 230 | - 'for_each_bvec' 231 | - 'for_each_card_auxs' 232 | - 'for_each_card_auxs_safe' 233 | - 'for_each_card_components' 234 | - 'for_each_card_dapms' 235 | - 'for_each_card_pre_auxs' 236 | - 'for_each_card_prelinks' 237 | - 'for_each_card_rtds' 238 | - 'for_each_card_rtds_safe' 239 | - 'for_each_card_widgets' 240 | - 'for_each_card_widgets_safe' 241 | - 'for_each_cgroup_storage_type' 242 | - 'for_each_child_of_node' 243 | - 'for_each_child_of_node_scoped' 244 | - 'for_each_clear_bit' 245 | - 'for_each_clear_bit_from' 246 | - 'for_each_clear_bitrange' 247 | - 'for_each_clear_bitrange_from' 248 | - 'for_each_cmd' 249 | - 'for_each_cmsghdr' 250 | - 'for_each_collection' 251 | - 'for_each_comp_order' 252 | - 'for_each_compatible_node' 253 | - 'for_each_component_dais' 254 | - 'for_each_component_dais_safe' 255 | - 'for_each_conduit' 256 | - 'for_each_console' 257 | - 'for_each_console_srcu' 258 | - 'for_each_cpu' 259 | - 'for_each_cpu_and' 260 | - 'for_each_cpu_andnot' 261 | - 'for_each_cpu_from' 262 | - 'for_each_cpu_or' 263 | - 'for_each_cpu_wrap' 264 | - 'for_each_dapm_widgets' 265 | - 'for_each_dedup_cand' 266 | - 'for_each_dev_addr' 267 | - 'for_each_dev_scope' 268 | - 'for_each_dma_cap_mask' 269 | - 'for_each_dpcm_be' 270 | - 'for_each_dpcm_be_rollback' 271 | - 'for_each_dpcm_be_safe' 272 | - 'for_each_dpcm_fe' 273 | - 'for_each_drhd_unit' 274 | - 'for_each_dss_dev' 275 | - 'for_each_efi_memory_desc' 276 | - 'for_each_efi_memory_desc_in_map' 277 | - 'for_each_element' 278 | - 'for_each_element_extid' 279 | - 'for_each_element_id' 280 | - 'for_each_enabled_cpu' 281 | - 'for_each_endpoint_of_node' 282 | - 'for_each_event' 283 | - 'for_each_event_tps' 284 | - 'for_each_evictable_lru' 285 | - 'for_each_fib6_node_rt_rcu' 286 | - 'for_each_fib6_walker_rt' 287 | - 'for_each_file_lock' 288 | - 'for_each_free_mem_pfn_range_in_zone_from' 289 | - 'for_each_free_mem_range' 290 | - 'for_each_free_mem_range_reverse' 291 | - 'for_each_func_rsrc' 292 | - 'for_each_gpiochip_node' 293 | - 'for_each_group_evsel' 294 | - 'for_each_group_evsel_head' 295 | - 'for_each_group_member' 296 | - 'for_each_group_member_head' 297 | - 'for_each_hstate' 298 | - 'for_each_hwgpio' 299 | - 'for_each_if' 300 | - 'for_each_inject_fn' 301 | - 'for_each_insn' 302 | - 'for_each_insn_op_loc' 303 | - 'for_each_insn_prefix' 304 | - 'for_each_intid' 305 | - 'for_each_iommu' 306 | - 'for_each_ip_tunnel_rcu' 307 | - 'for_each_irq_nr' 308 | - 'for_each_lang' 309 | - 'for_each_link_ch_maps' 310 | - 'for_each_link_codecs' 311 | - 'for_each_link_cpus' 312 | - 'for_each_link_platforms' 313 | - 'for_each_lru' 314 | - 'for_each_matching_node' 315 | - 'for_each_matching_node_and_match' 316 | - 'for_each_media_entity_data_link' 317 | - 'for_each_mem_pfn_range' 318 | - 'for_each_mem_range' 319 | - 'for_each_mem_range_rev' 320 | - 'for_each_mem_region' 321 | - 'for_each_member' 322 | - 'for_each_memory' 323 | - 'for_each_migratetype_order' 324 | - 'for_each_missing_reg' 325 | - 'for_each_mle_subelement' 326 | - 'for_each_mod_mem_type' 327 | - 'for_each_net' 328 | - 'for_each_net_continue_reverse' 329 | - 'for_each_net_rcu' 330 | - 'for_each_netdev' 331 | - 'for_each_netdev_continue' 332 | - 'for_each_netdev_continue_rcu' 333 | - 'for_each_netdev_continue_reverse' 334 | - 'for_each_netdev_dump' 335 | - 'for_each_netdev_feature' 336 | - 'for_each_netdev_in_bond_rcu' 337 | - 'for_each_netdev_rcu' 338 | - 'for_each_netdev_reverse' 339 | - 'for_each_netdev_safe' 340 | - 'for_each_new_connector_in_state' 341 | - 'for_each_new_crtc_in_state' 342 | - 'for_each_new_mst_mgr_in_state' 343 | - 'for_each_new_plane_in_state' 344 | - 'for_each_new_plane_in_state_reverse' 345 | - 'for_each_new_private_obj_in_state' 346 | - 'for_each_new_reg' 347 | - 'for_each_nhlt_endpoint' 348 | - 'for_each_nhlt_endpoint_fmtcfg' 349 | - 'for_each_nhlt_fmtcfg' 350 | - 'for_each_node' 351 | - 'for_each_node_by_name' 352 | - 'for_each_node_by_type' 353 | - 'for_each_node_mask' 354 | - 'for_each_node_state' 355 | - 'for_each_node_with_cpus' 356 | - 'for_each_node_with_property' 357 | - 'for_each_nonreserved_multicast_dest_pgid' 358 | - 'for_each_numa_hop_mask' 359 | - 'for_each_of_allnodes' 360 | - 'for_each_of_allnodes_from' 361 | - 'for_each_of_cpu_node' 362 | - 'for_each_of_pci_range' 363 | - 'for_each_old_connector_in_state' 364 | - 'for_each_old_crtc_in_state' 365 | - 'for_each_old_mst_mgr_in_state' 366 | - 'for_each_old_plane_in_state' 367 | - 'for_each_old_private_obj_in_state' 368 | - 'for_each_oldnew_connector_in_state' 369 | - 'for_each_oldnew_crtc_in_state' 370 | - 'for_each_oldnew_mst_mgr_in_state' 371 | - 'for_each_oldnew_plane_in_state' 372 | - 'for_each_oldnew_plane_in_state_reverse' 373 | - 'for_each_oldnew_private_obj_in_state' 374 | - 'for_each_online_cpu' 375 | - 'for_each_online_node' 376 | - 'for_each_online_pgdat' 377 | - 'for_each_or_bit' 378 | - 'for_each_path' 379 | - 'for_each_pci_bridge' 380 | - 'for_each_pci_dev' 381 | - 'for_each_pcm_streams' 382 | - 'for_each_physmem_range' 383 | - 'for_each_populated_zone' 384 | - 'for_each_possible_cpu' 385 | - 'for_each_present_blessed_reg' 386 | - 'for_each_present_cpu' 387 | - 'for_each_prime_number' 388 | - 'for_each_prime_number_from' 389 | - 'for_each_probe_cache_entry' 390 | - 'for_each_process' 391 | - 'for_each_process_thread' 392 | - 'for_each_prop_codec_conf' 393 | - 'for_each_prop_dai_codec' 394 | - 'for_each_prop_dai_cpu' 395 | - 'for_each_prop_dlc_codecs' 396 | - 'for_each_prop_dlc_cpus' 397 | - 'for_each_prop_dlc_platforms' 398 | - 'for_each_property_of_node' 399 | - 'for_each_reg' 400 | - 'for_each_reg_filtered' 401 | - 'for_each_reloc' 402 | - 'for_each_reloc_from' 403 | - 'for_each_requested_gpio' 404 | - 'for_each_requested_gpio_in_range' 405 | - 'for_each_reserved_child_of_node' 406 | - 'for_each_reserved_mem_range' 407 | - 'for_each_reserved_mem_region' 408 | - 'for_each_rtd_ch_maps' 409 | - 'for_each_rtd_codec_dais' 410 | - 'for_each_rtd_components' 411 | - 'for_each_rtd_cpu_dais' 412 | - 'for_each_rtd_dais' 413 | - 'for_each_rtd_dais_reverse' 414 | - 'for_each_sband_iftype_data' 415 | - 'for_each_script' 416 | - 'for_each_sec' 417 | - 'for_each_set_bit' 418 | - 'for_each_set_bit_from' 419 | - 'for_each_set_bit_wrap' 420 | - 'for_each_set_bitrange' 421 | - 'for_each_set_bitrange_from' 422 | - 'for_each_set_clump8' 423 | - 'for_each_sg' 424 | - 'for_each_sg_dma_page' 425 | - 'for_each_sg_page' 426 | - 'for_each_sgtable_dma_page' 427 | - 'for_each_sgtable_dma_sg' 428 | - 'for_each_sgtable_page' 429 | - 'for_each_sgtable_sg' 430 | - 'for_each_sibling_event' 431 | - 'for_each_sta_active_link' 432 | - 'for_each_subelement' 433 | - 'for_each_subelement_extid' 434 | - 'for_each_subelement_id' 435 | - 'for_each_sublist' 436 | - 'for_each_subsystem' 437 | - 'for_each_supported_activate_fn' 438 | - 'for_each_supported_inject_fn' 439 | - 'for_each_sym' 440 | - 'for_each_test' 441 | - 'for_each_thread' 442 | - 'for_each_token' 443 | - 'for_each_unicast_dest_pgid' 444 | - 'for_each_valid_link' 445 | - 'for_each_vif_active_link' 446 | - 'for_each_vma' 447 | - 'for_each_vma_range' 448 | - 'for_each_vsi' 449 | - 'for_each_wakeup_source' 450 | - 'for_each_zone' 451 | - 'for_each_zone_zonelist' 452 | - 'for_each_zone_zonelist_nodemask' 453 | - 'func_for_each_insn' 454 | - 'fwnode_for_each_available_child_node' 455 | - 'fwnode_for_each_child_node' 456 | - 'fwnode_for_each_parent_node' 457 | - 'fwnode_graph_for_each_endpoint' 458 | - 'gadget_for_each_ep' 459 | - 'genradix_for_each' 460 | - 'genradix_for_each_from' 461 | - 'genradix_for_each_reverse' 462 | - 'hash_for_each' 463 | - 'hash_for_each_possible' 464 | - 'hash_for_each_possible_rcu' 465 | - 'hash_for_each_possible_rcu_notrace' 466 | - 'hash_for_each_possible_safe' 467 | - 'hash_for_each_rcu' 468 | - 'hash_for_each_safe' 469 | - 'hashmap__for_each_entry' 470 | - 'hashmap__for_each_entry_safe' 471 | - 'hashmap__for_each_key_entry' 472 | - 'hashmap__for_each_key_entry_safe' 473 | - 'hctx_for_each_ctx' 474 | - 'hists__for_each_format' 475 | - 'hists__for_each_sort_list' 476 | - 'hlist_bl_for_each_entry' 477 | - 'hlist_bl_for_each_entry_rcu' 478 | - 'hlist_bl_for_each_entry_safe' 479 | - 'hlist_for_each' 480 | - 'hlist_for_each_entry' 481 | - 'hlist_for_each_entry_continue' 482 | - 'hlist_for_each_entry_continue_rcu' 483 | - 'hlist_for_each_entry_continue_rcu_bh' 484 | - 'hlist_for_each_entry_from' 485 | - 'hlist_for_each_entry_from_rcu' 486 | - 'hlist_for_each_entry_rcu' 487 | - 'hlist_for_each_entry_rcu_bh' 488 | - 'hlist_for_each_entry_rcu_notrace' 489 | - 'hlist_for_each_entry_safe' 490 | - 'hlist_for_each_entry_srcu' 491 | - 'hlist_for_each_safe' 492 | - 'hlist_nulls_for_each_entry' 493 | - 'hlist_nulls_for_each_entry_from' 494 | - 'hlist_nulls_for_each_entry_rcu' 495 | - 'hlist_nulls_for_each_entry_safe' 496 | - 'i3c_bus_for_each_i2cdev' 497 | - 'i3c_bus_for_each_i3cdev' 498 | - 'idr_for_each_entry' 499 | - 'idr_for_each_entry_continue' 500 | - 'idr_for_each_entry_continue_ul' 501 | - 'idr_for_each_entry_ul' 502 | - 'in_dev_for_each_ifa_rcu' 503 | - 'in_dev_for_each_ifa_rtnl' 504 | - 'inet_bind_bucket_for_each' 505 | - 'interval_tree_for_each_span' 506 | - 'intlist__for_each_entry' 507 | - 'intlist__for_each_entry_safe' 508 | - 'kcore_copy__for_each_phdr' 509 | - 'key_for_each' 510 | - 'key_for_each_safe' 511 | - 'klp_for_each_func' 512 | - 'klp_for_each_func_safe' 513 | - 'klp_for_each_func_static' 514 | - 'klp_for_each_object' 515 | - 'klp_for_each_object_safe' 516 | - 'klp_for_each_object_static' 517 | - 'kunit_suite_for_each_test_case' 518 | - 'kvm_for_each_memslot' 519 | - 'kvm_for_each_memslot_in_gfn_range' 520 | - 'kvm_for_each_vcpu' 521 | - 'libbpf_nla_for_each_attr' 522 | - 'list_for_each' 523 | - 'list_for_each_codec' 524 | - 'list_for_each_codec_safe' 525 | - 'list_for_each_continue' 526 | - 'list_for_each_entry' 527 | - 'list_for_each_entry_continue' 528 | - 'list_for_each_entry_continue_rcu' 529 | - 'list_for_each_entry_continue_reverse' 530 | - 'list_for_each_entry_from' 531 | - 'list_for_each_entry_from_rcu' 532 | - 'list_for_each_entry_from_reverse' 533 | - 'list_for_each_entry_lockless' 534 | - 'list_for_each_entry_rcu' 535 | - 'list_for_each_entry_reverse' 536 | - 'list_for_each_entry_safe' 537 | - 'list_for_each_entry_safe_continue' 538 | - 'list_for_each_entry_safe_from' 539 | - 'list_for_each_entry_safe_reverse' 540 | - 'list_for_each_entry_srcu' 541 | - 'list_for_each_from' 542 | - 'list_for_each_prev' 543 | - 'list_for_each_prev_safe' 544 | - 'list_for_each_rcu' 545 | - 'list_for_each_reverse' 546 | - 'list_for_each_safe' 547 | - 'llist_for_each' 548 | - 'llist_for_each_entry' 549 | - 'llist_for_each_entry_safe' 550 | - 'llist_for_each_safe' 551 | - 'lwq_for_each_safe' 552 | - 'map__for_each_symbol' 553 | - 'map__for_each_symbol_by_name' 554 | - 'mas_for_each' 555 | - 'mci_for_each_dimm' 556 | - 'media_device_for_each_entity' 557 | - 'media_device_for_each_intf' 558 | - 'media_device_for_each_link' 559 | - 'media_device_for_each_pad' 560 | - 'media_entity_for_each_pad' 561 | - 'media_pipeline_for_each_entity' 562 | - 'media_pipeline_for_each_pad' 563 | - 'mlx5_lag_for_each_peer_mdev' 564 | - 'msi_domain_for_each_desc' 565 | - 'msi_for_each_desc' 566 | - 'mt_for_each' 567 | - 'nanddev_io_for_each_page' 568 | - 'netdev_for_each_lower_dev' 569 | - 'netdev_for_each_lower_private' 570 | - 'netdev_for_each_lower_private_rcu' 571 | - 'netdev_for_each_mc_addr' 572 | - 'netdev_for_each_synced_mc_addr' 573 | - 'netdev_for_each_synced_uc_addr' 574 | - 'netdev_for_each_uc_addr' 575 | - 'netdev_for_each_upper_dev_rcu' 576 | - 'netdev_hw_addr_list_for_each' 577 | - 'nft_rule_for_each_expr' 578 | - 'nla_for_each_attr' 579 | - 'nla_for_each_attr_type' 580 | - 'nla_for_each_nested' 581 | - 'nla_for_each_nested_type' 582 | - 'nlmsg_for_each_attr' 583 | - 'nlmsg_for_each_msg' 584 | - 'nr_neigh_for_each' 585 | - 'nr_neigh_for_each_safe' 586 | - 'nr_node_for_each' 587 | - 'nr_node_for_each_safe' 588 | - 'of_for_each_phandle' 589 | - 'of_property_for_each_string' 590 | - 'of_property_for_each_u32' 591 | - 'pci_bus_for_each_resource' 592 | - 'pci_dev_for_each_resource' 593 | - 'pcl_for_each_chunk' 594 | - 'pcl_for_each_segment' 595 | - 'pcm_for_each_format' 596 | - 'perf_config_items__for_each_entry' 597 | - 'perf_config_sections__for_each_entry' 598 | - 'perf_config_set__for_each_entry' 599 | - 'perf_cpu_map__for_each_cpu' 600 | - 'perf_cpu_map__for_each_cpu_skip_any' 601 | - 'perf_cpu_map__for_each_idx' 602 | - 'perf_evlist__for_each_entry' 603 | - 'perf_evlist__for_each_entry_reverse' 604 | - 'perf_evlist__for_each_entry_safe' 605 | - 'perf_evlist__for_each_evsel' 606 | - 'perf_evlist__for_each_mmap' 607 | - 'perf_hpp_list__for_each_format' 608 | - 'perf_hpp_list__for_each_format_safe' 609 | - 'perf_hpp_list__for_each_sort_list' 610 | - 'perf_hpp_list__for_each_sort_list_safe' 611 | - 'perf_tool_event__for_each_event' 612 | - 'plist_for_each' 613 | - 'plist_for_each_continue' 614 | - 'plist_for_each_entry' 615 | - 'plist_for_each_entry_continue' 616 | - 'plist_for_each_entry_safe' 617 | - 'plist_for_each_safe' 618 | - 'pnp_for_each_card' 619 | - 'pnp_for_each_dev' 620 | - 'protocol_for_each_card' 621 | - 'protocol_for_each_dev' 622 | - 'queue_for_each_hw_ctx' 623 | - 'radix_tree_for_each_slot' 624 | - 'radix_tree_for_each_tagged' 625 | - 'rb_for_each' 626 | - 'rbtree_postorder_for_each_entry_safe' 627 | - 'rdma_for_each_block' 628 | - 'rdma_for_each_port' 629 | - 'rdma_umem_for_each_dma_block' 630 | - 'resort_rb__for_each_entry' 631 | - 'resource_list_for_each_entry' 632 | - 'resource_list_for_each_entry_safe' 633 | - 'rhl_for_each_entry_rcu' 634 | - 'rhl_for_each_rcu' 635 | - 'rht_for_each' 636 | - 'rht_for_each_entry' 637 | - 'rht_for_each_entry_from' 638 | - 'rht_for_each_entry_rcu' 639 | - 'rht_for_each_entry_rcu_from' 640 | - 'rht_for_each_entry_safe' 641 | - 'rht_for_each_from' 642 | - 'rht_for_each_rcu' 643 | - 'rht_for_each_rcu_from' 644 | - 'rq_for_each_bvec' 645 | - 'rq_for_each_segment' 646 | - 'rq_list_for_each' 647 | - 'rq_list_for_each_safe' 648 | - 'sample_read_group__for_each' 649 | - 'scsi_for_each_prot_sg' 650 | - 'scsi_for_each_sg' 651 | - 'sctp_for_each_hentry' 652 | - 'sctp_skb_for_each' 653 | - 'sec_for_each_insn' 654 | - 'sec_for_each_insn_continue' 655 | - 'sec_for_each_insn_from' 656 | - 'sec_for_each_sym' 657 | - 'shdma_for_each_chan' 658 | - 'shost_for_each_device' 659 | - 'sk_for_each' 660 | - 'sk_for_each_bound' 661 | - 'sk_for_each_entry_offset_rcu' 662 | - 'sk_for_each_from' 663 | - 'sk_for_each_rcu' 664 | - 'sk_for_each_safe' 665 | - 'sk_nulls_for_each' 666 | - 'sk_nulls_for_each_from' 667 | - 'sk_nulls_for_each_rcu' 668 | - 'snd_array_for_each' 669 | - 'snd_pcm_group_for_each_entry' 670 | - 'snd_soc_dapm_widget_for_each_path' 671 | - 'snd_soc_dapm_widget_for_each_path_safe' 672 | - 'snd_soc_dapm_widget_for_each_sink_path' 673 | - 'snd_soc_dapm_widget_for_each_source_path' 674 | - 'sparsebit_for_each_set_range' 675 | - 'strlist__for_each_entry' 676 | - 'strlist__for_each_entry_safe' 677 | - 'sym_for_each_insn' 678 | - 'sym_for_each_insn_continue_reverse' 679 | - 'symbols__for_each_entry' 680 | - 'tb_property_for_each' 681 | - 'tcf_act_for_each_action' 682 | - 'tcf_exts_for_each_action' 683 | - 'ttm_resource_manager_for_each_res' 684 | - 'udp_portaddr_for_each_entry' 685 | - 'udp_portaddr_for_each_entry_rcu' 686 | - 'usb_hub_for_each_child' 687 | - 'v4l2_device_for_each_subdev' 688 | - 'v4l2_m2m_for_each_dst_buf' 689 | - 'v4l2_m2m_for_each_dst_buf_safe' 690 | - 'v4l2_m2m_for_each_src_buf' 691 | - 'v4l2_m2m_for_each_src_buf_safe' 692 | - 'virtio_device_for_each_vq' 693 | - 'while_for_each_ftrace_op' 694 | - 'xa_for_each' 695 | - 'xa_for_each_marked' 696 | - 'xa_for_each_range' 697 | - 'xa_for_each_start' 698 | - 'xas_for_each' 699 | - 'xas_for_each_conflict' 700 | - 'xas_for_each_marked' 701 | - 'xbc_array_for_each_value' 702 | - 'xbc_for_each_key_value' 703 | - 'xbc_node_for_each_array_value' 704 | - 'xbc_node_for_each_child' 705 | - 'xbc_node_for_each_key_value' 706 | - 'xbc_node_for_each_subkey' 707 | - 'ynl_attr_for_each' 708 | - 'ynl_attr_for_each_nested' 709 | - 'ynl_attr_for_each_payload' 710 | - 'zorro_for_each_dev' 711 | 712 | IncludeBlocks: Preserve 713 | IncludeCategories: 714 | - Regex: '.*' 715 | Priority: 1 716 | IncludeIsMainRegex: '(Test)?$' 717 | IndentCaseLabels: false 718 | IndentGotoLabels: false 719 | IndentPPDirectives: None 720 | IndentWidth: 8 721 | IndentWrappedFunctionNames: false 722 | JavaScriptQuotes: Leave 723 | JavaScriptWrapImports: true 724 | KeepEmptyLinesAtTheStartOfBlocks: false 725 | MacroBlockBegin: '' 726 | MacroBlockEnd: '' 727 | MaxEmptyLinesToKeep: 1 728 | NamespaceIndentation: None 729 | ObjCBinPackProtocolList: Auto 730 | ObjCBlockIndentWidth: 8 731 | ObjCSpaceAfterProperty: true 732 | ObjCSpaceBeforeProtocolList: true 733 | 734 | # Taken from git's rules 735 | PenaltyBreakAssignment: 10 736 | PenaltyBreakBeforeFirstCallParameter: 30 737 | PenaltyBreakComment: 10 738 | PenaltyBreakFirstLessLess: 0 739 | PenaltyBreakString: 10 740 | PenaltyExcessCharacter: 100 741 | PenaltyReturnTypeOnItsOwnLine: 60 742 | 743 | PointerAlignment: Right 744 | ReflowComments: false 745 | SortIncludes: false 746 | SortUsingDeclarations: false 747 | SpaceAfterCStyleCast: false 748 | SpaceAfterTemplateKeyword: true 749 | SpaceBeforeAssignmentOperators: true 750 | SpaceBeforeCtorInitializerColon: true 751 | SpaceBeforeInheritanceColon: true 752 | SpaceBeforeParens: ControlStatementsExceptForEachMacros 753 | SpaceBeforeRangeBasedForLoopColon: true 754 | SpaceInEmptyParentheses: false 755 | SpacesBeforeTrailingComments: 1 756 | SpacesInAngles: false 757 | SpacesInContainerLiterals: false 758 | SpacesInCStyleCastParentheses: false 759 | SpacesInParentheses: false 760 | SpacesInSquareBrackets: false 761 | Standard: Cpp03 762 | TabWidth: 8 763 | UseTab: Always 764 | ... 765 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [meson.build] 10 | indent_size = 4 11 | indent_style = space 12 | 13 | [*.{c,h}] 14 | indent_size = 8 15 | indent_style = tab 16 | -------------------------------------------------------------------------------- /.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 | podman exec -i -u root stable apt update 34 | podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \ 35 | clang \ 36 | cmake \ 37 | gcc \ 38 | gcc-aarch64-linux-gnu \ 39 | gcc-arm-linux-gnueabihf \ 40 | gcc-mips-linux-gnu \ 41 | meson \ 42 | libsocketcan-dev \ 43 | libconfig-dev 44 | 45 | - name: Configure & Build with gcc 46 | env: 47 | cc: gcc 48 | run: | 49 | podman exec -i --env CC=${cc} stable meson setup -Dlibconfig=true -Dlibsocketcan=true build-${cc} 50 | podman exec -i stable ninja -C build-${cc} 51 | 52 | - name: Configure & Build with clang 53 | env: 54 | cc: clang 55 | run: | 56 | podman exec -i --env CC=${cc} stable meson setup -Dlibconfig=true -Dlibsocketcan=true build-${cc} 57 | podman exec -i stable ninja -C build-${cc} 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.cache 2 | /.ccls-cache 3 | /tags 4 | -------------------------------------------------------------------------------- /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/GPL-2.0-only.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | socketcand 2 | ========== 3 | 4 | Socketcand is a daemon that provides access to CAN interfaces on a machine via a network interface. The communication protocol uses a TCP/IP connection and a specific protocol to transfer CAN frames and control commands. The protocol specification can be found in ./doc/protocol.md. 5 | 6 | Installation 7 | ------------ 8 | 9 | To build and run socketcand make sure you have the following tools installed: 10 | 11 | * meson 12 | * gcc or another C compiler 13 | * a kernel that includes the SocketCAN modules 14 | * the headers for your kernel version 15 | * the libconfig with headers (libconfig-dev under debian based systems) 16 | * the libsocketcan with headers (libsocketcan-dev under debian based systems) is a requirement to configure the interfaces from socketcand 17 | 18 | Execute the following commands to configure, build, and install the software: 19 | 20 | $ meson setup -Dlibconfig=true --buildtype=release build 21 | $ meson compile -C build 22 | $ meson install -C build 23 | 24 | Service discovery 25 | ----------------- 26 | 27 | The daemon uses a simple UDP beacon mechanism for service discovery. A beacon containing the service name, type and address is sent to the broadcast address (port 42000) at minimum every 3 seconds. A client only has to listen for messages of this type to detect all SocketCAN daemons in the local network. 28 | 29 | Usage 30 | ----- 31 | 32 | socketcand [-v | --verbose] [-i interfaces | --interfaces interfaces] 33 | [-p port | --port port] [-l interface | --listen interface] 34 | [-u name | --afuxname name] [-n | --no-beacon] [-d | --daemon] 35 | [-e error_mask | --error-mask error_mask] 36 | [-h | --help] 37 | 38 | ### Description of the options 39 | * **-v** (activates verbose output to STDOUT) 40 | * **-i interfaces** (comma separated list of CAN interfaces the daemon shall provide access to e.g. '-i can0,vcan1' - default: vcan0) 41 | * **-p port** (changes the default port '29536' the daemon is listening at) 42 | * **-l interface** (changes the default network interface the daemon will bind to - default: eth0) 43 | * **-u name** (the AF_UNIX socket path - an abstract name is used when the leading '/' is missing. N.B. the AF_UNIX binding will supersede the port/interface settings) 44 | * **-n** (deactivates the discovery beacon) 45 | * **-e error_mask** (enable CAN error frames in raw mode providing an hexadecimal error mask, e.g: 0x1FFFFFFF) 46 | * **-d** (set this flag if you want log to syslog instead of STDOUT) 47 | * **-h** (prints this message) 48 | 49 | License 50 | ------- 51 | 52 | The source code is released under either GPL-2.0-only or BSD-3-Clause licenses. 53 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | debhelper-build-stamp 2 | files 3 | socketcand.substvars 4 | socketcand.debhelper.log 5 | socketcand.postinst.debhelper 6 | socketcand.postrm.debhelper 7 | socketcand.prerm.debhelper 8 | 9 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | socketcand (0.6.1-1) unstable; urgency=medium 2 | 3 | * Initial Debian port 4 | 5 | -- Yegor Yefremov Wed, 04 Dec 2024 10:41:56 +0100 6 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: socketcand 2 | Section: net 3 | Priority: extra 4 | Maintainer: Yegor Yefremov 5 | Build-Depends: debhelper-compat (= 10), 6 | gzip, 7 | libconfig-dev, 8 | libsocketcan-dev, 9 | meson, 10 | pkg-config, 11 | Standards-Version: 3.9.3 12 | Homepage: https://github.com/linux-can/socketcand 13 | 14 | Package: socketcand 15 | Architecture: any 16 | Depends: ${shlibs:Depends}, ${misc:Depends} 17 | Description: CAN over IP Daemon 18 | Socketcand is a daemon that provides access to CAN interfaces on 19 | a machine via a network interface. The communication protocol uses 20 | a TCP/IP connection and a specific protocol to transfer CAN frames 21 | and control commands. 22 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: socketcand 3 | Source: 4 | 5 | Files: * 6 | Copyright: 2002-2009 Volkswagen Group Electronic Research 7 | License: GPL-2.0-only OR BSD-3-Clause 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 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # Uncomment this to turn on verbose mode. 4 | #export DH_VERBOSE=1 5 | 6 | DEB_CONFIGURE_EXTRA_FLAGS = -Dlibconfig=true -Dlibsocketcan=true 7 | 8 | override_dh_auto_configure: 9 | dh_auto_configure \ 10 | -- \ 11 | $(DEB_CONFIGURE_EXTRA_FLAGS) \ 12 | $(NULL) 13 | 14 | override_dh_usrlocal: 15 | 16 | %: 17 | dh $@ 18 | -------------------------------------------------------------------------------- /debian/socketcand.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=CAN over IP Daemon 3 | After=network-online.target 4 | Wants=network-online.target 5 | 6 | [Service] 7 | Type=simple 8 | ExecStart=/usr/sbin/socketcand 9 | KillMode=process 10 | DevicePolicy=auto 11 | Restart=no 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /doc/protocol.md: -------------------------------------------------------------------------------- 1 | Socketcand protocol 2 | =================== 3 | 4 | The socketcand provides a network interface to a number of CAN buses on the host. It can be controlled over a single TCP socket and supports transmission and reception of CAN frames. The used protocol is ASCII based and has some states in which different commands may be used. 5 | 6 | ## Mode NO_BUS ## 7 | After connecting to the socket the client is greeted with '< hi >'. The open command is used to select one of the CAN buses that were announced in the broadcast beacon. The syntax is '', e.g. 8 | 9 | < open can0 > 10 | 11 | where canbus may be at maximum 16 characters long. If the client is allowed to access the bus the server will respond with '< ok >'. Otherwise an error is returned and the connection is terminated. 12 | After a bus was opened the mode is switched to BCM mode. The Mode NO_BUS is the only mode where bittimings or other bus configuration settings may be done. 13 | 14 | #### Configure the bittiming #### 15 | The protocol enables the client to change the bittiming of a given bus as provided by set link. Automatic bitrate configuration by the kernel is not supported because it is not guaranteed that the corresponding option was enabled during compile time (e.g. in Ubuntu 10.10 it is not). This way it it also easier to implement the function in a microcontroller based adapter. 16 | 17 | < can0 B bitrate sample_point tq prop_seg phase_seg1 phase_seg2 sjw brp > 18 | 19 | #### Set the controlmode #### 20 | The control mode controls if the bus is set to listen only, if sent packages are looped back and if the controller is configured to take three samples. The following command provides access to these settings. Each field must be set to '0' or '1' to disable or enable the setting. 21 | 22 | < can0 C listen_only loopback three_samples > 23 | 24 | **_NOTE:_** The interface configuration only works if socketcand is compiled with libsocketcan dependency. 25 | 26 | ## Mode BCM (default mode) ## 27 | After the client has successfully opened a bus the mode is switched to BCM mode (DEFAULT). In this mode a BCM socket to the bus will be opened and can be controlled over the connection. The following commands are understood: 28 | 29 | ### Commands for transmission ### 30 | There are a few commands that control the transmission of CAN frames. Most of them are interval based and the Socket CAN broadcast manager guarantees that the frames are sent cyclic with the given interval. To be able to control these transmission jobs they are automatically removed when the BCM server socket is closed. 31 | 32 | #### Add a new frame for transmission #### 33 | This command adds a new frame to the BCM queue. An interval can be configured to have the frame sent cyclic. 34 | 35 | Examples: 36 | 37 | Send the CAN frame 123#1122334455667788 every second 38 | 39 | < add 1 0 123 8 11 22 33 44 55 66 77 88 > 40 | 41 | Send the CAN frame 123#1122334455667788 every 10 usecs 42 | 43 | < add 0 10 123 8 11 22 33 44 55 66 77 88 > 44 | 45 | Send the CAN frame 123#42424242 every 20 msecs 46 | 47 | < add 0 20000 123 4 42 42 42 42 > 48 | 49 | #### Update a frame #### 50 | This command updates a frame transmission job that was created via the 'add' command with new content. The transmission timers are not touched 51 | 52 | Example: 53 | Update the CAN frame 123#42424242 with 123#112233 - no change of timers 54 | 55 | < update 123 3 11 22 33 > 56 | 57 | #### Delete a send job #### 58 | A send job can be removed with the 'delete' command. 59 | 60 | Example: 61 | Delete the cyclic send job from above 62 | 63 | < delete 123 > 64 | 65 | #### Send a single frame #### 66 | This command is used to send a single CAN frame. The data is lowercase unpadded hex with spaces inbetween. 67 | 68 | < send can_id can_dlc [data]* > 69 | 70 | Example: 71 | Send a single CAN frame without cyclic transmission 72 | 73 | // ID: 123, no data 74 | < send 123 0 > 75 | 76 | // ID: 1AAAAAAA, Length: 2, Data: 0x01 0xF1 77 | < send 1AAAAAAA 2 1 f1 > 78 | 79 | ### Commands for reception ### 80 | The commands for reception are 'subscribe' , 'unsubscribe' and 'filter'. 81 | 82 | #### Content filtering #### 83 | This command is used to configure the broadcast manager for reception of frames with a given CAN ID. Frames are only sent when they match the pattern that is provided. The time value given is used to throttle the incoming update rate. 84 | 85 | < filter secs usecs can_id can_dlc [data]* > 86 | 87 | * secs - number of seconds (throttle update rate) 88 | * usecs - number of microseconds (throttle update rate) 89 | * can_id - CAN identifier 90 | * can_dlc - data length code (values 0 .. 8) 91 | * data - ASCII hex bytes depending on the can_dlc value 92 | 93 | Examples: 94 | 95 | Receive CAN ID 0x123 and check for changes in the first byte 96 | 97 | < filter 0 0 123 1 FF > 98 | 99 | Receive CAN ID 0x123 and check for changes in given mask 100 | 101 | < filter 0 0 123 8 FF 00 F8 00 00 00 00 00 > 102 | 103 | As above but throttle receive update rate down to 1.5 seconds 104 | 105 | < filter 1 500000 123 8 FF 00 F8 00 00 00 00 00 > 106 | 107 | #### Content filtering for multiplex CAN messages #### 108 | This command is used to configure the broadcast manager for reception of frames with a given CAN ID and a multiplex message filter mask. Frames are only sent when they match the pattern that is provided. The time value given is used to throttle the incoming update rate. 109 | 110 | 111 | < muxfilter secs usecs can_id nframes [data]+ > 112 | 113 | * secs - number of seconds (throttle update rate) 114 | * usecs - number of microseconds (throttle update rate) 115 | * can_id - CAN identifier 116 | * nframes - number of 8 byte filter tuples (one mux filter + 1..256 mux content filters) 117 | * data - ASCII hex bytes depending on the nframes value multiplied by 8 118 | 119 | Examples: 120 | 121 | The first 8 byte tuple is the multiplex mask which identifies the position of multiplex identifier. The following 8 byte tuples contain the value of the multiplex id at this position and the filter for that specific multiplex identifier in the remaining content of its 8 byte tuple. 122 | 123 | FF 00 00 00 00 00 00 00 <--> multiplex mask (here: entire first byte) 124 | 33 FF FF FF FF FF FF FF <--> filter mask 'FF FF FF FF FF FF FF' for multiplex id '33' 125 | 56 FF 00 00 00 00 FF FF <--> filter mask 'FF 00 00 00 00 FF FF' for multiplex id '56' 126 | 44 FF FF FF FF 00 00 FF <--> filter mask 'FF FF FF FF 00 00 FF' for multiplex id '44' 127 | ED 00 00 00 00 00 FF FF <--> filter mask '00 00 00 00 00 FF FF' for multiplex id 'ED' 128 | 129 | Receive CAN ID 0x123 and check for changes in given mutiplex mask '33'. The fourth value '2' is the number of frames (2 <= nframes <= 257): 130 | 131 | < muxfilter 0 0 123 2 FF 00 00 00 00 00 00 00 33 FF FF FF FF FF FF FF > 132 | 133 | #### Subscribe to CAN ID #### 134 | Adds a subscription a CAN ID. The frames are sent regardless of their content. An interval in seconds or microseconds may be set. 135 | 136 | < subscribe ival_s ival_us can_id > 137 | 138 | Example: 139 | Subscribe to CAN ID 0x123 without content filtering 140 | 141 | < subscribe 0 0 123 > 142 | 143 | #### Delete a subscription or filter #### 144 | This deletes all subscriptions or filters for a specific CAN ID. 145 | 146 | < unsubscribe can_id > 147 | 148 | Example: 149 | Delete receive filter ('R' or 'F') for CAN ID 0x123 150 | 151 | < unsubscribe 123 > 152 | 153 | #### Echo command #### 154 | After the server receives an '< echo >' it immediately returns the same string. This can be used to see if the connection is still up and to measure latencies. 155 | 156 | < echo > 157 | 158 | ## Mode RAW ## 159 | After switching to RAW mode the BCM socket is closed and a RAW socket is opened. Now every frame on the bus will immediately be received. Therefore no commands to control which frames are received are supported, but the send command works as in BCM mode. 160 | 161 | #### Switch to RAW mode #### 162 | A mode switch to RAW mode can be initiated by sending '< rawmode >'. 163 | 164 | < rawmode > 165 | 166 | #### Frame transmission #### 167 | CAN messages received by the given filters are send in the following format. Note the data part is padded uppercase hex without spaces inbetween. 168 | < frame can_id seconds.useconds [data]* > 169 | 170 | Example: 171 | Reception of a CAN frame with CAN ID 0x123 , data length 4 and data 0x1A, 0x22, 0x03 and 0x44 at time 23.424242>. 172 | 173 | < frame 123 23.424242 1A220344 > 174 | 175 | #### Switch to BCM mode #### 176 | With '< bcmmode >' it is possible to switch back to BCM mode. 177 | 178 | < bcmmode > 179 | 180 | #### Echo command #### 181 | The echo command is supported and works as described under mode BCM. 182 | 183 | ## Mode CONTROL ## 184 | With '< controlmode >' it is possible to enter the CONTROL mode. Here statistics can be enabled or disabled. 185 | 186 | #### Statistics #### 187 | In CONTROL mode it is possible to receive bus statistics. Transmission is enabled by the '< statistics ival >' command. Ival is the interval between two statistics transmissions in milliseconds. The ival may be set to '0' to deactivate transmission. 188 | After enabling statistics transmission the data is send inline with normal CAN frames and other data. The daemon takes care of the interval that was specified. The information is transferred in the following format: 189 | < stat rbytes rpackets tbytes tpackets > 190 | The reported bytes and packets are reported as unsigned integers. 191 | 192 | Example for CAN interface 'can0' to enable statistics with interval of one second: 193 | 194 | < open can0 >< controlmode >< statistics 1000 > 195 | 196 | ## Mode ISO-TP ## 197 | A transport protocol, such as ISO-TP, is needed to enable e.g. software upload via CAN. It organises the connection-less transmission of a sequence of data. An ISO-TP channel consists of two exclusive CAN IDs, one to transmit data and the other to receive data. 198 | After configuration a single ISO-TP channel can be used. The ISO-TP mode can be used exclusively like the other modes (bcmmode, rawmode, isotpmode). 199 | 200 | Switch to ISO-TP mode 201 | 202 | < isotpmode > 203 | 204 | Configure the ISO-TP channel - optional parameters are in [ ] brackets. 205 | 206 | < isotpconf tx_id rx_id flags blocksize stmin [ wftmax txpad_content rxpad_content ext_address rx_ext_address ] > 207 | 208 | * tx_id - CAN ID of channel to transmit data (from the host / src). CAN IDs 000h up to 7FFh (standard frame format) and 00000000h up to 1FFFFFFFh (extended frame format). 209 | * rx_id - CAN ID of channel to receive data (to the host / dst). CAN IDs in same format as tx_id. 210 | * flags - hex value built from the original flags from isotp.h. These flags define which of the following parameters is used/required in which way. 211 | * blocksize - can take values from 0 (=off) to 15 212 | * stmin - separation time minimum. Hex value from 00h - FFh according to ISO-TP specification 213 | * wftmax - maximum number of wait frames (0 = off) 214 | * txpad_content - padding value in the tx path (enable CAN_ISOTP_TX_PADDING in flags) 215 | * rxpad_content - padding value in the rx path (enable CAN_ISOTP_RX_PADDING in flags) 216 | * ext_address - extended addressing freature (value for tx and rx if not specified separately / enable CAN_ISOTP_EXTEND_ADDR in flags) 217 | * rx_ext_address - extended addressing freature (separate value for rx / enable CAN_ISOTP_RX_EXT_ADDR in flags) 218 | 219 | The flags contents are built from the original isotp.h file: 220 | 221 | #define CAN_ISOTP_LISTEN_MODE 0x001 /* listen only (do not send FC) */ 222 | #define CAN_ISOTP_EXTEND_ADDR 0x002 /* enable extended addressing */ 223 | #define CAN_ISOTP_TX_PADDING 0x004 /* enable CAN frame padding tx path */ 224 | #define CAN_ISOTP_RX_PADDING 0x008 /* enable CAN frame padding rx path */ 225 | #define CAN_ISOTP_CHK_PAD_LEN 0x010 /* check received CAN frame padding */ 226 | #define CAN_ISOTP_CHK_PAD_DATA 0x020 /* check received CAN frame padding */ 227 | #define CAN_ISOTP_HALF_DUPLEX 0x040 /* half duplex error state handling */ 228 | #define CAN_ISOTP_FORCE_TXSTMIN 0x080 /* ignore stmin from received FC */ 229 | #define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */ 230 | #define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */ 231 | 232 | 233 | Example: Configuration with 1F998877h as source and 1F998876h as destination id for this specific ISO-TP channel (host view) with tx padding AAh and rx padding 55h. The flags are calculated by adding CAN_ISOTP_TX_PADDING (4) and CAN_ISOTP_RX_PADDING (8) to the hex value Ch. The Blocksize is 4 and STmin is 0. 234 | 235 | < isotpconf 1F998877 1F998876 C 4 0 0 AA 55 > 236 | 237 | As one can see only the needed parameters need to be provided, e.g. a set CAN_ISOTP_RX_PADDING flag requires the rxpad_content. The parameters up to stmin are mandatory, so the shortest isotpconf can be: 238 | 239 | < isotpconf 1F998877 1F998876 0 0 0 > 240 | 241 | To send a protocol data unit (PDU) use the '< sendpdu ... >' command. 242 | 243 | < sendpdu pdudata > 244 | 245 | Example: Sending of a PDU consisting of 16 bytes data 00112233445566778899AABBCCDDEEFF 246 | 247 | < sendpdu 00112233445566778899AABBCCDDEEFF > 248 | 249 | Receiving of a PDU on the same channel is quite similar but is supplemented by a timestamp 250 | 251 | < pdu timestamp pdudata > 252 | 253 | Example: Receiving of the same data as sent in the example above 254 | 255 | < pdu 1417687245.814579 00112233445566778899AABBCCDDEEFF > 256 | 257 | Service discovery 258 | ----------------- 259 | 260 | Because configuration shall be as easy as possible and the virtual CAN bus and the Kayak instance are not necessarily on the same machine a mechanism for service discovery is necessary. 261 | 262 | The server sends a UDP broadcast beacon to port 42000 on the subnet where the server port was bound. The interval for these discovery beacons shall not be longer than three seconds. Because the BCM server handles all communication (even for multiple buses) over a single TCP connection the broadcast must provide information about all buses that are accessible through the BCM server. 263 | 264 | ### Content ### 265 | 266 | Required: 267 | 268 | * Name of the device that provides access to the buses. On linux machines this could be the hostname 269 | * Name of the buses (in case of socketCAN and embedded this should be the same as the device name) 270 | * URL with port and IP address. If the server is listening on multiple sockets all of them should be included in the beacon 271 | * Device type the service is running on 272 | 273 | Optional: 274 | 275 | * Description of the service in a human readable form 276 | 277 | ### Device types #### 278 | 279 | * SocketCAN - general socketCAN service on a linux machine 280 | * embedded - embedded linux with access to a bus over socketCAN 281 | * adapter - e.g. microcontroller driven CAN to ethernet adapter 282 | 283 | ### Structure ### 284 | 285 | For simple parsing and a human readable schema XML is used to structure the information in a CAN beacon. 286 | 287 | ### Example ### 288 | 289 | 290 | can://127.0.0.1:29536 291 | 292 | 293 | 294 | 295 | Error frame transmission 296 | ------------------------ 297 | 298 | Error frames are sent inline with regular frames. 'data' is an integer with the encoded error data (see socketcan/can/error.h for further information): 299 | < error data > 300 | -------------------------------------------------------------------------------- /files/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 | # SPDX-FileCopyrightText: 2024 Yegor Yefremov 3 | 4 | if enable_libconfig 5 | install_data( 6 | sources: 'socketcand.conf', 7 | install_dir: '/etc', 8 | ) 9 | endif 10 | 11 | if enable_rc_script 12 | install_data( 13 | sources: 'socketcand-rc.d', 14 | rename: 'socketcand', 15 | install_mode: 'rwxr-xr-x', 16 | install_dir: '/etc/rc.d', 17 | ) 18 | endif 19 | 20 | if enable_init_script 21 | init_conf = configuration_data() 22 | init_conf.set('fullpath', get_option('prefix') / get_option('sbindir')) 23 | configure_file( 24 | input : 'socketcand-init.d.in', 25 | output : 'socketcand', 26 | configuration : init_conf, 27 | install : true, 28 | install_mode : 'rwxr-xr-x', 29 | install_dir : '/etc/init.d', 30 | ) 31 | endif 32 | -------------------------------------------------------------------------------- /files/socketcand-init.d.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: socketcand 5 | # Required-Start: $remote_fs 6 | # Required-Stop: $remote_fs 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 9 | # Short-Description: socketcand 10 | # Description: daemon that provides network access to local CAN buses 11 | ### END INIT INFO 12 | 13 | [ -f /etc/default/rcS ] && . /etc/default/rcS 14 | PATH=/bin:/usr/bin:/sbin:/usr/sbin 15 | DAEMON=@fullpath@/socketcand 16 | DESC="SocketCAN daemon" 17 | NAME="socketcand" 18 | PIDFILE=/var/run/socketcand.pid 19 | 20 | test -x $DAEMON || exit 0 21 | 22 | case "$1" in 23 | start) 24 | echo "Starting $DESC" "$NAME" 25 | start-stop-daemon --start --quiet --background --pidfile $PIDFILE --startas $DAEMON -m -- --daemon 26 | ;; 27 | stop) 28 | echo "Stopping $DESC" "$NAME" 29 | start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo --startas $DAEMON 30 | rm -f $PIDFILE 31 | ;; 32 | status) 33 | printf "%-50s" "Checking $NAME..." 34 | if [ -f $PIDFILE ]; then 35 | PID=`cat $PIDFILE` 36 | if [ -z "`ps axf | grep ${PID} | grep -v grep`" ]; then 37 | printf "%s\n" "Process dead but pidfile exists" 38 | return 1 39 | else 40 | echo "Running" 41 | return 0 42 | fi 43 | else 44 | printf "%s\n" "Service not running" 45 | return 1 46 | fi 47 | ;; 48 | restart) 49 | $0 stop 50 | sleep 1 51 | $0 start 52 | ;; 53 | force-reload) 54 | if start-stop-daemon --stop --test --quiet --pidfile $PIDFILE --startas $DAEMON ; then 55 | $0 restart 56 | fi 57 | ;; 58 | *) 59 | echo "Usage: /etc/init.d/socketcand {start|stop|restart|force-reload}" 60 | exit 1 61 | ;; 62 | esac 63 | 64 | exit 0 65 | -------------------------------------------------------------------------------- /files/socketcand-rc.d: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . /etc/rc.conf 4 | . /etc/rc.d/functions 5 | 6 | DAEMON=socketcand 7 | ARGS="--daemon" 8 | 9 | PID=$(pidof -o %PPID $DAEMON) 10 | 11 | case "$1" in 12 | start) 13 | stat_busy "Starting $DAEMON" 14 | [ -z "$PID" ] && $DAEMON $ARGS &>/dev/null & 15 | if [ $? = 0 ]; then 16 | add_daemon $DAEMON 17 | stat_done 18 | else 19 | stat_fail 20 | exit 1 21 | fi 22 | ;; 23 | stop) 24 | stat_busy "Stopping $DAEMON" 25 | [ -n "$PID" ] && kill $PID &>/dev/null 26 | if [ $? = 0 ]; then 27 | rm_daemon $DAEMON 28 | stat_done 29 | else 30 | stat_fail 31 | exit 1 32 | fi 33 | ;; 34 | restart) 35 | $0 stop 36 | sleep 1 37 | $0 start 38 | ;; 39 | *) 40 | echo "usage: $0 {start|stop|restart}" 41 | esac 42 | -------------------------------------------------------------------------------- /files/socketcand.conf: -------------------------------------------------------------------------------- 1 | # The network interface the socketcand will bind to 2 | # listen = "eth0"; 3 | 4 | # The port the socketcand is listening on 5 | # port = 29536; 6 | 7 | # List of buses the daemon shall provide access to 8 | # Multiple buses must be separated with ',' and whitespace 9 | # is not allowed. eg "vcan0,vcan1" 10 | busses = "vcan0"; 11 | 12 | # Description of the service. This will show up in the discovery beacon 13 | # description = "socketcand"; 14 | 15 | # AF_UNIX name. As alternative to bind to a TCP/IP socket the socketcand can 16 | # listen on an AF_UNIX socket. 17 | # When afuxname starts with a '/' a path for the AF_UNIX socket is created. 18 | # Alternatively an abstract AF_UNIX namespace is allocated with afuxname 19 | # afuxname = "socketcand"; 20 | 21 | -------------------------------------------------------------------------------- /include/linux/can.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 | /* 3 | * linux/can.h 4 | * 5 | * Definitions for CAN network layer (socket addr / CAN frame / CAN filter) 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_H 47 | #define _UAPI_CAN_H 48 | 49 | #include 50 | #include 51 | #include /* for offsetof */ 52 | 53 | /* controller area network (CAN) kernel definitions */ 54 | 55 | /* special address description flags for the CAN_ID */ 56 | #define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */ 57 | #define CAN_RTR_FLAG 0x40000000U /* remote transmission request */ 58 | #define CAN_ERR_FLAG 0x20000000U /* error message frame */ 59 | 60 | /* valid bits in CAN ID for frame formats */ 61 | #define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */ 62 | #define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */ 63 | #define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */ 64 | #define CANXL_PRIO_MASK CAN_SFF_MASK /* 11 bit priority mask */ 65 | 66 | /* 67 | * Controller Area Network Identifier structure 68 | * 69 | * bit 0-28 : CAN identifier (11/29 bit) 70 | * bit 29 : error message frame flag (0 = data frame, 1 = error message) 71 | * bit 30 : remote transmission request flag (1 = rtr frame) 72 | * bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit) 73 | */ 74 | typedef __u32 canid_t; 75 | 76 | #define CAN_SFF_ID_BITS 11 77 | #define CAN_EFF_ID_BITS 29 78 | #define CANXL_PRIO_BITS CAN_SFF_ID_BITS 79 | 80 | /* 81 | * Controller Area Network Error Message Frame Mask structure 82 | * 83 | * bit 0-28 : error class mask (see include/uapi/linux/can/error.h) 84 | * bit 29-31 : set to zero 85 | */ 86 | typedef __u32 can_err_mask_t; 87 | 88 | /* CAN payload length and DLC definitions according to ISO 11898-1 */ 89 | #define CAN_MAX_DLC 8 90 | #define CAN_MAX_RAW_DLC 15 91 | #define CAN_MAX_DLEN 8 92 | 93 | /* CAN FD payload length and DLC definitions according to ISO 11898-7 */ 94 | #define CANFD_MAX_DLC 15 95 | #define CANFD_MAX_DLEN 64 96 | 97 | /* 98 | * CAN XL payload length and DLC definitions according to ISO 11898-1 99 | * CAN XL DLC ranges from 0 .. 2047 => data length from 1 .. 2048 byte 100 | */ 101 | #define CANXL_MIN_DLC 0 102 | #define CANXL_MAX_DLC 2047 103 | #define CANXL_MAX_DLC_MASK 0x07FF 104 | #define CANXL_MIN_DLEN 1 105 | #define CANXL_MAX_DLEN 2048 106 | 107 | /** 108 | * struct can_frame - Classical CAN frame structure (aka CAN 2.0B) 109 | * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition 110 | * @len: CAN frame payload length in byte (0 .. 8) 111 | * @can_dlc: deprecated name for CAN frame payload length in byte (0 .. 8) 112 | * @__pad: padding 113 | * @__res0: reserved / padding 114 | * @len8_dlc: optional DLC value (9 .. 15) at 8 byte payload length 115 | * len8_dlc contains values from 9 .. 15 when the payload length is 116 | * 8 bytes but the DLC value (see ISO 11898-1) is greater then 8. 117 | * CAN_CTRLMODE_CC_LEN8_DLC flag has to be enabled in CAN driver. 118 | * @data: CAN frame payload (up to 8 byte) 119 | */ 120 | struct can_frame { 121 | canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ 122 | union { 123 | /* CAN frame payload length in byte (0 .. CAN_MAX_DLEN) 124 | * was previously named can_dlc so we need to carry that 125 | * name for legacy support 126 | */ 127 | __u8 len; 128 | __u8 can_dlc; /* deprecated */ 129 | } __attribute__((packed)); /* disable padding added in some ABIs */ 130 | __u8 __pad; /* padding */ 131 | __u8 __res0; /* reserved / padding */ 132 | __u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */ 133 | __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8))); 134 | }; 135 | 136 | /* 137 | * defined bits for canfd_frame.flags 138 | * 139 | * The use of struct canfd_frame implies the FD Frame (FDF) bit to 140 | * be set in the CAN frame bitstream on the wire. The FDF bit switch turns 141 | * the CAN controllers bitstream processor into the CAN FD mode which creates 142 | * two new options within the CAN FD frame specification: 143 | * 144 | * Bit Rate Switch - to indicate a second bitrate is/was used for the payload 145 | * Error State Indicator - represents the error state of the transmitting node 146 | * 147 | * As the CANFD_ESI bit is internally generated by the transmitting CAN 148 | * controller only the CANFD_BRS bit is relevant for real CAN controllers when 149 | * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make 150 | * sense for virtual CAN interfaces to test applications with echoed frames. 151 | * 152 | * The struct can_frame and struct canfd_frame intentionally share the same 153 | * layout to be able to write CAN frame content into a CAN FD frame structure. 154 | * When this is done the former differentiation via CAN_MTU / CANFD_MTU gets 155 | * lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of 156 | * using struct canfd_frame for mixed CAN / CAN FD content (dual use). 157 | * Since the introduction of CAN XL the CANFD_FDF flag is set in all CAN FD 158 | * frame structures provided by the CAN subsystem of the Linux kernel. 159 | */ 160 | #define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */ 161 | #define CANFD_ESI 0x02 /* error state indicator of the transmitting node */ 162 | #define CANFD_FDF 0x04 /* mark CAN FD for dual use of struct canfd_frame */ 163 | 164 | /** 165 | * struct canfd_frame - CAN flexible data rate frame structure 166 | * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition 167 | * @len: frame payload length in byte (0 .. CANFD_MAX_DLEN) 168 | * @flags: additional flags for CAN FD 169 | * @__res0: reserved / padding 170 | * @__res1: reserved / padding 171 | * @data: CAN FD frame payload (up to CANFD_MAX_DLEN byte) 172 | */ 173 | struct canfd_frame { 174 | canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ 175 | __u8 len; /* frame payload length in byte */ 176 | __u8 flags; /* additional flags for CAN FD */ 177 | __u8 __res0; /* reserved / padding */ 178 | __u8 __res1; /* reserved / padding */ 179 | __u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8))); 180 | }; 181 | 182 | /* 183 | * defined bits for canxl_frame.flags 184 | * 185 | * The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC 186 | * and shares the relative position of the struct can[fd]_frame.len element. 187 | * The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame. 188 | * As a side effect setting this bit intentionally breaks the length checks 189 | * for Classical CAN and CAN FD frames. 190 | * 191 | * Undefined bits in canxl_frame.flags are reserved and shall be set to zero. 192 | */ 193 | #define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */ 194 | #define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */ 195 | 196 | /* the 8-bit VCID is optionally placed in the canxl_frame.prio element */ 197 | #define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */ 198 | #define CANXL_VCID_VAL_MASK 0xFFUL /* VCID is an 8-bit value */ 199 | #define CANXL_VCID_MASK (CANXL_VCID_VAL_MASK << CANXL_VCID_OFFSET) 200 | 201 | /** 202 | * struct canxl_frame - CAN with e'X'tended frame 'L'ength frame structure 203 | * @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags / VCID 204 | * @flags: additional flags for CAN XL 205 | * @sdt: SDU (service data unit) type 206 | * @len: frame payload length in byte (CANXL_MIN_DLEN .. CANXL_MAX_DLEN) 207 | * @af: acceptance field 208 | * @data: CAN XL frame payload (CANXL_MIN_DLEN .. CANXL_MAX_DLEN byte) 209 | * 210 | * @prio shares the same position as @can_id from struct can[fd]_frame. 211 | */ 212 | struct canxl_frame { 213 | canid_t prio; /* 11 bit priority for arbitration / 8 bit VCID */ 214 | __u8 flags; /* additional flags for CAN XL */ 215 | __u8 sdt; /* SDU (service data unit) type */ 216 | __u16 len; /* frame payload length in byte */ 217 | __u32 af; /* acceptance field */ 218 | __u8 data[CANXL_MAX_DLEN]; 219 | }; 220 | 221 | #define CAN_MTU (sizeof(struct can_frame)) 222 | #define CANFD_MTU (sizeof(struct canfd_frame)) 223 | #define CANXL_MTU (sizeof(struct canxl_frame)) 224 | #define CANXL_HDR_SIZE (offsetof(struct canxl_frame, data)) 225 | #define CANXL_MIN_MTU (CANXL_HDR_SIZE + 64) 226 | #define CANXL_MAX_MTU CANXL_MTU 227 | 228 | /* particular protocols of the protocol family PF_CAN */ 229 | #define CAN_RAW 1 /* RAW sockets */ 230 | #define CAN_BCM 2 /* Broadcast Manager */ 231 | #define CAN_TP16 3 /* VAG Transport Protocol v1.6 */ 232 | #define CAN_TP20 4 /* VAG Transport Protocol v2.0 */ 233 | #define CAN_MCNET 5 /* Bosch MCNet */ 234 | #define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */ 235 | #define CAN_J1939 7 /* SAE J1939 */ 236 | #define CAN_NPROTO 8 237 | 238 | #define SOL_CAN_BASE 100 239 | 240 | /** 241 | * struct sockaddr_can - the sockaddr structure for CAN sockets 242 | * @can_family: address family number AF_CAN. 243 | * @can_ifindex: CAN network interface index. 244 | * @can_addr: protocol specific address information 245 | */ 246 | struct sockaddr_can { 247 | __kernel_sa_family_t can_family; 248 | int can_ifindex; 249 | union { 250 | /* transport protocol class address information (e.g. ISOTP) */ 251 | struct { canid_t rx_id, tx_id; } tp; 252 | 253 | /* J1939 address information */ 254 | struct { 255 | /* 8 byte name when using dynamic addressing */ 256 | __u64 name; 257 | 258 | /* pgn: 259 | * 8 bit: PS in PDU2 case, else 0 260 | * 8 bit: PF 261 | * 1 bit: DP 262 | * 1 bit: reserved 263 | */ 264 | __u32 pgn; 265 | 266 | /* 1 byte address */ 267 | __u8 addr; 268 | } j1939; 269 | 270 | /* reserved for future CAN protocols address information */ 271 | } can_addr; 272 | }; 273 | 274 | /** 275 | * struct can_filter - CAN ID based filter in can_register(). 276 | * @can_id: relevant bits of CAN ID which are not masked out. 277 | * @can_mask: CAN mask (see description) 278 | * 279 | * Description: 280 | * A filter matches, when 281 | * 282 | * & mask == can_id & mask 283 | * 284 | * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can 285 | * filter for error message frames (CAN_ERR_FLAG bit set in mask). 286 | */ 287 | struct can_filter { 288 | canid_t can_id; 289 | canid_t can_mask; 290 | }; 291 | 292 | #define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ 293 | 294 | #endif /* !_UAPI_CAN_H */ 295 | -------------------------------------------------------------------------------- /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/isotp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 | /* 3 | * linux/can/isotp.h 4 | * 5 | * Definitions for ISO 15765-2 CAN transport protocol sockets 6 | * 7 | * Copyright (c) 2020 Volkswagen Group Electronic Research 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 3. Neither the name of Volkswagen nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior 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 | 44 | #ifndef _UAPI_CAN_ISOTP_H 45 | #define _UAPI_CAN_ISOTP_H 46 | 47 | #include 48 | #include 49 | 50 | #define SOL_CAN_ISOTP (SOL_CAN_BASE + CAN_ISOTP) 51 | 52 | /* for socket options affecting the socket (not the global system) */ 53 | 54 | #define CAN_ISOTP_OPTS 1 /* pass struct can_isotp_options */ 55 | 56 | #define CAN_ISOTP_RECV_FC 2 /* pass struct can_isotp_fc_options */ 57 | 58 | /* sockopts to force stmin timer values for protocol regression tests */ 59 | 60 | #define CAN_ISOTP_TX_STMIN 3 /* pass __u32 value in nano secs */ 61 | /* use this time instead of value */ 62 | /* provided in FC from the receiver */ 63 | 64 | #define CAN_ISOTP_RX_STMIN 4 /* pass __u32 value in nano secs */ 65 | /* ignore received CF frames which */ 66 | /* timestamps differ less than val */ 67 | 68 | #define CAN_ISOTP_LL_OPTS 5 /* pass struct can_isotp_ll_options */ 69 | 70 | struct can_isotp_options { 71 | 72 | __u32 flags; /* set flags for isotp behaviour. */ 73 | /* __u32 value : flags see below */ 74 | 75 | __u32 frame_txtime; /* frame transmission time (N_As/N_Ar) */ 76 | /* __u32 value : time in nano secs */ 77 | 78 | __u8 ext_address; /* set address for extended addressing */ 79 | /* __u8 value : extended address */ 80 | 81 | __u8 txpad_content; /* set content of padding byte (tx) */ 82 | /* __u8 value : content on tx path */ 83 | 84 | __u8 rxpad_content; /* set content of padding byte (rx) */ 85 | /* __u8 value : content on rx path */ 86 | 87 | __u8 rx_ext_address; /* set address for extended addressing */ 88 | /* __u8 value : extended address (rx) */ 89 | }; 90 | 91 | struct can_isotp_fc_options { 92 | 93 | __u8 bs; /* blocksize provided in FC frame */ 94 | /* __u8 value : blocksize. 0 = off */ 95 | 96 | __u8 stmin; /* separation time provided in FC frame */ 97 | /* __u8 value : */ 98 | /* 0x00 - 0x7F : 0 - 127 ms */ 99 | /* 0x80 - 0xF0 : reserved */ 100 | /* 0xF1 - 0xF9 : 100 us - 900 us */ 101 | /* 0xFA - 0xFF : reserved */ 102 | 103 | __u8 wftmax; /* max. number of wait frame transmiss. */ 104 | /* __u8 value : 0 = omit FC N_PDU WT */ 105 | }; 106 | 107 | struct can_isotp_ll_options { 108 | 109 | __u8 mtu; /* generated & accepted CAN frame type */ 110 | /* __u8 value : */ 111 | /* CAN_MTU (16) -> standard CAN 2.0 */ 112 | /* CANFD_MTU (72) -> CAN FD frame */ 113 | 114 | __u8 tx_dl; /* tx link layer data length in bytes */ 115 | /* (configured maximum payload length) */ 116 | /* __u8 value : 8,12,16,20,24,32,48,64 */ 117 | /* => rx path supports all LL_DL values */ 118 | 119 | __u8 tx_flags; /* set into struct canfd_frame.flags */ 120 | /* at frame creation: e.g. CANFD_BRS */ 121 | /* Obsolete when the BRS flag is fixed */ 122 | /* by the CAN netdriver configuration */ 123 | }; 124 | 125 | /* flags for isotp behaviour */ 126 | 127 | #define CAN_ISOTP_LISTEN_MODE 0x0001 /* listen only (do not send FC) */ 128 | #define CAN_ISOTP_EXTEND_ADDR 0x0002 /* enable extended addressing */ 129 | #define CAN_ISOTP_TX_PADDING 0x0004 /* enable CAN frame padding tx path */ 130 | #define CAN_ISOTP_RX_PADDING 0x0008 /* enable CAN frame padding rx path */ 131 | #define CAN_ISOTP_CHK_PAD_LEN 0x0010 /* check received CAN frame padding */ 132 | #define CAN_ISOTP_CHK_PAD_DATA 0x0020 /* check received CAN frame padding */ 133 | #define CAN_ISOTP_HALF_DUPLEX 0x0040 /* half duplex error state handling */ 134 | #define CAN_ISOTP_FORCE_TXSTMIN 0x0080 /* ignore stmin from received FC */ 135 | #define CAN_ISOTP_FORCE_RXSTMIN 0x0100 /* ignore CFs depending on rx stmin */ 136 | #define CAN_ISOTP_RX_EXT_ADDR 0x0200 /* different rx extended addressing */ 137 | #define CAN_ISOTP_WAIT_TX_DONE 0x0400 /* wait for tx completion */ 138 | #define CAN_ISOTP_SF_BROADCAST 0x0800 /* 1-to-N functional addressing */ 139 | #define CAN_ISOTP_CF_BROADCAST 0x1000 /* 1-to-N transmission w/o FC */ 140 | #define CAN_ISOTP_DYN_FC_PARMS 0x2000 /* dynamic FC parameters BS/STmin */ 141 | 142 | /* protocol machine default values */ 143 | 144 | #define CAN_ISOTP_DEFAULT_FLAGS 0 145 | #define CAN_ISOTP_DEFAULT_EXT_ADDRESS 0x00 146 | #define CAN_ISOTP_DEFAULT_PAD_CONTENT 0xCC /* prevent bit-stuffing */ 147 | #define CAN_ISOTP_DEFAULT_FRAME_TXTIME 50000 /* 50 micro seconds */ 148 | #define CAN_ISOTP_DEFAULT_RECV_BS 0 149 | #define CAN_ISOTP_DEFAULT_RECV_STMIN 0x00 150 | #define CAN_ISOTP_DEFAULT_RECV_WFTMAX 0 151 | 152 | /* 153 | * Remark on CAN_ISOTP_DEFAULT_RECV_* values: 154 | * 155 | * We can strongly assume, that the Linux Kernel implementation of 156 | * CAN_ISOTP is capable to run with BS=0, STmin=0 and WFTmax=0. 157 | * But as we like to be able to behave as a commonly available ECU, 158 | * these default settings can be changed via sockopts. 159 | * For that reason the STmin value is intentionally _not_ checked for 160 | * consistency and copied directly into the flow control (FC) frame. 161 | */ 162 | 163 | /* link layer default values => make use of Classical CAN frames */ 164 | 165 | #define CAN_ISOTP_DEFAULT_LL_MTU CAN_MTU 166 | #define CAN_ISOTP_DEFAULT_LL_TX_DL CAN_MAX_DLEN 167 | #define CAN_ISOTP_DEFAULT_LL_TX_FLAGS 0 168 | 169 | /* 170 | * The CAN_ISOTP_DEFAULT_FRAME_TXTIME has become a non-zero value as 171 | * it only makes sense for isotp implementation tests to run without 172 | * a N_As value. As user space applications usually do not set the 173 | * frame_txtime element of struct can_isotp_options the new in-kernel 174 | * default is very likely overwritten with zero when the sockopt() 175 | * CAN_ISOTP_OPTS is invoked. 176 | * To make sure that a N_As value of zero is only set intentional the 177 | * value '0' is now interpreted as 'do not change the current value'. 178 | * When a frame_txtime of zero is required for testing purposes this 179 | * CAN_ISOTP_FRAME_TXTIME_ZERO u32 value has to be set in frame_txtime. 180 | */ 181 | #define CAN_ISOTP_FRAME_TXTIME_ZERO 0xFFFFFFFF 182 | 183 | #endif /* !_UAPI_CAN_ISOTP_H */ 184 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 | # SPDX-FileCopyrightText: 2024 Matthias Weißer 3 | 4 | project('socketcand', 'c', version : '0.6.1') 5 | conf = configuration_data() 6 | 7 | top_inc = include_directories('.', 'include') 8 | deps = [dependency('threads')] 9 | 10 | enable_rc_script = get_option('rc_script') 11 | enable_init_script = get_option('init_script') 12 | 13 | # Check if libconfig is available 14 | enable_libconfig = get_option('libconfig') 15 | if enable_libconfig 16 | conf.set_quoted('HAVE_LIBCONFIG', '1') 17 | deps += dependency('libconfig') 18 | endif 19 | 20 | # Check if libsocketcan is available 21 | enable_libsocketcan = get_option('libsocketcan') 22 | if enable_libsocketcan 23 | conf.set_quoted('HAVE_LIBSOCKETCAN', '1') 24 | deps += dependency('libsocketcan') 25 | endif 26 | 27 | conf.set_quoted('PACKAGE_VERSION', meson.project_version()) 28 | conf.set_quoted('PACKAGE_NAME', meson.project_name()) 29 | conf.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/linux-can/socketcand/issues') 30 | configure_file(output : 'config.h', configuration : conf) 31 | 32 | subdir('src') 33 | subdir('files') 34 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 | # SPDX-FileCopyrightText: 2024 Matthias Weißer 3 | 4 | option('libconfig', type: 'boolean', value: false, description: 'enable support for libconfig') 5 | option('libsocketcan', type: 'boolean', value: false, description: 'enable support for libsocketcan') 6 | option('rc_script', type: 'boolean', value: false, description: 'enable creation of rc.d start script') 7 | option('init_script', type: 'boolean', value: false, description: 'enable creation of init.d start script') 8 | -------------------------------------------------------------------------------- /socketcand.1: -------------------------------------------------------------------------------- 1 | .TH socketcand 1 "JANUARY 2011" Linux "User Manuals" 2 | .SH NAME 3 | socketcand \- The Socket CAN daemon 4 | .SH SYNOPSIS 5 | .B socketcand [-v | --verbose] [-i 6 | .I interfaces 7 | .B | --interfaces 8 | .I interfaces 9 | .B ] [-p 10 | .I port 11 | .B | --port 12 | .I port 13 | .B ] [-l 14 | .I interface 15 | .B | --listen 16 | .I interface 17 | .B ] [-d | --daemon ] [-n | --no-beacon] 18 | .SH DESCRIPTION 19 | .B socketcand 20 | is a daemon that provides access to CAN interfaces on a machine via a network interface. The communication protocol uses a TCP/IP connection and a specific protocol to transfer CAN frames and control commands. 21 | .SH OPTIONS 22 | .IP -v 23 | activates verbose output 24 | .IP -i 25 | comma separated list of SocketCAN interfaces the daemon shall provide access to (e.g. -i can0,vcan1) 26 | .IP -p 27 | port changes the default port (29536) the daemon is listening at 28 | .IP -l 29 | interface changes the default interface (eth0) the daemon will bind to 30 | .IP -d 31 | set this flag if you want log to syslog instead of STDOUT 32 | .IP -n 33 | disables the discovery beacon 34 | .IP -h 35 | prints a help message 36 | -------------------------------------------------------------------------------- /src/beacon.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include "config.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "socketcand.h" 15 | #include "beacon.h" 16 | 17 | void *beacon_loop(void *ptr) 18 | { 19 | int i, n, chars_left, ret; 20 | int udp_socket; 21 | int optval; 22 | char buffer[BEACON_LENGTH]; 23 | char hostname[32]; 24 | 25 | if ((udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 26 | PRINT_ERROR("Failed to create broadcast socket"); 27 | return NULL; 28 | } 29 | 30 | /* Activate broadcast option */ 31 | optval = 1; 32 | ret = setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(int)); 33 | if (ret) { 34 | PRINT_ERROR("Could not activate SO_BROADCAST\n"); 35 | } 36 | 37 | /* Connect the socket */ 38 | if (connect(udp_socket, (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) { 39 | PRINT_ERROR("Failed to connect broadcast socket"); 40 | return NULL; 41 | } 42 | 43 | while (1) { 44 | /* Build the beacon */ 45 | gethostname((char *)&hostname, (size_t)32); 46 | snprintf(buffer, BEACON_LENGTH, "\ncan://%s:%d", 47 | hostname, BEACON_TYPE, description, inet_ntoa(saddr.sin_addr), port); 48 | 49 | for (i = 0; i < interface_count; i++) { 50 | /* Find \0 in beacon buffer */ 51 | for (n = 0;; n++) { 52 | if (buffer[n] == '\0') 53 | break; 54 | } 55 | chars_left = BEACON_LENGTH - n; 56 | 57 | snprintf(buffer + (n * sizeof(char)), chars_left, "", interface_names[i]); 58 | } 59 | 60 | /* Find \0 in beacon buffer */ 61 | for (n = 0;; n++) { 62 | if (buffer[n] == '\0') 63 | break; 64 | } 65 | chars_left = BEACON_LENGTH - n; 66 | 67 | snprintf(buffer + (n * sizeof(char)), chars_left, ""); 68 | 69 | ret = send(udp_socket, buffer, strlen(buffer), 0); 70 | if (ret == -1) { 71 | PRINT_ERROR("Error in beacon send()\n"); 72 | } 73 | sleep(3); 74 | } 75 | 76 | return NULL; 77 | } 78 | -------------------------------------------------------------------------------- /src/beacon.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #define BROADCAST_PORT 42000 4 | #define BEACON_LENGTH 2048 5 | #define BEACON_TYPE "SocketCAN" 6 | #define BEACON_DESCRIPTION "socketcand" 7 | 8 | void *beacon_loop(void *ptr); 9 | -------------------------------------------------------------------------------- /src/canctl.c: -------------------------------------------------------------------------------- 1 | /** 2 | * SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 3 | * SPDX-FileCopyrightText: 2024 Jesus Jorge Serrano 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | int canctl_set_bittiming(const char *bus_name, const char *buff_bittiming_conf, int buff_length) 13 | { 14 | int bitrate, sample_point, tq, prop_seg, phase_seg1, phase_seg2, sjw, brp, items; 15 | 16 | items = sscanf(buff_bittiming_conf, "< %*s B %d %d %d %d %d %d %d %d >", 17 | &bitrate, 18 | &sample_point, 19 | &tq, 20 | &prop_seg, 21 | &phase_seg1, 22 | &phase_seg2, 23 | &sjw, 24 | &brp); 25 | 26 | if (items != 8) { 27 | return -1; 28 | } 29 | 30 | struct can_bittiming bt; 31 | memset(&bt, 0, sizeof(bt)); 32 | if (bitrate >= 0) { 33 | bt.bitrate = bitrate; 34 | } 35 | 36 | if (sample_point >= 0) { 37 | bt.sample_point = sample_point; 38 | } 39 | 40 | if (tq >= 0) { 41 | bt.tq = tq; 42 | } 43 | 44 | if (prop_seg >= 0) { 45 | bt.prop_seg = prop_seg; 46 | } 47 | 48 | if (phase_seg1 >= 0) { 49 | bt.phase_seg1 = phase_seg1; 50 | } 51 | 52 | if (phase_seg2 >= 0) { 53 | bt.phase_seg2 = phase_seg2; 54 | } 55 | 56 | if (sjw >= 0) { 57 | bt.sjw = sjw; 58 | } 59 | 60 | if (brp >= 0) { 61 | bt.brp = brp; 62 | } 63 | 64 | return !(can_do_stop(bus_name) || can_set_bittiming(bus_name, &bt)) ? 0 : -1; 65 | } 66 | 67 | int canctl_set_control_modes(const char *bus_name, const char *buff_control_modes_conf, int buff_length) 68 | { 69 | int listen_only, loopback, three_samples, items; 70 | 71 | items = sscanf(buff_control_modes_conf, "< %*s C %d %d %d >", 72 | &listen_only, &loopback, &three_samples); 73 | 74 | if (items != 3) { 75 | return -1; 76 | } 77 | 78 | struct can_ctrlmode cm = { 79 | .mask = CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_3_SAMPLES, 80 | }; 81 | 82 | if (listen_only) 83 | cm.flags |= CAN_CTRLMODE_LISTENONLY; 84 | if (loopback) 85 | cm.flags |= CAN_CTRLMODE_LOOPBACK; 86 | if (three_samples) 87 | cm.flags |= CAN_CTRLMODE_3_SAMPLES; 88 | 89 | return !(can_do_stop(bus_name) || can_set_ctrlmode(bus_name, &cm)) ? 0 : -1; 90 | } 91 | -------------------------------------------------------------------------------- /src/canctl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 3 | * SPDX-FileCopyrightText: 2024 Jesus Jorge Serrano 4 | */ 5 | 6 | /** 7 | * canctrl.h 8 | * 9 | * Functions to configure the CAN interfaces (bitrates, control modes, etc...) 10 | */ 11 | 12 | #ifndef __CANCTRL_H__ 13 | #define __CANCTRL_H__ 14 | 15 | #include "config.h" 16 | 17 | #ifdef HAVE_LIBSOCKETCAN 18 | 19 | #include 20 | 21 | /** 22 | * canctl_set_bittiming - Set the interface bittiming. 23 | * 24 | * @param bus_name name of the can interface to configure. 25 | * @param buff_bittiming_conf buffer which contains the remaining config of the interface. 26 | * @param buff_length config buffer length. 27 | * 28 | * returns 0 - ok / -1 error 29 | */ 30 | int canctl_set_bittiming(const char *bus_name, const char *buff_bittiming_conf, int buff_length); 31 | 32 | /** 33 | * canctl_start_iface - Start the can interface. 34 | * 35 | * @param bus_name name of the can interface to start. 36 | * 37 | * returns 0 - ok / -1 error 38 | */ 39 | static inline int canctl_start_iface(const char *bus_name) 40 | { 41 | return can_do_start(bus_name); 42 | } 43 | 44 | /** 45 | * canctl_set_control_modes - set up control modes for given interface. 46 | * 47 | * @param bus_name name of the can interface to configure. 48 | * @param buff_control_modes_conf buffer which contains the control modes configuration. 49 | * @param buff_length config buffer length. 50 | * 51 | * returns 0 - ok / -1 error 52 | */ 53 | int canctl_set_control_modes(const char *bus_name, const char *buff_control_modes_conf, int buff_length); 54 | 55 | #else 56 | 57 | #include 58 | 59 | static inline int canctl_set_bittiming(const char *bus_name, const char *buff_bittiming_conf, int buff_length) 60 | { 61 | return -EINVAL; 62 | } 63 | 64 | static inline int canctl_start_iface(const char *bus_name) 65 | { 66 | return 0; 67 | } 68 | 69 | static inline int canctl_set_control_modes(const char *bus_name, const char *buff_control_modes_conf, int buff_length) 70 | { 71 | return -EINVAL; 72 | } 73 | 74 | #endif 75 | #endif 76 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 | # SPDX-FileCopyrightText: 2024 Matthias Weißer 3 | 4 | src = [ 5 | 'socketcand.c', 6 | 'statistics.c', 7 | 'beacon.c', 8 | 'state_bcm.c', 9 | 'state_raw.c', 10 | 'state_isotp.c', 11 | 'state_control.c', 12 | 'state_nobus.c', 13 | ] 14 | 15 | 16 | if enable_libsocketcan 17 | src += 'canctl.c' 18 | endif 19 | 20 | executable('socketcand', 21 | src, 22 | include_directories : top_inc, 23 | dependencies: deps, 24 | install : true, 25 | install_dir : get_option('sbindir') 26 | ) 27 | 28 | executable('socketcandcl', 29 | [ 30 | 'socketcandcl.c', 31 | ], 32 | include_directories : top_inc, 33 | dependencies: deps, 34 | install : true 35 | ) 36 | -------------------------------------------------------------------------------- /src/socketcand.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | /* 3 | * Authors: 4 | * Andre Naujoks (the socket server stuff) 5 | * Oliver Hartkopp (the rest) 6 | * Jan-Niklas Meier (extensions for use with kayak) 7 | * 8 | * Copyright (c) 2002-2009 Volkswagen Group Electronic Research 9 | * All rights reserved. 10 | * 11 | * Send feedback to 12 | * 13 | */ 14 | 15 | #include "config.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #ifdef HAVE_LIBCONFIG 37 | #include 38 | #endif 39 | 40 | #include "socketcand.h" 41 | #include "statistics.h" 42 | #include "beacon.h" 43 | 44 | void print_usage(void); 45 | void sigint(int signum); 46 | void childdied(int signum); 47 | void determine_adress(); 48 | int receive_command(int socket, char *buf); 49 | 50 | int sl, client_socket; 51 | pthread_t beacon_thread, statistics_thread; 52 | char **interface_names; 53 | int interface_count = 0; 54 | int port; 55 | int verbose_flag = 0; 56 | int daemon_flag = 0; 57 | int disable_beacon = 0; 58 | int tcp_quickack_flag = 0; 59 | int state = STATE_NO_BUS; 60 | int previous_state = -1; 61 | char bus_name[MAX_BUSNAME]; 62 | char cmd_buffer[MAXLEN]; 63 | int cmd_index = 0; 64 | char *description; 65 | char *afuxname; 66 | int more_elements = 0; 67 | can_err_mask_t error_mask = 0; 68 | struct sockaddr_in saddr, broadcast_addr; 69 | struct sockaddr_un unaddr; 70 | socklen_t unaddrlen; 71 | struct sockaddr_un remote_unaddr; 72 | socklen_t remote_unaddrlen; 73 | char *interface_string; 74 | 75 | void tcp_quickack(int s) 76 | { 77 | int i = 1; 78 | 79 | if (tcp_quickack_flag) 80 | setsockopt(s, IPPROTO_TCP, TCP_QUICKACK, &i, sizeof(int)); 81 | } 82 | 83 | int state_changed(char *buf, int current_state) 84 | { 85 | if (!strcmp("< rawmode >", buf)) 86 | state = STATE_RAW; 87 | else if (!strcmp("< bcmmode >", buf)) 88 | state = STATE_BCM; 89 | else if (!strcmp("< isotpmode >", buf)) 90 | state = STATE_ISOTP; 91 | else if (!strcmp("< controlmode >", buf)) 92 | state = STATE_CONTROL; 93 | 94 | if (current_state != state) 95 | PRINT_INFO("state changed to %d\n", state); 96 | 97 | return (current_state != state); 98 | } 99 | 100 | char *element_start(char *buf, int element) 101 | { 102 | int len = strlen(buf); 103 | int elem, i; 104 | 105 | /* 106 | * < elem1 elem2 elem3 > 107 | * 108 | * get the position of the requested element as char pointer 109 | */ 110 | 111 | for (i = 0, elem = 0; i < len; i++) { 112 | if (buf[i] == ' ') { 113 | elem++; 114 | 115 | /* step to next non-space */ 116 | while (buf[i] == ' ') 117 | i++; 118 | 119 | if (i >= len) 120 | return NULL; 121 | } 122 | 123 | if (elem == element) 124 | return &buf[i]; 125 | } 126 | return NULL; 127 | } 128 | 129 | int element_length(char *buf, int element) 130 | { 131 | int len; 132 | int j = 0; 133 | char *elembuf; 134 | 135 | /* 136 | * < elem1 elem2 elem3 > 137 | * 138 | * get the length of the requested element in bytes 139 | */ 140 | 141 | elembuf = element_start(buf, element); 142 | if (elembuf == NULL) 143 | return 0; 144 | 145 | len = strlen(elembuf); 146 | 147 | while (j < len && elembuf[j] != ' ') 148 | j++; 149 | 150 | return j; 151 | } 152 | 153 | int asc2nibble(char c) 154 | { 155 | if ((c >= '0') && (c <= '9')) 156 | return c - '0'; 157 | 158 | if ((c >= 'A') && (c <= 'F')) 159 | return c - 'A' + 10; 160 | 161 | if ((c >= 'a') && (c <= 'f')) 162 | return c - 'a' + 10; 163 | 164 | return 16; /* error */ 165 | } 166 | 167 | int main(int argc, char **argv) 168 | { 169 | int i; 170 | struct sockaddr_in clientaddr; 171 | socklen_t sin_size = sizeof(clientaddr); 172 | struct sigaction signalaction, sigint_action; 173 | sigset_t sigset; 174 | int c; 175 | char *busses_string; 176 | #ifdef HAVE_LIBCONFIG 177 | config_t config; 178 | #endif 179 | 180 | /* set default config settings */ 181 | port = PORT; 182 | description = malloc(sizeof(BEACON_DESCRIPTION)); 183 | strcpy(description, BEACON_DESCRIPTION); 184 | interface_string = malloc(strlen(DEFAULT_INTERFACE) + 1); 185 | strcpy(interface_string, DEFAULT_INTERFACE); 186 | busses_string = malloc(strlen(DEFAULT_BUSNAME) + 1); 187 | strcpy(busses_string, DEFAULT_BUSNAME); 188 | afuxname = NULL; 189 | 190 | #ifdef HAVE_LIBCONFIG 191 | /* Read config file before parsing commandline arguments */ 192 | config_init(&config); 193 | if (CONFIG_TRUE == config_read_file(&config, "/etc/socketcand.conf")) { 194 | config_lookup_int(&config, "port", (int *)&port); 195 | config_lookup_string(&config, "description", (const char **)&description); 196 | config_lookup_string(&config, "afuxname", (const char **)&afuxname); 197 | config_lookup_string(&config, "busses", (const char **)&busses_string); 198 | config_lookup_string(&config, "listen", (const char **)&interface_string); 199 | } 200 | #endif 201 | 202 | /* Parse commandline arguments */ 203 | while (1) { 204 | /* getopt_long stores the option index here. */ 205 | int option_index = 0; 206 | static struct option long_options[] = { 207 | { "verbose", no_argument, 0, 'v' }, 208 | { "interfaces", required_argument, 0, 'i' }, 209 | { "port", required_argument, 0, 'p' }, 210 | { "quick-ack", no_argument, 0, 'q' }, 211 | { "afuxname", required_argument, 0, 'u' }, 212 | { "listen", required_argument, 0, 'l' }, 213 | { "daemon", no_argument, 0, 'd' }, 214 | { "version", no_argument, 0, 'z' }, 215 | { "no-beacon", no_argument, 0, 'n' }, 216 | { "error-mask", required_argument, 0, 'e' }, 217 | { "help", no_argument, 0, 'h' }, 218 | { 0, 0, 0, 0 } 219 | }; 220 | 221 | c = getopt_long(argc, argv, "vi:p:qu:l:dzne:h", long_options, &option_index); 222 | 223 | if (c == -1) 224 | break; 225 | 226 | switch (c) { 227 | case 0: 228 | /* If this option set a flag, do nothing else now. */ 229 | if (long_options[option_index].flag != 0) 230 | break; 231 | break; 232 | 233 | case 'v': 234 | puts("Verbose output activated\n"); 235 | verbose_flag = 1; 236 | break; 237 | 238 | case 'i': 239 | busses_string = realloc(busses_string, strlen(optarg) + 1); 240 | strcpy(busses_string, optarg); 241 | break; 242 | 243 | case 'p': 244 | port = atoi(optarg); 245 | break; 246 | 247 | case 'q': 248 | PRINT_VERBOSE("TCP_QUICKACK socket option activated\n"); 249 | tcp_quickack_flag = 1; 250 | break; 251 | 252 | case 'u': 253 | afuxname = realloc(afuxname, strlen(optarg) + 1); 254 | strcpy(afuxname, optarg); 255 | break; 256 | 257 | case 'l': 258 | interface_string = realloc(interface_string, strlen(optarg) + 1); 259 | strcpy(interface_string, optarg); 260 | break; 261 | 262 | case 'd': 263 | daemon_flag = 1; 264 | break; 265 | 266 | case 'z': 267 | printf("socketcand version '%s'\n", PACKAGE_VERSION); 268 | return 0; 269 | 270 | case 'n': 271 | disable_beacon = 1; 272 | break; 273 | 274 | case 'e': 275 | error_mask = strtoul(optarg, NULL, 16); 276 | break; 277 | 278 | case 'h': 279 | print_usage(); 280 | return 0; 281 | 282 | case '?': 283 | print_usage(); 284 | return 0; 285 | 286 | default: 287 | print_usage(); 288 | return -1; 289 | } 290 | } 291 | 292 | /* parse buses */ 293 | for (i = 0;; i++) { 294 | if (busses_string[i] == '\0') 295 | break; 296 | if (busses_string[i] == ',') 297 | interface_count++; 298 | } 299 | interface_count++; 300 | 301 | interface_names = malloc(sizeof(char *) * interface_count); 302 | 303 | interface_names[0] = strtok(busses_string, ","); 304 | 305 | for (i = 1; i < interface_count; i++) { 306 | interface_names[i] = strtok(NULL, ","); 307 | } 308 | 309 | /* if daemon mode was activated the syslog must be opened */ 310 | if (daemon_flag) { 311 | openlog("socketcand", 0, LOG_DAEMON); 312 | } 313 | 314 | sigemptyset(&sigset); 315 | signalaction.sa_handler = &childdied; 316 | signalaction.sa_mask = sigset; 317 | signalaction.sa_flags = 0; 318 | sigaction(SIGCHLD, &signalaction, NULL); /* signal for dying child */ 319 | 320 | sigint_action.sa_handler = &sigint; 321 | sigint_action.sa_mask = sigset; 322 | sigint_action.sa_flags = 0; 323 | sigaction(SIGINT, &sigint_action, NULL); 324 | 325 | determine_adress(); 326 | 327 | if (!disable_beacon) { 328 | PRINT_VERBOSE("creating broadcast thread...\n"); 329 | i = pthread_create(&beacon_thread, NULL, &beacon_loop, NULL); 330 | if (i) 331 | PRINT_ERROR("could not create broadcast thread.\n"); 332 | } else { 333 | PRINT_VERBOSE("Discovery beacon disabled\n"); 334 | } 335 | 336 | if (afuxname) { 337 | /* create PF_UNIX socket */ 338 | if ((sl = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { 339 | perror("unixsocket"); 340 | exit(1); 341 | } 342 | 343 | unaddr.sun_family = AF_UNIX; 344 | if (strlen(afuxname) > sizeof(unaddr.sun_path) - 3) { 345 | printf("afuxname is too long.\n"); 346 | exit(1); 347 | } 348 | 349 | /* when the given afuxname starts with a '/' we assume the path name scheme, e.g. 350 | * /var/run/socketcand or /tmp/socketcand-afunix-socket 351 | * Without the leading '/' we use the string as abstract socket address. 352 | */ 353 | 354 | if (afuxname[0] == '/') { 355 | strcpy(&unaddr.sun_path[0], afuxname); 356 | /* due to the trailing \0 in path name definition we can write the entire struct */ 357 | unaddrlen = sizeof(unaddr); 358 | } else { 359 | strcpy(&unaddr.sun_path[1], afuxname); 360 | unaddr.sun_path[0] = 0; 361 | /* abstract name length definition without trailing \0 but with leading \0 */ 362 | unaddrlen = strlen(afuxname) + sizeof(unaddr.sun_family) + 1; 363 | } 364 | PRINT_VERBOSE("binding unix socket to '%s' with unaddrlen %d\n", afuxname, unaddrlen); 365 | if (bind(sl, (struct sockaddr *)&unaddr, unaddrlen) < 0) { 366 | perror("unixbind"); 367 | exit(-1); 368 | } 369 | 370 | if (listen(sl, 3) != 0) { 371 | perror("unixlisten"); 372 | exit(1); 373 | } 374 | 375 | while (1) { 376 | remote_unaddrlen = sizeof(struct sockaddr_un); 377 | client_socket = accept(sl, (struct sockaddr *)&remote_unaddr, &remote_unaddrlen); 378 | if (client_socket > 0) { 379 | if (fork()) 380 | close(client_socket); 381 | else 382 | break; 383 | } else { 384 | if (errno != EINTR) { 385 | /* 386 | * If the cause for the error was NOT the 387 | * signal from a dying child => give an error 388 | */ 389 | perror("accept"); 390 | exit(1); 391 | } 392 | } 393 | } 394 | 395 | PRINT_VERBOSE("client connected\n"); 396 | 397 | } else { 398 | /* create PF_INET socket */ 399 | 400 | if ((sl = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 401 | perror("inetsocket"); 402 | exit(1); 403 | } 404 | 405 | #ifdef DEBUG 406 | if (verbose_flag) 407 | printf("setting SO_REUSEADDR\n"); 408 | i = 1; 409 | if (setsockopt(sl, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) { 410 | perror("setting SO_REUSEADDR failed"); 411 | } 412 | #endif 413 | 414 | PRINT_VERBOSE("binding socket to %s:%d\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 415 | if (bind(sl, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 416 | perror("bind"); 417 | exit(-1); 418 | } 419 | 420 | if (listen(sl, 3) != 0) { 421 | perror("listen"); 422 | exit(1); 423 | } 424 | 425 | while (1) { 426 | client_socket = accept(sl, (struct sockaddr *)&clientaddr, &sin_size); 427 | if (client_socket > 0) { 428 | int flag; 429 | flag = 1; 430 | setsockopt(client_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); 431 | if (fork()) 432 | close(client_socket); 433 | else 434 | break; 435 | } else { 436 | if (errno != EINTR) { 437 | /* 438 | * If the cause for the error was NOT the 439 | * signal from a dying child => give an error 440 | */ 441 | perror("accept"); 442 | exit(1); 443 | } 444 | } 445 | } 446 | 447 | PRINT_VERBOSE("client connected\n"); 448 | 449 | #ifdef DEBUG 450 | PRINT_VERBOSE("setting SO_REUSEADDR\n"); 451 | i = 1; 452 | if (setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) { 453 | perror("setting SO_REUSEADDR failed"); 454 | } 455 | #endif 456 | } 457 | /* main loop with state machine */ 458 | while (1) { 459 | switch (state) { 460 | case STATE_NO_BUS: 461 | state_nobus(); 462 | break; 463 | case STATE_BCM: 464 | state_bcm(); 465 | break; 466 | case STATE_RAW: 467 | state_raw(); 468 | break; 469 | case STATE_ISOTP: 470 | state_isotp(); 471 | break; 472 | case STATE_CONTROL: 473 | state_control(); 474 | break; 475 | 476 | case STATE_SHUTDOWN: 477 | PRINT_VERBOSE("Closing client connection.\n"); 478 | close(client_socket); 479 | return 0; 480 | } 481 | } 482 | return 0; 483 | } 484 | 485 | /* reads all available data from the socket into the command buffer. 486 | * returns '-1' if no command could be received. 487 | */ 488 | int receive_command(int socket, char *buffer) 489 | { 490 | int i, start, stop; 491 | 492 | /* if there are no more elements in the buffer read more data from the 493 | * socket. 494 | */ 495 | if (!more_elements) { 496 | cmd_index += read(socket, cmd_buffer + cmd_index, MAXLEN - cmd_index); 497 | tcp_quickack(client_socket); 498 | #ifdef DEBUG_RECEPTION 499 | PRINT_VERBOSE("\tRead from socket\n"); 500 | #endif 501 | } 502 | 503 | #ifdef DEBUG_RECEPTION 504 | PRINT_VERBOSE("\tcmd_index now %d\n", cmd_index); 505 | #endif 506 | 507 | more_elements = 0; 508 | 509 | /* find first '<' in string */ 510 | start = -1; 511 | for (i = 0; i < cmd_index; i++) { 512 | if (cmd_buffer[i] == '<') { 513 | start = i; 514 | break; 515 | } 516 | } 517 | 518 | /* 519 | * if there is no '<' in string it makes no sense to keep data because 520 | * we will never be able to construct a command of it 521 | */ 522 | if (start == -1) { 523 | cmd_index = 0; 524 | #ifdef DEBUG_RECEPTION 525 | PRINT_VERBOSE("\tBad data. No element found\n"); 526 | #endif 527 | return -1; 528 | } 529 | 530 | /* check whether the command is completely in the buffer */ 531 | stop = -1; 532 | for (i = 1; i < cmd_index; i++) { 533 | if (cmd_buffer[i] == '>') { 534 | stop = i; 535 | break; 536 | } 537 | } 538 | 539 | /* if no '>' is in the string we have to wait for more data */ 540 | if (stop == -1) { 541 | #ifdef DEBUG_RECEPTION 542 | PRINT_VERBOSE("\tNo full element in the buffer\n"); 543 | #endif 544 | return -1; 545 | } 546 | 547 | #ifdef DEBUG_RECEPTION 548 | PRINT_VERBOSE("\tElement between %d and %d\n", start, stop); 549 | #endif 550 | 551 | /* copy string to new destination and correct cmd_buffer */ 552 | for (i = start; i <= stop; i++) { 553 | buffer[i - start] = cmd_buffer[i]; 554 | } 555 | buffer[i - start] = '\0'; 556 | 557 | #ifdef DEBUG_RECEPTION 558 | PRINT_VERBOSE("\tElement is '%s'\n", buffer); 559 | #endif 560 | 561 | /* if only this message was in the buffer we're done */ 562 | if (stop == cmd_index - 1) { 563 | cmd_index = 0; 564 | } else { 565 | /* check if there is a '<' after the stop */ 566 | start = -1; 567 | for (i = stop; i < cmd_index; i++) { 568 | if (cmd_buffer[i] == '<') { 569 | start = i; 570 | break; 571 | } 572 | } 573 | 574 | /* if there is none it is only garbage we can remove */ 575 | if (start == -1) { 576 | cmd_index = 0; 577 | #ifdef DEBUG_RECEPTION 578 | PRINT_VERBOSE("\tGarbage after the first element in the buffer\n"); 579 | #endif 580 | return 0; 581 | /* otherwise we copy the valid data to the beginning of the buffer */ 582 | } else { 583 | for (i = start; i < cmd_index; i++) { 584 | cmd_buffer[i - start] = cmd_buffer[i]; 585 | } 586 | cmd_index -= start; 587 | 588 | /* check if there is at least one full element in the buffer */ 589 | stop = -1; 590 | for (i = 1; i < cmd_index; i++) { 591 | if (cmd_buffer[i] == '>') { 592 | stop = i; 593 | break; 594 | } 595 | } 596 | 597 | if (stop != -1) { 598 | more_elements = 1; 599 | #ifdef DEBUG_RECEPTION 600 | PRINT_VERBOSE("\tMore than one full element in the buffer.\n"); 601 | #endif 602 | } 603 | } 604 | } 605 | return 0; 606 | } 607 | 608 | void determine_adress() 609 | { 610 | struct ifreq ifr, ifr_mask; 611 | 612 | int probe_socket = socket(AF_INET, SOCK_DGRAM, 0); 613 | 614 | if (probe_socket < 0) { 615 | PRINT_ERROR("Could not create socket!\n"); 616 | exit(-1); 617 | } 618 | 619 | PRINT_VERBOSE("Using network interface '%s'\n", interface_string); 620 | 621 | ifr.ifr_addr.sa_family = AF_INET; 622 | strncpy(ifr.ifr_name, interface_string, IFNAMSIZ - 1); 623 | ioctl(probe_socket, SIOCGIFADDR, &ifr); 624 | 625 | ifr_mask.ifr_addr.sa_family = AF_INET; 626 | strncpy(ifr_mask.ifr_name, interface_string, IFNAMSIZ - 1); 627 | ioctl(probe_socket, SIOCGIFNETMASK, &ifr_mask); 628 | 629 | close(probe_socket); 630 | 631 | PRINT_VERBOSE("Listen address is %s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); 632 | PRINT_VERBOSE("Netmask is %s\n", inet_ntoa(((struct sockaddr_in *)&ifr_mask.ifr_netmask)->sin_addr)); 633 | 634 | /* set listen address */ 635 | saddr.sin_family = AF_INET; 636 | saddr.sin_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; 637 | saddr.sin_port = htons(port); 638 | 639 | /* calculate and set broadcast address */ 640 | broadcast_addr.sin_family = AF_INET; 641 | broadcast_addr.sin_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; 642 | broadcast_addr.sin_addr.s_addr |= ~((struct sockaddr_in *)&ifr_mask.ifr_netmask)->sin_addr.s_addr; 643 | broadcast_addr.sin_port = htons(BROADCAST_PORT); 644 | PRINT_VERBOSE("Broadcast address is %s\n", inet_ntoa(broadcast_addr.sin_addr)); 645 | } 646 | 647 | void print_usage(void) 648 | { 649 | printf("%s Version %s\n", PACKAGE_NAME, PACKAGE_VERSION); 650 | printf("Report bugs to %s\n\n", PACKAGE_BUGREPORT); 651 | printf("Usage: socketcand [-v | --verbose] [-i interfaces | --interfaces interfaces]\n\t\t[-p port | --port port] [-q | --quick-ack]\n\t\t[-l interface | --listen interface] [-u name | --afuxname name]\n\t\t[-e error_mask | --error-mask error_mask]\n\t\t[-n | --no-beacon] [-d | --daemon] [-h | --help]\n\n"); 652 | printf("Options:\n"); 653 | printf("\t-v (activates verbose output to STDOUT)\n"); 654 | printf("\t-i (comma separated list of CAN interfaces the daemon\n\t\tshall provide access to e.g. '-i can0,vcan1' - default: %s)\n", DEFAULT_BUSNAME); 655 | printf("\t-p (changes the default port '%d' the daemon is listening at)\n", PORT); 656 | printf("\t-q (enable TCP_QUICKACK socket option)\n"); 657 | printf("\t-l (changes the default network interface the daemon will\n\t\tbind to - default: %s)\n", DEFAULT_INTERFACE); 658 | printf("\t-u (the AF_UNIX socket path - an abstract name is used when\n\t\tthe leading '/' is missing. N.B. the AF_UNIX binding will\n\t\tsupersede the port/interface settings)\n"); 659 | printf("\t-n (deactivates the discovery beacon)\n"); 660 | printf("\t-e (enable CAN error frames in raw mode providing an\n\t\thexadecimal error mask, e.g: 0x1FFFFFFF)\n"); 661 | printf("\t-d (set this flag if you want log to syslog instead of STDOUT)\n"); 662 | printf("\t-h (prints this message)\n"); 663 | } 664 | 665 | void childdied(int signum) 666 | { 667 | wait(NULL); 668 | } 669 | 670 | void sigint(int signum) 671 | { 672 | if (verbose_flag) 673 | PRINT_ERROR("received SIGINT\n"); 674 | 675 | if (sl != -1) { 676 | if (verbose_flag) 677 | PRINT_INFO("closing listening socket\n"); 678 | if (!close(sl)) 679 | sl = -1; 680 | } 681 | 682 | if (client_socket != -1) { 683 | if (verbose_flag) 684 | PRINT_INFO("closing client socket\n"); 685 | if (!close(client_socket)) 686 | client_socket = -1; 687 | } 688 | 689 | closelog(); 690 | 691 | exit(0); 692 | } 693 | -------------------------------------------------------------------------------- /src/socketcand.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /* max. length for ISO 15765-2 PDUs */ 8 | #define ISOTPLEN 4095 9 | 10 | /* receive buffer length from inet socket for an isotp PDU plus command */ 11 | #define MAXLEN (2 * ISOTPLEN + 100) /* 4095 * 2 + cmd stuff */ 12 | 13 | #define MAX_BUSNAME 16 + 1 14 | #define PORT 29536 15 | #define DEFAULT_INTERFACE "eth0" 16 | #define DEFAULT_BUSNAME "vcan0" 17 | 18 | #define STATE_NO_BUS 0 19 | #define STATE_BCM 1 20 | #define STATE_RAW 2 21 | #define STATE_SHUTDOWN 3 22 | #define STATE_CONTROL 4 23 | #define STATE_ISOTP 5 24 | 25 | #define PRINT_INFO(...) \ 26 | do { \ 27 | if (daemon_flag) \ 28 | syslog(LOG_INFO, __VA_ARGS__); \ 29 | else \ 30 | printf(__VA_ARGS__); \ 31 | } while (0) 32 | #define PRINT_ERROR(...) \ 33 | do { \ 34 | if (daemon_flag) \ 35 | syslog(LOG_ERR, __VA_ARGS__); \ 36 | else \ 37 | fprintf(stderr, __VA_ARGS__); \ 38 | } while (0) 39 | #define PRINT_VERBOSE(...) \ 40 | do { \ 41 | if (verbose_flag && !daemon_flag) \ 42 | printf(__VA_ARGS__); \ 43 | } while (0) 44 | 45 | #ifndef VERSION_STRING 46 | #define VERSION_STRING "SNAPSHOT" 47 | #endif 48 | 49 | #undef DEBUG_RECEPTION 50 | 51 | void state_bcm(void); 52 | void state_raw(void); 53 | void state_isotp(void); 54 | void state_control(void); 55 | void tcp_quickack(int s); 56 | void state_nobus(void); 57 | 58 | extern int client_socket; 59 | extern char **interface_names; 60 | extern int interface_count; 61 | extern int port; 62 | extern int verbose_flag; 63 | extern int daemon_flag; 64 | extern int state; 65 | extern int previous_state; 66 | extern char bus_name[]; 67 | extern char *description; 68 | extern char *afuxname; 69 | extern pthread_t statistics_thread; 70 | extern int more_elements; 71 | extern struct sockaddr_in broadcast_addr; 72 | extern struct sockaddr_in saddr; 73 | extern can_err_mask_t error_mask; 74 | 75 | int receive_command(int socket, char *buf); 76 | int state_changed(char *buf, int current_state); 77 | char *element_start(char *buf, int element); 78 | int element_length(char *buf, int element); 79 | int asc2nibble(char c); -------------------------------------------------------------------------------- /src/socketcandcl.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | /* 3 | * Authors: 4 | * Andre Naujoks 5 | * Oliver Hartkopp 6 | * Jan-Niklas Meier 7 | * Felix Obenhuber 8 | * 9 | * Copyright (c) 2002-2012 Volkswagen Group Electronic Research 10 | * All rights reserved. 11 | * 12 | * Send feedback to 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #define MAXLEN 4000 39 | #define PORT 29536 40 | 41 | #define STATE_INIT 0 42 | #define STATE_CONNECTED 1 43 | #define STATE_SHUTDOWN 2 44 | 45 | #define PRINT_INFO(...) \ 46 | do { \ 47 | printf(__VA_ARGS__); \ 48 | } while (0) 49 | #define PRINT_ERROR(...) \ 50 | do { \ 51 | fprintf(stderr, __VA_ARGS__); \ 52 | } while (0) 53 | #define PRINT_VERBOSE(...) \ 54 | do { \ 55 | printf(__VA_ARGS__); \ 56 | } while (0) 57 | 58 | void print_usage(void); 59 | void sigint(int signum); 60 | int receive_command(int socket, char *buf); 61 | void state_connected(); 62 | 63 | static int server_socket; 64 | static int raw_socket; 65 | static int port; 66 | static int verbose_flag = 0; 67 | static int cmd_index = 0; 68 | static int more_elements = 0; 69 | static int state, previous_state; 70 | static char ldev[IFNAMSIZ]; 71 | static char rdev[IFNAMSIZ]; 72 | static char buf[MAXLEN]; 73 | static char cmd_buffer[MAXLEN]; 74 | 75 | int main(int argc, char **argv) 76 | { 77 | int i; 78 | struct sockaddr_in serveraddr; 79 | struct sockaddr_un serveraddr_un; 80 | socklen_t serveraddr_un_len; 81 | struct hostent *server_ent; 82 | struct sigaction sigint_action; 83 | char buf[MAXLEN]; 84 | char *server_string; 85 | char *afuxname; 86 | 87 | /* set default config settings */ 88 | port = PORT; 89 | strcpy(ldev, "can0"); 90 | strcpy(rdev, "can0"); 91 | server_string = malloc(strlen("localhost")); 92 | afuxname = NULL; 93 | 94 | /* Parse commandline arguments */ 95 | for (;;) { 96 | /* getopt_long stores the option index here. */ 97 | int c, option_index = 0; 98 | static struct option long_options[] = { 99 | { "verbose", no_argument, 0, 'v' }, 100 | { "interfaces", required_argument, 0, 'i' }, 101 | { "afuxname", required_argument, 0, 'u' }, 102 | { "server", required_argument, 0, 's' }, 103 | { "port", required_argument, 0, 'p' }, 104 | { "version", no_argument, 0, 'z' }, 105 | { 0, 0, 0, 0 } 106 | }; 107 | 108 | c = getopt_long(argc, argv, "vhi:p:l:s:u:", long_options, &option_index); 109 | 110 | if (c == -1) 111 | break; 112 | 113 | switch (c) { 114 | case 0: 115 | /* If this option set a flag, do nothing else now. */ 116 | if (long_options[option_index].flag != 0) 117 | break; 118 | break; 119 | 120 | case 'v': 121 | puts("Verbose output activated\n"); 122 | verbose_flag = 1; 123 | break; 124 | 125 | case 'p': 126 | port = atoi(optarg); 127 | break; 128 | 129 | case 'u': 130 | afuxname = realloc(afuxname, strlen(optarg) + 1); 131 | strcpy(afuxname, optarg); 132 | break; 133 | 134 | case 's': 135 | server_string = realloc(server_string, strlen(optarg) + 1); 136 | strcpy(server_string, optarg); 137 | break; 138 | 139 | case 'i': 140 | strcpy(rdev, strtok(optarg, ",")); 141 | strcpy(ldev, strtok(NULL, ",")); 142 | break; 143 | 144 | case 'h': 145 | print_usage(); 146 | return 0; 147 | 148 | case 'z': 149 | printf("socketcandcl version '%s'\n", "0.1"); 150 | return 0; 151 | 152 | case '?': 153 | print_usage(); 154 | return 0; 155 | 156 | default: 157 | print_usage(); 158 | return -1; 159 | } 160 | } 161 | 162 | sigint_action.sa_handler = &sigint; 163 | sigemptyset(&sigint_action.sa_mask); 164 | sigint_action.sa_flags = 0; 165 | sigaction(SIGINT, &sigint_action, NULL); 166 | 167 | if (afuxname) { 168 | /* create AF_UNIX socket */ 169 | server_socket = socket(AF_UNIX, SOCK_STREAM, 0); 170 | if (server_socket < 0) { 171 | perror("unixsocket"); 172 | exit(1); 173 | } 174 | 175 | serveraddr_un.sun_family = AF_UNIX; 176 | if (strlen(afuxname) > sizeof(serveraddr_un.sun_path) - 3) { 177 | printf("afuxname is too long.\n"); 178 | exit(1); 179 | } 180 | 181 | /* when the given afuxname starts with a '/' we assume the path name scheme, e.g. 182 | * /var/run/socketcand or /tmp/socketcand-afunix-socket 183 | * Without the leading '/' we use the string as abstract socket address. 184 | */ 185 | 186 | if (afuxname[0] == '/') { 187 | strcpy(&serveraddr_un.sun_path[0], afuxname); 188 | /* due to the trailing \0 in path name definition we can write the entire struct */ 189 | serveraddr_un_len = sizeof(serveraddr_un); 190 | } else { 191 | strcpy(&serveraddr_un.sun_path[1], afuxname); 192 | serveraddr_un.sun_path[0] = 0; 193 | /* abstract name length definition without trailing \0 but with leading \0 */ 194 | serveraddr_un_len = strlen(afuxname) + sizeof(serveraddr_un.sun_family) + 1; 195 | } 196 | 197 | if (connect(server_socket, (struct sockaddr *)&serveraddr_un, serveraddr_un_len) != 0) { 198 | perror("connect"); 199 | exit(1); 200 | } 201 | } else { 202 | /* create AF_INET socket */ 203 | 204 | server_socket = socket(AF_INET, SOCK_STREAM, 0); 205 | if (server_socket < 0) { 206 | perror("socket"); 207 | exit(1); 208 | } 209 | 210 | memset(&serveraddr, 0, sizeof(serveraddr)); 211 | serveraddr.sin_family = AF_INET; 212 | serveraddr.sin_port = htons(port); 213 | 214 | server_ent = gethostbyname(server_string); 215 | if (server_ent == 0) { 216 | perror(server_string); 217 | exit(1); 218 | } 219 | 220 | memcpy(&(serveraddr.sin_addr.s_addr), server_ent->h_addr, 221 | server_ent->h_length); 222 | 223 | if (connect(server_socket, (struct sockaddr *)&serveraddr, 224 | sizeof(serveraddr)) != 0) { 225 | perror("connect"); 226 | exit(1); 227 | } 228 | } 229 | 230 | for (;;) { 231 | switch (state) { 232 | case STATE_INIT: 233 | /* has to start with a command */ 234 | i = receive_command(server_socket, (char *)&buf); 235 | if (i != 0) { 236 | PRINT_ERROR("Connection terminated while waiting for command.\n"); 237 | state = STATE_SHUTDOWN; 238 | previous_state = STATE_INIT; 239 | break; 240 | } 241 | 242 | if (!strncmp("< hi", buf, 4)) { 243 | /* send open and rawmode command */ 244 | sprintf(buf, "< open %s >", rdev); 245 | send(server_socket, buf, strlen(buf), 0); 246 | 247 | /* send rawmode command */ 248 | strcpy(buf, "< rawmode >"); 249 | send(server_socket, buf, strlen(buf), 0); 250 | state = STATE_CONNECTED; 251 | } 252 | break; 253 | 254 | case STATE_CONNECTED: 255 | state_connected(); 256 | break; 257 | case STATE_SHUTDOWN: 258 | PRINT_VERBOSE("Closing client connection.\n"); 259 | close(server_socket); 260 | return 0; 261 | } 262 | } 263 | return 0; 264 | } 265 | 266 | inline void state_connected() 267 | { 268 | int ret; 269 | static struct can_frame frame; 270 | static struct ifreq ifr; 271 | static struct sockaddr_can addr; 272 | fd_set readfds; 273 | 274 | if (previous_state != STATE_CONNECTED) { 275 | if ((raw_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { 276 | PRINT_ERROR("Error while creating RAW socket %s\n", strerror(errno)); 277 | state = STATE_SHUTDOWN; 278 | return; 279 | } 280 | 281 | strcpy(ifr.ifr_name, ldev); 282 | if (ioctl(raw_socket, SIOCGIFINDEX, &ifr) < 0) { 283 | PRINT_ERROR("Error while searching for bus %s\n", strerror(errno)); 284 | state = STATE_SHUTDOWN; 285 | return; 286 | } 287 | 288 | addr.can_family = AF_CAN; 289 | addr.can_ifindex = ifr.ifr_ifindex; 290 | 291 | /* turn on timestamp */ 292 | const int timestamp_on = 0; 293 | if (setsockopt(raw_socket, SOL_SOCKET, SO_TIMESTAMP, 294 | ×tamp_on, sizeof(timestamp_on)) < 0) { 295 | PRINT_ERROR("Could not enable CAN timestamps\n"); 296 | state = STATE_SHUTDOWN; 297 | return; 298 | } 299 | /* bind socket */ 300 | if (bind(raw_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 301 | PRINT_ERROR("Error while binding RAW socket %s\n", strerror(errno)); 302 | state = STATE_SHUTDOWN; 303 | return; 304 | } 305 | previous_state = STATE_CONNECTED; 306 | } 307 | 308 | if (fork()) { 309 | for (;;) { 310 | FD_ZERO(&readfds); 311 | FD_SET(server_socket, &readfds); 312 | 313 | /* 314 | * Check if there are more elements in the element buffer before 315 | * calling select() and blocking for new packets. 316 | */ 317 | if (!more_elements) { 318 | ret = select(server_socket + 1, &readfds, NULL, NULL, NULL); 319 | 320 | if (ret < 0) { 321 | PRINT_ERROR("Error in select()\n"); 322 | state = STATE_SHUTDOWN; 323 | return; 324 | } 325 | } 326 | 327 | if (FD_ISSET(server_socket, &readfds) || more_elements) { 328 | ret = receive_command(server_socket, (char *)&buf); 329 | if (ret == 0) { 330 | if (!strncmp("< frame", buf, 7)) { 331 | char data_str[2 * 8]; 332 | 333 | sscanf(buf, "< frame %x %*d.%*d %s >", &frame.can_id, 334 | data_str); 335 | 336 | char *s = buf + 7; 337 | for (; ++s;) { 338 | if (*s == ' ') { 339 | break; 340 | } 341 | } 342 | if ((s - buf - 7) > 4) 343 | frame.can_id |= CAN_EFF_FLAG; 344 | 345 | frame.can_dlc = strlen(data_str) / 2; 346 | 347 | sscanf(data_str, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 348 | &frame.data[0], &frame.data[1], 349 | &frame.data[2], &frame.data[3], 350 | &frame.data[4], &frame.data[5], 351 | &frame.data[6], &frame.data[7]); 352 | 353 | ret = write(raw_socket, &frame, sizeof(struct can_frame)); 354 | if (ret < sizeof(struct can_frame)) { 355 | perror("Writing CAN frame to can socket\n"); 356 | } 357 | } 358 | } 359 | } else { 360 | ret = read(server_socket, &buf, 0); 361 | if (ret == -1) { 362 | state = STATE_SHUTDOWN; 363 | return; 364 | } 365 | } 366 | } 367 | } else { 368 | for (;;) { 369 | FD_ZERO(&readfds); 370 | FD_SET(raw_socket, &readfds); 371 | 372 | ret = select(raw_socket + 1, &readfds, NULL, NULL, NULL); 373 | if (ret < 0) { 374 | PRINT_ERROR("Error in select()\n"); 375 | state = STATE_SHUTDOWN; 376 | return; 377 | } 378 | 379 | if (FD_ISSET(raw_socket, &readfds)) { 380 | ret = recv(raw_socket, &frame, sizeof(struct can_frame), MSG_WAITALL); 381 | if (ret < sizeof(struct can_frame)) { 382 | PRINT_ERROR("Error reading frame from RAW socket\n"); 383 | perror("Reading CAN socket\n"); 384 | } else { 385 | if (frame.can_id & CAN_ERR_FLAG) { 386 | /* TODO implement */ 387 | } else if (frame.can_id & CAN_RTR_FLAG) { 388 | /* TODO implement */ 389 | } else { 390 | int i; 391 | if (frame.can_id & CAN_EFF_FLAG) { 392 | ret = sprintf(buf, "< send %08X %d ", 393 | frame.can_id & CAN_EFF_MASK, frame.can_dlc); 394 | } else { 395 | ret = sprintf(buf, "< send %03X %d ", 396 | frame.can_id & CAN_SFF_MASK, frame.can_dlc); 397 | } 398 | for (i = 0; i < frame.can_dlc; i++) { 399 | ret += sprintf(buf + ret, "%02x ", frame.data[i]); 400 | } 401 | sprintf(buf + ret, " >"); 402 | 403 | const size_t len = strlen(buf); 404 | ret = send(server_socket, buf, len, 0); 405 | if (ret < sizeof(len)) { 406 | perror("Error sending TCP frame\n"); 407 | } 408 | } 409 | } 410 | } 411 | } 412 | } 413 | } 414 | 415 | /* reads all available data from the socket into the command buffer. 416 | * returns '-1' if no command could be received. 417 | */ 418 | int receive_command(int socket, char *buffer) 419 | { 420 | int i, start, stop; 421 | 422 | /* if there are no more elements in the buffer read more data from the 423 | * socket. 424 | */ 425 | if (!more_elements) { 426 | cmd_index += read(socket, cmd_buffer + cmd_index, MAXLEN - cmd_index); 427 | } 428 | 429 | more_elements = 0; 430 | 431 | /* find first '<' in string */ 432 | start = -1; 433 | for (i = 0; i < cmd_index; i++) { 434 | if (cmd_buffer[i] == '<') { 435 | start = i; 436 | break; 437 | } 438 | } 439 | 440 | /* 441 | * if there is no '<' in string it makes no sense to keep data because 442 | * we will never be able to construct a command of it 443 | */ 444 | if (start == -1) { 445 | cmd_index = 0; 446 | return -1; 447 | } 448 | 449 | /* check whether the command is completely in the buffer */ 450 | stop = -1; 451 | for (i = 1; i < cmd_index; i++) { 452 | if (cmd_buffer[i] == '>') { 453 | stop = i; 454 | break; 455 | } 456 | } 457 | 458 | /* if no '>' is in the string we have to wait for more data */ 459 | if (stop == -1) { 460 | return -1; 461 | } 462 | 463 | /* copy string to new destination and correct cmd_buffer */ 464 | for (i = start; i <= stop; i++) { 465 | buffer[i - start] = cmd_buffer[i]; 466 | } 467 | buffer[i - start] = '\0'; 468 | 469 | /* if only this message was in the buffer we're done */ 470 | if (stop == cmd_index - 1) { 471 | cmd_index = 0; 472 | } else { 473 | /* check if there is a '<' after the stop */ 474 | start = -1; 475 | for (i = stop; i < cmd_index; i++) { 476 | if (cmd_buffer[i] == '<') { 477 | start = i; 478 | break; 479 | } 480 | } 481 | 482 | /* if there is none it is only garbage we can remove */ 483 | if (start == -1) { 484 | cmd_index = 0; 485 | return 0; 486 | /* otherwise we copy the valid data to the beginning of the buffer */ 487 | } else { 488 | for (i = start; i < cmd_index; i++) { 489 | cmd_buffer[i - start] = cmd_buffer[i]; 490 | } 491 | cmd_index -= start; 492 | 493 | /* check if there is at least one full element in the buffer */ 494 | stop = -1; 495 | for (i = 1; i < cmd_index; i++) { 496 | if (cmd_buffer[i] == '>') { 497 | stop = i; 498 | break; 499 | } 500 | } 501 | 502 | if (stop != -1) { 503 | more_elements = 1; 504 | } 505 | } 506 | } 507 | return 0; 508 | } 509 | 510 | void print_usage(void) 511 | { 512 | printf("Usage: socketcandcl [-v | --verbose] [-i interfaces | --interfaces interfaces]\n\t\t[-s server | --server server ] [-u name | --afuxname name]\n\t\t[-p port | --port port]\n"); 513 | printf("Options:\n"); 514 | printf("\t-v activates verbose output to STDOUT\n"); 515 | printf("\t-s server hostname\n"); 516 | printf("\t-i SocketCAN interfaces to use: device_server,device_client \n"); 517 | printf("\t-p port changes the default port (%d) the client connects to\n", PORT); 518 | printf("\t-u AF_UNIX socket path - abstract name when leading '/' is missing\n"); 519 | printf("\t-h prints this message\n"); 520 | } 521 | 522 | void childdied(int signum) 523 | { 524 | wait(NULL); 525 | } 526 | 527 | void sigint(int signum) 528 | { 529 | if (verbose_flag) 530 | PRINT_ERROR("received SIGINT\n"); 531 | 532 | if (server_socket != -1) { 533 | if (verbose_flag) 534 | PRINT_INFO("closing server socket\n"); 535 | close(server_socket); 536 | } 537 | 538 | if (raw_socket != -1) { 539 | if (verbose_flag) 540 | PRINT_INFO("closing can socket\n"); 541 | close(raw_socket); 542 | } 543 | 544 | exit(0); 545 | } 546 | 547 | /* eof */ 548 | -------------------------------------------------------------------------------- /src/state_bcm.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include "config.h" 4 | #include "socketcand.h" 5 | #include "statistics.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define RXLEN 128 29 | 30 | int sc = -1; 31 | 32 | void state_bcm(void) 33 | { 34 | int i, j, ret; 35 | unsigned long long sec, usec; 36 | struct sockaddr_can caddr; 37 | socklen_t caddrlen = sizeof(caddr); 38 | struct ifreq ifr; 39 | char rxmsg[RXLEN]; 40 | char buf[MAXLEN]; 41 | fd_set readfds; 42 | 43 | struct { 44 | struct bcm_msg_head msg_head; 45 | struct can_frame frame; 46 | } msg; 47 | 48 | struct { 49 | struct bcm_msg_head msg_head; 50 | struct can_frame frame[257]; /* MAX_NFRAMES + MUX MASK */ 51 | } muxmsg; 52 | 53 | if (previous_state != STATE_BCM) { 54 | /* open BCM socket */ 55 | if ((sc = socket(PF_CAN, SOCK_DGRAM, CAN_BCM)) < 0) { 56 | PRINT_ERROR("Error while opening BCM socket %s\n", strerror(errno)); 57 | state = STATE_SHUTDOWN; 58 | return; 59 | } 60 | 61 | memset(&caddr, 0, sizeof(caddr)); 62 | caddr.can_family = PF_CAN; 63 | /* can_ifindex is set to 0 (any device) => need for sendto() */ 64 | 65 | PRINT_VERBOSE("connecting BCM socket...\n"); 66 | if (connect(sc, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) { 67 | PRINT_ERROR("Error while connecting BCM socket %s\n", strerror(errno)); 68 | state = STATE_SHUTDOWN; 69 | return; 70 | } 71 | previous_state = STATE_BCM; 72 | } 73 | 74 | FD_ZERO(&readfds); 75 | FD_SET(sc, &readfds); 76 | FD_SET(client_socket, &readfds); 77 | 78 | /* 79 | * Check if there are more elements in the element buffer before calling select() and 80 | * blocking for new packets. 81 | */ 82 | if (more_elements) { 83 | FD_CLR(sc, &readfds); 84 | } else { 85 | ret = select((sc > client_socket) ? sc + 1 : client_socket + 1, &readfds, NULL, NULL, NULL); 86 | 87 | if (ret < 0) { 88 | PRINT_ERROR("Error in select()\n"); 89 | state = STATE_SHUTDOWN; 90 | return; 91 | } 92 | } 93 | 94 | if (FD_ISSET(sc, &readfds)) { 95 | struct timeval tv; 96 | 97 | ret = recvfrom(sc, &msg, sizeof(msg), 0, 98 | (struct sockaddr *)&caddr, &caddrlen); 99 | 100 | /* read timestamp data */ 101 | if (ioctl(sc, SIOCGSTAMP, &tv) < 0) { 102 | PRINT_ERROR("Could not receive timestamp\n"); 103 | } 104 | 105 | /* Check if this is an error frame */ 106 | if (msg.msg_head.can_id & CAN_ERR_FLAG) { 107 | if (msg.frame.can_dlc != CAN_ERR_DLC) { 108 | PRINT_ERROR("Error frame has a wrong DLC!\n"); 109 | } else { 110 | snprintf(rxmsg, RXLEN, "< error %03X %lld.%06lld ", msg.msg_head.can_id, 111 | (signed long long) tv.tv_sec, (signed long long) tv.tv_usec); 112 | 113 | for (i = 0; i < msg.frame.can_dlc; i++) 114 | snprintf(rxmsg + strlen(rxmsg), RXLEN - strlen(rxmsg), "%02X ", 115 | msg.frame.data[i]); 116 | 117 | snprintf(rxmsg + strlen(rxmsg), RXLEN - strlen(rxmsg), " >"); 118 | send(client_socket, rxmsg, strlen(rxmsg), 0); 119 | tcp_quickack(client_socket); 120 | } 121 | } else { 122 | if (msg.msg_head.can_id & CAN_EFF_FLAG) { 123 | snprintf(rxmsg, RXLEN, "< frame %08X %lld.%06lld ", 124 | msg.msg_head.can_id & CAN_EFF_MASK, 125 | (signed long long) tv.tv_sec, (signed long long) tv.tv_usec); 126 | } else { 127 | snprintf(rxmsg, RXLEN, "< frame %03X %lld.%06lld ", 128 | msg.msg_head.can_id & CAN_SFF_MASK, 129 | (signed long long) tv.tv_sec, (signed long long) tv.tv_usec); 130 | } 131 | 132 | for (i = 0; i < msg.frame.can_dlc; i++) 133 | snprintf(rxmsg + strlen(rxmsg), RXLEN - strlen(rxmsg), "%02X ", 134 | msg.frame.data[i]); 135 | 136 | snprintf(rxmsg + strlen(rxmsg), RXLEN - strlen(rxmsg), " >"); 137 | send(client_socket, rxmsg, strlen(rxmsg), 0); 138 | tcp_quickack(client_socket); 139 | } 140 | } 141 | 142 | if (FD_ISSET(client_socket, &readfds)) { 143 | int items; 144 | 145 | ret = receive_command(client_socket, buf); 146 | 147 | if (ret != 0) { 148 | state = STATE_SHUTDOWN; 149 | return; 150 | } 151 | 152 | /* prepare bcm message settings */ 153 | memset(&msg, 0, sizeof(msg)); 154 | msg.msg_head.nframes = 1; 155 | 156 | strncpy(ifr.ifr_name, bus_name, IFNAMSIZ - 1); 157 | ifr.ifr_name[IFNAMSIZ - 1] = '\0'; 158 | 159 | if (state_changed(buf, state)) { 160 | close(sc); 161 | strcpy(buf, "< ok >"); 162 | send(client_socket, buf, strlen(buf), 0); 163 | tcp_quickack(client_socket); 164 | return; 165 | } 166 | 167 | if (!strcmp("< echo >", buf)) { 168 | send(client_socket, buf, strlen(buf), 0); 169 | tcp_quickack(client_socket); 170 | return; 171 | } 172 | 173 | /* Send a single frame */ 174 | if (!strncmp("< send ", buf, 7)) { 175 | items = sscanf(buf, "< %*s %x %hhu " 176 | "%hhx %hhx %hhx %hhx %hhx %hhx " 177 | "%hhx %hhx >", 178 | &msg.msg_head.can_id, 179 | &msg.frame.can_dlc, 180 | &msg.frame.data[0], 181 | &msg.frame.data[1], 182 | &msg.frame.data[2], 183 | &msg.frame.data[3], 184 | &msg.frame.data[4], 185 | &msg.frame.data[5], 186 | &msg.frame.data[6], 187 | &msg.frame.data[7]); 188 | 189 | if ((items < 2) || 190 | (msg.frame.can_dlc > 8) || 191 | (items != 2 + msg.frame.can_dlc)) { 192 | PRINT_ERROR("Syntax error in send command\n"); 193 | return; 194 | } 195 | 196 | /* < send XXXXXXXX ... > check for extended identifier */ 197 | if (element_length(buf, 2) == 8) 198 | msg.msg_head.can_id |= CAN_EFF_FLAG; 199 | 200 | msg.msg_head.opcode = TX_SEND; 201 | msg.frame.can_id = msg.msg_head.can_id; 202 | 203 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 204 | caddr.can_ifindex = ifr.ifr_ifindex; 205 | sendto(sc, &msg, sizeof(msg), 0, 206 | (struct sockaddr *)&caddr, sizeof(caddr)); 207 | } 208 | /* Add a send job */ 209 | } else if (!strncmp("< add ", buf, 6)) { 210 | 211 | items = sscanf(buf, "< %*s %llu %llu %x %hhu " 212 | "%hhx %hhx %hhx %hhx %hhx %hhx " 213 | "%hhx %hhx >", 214 | &sec, 215 | &usec, 216 | &msg.msg_head.can_id, 217 | &msg.frame.can_dlc, 218 | &msg.frame.data[0], 219 | &msg.frame.data[1], 220 | &msg.frame.data[2], 221 | &msg.frame.data[3], 222 | &msg.frame.data[4], 223 | &msg.frame.data[5], 224 | &msg.frame.data[6], 225 | &msg.frame.data[7]); 226 | 227 | if ((items < 4) || 228 | (msg.frame.can_dlc > 8) || 229 | (items != 4 + msg.frame.can_dlc)) { 230 | PRINT_ERROR("Syntax error in add command.\n"); 231 | return; 232 | } 233 | 234 | /* < add sec usec XXXXXXXX ... > check for extended identifier */ 235 | if (element_length(buf, 4) == 8) 236 | msg.msg_head.can_id |= CAN_EFF_FLAG; 237 | 238 | msg.msg_head.ival2.tv_sec = sec; 239 | msg.msg_head.ival2.tv_usec = usec; 240 | msg.msg_head.opcode = TX_SETUP; 241 | msg.msg_head.flags |= SETTIMER | STARTTIMER; 242 | msg.frame.can_id = msg.msg_head.can_id; 243 | 244 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 245 | caddr.can_ifindex = ifr.ifr_ifindex; 246 | sendto(sc, &msg, sizeof(msg), 0, 247 | (struct sockaddr *)&caddr, sizeof(caddr)); 248 | } 249 | /* Update send job */ 250 | } else if (!strncmp("< update ", buf, 9)) { 251 | items = sscanf(buf, "< %*s %x %hhu " 252 | "%hhx %hhx %hhx %hhx %hhx %hhx " 253 | "%hhx %hhx >", 254 | &msg.msg_head.can_id, 255 | &msg.frame.can_dlc, 256 | &msg.frame.data[0], 257 | &msg.frame.data[1], 258 | &msg.frame.data[2], 259 | &msg.frame.data[3], 260 | &msg.frame.data[4], 261 | &msg.frame.data[5], 262 | &msg.frame.data[6], 263 | &msg.frame.data[7]); 264 | 265 | if ((items < 2) || 266 | (msg.frame.can_dlc > 8) || 267 | (items != 2 + msg.frame.can_dlc)) { 268 | PRINT_ERROR("Syntax error in update send job command\n"); 269 | return; 270 | } 271 | 272 | /* < update XXXXXXXX ... > check for extended identifier */ 273 | if (element_length(buf, 2) == 8) 274 | msg.msg_head.can_id |= CAN_EFF_FLAG; 275 | 276 | msg.msg_head.opcode = TX_SETUP; 277 | msg.msg_head.flags = 0; 278 | msg.frame.can_id = msg.msg_head.can_id; 279 | 280 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 281 | caddr.can_ifindex = ifr.ifr_ifindex; 282 | sendto(sc, &msg, sizeof(msg), 0, 283 | (struct sockaddr *)&caddr, sizeof(caddr)); 284 | } 285 | /* Delete a send job */ 286 | } else if (!strncmp("< delete ", buf, 9)) { 287 | items = sscanf(buf, "< %*s %x >", 288 | &msg.msg_head.can_id); 289 | 290 | if (items != 1) { 291 | PRINT_ERROR("Syntax error in delete job command\n"); 292 | return; 293 | } 294 | 295 | /* < delete XXXXXXXX ... > check for extended identifier */ 296 | if (element_length(buf, 2) == 8) 297 | msg.msg_head.can_id |= CAN_EFF_FLAG; 298 | 299 | msg.msg_head.opcode = TX_DELETE; 300 | msg.frame.can_id = msg.msg_head.can_id; 301 | 302 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 303 | caddr.can_ifindex = ifr.ifr_ifindex; 304 | sendto(sc, &msg, sizeof(msg), 0, 305 | (struct sockaddr *)&caddr, sizeof(caddr)); 306 | } 307 | /* Receive CAN ID with content matching */ 308 | } else if (!strncmp("< filter ", buf, 9)) { 309 | items = sscanf(buf, "< %*s %llu %llu %x %hhu " 310 | "%hhx %hhx %hhx %hhx %hhx %hhx " 311 | "%hhx %hhx >", 312 | &sec, 313 | &usec, 314 | &msg.msg_head.can_id, 315 | &msg.frame.can_dlc, 316 | &msg.frame.data[0], 317 | &msg.frame.data[1], 318 | &msg.frame.data[2], 319 | &msg.frame.data[3], 320 | &msg.frame.data[4], 321 | &msg.frame.data[5], 322 | &msg.frame.data[6], 323 | &msg.frame.data[7]); 324 | 325 | if ((items < 4) || 326 | (msg.frame.can_dlc > 8) || 327 | (items != 4 + msg.frame.can_dlc)) { 328 | PRINT_ERROR("syntax error in filter command.\n"); 329 | return; 330 | } 331 | 332 | /* < filter sec usec XXXXXXXX ... > check for extended identifier */ 333 | if (element_length(buf, 4) == 8) 334 | msg.msg_head.can_id |= CAN_EFF_FLAG; 335 | 336 | msg.msg_head.ival2.tv_sec = sec; 337 | msg.msg_head.ival2.tv_usec = usec; 338 | msg.msg_head.opcode = RX_SETUP; 339 | msg.msg_head.flags = SETTIMER; 340 | msg.frame.can_id = msg.msg_head.can_id; 341 | 342 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 343 | caddr.can_ifindex = ifr.ifr_ifindex; 344 | sendto(sc, &msg, sizeof(msg), 0, 345 | (struct sockaddr *)&caddr, sizeof(caddr)); 346 | } 347 | /* Receive CAN ID with multiplex content matching */ 348 | } else if (!strncmp("< muxfilter ", buf, 12)) { 349 | char *cfptr; 350 | char tmp; 351 | 352 | memset(&muxmsg, 0, sizeof(muxmsg)); 353 | 354 | items = sscanf(buf, "< %*s %llu %llu %x %u ", 355 | &sec, 356 | &usec, 357 | &muxmsg.msg_head.can_id, 358 | &muxmsg.msg_head.nframes); 359 | 360 | if ((items != 4) || 361 | (muxmsg.msg_head.nframes < 2) || 362 | (muxmsg.msg_head.nframes > 257)) { 363 | PRINT_ERROR("syntax error in muxfilter command.\n"); 364 | return; 365 | } 366 | 367 | /* < muxfilter sec usec XXXXXXXX ... > check for extended identifier */ 368 | if (element_length(buf, 4) == 8) 369 | muxmsg.msg_head.can_id |= CAN_EFF_FLAG; 370 | 371 | msg.msg_head.ival2.tv_sec = sec; 372 | msg.msg_head.ival2.tv_usec = usec; 373 | muxmsg.msg_head.opcode = RX_SETUP; 374 | muxmsg.msg_head.flags = SETTIMER; 375 | 376 | cfptr = element_start(buf, 6); 377 | if (cfptr == NULL) { 378 | PRINT_ERROR("failed to find filter data start in muxfilter.\n"); 379 | return; 380 | } 381 | 382 | if (strlen(cfptr) < muxmsg.msg_head.nframes * 24) { 383 | PRINT_ERROR("muxfilter data too short.\n"); 384 | return; 385 | } 386 | 387 | /* copy filter data and mux mask in muxmsg.frame[0] */ 388 | for (i = 0; i < muxmsg.msg_head.nframes; i++) { 389 | 390 | for (j = 0; j < 8; j++) { 391 | 392 | tmp = asc2nibble(cfptr[(24 * i + 3 * j)]); 393 | if (tmp > 0x0F) { 394 | PRINT_ERROR("failed to process filter data in muxfilter.\n"); 395 | return; 396 | } 397 | 398 | muxmsg.frame[i].data[j] = (tmp << 4); 399 | 400 | tmp = asc2nibble(cfptr[(24 * i + 3 * j) + 1]); 401 | if (tmp > 0x0F) { 402 | PRINT_ERROR("failed to process filter data in muxfilter.\n"); 403 | return; 404 | } 405 | 406 | muxmsg.frame[i].data[j] |= tmp; 407 | } 408 | } 409 | 410 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 411 | caddr.can_ifindex = ifr.ifr_ifindex; 412 | sendto(sc, &muxmsg, sizeof(struct bcm_msg_head) + 413 | sizeof(struct can_frame) * muxmsg.msg_head.nframes, 414 | 0, (struct sockaddr *)&caddr, sizeof(caddr)); 415 | } 416 | /* Add a filter */ 417 | } else if (!strncmp("< subscribe ", buf, 12)) { 418 | items = sscanf(buf, "< %*s %llu %llu %x >", 419 | &sec, 420 | &usec, 421 | &msg.msg_head.can_id); 422 | 423 | if (items != 3) { 424 | PRINT_ERROR("syntax error in subscribe command\n"); 425 | return; 426 | } 427 | 428 | /* < subscribe sec usec XXXXXXXX ... > check for extended identifier */ 429 | if (element_length(buf, 4) == 8) 430 | msg.msg_head.can_id |= CAN_EFF_FLAG; 431 | 432 | msg.msg_head.ival2.tv_sec = sec; 433 | msg.msg_head.ival2.tv_usec = usec; 434 | msg.msg_head.opcode = RX_SETUP; 435 | msg.msg_head.flags = RX_FILTER_ID | SETTIMER; 436 | msg.frame.can_id = msg.msg_head.can_id; 437 | 438 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 439 | caddr.can_ifindex = ifr.ifr_ifindex; 440 | sendto(sc, &msg, sizeof(msg), 0, 441 | (struct sockaddr *)&caddr, sizeof(caddr)); 442 | } 443 | /* Delete filter */ 444 | } else if (!strncmp("< unsubscribe ", buf, 14)) { 445 | items = sscanf(buf, "< %*s %x >", 446 | &msg.msg_head.can_id); 447 | 448 | if (items != 1) { 449 | PRINT_ERROR("syntax error in unsubscribe command\n"); 450 | return; 451 | } 452 | 453 | /* < unsubscribe XXXXXXXX ... > check for extended identifier */ 454 | if (element_length(buf, 2) == 8) 455 | msg.msg_head.can_id |= CAN_EFF_FLAG; 456 | 457 | msg.msg_head.opcode = RX_DELETE; 458 | msg.frame.can_id = msg.msg_head.can_id; 459 | 460 | if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { 461 | caddr.can_ifindex = ifr.ifr_ifindex; 462 | sendto(sc, &msg, sizeof(msg), 0, 463 | (struct sockaddr *)&caddr, sizeof(caddr)); 464 | } 465 | } else { 466 | PRINT_ERROR("unknown command '%s'.\n", buf); 467 | strcpy(buf, "< error unknown command >"); 468 | send(client_socket, buf, strlen(buf), 0); 469 | tcp_quickack(client_socket); 470 | } 471 | } 472 | } 473 | -------------------------------------------------------------------------------- /src/state_control.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include "config.h" 4 | #include "socketcand.h" 5 | #include "statistics.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | void state_control(void) 23 | { 24 | char buf[MAXLEN]; 25 | int i, items; 26 | 27 | if (previous_state != STATE_CONTROL) { 28 | PRINT_VERBOSE("starting statistics thread...\n"); 29 | pthread_create(&statistics_thread, NULL, &statistics_loop, NULL); 30 | 31 | previous_state = STATE_CONTROL; 32 | } 33 | 34 | i = receive_command(client_socket, (char *)&buf); 35 | 36 | if (i != 0) { 37 | PRINT_ERROR("Connection terminated while waiting for command.\n"); 38 | state = STATE_SHUTDOWN; 39 | return; 40 | } 41 | 42 | if (state_changed(buf, state)) { 43 | pthread_cancel(statistics_thread); 44 | strcpy(buf, "< ok >"); 45 | send(client_socket, buf, strlen(buf), 0); 46 | tcp_quickack(client_socket); 47 | return; 48 | } 49 | 50 | if (!strcmp("< echo >", buf)) { 51 | send(client_socket, buf, strlen(buf), 0); 52 | tcp_quickack(client_socket); 53 | return; 54 | } 55 | 56 | if (!strncmp("< statistics ", buf, 13)) { 57 | items = sscanf(buf, "< %*s %u >", 58 | &i); 59 | 60 | if (items != 1) { 61 | PRINT_ERROR("Syntax error in statistics command\n"); 62 | } else { 63 | statistics_ival = i; 64 | } 65 | } else { 66 | PRINT_ERROR("unknown command '%s'.\n", buf); 67 | strcpy(buf, "< error unknown command >"); 68 | send(client_socket, buf, strlen(buf), 0); 69 | tcp_quickack(client_socket); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/state_isotp.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include "config.h" 4 | #include "socketcand.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | int si = -1; 28 | 29 | void state_isotp(void) 30 | { 31 | int i, items, ret; 32 | 33 | struct sockaddr_can addr; 34 | struct ifreq ifr; 35 | static struct can_isotp_options opts; 36 | static struct can_isotp_fc_options fcopts; 37 | 38 | char rxmsg[MAXLEN]; /* can to inet */ 39 | char buf[MAXLEN]; /* inet commands to can */ 40 | unsigned char isobuf[ISOTPLEN + 1]; /* binary buffer for isotp socket */ 41 | unsigned char tmp; 42 | fd_set readfds; 43 | 44 | while (previous_state != STATE_ISOTP) { 45 | ret = receive_command(client_socket, buf); 46 | if (ret != 0) { 47 | state = STATE_SHUTDOWN; 48 | return; 49 | } 50 | 51 | strncpy(ifr.ifr_name, bus_name, IFNAMSIZ - 1); 52 | ifr.ifr_name[IFNAMSIZ - 1] = '\0'; 53 | 54 | if (state_changed(buf, state)) { 55 | /* ensure proper handling in other states */ 56 | previous_state = STATE_ISOTP; 57 | strcpy(buf, "< ok >"); 58 | send(client_socket, buf, strlen(buf), 0); 59 | tcp_quickack(client_socket); 60 | return; 61 | } 62 | 63 | if (!strcmp("< echo >", buf)) { 64 | send(client_socket, buf, strlen(buf), 0); 65 | tcp_quickack(client_socket); 66 | continue; 67 | } 68 | 69 | memset(&opts, 0, sizeof(opts)); 70 | memset(&fcopts, 0, sizeof(fcopts)); 71 | memset(&addr, 0, sizeof(addr)); 72 | 73 | /* get configuration to open the socket */ 74 | if (!strncmp("< isotpconf ", buf, 12)) { 75 | items = sscanf(buf, "< %*s %x %x %x " 76 | "%hhu %hhx %hhu " 77 | "%hhx %hhx %hhx %hhx >", 78 | &addr.can_addr.tp.tx_id, 79 | &addr.can_addr.tp.rx_id, 80 | &opts.flags, 81 | &fcopts.bs, 82 | &fcopts.stmin, 83 | &fcopts.wftmax, 84 | &opts.txpad_content, 85 | &opts.rxpad_content, 86 | &opts.ext_address, 87 | &opts.rx_ext_address); 88 | 89 | /* < isotpconf XXXXXXXX ... > check for extended identifier */ 90 | if (element_length(buf, 2) == 8) 91 | addr.can_addr.tp.tx_id |= CAN_EFF_FLAG; 92 | 93 | if (element_length(buf, 3) == 8) 94 | addr.can_addr.tp.rx_id |= CAN_EFF_FLAG; 95 | 96 | if ((opts.flags & CAN_ISOTP_RX_EXT_ADDR && items < 10) || 97 | (opts.flags & CAN_ISOTP_EXTEND_ADDR && items < 9) || 98 | (opts.flags & CAN_ISOTP_RX_PADDING && items < 8) || 99 | (opts.flags & CAN_ISOTP_TX_PADDING && items < 7) || 100 | (items < 5)) { 101 | PRINT_ERROR("Syntax error in isotpconf command\n"); 102 | /* try it once more */ 103 | continue; 104 | } 105 | 106 | /* open ISOTP socket */ 107 | if ((si = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) { 108 | PRINT_ERROR("Error while opening ISOTP socket %s\n", strerror(errno)); 109 | /* ensure proper handling in other states */ 110 | previous_state = STATE_ISOTP; 111 | state = STATE_SHUTDOWN; 112 | return; 113 | } 114 | 115 | strcpy(ifr.ifr_name, bus_name); 116 | if (ioctl(si, SIOCGIFINDEX, &ifr) < 0) { 117 | PRINT_ERROR("Error while searching for bus %s\n", strerror(errno)); 118 | /* ensure proper handling in other states */ 119 | previous_state = STATE_ISOTP; 120 | state = STATE_SHUTDOWN; 121 | return; 122 | } 123 | 124 | addr.can_family = PF_CAN; 125 | addr.can_ifindex = ifr.ifr_ifindex; 126 | 127 | /* only change the built-in defaults when required */ 128 | if (opts.flags) 129 | setsockopt(si, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)); 130 | 131 | setsockopt(si, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts)); 132 | 133 | PRINT_VERBOSE("binding ISOTP socket...\n"); 134 | if (bind(si, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 135 | PRINT_ERROR("Error while binding ISOTP socket %s\n", strerror(errno)); 136 | /* ensure proper handling in other states */ 137 | previous_state = STATE_ISOTP; 138 | state = STATE_SHUTDOWN; 139 | return; 140 | } 141 | 142 | /* ok we made it and have a proper isotp socket open */ 143 | previous_state = STATE_ISOTP; 144 | } 145 | } /* while */ 146 | 147 | FD_ZERO(&readfds); 148 | FD_SET(si, &readfds); 149 | FD_SET(client_socket, &readfds); 150 | 151 | /* 152 | * Check if there are more elements in the element buffer before calling select() and 153 | * blocking for new packets. 154 | */ 155 | if (more_elements) { 156 | FD_CLR(si, &readfds); 157 | } else { 158 | ret = select((si > client_socket) ? si + 1 : client_socket + 1, &readfds, NULL, NULL, NULL); 159 | if (ret < 0) { 160 | PRINT_ERROR("Error in select()\n"); 161 | return; 162 | } 163 | } 164 | 165 | if (FD_ISSET(si, &readfds)) { 166 | struct timeval tv = { 0 }; 167 | 168 | items = read(si, isobuf, ISOTPLEN); 169 | 170 | /* read timestamp data */ 171 | if (ioctl(si, SIOCGSTAMP, &tv) < 0) { 172 | PRINT_ERROR("Could not receive timestamp\n"); 173 | } 174 | 175 | if (items > 0 && items <= ISOTPLEN) { 176 | int startlen; 177 | 178 | sprintf(rxmsg, "< pdu %lld.%06lld ", (signed long long) tv.tv_sec, 179 | (signed long long) tv.tv_usec); 180 | startlen = strlen(rxmsg); 181 | 182 | for (i = 0; i < items; i++) 183 | sprintf(rxmsg + startlen + 2 * i, "%02X", isobuf[i]); 184 | 185 | sprintf(rxmsg + strlen(rxmsg), " >"); 186 | send(client_socket, rxmsg, strlen(rxmsg), 0); 187 | tcp_quickack(client_socket); 188 | } 189 | } 190 | 191 | if (FD_ISSET(client_socket, &readfds)) { 192 | ret = receive_command(client_socket, buf); 193 | if (ret != 0) { 194 | state = STATE_SHUTDOWN; 195 | return; 196 | } 197 | 198 | if (state_changed(buf, state)) { 199 | close(si); 200 | strcpy(buf, "< ok >"); 201 | send(client_socket, buf, strlen(buf), 0); 202 | tcp_quickack(client_socket); 203 | return; 204 | } 205 | 206 | if (!strcmp("< echo >", buf)) { 207 | send(client_socket, buf, strlen(buf), 0); 208 | tcp_quickack(client_socket); 209 | return; 210 | } 211 | 212 | if (!strncmp("< sendpdu ", buf, 10)) { 213 | items = element_length(buf, 2); 214 | if (items & 1) { 215 | PRINT_ERROR("odd number of ASCII Hex values\n"); 216 | return; 217 | } 218 | 219 | items /= 2; 220 | if (items > ISOTPLEN) { 221 | PRINT_ERROR("PDU too long\n"); 222 | return; 223 | } 224 | 225 | for (i = 0; i < items; i++) { 226 | tmp = asc2nibble(buf[(2 * i) + 10]); 227 | if (tmp > 0x0F) 228 | return; 229 | isobuf[i] = (tmp << 4); 230 | tmp = asc2nibble(buf[(2 * i) + 11]); 231 | if (tmp > 0x0F) 232 | return; 233 | isobuf[i] |= tmp; 234 | } 235 | 236 | ret = write(si, isobuf, items); 237 | if (ret != items) { 238 | PRINT_ERROR("Error in write()\n"); 239 | state = STATE_SHUTDOWN; 240 | return; 241 | } 242 | } else { 243 | PRINT_ERROR("unknown command '%s'.\n", buf); 244 | strcpy(buf, "< error unknown command >"); 245 | send(client_socket, buf, strlen(buf), 0); 246 | tcp_quickack(client_socket); 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/state_nobus.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include "canctl.h" 4 | #include "config.h" 5 | #include "socketcand.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | static int check_bus(const char *bus_name) 12 | { 13 | int found = 0, i; 14 | 15 | for (i = 0; i < interface_count; i++) { 16 | if (!strcmp(interface_names[i], bus_name)) 17 | found = 1; 18 | } 19 | return found; 20 | } 21 | 22 | void state_nobus(void) 23 | { 24 | int i; 25 | char buf[MAXLEN], op; 26 | 27 | if (previous_state != STATE_NO_BUS) { 28 | strcpy(buf, "< hi >"); 29 | send(client_socket, buf, strlen(buf), 0); 30 | tcp_quickack(client_socket); 31 | previous_state = STATE_NO_BUS; 32 | } 33 | 34 | /* client has to start with a command */ 35 | i = receive_command(client_socket, buf); 36 | if (i != 0) { 37 | PRINT_ERROR("Connection terminated while waiting for command.\n"); 38 | state = STATE_SHUTDOWN; 39 | return; 40 | } 41 | 42 | if (!strncmp("< open ", buf, 7)) { 43 | sscanf(buf, "< open %s>", bus_name); 44 | 45 | /* check if access to this bus is allowed */ 46 | if (!check_bus(bus_name)) { 47 | PRINT_INFO("client tried to access unauthorized bus.\n"); 48 | strcpy(buf, "< error could not open bus >"); 49 | goto shutdown_err; 50 | } 51 | if (canctl_start_iface(bus_name)) { 52 | PRINT_INFO("Error starting CAN interface.\n"); 53 | snprintf(buf, MAXLEN, "< error could not start interface %s >", bus_name); 54 | goto shutdown_err; 55 | } 56 | state = STATE_BCM; 57 | goto return_ok; 58 | } else if (sscanf(buf, "< %s %c ", bus_name, &op) == 2) { 59 | /* check if access to this bus is allowed */ 60 | if (!check_bus(bus_name)) { 61 | PRINT_INFO("client tried to access unauthorized bus.\n"); 62 | strcpy(buf, "< error could not open bus >"); 63 | goto shutdown_err; 64 | } 65 | 66 | /* Check the configuration operation */ 67 | switch (op) { 68 | case 'B': 69 | if (canctl_set_bittiming(bus_name, buf, strlen(buf))) { 70 | PRINT_ERROR("Error configuring bus bittiming.\n"); 71 | snprintf(buf, MAXLEN, "< error configuring interface %s > \n", bus_name); 72 | goto shutdown_err; 73 | } 74 | break; 75 | case 'C': 76 | if (canctl_set_control_modes(bus_name, buf, strlen(buf))) { 77 | PRINT_ERROR("Error configuring bus control modes.\n"); 78 | snprintf(buf, MAXLEN, "< error configuring interface %s > \n", bus_name); 79 | goto shutdown_err; 80 | } 81 | break; 82 | default: 83 | PRINT_ERROR("Configuration operation not supported\n"); 84 | snprintf(buf, MAXLEN, "< configuration operation not supported %c > \n", op); 85 | goto shutdown_err; 86 | break; 87 | } 88 | 89 | goto return_ok; 90 | } else { 91 | PRINT_ERROR("unknown command '%s'.\n", buf); 92 | strcpy(buf, "< error unknown command >"); 93 | send(client_socket, buf, strlen(buf), 0); 94 | tcp_quickack(client_socket); 95 | } 96 | 97 | return_ok: 98 | strcpy(buf, "< ok >"); 99 | send(client_socket, buf, strlen(buf), 0); 100 | tcp_quickack(client_socket); 101 | return; 102 | shutdown_err: 103 | send(client_socket, buf, strlen(buf), 0); 104 | tcp_quickack(client_socket); 105 | state = STATE_SHUTDOWN; 106 | } 107 | -------------------------------------------------------------------------------- /src/state_raw.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include "config.h" 4 | #include "socketcand.h" 5 | #include "statistics.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | static int raw_socket; 27 | static struct ifreq ifr; 28 | static struct sockaddr_can addr; 29 | static struct msghdr msg; 30 | static struct can_frame frame; 31 | static struct iovec iov; 32 | static char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))]; 33 | static struct timeval tv; 34 | static struct cmsghdr *cmsg; 35 | 36 | void state_raw(void) 37 | { 38 | char buf[MAXLEN]; 39 | int i, ret, items; 40 | fd_set readfds; 41 | 42 | if (previous_state != STATE_RAW) { 43 | if ((raw_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { 44 | PRINT_ERROR("Error while creating RAW socket %s\n", strerror(errno)); 45 | state = STATE_SHUTDOWN; 46 | return; 47 | } 48 | 49 | strcpy(ifr.ifr_name, bus_name); 50 | if (ioctl(raw_socket, SIOCGIFINDEX, &ifr) < 0) { 51 | PRINT_ERROR("Error while searching for bus %s\n", strerror(errno)); 52 | state = STATE_SHUTDOWN; 53 | return; 54 | } 55 | 56 | addr.can_family = AF_CAN; 57 | addr.can_ifindex = ifr.ifr_ifindex; 58 | 59 | const int timestamp_on = 1; 60 | if (setsockopt(raw_socket, SOL_SOCKET, SO_TIMESTAMP, ×tamp_on, sizeof(timestamp_on)) < 0) { 61 | PRINT_ERROR("Could not enable CAN timestamps\n"); 62 | state = STATE_SHUTDOWN; 63 | return; 64 | } 65 | 66 | if (error_mask != 0) { 67 | can_err_mask_t err_mask = (error_mask & CAN_ERR_MASK); 68 | if (setsockopt(raw_socket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask)) < 0) { 69 | PRINT_ERROR("Could not enable CAN_RAW_ERR_FILTER\n"); 70 | state = STATE_SHUTDOWN; 71 | return; 72 | } 73 | } 74 | 75 | if (bind(raw_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 76 | PRINT_ERROR("Error while binding RAW socket %s\n", strerror(errno)); 77 | state = STATE_SHUTDOWN; 78 | return; 79 | } 80 | 81 | iov.iov_base = &frame; 82 | msg.msg_name = &addr; 83 | msg.msg_iov = &iov; 84 | msg.msg_iovlen = 1; 85 | msg.msg_control = &ctrlmsg; 86 | 87 | previous_state = STATE_RAW; 88 | } 89 | 90 | FD_ZERO(&readfds); 91 | FD_SET(raw_socket, &readfds); 92 | FD_SET(client_socket, &readfds); 93 | 94 | /* 95 | * Check if there are more elements in the element buffer before calling select() and 96 | * blocking for new packets. 97 | */ 98 | if (more_elements) { 99 | FD_CLR(raw_socket, &readfds); 100 | } else { 101 | ret = select((raw_socket > client_socket) ? raw_socket + 1 : client_socket + 1, &readfds, NULL, NULL, NULL); 102 | 103 | if (ret < 0) { 104 | PRINT_ERROR("Error in select()\n"); 105 | state = STATE_SHUTDOWN; 106 | return; 107 | } 108 | } 109 | 110 | if (FD_ISSET(raw_socket, &readfds)) { 111 | iov.iov_len = sizeof(frame); 112 | msg.msg_namelen = sizeof(addr); 113 | msg.msg_flags = 0; 114 | msg.msg_controllen = sizeof(ctrlmsg); 115 | 116 | ret = recvmsg(raw_socket, &msg, 0); 117 | if (ret < sizeof(struct can_frame)) { 118 | PRINT_ERROR("Error reading frame from RAW socket\n"); 119 | } else { 120 | /* read timestamp data */ 121 | for (cmsg = CMSG_FIRSTHDR(&msg); 122 | cmsg && (cmsg->cmsg_level == SOL_SOCKET); 123 | cmsg = CMSG_NXTHDR(&msg, cmsg)) { 124 | if (cmsg->cmsg_type == SO_TIMESTAMP) { 125 | tv = *(struct timeval *)CMSG_DATA(cmsg); 126 | } 127 | } 128 | 129 | if (frame.can_id & CAN_ERR_FLAG) { 130 | canid_t class = frame.can_id & CAN_EFF_MASK; 131 | ret = sprintf(buf, "< error %03X %lld.%06lld >", class, 132 | (signed long long) tv.tv_sec, (signed long long) tv.tv_usec); 133 | send(client_socket, buf, strlen(buf), 0); 134 | tcp_quickack(client_socket); 135 | } else if (frame.can_id & CAN_RTR_FLAG) { 136 | /* TODO implement */ 137 | } else { 138 | if (frame.can_id & CAN_EFF_FLAG) { 139 | ret = sprintf(buf, "< frame %08X %lld.%06lld ", frame.can_id & CAN_EFF_MASK, 140 | (signed long long) tv.tv_sec, (signed long long) tv.tv_usec); 141 | } else { 142 | ret = sprintf(buf, "< frame %03X %lld.%06lld ", frame.can_id & CAN_SFF_MASK, 143 | (signed long long) tv.tv_sec, (signed long long) tv.tv_usec); 144 | } 145 | for (i = 0; i < frame.can_dlc; i++) { 146 | ret += sprintf(buf + ret, "%02X", frame.data[i]); 147 | } 148 | sprintf(buf + ret, " >"); 149 | send(client_socket, buf, strlen(buf), 0); 150 | tcp_quickack(client_socket); 151 | } 152 | } 153 | } 154 | 155 | if (FD_ISSET(client_socket, &readfds)) { 156 | ret = receive_command(client_socket, (char *)&buf); 157 | 158 | if (ret == 0) { 159 | if (state_changed(buf, state)) { 160 | close(raw_socket); 161 | strcpy(buf, "< ok >"); 162 | send(client_socket, buf, strlen(buf), 0); 163 | tcp_quickack(client_socket); 164 | return; 165 | } 166 | 167 | if (!strcmp("< echo >", buf)) { 168 | send(client_socket, buf, strlen(buf), 0); 169 | tcp_quickack(client_socket); 170 | return; 171 | } 172 | 173 | /* Send a single frame */ 174 | if (!strncmp("< send ", buf, 7)) { 175 | items = sscanf(buf, "< %*s %x %hhu " 176 | "%hhx %hhx %hhx %hhx %hhx %hhx " 177 | "%hhx %hhx >", 178 | &frame.can_id, 179 | &frame.can_dlc, 180 | &frame.data[0], 181 | &frame.data[1], 182 | &frame.data[2], 183 | &frame.data[3], 184 | &frame.data[4], 185 | &frame.data[5], 186 | &frame.data[6], 187 | &frame.data[7]); 188 | 189 | if ((items < 2) || 190 | (frame.can_dlc > 8) || 191 | (items != 2 + frame.can_dlc)) { 192 | PRINT_ERROR("Syntax error in send command\n"); 193 | return; 194 | } 195 | 196 | /* < send XXXXXXXX ... > check for extended identifier */ 197 | if (element_length(buf, 2) == 8) 198 | frame.can_id |= CAN_EFF_FLAG; 199 | 200 | ret = send(raw_socket, &frame, sizeof(struct can_frame), 0); 201 | if (ret == -1) { 202 | state = STATE_SHUTDOWN; 203 | return; 204 | } 205 | 206 | } else { 207 | PRINT_ERROR("unknown command '%s'\n", buf); 208 | strcpy(buf, "< error unknown command >"); 209 | send(client_socket, buf, strlen(buf), 0); 210 | tcp_quickack(client_socket); 211 | } 212 | } else { 213 | state = STATE_SHUTDOWN; 214 | return; 215 | } 216 | } else { 217 | ret = read(client_socket, &buf, 0); 218 | tcp_quickack(client_socket); 219 | if (ret == -1) { 220 | state = STATE_SHUTDOWN; 221 | return; 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/statistics.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include "config.h" 4 | #include "statistics.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "socketcand.h" 14 | 15 | int statistics_ival = 0; 16 | 17 | static struct timeval last_fired; 18 | 19 | void *statistics_loop(void *ptr) 20 | { 21 | int items, found; 22 | struct timeval current_time; 23 | int elapsed; 24 | char buffer[STAT_BUF_LEN]; 25 | /*int state; 26 | struct can_berr_counter errorcnt;*/ 27 | FILE *proc_net_dev; 28 | struct proc_stat_entry proc_entry; 29 | char line[PROC_LINESIZE]; 30 | 31 | gettimeofday(&last_fired, 0); 32 | 33 | while (1) { 34 | /* check if statistics are enabled */ 35 | if (statistics_ival == 0) { 36 | sleep(1); 37 | continue; 38 | } 39 | 40 | /* read /proc/net/dev */ 41 | proc_net_dev = fopen("/proc/net/dev", "r"); 42 | if (proc_net_dev == NULL) { 43 | PRINT_ERROR("could not open /proc/net/dev"); 44 | sleep(1); 45 | continue; 46 | } 47 | 48 | found = 0; 49 | while (1) { 50 | if (fgets(line, PROC_LINESIZE, proc_net_dev) == NULL) 51 | break; 52 | 53 | /* extract name */ 54 | char *s = (char *)&line; 55 | char *name = strsep(&s, ":"); 56 | if (s == NULL) { /* no : in line */ 57 | continue; 58 | } 59 | 60 | /* remove heading whitespace */ 61 | int pos = 0; 62 | for (; pos < strlen(name); pos++) 63 | if (name[pos] != ' ') 64 | break; 65 | name += pos; 66 | 67 | /* do we care for this device? */ 68 | if (strcmp(bus_name, name)) 69 | continue; 70 | 71 | items = sscanf(s, " %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 72 | &proc_entry.rbytes, 73 | &proc_entry.rpackets, 74 | &proc_entry.rerrs, 75 | &proc_entry.rdrop, 76 | &proc_entry.rfifo, 77 | &proc_entry.rframe, 78 | &proc_entry.rcompressed, 79 | &proc_entry.rmulticast, 80 | &proc_entry.tbytes, 81 | &proc_entry.tpackets, 82 | &proc_entry.terrs, 83 | &proc_entry.tdrop, 84 | &proc_entry.tfifo, 85 | &proc_entry.tcolls, 86 | &proc_entry.tcarrier, 87 | &proc_entry.tcompressed); 88 | 89 | if (items == 16) { 90 | found = 1; 91 | break; 92 | } 93 | } 94 | fclose(proc_net_dev); 95 | 96 | /* If we didn't find the device there is something wrong. */ 97 | if (!found) { 98 | PRINT_ERROR("could not find device %s in /proc/net/dev\n", bus_name); 99 | sleep(1); 100 | continue; 101 | } 102 | 103 | gettimeofday(¤t_time, 0); 104 | 105 | elapsed = ((current_time.tv_sec - last_fired.tv_sec) * 1000 + 106 | (current_time.tv_usec - last_fired.tv_usec) / 1000.0) + 0.5; 107 | 108 | if (elapsed >= statistics_ival) { 109 | /* 110 | * TODO this does not work for virtual devices. therefore it is commented out until 111 | * a solution is found to identify virtual CAN devices 112 | */ 113 | /*if( can_get_state( current_entry.bus_name, &state ) ) { 114 | printf( "unable to get state of %s\n", current_entry.bus_name ); 115 | continue; 116 | } 117 | if( can_get_berr_counter( current_entry.bus_name, &errorcnt ) ) { 118 | printf( "unable to get error count of %s\n", current_entry.bus_name ); 119 | continue; 120 | }*/ 121 | 122 | snprintf(buffer, STAT_BUF_LEN, "< stat %u %u %u %u >", 123 | proc_entry.rbytes, 124 | proc_entry.rpackets, 125 | proc_entry.tbytes, 126 | proc_entry.tpackets); 127 | 128 | /* no lock needed here because POSIX send is thread-safe and does locking itself */ 129 | send(client_socket, buffer, strlen(buffer), 0); 130 | tcp_quickack(client_socket); 131 | 132 | last_fired.tv_sec = current_time.tv_sec; 133 | last_fired.tv_usec = current_time.tv_usec; 134 | } 135 | 136 | usleep(10000); 137 | } 138 | 139 | return NULL; 140 | } 141 | -------------------------------------------------------------------------------- /src/statistics.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 | 3 | #include 4 | 5 | #define STAT_BUF_LEN 512 6 | #define PROC_LINESIZE 256 7 | #define PROC_LINECOUNT 32 8 | 9 | extern int statistics_ival; 10 | void *statistics_loop(void *ptr); 11 | 12 | struct proc_stat_entry { 13 | char device_name[6]; 14 | unsigned int rbytes; 15 | unsigned int rpackets; 16 | unsigned int rerrs; 17 | unsigned int rdrop; 18 | unsigned int rfifo; 19 | unsigned int rframe; 20 | unsigned int rcompressed; 21 | unsigned int rmulticast; 22 | unsigned int tbytes; 23 | unsigned int tpackets; 24 | unsigned int terrs; 25 | unsigned int tdrop; 26 | unsigned int tfifo; 27 | unsigned int tcolls; 28 | unsigned int tcarrier; 29 | unsigned int tcompressed; 30 | }; 31 | --------------------------------------------------------------------------------