linux/net/can/j1939/socket.c

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2010-2011 EIA Electronics,
//                         Pieter Beyens <[email protected]>
// Copyright (c) 2010-2011 EIA Electronics,
//                         Kurt Van Dijck <[email protected]>
// Copyright (c) 2018 Protonic,
//                         Robin van der Gracht <[email protected]>
// Copyright (c) 2017-2019 Pengutronix,
//                         Marc Kleine-Budde <[email protected]>
// Copyright (c) 2017-2019 Pengutronix,
//                         Oleksij Rempel <[email protected]>

#define pr_fmt(fmt)

#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/errqueue.h>
#include <linux/if_arp.h>

#include "j1939-priv.h"

#define J1939_MIN_NAMELEN

/* conversion function between struct sock::sk_priority from linux and
 * j1939 priority field
 */
static inline priority_t j1939_prio(u32 sk_priority)
{}

static inline u32 j1939_to_sk_priority(priority_t prio)
{}

/* function to see if pgn is to be evaluated */
static inline bool j1939_pgn_is_valid(pgn_t pgn)
{}

/* test function to avoid non-zero DA placeholder for pdu1 pgn's */
static inline bool j1939_pgn_is_clean_pdu(pgn_t pgn)
{}

static inline void j1939_sock_pending_add(struct sock *sk)
{}

static int j1939_sock_pending_get(struct sock *sk)
{}

void j1939_sock_pending_del(struct sock *sk)
{}

static void j1939_jsk_add(struct j1939_priv *priv, struct j1939_sock *jsk)
{}

static void j1939_jsk_del(struct j1939_priv *priv, struct j1939_sock *jsk)
{}

static bool j1939_sk_queue_session(struct j1939_session *session)
{}

static struct
j1939_session *j1939_sk_get_incomplete_session(struct j1939_sock *jsk)
{}

static void j1939_sk_queue_drop_all(struct j1939_priv *priv,
				    struct j1939_sock *jsk, int err)
{}

static void j1939_sk_queue_activate_next_locked(struct j1939_session *session)
{}

void j1939_sk_queue_activate_next(struct j1939_session *session)
{}

static bool j1939_sk_match_dst(struct j1939_sock *jsk,
			       const struct j1939_sk_buff_cb *skcb)
{}

/* matches skb control buffer (addr) with a j1939 filter */
static bool j1939_sk_match_filter(struct j1939_sock *jsk,
				  const struct j1939_sk_buff_cb *skcb)
{}

static bool j1939_sk_recv_match_one(struct j1939_sock *jsk,
				    const struct j1939_sk_buff_cb *skcb)
{}

static void j1939_sk_recv_one(struct j1939_sock *jsk, struct sk_buff *oskb)
{}

bool j1939_sk_recv_match(struct j1939_priv *priv, struct j1939_sk_buff_cb *skcb)
{}

void j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb)
{}

static void j1939_sk_sock_destruct(struct sock *sk)
{}

static int j1939_sk_init(struct sock *sk)
{}

static int j1939_sk_sanity_check(struct sockaddr_can *addr, int len)
{}

static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
{}

static int j1939_sk_connect(struct socket *sock, struct sockaddr *uaddr,
			    int len, int flags)
{}

static void j1939_sk_sock2sockaddr_can(struct sockaddr_can *addr,
				       const struct j1939_sock *jsk, int peer)
{}

static int j1939_sk_getname(struct socket *sock, struct sockaddr *uaddr,
			    int peer)
{}

static int j1939_sk_release(struct socket *sock)
{}

static int j1939_sk_setsockopt_flag(struct j1939_sock *jsk, sockptr_t optval,
				    unsigned int optlen, int flag)
{}

static int j1939_sk_setsockopt(struct socket *sock, int level, int optname,
			       sockptr_t optval, unsigned int optlen)
{}

static int j1939_sk_getsockopt(struct socket *sock, int level, int optname,
			       char __user *optval, int __user *optlen)
{}

static int j1939_sk_recvmsg(struct socket *sock, struct msghdr *msg,
			    size_t size, int flags)
{}

static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev,
					  struct sock *sk,
					  struct msghdr *msg, size_t size,
					  int *errcode)
{}

static size_t j1939_sk_opt_stats_get_size(enum j1939_sk_errqueue_type type)
{}

static struct sk_buff *
j1939_sk_get_timestamping_opt_stats(struct j1939_session *session,
				    enum j1939_sk_errqueue_type type)
{}

static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
				enum j1939_sk_errqueue_type type)
{
	struct j1939_priv *priv = session->priv;
	struct j1939_sock *jsk;
	struct sock_exterr_skb *serr;
	struct sk_buff *skb;
	char *state = "UNK";
	u32 tsflags;
	int err;

	jsk = j1939_sk(sk);

	if (!(jsk->state & J1939_SOCK_ERRQUEUE))
		return;

	tsflags = READ_ONCE(sk->sk_tsflags);
	switch (type) {
	case J1939_ERRQUEUE_TX_ACK:
		if (!(tsflags & SOF_TIMESTAMPING_TX_ACK))
			return;
		break;
	case J1939_ERRQUEUE_TX_SCHED:
		if (!(tsflags & SOF_TIMESTAMPING_TX_SCHED))
			return;
		break;
	case J1939_ERRQUEUE_TX_ABORT:
		break;
	case J1939_ERRQUEUE_RX_RTS:
		fallthrough;
	case J1939_ERRQUEUE_RX_DPO:
		fallthrough;
	case J1939_ERRQUEUE_RX_ABORT:
		if (!(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE))
			return;
		break;
	default:
		netdev_err(priv->ndev, "Unknown errqueue type %i\n", type);
	}

	skb = j1939_sk_get_timestamping_opt_stats(session, type);
	if (!skb)
		return;

	skb->tstamp = ktime_get_real();

	BUILD_BUG_ON(sizeof(struct sock_exterr_skb) > sizeof(skb->cb));

	serr = SKB_EXT_ERR(skb);
	memset(serr, 0, sizeof(*serr));
	switch (type) {
	case J1939_ERRQUEUE_TX_ACK:
		serr->ee.ee_errno = ENOMSG;
		serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
		serr->ee.ee_info = SCM_TSTAMP_ACK;
		state = "TX ACK";
		break;
	case J1939_ERRQUEUE_TX_SCHED:
		serr->ee.ee_errno = ENOMSG;
		serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
		serr->ee.ee_info = SCM_TSTAMP_SCHED;
		state = "TX SCH";
		break;
	case J1939_ERRQUEUE_TX_ABORT:
		serr->ee.ee_errno = session->err;
		serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
		serr->ee.ee_info = J1939_EE_INFO_TX_ABORT;
		state = "TX ABT";
		break;
	case J1939_ERRQUEUE_RX_RTS:
		serr->ee.ee_errno = ENOMSG;
		serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
		serr->ee.ee_info = J1939_EE_INFO_RX_RTS;
		state = "RX RTS";
		break;
	case J1939_ERRQUEUE_RX_DPO:
		serr->ee.ee_errno = ENOMSG;
		serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
		serr->ee.ee_info = J1939_EE_INFO_RX_DPO;
		state = "RX DPO";
		break;
	case J1939_ERRQUEUE_RX_ABORT:
		serr->ee.ee_errno = session->err;
		serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
		serr->ee.ee_info = J1939_EE_INFO_RX_ABORT;
		state = "RX ABT";
		break;
	}

	serr->opt_stats = true;
	if (tsflags & SOF_TIMESTAMPING_OPT_ID)
		serr->ee.ee_data = session->tskey;

	netdev_dbg(session->priv->ndev, "%s: 0x%p tskey: %i, state: %s\n",
		   __func__, session, session->tskey, state);
	err = sock_queue_err_skb(sk, skb);

	if (err)
		kfree_skb(skb);
};

void j1939_sk_errqueue(struct j1939_session *session,
		       enum j1939_sk_errqueue_type type)
{
	struct j1939_priv *priv = session->priv;
	struct j1939_sock *jsk;

	if (session->sk) {
		/* send TX notifications to the socket of origin  */
		__j1939_sk_errqueue(session, session->sk, type);
		return;
	}

	/* spread RX notifications to all sockets subscribed to this session */
	read_lock_bh(&priv->j1939_socks_lock);
	list_for_each_entry(jsk, &priv->j1939_socks, list) {
		if (j1939_sk_recv_match_one(jsk, &session->skcb))
			__j1939_sk_errqueue(session, &jsk->sk, type);
	}
	read_unlock_bh(&priv->j1939_socks_lock);
};

void j1939_sk_send_loop_abort(struct sock *sk, int err)
{}

static int j1939_sk_send_loop(struct j1939_priv *priv,  struct sock *sk,
			      struct msghdr *msg, size_t size)

{}

static int j1939_sk_sendmsg(struct socket *sock, struct msghdr *msg,
			    size_t size)
{}

void j1939_sk_netdev_event_netdown(struct j1939_priv *priv)
{}

static int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd,
				unsigned long arg)
{}

static const struct proto_ops j1939_ops =;

static struct proto j1939_proto __read_mostly =;

const struct can_proto j1939_can_proto =;