diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 820f553..b6d28bd 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -23,7 +23,8 @@ This file contains 4.1.3 RAW socket option CAN_RAW_LOOPBACK 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS 4.1.5 RAW socket option CAN_RAW_FD_FRAMES - 4.1.6 RAW socket returned message flags + 4.1.6 RAW socket option CAN_RAW_RECV_HOST_MSGS + 4.1.7 RAW socket returned message flags 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) 4.3 connected transport protocols (SOCK_SEQPACKET) 4.4 unconnected transport protocols (SOCK_DGRAM) @@ -581,7 +582,23 @@ solution for a couple of reasons: CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU. The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. - 4.1.6 RAW socket returned message flags + 4.1.6 RAW socket option CAN_RAW_RECV_HOST_MSGS + + When the local loopback is enabled, all the sent CAN frames are + looped back to the open CAN sockets that registered for the CAN + frames' CAN-ID on this given interface to meet the multi user + needs. The reception of the CAN frames originated from the local host + is therefore a wanted behaviour and enabled by default. + + When the reception of locally generated CAN frames is not wanted, this + default behaviour may be changed on demand: + + int recv_host_msgs = 0; /* 0 = disabled, 1 = enabled (default) */ + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_HOST_MSGS, + &recv_host_msgs, sizeof(recv_host_msgs)); + + 4.1.7 RAW socket returned message flags When using recvmsg() call, the msg->msg_flags may contain following flags: diff --git a/include/linux/can/raw.h b/include/linux/can/raw.h index a814062..0d53fb6 100644 --- a/include/linux/can/raw.h +++ b/include/linux/can/raw.h @@ -25,6 +25,7 @@ enum { CAN_RAW_LOOPBACK, /* local loopback (default:on) */ CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ + CAN_RAW_RECV_HOST_MSGS, /* recv local host msgs (default:on) */ }; #endif diff --git a/net/can/raw.c b/net/can/raw.c index 3e9c893..0cfbc16 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -83,6 +83,7 @@ struct raw_sock { int loopback; int recv_own_msgs; int fd_frames; + int recv_host_msgs; int count; /* number of active filters */ struct can_filter dfilter; /* default/single filter */ struct can_filter *filter; /* pointer to filter(s) */ @@ -120,6 +121,10 @@ static void raw_rcv(struct sk_buff *oskb, void *data) if (!ro->recv_own_msgs && oskb->sk == sk) return; + /* check if we need to skip locally generated messages */ + if (!ro->recv_host_msgs && oskb->sk) + return; + /* do not pass frames with DLC > 8 to a legacy socket */ if (!ro->fd_frames) { struct canfd_frame *cfd = (struct canfd_frame *)oskb->data; @@ -301,6 +306,7 @@ static int raw_init(struct sock *sk) ro->loopback = 1; ro->recv_own_msgs = 0; ro->fd_frames = 0; + ro->recv_host_msgs = 1; /* set notifier */ ro->notifier.notifier_call = raw_notifier; @@ -588,6 +594,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, break; + case CAN_RAW_RECV_HOST_MSGS: + if (optlen != sizeof(ro->recv_host_msgs)) + return -EINVAL; + + if (copy_from_user(&ro->recv_host_msgs, optval, optlen)) + return -EFAULT; + + break; + default: return -ENOPROTOOPT; } @@ -652,6 +667,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, val = &ro->fd_frames; break; + case CAN_RAW_RECV_HOST_MSGS: + if (len > sizeof(int)) + len = sizeof(int); + val = &ro->recv_host_msgs; + break; + default: return -ENOPROTOOPT; }