#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 …
static inline priority_t j1939_prio(u32 sk_priority)
{ … }
static inline u32 j1939_to_sk_priority(priority_t prio)
{ … }
static inline bool j1939_pgn_is_valid(pgn_t pgn)
{ … }
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)
{ … }
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) {
__j1939_sk_errqueue(session, session->sk, type);
return;
}
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 = …;