1/*- 2 * Copyright (c) 2014 Yandex LLC. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2014 Yandex LLC. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h>
|
53#include <net/vnet.h> 54 55#include <netinet/in.h> 56#include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 57#include <netinet/ip_fw.h> 58 59#include <netpfil/ipfw/ip_fw_private.h> 60 61#define CHAIN_TO_II(ch) ((struct namedobj_instance *)ch->ifcfg) 62 63#define DEFAULT_IFACES 128 64 65static void handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 66 uint16_t ifindex); 67static void handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 68 uint16_t ifindex); 69static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 70 struct sockopt_data *sd); 71 72static struct ipfw_sopt_handler scodes[] = { 73 { IP_FW_XIFLIST, 0, HDIR_GET, list_ifaces }, 74}; 75 76/* 77 * FreeBSD Kernel interface. 78 */ 79static void ipfw_kifhandler(void *arg, struct ifnet *ifp); 80static int ipfw_kiflookup(char *name); 81static void iface_khandler_register(void); 82static void iface_khandler_deregister(void); 83 84static eventhandler_tag ipfw_ifdetach_event, ipfw_ifattach_event; 85static int num_vnets = 0; 86static struct mtx vnet_mtx; 87 88/* 89 * Checks if kernel interface is contained in our tracked 90 * interface list and calls attach/detach handler. 91 */ 92static void 93ipfw_kifhandler(void *arg, struct ifnet *ifp) 94{ 95 struct ip_fw_chain *ch; 96 struct ipfw_iface *iif; 97 struct namedobj_instance *ii; 98 uintptr_t htype; 99 100 if (V_ipfw_vnet_ready == 0) 101 return; 102 103 ch = &V_layer3_chain; 104 htype = (uintptr_t)arg; 105 106 IPFW_UH_WLOCK(ch); 107 ii = CHAIN_TO_II(ch); 108 if (ii == NULL) { 109 IPFW_UH_WUNLOCK(ch); 110 return; 111 } 112 iif = (struct ipfw_iface*)ipfw_objhash_lookup_name(ii, 0, 113 if_name(ifp)); 114 if (iif != NULL) { 115 if (htype == 1) 116 handle_ifattach(ch, iif, ifp->if_index); 117 else 118 handle_ifdetach(ch, iif, ifp->if_index); 119 } 120 IPFW_UH_WUNLOCK(ch); 121} 122 123/* 124 * Reference current VNET as iface tracking API user. 125 * Registers interface tracking handlers for first VNET. 126 */ 127static void 128iface_khandler_register() 129{ 130 int create; 131 132 create = 0; 133 134 mtx_lock(&vnet_mtx); 135 if (num_vnets == 0) 136 create = 1; 137 num_vnets++; 138 mtx_unlock(&vnet_mtx); 139 140 if (create == 0) 141 return; 142 143 printf("IPFW: starting up interface tracker\n"); 144 145 ipfw_ifdetach_event = EVENTHANDLER_REGISTER( 146 ifnet_departure_event, ipfw_kifhandler, NULL, 147 EVENTHANDLER_PRI_ANY); 148 ipfw_ifattach_event = EVENTHANDLER_REGISTER( 149 ifnet_arrival_event, ipfw_kifhandler, (void*)((uintptr_t)1), 150 EVENTHANDLER_PRI_ANY); 151} 152 153/* 154 * 155 * Detach interface event handlers on last VNET instance 156 * detach. 157 */ 158static void 159iface_khandler_deregister() 160{ 161 int destroy; 162 163 destroy = 0; 164 mtx_lock(&vnet_mtx); 165 if (num_vnets == 1) 166 destroy = 1; 167 num_vnets--; 168 mtx_unlock(&vnet_mtx); 169 170 if (destroy == 0) 171 return; 172 173 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, 174 ipfw_ifattach_event); 175 EVENTHANDLER_DEREGISTER(ifnet_departure_event, 176 ipfw_ifdetach_event); 177} 178 179/* 180 * Retrieves ifindex for given @name. 181 * 182 * Returns ifindex or 0. 183 */ 184static int 185ipfw_kiflookup(char *name) 186{ 187 struct ifnet *ifp; 188 int ifindex; 189 190 ifindex = 0; 191 192 if ((ifp = ifunit_ref(name)) != NULL) { 193 ifindex = ifp->if_index; 194 if_rele(ifp); 195 } 196 197 return (ifindex); 198} 199 200/* 201 * Global ipfw startup hook. 202 * Since we perform lazy initialization, do nothing except 203 * mutex init. 204 */ 205int 206ipfw_iface_init() 207{ 208 209 mtx_init(&vnet_mtx, "IPFW ifhandler mtx", NULL, MTX_DEF); 210 IPFW_ADD_SOPT_HANDLER(1, scodes); 211 return (0); 212} 213 214/* 215 * Global ipfw destroy hook. 216 * Unregister khandlers iff init has been done. 217 */ 218void 219ipfw_iface_destroy() 220{ 221 222 IPFW_DEL_SOPT_HANDLER(1, scodes); 223 mtx_destroy(&vnet_mtx); 224} 225 226/* 227 * Perform actual init on internal request. 228 * Inits both namehash and global khandler. 229 */ 230static void 231vnet_ipfw_iface_init(struct ip_fw_chain *ch) 232{ 233 struct namedobj_instance *ii; 234 235 ii = ipfw_objhash_create(DEFAULT_IFACES); 236 IPFW_UH_WLOCK(ch); 237 if (ch->ifcfg == NULL) { 238 ch->ifcfg = ii; 239 ii = NULL; 240 } 241 IPFW_UH_WUNLOCK(ch); 242 243 if (ii != NULL) { 244 /* Already initialized. Free namehash. */ 245 ipfw_objhash_destroy(ii); 246 } else { 247 /* We're the first ones. Init kernel hooks. */ 248 iface_khandler_register(); 249 } 250} 251 252static int 253destroy_iface(struct namedobj_instance *ii, struct named_object *no, 254 void *arg) 255{ 256 257 /* Assume all consumers have been already detached */ 258 free(no, M_IPFW); 259 return (0); 260} 261 262/* 263 * Per-VNET ipfw detach hook. 264 * 265 */ 266void 267vnet_ipfw_iface_destroy(struct ip_fw_chain *ch) 268{ 269 struct namedobj_instance *ii; 270 271 IPFW_UH_WLOCK(ch); 272 ii = CHAIN_TO_II(ch); 273 ch->ifcfg = NULL; 274 IPFW_UH_WUNLOCK(ch); 275 276 if (ii != NULL) { 277 ipfw_objhash_foreach(ii, destroy_iface, ch); 278 ipfw_objhash_destroy(ii); 279 iface_khandler_deregister(); 280 } 281} 282 283/* 284 * Notify the subsystem that we are interested in tracking 285 * interface @name. This function has to be called without 286 * holding any locks to permit allocating the necessary states 287 * for proper interface tracking. 288 * 289 * Returns 0 on success. 290 */ 291int 292ipfw_iface_ref(struct ip_fw_chain *ch, char *name, 293 struct ipfw_ifc *ic) 294{ 295 struct namedobj_instance *ii; 296 struct ipfw_iface *iif, *tmp; 297 298 if (strlen(name) >= sizeof(iif->ifname)) 299 return (EINVAL); 300 301 IPFW_UH_WLOCK(ch); 302 303 ii = CHAIN_TO_II(ch); 304 if (ii == NULL) { 305 306 /* 307 * First request to subsystem. 308 * Let's perform init. 309 */ 310 IPFW_UH_WUNLOCK(ch); 311 vnet_ipfw_iface_init(ch); 312 IPFW_UH_WLOCK(ch); 313 ii = CHAIN_TO_II(ch); 314 } 315 316 iif = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name); 317 318 if (iif != NULL) { 319 iif->no.refcnt++; 320 ic->iface = iif; 321 IPFW_UH_WUNLOCK(ch); 322 return (0); 323 } 324 325 IPFW_UH_WUNLOCK(ch); 326 327 /* Not found. Let's create one */ 328 iif = malloc(sizeof(struct ipfw_iface), M_IPFW, M_WAITOK | M_ZERO); 329 TAILQ_INIT(&iif->consumers); 330 iif->no.name = iif->ifname; 331 strlcpy(iif->ifname, name, sizeof(iif->ifname)); 332 333 /* 334 * Ref & link to the list. 335 * 336 * We assume ifnet_arrival_event / ifnet_departure_event 337 * are not holding any locks. 338 */ 339 iif->no.refcnt = 1; 340 IPFW_UH_WLOCK(ch); 341 342 tmp = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name); 343 if (tmp != NULL) { 344 /* Interface has been created since unlock. Ref and return */ 345 tmp->no.refcnt++; 346 ic->iface = tmp; 347 IPFW_UH_WUNLOCK(ch); 348 free(iif, M_IPFW); 349 return (0); 350 } 351 352 iif->ifindex = ipfw_kiflookup(name); 353 if (iif->ifindex != 0) 354 iif->resolved = 1; 355 356 ipfw_objhash_add(ii, &iif->no); 357 ic->iface = iif; 358 359 IPFW_UH_WUNLOCK(ch); 360 361 return (0); 362} 363 364/* 365 * Adds @ic to the list of iif interface consumers. 366 * Must be called with holding both UH+WLOCK. 367 * Callback may be immediately called (if interface exists). 368 */ 369void 370ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 371{ 372 struct ipfw_iface *iif; 373 374 IPFW_UH_WLOCK_ASSERT(ch); 375 IPFW_WLOCK_ASSERT(ch); 376 377 iif = ic->iface; 378 379 TAILQ_INSERT_TAIL(&iif->consumers, ic, next); 380 if (iif->resolved != 0) 381 ic->cb(ch, ic->cbdata, iif->ifindex); 382} 383 384/* 385 * Unlinks interface tracker object @ic from interface. 386 * Must be called while holding UH lock. 387 */ 388void 389ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 390{ 391 struct ipfw_iface *iif; 392 393 IPFW_UH_WLOCK_ASSERT(ch); 394 395 iif = ic->iface; 396 TAILQ_REMOVE(&iif->consumers, ic, next); 397} 398 399/* 400 * Unreference interface specified by @ic. 401 * Must be called while holding UH lock. 402 */ 403void 404ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 405{ 406 struct ipfw_iface *iif; 407 408 IPFW_UH_WLOCK_ASSERT(ch); 409 410 iif = ic->iface; 411 ic->iface = NULL; 412 413 iif->no.refcnt--; 414 /* TODO: check for references & delete */ 415} 416 417/* 418 * Interface arrival handler. 419 */ 420static void 421handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 422 uint16_t ifindex) 423{ 424 struct ipfw_ifc *ic; 425 426 IPFW_UH_WLOCK_ASSERT(ch); 427 428 iif->gencnt++; 429 iif->resolved = 1; 430 iif->ifindex = ifindex; 431 432 IPFW_WLOCK(ch); 433 TAILQ_FOREACH(ic, &iif->consumers, next) 434 ic->cb(ch, ic->cbdata, iif->ifindex); 435 IPFW_WUNLOCK(ch); 436} 437 438/* 439 * Interface departure handler. 440 */ 441static void 442handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 443 uint16_t ifindex) 444{ 445 struct ipfw_ifc *ic; 446 447 IPFW_UH_WLOCK_ASSERT(ch); 448 449 IPFW_WLOCK(ch); 450 TAILQ_FOREACH(ic, &iif->consumers, next) 451 ic->cb(ch, ic->cbdata, 0); 452 IPFW_WUNLOCK(ch); 453 454 iif->gencnt++; 455 iif->resolved = 0; 456 iif->ifindex = 0; 457} 458 459struct dump_iface_args { 460 struct ip_fw_chain *ch; 461 struct sockopt_data *sd; 462}; 463 464static int 465export_iface_internal(struct namedobj_instance *ii, struct named_object *no, 466 void *arg) 467{ 468 ipfw_iface_info *i; 469 struct dump_iface_args *da; 470 struct ipfw_iface *iif; 471 472 da = (struct dump_iface_args *)arg; 473 474 i = (ipfw_iface_info *)ipfw_get_sopt_space(da->sd, sizeof(*i)); 475 KASSERT(i != NULL, ("previously checked buffer is not enough")); 476 477 iif = (struct ipfw_iface *)no; 478 479 strlcpy(i->ifname, iif->ifname, sizeof(i->ifname)); 480 if (iif->resolved) 481 i->flags |= IPFW_IFFLAG_RESOLVED; 482 i->ifindex = iif->ifindex; 483 i->refcnt = iif->no.refcnt; 484 i->gencnt = iif->gencnt; 485 return (0); 486} 487 488/* 489 * Lists all interface currently tracked by ipfw. 490 * Data layout (v0)(current): 491 * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 492 * Reply: [ ipfw_obj_lheader ipfw_iface_info x N ] 493 * 494 * Returns 0 on success 495 */ 496static int 497list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 498 struct sockopt_data *sd) 499{ 500 struct namedobj_instance *ii; 501 struct _ipfw_obj_lheader *olh; 502 struct dump_iface_args da; 503 uint32_t count, size; 504 505 olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 506 if (olh == NULL) 507 return (EINVAL); 508 if (sd->valsize < olh->size) 509 return (EINVAL); 510 511 IPFW_UH_RLOCK(ch); 512 ii = CHAIN_TO_II(ch); 513 if (ii != NULL) 514 count = ipfw_objhash_count(ii); 515 else 516 count = 0; 517 size = count * sizeof(ipfw_iface_info) + sizeof(ipfw_obj_lheader); 518 519 /* Fill in header regadless of buffer size */ 520 olh->count = count; 521 olh->objsize = sizeof(ipfw_iface_info); 522 523 if (size > olh->size) { 524 olh->size = size; 525 IPFW_UH_RUNLOCK(ch); 526 return (ENOMEM); 527 } 528 olh->size = size; 529 530 da.ch = ch; 531 da.sd = sd; 532 533 if (ii != NULL) 534 ipfw_objhash_foreach(ii, export_iface_internal, &da); 535 IPFW_UH_RUNLOCK(ch); 536 537 return (0); 538} 539
| 54#include <net/vnet.h> 55 56#include <netinet/in.h> 57#include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 58#include <netinet/ip_fw.h> 59 60#include <netpfil/ipfw/ip_fw_private.h> 61 62#define CHAIN_TO_II(ch) ((struct namedobj_instance *)ch->ifcfg) 63 64#define DEFAULT_IFACES 128 65 66static void handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 67 uint16_t ifindex); 68static void handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 69 uint16_t ifindex); 70static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 71 struct sockopt_data *sd); 72 73static struct ipfw_sopt_handler scodes[] = { 74 { IP_FW_XIFLIST, 0, HDIR_GET, list_ifaces }, 75}; 76 77/* 78 * FreeBSD Kernel interface. 79 */ 80static void ipfw_kifhandler(void *arg, struct ifnet *ifp); 81static int ipfw_kiflookup(char *name); 82static void iface_khandler_register(void); 83static void iface_khandler_deregister(void); 84 85static eventhandler_tag ipfw_ifdetach_event, ipfw_ifattach_event; 86static int num_vnets = 0; 87static struct mtx vnet_mtx; 88 89/* 90 * Checks if kernel interface is contained in our tracked 91 * interface list and calls attach/detach handler. 92 */ 93static void 94ipfw_kifhandler(void *arg, struct ifnet *ifp) 95{ 96 struct ip_fw_chain *ch; 97 struct ipfw_iface *iif; 98 struct namedobj_instance *ii; 99 uintptr_t htype; 100 101 if (V_ipfw_vnet_ready == 0) 102 return; 103 104 ch = &V_layer3_chain; 105 htype = (uintptr_t)arg; 106 107 IPFW_UH_WLOCK(ch); 108 ii = CHAIN_TO_II(ch); 109 if (ii == NULL) { 110 IPFW_UH_WUNLOCK(ch); 111 return; 112 } 113 iif = (struct ipfw_iface*)ipfw_objhash_lookup_name(ii, 0, 114 if_name(ifp)); 115 if (iif != NULL) { 116 if (htype == 1) 117 handle_ifattach(ch, iif, ifp->if_index); 118 else 119 handle_ifdetach(ch, iif, ifp->if_index); 120 } 121 IPFW_UH_WUNLOCK(ch); 122} 123 124/* 125 * Reference current VNET as iface tracking API user. 126 * Registers interface tracking handlers for first VNET. 127 */ 128static void 129iface_khandler_register() 130{ 131 int create; 132 133 create = 0; 134 135 mtx_lock(&vnet_mtx); 136 if (num_vnets == 0) 137 create = 1; 138 num_vnets++; 139 mtx_unlock(&vnet_mtx); 140 141 if (create == 0) 142 return; 143 144 printf("IPFW: starting up interface tracker\n"); 145 146 ipfw_ifdetach_event = EVENTHANDLER_REGISTER( 147 ifnet_departure_event, ipfw_kifhandler, NULL, 148 EVENTHANDLER_PRI_ANY); 149 ipfw_ifattach_event = EVENTHANDLER_REGISTER( 150 ifnet_arrival_event, ipfw_kifhandler, (void*)((uintptr_t)1), 151 EVENTHANDLER_PRI_ANY); 152} 153 154/* 155 * 156 * Detach interface event handlers on last VNET instance 157 * detach. 158 */ 159static void 160iface_khandler_deregister() 161{ 162 int destroy; 163 164 destroy = 0; 165 mtx_lock(&vnet_mtx); 166 if (num_vnets == 1) 167 destroy = 1; 168 num_vnets--; 169 mtx_unlock(&vnet_mtx); 170 171 if (destroy == 0) 172 return; 173 174 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, 175 ipfw_ifattach_event); 176 EVENTHANDLER_DEREGISTER(ifnet_departure_event, 177 ipfw_ifdetach_event); 178} 179 180/* 181 * Retrieves ifindex for given @name. 182 * 183 * Returns ifindex or 0. 184 */ 185static int 186ipfw_kiflookup(char *name) 187{ 188 struct ifnet *ifp; 189 int ifindex; 190 191 ifindex = 0; 192 193 if ((ifp = ifunit_ref(name)) != NULL) { 194 ifindex = ifp->if_index; 195 if_rele(ifp); 196 } 197 198 return (ifindex); 199} 200 201/* 202 * Global ipfw startup hook. 203 * Since we perform lazy initialization, do nothing except 204 * mutex init. 205 */ 206int 207ipfw_iface_init() 208{ 209 210 mtx_init(&vnet_mtx, "IPFW ifhandler mtx", NULL, MTX_DEF); 211 IPFW_ADD_SOPT_HANDLER(1, scodes); 212 return (0); 213} 214 215/* 216 * Global ipfw destroy hook. 217 * Unregister khandlers iff init has been done. 218 */ 219void 220ipfw_iface_destroy() 221{ 222 223 IPFW_DEL_SOPT_HANDLER(1, scodes); 224 mtx_destroy(&vnet_mtx); 225} 226 227/* 228 * Perform actual init on internal request. 229 * Inits both namehash and global khandler. 230 */ 231static void 232vnet_ipfw_iface_init(struct ip_fw_chain *ch) 233{ 234 struct namedobj_instance *ii; 235 236 ii = ipfw_objhash_create(DEFAULT_IFACES); 237 IPFW_UH_WLOCK(ch); 238 if (ch->ifcfg == NULL) { 239 ch->ifcfg = ii; 240 ii = NULL; 241 } 242 IPFW_UH_WUNLOCK(ch); 243 244 if (ii != NULL) { 245 /* Already initialized. Free namehash. */ 246 ipfw_objhash_destroy(ii); 247 } else { 248 /* We're the first ones. Init kernel hooks. */ 249 iface_khandler_register(); 250 } 251} 252 253static int 254destroy_iface(struct namedobj_instance *ii, struct named_object *no, 255 void *arg) 256{ 257 258 /* Assume all consumers have been already detached */ 259 free(no, M_IPFW); 260 return (0); 261} 262 263/* 264 * Per-VNET ipfw detach hook. 265 * 266 */ 267void 268vnet_ipfw_iface_destroy(struct ip_fw_chain *ch) 269{ 270 struct namedobj_instance *ii; 271 272 IPFW_UH_WLOCK(ch); 273 ii = CHAIN_TO_II(ch); 274 ch->ifcfg = NULL; 275 IPFW_UH_WUNLOCK(ch); 276 277 if (ii != NULL) { 278 ipfw_objhash_foreach(ii, destroy_iface, ch); 279 ipfw_objhash_destroy(ii); 280 iface_khandler_deregister(); 281 } 282} 283 284/* 285 * Notify the subsystem that we are interested in tracking 286 * interface @name. This function has to be called without 287 * holding any locks to permit allocating the necessary states 288 * for proper interface tracking. 289 * 290 * Returns 0 on success. 291 */ 292int 293ipfw_iface_ref(struct ip_fw_chain *ch, char *name, 294 struct ipfw_ifc *ic) 295{ 296 struct namedobj_instance *ii; 297 struct ipfw_iface *iif, *tmp; 298 299 if (strlen(name) >= sizeof(iif->ifname)) 300 return (EINVAL); 301 302 IPFW_UH_WLOCK(ch); 303 304 ii = CHAIN_TO_II(ch); 305 if (ii == NULL) { 306 307 /* 308 * First request to subsystem. 309 * Let's perform init. 310 */ 311 IPFW_UH_WUNLOCK(ch); 312 vnet_ipfw_iface_init(ch); 313 IPFW_UH_WLOCK(ch); 314 ii = CHAIN_TO_II(ch); 315 } 316 317 iif = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name); 318 319 if (iif != NULL) { 320 iif->no.refcnt++; 321 ic->iface = iif; 322 IPFW_UH_WUNLOCK(ch); 323 return (0); 324 } 325 326 IPFW_UH_WUNLOCK(ch); 327 328 /* Not found. Let's create one */ 329 iif = malloc(sizeof(struct ipfw_iface), M_IPFW, M_WAITOK | M_ZERO); 330 TAILQ_INIT(&iif->consumers); 331 iif->no.name = iif->ifname; 332 strlcpy(iif->ifname, name, sizeof(iif->ifname)); 333 334 /* 335 * Ref & link to the list. 336 * 337 * We assume ifnet_arrival_event / ifnet_departure_event 338 * are not holding any locks. 339 */ 340 iif->no.refcnt = 1; 341 IPFW_UH_WLOCK(ch); 342 343 tmp = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name); 344 if (tmp != NULL) { 345 /* Interface has been created since unlock. Ref and return */ 346 tmp->no.refcnt++; 347 ic->iface = tmp; 348 IPFW_UH_WUNLOCK(ch); 349 free(iif, M_IPFW); 350 return (0); 351 } 352 353 iif->ifindex = ipfw_kiflookup(name); 354 if (iif->ifindex != 0) 355 iif->resolved = 1; 356 357 ipfw_objhash_add(ii, &iif->no); 358 ic->iface = iif; 359 360 IPFW_UH_WUNLOCK(ch); 361 362 return (0); 363} 364 365/* 366 * Adds @ic to the list of iif interface consumers. 367 * Must be called with holding both UH+WLOCK. 368 * Callback may be immediately called (if interface exists). 369 */ 370void 371ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 372{ 373 struct ipfw_iface *iif; 374 375 IPFW_UH_WLOCK_ASSERT(ch); 376 IPFW_WLOCK_ASSERT(ch); 377 378 iif = ic->iface; 379 380 TAILQ_INSERT_TAIL(&iif->consumers, ic, next); 381 if (iif->resolved != 0) 382 ic->cb(ch, ic->cbdata, iif->ifindex); 383} 384 385/* 386 * Unlinks interface tracker object @ic from interface. 387 * Must be called while holding UH lock. 388 */ 389void 390ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 391{ 392 struct ipfw_iface *iif; 393 394 IPFW_UH_WLOCK_ASSERT(ch); 395 396 iif = ic->iface; 397 TAILQ_REMOVE(&iif->consumers, ic, next); 398} 399 400/* 401 * Unreference interface specified by @ic. 402 * Must be called while holding UH lock. 403 */ 404void 405ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 406{ 407 struct ipfw_iface *iif; 408 409 IPFW_UH_WLOCK_ASSERT(ch); 410 411 iif = ic->iface; 412 ic->iface = NULL; 413 414 iif->no.refcnt--; 415 /* TODO: check for references & delete */ 416} 417 418/* 419 * Interface arrival handler. 420 */ 421static void 422handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 423 uint16_t ifindex) 424{ 425 struct ipfw_ifc *ic; 426 427 IPFW_UH_WLOCK_ASSERT(ch); 428 429 iif->gencnt++; 430 iif->resolved = 1; 431 iif->ifindex = ifindex; 432 433 IPFW_WLOCK(ch); 434 TAILQ_FOREACH(ic, &iif->consumers, next) 435 ic->cb(ch, ic->cbdata, iif->ifindex); 436 IPFW_WUNLOCK(ch); 437} 438 439/* 440 * Interface departure handler. 441 */ 442static void 443handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 444 uint16_t ifindex) 445{ 446 struct ipfw_ifc *ic; 447 448 IPFW_UH_WLOCK_ASSERT(ch); 449 450 IPFW_WLOCK(ch); 451 TAILQ_FOREACH(ic, &iif->consumers, next) 452 ic->cb(ch, ic->cbdata, 0); 453 IPFW_WUNLOCK(ch); 454 455 iif->gencnt++; 456 iif->resolved = 0; 457 iif->ifindex = 0; 458} 459 460struct dump_iface_args { 461 struct ip_fw_chain *ch; 462 struct sockopt_data *sd; 463}; 464 465static int 466export_iface_internal(struct namedobj_instance *ii, struct named_object *no, 467 void *arg) 468{ 469 ipfw_iface_info *i; 470 struct dump_iface_args *da; 471 struct ipfw_iface *iif; 472 473 da = (struct dump_iface_args *)arg; 474 475 i = (ipfw_iface_info *)ipfw_get_sopt_space(da->sd, sizeof(*i)); 476 KASSERT(i != NULL, ("previously checked buffer is not enough")); 477 478 iif = (struct ipfw_iface *)no; 479 480 strlcpy(i->ifname, iif->ifname, sizeof(i->ifname)); 481 if (iif->resolved) 482 i->flags |= IPFW_IFFLAG_RESOLVED; 483 i->ifindex = iif->ifindex; 484 i->refcnt = iif->no.refcnt; 485 i->gencnt = iif->gencnt; 486 return (0); 487} 488 489/* 490 * Lists all interface currently tracked by ipfw. 491 * Data layout (v0)(current): 492 * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 493 * Reply: [ ipfw_obj_lheader ipfw_iface_info x N ] 494 * 495 * Returns 0 on success 496 */ 497static int 498list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 499 struct sockopt_data *sd) 500{ 501 struct namedobj_instance *ii; 502 struct _ipfw_obj_lheader *olh; 503 struct dump_iface_args da; 504 uint32_t count, size; 505 506 olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 507 if (olh == NULL) 508 return (EINVAL); 509 if (sd->valsize < olh->size) 510 return (EINVAL); 511 512 IPFW_UH_RLOCK(ch); 513 ii = CHAIN_TO_II(ch); 514 if (ii != NULL) 515 count = ipfw_objhash_count(ii); 516 else 517 count = 0; 518 size = count * sizeof(ipfw_iface_info) + sizeof(ipfw_obj_lheader); 519 520 /* Fill in header regadless of buffer size */ 521 olh->count = count; 522 olh->objsize = sizeof(ipfw_iface_info); 523 524 if (size > olh->size) { 525 olh->size = size; 526 IPFW_UH_RUNLOCK(ch); 527 return (ENOMEM); 528 } 529 olh->size = size; 530 531 da.ch = ch; 532 da.sd = sd; 533 534 if (ii != NULL) 535 ipfw_objhash_foreach(ii, export_iface_internal, &da); 536 IPFW_UH_RUNLOCK(ch); 537 538 return (0); 539} 540
|