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