1 1.1 rmind /*- 2 1.1 rmind * Copyright (c) 2014 The NetBSD Foundation, Inc. 3 1.1 rmind * All rights reserved. 4 1.1 rmind * 5 1.1 rmind * This code is derived from software contributed to The NetBSD Foundation 6 1.1 rmind * by Mindaugas Rasiukevicius. 7 1.1 rmind * 8 1.1 rmind * Redistribution and use in source and binary forms, with or without 9 1.1 rmind * modification, are permitted provided that the following conditions 10 1.1 rmind * are met: 11 1.1 rmind * 1. Redistributions of source code must retain the above copyright 12 1.1 rmind * notice, this list of conditions and the following disclaimer. 13 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 rmind * notice, this list of conditions and the following disclaimer in the 15 1.1 rmind * documentation and/or other materials provided with the distribution. 16 1.1 rmind * 17 1.1 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 1.1 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 1.1 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 1.1 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 1.1 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 1.1 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 1.1 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 1.1 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 1.1 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 1.1 rmind * POSSIBILITY OF SUCH DAMAGE. 28 1.1 rmind */ 29 1.1 rmind 30 1.1 rmind /* 31 1.1 rmind * NPF network interface handling module. 32 1.1 rmind */ 33 1.1 rmind 34 1.4 rmind #ifdef _KERNEL 35 1.1 rmind #include <sys/cdefs.h> 36 1.8 riastrad __KERNEL_RCSID(0, "$NetBSD: npf_ifaddr.c,v 1.8 2022/02/13 19:20:11 riastradh Exp $"); 37 1.1 rmind 38 1.1 rmind #include <sys/param.h> 39 1.1 rmind #include <sys/types.h> 40 1.1 rmind #include <sys/kmem.h> 41 1.1 rmind 42 1.1 rmind #include <net/if.h> 43 1.1 rmind #include <netinet/in.h> 44 1.1 rmind #include <netinet6/in6_var.h> 45 1.4 rmind #endif 46 1.1 rmind 47 1.1 rmind #include "npf_impl.h" 48 1.1 rmind 49 1.1 rmind static npf_table_t * 50 1.1 rmind lookup_ifnet_table(npf_t *npf, ifnet_t *ifp) 51 1.1 rmind { 52 1.1 rmind const npf_ifops_t *ifops = npf->ifops; 53 1.1 rmind char tname[NPF_TABLE_MAXNAMELEN]; 54 1.1 rmind const char *ifname; 55 1.6 rmind npf_config_t *nc; 56 1.1 rmind npf_table_t *t; 57 1.7 rmind unsigned tid; 58 1.1 rmind 59 1.1 rmind /* Get the interface name and prefix it. */ 60 1.7 rmind ifname = ifops->getname(npf, ifp); 61 1.1 rmind snprintf(tname, sizeof(tname), ".ifnet-%s", ifname); 62 1.1 rmind 63 1.1 rmind KERNEL_LOCK(1, NULL); 64 1.6 rmind nc = npf_config_enter(npf); 65 1.1 rmind 66 1.1 rmind /* 67 1.1 rmind * Check whether this interface is of any interest to us. 68 1.1 rmind */ 69 1.6 rmind t = npf_tableset_getbyname(nc->tableset, tname); 70 1.1 rmind if (!t) { 71 1.1 rmind goto out; 72 1.1 rmind } 73 1.1 rmind tid = npf_table_getid(t); 74 1.1 rmind 75 1.1 rmind /* Create a new NPF table for the interface. */ 76 1.5 rmind t = npf_table_create(tname, tid, NPF_TABLE_IFADDR, NULL, 0); 77 1.1 rmind if (!t) { 78 1.1 rmind goto out; 79 1.1 rmind } 80 1.1 rmind return t; 81 1.1 rmind out: 82 1.1 rmind npf_config_exit(npf); 83 1.1 rmind KERNEL_UNLOCK_ONE(NULL); 84 1.1 rmind return NULL; 85 1.1 rmind } 86 1.1 rmind 87 1.1 rmind static void 88 1.1 rmind replace_ifnet_table(npf_t *npf, npf_table_t *newt) 89 1.1 rmind { 90 1.8 riastrad npf_tableset_t *ts = atomic_load_relaxed(&npf->config)->tableset; 91 1.1 rmind npf_table_t *oldt; 92 1.1 rmind 93 1.8 riastrad KASSERT(npf_config_locked_p(npf)); 94 1.8 riastrad 95 1.1 rmind KERNEL_UNLOCK_ONE(NULL); 96 1.1 rmind 97 1.1 rmind /* 98 1.1 rmind * Finally, swap the tables and issue a sync barrier. 99 1.1 rmind */ 100 1.1 rmind oldt = npf_tableset_swap(ts, newt); 101 1.1 rmind npf_config_sync(npf); 102 1.1 rmind npf_config_exit(npf); 103 1.1 rmind 104 1.1 rmind /* At this point, it is safe to destroy the old table. */ 105 1.1 rmind npf_table_destroy(oldt); 106 1.1 rmind } 107 1.1 rmind 108 1.1 rmind void 109 1.1 rmind npf_ifaddr_sync(npf_t *npf, ifnet_t *ifp) 110 1.1 rmind { 111 1.1 rmind npf_table_t *t; 112 1.1 rmind struct ifaddr *ifa; 113 1.1 rmind 114 1.1 rmind /* 115 1.1 rmind * First, check whether this interface is of any interest to us. 116 1.1 rmind * 117 1.1 rmind * => Acquires npf-config-lock and kernel-lock on success. 118 1.1 rmind */ 119 1.1 rmind t = lookup_ifnet_table(npf, ifp); 120 1.1 rmind if (!t) 121 1.1 rmind return; 122 1.1 rmind 123 1.1 rmind /* 124 1.1 rmind * Populate the table with the interface addresses. 125 1.1 rmind * Note: currently, this list is protected by the kernel-lock. 126 1.1 rmind */ 127 1.1 rmind IFADDR_FOREACH(ifa, ifp) { 128 1.1 rmind struct sockaddr *sa = ifa->ifa_addr; 129 1.1 rmind const void *p = NULL; 130 1.1 rmind int alen = 0; 131 1.1 rmind 132 1.1 rmind if (sa->sa_family == AF_INET) { 133 1.1 rmind const struct sockaddr_in *sin4 = satosin(sa); 134 1.1 rmind alen = sizeof(struct in_addr); 135 1.1 rmind p = &sin4->sin_addr; 136 1.1 rmind } 137 1.1 rmind if (sa->sa_family == AF_INET6) { 138 1.1 rmind const struct sockaddr_in6 *sin6 = satosin6(sa); 139 1.1 rmind alen = sizeof(struct in6_addr); 140 1.1 rmind p = &sin6->sin6_addr; 141 1.1 rmind } 142 1.1 rmind if (alen) { 143 1.1 rmind npf_addr_t addr; 144 1.1 rmind memcpy(&addr, p, alen); 145 1.1 rmind npf_table_insert(t, alen, &addr, NPF_NO_NETMASK); 146 1.1 rmind } 147 1.1 rmind } 148 1.1 rmind 149 1.1 rmind /* Publish the new table. */ 150 1.1 rmind replace_ifnet_table(npf, t); 151 1.1 rmind } 152 1.1 rmind 153 1.1 rmind void 154 1.1 rmind npf_ifaddr_flush(npf_t *npf, ifnet_t *ifp) 155 1.1 rmind { 156 1.1 rmind npf_table_t *t; 157 1.1 rmind 158 1.1 rmind /* 159 1.1 rmind * Flush: just load an empty table. 160 1.1 rmind */ 161 1.1 rmind t = lookup_ifnet_table(npf, ifp); 162 1.1 rmind if (!t) { 163 1.1 rmind return; 164 1.1 rmind } 165 1.1 rmind replace_ifnet_table(npf, t); 166 1.1 rmind } 167 1.2 rmind 168 1.2 rmind void 169 1.2 rmind npf_ifaddr_syncall(npf_t *npf) 170 1.2 rmind { 171 1.2 rmind ifnet_t *ifp; 172 1.2 rmind 173 1.2 rmind KERNEL_LOCK(1, NULL); 174 1.3 ozaki IFNET_GLOBAL_LOCK(); 175 1.2 rmind IFNET_WRITER_FOREACH(ifp) { 176 1.2 rmind npf_ifaddr_sync(npf, ifp); 177 1.2 rmind } 178 1.3 ozaki IFNET_GLOBAL_UNLOCK(); 179 1.2 rmind KERNEL_UNLOCK_ONE(NULL); 180 1.2 rmind } 181