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

Reply via email to