/* $NetBSD$ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Mindaugas Rasiukevicius. * * 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. */ /* * NPF route extension. */ #include __KERNEL_RCSID(0, "$NetBSD$"); #include #include #include #include #include #include #include #include #include #include #include "npf_impl.h" NPF_EXT_MODULE(npf_ext_route, ""); #define NPFEXT_ROUTE_VER 1 static void * npf_ext_route_id; typedef struct { unsigned int if_idx; } npf_ext_route_t; static int npf_route_ctor(npf_rproc_t *rp, prop_dictionary_t params) { npf_ext_route_t *meta; meta = kmem_zalloc(sizeof(npf_ext_route_t), KM_SLEEP); prop_dictionary_get_uint32(params, "route-interface", &meta->if_idx); npf_rproc_assign(rp, meta); return 0; } static void npf_route_dtor(npf_rproc_t *rp, void *meta) { kmem_free(meta, sizeof(npf_ext_route_t)); } static void npf_route(npf_cache_t *npc, nbuf_t *nbuf, void *meta, int *decision) { struct mbuf *m = nbuf_head_mbuf(nbuf); const npf_ext_route_t *route = meta; struct sockaddr_in dst; ifnet_t *ifp; memset(ro, 0, sizeof(struct route)); sockaddr_in_init(&dst, &route->dst, 0); KERNEL_LOCK(1, NULL); ifp = if_byindex(route->if_idx); if (ifp == NULL) { /* XXX: oops */ goto out; } if (m->m_pkthdr.len > ifp->if_mtu) { /* XXX: should do the fragmentation */ goto out; } error = (*ifp->if_output)(ifp, m, dst, NULL); if (error) { /* XXX: statistics */ goto out; } out: KERNEL_UNLOCK_ONE(NULL); } static int npf_ext_route_modcmd(modcmd_t cmd, void *arg) { static const npf_ext_ops_t npf_route_ops = { .version = NPFEXT_ROUTE_VER, .ctx = NULL, .ctor = npf_route_ctor, .dtor = npf_route_dtor, .proc = npf_route }; int error; switch (cmd) { case MODULE_CMD_INIT: npf_ext_route_id = npf_ext_register("route", &npf_route_ops); if (!npf_ext_route_id) { return EEXIST; } break; case MODULE_CMD_FINI: error = npf_ext_unregister(npf_ext_route_id); if (error) { return error; } break; case MODULE_CMD_AUTOUNLOAD: /* Allow auto-unload only if NPF permits it. */ return npf_autounload_p() ? 0 : EBUSY; default: return ENOTTY; } return 0; }