1/*	$NetBSD: if_canloop.c,v 1.10 2022/09/03 02:48:00 thorpej Exp $	*/
2
3/*-
4 * Copyright (c) 2017 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Manuel Bouyer.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32
33/*
34 * Loopback interface driver for the CAN protocol
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.10 2022/09/03 02:48:00 thorpej Exp $");
39
40#ifdef _KERNEL_OPT
41#include "opt_can.h"
42#include "opt_net_mpsafe.h"
43#endif
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/mbuf.h>
49#include <sys/socket.h>
50#include <sys/errno.h>
51#include <sys/ioctl.h>
52#include <sys/time.h>
53#include <sys/device.h>
54#include <sys/module.h>
55
56#include <sys/cpu.h>
57
58#include <net/if.h>
59#include <net/if_types.h>
60
61#ifdef	CAN
62#include <netcan/can.h>
63#include <netcan/can_var.h>
64#endif
65
66void canloopattach(int);
67void canloopinit(void);
68static int	canloop_clone_create(struct if_clone *, int);
69static int	canloop_clone_destroy(struct ifnet *);
70static int	canloop_ioctl(struct ifnet *, u_long, void *);
71static void	canloop_ifstart(struct ifnet *);
72
73static int	canloop_count;
74
75static struct if_clone canloop_cloner =
76    IF_CLONE_INITIALIZER("canlo", canloop_clone_create, canloop_clone_destroy);
77
78void
79canloopattach(int n)
80{
81
82	/*
83	 * Nothing to do here, initialization is handled by the
84	 * module initialization code in canloopinit() below).
85	 */
86}
87
88void
89canloopinit(void)
90{
91
92	canloop_count = 0;
93	if_clone_attach(&canloop_cloner);
94}
95
96static int
97canloopdetach(void)
98{
99	if (canloop_count > 0)
100		return EBUSY;
101	if_clone_detach(&canloop_cloner);
102	return 0;
103}
104
105static int
106canloop_clone_create(struct if_clone *ifc, int unit)
107{
108	struct ifnet *ifp;
109
110	ifp = if_alloc(IFT_OTHER);
111
112	if_initname(ifp, ifc->ifc_name, unit);
113
114	ifp->if_flags = IFF_LOOPBACK;
115#ifdef NET_MPSAFE
116	ifp->if_extflags = IFEF_MPSAFE;
117#endif
118	ifp->if_ioctl = canloop_ioctl;
119	ifp->if_start = canloop_ifstart;
120	can_ifattach(ifp);
121#ifdef MBUFTRACE
122	ifp->if_mowner = malloc(sizeof(struct mowner), M_DEVBUF,
123	    M_WAITOK | M_ZERO);
124	strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
125	    sizeof(ifp->if_mowner->mo_name));
126	MOWNER_ATTACH(ifp->if_mowner);
127#endif
128	canloop_count++;
129	ifp->if_flags |= IFF_RUNNING;
130
131	return (0);
132}
133
134static int
135canloop_clone_destroy(struct ifnet *ifp)
136{
137
138	ifp->if_flags &= ~IFF_RUNNING;
139
140#ifdef MBUFTRACE
141	MOWNER_DETACH(ifp->if_mowner);
142	free(ifp->if_mowner, M_DEVBUF);
143#endif
144
145	can_ifdetach(ifp);
146
147	if_free(ifp);
148	canloop_count--;
149	KASSERT(canloop_count >= 0);
150	return (0);
151}
152
153static void
154canloop_ifstart(struct ifnet *ifp)
155{
156	size_t pktlen;
157	struct mbuf *m;
158
159	KERNEL_LOCK(1, NULL);
160	while (true) {
161		IF_DEQUEUE(&ifp->if_snd, m);
162		if (m == NULL)
163			break;
164		MCLAIM(m, ifp->if_mowner);
165
166		if ((m->m_flags & M_PKTHDR) == 0)
167			panic("canloop_output: no header mbuf");
168		m_set_rcvif(m, ifp);
169		if (ifp->if_flags & IFF_LOOPBACK)
170			can_bpf_mtap(ifp, m, 0);
171
172		pktlen = m->m_pkthdr.len;
173		if_statadd2(ifp, if_opackets, 1, if_obytes, pktlen);
174
175#ifdef CAN
176		can_mbuf_tag_clean(m);
177		can_input(ifp, m);
178#else
179		printf("%s: can't handle CAN packet\n", ifp->if_xname);
180		m_freem(m);
181#endif
182	}
183
184	KERNEL_UNLOCK_ONE(NULL);
185}
186
187/*
188 * Process an ioctl request.
189 */
190/* ARGSUSED */
191static int
192canloop_ioctl(struct ifnet *ifp, u_long cmd, void *data)
193{
194	struct ifreq *ifr = data;
195	int error = 0;
196
197	switch (cmd) {
198
199	case SIOCINITIFADDR:
200		error = EAFNOSUPPORT;
201		break;
202
203	case SIOCSIFMTU:
204		if ((unsigned)ifr->ifr_mtu != sizeof(struct can_frame))
205			error = EINVAL;
206		break;
207
208	case SIOCADDMULTI:
209	case SIOCDELMULTI:
210		error = EAFNOSUPPORT;
211		break;
212
213	default:
214		error = ifioctl_common(ifp, cmd, data);
215	}
216	return (error);
217}
218
219/*
220 * Module infrastructure
221 */
222#include "../net/if_module.h"
223
224IF_MODULE(MODULE_CLASS_DRIVER, canloop, NULL)
225