1/* $NetBSD: npf_ext_log.c,v 1.1.4.2 2012/11/18 22:38:26 riz Exp $ */ 2 3/*- 4 * Copyright (c) 2010-2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 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 * NPF logging extension. 34 */ 35 36#include <sys/cdefs.h> 37__KERNEL_RCSID(0, "$NetBSD: npf_ext_log.c,v 1.1.4.2 2012/11/18 22:38:26 riz Exp $"); 38 39#include <sys/types.h> 40#include <sys/module.h> 41 42#include <sys/conf.h> 43#include <sys/kmem.h> 44#include <sys/mbuf.h> 45#include <sys/mutex.h> 46#include <sys/queue.h> 47 48#include <net/if.h> 49#include <net/if_types.h> 50#include <net/bpf.h> 51 52#include "npf_impl.h" 53 54NPF_EXT_MODULE(npf_ext_log, ""); 55 56#define NPFEXT_LOG_VER 1 57 58static void * npf_ext_log_id; 59 60typedef struct { 61 unsigned int if_idx; 62} npf_ext_log_t; 63 64typedef struct npflog_softc { 65 LIST_ENTRY(npflog_softc) sc_entry; 66 kmutex_t sc_lock; 67 ifnet_t sc_if; 68 int sc_unit; 69} npflog_softc_t; 70 71static int npflog_clone_create(struct if_clone *, int); 72static int npflog_clone_destroy(ifnet_t *); 73 74static LIST_HEAD(, npflog_softc) npflog_if_list __cacheline_aligned; 75static struct if_clone npflog_cloner = 76 IF_CLONE_INITIALIZER("npflog", npflog_clone_create, npflog_clone_destroy); 77 78void 79npflogattach(int nunits) 80{ 81 82 LIST_INIT(&npflog_if_list); 83 if_clone_attach(&npflog_cloner); 84} 85 86void 87npflogdetach(void) 88{ 89 npflog_softc_t *sc; 90 91 while ((sc = LIST_FIRST(&npflog_if_list)) != NULL) { 92 npflog_clone_destroy(&sc->sc_if); 93 } 94 if_clone_detach(&npflog_cloner); 95} 96 97static int 98npflog_ioctl(ifnet_t *ifp, u_long cmd, void *data) 99{ 100 npflog_softc_t *sc = ifp->if_softc; 101 int error = 0; 102 103 mutex_enter(&sc->sc_lock); 104 switch (cmd) { 105 case SIOCINITIFADDR: 106 ifp->if_flags |= (IFF_UP | IFF_RUNNING); 107 break; 108 default: 109 error = ifioctl_common(ifp, cmd, data); 110 break; 111 } 112 mutex_exit(&sc->sc_lock); 113 return error; 114} 115 116static int 117npflog_clone_create(struct if_clone *ifc, int unit) 118{ 119 npflog_softc_t *sc; 120 ifnet_t *ifp; 121 122 sc = kmem_zalloc(sizeof(npflog_softc_t), KM_SLEEP); 123 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTNET); 124 125 ifp = &sc->sc_if; 126 ifp->if_softc = sc; 127 128 if_initname(ifp, "npflog", unit); 129 ifp->if_type = IFT_OTHER; 130 ifp->if_dlt = DLT_NULL; 131 ifp->if_ioctl = npflog_ioctl; 132 133 KERNEL_LOCK(1, NULL); 134 if_attach(ifp); 135 if_alloc_sadl(ifp); 136 bpf_attach(ifp, DLT_NULL, 0); 137 LIST_INSERT_HEAD(&npflog_if_list, sc, sc_entry); 138 KERNEL_UNLOCK_ONE(NULL); 139 140 return 0; 141} 142 143static int 144npflog_clone_destroy(ifnet_t *ifp) 145{ 146 npflog_softc_t *sc = ifp->if_softc; 147 148 KERNEL_LOCK(1, NULL); 149 LIST_REMOVE(sc, sc_entry); 150 bpf_detach(ifp); 151 if_detach(ifp); 152 KERNEL_UNLOCK_ONE(NULL); 153 154 mutex_destroy(&sc->sc_lock); 155 kmem_free(sc, sizeof(npflog_softc_t)); 156 return 0; 157} 158 159static int 160npf_log_ctor(npf_rproc_t *rp, prop_dictionary_t params) 161{ 162 npf_ext_log_t *meta; 163 164 meta = kmem_zalloc(sizeof(npf_ext_log_t), KM_SLEEP); 165 prop_dictionary_get_uint32(params, "log-interface", &meta->if_idx); 166 npf_rproc_assign(rp, meta); 167 return 0; 168} 169 170static void 171npf_log_dtor(npf_rproc_t *rp, void *meta) 172{ 173 kmem_free(meta, sizeof(npf_ext_log_t)); 174} 175 176static void 177npf_log(npf_cache_t *npc, nbuf_t *nbuf, void *meta, int *decision) 178{ 179 struct mbuf *m = nbuf_head_mbuf(nbuf); 180 const npf_ext_log_t *log = meta; 181 ifnet_t *ifp; 182 int family; 183 184 /* Set the address family. */ 185 if (npf_iscached(npc, NPC_IP4)) { 186 family = AF_INET; 187 } else if (npf_iscached(npc, NPC_IP6)) { 188 family = AF_INET6; 189 } else { 190 family = AF_UNSPEC; 191 } 192 193 KERNEL_LOCK(1, NULL); 194 195 /* Find a pseudo-interface to log. */ 196 ifp = if_byindex(log->if_idx); 197 if (ifp == NULL) { 198 /* No interface. */ 199 KERNEL_UNLOCK_ONE(NULL); 200 return; 201 } 202 203 /* Pass through BPF. */ 204 ifp->if_opackets++; 205 ifp->if_obytes += m->m_pkthdr.len; 206 bpf_mtap_af(ifp, family, m); 207 KERNEL_UNLOCK_ONE(NULL); 208} 209 210/* 211 * Module interface. 212 */ 213static int 214npf_ext_log_modcmd(modcmd_t cmd, void *arg) 215{ 216 static const npf_ext_ops_t npf_log_ops = { 217 .version = NPFEXT_LOG_VER, 218 .ctx = NULL, 219 .ctor = npf_log_ctor, 220 .dtor = npf_log_dtor, 221 .proc = npf_log 222 }; 223 int error; 224 225 switch (cmd) { 226 case MODULE_CMD_INIT: 227 /* 228 * Initialise the NPF logging extension. 229 */ 230 npflogattach(1); 231 npf_ext_log_id = npf_ext_register("log", &npf_log_ops); 232 if (!npf_ext_log_id) { 233 npflogdetach(); 234 return EEXIST; 235 } 236 break; 237 238 case MODULE_CMD_FINI: 239 error = npf_ext_unregister(npf_ext_log_id); 240 if (error) { 241 return error; 242 } 243 npflogdetach(); 244 break; 245 246 case MODULE_CMD_AUTOUNLOAD: 247 /* Allow auto-unload only if NPF permits it. */ 248 return npf_autounload_p() ? 0 : EBUSY; 249 250 default: 251 return ENOTTY; 252 } 253 return 0; 254} 255