1/* $OpenBSD: if.c,v 1.165 2007/07/06 14:00:59 naddy Exp $ */ 2/* $NetBSD$ */ 3 4/* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33/* 34 * Copyright (c) 1980, 1986, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)if.c 8.3 (Berkeley) 1/4/94 62 */ 63 64#include <sys/cdefs.h> 65__KERNEL_RCSID(0, "$NetBSD$"); 66 67#include "pf.h" 68 69#include <sys/param.h> 70#include <sys/systm.h> 71#include <sys/malloc.h> 72#include <sys/socket.h> 73#include <sys/socketvar.h> 74 75#include <net/if.h> 76 77#include <netinet/in.h> 78#include <netinet/in_var.h> 79 80#include <net/if_compat.h> 81 82#if NPF > 0 83#include <net/pfvar.h> 84#endif 85 86#if 0 /* XXX unused - remove later */ 87static int if_getgroup(void *, struct ifnet *); 88static int if_getgroupmembers(void *); 89 90static int if_group_egress_build(void); 91#endif 92 93TAILQ_HEAD(, ifg_group) ifg_head = TAILQ_HEAD_INITIALIZER(ifg_head); 94 95void 96if_init_groups(struct ifnet *ifp) 97{ 98 struct ifg_list_head *ifgh; 99 100 ifgh = malloc(sizeof(struct ifg_list_head), M_TEMP, M_WAITOK); 101 TAILQ_INIT(ifgh); 102 103 ifp->if_pf_groups = ifgh; 104} 105 106void 107if_destroy_groups(struct ifnet *ifp) 108{ 109 struct ifg_list_head *ifgh = if_get_groups(ifp); 110 111 free(ifgh, M_TEMP); 112} 113 114struct ifg_list_head * 115if_get_groups(struct ifnet *ifp) 116{ 117 return (ifp->if_pf_groups); 118} 119 120/* 121 * Create interface group without members. 122 */ 123struct ifg_group * 124if_creategroup(const char *groupname) 125{ 126 struct ifg_group *ifg = NULL; 127 128 if ((ifg = (struct ifg_group *)malloc(sizeof(struct ifg_group), 129 M_TEMP, M_NOWAIT)) == NULL) 130 return (NULL); 131 132 strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group)); 133 ifg->ifg_refcnt = 0; 134 ifg->ifg_carp_demoted = 0; 135 TAILQ_INIT(&ifg->ifg_members); 136#if NPF > 0 137 pfi_attach_ifgroup(ifg); 138#endif 139 TAILQ_INSERT_TAIL(&ifg_head, ifg, ifg_next); 140 141 return (ifg); 142} 143 144/* 145 * Add a group to an interface. 146 */ 147int 148if_addgroup(struct ifnet *ifp, const char *groupname) 149{ 150 struct ifg_list_head *ifgh = if_get_groups(ifp); 151 struct ifg_list *ifgl; 152 struct ifg_group *ifg = NULL; 153 struct ifg_member *ifgm; 154 155 if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' && 156 groupname[strlen(groupname) - 1] <= '9') 157 return (EINVAL); 158 159 TAILQ_FOREACH(ifgl, ifgh, ifgl_next) 160 if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) 161 return (EEXIST); 162 163 if ((ifgl = (struct ifg_list *)malloc(sizeof(struct ifg_list), M_TEMP, 164 M_NOWAIT)) == NULL) 165 return (ENOMEM); 166 167 if ((ifgm = (struct ifg_member *)malloc(sizeof(struct ifg_member), 168 M_TEMP, M_NOWAIT)) == NULL) { 169 free(ifgl, M_TEMP); 170 return (ENOMEM); 171 } 172 173 TAILQ_FOREACH(ifg, &ifg_head, ifg_next) 174 if (!strcmp(ifg->ifg_group, groupname)) 175 break; 176 177 if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) { 178 free(ifgl, M_TEMP); 179 free(ifgm, M_TEMP); 180 return (ENOMEM); 181 } 182 183 ifg->ifg_refcnt++; 184 ifgl->ifgl_group = ifg; 185 ifgm->ifgm_ifp = ifp; 186 187 TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next); 188 TAILQ_INSERT_TAIL(ifgh, ifgl, ifgl_next); 189 190#if NPF > 0 191 pfi_group_change(groupname); 192#endif 193 194 return (0); 195} 196 197/* 198 * Remove a group from an interface. 199 */ 200int 201if_delgroup(struct ifnet *ifp, const char *groupname) 202{ 203 struct ifg_list_head *ifgh = if_get_groups(ifp); 204 struct ifg_list *ifgl; 205 struct ifg_member *ifgm; 206 207 TAILQ_FOREACH(ifgl, ifgh, ifgl_next) 208 if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) 209 break; 210 if (ifgl == NULL) 211 return (ENOENT); 212 213 TAILQ_REMOVE(ifgh, ifgl, ifgl_next); 214 215 TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) 216 if (ifgm->ifgm_ifp == ifp) 217 break; 218 219 if (ifgm != NULL) { 220 TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifgm_next); 221 free(ifgm, M_TEMP); 222 } 223 224 if (--ifgl->ifgl_group->ifg_refcnt == 0) { 225 TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next); 226#if NPF > 0 227 pfi_detach_ifgroup(ifgl->ifgl_group); 228#endif 229 free(ifgl->ifgl_group, M_TEMP); 230 } 231 232 free(ifgl, M_TEMP); 233 234#if NPF > 0 235 pfi_group_change(groupname); 236#endif 237 238 return (0); 239} 240 241#if 0 242/* 243 * Stores all groups from an interface in memory pointed 244 * to by data. 245 */ 246static int 247if_getgroup(void *data, struct ifnet *ifp) 248{ 249 int len, error; 250 struct ifg_list_head *ifgh = if_get_groups(ifp); 251 struct ifg_list *ifgl; 252 struct ifg_req ifgrq, *ifgp; 253 struct ifgroupreq *ifgr = (struct ifgroupreq *)data; 254 255 if (ifgr->ifgr_len == 0) { 256 TAILQ_FOREACH(ifgl, ifgh, ifgl_next) 257 ifgr->ifgr_len += sizeof(struct ifg_req); 258 return (0); 259 } 260 261 len = ifgr->ifgr_len; 262 ifgp = ifgr->ifgr_groups; 263 TAILQ_FOREACH(ifgl, ifgh, ifgl_next) { 264 if (len < sizeof(ifgrq)) 265 return (EINVAL); 266 bzero(&ifgrq, sizeof ifgrq); 267 strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group, 268 sizeof(ifgrq.ifgrq_group)); 269 if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) 270 return (error); 271 len -= sizeof(ifgrq); 272 ifgp++; 273 } 274 275 return (0); 276} 277 278/* 279 * Stores all members of a group in memory pointed to by data. 280 */ 281static int 282if_getgroupmembers(void *data) 283{ 284 struct ifgroupreq *ifgr = (struct ifgroupreq *)data; 285 struct ifg_group *ifg; 286 struct ifg_member *ifgm; 287 struct ifg_req ifgrq, *ifgp; 288 int len, error; 289 290 TAILQ_FOREACH(ifg, &ifg_head, ifg_next) 291 if (!strcmp(ifg->ifg_group, ifgr->ifgr_name)) 292 break; 293 if (ifg == NULL) 294 return (ENOENT); 295 296 if (ifgr->ifgr_len == 0) { 297 TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) 298 ifgr->ifgr_len += sizeof(ifgrq); 299 return (0); 300 } 301 302 len = ifgr->ifgr_len; 303 ifgp = ifgr->ifgr_groups; 304 TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) { 305 if (len < sizeof(ifgrq)) 306 return (EINVAL); 307 bzero(&ifgrq, sizeof ifgrq); 308 strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname, 309 sizeof(ifgrq.ifgrq_member)); 310 if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) 311 return (error); 312 len -= sizeof(ifgrq); 313 ifgp++; 314 } 315 316 return (0); 317} 318 319void 320if_group_routechange(struct sockaddr *dst, struct sockaddr *mask) 321{ 322 switch (dst->sa_family) { 323 case AF_INET: 324 if (satosin(dst)->sin_addr.s_addr == INADDR_ANY) 325 if_group_egress_build(); 326 break; 327#ifdef INET6 328 case AF_INET6: 329 if (IN6_ARE_ADDR_EQUAL(&(satosin6(dst))->sin6_addr, 330 &in6addr_any) && 331 mask && IN6_ARE_ADDR_EQUAL(&(satosin6(mask))->sin6_addr, 332 &in6addr_any)) 333 if_group_egress_build(); 334 break; 335#endif 336 } 337} 338 339static int 340if_group_egress_build(void) 341{ 342 struct ifg_group *ifg; 343 struct ifg_member *ifgm, *next; 344 struct sockaddr_in sa_in; 345#ifdef INET6 346 struct sockaddr_in6 sa_in6; 347#endif 348 struct radix_node *rn; 349 struct rtentry *rt; 350 351 TAILQ_FOREACH(ifg, &ifg_head, ifg_next) 352 if (!strcmp(ifg->ifg_group, IFG_EGRESS)) 353 break; 354 355 if (ifg != NULL) 356 for (ifgm = TAILQ_FIRST(&ifg->ifg_members); ifgm; ifgm = next) { 357 next = TAILQ_NEXT(ifgm, ifgm_next); 358 if_delgroup(ifgm->ifgm_ifp, IFG_EGRESS); 359 } 360 361 bzero(&sa_in, sizeof(sa_in)); 362 sa_in.sin_len = sizeof(sa_in); 363 sa_in.sin_family = AF_INET; 364 if ((rn = rt_lookup(sintosa(&sa_in), sintosa(&sa_in), 0)) != NULL) { 365 do { 366 rt = (struct rtentry *)rn; 367 if (rt->rt_ifp) 368 if_addgroup(rt->rt_ifp, IFG_EGRESS); 369#ifndef SMALL_KERNEL 370 rn = rn_mpath_next(rn); 371#else 372 rn = NULL; 373#endif 374 } while (rn != NULL); 375 } 376 377#ifdef INET6 378 bcopy(&sa6_any, &sa_in6, sizeof(sa_in6)); 379 if ((rn = rt_lookup(sin6tosa(&sa_in6), sin6tosa(&sa_in6), 0)) != NULL) { 380 do { 381 rt = (struct rtentry *)rn; 382 if (rt->rt_ifp) 383 if_addgroup(rt->rt_ifp, IFG_EGRESS); 384#ifndef SMALL_KERNEL 385 rn = rn_mpath_next(rn); 386#else 387 rn = NULL; 388#endif 389 } while (rn != NULL); 390 } 391#endif 392 393 return (0); 394} 395#endif 396