xref: /netbsd-src/sys/net/npf/npf_if.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: npf_if.c,v 1.2 2013/11/11 15:28:37 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 2013 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Mindaugas Rasiukevicius.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * NPF network interface handling module.
34  *
35  * NPF uses its own interface IDs (npf-if-id).  When NPF configuration is
36  * (re)loaded, each required interface name is registered and a matching
37  * network interface gets an ID assigned.  If an interface is not present,
38  * it gets an ID on attach.  Any other interfaces get INACTIVE_ID.
39  *
40  * The IDs are mapped synchronously based on interface events which are
41  * monitored using pfil(9) hooks.
42  */
43 
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1.2 2013/11/11 15:28:37 martin Exp $");
46 
47 #ifdef _KERNEL_OPT
48 #include "pf.h"
49 #if NPF > 0
50 #error "NPF and PF are mutually exclusive; please select one"
51 #endif
52 #endif
53 
54 #include <sys/param.h>
55 #include <sys/types.h>
56 #include <sys/kmem.h>
57 
58 #include <net/if.h>
59 
60 #include "npf_impl.h"
61 
62 #define	INACTIVE_ID	((u_int)-1)
63 
64 typedef struct {
65 	char		n_ifname[IFNAMSIZ];
66 } npf_ifmap_t;
67 
68 static npf_ifmap_t	npf_ifmap[NPF_MAX_IFMAP]	__read_mostly;
69 static u_int		npf_ifmap_cnt			__read_mostly;
70 
71 /*
72  * NOTE: IDs start from 1.  Zero is reseved for "no interface" and
73  * (unsigned)-1 for "inactive interface".  Therefore, an interface
74  * can have either INACTIVE_ID or non-zero ID.
75  */
76 
77 static u_int
78 npf_ifmap_new(void)
79 {
80 	KASSERT(npf_config_locked_p());
81 
82 	for (u_int i = 0; i < npf_ifmap_cnt; i++)
83 		if (npf_ifmap[i].n_ifname[0] == '\0')
84 			return i + 1;
85 
86 	if (npf_ifmap_cnt == NPF_MAX_IFMAP) {
87 		printf("npf_ifmap_new: out of slots; bump NPF_MAX_IFMAP\n");
88 		return INACTIVE_ID;
89 	}
90 	return ++npf_ifmap_cnt;
91 }
92 
93 static u_int
94 npf_ifmap_lookup(const char *ifname)
95 {
96 	KASSERT(npf_config_locked_p());
97 
98 	for (u_int i = 0; i < npf_ifmap_cnt; i++) {
99 		npf_ifmap_t *nim = &npf_ifmap[i];
100 
101 		if (nim->n_ifname[0] && strcmp(nim->n_ifname, ifname) == 0)
102 			return i + 1;
103 	}
104 	return INACTIVE_ID;
105 }
106 
107 u_int
108 npf_ifmap_register(const char *ifname)
109 {
110 	npf_ifmap_t *nim;
111 	ifnet_t *ifp;
112 	u_int i;
113 
114 	npf_config_enter();
115 	if ((i = npf_ifmap_lookup(ifname)) != INACTIVE_ID) {
116 		goto out;
117 	}
118 	if ((i = npf_ifmap_new()) == INACTIVE_ID) {
119 		i = INACTIVE_ID;
120 		goto out;
121 	}
122 	nim = &npf_ifmap[i - 1];
123 	strlcpy(nim->n_ifname, ifname, IFNAMSIZ);
124 
125 	KERNEL_LOCK(1, NULL);
126 	if ((ifp = ifunit(ifname)) != NULL) {
127 		ifp->if_pf_kif = (void *)(uintptr_t)i;
128 	}
129 	KERNEL_UNLOCK_ONE(NULL);
130 out:
131 	npf_config_exit();
132 	return i;
133 }
134 
135 void
136 npf_ifmap_flush(void)
137 {
138 	ifnet_t *ifp;
139 
140 	KASSERT(npf_config_locked_p());
141 
142 	for (u_int i = 0; i < npf_ifmap_cnt; i++) {
143 		npf_ifmap[i].n_ifname[0] = '\0';
144 	}
145 	npf_ifmap_cnt = 0;
146 
147 	KERNEL_LOCK(1, NULL);
148 	IFNET_FOREACH(ifp) {
149 		ifp->if_pf_kif = (void *)(uintptr_t)INACTIVE_ID;
150 	}
151 	KERNEL_UNLOCK_ONE(NULL);
152 }
153 
154 u_int
155 npf_ifmap_id(const ifnet_t *ifp)
156 {
157 	const u_int i = (uintptr_t)ifp->if_pf_kif;
158 
159 	KASSERT(i == INACTIVE_ID || (i > 0 && i <= npf_ifmap_cnt));
160 	return i;
161 }
162 
163 void
164 npf_ifmap_attach(ifnet_t *ifp)
165 {
166 	npf_config_enter();
167 	ifp->if_pf_kif = (void *)(uintptr_t)npf_ifmap_lookup(ifp->if_xname);
168 	npf_config_exit();
169 }
170 
171 void
172 npf_ifmap_detach(ifnet_t *ifp)
173 {
174 	npf_config_enter();
175 	ifp->if_pf_kif = (void *)(uintptr_t)INACTIVE_ID; /* diagnostic */
176 	npf_config_exit();
177 }
178