1 /* $OpenBSD: if.c,v 1.165 2007/07/06 14:00:59 naddy Exp $ */ 2 /* $NetBSD: if_compat.c,v 1.2 2008/06/18 09:06:27 yamt Exp $ */ 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: if_compat.c,v 1.2 2008/06/18 09:06:27 yamt Exp $"); 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 */ 87 static int if_getgroup(void *, struct ifnet *); 88 static int if_getgroupmembers(void *); 89 90 static int if_group_egress_build(void); 91 #endif 92 93 TAILQ_HEAD(, ifg_group) ifg_head = TAILQ_HEAD_INITIALIZER(ifg_head); 94 95 void 96 if_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 106 void 107 if_destroy_groups(struct ifnet *ifp) 108 { 109 struct ifg_list_head *ifgh = if_get_groups(ifp); 110 111 free(ifgh, M_TEMP); 112 } 113 114 struct ifg_list_head * 115 if_get_groups(struct ifnet *ifp) 116 { 117 return (ifp->if_pf_groups); 118 } 119 120 /* 121 * Create interface group without members. 122 */ 123 struct ifg_group * 124 if_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 */ 147 int 148 if_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 */ 200 int 201 if_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 */ 246 static int 247 if_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 */ 281 static int 282 if_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 319 void 320 if_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 339 static int 340 if_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