Module Name: src
Committed By: bouyer
Date: Mon Jan 16 18:03:38 UTC 2017
Modified Files:
src/sys/netcan [bouyer-socketcan]: can.c can.h can_pcb.h can_proto.c
can_var.h if_canloop.c
Log Message:
Use PACKET_TAG_SO to store the sender's struct socket pointer, and use
it to implement socket options CAN_RAW_LOOPBACK and CAN_RAW_RECV_OWN_MSGS.
To generate a diff of this commit:
cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/sys/netcan/can.c \
src/sys/netcan/can_pcb.h src/sys/netcan/can_proto.c \
src/sys/netcan/can_var.h src/sys/netcan/if_canloop.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/netcan/can.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/netcan/can.c
diff -u src/sys/netcan/can.c:1.1.2.1 src/sys/netcan/can.c:1.1.2.2
--- src/sys/netcan/can.c:1.1.2.1 Sun Jan 15 20:27:33 2017
+++ src/sys/netcan/can.c Mon Jan 16 18:03:38 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $ */
+/* $NetBSD: can.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,12 +30,13 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
+#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/errno.h>
#include <sys/socket.h>
@@ -119,25 +120,35 @@ can_output(struct mbuf *m, struct canpcb
{
struct ifnet *ifp;
int error = 0;
+ struct m_tag *sotag;
- if (canp == 0) {
+ if (canp == NULL) {
printf("can_output: no pcb\n");
error = EINVAL;
- goto done;
+ return error;
}
ifp = canp->canp_ifp;
if (ifp == 0) {
error = EDESTADDRREQ;
- goto done;
+ goto bad;
+ }
+ sotag = m_tag_get(PACKET_TAG_SO, sizeof(struct socket *), PR_NOWAIT);
+ if (sotag == NULL) {
+ ifp->if_oerrors++;
+ error = ENOMEM;
+ goto bad;
}
+ *(struct socket **)(sotag + 1) = canp->canp_socket;
+ m_tag_prepend(m, sotag);
+
if (m->m_len <= ifp->if_mtu) {
can_output_cnt++;
error = (*ifp->if_output)(ifp, m, NULL, 0);
- goto done;
- } else error = EMSGSIZE;
-
+ return error;
+ } else
+ error = EMSGSIZE;
+bad:
m_freem(m);
-done:
return (error);
}
@@ -180,6 +191,9 @@ canintr(void)
struct sockaddr_can from;
struct canpcb *canp;
+ struct m_tag *sotag;
+ struct socket *so;
+ struct canpcb *sender_canp;
mutex_enter(softnet_lock);
for (;;) {
@@ -187,9 +201,22 @@ canintr(void)
IF_DEQUEUE(&canintrq, m);
IFQ_UNLOCK(&canintrq);
- if (m == 0) /* no more queued packets */
+ if (m == NULL) /* no more queued packets */
break;
+ sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
+ if (sotag) {
+ so = *(struct socket **)(sotag + 1);
+ sender_canp = sotocanpcb(so);
+ m_tag_delete(m, sotag);
+ /* if the sender doesn't want loopback, don't do it */
+ if (sender_canp->canp_flags & CANP_NO_LOOPBACK) {
+ m_freem(m);
+ continue;
+ }
+ } else {
+ sender_canp = NULL;
+ }
memset(&from, 0, sizeof(struct sockaddr_can));
rcv_ifindex = m->m_pkthdr.rcvif_index;
#if 0
@@ -201,10 +228,17 @@ canintr(void)
TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
struct mbuf *mc;
+
+ /* don't loop back to sockets on other interfaces */
if (canp->canp_ifp != NULL &&
canp->canp_ifp->if_index != rcv_ifindex) {
continue;
}
+ /* don't loop back to myself if I don't want it */
+ if (canp == sender_canp &&
+ (canp->canp_flags & CANP_RECEIVE_OWN) == 0)
+ continue;
+
if (TAILQ_NEXT(canp, canp_queue) != NULL) {
/*
* we can't be sure we won't need
@@ -653,6 +687,97 @@ can_ctlinput(int cmd, struct sockaddr *s
}
#endif
+static int
+can_raw_getop(struct canpcb *canp, struct sockopt *sopt)
+{
+ int optval = 0;
+ int error;
+
+ switch (sopt->sopt_name) {
+ case CAN_RAW_LOOPBACK:
+ optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1;
+ error = sockopt_set(sopt, &optval, sizeof(optval));
+ break;
+ case CAN_RAW_RECV_OWN_MSGS:
+ optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
+ error = sockopt_set(sopt, &optval, sizeof(optval));
+ break;
+ default:
+ error = ENOPROTOOPT;
+ break;
+ }
+ return error;
+}
+
+static int
+can_raw_setop(struct canpcb *canp, struct sockopt *sopt)
+{
+ int optval = 0;
+ int error;
+
+ switch (sopt->sopt_name) {
+ case CAN_RAW_LOOPBACK:
+ error = sockopt_getint(sopt, &optval);
+ if (error == 0) {
+ if (optval) {
+ canp->canp_flags &= ~CANP_NO_LOOPBACK;
+ } else {
+ canp->canp_flags |= CANP_NO_LOOPBACK;
+ }
+ }
+ break;
+ case CAN_RAW_RECV_OWN_MSGS:
+ error = sockopt_getint(sopt, &optval);
+ if (error == 0) {
+ if (optval) {
+ canp->canp_flags |= CANP_RECEIVE_OWN;
+ } else {
+ canp->canp_flags &= ~CANP_RECEIVE_OWN;
+ }
+ }
+ break;
+ default:
+ error = ENOPROTOOPT;
+ break;
+ }
+ return error;
+}
+
+/*
+ * Called by getsockopt and setsockopt.
+ *
+ */
+int
+can_ctloutput(int op, struct socket *so, struct sockopt *sopt)
+{
+ struct canpcb *canp;
+ int error;
+ int s;
+
+ if (so->so_proto->pr_domain->dom_family != PF_CAN)
+ return EAFNOSUPPORT;
+
+ if (sopt->sopt_level != SOL_CAN_RAW)
+ return EINVAL;
+
+ s = splsoftnet();
+ canp = sotocanpcb(so);
+ if (canp == NULL) {
+ splx(s);
+ return ECONNRESET;
+ }
+
+ if (op == PRCO_SETOPT) {
+ error = can_raw_setop(canp, sopt);
+ } else if (op == PRCO_GETOPT) {
+ error = can_raw_getop(canp, sopt);
+ } else {
+ error = EINVAL;
+ }
+ splx(s);
+ return error;
+}
+
PR_WRAP_USRREQS(can)
#define can_attach can_attach_wrapper
#define can_detach can_detach_wrapper
Index: src/sys/netcan/can_pcb.h
diff -u src/sys/netcan/can_pcb.h:1.1.2.1 src/sys/netcan/can_pcb.h:1.1.2.2
--- src/sys/netcan/can_pcb.h:1.1.2.1 Sun Jan 15 20:27:33 2017
+++ src/sys/netcan/can_pcb.h Mon Jan 16 18:03:38 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can_pcb.h,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $ */
+/* $NetBSD: can_pcb.h,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -49,8 +49,9 @@ struct canpcb {
LIST_ENTRY(canpcb) canp_lhash;
TAILQ_ENTRY(canpcb) canp_queue;
int canp_state;
+ int canp_flags;
struct socket *canp_socket; /* back pointer to socket */
- struct ifnet *canp_ifp;
+ struct ifnet *canp_ifp; /* interface this socket is bound to */
struct canpcbtable *canp_table;
};
@@ -68,12 +69,15 @@ struct canpcbtable {
u_long canpt_connecthash;
};
-/* states in inp_state: */
+/* states in canp_state: */
#define CANP_ATTACHED 0
#define CANP_BOUND 1
#define CANP_CONNECTED 2
-/* flags in inp_flags: */
+/* flags in canp_flags: */
+#define CANP_NO_LOOPBACK 0x0001 /* local loopback disabled */
+#define CANP_RECEIVE_OWN 0x0002 /* receive own message */
+
#define sotocanpcb(so) ((struct canpcb *)(so)->so_pcb)
Index: src/sys/netcan/can_proto.c
diff -u src/sys/netcan/can_proto.c:1.1.2.1 src/sys/netcan/can_proto.c:1.1.2.2
--- src/sys/netcan/can_proto.c:1.1.2.1 Sun Jan 15 20:27:33 2017
+++ src/sys/netcan/can_proto.c Mon Jan 16 18:03:38 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can_proto.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $ */
+/* $NetBSD: can_proto.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can_proto.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can_proto.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $");
#include <sys/param.h>
#include <sys/socket.h>
@@ -57,6 +57,7 @@ const struct protosw cansw[] = {
.pr_init = can_init,
.pr_flags = PR_ATOMIC|PR_ADDR,
.pr_usrreqs = &can_usrreqs,
+ .pr_ctloutput = &can_ctloutput,
}
};
Index: src/sys/netcan/can_var.h
diff -u src/sys/netcan/can_var.h:1.1.2.1 src/sys/netcan/can_var.h:1.1.2.2
--- src/sys/netcan/can_var.h:1.1.2.1 Sun Jan 15 20:27:33 2017
+++ src/sys/netcan/can_var.h Mon Jan 16 18:03:38 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can_var.h,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $ */
+/* $NetBSD: can_var.h,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -47,7 +47,7 @@ extern const struct pr_usrreqs can_usrre
void can_input(struct ifnet *, struct mbuf *);
void *can_ctlinput(int, struct sockaddr *, void *);
-int can_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int can_ctloutput(int, struct socket *, struct sockopt *);
void can_init(void);
void canintr(void);
Index: src/sys/netcan/if_canloop.c
diff -u src/sys/netcan/if_canloop.c:1.1.2.1 src/sys/netcan/if_canloop.c:1.1.2.2
--- src/sys/netcan/if_canloop.c:1.1.2.1 Sun Jan 15 20:27:33 2017
+++ src/sys/netcan/if_canloop.c Mon Jan 16 18:03:38 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: if_canloop.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $ */
+/* $NetBSD: if_canloop.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $ */
/*-
* Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $");
#ifdef _KERNEL_OPT
#include "opt_can.h"
@@ -162,6 +162,7 @@ canloop_output(struct ifnet *ifp, struct
{
int error = 0;
size_t pktlen;
+ struct m_tag *sotag;
MCLAIM(m, ifp->if_mowner);
@@ -177,8 +178,11 @@ canloop_output(struct ifnet *ifp, struct
ifp->if_opackets++;
ifp->if_obytes += pktlen;
+ /* we have to preserve the socket tag */
+ sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
m_tag_delete_nonpersistent(m);
-
+ if (sotag)
+ m_tag_prepend(m, sotag);
#ifdef CAN
can_input(ifp, m);
#else
Index: src/sys/netcan/can.h
diff -u src/sys/netcan/can.h:1.1.2.2 src/sys/netcan/can.h:1.1.2.3
--- src/sys/netcan/can.h:1.1.2.2 Sun Jan 15 21:01:34 2017
+++ src/sys/netcan/can.h Mon Jan 16 18:03:38 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can.h,v 1.1.2.2 2017/01/15 21:01:34 bouyer Exp $ */
+/* $NetBSD: can.h,v 1.1.2.3 2017/01/16 18:03:38 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -77,8 +77,6 @@ struct can_frame {
#define CAN_RAW 1 /* RAW sockets */
#define CAN_NPROTO 2
-#define SOL_CAN_BASE 100
-
/*
* Socket address, CAN style
*/
@@ -94,11 +92,14 @@ struct sockaddr_can {
};
/*
- * Options for use with [gs]etsockopt
+ * Options for use with [gs]etsockopt for raw sockets
* First word of comment is data type; bool is stored in int.
*/
+#define SOL_CAN_RAW CAN_RAW
-#define CAN_RAW_FILTER 1 /* struct can_filter: set filter */
+#define CAN_RAW_FILTER 1 /* struct can_filter: set filter */
+#define CAN_RAW_LOOPBACK 4 /* bool: loopback to local sockets (default:on) */
+#define CAN_RAW_RECV_OWN_MSGS 5 /* bool: receive my own msgs (default:off) */
/*
* CAN ID based filter