162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 262306a36Sopenharmony_ci/* isotp.c - ISO 15765-2 CAN transport protocol for protocol family CAN 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This implementation does not provide ISO-TP specific return values to the 562306a36Sopenharmony_ci * userspace. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * - RX path timeout of data reception leads to -ETIMEDOUT 862306a36Sopenharmony_ci * - RX path SN mismatch leads to -EILSEQ 962306a36Sopenharmony_ci * - RX path data reception with wrong padding leads to -EBADMSG 1062306a36Sopenharmony_ci * - TX path flowcontrol reception timeout leads to -ECOMM 1162306a36Sopenharmony_ci * - TX path flowcontrol reception overflow leads to -EMSGSIZE 1262306a36Sopenharmony_ci * - TX path flowcontrol reception with wrong layout/padding leads to -EBADMSG 1362306a36Sopenharmony_ci * - when a transfer (tx) is on the run the next write() blocks until it's done 1462306a36Sopenharmony_ci * - use CAN_ISOTP_WAIT_TX_DONE flag to block the caller until the PDU is sent 1562306a36Sopenharmony_ci * - as we have static buffers the check whether the PDU fits into the buffer 1662306a36Sopenharmony_ci * is done at FF reception time (no support for sending 'wait frames') 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Copyright (c) 2020 Volkswagen Group Electronic Research 1962306a36Sopenharmony_ci * All rights reserved. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 2262306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 2362306a36Sopenharmony_ci * are met: 2462306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 2562306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 2662306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 2762306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 2862306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 2962306a36Sopenharmony_ci * 3. Neither the name of Volkswagen nor the names of its contributors 3062306a36Sopenharmony_ci * may be used to endorse or promote products derived from this software 3162306a36Sopenharmony_ci * without specific prior written permission. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Alternatively, provided that this notice is retained in full, this 3462306a36Sopenharmony_ci * software may be distributed under the terms of the GNU General 3562306a36Sopenharmony_ci * Public License ("GPL") version 2, in which case the provisions of the 3662306a36Sopenharmony_ci * GPL apply INSTEAD OF those given above. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * The provided data structures and external interfaces from this code 3962306a36Sopenharmony_ci * are not restricted to be used by modules with a GPL compatible license. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 4262306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 4362306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 4462306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 4562306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4662306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 4762306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4862306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 4962306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5062306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 5162306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 5262306a36Sopenharmony_ci * DAMAGE. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#include <linux/module.h> 5662306a36Sopenharmony_ci#include <linux/init.h> 5762306a36Sopenharmony_ci#include <linux/interrupt.h> 5862306a36Sopenharmony_ci#include <linux/spinlock.h> 5962306a36Sopenharmony_ci#include <linux/hrtimer.h> 6062306a36Sopenharmony_ci#include <linux/wait.h> 6162306a36Sopenharmony_ci#include <linux/uio.h> 6262306a36Sopenharmony_ci#include <linux/net.h> 6362306a36Sopenharmony_ci#include <linux/netdevice.h> 6462306a36Sopenharmony_ci#include <linux/socket.h> 6562306a36Sopenharmony_ci#include <linux/if_arp.h> 6662306a36Sopenharmony_ci#include <linux/skbuff.h> 6762306a36Sopenharmony_ci#include <linux/can.h> 6862306a36Sopenharmony_ci#include <linux/can/core.h> 6962306a36Sopenharmony_ci#include <linux/can/skb.h> 7062306a36Sopenharmony_ci#include <linux/can/isotp.h> 7162306a36Sopenharmony_ci#include <linux/slab.h> 7262306a36Sopenharmony_ci#include <net/sock.h> 7362306a36Sopenharmony_ci#include <net/net_namespace.h> 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciMODULE_DESCRIPTION("PF_CAN isotp 15765-2:2016 protocol"); 7662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 7762306a36Sopenharmony_ciMODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>"); 7862306a36Sopenharmony_ciMODULE_ALIAS("can-proto-6"); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define ISOTP_MIN_NAMELEN CAN_REQUIRED_SIZE(struct sockaddr_can, can_addr.tp) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define SINGLE_MASK(id) (((id) & CAN_EFF_FLAG) ? \ 8362306a36Sopenharmony_ci (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \ 8462306a36Sopenharmony_ci (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG)) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* ISO 15765-2:2016 supports more than 4095 byte per ISO PDU as the FF_DL can 8762306a36Sopenharmony_ci * take full 32 bit values (4 Gbyte). We would need some good concept to handle 8862306a36Sopenharmony_ci * this between user space and kernel space. For now set the static buffer to 8962306a36Sopenharmony_ci * something about 8 kbyte to be able to test this new functionality. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci#define DEFAULT_MAX_PDU_SIZE 8300 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* maximum PDU size before ISO 15765-2:2016 extension was 4095 */ 9462306a36Sopenharmony_ci#define MAX_12BIT_PDU_SIZE 4095 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* limit the isotp pdu size from the optional module parameter to 1MByte */ 9762306a36Sopenharmony_ci#define MAX_PDU_SIZE (1025 * 1024U) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic unsigned int max_pdu_size __read_mostly = DEFAULT_MAX_PDU_SIZE; 10062306a36Sopenharmony_cimodule_param(max_pdu_size, uint, 0444); 10162306a36Sopenharmony_ciMODULE_PARM_DESC(max_pdu_size, "maximum isotp pdu size (default " 10262306a36Sopenharmony_ci __stringify(DEFAULT_MAX_PDU_SIZE) ")"); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* N_PCI type values in bits 7-4 of N_PCI bytes */ 10562306a36Sopenharmony_ci#define N_PCI_SF 0x00 /* single frame */ 10662306a36Sopenharmony_ci#define N_PCI_FF 0x10 /* first frame */ 10762306a36Sopenharmony_ci#define N_PCI_CF 0x20 /* consecutive frame */ 10862306a36Sopenharmony_ci#define N_PCI_FC 0x30 /* flow control */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#define N_PCI_SZ 1 /* size of the PCI byte #1 */ 11162306a36Sopenharmony_ci#define SF_PCI_SZ4 1 /* size of SingleFrame PCI including 4 bit SF_DL */ 11262306a36Sopenharmony_ci#define SF_PCI_SZ8 2 /* size of SingleFrame PCI including 8 bit SF_DL */ 11362306a36Sopenharmony_ci#define FF_PCI_SZ12 2 /* size of FirstFrame PCI including 12 bit FF_DL */ 11462306a36Sopenharmony_ci#define FF_PCI_SZ32 6 /* size of FirstFrame PCI including 32 bit FF_DL */ 11562306a36Sopenharmony_ci#define FC_CONTENT_SZ 3 /* flow control content size in byte (FS/BS/STmin) */ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define ISOTP_CHECK_PADDING (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA) 11862306a36Sopenharmony_ci#define ISOTP_ALL_BC_FLAGS (CAN_ISOTP_SF_BROADCAST | CAN_ISOTP_CF_BROADCAST) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* Flow Status given in FC frame */ 12162306a36Sopenharmony_ci#define ISOTP_FC_CTS 0 /* clear to send */ 12262306a36Sopenharmony_ci#define ISOTP_FC_WT 1 /* wait */ 12362306a36Sopenharmony_ci#define ISOTP_FC_OVFLW 2 /* overflow */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define ISOTP_FC_TIMEOUT 1 /* 1 sec */ 12662306a36Sopenharmony_ci#define ISOTP_ECHO_TIMEOUT 2 /* 2 secs */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cienum { 12962306a36Sopenharmony_ci ISOTP_IDLE = 0, 13062306a36Sopenharmony_ci ISOTP_WAIT_FIRST_FC, 13162306a36Sopenharmony_ci ISOTP_WAIT_FC, 13262306a36Sopenharmony_ci ISOTP_WAIT_DATA, 13362306a36Sopenharmony_ci ISOTP_SENDING, 13462306a36Sopenharmony_ci ISOTP_SHUTDOWN, 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistruct tpcon { 13862306a36Sopenharmony_ci u8 *buf; 13962306a36Sopenharmony_ci unsigned int buflen; 14062306a36Sopenharmony_ci unsigned int len; 14162306a36Sopenharmony_ci unsigned int idx; 14262306a36Sopenharmony_ci u32 state; 14362306a36Sopenharmony_ci u8 bs; 14462306a36Sopenharmony_ci u8 sn; 14562306a36Sopenharmony_ci u8 ll_dl; 14662306a36Sopenharmony_ci u8 sbuf[DEFAULT_MAX_PDU_SIZE]; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistruct isotp_sock { 15062306a36Sopenharmony_ci struct sock sk; 15162306a36Sopenharmony_ci int bound; 15262306a36Sopenharmony_ci int ifindex; 15362306a36Sopenharmony_ci canid_t txid; 15462306a36Sopenharmony_ci canid_t rxid; 15562306a36Sopenharmony_ci ktime_t tx_gap; 15662306a36Sopenharmony_ci ktime_t lastrxcf_tstamp; 15762306a36Sopenharmony_ci struct hrtimer rxtimer, txtimer, txfrtimer; 15862306a36Sopenharmony_ci struct can_isotp_options opt; 15962306a36Sopenharmony_ci struct can_isotp_fc_options rxfc, txfc; 16062306a36Sopenharmony_ci struct can_isotp_ll_options ll; 16162306a36Sopenharmony_ci u32 frame_txtime; 16262306a36Sopenharmony_ci u32 force_tx_stmin; 16362306a36Sopenharmony_ci u32 force_rx_stmin; 16462306a36Sopenharmony_ci u32 cfecho; /* consecutive frame echo tag */ 16562306a36Sopenharmony_ci struct tpcon rx, tx; 16662306a36Sopenharmony_ci struct list_head notifier; 16762306a36Sopenharmony_ci wait_queue_head_t wait; 16862306a36Sopenharmony_ci spinlock_t rx_lock; /* protect single thread state machine */ 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic LIST_HEAD(isotp_notifier_list); 17262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(isotp_notifier_lock); 17362306a36Sopenharmony_cistatic struct isotp_sock *isotp_busy_notifier; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic inline struct isotp_sock *isotp_sk(const struct sock *sk) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return (struct isotp_sock *)sk; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic u32 isotp_bc_flags(struct isotp_sock *so) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return so->opt.flags & ISOTP_ALL_BC_FLAGS; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic bool isotp_register_rxid(struct isotp_sock *so) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci /* no broadcast modes => register rx_id for FC frame reception */ 18862306a36Sopenharmony_ci return (isotp_bc_flags(so) == 0); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic enum hrtimer_restart isotp_rx_timer_handler(struct hrtimer *hrtimer) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct isotp_sock *so = container_of(hrtimer, struct isotp_sock, 19462306a36Sopenharmony_ci rxtimer); 19562306a36Sopenharmony_ci struct sock *sk = &so->sk; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (so->rx.state == ISOTP_WAIT_DATA) { 19862306a36Sopenharmony_ci /* we did not get new data frames in time */ 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* report 'connection timed out' */ 20162306a36Sopenharmony_ci sk->sk_err = ETIMEDOUT; 20262306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 20362306a36Sopenharmony_ci sk_error_report(sk); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* reset rx state */ 20662306a36Sopenharmony_ci so->rx.state = ISOTP_IDLE; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return HRTIMER_NORESTART; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct net_device *dev; 21562306a36Sopenharmony_ci struct sk_buff *nskb; 21662306a36Sopenharmony_ci struct canfd_frame *ncf; 21762306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 21862306a36Sopenharmony_ci int can_send_ret; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci nskb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), gfp_any()); 22162306a36Sopenharmony_ci if (!nskb) 22262306a36Sopenharmony_ci return 1; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci dev = dev_get_by_index(sock_net(sk), so->ifindex); 22562306a36Sopenharmony_ci if (!dev) { 22662306a36Sopenharmony_ci kfree_skb(nskb); 22762306a36Sopenharmony_ci return 1; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci can_skb_reserve(nskb); 23162306a36Sopenharmony_ci can_skb_prv(nskb)->ifindex = dev->ifindex; 23262306a36Sopenharmony_ci can_skb_prv(nskb)->skbcnt = 0; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci nskb->dev = dev; 23562306a36Sopenharmony_ci can_skb_set_owner(nskb, sk); 23662306a36Sopenharmony_ci ncf = (struct canfd_frame *)nskb->data; 23762306a36Sopenharmony_ci skb_put_zero(nskb, so->ll.mtu); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* create & send flow control reply */ 24062306a36Sopenharmony_ci ncf->can_id = so->txid; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_TX_PADDING) { 24362306a36Sopenharmony_ci memset(ncf->data, so->opt.txpad_content, CAN_MAX_DLEN); 24462306a36Sopenharmony_ci ncf->len = CAN_MAX_DLEN; 24562306a36Sopenharmony_ci } else { 24662306a36Sopenharmony_ci ncf->len = ae + FC_CONTENT_SZ; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ncf->data[ae] = N_PCI_FC | flowstatus; 25062306a36Sopenharmony_ci ncf->data[ae + 1] = so->rxfc.bs; 25162306a36Sopenharmony_ci ncf->data[ae + 2] = so->rxfc.stmin; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (ae) 25462306a36Sopenharmony_ci ncf->data[0] = so->opt.ext_address; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ncf->flags = so->ll.tx_flags; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci can_send_ret = can_send(nskb, 1); 25962306a36Sopenharmony_ci if (can_send_ret) 26062306a36Sopenharmony_ci pr_notice_once("can-isotp: %s: can_send_ret %pe\n", 26162306a36Sopenharmony_ci __func__, ERR_PTR(can_send_ret)); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci dev_put(dev); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* reset blocksize counter */ 26662306a36Sopenharmony_ci so->rx.bs = 0; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* reset last CF frame rx timestamp for rx stmin enforcement */ 26962306a36Sopenharmony_ci so->lastrxcf_tstamp = ktime_set(0, 0); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* start rx timeout watchdog */ 27262306a36Sopenharmony_ci hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0), 27362306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void isotp_rcv_skb(struct sk_buff *skb, struct sock *sk) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct sockaddr_can *addr = (struct sockaddr_can *)skb->cb; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct sockaddr_can)); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci memset(addr, 0, sizeof(*addr)); 28462306a36Sopenharmony_ci addr->can_family = AF_CAN; 28562306a36Sopenharmony_ci addr->can_ifindex = skb->dev->ifindex; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb) < 0) 28862306a36Sopenharmony_ci kfree_skb(skb); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic u8 padlen(u8 datalen) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci static const u8 plen[] = { 29462306a36Sopenharmony_ci 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0 - 8 */ 29562306a36Sopenharmony_ci 12, 12, 12, 12, /* 9 - 12 */ 29662306a36Sopenharmony_ci 16, 16, 16, 16, /* 13 - 16 */ 29762306a36Sopenharmony_ci 20, 20, 20, 20, /* 17 - 20 */ 29862306a36Sopenharmony_ci 24, 24, 24, 24, /* 21 - 24 */ 29962306a36Sopenharmony_ci 32, 32, 32, 32, 32, 32, 32, 32, /* 25 - 32 */ 30062306a36Sopenharmony_ci 48, 48, 48, 48, 48, 48, 48, 48, /* 33 - 40 */ 30162306a36Sopenharmony_ci 48, 48, 48, 48, 48, 48, 48, 48 /* 41 - 48 */ 30262306a36Sopenharmony_ci }; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (datalen > 48) 30562306a36Sopenharmony_ci return 64; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return plen[datalen]; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* check for length optimization and return 1/true when the check fails */ 31162306a36Sopenharmony_cistatic int check_optimized(struct canfd_frame *cf, int start_index) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci /* for CAN_DL <= 8 the start_index is equal to the CAN_DL as the 31462306a36Sopenharmony_ci * padding would start at this point. E.g. if the padding would 31562306a36Sopenharmony_ci * start at cf.data[7] cf->len has to be 7 to be optimal. 31662306a36Sopenharmony_ci * Note: The data[] index starts with zero. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci if (cf->len <= CAN_MAX_DLEN) 31962306a36Sopenharmony_ci return (cf->len != start_index); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* This relation is also valid in the non-linear DLC range, where 32262306a36Sopenharmony_ci * we need to take care of the minimal next possible CAN_DL. 32362306a36Sopenharmony_ci * The correct check would be (padlen(cf->len) != padlen(start_index)). 32462306a36Sopenharmony_ci * But as cf->len can only take discrete values from 12, .., 64 at this 32562306a36Sopenharmony_ci * point the padlen(cf->len) is always equal to cf->len. 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ci return (cf->len != padlen(start_index)); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/* check padding and return 1/true when the check fails */ 33162306a36Sopenharmony_cistatic int check_pad(struct isotp_sock *so, struct canfd_frame *cf, 33262306a36Sopenharmony_ci int start_index, u8 content) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci int i; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* no RX_PADDING value => check length of optimized frame length */ 33762306a36Sopenharmony_ci if (!(so->opt.flags & CAN_ISOTP_RX_PADDING)) { 33862306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_CHK_PAD_LEN) 33962306a36Sopenharmony_ci return check_optimized(cf, start_index); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* no valid test against empty value => ignore frame */ 34262306a36Sopenharmony_ci return 1; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* check datalength of correctly padded CAN frame */ 34662306a36Sopenharmony_ci if ((so->opt.flags & CAN_ISOTP_CHK_PAD_LEN) && 34762306a36Sopenharmony_ci cf->len != padlen(cf->len)) 34862306a36Sopenharmony_ci return 1; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* check padding content */ 35162306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_CHK_PAD_DATA) { 35262306a36Sopenharmony_ci for (i = start_index; i < cf->len; i++) 35362306a36Sopenharmony_ci if (cf->data[i] != content) 35462306a36Sopenharmony_ci return 1; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void isotp_send_cframe(struct isotp_sock *so); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct sock *sk = &so->sk; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (so->tx.state != ISOTP_WAIT_FC && 36662306a36Sopenharmony_ci so->tx.state != ISOTP_WAIT_FIRST_FC) 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci hrtimer_cancel(&so->txtimer); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if ((cf->len < ae + FC_CONTENT_SZ) || 37262306a36Sopenharmony_ci ((so->opt.flags & ISOTP_CHECK_PADDING) && 37362306a36Sopenharmony_ci check_pad(so, cf, ae + FC_CONTENT_SZ, so->opt.rxpad_content))) { 37462306a36Sopenharmony_ci /* malformed PDU - report 'not a data message' */ 37562306a36Sopenharmony_ci sk->sk_err = EBADMSG; 37662306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 37762306a36Sopenharmony_ci sk_error_report(sk); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci so->tx.state = ISOTP_IDLE; 38062306a36Sopenharmony_ci wake_up_interruptible(&so->wait); 38162306a36Sopenharmony_ci return 1; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* get communication parameters only from the first FC frame */ 38562306a36Sopenharmony_ci if (so->tx.state == ISOTP_WAIT_FIRST_FC) { 38662306a36Sopenharmony_ci so->txfc.bs = cf->data[ae + 1]; 38762306a36Sopenharmony_ci so->txfc.stmin = cf->data[ae + 2]; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* fix wrong STmin values according spec */ 39062306a36Sopenharmony_ci if (so->txfc.stmin > 0x7F && 39162306a36Sopenharmony_ci (so->txfc.stmin < 0xF1 || so->txfc.stmin > 0xF9)) 39262306a36Sopenharmony_ci so->txfc.stmin = 0x7F; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci so->tx_gap = ktime_set(0, 0); 39562306a36Sopenharmony_ci /* add transmission time for CAN frame N_As */ 39662306a36Sopenharmony_ci so->tx_gap = ktime_add_ns(so->tx_gap, so->frame_txtime); 39762306a36Sopenharmony_ci /* add waiting time for consecutive frames N_Cs */ 39862306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_FORCE_TXSTMIN) 39962306a36Sopenharmony_ci so->tx_gap = ktime_add_ns(so->tx_gap, 40062306a36Sopenharmony_ci so->force_tx_stmin); 40162306a36Sopenharmony_ci else if (so->txfc.stmin < 0x80) 40262306a36Sopenharmony_ci so->tx_gap = ktime_add_ns(so->tx_gap, 40362306a36Sopenharmony_ci so->txfc.stmin * 1000000); 40462306a36Sopenharmony_ci else 40562306a36Sopenharmony_ci so->tx_gap = ktime_add_ns(so->tx_gap, 40662306a36Sopenharmony_ci (so->txfc.stmin - 0xF0) 40762306a36Sopenharmony_ci * 100000); 40862306a36Sopenharmony_ci so->tx.state = ISOTP_WAIT_FC; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci switch (cf->data[ae] & 0x0F) { 41262306a36Sopenharmony_ci case ISOTP_FC_CTS: 41362306a36Sopenharmony_ci so->tx.bs = 0; 41462306a36Sopenharmony_ci so->tx.state = ISOTP_SENDING; 41562306a36Sopenharmony_ci /* send CF frame and enable echo timeout handling */ 41662306a36Sopenharmony_ci hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), 41762306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 41862306a36Sopenharmony_ci isotp_send_cframe(so); 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci case ISOTP_FC_WT: 42262306a36Sopenharmony_ci /* start timer to wait for next FC frame */ 42362306a36Sopenharmony_ci hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0), 42462306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci case ISOTP_FC_OVFLW: 42862306a36Sopenharmony_ci /* overflow on receiver side - report 'message too long' */ 42962306a36Sopenharmony_ci sk->sk_err = EMSGSIZE; 43062306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 43162306a36Sopenharmony_ci sk_error_report(sk); 43262306a36Sopenharmony_ci fallthrough; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci default: 43562306a36Sopenharmony_ci /* stop this tx job */ 43662306a36Sopenharmony_ci so->tx.state = ISOTP_IDLE; 43762306a36Sopenharmony_ci wake_up_interruptible(&so->wait); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int isotp_rcv_sf(struct sock *sk, struct canfd_frame *cf, int pcilen, 44362306a36Sopenharmony_ci struct sk_buff *skb, int len) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 44662306a36Sopenharmony_ci struct sk_buff *nskb; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci hrtimer_cancel(&so->rxtimer); 44962306a36Sopenharmony_ci so->rx.state = ISOTP_IDLE; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!len || len > cf->len - pcilen) 45262306a36Sopenharmony_ci return 1; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if ((so->opt.flags & ISOTP_CHECK_PADDING) && 45562306a36Sopenharmony_ci check_pad(so, cf, pcilen + len, so->opt.rxpad_content)) { 45662306a36Sopenharmony_ci /* malformed PDU - report 'not a data message' */ 45762306a36Sopenharmony_ci sk->sk_err = EBADMSG; 45862306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 45962306a36Sopenharmony_ci sk_error_report(sk); 46062306a36Sopenharmony_ci return 1; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci nskb = alloc_skb(len, gfp_any()); 46462306a36Sopenharmony_ci if (!nskb) 46562306a36Sopenharmony_ci return 1; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci memcpy(skb_put(nskb, len), &cf->data[pcilen], len); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci nskb->tstamp = skb->tstamp; 47062306a36Sopenharmony_ci nskb->dev = skb->dev; 47162306a36Sopenharmony_ci isotp_rcv_skb(nskb, sk); 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int isotp_rcv_ff(struct sock *sk, struct canfd_frame *cf, int ae) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 47862306a36Sopenharmony_ci int i; 47962306a36Sopenharmony_ci int off; 48062306a36Sopenharmony_ci int ff_pci_sz; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci hrtimer_cancel(&so->rxtimer); 48362306a36Sopenharmony_ci so->rx.state = ISOTP_IDLE; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* get the used sender LL_DL from the (first) CAN frame data length */ 48662306a36Sopenharmony_ci so->rx.ll_dl = padlen(cf->len); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* the first frame has to use the entire frame up to LL_DL length */ 48962306a36Sopenharmony_ci if (cf->len != so->rx.ll_dl) 49062306a36Sopenharmony_ci return 1; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* get the FF_DL */ 49362306a36Sopenharmony_ci so->rx.len = (cf->data[ae] & 0x0F) << 8; 49462306a36Sopenharmony_ci so->rx.len += cf->data[ae + 1]; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* Check for FF_DL escape sequence supporting 32 bit PDU length */ 49762306a36Sopenharmony_ci if (so->rx.len) { 49862306a36Sopenharmony_ci ff_pci_sz = FF_PCI_SZ12; 49962306a36Sopenharmony_ci } else { 50062306a36Sopenharmony_ci /* FF_DL = 0 => get real length from next 4 bytes */ 50162306a36Sopenharmony_ci so->rx.len = cf->data[ae + 2] << 24; 50262306a36Sopenharmony_ci so->rx.len += cf->data[ae + 3] << 16; 50362306a36Sopenharmony_ci so->rx.len += cf->data[ae + 4] << 8; 50462306a36Sopenharmony_ci so->rx.len += cf->data[ae + 5]; 50562306a36Sopenharmony_ci ff_pci_sz = FF_PCI_SZ32; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* take care of a potential SF_DL ESC offset for TX_DL > 8 */ 50962306a36Sopenharmony_ci off = (so->rx.ll_dl > CAN_MAX_DLEN) ? 1 : 0; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (so->rx.len + ae + off + ff_pci_sz < so->rx.ll_dl) 51262306a36Sopenharmony_ci return 1; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* PDU size > default => try max_pdu_size */ 51562306a36Sopenharmony_ci if (so->rx.len > so->rx.buflen && so->rx.buflen < max_pdu_size) { 51662306a36Sopenharmony_ci u8 *newbuf = kmalloc(max_pdu_size, GFP_ATOMIC); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (newbuf) { 51962306a36Sopenharmony_ci so->rx.buf = newbuf; 52062306a36Sopenharmony_ci so->rx.buflen = max_pdu_size; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (so->rx.len > so->rx.buflen) { 52562306a36Sopenharmony_ci /* send FC frame with overflow status */ 52662306a36Sopenharmony_ci isotp_send_fc(sk, ae, ISOTP_FC_OVFLW); 52762306a36Sopenharmony_ci return 1; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* copy the first received data bytes */ 53162306a36Sopenharmony_ci so->rx.idx = 0; 53262306a36Sopenharmony_ci for (i = ae + ff_pci_sz; i < so->rx.ll_dl; i++) 53362306a36Sopenharmony_ci so->rx.buf[so->rx.idx++] = cf->data[i]; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* initial setup for this pdu reception */ 53662306a36Sopenharmony_ci so->rx.sn = 1; 53762306a36Sopenharmony_ci so->rx.state = ISOTP_WAIT_DATA; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* no creation of flow control frames */ 54062306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_LISTEN_MODE) 54162306a36Sopenharmony_ci return 0; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* send our first FC frame */ 54462306a36Sopenharmony_ci isotp_send_fc(sk, ae, ISOTP_FC_CTS); 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae, 54962306a36Sopenharmony_ci struct sk_buff *skb) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 55262306a36Sopenharmony_ci struct sk_buff *nskb; 55362306a36Sopenharmony_ci int i; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (so->rx.state != ISOTP_WAIT_DATA) 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* drop if timestamp gap is less than force_rx_stmin nano secs */ 55962306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_FORCE_RXSTMIN) { 56062306a36Sopenharmony_ci if (ktime_to_ns(ktime_sub(skb->tstamp, so->lastrxcf_tstamp)) < 56162306a36Sopenharmony_ci so->force_rx_stmin) 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci so->lastrxcf_tstamp = skb->tstamp; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci hrtimer_cancel(&so->rxtimer); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* CFs are never longer than the FF */ 57062306a36Sopenharmony_ci if (cf->len > so->rx.ll_dl) 57162306a36Sopenharmony_ci return 1; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* CFs have usually the LL_DL length */ 57462306a36Sopenharmony_ci if (cf->len < so->rx.ll_dl) { 57562306a36Sopenharmony_ci /* this is only allowed for the last CF */ 57662306a36Sopenharmony_ci if (so->rx.len - so->rx.idx > so->rx.ll_dl - ae - N_PCI_SZ) 57762306a36Sopenharmony_ci return 1; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if ((cf->data[ae] & 0x0F) != so->rx.sn) { 58162306a36Sopenharmony_ci /* wrong sn detected - report 'illegal byte sequence' */ 58262306a36Sopenharmony_ci sk->sk_err = EILSEQ; 58362306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 58462306a36Sopenharmony_ci sk_error_report(sk); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* reset rx state */ 58762306a36Sopenharmony_ci so->rx.state = ISOTP_IDLE; 58862306a36Sopenharmony_ci return 1; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci so->rx.sn++; 59162306a36Sopenharmony_ci so->rx.sn %= 16; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci for (i = ae + N_PCI_SZ; i < cf->len; i++) { 59462306a36Sopenharmony_ci so->rx.buf[so->rx.idx++] = cf->data[i]; 59562306a36Sopenharmony_ci if (so->rx.idx >= so->rx.len) 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (so->rx.idx >= so->rx.len) { 60062306a36Sopenharmony_ci /* we are done */ 60162306a36Sopenharmony_ci so->rx.state = ISOTP_IDLE; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if ((so->opt.flags & ISOTP_CHECK_PADDING) && 60462306a36Sopenharmony_ci check_pad(so, cf, i + 1, so->opt.rxpad_content)) { 60562306a36Sopenharmony_ci /* malformed PDU - report 'not a data message' */ 60662306a36Sopenharmony_ci sk->sk_err = EBADMSG; 60762306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 60862306a36Sopenharmony_ci sk_error_report(sk); 60962306a36Sopenharmony_ci return 1; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci nskb = alloc_skb(so->rx.len, gfp_any()); 61362306a36Sopenharmony_ci if (!nskb) 61462306a36Sopenharmony_ci return 1; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci memcpy(skb_put(nskb, so->rx.len), so->rx.buf, 61762306a36Sopenharmony_ci so->rx.len); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci nskb->tstamp = skb->tstamp; 62062306a36Sopenharmony_ci nskb->dev = skb->dev; 62162306a36Sopenharmony_ci isotp_rcv_skb(nskb, sk); 62262306a36Sopenharmony_ci return 0; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* perform blocksize handling, if enabled */ 62662306a36Sopenharmony_ci if (!so->rxfc.bs || ++so->rx.bs < so->rxfc.bs) { 62762306a36Sopenharmony_ci /* start rx timeout watchdog */ 62862306a36Sopenharmony_ci hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0), 62962306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* no creation of flow control frames */ 63462306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_LISTEN_MODE) 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* we reached the specified blocksize so->rxfc.bs */ 63862306a36Sopenharmony_ci isotp_send_fc(sk, ae, ISOTP_FC_CTS); 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic void isotp_rcv(struct sk_buff *skb, void *data) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct sock *sk = (struct sock *)data; 64562306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 64662306a36Sopenharmony_ci struct canfd_frame *cf; 64762306a36Sopenharmony_ci int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; 64862306a36Sopenharmony_ci u8 n_pci_type, sf_dl; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* Strictly receive only frames with the configured MTU size 65162306a36Sopenharmony_ci * => clear separation of CAN2.0 / CAN FD transport channels 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci if (skb->len != so->ll.mtu) 65462306a36Sopenharmony_ci return; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci cf = (struct canfd_frame *)skb->data; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* if enabled: check reception of my configured extended address */ 65962306a36Sopenharmony_ci if (ae && cf->data[0] != so->opt.rx_ext_address) 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci n_pci_type = cf->data[ae] & 0xF0; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* Make sure the state changes and data structures stay consistent at 66562306a36Sopenharmony_ci * CAN frame reception time. This locking is not needed in real world 66662306a36Sopenharmony_ci * use cases but the inconsistency can be triggered with syzkaller. 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ci spin_lock(&so->rx_lock); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_HALF_DUPLEX) { 67162306a36Sopenharmony_ci /* check rx/tx path half duplex expectations */ 67262306a36Sopenharmony_ci if ((so->tx.state != ISOTP_IDLE && n_pci_type != N_PCI_FC) || 67362306a36Sopenharmony_ci (so->rx.state != ISOTP_IDLE && n_pci_type == N_PCI_FC)) 67462306a36Sopenharmony_ci goto out_unlock; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci switch (n_pci_type) { 67862306a36Sopenharmony_ci case N_PCI_FC: 67962306a36Sopenharmony_ci /* tx path: flow control frame containing the FC parameters */ 68062306a36Sopenharmony_ci isotp_rcv_fc(so, cf, ae); 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci case N_PCI_SF: 68462306a36Sopenharmony_ci /* rx path: single frame 68562306a36Sopenharmony_ci * 68662306a36Sopenharmony_ci * As we do not have a rx.ll_dl configuration, we can only test 68762306a36Sopenharmony_ci * if the CAN frames payload length matches the LL_DL == 8 68862306a36Sopenharmony_ci * requirements - no matter if it's CAN 2.0 or CAN FD 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* get the SF_DL from the N_PCI byte */ 69262306a36Sopenharmony_ci sf_dl = cf->data[ae] & 0x0F; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (cf->len <= CAN_MAX_DLEN) { 69562306a36Sopenharmony_ci isotp_rcv_sf(sk, cf, SF_PCI_SZ4 + ae, skb, sf_dl); 69662306a36Sopenharmony_ci } else { 69762306a36Sopenharmony_ci if (can_is_canfd_skb(skb)) { 69862306a36Sopenharmony_ci /* We have a CAN FD frame and CAN_DL is greater than 8: 69962306a36Sopenharmony_ci * Only frames with the SF_DL == 0 ESC value are valid. 70062306a36Sopenharmony_ci * 70162306a36Sopenharmony_ci * If so take care of the increased SF PCI size 70262306a36Sopenharmony_ci * (SF_PCI_SZ8) to point to the message content behind 70362306a36Sopenharmony_ci * the extended SF PCI info and get the real SF_DL 70462306a36Sopenharmony_ci * length value from the formerly first data byte. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci if (sf_dl == 0) 70762306a36Sopenharmony_ci isotp_rcv_sf(sk, cf, SF_PCI_SZ8 + ae, skb, 70862306a36Sopenharmony_ci cf->data[SF_PCI_SZ4 + ae]); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci case N_PCI_FF: 71462306a36Sopenharmony_ci /* rx path: first frame */ 71562306a36Sopenharmony_ci isotp_rcv_ff(sk, cf, ae); 71662306a36Sopenharmony_ci break; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci case N_PCI_CF: 71962306a36Sopenharmony_ci /* rx path: consecutive frame */ 72062306a36Sopenharmony_ci isotp_rcv_cf(sk, cf, ae, skb); 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ciout_unlock: 72562306a36Sopenharmony_ci spin_unlock(&so->rx_lock); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic void isotp_fill_dataframe(struct canfd_frame *cf, struct isotp_sock *so, 72962306a36Sopenharmony_ci int ae, int off) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci int pcilen = N_PCI_SZ + ae + off; 73262306a36Sopenharmony_ci int space = so->tx.ll_dl - pcilen; 73362306a36Sopenharmony_ci int num = min_t(int, so->tx.len - so->tx.idx, space); 73462306a36Sopenharmony_ci int i; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci cf->can_id = so->txid; 73762306a36Sopenharmony_ci cf->len = num + pcilen; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (num < space) { 74062306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_TX_PADDING) { 74162306a36Sopenharmony_ci /* user requested padding */ 74262306a36Sopenharmony_ci cf->len = padlen(cf->len); 74362306a36Sopenharmony_ci memset(cf->data, so->opt.txpad_content, cf->len); 74462306a36Sopenharmony_ci } else if (cf->len > CAN_MAX_DLEN) { 74562306a36Sopenharmony_ci /* mandatory padding for CAN FD frames */ 74662306a36Sopenharmony_ci cf->len = padlen(cf->len); 74762306a36Sopenharmony_ci memset(cf->data, CAN_ISOTP_DEFAULT_PAD_CONTENT, 74862306a36Sopenharmony_ci cf->len); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci for (i = 0; i < num; i++) 75362306a36Sopenharmony_ci cf->data[pcilen + i] = so->tx.buf[so->tx.idx++]; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (ae) 75662306a36Sopenharmony_ci cf->data[0] = so->opt.ext_address; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic void isotp_send_cframe(struct isotp_sock *so) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct sock *sk = &so->sk; 76262306a36Sopenharmony_ci struct sk_buff *skb; 76362306a36Sopenharmony_ci struct net_device *dev; 76462306a36Sopenharmony_ci struct canfd_frame *cf; 76562306a36Sopenharmony_ci int can_send_ret; 76662306a36Sopenharmony_ci int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci dev = dev_get_by_index(sock_net(sk), so->ifindex); 76962306a36Sopenharmony_ci if (!dev) 77062306a36Sopenharmony_ci return; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci skb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), GFP_ATOMIC); 77362306a36Sopenharmony_ci if (!skb) { 77462306a36Sopenharmony_ci dev_put(dev); 77562306a36Sopenharmony_ci return; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci can_skb_reserve(skb); 77962306a36Sopenharmony_ci can_skb_prv(skb)->ifindex = dev->ifindex; 78062306a36Sopenharmony_ci can_skb_prv(skb)->skbcnt = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci cf = (struct canfd_frame *)skb->data; 78362306a36Sopenharmony_ci skb_put_zero(skb, so->ll.mtu); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* create consecutive frame */ 78662306a36Sopenharmony_ci isotp_fill_dataframe(cf, so, ae, 0); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* place consecutive frame N_PCI in appropriate index */ 78962306a36Sopenharmony_ci cf->data[ae] = N_PCI_CF | so->tx.sn++; 79062306a36Sopenharmony_ci so->tx.sn %= 16; 79162306a36Sopenharmony_ci so->tx.bs++; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci cf->flags = so->ll.tx_flags; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci skb->dev = dev; 79662306a36Sopenharmony_ci can_skb_set_owner(skb, sk); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* cfecho should have been zero'ed by init/isotp_rcv_echo() */ 79962306a36Sopenharmony_ci if (so->cfecho) 80062306a36Sopenharmony_ci pr_notice_once("can-isotp: cfecho is %08X != 0\n", so->cfecho); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* set consecutive frame echo tag */ 80362306a36Sopenharmony_ci so->cfecho = *(u32 *)cf->data; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* send frame with local echo enabled */ 80662306a36Sopenharmony_ci can_send_ret = can_send(skb, 1); 80762306a36Sopenharmony_ci if (can_send_ret) { 80862306a36Sopenharmony_ci pr_notice_once("can-isotp: %s: can_send_ret %pe\n", 80962306a36Sopenharmony_ci __func__, ERR_PTR(can_send_ret)); 81062306a36Sopenharmony_ci if (can_send_ret == -ENOBUFS) 81162306a36Sopenharmony_ci pr_notice_once("can-isotp: tx queue is full\n"); 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci dev_put(dev); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic void isotp_create_fframe(struct canfd_frame *cf, struct isotp_sock *so, 81762306a36Sopenharmony_ci int ae) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci int i; 82062306a36Sopenharmony_ci int ff_pci_sz; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci cf->can_id = so->txid; 82362306a36Sopenharmony_ci cf->len = so->tx.ll_dl; 82462306a36Sopenharmony_ci if (ae) 82562306a36Sopenharmony_ci cf->data[0] = so->opt.ext_address; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* create N_PCI bytes with 12/32 bit FF_DL data length */ 82862306a36Sopenharmony_ci if (so->tx.len > MAX_12BIT_PDU_SIZE) { 82962306a36Sopenharmony_ci /* use 32 bit FF_DL notation */ 83062306a36Sopenharmony_ci cf->data[ae] = N_PCI_FF; 83162306a36Sopenharmony_ci cf->data[ae + 1] = 0; 83262306a36Sopenharmony_ci cf->data[ae + 2] = (u8)(so->tx.len >> 24) & 0xFFU; 83362306a36Sopenharmony_ci cf->data[ae + 3] = (u8)(so->tx.len >> 16) & 0xFFU; 83462306a36Sopenharmony_ci cf->data[ae + 4] = (u8)(so->tx.len >> 8) & 0xFFU; 83562306a36Sopenharmony_ci cf->data[ae + 5] = (u8)so->tx.len & 0xFFU; 83662306a36Sopenharmony_ci ff_pci_sz = FF_PCI_SZ32; 83762306a36Sopenharmony_ci } else { 83862306a36Sopenharmony_ci /* use 12 bit FF_DL notation */ 83962306a36Sopenharmony_ci cf->data[ae] = (u8)(so->tx.len >> 8) | N_PCI_FF; 84062306a36Sopenharmony_ci cf->data[ae + 1] = (u8)so->tx.len & 0xFFU; 84162306a36Sopenharmony_ci ff_pci_sz = FF_PCI_SZ12; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* add first data bytes depending on ae */ 84562306a36Sopenharmony_ci for (i = ae + ff_pci_sz; i < so->tx.ll_dl; i++) 84662306a36Sopenharmony_ci cf->data[i] = so->tx.buf[so->tx.idx++]; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci so->tx.sn = 1; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic void isotp_rcv_echo(struct sk_buff *skb, void *data) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct sock *sk = (struct sock *)data; 85462306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 85562306a36Sopenharmony_ci struct canfd_frame *cf = (struct canfd_frame *)skb->data; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* only handle my own local echo CF/SF skb's (no FF!) */ 85862306a36Sopenharmony_ci if (skb->sk != sk || so->cfecho != *(u32 *)cf->data) 85962306a36Sopenharmony_ci return; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* cancel local echo timeout */ 86262306a36Sopenharmony_ci hrtimer_cancel(&so->txtimer); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* local echo skb with consecutive frame has been consumed */ 86562306a36Sopenharmony_ci so->cfecho = 0; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (so->tx.idx >= so->tx.len) { 86862306a36Sopenharmony_ci /* we are done */ 86962306a36Sopenharmony_ci so->tx.state = ISOTP_IDLE; 87062306a36Sopenharmony_ci wake_up_interruptible(&so->wait); 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (so->txfc.bs && so->tx.bs >= so->txfc.bs) { 87562306a36Sopenharmony_ci /* stop and wait for FC with timeout */ 87662306a36Sopenharmony_ci so->tx.state = ISOTP_WAIT_FC; 87762306a36Sopenharmony_ci hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0), 87862306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 87962306a36Sopenharmony_ci return; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* no gap between data frames needed => use burst mode */ 88362306a36Sopenharmony_ci if (!so->tx_gap) { 88462306a36Sopenharmony_ci /* enable echo timeout handling */ 88562306a36Sopenharmony_ci hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), 88662306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 88762306a36Sopenharmony_ci isotp_send_cframe(so); 88862306a36Sopenharmony_ci return; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* start timer to send next consecutive frame with correct delay */ 89262306a36Sopenharmony_ci hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct isotp_sock *so = container_of(hrtimer, struct isotp_sock, 89862306a36Sopenharmony_ci txtimer); 89962306a36Sopenharmony_ci struct sock *sk = &so->sk; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* don't handle timeouts in IDLE or SHUTDOWN state */ 90262306a36Sopenharmony_ci if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN) 90362306a36Sopenharmony_ci return HRTIMER_NORESTART; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* we did not get any flow control or echo frame in time */ 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* report 'communication error on send' */ 90862306a36Sopenharmony_ci sk->sk_err = ECOMM; 90962306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 91062306a36Sopenharmony_ci sk_error_report(sk); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* reset tx state */ 91362306a36Sopenharmony_ci so->tx.state = ISOTP_IDLE; 91462306a36Sopenharmony_ci wake_up_interruptible(&so->wait); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return HRTIMER_NORESTART; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct isotp_sock *so = container_of(hrtimer, struct isotp_sock, 92262306a36Sopenharmony_ci txfrtimer); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* start echo timeout handling and cover below protocol error */ 92562306a36Sopenharmony_ci hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), 92662306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* cfecho should be consumed by isotp_rcv_echo() here */ 92962306a36Sopenharmony_ci if (so->tx.state == ISOTP_SENDING && !so->cfecho) 93062306a36Sopenharmony_ci isotp_send_cframe(so); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci return HRTIMER_NORESTART; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci struct sock *sk = sock->sk; 93862306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 93962306a36Sopenharmony_ci struct sk_buff *skb; 94062306a36Sopenharmony_ci struct net_device *dev; 94162306a36Sopenharmony_ci struct canfd_frame *cf; 94262306a36Sopenharmony_ci int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; 94362306a36Sopenharmony_ci int wait_tx_done = (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0; 94462306a36Sopenharmony_ci s64 hrtimer_sec = ISOTP_ECHO_TIMEOUT; 94562306a36Sopenharmony_ci int off; 94662306a36Sopenharmony_ci int err; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (!so->bound || so->tx.state == ISOTP_SHUTDOWN) 94962306a36Sopenharmony_ci return -EADDRNOTAVAIL; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci while (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) { 95262306a36Sopenharmony_ci /* we do not support multiple buffers - for now */ 95362306a36Sopenharmony_ci if (msg->msg_flags & MSG_DONTWAIT) 95462306a36Sopenharmony_ci return -EAGAIN; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (so->tx.state == ISOTP_SHUTDOWN) 95762306a36Sopenharmony_ci return -EADDRNOTAVAIL; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* wait for complete transmission of current pdu */ 96062306a36Sopenharmony_ci err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE); 96162306a36Sopenharmony_ci if (err) 96262306a36Sopenharmony_ci goto err_event_drop; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* PDU size > default => try max_pdu_size */ 96662306a36Sopenharmony_ci if (size > so->tx.buflen && so->tx.buflen < max_pdu_size) { 96762306a36Sopenharmony_ci u8 *newbuf = kmalloc(max_pdu_size, GFP_KERNEL); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (newbuf) { 97062306a36Sopenharmony_ci so->tx.buf = newbuf; 97162306a36Sopenharmony_ci so->tx.buflen = max_pdu_size; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (!size || size > so->tx.buflen) { 97662306a36Sopenharmony_ci err = -EINVAL; 97762306a36Sopenharmony_ci goto err_out_drop; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* take care of a potential SF_DL ESC offset for TX_DL > 8 */ 98162306a36Sopenharmony_ci off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* does the given data fit into a single frame for SF_BROADCAST? */ 98462306a36Sopenharmony_ci if ((isotp_bc_flags(so) == CAN_ISOTP_SF_BROADCAST) && 98562306a36Sopenharmony_ci (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) { 98662306a36Sopenharmony_ci err = -EINVAL; 98762306a36Sopenharmony_ci goto err_out_drop; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci err = memcpy_from_msg(so->tx.buf, msg, size); 99162306a36Sopenharmony_ci if (err < 0) 99262306a36Sopenharmony_ci goto err_out_drop; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci dev = dev_get_by_index(sock_net(sk), so->ifindex); 99562306a36Sopenharmony_ci if (!dev) { 99662306a36Sopenharmony_ci err = -ENXIO; 99762306a36Sopenharmony_ci goto err_out_drop; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv), 100162306a36Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, &err); 100262306a36Sopenharmony_ci if (!skb) { 100362306a36Sopenharmony_ci dev_put(dev); 100462306a36Sopenharmony_ci goto err_out_drop; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci can_skb_reserve(skb); 100862306a36Sopenharmony_ci can_skb_prv(skb)->ifindex = dev->ifindex; 100962306a36Sopenharmony_ci can_skb_prv(skb)->skbcnt = 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci so->tx.len = size; 101262306a36Sopenharmony_ci so->tx.idx = 0; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci cf = (struct canfd_frame *)skb->data; 101562306a36Sopenharmony_ci skb_put_zero(skb, so->ll.mtu); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* cfecho should have been zero'ed by init / former isotp_rcv_echo() */ 101862306a36Sopenharmony_ci if (so->cfecho) 101962306a36Sopenharmony_ci pr_notice_once("can-isotp: uninit cfecho %08X\n", so->cfecho); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* check for single frame transmission depending on TX_DL */ 102262306a36Sopenharmony_ci if (size <= so->tx.ll_dl - SF_PCI_SZ4 - ae - off) { 102362306a36Sopenharmony_ci /* The message size generally fits into a SingleFrame - good. 102462306a36Sopenharmony_ci * 102562306a36Sopenharmony_ci * SF_DL ESC offset optimization: 102662306a36Sopenharmony_ci * 102762306a36Sopenharmony_ci * When TX_DL is greater 8 but the message would still fit 102862306a36Sopenharmony_ci * into a 8 byte CAN frame, we can omit the offset. 102962306a36Sopenharmony_ci * This prevents a protocol caused length extension from 103062306a36Sopenharmony_ci * CAN_DL = 8 to CAN_DL = 12 due to the SF_SL ESC handling. 103162306a36Sopenharmony_ci */ 103262306a36Sopenharmony_ci if (size <= CAN_MAX_DLEN - SF_PCI_SZ4 - ae) 103362306a36Sopenharmony_ci off = 0; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci isotp_fill_dataframe(cf, so, ae, off); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* place single frame N_PCI w/o length in appropriate index */ 103862306a36Sopenharmony_ci cf->data[ae] = N_PCI_SF; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* place SF_DL size value depending on the SF_DL ESC offset */ 104162306a36Sopenharmony_ci if (off) 104262306a36Sopenharmony_ci cf->data[SF_PCI_SZ4 + ae] = size; 104362306a36Sopenharmony_ci else 104462306a36Sopenharmony_ci cf->data[ae] |= size; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* set CF echo tag for isotp_rcv_echo() (SF-mode) */ 104762306a36Sopenharmony_ci so->cfecho = *(u32 *)cf->data; 104862306a36Sopenharmony_ci } else { 104962306a36Sopenharmony_ci /* send first frame */ 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci isotp_create_fframe(cf, so, ae); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (isotp_bc_flags(so) == CAN_ISOTP_CF_BROADCAST) { 105462306a36Sopenharmony_ci /* set timer for FC-less operation (STmin = 0) */ 105562306a36Sopenharmony_ci if (so->opt.flags & CAN_ISOTP_FORCE_TXSTMIN) 105662306a36Sopenharmony_ci so->tx_gap = ktime_set(0, so->force_tx_stmin); 105762306a36Sopenharmony_ci else 105862306a36Sopenharmony_ci so->tx_gap = ktime_set(0, so->frame_txtime); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* disable wait for FCs due to activated block size */ 106162306a36Sopenharmony_ci so->txfc.bs = 0; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* set CF echo tag for isotp_rcv_echo() (CF-mode) */ 106462306a36Sopenharmony_ci so->cfecho = *(u32 *)cf->data; 106562306a36Sopenharmony_ci } else { 106662306a36Sopenharmony_ci /* standard flow control check */ 106762306a36Sopenharmony_ci so->tx.state = ISOTP_WAIT_FIRST_FC; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci /* start timeout for FC */ 107062306a36Sopenharmony_ci hrtimer_sec = ISOTP_FC_TIMEOUT; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* no CF echo tag for isotp_rcv_echo() (FF-mode) */ 107362306a36Sopenharmony_ci so->cfecho = 0; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0), 107862306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* send the first or only CAN frame */ 108162306a36Sopenharmony_ci cf->flags = so->ll.tx_flags; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci skb->dev = dev; 108462306a36Sopenharmony_ci skb->sk = sk; 108562306a36Sopenharmony_ci err = can_send(skb, 1); 108662306a36Sopenharmony_ci dev_put(dev); 108762306a36Sopenharmony_ci if (err) { 108862306a36Sopenharmony_ci pr_notice_once("can-isotp: %s: can_send_ret %pe\n", 108962306a36Sopenharmony_ci __func__, ERR_PTR(err)); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci /* no transmission -> no timeout monitoring */ 109262306a36Sopenharmony_ci hrtimer_cancel(&so->txtimer); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* reset consecutive frame echo tag */ 109562306a36Sopenharmony_ci so->cfecho = 0; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci goto err_out_drop; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (wait_tx_done) { 110162306a36Sopenharmony_ci /* wait for complete transmission of current pdu */ 110262306a36Sopenharmony_ci err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE); 110362306a36Sopenharmony_ci if (err) 110462306a36Sopenharmony_ci goto err_event_drop; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci err = sock_error(sk); 110762306a36Sopenharmony_ci if (err) 110862306a36Sopenharmony_ci return err; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return size; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cierr_event_drop: 111462306a36Sopenharmony_ci /* got signal: force tx state machine to be idle */ 111562306a36Sopenharmony_ci so->tx.state = ISOTP_IDLE; 111662306a36Sopenharmony_ci hrtimer_cancel(&so->txfrtimer); 111762306a36Sopenharmony_ci hrtimer_cancel(&so->txtimer); 111862306a36Sopenharmony_cierr_out_drop: 111962306a36Sopenharmony_ci /* drop this PDU and unlock a potential wait queue */ 112062306a36Sopenharmony_ci so->tx.state = ISOTP_IDLE; 112162306a36Sopenharmony_ci wake_up_interruptible(&so->wait); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci return err; 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, 112762306a36Sopenharmony_ci int flags) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci struct sock *sk = sock->sk; 113062306a36Sopenharmony_ci struct sk_buff *skb; 113162306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 113262306a36Sopenharmony_ci int ret = 0; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK | MSG_CMSG_COMPAT)) 113562306a36Sopenharmony_ci return -EINVAL; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (!so->bound) 113862306a36Sopenharmony_ci return -EADDRNOTAVAIL; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &ret); 114162306a36Sopenharmony_ci if (!skb) 114262306a36Sopenharmony_ci return ret; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (size < skb->len) 114562306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 114662306a36Sopenharmony_ci else 114762306a36Sopenharmony_ci size = skb->len; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci ret = memcpy_to_msg(msg, skb->data, size); 115062306a36Sopenharmony_ci if (ret < 0) 115162306a36Sopenharmony_ci goto out_err; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (msg->msg_name) { 115662306a36Sopenharmony_ci __sockaddr_check_size(ISOTP_MIN_NAMELEN); 115762306a36Sopenharmony_ci msg->msg_namelen = ISOTP_MIN_NAMELEN; 115862306a36Sopenharmony_ci memcpy(msg->msg_name, skb->cb, msg->msg_namelen); 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* set length of return value */ 116262306a36Sopenharmony_ci ret = (flags & MSG_TRUNC) ? skb->len : size; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ciout_err: 116562306a36Sopenharmony_ci skb_free_datagram(sk, skb); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci return ret; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic int isotp_release(struct socket *sock) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct sock *sk = sock->sk; 117362306a36Sopenharmony_ci struct isotp_sock *so; 117462306a36Sopenharmony_ci struct net *net; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci if (!sk) 117762306a36Sopenharmony_ci return 0; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci so = isotp_sk(sk); 118062306a36Sopenharmony_ci net = sock_net(sk); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* wait for complete transmission of current pdu */ 118362306a36Sopenharmony_ci while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 && 118462306a36Sopenharmony_ci cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE) 118562306a36Sopenharmony_ci ; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* force state machines to be idle also when a signal occurred */ 118862306a36Sopenharmony_ci so->tx.state = ISOTP_SHUTDOWN; 118962306a36Sopenharmony_ci so->rx.state = ISOTP_IDLE; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci spin_lock(&isotp_notifier_lock); 119262306a36Sopenharmony_ci while (isotp_busy_notifier == so) { 119362306a36Sopenharmony_ci spin_unlock(&isotp_notifier_lock); 119462306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 119562306a36Sopenharmony_ci spin_lock(&isotp_notifier_lock); 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci list_del(&so->notifier); 119862306a36Sopenharmony_ci spin_unlock(&isotp_notifier_lock); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci lock_sock(sk); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* remove current filters & unregister */ 120362306a36Sopenharmony_ci if (so->bound) { 120462306a36Sopenharmony_ci if (so->ifindex) { 120562306a36Sopenharmony_ci struct net_device *dev; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci dev = dev_get_by_index(net, so->ifindex); 120862306a36Sopenharmony_ci if (dev) { 120962306a36Sopenharmony_ci if (isotp_register_rxid(so)) 121062306a36Sopenharmony_ci can_rx_unregister(net, dev, so->rxid, 121162306a36Sopenharmony_ci SINGLE_MASK(so->rxid), 121262306a36Sopenharmony_ci isotp_rcv, sk); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci can_rx_unregister(net, dev, so->txid, 121562306a36Sopenharmony_ci SINGLE_MASK(so->txid), 121662306a36Sopenharmony_ci isotp_rcv_echo, sk); 121762306a36Sopenharmony_ci dev_put(dev); 121862306a36Sopenharmony_ci synchronize_rcu(); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci hrtimer_cancel(&so->txfrtimer); 122462306a36Sopenharmony_ci hrtimer_cancel(&so->txtimer); 122562306a36Sopenharmony_ci hrtimer_cancel(&so->rxtimer); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci so->ifindex = 0; 122862306a36Sopenharmony_ci so->bound = 0; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (so->rx.buf != so->rx.sbuf) 123162306a36Sopenharmony_ci kfree(so->rx.buf); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (so->tx.buf != so->tx.sbuf) 123462306a36Sopenharmony_ci kfree(so->tx.buf); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci sock_orphan(sk); 123762306a36Sopenharmony_ci sock->sk = NULL; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci release_sock(sk); 124062306a36Sopenharmony_ci sock_put(sk); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci return 0; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cistatic int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; 124862306a36Sopenharmony_ci struct sock *sk = sock->sk; 124962306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 125062306a36Sopenharmony_ci struct net *net = sock_net(sk); 125162306a36Sopenharmony_ci int ifindex; 125262306a36Sopenharmony_ci struct net_device *dev; 125362306a36Sopenharmony_ci canid_t tx_id = addr->can_addr.tp.tx_id; 125462306a36Sopenharmony_ci canid_t rx_id = addr->can_addr.tp.rx_id; 125562306a36Sopenharmony_ci int err = 0; 125662306a36Sopenharmony_ci int notify_enetdown = 0; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci if (len < ISOTP_MIN_NAMELEN) 125962306a36Sopenharmony_ci return -EINVAL; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (addr->can_family != AF_CAN) 126262306a36Sopenharmony_ci return -EINVAL; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* sanitize tx CAN identifier */ 126562306a36Sopenharmony_ci if (tx_id & CAN_EFF_FLAG) 126662306a36Sopenharmony_ci tx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK); 126762306a36Sopenharmony_ci else 126862306a36Sopenharmony_ci tx_id &= CAN_SFF_MASK; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* give feedback on wrong CAN-ID value */ 127162306a36Sopenharmony_ci if (tx_id != addr->can_addr.tp.tx_id) 127262306a36Sopenharmony_ci return -EINVAL; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* sanitize rx CAN identifier (if needed) */ 127562306a36Sopenharmony_ci if (isotp_register_rxid(so)) { 127662306a36Sopenharmony_ci if (rx_id & CAN_EFF_FLAG) 127762306a36Sopenharmony_ci rx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK); 127862306a36Sopenharmony_ci else 127962306a36Sopenharmony_ci rx_id &= CAN_SFF_MASK; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* give feedback on wrong CAN-ID value */ 128262306a36Sopenharmony_ci if (rx_id != addr->can_addr.tp.rx_id) 128362306a36Sopenharmony_ci return -EINVAL; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (!addr->can_ifindex) 128762306a36Sopenharmony_ci return -ENODEV; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci lock_sock(sk); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci if (so->bound) { 129262306a36Sopenharmony_ci err = -EINVAL; 129362306a36Sopenharmony_ci goto out; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* ensure different CAN IDs when the rx_id is to be registered */ 129762306a36Sopenharmony_ci if (isotp_register_rxid(so) && rx_id == tx_id) { 129862306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 129962306a36Sopenharmony_ci goto out; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci dev = dev_get_by_index(net, addr->can_ifindex); 130362306a36Sopenharmony_ci if (!dev) { 130462306a36Sopenharmony_ci err = -ENODEV; 130562306a36Sopenharmony_ci goto out; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci if (dev->type != ARPHRD_CAN) { 130862306a36Sopenharmony_ci dev_put(dev); 130962306a36Sopenharmony_ci err = -ENODEV; 131062306a36Sopenharmony_ci goto out; 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci if (dev->mtu < so->ll.mtu) { 131362306a36Sopenharmony_ci dev_put(dev); 131462306a36Sopenharmony_ci err = -EINVAL; 131562306a36Sopenharmony_ci goto out; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci if (!(dev->flags & IFF_UP)) 131862306a36Sopenharmony_ci notify_enetdown = 1; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci ifindex = dev->ifindex; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (isotp_register_rxid(so)) 132362306a36Sopenharmony_ci can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id), 132462306a36Sopenharmony_ci isotp_rcv, sk, "isotp", sk); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* no consecutive frame echo skb in flight */ 132762306a36Sopenharmony_ci so->cfecho = 0; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci /* register for echo skb's */ 133062306a36Sopenharmony_ci can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id), 133162306a36Sopenharmony_ci isotp_rcv_echo, sk, "isotpe", sk); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci dev_put(dev); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* switch to new settings */ 133662306a36Sopenharmony_ci so->ifindex = ifindex; 133762306a36Sopenharmony_ci so->rxid = rx_id; 133862306a36Sopenharmony_ci so->txid = tx_id; 133962306a36Sopenharmony_ci so->bound = 1; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ciout: 134262306a36Sopenharmony_ci release_sock(sk); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if (notify_enetdown) { 134562306a36Sopenharmony_ci sk->sk_err = ENETDOWN; 134662306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 134762306a36Sopenharmony_ci sk_error_report(sk); 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci return err; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int isotp_getname(struct socket *sock, struct sockaddr *uaddr, int peer) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; 135662306a36Sopenharmony_ci struct sock *sk = sock->sk; 135762306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if (peer) 136062306a36Sopenharmony_ci return -EOPNOTSUPP; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci memset(addr, 0, ISOTP_MIN_NAMELEN); 136362306a36Sopenharmony_ci addr->can_family = AF_CAN; 136462306a36Sopenharmony_ci addr->can_ifindex = so->ifindex; 136562306a36Sopenharmony_ci addr->can_addr.tp.rx_id = so->rxid; 136662306a36Sopenharmony_ci addr->can_addr.tp.tx_id = so->txid; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci return ISOTP_MIN_NAMELEN; 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic int isotp_setsockopt_locked(struct socket *sock, int level, int optname, 137262306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci struct sock *sk = sock->sk; 137562306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 137662306a36Sopenharmony_ci int ret = 0; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci if (so->bound) 137962306a36Sopenharmony_ci return -EISCONN; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci switch (optname) { 138262306a36Sopenharmony_ci case CAN_ISOTP_OPTS: 138362306a36Sopenharmony_ci if (optlen != sizeof(struct can_isotp_options)) 138462306a36Sopenharmony_ci return -EINVAL; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (copy_from_sockptr(&so->opt, optval, optlen)) 138762306a36Sopenharmony_ci return -EFAULT; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci /* no separate rx_ext_address is given => use ext_address */ 139062306a36Sopenharmony_ci if (!(so->opt.flags & CAN_ISOTP_RX_EXT_ADDR)) 139162306a36Sopenharmony_ci so->opt.rx_ext_address = so->opt.ext_address; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* these broadcast flags are not allowed together */ 139462306a36Sopenharmony_ci if (isotp_bc_flags(so) == ISOTP_ALL_BC_FLAGS) { 139562306a36Sopenharmony_ci /* CAN_ISOTP_SF_BROADCAST is prioritized */ 139662306a36Sopenharmony_ci so->opt.flags &= ~CAN_ISOTP_CF_BROADCAST; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci /* give user feedback on wrong config attempt */ 139962306a36Sopenharmony_ci ret = -EINVAL; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci /* check for frame_txtime changes (0 => no changes) */ 140362306a36Sopenharmony_ci if (so->opt.frame_txtime) { 140462306a36Sopenharmony_ci if (so->opt.frame_txtime == CAN_ISOTP_FRAME_TXTIME_ZERO) 140562306a36Sopenharmony_ci so->frame_txtime = 0; 140662306a36Sopenharmony_ci else 140762306a36Sopenharmony_ci so->frame_txtime = so->opt.frame_txtime; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci break; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci case CAN_ISOTP_RECV_FC: 141262306a36Sopenharmony_ci if (optlen != sizeof(struct can_isotp_fc_options)) 141362306a36Sopenharmony_ci return -EINVAL; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci if (copy_from_sockptr(&so->rxfc, optval, optlen)) 141662306a36Sopenharmony_ci return -EFAULT; 141762306a36Sopenharmony_ci break; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci case CAN_ISOTP_TX_STMIN: 142062306a36Sopenharmony_ci if (optlen != sizeof(u32)) 142162306a36Sopenharmony_ci return -EINVAL; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (copy_from_sockptr(&so->force_tx_stmin, optval, optlen)) 142462306a36Sopenharmony_ci return -EFAULT; 142562306a36Sopenharmony_ci break; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci case CAN_ISOTP_RX_STMIN: 142862306a36Sopenharmony_ci if (optlen != sizeof(u32)) 142962306a36Sopenharmony_ci return -EINVAL; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (copy_from_sockptr(&so->force_rx_stmin, optval, optlen)) 143262306a36Sopenharmony_ci return -EFAULT; 143362306a36Sopenharmony_ci break; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci case CAN_ISOTP_LL_OPTS: 143662306a36Sopenharmony_ci if (optlen == sizeof(struct can_isotp_ll_options)) { 143762306a36Sopenharmony_ci struct can_isotp_ll_options ll; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (copy_from_sockptr(&ll, optval, optlen)) 144062306a36Sopenharmony_ci return -EFAULT; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* check for correct ISO 11898-1 DLC data length */ 144362306a36Sopenharmony_ci if (ll.tx_dl != padlen(ll.tx_dl)) 144462306a36Sopenharmony_ci return -EINVAL; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci if (ll.mtu != CAN_MTU && ll.mtu != CANFD_MTU) 144762306a36Sopenharmony_ci return -EINVAL; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (ll.mtu == CAN_MTU && 145062306a36Sopenharmony_ci (ll.tx_dl > CAN_MAX_DLEN || ll.tx_flags != 0)) 145162306a36Sopenharmony_ci return -EINVAL; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci memcpy(&so->ll, &ll, sizeof(ll)); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* set ll_dl for tx path to similar place as for rx */ 145662306a36Sopenharmony_ci so->tx.ll_dl = ll.tx_dl; 145762306a36Sopenharmony_ci } else { 145862306a36Sopenharmony_ci return -EINVAL; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci break; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci default: 146362306a36Sopenharmony_ci ret = -ENOPROTOOPT; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci return ret; 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cistatic int isotp_setsockopt(struct socket *sock, int level, int optname, 147062306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci{ 147362306a36Sopenharmony_ci struct sock *sk = sock->sk; 147462306a36Sopenharmony_ci int ret; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci if (level != SOL_CAN_ISOTP) 147762306a36Sopenharmony_ci return -EINVAL; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci lock_sock(sk); 148062306a36Sopenharmony_ci ret = isotp_setsockopt_locked(sock, level, optname, optval, optlen); 148162306a36Sopenharmony_ci release_sock(sk); 148262306a36Sopenharmony_ci return ret; 148362306a36Sopenharmony_ci} 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_cistatic int isotp_getsockopt(struct socket *sock, int level, int optname, 148662306a36Sopenharmony_ci char __user *optval, int __user *optlen) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci struct sock *sk = sock->sk; 148962306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 149062306a36Sopenharmony_ci int len; 149162306a36Sopenharmony_ci void *val; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (level != SOL_CAN_ISOTP) 149462306a36Sopenharmony_ci return -EINVAL; 149562306a36Sopenharmony_ci if (get_user(len, optlen)) 149662306a36Sopenharmony_ci return -EFAULT; 149762306a36Sopenharmony_ci if (len < 0) 149862306a36Sopenharmony_ci return -EINVAL; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci switch (optname) { 150162306a36Sopenharmony_ci case CAN_ISOTP_OPTS: 150262306a36Sopenharmony_ci len = min_t(int, len, sizeof(struct can_isotp_options)); 150362306a36Sopenharmony_ci val = &so->opt; 150462306a36Sopenharmony_ci break; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci case CAN_ISOTP_RECV_FC: 150762306a36Sopenharmony_ci len = min_t(int, len, sizeof(struct can_isotp_fc_options)); 150862306a36Sopenharmony_ci val = &so->rxfc; 150962306a36Sopenharmony_ci break; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci case CAN_ISOTP_TX_STMIN: 151262306a36Sopenharmony_ci len = min_t(int, len, sizeof(u32)); 151362306a36Sopenharmony_ci val = &so->force_tx_stmin; 151462306a36Sopenharmony_ci break; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci case CAN_ISOTP_RX_STMIN: 151762306a36Sopenharmony_ci len = min_t(int, len, sizeof(u32)); 151862306a36Sopenharmony_ci val = &so->force_rx_stmin; 151962306a36Sopenharmony_ci break; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci case CAN_ISOTP_LL_OPTS: 152262306a36Sopenharmony_ci len = min_t(int, len, sizeof(struct can_isotp_ll_options)); 152362306a36Sopenharmony_ci val = &so->ll; 152462306a36Sopenharmony_ci break; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci default: 152762306a36Sopenharmony_ci return -ENOPROTOOPT; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (put_user(len, optlen)) 153162306a36Sopenharmony_ci return -EFAULT; 153262306a36Sopenharmony_ci if (copy_to_user(optval, val, len)) 153362306a36Sopenharmony_ci return -EFAULT; 153462306a36Sopenharmony_ci return 0; 153562306a36Sopenharmony_ci} 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_cistatic void isotp_notify(struct isotp_sock *so, unsigned long msg, 153862306a36Sopenharmony_ci struct net_device *dev) 153962306a36Sopenharmony_ci{ 154062306a36Sopenharmony_ci struct sock *sk = &so->sk; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (!net_eq(dev_net(dev), sock_net(sk))) 154362306a36Sopenharmony_ci return; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (so->ifindex != dev->ifindex) 154662306a36Sopenharmony_ci return; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci switch (msg) { 154962306a36Sopenharmony_ci case NETDEV_UNREGISTER: 155062306a36Sopenharmony_ci lock_sock(sk); 155162306a36Sopenharmony_ci /* remove current filters & unregister */ 155262306a36Sopenharmony_ci if (so->bound) { 155362306a36Sopenharmony_ci if (isotp_register_rxid(so)) 155462306a36Sopenharmony_ci can_rx_unregister(dev_net(dev), dev, so->rxid, 155562306a36Sopenharmony_ci SINGLE_MASK(so->rxid), 155662306a36Sopenharmony_ci isotp_rcv, sk); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci can_rx_unregister(dev_net(dev), dev, so->txid, 155962306a36Sopenharmony_ci SINGLE_MASK(so->txid), 156062306a36Sopenharmony_ci isotp_rcv_echo, sk); 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci so->ifindex = 0; 156462306a36Sopenharmony_ci so->bound = 0; 156562306a36Sopenharmony_ci release_sock(sk); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci sk->sk_err = ENODEV; 156862306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 156962306a36Sopenharmony_ci sk_error_report(sk); 157062306a36Sopenharmony_ci break; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci case NETDEV_DOWN: 157362306a36Sopenharmony_ci sk->sk_err = ENETDOWN; 157462306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 157562306a36Sopenharmony_ci sk_error_report(sk); 157662306a36Sopenharmony_ci break; 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_cistatic int isotp_notifier(struct notifier_block *nb, unsigned long msg, 158162306a36Sopenharmony_ci void *ptr) 158262306a36Sopenharmony_ci{ 158362306a36Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (dev->type != ARPHRD_CAN) 158662306a36Sopenharmony_ci return NOTIFY_DONE; 158762306a36Sopenharmony_ci if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN) 158862306a36Sopenharmony_ci return NOTIFY_DONE; 158962306a36Sopenharmony_ci if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */ 159062306a36Sopenharmony_ci return NOTIFY_DONE; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci spin_lock(&isotp_notifier_lock); 159362306a36Sopenharmony_ci list_for_each_entry(isotp_busy_notifier, &isotp_notifier_list, notifier) { 159462306a36Sopenharmony_ci spin_unlock(&isotp_notifier_lock); 159562306a36Sopenharmony_ci isotp_notify(isotp_busy_notifier, msg, dev); 159662306a36Sopenharmony_ci spin_lock(&isotp_notifier_lock); 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci isotp_busy_notifier = NULL; 159962306a36Sopenharmony_ci spin_unlock(&isotp_notifier_lock); 160062306a36Sopenharmony_ci return NOTIFY_DONE; 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic int isotp_init(struct sock *sk) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci so->ifindex = 0; 160862306a36Sopenharmony_ci so->bound = 0; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci so->opt.flags = CAN_ISOTP_DEFAULT_FLAGS; 161162306a36Sopenharmony_ci so->opt.ext_address = CAN_ISOTP_DEFAULT_EXT_ADDRESS; 161262306a36Sopenharmony_ci so->opt.rx_ext_address = CAN_ISOTP_DEFAULT_EXT_ADDRESS; 161362306a36Sopenharmony_ci so->opt.rxpad_content = CAN_ISOTP_DEFAULT_PAD_CONTENT; 161462306a36Sopenharmony_ci so->opt.txpad_content = CAN_ISOTP_DEFAULT_PAD_CONTENT; 161562306a36Sopenharmony_ci so->opt.frame_txtime = CAN_ISOTP_DEFAULT_FRAME_TXTIME; 161662306a36Sopenharmony_ci so->frame_txtime = CAN_ISOTP_DEFAULT_FRAME_TXTIME; 161762306a36Sopenharmony_ci so->rxfc.bs = CAN_ISOTP_DEFAULT_RECV_BS; 161862306a36Sopenharmony_ci so->rxfc.stmin = CAN_ISOTP_DEFAULT_RECV_STMIN; 161962306a36Sopenharmony_ci so->rxfc.wftmax = CAN_ISOTP_DEFAULT_RECV_WFTMAX; 162062306a36Sopenharmony_ci so->ll.mtu = CAN_ISOTP_DEFAULT_LL_MTU; 162162306a36Sopenharmony_ci so->ll.tx_dl = CAN_ISOTP_DEFAULT_LL_TX_DL; 162262306a36Sopenharmony_ci so->ll.tx_flags = CAN_ISOTP_DEFAULT_LL_TX_FLAGS; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* set ll_dl for tx path to similar place as for rx */ 162562306a36Sopenharmony_ci so->tx.ll_dl = so->ll.tx_dl; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci so->rx.state = ISOTP_IDLE; 162862306a36Sopenharmony_ci so->tx.state = ISOTP_IDLE; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci so->rx.buf = so->rx.sbuf; 163162306a36Sopenharmony_ci so->tx.buf = so->tx.sbuf; 163262306a36Sopenharmony_ci so->rx.buflen = ARRAY_SIZE(so->rx.sbuf); 163362306a36Sopenharmony_ci so->tx.buflen = ARRAY_SIZE(so->tx.sbuf); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci hrtimer_init(&so->rxtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); 163662306a36Sopenharmony_ci so->rxtimer.function = isotp_rx_timer_handler; 163762306a36Sopenharmony_ci hrtimer_init(&so->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); 163862306a36Sopenharmony_ci so->txtimer.function = isotp_tx_timer_handler; 163962306a36Sopenharmony_ci hrtimer_init(&so->txfrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); 164062306a36Sopenharmony_ci so->txfrtimer.function = isotp_txfr_timer_handler; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci init_waitqueue_head(&so->wait); 164362306a36Sopenharmony_ci spin_lock_init(&so->rx_lock); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci spin_lock(&isotp_notifier_lock); 164662306a36Sopenharmony_ci list_add_tail(&so->notifier, &isotp_notifier_list); 164762306a36Sopenharmony_ci spin_unlock(&isotp_notifier_lock); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci return 0; 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_cistatic __poll_t isotp_poll(struct file *file, struct socket *sock, poll_table *wait) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci struct sock *sk = sock->sk; 165562306a36Sopenharmony_ci struct isotp_sock *so = isotp_sk(sk); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci __poll_t mask = datagram_poll(file, sock, wait); 165862306a36Sopenharmony_ci poll_wait(file, &so->wait, wait); 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci /* Check for false positives due to TX state */ 166162306a36Sopenharmony_ci if ((mask & EPOLLWRNORM) && (so->tx.state != ISOTP_IDLE)) 166262306a36Sopenharmony_ci mask &= ~(EPOLLOUT | EPOLLWRNORM); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci return mask; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic int isotp_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd, 166862306a36Sopenharmony_ci unsigned long arg) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci /* no ioctls for socket layer -> hand it down to NIC layer */ 167162306a36Sopenharmony_ci return -ENOIOCTLCMD; 167262306a36Sopenharmony_ci} 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_cistatic const struct proto_ops isotp_ops = { 167562306a36Sopenharmony_ci .family = PF_CAN, 167662306a36Sopenharmony_ci .release = isotp_release, 167762306a36Sopenharmony_ci .bind = isotp_bind, 167862306a36Sopenharmony_ci .connect = sock_no_connect, 167962306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 168062306a36Sopenharmony_ci .accept = sock_no_accept, 168162306a36Sopenharmony_ci .getname = isotp_getname, 168262306a36Sopenharmony_ci .poll = isotp_poll, 168362306a36Sopenharmony_ci .ioctl = isotp_sock_no_ioctlcmd, 168462306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 168562306a36Sopenharmony_ci .listen = sock_no_listen, 168662306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 168762306a36Sopenharmony_ci .setsockopt = isotp_setsockopt, 168862306a36Sopenharmony_ci .getsockopt = isotp_getsockopt, 168962306a36Sopenharmony_ci .sendmsg = isotp_sendmsg, 169062306a36Sopenharmony_ci .recvmsg = isotp_recvmsg, 169162306a36Sopenharmony_ci .mmap = sock_no_mmap, 169262306a36Sopenharmony_ci}; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic struct proto isotp_proto __read_mostly = { 169562306a36Sopenharmony_ci .name = "CAN_ISOTP", 169662306a36Sopenharmony_ci .owner = THIS_MODULE, 169762306a36Sopenharmony_ci .obj_size = sizeof(struct isotp_sock), 169862306a36Sopenharmony_ci .init = isotp_init, 169962306a36Sopenharmony_ci}; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_cistatic const struct can_proto isotp_can_proto = { 170262306a36Sopenharmony_ci .type = SOCK_DGRAM, 170362306a36Sopenharmony_ci .protocol = CAN_ISOTP, 170462306a36Sopenharmony_ci .ops = &isotp_ops, 170562306a36Sopenharmony_ci .prot = &isotp_proto, 170662306a36Sopenharmony_ci}; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cistatic struct notifier_block canisotp_notifier = { 170962306a36Sopenharmony_ci .notifier_call = isotp_notifier 171062306a36Sopenharmony_ci}; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic __init int isotp_module_init(void) 171362306a36Sopenharmony_ci{ 171462306a36Sopenharmony_ci int err; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci max_pdu_size = max_t(unsigned int, max_pdu_size, MAX_12BIT_PDU_SIZE); 171762306a36Sopenharmony_ci max_pdu_size = min_t(unsigned int, max_pdu_size, MAX_PDU_SIZE); 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci pr_info("can: isotp protocol (max_pdu_size %d)\n", max_pdu_size); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci err = can_proto_register(&isotp_can_proto); 172262306a36Sopenharmony_ci if (err < 0) 172362306a36Sopenharmony_ci pr_err("can: registration of isotp protocol failed %pe\n", ERR_PTR(err)); 172462306a36Sopenharmony_ci else 172562306a36Sopenharmony_ci register_netdevice_notifier(&canisotp_notifier); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci return err; 172862306a36Sopenharmony_ci} 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_cistatic __exit void isotp_module_exit(void) 173162306a36Sopenharmony_ci{ 173262306a36Sopenharmony_ci can_proto_unregister(&isotp_can_proto); 173362306a36Sopenharmony_ci unregister_netdevice_notifier(&canisotp_notifier); 173462306a36Sopenharmony_ci} 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cimodule_init(isotp_module_init); 173762306a36Sopenharmony_cimodule_exit(isotp_module_exit); 1738