From 4d2be3830f8d431e855436cc17bcf0a4a69c7679 Mon Sep 17 00:00:00 2001 From: pancake Date: Thu, 16 Sep 2021 03:53:23 -0700 Subject: [PATCH] Initial import of the isotp:// plugin ##io --- dist/plugins-cfg/plugins.def.cfg | 1 + libr/include/r_io.h | 1 + libr/include/r_socket.h | 1 + libr/io/meson.build | 1 + libr/io/p/Makefile | 2 +- libr/io/p/io_isotp.c | 156 +++++++++++++++++++++ libr/io/p/io_shm.c | 2 +- libr/io/p/io_socket.c | 2 +- libr/io/p/isotp.mk | 17 +++ libr/socket/i/can.h | 228 +++++++++++++++++++++++++++++++ libr/socket/i/isotp.h | 130 ++++++++++++++++++ libr/socket/socket.c | 58 ++++++++ 12 files changed, 596 insertions(+), 3 deletions(-) create mode 100644 libr/io/p/io_isotp.c create mode 100644 libr/io/p/isotp.mk create mode 100644 libr/socket/i/can.h create mode 100644 libr/socket/i/isotp.h diff --git a/dist/plugins-cfg/plugins.def.cfg b/dist/plugins-cfg/plugins.def.cfg index b6d3a2edeb..5de673b082 100644 --- a/dist/plugins-cfg/plugins.def.cfg +++ b/dist/plugins-cfg/plugins.def.cfg @@ -271,6 +271,7 @@ io.zip io.r2k io.ar io.fd +io.isotp io.rbuf lang.c lang.v diff --git a/libr/include/r_io.h b/libr/include/r_io.h index 202183f5ff..1ac80983c2 100644 --- a/libr/include/r_io.h +++ b/libr/include/r_io.h @@ -525,6 +525,7 @@ extern RIOPlugin r_io_plugin_winedbg; extern RIOPlugin r_io_plugin_gprobe; extern RIOPlugin r_io_plugin_fd; extern RIOPlugin r_io_plugin_socket; +extern RIOPlugin r_io_plugin_isotp; #if __cplusplus } diff --git a/libr/include/r_socket.h b/libr/include/r_socket.h index 09a0de0163..7c538cc472 100644 --- a/libr/include/r_socket.h +++ b/libr/include/r_socket.h @@ -87,6 +87,7 @@ typedef struct r_socket_http_options { #define R_SOCKET_PROTO_TCP IPPROTO_TCP #define R_SOCKET_PROTO_UDP IPPROTO_UDP +#define R_SOCKET_PROTO_CAN 0xc42b05 #define R_SOCKET_PROTO_UNIX 0x1337 #define R_SOCKET_PROTO_NONE 0 #define R_SOCKET_PROTO_DEFAULT R_SOCKET_PROTO_TCP diff --git a/libr/io/meson.build b/libr/io/meson.build index fab941cb3f..f556e00c80 100644 --- a/libr/io/meson.build +++ b/libr/io/meson.build @@ -71,6 +71,7 @@ endif if host_machine.system() == 'linux' or host_machine.system() == 'android' r_io_sources += [ 'p/io_r2k_linux.c', + 'p/io_isotp.c', ] ## only for shm_open # r_io_deps += meson.get_compiler('c').find_library('rt') diff --git a/libr/io/p/Makefile b/libr/io/p/Makefile index 76ee98b786..11b3432f9f 100644 --- a/libr/io/p/Makefile +++ b/libr/io/p/Makefile @@ -15,7 +15,7 @@ endif all: ${ALL_TARGETS} ALL_TARGETS= -PLUGINS=ptrace.mk debug.mk gdb.mk malloc.mk shm.mk mach.mk w32dbg.mk procpid.mk winkd.mk bochs.mk qnx.mk r2k.mk ar.mk rbuf.mk gprobe.mk +PLUGINS=ptrace.mk debug.mk gdb.mk malloc.mk shm.mk mach.mk w32dbg.mk procpid.mk winkd.mk bochs.mk qnx.mk r2k.mk ar.mk rbuf.mk gprobe.mk isotp.mk #zip.mk #PLUGINS=ptrace.mk debug.mk gdb.mk malloc.mk mach.mk w32dbg.mk procpid.mk include ${PLUGINS} diff --git a/libr/io/p/io_isotp.c b/libr/io/p/io_isotp.c new file mode 100644 index 0000000000..4dc2270c59 --- /dev/null +++ b/libr/io/p/io_isotp.c @@ -0,0 +1,156 @@ +/* radare - LGPL - Copyright 2021 - pancake */ + +#include +#include +#include + +#if __linux__ + +#include "../io_memory.h" +#include +#include +#include + +#include +#include + +#define ISOTPURI "isotp://" + +typedef struct { + RSocket *sc; + int count; +} RIOSocketData; + +static void free_socketdata(RIOSocketData *sd) { + if (sd) { + r_socket_free (sd->sc); + free (sd); + } +} + +static int __write(RIO *io, RIODesc *desc, const ut8 *buf, int count) { + RIOMalloc *mal = (RIOMalloc*)desc->data; + if (mal) { + r_cons_break_push (NULL, NULL); + RSocket *s = ((RIOSocketData*)(mal->data))->sc; + return r_socket_write (s, buf, count); + } + return -1; +} + +static int __read(RIO *io, RIODesc *desc, ut8 *buf, int count) { + RIOMalloc *mal = (RIOMalloc*)desc->data; + if (mal) { + ut64 addr = mal->offset; + r_cons_break_push (NULL, NULL); + RIOSocketData *sdat = mal->data; + RSocket *s = sdat->sc; + ut8 *mem = malloc (4096); + if (mem) { + int c = r_socket_read (s, mem, 4096); + if (c > 0) { + int osz = mal->size; + io_memory_resize (io, desc, mal->size + c); + memcpy (mal->buf + osz, mem, c); + io->corebind.cmdf (io->corebind.core, "f nread_%d %d %d", + sdat->count, c, mal->size); + io->corebind.cmdf (io->corebind.core, "omr 1 %d", mal->size); + sdat->count++; + } + free (mem); + } + r_cons_break_pop (); + mal->offset = addr; + return io_memory_read (io, desc, buf, count); + } + return -1; +} + +static int __close(RIODesc *desc) { + R_FREE (desc->data); + return 0; +} + +static bool __check(RIO *io, const char *pathname, bool many) { + return !strncmp (pathname, ISOTPURI, strlen (ISOTPURI)); +} + +static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) { + if (r_sandbox_enable (false)) { + eprintf ("The " ISOTPURI " uri is not permitted in sandbox mode.\n"); + return NULL; + } + if (!__check (io, pathname, 0)) { + return NULL; + } + RIOMalloc *mal = R_NEW0 (RIOMalloc); + if (!mal) { + return NULL; + } + RIOSocketData *data = R_NEW0 (RIOSocketData); + if (!mal || !data) { + free (mal); + free_socketdata (data); + return NULL; + } + mal->data = data; + mal->buf = calloc (1, 1); + if (!mal->buf) { + free (mal); + free_socketdata (data); + return NULL; + } + mal->size = 1; + mal->offset = 0; + pathname += strlen (ISOTPURI); + + if (*pathname == '?') { + eprintf ("Usage: r2 isotp://interface/source/destination\n"); + } else { + char *host = strdup (pathname); + const char *port = ""; + char *slash = strchr (host, '/'); + if (slash) { + *slash = 0; + port = slash + 1; + } + data->sc = r_socket_new (false); + if (!r_socket_connect (data->sc, host, port, R_SOCKET_PROTO_CAN, 0)) { + eprintf ("Cannot connect\n"); + free (host); + free_socketdata (data); + return NULL; + } + r_socket_block_time (data->sc, false, 0, 0); + free (host); + } + return r_io_desc_new (io, &r_io_plugin_isotp, pathname, R_PERM_RW | rw, mode, mal); +} + +RIOPlugin r_io_plugin_isotp = { + .name = "isotp", + .desc = "Connect using the ISOTP protocol (isotp://interface/srcid/dstid)", + .uris = ISOTPURI, + .license = "MIT", + .open = __open, + .close = __close, + .read = __read, + .seek = io_memory_lseek, + .check = __check, + .write = __write, +}; + +#else +RIOPlugin r_io_plugin_isotp = { + .name = "isotp", + .desc = "shared memory resources (not for this platform)", +}; +#endif + +#ifndef R2_PLUGIN_INCORE +R_API RLibStruct radare_plugin = { + .type = R_LIB_TYPE_IO, + .data = &r_io_plugin_isotp, + .version = R2_VERSION +}; +#endif diff --git a/libr/io/p/io_shm.c b/libr/io/p/io_shm.c index 5439c4f5e7..8450304ea1 100644 --- a/libr/io/p/io_shm.c +++ b/libr/io/p/io_shm.c @@ -144,7 +144,7 @@ RIOPlugin r_io_plugin_shm = { #else RIOPlugin r_io_plugin_shm = { .name = "shm", - .desc = "shared memory resources (not for w32)", + .desc = "shared memory resources (not for this platform)", }; #endif diff --git a/libr/io/p/io_socket.c b/libr/io/p/io_socket.c index b00d9ecdf6..7f0f59650d 100644 --- a/libr/io/p/io_socket.c +++ b/libr/io/p/io_socket.c @@ -93,7 +93,7 @@ static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) { } mal->size = 1; mal->offset = 0; - pathname += strlen ("socket://"); + pathname += strlen (SOCKETURI); if (*pathname == '?') { eprintf ("Usage: $ nc -l -p 9999 ; r2 socket://localhost:9999\n"); diff --git a/libr/io/p/isotp.mk b/libr/io/p/isotp.mk new file mode 100644 index 0000000000..79a0532f6d --- /dev/null +++ b/libr/io/p/isotp.mk @@ -0,0 +1,17 @@ +OBJ_ISOTP=io_isotp.o + +STATIC_OBJ+=${OBJ_ISOTP} +TARGET_ISOTP=io_isotp.${EXT_SO} +ALL_TARGETS+=${TARGET_ISOTP} + +ifeq (${WITHPIC},0) +LINKFLAGS+=../../util/libr_util.a +LINKFLAGS+=../../io/libr_io.a +else +LINKFLAGS+=-L../../util -lr_util +LINKFLAGS+=-L.. -lr_io +endif + +${TARGET_ISOTP}: ${OBJ_ISOTP} + ${CC_LIB} $(call libname,io_isotp) ${CFLAGS} -o ${TARGET_ISOTP} \ + ${LDFLAGS} ${OBJ_ISOTP} ${LINKFLAGS} diff --git a/libr/socket/i/can.h b/libr/socket/i/can.h new file mode 100644 index 0000000000..2584c7e3c4 --- /dev/null +++ b/libr/socket/i/can.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * linux/can.h + * + * Definitions for CAN network layer (socket addr / CAN frame / CAN filter) + * + * Authors: Oliver Hartkopp + * Urs Thuermann + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _CAN_H +#define _CAN_H + +#if 0 +#include +#include +#else +#define __u8 unsigned char +#define __u16 unsigned short +#define __u32 unsigned int +#define __u64 unsigned long long +#define __kernel_sa_family_t unsigned short +#endif + +/* controller area network (CAN) kernel definitions */ + +/* special address description flags for the CAN_ID */ +#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */ +#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */ +#define CAN_ERR_FLAG 0x20000000U /* error message frame */ + +/* valid bits in CAN ID for frame formats */ +#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */ +#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */ +#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */ + +/* + * Controller Area Network Identifier structure + * + * bit 0-28 : CAN identifier (11/29 bit) + * bit 29 : error message frame flag (0 = data frame, 1 = error message) + * bit 30 : remote transmission request flag (1 = rtr frame) + * bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit) + */ +typedef __u32 canid_t; + +#define CAN_SFF_ID_BITS 11 +#define CAN_EFF_ID_BITS 29 + +/* + * Controller Area Network Error Message Frame Mask structure + * + * bit 0-28 : error class mask (see include/uapi/linux/can/error.h) + * bit 29-31 : set to zero + */ +typedef __u32 can_err_mask_t; + +/* CAN payload length and DLC definitions according to ISO 11898-1 */ +#define CAN_MAX_DLC 8 +#define CAN_MAX_DLEN 8 + +/* CAN FD payload length and DLC definitions according to ISO 11898-7 */ +#define CANFD_MAX_DLC 15 +#define CANFD_MAX_DLEN 64 + +/** + * struct can_frame - basic CAN frame structure + * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition + * @can_dlc: frame payload length in byte (0 .. 8) aka data length code + * N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1 + * mapping of the 'data length code' to the real payload length + * @__pad: padding + * @__res0: reserved / padding + * @__res1: reserved / padding + * @data: CAN frame payload (up to 8 byte) + */ +struct can_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + __u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */ + __u8 __pad; /* padding */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ + __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8))); +}; + +/* + * defined bits for canfd_frame.flags + * + * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to + * be set in the CAN frame bitstream on the wire. The EDL bit switch turns + * the CAN controllers bitstream processor into the CAN FD mode which creates + * two new options within the CAN FD frame specification: + * + * Bit Rate Switch - to indicate a second bitrate is/was used for the payload + * Error State Indicator - represents the error state of the transmitting node + * + * As the CANFD_ESI bit is internally generated by the transmitting CAN + * controller only the CANFD_BRS bit is relevant for real CAN controllers when + * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make + * sense for virtual CAN interfaces to test applications with echoed frames. + */ +#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */ +#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */ + +/** + * struct canfd_frame - CAN flexible data rate frame structure + * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition + * @len: frame payload length in byte (0 .. CANFD_MAX_DLEN) + * @flags: additional flags for CAN FD + * @__res0: reserved / padding + * @__res1: reserved / padding + * @data: CAN FD frame payload (up to CANFD_MAX_DLEN byte) + */ +struct canfd_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + __u8 len; /* frame payload length in byte */ + __u8 flags; /* additional flags for CAN FD */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ + __u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8))); +}; + +#define CAN_MTU (sizeof(struct can_frame)) +#define CANFD_MTU (sizeof(struct canfd_frame)) + +/* particular protocols of the protocol family PF_CAN */ +#define CAN_RAW 1 /* RAW sockets */ +#define CAN_BCM 2 /* Broadcast Manager */ +#define CAN_TP16 3 /* VAG Transport Protocol v1.6 */ +#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */ +#define CAN_MCNET 5 /* Bosch MCNet */ +#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */ +#define CAN_J1939 7 /* SAE J1939 */ +#define CAN_NPROTO 8 + +#define SOL_CAN_BASE 100 + +/** + * struct sockaddr_can - the sockaddr structure for CAN sockets + * @can_family: address family number AF_CAN. + * @can_ifindex: CAN network interface index. + * @can_addr: protocol specific address information + */ +struct sockaddr_can { + __kernel_sa_family_t can_family; + int can_ifindex; + union { + /* transport protocol class address information (e.g. ISOTP) */ + struct { canid_t rx_id, tx_id; } tp; + + /* J1939 address information */ + struct { + /* 8 byte name when using dynamic addressing */ + __u64 name; + + /* pgn: + * 8 bit: PS in PDU2 case, else 0 + * 8 bit: PF + * 1 bit: DP + * 1 bit: reserved + */ + __u32 pgn; + + /* 1 byte address */ + __u8 addr; + } j1939; + + /* reserved for future CAN protocols address information */ + } can_addr; +}; + +/** + * struct can_filter - CAN ID based filter in can_register(). + * @can_id: relevant bits of CAN ID which are not masked out. + * @can_mask: CAN mask (see description) + * + * Description: + * A filter matches, when + * + * & mask == can_id & mask + * + * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can + * filter for error message frames (CAN_ERR_FLAG bit set in mask). + */ +struct can_filter { + canid_t can_id; + canid_t can_mask; +}; + +#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ +#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ + +#endif /* !_UAPI_CAN_H */ diff --git a/libr/socket/i/isotp.h b/libr/socket/i/isotp.h new file mode 100644 index 0000000000..5374d0d5a1 --- /dev/null +++ b/libr/socket/i/isotp.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * socketcan/can/isotp.h + * + * Definitions for isotp CAN sockets + * + * Author: Oliver Hartkopp + * Copyright (c) 2008 Volkswagen Group Electronic Research + * All rights reserved. + * + * Send feedback to + * + */ + +#ifndef CAN_ISOTP_H +#define CAN_ISOTP_H + +#include +#include +#include +// #include +#include "can.h" + +#define SOL_CAN_ISOTP (SOL_CAN_BASE + CAN_ISOTP) + +/* for socket options affecting the socket (not the global system) */ + +#define CAN_ISOTP_OPTS 1 /* pass struct can_isotp_options */ + +#define CAN_ISOTP_RECV_FC 2 /* pass struct can_isotp_fc_options */ + +/* sockopts to force stmin timer values for protocol regression tests */ + +#define CAN_ISOTP_TX_STMIN 3 /* pass __u32 value in nano secs */ + /* use this time instead of value */ + /* provided in FC from the receiver */ + +#define CAN_ISOTP_RX_STMIN 4 /* pass __u32 value in nano secs */ + /* ignore received CF frames which */ + /* timestamps differ less than val */ + +#define CAN_ISOTP_LL_OPTS 5 /* pass struct can_isotp_ll_options */ + +struct can_isotp_options { + __u32 flags; /* set flags for isotp behaviour. */ + /* __u32 value : flags see below */ + __u32 frame_txtime; /* frame transmission time (N_As/N_Ar) */ + /* __u32 value : time in nano secs */ + __u8 ext_address; /* set address for extended addressing */ + /* __u8 value : extended address */ + __u8 txpad_content; /* set content of padding byte (tx) */ + /* __u8 value : content on tx path */ + __u8 rxpad_content; /* set content of padding byte (rx) */ + /* __u8 value : content on rx path */ + __u8 rx_ext_address; /* set address for extended addressing */ + /* __u8 value : extended address (rx) */ +}; + +struct can_isotp_fc_options { + __u8 bs; /* blocksize provided in FC frame */ + /* __u8 value : blocksize. 0 = off */ + + __u8 stmin; /* separation time provided in FC frame */ + /* __u8 value : */ + /* 0x00 - 0x7F : 0 - 127 ms */ + /* 0x80 - 0xF0 : reserved */ + /* 0xF1 - 0xF9 : 100 us - 900 us */ + /* 0xFA - 0xFF : reserved */ + + __u8 wftmax; /* max. number of wait frame transmiss. */ + /* __u8 value : 0 = omit FC N_PDU WT */ +}; + +struct can_isotp_ll_options { + __u8 mtu; /* generated & accepted CAN frame type */ + /* __u8 value : */ + /* CAN_MTU (16) -> standard CAN 2.0 */ + /* CANFD_MTU (72) -> CAN FD frame */ + __u8 tx_dl; /* tx link layer data length in bytes */ + /* (configured maximum payload length) */ + /* __u8 value : 8,12,16,20,24,32,48,64 */ + /* => rx path supports all LL_DL values */ + __u8 tx_flags; /* set into struct canfd_frame.flags */ + /* at frame creation: e.g. CANFD_BRS */ + /* Obsolete when the BRS flag is fixed */ + /* by the CAN netdriver configuration */ +}; + +/* flags for isotp behaviour */ + +#define CAN_ISOTP_LISTEN_MODE 0x001 /* listen only (do not send FC) */ +#define CAN_ISOTP_EXTEND_ADDR 0x002 /* enable extended addressing */ +#define CAN_ISOTP_TX_PADDING 0x004 /* enable CAN frame padding tx path */ +#define CAN_ISOTP_RX_PADDING 0x008 /* enable CAN frame padding rx path */ +#define CAN_ISOTP_CHK_PAD_LEN 0x010 /* check received CAN frame padding */ +#define CAN_ISOTP_CHK_PAD_DATA 0x020 /* check received CAN frame padding */ +#define CAN_ISOTP_HALF_DUPLEX 0x040 /* half duplex error state handling */ +#define CAN_ISOTP_FORCE_TXSTMIN 0x080 /* ignore stmin from received FC */ +#define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */ +#define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */ +#define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */ +#define CAN_ISOTP_SF_BROADCAST 0x800 /* 1-to-N functional addressing */ + +/* default values */ + +#define CAN_ISOTP_DEFAULT_FLAGS 0 +#define CAN_ISOTP_DEFAULT_EXT_ADDRESS 0x00 +#define CAN_ISOTP_DEFAULT_PAD_CONTENT 0xCC /* prevent bit-stuffing */ +#define CAN_ISOTP_DEFAULT_FRAME_TXTIME 0 +#define CAN_ISOTP_DEFAULT_RECV_BS 0 +#define CAN_ISOTP_DEFAULT_RECV_STMIN 0x00 +#define CAN_ISOTP_DEFAULT_RECV_WFTMAX 0 + +#define CAN_ISOTP_DEFAULT_LL_MTU CAN_MTU +#define CAN_ISOTP_DEFAULT_LL_TX_DL CAN_MAX_DLEN +#define CAN_ISOTP_DEFAULT_LL_TX_FLAGS 0 + +/* + * Remark on CAN_ISOTP_DEFAULT_RECV_* values: + * + * We can strongly assume, that the Linux Kernel implementation of + * CAN_ISOTP is capable to run with BS=0, STmin=0 and WFTmax=0. + * But as we like to be able to behave as a commonly available ECU, + * these default settings can be changed via sockopts. + * For that reason the STmin value is intentionally _not_ checked for + * consistency and copied directly into the flow control (FC) frame. + * + */ + +#endif diff --git a/libr/socket/socket.c b/libr/socket/socket.c index 17d079c204..deb0e8a433 100644 --- a/libr/socket/socket.c +++ b/libr/socket/socket.c @@ -6,6 +6,10 @@ #include #include +#if __linux__ +#include "i/isotp.h" +#endif + #if EMSCRIPTEN || __wasi__ || defined(__serenity__) #define NETWORK_DISABLED 1 #else @@ -269,6 +273,60 @@ R_API bool r_socket_connect(RSocket *s, const char *host, const char *port, int if (!__connect_unix (s, host)) { return false; } +#endif + } else if (proto == R_SOCKET_PROTO_CAN) { +#if __linux__ + // host: can interface name + // port: src and dst can identifiers + ut32 srcid = 0; + ut32 dstid = 0; + sscanf (port, "0x%x/0x%x", &srcid, &dstid); + // s = socket(PF_CAN, SOCK_RAW, CAN_RAW); + int fd = socket (PF_CAN, SOCK_DGRAM, CAN_ISOTP); + if (fd == -1) { + return false; + } + static struct can_isotp_options opts = { + .txpad_content = 0xcc, + .rxpad_content = 0xcc, + .frame_txtime = 0x1000, + }; + setsockopt (fd, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof (opts)); + static struct can_isotp_fc_options fcopts = { + .stmin = 0xf3 + }; + setsockopt (fd, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof (fcopts)); + static struct can_isotp_ll_options llopts = { + .mtu = 8, + .tx_dl = 8, + }; + setsockopt (fd, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof (llopts)); + + struct ifreq ifr = {0}; + r_str_ncpy (ifr.ifr_name, host, sizeof (ifr.ifr_name)); + if (ioctl (fd, SIOCGIFINDEX, &ifr) == -1) { + r_sys_perror ("ioctl"); + close (fd); + return -1; + } + + struct sockaddr_can addr = {0}; + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + addr.can_addr.tp.rx_id = srcid | 0x80000000; + addr.can_addr.tp.tx_id = dstid | 0x80000000; + + if (bind (fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { + r_sys_perror ("bind"); + close (fd); + return false; + } + s->fd = fd; + s->is_ssl = false; + return true; +#else + eprintf ("Unsupported ISOTP socket protocol\n"); + return false; #endif } else { hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */