1e057dd3fSOliver Hartkopp // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2e057dd3fSOliver Hartkopp /* isotp.c - ISO 15765-2 CAN transport protocol for protocol family CAN
3e057dd3fSOliver Hartkopp *
4e057dd3fSOliver Hartkopp * This implementation does not provide ISO-TP specific return values to the
5e057dd3fSOliver Hartkopp * userspace.
6e057dd3fSOliver Hartkopp *
7e057dd3fSOliver Hartkopp * - RX path timeout of data reception leads to -ETIMEDOUT
8e057dd3fSOliver Hartkopp * - RX path SN mismatch leads to -EILSEQ
9e057dd3fSOliver Hartkopp * - RX path data reception with wrong padding leads to -EBADMSG
10e057dd3fSOliver Hartkopp * - TX path flowcontrol reception timeout leads to -ECOMM
11e057dd3fSOliver Hartkopp * - TX path flowcontrol reception overflow leads to -EMSGSIZE
12e057dd3fSOliver Hartkopp * - TX path flowcontrol reception with wrong layout/padding leads to -EBADMSG
13e057dd3fSOliver Hartkopp * - when a transfer (tx) is on the run the next write() blocks until it's done
14e057dd3fSOliver Hartkopp * - use CAN_ISOTP_WAIT_TX_DONE flag to block the caller until the PDU is sent
15e057dd3fSOliver Hartkopp * - as we have static buffers the check whether the PDU fits into the buffer
16e057dd3fSOliver Hartkopp * is done at FF reception time (no support for sending 'wait frames')
17e057dd3fSOliver Hartkopp *
18e057dd3fSOliver Hartkopp * Copyright (c) 2020 Volkswagen Group Electronic Research
19e057dd3fSOliver Hartkopp * All rights reserved.
20e057dd3fSOliver Hartkopp *
21e057dd3fSOliver Hartkopp * Redistribution and use in source and binary forms, with or without
22e057dd3fSOliver Hartkopp * modification, are permitted provided that the following conditions
23e057dd3fSOliver Hartkopp * are met:
24e057dd3fSOliver Hartkopp * 1. Redistributions of source code must retain the above copyright
25e057dd3fSOliver Hartkopp * notice, this list of conditions and the following disclaimer.
26e057dd3fSOliver Hartkopp * 2. Redistributions in binary form must reproduce the above copyright
27e057dd3fSOliver Hartkopp * notice, this list of conditions and the following disclaimer in the
28e057dd3fSOliver Hartkopp * documentation and/or other materials provided with the distribution.
29e057dd3fSOliver Hartkopp * 3. Neither the name of Volkswagen nor the names of its contributors
30e057dd3fSOliver Hartkopp * may be used to endorse or promote products derived from this software
31e057dd3fSOliver Hartkopp * without specific prior written permission.
32e057dd3fSOliver Hartkopp *
33e057dd3fSOliver Hartkopp * Alternatively, provided that this notice is retained in full, this
34e057dd3fSOliver Hartkopp * software may be distributed under the terms of the GNU General
35e057dd3fSOliver Hartkopp * Public License ("GPL") version 2, in which case the provisions of the
36e057dd3fSOliver Hartkopp * GPL apply INSTEAD OF those given above.
37e057dd3fSOliver Hartkopp *
38e057dd3fSOliver Hartkopp * The provided data structures and external interfaces from this code
39e057dd3fSOliver Hartkopp * are not restricted to be used by modules with a GPL compatible license.
40e057dd3fSOliver Hartkopp *
41e057dd3fSOliver Hartkopp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42e057dd3fSOliver Hartkopp * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
43e057dd3fSOliver Hartkopp * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
44e057dd3fSOliver Hartkopp * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
45e057dd3fSOliver Hartkopp * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46e057dd3fSOliver Hartkopp * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47e057dd3fSOliver Hartkopp * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48e057dd3fSOliver Hartkopp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49e057dd3fSOliver Hartkopp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50e057dd3fSOliver Hartkopp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
51e057dd3fSOliver Hartkopp * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
52e057dd3fSOliver Hartkopp * DAMAGE.
53e057dd3fSOliver Hartkopp */
54e057dd3fSOliver Hartkopp
55e057dd3fSOliver Hartkopp #include <linux/module.h>
56e057dd3fSOliver Hartkopp #include <linux/init.h>
57e057dd3fSOliver Hartkopp #include <linux/interrupt.h>
587c759040SOliver Hartkopp #include <linux/spinlock.h>
59e057dd3fSOliver Hartkopp #include <linux/hrtimer.h>
60e057dd3fSOliver Hartkopp #include <linux/wait.h>
61e057dd3fSOliver Hartkopp #include <linux/uio.h>
62e057dd3fSOliver Hartkopp #include <linux/net.h>
63e057dd3fSOliver Hartkopp #include <linux/netdevice.h>
64e057dd3fSOliver Hartkopp #include <linux/socket.h>
65e057dd3fSOliver Hartkopp #include <linux/if_arp.h>
66e057dd3fSOliver Hartkopp #include <linux/skbuff.h>
67e057dd3fSOliver Hartkopp #include <linux/can.h>
68e057dd3fSOliver Hartkopp #include <linux/can/core.h>
69e057dd3fSOliver Hartkopp #include <linux/can/skb.h>
70e057dd3fSOliver Hartkopp #include <linux/can/isotp.h>
71e057dd3fSOliver Hartkopp #include <linux/slab.h>
72e057dd3fSOliver Hartkopp #include <net/sock.h>
73e057dd3fSOliver Hartkopp #include <net/net_namespace.h>
74e057dd3fSOliver Hartkopp
75e057dd3fSOliver Hartkopp MODULE_DESCRIPTION("PF_CAN isotp 15765-2:2016 protocol");
76e057dd3fSOliver Hartkopp MODULE_LICENSE("Dual BSD/GPL");
77e057dd3fSOliver Hartkopp MODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>");
78e057dd3fSOliver Hartkopp MODULE_ALIAS("can-proto-6");
79e057dd3fSOliver Hartkopp
80f522d955SOliver Hartkopp #define ISOTP_MIN_NAMELEN CAN_REQUIRED_SIZE(struct sockaddr_can, can_addr.tp)
81f522d955SOliver Hartkopp
82e057dd3fSOliver Hartkopp #define SINGLE_MASK(id) (((id) & CAN_EFF_FLAG) ? \
83e057dd3fSOliver Hartkopp (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \
84e057dd3fSOliver Hartkopp (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG))
85e057dd3fSOliver Hartkopp
86e057dd3fSOliver Hartkopp /* ISO 15765-2:2016 supports more than 4095 byte per ISO PDU as the FF_DL can
87e057dd3fSOliver Hartkopp * take full 32 bit values (4 Gbyte). We would need some good concept to handle
8896d1c81eSOliver Hartkopp * this between user space and kernel space. For now set the static buffer to
8996d1c81eSOliver Hartkopp * something about 8 kbyte to be able to test this new functionality.
90e057dd3fSOliver Hartkopp */
9196d1c81eSOliver Hartkopp #define DEFAULT_MAX_PDU_SIZE 8300
9296d1c81eSOliver Hartkopp
9396d1c81eSOliver Hartkopp /* maximum PDU size before ISO 15765-2:2016 extension was 4095 */
9496d1c81eSOliver Hartkopp #define MAX_12BIT_PDU_SIZE 4095
9596d1c81eSOliver Hartkopp
9696d1c81eSOliver Hartkopp /* limit the isotp pdu size from the optional module parameter to 1MByte */
9796d1c81eSOliver Hartkopp #define MAX_PDU_SIZE (1025 * 1024U)
9896d1c81eSOliver Hartkopp
9996d1c81eSOliver Hartkopp static unsigned int max_pdu_size __read_mostly = DEFAULT_MAX_PDU_SIZE;
10096d1c81eSOliver Hartkopp module_param(max_pdu_size, uint, 0444);
10196d1c81eSOliver Hartkopp MODULE_PARM_DESC(max_pdu_size, "maximum isotp pdu size (default "
10296d1c81eSOliver Hartkopp __stringify(DEFAULT_MAX_PDU_SIZE) ")");
103e057dd3fSOliver Hartkopp
104e057dd3fSOliver Hartkopp /* N_PCI type values in bits 7-4 of N_PCI bytes */
105e057dd3fSOliver Hartkopp #define N_PCI_SF 0x00 /* single frame */
106e057dd3fSOliver Hartkopp #define N_PCI_FF 0x10 /* first frame */
107e057dd3fSOliver Hartkopp #define N_PCI_CF 0x20 /* consecutive frame */
108e057dd3fSOliver Hartkopp #define N_PCI_FC 0x30 /* flow control */
109e057dd3fSOliver Hartkopp
110e057dd3fSOliver Hartkopp #define N_PCI_SZ 1 /* size of the PCI byte #1 */
111e057dd3fSOliver Hartkopp #define SF_PCI_SZ4 1 /* size of SingleFrame PCI including 4 bit SF_DL */
112e057dd3fSOliver Hartkopp #define SF_PCI_SZ8 2 /* size of SingleFrame PCI including 8 bit SF_DL */
113e057dd3fSOliver Hartkopp #define FF_PCI_SZ12 2 /* size of FirstFrame PCI including 12 bit FF_DL */
114e057dd3fSOliver Hartkopp #define FF_PCI_SZ32 6 /* size of FirstFrame PCI including 32 bit FF_DL */
115e057dd3fSOliver Hartkopp #define FC_CONTENT_SZ 3 /* flow control content size in byte (FS/BS/STmin) */
116e057dd3fSOliver Hartkopp
117e057dd3fSOliver Hartkopp #define ISOTP_CHECK_PADDING (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA)
1189f39d365SOliver Hartkopp #define ISOTP_ALL_BC_FLAGS (CAN_ISOTP_SF_BROADCAST | CAN_ISOTP_CF_BROADCAST)
119e057dd3fSOliver Hartkopp
120e057dd3fSOliver Hartkopp /* Flow Status given in FC frame */
121e057dd3fSOliver Hartkopp #define ISOTP_FC_CTS 0 /* clear to send */
122e057dd3fSOliver Hartkopp #define ISOTP_FC_WT 1 /* wait */
123e057dd3fSOliver Hartkopp #define ISOTP_FC_OVFLW 2 /* overflow */
124e057dd3fSOliver Hartkopp
12586633786SOliver Hartkopp #define ISOTP_FC_TIMEOUT 1 /* 1 sec */
12686633786SOliver Hartkopp #define ISOTP_ECHO_TIMEOUT 2 /* 2 secs */
12786633786SOliver Hartkopp
128e057dd3fSOliver Hartkopp enum {
129e057dd3fSOliver Hartkopp ISOTP_IDLE = 0,
130e057dd3fSOliver Hartkopp ISOTP_WAIT_FIRST_FC,
131e057dd3fSOliver Hartkopp ISOTP_WAIT_FC,
132e057dd3fSOliver Hartkopp ISOTP_WAIT_DATA,
13305173743SOliver Hartkopp ISOTP_SENDING,
13405173743SOliver Hartkopp ISOTP_SHUTDOWN,
135e057dd3fSOliver Hartkopp };
136e057dd3fSOliver Hartkopp
137e057dd3fSOliver Hartkopp struct tpcon {
13896d1c81eSOliver Hartkopp u8 *buf;
13996d1c81eSOliver Hartkopp unsigned int buflen;
1405f33a09eSMarc Kleine-Budde unsigned int len;
14196d1c81eSOliver Hartkopp unsigned int idx;
14243a08c3bSZiyang Xuan u32 state;
143e057dd3fSOliver Hartkopp u8 bs;
144e057dd3fSOliver Hartkopp u8 sn;
145e057dd3fSOliver Hartkopp u8 ll_dl;
14696d1c81eSOliver Hartkopp u8 sbuf[DEFAULT_MAX_PDU_SIZE];
147e057dd3fSOliver Hartkopp };
148e057dd3fSOliver Hartkopp
149e057dd3fSOliver Hartkopp struct isotp_sock {
150e057dd3fSOliver Hartkopp struct sock sk;
151e057dd3fSOliver Hartkopp int bound;
152e057dd3fSOliver Hartkopp int ifindex;
153e057dd3fSOliver Hartkopp canid_t txid;
154e057dd3fSOliver Hartkopp canid_t rxid;
155e057dd3fSOliver Hartkopp ktime_t tx_gap;
156e057dd3fSOliver Hartkopp ktime_t lastrxcf_tstamp;
1574f027cbaSOliver Hartkopp struct hrtimer rxtimer, txtimer, txfrtimer;
158e057dd3fSOliver Hartkopp struct can_isotp_options opt;
159e057dd3fSOliver Hartkopp struct can_isotp_fc_options rxfc, txfc;
160e057dd3fSOliver Hartkopp struct can_isotp_ll_options ll;
161530e0d46SOliver Hartkopp u32 frame_txtime;
162e057dd3fSOliver Hartkopp u32 force_tx_stmin;
163e057dd3fSOliver Hartkopp u32 force_rx_stmin;
1644b7fe92cSOliver Hartkopp u32 cfecho; /* consecutive frame echo tag */
165e057dd3fSOliver Hartkopp struct tpcon rx, tx;
1668d0caedbSTetsuo Handa struct list_head notifier;
167e057dd3fSOliver Hartkopp wait_queue_head_t wait;
1687c759040SOliver Hartkopp spinlock_t rx_lock; /* protect single thread state machine */
169e057dd3fSOliver Hartkopp };
170e057dd3fSOliver Hartkopp
1718d0caedbSTetsuo Handa static LIST_HEAD(isotp_notifier_list);
1728d0caedbSTetsuo Handa static DEFINE_SPINLOCK(isotp_notifier_lock);
1738d0caedbSTetsuo Handa static struct isotp_sock *isotp_busy_notifier;
1748d0caedbSTetsuo Handa
isotp_sk(const struct sock * sk)175e057dd3fSOliver Hartkopp static inline struct isotp_sock *isotp_sk(const struct sock *sk)
176e057dd3fSOliver Hartkopp {
177e057dd3fSOliver Hartkopp return (struct isotp_sock *)sk;
178e057dd3fSOliver Hartkopp }
179e057dd3fSOliver Hartkopp
isotp_bc_flags(struct isotp_sock * so)1809f39d365SOliver Hartkopp static u32 isotp_bc_flags(struct isotp_sock *so)
1819f39d365SOliver Hartkopp {
1829f39d365SOliver Hartkopp return so->opt.flags & ISOTP_ALL_BC_FLAGS;
1839f39d365SOliver Hartkopp }
1849f39d365SOliver Hartkopp
isotp_register_rxid(struct isotp_sock * so)1859f39d365SOliver Hartkopp static bool isotp_register_rxid(struct isotp_sock *so)
1869f39d365SOliver Hartkopp {
1879f39d365SOliver Hartkopp /* no broadcast modes => register rx_id for FC frame reception */
1889f39d365SOliver Hartkopp return (isotp_bc_flags(so) == 0);
1899f39d365SOliver Hartkopp }
1909f39d365SOliver Hartkopp
isotp_rx_timer_handler(struct hrtimer * hrtimer)191e057dd3fSOliver Hartkopp static enum hrtimer_restart isotp_rx_timer_handler(struct hrtimer *hrtimer)
192e057dd3fSOliver Hartkopp {
193e057dd3fSOliver Hartkopp struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
194e057dd3fSOliver Hartkopp rxtimer);
195e057dd3fSOliver Hartkopp struct sock *sk = &so->sk;
196e057dd3fSOliver Hartkopp
197e057dd3fSOliver Hartkopp if (so->rx.state == ISOTP_WAIT_DATA) {
198e057dd3fSOliver Hartkopp /* we did not get new data frames in time */
199e057dd3fSOliver Hartkopp
200e057dd3fSOliver Hartkopp /* report 'connection timed out' */
201e057dd3fSOliver Hartkopp sk->sk_err = ETIMEDOUT;
202e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
203e3ae2365SAlexander Aring sk_error_report(sk);
204e057dd3fSOliver Hartkopp
205e057dd3fSOliver Hartkopp /* reset rx state */
206e057dd3fSOliver Hartkopp so->rx.state = ISOTP_IDLE;
207e057dd3fSOliver Hartkopp }
208e057dd3fSOliver Hartkopp
209e057dd3fSOliver Hartkopp return HRTIMER_NORESTART;
210e057dd3fSOliver Hartkopp }
211e057dd3fSOliver Hartkopp
isotp_send_fc(struct sock * sk,int ae,u8 flowstatus)212e057dd3fSOliver Hartkopp static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus)
213e057dd3fSOliver Hartkopp {
214e057dd3fSOliver Hartkopp struct net_device *dev;
215e057dd3fSOliver Hartkopp struct sk_buff *nskb;
216e057dd3fSOliver Hartkopp struct canfd_frame *ncf;
217e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
218e057dd3fSOliver Hartkopp int can_send_ret;
219e057dd3fSOliver Hartkopp
220e057dd3fSOliver Hartkopp nskb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), gfp_any());
221e057dd3fSOliver Hartkopp if (!nskb)
222e057dd3fSOliver Hartkopp return 1;
223e057dd3fSOliver Hartkopp
224e057dd3fSOliver Hartkopp dev = dev_get_by_index(sock_net(sk), so->ifindex);
225e057dd3fSOliver Hartkopp if (!dev) {
226e057dd3fSOliver Hartkopp kfree_skb(nskb);
227e057dd3fSOliver Hartkopp return 1;
228e057dd3fSOliver Hartkopp }
229e057dd3fSOliver Hartkopp
230e057dd3fSOliver Hartkopp can_skb_reserve(nskb);
231e057dd3fSOliver Hartkopp can_skb_prv(nskb)->ifindex = dev->ifindex;
232e057dd3fSOliver Hartkopp can_skb_prv(nskb)->skbcnt = 0;
233e057dd3fSOliver Hartkopp
234e057dd3fSOliver Hartkopp nskb->dev = dev;
235e057dd3fSOliver Hartkopp can_skb_set_owner(nskb, sk);
236e057dd3fSOliver Hartkopp ncf = (struct canfd_frame *)nskb->data;
237b5f020f8SOliver Hartkopp skb_put_zero(nskb, so->ll.mtu);
238e057dd3fSOliver Hartkopp
239e057dd3fSOliver Hartkopp /* create & send flow control reply */
240e057dd3fSOliver Hartkopp ncf->can_id = so->txid;
241e057dd3fSOliver Hartkopp
242e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_TX_PADDING) {
243e057dd3fSOliver Hartkopp memset(ncf->data, so->opt.txpad_content, CAN_MAX_DLEN);
244e057dd3fSOliver Hartkopp ncf->len = CAN_MAX_DLEN;
245e057dd3fSOliver Hartkopp } else {
246e057dd3fSOliver Hartkopp ncf->len = ae + FC_CONTENT_SZ;
247e057dd3fSOliver Hartkopp }
248e057dd3fSOliver Hartkopp
249e057dd3fSOliver Hartkopp ncf->data[ae] = N_PCI_FC | flowstatus;
250e057dd3fSOliver Hartkopp ncf->data[ae + 1] = so->rxfc.bs;
251e057dd3fSOliver Hartkopp ncf->data[ae + 2] = so->rxfc.stmin;
252e057dd3fSOliver Hartkopp
253e057dd3fSOliver Hartkopp if (ae)
254e057dd3fSOliver Hartkopp ncf->data[0] = so->opt.ext_address;
255e057dd3fSOliver Hartkopp
256e057dd3fSOliver Hartkopp ncf->flags = so->ll.tx_flags;
257e057dd3fSOliver Hartkopp
258e057dd3fSOliver Hartkopp can_send_ret = can_send(nskb, 1);
259e057dd3fSOliver Hartkopp if (can_send_ret)
26046d8657aSPatrick Menschel pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
26146d8657aSPatrick Menschel __func__, ERR_PTR(can_send_ret));
262e057dd3fSOliver Hartkopp
263e057dd3fSOliver Hartkopp dev_put(dev);
264e057dd3fSOliver Hartkopp
265e057dd3fSOliver Hartkopp /* reset blocksize counter */
266e057dd3fSOliver Hartkopp so->rx.bs = 0;
267e057dd3fSOliver Hartkopp
268e057dd3fSOliver Hartkopp /* reset last CF frame rx timestamp for rx stmin enforcement */
269e057dd3fSOliver Hartkopp so->lastrxcf_tstamp = ktime_set(0, 0);
270e057dd3fSOliver Hartkopp
271e057dd3fSOliver Hartkopp /* start rx timeout watchdog */
27286633786SOliver Hartkopp hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
27386633786SOliver Hartkopp HRTIMER_MODE_REL_SOFT);
274e057dd3fSOliver Hartkopp return 0;
275e057dd3fSOliver Hartkopp }
276e057dd3fSOliver Hartkopp
isotp_rcv_skb(struct sk_buff * skb,struct sock * sk)277e057dd3fSOliver Hartkopp static void isotp_rcv_skb(struct sk_buff *skb, struct sock *sk)
278e057dd3fSOliver Hartkopp {
279e057dd3fSOliver Hartkopp struct sockaddr_can *addr = (struct sockaddr_can *)skb->cb;
280e057dd3fSOliver Hartkopp
281e057dd3fSOliver Hartkopp BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct sockaddr_can));
282e057dd3fSOliver Hartkopp
283e057dd3fSOliver Hartkopp memset(addr, 0, sizeof(*addr));
284e057dd3fSOliver Hartkopp addr->can_family = AF_CAN;
285e057dd3fSOliver Hartkopp addr->can_ifindex = skb->dev->ifindex;
286e057dd3fSOliver Hartkopp
287e057dd3fSOliver Hartkopp if (sock_queue_rcv_skb(sk, skb) < 0)
288e057dd3fSOliver Hartkopp kfree_skb(skb);
289e057dd3fSOliver Hartkopp }
290e057dd3fSOliver Hartkopp
padlen(u8 datalen)291e057dd3fSOliver Hartkopp static u8 padlen(u8 datalen)
292e057dd3fSOliver Hartkopp {
293c3ddac4bSColin Ian King static const u8 plen[] = {
294c3ddac4bSColin Ian King 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0 - 8 */
295e057dd3fSOliver Hartkopp 12, 12, 12, 12, /* 9 - 12 */
296e057dd3fSOliver Hartkopp 16, 16, 16, 16, /* 13 - 16 */
297e057dd3fSOliver Hartkopp 20, 20, 20, 20, /* 17 - 20 */
298e057dd3fSOliver Hartkopp 24, 24, 24, 24, /* 21 - 24 */
299e057dd3fSOliver Hartkopp 32, 32, 32, 32, 32, 32, 32, 32, /* 25 - 32 */
300e057dd3fSOliver Hartkopp 48, 48, 48, 48, 48, 48, 48, 48, /* 33 - 40 */
301c3ddac4bSColin Ian King 48, 48, 48, 48, 48, 48, 48, 48 /* 41 - 48 */
302c3ddac4bSColin Ian King };
303e057dd3fSOliver Hartkopp
304e057dd3fSOliver Hartkopp if (datalen > 48)
305e057dd3fSOliver Hartkopp return 64;
306e057dd3fSOliver Hartkopp
307e057dd3fSOliver Hartkopp return plen[datalen];
308e057dd3fSOliver Hartkopp }
309e057dd3fSOliver Hartkopp
310e057dd3fSOliver Hartkopp /* check for length optimization and return 1/true when the check fails */
check_optimized(struct canfd_frame * cf,int start_index)311e057dd3fSOliver Hartkopp static int check_optimized(struct canfd_frame *cf, int start_index)
312e057dd3fSOliver Hartkopp {
313e057dd3fSOliver Hartkopp /* for CAN_DL <= 8 the start_index is equal to the CAN_DL as the
314e057dd3fSOliver Hartkopp * padding would start at this point. E.g. if the padding would
315e057dd3fSOliver Hartkopp * start at cf.data[7] cf->len has to be 7 to be optimal.
316e057dd3fSOliver Hartkopp * Note: The data[] index starts with zero.
317e057dd3fSOliver Hartkopp */
318e057dd3fSOliver Hartkopp if (cf->len <= CAN_MAX_DLEN)
319e057dd3fSOliver Hartkopp return (cf->len != start_index);
320e057dd3fSOliver Hartkopp
321e057dd3fSOliver Hartkopp /* This relation is also valid in the non-linear DLC range, where
322e057dd3fSOliver Hartkopp * we need to take care of the minimal next possible CAN_DL.
323e057dd3fSOliver Hartkopp * The correct check would be (padlen(cf->len) != padlen(start_index)).
324e057dd3fSOliver Hartkopp * But as cf->len can only take discrete values from 12, .., 64 at this
325e057dd3fSOliver Hartkopp * point the padlen(cf->len) is always equal to cf->len.
326e057dd3fSOliver Hartkopp */
327e057dd3fSOliver Hartkopp return (cf->len != padlen(start_index));
328e057dd3fSOliver Hartkopp }
329e057dd3fSOliver Hartkopp
330e057dd3fSOliver Hartkopp /* check padding and return 1/true when the check fails */
check_pad(struct isotp_sock * so,struct canfd_frame * cf,int start_index,u8 content)331e057dd3fSOliver Hartkopp static int check_pad(struct isotp_sock *so, struct canfd_frame *cf,
332e057dd3fSOliver Hartkopp int start_index, u8 content)
333e057dd3fSOliver Hartkopp {
334e057dd3fSOliver Hartkopp int i;
335e057dd3fSOliver Hartkopp
336e057dd3fSOliver Hartkopp /* no RX_PADDING value => check length of optimized frame length */
337e057dd3fSOliver Hartkopp if (!(so->opt.flags & CAN_ISOTP_RX_PADDING)) {
338e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_CHK_PAD_LEN)
339e057dd3fSOliver Hartkopp return check_optimized(cf, start_index);
340e057dd3fSOliver Hartkopp
341e057dd3fSOliver Hartkopp /* no valid test against empty value => ignore frame */
342e057dd3fSOliver Hartkopp return 1;
343e057dd3fSOliver Hartkopp }
344e057dd3fSOliver Hartkopp
345e057dd3fSOliver Hartkopp /* check datalength of correctly padded CAN frame */
346e057dd3fSOliver Hartkopp if ((so->opt.flags & CAN_ISOTP_CHK_PAD_LEN) &&
347e057dd3fSOliver Hartkopp cf->len != padlen(cf->len))
348e057dd3fSOliver Hartkopp return 1;
349e057dd3fSOliver Hartkopp
350e057dd3fSOliver Hartkopp /* check padding content */
351e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_CHK_PAD_DATA) {
352e057dd3fSOliver Hartkopp for (i = start_index; i < cf->len; i++)
353e057dd3fSOliver Hartkopp if (cf->data[i] != content)
354e057dd3fSOliver Hartkopp return 1;
355e057dd3fSOliver Hartkopp }
356e057dd3fSOliver Hartkopp return 0;
357e057dd3fSOliver Hartkopp }
358e057dd3fSOliver Hartkopp
35986633786SOliver Hartkopp static void isotp_send_cframe(struct isotp_sock *so);
36086633786SOliver Hartkopp
isotp_rcv_fc(struct isotp_sock * so,struct canfd_frame * cf,int ae)361e057dd3fSOliver Hartkopp static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
362e057dd3fSOliver Hartkopp {
363e057dd3fSOliver Hartkopp struct sock *sk = &so->sk;
364e057dd3fSOliver Hartkopp
365e057dd3fSOliver Hartkopp if (so->tx.state != ISOTP_WAIT_FC &&
366e057dd3fSOliver Hartkopp so->tx.state != ISOTP_WAIT_FIRST_FC)
367e057dd3fSOliver Hartkopp return 0;
368e057dd3fSOliver Hartkopp
369e057dd3fSOliver Hartkopp hrtimer_cancel(&so->txtimer);
370e057dd3fSOliver Hartkopp
371e057dd3fSOliver Hartkopp if ((cf->len < ae + FC_CONTENT_SZ) ||
372e057dd3fSOliver Hartkopp ((so->opt.flags & ISOTP_CHECK_PADDING) &&
373e057dd3fSOliver Hartkopp check_pad(so, cf, ae + FC_CONTENT_SZ, so->opt.rxpad_content))) {
374e057dd3fSOliver Hartkopp /* malformed PDU - report 'not a data message' */
375e057dd3fSOliver Hartkopp sk->sk_err = EBADMSG;
376e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
377e3ae2365SAlexander Aring sk_error_report(sk);
378e057dd3fSOliver Hartkopp
379e057dd3fSOliver Hartkopp so->tx.state = ISOTP_IDLE;
380e057dd3fSOliver Hartkopp wake_up_interruptible(&so->wait);
381e057dd3fSOliver Hartkopp return 1;
382e057dd3fSOliver Hartkopp }
383e057dd3fSOliver Hartkopp
384e057dd3fSOliver Hartkopp /* get communication parameters only from the first FC frame */
385e057dd3fSOliver Hartkopp if (so->tx.state == ISOTP_WAIT_FIRST_FC) {
386e057dd3fSOliver Hartkopp so->txfc.bs = cf->data[ae + 1];
387e057dd3fSOliver Hartkopp so->txfc.stmin = cf->data[ae + 2];
388e057dd3fSOliver Hartkopp
389e057dd3fSOliver Hartkopp /* fix wrong STmin values according spec */
390e057dd3fSOliver Hartkopp if (so->txfc.stmin > 0x7F &&
391e057dd3fSOliver Hartkopp (so->txfc.stmin < 0xF1 || so->txfc.stmin > 0xF9))
392e057dd3fSOliver Hartkopp so->txfc.stmin = 0x7F;
393e057dd3fSOliver Hartkopp
394e057dd3fSOliver Hartkopp so->tx_gap = ktime_set(0, 0);
395e057dd3fSOliver Hartkopp /* add transmission time for CAN frame N_As */
396530e0d46SOliver Hartkopp so->tx_gap = ktime_add_ns(so->tx_gap, so->frame_txtime);
397e057dd3fSOliver Hartkopp /* add waiting time for consecutive frames N_Cs */
398e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_FORCE_TXSTMIN)
399e057dd3fSOliver Hartkopp so->tx_gap = ktime_add_ns(so->tx_gap,
400e057dd3fSOliver Hartkopp so->force_tx_stmin);
401e057dd3fSOliver Hartkopp else if (so->txfc.stmin < 0x80)
402e057dd3fSOliver Hartkopp so->tx_gap = ktime_add_ns(so->tx_gap,
403e057dd3fSOliver Hartkopp so->txfc.stmin * 1000000);
404e057dd3fSOliver Hartkopp else
405e057dd3fSOliver Hartkopp so->tx_gap = ktime_add_ns(so->tx_gap,
406e057dd3fSOliver Hartkopp (so->txfc.stmin - 0xF0)
407e057dd3fSOliver Hartkopp * 100000);
408e057dd3fSOliver Hartkopp so->tx.state = ISOTP_WAIT_FC;
409e057dd3fSOliver Hartkopp }
410e057dd3fSOliver Hartkopp
411e057dd3fSOliver Hartkopp switch (cf->data[ae] & 0x0F) {
412e057dd3fSOliver Hartkopp case ISOTP_FC_CTS:
413e057dd3fSOliver Hartkopp so->tx.bs = 0;
414e057dd3fSOliver Hartkopp so->tx.state = ISOTP_SENDING;
41586633786SOliver Hartkopp /* send CF frame and enable echo timeout handling */
41686633786SOliver Hartkopp hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
417e057dd3fSOliver Hartkopp HRTIMER_MODE_REL_SOFT);
41886633786SOliver Hartkopp isotp_send_cframe(so);
419e057dd3fSOliver Hartkopp break;
420e057dd3fSOliver Hartkopp
421e057dd3fSOliver Hartkopp case ISOTP_FC_WT:
422e057dd3fSOliver Hartkopp /* start timer to wait for next FC frame */
42386633786SOliver Hartkopp hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
424e057dd3fSOliver Hartkopp HRTIMER_MODE_REL_SOFT);
425e057dd3fSOliver Hartkopp break;
426e057dd3fSOliver Hartkopp
427e057dd3fSOliver Hartkopp case ISOTP_FC_OVFLW:
428e057dd3fSOliver Hartkopp /* overflow on receiver side - report 'message too long' */
429e057dd3fSOliver Hartkopp sk->sk_err = EMSGSIZE;
430e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
431e3ae2365SAlexander Aring sk_error_report(sk);
432e057dd3fSOliver Hartkopp fallthrough;
433e057dd3fSOliver Hartkopp
434e057dd3fSOliver Hartkopp default:
435e057dd3fSOliver Hartkopp /* stop this tx job */
436e057dd3fSOliver Hartkopp so->tx.state = ISOTP_IDLE;
437e057dd3fSOliver Hartkopp wake_up_interruptible(&so->wait);
438e057dd3fSOliver Hartkopp }
439e057dd3fSOliver Hartkopp return 0;
440e057dd3fSOliver Hartkopp }
441e057dd3fSOliver Hartkopp
isotp_rcv_sf(struct sock * sk,struct canfd_frame * cf,int pcilen,struct sk_buff * skb,int len)442e057dd3fSOliver Hartkopp static int isotp_rcv_sf(struct sock *sk, struct canfd_frame *cf, int pcilen,
443e057dd3fSOliver Hartkopp struct sk_buff *skb, int len)
444e057dd3fSOliver Hartkopp {
445e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
446e057dd3fSOliver Hartkopp struct sk_buff *nskb;
447e057dd3fSOliver Hartkopp
448e057dd3fSOliver Hartkopp hrtimer_cancel(&so->rxtimer);
449e057dd3fSOliver Hartkopp so->rx.state = ISOTP_IDLE;
450e057dd3fSOliver Hartkopp
451e057dd3fSOliver Hartkopp if (!len || len > cf->len - pcilen)
452e057dd3fSOliver Hartkopp return 1;
453e057dd3fSOliver Hartkopp
454e057dd3fSOliver Hartkopp if ((so->opt.flags & ISOTP_CHECK_PADDING) &&
455e057dd3fSOliver Hartkopp check_pad(so, cf, pcilen + len, so->opt.rxpad_content)) {
456e057dd3fSOliver Hartkopp /* malformed PDU - report 'not a data message' */
457e057dd3fSOliver Hartkopp sk->sk_err = EBADMSG;
458e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
459e3ae2365SAlexander Aring sk_error_report(sk);
460e057dd3fSOliver Hartkopp return 1;
461e057dd3fSOliver Hartkopp }
462e057dd3fSOliver Hartkopp
463e057dd3fSOliver Hartkopp nskb = alloc_skb(len, gfp_any());
464e057dd3fSOliver Hartkopp if (!nskb)
465e057dd3fSOliver Hartkopp return 1;
466e057dd3fSOliver Hartkopp
467e057dd3fSOliver Hartkopp memcpy(skb_put(nskb, len), &cf->data[pcilen], len);
468e057dd3fSOliver Hartkopp
469e057dd3fSOliver Hartkopp nskb->tstamp = skb->tstamp;
470e057dd3fSOliver Hartkopp nskb->dev = skb->dev;
471e057dd3fSOliver Hartkopp isotp_rcv_skb(nskb, sk);
472e057dd3fSOliver Hartkopp return 0;
473e057dd3fSOliver Hartkopp }
474e057dd3fSOliver Hartkopp
isotp_rcv_ff(struct sock * sk,struct canfd_frame * cf,int ae)475e057dd3fSOliver Hartkopp static int isotp_rcv_ff(struct sock *sk, struct canfd_frame *cf, int ae)
476e057dd3fSOliver Hartkopp {
477e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
478e057dd3fSOliver Hartkopp int i;
479e057dd3fSOliver Hartkopp int off;
480e057dd3fSOliver Hartkopp int ff_pci_sz;
481e057dd3fSOliver Hartkopp
482e057dd3fSOliver Hartkopp hrtimer_cancel(&so->rxtimer);
483e057dd3fSOliver Hartkopp so->rx.state = ISOTP_IDLE;
484e057dd3fSOliver Hartkopp
485e057dd3fSOliver Hartkopp /* get the used sender LL_DL from the (first) CAN frame data length */
486e057dd3fSOliver Hartkopp so->rx.ll_dl = padlen(cf->len);
487e057dd3fSOliver Hartkopp
488e057dd3fSOliver Hartkopp /* the first frame has to use the entire frame up to LL_DL length */
489e057dd3fSOliver Hartkopp if (cf->len != so->rx.ll_dl)
490e057dd3fSOliver Hartkopp return 1;
491e057dd3fSOliver Hartkopp
492e057dd3fSOliver Hartkopp /* get the FF_DL */
493e057dd3fSOliver Hartkopp so->rx.len = (cf->data[ae] & 0x0F) << 8;
494e057dd3fSOliver Hartkopp so->rx.len += cf->data[ae + 1];
495e057dd3fSOliver Hartkopp
496e057dd3fSOliver Hartkopp /* Check for FF_DL escape sequence supporting 32 bit PDU length */
497e057dd3fSOliver Hartkopp if (so->rx.len) {
498e057dd3fSOliver Hartkopp ff_pci_sz = FF_PCI_SZ12;
499e057dd3fSOliver Hartkopp } else {
500e057dd3fSOliver Hartkopp /* FF_DL = 0 => get real length from next 4 bytes */
501e057dd3fSOliver Hartkopp so->rx.len = cf->data[ae + 2] << 24;
502e057dd3fSOliver Hartkopp so->rx.len += cf->data[ae + 3] << 16;
503e057dd3fSOliver Hartkopp so->rx.len += cf->data[ae + 4] << 8;
504e057dd3fSOliver Hartkopp so->rx.len += cf->data[ae + 5];
505e057dd3fSOliver Hartkopp ff_pci_sz = FF_PCI_SZ32;
506e057dd3fSOliver Hartkopp }
507e057dd3fSOliver Hartkopp
508e057dd3fSOliver Hartkopp /* take care of a potential SF_DL ESC offset for TX_DL > 8 */
509e057dd3fSOliver Hartkopp off = (so->rx.ll_dl > CAN_MAX_DLEN) ? 1 : 0;
510e057dd3fSOliver Hartkopp
511e057dd3fSOliver Hartkopp if (so->rx.len + ae + off + ff_pci_sz < so->rx.ll_dl)
512e057dd3fSOliver Hartkopp return 1;
513e057dd3fSOliver Hartkopp
51496d1c81eSOliver Hartkopp /* PDU size > default => try max_pdu_size */
51596d1c81eSOliver Hartkopp if (so->rx.len > so->rx.buflen && so->rx.buflen < max_pdu_size) {
51696d1c81eSOliver Hartkopp u8 *newbuf = kmalloc(max_pdu_size, GFP_ATOMIC);
51796d1c81eSOliver Hartkopp
51896d1c81eSOliver Hartkopp if (newbuf) {
51996d1c81eSOliver Hartkopp so->rx.buf = newbuf;
52096d1c81eSOliver Hartkopp so->rx.buflen = max_pdu_size;
52196d1c81eSOliver Hartkopp }
52296d1c81eSOliver Hartkopp }
52396d1c81eSOliver Hartkopp
52496d1c81eSOliver Hartkopp if (so->rx.len > so->rx.buflen) {
525e057dd3fSOliver Hartkopp /* send FC frame with overflow status */
526e057dd3fSOliver Hartkopp isotp_send_fc(sk, ae, ISOTP_FC_OVFLW);
527e057dd3fSOliver Hartkopp return 1;
528e057dd3fSOliver Hartkopp }
529e057dd3fSOliver Hartkopp
530e057dd3fSOliver Hartkopp /* copy the first received data bytes */
531e057dd3fSOliver Hartkopp so->rx.idx = 0;
532e057dd3fSOliver Hartkopp for (i = ae + ff_pci_sz; i < so->rx.ll_dl; i++)
533e057dd3fSOliver Hartkopp so->rx.buf[so->rx.idx++] = cf->data[i];
534e057dd3fSOliver Hartkopp
535e057dd3fSOliver Hartkopp /* initial setup for this pdu reception */
536e057dd3fSOliver Hartkopp so->rx.sn = 1;
537e057dd3fSOliver Hartkopp so->rx.state = ISOTP_WAIT_DATA;
538e057dd3fSOliver Hartkopp
539e057dd3fSOliver Hartkopp /* no creation of flow control frames */
540e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_LISTEN_MODE)
541e057dd3fSOliver Hartkopp return 0;
542e057dd3fSOliver Hartkopp
543e057dd3fSOliver Hartkopp /* send our first FC frame */
544e057dd3fSOliver Hartkopp isotp_send_fc(sk, ae, ISOTP_FC_CTS);
545e057dd3fSOliver Hartkopp return 0;
546e057dd3fSOliver Hartkopp }
547e057dd3fSOliver Hartkopp
isotp_rcv_cf(struct sock * sk,struct canfd_frame * cf,int ae,struct sk_buff * skb)548e057dd3fSOliver Hartkopp static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
549e057dd3fSOliver Hartkopp struct sk_buff *skb)
550e057dd3fSOliver Hartkopp {
551e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
552e057dd3fSOliver Hartkopp struct sk_buff *nskb;
553e057dd3fSOliver Hartkopp int i;
554e057dd3fSOliver Hartkopp
555e057dd3fSOliver Hartkopp if (so->rx.state != ISOTP_WAIT_DATA)
556e057dd3fSOliver Hartkopp return 0;
557e057dd3fSOliver Hartkopp
558e057dd3fSOliver Hartkopp /* drop if timestamp gap is less than force_rx_stmin nano secs */
559e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_FORCE_RXSTMIN) {
560e057dd3fSOliver Hartkopp if (ktime_to_ns(ktime_sub(skb->tstamp, so->lastrxcf_tstamp)) <
561e057dd3fSOliver Hartkopp so->force_rx_stmin)
562e057dd3fSOliver Hartkopp return 0;
563e057dd3fSOliver Hartkopp
564e057dd3fSOliver Hartkopp so->lastrxcf_tstamp = skb->tstamp;
565e057dd3fSOliver Hartkopp }
566e057dd3fSOliver Hartkopp
567e057dd3fSOliver Hartkopp hrtimer_cancel(&so->rxtimer);
568e057dd3fSOliver Hartkopp
569e057dd3fSOliver Hartkopp /* CFs are never longer than the FF */
570e057dd3fSOliver Hartkopp if (cf->len > so->rx.ll_dl)
571e057dd3fSOliver Hartkopp return 1;
572e057dd3fSOliver Hartkopp
573e057dd3fSOliver Hartkopp /* CFs have usually the LL_DL length */
574e057dd3fSOliver Hartkopp if (cf->len < so->rx.ll_dl) {
575e057dd3fSOliver Hartkopp /* this is only allowed for the last CF */
576e057dd3fSOliver Hartkopp if (so->rx.len - so->rx.idx > so->rx.ll_dl - ae - N_PCI_SZ)
577e057dd3fSOliver Hartkopp return 1;
578e057dd3fSOliver Hartkopp }
579e057dd3fSOliver Hartkopp
580e057dd3fSOliver Hartkopp if ((cf->data[ae] & 0x0F) != so->rx.sn) {
581e057dd3fSOliver Hartkopp /* wrong sn detected - report 'illegal byte sequence' */
582e057dd3fSOliver Hartkopp sk->sk_err = EILSEQ;
583e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
584e3ae2365SAlexander Aring sk_error_report(sk);
585e057dd3fSOliver Hartkopp
586e057dd3fSOliver Hartkopp /* reset rx state */
587e057dd3fSOliver Hartkopp so->rx.state = ISOTP_IDLE;
588e057dd3fSOliver Hartkopp return 1;
589e057dd3fSOliver Hartkopp }
590e057dd3fSOliver Hartkopp so->rx.sn++;
591e057dd3fSOliver Hartkopp so->rx.sn %= 16;
592e057dd3fSOliver Hartkopp
593e057dd3fSOliver Hartkopp for (i = ae + N_PCI_SZ; i < cf->len; i++) {
594e057dd3fSOliver Hartkopp so->rx.buf[so->rx.idx++] = cf->data[i];
595e057dd3fSOliver Hartkopp if (so->rx.idx >= so->rx.len)
596e057dd3fSOliver Hartkopp break;
597e057dd3fSOliver Hartkopp }
598e057dd3fSOliver Hartkopp
599e057dd3fSOliver Hartkopp if (so->rx.idx >= so->rx.len) {
600e057dd3fSOliver Hartkopp /* we are done */
601e057dd3fSOliver Hartkopp so->rx.state = ISOTP_IDLE;
602e057dd3fSOliver Hartkopp
603e057dd3fSOliver Hartkopp if ((so->opt.flags & ISOTP_CHECK_PADDING) &&
604e057dd3fSOliver Hartkopp check_pad(so, cf, i + 1, so->opt.rxpad_content)) {
605e057dd3fSOliver Hartkopp /* malformed PDU - report 'not a data message' */
606e057dd3fSOliver Hartkopp sk->sk_err = EBADMSG;
607e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
608e3ae2365SAlexander Aring sk_error_report(sk);
609e057dd3fSOliver Hartkopp return 1;
610e057dd3fSOliver Hartkopp }
611e057dd3fSOliver Hartkopp
612e057dd3fSOliver Hartkopp nskb = alloc_skb(so->rx.len, gfp_any());
613e057dd3fSOliver Hartkopp if (!nskb)
614e057dd3fSOliver Hartkopp return 1;
615e057dd3fSOliver Hartkopp
616e057dd3fSOliver Hartkopp memcpy(skb_put(nskb, so->rx.len), so->rx.buf,
617e057dd3fSOliver Hartkopp so->rx.len);
618e057dd3fSOliver Hartkopp
619e057dd3fSOliver Hartkopp nskb->tstamp = skb->tstamp;
620e057dd3fSOliver Hartkopp nskb->dev = skb->dev;
621e057dd3fSOliver Hartkopp isotp_rcv_skb(nskb, sk);
622e057dd3fSOliver Hartkopp return 0;
623e057dd3fSOliver Hartkopp }
624e057dd3fSOliver Hartkopp
625e057dd3fSOliver Hartkopp /* perform blocksize handling, if enabled */
626e057dd3fSOliver Hartkopp if (!so->rxfc.bs || ++so->rx.bs < so->rxfc.bs) {
627e057dd3fSOliver Hartkopp /* start rx timeout watchdog */
62886633786SOliver Hartkopp hrtimer_start(&so->rxtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
629e057dd3fSOliver Hartkopp HRTIMER_MODE_REL_SOFT);
630e057dd3fSOliver Hartkopp return 0;
631e057dd3fSOliver Hartkopp }
632e057dd3fSOliver Hartkopp
63378656ea2SOliver Hartkopp /* no creation of flow control frames */
63478656ea2SOliver Hartkopp if (so->opt.flags & CAN_ISOTP_LISTEN_MODE)
63578656ea2SOliver Hartkopp return 0;
63678656ea2SOliver Hartkopp
637e057dd3fSOliver Hartkopp /* we reached the specified blocksize so->rxfc.bs */
638e057dd3fSOliver Hartkopp isotp_send_fc(sk, ae, ISOTP_FC_CTS);
639e057dd3fSOliver Hartkopp return 0;
640e057dd3fSOliver Hartkopp }
641e057dd3fSOliver Hartkopp
isotp_rcv(struct sk_buff * skb,void * data)642e057dd3fSOliver Hartkopp static void isotp_rcv(struct sk_buff *skb, void *data)
643e057dd3fSOliver Hartkopp {
644e057dd3fSOliver Hartkopp struct sock *sk = (struct sock *)data;
645e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
646e057dd3fSOliver Hartkopp struct canfd_frame *cf;
647e057dd3fSOliver Hartkopp int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
648e057dd3fSOliver Hartkopp u8 n_pci_type, sf_dl;
649e057dd3fSOliver Hartkopp
650e057dd3fSOliver Hartkopp /* Strictly receive only frames with the configured MTU size
651e057dd3fSOliver Hartkopp * => clear separation of CAN2.0 / CAN FD transport channels
652e057dd3fSOliver Hartkopp */
653e057dd3fSOliver Hartkopp if (skb->len != so->ll.mtu)
654e057dd3fSOliver Hartkopp return;
655e057dd3fSOliver Hartkopp
656e057dd3fSOliver Hartkopp cf = (struct canfd_frame *)skb->data;
657e057dd3fSOliver Hartkopp
658e057dd3fSOliver Hartkopp /* if enabled: check reception of my configured extended address */
659e057dd3fSOliver Hartkopp if (ae && cf->data[0] != so->opt.rx_ext_address)
660e057dd3fSOliver Hartkopp return;
661e057dd3fSOliver Hartkopp
662e057dd3fSOliver Hartkopp n_pci_type = cf->data[ae] & 0xF0;
663e057dd3fSOliver Hartkopp
6647c759040SOliver Hartkopp /* Make sure the state changes and data structures stay consistent at
6657c759040SOliver Hartkopp * CAN frame reception time. This locking is not needed in real world
6667c759040SOliver Hartkopp * use cases but the inconsistency can be triggered with syzkaller.
6677c759040SOliver Hartkopp */
6687c759040SOliver Hartkopp spin_lock(&so->rx_lock);
6697c759040SOliver Hartkopp
670e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_HALF_DUPLEX) {
671e057dd3fSOliver Hartkopp /* check rx/tx path half duplex expectations */
672e057dd3fSOliver Hartkopp if ((so->tx.state != ISOTP_IDLE && n_pci_type != N_PCI_FC) ||
673e057dd3fSOliver Hartkopp (so->rx.state != ISOTP_IDLE && n_pci_type == N_PCI_FC))
6747c759040SOliver Hartkopp goto out_unlock;
675e057dd3fSOliver Hartkopp }
676e057dd3fSOliver Hartkopp
677e057dd3fSOliver Hartkopp switch (n_pci_type) {
678e057dd3fSOliver Hartkopp case N_PCI_FC:
679e057dd3fSOliver Hartkopp /* tx path: flow control frame containing the FC parameters */
680e057dd3fSOliver Hartkopp isotp_rcv_fc(so, cf, ae);
681e057dd3fSOliver Hartkopp break;
682e057dd3fSOliver Hartkopp
683e057dd3fSOliver Hartkopp case N_PCI_SF:
684e057dd3fSOliver Hartkopp /* rx path: single frame
685e057dd3fSOliver Hartkopp *
686e057dd3fSOliver Hartkopp * As we do not have a rx.ll_dl configuration, we can only test
687e057dd3fSOliver Hartkopp * if the CAN frames payload length matches the LL_DL == 8
688e057dd3fSOliver Hartkopp * requirements - no matter if it's CAN 2.0 or CAN FD
689e057dd3fSOliver Hartkopp */
690e057dd3fSOliver Hartkopp
691e057dd3fSOliver Hartkopp /* get the SF_DL from the N_PCI byte */
692e057dd3fSOliver Hartkopp sf_dl = cf->data[ae] & 0x0F;
693e057dd3fSOliver Hartkopp
694e057dd3fSOliver Hartkopp if (cf->len <= CAN_MAX_DLEN) {
695e057dd3fSOliver Hartkopp isotp_rcv_sf(sk, cf, SF_PCI_SZ4 + ae, skb, sf_dl);
696e057dd3fSOliver Hartkopp } else {
69796a7457aSOliver Hartkopp if (can_is_canfd_skb(skb)) {
698e057dd3fSOliver Hartkopp /* We have a CAN FD frame and CAN_DL is greater than 8:
699e057dd3fSOliver Hartkopp * Only frames with the SF_DL == 0 ESC value are valid.
700e057dd3fSOliver Hartkopp *
701e057dd3fSOliver Hartkopp * If so take care of the increased SF PCI size
702e057dd3fSOliver Hartkopp * (SF_PCI_SZ8) to point to the message content behind
703e057dd3fSOliver Hartkopp * the extended SF PCI info and get the real SF_DL
704e057dd3fSOliver Hartkopp * length value from the formerly first data byte.
705e057dd3fSOliver Hartkopp */
706e057dd3fSOliver Hartkopp if (sf_dl == 0)
707e057dd3fSOliver Hartkopp isotp_rcv_sf(sk, cf, SF_PCI_SZ8 + ae, skb,
708e057dd3fSOliver Hartkopp cf->data[SF_PCI_SZ4 + ae]);
709e057dd3fSOliver Hartkopp }
710e057dd3fSOliver Hartkopp }
711e057dd3fSOliver Hartkopp break;
712e057dd3fSOliver Hartkopp
713e057dd3fSOliver Hartkopp case N_PCI_FF:
714e057dd3fSOliver Hartkopp /* rx path: first frame */
715e057dd3fSOliver Hartkopp isotp_rcv_ff(sk, cf, ae);
716e057dd3fSOliver Hartkopp break;
717e057dd3fSOliver Hartkopp
718e057dd3fSOliver Hartkopp case N_PCI_CF:
719e057dd3fSOliver Hartkopp /* rx path: consecutive frame */
720e057dd3fSOliver Hartkopp isotp_rcv_cf(sk, cf, ae, skb);
721e057dd3fSOliver Hartkopp break;
722e057dd3fSOliver Hartkopp }
7237c759040SOliver Hartkopp
7247c759040SOliver Hartkopp out_unlock:
7257c759040SOliver Hartkopp spin_unlock(&so->rx_lock);
726e057dd3fSOliver Hartkopp }
727e057dd3fSOliver Hartkopp
isotp_fill_dataframe(struct canfd_frame * cf,struct isotp_sock * so,int ae,int off)728e057dd3fSOliver Hartkopp static void isotp_fill_dataframe(struct canfd_frame *cf, struct isotp_sock *so,
729e057dd3fSOliver Hartkopp int ae, int off)
730e057dd3fSOliver Hartkopp {
731e057dd3fSOliver Hartkopp int pcilen = N_PCI_SZ + ae + off;
732e057dd3fSOliver Hartkopp int space = so->tx.ll_dl - pcilen;
733e057dd3fSOliver Hartkopp int num = min_t(int, so->tx.len - so->tx.idx, space);
734e057dd3fSOliver Hartkopp int i;
735e057dd3fSOliver Hartkopp
736e057dd3fSOliver Hartkopp cf->can_id = so->txid;
737e057dd3fSOliver Hartkopp cf->len = num + pcilen;
738e057dd3fSOliver Hartkopp
739e057dd3fSOliver Hartkopp if (num < space) {
740e057dd3fSOliver Hartkopp if (so->opt.flags & CAN_ISOTP_TX_PADDING) {
741e057dd3fSOliver Hartkopp /* user requested padding */
742e057dd3fSOliver Hartkopp cf->len = padlen(cf->len);
743e057dd3fSOliver Hartkopp memset(cf->data, so->opt.txpad_content, cf->len);
744e057dd3fSOliver Hartkopp } else if (cf->len > CAN_MAX_DLEN) {
745e057dd3fSOliver Hartkopp /* mandatory padding for CAN FD frames */
746e057dd3fSOliver Hartkopp cf->len = padlen(cf->len);
747e057dd3fSOliver Hartkopp memset(cf->data, CAN_ISOTP_DEFAULT_PAD_CONTENT,
748e057dd3fSOliver Hartkopp cf->len);
749e057dd3fSOliver Hartkopp }
750e057dd3fSOliver Hartkopp }
751e057dd3fSOliver Hartkopp
752e057dd3fSOliver Hartkopp for (i = 0; i < num; i++)
753e057dd3fSOliver Hartkopp cf->data[pcilen + i] = so->tx.buf[so->tx.idx++];
754e057dd3fSOliver Hartkopp
755e057dd3fSOliver Hartkopp if (ae)
756e057dd3fSOliver Hartkopp cf->data[0] = so->opt.ext_address;
757e057dd3fSOliver Hartkopp }
758e057dd3fSOliver Hartkopp
isotp_send_cframe(struct isotp_sock * so)7594b7fe92cSOliver Hartkopp static void isotp_send_cframe(struct isotp_sock *so)
7604b7fe92cSOliver Hartkopp {
7614b7fe92cSOliver Hartkopp struct sock *sk = &so->sk;
7624b7fe92cSOliver Hartkopp struct sk_buff *skb;
7634b7fe92cSOliver Hartkopp struct net_device *dev;
7644b7fe92cSOliver Hartkopp struct canfd_frame *cf;
7654b7fe92cSOliver Hartkopp int can_send_ret;
7664b7fe92cSOliver Hartkopp int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
7674b7fe92cSOliver Hartkopp
7684b7fe92cSOliver Hartkopp dev = dev_get_by_index(sock_net(sk), so->ifindex);
7694b7fe92cSOliver Hartkopp if (!dev)
7704b7fe92cSOliver Hartkopp return;
7714b7fe92cSOliver Hartkopp
7724b7fe92cSOliver Hartkopp skb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), GFP_ATOMIC);
7734b7fe92cSOliver Hartkopp if (!skb) {
7744b7fe92cSOliver Hartkopp dev_put(dev);
7754b7fe92cSOliver Hartkopp return;
7764b7fe92cSOliver Hartkopp }
7774b7fe92cSOliver Hartkopp
7784b7fe92cSOliver Hartkopp can_skb_reserve(skb);
7794b7fe92cSOliver Hartkopp can_skb_prv(skb)->ifindex = dev->ifindex;
7804b7fe92cSOliver Hartkopp can_skb_prv(skb)->skbcnt = 0;
7814b7fe92cSOliver Hartkopp
7824b7fe92cSOliver Hartkopp cf = (struct canfd_frame *)skb->data;
7834b7fe92cSOliver Hartkopp skb_put_zero(skb, so->ll.mtu);
7844b7fe92cSOliver Hartkopp
7854b7fe92cSOliver Hartkopp /* create consecutive frame */
7864b7fe92cSOliver Hartkopp isotp_fill_dataframe(cf, so, ae, 0);
7874b7fe92cSOliver Hartkopp
7884b7fe92cSOliver Hartkopp /* place consecutive frame N_PCI in appropriate index */
7894b7fe92cSOliver Hartkopp cf->data[ae] = N_PCI_CF | so->tx.sn++;
7904b7fe92cSOliver Hartkopp so->tx.sn %= 16;
7914b7fe92cSOliver Hartkopp so->tx.bs++;
7924b7fe92cSOliver Hartkopp
7934b7fe92cSOliver Hartkopp cf->flags = so->ll.tx_flags;
7944b7fe92cSOliver Hartkopp
7954b7fe92cSOliver Hartkopp skb->dev = dev;
7964b7fe92cSOliver Hartkopp can_skb_set_owner(skb, sk);
7974b7fe92cSOliver Hartkopp
7984b7fe92cSOliver Hartkopp /* cfecho should have been zero'ed by init/isotp_rcv_echo() */
7994b7fe92cSOliver Hartkopp if (so->cfecho)
8004b7fe92cSOliver Hartkopp pr_notice_once("can-isotp: cfecho is %08X != 0\n", so->cfecho);
8014b7fe92cSOliver Hartkopp
8024b7fe92cSOliver Hartkopp /* set consecutive frame echo tag */
8034b7fe92cSOliver Hartkopp so->cfecho = *(u32 *)cf->data;
8044b7fe92cSOliver Hartkopp
8054b7fe92cSOliver Hartkopp /* send frame with local echo enabled */
8064b7fe92cSOliver Hartkopp can_send_ret = can_send(skb, 1);
8074b7fe92cSOliver Hartkopp if (can_send_ret) {
8084b7fe92cSOliver Hartkopp pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
8094b7fe92cSOliver Hartkopp __func__, ERR_PTR(can_send_ret));
8104b7fe92cSOliver Hartkopp if (can_send_ret == -ENOBUFS)
8114b7fe92cSOliver Hartkopp pr_notice_once("can-isotp: tx queue is full\n");
8124b7fe92cSOliver Hartkopp }
8134b7fe92cSOliver Hartkopp dev_put(dev);
8144b7fe92cSOliver Hartkopp }
8154b7fe92cSOliver Hartkopp
isotp_create_fframe(struct canfd_frame * cf,struct isotp_sock * so,int ae)816e057dd3fSOliver Hartkopp static void isotp_create_fframe(struct canfd_frame *cf, struct isotp_sock *so,
817e057dd3fSOliver Hartkopp int ae)
818e057dd3fSOliver Hartkopp {
819e057dd3fSOliver Hartkopp int i;
820e057dd3fSOliver Hartkopp int ff_pci_sz;
821e057dd3fSOliver Hartkopp
822e057dd3fSOliver Hartkopp cf->can_id = so->txid;
823e057dd3fSOliver Hartkopp cf->len = so->tx.ll_dl;
824e057dd3fSOliver Hartkopp if (ae)
825e057dd3fSOliver Hartkopp cf->data[0] = so->opt.ext_address;
826e057dd3fSOliver Hartkopp
827e057dd3fSOliver Hartkopp /* create N_PCI bytes with 12/32 bit FF_DL data length */
82896d1c81eSOliver Hartkopp if (so->tx.len > MAX_12BIT_PDU_SIZE) {
829e057dd3fSOliver Hartkopp /* use 32 bit FF_DL notation */
830e057dd3fSOliver Hartkopp cf->data[ae] = N_PCI_FF;
831e057dd3fSOliver Hartkopp cf->data[ae + 1] = 0;
832e057dd3fSOliver Hartkopp cf->data[ae + 2] = (u8)(so->tx.len >> 24) & 0xFFU;
833e057dd3fSOliver Hartkopp cf->data[ae + 3] = (u8)(so->tx.len >> 16) & 0xFFU;
834e057dd3fSOliver Hartkopp cf->data[ae + 4] = (u8)(so->tx.len >> 8) & 0xFFU;
835e057dd3fSOliver Hartkopp cf->data[ae + 5] = (u8)so->tx.len & 0xFFU;
836e057dd3fSOliver Hartkopp ff_pci_sz = FF_PCI_SZ32;
837e057dd3fSOliver Hartkopp } else {
838e057dd3fSOliver Hartkopp /* use 12 bit FF_DL notation */
839e057dd3fSOliver Hartkopp cf->data[ae] = (u8)(so->tx.len >> 8) | N_PCI_FF;
840e057dd3fSOliver Hartkopp cf->data[ae + 1] = (u8)so->tx.len & 0xFFU;
841e057dd3fSOliver Hartkopp ff_pci_sz = FF_PCI_SZ12;
842e057dd3fSOliver Hartkopp }
843e057dd3fSOliver Hartkopp
844e057dd3fSOliver Hartkopp /* add first data bytes depending on ae */
845e057dd3fSOliver Hartkopp for (i = ae + ff_pci_sz; i < so->tx.ll_dl; i++)
846e057dd3fSOliver Hartkopp cf->data[i] = so->tx.buf[so->tx.idx++];
847e057dd3fSOliver Hartkopp
848e057dd3fSOliver Hartkopp so->tx.sn = 1;
849e057dd3fSOliver Hartkopp }
850e057dd3fSOliver Hartkopp
isotp_rcv_echo(struct sk_buff * skb,void * data)8514b7fe92cSOliver Hartkopp static void isotp_rcv_echo(struct sk_buff *skb, void *data)
8524b7fe92cSOliver Hartkopp {
8534b7fe92cSOliver Hartkopp struct sock *sk = (struct sock *)data;
8544b7fe92cSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
8554b7fe92cSOliver Hartkopp struct canfd_frame *cf = (struct canfd_frame *)skb->data;
8564b7fe92cSOliver Hartkopp
85786633786SOliver Hartkopp /* only handle my own local echo CF/SF skb's (no FF!) */
8584b7fe92cSOliver Hartkopp if (skb->sk != sk || so->cfecho != *(u32 *)cf->data)
8594b7fe92cSOliver Hartkopp return;
8604b7fe92cSOliver Hartkopp
8614b7fe92cSOliver Hartkopp /* cancel local echo timeout */
8624b7fe92cSOliver Hartkopp hrtimer_cancel(&so->txtimer);
8634b7fe92cSOliver Hartkopp
8644b7fe92cSOliver Hartkopp /* local echo skb with consecutive frame has been consumed */
8654b7fe92cSOliver Hartkopp so->cfecho = 0;
8664b7fe92cSOliver Hartkopp
8674b7fe92cSOliver Hartkopp if (so->tx.idx >= so->tx.len) {
8684b7fe92cSOliver Hartkopp /* we are done */
8694b7fe92cSOliver Hartkopp so->tx.state = ISOTP_IDLE;
8704b7fe92cSOliver Hartkopp wake_up_interruptible(&so->wait);
8714b7fe92cSOliver Hartkopp return;
8724b7fe92cSOliver Hartkopp }
8734b7fe92cSOliver Hartkopp
8744b7fe92cSOliver Hartkopp if (so->txfc.bs && so->tx.bs >= so->txfc.bs) {
8754b7fe92cSOliver Hartkopp /* stop and wait for FC with timeout */
8764b7fe92cSOliver Hartkopp so->tx.state = ISOTP_WAIT_FC;
87786633786SOliver Hartkopp hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
8784b7fe92cSOliver Hartkopp HRTIMER_MODE_REL_SOFT);
8794b7fe92cSOliver Hartkopp return;
8804b7fe92cSOliver Hartkopp }
8814b7fe92cSOliver Hartkopp
8824b7fe92cSOliver Hartkopp /* no gap between data frames needed => use burst mode */
8834b7fe92cSOliver Hartkopp if (!so->tx_gap) {
88486633786SOliver Hartkopp /* enable echo timeout handling */
88586633786SOliver Hartkopp hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
88686633786SOliver Hartkopp HRTIMER_MODE_REL_SOFT);
8874b7fe92cSOliver Hartkopp isotp_send_cframe(so);
8884b7fe92cSOliver Hartkopp return;
8894b7fe92cSOliver Hartkopp }
8904b7fe92cSOliver Hartkopp
8914b7fe92cSOliver Hartkopp /* start timer to send next consecutive frame with correct delay */
8924f027cbaSOliver Hartkopp hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
8934b7fe92cSOliver Hartkopp }
8944b7fe92cSOliver Hartkopp
isotp_tx_timer_handler(struct hrtimer * hrtimer)895e057dd3fSOliver Hartkopp static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
896e057dd3fSOliver Hartkopp {
897e057dd3fSOliver Hartkopp struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
898e057dd3fSOliver Hartkopp txtimer);
899e057dd3fSOliver Hartkopp struct sock *sk = &so->sk;
900e057dd3fSOliver Hartkopp
90105173743SOliver Hartkopp /* don't handle timeouts in IDLE or SHUTDOWN state */
90205173743SOliver Hartkopp if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN)
9034f027cbaSOliver Hartkopp return HRTIMER_NORESTART;
9044b7fe92cSOliver Hartkopp
9054f027cbaSOliver Hartkopp /* we did not get any flow control or echo frame in time */
906e057dd3fSOliver Hartkopp
907e057dd3fSOliver Hartkopp /* report 'communication error on send' */
908e057dd3fSOliver Hartkopp sk->sk_err = ECOMM;
909e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
910e3ae2365SAlexander Aring sk_error_report(sk);
911e057dd3fSOliver Hartkopp
912e057dd3fSOliver Hartkopp /* reset tx state */
913e057dd3fSOliver Hartkopp so->tx.state = ISOTP_IDLE;
914e057dd3fSOliver Hartkopp wake_up_interruptible(&so->wait);
915e057dd3fSOliver Hartkopp
9164f027cbaSOliver Hartkopp return HRTIMER_NORESTART;
917e057dd3fSOliver Hartkopp }
918e057dd3fSOliver Hartkopp
isotp_txfr_timer_handler(struct hrtimer * hrtimer)9194f027cbaSOliver Hartkopp static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
9204f027cbaSOliver Hartkopp {
9214f027cbaSOliver Hartkopp struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
9224f027cbaSOliver Hartkopp txfrtimer);
9234f027cbaSOliver Hartkopp
9244f027cbaSOliver Hartkopp /* start echo timeout handling and cover below protocol error */
9254f027cbaSOliver Hartkopp hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
9264f027cbaSOliver Hartkopp HRTIMER_MODE_REL_SOFT);
9274f027cbaSOliver Hartkopp
9284f027cbaSOliver Hartkopp /* cfecho should be consumed by isotp_rcv_echo() here */
9294f027cbaSOliver Hartkopp if (so->tx.state == ISOTP_SENDING && !so->cfecho)
9304f027cbaSOliver Hartkopp isotp_send_cframe(so);
9314f027cbaSOliver Hartkopp
9324f027cbaSOliver Hartkopp return HRTIMER_NORESTART;
933e057dd3fSOliver Hartkopp }
934e057dd3fSOliver Hartkopp
isotp_sendmsg(struct socket * sock,struct msghdr * msg,size_t size)935e057dd3fSOliver Hartkopp static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
936e057dd3fSOliver Hartkopp {
937e057dd3fSOliver Hartkopp struct sock *sk = sock->sk;
938e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
939e057dd3fSOliver Hartkopp struct sk_buff *skb;
940e057dd3fSOliver Hartkopp struct net_device *dev;
941e057dd3fSOliver Hartkopp struct canfd_frame *cf;
942e057dd3fSOliver Hartkopp int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
943e057dd3fSOliver Hartkopp int wait_tx_done = (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0;
94486633786SOliver Hartkopp s64 hrtimer_sec = ISOTP_ECHO_TIMEOUT;
945e057dd3fSOliver Hartkopp int off;
946e057dd3fSOliver Hartkopp int err;
947e057dd3fSOliver Hartkopp
94805173743SOliver Hartkopp if (!so->bound || so->tx.state == ISOTP_SHUTDOWN)
949e057dd3fSOliver Hartkopp return -EADDRNOTAVAIL;
950e057dd3fSOliver Hartkopp
951*d9c2ba65SLukas Magel while (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
952e057dd3fSOliver Hartkopp /* we do not support multiple buffers - for now */
953*d9c2ba65SLukas Magel if (msg->msg_flags & MSG_DONTWAIT)
95405173743SOliver Hartkopp return -EAGAIN;
955e057dd3fSOliver Hartkopp
956*d9c2ba65SLukas Magel if (so->tx.state == ISOTP_SHUTDOWN)
957*d9c2ba65SLukas Magel return -EADDRNOTAVAIL;
958*d9c2ba65SLukas Magel
959e057dd3fSOliver Hartkopp /* wait for complete transmission of current pdu */
9609acf6362SZiyang Xuan err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
9619acf6362SZiyang Xuan if (err)
96205173743SOliver Hartkopp goto err_event_drop;
963e057dd3fSOliver Hartkopp }
964e057dd3fSOliver Hartkopp
96596d1c81eSOliver Hartkopp /* PDU size > default => try max_pdu_size */
96696d1c81eSOliver Hartkopp if (size > so->tx.buflen && so->tx.buflen < max_pdu_size) {
96796d1c81eSOliver Hartkopp u8 *newbuf = kmalloc(max_pdu_size, GFP_KERNEL);
96896d1c81eSOliver Hartkopp
96996d1c81eSOliver Hartkopp if (newbuf) {
97096d1c81eSOliver Hartkopp so->tx.buf = newbuf;
97196d1c81eSOliver Hartkopp so->tx.buflen = max_pdu_size;
97296d1c81eSOliver Hartkopp }
97396d1c81eSOliver Hartkopp }
97496d1c81eSOliver Hartkopp
97596d1c81eSOliver Hartkopp if (!size || size > so->tx.buflen) {
97643a08c3bSZiyang Xuan err = -EINVAL;
9778375dfacSOliver Hartkopp goto err_out_drop;
97843a08c3bSZiyang Xuan }
979e057dd3fSOliver Hartkopp
980921ca574SOliver Hartkopp /* take care of a potential SF_DL ESC offset for TX_DL > 8 */
981921ca574SOliver Hartkopp off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0;
982921ca574SOliver Hartkopp
983921ca574SOliver Hartkopp /* does the given data fit into a single frame for SF_BROADCAST? */
9849f39d365SOliver Hartkopp if ((isotp_bc_flags(so) == CAN_ISOTP_SF_BROADCAST) &&
98543a08c3bSZiyang Xuan (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) {
98643a08c3bSZiyang Xuan err = -EINVAL;
9878375dfacSOliver Hartkopp goto err_out_drop;
98843a08c3bSZiyang Xuan }
989921ca574SOliver Hartkopp
990e057dd3fSOliver Hartkopp err = memcpy_from_msg(so->tx.buf, msg, size);
991e057dd3fSOliver Hartkopp if (err < 0)
9928375dfacSOliver Hartkopp goto err_out_drop;
993e057dd3fSOliver Hartkopp
994e057dd3fSOliver Hartkopp dev = dev_get_by_index(sock_net(sk), so->ifindex);
99543a08c3bSZiyang Xuan if (!dev) {
99643a08c3bSZiyang Xuan err = -ENXIO;
9978375dfacSOliver Hartkopp goto err_out_drop;
99843a08c3bSZiyang Xuan }
999e057dd3fSOliver Hartkopp
1000e057dd3fSOliver Hartkopp skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv),
1001e057dd3fSOliver Hartkopp msg->msg_flags & MSG_DONTWAIT, &err);
1002e057dd3fSOliver Hartkopp if (!skb) {
1003e057dd3fSOliver Hartkopp dev_put(dev);
10048375dfacSOliver Hartkopp goto err_out_drop;
1005e057dd3fSOliver Hartkopp }
1006e057dd3fSOliver Hartkopp
1007e057dd3fSOliver Hartkopp can_skb_reserve(skb);
1008e057dd3fSOliver Hartkopp can_skb_prv(skb)->ifindex = dev->ifindex;
1009e057dd3fSOliver Hartkopp can_skb_prv(skb)->skbcnt = 0;
1010e057dd3fSOliver Hartkopp
1011e057dd3fSOliver Hartkopp so->tx.len = size;
1012e057dd3fSOliver Hartkopp so->tx.idx = 0;
1013e057dd3fSOliver Hartkopp
1014e057dd3fSOliver Hartkopp cf = (struct canfd_frame *)skb->data;
1015b5f020f8SOliver Hartkopp skb_put_zero(skb, so->ll.mtu);
1016e057dd3fSOliver Hartkopp
101786633786SOliver Hartkopp /* cfecho should have been zero'ed by init / former isotp_rcv_echo() */
101886633786SOliver Hartkopp if (so->cfecho)
101986633786SOliver Hartkopp pr_notice_once("can-isotp: uninit cfecho %08X\n", so->cfecho);
102086633786SOliver Hartkopp
1021e057dd3fSOliver Hartkopp /* check for single frame transmission depending on TX_DL */
1022e057dd3fSOliver Hartkopp if (size <= so->tx.ll_dl - SF_PCI_SZ4 - ae - off) {
1023e057dd3fSOliver Hartkopp /* The message size generally fits into a SingleFrame - good.
1024e057dd3fSOliver Hartkopp *
1025e057dd3fSOliver Hartkopp * SF_DL ESC offset optimization:
1026e057dd3fSOliver Hartkopp *
1027e057dd3fSOliver Hartkopp * When TX_DL is greater 8 but the message would still fit
1028e057dd3fSOliver Hartkopp * into a 8 byte CAN frame, we can omit the offset.
1029e057dd3fSOliver Hartkopp * This prevents a protocol caused length extension from
1030e057dd3fSOliver Hartkopp * CAN_DL = 8 to CAN_DL = 12 due to the SF_SL ESC handling.
1031e057dd3fSOliver Hartkopp */
1032e057dd3fSOliver Hartkopp if (size <= CAN_MAX_DLEN - SF_PCI_SZ4 - ae)
1033e057dd3fSOliver Hartkopp off = 0;
1034e057dd3fSOliver Hartkopp
1035e057dd3fSOliver Hartkopp isotp_fill_dataframe(cf, so, ae, off);
1036e057dd3fSOliver Hartkopp
1037e057dd3fSOliver Hartkopp /* place single frame N_PCI w/o length in appropriate index */
1038e057dd3fSOliver Hartkopp cf->data[ae] = N_PCI_SF;
1039e057dd3fSOliver Hartkopp
1040e057dd3fSOliver Hartkopp /* place SF_DL size value depending on the SF_DL ESC offset */
1041e057dd3fSOliver Hartkopp if (off)
1042e057dd3fSOliver Hartkopp cf->data[SF_PCI_SZ4 + ae] = size;
1043e057dd3fSOliver Hartkopp else
1044e057dd3fSOliver Hartkopp cf->data[ae] |= size;
1045e057dd3fSOliver Hartkopp
104686633786SOliver Hartkopp /* set CF echo tag for isotp_rcv_echo() (SF-mode) */
104786633786SOliver Hartkopp so->cfecho = *(u32 *)cf->data;
1048e057dd3fSOliver Hartkopp } else {
10499f39d365SOliver Hartkopp /* send first frame */
1050e057dd3fSOliver Hartkopp
1051e057dd3fSOliver Hartkopp isotp_create_fframe(cf, so, ae);
1052e057dd3fSOliver Hartkopp
10539f39d365SOliver Hartkopp if (isotp_bc_flags(so) == CAN_ISOTP_CF_BROADCAST) {
10549f39d365SOliver Hartkopp /* set timer for FC-less operation (STmin = 0) */
10559f39d365SOliver Hartkopp if (so->opt.flags & CAN_ISOTP_FORCE_TXSTMIN)
10569f39d365SOliver Hartkopp so->tx_gap = ktime_set(0, so->force_tx_stmin);
10579f39d365SOliver Hartkopp else
10589f39d365SOliver Hartkopp so->tx_gap = ktime_set(0, so->frame_txtime);
10599f39d365SOliver Hartkopp
10609f39d365SOliver Hartkopp /* disable wait for FCs due to activated block size */
10619f39d365SOliver Hartkopp so->txfc.bs = 0;
10629f39d365SOliver Hartkopp
106386633786SOliver Hartkopp /* set CF echo tag for isotp_rcv_echo() (CF-mode) */
10649f39d365SOliver Hartkopp so->cfecho = *(u32 *)cf->data;
10659f39d365SOliver Hartkopp } else {
10669f39d365SOliver Hartkopp /* standard flow control check */
10679f39d365SOliver Hartkopp so->tx.state = ISOTP_WAIT_FIRST_FC;
10689f39d365SOliver Hartkopp
1069e057dd3fSOliver Hartkopp /* start timeout for FC */
107086633786SOliver Hartkopp hrtimer_sec = ISOTP_FC_TIMEOUT;
107186633786SOliver Hartkopp
107286633786SOliver Hartkopp /* no CF echo tag for isotp_rcv_echo() (FF-mode) */
107386633786SOliver Hartkopp so->cfecho = 0;
107486633786SOliver Hartkopp }
10759f39d365SOliver Hartkopp }
10769f39d365SOliver Hartkopp
1077d7349708SOliver Hartkopp hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0),
1078d7349708SOliver Hartkopp HRTIMER_MODE_REL_SOFT);
1079e057dd3fSOliver Hartkopp
1080e057dd3fSOliver Hartkopp /* send the first or only CAN frame */
1081e057dd3fSOliver Hartkopp cf->flags = so->ll.tx_flags;
1082e057dd3fSOliver Hartkopp
1083e057dd3fSOliver Hartkopp skb->dev = dev;
1084e057dd3fSOliver Hartkopp skb->sk = sk;
1085e057dd3fSOliver Hartkopp err = can_send(skb, 1);
1086e057dd3fSOliver Hartkopp dev_put(dev);
1087e057dd3fSOliver Hartkopp if (err) {
108846d8657aSPatrick Menschel pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
108946d8657aSPatrick Menschel __func__, ERR_PTR(err));
1090d7349708SOliver Hartkopp
1091d7349708SOliver Hartkopp /* no transmission -> no timeout monitoring */
1092d7349708SOliver Hartkopp hrtimer_cancel(&so->txtimer);
1093d7349708SOliver Hartkopp
10949f39d365SOliver Hartkopp /* reset consecutive frame echo tag */
10959f39d365SOliver Hartkopp so->cfecho = 0;
10969f39d365SOliver Hartkopp
10978375dfacSOliver Hartkopp goto err_out_drop;
1098e057dd3fSOliver Hartkopp }
1099e057dd3fSOliver Hartkopp
1100e057dd3fSOliver Hartkopp if (wait_tx_done) {
1101e057dd3fSOliver Hartkopp /* wait for complete transmission of current pdu */
110205173743SOliver Hartkopp err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
110305173743SOliver Hartkopp if (err)
110405173743SOliver Hartkopp goto err_event_drop;
1105d674a8f1SMarc Kleine-Budde
1106e38910c0SOliver Hartkopp err = sock_error(sk);
1107e38910c0SOliver Hartkopp if (err)
1108e38910c0SOliver Hartkopp return err;
1109e057dd3fSOliver Hartkopp }
1110e057dd3fSOliver Hartkopp
1111e057dd3fSOliver Hartkopp return size;
111243a08c3bSZiyang Xuan
111305173743SOliver Hartkopp err_event_drop:
111405173743SOliver Hartkopp /* got signal: force tx state machine to be idle */
111505173743SOliver Hartkopp so->tx.state = ISOTP_IDLE;
111605173743SOliver Hartkopp hrtimer_cancel(&so->txfrtimer);
111705173743SOliver Hartkopp hrtimer_cancel(&so->txtimer);
11188375dfacSOliver Hartkopp err_out_drop:
11198375dfacSOliver Hartkopp /* drop this PDU and unlock a potential wait queue */
112005173743SOliver Hartkopp so->tx.state = ISOTP_IDLE;
112143a08c3bSZiyang Xuan wake_up_interruptible(&so->wait);
112243a08c3bSZiyang Xuan
112343a08c3bSZiyang Xuan return err;
1124e057dd3fSOliver Hartkopp }
1125e057dd3fSOliver Hartkopp
isotp_recvmsg(struct socket * sock,struct msghdr * msg,size_t size,int flags)1126e057dd3fSOliver Hartkopp static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
1127e057dd3fSOliver Hartkopp int flags)
1128e057dd3fSOliver Hartkopp {
1129e057dd3fSOliver Hartkopp struct sock *sk = sock->sk;
1130e057dd3fSOliver Hartkopp struct sk_buff *skb;
113130ffd533SOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
113242bf50a1SOliver Hartkopp int ret = 0;
1133e057dd3fSOliver Hartkopp
1134db2773d6SOliver Hartkopp if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK | MSG_CMSG_COMPAT))
113542bf50a1SOliver Hartkopp return -EINVAL;
1136e057dd3fSOliver Hartkopp
113730ffd533SOliver Hartkopp if (!so->bound)
113830ffd533SOliver Hartkopp return -EADDRNOTAVAIL;
113930ffd533SOliver Hartkopp
1140f4b41f06SOliver Hartkopp skb = skb_recv_datagram(sk, flags, &ret);
1141e057dd3fSOliver Hartkopp if (!skb)
114242bf50a1SOliver Hartkopp return ret;
1143e057dd3fSOliver Hartkopp
1144e057dd3fSOliver Hartkopp if (size < skb->len)
1145e057dd3fSOliver Hartkopp msg->msg_flags |= MSG_TRUNC;
1146e057dd3fSOliver Hartkopp else
1147e057dd3fSOliver Hartkopp size = skb->len;
1148e057dd3fSOliver Hartkopp
114942bf50a1SOliver Hartkopp ret = memcpy_to_msg(msg, skb->data, size);
115042bf50a1SOliver Hartkopp if (ret < 0)
115142bf50a1SOliver Hartkopp goto out_err;
1152e057dd3fSOliver Hartkopp
11530145462fSOliver Hartkopp sock_recv_cmsgs(msg, sk, skb);
1154e057dd3fSOliver Hartkopp
1155e057dd3fSOliver Hartkopp if (msg->msg_name) {
1156f522d955SOliver Hartkopp __sockaddr_check_size(ISOTP_MIN_NAMELEN);
1157f522d955SOliver Hartkopp msg->msg_namelen = ISOTP_MIN_NAMELEN;
1158e057dd3fSOliver Hartkopp memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
1159e057dd3fSOliver Hartkopp }
1160e057dd3fSOliver Hartkopp
116142bf50a1SOliver Hartkopp /* set length of return value */
116242bf50a1SOliver Hartkopp ret = (flags & MSG_TRUNC) ? skb->len : size;
116342bf50a1SOliver Hartkopp
116442bf50a1SOliver Hartkopp out_err:
1165e057dd3fSOliver Hartkopp skb_free_datagram(sk, skb);
1166e057dd3fSOliver Hartkopp
116742bf50a1SOliver Hartkopp return ret;
1168e057dd3fSOliver Hartkopp }
1169e057dd3fSOliver Hartkopp
isotp_release(struct socket * sock)1170e057dd3fSOliver Hartkopp static int isotp_release(struct socket *sock)
1171e057dd3fSOliver Hartkopp {
1172e057dd3fSOliver Hartkopp struct sock *sk = sock->sk;
1173e057dd3fSOliver Hartkopp struct isotp_sock *so;
1174e057dd3fSOliver Hartkopp struct net *net;
1175e057dd3fSOliver Hartkopp
1176e057dd3fSOliver Hartkopp if (!sk)
1177e057dd3fSOliver Hartkopp return 0;
1178e057dd3fSOliver Hartkopp
1179e057dd3fSOliver Hartkopp so = isotp_sk(sk);
1180e057dd3fSOliver Hartkopp net = sock_net(sk);
1181e057dd3fSOliver Hartkopp
1182e057dd3fSOliver Hartkopp /* wait for complete transmission of current pdu */
118305173743SOliver Hartkopp while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 &&
118405173743SOliver Hartkopp cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE)
118505173743SOliver Hartkopp ;
1186e057dd3fSOliver Hartkopp
1187823b2e42SOliver Hartkopp /* force state machines to be idle also when a signal occurred */
118805173743SOliver Hartkopp so->tx.state = ISOTP_SHUTDOWN;
1189823b2e42SOliver Hartkopp so->rx.state = ISOTP_IDLE;
1190823b2e42SOliver Hartkopp
11918d0caedbSTetsuo Handa spin_lock(&isotp_notifier_lock);
11928d0caedbSTetsuo Handa while (isotp_busy_notifier == so) {
11938d0caedbSTetsuo Handa spin_unlock(&isotp_notifier_lock);
11948d0caedbSTetsuo Handa schedule_timeout_uninterruptible(1);
11958d0caedbSTetsuo Handa spin_lock(&isotp_notifier_lock);
11968d0caedbSTetsuo Handa }
11978d0caedbSTetsuo Handa list_del(&so->notifier);
11988d0caedbSTetsuo Handa spin_unlock(&isotp_notifier_lock);
1199e057dd3fSOliver Hartkopp
1200e057dd3fSOliver Hartkopp lock_sock(sk);
1201e057dd3fSOliver Hartkopp
1202e057dd3fSOliver Hartkopp /* remove current filters & unregister */
12030bfe7115SOliver Hartkopp if (so->bound) {
1204e057dd3fSOliver Hartkopp if (so->ifindex) {
1205e057dd3fSOliver Hartkopp struct net_device *dev;
1206e057dd3fSOliver Hartkopp
1207e057dd3fSOliver Hartkopp dev = dev_get_by_index(net, so->ifindex);
1208e057dd3fSOliver Hartkopp if (dev) {
12099f39d365SOliver Hartkopp if (isotp_register_rxid(so))
1210e057dd3fSOliver Hartkopp can_rx_unregister(net, dev, so->rxid,
1211e057dd3fSOliver Hartkopp SINGLE_MASK(so->rxid),
1212e057dd3fSOliver Hartkopp isotp_rcv, sk);
12139f39d365SOliver Hartkopp
12144b7fe92cSOliver Hartkopp can_rx_unregister(net, dev, so->txid,
12154b7fe92cSOliver Hartkopp SINGLE_MASK(so->txid),
12164b7fe92cSOliver Hartkopp isotp_rcv_echo, sk);
1217e057dd3fSOliver Hartkopp dev_put(dev);
121814a4696bSOliver Hartkopp synchronize_rcu();
1219e057dd3fSOliver Hartkopp }
1220e057dd3fSOliver Hartkopp }
1221e057dd3fSOliver Hartkopp }
1222e057dd3fSOliver Hartkopp
12234f027cbaSOliver Hartkopp hrtimer_cancel(&so->txfrtimer);
122414a4696bSOliver Hartkopp hrtimer_cancel(&so->txtimer);
122514a4696bSOliver Hartkopp hrtimer_cancel(&so->rxtimer);
122614a4696bSOliver Hartkopp
1227e057dd3fSOliver Hartkopp so->ifindex = 0;
1228e057dd3fSOliver Hartkopp so->bound = 0;
1229e057dd3fSOliver Hartkopp
123096d1c81eSOliver Hartkopp if (so->rx.buf != so->rx.sbuf)
123196d1c81eSOliver Hartkopp kfree(so->rx.buf);
123296d1c81eSOliver Hartkopp
123396d1c81eSOliver Hartkopp if (so->tx.buf != so->tx.sbuf)
123496d1c81eSOliver Hartkopp kfree(so->tx.buf);
123596d1c81eSOliver Hartkopp
1236e057dd3fSOliver Hartkopp sock_orphan(sk);
1237e057dd3fSOliver Hartkopp sock->sk = NULL;
1238e057dd3fSOliver Hartkopp
1239e057dd3fSOliver Hartkopp release_sock(sk);
1240e057dd3fSOliver Hartkopp sock_put(sk);
1241e057dd3fSOliver Hartkopp
1242e057dd3fSOliver Hartkopp return 0;
1243e057dd3fSOliver Hartkopp }
1244e057dd3fSOliver Hartkopp
isotp_bind(struct socket * sock,struct sockaddr * uaddr,int len)1245e057dd3fSOliver Hartkopp static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
1246e057dd3fSOliver Hartkopp {
1247e057dd3fSOliver Hartkopp struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
1248e057dd3fSOliver Hartkopp struct sock *sk = sock->sk;
1249e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
1250e057dd3fSOliver Hartkopp struct net *net = sock_net(sk);
1251e057dd3fSOliver Hartkopp int ifindex;
1252e057dd3fSOliver Hartkopp struct net_device *dev;
1253b76b163fSOliver Hartkopp canid_t tx_id = addr->can_addr.tp.tx_id;
1254b76b163fSOliver Hartkopp canid_t rx_id = addr->can_addr.tp.rx_id;
1255e057dd3fSOliver Hartkopp int err = 0;
1256e057dd3fSOliver Hartkopp int notify_enetdown = 0;
1257e057dd3fSOliver Hartkopp
1258f522d955SOliver Hartkopp if (len < ISOTP_MIN_NAMELEN)
1259e057dd3fSOliver Hartkopp return -EINVAL;
1260e057dd3fSOliver Hartkopp
1261c6adf659SOliver Hartkopp if (addr->can_family != AF_CAN)
1262c6adf659SOliver Hartkopp return -EINVAL;
1263c6adf659SOliver Hartkopp
1264b76b163fSOliver Hartkopp /* sanitize tx CAN identifier */
12653ea56642SOliver Hartkopp if (tx_id & CAN_EFF_FLAG)
12663ea56642SOliver Hartkopp tx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK);
12673ea56642SOliver Hartkopp else
12683ea56642SOliver Hartkopp tx_id &= CAN_SFF_MASK;
12693ea56642SOliver Hartkopp
1270b76b163fSOliver Hartkopp /* give feedback on wrong CAN-ID value */
1271b76b163fSOliver Hartkopp if (tx_id != addr->can_addr.tp.tx_id)
1272b76b163fSOliver Hartkopp return -EINVAL;
1273b76b163fSOliver Hartkopp
1274b76b163fSOliver Hartkopp /* sanitize rx CAN identifier (if needed) */
1275b76b163fSOliver Hartkopp if (isotp_register_rxid(so)) {
12763ea56642SOliver Hartkopp if (rx_id & CAN_EFF_FLAG)
12773ea56642SOliver Hartkopp rx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK);
12783ea56642SOliver Hartkopp else
12793ea56642SOliver Hartkopp rx_id &= CAN_SFF_MASK;
1280e057dd3fSOliver Hartkopp
1281b76b163fSOliver Hartkopp /* give feedback on wrong CAN-ID value */
1282b76b163fSOliver Hartkopp if (rx_id != addr->can_addr.tp.rx_id)
12832aa39889SOliver Hartkopp return -EINVAL;
1284b76b163fSOliver Hartkopp }
12852aa39889SOliver Hartkopp
1286e057dd3fSOliver Hartkopp if (!addr->can_ifindex)
1287e057dd3fSOliver Hartkopp return -ENODEV;
1288e057dd3fSOliver Hartkopp
1289e057dd3fSOliver Hartkopp lock_sock(sk);
1290e057dd3fSOliver Hartkopp
129172ed3ee9SOliver Hartkopp if (so->bound) {
129272ed3ee9SOliver Hartkopp err = -EINVAL;
129372ed3ee9SOliver Hartkopp goto out;
129472ed3ee9SOliver Hartkopp }
129572ed3ee9SOliver Hartkopp
12969f39d365SOliver Hartkopp /* ensure different CAN IDs when the rx_id is to be registered */
12979f39d365SOliver Hartkopp if (isotp_register_rxid(so) && rx_id == tx_id) {
12982b17c400SNorbert Slusarek err = -EADDRNOTAVAIL;
12992b17c400SNorbert Slusarek goto out;
13002b17c400SNorbert Slusarek }
13012b17c400SNorbert Slusarek
1302e057dd3fSOliver Hartkopp dev = dev_get_by_index(net, addr->can_ifindex);
1303e057dd3fSOliver Hartkopp if (!dev) {
1304e057dd3fSOliver Hartkopp err = -ENODEV;
1305e057dd3fSOliver Hartkopp goto out;
1306e057dd3fSOliver Hartkopp }
1307e057dd3fSOliver Hartkopp if (dev->type != ARPHRD_CAN) {
1308e057dd3fSOliver Hartkopp dev_put(dev);
1309e057dd3fSOliver Hartkopp err = -ENODEV;
1310e057dd3fSOliver Hartkopp goto out;
1311e057dd3fSOliver Hartkopp }
1312e057dd3fSOliver Hartkopp if (dev->mtu < so->ll.mtu) {
1313e057dd3fSOliver Hartkopp dev_put(dev);
1314e057dd3fSOliver Hartkopp err = -EINVAL;
1315e057dd3fSOliver Hartkopp goto out;
1316e057dd3fSOliver Hartkopp }
1317e057dd3fSOliver Hartkopp if (!(dev->flags & IFF_UP))
1318e057dd3fSOliver Hartkopp notify_enetdown = 1;
1319e057dd3fSOliver Hartkopp
1320e057dd3fSOliver Hartkopp ifindex = dev->ifindex;
1321e057dd3fSOliver Hartkopp
13229f39d365SOliver Hartkopp if (isotp_register_rxid(so))
13233ea56642SOliver Hartkopp can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id),
1324921ca574SOliver Hartkopp isotp_rcv, sk, "isotp", sk);
1325e057dd3fSOliver Hartkopp
13264b7fe92cSOliver Hartkopp /* no consecutive frame echo skb in flight */
13274b7fe92cSOliver Hartkopp so->cfecho = 0;
13284b7fe92cSOliver Hartkopp
13294b7fe92cSOliver Hartkopp /* register for echo skb's */
13303ea56642SOliver Hartkopp can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
13314b7fe92cSOliver Hartkopp isotp_rcv_echo, sk, "isotpe", sk);
13324b7fe92cSOliver Hartkopp
1333e057dd3fSOliver Hartkopp dev_put(dev);
1334e057dd3fSOliver Hartkopp
1335e057dd3fSOliver Hartkopp /* switch to new settings */
1336e057dd3fSOliver Hartkopp so->ifindex = ifindex;
13373ea56642SOliver Hartkopp so->rxid = rx_id;
13383ea56642SOliver Hartkopp so->txid = tx_id;
1339e057dd3fSOliver Hartkopp so->bound = 1;
1340e057dd3fSOliver Hartkopp
1341e057dd3fSOliver Hartkopp out:
1342e057dd3fSOliver Hartkopp release_sock(sk);
1343e057dd3fSOliver Hartkopp
1344e057dd3fSOliver Hartkopp if (notify_enetdown) {
1345e057dd3fSOliver Hartkopp sk->sk_err = ENETDOWN;
1346e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
1347e3ae2365SAlexander Aring sk_error_report(sk);
1348e057dd3fSOliver Hartkopp }
1349e057dd3fSOliver Hartkopp
1350e057dd3fSOliver Hartkopp return err;
1351e057dd3fSOliver Hartkopp }
1352e057dd3fSOliver Hartkopp
isotp_getname(struct socket * sock,struct sockaddr * uaddr,int peer)1353e057dd3fSOliver Hartkopp static int isotp_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
1354e057dd3fSOliver Hartkopp {
1355e057dd3fSOliver Hartkopp struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
1356e057dd3fSOliver Hartkopp struct sock *sk = sock->sk;
1357e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
1358e057dd3fSOliver Hartkopp
1359e057dd3fSOliver Hartkopp if (peer)
1360e057dd3fSOliver Hartkopp return -EOPNOTSUPP;
1361e057dd3fSOliver Hartkopp
1362f522d955SOliver Hartkopp memset(addr, 0, ISOTP_MIN_NAMELEN);
1363e057dd3fSOliver Hartkopp addr->can_family = AF_CAN;
1364e057dd3fSOliver Hartkopp addr->can_ifindex = so->ifindex;
1365e057dd3fSOliver Hartkopp addr->can_addr.tp.rx_id = so->rxid;
1366e057dd3fSOliver Hartkopp addr->can_addr.tp.tx_id = so->txid;
1367e057dd3fSOliver Hartkopp
1368f522d955SOliver Hartkopp return ISOTP_MIN_NAMELEN;
1369e057dd3fSOliver Hartkopp }
1370e057dd3fSOliver Hartkopp
isotp_setsockopt_locked(struct socket * sock,int level,int optname,sockptr_t optval,unsigned int optlen)13712b17c400SNorbert Slusarek static int isotp_setsockopt_locked(struct socket *sock, int level, int optname,
1372e057dd3fSOliver Hartkopp sockptr_t optval, unsigned int optlen)
1373e057dd3fSOliver Hartkopp {
1374e057dd3fSOliver Hartkopp struct sock *sk = sock->sk;
1375e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
1376e057dd3fSOliver Hartkopp int ret = 0;
1377e057dd3fSOliver Hartkopp
1378323a391aSOliver Hartkopp if (so->bound)
1379323a391aSOliver Hartkopp return -EISCONN;
1380323a391aSOliver Hartkopp
1381e057dd3fSOliver Hartkopp switch (optname) {
1382e057dd3fSOliver Hartkopp case CAN_ISOTP_OPTS:
1383e057dd3fSOliver Hartkopp if (optlen != sizeof(struct can_isotp_options))
1384e057dd3fSOliver Hartkopp return -EINVAL;
1385e057dd3fSOliver Hartkopp
1386e057dd3fSOliver Hartkopp if (copy_from_sockptr(&so->opt, optval, optlen))
1387e057dd3fSOliver Hartkopp return -EFAULT;
1388e057dd3fSOliver Hartkopp
1389e057dd3fSOliver Hartkopp /* no separate rx_ext_address is given => use ext_address */
1390e057dd3fSOliver Hartkopp if (!(so->opt.flags & CAN_ISOTP_RX_EXT_ADDR))
1391e057dd3fSOliver Hartkopp so->opt.rx_ext_address = so->opt.ext_address;
1392530e0d46SOliver Hartkopp
13939f39d365SOliver Hartkopp /* these broadcast flags are not allowed together */
13949f39d365SOliver Hartkopp if (isotp_bc_flags(so) == ISOTP_ALL_BC_FLAGS) {
13959f39d365SOliver Hartkopp /* CAN_ISOTP_SF_BROADCAST is prioritized */
13969f39d365SOliver Hartkopp so->opt.flags &= ~CAN_ISOTP_CF_BROADCAST;
13979f39d365SOliver Hartkopp
13989f39d365SOliver Hartkopp /* give user feedback on wrong config attempt */
13999f39d365SOliver Hartkopp ret = -EINVAL;
14009f39d365SOliver Hartkopp }
14019f39d365SOliver Hartkopp
1402530e0d46SOliver Hartkopp /* check for frame_txtime changes (0 => no changes) */
1403530e0d46SOliver Hartkopp if (so->opt.frame_txtime) {
1404530e0d46SOliver Hartkopp if (so->opt.frame_txtime == CAN_ISOTP_FRAME_TXTIME_ZERO)
1405530e0d46SOliver Hartkopp so->frame_txtime = 0;
1406530e0d46SOliver Hartkopp else
1407530e0d46SOliver Hartkopp so->frame_txtime = so->opt.frame_txtime;
1408530e0d46SOliver Hartkopp }
1409e057dd3fSOliver Hartkopp break;
1410e057dd3fSOliver Hartkopp
1411e057dd3fSOliver Hartkopp case CAN_ISOTP_RECV_FC:
1412e057dd3fSOliver Hartkopp if (optlen != sizeof(struct can_isotp_fc_options))
1413e057dd3fSOliver Hartkopp return -EINVAL;
1414e057dd3fSOliver Hartkopp
1415e057dd3fSOliver Hartkopp if (copy_from_sockptr(&so->rxfc, optval, optlen))
1416e057dd3fSOliver Hartkopp return -EFAULT;
1417e057dd3fSOliver Hartkopp break;
1418e057dd3fSOliver Hartkopp
1419e057dd3fSOliver Hartkopp case CAN_ISOTP_TX_STMIN:
1420e057dd3fSOliver Hartkopp if (optlen != sizeof(u32))
1421e057dd3fSOliver Hartkopp return -EINVAL;
1422e057dd3fSOliver Hartkopp
1423e057dd3fSOliver Hartkopp if (copy_from_sockptr(&so->force_tx_stmin, optval, optlen))
1424e057dd3fSOliver Hartkopp return -EFAULT;
1425e057dd3fSOliver Hartkopp break;
1426e057dd3fSOliver Hartkopp
1427e057dd3fSOliver Hartkopp case CAN_ISOTP_RX_STMIN:
1428e057dd3fSOliver Hartkopp if (optlen != sizeof(u32))
1429e057dd3fSOliver Hartkopp return -EINVAL;
1430e057dd3fSOliver Hartkopp
1431e057dd3fSOliver Hartkopp if (copy_from_sockptr(&so->force_rx_stmin, optval, optlen))
1432e057dd3fSOliver Hartkopp return -EFAULT;
1433e057dd3fSOliver Hartkopp break;
1434e057dd3fSOliver Hartkopp
1435e057dd3fSOliver Hartkopp case CAN_ISOTP_LL_OPTS:
1436e057dd3fSOliver Hartkopp if (optlen == sizeof(struct can_isotp_ll_options)) {
1437e057dd3fSOliver Hartkopp struct can_isotp_ll_options ll;
1438e057dd3fSOliver Hartkopp
1439e057dd3fSOliver Hartkopp if (copy_from_sockptr(&ll, optval, optlen))
1440e057dd3fSOliver Hartkopp return -EFAULT;
1441e057dd3fSOliver Hartkopp
1442e057dd3fSOliver Hartkopp /* check for correct ISO 11898-1 DLC data length */
1443e057dd3fSOliver Hartkopp if (ll.tx_dl != padlen(ll.tx_dl))
1444e057dd3fSOliver Hartkopp return -EINVAL;
1445e057dd3fSOliver Hartkopp
1446e057dd3fSOliver Hartkopp if (ll.mtu != CAN_MTU && ll.mtu != CANFD_MTU)
1447e057dd3fSOliver Hartkopp return -EINVAL;
1448e057dd3fSOliver Hartkopp
1449e4912459SMarc Kleine-Budde if (ll.mtu == CAN_MTU &&
1450e4912459SMarc Kleine-Budde (ll.tx_dl > CAN_MAX_DLEN || ll.tx_flags != 0))
1451e057dd3fSOliver Hartkopp return -EINVAL;
1452e057dd3fSOliver Hartkopp
1453e057dd3fSOliver Hartkopp memcpy(&so->ll, &ll, sizeof(ll));
1454e057dd3fSOliver Hartkopp
1455e057dd3fSOliver Hartkopp /* set ll_dl for tx path to similar place as for rx */
1456e057dd3fSOliver Hartkopp so->tx.ll_dl = ll.tx_dl;
1457e057dd3fSOliver Hartkopp } else {
1458e057dd3fSOliver Hartkopp return -EINVAL;
1459e057dd3fSOliver Hartkopp }
1460e057dd3fSOliver Hartkopp break;
1461e057dd3fSOliver Hartkopp
1462e057dd3fSOliver Hartkopp default:
1463e057dd3fSOliver Hartkopp ret = -ENOPROTOOPT;
1464e057dd3fSOliver Hartkopp }
1465e057dd3fSOliver Hartkopp
1466e057dd3fSOliver Hartkopp return ret;
1467e057dd3fSOliver Hartkopp }
1468e057dd3fSOliver Hartkopp
isotp_setsockopt(struct socket * sock,int level,int optname,sockptr_t optval,unsigned int optlen)14692b17c400SNorbert Slusarek static int isotp_setsockopt(struct socket *sock, int level, int optname,
14702b17c400SNorbert Slusarek sockptr_t optval, unsigned int optlen)
14712b17c400SNorbert Slusarek
14722b17c400SNorbert Slusarek {
14732b17c400SNorbert Slusarek struct sock *sk = sock->sk;
14742b17c400SNorbert Slusarek int ret;
14752b17c400SNorbert Slusarek
14762b17c400SNorbert Slusarek if (level != SOL_CAN_ISOTP)
14772b17c400SNorbert Slusarek return -EINVAL;
14782b17c400SNorbert Slusarek
14792b17c400SNorbert Slusarek lock_sock(sk);
14802b17c400SNorbert Slusarek ret = isotp_setsockopt_locked(sock, level, optname, optval, optlen);
14812b17c400SNorbert Slusarek release_sock(sk);
14822b17c400SNorbert Slusarek return ret;
14832b17c400SNorbert Slusarek }
14842b17c400SNorbert Slusarek
isotp_getsockopt(struct socket * sock,int level,int optname,char __user * optval,int __user * optlen)1485e057dd3fSOliver Hartkopp static int isotp_getsockopt(struct socket *sock, int level, int optname,
1486e057dd3fSOliver Hartkopp char __user *optval, int __user *optlen)
1487e057dd3fSOliver Hartkopp {
1488e057dd3fSOliver Hartkopp struct sock *sk = sock->sk;
1489e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
1490e057dd3fSOliver Hartkopp int len;
1491e057dd3fSOliver Hartkopp void *val;
1492e057dd3fSOliver Hartkopp
1493e057dd3fSOliver Hartkopp if (level != SOL_CAN_ISOTP)
1494e057dd3fSOliver Hartkopp return -EINVAL;
1495e057dd3fSOliver Hartkopp if (get_user(len, optlen))
1496e057dd3fSOliver Hartkopp return -EFAULT;
1497e057dd3fSOliver Hartkopp if (len < 0)
1498e057dd3fSOliver Hartkopp return -EINVAL;
1499e057dd3fSOliver Hartkopp
1500e057dd3fSOliver Hartkopp switch (optname) {
1501e057dd3fSOliver Hartkopp case CAN_ISOTP_OPTS:
1502e057dd3fSOliver Hartkopp len = min_t(int, len, sizeof(struct can_isotp_options));
1503e057dd3fSOliver Hartkopp val = &so->opt;
1504e057dd3fSOliver Hartkopp break;
1505e057dd3fSOliver Hartkopp
1506e057dd3fSOliver Hartkopp case CAN_ISOTP_RECV_FC:
1507e057dd3fSOliver Hartkopp len = min_t(int, len, sizeof(struct can_isotp_fc_options));
1508e057dd3fSOliver Hartkopp val = &so->rxfc;
1509e057dd3fSOliver Hartkopp break;
1510e057dd3fSOliver Hartkopp
1511e057dd3fSOliver Hartkopp case CAN_ISOTP_TX_STMIN:
1512e057dd3fSOliver Hartkopp len = min_t(int, len, sizeof(u32));
1513e057dd3fSOliver Hartkopp val = &so->force_tx_stmin;
1514e057dd3fSOliver Hartkopp break;
1515e057dd3fSOliver Hartkopp
1516e057dd3fSOliver Hartkopp case CAN_ISOTP_RX_STMIN:
1517e057dd3fSOliver Hartkopp len = min_t(int, len, sizeof(u32));
1518e057dd3fSOliver Hartkopp val = &so->force_rx_stmin;
1519e057dd3fSOliver Hartkopp break;
1520e057dd3fSOliver Hartkopp
1521e057dd3fSOliver Hartkopp case CAN_ISOTP_LL_OPTS:
1522e057dd3fSOliver Hartkopp len = min_t(int, len, sizeof(struct can_isotp_ll_options));
1523e057dd3fSOliver Hartkopp val = &so->ll;
1524e057dd3fSOliver Hartkopp break;
1525e057dd3fSOliver Hartkopp
1526e057dd3fSOliver Hartkopp default:
1527e057dd3fSOliver Hartkopp return -ENOPROTOOPT;
1528e057dd3fSOliver Hartkopp }
1529e057dd3fSOliver Hartkopp
1530e057dd3fSOliver Hartkopp if (put_user(len, optlen))
1531e057dd3fSOliver Hartkopp return -EFAULT;
1532e057dd3fSOliver Hartkopp if (copy_to_user(optval, val, len))
1533e057dd3fSOliver Hartkopp return -EFAULT;
1534e057dd3fSOliver Hartkopp return 0;
1535e057dd3fSOliver Hartkopp }
1536e057dd3fSOliver Hartkopp
isotp_notify(struct isotp_sock * so,unsigned long msg,struct net_device * dev)15378d0caedbSTetsuo Handa static void isotp_notify(struct isotp_sock *so, unsigned long msg,
15388d0caedbSTetsuo Handa struct net_device *dev)
1539e057dd3fSOliver Hartkopp {
1540e057dd3fSOliver Hartkopp struct sock *sk = &so->sk;
1541e057dd3fSOliver Hartkopp
1542e057dd3fSOliver Hartkopp if (!net_eq(dev_net(dev), sock_net(sk)))
15438d0caedbSTetsuo Handa return;
1544e057dd3fSOliver Hartkopp
1545e057dd3fSOliver Hartkopp if (so->ifindex != dev->ifindex)
15468d0caedbSTetsuo Handa return;
1547e057dd3fSOliver Hartkopp
1548e057dd3fSOliver Hartkopp switch (msg) {
1549e057dd3fSOliver Hartkopp case NETDEV_UNREGISTER:
1550e057dd3fSOliver Hartkopp lock_sock(sk);
1551e057dd3fSOliver Hartkopp /* remove current filters & unregister */
15520bfe7115SOliver Hartkopp if (so->bound) {
15539f39d365SOliver Hartkopp if (isotp_register_rxid(so))
1554e057dd3fSOliver Hartkopp can_rx_unregister(dev_net(dev), dev, so->rxid,
1555e057dd3fSOliver Hartkopp SINGLE_MASK(so->rxid),
1556e057dd3fSOliver Hartkopp isotp_rcv, sk);
15579f39d365SOliver Hartkopp
15584b7fe92cSOliver Hartkopp can_rx_unregister(dev_net(dev), dev, so->txid,
15594b7fe92cSOliver Hartkopp SINGLE_MASK(so->txid),
15604b7fe92cSOliver Hartkopp isotp_rcv_echo, sk);
15614b7fe92cSOliver Hartkopp }
1562e057dd3fSOliver Hartkopp
1563e057dd3fSOliver Hartkopp so->ifindex = 0;
1564e057dd3fSOliver Hartkopp so->bound = 0;
1565e057dd3fSOliver Hartkopp release_sock(sk);
1566e057dd3fSOliver Hartkopp
1567e057dd3fSOliver Hartkopp sk->sk_err = ENODEV;
1568e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
1569e3ae2365SAlexander Aring sk_error_report(sk);
1570e057dd3fSOliver Hartkopp break;
1571e057dd3fSOliver Hartkopp
1572e057dd3fSOliver Hartkopp case NETDEV_DOWN:
1573e057dd3fSOliver Hartkopp sk->sk_err = ENETDOWN;
1574e057dd3fSOliver Hartkopp if (!sock_flag(sk, SOCK_DEAD))
1575e3ae2365SAlexander Aring sk_error_report(sk);
1576e057dd3fSOliver Hartkopp break;
1577e057dd3fSOliver Hartkopp }
15788d0caedbSTetsuo Handa }
1579e057dd3fSOliver Hartkopp
isotp_notifier(struct notifier_block * nb,unsigned long msg,void * ptr)15808d0caedbSTetsuo Handa static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
15818d0caedbSTetsuo Handa void *ptr)
15828d0caedbSTetsuo Handa {
15838d0caedbSTetsuo Handa struct net_device *dev = netdev_notifier_info_to_dev(ptr);
15848d0caedbSTetsuo Handa
15858d0caedbSTetsuo Handa if (dev->type != ARPHRD_CAN)
15868d0caedbSTetsuo Handa return NOTIFY_DONE;
15878d0caedbSTetsuo Handa if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
15888d0caedbSTetsuo Handa return NOTIFY_DONE;
15898d0caedbSTetsuo Handa if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */
15908d0caedbSTetsuo Handa return NOTIFY_DONE;
15918d0caedbSTetsuo Handa
15928d0caedbSTetsuo Handa spin_lock(&isotp_notifier_lock);
15938d0caedbSTetsuo Handa list_for_each_entry(isotp_busy_notifier, &isotp_notifier_list, notifier) {
15948d0caedbSTetsuo Handa spin_unlock(&isotp_notifier_lock);
15958d0caedbSTetsuo Handa isotp_notify(isotp_busy_notifier, msg, dev);
15968d0caedbSTetsuo Handa spin_lock(&isotp_notifier_lock);
15978d0caedbSTetsuo Handa }
15988d0caedbSTetsuo Handa isotp_busy_notifier = NULL;
15998d0caedbSTetsuo Handa spin_unlock(&isotp_notifier_lock);
1600e057dd3fSOliver Hartkopp return NOTIFY_DONE;
1601e057dd3fSOliver Hartkopp }
1602e057dd3fSOliver Hartkopp
isotp_init(struct sock * sk)1603e057dd3fSOliver Hartkopp static int isotp_init(struct sock *sk)
1604e057dd3fSOliver Hartkopp {
1605e057dd3fSOliver Hartkopp struct isotp_sock *so = isotp_sk(sk);
1606e057dd3fSOliver Hartkopp
1607e057dd3fSOliver Hartkopp so->ifindex = 0;
1608e057dd3fSOliver Hartkopp so->bound = 0;
1609e057dd3fSOliver Hartkopp
1610e057dd3fSOliver Hartkopp so->opt.flags = CAN_ISOTP_DEFAULT_FLAGS;
1611e057dd3fSOliver Hartkopp so->opt.ext_address = CAN_ISOTP_DEFAULT_EXT_ADDRESS;
1612e057dd3fSOliver Hartkopp so->opt.rx_ext_address = CAN_ISOTP_DEFAULT_EXT_ADDRESS;
1613e057dd3fSOliver Hartkopp so->opt.rxpad_content = CAN_ISOTP_DEFAULT_PAD_CONTENT;
1614e057dd3fSOliver Hartkopp so->opt.txpad_content = CAN_ISOTP_DEFAULT_PAD_CONTENT;
1615e057dd3fSOliver Hartkopp so->opt.frame_txtime = CAN_ISOTP_DEFAULT_FRAME_TXTIME;
1616530e0d46SOliver Hartkopp so->frame_txtime = CAN_ISOTP_DEFAULT_FRAME_TXTIME;
1617e057dd3fSOliver Hartkopp so->rxfc.bs = CAN_ISOTP_DEFAULT_RECV_BS;
1618e057dd3fSOliver Hartkopp so->rxfc.stmin = CAN_ISOTP_DEFAULT_RECV_STMIN;
1619e057dd3fSOliver Hartkopp so->rxfc.wftmax = CAN_ISOTP_DEFAULT_RECV_WFTMAX;
1620e057dd3fSOliver Hartkopp so->ll.mtu = CAN_ISOTP_DEFAULT_LL_MTU;
1621e057dd3fSOliver Hartkopp so->ll.tx_dl = CAN_ISOTP_DEFAULT_LL_TX_DL;
1622e057dd3fSOliver Hartkopp so->ll.tx_flags = CAN_ISOTP_DEFAULT_LL_TX_FLAGS;
1623e057dd3fSOliver Hartkopp
1624e057dd3fSOliver Hartkopp /* set ll_dl for tx path to similar place as for rx */
1625e057dd3fSOliver Hartkopp so->tx.ll_dl = so->ll.tx_dl;
1626e057dd3fSOliver Hartkopp
1627e057dd3fSOliver Hartkopp so->rx.state = ISOTP_IDLE;
1628e057dd3fSOliver Hartkopp so->tx.state = ISOTP_IDLE;
1629e057dd3fSOliver Hartkopp
163096d1c81eSOliver Hartkopp so->rx.buf = so->rx.sbuf;
163196d1c81eSOliver Hartkopp so->tx.buf = so->tx.sbuf;
163296d1c81eSOliver Hartkopp so->rx.buflen = ARRAY_SIZE(so->rx.sbuf);
163396d1c81eSOliver Hartkopp so->tx.buflen = ARRAY_SIZE(so->tx.sbuf);
163496d1c81eSOliver Hartkopp
1635e057dd3fSOliver Hartkopp hrtimer_init(&so->rxtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1636e057dd3fSOliver Hartkopp so->rxtimer.function = isotp_rx_timer_handler;
1637e057dd3fSOliver Hartkopp hrtimer_init(&so->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1638e057dd3fSOliver Hartkopp so->txtimer.function = isotp_tx_timer_handler;
16394f027cbaSOliver Hartkopp hrtimer_init(&so->txfrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
16404f027cbaSOliver Hartkopp so->txfrtimer.function = isotp_txfr_timer_handler;
1641e057dd3fSOliver Hartkopp
1642e057dd3fSOliver Hartkopp init_waitqueue_head(&so->wait);
16437c759040SOliver Hartkopp spin_lock_init(&so->rx_lock);
1644e057dd3fSOliver Hartkopp
16458d0caedbSTetsuo Handa spin_lock(&isotp_notifier_lock);
16468d0caedbSTetsuo Handa list_add_tail(&so->notifier, &isotp_notifier_list);
16478d0caedbSTetsuo Handa spin_unlock(&isotp_notifier_lock);
1648e057dd3fSOliver Hartkopp
1649e057dd3fSOliver Hartkopp return 0;
1650e057dd3fSOliver Hartkopp }
1651e057dd3fSOliver Hartkopp
isotp_poll(struct file * file,struct socket * sock,poll_table * wait)165279e19fa7SMichal Sojka static __poll_t isotp_poll(struct file *file, struct socket *sock, poll_table *wait)
165379e19fa7SMichal Sojka {
165479e19fa7SMichal Sojka struct sock *sk = sock->sk;
165579e19fa7SMichal Sojka struct isotp_sock *so = isotp_sk(sk);
165679e19fa7SMichal Sojka
165779e19fa7SMichal Sojka __poll_t mask = datagram_poll(file, sock, wait);
165879e19fa7SMichal Sojka poll_wait(file, &so->wait, wait);
165979e19fa7SMichal Sojka
166079e19fa7SMichal Sojka /* Check for false positives due to TX state */
166179e19fa7SMichal Sojka if ((mask & EPOLLWRNORM) && (so->tx.state != ISOTP_IDLE))
166279e19fa7SMichal Sojka mask &= ~(EPOLLOUT | EPOLLWRNORM);
166379e19fa7SMichal Sojka
166479e19fa7SMichal Sojka return mask;
166579e19fa7SMichal Sojka }
166679e19fa7SMichal Sojka
isotp_sock_no_ioctlcmd(struct socket * sock,unsigned int cmd,unsigned long arg)1667e057dd3fSOliver Hartkopp static int isotp_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd,
1668e057dd3fSOliver Hartkopp unsigned long arg)
1669e057dd3fSOliver Hartkopp {
1670e057dd3fSOliver Hartkopp /* no ioctls for socket layer -> hand it down to NIC layer */
1671e057dd3fSOliver Hartkopp return -ENOIOCTLCMD;
1672e057dd3fSOliver Hartkopp }
1673e057dd3fSOliver Hartkopp
1674e057dd3fSOliver Hartkopp static const struct proto_ops isotp_ops = {
1675e057dd3fSOliver Hartkopp .family = PF_CAN,
1676e057dd3fSOliver Hartkopp .release = isotp_release,
1677e057dd3fSOliver Hartkopp .bind = isotp_bind,
1678e057dd3fSOliver Hartkopp .connect = sock_no_connect,
1679e057dd3fSOliver Hartkopp .socketpair = sock_no_socketpair,
1680e057dd3fSOliver Hartkopp .accept = sock_no_accept,
1681e057dd3fSOliver Hartkopp .getname = isotp_getname,
168279e19fa7SMichal Sojka .poll = isotp_poll,
1683e057dd3fSOliver Hartkopp .ioctl = isotp_sock_no_ioctlcmd,
1684e057dd3fSOliver Hartkopp .gettstamp = sock_gettstamp,
1685e057dd3fSOliver Hartkopp .listen = sock_no_listen,
1686e057dd3fSOliver Hartkopp .shutdown = sock_no_shutdown,
1687e057dd3fSOliver Hartkopp .setsockopt = isotp_setsockopt,
1688e057dd3fSOliver Hartkopp .getsockopt = isotp_getsockopt,
1689e057dd3fSOliver Hartkopp .sendmsg = isotp_sendmsg,
1690e057dd3fSOliver Hartkopp .recvmsg = isotp_recvmsg,
1691e057dd3fSOliver Hartkopp .mmap = sock_no_mmap,
1692e057dd3fSOliver Hartkopp };
1693e057dd3fSOliver Hartkopp
1694e057dd3fSOliver Hartkopp static struct proto isotp_proto __read_mostly = {
1695e057dd3fSOliver Hartkopp .name = "CAN_ISOTP",
1696e057dd3fSOliver Hartkopp .owner = THIS_MODULE,
1697e057dd3fSOliver Hartkopp .obj_size = sizeof(struct isotp_sock),
1698e057dd3fSOliver Hartkopp .init = isotp_init,
1699e057dd3fSOliver Hartkopp };
1700e057dd3fSOliver Hartkopp
1701e057dd3fSOliver Hartkopp static const struct can_proto isotp_can_proto = {
1702e057dd3fSOliver Hartkopp .type = SOCK_DGRAM,
1703e057dd3fSOliver Hartkopp .protocol = CAN_ISOTP,
1704e057dd3fSOliver Hartkopp .ops = &isotp_ops,
1705e057dd3fSOliver Hartkopp .prot = &isotp_proto,
1706e057dd3fSOliver Hartkopp };
1707e057dd3fSOliver Hartkopp
17088d0caedbSTetsuo Handa static struct notifier_block canisotp_notifier = {
17098d0caedbSTetsuo Handa .notifier_call = isotp_notifier
17108d0caedbSTetsuo Handa };
17118d0caedbSTetsuo Handa
isotp_module_init(void)1712e057dd3fSOliver Hartkopp static __init int isotp_module_init(void)
1713e057dd3fSOliver Hartkopp {
1714e057dd3fSOliver Hartkopp int err;
1715e057dd3fSOliver Hartkopp
171696d1c81eSOliver Hartkopp max_pdu_size = max_t(unsigned int, max_pdu_size, MAX_12BIT_PDU_SIZE);
171796d1c81eSOliver Hartkopp max_pdu_size = min_t(unsigned int, max_pdu_size, MAX_PDU_SIZE);
171896d1c81eSOliver Hartkopp
171996d1c81eSOliver Hartkopp pr_info("can: isotp protocol (max_pdu_size %d)\n", max_pdu_size);
1720e057dd3fSOliver Hartkopp
1721e057dd3fSOliver Hartkopp err = can_proto_register(&isotp_can_proto);
1722e057dd3fSOliver Hartkopp if (err < 0)
17236a5ddae5SPatrick Menschel pr_err("can: registration of isotp protocol failed %pe\n", ERR_PTR(err));
17248d0caedbSTetsuo Handa else
17258d0caedbSTetsuo Handa register_netdevice_notifier(&canisotp_notifier);
1726e057dd3fSOliver Hartkopp
1727e057dd3fSOliver Hartkopp return err;
1728e057dd3fSOliver Hartkopp }
1729e057dd3fSOliver Hartkopp
isotp_module_exit(void)1730e057dd3fSOliver Hartkopp static __exit void isotp_module_exit(void)
1731e057dd3fSOliver Hartkopp {
1732e057dd3fSOliver Hartkopp can_proto_unregister(&isotp_can_proto);
17338d0caedbSTetsuo Handa unregister_netdevice_notifier(&canisotp_notifier);
1734e057dd3fSOliver Hartkopp }
1735e057dd3fSOliver Hartkopp
1736e057dd3fSOliver Hartkopp module_init(isotp_module_init);
1737e057dd3fSOliver Hartkopp module_exit(isotp_module_exit);
1738