168394ec8SAlexander V. Chernikov /*- 268394ec8SAlexander V. Chernikov * Copyright (c) 2014 Yandex LLC. 368394ec8SAlexander V. Chernikov * 468394ec8SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 568394ec8SAlexander V. Chernikov * modification, are permitted provided that the following conditions 668394ec8SAlexander V. Chernikov * are met: 768394ec8SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 868394ec8SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 968394ec8SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 1068394ec8SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 1168394ec8SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 1268394ec8SAlexander V. Chernikov * 1368394ec8SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1468394ec8SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1568394ec8SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1668394ec8SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1768394ec8SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1868394ec8SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1968394ec8SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2068394ec8SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2168394ec8SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2268394ec8SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2368394ec8SAlexander V. Chernikov * SUCH DAMAGE. 2468394ec8SAlexander V. Chernikov */ 2568394ec8SAlexander V. Chernikov 2668394ec8SAlexander V. Chernikov #include <sys/cdefs.h> 2768394ec8SAlexander V. Chernikov __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_iface.c 267384 2014-06-12 09:59:11Z melifaro $"); 2868394ec8SAlexander V. Chernikov 2968394ec8SAlexander V. Chernikov /* 3068394ec8SAlexander V. Chernikov * Kernel interface tracking API. 3168394ec8SAlexander V. Chernikov * 3268394ec8SAlexander V. Chernikov */ 3368394ec8SAlexander V. Chernikov 3468394ec8SAlexander V. Chernikov #include "opt_ipfw.h" 3568394ec8SAlexander V. Chernikov #include "opt_inet.h" 3668394ec8SAlexander V. Chernikov #ifndef INET 3768394ec8SAlexander V. Chernikov #error IPFIREWALL requires INET. 3868394ec8SAlexander V. Chernikov #endif /* INET */ 3968394ec8SAlexander V. Chernikov #include "opt_inet6.h" 4068394ec8SAlexander V. Chernikov 4168394ec8SAlexander V. Chernikov #include <sys/param.h> 4268394ec8SAlexander V. Chernikov #include <sys/systm.h> 4368394ec8SAlexander V. Chernikov #include <sys/malloc.h> 4468394ec8SAlexander V. Chernikov #include <sys/kernel.h> 4568394ec8SAlexander V. Chernikov #include <sys/lock.h> 4668394ec8SAlexander V. Chernikov #include <sys/rwlock.h> 47*ccba94b8SAlexander V. Chernikov #include <sys/rmlock.h> 4868394ec8SAlexander V. Chernikov #include <sys/socket.h> 4968394ec8SAlexander V. Chernikov #include <sys/queue.h> 5068394ec8SAlexander V. Chernikov #include <sys/eventhandler.h> 5168394ec8SAlexander V. Chernikov #include <net/if.h> 5268394ec8SAlexander V. Chernikov #include <net/if_var.h> 5368394ec8SAlexander V. Chernikov #include <net/vnet.h> 5468394ec8SAlexander V. Chernikov 5568394ec8SAlexander V. Chernikov #include <netinet/in.h> 5668394ec8SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 5768394ec8SAlexander V. Chernikov #include <netinet/ip_fw.h> 5868394ec8SAlexander V. Chernikov 5968394ec8SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 6068394ec8SAlexander V. Chernikov 6168394ec8SAlexander V. Chernikov #define CHAIN_TO_II(ch) ((struct namedobj_instance *)ch->ifcfg) 6268394ec8SAlexander V. Chernikov 6368394ec8SAlexander V. Chernikov #define DEFAULT_IFACES 128 6468394ec8SAlexander V. Chernikov 6568394ec8SAlexander V. Chernikov static void handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 6668394ec8SAlexander V. Chernikov uint16_t ifindex); 6768394ec8SAlexander V. Chernikov static void handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 6868394ec8SAlexander V. Chernikov uint16_t ifindex); 696b988f3aSAlexander V. Chernikov static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 706b988f3aSAlexander V. Chernikov struct sockopt_data *sd); 716b988f3aSAlexander V. Chernikov 726b988f3aSAlexander V. Chernikov static struct ipfw_sopt_handler scodes[] = { 736b988f3aSAlexander V. Chernikov { IP_FW_XIFLIST, 0, HDIR_GET, list_ifaces }, 746b988f3aSAlexander V. Chernikov }; 7568394ec8SAlexander V. Chernikov 7668394ec8SAlexander V. Chernikov /* 7768394ec8SAlexander V. Chernikov * FreeBSD Kernel interface. 7868394ec8SAlexander V. Chernikov */ 7968394ec8SAlexander V. Chernikov static void ipfw_kifhandler(void *arg, struct ifnet *ifp); 8068394ec8SAlexander V. Chernikov static int ipfw_kiflookup(char *name); 8168394ec8SAlexander V. Chernikov static void iface_khandler_register(void); 8268394ec8SAlexander V. Chernikov static void iface_khandler_deregister(void); 8368394ec8SAlexander V. Chernikov 8468394ec8SAlexander V. Chernikov static eventhandler_tag ipfw_ifdetach_event, ipfw_ifattach_event; 8568394ec8SAlexander V. Chernikov static int num_vnets = 0; 8698eff10eSAlexander V. Chernikov static struct mtx vnet_mtx; 8768394ec8SAlexander V. Chernikov 8868394ec8SAlexander V. Chernikov /* 8968394ec8SAlexander V. Chernikov * Checks if kernel interface is contained in our tracked 9068394ec8SAlexander V. Chernikov * interface list and calls attach/detach handler. 9168394ec8SAlexander V. Chernikov */ 9268394ec8SAlexander V. Chernikov static void 9368394ec8SAlexander V. Chernikov ipfw_kifhandler(void *arg, struct ifnet *ifp) 9468394ec8SAlexander V. Chernikov { 9568394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 9668394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 9768394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 9868394ec8SAlexander V. Chernikov uintptr_t htype; 9968394ec8SAlexander V. Chernikov 10098eff10eSAlexander V. Chernikov if (V_ipfw_vnet_ready == 0) 10198eff10eSAlexander V. Chernikov return; 10298eff10eSAlexander V. Chernikov 10368394ec8SAlexander V. Chernikov ch = &V_layer3_chain; 10468394ec8SAlexander V. Chernikov htype = (uintptr_t)arg; 10568394ec8SAlexander V. Chernikov 10668394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 10768394ec8SAlexander V. Chernikov ii = CHAIN_TO_II(ch); 10868394ec8SAlexander V. Chernikov if (ii == NULL) { 10968394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 11068394ec8SAlexander V. Chernikov return; 11168394ec8SAlexander V. Chernikov } 11298eff10eSAlexander V. Chernikov iif = (struct ipfw_iface*)ipfw_objhash_lookup_name(ii, 0, 11398eff10eSAlexander V. Chernikov if_name(ifp)); 11468394ec8SAlexander V. Chernikov if (iif != NULL) { 11568394ec8SAlexander V. Chernikov if (htype == 1) 11668394ec8SAlexander V. Chernikov handle_ifattach(ch, iif, ifp->if_index); 11768394ec8SAlexander V. Chernikov else 11868394ec8SAlexander V. Chernikov handle_ifdetach(ch, iif, ifp->if_index); 11968394ec8SAlexander V. Chernikov } 12068394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 12168394ec8SAlexander V. Chernikov } 12268394ec8SAlexander V. Chernikov 12368394ec8SAlexander V. Chernikov /* 12468394ec8SAlexander V. Chernikov * Reference current VNET as iface tracking API user. 12568394ec8SAlexander V. Chernikov * Registers interface tracking handlers for first VNET. 12668394ec8SAlexander V. Chernikov */ 12768394ec8SAlexander V. Chernikov static void 12868394ec8SAlexander V. Chernikov iface_khandler_register() 12968394ec8SAlexander V. Chernikov { 13068394ec8SAlexander V. Chernikov int create; 13168394ec8SAlexander V. Chernikov 13268394ec8SAlexander V. Chernikov create = 0; 13368394ec8SAlexander V. Chernikov 13468394ec8SAlexander V. Chernikov mtx_lock(&vnet_mtx); 13568394ec8SAlexander V. Chernikov if (num_vnets == 0) 13668394ec8SAlexander V. Chernikov create = 1; 13768394ec8SAlexander V. Chernikov num_vnets++; 13868394ec8SAlexander V. Chernikov mtx_unlock(&vnet_mtx); 13968394ec8SAlexander V. Chernikov 14068394ec8SAlexander V. Chernikov if (create == 0) 14168394ec8SAlexander V. Chernikov return; 14268394ec8SAlexander V. Chernikov 14368394ec8SAlexander V. Chernikov printf("IPFW: starting up interface tracker\n"); 14468394ec8SAlexander V. Chernikov 14568394ec8SAlexander V. Chernikov ipfw_ifdetach_event = EVENTHANDLER_REGISTER( 14668394ec8SAlexander V. Chernikov ifnet_departure_event, ipfw_kifhandler, NULL, 14768394ec8SAlexander V. Chernikov EVENTHANDLER_PRI_ANY); 14868394ec8SAlexander V. Chernikov ipfw_ifattach_event = EVENTHANDLER_REGISTER( 14968394ec8SAlexander V. Chernikov ifnet_arrival_event, ipfw_kifhandler, (void*)((uintptr_t)1), 15068394ec8SAlexander V. Chernikov EVENTHANDLER_PRI_ANY); 15168394ec8SAlexander V. Chernikov } 15268394ec8SAlexander V. Chernikov 15368394ec8SAlexander V. Chernikov /* 15468394ec8SAlexander V. Chernikov * 15568394ec8SAlexander V. Chernikov * Detach interface event handlers on last VNET instance 15668394ec8SAlexander V. Chernikov * detach. 15768394ec8SAlexander V. Chernikov */ 15868394ec8SAlexander V. Chernikov static void 15968394ec8SAlexander V. Chernikov iface_khandler_deregister() 16068394ec8SAlexander V. Chernikov { 16168394ec8SAlexander V. Chernikov int destroy; 16268394ec8SAlexander V. Chernikov 16368394ec8SAlexander V. Chernikov destroy = 0; 16468394ec8SAlexander V. Chernikov mtx_lock(&vnet_mtx); 16598eff10eSAlexander V. Chernikov if (num_vnets == 1) 16668394ec8SAlexander V. Chernikov destroy = 1; 16798eff10eSAlexander V. Chernikov num_vnets--; 16868394ec8SAlexander V. Chernikov mtx_unlock(&vnet_mtx); 16968394ec8SAlexander V. Chernikov 17068394ec8SAlexander V. Chernikov if (destroy == 0) 17168394ec8SAlexander V. Chernikov return; 17268394ec8SAlexander V. Chernikov 17368394ec8SAlexander V. Chernikov EVENTHANDLER_DEREGISTER(ifnet_arrival_event, 17468394ec8SAlexander V. Chernikov ipfw_ifattach_event); 17568394ec8SAlexander V. Chernikov EVENTHANDLER_DEREGISTER(ifnet_departure_event, 17668394ec8SAlexander V. Chernikov ipfw_ifdetach_event); 17768394ec8SAlexander V. Chernikov } 17868394ec8SAlexander V. Chernikov 17968394ec8SAlexander V. Chernikov /* 18068394ec8SAlexander V. Chernikov * Retrieves ifindex for given @name. 18168394ec8SAlexander V. Chernikov * 18268394ec8SAlexander V. Chernikov * Returns ifindex or 0. 18368394ec8SAlexander V. Chernikov */ 18468394ec8SAlexander V. Chernikov static int 18568394ec8SAlexander V. Chernikov ipfw_kiflookup(char *name) 18668394ec8SAlexander V. Chernikov { 18768394ec8SAlexander V. Chernikov struct ifnet *ifp; 18868394ec8SAlexander V. Chernikov int ifindex; 18968394ec8SAlexander V. Chernikov 19068394ec8SAlexander V. Chernikov ifindex = 0; 19168394ec8SAlexander V. Chernikov 19268394ec8SAlexander V. Chernikov if ((ifp = ifunit_ref(name)) != NULL) { 19368394ec8SAlexander V. Chernikov ifindex = ifp->if_index; 19468394ec8SAlexander V. Chernikov if_rele(ifp); 19568394ec8SAlexander V. Chernikov } 19668394ec8SAlexander V. Chernikov 19768394ec8SAlexander V. Chernikov return (ifindex); 19868394ec8SAlexander V. Chernikov } 19968394ec8SAlexander V. Chernikov 20068394ec8SAlexander V. Chernikov /* 20168394ec8SAlexander V. Chernikov * Global ipfw startup hook. 20268394ec8SAlexander V. Chernikov * Since we perform lazy initialization, do nothing except 20368394ec8SAlexander V. Chernikov * mutex init. 20468394ec8SAlexander V. Chernikov */ 20568394ec8SAlexander V. Chernikov int 20668394ec8SAlexander V. Chernikov ipfw_iface_init() 20768394ec8SAlexander V. Chernikov { 20868394ec8SAlexander V. Chernikov 20968394ec8SAlexander V. Chernikov mtx_init(&vnet_mtx, "IPFW ifhandler mtx", NULL, MTX_DEF); 2106b988f3aSAlexander V. Chernikov IPFW_ADD_SOPT_HANDLER(1, scodes); 21168394ec8SAlexander V. Chernikov return (0); 21268394ec8SAlexander V. Chernikov } 21368394ec8SAlexander V. Chernikov 21468394ec8SAlexander V. Chernikov /* 21568394ec8SAlexander V. Chernikov * Global ipfw destroy hook. 21668394ec8SAlexander V. Chernikov * Unregister khandlers iff init has been done. 21768394ec8SAlexander V. Chernikov */ 21868394ec8SAlexander V. Chernikov void 21968394ec8SAlexander V. Chernikov ipfw_iface_destroy() 22068394ec8SAlexander V. Chernikov { 22168394ec8SAlexander V. Chernikov 2226b988f3aSAlexander V. Chernikov IPFW_DEL_SOPT_HANDLER(1, scodes); 22368394ec8SAlexander V. Chernikov mtx_destroy(&vnet_mtx); 22468394ec8SAlexander V. Chernikov } 22568394ec8SAlexander V. Chernikov 22668394ec8SAlexander V. Chernikov /* 22768394ec8SAlexander V. Chernikov * Perform actual init on internal request. 22868394ec8SAlexander V. Chernikov * Inits both namehash and global khandler. 22968394ec8SAlexander V. Chernikov */ 23068394ec8SAlexander V. Chernikov static void 23168394ec8SAlexander V. Chernikov vnet_ipfw_iface_init(struct ip_fw_chain *ch) 23268394ec8SAlexander V. Chernikov { 23368394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 23468394ec8SAlexander V. Chernikov 23568394ec8SAlexander V. Chernikov ii = ipfw_objhash_create(DEFAULT_IFACES); 23668394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 23768394ec8SAlexander V. Chernikov if (ch->ifcfg == NULL) { 23868394ec8SAlexander V. Chernikov ch->ifcfg = ii; 23968394ec8SAlexander V. Chernikov ii = NULL; 24068394ec8SAlexander V. Chernikov } 24168394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 24268394ec8SAlexander V. Chernikov 24368394ec8SAlexander V. Chernikov if (ii != NULL) { 24468394ec8SAlexander V. Chernikov /* Already initialized. Free namehash. */ 24568394ec8SAlexander V. Chernikov ipfw_objhash_destroy(ii); 24668394ec8SAlexander V. Chernikov } else { 24768394ec8SAlexander V. Chernikov /* We're the first ones. Init kernel hooks. */ 24868394ec8SAlexander V. Chernikov iface_khandler_register(); 24968394ec8SAlexander V. Chernikov } 25068394ec8SAlexander V. Chernikov } 25168394ec8SAlexander V. Chernikov 25268394ec8SAlexander V. Chernikov static void 25368394ec8SAlexander V. Chernikov destroy_iface(struct namedobj_instance *ii, struct named_object *no, 25468394ec8SAlexander V. Chernikov void *arg) 25568394ec8SAlexander V. Chernikov { 25668394ec8SAlexander V. Chernikov 25768394ec8SAlexander V. Chernikov /* Assume all consumers have been already detached */ 25898eff10eSAlexander V. Chernikov free(no, M_IPFW); 25968394ec8SAlexander V. Chernikov } 26068394ec8SAlexander V. Chernikov 26168394ec8SAlexander V. Chernikov /* 26268394ec8SAlexander V. Chernikov * Per-VNET ipfw detach hook. 26368394ec8SAlexander V. Chernikov * 26468394ec8SAlexander V. Chernikov */ 26568394ec8SAlexander V. Chernikov void 26668394ec8SAlexander V. Chernikov vnet_ipfw_iface_destroy(struct ip_fw_chain *ch) 26768394ec8SAlexander V. Chernikov { 26868394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 26968394ec8SAlexander V. Chernikov 27068394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 27168394ec8SAlexander V. Chernikov ii = CHAIN_TO_II(ch); 27268394ec8SAlexander V. Chernikov ch->ifcfg = NULL; 27368394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 27468394ec8SAlexander V. Chernikov 27568394ec8SAlexander V. Chernikov if (ii != NULL) { 27668394ec8SAlexander V. Chernikov ipfw_objhash_foreach(ii, destroy_iface, ch); 27768394ec8SAlexander V. Chernikov ipfw_objhash_destroy(ii); 27868394ec8SAlexander V. Chernikov iface_khandler_deregister(); 27968394ec8SAlexander V. Chernikov } 28068394ec8SAlexander V. Chernikov } 28168394ec8SAlexander V. Chernikov 28268394ec8SAlexander V. Chernikov /* 28368394ec8SAlexander V. Chernikov * Notify the subsystem that we are interested in tracking 28468394ec8SAlexander V. Chernikov * interface @name. This function has to be called without 28568394ec8SAlexander V. Chernikov * holding any locks to permit allocating the necessary states 28668394ec8SAlexander V. Chernikov * for proper interface tracking. 28768394ec8SAlexander V. Chernikov * 28868394ec8SAlexander V. Chernikov * Returns 0 on success. 28968394ec8SAlexander V. Chernikov */ 29068394ec8SAlexander V. Chernikov int 29168394ec8SAlexander V. Chernikov ipfw_iface_ref(struct ip_fw_chain *ch, char *name, 29268394ec8SAlexander V. Chernikov struct ipfw_ifc *ic) 29368394ec8SAlexander V. Chernikov { 29468394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 29568394ec8SAlexander V. Chernikov struct ipfw_iface *iif, *tmp; 29668394ec8SAlexander V. Chernikov 29768394ec8SAlexander V. Chernikov if (strlen(name) >= sizeof(iif->ifname)) 29868394ec8SAlexander V. Chernikov return (EINVAL); 29968394ec8SAlexander V. Chernikov 30068394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 30168394ec8SAlexander V. Chernikov 30268394ec8SAlexander V. Chernikov ii = CHAIN_TO_II(ch); 30368394ec8SAlexander V. Chernikov if (ii == NULL) { 30468394ec8SAlexander V. Chernikov 30568394ec8SAlexander V. Chernikov /* 30668394ec8SAlexander V. Chernikov * First request to subsystem. 30768394ec8SAlexander V. Chernikov * Let's perform init. 30868394ec8SAlexander V. Chernikov */ 30968394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 31068394ec8SAlexander V. Chernikov vnet_ipfw_iface_init(ch); 31168394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 31268394ec8SAlexander V. Chernikov ii = CHAIN_TO_II(ch); 31368394ec8SAlexander V. Chernikov } 31468394ec8SAlexander V. Chernikov 31568394ec8SAlexander V. Chernikov iif = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name); 31668394ec8SAlexander V. Chernikov 31768394ec8SAlexander V. Chernikov if (iif != NULL) { 31868394ec8SAlexander V. Chernikov iif->no.refcnt++; 31968394ec8SAlexander V. Chernikov ic->iface = iif; 32068394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 32168394ec8SAlexander V. Chernikov return (0); 32268394ec8SAlexander V. Chernikov } 32368394ec8SAlexander V. Chernikov 32468394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 32568394ec8SAlexander V. Chernikov 32668394ec8SAlexander V. Chernikov /* Not found. Let's create one */ 32768394ec8SAlexander V. Chernikov iif = malloc(sizeof(struct ipfw_iface), M_IPFW, M_WAITOK | M_ZERO); 32868394ec8SAlexander V. Chernikov TAILQ_INIT(&iif->consumers); 32968394ec8SAlexander V. Chernikov iif->no.name = iif->ifname; 33068394ec8SAlexander V. Chernikov strlcpy(iif->ifname, name, sizeof(iif->ifname)); 33168394ec8SAlexander V. Chernikov 33268394ec8SAlexander V. Chernikov /* 33368394ec8SAlexander V. Chernikov * Ref & link to the list. 33468394ec8SAlexander V. Chernikov * 33568394ec8SAlexander V. Chernikov * We assume ifnet_arrival_event / ifnet_departure_event 33668394ec8SAlexander V. Chernikov * are not holding any locks. 33768394ec8SAlexander V. Chernikov */ 33868394ec8SAlexander V. Chernikov iif->no.refcnt = 1; 33968394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 34068394ec8SAlexander V. Chernikov 34168394ec8SAlexander V. Chernikov tmp = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name); 34268394ec8SAlexander V. Chernikov if (tmp != NULL) { 34368394ec8SAlexander V. Chernikov /* Interface has been created since unlock. Ref and return */ 34468394ec8SAlexander V. Chernikov tmp->no.refcnt++; 34568394ec8SAlexander V. Chernikov ic->iface = tmp; 34668394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 34768394ec8SAlexander V. Chernikov free(iif, M_IPFW); 34868394ec8SAlexander V. Chernikov return (0); 34968394ec8SAlexander V. Chernikov } 35068394ec8SAlexander V. Chernikov 35168394ec8SAlexander V. Chernikov iif->ifindex = ipfw_kiflookup(name); 35268394ec8SAlexander V. Chernikov if (iif->ifindex != 0) 35368394ec8SAlexander V. Chernikov iif->resolved = 1; 35468394ec8SAlexander V. Chernikov 35568394ec8SAlexander V. Chernikov ipfw_objhash_add(ii, &iif->no); 35668394ec8SAlexander V. Chernikov ic->iface = iif; 35768394ec8SAlexander V. Chernikov 35868394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 35968394ec8SAlexander V. Chernikov 36068394ec8SAlexander V. Chernikov return (0); 36168394ec8SAlexander V. Chernikov } 36268394ec8SAlexander V. Chernikov 36368394ec8SAlexander V. Chernikov /* 36468394ec8SAlexander V. Chernikov * Adds @ic to the list of iif interface consumers. 36568394ec8SAlexander V. Chernikov * Must be called with holding both UH+WLOCK. 36668394ec8SAlexander V. Chernikov * Callback may be immediately called (if interface exists). 36768394ec8SAlexander V. Chernikov */ 36868394ec8SAlexander V. Chernikov void 36968394ec8SAlexander V. Chernikov ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 37068394ec8SAlexander V. Chernikov { 37168394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 37268394ec8SAlexander V. Chernikov 37368394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 37468394ec8SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 37568394ec8SAlexander V. Chernikov 37668394ec8SAlexander V. Chernikov iif = ic->iface; 37768394ec8SAlexander V. Chernikov 37868394ec8SAlexander V. Chernikov TAILQ_INSERT_TAIL(&iif->consumers, ic, next); 37968394ec8SAlexander V. Chernikov if (iif->resolved != 0) 38068394ec8SAlexander V. Chernikov ic->cb(ch, ic->cbdata, iif->ifindex); 38168394ec8SAlexander V. Chernikov } 38268394ec8SAlexander V. Chernikov 38368394ec8SAlexander V. Chernikov /* 38468394ec8SAlexander V. Chernikov * Unlinks interface tracker object @ic from interface. 38598eff10eSAlexander V. Chernikov * Must be called while holding UH lock. 38668394ec8SAlexander V. Chernikov */ 38768394ec8SAlexander V. Chernikov void 38868394ec8SAlexander V. Chernikov ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 38968394ec8SAlexander V. Chernikov { 39068394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 39168394ec8SAlexander V. Chernikov 39268394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 39368394ec8SAlexander V. Chernikov 39468394ec8SAlexander V. Chernikov iif = ic->iface; 39568394ec8SAlexander V. Chernikov if (ic->linked != 0) 39668394ec8SAlexander V. Chernikov TAILQ_REMOVE(&iif->consumers, ic, next); 39768394ec8SAlexander V. Chernikov } 39868394ec8SAlexander V. Chernikov 39968394ec8SAlexander V. Chernikov /* 40068394ec8SAlexander V. Chernikov * Unreference interface specified by @ic. 40168394ec8SAlexander V. Chernikov * Must be called without holding any locks. 40268394ec8SAlexander V. Chernikov */ 40368394ec8SAlexander V. Chernikov void 40468394ec8SAlexander V. Chernikov ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic) 40568394ec8SAlexander V. Chernikov { 40668394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 40768394ec8SAlexander V. Chernikov 40868394ec8SAlexander V. Chernikov iif = ic->iface; 40968394ec8SAlexander V. Chernikov ic->iface = NULL; 41068394ec8SAlexander V. Chernikov 41168394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 41268394ec8SAlexander V. Chernikov iif->no.refcnt--; 41368394ec8SAlexander V. Chernikov /* TODO: check for references & delete */ 41468394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 41568394ec8SAlexander V. Chernikov } 41668394ec8SAlexander V. Chernikov 41768394ec8SAlexander V. Chernikov /* 41868394ec8SAlexander V. Chernikov * Interface arrival handler. 41968394ec8SAlexander V. Chernikov */ 42068394ec8SAlexander V. Chernikov static void 42168394ec8SAlexander V. Chernikov handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 42268394ec8SAlexander V. Chernikov uint16_t ifindex) 42368394ec8SAlexander V. Chernikov { 42468394ec8SAlexander V. Chernikov struct ipfw_ifc *ic; 42568394ec8SAlexander V. Chernikov 42668394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 42768394ec8SAlexander V. Chernikov 42868394ec8SAlexander V. Chernikov iif->gencnt++; 42968394ec8SAlexander V. Chernikov iif->resolved = 1; 43068394ec8SAlexander V. Chernikov iif->ifindex = ifindex; 43168394ec8SAlexander V. Chernikov 43268394ec8SAlexander V. Chernikov IPFW_WLOCK(ch); 43368394ec8SAlexander V. Chernikov TAILQ_FOREACH(ic, &iif->consumers, next) 43468394ec8SAlexander V. Chernikov ic->cb(ch, ic->cbdata, iif->ifindex); 43568394ec8SAlexander V. Chernikov IPFW_WUNLOCK(ch); 43668394ec8SAlexander V. Chernikov } 43768394ec8SAlexander V. Chernikov 43868394ec8SAlexander V. Chernikov /* 43968394ec8SAlexander V. Chernikov * Interface departure handler. 44068394ec8SAlexander V. Chernikov */ 44168394ec8SAlexander V. Chernikov static void 44268394ec8SAlexander V. Chernikov handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif, 44368394ec8SAlexander V. Chernikov uint16_t ifindex) 44468394ec8SAlexander V. Chernikov { 44568394ec8SAlexander V. Chernikov struct ipfw_ifc *ic; 44668394ec8SAlexander V. Chernikov 44768394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 44868394ec8SAlexander V. Chernikov 44968394ec8SAlexander V. Chernikov IPFW_WLOCK(ch); 45068394ec8SAlexander V. Chernikov TAILQ_FOREACH(ic, &iif->consumers, next) 45168394ec8SAlexander V. Chernikov ic->cb(ch, ic->cbdata, 0); 45268394ec8SAlexander V. Chernikov IPFW_WUNLOCK(ch); 45368394ec8SAlexander V. Chernikov 45468394ec8SAlexander V. Chernikov iif->gencnt++; 45568394ec8SAlexander V. Chernikov iif->resolved = 0; 45668394ec8SAlexander V. Chernikov iif->ifindex = 0; 45768394ec8SAlexander V. Chernikov } 45868394ec8SAlexander V. Chernikov 45968394ec8SAlexander V. Chernikov struct dump_iface_args { 46068394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 46168394ec8SAlexander V. Chernikov struct sockopt_data *sd; 46268394ec8SAlexander V. Chernikov }; 46368394ec8SAlexander V. Chernikov 46468394ec8SAlexander V. Chernikov static void 46568394ec8SAlexander V. Chernikov export_iface_internal(struct namedobj_instance *ii, struct named_object *no, 46668394ec8SAlexander V. Chernikov void *arg) 46768394ec8SAlexander V. Chernikov { 46868394ec8SAlexander V. Chernikov ipfw_iface_info *i; 46968394ec8SAlexander V. Chernikov struct dump_iface_args *da; 47068394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 47168394ec8SAlexander V. Chernikov 47268394ec8SAlexander V. Chernikov da = (struct dump_iface_args *)arg; 47368394ec8SAlexander V. Chernikov 47468394ec8SAlexander V. Chernikov i = (ipfw_iface_info *)ipfw_get_sopt_space(da->sd, sizeof(*i)); 47568394ec8SAlexander V. Chernikov KASSERT(i != 0, ("previously checked buffer is not enough")); 47668394ec8SAlexander V. Chernikov 47768394ec8SAlexander V. Chernikov iif = (struct ipfw_iface *)no; 47868394ec8SAlexander V. Chernikov 47968394ec8SAlexander V. Chernikov strlcpy(i->ifname, iif->ifname, sizeof(i->ifname)); 48068394ec8SAlexander V. Chernikov if (iif->resolved) 48168394ec8SAlexander V. Chernikov i->flags |= IPFW_IFFLAG_RESOLVED; 48268394ec8SAlexander V. Chernikov i->ifindex = iif->ifindex; 48368394ec8SAlexander V. Chernikov i->refcnt = iif->no.refcnt; 48468394ec8SAlexander V. Chernikov i->gencnt = iif->gencnt; 48568394ec8SAlexander V. Chernikov } 48668394ec8SAlexander V. Chernikov 48768394ec8SAlexander V. Chernikov /* 48868394ec8SAlexander V. Chernikov * Lists all interface currently tracked by ipfw. 48968394ec8SAlexander V. Chernikov * Data layout (v0)(current): 49068394ec8SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 49168394ec8SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_iface_info x N ] 49268394ec8SAlexander V. Chernikov * 49368394ec8SAlexander V. Chernikov * Returns 0 on success 49468394ec8SAlexander V. Chernikov */ 4956b988f3aSAlexander V. Chernikov static int 4966b988f3aSAlexander V. Chernikov list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 497e822d936SAlexander V. Chernikov struct sockopt_data *sd) 49868394ec8SAlexander V. Chernikov { 49935d5a820SAlexander V. Chernikov struct namedobj_instance *ii; 50068394ec8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 50168394ec8SAlexander V. Chernikov struct dump_iface_args da; 50268394ec8SAlexander V. Chernikov uint32_t count, size; 50368394ec8SAlexander V. Chernikov 50468394ec8SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 50568394ec8SAlexander V. Chernikov if (olh == NULL) 50668394ec8SAlexander V. Chernikov return (EINVAL); 50768394ec8SAlexander V. Chernikov if (sd->valsize < olh->size) 50868394ec8SAlexander V. Chernikov return (EINVAL); 50968394ec8SAlexander V. Chernikov 51068394ec8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 51135d5a820SAlexander V. Chernikov ii = CHAIN_TO_II(ch); 51235d5a820SAlexander V. Chernikov if (ii != NULL) 51335d5a820SAlexander V. Chernikov count = ipfw_objhash_count(ii); 51435d5a820SAlexander V. Chernikov else 51535d5a820SAlexander V. Chernikov count = 0; 51668394ec8SAlexander V. Chernikov size = count * sizeof(ipfw_iface_info) + sizeof(ipfw_obj_lheader); 51768394ec8SAlexander V. Chernikov 51868394ec8SAlexander V. Chernikov /* Fill in header regadless of buffer size */ 51968394ec8SAlexander V. Chernikov olh->count = count; 52068394ec8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_iface_info); 52168394ec8SAlexander V. Chernikov 52268394ec8SAlexander V. Chernikov if (size > olh->size) { 52368394ec8SAlexander V. Chernikov olh->size = size; 52468394ec8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 52568394ec8SAlexander V. Chernikov return (ENOMEM); 52668394ec8SAlexander V. Chernikov } 52768394ec8SAlexander V. Chernikov olh->size = size; 52868394ec8SAlexander V. Chernikov 52968394ec8SAlexander V. Chernikov da.ch = ch; 53068394ec8SAlexander V. Chernikov da.sd = sd; 53168394ec8SAlexander V. Chernikov 53235d5a820SAlexander V. Chernikov if (ii != NULL) 53335d5a820SAlexander V. Chernikov ipfw_objhash_foreach(ii, export_iface_internal, &da); 53468394ec8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 53568394ec8SAlexander V. Chernikov 53668394ec8SAlexander V. Chernikov return (0); 53768394ec8SAlexander V. Chernikov } 53868394ec8SAlexander V. Chernikov 539