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