221 lines
4.9 KiB
C
221 lines
4.9 KiB
C
/* $NetBSD: if_canloop.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Manuel Bouyer.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
/*
|
|
* Loopback interface driver for the CAN protocol
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
|
|
|
#ifdef _KERNEL_OPT
|
|
#include "opt_can.h"
|
|
#include "opt_net_mpsafe.h"
|
|
#endif
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/mbuf.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <sys/device.h>
|
|
#include <sys/module.h>
|
|
|
|
#include <sys/cpu.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_types.h>
|
|
#include <net/netisr.h>
|
|
|
|
#ifdef CAN
|
|
#include <netcan/can.h>
|
|
#endif
|
|
|
|
void canloopattach(int);
|
|
void canloopinit(void);
|
|
static int canloop_clone_create(struct if_clone *, int);
|
|
static int canloop_clone_destroy(struct ifnet *);
|
|
static int canloop_ioctl(struct ifnet *, u_long, void *);
|
|
static void canloop_ifstart(struct ifnet *);
|
|
|
|
static int canloop_count;
|
|
|
|
static struct if_clone canloop_cloner =
|
|
IF_CLONE_INITIALIZER("canlo", canloop_clone_create, canloop_clone_destroy);
|
|
|
|
void
|
|
canloopattach(int n)
|
|
{
|
|
|
|
/*
|
|
* Nothing to do here, initialization is handled by the
|
|
* module initialization code in canloopinit() below).
|
|
*/
|
|
}
|
|
|
|
void
|
|
canloopinit(void)
|
|
{
|
|
|
|
canloop_count = 0;
|
|
if_clone_attach(&canloop_cloner);
|
|
}
|
|
|
|
static int
|
|
canloopdetach(void)
|
|
{
|
|
if (canloop_count > 0)
|
|
return EBUSY;
|
|
if_clone_detach(&canloop_cloner);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
canloop_clone_create(struct if_clone *ifc, int unit)
|
|
{
|
|
struct ifnet *ifp;
|
|
|
|
ifp = if_alloc(IFT_OTHER);
|
|
|
|
if_initname(ifp, ifc->ifc_name, unit);
|
|
|
|
ifp->if_flags = IFF_LOOPBACK | IFF_RUNNING;
|
|
ifp->if_extflags = IFEF_OUTPUT_MPSAFE;
|
|
ifp->if_ioctl = canloop_ioctl;
|
|
ifp->if_start = canloop_ifstart;
|
|
can_ifattach(ifp);
|
|
#ifdef MBUFTRACE
|
|
ifp->if_mowner = malloc(sizeof(struct mowner), M_DEVBUF,
|
|
M_WAITOK | M_ZERO);
|
|
strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
|
|
sizeof(ifp->if_mowner->mo_name));
|
|
MOWNER_ATTACH(ifp->if_mowner);
|
|
#endif
|
|
canloop_count++;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
canloop_clone_destroy(struct ifnet *ifp)
|
|
{
|
|
|
|
#ifdef MBUFTRACE
|
|
MOWNER_DETACH(ifp->if_mowner);
|
|
free(ifp->if_mowner, M_DEVBUF);
|
|
#endif
|
|
|
|
can_ifdetach(ifp);
|
|
|
|
if_free(ifp);
|
|
canloop_count--;
|
|
KASSERT(canloop_count >= 0);
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
canloop_ifstart(struct ifnet *ifp)
|
|
{
|
|
size_t pktlen;
|
|
struct mbuf *m;
|
|
|
|
KERNEL_LOCK(1, NULL);
|
|
while (true) {
|
|
IF_DEQUEUE(&ifp->if_snd, m);
|
|
if (m == NULL)
|
|
break;
|
|
MCLAIM(m, ifp->if_mowner);
|
|
|
|
if ((m->m_flags & M_PKTHDR) == 0)
|
|
panic("canloop_output: no header mbuf");
|
|
m_set_rcvif(m, ifp);
|
|
if (ifp->if_flags & IFF_LOOPBACK)
|
|
can_bpf_mtap(ifp, m, 0);
|
|
|
|
pktlen = m->m_pkthdr.len;
|
|
ifp->if_opackets++;
|
|
ifp->if_obytes += pktlen;
|
|
|
|
#ifdef CAN
|
|
can_mbuf_tag_clean(m);
|
|
can_input(ifp, m);
|
|
#else
|
|
printf("%s: can't handle CAN packet\n", ifp->if_xname);
|
|
m_freem(m);
|
|
#endif
|
|
}
|
|
|
|
KERNEL_UNLOCK_ONE(NULL);
|
|
}
|
|
|
|
/*
|
|
* Process an ioctl request.
|
|
*/
|
|
/* ARGSUSED */
|
|
static int
|
|
canloop_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
|
{
|
|
struct ifreq *ifr = data;
|
|
int error = 0;
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCINITIFADDR:
|
|
error = EAFNOSUPPORT;
|
|
break;
|
|
|
|
case SIOCSIFMTU:
|
|
if ((unsigned)ifr->ifr_mtu != sizeof(struct can_frame))
|
|
error = EINVAL;
|
|
break;
|
|
|
|
case SIOCADDMULTI:
|
|
case SIOCDELMULTI:
|
|
error = EAFNOSUPPORT;
|
|
break;
|
|
|
|
default:
|
|
error = ifioctl_common(ifp, cmd, data);
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Module infrastructure
|
|
*/
|
|
#include "../net/if_module.h"
|
|
|
|
IF_MODULE(MODULE_CLASS_DRIVER, canloop, "")
|