18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (c) 2010-2011 EIA Electronics,
38c2ecf20Sopenharmony_ci//                         Pieter Beyens <pieter.beyens@eia.be>
48c2ecf20Sopenharmony_ci// Copyright (c) 2010-2011 EIA Electronics,
58c2ecf20Sopenharmony_ci//                         Kurt Van Dijck <kurt.van.dijck@eia.be>
68c2ecf20Sopenharmony_ci// Copyright (c) 2018 Protonic,
78c2ecf20Sopenharmony_ci//                         Robin van der Gracht <robin@protonic.nl>
88c2ecf20Sopenharmony_ci// Copyright (c) 2017-2019 Pengutronix,
98c2ecf20Sopenharmony_ci//                         Marc Kleine-Budde <kernel@pengutronix.de>
108c2ecf20Sopenharmony_ci// Copyright (c) 2017-2019 Pengutronix,
118c2ecf20Sopenharmony_ci//                         Oleksij Rempel <kernel@pengutronix.de>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/can/can-ml.h>
168c2ecf20Sopenharmony_ci#include <linux/can/core.h>
178c2ecf20Sopenharmony_ci#include <linux/can/skb.h>
188c2ecf20Sopenharmony_ci#include <linux/errqueue.h>
198c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "j1939-priv.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define J1939_MIN_NAMELEN CAN_REQUIRED_SIZE(struct sockaddr_can, can_addr.j1939)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* conversion function between struct sock::sk_priority from linux and
268c2ecf20Sopenharmony_ci * j1939 priority field
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_cistatic inline priority_t j1939_prio(u32 sk_priority)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	sk_priority = min(sk_priority, 7U);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	return 7 - sk_priority;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic inline u32 j1939_to_sk_priority(priority_t prio)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	return 7 - prio;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* function to see if pgn is to be evaluated */
418c2ecf20Sopenharmony_cistatic inline bool j1939_pgn_is_valid(pgn_t pgn)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	return pgn <= J1939_PGN_MAX;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* test function to avoid non-zero DA placeholder for pdu1 pgn's */
478c2ecf20Sopenharmony_cistatic inline bool j1939_pgn_is_clean_pdu(pgn_t pgn)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	if (j1939_pgn_is_pdu1(pgn))
508c2ecf20Sopenharmony_ci		return !(pgn & 0xff);
518c2ecf20Sopenharmony_ci	else
528c2ecf20Sopenharmony_ci		return true;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic inline void j1939_sock_pending_add(struct sock *sk)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	atomic_inc(&jsk->skb_pending);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int j1939_sock_pending_get(struct sock *sk)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return atomic_read(&jsk->skb_pending);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_civoid j1939_sock_pending_del(struct sock *sk)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* atomic_dec_return returns the new value */
748c2ecf20Sopenharmony_ci	if (!atomic_dec_return(&jsk->skb_pending))
758c2ecf20Sopenharmony_ci		wake_up(&jsk->waitq);	/* no pending SKB's */
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic void j1939_jsk_add(struct j1939_priv *priv, struct j1939_sock *jsk)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	jsk->state |= J1939_SOCK_BOUND;
818c2ecf20Sopenharmony_ci	j1939_priv_get(priv);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->j1939_socks_lock);
848c2ecf20Sopenharmony_ci	list_add_tail(&jsk->list, &priv->j1939_socks);
858c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->j1939_socks_lock);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic void j1939_jsk_del(struct j1939_priv *priv, struct j1939_sock *jsk)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->j1939_socks_lock);
918c2ecf20Sopenharmony_ci	list_del_init(&jsk->list);
928c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->j1939_socks_lock);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	j1939_priv_put(priv);
958c2ecf20Sopenharmony_ci	jsk->state &= ~J1939_SOCK_BOUND;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic bool j1939_sk_queue_session(struct j1939_session *session)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(session->sk);
1018c2ecf20Sopenharmony_ci	bool empty;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	spin_lock_bh(&jsk->sk_session_queue_lock);
1048c2ecf20Sopenharmony_ci	empty = list_empty(&jsk->sk_session_queue);
1058c2ecf20Sopenharmony_ci	j1939_session_get(session);
1068c2ecf20Sopenharmony_ci	list_add_tail(&session->sk_session_queue_entry, &jsk->sk_session_queue);
1078c2ecf20Sopenharmony_ci	spin_unlock_bh(&jsk->sk_session_queue_lock);
1088c2ecf20Sopenharmony_ci	j1939_sock_pending_add(&jsk->sk);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return empty;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic struct
1148c2ecf20Sopenharmony_cij1939_session *j1939_sk_get_incomplete_session(struct j1939_sock *jsk)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct j1939_session *session = NULL;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	spin_lock_bh(&jsk->sk_session_queue_lock);
1198c2ecf20Sopenharmony_ci	if (!list_empty(&jsk->sk_session_queue)) {
1208c2ecf20Sopenharmony_ci		session = list_last_entry(&jsk->sk_session_queue,
1218c2ecf20Sopenharmony_ci					  struct j1939_session,
1228c2ecf20Sopenharmony_ci					  sk_session_queue_entry);
1238c2ecf20Sopenharmony_ci		if (session->total_queued_size == session->total_message_size)
1248c2ecf20Sopenharmony_ci			session = NULL;
1258c2ecf20Sopenharmony_ci		else
1268c2ecf20Sopenharmony_ci			j1939_session_get(session);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci	spin_unlock_bh(&jsk->sk_session_queue_lock);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return session;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void j1939_sk_queue_drop_all(struct j1939_priv *priv,
1348c2ecf20Sopenharmony_ci				    struct j1939_sock *jsk, int err)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct j1939_session *session, *tmp;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	netdev_dbg(priv->ndev, "%s: err: %i\n", __func__, err);
1398c2ecf20Sopenharmony_ci	spin_lock_bh(&jsk->sk_session_queue_lock);
1408c2ecf20Sopenharmony_ci	list_for_each_entry_safe(session, tmp, &jsk->sk_session_queue,
1418c2ecf20Sopenharmony_ci				 sk_session_queue_entry) {
1428c2ecf20Sopenharmony_ci		list_del_init(&session->sk_session_queue_entry);
1438c2ecf20Sopenharmony_ci		session->err = err;
1448c2ecf20Sopenharmony_ci		j1939_session_put(session);
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci	spin_unlock_bh(&jsk->sk_session_queue_lock);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void j1939_sk_queue_activate_next_locked(struct j1939_session *session)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct j1939_sock *jsk;
1528c2ecf20Sopenharmony_ci	struct j1939_session *first;
1538c2ecf20Sopenharmony_ci	int err;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* RX-Session don't have a socket (yet) */
1568c2ecf20Sopenharmony_ci	if (!session->sk)
1578c2ecf20Sopenharmony_ci		return;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	jsk = j1939_sk(session->sk);
1608c2ecf20Sopenharmony_ci	lockdep_assert_held(&jsk->sk_session_queue_lock);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	err = session->err;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	first = list_first_entry_or_null(&jsk->sk_session_queue,
1658c2ecf20Sopenharmony_ci					 struct j1939_session,
1668c2ecf20Sopenharmony_ci					 sk_session_queue_entry);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* Some else has already activated the next session */
1698c2ecf20Sopenharmony_ci	if (first != session)
1708c2ecf20Sopenharmony_ci		return;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ciactivate_next:
1738c2ecf20Sopenharmony_ci	list_del_init(&first->sk_session_queue_entry);
1748c2ecf20Sopenharmony_ci	j1939_session_put(first);
1758c2ecf20Sopenharmony_ci	first = list_first_entry_or_null(&jsk->sk_session_queue,
1768c2ecf20Sopenharmony_ci					 struct j1939_session,
1778c2ecf20Sopenharmony_ci					 sk_session_queue_entry);
1788c2ecf20Sopenharmony_ci	if (!first)
1798c2ecf20Sopenharmony_ci		return;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (j1939_session_activate(first)) {
1828c2ecf20Sopenharmony_ci		netdev_warn_once(first->priv->ndev,
1838c2ecf20Sopenharmony_ci				 "%s: 0x%p: Identical session is already activated.\n",
1848c2ecf20Sopenharmony_ci				 __func__, first);
1858c2ecf20Sopenharmony_ci		first->err = -EBUSY;
1868c2ecf20Sopenharmony_ci		goto activate_next;
1878c2ecf20Sopenharmony_ci	} else {
1888c2ecf20Sopenharmony_ci		/* Give receiver some time (arbitrary chosen) to recover */
1898c2ecf20Sopenharmony_ci		int time_ms = 0;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		if (err)
1928c2ecf20Sopenharmony_ci			time_ms = 10 + prandom_u32_max(16);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		j1939_tp_schedule_txtimer(first, time_ms);
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_civoid j1939_sk_queue_activate_next(struct j1939_session *session)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct j1939_sock *jsk;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (!session->sk)
2038c2ecf20Sopenharmony_ci		return;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	jsk = j1939_sk(session->sk);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	spin_lock_bh(&jsk->sk_session_queue_lock);
2088c2ecf20Sopenharmony_ci	j1939_sk_queue_activate_next_locked(session);
2098c2ecf20Sopenharmony_ci	spin_unlock_bh(&jsk->sk_session_queue_lock);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic bool j1939_sk_match_dst(struct j1939_sock *jsk,
2138c2ecf20Sopenharmony_ci			       const struct j1939_sk_buff_cb *skcb)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	if ((jsk->state & J1939_SOCK_PROMISC))
2168c2ecf20Sopenharmony_ci		return true;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Destination address filter */
2198c2ecf20Sopenharmony_ci	if (jsk->addr.src_name && skcb->addr.dst_name) {
2208c2ecf20Sopenharmony_ci		if (jsk->addr.src_name != skcb->addr.dst_name)
2218c2ecf20Sopenharmony_ci			return false;
2228c2ecf20Sopenharmony_ci	} else {
2238c2ecf20Sopenharmony_ci		/* receive (all sockets) if
2248c2ecf20Sopenharmony_ci		 * - all packages that match our bind() address
2258c2ecf20Sopenharmony_ci		 * - all broadcast on a socket if SO_BROADCAST
2268c2ecf20Sopenharmony_ci		 *   is set
2278c2ecf20Sopenharmony_ci		 */
2288c2ecf20Sopenharmony_ci		if (j1939_address_is_unicast(skcb->addr.da)) {
2298c2ecf20Sopenharmony_ci			if (jsk->addr.sa != skcb->addr.da)
2308c2ecf20Sopenharmony_ci				return false;
2318c2ecf20Sopenharmony_ci		} else if (!sock_flag(&jsk->sk, SOCK_BROADCAST)) {
2328c2ecf20Sopenharmony_ci			/* receiving broadcast without SO_BROADCAST
2338c2ecf20Sopenharmony_ci			 * flag is not allowed
2348c2ecf20Sopenharmony_ci			 */
2358c2ecf20Sopenharmony_ci			return false;
2368c2ecf20Sopenharmony_ci		}
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* Source address filter */
2408c2ecf20Sopenharmony_ci	if (jsk->state & J1939_SOCK_CONNECTED) {
2418c2ecf20Sopenharmony_ci		/* receive (all sockets) if
2428c2ecf20Sopenharmony_ci		 * - all packages that match our connect() name or address
2438c2ecf20Sopenharmony_ci		 */
2448c2ecf20Sopenharmony_ci		if (jsk->addr.dst_name && skcb->addr.src_name) {
2458c2ecf20Sopenharmony_ci			if (jsk->addr.dst_name != skcb->addr.src_name)
2468c2ecf20Sopenharmony_ci				return false;
2478c2ecf20Sopenharmony_ci		} else {
2488c2ecf20Sopenharmony_ci			if (jsk->addr.da != skcb->addr.sa)
2498c2ecf20Sopenharmony_ci				return false;
2508c2ecf20Sopenharmony_ci		}
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* PGN filter */
2548c2ecf20Sopenharmony_ci	if (j1939_pgn_is_valid(jsk->pgn_rx_filter) &&
2558c2ecf20Sopenharmony_ci	    jsk->pgn_rx_filter != skcb->addr.pgn)
2568c2ecf20Sopenharmony_ci		return false;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return true;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/* matches skb control buffer (addr) with a j1939 filter */
2628c2ecf20Sopenharmony_cistatic bool j1939_sk_match_filter(struct j1939_sock *jsk,
2638c2ecf20Sopenharmony_ci				  const struct j1939_sk_buff_cb *skcb)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	const struct j1939_filter *f;
2668c2ecf20Sopenharmony_ci	int nfilter;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	spin_lock_bh(&jsk->filters_lock);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	f = jsk->filters;
2718c2ecf20Sopenharmony_ci	nfilter = jsk->nfilters;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (!nfilter)
2748c2ecf20Sopenharmony_ci		/* receive all when no filters are assigned */
2758c2ecf20Sopenharmony_ci		goto filter_match_found;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	for (; nfilter; ++f, --nfilter) {
2788c2ecf20Sopenharmony_ci		if ((skcb->addr.pgn & f->pgn_mask) != f->pgn)
2798c2ecf20Sopenharmony_ci			continue;
2808c2ecf20Sopenharmony_ci		if ((skcb->addr.sa & f->addr_mask) != f->addr)
2818c2ecf20Sopenharmony_ci			continue;
2828c2ecf20Sopenharmony_ci		if ((skcb->addr.src_name & f->name_mask) != f->name)
2838c2ecf20Sopenharmony_ci			continue;
2848c2ecf20Sopenharmony_ci		goto filter_match_found;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	spin_unlock_bh(&jsk->filters_lock);
2888c2ecf20Sopenharmony_ci	return false;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cifilter_match_found:
2918c2ecf20Sopenharmony_ci	spin_unlock_bh(&jsk->filters_lock);
2928c2ecf20Sopenharmony_ci	return true;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic bool j1939_sk_recv_match_one(struct j1939_sock *jsk,
2968c2ecf20Sopenharmony_ci				    const struct j1939_sk_buff_cb *skcb)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	if (!(jsk->state & J1939_SOCK_BOUND))
2998c2ecf20Sopenharmony_ci		return false;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (!j1939_sk_match_dst(jsk, skcb))
3028c2ecf20Sopenharmony_ci		return false;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (!j1939_sk_match_filter(jsk, skcb))
3058c2ecf20Sopenharmony_ci		return false;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return true;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic void j1939_sk_recv_one(struct j1939_sock *jsk, struct sk_buff *oskb)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	const struct j1939_sk_buff_cb *oskcb = j1939_skb_to_cb(oskb);
3138c2ecf20Sopenharmony_ci	struct j1939_sk_buff_cb *skcb;
3148c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (oskb->sk == &jsk->sk)
3178c2ecf20Sopenharmony_ci		return;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (!j1939_sk_recv_match_one(jsk, oskcb))
3208c2ecf20Sopenharmony_ci		return;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	skb = skb_clone(oskb, GFP_ATOMIC);
3238c2ecf20Sopenharmony_ci	if (!skb) {
3248c2ecf20Sopenharmony_ci		pr_warn("skb clone failed\n");
3258c2ecf20Sopenharmony_ci		return;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci	can_skb_set_owner(skb, oskb->sk);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	skcb = j1939_skb_to_cb(skb);
3308c2ecf20Sopenharmony_ci	skcb->msg_flags &= ~(MSG_DONTROUTE);
3318c2ecf20Sopenharmony_ci	if (skb->sk)
3328c2ecf20Sopenharmony_ci		skcb->msg_flags |= MSG_DONTROUTE;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (sock_queue_rcv_skb(&jsk->sk, skb) < 0)
3358c2ecf20Sopenharmony_ci		kfree_skb(skb);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cibool j1939_sk_recv_match(struct j1939_priv *priv, struct j1939_sk_buff_cb *skcb)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct j1939_sock *jsk;
3418c2ecf20Sopenharmony_ci	bool match = false;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->j1939_socks_lock);
3448c2ecf20Sopenharmony_ci	list_for_each_entry(jsk, &priv->j1939_socks, list) {
3458c2ecf20Sopenharmony_ci		match = j1939_sk_recv_match_one(jsk, skcb);
3468c2ecf20Sopenharmony_ci		if (match)
3478c2ecf20Sopenharmony_ci			break;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->j1939_socks_lock);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return match;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_civoid j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct j1939_sock *jsk;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->j1939_socks_lock);
3598c2ecf20Sopenharmony_ci	list_for_each_entry(jsk, &priv->j1939_socks, list) {
3608c2ecf20Sopenharmony_ci		j1939_sk_recv_one(jsk, skb);
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->j1939_socks_lock);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic void j1939_sk_sock_destruct(struct sock *sk)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* This function will be call by the generic networking code, when then
3708c2ecf20Sopenharmony_ci	 * the socket is ultimately closed (sk->sk_destruct).
3718c2ecf20Sopenharmony_ci	 *
3728c2ecf20Sopenharmony_ci	 * The race between
3738c2ecf20Sopenharmony_ci	 * - processing a received CAN frame
3748c2ecf20Sopenharmony_ci	 *   (can_receive -> j1939_can_recv)
3758c2ecf20Sopenharmony_ci	 *   and accessing j1939_priv
3768c2ecf20Sopenharmony_ci	 * ... and ...
3778c2ecf20Sopenharmony_ci	 * - closing a socket
3788c2ecf20Sopenharmony_ci	 *   (j1939_can_rx_unregister -> can_rx_unregister)
3798c2ecf20Sopenharmony_ci	 *   and calling the final j1939_priv_put()
3808c2ecf20Sopenharmony_ci	 *
3818c2ecf20Sopenharmony_ci	 * is avoided by calling the final j1939_priv_put() from this
3828c2ecf20Sopenharmony_ci	 * RCU deferred cleanup call.
3838c2ecf20Sopenharmony_ci	 */
3848c2ecf20Sopenharmony_ci	if (jsk->priv) {
3858c2ecf20Sopenharmony_ci		j1939_priv_put(jsk->priv);
3868c2ecf20Sopenharmony_ci		jsk->priv = NULL;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* call generic CAN sock destruct */
3908c2ecf20Sopenharmony_ci	can_sock_destruct(sk);
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int j1939_sk_init(struct sock *sk)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* Ensure that "sk" is first member in "struct j1939_sock", so that we
3988c2ecf20Sopenharmony_ci	 * can skip it during memset().
3998c2ecf20Sopenharmony_ci	 */
4008c2ecf20Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct j1939_sock, sk) != 0);
4018c2ecf20Sopenharmony_ci	memset((void *)jsk + sizeof(jsk->sk), 0x0,
4028c2ecf20Sopenharmony_ci	       sizeof(*jsk) - sizeof(jsk->sk));
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&jsk->list);
4058c2ecf20Sopenharmony_ci	init_waitqueue_head(&jsk->waitq);
4068c2ecf20Sopenharmony_ci	jsk->sk.sk_priority = j1939_to_sk_priority(6);
4078c2ecf20Sopenharmony_ci	jsk->sk.sk_reuse = 1; /* per default */
4088c2ecf20Sopenharmony_ci	jsk->addr.sa = J1939_NO_ADDR;
4098c2ecf20Sopenharmony_ci	jsk->addr.da = J1939_NO_ADDR;
4108c2ecf20Sopenharmony_ci	jsk->addr.pgn = J1939_NO_PGN;
4118c2ecf20Sopenharmony_ci	jsk->pgn_rx_filter = J1939_NO_PGN;
4128c2ecf20Sopenharmony_ci	atomic_set(&jsk->skb_pending, 0);
4138c2ecf20Sopenharmony_ci	spin_lock_init(&jsk->sk_session_queue_lock);
4148c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&jsk->sk_session_queue);
4158c2ecf20Sopenharmony_ci	spin_lock_init(&jsk->filters_lock);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* j1939_sk_sock_destruct() depends on SOCK_RCU_FREE flag */
4188c2ecf20Sopenharmony_ci	sock_set_flag(sk, SOCK_RCU_FREE);
4198c2ecf20Sopenharmony_ci	sk->sk_destruct = j1939_sk_sock_destruct;
4208c2ecf20Sopenharmony_ci	sk->sk_protocol = CAN_J1939;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int j1939_sk_sanity_check(struct sockaddr_can *addr, int len)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	if (!addr)
4288c2ecf20Sopenharmony_ci		return -EDESTADDRREQ;
4298c2ecf20Sopenharmony_ci	if (len < J1939_MIN_NAMELEN)
4308c2ecf20Sopenharmony_ci		return -EINVAL;
4318c2ecf20Sopenharmony_ci	if (addr->can_family != AF_CAN)
4328c2ecf20Sopenharmony_ci		return -EINVAL;
4338c2ecf20Sopenharmony_ci	if (!addr->can_ifindex)
4348c2ecf20Sopenharmony_ci		return -ENODEV;
4358c2ecf20Sopenharmony_ci	if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn) &&
4368c2ecf20Sopenharmony_ci	    !j1939_pgn_is_clean_pdu(addr->can_addr.j1939.pgn))
4378c2ecf20Sopenharmony_ci		return -EINVAL;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return 0;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
4458c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sock->sk);
4468c2ecf20Sopenharmony_ci	struct j1939_priv *priv;
4478c2ecf20Sopenharmony_ci	struct sock *sk;
4488c2ecf20Sopenharmony_ci	struct net *net;
4498c2ecf20Sopenharmony_ci	int ret = 0;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	ret = j1939_sk_sanity_check(addr, len);
4528c2ecf20Sopenharmony_ci	if (ret)
4538c2ecf20Sopenharmony_ci		return ret;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	lock_sock(sock->sk);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	priv = jsk->priv;
4588c2ecf20Sopenharmony_ci	sk = sock->sk;
4598c2ecf20Sopenharmony_ci	net = sock_net(sk);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* Already bound to an interface? */
4628c2ecf20Sopenharmony_ci	if (jsk->state & J1939_SOCK_BOUND) {
4638c2ecf20Sopenharmony_ci		/* A re-bind() to a different interface is not
4648c2ecf20Sopenharmony_ci		 * supported.
4658c2ecf20Sopenharmony_ci		 */
4668c2ecf20Sopenharmony_ci		if (jsk->ifindex != addr->can_ifindex) {
4678c2ecf20Sopenharmony_ci			ret = -EINVAL;
4688c2ecf20Sopenharmony_ci			goto out_release_sock;
4698c2ecf20Sopenharmony_ci		}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		/* drop old references */
4728c2ecf20Sopenharmony_ci		j1939_jsk_del(priv, jsk);
4738c2ecf20Sopenharmony_ci		j1939_local_ecu_put(priv, jsk->addr.src_name, jsk->addr.sa);
4748c2ecf20Sopenharmony_ci	} else {
4758c2ecf20Sopenharmony_ci		struct can_ml_priv *can_ml;
4768c2ecf20Sopenharmony_ci		struct net_device *ndev;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		ndev = dev_get_by_index(net, addr->can_ifindex);
4798c2ecf20Sopenharmony_ci		if (!ndev) {
4808c2ecf20Sopenharmony_ci			ret = -ENODEV;
4818c2ecf20Sopenharmony_ci			goto out_release_sock;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		can_ml = can_get_ml_priv(ndev);
4858c2ecf20Sopenharmony_ci		if (!can_ml) {
4868c2ecf20Sopenharmony_ci			dev_put(ndev);
4878c2ecf20Sopenharmony_ci			ret = -ENODEV;
4888c2ecf20Sopenharmony_ci			goto out_release_sock;
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		if (!(ndev->flags & IFF_UP)) {
4928c2ecf20Sopenharmony_ci			dev_put(ndev);
4938c2ecf20Sopenharmony_ci			ret = -ENETDOWN;
4948c2ecf20Sopenharmony_ci			goto out_release_sock;
4958c2ecf20Sopenharmony_ci		}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		priv = j1939_netdev_start(ndev);
4988c2ecf20Sopenharmony_ci		dev_put(ndev);
4998c2ecf20Sopenharmony_ci		if (IS_ERR(priv)) {
5008c2ecf20Sopenharmony_ci			ret = PTR_ERR(priv);
5018c2ecf20Sopenharmony_ci			goto out_release_sock;
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		jsk->ifindex = addr->can_ifindex;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		/* the corresponding j1939_priv_put() is called via
5078c2ecf20Sopenharmony_ci		 * sk->sk_destruct, which points to j1939_sk_sock_destruct()
5088c2ecf20Sopenharmony_ci		 */
5098c2ecf20Sopenharmony_ci		j1939_priv_get(priv);
5108c2ecf20Sopenharmony_ci		jsk->priv = priv;
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/* set default transmit pgn */
5148c2ecf20Sopenharmony_ci	if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn))
5158c2ecf20Sopenharmony_ci		jsk->pgn_rx_filter = addr->can_addr.j1939.pgn;
5168c2ecf20Sopenharmony_ci	jsk->addr.src_name = addr->can_addr.j1939.name;
5178c2ecf20Sopenharmony_ci	jsk->addr.sa = addr->can_addr.j1939.addr;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/* get new references */
5208c2ecf20Sopenharmony_ci	ret = j1939_local_ecu_get(priv, jsk->addr.src_name, jsk->addr.sa);
5218c2ecf20Sopenharmony_ci	if (ret) {
5228c2ecf20Sopenharmony_ci		j1939_netdev_stop(priv);
5238c2ecf20Sopenharmony_ci		goto out_release_sock;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	j1939_jsk_add(priv, jsk);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci out_release_sock: /* fall through */
5298c2ecf20Sopenharmony_ci	release_sock(sock->sk);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return ret;
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic int j1939_sk_connect(struct socket *sock, struct sockaddr *uaddr,
5358c2ecf20Sopenharmony_ci			    int len, int flags)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
5388c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sock->sk);
5398c2ecf20Sopenharmony_ci	int ret = 0;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	ret = j1939_sk_sanity_check(addr, len);
5428c2ecf20Sopenharmony_ci	if (ret)
5438c2ecf20Sopenharmony_ci		return ret;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	lock_sock(sock->sk);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* bind() before connect() is mandatory */
5488c2ecf20Sopenharmony_ci	if (!(jsk->state & J1939_SOCK_BOUND)) {
5498c2ecf20Sopenharmony_ci		ret = -EINVAL;
5508c2ecf20Sopenharmony_ci		goto out_release_sock;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/* A connect() to a different interface is not supported. */
5548c2ecf20Sopenharmony_ci	if (jsk->ifindex != addr->can_ifindex) {
5558c2ecf20Sopenharmony_ci		ret = -EINVAL;
5568c2ecf20Sopenharmony_ci		goto out_release_sock;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (!addr->can_addr.j1939.name &&
5608c2ecf20Sopenharmony_ci	    addr->can_addr.j1939.addr == J1939_NO_ADDR &&
5618c2ecf20Sopenharmony_ci	    !sock_flag(&jsk->sk, SOCK_BROADCAST)) {
5628c2ecf20Sopenharmony_ci		/* broadcast, but SO_BROADCAST not set */
5638c2ecf20Sopenharmony_ci		ret = -EACCES;
5648c2ecf20Sopenharmony_ci		goto out_release_sock;
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	jsk->addr.dst_name = addr->can_addr.j1939.name;
5688c2ecf20Sopenharmony_ci	jsk->addr.da = addr->can_addr.j1939.addr;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn))
5718c2ecf20Sopenharmony_ci		jsk->addr.pgn = addr->can_addr.j1939.pgn;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	jsk->state |= J1939_SOCK_CONNECTED;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci out_release_sock: /* fall through */
5768c2ecf20Sopenharmony_ci	release_sock(sock->sk);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	return ret;
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic void j1939_sk_sock2sockaddr_can(struct sockaddr_can *addr,
5828c2ecf20Sopenharmony_ci				       const struct j1939_sock *jsk, int peer)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	/* There are two holes (2 bytes and 3 bytes) to clear to avoid
5858c2ecf20Sopenharmony_ci	 * leaking kernel information to user space.
5868c2ecf20Sopenharmony_ci	 */
5878c2ecf20Sopenharmony_ci	memset(addr, 0, J1939_MIN_NAMELEN);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	addr->can_family = AF_CAN;
5908c2ecf20Sopenharmony_ci	addr->can_ifindex = jsk->ifindex;
5918c2ecf20Sopenharmony_ci	addr->can_addr.j1939.pgn = jsk->addr.pgn;
5928c2ecf20Sopenharmony_ci	if (peer) {
5938c2ecf20Sopenharmony_ci		addr->can_addr.j1939.name = jsk->addr.dst_name;
5948c2ecf20Sopenharmony_ci		addr->can_addr.j1939.addr = jsk->addr.da;
5958c2ecf20Sopenharmony_ci	} else {
5968c2ecf20Sopenharmony_ci		addr->can_addr.j1939.name = jsk->addr.src_name;
5978c2ecf20Sopenharmony_ci		addr->can_addr.j1939.addr = jsk->addr.sa;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic int j1939_sk_getname(struct socket *sock, struct sockaddr *uaddr,
6028c2ecf20Sopenharmony_ci			    int peer)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
6058c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
6068c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
6078c2ecf20Sopenharmony_ci	int ret = 0;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	lock_sock(sk);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (peer && !(jsk->state & J1939_SOCK_CONNECTED)) {
6128c2ecf20Sopenharmony_ci		ret = -EADDRNOTAVAIL;
6138c2ecf20Sopenharmony_ci		goto failure;
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	j1939_sk_sock2sockaddr_can(addr, jsk, peer);
6178c2ecf20Sopenharmony_ci	ret = J1939_MIN_NAMELEN;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci failure:
6208c2ecf20Sopenharmony_ci	release_sock(sk);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	return ret;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic int j1939_sk_release(struct socket *sock)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
6288c2ecf20Sopenharmony_ci	struct j1939_sock *jsk;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	if (!sk)
6318c2ecf20Sopenharmony_ci		return 0;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	lock_sock(sk);
6348c2ecf20Sopenharmony_ci	jsk = j1939_sk(sk);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	if (jsk->state & J1939_SOCK_BOUND) {
6378c2ecf20Sopenharmony_ci		struct j1939_priv *priv = jsk->priv;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci		if (wait_event_interruptible(jsk->waitq,
6408c2ecf20Sopenharmony_ci					     !j1939_sock_pending_get(&jsk->sk))) {
6418c2ecf20Sopenharmony_ci			j1939_cancel_active_session(priv, sk);
6428c2ecf20Sopenharmony_ci			j1939_sk_queue_drop_all(priv, jsk, ESHUTDOWN);
6438c2ecf20Sopenharmony_ci		}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		j1939_jsk_del(priv, jsk);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		j1939_local_ecu_put(priv, jsk->addr.src_name,
6488c2ecf20Sopenharmony_ci				    jsk->addr.sa);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		j1939_netdev_stop(priv);
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	kfree(jsk->filters);
6548c2ecf20Sopenharmony_ci	sock_orphan(sk);
6558c2ecf20Sopenharmony_ci	sock->sk = NULL;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	release_sock(sk);
6588c2ecf20Sopenharmony_ci	sock_put(sk);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	return 0;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic int j1939_sk_setsockopt_flag(struct j1939_sock *jsk, sockptr_t optval,
6648c2ecf20Sopenharmony_ci				    unsigned int optlen, int flag)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	int tmp;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	if (optlen != sizeof(tmp))
6698c2ecf20Sopenharmony_ci		return -EINVAL;
6708c2ecf20Sopenharmony_ci	if (copy_from_sockptr(&tmp, optval, optlen))
6718c2ecf20Sopenharmony_ci		return -EFAULT;
6728c2ecf20Sopenharmony_ci	lock_sock(&jsk->sk);
6738c2ecf20Sopenharmony_ci	if (tmp)
6748c2ecf20Sopenharmony_ci		jsk->state |= flag;
6758c2ecf20Sopenharmony_ci	else
6768c2ecf20Sopenharmony_ci		jsk->state &= ~flag;
6778c2ecf20Sopenharmony_ci	release_sock(&jsk->sk);
6788c2ecf20Sopenharmony_ci	return tmp;
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistatic int j1939_sk_setsockopt(struct socket *sock, int level, int optname,
6828c2ecf20Sopenharmony_ci			       sockptr_t optval, unsigned int optlen)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
6858c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
6868c2ecf20Sopenharmony_ci	int tmp, count = 0, ret = 0;
6878c2ecf20Sopenharmony_ci	struct j1939_filter *filters = NULL, *ofilters;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (level != SOL_CAN_J1939)
6908c2ecf20Sopenharmony_ci		return -EINVAL;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	switch (optname) {
6938c2ecf20Sopenharmony_ci	case SO_J1939_FILTER:
6948c2ecf20Sopenharmony_ci		if (!sockptr_is_null(optval) && optlen != 0) {
6958c2ecf20Sopenharmony_ci			struct j1939_filter *f;
6968c2ecf20Sopenharmony_ci			int c;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci			if (optlen % sizeof(*filters) != 0)
6998c2ecf20Sopenharmony_ci				return -EINVAL;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci			if (optlen > J1939_FILTER_MAX *
7028c2ecf20Sopenharmony_ci			    sizeof(struct j1939_filter))
7038c2ecf20Sopenharmony_ci				return -EINVAL;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci			count = optlen / sizeof(*filters);
7068c2ecf20Sopenharmony_ci			filters = memdup_sockptr(optval, optlen);
7078c2ecf20Sopenharmony_ci			if (IS_ERR(filters))
7088c2ecf20Sopenharmony_ci				return PTR_ERR(filters);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci			for (f = filters, c = count; c; f++, c--) {
7118c2ecf20Sopenharmony_ci				f->name &= f->name_mask;
7128c2ecf20Sopenharmony_ci				f->pgn &= f->pgn_mask;
7138c2ecf20Sopenharmony_ci				f->addr &= f->addr_mask;
7148c2ecf20Sopenharmony_ci			}
7158c2ecf20Sopenharmony_ci		}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci		lock_sock(&jsk->sk);
7188c2ecf20Sopenharmony_ci		spin_lock_bh(&jsk->filters_lock);
7198c2ecf20Sopenharmony_ci		ofilters = jsk->filters;
7208c2ecf20Sopenharmony_ci		jsk->filters = filters;
7218c2ecf20Sopenharmony_ci		jsk->nfilters = count;
7228c2ecf20Sopenharmony_ci		spin_unlock_bh(&jsk->filters_lock);
7238c2ecf20Sopenharmony_ci		release_sock(&jsk->sk);
7248c2ecf20Sopenharmony_ci		kfree(ofilters);
7258c2ecf20Sopenharmony_ci		return 0;
7268c2ecf20Sopenharmony_ci	case SO_J1939_PROMISC:
7278c2ecf20Sopenharmony_ci		return j1939_sk_setsockopt_flag(jsk, optval, optlen,
7288c2ecf20Sopenharmony_ci						J1939_SOCK_PROMISC);
7298c2ecf20Sopenharmony_ci	case SO_J1939_ERRQUEUE:
7308c2ecf20Sopenharmony_ci		ret = j1939_sk_setsockopt_flag(jsk, optval, optlen,
7318c2ecf20Sopenharmony_ci					       J1939_SOCK_ERRQUEUE);
7328c2ecf20Sopenharmony_ci		if (ret < 0)
7338c2ecf20Sopenharmony_ci			return ret;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		if (!(jsk->state & J1939_SOCK_ERRQUEUE))
7368c2ecf20Sopenharmony_ci			skb_queue_purge(&sk->sk_error_queue);
7378c2ecf20Sopenharmony_ci		return ret;
7388c2ecf20Sopenharmony_ci	case SO_J1939_SEND_PRIO:
7398c2ecf20Sopenharmony_ci		if (optlen != sizeof(tmp))
7408c2ecf20Sopenharmony_ci			return -EINVAL;
7418c2ecf20Sopenharmony_ci		if (copy_from_sockptr(&tmp, optval, optlen))
7428c2ecf20Sopenharmony_ci			return -EFAULT;
7438c2ecf20Sopenharmony_ci		if (tmp < 0 || tmp > 7)
7448c2ecf20Sopenharmony_ci			return -EDOM;
7458c2ecf20Sopenharmony_ci		if (tmp < 2 && !capable(CAP_NET_ADMIN))
7468c2ecf20Sopenharmony_ci			return -EPERM;
7478c2ecf20Sopenharmony_ci		lock_sock(&jsk->sk);
7488c2ecf20Sopenharmony_ci		jsk->sk.sk_priority = j1939_to_sk_priority(tmp);
7498c2ecf20Sopenharmony_ci		release_sock(&jsk->sk);
7508c2ecf20Sopenharmony_ci		return 0;
7518c2ecf20Sopenharmony_ci	default:
7528c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic int j1939_sk_getsockopt(struct socket *sock, int level, int optname,
7578c2ecf20Sopenharmony_ci			       char __user *optval, int __user *optlen)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
7608c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
7618c2ecf20Sopenharmony_ci	int ret, ulen;
7628c2ecf20Sopenharmony_ci	/* set defaults for using 'int' properties */
7638c2ecf20Sopenharmony_ci	int tmp = 0;
7648c2ecf20Sopenharmony_ci	int len = sizeof(tmp);
7658c2ecf20Sopenharmony_ci	void *val = &tmp;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	if (level != SOL_CAN_J1939)
7688c2ecf20Sopenharmony_ci		return -EINVAL;
7698c2ecf20Sopenharmony_ci	if (get_user(ulen, optlen))
7708c2ecf20Sopenharmony_ci		return -EFAULT;
7718c2ecf20Sopenharmony_ci	if (ulen < 0)
7728c2ecf20Sopenharmony_ci		return -EINVAL;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	lock_sock(&jsk->sk);
7758c2ecf20Sopenharmony_ci	switch (optname) {
7768c2ecf20Sopenharmony_ci	case SO_J1939_PROMISC:
7778c2ecf20Sopenharmony_ci		tmp = (jsk->state & J1939_SOCK_PROMISC) ? 1 : 0;
7788c2ecf20Sopenharmony_ci		break;
7798c2ecf20Sopenharmony_ci	case SO_J1939_ERRQUEUE:
7808c2ecf20Sopenharmony_ci		tmp = (jsk->state & J1939_SOCK_ERRQUEUE) ? 1 : 0;
7818c2ecf20Sopenharmony_ci		break;
7828c2ecf20Sopenharmony_ci	case SO_J1939_SEND_PRIO:
7838c2ecf20Sopenharmony_ci		tmp = j1939_prio(jsk->sk.sk_priority);
7848c2ecf20Sopenharmony_ci		break;
7858c2ecf20Sopenharmony_ci	default:
7868c2ecf20Sopenharmony_ci		ret = -ENOPROTOOPT;
7878c2ecf20Sopenharmony_ci		goto no_copy;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/* copy to user, based on 'len' & 'val'
7918c2ecf20Sopenharmony_ci	 * but most sockopt's are 'int' properties, and have 'len' & 'val'
7928c2ecf20Sopenharmony_ci	 * left unchanged, but instead modified 'tmp'
7938c2ecf20Sopenharmony_ci	 */
7948c2ecf20Sopenharmony_ci	if (len > ulen)
7958c2ecf20Sopenharmony_ci		ret = -EFAULT;
7968c2ecf20Sopenharmony_ci	else if (put_user(len, optlen))
7978c2ecf20Sopenharmony_ci		ret = -EFAULT;
7988c2ecf20Sopenharmony_ci	else if (copy_to_user(optval, val, len))
7998c2ecf20Sopenharmony_ci		ret = -EFAULT;
8008c2ecf20Sopenharmony_ci	else
8018c2ecf20Sopenharmony_ci		ret = 0;
8028c2ecf20Sopenharmony_ci no_copy:
8038c2ecf20Sopenharmony_ci	release_sock(&jsk->sk);
8048c2ecf20Sopenharmony_ci	return ret;
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic int j1939_sk_recvmsg(struct socket *sock, struct msghdr *msg,
8088c2ecf20Sopenharmony_ci			    size_t size, int flags)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
8118c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8128c2ecf20Sopenharmony_ci	struct j1939_sk_buff_cb *skcb;
8138c2ecf20Sopenharmony_ci	int ret = 0;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (flags & ~(MSG_DONTWAIT | MSG_ERRQUEUE | MSG_CMSG_COMPAT))
8168c2ecf20Sopenharmony_ci		return -EINVAL;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (flags & MSG_ERRQUEUE)
8198c2ecf20Sopenharmony_ci		return sock_recv_errqueue(sock->sk, msg, size, SOL_CAN_J1939,
8208c2ecf20Sopenharmony_ci					  SCM_J1939_ERRQUEUE);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	skb = skb_recv_datagram(sk, flags, 0, &ret);
8238c2ecf20Sopenharmony_ci	if (!skb)
8248c2ecf20Sopenharmony_ci		return ret;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (size < skb->len)
8278c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
8288c2ecf20Sopenharmony_ci	else
8298c2ecf20Sopenharmony_ci		size = skb->len;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	ret = memcpy_to_msg(msg, skb->data, size);
8328c2ecf20Sopenharmony_ci	if (ret < 0) {
8338c2ecf20Sopenharmony_ci		skb_free_datagram(sk, skb);
8348c2ecf20Sopenharmony_ci		return ret;
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	skcb = j1939_skb_to_cb(skb);
8388c2ecf20Sopenharmony_ci	if (j1939_address_is_valid(skcb->addr.da))
8398c2ecf20Sopenharmony_ci		put_cmsg(msg, SOL_CAN_J1939, SCM_J1939_DEST_ADDR,
8408c2ecf20Sopenharmony_ci			 sizeof(skcb->addr.da), &skcb->addr.da);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	if (skcb->addr.dst_name)
8438c2ecf20Sopenharmony_ci		put_cmsg(msg, SOL_CAN_J1939, SCM_J1939_DEST_NAME,
8448c2ecf20Sopenharmony_ci			 sizeof(skcb->addr.dst_name), &skcb->addr.dst_name);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	put_cmsg(msg, SOL_CAN_J1939, SCM_J1939_PRIO,
8478c2ecf20Sopenharmony_ci		 sizeof(skcb->priority), &skcb->priority);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (msg->msg_name) {
8508c2ecf20Sopenharmony_ci		struct sockaddr_can *paddr = msg->msg_name;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci		msg->msg_namelen = J1939_MIN_NAMELEN;
8538c2ecf20Sopenharmony_ci		memset(msg->msg_name, 0, msg->msg_namelen);
8548c2ecf20Sopenharmony_ci		paddr->can_family = AF_CAN;
8558c2ecf20Sopenharmony_ci		paddr->can_ifindex = skb->skb_iif;
8568c2ecf20Sopenharmony_ci		paddr->can_addr.j1939.name = skcb->addr.src_name;
8578c2ecf20Sopenharmony_ci		paddr->can_addr.j1939.addr = skcb->addr.sa;
8588c2ecf20Sopenharmony_ci		paddr->can_addr.j1939.pgn = skcb->addr.pgn;
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	sock_recv_ts_and_drops(msg, sk, skb);
8628c2ecf20Sopenharmony_ci	msg->msg_flags |= skcb->msg_flags;
8638c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	return size;
8668c2ecf20Sopenharmony_ci}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev,
8698c2ecf20Sopenharmony_ci					  struct sock *sk,
8708c2ecf20Sopenharmony_ci					  struct msghdr *msg, size_t size,
8718c2ecf20Sopenharmony_ci					  int *errcode)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
8748c2ecf20Sopenharmony_ci	struct j1939_sk_buff_cb *skcb;
8758c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8768c2ecf20Sopenharmony_ci	int ret;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	skb = sock_alloc_send_skb(sk,
8798c2ecf20Sopenharmony_ci				  size +
8808c2ecf20Sopenharmony_ci				  sizeof(struct can_frame) -
8818c2ecf20Sopenharmony_ci				  sizeof(((struct can_frame *)NULL)->data) +
8828c2ecf20Sopenharmony_ci				  sizeof(struct can_skb_priv),
8838c2ecf20Sopenharmony_ci				  msg->msg_flags & MSG_DONTWAIT, &ret);
8848c2ecf20Sopenharmony_ci	if (!skb)
8858c2ecf20Sopenharmony_ci		goto failure;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	can_skb_reserve(skb);
8888c2ecf20Sopenharmony_ci	can_skb_prv(skb)->ifindex = ndev->ifindex;
8898c2ecf20Sopenharmony_ci	can_skb_prv(skb)->skbcnt = 0;
8908c2ecf20Sopenharmony_ci	skb_reserve(skb, offsetof(struct can_frame, data));
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	ret = memcpy_from_msg(skb_put(skb, size), msg, size);
8938c2ecf20Sopenharmony_ci	if (ret < 0)
8948c2ecf20Sopenharmony_ci		goto free_skb;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	skb->dev = ndev;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	skcb = j1939_skb_to_cb(skb);
8998c2ecf20Sopenharmony_ci	memset(skcb, 0, sizeof(*skcb));
9008c2ecf20Sopenharmony_ci	skcb->addr = jsk->addr;
9018c2ecf20Sopenharmony_ci	skcb->priority = j1939_prio(sk->sk_priority);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if (msg->msg_name) {
9048c2ecf20Sopenharmony_ci		struct sockaddr_can *addr = msg->msg_name;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci		if (addr->can_addr.j1939.name ||
9078c2ecf20Sopenharmony_ci		    addr->can_addr.j1939.addr != J1939_NO_ADDR) {
9088c2ecf20Sopenharmony_ci			skcb->addr.dst_name = addr->can_addr.j1939.name;
9098c2ecf20Sopenharmony_ci			skcb->addr.da = addr->can_addr.j1939.addr;
9108c2ecf20Sopenharmony_ci		}
9118c2ecf20Sopenharmony_ci		if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn))
9128c2ecf20Sopenharmony_ci			skcb->addr.pgn = addr->can_addr.j1939.pgn;
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	*errcode = ret;
9168c2ecf20Sopenharmony_ci	return skb;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_cifree_skb:
9198c2ecf20Sopenharmony_ci	kfree_skb(skb);
9208c2ecf20Sopenharmony_cifailure:
9218c2ecf20Sopenharmony_ci	*errcode = ret;
9228c2ecf20Sopenharmony_ci	return NULL;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic size_t j1939_sk_opt_stats_get_size(void)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	return
9288c2ecf20Sopenharmony_ci		nla_total_size(sizeof(u32)) + /* J1939_NLA_BYTES_ACKED */
9298c2ecf20Sopenharmony_ci		0;
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic struct sk_buff *
9338c2ecf20Sopenharmony_cij1939_sk_get_timestamping_opt_stats(struct j1939_session *session)
9348c2ecf20Sopenharmony_ci{
9358c2ecf20Sopenharmony_ci	struct sk_buff *stats;
9368c2ecf20Sopenharmony_ci	u32 size;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	stats = alloc_skb(j1939_sk_opt_stats_get_size(), GFP_ATOMIC);
9398c2ecf20Sopenharmony_ci	if (!stats)
9408c2ecf20Sopenharmony_ci		return NULL;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (session->skcb.addr.type == J1939_SIMPLE)
9438c2ecf20Sopenharmony_ci		size = session->total_message_size;
9448c2ecf20Sopenharmony_ci	else
9458c2ecf20Sopenharmony_ci		size = min(session->pkt.tx_acked * 7,
9468c2ecf20Sopenharmony_ci			   session->total_message_size);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	nla_put_u32(stats, J1939_NLA_BYTES_ACKED, size);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	return stats;
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_civoid j1939_sk_errqueue(struct j1939_session *session,
9548c2ecf20Sopenharmony_ci		       enum j1939_sk_errqueue_type type)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	struct j1939_priv *priv = session->priv;
9578c2ecf20Sopenharmony_ci	struct sock *sk = session->sk;
9588c2ecf20Sopenharmony_ci	struct j1939_sock *jsk;
9598c2ecf20Sopenharmony_ci	struct sock_exterr_skb *serr;
9608c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9618c2ecf20Sopenharmony_ci	char *state = "UNK";
9628c2ecf20Sopenharmony_ci	int err;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	/* currently we have no sk for the RX session */
9658c2ecf20Sopenharmony_ci	if (!sk)
9668c2ecf20Sopenharmony_ci		return;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	jsk = j1939_sk(sk);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	if (!(jsk->state & J1939_SOCK_ERRQUEUE))
9718c2ecf20Sopenharmony_ci		return;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	skb = j1939_sk_get_timestamping_opt_stats(session);
9748c2ecf20Sopenharmony_ci	if (!skb)
9758c2ecf20Sopenharmony_ci		return;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	skb->tstamp = ktime_get_real();
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct sock_exterr_skb) > sizeof(skb->cb));
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	serr = SKB_EXT_ERR(skb);
9828c2ecf20Sopenharmony_ci	memset(serr, 0, sizeof(*serr));
9838c2ecf20Sopenharmony_ci	switch (type) {
9848c2ecf20Sopenharmony_ci	case J1939_ERRQUEUE_ACK:
9858c2ecf20Sopenharmony_ci		if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)) {
9868c2ecf20Sopenharmony_ci			kfree_skb(skb);
9878c2ecf20Sopenharmony_ci			return;
9888c2ecf20Sopenharmony_ci		}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		serr->ee.ee_errno = ENOMSG;
9918c2ecf20Sopenharmony_ci		serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
9928c2ecf20Sopenharmony_ci		serr->ee.ee_info = SCM_TSTAMP_ACK;
9938c2ecf20Sopenharmony_ci		state = "ACK";
9948c2ecf20Sopenharmony_ci		break;
9958c2ecf20Sopenharmony_ci	case J1939_ERRQUEUE_SCHED:
9968c2ecf20Sopenharmony_ci		if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED)) {
9978c2ecf20Sopenharmony_ci			kfree_skb(skb);
9988c2ecf20Sopenharmony_ci			return;
9998c2ecf20Sopenharmony_ci		}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci		serr->ee.ee_errno = ENOMSG;
10028c2ecf20Sopenharmony_ci		serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
10038c2ecf20Sopenharmony_ci		serr->ee.ee_info = SCM_TSTAMP_SCHED;
10048c2ecf20Sopenharmony_ci		state = "SCH";
10058c2ecf20Sopenharmony_ci		break;
10068c2ecf20Sopenharmony_ci	case J1939_ERRQUEUE_ABORT:
10078c2ecf20Sopenharmony_ci		serr->ee.ee_errno = session->err;
10088c2ecf20Sopenharmony_ci		serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
10098c2ecf20Sopenharmony_ci		serr->ee.ee_info = J1939_EE_INFO_TX_ABORT;
10108c2ecf20Sopenharmony_ci		state = "ABT";
10118c2ecf20Sopenharmony_ci		break;
10128c2ecf20Sopenharmony_ci	default:
10138c2ecf20Sopenharmony_ci		netdev_err(priv->ndev, "Unknown errqueue type %i\n", type);
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	serr->opt_stats = true;
10178c2ecf20Sopenharmony_ci	if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
10188c2ecf20Sopenharmony_ci		serr->ee.ee_data = session->tskey;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	netdev_dbg(session->priv->ndev, "%s: 0x%p tskey: %i, state: %s\n",
10218c2ecf20Sopenharmony_ci		   __func__, session, session->tskey, state);
10228c2ecf20Sopenharmony_ci	err = sock_queue_err_skb(sk, skb);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (err)
10258c2ecf20Sopenharmony_ci		kfree_skb(skb);
10268c2ecf20Sopenharmony_ci};
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_civoid j1939_sk_send_loop_abort(struct sock *sk, int err)
10298c2ecf20Sopenharmony_ci{
10308c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (jsk->state & J1939_SOCK_ERRQUEUE)
10338c2ecf20Sopenharmony_ci		return;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	sk->sk_err = err;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	sk->sk_error_report(sk);
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic int j1939_sk_send_loop(struct j1939_priv *priv,  struct sock *sk,
10418c2ecf20Sopenharmony_ci			      struct msghdr *msg, size_t size)
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci{
10448c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
10458c2ecf20Sopenharmony_ci	struct j1939_session *session = j1939_sk_get_incomplete_session(jsk);
10468c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10478c2ecf20Sopenharmony_ci	size_t segment_size, todo_size;
10488c2ecf20Sopenharmony_ci	int ret = 0;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	if (session &&
10518c2ecf20Sopenharmony_ci	    session->total_message_size != session->total_queued_size + size) {
10528c2ecf20Sopenharmony_ci		j1939_session_put(session);
10538c2ecf20Sopenharmony_ci		return -EIO;
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	todo_size = size;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	while (todo_size) {
10598c2ecf20Sopenharmony_ci		struct j1939_sk_buff_cb *skcb;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci		segment_size = min_t(size_t, J1939_MAX_TP_PACKET_SIZE,
10628c2ecf20Sopenharmony_ci				     todo_size);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci		/* Allocate skb for one segment */
10658c2ecf20Sopenharmony_ci		skb = j1939_sk_alloc_skb(priv->ndev, sk, msg, segment_size,
10668c2ecf20Sopenharmony_ci					 &ret);
10678c2ecf20Sopenharmony_ci		if (ret)
10688c2ecf20Sopenharmony_ci			break;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci		skcb = j1939_skb_to_cb(skb);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci		if (!session) {
10738c2ecf20Sopenharmony_ci			/* at this point the size should be full size
10748c2ecf20Sopenharmony_ci			 * of the session
10758c2ecf20Sopenharmony_ci			 */
10768c2ecf20Sopenharmony_ci			skcb->offset = 0;
10778c2ecf20Sopenharmony_ci			session = j1939_tp_send(priv, skb, size);
10788c2ecf20Sopenharmony_ci			if (IS_ERR(session)) {
10798c2ecf20Sopenharmony_ci				ret = PTR_ERR(session);
10808c2ecf20Sopenharmony_ci				goto kfree_skb;
10818c2ecf20Sopenharmony_ci			}
10828c2ecf20Sopenharmony_ci			if (j1939_sk_queue_session(session)) {
10838c2ecf20Sopenharmony_ci				/* try to activate session if we a
10848c2ecf20Sopenharmony_ci				 * fist in the queue
10858c2ecf20Sopenharmony_ci				 */
10868c2ecf20Sopenharmony_ci				if (!j1939_session_activate(session)) {
10878c2ecf20Sopenharmony_ci					j1939_tp_schedule_txtimer(session, 0);
10888c2ecf20Sopenharmony_ci				} else {
10898c2ecf20Sopenharmony_ci					ret = -EBUSY;
10908c2ecf20Sopenharmony_ci					session->err = ret;
10918c2ecf20Sopenharmony_ci					j1939_sk_queue_drop_all(priv, jsk,
10928c2ecf20Sopenharmony_ci								EBUSY);
10938c2ecf20Sopenharmony_ci					break;
10948c2ecf20Sopenharmony_ci				}
10958c2ecf20Sopenharmony_ci			}
10968c2ecf20Sopenharmony_ci		} else {
10978c2ecf20Sopenharmony_ci			skcb->offset = session->total_queued_size;
10988c2ecf20Sopenharmony_ci			j1939_session_skb_queue(session, skb);
10998c2ecf20Sopenharmony_ci		}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		todo_size -= segment_size;
11028c2ecf20Sopenharmony_ci		session->total_queued_size += segment_size;
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	switch (ret) {
11068c2ecf20Sopenharmony_ci	case 0: /* OK */
11078c2ecf20Sopenharmony_ci		if (todo_size)
11088c2ecf20Sopenharmony_ci			netdev_warn(priv->ndev,
11098c2ecf20Sopenharmony_ci				    "no error found and not completely queued?! %zu\n",
11108c2ecf20Sopenharmony_ci				    todo_size);
11118c2ecf20Sopenharmony_ci		ret = size;
11128c2ecf20Sopenharmony_ci		break;
11138c2ecf20Sopenharmony_ci	case -ERESTARTSYS:
11148c2ecf20Sopenharmony_ci		ret = -EINTR;
11158c2ecf20Sopenharmony_ci		fallthrough;
11168c2ecf20Sopenharmony_ci	case -EAGAIN: /* OK */
11178c2ecf20Sopenharmony_ci		if (todo_size != size)
11188c2ecf20Sopenharmony_ci			ret = size - todo_size;
11198c2ecf20Sopenharmony_ci		break;
11208c2ecf20Sopenharmony_ci	default: /* ERROR */
11218c2ecf20Sopenharmony_ci		break;
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (session)
11258c2ecf20Sopenharmony_ci		j1939_session_put(session);
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	return ret;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci kfree_skb:
11308c2ecf20Sopenharmony_ci	kfree_skb(skb);
11318c2ecf20Sopenharmony_ci	return ret;
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_cistatic int j1939_sk_sendmsg(struct socket *sock, struct msghdr *msg,
11358c2ecf20Sopenharmony_ci			    size_t size)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
11388c2ecf20Sopenharmony_ci	struct j1939_sock *jsk = j1939_sk(sk);
11398c2ecf20Sopenharmony_ci	struct j1939_priv *priv;
11408c2ecf20Sopenharmony_ci	int ifindex;
11418c2ecf20Sopenharmony_ci	int ret;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	lock_sock(sock->sk);
11448c2ecf20Sopenharmony_ci	/* various socket state tests */
11458c2ecf20Sopenharmony_ci	if (!(jsk->state & J1939_SOCK_BOUND)) {
11468c2ecf20Sopenharmony_ci		ret = -EBADFD;
11478c2ecf20Sopenharmony_ci		goto sendmsg_done;
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	priv = jsk->priv;
11518c2ecf20Sopenharmony_ci	ifindex = jsk->ifindex;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	if (!jsk->addr.src_name && jsk->addr.sa == J1939_NO_ADDR) {
11548c2ecf20Sopenharmony_ci		/* no source address assigned yet */
11558c2ecf20Sopenharmony_ci		ret = -EBADFD;
11568c2ecf20Sopenharmony_ci		goto sendmsg_done;
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	/* deal with provided destination address info */
11608c2ecf20Sopenharmony_ci	if (msg->msg_name) {
11618c2ecf20Sopenharmony_ci		struct sockaddr_can *addr = msg->msg_name;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci		if (msg->msg_namelen < J1939_MIN_NAMELEN) {
11648c2ecf20Sopenharmony_ci			ret = -EINVAL;
11658c2ecf20Sopenharmony_ci			goto sendmsg_done;
11668c2ecf20Sopenharmony_ci		}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		if (addr->can_family != AF_CAN) {
11698c2ecf20Sopenharmony_ci			ret = -EINVAL;
11708c2ecf20Sopenharmony_ci			goto sendmsg_done;
11718c2ecf20Sopenharmony_ci		}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci		if (addr->can_ifindex && addr->can_ifindex != ifindex) {
11748c2ecf20Sopenharmony_ci			ret = -EBADFD;
11758c2ecf20Sopenharmony_ci			goto sendmsg_done;
11768c2ecf20Sopenharmony_ci		}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci		if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn) &&
11798c2ecf20Sopenharmony_ci		    !j1939_pgn_is_clean_pdu(addr->can_addr.j1939.pgn)) {
11808c2ecf20Sopenharmony_ci			ret = -EINVAL;
11818c2ecf20Sopenharmony_ci			goto sendmsg_done;
11828c2ecf20Sopenharmony_ci		}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci		if (!addr->can_addr.j1939.name &&
11858c2ecf20Sopenharmony_ci		    addr->can_addr.j1939.addr == J1939_NO_ADDR &&
11868c2ecf20Sopenharmony_ci		    !sock_flag(sk, SOCK_BROADCAST)) {
11878c2ecf20Sopenharmony_ci			/* broadcast, but SO_BROADCAST not set */
11888c2ecf20Sopenharmony_ci			ret = -EACCES;
11898c2ecf20Sopenharmony_ci			goto sendmsg_done;
11908c2ecf20Sopenharmony_ci		}
11918c2ecf20Sopenharmony_ci	} else {
11928c2ecf20Sopenharmony_ci		if (!jsk->addr.dst_name && jsk->addr.da == J1939_NO_ADDR &&
11938c2ecf20Sopenharmony_ci		    !sock_flag(sk, SOCK_BROADCAST)) {
11948c2ecf20Sopenharmony_ci			/* broadcast, but SO_BROADCAST not set */
11958c2ecf20Sopenharmony_ci			ret = -EACCES;
11968c2ecf20Sopenharmony_ci			goto sendmsg_done;
11978c2ecf20Sopenharmony_ci		}
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	ret = j1939_sk_send_loop(priv, sk, msg, size);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cisendmsg_done:
12038c2ecf20Sopenharmony_ci	release_sock(sock->sk);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	return ret;
12068c2ecf20Sopenharmony_ci}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_civoid j1939_sk_netdev_event_netdown(struct j1939_priv *priv)
12098c2ecf20Sopenharmony_ci{
12108c2ecf20Sopenharmony_ci	struct j1939_sock *jsk;
12118c2ecf20Sopenharmony_ci	int error_code = ENETDOWN;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->j1939_socks_lock);
12148c2ecf20Sopenharmony_ci	list_for_each_entry(jsk, &priv->j1939_socks, list) {
12158c2ecf20Sopenharmony_ci		jsk->sk.sk_err = error_code;
12168c2ecf20Sopenharmony_ci		if (!sock_flag(&jsk->sk, SOCK_DEAD))
12178c2ecf20Sopenharmony_ci			jsk->sk.sk_error_report(&jsk->sk);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci		j1939_sk_queue_drop_all(priv, jsk, error_code);
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->j1939_socks_lock);
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_cistatic int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd,
12258c2ecf20Sopenharmony_ci				unsigned long arg)
12268c2ecf20Sopenharmony_ci{
12278c2ecf20Sopenharmony_ci	/* no ioctls for socket layer -> hand it down to NIC layer */
12288c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
12298c2ecf20Sopenharmony_ci}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_cistatic const struct proto_ops j1939_ops = {
12328c2ecf20Sopenharmony_ci	.family = PF_CAN,
12338c2ecf20Sopenharmony_ci	.release = j1939_sk_release,
12348c2ecf20Sopenharmony_ci	.bind = j1939_sk_bind,
12358c2ecf20Sopenharmony_ci	.connect = j1939_sk_connect,
12368c2ecf20Sopenharmony_ci	.socketpair = sock_no_socketpair,
12378c2ecf20Sopenharmony_ci	.accept = sock_no_accept,
12388c2ecf20Sopenharmony_ci	.getname = j1939_sk_getname,
12398c2ecf20Sopenharmony_ci	.poll = datagram_poll,
12408c2ecf20Sopenharmony_ci	.ioctl = j1939_sk_no_ioctlcmd,
12418c2ecf20Sopenharmony_ci	.listen = sock_no_listen,
12428c2ecf20Sopenharmony_ci	.shutdown = sock_no_shutdown,
12438c2ecf20Sopenharmony_ci	.setsockopt = j1939_sk_setsockopt,
12448c2ecf20Sopenharmony_ci	.getsockopt = j1939_sk_getsockopt,
12458c2ecf20Sopenharmony_ci	.sendmsg = j1939_sk_sendmsg,
12468c2ecf20Sopenharmony_ci	.recvmsg = j1939_sk_recvmsg,
12478c2ecf20Sopenharmony_ci	.mmap = sock_no_mmap,
12488c2ecf20Sopenharmony_ci	.sendpage = sock_no_sendpage,
12498c2ecf20Sopenharmony_ci};
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_cistatic struct proto j1939_proto __read_mostly = {
12528c2ecf20Sopenharmony_ci	.name = "CAN_J1939",
12538c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
12548c2ecf20Sopenharmony_ci	.obj_size = sizeof(struct j1939_sock),
12558c2ecf20Sopenharmony_ci	.init = j1939_sk_init,
12568c2ecf20Sopenharmony_ci};
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ciconst struct can_proto j1939_can_proto = {
12598c2ecf20Sopenharmony_ci	.type = SOCK_DGRAM,
12608c2ecf20Sopenharmony_ci	.protocol = CAN_J1939,
12618c2ecf20Sopenharmony_ci	.ops = &j1939_ops,
12628c2ecf20Sopenharmony_ci	.prot = &j1939_proto,
12638c2ecf20Sopenharmony_ci};
1264