if_compat.c revision 1.1.2.2 1 /* $OpenBSD: if.c,v 1.165 2007/07/06 14:00:59 naddy Exp $ */
2 /* $NetBSD: if_compat.c,v 1.1.2.2 2008/04/23 18:14:49 peter 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.1.2.2 2008/04/23 18:14:49 peter 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 /* XXXPF incomplete */
114 }
115
116 struct ifg_list_head *
117 if_get_groups(struct ifnet *ifp)
118 {
119 return (ifp->if_pf_groups);
120 }
121
122 /*
123 * Create interface group without members.
124 */
125 struct ifg_group *
126 if_creategroup(const char *groupname)
127 {
128 struct ifg_group *ifg = NULL;
129
130 if ((ifg = (struct ifg_group *)malloc(sizeof(struct ifg_group),
131 M_TEMP, M_NOWAIT)) == NULL)
132 return (NULL);
133
134 strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
135 ifg->ifg_refcnt = 0;
136 ifg->ifg_carp_demoted = 0;
137 TAILQ_INIT(&ifg->ifg_members);
138 #if NPF > 0
139 pfi_attach_ifgroup(ifg);
140 #endif
141 TAILQ_INSERT_TAIL(&ifg_head, ifg, ifg_next);
142
143 return (ifg);
144 }
145
146 /*
147 * Add a group to an interface.
148 */
149 int
150 if_addgroup(struct ifnet *ifp, const char *groupname)
151 {
152 struct ifg_list_head *ifgh = if_get_groups(ifp);
153 struct ifg_list *ifgl;
154 struct ifg_group *ifg = NULL;
155 struct ifg_member *ifgm;
156
157 if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' &&
158 groupname[strlen(groupname) - 1] <= '9')
159 return (EINVAL);
160
161 TAILQ_FOREACH(ifgl, ifgh, ifgl_next)
162 if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
163 return (EEXIST);
164
165 if ((ifgl = (struct ifg_list *)malloc(sizeof(struct ifg_list), M_TEMP,
166 M_NOWAIT)) == NULL)
167 return (ENOMEM);
168
169 if ((ifgm = (struct ifg_member *)malloc(sizeof(struct ifg_member),
170 M_TEMP, M_NOWAIT)) == NULL) {
171 free(ifgl, M_TEMP);
172 return (ENOMEM);
173 }
174
175 TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
176 if (!strcmp(ifg->ifg_group, groupname))
177 break;
178
179 if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
180 free(ifgl, M_TEMP);
181 free(ifgm, M_TEMP);
182 return (ENOMEM);
183 }
184
185 ifg->ifg_refcnt++;
186 ifgl->ifgl_group = ifg;
187 ifgm->ifgm_ifp = ifp;
188
189 TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
190 TAILQ_INSERT_TAIL(ifgh, ifgl, ifgl_next);
191
192 #if NPF > 0
193 pfi_group_change(groupname);
194 #endif
195
196 return (0);
197 }
198
199 /*
200 * Remove a group from an interface.
201 */
202 int
203 if_delgroup(struct ifnet *ifp, const char *groupname)
204 {
205 struct ifg_list_head *ifgh = if_get_groups(ifp);
206 struct ifg_list *ifgl;
207 struct ifg_member *ifgm;
208
209 TAILQ_FOREACH(ifgl, ifgh, ifgl_next)
210 if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
211 break;
212 if (ifgl == NULL)
213 return (ENOENT);
214
215 TAILQ_REMOVE(ifgh, ifgl, ifgl_next);
216
217 TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
218 if (ifgm->ifgm_ifp == ifp)
219 break;
220
221 if (ifgm != NULL) {
222 TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifgm_next);
223 free(ifgm, M_TEMP);
224 }
225
226 if (--ifgl->ifgl_group->ifg_refcnt == 0) {
227 TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
228 #if NPF > 0
229 pfi_detach_ifgroup(ifgl->ifgl_group);
230 #endif
231 free(ifgl->ifgl_group, M_TEMP);
232 }
233
234 free(ifgl, M_TEMP);
235
236 #if NPF > 0
237 pfi_group_change(groupname);
238 #endif
239
240 return (0);
241 }
242
243 #if 0
244 /*
245 * Stores all groups from an interface in memory pointed
246 * to by data.
247 */
248 static int
249 if_getgroup(void *data, struct ifnet *ifp)
250 {
251 int len, error;
252 struct ifg_list_head *ifgh = if_get_groups(ifp);
253 struct ifg_list *ifgl;
254 struct ifg_req ifgrq, *ifgp;
255 struct ifgroupreq *ifgr = (struct ifgroupreq *)data;
256
257 if (ifgr->ifgr_len == 0) {
258 TAILQ_FOREACH(ifgl, ifgh, ifgl_next)
259 ifgr->ifgr_len += sizeof(struct ifg_req);
260 return (0);
261 }
262
263 len = ifgr->ifgr_len;
264 ifgp = ifgr->ifgr_groups;
265 TAILQ_FOREACH(ifgl, ifgh, ifgl_next) {
266 if (len < sizeof(ifgrq))
267 return (EINVAL);
268 bzero(&ifgrq, sizeof ifgrq);
269 strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
270 sizeof(ifgrq.ifgrq_group));
271 if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req))))
272 return (error);
273 len -= sizeof(ifgrq);
274 ifgp++;
275 }
276
277 return (0);
278 }
279
280 /*
281 * Stores all members of a group in memory pointed to by data.
282 */
283 static int
284 if_getgroupmembers(void *data)
285 {
286 struct ifgroupreq *ifgr = (struct ifgroupreq *)data;
287 struct ifg_group *ifg;
288 struct ifg_member *ifgm;
289 struct ifg_req ifgrq, *ifgp;
290 int len, error;
291
292 TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
293 if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
294 break;
295 if (ifg == NULL)
296 return (ENOENT);
297
298 if (ifgr->ifgr_len == 0) {
299 TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
300 ifgr->ifgr_len += sizeof(ifgrq);
301 return (0);
302 }
303
304 len = ifgr->ifgr_len;
305 ifgp = ifgr->ifgr_groups;
306 TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
307 if (len < sizeof(ifgrq))
308 return (EINVAL);
309 bzero(&ifgrq, sizeof ifgrq);
310 strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname,
311 sizeof(ifgrq.ifgrq_member));
312 if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req))))
313 return (error);
314 len -= sizeof(ifgrq);
315 ifgp++;
316 }
317
318 return (0);
319 }
320
321 void
322 if_group_routechange(struct sockaddr *dst, struct sockaddr *mask)
323 {
324 switch (dst->sa_family) {
325 case AF_INET:
326 if (satosin(dst)->sin_addr.s_addr == INADDR_ANY)
327 if_group_egress_build();
328 break;
329 #ifdef INET6
330 case AF_INET6:
331 if (IN6_ARE_ADDR_EQUAL(&(satosin6(dst))->sin6_addr,
332 &in6addr_any) &&
333 mask && IN6_ARE_ADDR_EQUAL(&(satosin6(mask))->sin6_addr,
334 &in6addr_any))
335 if_group_egress_build();
336 break;
337 #endif
338 }
339 }
340
341 static int
342 if_group_egress_build(void)
343 {
344 struct ifg_group *ifg;
345 struct ifg_member *ifgm, *next;
346 struct sockaddr_in sa_in;
347 #ifdef INET6
348 struct sockaddr_in6 sa_in6;
349 #endif
350 struct radix_node *rn;
351 struct rtentry *rt;
352
353 TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
354 if (!strcmp(ifg->ifg_group, IFG_EGRESS))
355 break;
356
357 if (ifg != NULL)
358 for (ifgm = TAILQ_FIRST(&ifg->ifg_members); ifgm; ifgm = next) {
359 next = TAILQ_NEXT(ifgm, ifgm_next);
360 if_delgroup(ifgm->ifgm_ifp, IFG_EGRESS);
361 }
362
363 bzero(&sa_in, sizeof(sa_in));
364 sa_in.sin_len = sizeof(sa_in);
365 sa_in.sin_family = AF_INET;
366 if ((rn = rt_lookup(sintosa(&sa_in), sintosa(&sa_in), 0)) != NULL) {
367 do {
368 rt = (struct rtentry *)rn;
369 if (rt->rt_ifp)
370 if_addgroup(rt->rt_ifp, IFG_EGRESS);
371 #ifndef SMALL_KERNEL
372 rn = rn_mpath_next(rn);
373 #else
374 rn = NULL;
375 #endif
376 } while (rn != NULL);
377 }
378
379 #ifdef INET6
380 bcopy(&sa6_any, &sa_in6, sizeof(sa_in6));
381 if ((rn = rt_lookup(sin6tosa(&sa_in6), sin6tosa(&sa_in6), 0)) != NULL) {
382 do {
383 rt = (struct rtentry *)rn;
384 if (rt->rt_ifp)
385 if_addgroup(rt->rt_ifp, IFG_EGRESS);
386 #ifndef SMALL_KERNEL
387 rn = rn_mpath_next(rn);
388 #else
389 rn = NULL;
390 #endif
391 } while (rn != NULL);
392 }
393 #endif
394
395 return (0);
396 }
397 #endif
398