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 /*
2868394ec8SAlexander V. Chernikov * Kernel interface tracking API.
2968394ec8SAlexander V. Chernikov *
3068394ec8SAlexander V. Chernikov */
3168394ec8SAlexander V. Chernikov
3268394ec8SAlexander V. Chernikov #include "opt_ipfw.h"
3368394ec8SAlexander V. Chernikov #include "opt_inet.h"
3468394ec8SAlexander V. Chernikov #ifndef INET
3568394ec8SAlexander V. Chernikov #error IPFIREWALL requires INET.
3668394ec8SAlexander V. Chernikov #endif /* INET */
3768394ec8SAlexander V. Chernikov #include "opt_inet6.h"
3868394ec8SAlexander V. Chernikov
3968394ec8SAlexander V. Chernikov #include <sys/param.h>
4068394ec8SAlexander V. Chernikov #include <sys/systm.h>
4168394ec8SAlexander V. Chernikov #include <sys/malloc.h>
4268394ec8SAlexander V. Chernikov #include <sys/kernel.h>
4368394ec8SAlexander V. Chernikov #include <sys/lock.h>
4468394ec8SAlexander V. Chernikov #include <sys/rwlock.h>
45ccba94b8SAlexander V. Chernikov #include <sys/rmlock.h>
4668394ec8SAlexander V. Chernikov #include <sys/socket.h>
4768394ec8SAlexander V. Chernikov #include <sys/queue.h>
4868394ec8SAlexander V. Chernikov #include <sys/eventhandler.h>
4968394ec8SAlexander V. Chernikov #include <net/if.h>
5068394ec8SAlexander V. Chernikov #include <net/if_var.h>
51*3d0d5b21SJustin Hibbits #include <net/if_private.h>
5268394ec8SAlexander V. Chernikov #include <net/vnet.h>
5368394ec8SAlexander V. Chernikov
5468394ec8SAlexander V. Chernikov #include <netinet/in.h>
5568394ec8SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */
5668394ec8SAlexander V. Chernikov #include <netinet/ip_fw.h>
5768394ec8SAlexander V. Chernikov
5868394ec8SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h>
5968394ec8SAlexander V. Chernikov
6068394ec8SAlexander V. Chernikov #define CHAIN_TO_II(ch) ((struct namedobj_instance *)ch->ifcfg)
6168394ec8SAlexander V. Chernikov
6268394ec8SAlexander V. Chernikov #define DEFAULT_IFACES 128
6368394ec8SAlexander V. Chernikov
6468394ec8SAlexander V. Chernikov static void handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
6568394ec8SAlexander V. Chernikov uint16_t ifindex);
6668394ec8SAlexander V. Chernikov static void handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
6768394ec8SAlexander V. Chernikov uint16_t ifindex);
686b988f3aSAlexander V. Chernikov static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
696b988f3aSAlexander V. Chernikov struct sockopt_data *sd);
706b988f3aSAlexander V. Chernikov
716b988f3aSAlexander V. Chernikov static struct ipfw_sopt_handler scodes[] = {
726b988f3aSAlexander V. Chernikov { IP_FW_XIFLIST, 0, HDIR_GET, list_ifaces },
736b988f3aSAlexander V. Chernikov };
7468394ec8SAlexander V. Chernikov
7568394ec8SAlexander V. Chernikov /*
7668394ec8SAlexander V. Chernikov * FreeBSD Kernel interface.
7768394ec8SAlexander V. Chernikov */
7868394ec8SAlexander V. Chernikov static void ipfw_kifhandler(void *arg, struct ifnet *ifp);
7968394ec8SAlexander V. Chernikov static int ipfw_kiflookup(char *name);
8068394ec8SAlexander V. Chernikov static void iface_khandler_register(void);
8168394ec8SAlexander V. Chernikov static void iface_khandler_deregister(void);
8268394ec8SAlexander V. Chernikov
8368394ec8SAlexander V. Chernikov static eventhandler_tag ipfw_ifdetach_event, ipfw_ifattach_event;
8468394ec8SAlexander V. Chernikov static int num_vnets = 0;
8598eff10eSAlexander V. Chernikov static struct mtx vnet_mtx;
8668394ec8SAlexander V. Chernikov
8768394ec8SAlexander V. Chernikov /*
8868394ec8SAlexander V. Chernikov * Checks if kernel interface is contained in our tracked
8968394ec8SAlexander V. Chernikov * interface list and calls attach/detach handler.
9068394ec8SAlexander V. Chernikov */
9168394ec8SAlexander V. Chernikov static void
ipfw_kifhandler(void * arg,struct ifnet * ifp)9268394ec8SAlexander V. Chernikov ipfw_kifhandler(void *arg, struct ifnet *ifp)
9368394ec8SAlexander V. Chernikov {
9468394ec8SAlexander V. Chernikov struct ip_fw_chain *ch;
9568394ec8SAlexander V. Chernikov struct ipfw_iface *iif;
9668394ec8SAlexander V. Chernikov struct namedobj_instance *ii;
9768394ec8SAlexander V. Chernikov uintptr_t htype;
9868394ec8SAlexander V. Chernikov
9998eff10eSAlexander V. Chernikov if (V_ipfw_vnet_ready == 0)
10098eff10eSAlexander V. Chernikov return;
10198eff10eSAlexander V. Chernikov
10268394ec8SAlexander V. Chernikov ch = &V_layer3_chain;
10368394ec8SAlexander V. Chernikov htype = (uintptr_t)arg;
10468394ec8SAlexander V. Chernikov
10568394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch);
10668394ec8SAlexander V. Chernikov ii = CHAIN_TO_II(ch);
10768394ec8SAlexander V. Chernikov if (ii == NULL) {
10868394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
10968394ec8SAlexander V. Chernikov return;
11068394ec8SAlexander V. Chernikov }
11198eff10eSAlexander V. Chernikov iif = (struct ipfw_iface*)ipfw_objhash_lookup_name(ii, 0,
11298eff10eSAlexander V. Chernikov if_name(ifp));
11368394ec8SAlexander V. Chernikov if (iif != NULL) {
11468394ec8SAlexander V. Chernikov if (htype == 1)
11568394ec8SAlexander V. Chernikov handle_ifattach(ch, iif, ifp->if_index);
11668394ec8SAlexander V. Chernikov else
11768394ec8SAlexander V. Chernikov handle_ifdetach(ch, iif, ifp->if_index);
11868394ec8SAlexander V. Chernikov }
11968394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
12068394ec8SAlexander V. Chernikov }
12168394ec8SAlexander V. Chernikov
12268394ec8SAlexander V. Chernikov /*
12368394ec8SAlexander V. Chernikov * Reference current VNET as iface tracking API user.
12468394ec8SAlexander V. Chernikov * Registers interface tracking handlers for first VNET.
12568394ec8SAlexander V. Chernikov */
12668394ec8SAlexander V. Chernikov static void
iface_khandler_register(void)127edf1e1f7SDimitry Andric iface_khandler_register(void)
12868394ec8SAlexander V. Chernikov {
12968394ec8SAlexander V. Chernikov int create;
13068394ec8SAlexander V. Chernikov
13168394ec8SAlexander V. Chernikov create = 0;
13268394ec8SAlexander V. Chernikov
13368394ec8SAlexander V. Chernikov mtx_lock(&vnet_mtx);
13468394ec8SAlexander V. Chernikov if (num_vnets == 0)
13568394ec8SAlexander V. Chernikov create = 1;
13668394ec8SAlexander V. Chernikov num_vnets++;
13768394ec8SAlexander V. Chernikov mtx_unlock(&vnet_mtx);
13868394ec8SAlexander V. Chernikov
13968394ec8SAlexander V. Chernikov if (create == 0)
14068394ec8SAlexander V. Chernikov return;
14168394ec8SAlexander V. Chernikov
14268394ec8SAlexander V. Chernikov printf("IPFW: starting up interface tracker\n");
14368394ec8SAlexander V. Chernikov
14468394ec8SAlexander V. Chernikov ipfw_ifdetach_event = EVENTHANDLER_REGISTER(
14568394ec8SAlexander V. Chernikov ifnet_departure_event, ipfw_kifhandler, NULL,
14668394ec8SAlexander V. Chernikov EVENTHANDLER_PRI_ANY);
14768394ec8SAlexander V. Chernikov ipfw_ifattach_event = EVENTHANDLER_REGISTER(
14868394ec8SAlexander V. Chernikov ifnet_arrival_event, ipfw_kifhandler, (void*)((uintptr_t)1),
14968394ec8SAlexander V. Chernikov EVENTHANDLER_PRI_ANY);
15068394ec8SAlexander V. Chernikov }
15168394ec8SAlexander V. Chernikov
15268394ec8SAlexander V. Chernikov /*
15368394ec8SAlexander V. Chernikov *
15468394ec8SAlexander V. Chernikov * Detach interface event handlers on last VNET instance
15568394ec8SAlexander V. Chernikov * detach.
15668394ec8SAlexander V. Chernikov */
15768394ec8SAlexander V. Chernikov static void
iface_khandler_deregister(void)1584100dc46SDimitry Andric iface_khandler_deregister(void)
15968394ec8SAlexander V. Chernikov {
16068394ec8SAlexander V. Chernikov int destroy;
16168394ec8SAlexander V. Chernikov
16268394ec8SAlexander V. Chernikov destroy = 0;
16368394ec8SAlexander V. Chernikov mtx_lock(&vnet_mtx);
16498eff10eSAlexander V. Chernikov if (num_vnets == 1)
16568394ec8SAlexander V. Chernikov destroy = 1;
16698eff10eSAlexander V. Chernikov num_vnets--;
16768394ec8SAlexander V. Chernikov mtx_unlock(&vnet_mtx);
16868394ec8SAlexander V. Chernikov
16968394ec8SAlexander V. Chernikov if (destroy == 0)
17068394ec8SAlexander V. Chernikov return;
17168394ec8SAlexander V. Chernikov
17268394ec8SAlexander V. Chernikov EVENTHANDLER_DEREGISTER(ifnet_arrival_event,
17368394ec8SAlexander V. Chernikov ipfw_ifattach_event);
17468394ec8SAlexander V. Chernikov EVENTHANDLER_DEREGISTER(ifnet_departure_event,
17568394ec8SAlexander V. Chernikov ipfw_ifdetach_event);
17668394ec8SAlexander V. Chernikov }
17768394ec8SAlexander V. Chernikov
17868394ec8SAlexander V. Chernikov /*
17968394ec8SAlexander V. Chernikov * Retrieves ifindex for given @name.
18068394ec8SAlexander V. Chernikov *
18168394ec8SAlexander V. Chernikov * Returns ifindex or 0.
18268394ec8SAlexander V. Chernikov */
18368394ec8SAlexander V. Chernikov static int
ipfw_kiflookup(char * name)18468394ec8SAlexander V. Chernikov ipfw_kiflookup(char *name)
18568394ec8SAlexander V. Chernikov {
18668394ec8SAlexander V. Chernikov struct ifnet *ifp;
18768394ec8SAlexander V. Chernikov int ifindex;
18868394ec8SAlexander V. Chernikov
18968394ec8SAlexander V. Chernikov ifindex = 0;
19068394ec8SAlexander V. Chernikov
19168394ec8SAlexander V. Chernikov if ((ifp = ifunit_ref(name)) != NULL) {
19268394ec8SAlexander V. Chernikov ifindex = ifp->if_index;
19368394ec8SAlexander V. Chernikov if_rele(ifp);
19468394ec8SAlexander V. Chernikov }
19568394ec8SAlexander V. Chernikov
19668394ec8SAlexander V. Chernikov return (ifindex);
19768394ec8SAlexander V. Chernikov }
19868394ec8SAlexander V. Chernikov
19968394ec8SAlexander V. Chernikov /*
20068394ec8SAlexander V. Chernikov * Global ipfw startup hook.
20168394ec8SAlexander V. Chernikov * Since we perform lazy initialization, do nothing except
20268394ec8SAlexander V. Chernikov * mutex init.
20368394ec8SAlexander V. Chernikov */
20468394ec8SAlexander V. Chernikov int
ipfw_iface_init(void)2051eea6b90SDimitry Andric ipfw_iface_init(void)
20668394ec8SAlexander V. Chernikov {
20768394ec8SAlexander V. Chernikov
20868394ec8SAlexander V. Chernikov mtx_init(&vnet_mtx, "IPFW ifhandler mtx", NULL, MTX_DEF);
2096b988f3aSAlexander V. Chernikov IPFW_ADD_SOPT_HANDLER(1, scodes);
21068394ec8SAlexander V. Chernikov return (0);
21168394ec8SAlexander V. Chernikov }
21268394ec8SAlexander V. Chernikov
21368394ec8SAlexander V. Chernikov /*
21468394ec8SAlexander V. Chernikov * Global ipfw destroy hook.
21568394ec8SAlexander V. Chernikov * Unregister khandlers iff init has been done.
21668394ec8SAlexander V. Chernikov */
21768394ec8SAlexander V. Chernikov void
ipfw_iface_destroy(void)2181eea6b90SDimitry Andric ipfw_iface_destroy(void)
21968394ec8SAlexander V. Chernikov {
22068394ec8SAlexander V. Chernikov
2216b988f3aSAlexander V. Chernikov IPFW_DEL_SOPT_HANDLER(1, scodes);
22268394ec8SAlexander V. Chernikov mtx_destroy(&vnet_mtx);
22368394ec8SAlexander V. Chernikov }
22468394ec8SAlexander V. Chernikov
22568394ec8SAlexander V. Chernikov /*
22668394ec8SAlexander V. Chernikov * Perform actual init on internal request.
22768394ec8SAlexander V. Chernikov * Inits both namehash and global khandler.
22868394ec8SAlexander V. Chernikov */
22968394ec8SAlexander V. Chernikov static void
vnet_ipfw_iface_init(struct ip_fw_chain * ch)23068394ec8SAlexander V. Chernikov vnet_ipfw_iface_init(struct ip_fw_chain *ch)
23168394ec8SAlexander V. Chernikov {
23268394ec8SAlexander V. Chernikov struct namedobj_instance *ii;
23368394ec8SAlexander V. Chernikov
23468394ec8SAlexander V. Chernikov ii = ipfw_objhash_create(DEFAULT_IFACES);
23568394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch);
23668394ec8SAlexander V. Chernikov if (ch->ifcfg == NULL) {
23768394ec8SAlexander V. Chernikov ch->ifcfg = ii;
23868394ec8SAlexander V. Chernikov ii = NULL;
23968394ec8SAlexander V. Chernikov }
24068394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
24168394ec8SAlexander V. Chernikov
24268394ec8SAlexander V. Chernikov if (ii != NULL) {
24368394ec8SAlexander V. Chernikov /* Already initialized. Free namehash. */
24468394ec8SAlexander V. Chernikov ipfw_objhash_destroy(ii);
24568394ec8SAlexander V. Chernikov } else {
24668394ec8SAlexander V. Chernikov /* We're the first ones. Init kernel hooks. */
24768394ec8SAlexander V. Chernikov iface_khandler_register();
24868394ec8SAlexander V. Chernikov }
24968394ec8SAlexander V. Chernikov }
25068394ec8SAlexander V. Chernikov
251b309f085SAndrey V. Elsukov static int
destroy_iface(struct namedobj_instance * ii,struct named_object * no,void * arg)25268394ec8SAlexander V. Chernikov destroy_iface(struct namedobj_instance *ii, struct named_object *no,
25368394ec8SAlexander V. Chernikov void *arg)
25468394ec8SAlexander V. Chernikov {
25568394ec8SAlexander V. Chernikov
25668394ec8SAlexander V. Chernikov /* Assume all consumers have been already detached */
25798eff10eSAlexander V. Chernikov free(no, M_IPFW);
258b309f085SAndrey V. Elsukov return (0);
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
vnet_ipfw_iface_destroy(struct ip_fw_chain * ch)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
ipfw_iface_ref(struct ip_fw_chain * ch,char * name,struct ipfw_ifc * ic)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 * First request to subsystem.
30668394ec8SAlexander V. Chernikov * Let's perform init.
30768394ec8SAlexander V. Chernikov */
30868394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
30968394ec8SAlexander V. Chernikov vnet_ipfw_iface_init(ch);
31068394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch);
31168394ec8SAlexander V. Chernikov ii = CHAIN_TO_II(ch);
31268394ec8SAlexander V. Chernikov }
31368394ec8SAlexander V. Chernikov
31468394ec8SAlexander V. Chernikov iif = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name);
31568394ec8SAlexander V. Chernikov
31668394ec8SAlexander V. Chernikov if (iif != NULL) {
31768394ec8SAlexander V. Chernikov iif->no.refcnt++;
31868394ec8SAlexander V. Chernikov ic->iface = iif;
31968394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
32068394ec8SAlexander V. Chernikov return (0);
32168394ec8SAlexander V. Chernikov }
32268394ec8SAlexander V. Chernikov
32368394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
32468394ec8SAlexander V. Chernikov
32568394ec8SAlexander V. Chernikov /* Not found. Let's create one */
32668394ec8SAlexander V. Chernikov iif = malloc(sizeof(struct ipfw_iface), M_IPFW, M_WAITOK | M_ZERO);
32768394ec8SAlexander V. Chernikov TAILQ_INIT(&iif->consumers);
32868394ec8SAlexander V. Chernikov iif->no.name = iif->ifname;
32968394ec8SAlexander V. Chernikov strlcpy(iif->ifname, name, sizeof(iif->ifname));
33068394ec8SAlexander V. Chernikov
33168394ec8SAlexander V. Chernikov /*
33268394ec8SAlexander V. Chernikov * Ref & link to the list.
33368394ec8SAlexander V. Chernikov *
33468394ec8SAlexander V. Chernikov * We assume ifnet_arrival_event / ifnet_departure_event
33568394ec8SAlexander V. Chernikov * are not holding any locks.
33668394ec8SAlexander V. Chernikov */
33768394ec8SAlexander V. Chernikov iif->no.refcnt = 1;
33868394ec8SAlexander V. Chernikov IPFW_UH_WLOCK(ch);
33968394ec8SAlexander V. Chernikov
34068394ec8SAlexander V. Chernikov tmp = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name);
34168394ec8SAlexander V. Chernikov if (tmp != NULL) {
34268394ec8SAlexander V. Chernikov /* Interface has been created since unlock. Ref and return */
34368394ec8SAlexander V. Chernikov tmp->no.refcnt++;
34468394ec8SAlexander V. Chernikov ic->iface = tmp;
34568394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
34668394ec8SAlexander V. Chernikov free(iif, M_IPFW);
34768394ec8SAlexander V. Chernikov return (0);
34868394ec8SAlexander V. Chernikov }
34968394ec8SAlexander V. Chernikov
35068394ec8SAlexander V. Chernikov iif->ifindex = ipfw_kiflookup(name);
35168394ec8SAlexander V. Chernikov if (iif->ifindex != 0)
35268394ec8SAlexander V. Chernikov iif->resolved = 1;
35368394ec8SAlexander V. Chernikov
35468394ec8SAlexander V. Chernikov ipfw_objhash_add(ii, &iif->no);
35568394ec8SAlexander V. Chernikov ic->iface = iif;
35668394ec8SAlexander V. Chernikov
35768394ec8SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
35868394ec8SAlexander V. Chernikov
35968394ec8SAlexander V. Chernikov return (0);
36068394ec8SAlexander V. Chernikov }
36168394ec8SAlexander V. Chernikov
36268394ec8SAlexander V. Chernikov /*
36368394ec8SAlexander V. Chernikov * Adds @ic to the list of iif interface consumers.
36468394ec8SAlexander V. Chernikov * Must be called with holding both UH+WLOCK.
36568394ec8SAlexander V. Chernikov * Callback may be immediately called (if interface exists).
36668394ec8SAlexander V. Chernikov */
36768394ec8SAlexander V. Chernikov void
ipfw_iface_add_notify(struct ip_fw_chain * ch,struct ipfw_ifc * ic)36868394ec8SAlexander V. Chernikov ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic)
36968394ec8SAlexander V. Chernikov {
37068394ec8SAlexander V. Chernikov struct ipfw_iface *iif;
37168394ec8SAlexander V. Chernikov
37268394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch);
37368394ec8SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch);
37468394ec8SAlexander V. Chernikov
37568394ec8SAlexander V. Chernikov iif = ic->iface;
37668394ec8SAlexander V. Chernikov
37768394ec8SAlexander V. Chernikov TAILQ_INSERT_TAIL(&iif->consumers, ic, next);
37868394ec8SAlexander V. Chernikov if (iif->resolved != 0)
37968394ec8SAlexander V. Chernikov ic->cb(ch, ic->cbdata, iif->ifindex);
38068394ec8SAlexander V. Chernikov }
38168394ec8SAlexander V. Chernikov
38268394ec8SAlexander V. Chernikov /*
38368394ec8SAlexander V. Chernikov * Unlinks interface tracker object @ic from interface.
38498eff10eSAlexander V. Chernikov * Must be called while holding UH lock.
38568394ec8SAlexander V. Chernikov */
38668394ec8SAlexander V. Chernikov void
ipfw_iface_del_notify(struct ip_fw_chain * ch,struct ipfw_ifc * ic)38768394ec8SAlexander V. Chernikov ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic)
38868394ec8SAlexander V. Chernikov {
38968394ec8SAlexander V. Chernikov struct ipfw_iface *iif;
39068394ec8SAlexander V. Chernikov
39168394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch);
39268394ec8SAlexander V. Chernikov
39368394ec8SAlexander V. Chernikov iif = ic->iface;
39468394ec8SAlexander V. Chernikov TAILQ_REMOVE(&iif->consumers, ic, next);
39568394ec8SAlexander V. Chernikov }
39668394ec8SAlexander V. Chernikov
39768394ec8SAlexander V. Chernikov /*
39868394ec8SAlexander V. Chernikov * Unreference interface specified by @ic.
3990caab009SAlexander V. Chernikov * Must be called while holding UH lock.
40068394ec8SAlexander V. Chernikov */
40168394ec8SAlexander V. Chernikov void
ipfw_iface_unref(struct ip_fw_chain * ch,struct ipfw_ifc * ic)40268394ec8SAlexander V. Chernikov ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic)
40368394ec8SAlexander V. Chernikov {
40468394ec8SAlexander V. Chernikov struct ipfw_iface *iif;
40568394ec8SAlexander V. Chernikov
4060caab009SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch);
4070caab009SAlexander V. Chernikov
40868394ec8SAlexander V. Chernikov iif = ic->iface;
40968394ec8SAlexander V. Chernikov ic->iface = NULL;
41068394ec8SAlexander V. Chernikov
41168394ec8SAlexander V. Chernikov iif->no.refcnt--;
41268394ec8SAlexander V. Chernikov /* TODO: check for references & delete */
41368394ec8SAlexander V. Chernikov }
41468394ec8SAlexander V. Chernikov
41568394ec8SAlexander V. Chernikov /*
41668394ec8SAlexander V. Chernikov * Interface arrival handler.
41768394ec8SAlexander V. Chernikov */
41868394ec8SAlexander V. Chernikov static void
handle_ifattach(struct ip_fw_chain * ch,struct ipfw_iface * iif,uint16_t ifindex)41968394ec8SAlexander V. Chernikov handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
42068394ec8SAlexander V. Chernikov uint16_t ifindex)
42168394ec8SAlexander V. Chernikov {
42268394ec8SAlexander V. Chernikov struct ipfw_ifc *ic;
42368394ec8SAlexander V. Chernikov
42468394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch);
42568394ec8SAlexander V. Chernikov
42668394ec8SAlexander V. Chernikov iif->gencnt++;
42768394ec8SAlexander V. Chernikov iif->resolved = 1;
42868394ec8SAlexander V. Chernikov iif->ifindex = ifindex;
42968394ec8SAlexander V. Chernikov
43068394ec8SAlexander V. Chernikov IPFW_WLOCK(ch);
43168394ec8SAlexander V. Chernikov TAILQ_FOREACH(ic, &iif->consumers, next)
43268394ec8SAlexander V. Chernikov ic->cb(ch, ic->cbdata, iif->ifindex);
43368394ec8SAlexander V. Chernikov IPFW_WUNLOCK(ch);
43468394ec8SAlexander V. Chernikov }
43568394ec8SAlexander V. Chernikov
43668394ec8SAlexander V. Chernikov /*
43768394ec8SAlexander V. Chernikov * Interface departure handler.
43868394ec8SAlexander V. Chernikov */
43968394ec8SAlexander V. Chernikov static void
handle_ifdetach(struct ip_fw_chain * ch,struct ipfw_iface * iif,uint16_t ifindex)44068394ec8SAlexander V. Chernikov handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
44168394ec8SAlexander V. Chernikov uint16_t ifindex)
44268394ec8SAlexander V. Chernikov {
44368394ec8SAlexander V. Chernikov struct ipfw_ifc *ic;
44468394ec8SAlexander V. Chernikov
44568394ec8SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch);
44668394ec8SAlexander V. Chernikov
44768394ec8SAlexander V. Chernikov IPFW_WLOCK(ch);
44868394ec8SAlexander V. Chernikov TAILQ_FOREACH(ic, &iif->consumers, next)
44968394ec8SAlexander V. Chernikov ic->cb(ch, ic->cbdata, 0);
45068394ec8SAlexander V. Chernikov IPFW_WUNLOCK(ch);
45168394ec8SAlexander V. Chernikov
45268394ec8SAlexander V. Chernikov iif->gencnt++;
45368394ec8SAlexander V. Chernikov iif->resolved = 0;
45468394ec8SAlexander V. Chernikov iif->ifindex = 0;
45568394ec8SAlexander V. Chernikov }
45668394ec8SAlexander V. Chernikov
45768394ec8SAlexander V. Chernikov struct dump_iface_args {
45868394ec8SAlexander V. Chernikov struct ip_fw_chain *ch;
45968394ec8SAlexander V. Chernikov struct sockopt_data *sd;
46068394ec8SAlexander V. Chernikov };
46168394ec8SAlexander V. Chernikov
462b309f085SAndrey V. Elsukov static int
export_iface_internal(struct namedobj_instance * ii,struct named_object * no,void * arg)46368394ec8SAlexander V. Chernikov export_iface_internal(struct namedobj_instance *ii, struct named_object *no,
46468394ec8SAlexander V. Chernikov void *arg)
46568394ec8SAlexander V. Chernikov {
46668394ec8SAlexander V. Chernikov ipfw_iface_info *i;
46768394ec8SAlexander V. Chernikov struct dump_iface_args *da;
46868394ec8SAlexander V. Chernikov struct ipfw_iface *iif;
46968394ec8SAlexander V. Chernikov
47068394ec8SAlexander V. Chernikov da = (struct dump_iface_args *)arg;
47168394ec8SAlexander V. Chernikov
47268394ec8SAlexander V. Chernikov i = (ipfw_iface_info *)ipfw_get_sopt_space(da->sd, sizeof(*i));
4737a6ab8f1SPedro F. Giffuni KASSERT(i != NULL, ("previously checked buffer is not enough"));
47468394ec8SAlexander V. Chernikov
47568394ec8SAlexander V. Chernikov iif = (struct ipfw_iface *)no;
47668394ec8SAlexander V. Chernikov
47768394ec8SAlexander V. Chernikov strlcpy(i->ifname, iif->ifname, sizeof(i->ifname));
47868394ec8SAlexander V. Chernikov if (iif->resolved)
47968394ec8SAlexander V. Chernikov i->flags |= IPFW_IFFLAG_RESOLVED;
48068394ec8SAlexander V. Chernikov i->ifindex = iif->ifindex;
48168394ec8SAlexander V. Chernikov i->refcnt = iif->no.refcnt;
48268394ec8SAlexander V. Chernikov i->gencnt = iif->gencnt;
483b309f085SAndrey V. Elsukov return (0);
48468394ec8SAlexander V. Chernikov }
48568394ec8SAlexander V. Chernikov
48668394ec8SAlexander V. Chernikov /*
48768394ec8SAlexander V. Chernikov * Lists all interface currently tracked by ipfw.
48868394ec8SAlexander V. Chernikov * Data layout (v0)(current):
48968394ec8SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
49068394ec8SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_iface_info x N ]
49168394ec8SAlexander V. Chernikov *
49268394ec8SAlexander V. Chernikov * Returns 0 on success
49368394ec8SAlexander V. Chernikov */
4946b988f3aSAlexander V. Chernikov static int
list_ifaces(struct ip_fw_chain * ch,ip_fw3_opheader * op3,struct sockopt_data * sd)4956b988f3aSAlexander V. Chernikov list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
496e822d936SAlexander V. Chernikov struct sockopt_data *sd)
49768394ec8SAlexander V. Chernikov {
49835d5a820SAlexander V. Chernikov struct namedobj_instance *ii;
49968394ec8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh;
50068394ec8SAlexander V. Chernikov struct dump_iface_args da;
50168394ec8SAlexander V. Chernikov uint32_t count, size;
50268394ec8SAlexander V. Chernikov
50368394ec8SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
50468394ec8SAlexander V. Chernikov if (olh == NULL)
50568394ec8SAlexander V. Chernikov return (EINVAL);
50668394ec8SAlexander V. Chernikov if (sd->valsize < olh->size)
50768394ec8SAlexander V. Chernikov return (EINVAL);
50868394ec8SAlexander V. Chernikov
50968394ec8SAlexander V. Chernikov IPFW_UH_RLOCK(ch);
51035d5a820SAlexander V. Chernikov ii = CHAIN_TO_II(ch);
51135d5a820SAlexander V. Chernikov if (ii != NULL)
51235d5a820SAlexander V. Chernikov count = ipfw_objhash_count(ii);
51335d5a820SAlexander V. Chernikov else
51435d5a820SAlexander V. Chernikov count = 0;
51568394ec8SAlexander V. Chernikov size = count * sizeof(ipfw_iface_info) + sizeof(ipfw_obj_lheader);
51668394ec8SAlexander V. Chernikov
51768394ec8SAlexander V. Chernikov /* Fill in header regadless of buffer size */
51868394ec8SAlexander V. Chernikov olh->count = count;
51968394ec8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_iface_info);
52068394ec8SAlexander V. Chernikov
52168394ec8SAlexander V. Chernikov if (size > olh->size) {
52268394ec8SAlexander V. Chernikov olh->size = size;
52368394ec8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch);
52468394ec8SAlexander V. Chernikov return (ENOMEM);
52568394ec8SAlexander V. Chernikov }
52668394ec8SAlexander V. Chernikov olh->size = size;
52768394ec8SAlexander V. Chernikov
52868394ec8SAlexander V. Chernikov da.ch = ch;
52968394ec8SAlexander V. Chernikov da.sd = sd;
53068394ec8SAlexander V. Chernikov
53135d5a820SAlexander V. Chernikov if (ii != NULL)
53235d5a820SAlexander V. Chernikov ipfw_objhash_foreach(ii, export_iface_internal, &da);
53368394ec8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch);
53468394ec8SAlexander V. Chernikov
53568394ec8SAlexander V. Chernikov return (0);
53668394ec8SAlexander V. Chernikov }
537