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 66 void canloopattach(int); 67 void canloopinit(void); 68 static int canloop_clone_create(struct if_clone *, int); 69 static int canloop_clone_destroy(struct ifnet *); 70 static int canloop_ioctl(struct ifnet *, u_long, void *); 71 static void canloop_ifstart(struct ifnet *); 72 73 static int canloop_count; 74 75 static struct if_clone canloop_cloner = 76 IF_CLONE_INITIALIZER("canlo", canloop_clone_create, canloop_clone_destroy); 77 78 void 79 canloopattach(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 88 void 89 canloopinit(void) 90 { 91 92 canloop_count = 0; 93 if_clone_attach(&canloop_cloner); 94 } 95 96 static int 97 canloopdetach(void) 98 { 99 if (canloop_count > 0) 100 return EBUSY; 101 if_clone_detach(&canloop_cloner); 102 return 0; 103 } 104 105 static int 106 canloop_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 134 static int 135 canloop_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 153 static void 154 canloop_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 */ 191 static int 192 canloop_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 224 IF_MODULE(MODULE_CLASS_DRIVER, canloop, NULL) 225