1 /* $OpenBSD: if.c,v 1.165 2007/07/06 14:00:59 naddy Exp $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
34 * Copyright (c) 1980, 1986, 1993
35 * The Regents of the University of California. All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
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.
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
61 * @(#)if.c 8.3 (Berkeley) 1/4/94
64 #include <sys/cdefs.h>
65 __KERNEL_RCSID(0, "$NetBSD$");
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>
77 #include <netinet/in.h>
78 #include <netinet/in_var.h>
80 #include <net/if_compat.h>
83 #include <net/pfvar.h>
86 #if 0 /* XXX unused - remove later */
87 static int if_getgroup(void *, struct ifnet
*);
88 static int if_getgroupmembers(void *);
90 static int if_group_egress_build(void);
93 TAILQ_HEAD(, ifg_group
) ifg_head
= TAILQ_HEAD_INITIALIZER(ifg_head
);
96 if_init_groups(struct ifnet
*ifp
)
98 struct ifg_list_head
*ifgh
;
100 ifgh
= malloc(sizeof(struct ifg_list_head
), M_TEMP
, M_WAITOK
);
103 ifp
->if_pf_groups
= ifgh
;
107 if_destroy_groups(struct ifnet
*ifp
)
109 struct ifg_list_head
*ifgh
= if_get_groups(ifp
);
114 struct ifg_list_head
*
115 if_get_groups(struct ifnet
*ifp
)
117 return (ifp
->if_pf_groups
);
121 * Create interface group without members.
124 if_creategroup(const char *groupname
)
126 struct ifg_group
*ifg
= NULL
;
128 if ((ifg
= (struct ifg_group
*)malloc(sizeof(struct ifg_group
),
129 M_TEMP
, M_NOWAIT
)) == NULL
)
132 strlcpy(ifg
->ifg_group
, groupname
, sizeof(ifg
->ifg_group
));
134 ifg
->ifg_carp_demoted
= 0;
135 TAILQ_INIT(&ifg
->ifg_members
);
137 pfi_attach_ifgroup(ifg
);
139 TAILQ_INSERT_TAIL(&ifg_head
, ifg
, ifg_next
);
145 * Add a group to an interface.
148 if_addgroup(struct ifnet
*ifp
, const char *groupname
)
150 struct ifg_list_head
*ifgh
= if_get_groups(ifp
);
151 struct ifg_list
*ifgl
;
152 struct ifg_group
*ifg
= NULL
;
153 struct ifg_member
*ifgm
;
155 if (groupname
[0] && groupname
[strlen(groupname
) - 1] >= '0' &&
156 groupname
[strlen(groupname
) - 1] <= '9')
159 TAILQ_FOREACH(ifgl
, ifgh
, ifgl_next
)
160 if (!strcmp(ifgl
->ifgl_group
->ifg_group
, groupname
))
163 if ((ifgl
= (struct ifg_list
*)malloc(sizeof(struct ifg_list
), M_TEMP
,
167 if ((ifgm
= (struct ifg_member
*)malloc(sizeof(struct ifg_member
),
168 M_TEMP
, M_NOWAIT
)) == NULL
) {
173 TAILQ_FOREACH(ifg
, &ifg_head
, ifg_next
)
174 if (!strcmp(ifg
->ifg_group
, groupname
))
177 if (ifg
== NULL
&& (ifg
= if_creategroup(groupname
)) == NULL
) {
184 ifgl
->ifgl_group
= ifg
;
185 ifgm
->ifgm_ifp
= ifp
;
187 TAILQ_INSERT_TAIL(&ifg
->ifg_members
, ifgm
, ifgm_next
);
188 TAILQ_INSERT_TAIL(ifgh
, ifgl
, ifgl_next
);
191 pfi_group_change(groupname
);
198 * Remove a group from an interface.
201 if_delgroup(struct ifnet
*ifp
, const char *groupname
)
203 struct ifg_list_head
*ifgh
= if_get_groups(ifp
);
204 struct ifg_list
*ifgl
;
205 struct ifg_member
*ifgm
;
207 TAILQ_FOREACH(ifgl
, ifgh
, ifgl_next
)
208 if (!strcmp(ifgl
->ifgl_group
->ifg_group
, groupname
))
213 TAILQ_REMOVE(ifgh
, ifgl
, ifgl_next
);
215 TAILQ_FOREACH(ifgm
, &ifgl
->ifgl_group
->ifg_members
, ifgm_next
)
216 if (ifgm
->ifgm_ifp
== ifp
)
220 TAILQ_REMOVE(&ifgl
->ifgl_group
->ifg_members
, ifgm
, ifgm_next
);
224 if (--ifgl
->ifgl_group
->ifg_refcnt
== 0) {
225 TAILQ_REMOVE(&ifg_head
, ifgl
->ifgl_group
, ifg_next
);
227 pfi_detach_ifgroup(ifgl
->ifgl_group
);
229 free(ifgl
->ifgl_group
, M_TEMP
);
235 pfi_group_change(groupname
);
243 * Stores all groups from an interface in memory pointed
247 if_getgroup(void *data
, struct ifnet
*ifp
)
250 struct ifg_list_head
*ifgh
= if_get_groups(ifp
);
251 struct ifg_list
*ifgl
;
252 struct ifg_req ifgrq
, *ifgp
;
253 struct ifgroupreq
*ifgr
= (struct ifgroupreq
*)data
;
255 if (ifgr
->ifgr_len
== 0) {
256 TAILQ_FOREACH(ifgl
, ifgh
, ifgl_next
)
257 ifgr
->ifgr_len
+= sizeof(struct ifg_req
);
261 len
= ifgr
->ifgr_len
;
262 ifgp
= ifgr
->ifgr_groups
;
263 TAILQ_FOREACH(ifgl
, ifgh
, ifgl_next
) {
264 if (len
< sizeof(ifgrq
))
266 bzero(&ifgrq
, sizeof ifgrq
);
267 strlcpy(ifgrq
.ifgrq_group
, ifgl
->ifgl_group
->ifg_group
,
268 sizeof(ifgrq
.ifgrq_group
));
269 if ((error
= copyout(&ifgrq
, ifgp
, sizeof(struct ifg_req
))))
271 len
-= sizeof(ifgrq
);
279 * Stores all members of a group in memory pointed to by data.
282 if_getgroupmembers(void *data
)
284 struct ifgroupreq
*ifgr
= (struct ifgroupreq
*)data
;
285 struct ifg_group
*ifg
;
286 struct ifg_member
*ifgm
;
287 struct ifg_req ifgrq
, *ifgp
;
290 TAILQ_FOREACH(ifg
, &ifg_head
, ifg_next
)
291 if (!strcmp(ifg
->ifg_group
, ifgr
->ifgr_name
))
296 if (ifgr
->ifgr_len
== 0) {
297 TAILQ_FOREACH(ifgm
, &ifg
->ifg_members
, ifgm_next
)
298 ifgr
->ifgr_len
+= sizeof(ifgrq
);
302 len
= ifgr
->ifgr_len
;
303 ifgp
= ifgr
->ifgr_groups
;
304 TAILQ_FOREACH(ifgm
, &ifg
->ifg_members
, ifgm_next
) {
305 if (len
< sizeof(ifgrq
))
307 bzero(&ifgrq
, sizeof ifgrq
);
308 strlcpy(ifgrq
.ifgrq_member
, ifgm
->ifgm_ifp
->if_xname
,
309 sizeof(ifgrq
.ifgrq_member
));
310 if ((error
= copyout(&ifgrq
, ifgp
, sizeof(struct ifg_req
))))
312 len
-= sizeof(ifgrq
);
320 if_group_routechange(struct sockaddr
*dst
, struct sockaddr
*mask
)
322 switch (dst
->sa_family
) {
324 if (satosin(dst
)->sin_addr
.s_addr
== INADDR_ANY
)
325 if_group_egress_build();
329 if (IN6_ARE_ADDR_EQUAL(&(satosin6(dst
))->sin6_addr
,
331 mask
&& IN6_ARE_ADDR_EQUAL(&(satosin6(mask
))->sin6_addr
,
333 if_group_egress_build();
340 if_group_egress_build(void)
342 struct ifg_group
*ifg
;
343 struct ifg_member
*ifgm
, *next
;
344 struct sockaddr_in sa_in
;
346 struct sockaddr_in6 sa_in6
;
348 struct radix_node
*rn
;
351 TAILQ_FOREACH(ifg
, &ifg_head
, ifg_next
)
352 if (!strcmp(ifg
->ifg_group
, IFG_EGRESS
))
356 for (ifgm
= TAILQ_FIRST(&ifg
->ifg_members
); ifgm
; ifgm
= next
) {
357 next
= TAILQ_NEXT(ifgm
, ifgm_next
);
358 if_delgroup(ifgm
->ifgm_ifp
, IFG_EGRESS
);
361 bzero(&sa_in
, sizeof(sa_in
));
362 sa_in
.sin_len
= sizeof(sa_in
);
363 sa_in
.sin_family
= AF_INET
;
364 if ((rn
= rt_lookup(sintosa(&sa_in
), sintosa(&sa_in
), 0)) != NULL
) {
366 rt
= (struct rtentry
*)rn
;
368 if_addgroup(rt
->rt_ifp
, IFG_EGRESS
);
370 rn
= rn_mpath_next(rn
);
374 } while (rn
!= NULL
);
378 bcopy(&sa6_any
, &sa_in6
, sizeof(sa_in6
));
379 if ((rn
= rt_lookup(sin6tosa(&sa_in6
), sin6tosa(&sa_in6
), 0)) != NULL
) {
381 rt
= (struct rtentry
*)rn
;
383 if_addgroup(rt
->rt_ifp
, IFG_EGRESS
);
385 rn
= rn_mpath_next(rn
);
389 } while (rn
!= NULL
);