1 /* $NetBSD: npf_if.c,v 1.8 2017/02/18 23:27:32 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by 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 network interface handling module. 34 * 35 * NPF uses its own interface IDs (npf-if-id). When NPF configuration is 36 * (re)loaded, each required interface name is registered and a matching 37 * network interface gets an ID assigned. If an interface is not present, 38 * it gets an ID on attach. 39 * 40 * IDs start from 1. Zero is reserved to indicate "no interface" case or 41 * an interface of no interest (i.e. not registered). 42 * 43 * The IDs are mapped synchronously based on interface events which are 44 * monitored using pfil(9) hooks. 45 */ 46 47 #ifdef _KERNEL 48 #include <sys/cdefs.h> 49 __KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1.8 2017/02/18 23:27:32 christos Exp $"); 50 51 #include <sys/param.h> 52 #include <sys/types.h> 53 #include <sys/kmem.h> 54 #include <net/if.h> 55 #endif 56 57 #include "npf_impl.h" 58 59 typedef struct npf_ifmap { 60 char n_ifname[IFNAMSIZ]; 61 } npf_ifmap_t; 62 63 void 64 npf_ifmap_init(npf_t *npf, const npf_ifops_t *ifops) 65 { 66 const size_t nbytes = sizeof(npf_ifmap_t) * NPF_MAX_IFMAP; 67 68 KASSERT(ifops != NULL); 69 ifops->flush((void *)(uintptr_t)0); 70 71 npf->ifmap = kmem_zalloc(nbytes, KM_SLEEP); 72 npf->ifmap_cnt = 0; 73 npf->ifops = ifops; 74 } 75 76 void 77 npf_ifmap_fini(npf_t *npf) 78 { 79 const size_t nbytes = sizeof(npf_ifmap_t) * NPF_MAX_IFMAP; 80 kmem_free(npf->ifmap, nbytes); 81 } 82 83 static u_int 84 npf_ifmap_new(npf_t *npf) 85 { 86 KASSERT(npf_config_locked_p(npf)); 87 88 for (u_int i = 0; i < npf->ifmap_cnt; i++) 89 if (npf->ifmap[i].n_ifname[0] == '\0') 90 return i + 1; 91 92 if (npf->ifmap_cnt == NPF_MAX_IFMAP) { 93 printf("npf_ifmap_new: out of slots; bump NPF_MAX_IFMAP\n"); 94 return 0; 95 } 96 return ++npf->ifmap_cnt; 97 } 98 99 static u_int 100 npf_ifmap_lookup(npf_t *npf, const char *ifname) 101 { 102 KASSERT(npf_config_locked_p(npf)); 103 104 for (u_int i = 0; i < npf->ifmap_cnt; i++) { 105 npf_ifmap_t *nim = &npf->ifmap[i]; 106 107 if (nim->n_ifname[0] && strcmp(nim->n_ifname, ifname) == 0) 108 return i + 1; 109 } 110 return 0; 111 } 112 113 u_int 114 npf_ifmap_register(npf_t *npf, const char *ifname) 115 { 116 npf_ifmap_t *nim; 117 ifnet_t *ifp; 118 u_int i; 119 120 npf_config_enter(npf); 121 if ((i = npf_ifmap_lookup(npf, ifname)) != 0) { 122 goto out; 123 } 124 if ((i = npf_ifmap_new(npf)) == 0) { 125 goto out; 126 } 127 nim = &npf->ifmap[i - 1]; 128 strlcpy(nim->n_ifname, ifname, IFNAMSIZ); 129 130 if ((ifp = npf->ifops->lookup(ifname)) != NULL) { 131 npf->ifops->setmeta(ifp, (void *)(uintptr_t)i); 132 } 133 out: 134 npf_config_exit(npf); 135 return i; 136 } 137 138 void 139 npf_ifmap_flush(npf_t *npf) 140 { 141 KASSERT(npf_config_locked_p(npf)); 142 143 for (u_int i = 0; i < npf->ifmap_cnt; i++) { 144 npf->ifmap[i].n_ifname[0] = '\0'; 145 } 146 npf->ifmap_cnt = 0; 147 npf->ifops->flush((void *)(uintptr_t)0); 148 } 149 150 u_int 151 npf_ifmap_getid(npf_t *npf, const ifnet_t *ifp) 152 { 153 const u_int i = (uintptr_t)npf->ifops->getmeta(ifp); 154 KASSERT(i <= npf->ifmap_cnt); 155 return i; 156 } 157 158 /* 159 * This function is toxic; it can return garbage since we don't 160 * lock, but it is only used temporarily and only for logging. 161 */ 162 void 163 npf_ifmap_copyname(npf_t *npf, u_int id, char *buf, size_t len) 164 { 165 if (id > 0 && id < npf->ifmap_cnt) 166 strlcpy(buf, npf->ifmap[id - 1].n_ifname, 167 MIN(len, sizeof(npf->ifmap[id - 1].n_ifname))); 168 else 169 strlcpy(buf, "???", len); 170 } 171 172 const char * 173 npf_ifmap_getname(npf_t *npf, const u_int id) 174 { 175 const char *ifname; 176 177 KASSERT(npf_config_locked_p(npf)); 178 KASSERT(id > 0 && id <= npf->ifmap_cnt); 179 180 ifname = npf->ifmap[id - 1].n_ifname; 181 KASSERT(ifname[0] != '\0'); 182 return ifname; 183 } 184 185 __dso_public void 186 npf_ifmap_attach(npf_t *npf, ifnet_t *ifp) 187 { 188 const npf_ifops_t *ifops = npf->ifops; 189 u_int i; 190 191 npf_config_enter(npf); 192 i = npf_ifmap_lookup(npf, ifops->getname(ifp)); 193 ifops->setmeta(ifp, (void *)(uintptr_t)i); 194 npf_config_exit(npf); 195 } 196 197 __dso_public void 198 npf_ifmap_detach(npf_t *npf, ifnet_t *ifp) 199 { 200 /* Diagnostic. */ 201 npf_config_enter(npf); 202 npf->ifops->setmeta(ifp, (void *)(uintptr_t)0); 203 npf_config_exit(npf); 204 } 205