1 /* $NetBSD: if_canloop.c,v 1.8 2019/04/27 08:49:19 pgoyette 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.8 2019/04/27 08:49:19 pgoyette 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 #include <net/netisr.h> 61 62 #ifdef CAN 63 #include <netcan/can.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 ifp->if_opackets++; 174 ifp->if_obytes += pktlen; 175 176 #ifdef CAN 177 can_mbuf_tag_clean(m); 178 can_input(ifp, m); 179 #else 180 printf("%s: can't handle CAN packet\n", ifp->if_xname); 181 m_freem(m); 182 #endif 183 } 184 185 KERNEL_UNLOCK_ONE(NULL); 186 } 187 188 /* 189 * Process an ioctl request. 190 */ 191 /* ARGSUSED */ 192 static int 193 canloop_ioctl(struct ifnet *ifp, u_long cmd, void *data) 194 { 195 struct ifreq *ifr = data; 196 int error = 0; 197 198 switch (cmd) { 199 200 case SIOCINITIFADDR: 201 error = EAFNOSUPPORT; 202 break; 203 204 case SIOCSIFMTU: 205 if ((unsigned)ifr->ifr_mtu != sizeof(struct can_frame)) 206 error = EINVAL; 207 break; 208 209 case SIOCADDMULTI: 210 case SIOCDELMULTI: 211 error = EAFNOSUPPORT; 212 break; 213 214 default: 215 error = ifioctl_common(ifp, cmd, data); 216 } 217 return (error); 218 } 219 220 /* 221 * Module infrastructure 222 */ 223 #include "../net/if_module.h" 224 225 IF_MODULE(MODULE_CLASS_DRIVER, canloop, NULL) 226