| @@ -1,2360 +1,2361 @@ | | | @@ -1,2360 +1,2361 @@ |
1 | /* $NetBSD: if_bridge.c,v 1.146 2017/12/19 03:32:35 ozaki-r Exp $ */ | | 1 | /* $NetBSD: if_bridge.c,v 1.147 2017/12/28 07:06:36 ozaki-r Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright 2001 Wasabi Systems, Inc. | | 4 | * Copyright 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software | | 17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: | | 18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by | | 19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. | | 20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | | 21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior | | 22 | * or promote products derived from this software without specific prior |
23 | * written permission. | | 23 | * written permission. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | | 25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | /* | | 38 | /* |
39 | * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) | | 39 | * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) |
40 | * All rights reserved. | | 40 | * All rights reserved. |
41 | * | | 41 | * |
42 | * Redistribution and use in source and binary forms, with or without | | 42 | * Redistribution and use in source and binary forms, with or without |
43 | * modification, are permitted provided that the following conditions | | 43 | * modification, are permitted provided that the following conditions |
44 | * are met: | | 44 | * are met: |
45 | * 1. Redistributions of source code must retain the above copyright | | 45 | * 1. Redistributions of source code must retain the above copyright |
46 | * notice, this list of conditions and the following disclaimer. | | 46 | * notice, this list of conditions and the following disclaimer. |
47 | * 2. Redistributions in binary form must reproduce the above copyright | | 47 | * 2. Redistributions in binary form must reproduce the above copyright |
48 | * notice, this list of conditions and the following disclaimer in the | | 48 | * notice, this list of conditions and the following disclaimer in the |
49 | * documentation and/or other materials provided with the distribution. | | 49 | * documentation and/or other materials provided with the distribution. |
50 | * 3. All advertising materials mentioning features or use of this software | | 50 | * 3. All advertising materials mentioning features or use of this software |
51 | * must display the following acknowledgement: | | 51 | * must display the following acknowledgement: |
52 | * This product includes software developed by Jason L. Wright | | 52 | * This product includes software developed by Jason L. Wright |
53 | * 4. The name of the author may not be used to endorse or promote products | | 53 | * 4. The name of the author may not be used to endorse or promote products |
54 | * derived from this software without specific prior written permission. | | 54 | * derived from this software without specific prior written permission. |
55 | * | | 55 | * |
56 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 56 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
57 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | | 57 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
58 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | 58 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
59 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | | 59 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, |
60 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | | 60 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
61 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | 61 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
62 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 62 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
63 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | | 63 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
64 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | | 64 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
65 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 65 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
66 | * POSSIBILITY OF SUCH DAMAGE. | | 66 | * POSSIBILITY OF SUCH DAMAGE. |
67 | * | | 67 | * |
68 | * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp | | 68 | * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp |
69 | */ | | 69 | */ |
70 | | | 70 | |
71 | /* | | 71 | /* |
72 | * Network interface bridge support. | | 72 | * Network interface bridge support. |
73 | * | | 73 | * |
74 | * TODO: | | 74 | * TODO: |
75 | * | | 75 | * |
76 | * - Currently only supports Ethernet-like interfaces (Ethernet, | | 76 | * - Currently only supports Ethernet-like interfaces (Ethernet, |
77 | * 802.11, VLANs on Ethernet, etc.) Figure out a nice way | | 77 | * 802.11, VLANs on Ethernet, etc.) Figure out a nice way |
78 | * to bridge other types of interfaces (FDDI-FDDI, and maybe | | 78 | * to bridge other types of interfaces (FDDI-FDDI, and maybe |
79 | * consider heterogenous bridges). | | 79 | * consider heterogenous bridges). |
80 | */ | | 80 | */ |
81 | | | 81 | |
82 | #include <sys/cdefs.h> | | 82 | #include <sys/cdefs.h> |
83 | __KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.146 2017/12/19 03:32:35 ozaki-r Exp $"); | | 83 | __KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.147 2017/12/28 07:06:36 ozaki-r Exp $"); |
84 | | | 84 | |
85 | #ifdef _KERNEL_OPT | | 85 | #ifdef _KERNEL_OPT |
86 | #include "opt_bridge_ipf.h" | | 86 | #include "opt_bridge_ipf.h" |
87 | #include "opt_inet.h" | | 87 | #include "opt_inet.h" |
88 | #include "opt_net_mpsafe.h" | | 88 | #include "opt_net_mpsafe.h" |
89 | #endif /* _KERNEL_OPT */ | | 89 | #endif /* _KERNEL_OPT */ |
90 | | | 90 | |
91 | #include <sys/param.h> | | 91 | #include <sys/param.h> |
92 | #include <sys/kernel.h> | | 92 | #include <sys/kernel.h> |
93 | #include <sys/mbuf.h> | | 93 | #include <sys/mbuf.h> |
94 | #include <sys/queue.h> | | 94 | #include <sys/queue.h> |
95 | #include <sys/socket.h> | | 95 | #include <sys/socket.h> |
96 | #include <sys/socketvar.h> /* for softnet_lock */ | | 96 | #include <sys/socketvar.h> /* for softnet_lock */ |
97 | #include <sys/sockio.h> | | 97 | #include <sys/sockio.h> |
98 | #include <sys/systm.h> | | 98 | #include <sys/systm.h> |
99 | #include <sys/proc.h> | | 99 | #include <sys/proc.h> |
100 | #include <sys/pool.h> | | 100 | #include <sys/pool.h> |
101 | #include <sys/kauth.h> | | 101 | #include <sys/kauth.h> |
102 | #include <sys/cpu.h> | | 102 | #include <sys/cpu.h> |
103 | #include <sys/cprng.h> | | 103 | #include <sys/cprng.h> |
104 | #include <sys/mutex.h> | | 104 | #include <sys/mutex.h> |
105 | #include <sys/kmem.h> | | 105 | #include <sys/kmem.h> |
106 | | | 106 | |
107 | #include <net/bpf.h> | | 107 | #include <net/bpf.h> |
108 | #include <net/if.h> | | 108 | #include <net/if.h> |
109 | #include <net/if_dl.h> | | 109 | #include <net/if_dl.h> |
110 | #include <net/if_types.h> | | 110 | #include <net/if_types.h> |
111 | #include <net/if_llc.h> | | 111 | #include <net/if_llc.h> |
112 | | | 112 | |
113 | #include <net/if_ether.h> | | 113 | #include <net/if_ether.h> |
114 | #include <net/if_bridgevar.h> | | 114 | #include <net/if_bridgevar.h> |
115 | | | 115 | |
116 | #if defined(BRIDGE_IPF) | | 116 | #if defined(BRIDGE_IPF) |
117 | /* Used for bridge_ip[6]_checkbasic */ | | 117 | /* Used for bridge_ip[6]_checkbasic */ |
118 | #include <netinet/in.h> | | 118 | #include <netinet/in.h> |
119 | #include <netinet/in_systm.h> | | 119 | #include <netinet/in_systm.h> |
120 | #include <netinet/ip.h> | | 120 | #include <netinet/ip.h> |
121 | #include <netinet/ip_var.h> | | 121 | #include <netinet/ip_var.h> |
122 | #include <netinet/ip_private.h> /* XXX */ | | 122 | #include <netinet/ip_private.h> /* XXX */ |
123 | | | 123 | |
124 | #include <netinet/ip6.h> | | 124 | #include <netinet/ip6.h> |
125 | #include <netinet6/in6_var.h> | | 125 | #include <netinet6/in6_var.h> |
126 | #include <netinet6/ip6_var.h> | | 126 | #include <netinet6/ip6_var.h> |
127 | #include <netinet6/ip6_private.h> /* XXX */ | | 127 | #include <netinet6/ip6_private.h> /* XXX */ |
128 | #endif /* BRIDGE_IPF */ | | 128 | #endif /* BRIDGE_IPF */ |
129 | | | 129 | |
130 | /* | | 130 | /* |
131 | * Size of the route hash table. Must be a power of two. | | 131 | * Size of the route hash table. Must be a power of two. |
132 | */ | | 132 | */ |
133 | #ifndef BRIDGE_RTHASH_SIZE | | 133 | #ifndef BRIDGE_RTHASH_SIZE |
134 | #define BRIDGE_RTHASH_SIZE 1024 | | 134 | #define BRIDGE_RTHASH_SIZE 1024 |
135 | #endif | | 135 | #endif |
136 | | | 136 | |
137 | #define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1) | | 137 | #define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1) |
138 | | | 138 | |
139 | #include "carp.h" | | 139 | #include "carp.h" |
140 | #if NCARP > 0 | | 140 | #if NCARP > 0 |
141 | #include <netinet/in.h> | | 141 | #include <netinet/in.h> |
142 | #include <netinet/in_var.h> | | 142 | #include <netinet/in_var.h> |
143 | #include <netinet/ip_carp.h> | | 143 | #include <netinet/ip_carp.h> |
144 | #endif | | 144 | #endif |
145 | | | 145 | |
146 | #include "ioconf.h" | | 146 | #include "ioconf.h" |
147 | | | 147 | |
148 | __CTASSERT(sizeof(struct ifbifconf) == sizeof(struct ifbaconf)); | | 148 | __CTASSERT(sizeof(struct ifbifconf) == sizeof(struct ifbaconf)); |
149 | __CTASSERT(offsetof(struct ifbifconf, ifbic_len) == offsetof(struct ifbaconf, ifbac_len)); | | 149 | __CTASSERT(offsetof(struct ifbifconf, ifbic_len) == offsetof(struct ifbaconf, ifbac_len)); |
150 | __CTASSERT(offsetof(struct ifbifconf, ifbic_buf) == offsetof(struct ifbaconf, ifbac_buf)); | | 150 | __CTASSERT(offsetof(struct ifbifconf, ifbic_buf) == offsetof(struct ifbaconf, ifbac_buf)); |
151 | | | 151 | |
152 | /* | | 152 | /* |
153 | * Maximum number of addresses to cache. | | 153 | * Maximum number of addresses to cache. |
154 | */ | | 154 | */ |
155 | #ifndef BRIDGE_RTABLE_MAX | | 155 | #ifndef BRIDGE_RTABLE_MAX |
156 | #define BRIDGE_RTABLE_MAX 100 | | 156 | #define BRIDGE_RTABLE_MAX 100 |
157 | #endif | | 157 | #endif |
158 | | | 158 | |
159 | /* | | 159 | /* |
160 | * Spanning tree defaults. | | 160 | * Spanning tree defaults. |
161 | */ | | 161 | */ |
162 | #define BSTP_DEFAULT_MAX_AGE (20 * 256) | | 162 | #define BSTP_DEFAULT_MAX_AGE (20 * 256) |
163 | #define BSTP_DEFAULT_HELLO_TIME (2 * 256) | | 163 | #define BSTP_DEFAULT_HELLO_TIME (2 * 256) |
164 | #define BSTP_DEFAULT_FORWARD_DELAY (15 * 256) | | 164 | #define BSTP_DEFAULT_FORWARD_DELAY (15 * 256) |
165 | #define BSTP_DEFAULT_HOLD_TIME (1 * 256) | | 165 | #define BSTP_DEFAULT_HOLD_TIME (1 * 256) |
166 | #define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000 | | 166 | #define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000 |
167 | #define BSTP_DEFAULT_PORT_PRIORITY 0x80 | | 167 | #define BSTP_DEFAULT_PORT_PRIORITY 0x80 |
168 | #define BSTP_DEFAULT_PATH_COST 55 | | 168 | #define BSTP_DEFAULT_PATH_COST 55 |
169 | | | 169 | |
170 | /* | | 170 | /* |
171 | * Timeout (in seconds) for entries learned dynamically. | | 171 | * Timeout (in seconds) for entries learned dynamically. |
172 | */ | | 172 | */ |
173 | #ifndef BRIDGE_RTABLE_TIMEOUT | | 173 | #ifndef BRIDGE_RTABLE_TIMEOUT |
174 | #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */ | | 174 | #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */ |
175 | #endif | | 175 | #endif |
176 | | | 176 | |
177 | /* | | 177 | /* |
178 | * Number of seconds between walks of the route list. | | 178 | * Number of seconds between walks of the route list. |
179 | */ | | 179 | */ |
180 | #ifndef BRIDGE_RTABLE_PRUNE_PERIOD | | 180 | #ifndef BRIDGE_RTABLE_PRUNE_PERIOD |
181 | #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) | | 181 | #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) |
182 | #endif | | 182 | #endif |
183 | | | 183 | |
184 | #define BRIDGE_RT_LOCK(_sc) if ((_sc)->sc_rtlist_lock) \ | | 184 | #define BRIDGE_RT_LOCK(_sc) if ((_sc)->sc_rtlist_lock) \ |
185 | mutex_enter((_sc)->sc_rtlist_lock) | | 185 | mutex_enter((_sc)->sc_rtlist_lock) |
186 | #define BRIDGE_RT_UNLOCK(_sc) if ((_sc)->sc_rtlist_lock) \ | | 186 | #define BRIDGE_RT_UNLOCK(_sc) if ((_sc)->sc_rtlist_lock) \ |
187 | mutex_exit((_sc)->sc_rtlist_lock) | | 187 | mutex_exit((_sc)->sc_rtlist_lock) |
188 | #define BRIDGE_RT_LOCKED(_sc) (!(_sc)->sc_rtlist_lock || \ | | 188 | #define BRIDGE_RT_LOCKED(_sc) (!(_sc)->sc_rtlist_lock || \ |
189 | mutex_owned((_sc)->sc_rtlist_lock)) | | 189 | mutex_owned((_sc)->sc_rtlist_lock)) |
190 | | | 190 | |
191 | #define BRIDGE_RT_PSZ_PERFORM(_sc) \ | | 191 | #define BRIDGE_RT_PSZ_PERFORM(_sc) \ |
192 | if ((_sc)->sc_rtlist_psz != NULL) \ | | 192 | if ((_sc)->sc_rtlist_psz != NULL) \ |
193 | pserialize_perform((_sc)->sc_rtlist_psz); | | 193 | pserialize_perform((_sc)->sc_rtlist_psz); |
194 | | | 194 | |
195 | #define BRIDGE_RT_RENTER(__s) do { __s = pserialize_read_enter(); } while (0) | | 195 | #define BRIDGE_RT_RENTER(__s) do { __s = pserialize_read_enter(); } while (0) |
196 | #define BRIDGE_RT_REXIT(__s) do { pserialize_read_exit(__s); } while (0) | | 196 | #define BRIDGE_RT_REXIT(__s) do { pserialize_read_exit(__s); } while (0) |
197 | | | 197 | |
198 | | | 198 | |
199 | #ifdef NET_MPSAFE | | 199 | #ifdef NET_MPSAFE |
200 | #define DECLARE_LOCK_VARIABLE | | 200 | #define DECLARE_LOCK_VARIABLE |
201 | #define ACQUIRE_GLOBAL_LOCKS() do { } while (0) | | 201 | #define ACQUIRE_GLOBAL_LOCKS() do { } while (0) |
202 | #define RELEASE_GLOBAL_LOCKS() do { } while (0) | | 202 | #define RELEASE_GLOBAL_LOCKS() do { } while (0) |
203 | #else | | 203 | #else |
204 | #define DECLARE_LOCK_VARIABLE int __s | | 204 | #define DECLARE_LOCK_VARIABLE int __s |
205 | #define ACQUIRE_GLOBAL_LOCKS() do { \ | | 205 | #define ACQUIRE_GLOBAL_LOCKS() do { \ |
206 | KERNEL_LOCK(1, NULL); \ | | 206 | KERNEL_LOCK(1, NULL); \ |
207 | mutex_enter(softnet_lock); \ | | 207 | mutex_enter(softnet_lock); \ |
208 | __s = splsoftnet(); \ | | 208 | __s = splsoftnet(); \ |
209 | } while (0) | | 209 | } while (0) |
210 | #define RELEASE_GLOBAL_LOCKS() do { \ | | 210 | #define RELEASE_GLOBAL_LOCKS() do { \ |
211 | splx(__s); \ | | 211 | splx(__s); \ |
212 | mutex_exit(softnet_lock); \ | | 212 | mutex_exit(softnet_lock); \ |
213 | KERNEL_UNLOCK_ONE(NULL); \ | | 213 | KERNEL_UNLOCK_ONE(NULL); \ |
214 | } while (0) | | 214 | } while (0) |
215 | #endif | | 215 | #endif |
216 | | | 216 | |
217 | struct psref_class *bridge_psref_class __read_mostly; | | 217 | struct psref_class *bridge_psref_class __read_mostly; |
218 | | | 218 | |
219 | int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; | | 219 | int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; |
220 | | | 220 | |
221 | static struct pool bridge_rtnode_pool; | | 221 | static struct pool bridge_rtnode_pool; |
222 | | | 222 | |
223 | static int bridge_clone_create(struct if_clone *, int); | | 223 | static int bridge_clone_create(struct if_clone *, int); |
224 | static int bridge_clone_destroy(struct ifnet *); | | 224 | static int bridge_clone_destroy(struct ifnet *); |
225 | | | 225 | |
226 | static int bridge_ioctl(struct ifnet *, u_long, void *); | | 226 | static int bridge_ioctl(struct ifnet *, u_long, void *); |
227 | static int bridge_init(struct ifnet *); | | 227 | static int bridge_init(struct ifnet *); |
228 | static void bridge_stop(struct ifnet *, int); | | 228 | static void bridge_stop(struct ifnet *, int); |
229 | static void bridge_start(struct ifnet *); | | 229 | static void bridge_start(struct ifnet *); |
230 | | | 230 | |
231 | static void bridge_input(struct ifnet *, struct mbuf *); | | 231 | static void bridge_input(struct ifnet *, struct mbuf *); |
232 | static void bridge_forward(struct bridge_softc *, struct mbuf *); | | 232 | static void bridge_forward(struct bridge_softc *, struct mbuf *); |
233 | | | 233 | |
234 | static void bridge_timer(void *); | | 234 | static void bridge_timer(void *); |
235 | | | 235 | |
236 | static void bridge_broadcast(struct bridge_softc *, struct ifnet *, | | 236 | static void bridge_broadcast(struct bridge_softc *, struct ifnet *, |
237 | struct mbuf *); | | 237 | struct mbuf *); |
238 | | | 238 | |
239 | static int bridge_rtupdate(struct bridge_softc *, const uint8_t *, | | 239 | static int bridge_rtupdate(struct bridge_softc *, const uint8_t *, |
240 | struct ifnet *, int, uint8_t); | | 240 | struct ifnet *, int, uint8_t); |
241 | static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *); | | 241 | static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *); |
242 | static void bridge_rttrim(struct bridge_softc *); | | 242 | static void bridge_rttrim(struct bridge_softc *); |
243 | static void bridge_rtage(struct bridge_softc *); | | 243 | static void bridge_rtage(struct bridge_softc *); |
244 | static void bridge_rtage_work(struct work *, void *); | | 244 | static void bridge_rtage_work(struct work *, void *); |
245 | static void bridge_rtflush(struct bridge_softc *, int); | | 245 | static void bridge_rtflush(struct bridge_softc *, int); |
246 | static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *); | | 246 | static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *); |
247 | static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp); | | 247 | static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp); |
248 | | | 248 | |
249 | static void bridge_rtable_init(struct bridge_softc *); | | 249 | static void bridge_rtable_init(struct bridge_softc *); |
250 | static void bridge_rtable_fini(struct bridge_softc *); | | 250 | static void bridge_rtable_fini(struct bridge_softc *); |
251 | | | 251 | |
252 | static struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *, | | 252 | static struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *, |
253 | const uint8_t *); | | 253 | const uint8_t *); |
254 | static int bridge_rtnode_insert(struct bridge_softc *, | | 254 | static int bridge_rtnode_insert(struct bridge_softc *, |
255 | struct bridge_rtnode *); | | 255 | struct bridge_rtnode *); |
256 | static void bridge_rtnode_remove(struct bridge_softc *, | | 256 | static void bridge_rtnode_remove(struct bridge_softc *, |
257 | struct bridge_rtnode *); | | 257 | struct bridge_rtnode *); |
258 | static void bridge_rtnode_destroy(struct bridge_rtnode *); | | 258 | static void bridge_rtnode_destroy(struct bridge_rtnode *); |
259 | | | 259 | |
260 | static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *, | | 260 | static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *, |
261 | const char *name, | | 261 | const char *name, |
262 | struct psref *); | | 262 | struct psref *); |
263 | static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, | | 263 | static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, |
264 | struct ifnet *ifp, | | 264 | struct ifnet *ifp, |
265 | struct psref *); | | 265 | struct psref *); |
266 | static void bridge_release_member(struct bridge_softc *, struct bridge_iflist *, | | 266 | static void bridge_release_member(struct bridge_softc *, struct bridge_iflist *, |
267 | struct psref *); | | 267 | struct psref *); |
268 | static void bridge_delete_member(struct bridge_softc *, | | 268 | static void bridge_delete_member(struct bridge_softc *, |
269 | struct bridge_iflist *); | | 269 | struct bridge_iflist *); |
270 | static void bridge_acquire_member(struct bridge_softc *sc, | | 270 | static void bridge_acquire_member(struct bridge_softc *sc, |
271 | struct bridge_iflist *, | | 271 | struct bridge_iflist *, |
272 | struct psref *); | | 272 | struct psref *); |
273 | | | 273 | |
274 | static int bridge_ioctl_add(struct bridge_softc *, void *); | | 274 | static int bridge_ioctl_add(struct bridge_softc *, void *); |
275 | static int bridge_ioctl_del(struct bridge_softc *, void *); | | 275 | static int bridge_ioctl_del(struct bridge_softc *, void *); |
276 | static int bridge_ioctl_gifflags(struct bridge_softc *, void *); | | 276 | static int bridge_ioctl_gifflags(struct bridge_softc *, void *); |
277 | static int bridge_ioctl_sifflags(struct bridge_softc *, void *); | | 277 | static int bridge_ioctl_sifflags(struct bridge_softc *, void *); |
278 | static int bridge_ioctl_scache(struct bridge_softc *, void *); | | 278 | static int bridge_ioctl_scache(struct bridge_softc *, void *); |
279 | static int bridge_ioctl_gcache(struct bridge_softc *, void *); | | 279 | static int bridge_ioctl_gcache(struct bridge_softc *, void *); |
280 | static int bridge_ioctl_gifs(struct bridge_softc *, void *); | | 280 | static int bridge_ioctl_gifs(struct bridge_softc *, void *); |
281 | static int bridge_ioctl_rts(struct bridge_softc *, void *); | | 281 | static int bridge_ioctl_rts(struct bridge_softc *, void *); |
282 | static int bridge_ioctl_saddr(struct bridge_softc *, void *); | | 282 | static int bridge_ioctl_saddr(struct bridge_softc *, void *); |
283 | static int bridge_ioctl_sto(struct bridge_softc *, void *); | | 283 | static int bridge_ioctl_sto(struct bridge_softc *, void *); |
284 | static int bridge_ioctl_gto(struct bridge_softc *, void *); | | 284 | static int bridge_ioctl_gto(struct bridge_softc *, void *); |
285 | static int bridge_ioctl_daddr(struct bridge_softc *, void *); | | 285 | static int bridge_ioctl_daddr(struct bridge_softc *, void *); |
286 | static int bridge_ioctl_flush(struct bridge_softc *, void *); | | 286 | static int bridge_ioctl_flush(struct bridge_softc *, void *); |
287 | static int bridge_ioctl_gpri(struct bridge_softc *, void *); | | 287 | static int bridge_ioctl_gpri(struct bridge_softc *, void *); |
288 | static int bridge_ioctl_spri(struct bridge_softc *, void *); | | 288 | static int bridge_ioctl_spri(struct bridge_softc *, void *); |
289 | static int bridge_ioctl_ght(struct bridge_softc *, void *); | | 289 | static int bridge_ioctl_ght(struct bridge_softc *, void *); |
290 | static int bridge_ioctl_sht(struct bridge_softc *, void *); | | 290 | static int bridge_ioctl_sht(struct bridge_softc *, void *); |
291 | static int bridge_ioctl_gfd(struct bridge_softc *, void *); | | 291 | static int bridge_ioctl_gfd(struct bridge_softc *, void *); |
292 | static int bridge_ioctl_sfd(struct bridge_softc *, void *); | | 292 | static int bridge_ioctl_sfd(struct bridge_softc *, void *); |
293 | static int bridge_ioctl_gma(struct bridge_softc *, void *); | | 293 | static int bridge_ioctl_gma(struct bridge_softc *, void *); |
294 | static int bridge_ioctl_sma(struct bridge_softc *, void *); | | 294 | static int bridge_ioctl_sma(struct bridge_softc *, void *); |
295 | static int bridge_ioctl_sifprio(struct bridge_softc *, void *); | | 295 | static int bridge_ioctl_sifprio(struct bridge_softc *, void *); |
296 | static int bridge_ioctl_sifcost(struct bridge_softc *, void *); | | 296 | static int bridge_ioctl_sifcost(struct bridge_softc *, void *); |
297 | #if defined(BRIDGE_IPF) | | 297 | #if defined(BRIDGE_IPF) |
298 | static int bridge_ioctl_gfilt(struct bridge_softc *, void *); | | 298 | static int bridge_ioctl_gfilt(struct bridge_softc *, void *); |
299 | static int bridge_ioctl_sfilt(struct bridge_softc *, void *); | | 299 | static int bridge_ioctl_sfilt(struct bridge_softc *, void *); |
300 | static int bridge_ipf(void *, struct mbuf **, struct ifnet *, int); | | 300 | static int bridge_ipf(void *, struct mbuf **, struct ifnet *, int); |
301 | static int bridge_ip_checkbasic(struct mbuf **mp); | | 301 | static int bridge_ip_checkbasic(struct mbuf **mp); |
302 | # ifdef INET6 | | 302 | # ifdef INET6 |
303 | static int bridge_ip6_checkbasic(struct mbuf **mp); | | 303 | static int bridge_ip6_checkbasic(struct mbuf **mp); |
304 | # endif /* INET6 */ | | 304 | # endif /* INET6 */ |
305 | #endif /* BRIDGE_IPF */ | | 305 | #endif /* BRIDGE_IPF */ |
306 | | | 306 | |
307 | struct bridge_control { | | 307 | struct bridge_control { |
308 | int (*bc_func)(struct bridge_softc *, void *); | | 308 | int (*bc_func)(struct bridge_softc *, void *); |
309 | int bc_argsize; | | 309 | int bc_argsize; |
310 | int bc_flags; | | 310 | int bc_flags; |
311 | }; | | 311 | }; |
312 | | | 312 | |
313 | #define BC_F_COPYIN 0x01 /* copy arguments in */ | | 313 | #define BC_F_COPYIN 0x01 /* copy arguments in */ |
314 | #define BC_F_COPYOUT 0x02 /* copy arguments out */ | | 314 | #define BC_F_COPYOUT 0x02 /* copy arguments out */ |
315 | #define BC_F_SUSER 0x04 /* do super-user check */ | | 315 | #define BC_F_SUSER 0x04 /* do super-user check */ |
316 | #define BC_F_XLATEIN 0x08 /* xlate arguments in */ | | 316 | #define BC_F_XLATEIN 0x08 /* xlate arguments in */ |
317 | #define BC_F_XLATEOUT 0x10 /* xlate arguments out */ | | 317 | #define BC_F_XLATEOUT 0x10 /* xlate arguments out */ |
318 | | | 318 | |
319 | static const struct bridge_control bridge_control_table[] = { | | 319 | static const struct bridge_control bridge_control_table[] = { |
320 | [BRDGADD] = {bridge_ioctl_add, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, | | 320 | [BRDGADD] = {bridge_ioctl_add, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, |
321 | [BRDGDEL] = {bridge_ioctl_del, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, | | 321 | [BRDGDEL] = {bridge_ioctl_del, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, |
322 | | | 322 | |
323 | [BRDGGIFFLGS] = {bridge_ioctl_gifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_COPYOUT}, | | 323 | [BRDGGIFFLGS] = {bridge_ioctl_gifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_COPYOUT}, |
324 | [BRDGSIFFLGS] = {bridge_ioctl_sifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, | | 324 | [BRDGSIFFLGS] = {bridge_ioctl_sifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, |
325 | | | 325 | |
326 | [BRDGSCACHE] = {bridge_ioctl_scache, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, | | 326 | [BRDGSCACHE] = {bridge_ioctl_scache, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, |
327 | [BRDGGCACHE] = {bridge_ioctl_gcache, sizeof(struct ifbrparam), BC_F_COPYOUT}, | | 327 | [BRDGGCACHE] = {bridge_ioctl_gcache, sizeof(struct ifbrparam), BC_F_COPYOUT}, |
328 | | | 328 | |
329 | [OBRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_COPYIN|BC_F_COPYOUT}, | | 329 | [OBRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_COPYIN|BC_F_COPYOUT}, |
330 | [OBRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_COPYIN|BC_F_COPYOUT}, | | 330 | [OBRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_COPYIN|BC_F_COPYOUT}, |
331 | | | 331 | |
332 | [BRDGSADDR] = {bridge_ioctl_saddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER}, | | 332 | [BRDGSADDR] = {bridge_ioctl_saddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER}, |
333 | | | 333 | |
334 | [BRDGSTO] = {bridge_ioctl_sto, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, | | 334 | [BRDGSTO] = {bridge_ioctl_sto, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, |
335 | [BRDGGTO] = {bridge_ioctl_gto, sizeof(struct ifbrparam), BC_F_COPYOUT}, | | 335 | [BRDGGTO] = {bridge_ioctl_gto, sizeof(struct ifbrparam), BC_F_COPYOUT}, |
336 | | | 336 | |
337 | [BRDGDADDR] = {bridge_ioctl_daddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER}, | | 337 | [BRDGDADDR] = {bridge_ioctl_daddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER}, |
338 | | | 338 | |
339 | [BRDGFLUSH] = {bridge_ioctl_flush, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, | | 339 | [BRDGFLUSH] = {bridge_ioctl_flush, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, |
340 | | | 340 | |
341 | [BRDGGPRI] = {bridge_ioctl_gpri, sizeof(struct ifbrparam), BC_F_COPYOUT}, | | 341 | [BRDGGPRI] = {bridge_ioctl_gpri, sizeof(struct ifbrparam), BC_F_COPYOUT}, |
342 | [BRDGSPRI] = {bridge_ioctl_spri, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, | | 342 | [BRDGSPRI] = {bridge_ioctl_spri, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, |
343 | | | 343 | |
344 | [BRDGGHT] = {bridge_ioctl_ght, sizeof(struct ifbrparam), BC_F_COPYOUT}, | | 344 | [BRDGGHT] = {bridge_ioctl_ght, sizeof(struct ifbrparam), BC_F_COPYOUT}, |
345 | [BRDGSHT] = {bridge_ioctl_sht, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, | | 345 | [BRDGSHT] = {bridge_ioctl_sht, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, |
346 | | | 346 | |
347 | [BRDGGFD] = {bridge_ioctl_gfd, sizeof(struct ifbrparam), BC_F_COPYOUT}, | | 347 | [BRDGGFD] = {bridge_ioctl_gfd, sizeof(struct ifbrparam), BC_F_COPYOUT}, |
348 | [BRDGSFD] = {bridge_ioctl_sfd, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, | | 348 | [BRDGSFD] = {bridge_ioctl_sfd, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, |
349 | | | 349 | |
350 | [BRDGGMA] = {bridge_ioctl_gma, sizeof(struct ifbrparam), BC_F_COPYOUT}, | | 350 | [BRDGGMA] = {bridge_ioctl_gma, sizeof(struct ifbrparam), BC_F_COPYOUT}, |
351 | [BRDGSMA] = {bridge_ioctl_sma, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, | | 351 | [BRDGSMA] = {bridge_ioctl_sma, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, |
352 | | | 352 | |
353 | [BRDGSIFPRIO] = {bridge_ioctl_sifprio, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, | | 353 | [BRDGSIFPRIO] = {bridge_ioctl_sifprio, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, |
354 | | | 354 | |
355 | [BRDGSIFCOST] = {bridge_ioctl_sifcost, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, | | 355 | [BRDGSIFCOST] = {bridge_ioctl_sifcost, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, |
356 | #if defined(BRIDGE_IPF) | | 356 | #if defined(BRIDGE_IPF) |
357 | [BRDGGFILT] = {bridge_ioctl_gfilt, sizeof(struct ifbrparam), BC_F_COPYOUT}, | | 357 | [BRDGGFILT] = {bridge_ioctl_gfilt, sizeof(struct ifbrparam), BC_F_COPYOUT}, |
358 | [BRDGSFILT] = {bridge_ioctl_sfilt, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, | | 358 | [BRDGSFILT] = {bridge_ioctl_sfilt, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, |
359 | #endif /* BRIDGE_IPF */ | | 359 | #endif /* BRIDGE_IPF */ |
360 | [BRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_XLATEIN|BC_F_XLATEOUT}, | | 360 | [BRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_XLATEIN|BC_F_XLATEOUT}, |
361 | [BRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_XLATEIN|BC_F_XLATEOUT}, | | 361 | [BRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_XLATEIN|BC_F_XLATEOUT}, |
362 | }; | | 362 | }; |
363 | | | 363 | |
364 | static const int bridge_control_table_size = __arraycount(bridge_control_table); | | 364 | static const int bridge_control_table_size = __arraycount(bridge_control_table); |
365 | | | 365 | |
366 | static struct if_clone bridge_cloner = | | 366 | static struct if_clone bridge_cloner = |
367 | IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy); | | 367 | IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy); |
368 | | | 368 | |
369 | /* | | 369 | /* |
370 | * bridgeattach: | | 370 | * bridgeattach: |
371 | * | | 371 | * |
372 | * Pseudo-device attach routine. | | 372 | * Pseudo-device attach routine. |
373 | */ | | 373 | */ |
374 | void | | 374 | void |
375 | bridgeattach(int n) | | 375 | bridgeattach(int n) |
376 | { | | 376 | { |
377 | | | 377 | |
378 | pool_init(&bridge_rtnode_pool, sizeof(struct bridge_rtnode), | | 378 | pool_init(&bridge_rtnode_pool, sizeof(struct bridge_rtnode), |
379 | 0, 0, 0, "brtpl", NULL, IPL_NET); | | 379 | 0, 0, 0, "brtpl", NULL, IPL_NET); |
380 | | | 380 | |
381 | bridge_psref_class = psref_class_create("bridge", IPL_SOFTNET); | | 381 | bridge_psref_class = psref_class_create("bridge", IPL_SOFTNET); |
382 | | | 382 | |
383 | if_clone_attach(&bridge_cloner); | | 383 | if_clone_attach(&bridge_cloner); |
384 | } | | 384 | } |
385 | | | 385 | |
386 | /* | | 386 | /* |
387 | * bridge_clone_create: | | 387 | * bridge_clone_create: |
388 | * | | 388 | * |
389 | * Create a new bridge instance. | | 389 | * Create a new bridge instance. |
390 | */ | | 390 | */ |
391 | static int | | 391 | static int |
392 | bridge_clone_create(struct if_clone *ifc, int unit) | | 392 | bridge_clone_create(struct if_clone *ifc, int unit) |
393 | { | | 393 | { |
394 | struct bridge_softc *sc; | | 394 | struct bridge_softc *sc; |
395 | struct ifnet *ifp; | | 395 | struct ifnet *ifp; |
396 | int error; | | 396 | int error; |
397 | | | 397 | |
398 | sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); | | 398 | sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); |
399 | ifp = &sc->sc_if; | | 399 | ifp = &sc->sc_if; |
400 | | | 400 | |
401 | sc->sc_brtmax = BRIDGE_RTABLE_MAX; | | 401 | sc->sc_brtmax = BRIDGE_RTABLE_MAX; |
402 | sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; | | 402 | sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; |
403 | sc->sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE; | | 403 | sc->sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE; |
404 | sc->sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME; | | 404 | sc->sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME; |
405 | sc->sc_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY; | | 405 | sc->sc_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY; |
406 | sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY; | | 406 | sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY; |
407 | sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME; | | 407 | sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME; |
408 | sc->sc_filter_flags = 0; | | 408 | sc->sc_filter_flags = 0; |
409 | | | 409 | |
410 | /* Initialize our routing table. */ | | 410 | /* Initialize our routing table. */ |
411 | bridge_rtable_init(sc); | | 411 | bridge_rtable_init(sc); |
412 | | | 412 | |
413 | error = workqueue_create(&sc->sc_rtage_wq, "bridge_rtage", | | 413 | error = workqueue_create(&sc->sc_rtage_wq, "bridge_rtage", |
414 | bridge_rtage_work, sc, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE); | | 414 | bridge_rtage_work, sc, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE); |
415 | if (error) | | 415 | if (error) |
416 | panic("%s: workqueue_create %d\n", __func__, error); | | 416 | panic("%s: workqueue_create %d\n", __func__, error); |
417 | | | 417 | |
418 | callout_init(&sc->sc_brcallout, CALLOUT_MPSAFE); | | 418 | callout_init(&sc->sc_brcallout, CALLOUT_MPSAFE); |
419 | callout_init(&sc->sc_bstpcallout, CALLOUT_MPSAFE); | | 419 | callout_init(&sc->sc_bstpcallout, CALLOUT_MPSAFE); |
420 | | | 420 | |
421 | mutex_init(&sc->sc_iflist_psref.bip_lock, MUTEX_DEFAULT, IPL_NONE); | | 421 | mutex_init(&sc->sc_iflist_psref.bip_lock, MUTEX_DEFAULT, IPL_NONE); |
422 | PSLIST_INIT(&sc->sc_iflist_psref.bip_iflist); | | 422 | PSLIST_INIT(&sc->sc_iflist_psref.bip_iflist); |
423 | sc->sc_iflist_psref.bip_psz = pserialize_create(); | | 423 | sc->sc_iflist_psref.bip_psz = pserialize_create(); |
424 | | | 424 | |
425 | if_initname(ifp, ifc->ifc_name, unit); | | 425 | if_initname(ifp, ifc->ifc_name, unit); |
426 | ifp->if_softc = sc; | | 426 | ifp->if_softc = sc; |
427 | ifp->if_extflags = IFEF_NO_LINK_STATE_CHANGE; | | 427 | ifp->if_extflags = IFEF_NO_LINK_STATE_CHANGE; |
428 | #ifdef NET_MPSAFE | | 428 | #ifdef NET_MPSAFE |
429 | ifp->if_extflags |= IFEF_MPSAFE; | | 429 | ifp->if_extflags |= IFEF_MPSAFE; |
430 | #endif | | 430 | #endif |
431 | ifp->if_mtu = ETHERMTU; | | 431 | ifp->if_mtu = ETHERMTU; |
432 | ifp->if_ioctl = bridge_ioctl; | | 432 | ifp->if_ioctl = bridge_ioctl; |
433 | ifp->if_output = bridge_output; | | 433 | ifp->if_output = bridge_output; |
434 | ifp->if_start = bridge_start; | | 434 | ifp->if_start = bridge_start; |
435 | ifp->if_stop = bridge_stop; | | 435 | ifp->if_stop = bridge_stop; |
436 | ifp->if_init = bridge_init; | | 436 | ifp->if_init = bridge_init; |
437 | ifp->if_type = IFT_BRIDGE; | | 437 | ifp->if_type = IFT_BRIDGE; |
438 | ifp->if_addrlen = 0; | | 438 | ifp->if_addrlen = 0; |
439 | ifp->if_dlt = DLT_EN10MB; | | 439 | ifp->if_dlt = DLT_EN10MB; |
440 | ifp->if_hdrlen = ETHER_HDR_LEN; | | 440 | ifp->if_hdrlen = ETHER_HDR_LEN; |
441 | | | 441 | |
442 | error = if_initialize(ifp); | | 442 | error = if_initialize(ifp); |
443 | if (error != 0) { | | 443 | if (error != 0) { |
444 | pserialize_destroy(sc->sc_iflist_psref.bip_psz); | | 444 | pserialize_destroy(sc->sc_iflist_psref.bip_psz); |
445 | mutex_destroy(&sc->sc_iflist_psref.bip_lock); | | 445 | mutex_destroy(&sc->sc_iflist_psref.bip_lock); |
446 | callout_destroy(&sc->sc_brcallout); | | 446 | callout_destroy(&sc->sc_brcallout); |
447 | callout_destroy(&sc->sc_bstpcallout); | | 447 | callout_destroy(&sc->sc_bstpcallout); |
448 | workqueue_destroy(sc->sc_rtage_wq); | | 448 | workqueue_destroy(sc->sc_rtage_wq); |
449 | bridge_rtable_fini(sc); | | 449 | bridge_rtable_fini(sc); |
450 | kmem_free(sc, sizeof(*sc)); | | 450 | kmem_free(sc, sizeof(*sc)); |
451 | | | 451 | |
452 | return error; | | 452 | return error; |
453 | } | | 453 | } |
454 | if_register(ifp); | | 454 | if_register(ifp); |
455 | | | 455 | |
456 | if_alloc_sadl(ifp); | | 456 | if_alloc_sadl(ifp); |
457 | | | 457 | |
458 | return 0; | | 458 | return 0; |
459 | } | | 459 | } |
460 | | | 460 | |
461 | /* | | 461 | /* |
462 | * bridge_clone_destroy: | | 462 | * bridge_clone_destroy: |
463 | * | | 463 | * |
464 | * Destroy a bridge instance. | | 464 | * Destroy a bridge instance. |
465 | */ | | 465 | */ |
466 | static int | | 466 | static int |
467 | bridge_clone_destroy(struct ifnet *ifp) | | 467 | bridge_clone_destroy(struct ifnet *ifp) |
468 | { | | 468 | { |
469 | struct bridge_softc *sc = ifp->if_softc; | | 469 | struct bridge_softc *sc = ifp->if_softc; |
470 | struct bridge_iflist *bif; | | 470 | struct bridge_iflist *bif; |
471 | | | 471 | |
472 | bridge_stop(ifp, 1); | | 472 | bridge_stop(ifp, 1); |
473 | | | 473 | |
474 | BRIDGE_LOCK(sc); | | 474 | BRIDGE_LOCK(sc); |
475 | for (;;) { | | 475 | for (;;) { |
476 | bif = PSLIST_WRITER_FIRST(&sc->sc_iflist_psref.bip_iflist, struct bridge_iflist, | | 476 | bif = PSLIST_WRITER_FIRST(&sc->sc_iflist_psref.bip_iflist, struct bridge_iflist, |
477 | bif_next); | | 477 | bif_next); |
478 | if (bif == NULL) | | 478 | if (bif == NULL) |
479 | break; | | 479 | break; |
480 | bridge_delete_member(sc, bif); | | 480 | bridge_delete_member(sc, bif); |
481 | } | | 481 | } |
482 | PSLIST_DESTROY(&sc->sc_iflist_psref.bip_iflist); | | 482 | PSLIST_DESTROY(&sc->sc_iflist_psref.bip_iflist); |
483 | BRIDGE_UNLOCK(sc); | | 483 | BRIDGE_UNLOCK(sc); |
484 | | | 484 | |
485 | if_detach(ifp); | | 485 | if_detach(ifp); |
486 | | | 486 | |
487 | /* Tear down the routing table. */ | | 487 | /* Tear down the routing table. */ |
488 | bridge_rtable_fini(sc); | | 488 | bridge_rtable_fini(sc); |
489 | | | 489 | |
490 | pserialize_destroy(sc->sc_iflist_psref.bip_psz); | | 490 | pserialize_destroy(sc->sc_iflist_psref.bip_psz); |
491 | mutex_destroy(&sc->sc_iflist_psref.bip_lock); | | 491 | mutex_destroy(&sc->sc_iflist_psref.bip_lock); |
492 | callout_destroy(&sc->sc_brcallout); | | 492 | callout_destroy(&sc->sc_brcallout); |
493 | callout_destroy(&sc->sc_bstpcallout); | | 493 | callout_destroy(&sc->sc_bstpcallout); |
494 | workqueue_destroy(sc->sc_rtage_wq); | | 494 | workqueue_destroy(sc->sc_rtage_wq); |
495 | kmem_free(sc, sizeof(*sc)); | | 495 | kmem_free(sc, sizeof(*sc)); |
496 | | | 496 | |
497 | return 0; | | 497 | return 0; |
498 | } | | 498 | } |
499 | | | 499 | |
500 | /* | | 500 | /* |
501 | * bridge_ioctl: | | 501 | * bridge_ioctl: |
502 | * | | 502 | * |
503 | * Handle a control request from the operator. | | 503 | * Handle a control request from the operator. |
504 | */ | | 504 | */ |
505 | static int | | 505 | static int |
506 | bridge_ioctl(struct ifnet *ifp, u_long cmd, void *data) | | 506 | bridge_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
507 | { | | 507 | { |
508 | struct bridge_softc *sc = ifp->if_softc; | | 508 | struct bridge_softc *sc = ifp->if_softc; |
509 | struct lwp *l = curlwp; /* XXX */ | | 509 | struct lwp *l = curlwp; /* XXX */ |
510 | union { | | 510 | union { |
511 | struct ifbreq ifbreq; | | 511 | struct ifbreq ifbreq; |
512 | struct ifbifconf ifbifconf; | | 512 | struct ifbifconf ifbifconf; |
513 | struct ifbareq ifbareq; | | 513 | struct ifbareq ifbareq; |
514 | struct ifbaconf ifbaconf; | | 514 | struct ifbaconf ifbaconf; |
515 | struct ifbrparam ifbrparam; | | 515 | struct ifbrparam ifbrparam; |
516 | } args; | | 516 | } args; |
517 | struct ifdrv *ifd = (struct ifdrv *) data; | | 517 | struct ifdrv *ifd = (struct ifdrv *) data; |
518 | const struct bridge_control *bc = NULL; /* XXXGCC */ | | 518 | const struct bridge_control *bc = NULL; /* XXXGCC */ |
519 | int s, error = 0; | | 519 | int s, error = 0; |
520 | | | 520 | |
521 | /* Authorize command before calling splsoftnet(). */ | | 521 | /* Authorize command before calling splsoftnet(). */ |
522 | switch (cmd) { | | 522 | switch (cmd) { |
523 | case SIOCGDRVSPEC: | | 523 | case SIOCGDRVSPEC: |
524 | case SIOCSDRVSPEC: | | 524 | case SIOCSDRVSPEC: |
525 | if (ifd->ifd_cmd >= bridge_control_table_size | | 525 | if (ifd->ifd_cmd >= bridge_control_table_size |
526 | || (bc = &bridge_control_table[ifd->ifd_cmd]) == NULL) { | | 526 | || (bc = &bridge_control_table[ifd->ifd_cmd]) == NULL) { |
527 | error = EINVAL; | | 527 | error = EINVAL; |
528 | return error; | | 528 | return error; |
529 | } | | 529 | } |
530 | | | 530 | |
531 | /* We only care about BC_F_SUSER at this point. */ | | 531 | /* We only care about BC_F_SUSER at this point. */ |
532 | if ((bc->bc_flags & BC_F_SUSER) == 0) | | 532 | if ((bc->bc_flags & BC_F_SUSER) == 0) |
533 | break; | | 533 | break; |
534 | | | 534 | |
535 | error = kauth_authorize_network(l->l_cred, | | 535 | error = kauth_authorize_network(l->l_cred, |
536 | KAUTH_NETWORK_INTERFACE_BRIDGE, | | 536 | KAUTH_NETWORK_INTERFACE_BRIDGE, |
537 | cmd == SIOCGDRVSPEC ? | | 537 | cmd == SIOCGDRVSPEC ? |
538 | KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_GETPRIV : | | 538 | KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_GETPRIV : |
539 | KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_SETPRIV, | | 539 | KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_SETPRIV, |
540 | ifd, NULL, NULL); | | 540 | ifd, NULL, NULL); |
541 | if (error) | | 541 | if (error) |
542 | return error; | | 542 | return error; |
543 | | | 543 | |
544 | break; | | 544 | break; |
545 | } | | 545 | } |
546 | | | 546 | |
547 | s = splsoftnet(); | | 547 | s = splsoftnet(); |
548 | | | 548 | |
549 | switch (cmd) { | | 549 | switch (cmd) { |
550 | case SIOCGDRVSPEC: | | 550 | case SIOCGDRVSPEC: |
551 | case SIOCSDRVSPEC: | | 551 | case SIOCSDRVSPEC: |
552 | KASSERT(bc != NULL); | | 552 | KASSERT(bc != NULL); |
553 | if (cmd == SIOCGDRVSPEC && | | 553 | if (cmd == SIOCGDRVSPEC && |
554 | (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) == 0) { | | 554 | (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) == 0) { |
555 | error = EINVAL; | | 555 | error = EINVAL; |
556 | break; | | 556 | break; |
557 | } | | 557 | } |
558 | else if (cmd == SIOCSDRVSPEC && | | 558 | else if (cmd == SIOCSDRVSPEC && |
559 | (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) != 0) { | | 559 | (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) != 0) { |
560 | error = EINVAL; | | 560 | error = EINVAL; |
561 | break; | | 561 | break; |
562 | } | | 562 | } |
563 | | | 563 | |
564 | /* BC_F_SUSER is checked above, before splsoftnet(). */ | | 564 | /* BC_F_SUSER is checked above, before splsoftnet(). */ |
565 | | | 565 | |
566 | if ((bc->bc_flags & (BC_F_XLATEIN|BC_F_XLATEOUT)) == 0 | | 566 | if ((bc->bc_flags & (BC_F_XLATEIN|BC_F_XLATEOUT)) == 0 |
567 | && (ifd->ifd_len != bc->bc_argsize | | 567 | && (ifd->ifd_len != bc->bc_argsize |
568 | || ifd->ifd_len > sizeof(args))) { | | 568 | || ifd->ifd_len > sizeof(args))) { |
569 | error = EINVAL; | | 569 | error = EINVAL; |
570 | break; | | 570 | break; |
571 | } | | 571 | } |
572 | | | 572 | |
573 | memset(&args, 0, sizeof(args)); | | 573 | memset(&args, 0, sizeof(args)); |
574 | if (bc->bc_flags & BC_F_COPYIN) { | | 574 | if (bc->bc_flags & BC_F_COPYIN) { |
575 | error = copyin(ifd->ifd_data, &args, ifd->ifd_len); | | 575 | error = copyin(ifd->ifd_data, &args, ifd->ifd_len); |
576 | if (error) | | 576 | if (error) |
577 | break; | | 577 | break; |
578 | } else if (bc->bc_flags & BC_F_XLATEIN) { | | 578 | } else if (bc->bc_flags & BC_F_XLATEIN) { |
579 | args.ifbifconf.ifbic_len = ifd->ifd_len; | | 579 | args.ifbifconf.ifbic_len = ifd->ifd_len; |
580 | args.ifbifconf.ifbic_buf = ifd->ifd_data; | | 580 | args.ifbifconf.ifbic_buf = ifd->ifd_data; |
581 | } | | 581 | } |
582 | | | 582 | |
583 | error = (*bc->bc_func)(sc, &args); | | 583 | error = (*bc->bc_func)(sc, &args); |
584 | if (error) | | 584 | if (error) |
585 | break; | | 585 | break; |
586 | | | 586 | |
587 | if (bc->bc_flags & BC_F_COPYOUT) { | | 587 | if (bc->bc_flags & BC_F_COPYOUT) { |
588 | error = copyout(&args, ifd->ifd_data, ifd->ifd_len); | | 588 | error = copyout(&args, ifd->ifd_data, ifd->ifd_len); |
589 | } else if (bc->bc_flags & BC_F_XLATEOUT) { | | 589 | } else if (bc->bc_flags & BC_F_XLATEOUT) { |
590 | ifd->ifd_len = args.ifbifconf.ifbic_len; | | 590 | ifd->ifd_len = args.ifbifconf.ifbic_len; |
591 | ifd->ifd_data = args.ifbifconf.ifbic_buf; | | 591 | ifd->ifd_data = args.ifbifconf.ifbic_buf; |
592 | } | | 592 | } |
593 | break; | | 593 | break; |
594 | | | 594 | |
595 | case SIOCSIFFLAGS: | | 595 | case SIOCSIFFLAGS: |
596 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | | 596 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) |
597 | break; | | 597 | break; |
598 | switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { | | 598 | switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { |
599 | case IFF_RUNNING: | | 599 | case IFF_RUNNING: |
600 | /* | | 600 | /* |
601 | * If interface is marked down and it is running, | | 601 | * If interface is marked down and it is running, |
602 | * then stop and disable it. | | 602 | * then stop and disable it. |
603 | */ | | 603 | */ |
604 | (*ifp->if_stop)(ifp, 1); | | 604 | (*ifp->if_stop)(ifp, 1); |
605 | break; | | 605 | break; |
606 | case IFF_UP: | | 606 | case IFF_UP: |
607 | /* | | 607 | /* |
608 | * If interface is marked up and it is stopped, then | | 608 | * If interface is marked up and it is stopped, then |
609 | * start it. | | 609 | * start it. |
610 | */ | | 610 | */ |
611 | error = (*ifp->if_init)(ifp); | | 611 | error = (*ifp->if_init)(ifp); |
612 | break; | | 612 | break; |
613 | default: | | 613 | default: |
614 | break; | | 614 | break; |
615 | } | | 615 | } |
616 | break; | | 616 | break; |
617 | | | 617 | |
618 | case SIOCSIFMTU: | | 618 | case SIOCSIFMTU: |
619 | if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) | | 619 | if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) |
620 | error = 0; | | 620 | error = 0; |
621 | break; | | 621 | break; |
622 | | | 622 | |
623 | default: | | 623 | default: |
624 | error = ifioctl_common(ifp, cmd, data); | | 624 | error = ifioctl_common(ifp, cmd, data); |
625 | break; | | 625 | break; |
626 | } | | 626 | } |
627 | | | 627 | |
628 | splx(s); | | 628 | splx(s); |
629 | | | 629 | |
630 | return error; | | 630 | return error; |
631 | } | | 631 | } |
632 | | | 632 | |
633 | /* | | 633 | /* |
634 | * bridge_lookup_member: | | 634 | * bridge_lookup_member: |
635 | * | | 635 | * |
636 | * Lookup a bridge member interface. | | 636 | * Lookup a bridge member interface. |
637 | */ | | 637 | */ |
638 | static struct bridge_iflist * | | 638 | static struct bridge_iflist * |
639 | bridge_lookup_member(struct bridge_softc *sc, const char *name, struct psref *psref) | | 639 | bridge_lookup_member(struct bridge_softc *sc, const char *name, struct psref *psref) |
640 | { | | 640 | { |
641 | struct bridge_iflist *bif; | | 641 | struct bridge_iflist *bif; |
642 | struct ifnet *ifp; | | 642 | struct ifnet *ifp; |
643 | int s; | | 643 | int s; |
644 | | | 644 | |
645 | BRIDGE_PSZ_RENTER(s); | | 645 | BRIDGE_PSZ_RENTER(s); |
646 | | | 646 | |
647 | BRIDGE_IFLIST_READER_FOREACH(bif, sc) { | | 647 | BRIDGE_IFLIST_READER_FOREACH(bif, sc) { |
648 | ifp = bif->bif_ifp; | | 648 | ifp = bif->bif_ifp; |
649 | if (strcmp(ifp->if_xname, name) == 0) | | 649 | if (strcmp(ifp->if_xname, name) == 0) |
650 | break; | | 650 | break; |
651 | } | | 651 | } |
652 | if (bif != NULL) | | 652 | if (bif != NULL) |
653 | bridge_acquire_member(sc, bif, psref); | | 653 | bridge_acquire_member(sc, bif, psref); |
654 | | | 654 | |
655 | BRIDGE_PSZ_REXIT(s); | | 655 | BRIDGE_PSZ_REXIT(s); |
656 | | | 656 | |
657 | return bif; | | 657 | return bif; |
658 | } | | 658 | } |
659 | | | 659 | |
660 | /* | | 660 | /* |
661 | * bridge_lookup_member_if: | | 661 | * bridge_lookup_member_if: |
662 | * | | 662 | * |
663 | * Lookup a bridge member interface by ifnet*. | | 663 | * Lookup a bridge member interface by ifnet*. |
664 | */ | | 664 | */ |
665 | static struct bridge_iflist * | | 665 | static struct bridge_iflist * |
666 | bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp, | | 666 | bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp, |
667 | struct psref *psref) | | 667 | struct psref *psref) |
668 | { | | 668 | { |
669 | struct bridge_iflist *bif; | | 669 | struct bridge_iflist *bif; |
670 | int s; | | 670 | int s; |
671 | | | 671 | |
672 | BRIDGE_PSZ_RENTER(s); | | 672 | BRIDGE_PSZ_RENTER(s); |
673 | | | 673 | |
674 | bif = member_ifp->if_bridgeif; | | 674 | bif = member_ifp->if_bridgeif; |
675 | if (bif != NULL) { | | 675 | if (bif != NULL) { |
676 | psref_acquire(psref, &bif->bif_psref, | | 676 | psref_acquire(psref, &bif->bif_psref, |
677 | bridge_psref_class); | | 677 | bridge_psref_class); |
678 | } | | 678 | } |
679 | | | 679 | |
680 | BRIDGE_PSZ_REXIT(s); | | 680 | BRIDGE_PSZ_REXIT(s); |
681 | | | 681 | |
682 | return bif; | | 682 | return bif; |
683 | } | | 683 | } |
684 | | | 684 | |
685 | static void | | 685 | static void |
686 | bridge_acquire_member(struct bridge_softc *sc, struct bridge_iflist *bif, | | 686 | bridge_acquire_member(struct bridge_softc *sc, struct bridge_iflist *bif, |
687 | struct psref *psref) | | 687 | struct psref *psref) |
688 | { | | 688 | { |
689 | | | 689 | |
690 | psref_acquire(psref, &bif->bif_psref, bridge_psref_class); | | 690 | psref_acquire(psref, &bif->bif_psref, bridge_psref_class); |
691 | } | | 691 | } |
692 | | | 692 | |
693 | /* | | 693 | /* |
694 | * bridge_release_member: | | 694 | * bridge_release_member: |
695 | * | | 695 | * |
696 | * Release the specified member interface. | | 696 | * Release the specified member interface. |
697 | */ | | 697 | */ |
698 | static void | | 698 | static void |
699 | bridge_release_member(struct bridge_softc *sc, struct bridge_iflist *bif, | | 699 | bridge_release_member(struct bridge_softc *sc, struct bridge_iflist *bif, |
700 | struct psref *psref) | | 700 | struct psref *psref) |
701 | { | | 701 | { |
702 | | | 702 | |
703 | psref_release(psref, &bif->bif_psref, bridge_psref_class); | | 703 | psref_release(psref, &bif->bif_psref, bridge_psref_class); |
704 | } | | 704 | } |
705 | | | 705 | |
706 | /* | | 706 | /* |
707 | * bridge_delete_member: | | 707 | * bridge_delete_member: |
708 | * | | 708 | * |
709 | * Delete the specified member interface. | | 709 | * Delete the specified member interface. |
710 | */ | | 710 | */ |
711 | static void | | 711 | static void |
712 | bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif) | | 712 | bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif) |
713 | { | | 713 | { |
714 | struct ifnet *ifs = bif->bif_ifp; | | 714 | struct ifnet *ifs = bif->bif_ifp; |
715 | | | 715 | |
716 | KASSERT(BRIDGE_LOCKED(sc)); | | 716 | KASSERT(BRIDGE_LOCKED(sc)); |
717 | | | 717 | |
718 | ifs->_if_input = ether_input; | | 718 | ifs->_if_input = ether_input; |
719 | ifs->if_bridge = NULL; | | 719 | ifs->if_bridge = NULL; |
720 | ifs->if_bridgeif = NULL; | | 720 | ifs->if_bridgeif = NULL; |
721 | | | 721 | |
722 | PSLIST_WRITER_REMOVE(bif, bif_next); | | 722 | PSLIST_WRITER_REMOVE(bif, bif_next); |
723 | BRIDGE_PSZ_PERFORM(sc); | | 723 | BRIDGE_PSZ_PERFORM(sc); |
724 | BRIDGE_UNLOCK(sc); | | 724 | BRIDGE_UNLOCK(sc); |
725 | | | 725 | |
726 | psref_target_destroy(&bif->bif_psref, bridge_psref_class); | | 726 | psref_target_destroy(&bif->bif_psref, bridge_psref_class); |
727 | | | 727 | |
728 | PSLIST_ENTRY_DESTROY(bif, bif_next); | | 728 | PSLIST_ENTRY_DESTROY(bif, bif_next); |
729 | kmem_free(bif, sizeof(*bif)); | | 729 | kmem_free(bif, sizeof(*bif)); |
730 | | | 730 | |
731 | BRIDGE_LOCK(sc); | | 731 | BRIDGE_LOCK(sc); |
732 | } | | 732 | } |
733 | | | 733 | |
734 | static int | | 734 | static int |
735 | bridge_ioctl_add(struct bridge_softc *sc, void *arg) | | 735 | bridge_ioctl_add(struct bridge_softc *sc, void *arg) |
736 | { | | 736 | { |
737 | struct ifbreq *req = arg; | | 737 | struct ifbreq *req = arg; |
738 | struct bridge_iflist *bif = NULL; | | 738 | struct bridge_iflist *bif = NULL; |
739 | struct ifnet *ifs; | | 739 | struct ifnet *ifs; |
740 | int error = 0; | | 740 | int error = 0; |
741 | struct psref psref; | | 741 | struct psref psref; |
742 | | | 742 | |
743 | ifs = if_get(req->ifbr_ifsname, &psref); | | 743 | ifs = if_get(req->ifbr_ifsname, &psref); |
744 | if (ifs == NULL) | | 744 | if (ifs == NULL) |
745 | return ENOENT; | | 745 | return ENOENT; |
746 | | | 746 | |
747 | if (ifs->if_bridge == sc) { | | 747 | if (ifs->if_bridge == sc) { |
748 | error = EEXIST; | | 748 | error = EEXIST; |
749 | goto out; | | 749 | goto out; |
750 | } | | 750 | } |
751 | | | 751 | |
752 | if (ifs->if_bridge != NULL) { | | 752 | if (ifs->if_bridge != NULL) { |
753 | error = EBUSY; | | 753 | error = EBUSY; |
754 | goto out; | | 754 | goto out; |
755 | } | | 755 | } |
756 | | | 756 | |
757 | if (ifs->_if_input != ether_input) { | | 757 | if (ifs->_if_input != ether_input) { |
758 | error = EINVAL; | | 758 | error = EINVAL; |
759 | goto out; | | 759 | goto out; |
760 | } | | 760 | } |
761 | | | 761 | |
762 | /* FIXME: doesn't work with non-IFF_SIMPLEX interfaces */ | | 762 | /* FIXME: doesn't work with non-IFF_SIMPLEX interfaces */ |
763 | if ((ifs->if_flags & IFF_SIMPLEX) == 0) { | | 763 | if ((ifs->if_flags & IFF_SIMPLEX) == 0) { |
764 | error = EINVAL; | | 764 | error = EINVAL; |
765 | goto out; | | 765 | goto out; |
766 | } | | 766 | } |
767 | | | 767 | |
768 | bif = kmem_alloc(sizeof(*bif), KM_SLEEP); | | 768 | bif = kmem_alloc(sizeof(*bif), KM_SLEEP); |
769 | | | 769 | |
770 | switch (ifs->if_type) { | | 770 | switch (ifs->if_type) { |
771 | case IFT_ETHER: | | 771 | case IFT_ETHER: |
772 | if (sc->sc_if.if_mtu != ifs->if_mtu) { | | 772 | if (sc->sc_if.if_mtu != ifs->if_mtu) { |
773 | error = EINVAL; | | 773 | error = EINVAL; |
774 | goto out; | | 774 | goto out; |
775 | } | | 775 | } |
776 | /* FALLTHROUGH */ | | 776 | /* FALLTHROUGH */ |
777 | case IFT_L2TP: | | 777 | case IFT_L2TP: |
778 | IFNET_LOCK(ifs); | | 778 | IFNET_LOCK(ifs); |
779 | error = ether_enable_vlan_mtu(ifs); | | 779 | error = ether_enable_vlan_mtu(ifs); |
780 | IFNET_UNLOCK(ifs); | | 780 | IFNET_UNLOCK(ifs); |
781 | if (error > 0) | | 781 | if (error > 0) |
782 | goto out; | | 782 | goto out; |
783 | /* | | 783 | /* |
784 | * Place the interface into promiscuous mode. | | 784 | * Place the interface into promiscuous mode. |
785 | */ | | 785 | */ |
786 | error = ifpromisc(ifs, 1); | | 786 | error = ifpromisc(ifs, 1); |
787 | if (error) | | 787 | if (error) |
788 | goto out; | | 788 | goto out; |
789 | break; | | 789 | break; |
790 | default: | | 790 | default: |
791 | error = EINVAL; | | 791 | error = EINVAL; |
792 | goto out; | | 792 | goto out; |
793 | } | | 793 | } |
794 | | | 794 | |
795 | bif->bif_ifp = ifs; | | 795 | bif->bif_ifp = ifs; |
796 | bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; | | 796 | bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; |
797 | bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY; | | 797 | bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY; |
798 | bif->bif_path_cost = BSTP_DEFAULT_PATH_COST; | | 798 | bif->bif_path_cost = BSTP_DEFAULT_PATH_COST; |
799 | PSLIST_ENTRY_INIT(bif, bif_next); | | 799 | PSLIST_ENTRY_INIT(bif, bif_next); |
800 | psref_target_init(&bif->bif_psref, bridge_psref_class); | | 800 | psref_target_init(&bif->bif_psref, bridge_psref_class); |
801 | | | 801 | |
802 | BRIDGE_LOCK(sc); | | 802 | BRIDGE_LOCK(sc); |
803 | | | 803 | |
804 | ifs->if_bridge = sc; | | 804 | ifs->if_bridge = sc; |
805 | ifs->if_bridgeif = bif; | | 805 | ifs->if_bridgeif = bif; |
806 | PSLIST_WRITER_INSERT_HEAD(&sc->sc_iflist_psref.bip_iflist, bif, bif_next); | | 806 | PSLIST_WRITER_INSERT_HEAD(&sc->sc_iflist_psref.bip_iflist, bif, bif_next); |
807 | ifs->_if_input = bridge_input; | | 807 | ifs->_if_input = bridge_input; |
808 | | | 808 | |
809 | BRIDGE_UNLOCK(sc); | | 809 | BRIDGE_UNLOCK(sc); |
810 | | | 810 | |
811 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 811 | if (sc->sc_if.if_flags & IFF_RUNNING) |
812 | bstp_initialization(sc); | | 812 | bstp_initialization(sc); |
813 | else | | 813 | else |
814 | bstp_stop(sc); | | 814 | bstp_stop(sc); |
815 | | | 815 | |
816 | out: | | 816 | out: |
817 | if_put(ifs, &psref); | | 817 | if_put(ifs, &psref); |
818 | if (error) { | | 818 | if (error) { |
819 | if (bif != NULL) | | 819 | if (bif != NULL) |
820 | kmem_free(bif, sizeof(*bif)); | | 820 | kmem_free(bif, sizeof(*bif)); |
821 | } | | 821 | } |
822 | return error; | | 822 | return error; |
823 | } | | 823 | } |
824 | | | 824 | |
825 | static int | | 825 | static int |
826 | bridge_ioctl_del(struct bridge_softc *sc, void *arg) | | 826 | bridge_ioctl_del(struct bridge_softc *sc, void *arg) |
827 | { | | 827 | { |
828 | struct ifbreq *req = arg; | | 828 | struct ifbreq *req = arg; |
829 | const char *name = req->ifbr_ifsname; | | 829 | const char *name = req->ifbr_ifsname; |
830 | struct bridge_iflist *bif; | | 830 | struct bridge_iflist *bif; |
831 | struct ifnet *ifs; | | 831 | struct ifnet *ifs; |
832 | | | 832 | |
833 | BRIDGE_LOCK(sc); | | 833 | BRIDGE_LOCK(sc); |
834 | | | 834 | |
835 | /* | | 835 | /* |
836 | * Don't use bridge_lookup_member. We want to get a member | | 836 | * Don't use bridge_lookup_member. We want to get a member |
837 | * with bif_refs == 0. | | 837 | * with bif_refs == 0. |
838 | */ | | 838 | */ |
839 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { | | 839 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { |
840 | ifs = bif->bif_ifp; | | 840 | ifs = bif->bif_ifp; |
841 | if (strcmp(ifs->if_xname, name) == 0) | | 841 | if (strcmp(ifs->if_xname, name) == 0) |
842 | break; | | 842 | break; |
843 | } | | 843 | } |
844 | | | 844 | |
845 | if (bif == NULL) { | | 845 | if (bif == NULL) { |
846 | BRIDGE_UNLOCK(sc); | | 846 | BRIDGE_UNLOCK(sc); |
847 | return ENOENT; | | 847 | return ENOENT; |
848 | } | | 848 | } |
849 | | | 849 | |
850 | bridge_delete_member(sc, bif); | | 850 | bridge_delete_member(sc, bif); |
851 | | | 851 | |
852 | BRIDGE_UNLOCK(sc); | | 852 | BRIDGE_UNLOCK(sc); |
853 | | | 853 | |
854 | switch (ifs->if_type) { | | 854 | switch (ifs->if_type) { |
855 | case IFT_ETHER: | | 855 | case IFT_ETHER: |
856 | case IFT_L2TP: | | 856 | case IFT_L2TP: |
857 | /* | | 857 | /* |
858 | * Take the interface out of promiscuous mode. | | 858 | * Take the interface out of promiscuous mode. |
859 | * Don't call it with holding a spin lock. | | 859 | * Don't call it with holding a spin lock. |
860 | */ | | 860 | */ |
861 | (void) ifpromisc(ifs, 0); | | 861 | (void) ifpromisc(ifs, 0); |
862 | IFNET_LOCK(ifs); | | 862 | IFNET_LOCK(ifs); |
863 | (void) ether_disable_vlan_mtu(ifs); | | 863 | (void) ether_disable_vlan_mtu(ifs); |
864 | IFNET_UNLOCK(ifs); | | 864 | IFNET_UNLOCK(ifs); |
865 | break; | | 865 | break; |
866 | default: | | 866 | default: |
867 | #ifdef DIAGNOSTIC | | 867 | #ifdef DIAGNOSTIC |
868 | panic("bridge_delete_member: impossible"); | | 868 | panic("bridge_delete_member: impossible"); |
869 | #endif | | 869 | #endif |
870 | break; | | 870 | break; |
871 | } | | 871 | } |
872 | | | 872 | |
873 | bridge_rtdelete(sc, ifs); | | 873 | bridge_rtdelete(sc, ifs); |
874 | | | 874 | |
875 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 875 | if (sc->sc_if.if_flags & IFF_RUNNING) |
876 | bstp_initialization(sc); | | 876 | bstp_initialization(sc); |
877 | | | 877 | |
878 | return 0; | | 878 | return 0; |
879 | } | | 879 | } |
880 | | | 880 | |
881 | static int | | 881 | static int |
882 | bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) | | 882 | bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) |
883 | { | | 883 | { |
884 | struct ifbreq *req = arg; | | 884 | struct ifbreq *req = arg; |
885 | struct bridge_iflist *bif; | | 885 | struct bridge_iflist *bif; |
886 | struct psref psref; | | 886 | struct psref psref; |
887 | | | 887 | |
888 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); | | 888 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); |
889 | if (bif == NULL) | | 889 | if (bif == NULL) |
890 | return ENOENT; | | 890 | return ENOENT; |
891 | | | 891 | |
892 | req->ifbr_ifsflags = bif->bif_flags; | | 892 | req->ifbr_ifsflags = bif->bif_flags; |
893 | req->ifbr_state = bif->bif_state; | | 893 | req->ifbr_state = bif->bif_state; |
894 | req->ifbr_priority = bif->bif_priority; | | 894 | req->ifbr_priority = bif->bif_priority; |
895 | req->ifbr_path_cost = bif->bif_path_cost; | | 895 | req->ifbr_path_cost = bif->bif_path_cost; |
896 | req->ifbr_portno = bif->bif_ifp->if_index & 0xff; | | 896 | req->ifbr_portno = bif->bif_ifp->if_index & 0xff; |
897 | | | 897 | |
898 | bridge_release_member(sc, bif, &psref); | | 898 | bridge_release_member(sc, bif, &psref); |
899 | | | 899 | |
900 | return 0; | | 900 | return 0; |
901 | } | | 901 | } |
902 | | | 902 | |
903 | static int | | 903 | static int |
904 | bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) | | 904 | bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) |
905 | { | | 905 | { |
906 | struct ifbreq *req = arg; | | 906 | struct ifbreq *req = arg; |
907 | struct bridge_iflist *bif; | | 907 | struct bridge_iflist *bif; |
908 | struct psref psref; | | 908 | struct psref psref; |
909 | | | 909 | |
910 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); | | 910 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); |
911 | if (bif == NULL) | | 911 | if (bif == NULL) |
912 | return ENOENT; | | 912 | return ENOENT; |
913 | | | 913 | |
914 | if (req->ifbr_ifsflags & IFBIF_STP) { | | 914 | if (req->ifbr_ifsflags & IFBIF_STP) { |
915 | switch (bif->bif_ifp->if_type) { | | 915 | switch (bif->bif_ifp->if_type) { |
916 | case IFT_ETHER: | | 916 | case IFT_ETHER: |
917 | case IFT_L2TP: | | 917 | case IFT_L2TP: |
918 | /* These can do spanning tree. */ | | 918 | /* These can do spanning tree. */ |
919 | break; | | 919 | break; |
920 | | | 920 | |
921 | default: | | 921 | default: |
922 | /* Nothing else can. */ | | 922 | /* Nothing else can. */ |
923 | bridge_release_member(sc, bif, &psref); | | 923 | bridge_release_member(sc, bif, &psref); |
924 | return EINVAL; | | 924 | return EINVAL; |
925 | } | | 925 | } |
926 | } | | 926 | } |
927 | | | 927 | |
928 | bif->bif_flags = req->ifbr_ifsflags; | | 928 | bif->bif_flags = req->ifbr_ifsflags; |
929 | | | 929 | |
930 | bridge_release_member(sc, bif, &psref); | | 930 | bridge_release_member(sc, bif, &psref); |
931 | | | 931 | |
932 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 932 | if (sc->sc_if.if_flags & IFF_RUNNING) |
933 | bstp_initialization(sc); | | 933 | bstp_initialization(sc); |
934 | | | 934 | |
935 | return 0; | | 935 | return 0; |
936 | } | | 936 | } |
937 | | | 937 | |
938 | static int | | 938 | static int |
939 | bridge_ioctl_scache(struct bridge_softc *sc, void *arg) | | 939 | bridge_ioctl_scache(struct bridge_softc *sc, void *arg) |
940 | { | | 940 | { |
941 | struct ifbrparam *param = arg; | | 941 | struct ifbrparam *param = arg; |
942 | | | 942 | |
943 | sc->sc_brtmax = param->ifbrp_csize; | | 943 | sc->sc_brtmax = param->ifbrp_csize; |
944 | bridge_rttrim(sc); | | 944 | bridge_rttrim(sc); |
945 | | | 945 | |
946 | return 0; | | 946 | return 0; |
947 | } | | 947 | } |
948 | | | 948 | |
949 | static int | | 949 | static int |
950 | bridge_ioctl_gcache(struct bridge_softc *sc, void *arg) | | 950 | bridge_ioctl_gcache(struct bridge_softc *sc, void *arg) |
951 | { | | 951 | { |
952 | struct ifbrparam *param = arg; | | 952 | struct ifbrparam *param = arg; |
953 | | | 953 | |
954 | param->ifbrp_csize = sc->sc_brtmax; | | 954 | param->ifbrp_csize = sc->sc_brtmax; |
955 | | | 955 | |
956 | return 0; | | 956 | return 0; |
957 | } | | 957 | } |
958 | | | 958 | |
959 | static int | | 959 | static int |
960 | bridge_ioctl_gifs(struct bridge_softc *sc, void *arg) | | 960 | bridge_ioctl_gifs(struct bridge_softc *sc, void *arg) |
961 | { | | 961 | { |
962 | struct ifbifconf *bifc = arg; | | 962 | struct ifbifconf *bifc = arg; |
963 | struct bridge_iflist *bif; | | 963 | struct bridge_iflist *bif; |
964 | struct ifbreq *breqs; | | 964 | struct ifbreq *breqs; |
965 | int i, count, error = 0; | | 965 | int i, count, error = 0; |
966 | | | 966 | |
967 | retry: | | 967 | retry: |
968 | BRIDGE_LOCK(sc); | | 968 | BRIDGE_LOCK(sc); |
969 | count = 0; | | 969 | count = 0; |
970 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) | | 970 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) |
971 | count++; | | 971 | count++; |
972 | BRIDGE_UNLOCK(sc); | | 972 | BRIDGE_UNLOCK(sc); |
973 | | | 973 | |
974 | if (count == 0) { | | 974 | if (count == 0) { |
975 | bifc->ifbic_len = 0; | | 975 | bifc->ifbic_len = 0; |
976 | return 0; | | 976 | return 0; |
977 | } | | 977 | } |
978 | | | 978 | |
979 | if (bifc->ifbic_len == 0 || bifc->ifbic_len < (sizeof(*breqs) * count)) { | | 979 | if (bifc->ifbic_len == 0 || bifc->ifbic_len < (sizeof(*breqs) * count)) { |
980 | /* Tell that a larger buffer is needed */ | | 980 | /* Tell that a larger buffer is needed */ |
981 | bifc->ifbic_len = sizeof(*breqs) * count; | | 981 | bifc->ifbic_len = sizeof(*breqs) * count; |
982 | return 0; | | 982 | return 0; |
983 | } | | 983 | } |
984 | | | 984 | |
985 | breqs = kmem_alloc(sizeof(*breqs) * count, KM_SLEEP); | | 985 | breqs = kmem_alloc(sizeof(*breqs) * count, KM_SLEEP); |
986 | | | 986 | |
987 | BRIDGE_LOCK(sc); | | 987 | BRIDGE_LOCK(sc); |
988 | | | 988 | |
989 | i = 0; | | 989 | i = 0; |
990 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) | | 990 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) |
991 | i++; | | 991 | i++; |
992 | if (i > count) { | | 992 | if (i > count) { |
993 | /* | | 993 | /* |
994 | * The number of members has been increased. | | 994 | * The number of members has been increased. |
995 | * We need more memory! | | 995 | * We need more memory! |
996 | */ | | 996 | */ |
997 | BRIDGE_UNLOCK(sc); | | 997 | BRIDGE_UNLOCK(sc); |
998 | kmem_free(breqs, sizeof(*breqs) * count); | | 998 | kmem_free(breqs, sizeof(*breqs) * count); |
999 | goto retry; | | 999 | goto retry; |
1000 | } | | 1000 | } |
1001 | | | 1001 | |
1002 | i = 0; | | 1002 | i = 0; |
1003 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { | | 1003 | BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { |
1004 | struct ifbreq *breq = &breqs[i++]; | | 1004 | struct ifbreq *breq = &breqs[i++]; |
1005 | memset(breq, 0, sizeof(*breq)); | | 1005 | memset(breq, 0, sizeof(*breq)); |
1006 | | | 1006 | |
1007 | strlcpy(breq->ifbr_ifsname, bif->bif_ifp->if_xname, | | 1007 | strlcpy(breq->ifbr_ifsname, bif->bif_ifp->if_xname, |
1008 | sizeof(breq->ifbr_ifsname)); | | 1008 | sizeof(breq->ifbr_ifsname)); |
1009 | breq->ifbr_ifsflags = bif->bif_flags; | | 1009 | breq->ifbr_ifsflags = bif->bif_flags; |
1010 | breq->ifbr_state = bif->bif_state; | | 1010 | breq->ifbr_state = bif->bif_state; |
1011 | breq->ifbr_priority = bif->bif_priority; | | 1011 | breq->ifbr_priority = bif->bif_priority; |
1012 | breq->ifbr_path_cost = bif->bif_path_cost; | | 1012 | breq->ifbr_path_cost = bif->bif_path_cost; |
1013 | breq->ifbr_portno = bif->bif_ifp->if_index & 0xff; | | 1013 | breq->ifbr_portno = bif->bif_ifp->if_index & 0xff; |
1014 | } | | 1014 | } |
1015 | | | 1015 | |
1016 | /* Don't call copyout with holding the mutex */ | | 1016 | /* Don't call copyout with holding the mutex */ |
1017 | BRIDGE_UNLOCK(sc); | | 1017 | BRIDGE_UNLOCK(sc); |
1018 | | | 1018 | |
1019 | for (i = 0; i < count; i++) { | | 1019 | for (i = 0; i < count; i++) { |
1020 | error = copyout(&breqs[i], bifc->ifbic_req + i, sizeof(*breqs)); | | 1020 | error = copyout(&breqs[i], bifc->ifbic_req + i, sizeof(*breqs)); |
1021 | if (error) | | 1021 | if (error) |
1022 | break; | | 1022 | break; |
1023 | } | | 1023 | } |
1024 | bifc->ifbic_len = sizeof(*breqs) * i; | | 1024 | bifc->ifbic_len = sizeof(*breqs) * i; |
1025 | | | 1025 | |
1026 | kmem_free(breqs, sizeof(*breqs) * count); | | 1026 | kmem_free(breqs, sizeof(*breqs) * count); |
1027 | | | 1027 | |
1028 | return error; | | 1028 | return error; |
1029 | } | | 1029 | } |
1030 | | | 1030 | |
1031 | static int | | 1031 | static int |
1032 | bridge_ioctl_rts(struct bridge_softc *sc, void *arg) | | 1032 | bridge_ioctl_rts(struct bridge_softc *sc, void *arg) |
1033 | { | | 1033 | { |
1034 | struct ifbaconf *bac = arg; | | 1034 | struct ifbaconf *bac = arg; |
1035 | struct bridge_rtnode *brt; | | 1035 | struct bridge_rtnode *brt; |
1036 | struct ifbareq bareq; | | 1036 | struct ifbareq bareq; |
1037 | int count = 0, error = 0, len; | | 1037 | int count = 0, error = 0, len; |
1038 | | | 1038 | |
1039 | if (bac->ifbac_len == 0) | | 1039 | if (bac->ifbac_len == 0) |
1040 | return 0; | | 1040 | return 0; |
1041 | | | 1041 | |
1042 | BRIDGE_RT_LOCK(sc); | | 1042 | BRIDGE_RT_LOCK(sc); |
1043 | | | 1043 | |
1044 | len = bac->ifbac_len; | | 1044 | len = bac->ifbac_len; |
1045 | LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { | | 1045 | LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { |
1046 | if (len < sizeof(bareq)) | | 1046 | if (len < sizeof(bareq)) |
1047 | goto out; | | 1047 | goto out; |
1048 | memset(&bareq, 0, sizeof(bareq)); | | 1048 | memset(&bareq, 0, sizeof(bareq)); |
1049 | strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, | | 1049 | strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, |
1050 | sizeof(bareq.ifba_ifsname)); | | 1050 | sizeof(bareq.ifba_ifsname)); |
1051 | memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); | | 1051 | memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); |
1052 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { | | 1052 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { |
1053 | bareq.ifba_expire = brt->brt_expire - time_uptime; | | 1053 | bareq.ifba_expire = brt->brt_expire - time_uptime; |
1054 | } else | | 1054 | } else |
1055 | bareq.ifba_expire = 0; | | 1055 | bareq.ifba_expire = 0; |
1056 | bareq.ifba_flags = brt->brt_flags; | | 1056 | bareq.ifba_flags = brt->brt_flags; |
1057 | | | 1057 | |
1058 | error = copyout(&bareq, bac->ifbac_req + count, sizeof(bareq)); | | 1058 | error = copyout(&bareq, bac->ifbac_req + count, sizeof(bareq)); |
1059 | if (error) | | 1059 | if (error) |
1060 | goto out; | | 1060 | goto out; |
1061 | count++; | | 1061 | count++; |
1062 | len -= sizeof(bareq); | | 1062 | len -= sizeof(bareq); |
1063 | } | | 1063 | } |
1064 | out: | | 1064 | out: |
1065 | BRIDGE_RT_UNLOCK(sc); | | 1065 | BRIDGE_RT_UNLOCK(sc); |
1066 | | | 1066 | |
1067 | bac->ifbac_len = sizeof(bareq) * count; | | 1067 | bac->ifbac_len = sizeof(bareq) * count; |
1068 | return error; | | 1068 | return error; |
1069 | } | | 1069 | } |
1070 | | | 1070 | |
1071 | static int | | 1071 | static int |
1072 | bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) | | 1072 | bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) |
1073 | { | | 1073 | { |
1074 | struct ifbareq *req = arg; | | 1074 | struct ifbareq *req = arg; |
1075 | struct bridge_iflist *bif; | | 1075 | struct bridge_iflist *bif; |
1076 | int error; | | 1076 | int error; |
1077 | struct psref psref; | | 1077 | struct psref psref; |
1078 | | | 1078 | |
1079 | bif = bridge_lookup_member(sc, req->ifba_ifsname, &psref); | | 1079 | bif = bridge_lookup_member(sc, req->ifba_ifsname, &psref); |
1080 | if (bif == NULL) | | 1080 | if (bif == NULL) |
1081 | return ENOENT; | | 1081 | return ENOENT; |
1082 | | | 1082 | |
1083 | error = bridge_rtupdate(sc, req->ifba_dst, bif->bif_ifp, 1, | | 1083 | error = bridge_rtupdate(sc, req->ifba_dst, bif->bif_ifp, 1, |
1084 | req->ifba_flags); | | 1084 | req->ifba_flags); |
1085 | | | 1085 | |
1086 | bridge_release_member(sc, bif, &psref); | | 1086 | bridge_release_member(sc, bif, &psref); |
1087 | | | 1087 | |
1088 | return error; | | 1088 | return error; |
1089 | } | | 1089 | } |
1090 | | | 1090 | |
1091 | static int | | 1091 | static int |
1092 | bridge_ioctl_sto(struct bridge_softc *sc, void *arg) | | 1092 | bridge_ioctl_sto(struct bridge_softc *sc, void *arg) |
1093 | { | | 1093 | { |
1094 | struct ifbrparam *param = arg; | | 1094 | struct ifbrparam *param = arg; |
1095 | | | 1095 | |
1096 | sc->sc_brttimeout = param->ifbrp_ctime; | | 1096 | sc->sc_brttimeout = param->ifbrp_ctime; |
1097 | | | 1097 | |
1098 | return 0; | | 1098 | return 0; |
1099 | } | | 1099 | } |
1100 | | | 1100 | |
1101 | static int | | 1101 | static int |
1102 | bridge_ioctl_gto(struct bridge_softc *sc, void *arg) | | 1102 | bridge_ioctl_gto(struct bridge_softc *sc, void *arg) |
1103 | { | | 1103 | { |
1104 | struct ifbrparam *param = arg; | | 1104 | struct ifbrparam *param = arg; |
1105 | | | 1105 | |
1106 | param->ifbrp_ctime = sc->sc_brttimeout; | | 1106 | param->ifbrp_ctime = sc->sc_brttimeout; |
1107 | | | 1107 | |
1108 | return 0; | | 1108 | return 0; |
1109 | } | | 1109 | } |
1110 | | | 1110 | |
1111 | static int | | 1111 | static int |
1112 | bridge_ioctl_daddr(struct bridge_softc *sc, void *arg) | | 1112 | bridge_ioctl_daddr(struct bridge_softc *sc, void *arg) |
1113 | { | | 1113 | { |
1114 | struct ifbareq *req = arg; | | 1114 | struct ifbareq *req = arg; |
1115 | | | 1115 | |
1116 | return (bridge_rtdaddr(sc, req->ifba_dst)); | | 1116 | return (bridge_rtdaddr(sc, req->ifba_dst)); |
1117 | } | | 1117 | } |
1118 | | | 1118 | |
1119 | static int | | 1119 | static int |
1120 | bridge_ioctl_flush(struct bridge_softc *sc, void *arg) | | 1120 | bridge_ioctl_flush(struct bridge_softc *sc, void *arg) |
1121 | { | | 1121 | { |
1122 | struct ifbreq *req = arg; | | 1122 | struct ifbreq *req = arg; |
1123 | | | 1123 | |
1124 | bridge_rtflush(sc, req->ifbr_ifsflags); | | 1124 | bridge_rtflush(sc, req->ifbr_ifsflags); |
1125 | | | 1125 | |
1126 | return 0; | | 1126 | return 0; |
1127 | } | | 1127 | } |
1128 | | | 1128 | |
1129 | static int | | 1129 | static int |
1130 | bridge_ioctl_gpri(struct bridge_softc *sc, void *arg) | | 1130 | bridge_ioctl_gpri(struct bridge_softc *sc, void *arg) |
1131 | { | | 1131 | { |
1132 | struct ifbrparam *param = arg; | | 1132 | struct ifbrparam *param = arg; |
1133 | | | 1133 | |
1134 | param->ifbrp_prio = sc->sc_bridge_priority; | | 1134 | param->ifbrp_prio = sc->sc_bridge_priority; |
1135 | | | 1135 | |
1136 | return 0; | | 1136 | return 0; |
1137 | } | | 1137 | } |
1138 | | | 1138 | |
1139 | static int | | 1139 | static int |
1140 | bridge_ioctl_spri(struct bridge_softc *sc, void *arg) | | 1140 | bridge_ioctl_spri(struct bridge_softc *sc, void *arg) |
1141 | { | | 1141 | { |
1142 | struct ifbrparam *param = arg; | | 1142 | struct ifbrparam *param = arg; |
1143 | | | 1143 | |
1144 | sc->sc_bridge_priority = param->ifbrp_prio; | | 1144 | sc->sc_bridge_priority = param->ifbrp_prio; |
1145 | | | 1145 | |
1146 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 1146 | if (sc->sc_if.if_flags & IFF_RUNNING) |
1147 | bstp_initialization(sc); | | 1147 | bstp_initialization(sc); |
1148 | | | 1148 | |
1149 | return 0; | | 1149 | return 0; |
1150 | } | | 1150 | } |
1151 | | | 1151 | |
1152 | static int | | 1152 | static int |
1153 | bridge_ioctl_ght(struct bridge_softc *sc, void *arg) | | 1153 | bridge_ioctl_ght(struct bridge_softc *sc, void *arg) |
1154 | { | | 1154 | { |
1155 | struct ifbrparam *param = arg; | | 1155 | struct ifbrparam *param = arg; |
1156 | | | 1156 | |
1157 | param->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8; | | 1157 | param->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8; |
1158 | | | 1158 | |
1159 | return 0; | | 1159 | return 0; |
1160 | } | | 1160 | } |
1161 | | | 1161 | |
1162 | static int | | 1162 | static int |
1163 | bridge_ioctl_sht(struct bridge_softc *sc, void *arg) | | 1163 | bridge_ioctl_sht(struct bridge_softc *sc, void *arg) |
1164 | { | | 1164 | { |
1165 | struct ifbrparam *param = arg; | | 1165 | struct ifbrparam *param = arg; |
1166 | | | 1166 | |
1167 | if (param->ifbrp_hellotime == 0) | | 1167 | if (param->ifbrp_hellotime == 0) |
1168 | return EINVAL; | | 1168 | return EINVAL; |
1169 | sc->sc_bridge_hello_time = param->ifbrp_hellotime << 8; | | 1169 | sc->sc_bridge_hello_time = param->ifbrp_hellotime << 8; |
1170 | | | 1170 | |
1171 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 1171 | if (sc->sc_if.if_flags & IFF_RUNNING) |
1172 | bstp_initialization(sc); | | 1172 | bstp_initialization(sc); |
1173 | | | 1173 | |
1174 | return 0; | | 1174 | return 0; |
1175 | } | | 1175 | } |
1176 | | | 1176 | |
1177 | static int | | 1177 | static int |
1178 | bridge_ioctl_gfd(struct bridge_softc *sc, void *arg) | | 1178 | bridge_ioctl_gfd(struct bridge_softc *sc, void *arg) |
1179 | { | | 1179 | { |
1180 | struct ifbrparam *param = arg; | | 1180 | struct ifbrparam *param = arg; |
1181 | | | 1181 | |
1182 | param->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8; | | 1182 | param->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8; |
1183 | | | 1183 | |
1184 | return 0; | | 1184 | return 0; |
1185 | } | | 1185 | } |
1186 | | | 1186 | |
1187 | static int | | 1187 | static int |
1188 | bridge_ioctl_sfd(struct bridge_softc *sc, void *arg) | | 1188 | bridge_ioctl_sfd(struct bridge_softc *sc, void *arg) |
1189 | { | | 1189 | { |
1190 | struct ifbrparam *param = arg; | | 1190 | struct ifbrparam *param = arg; |
1191 | | | 1191 | |
1192 | if (param->ifbrp_fwddelay == 0) | | 1192 | if (param->ifbrp_fwddelay == 0) |
1193 | return EINVAL; | | 1193 | return EINVAL; |
1194 | sc->sc_bridge_forward_delay = param->ifbrp_fwddelay << 8; | | 1194 | sc->sc_bridge_forward_delay = param->ifbrp_fwddelay << 8; |
1195 | | | 1195 | |
1196 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 1196 | if (sc->sc_if.if_flags & IFF_RUNNING) |
1197 | bstp_initialization(sc); | | 1197 | bstp_initialization(sc); |
1198 | | | 1198 | |
1199 | return 0; | | 1199 | return 0; |
1200 | } | | 1200 | } |
1201 | | | 1201 | |
1202 | static int | | 1202 | static int |
1203 | bridge_ioctl_gma(struct bridge_softc *sc, void *arg) | | 1203 | bridge_ioctl_gma(struct bridge_softc *sc, void *arg) |
1204 | { | | 1204 | { |
1205 | struct ifbrparam *param = arg; | | 1205 | struct ifbrparam *param = arg; |
1206 | | | 1206 | |
1207 | param->ifbrp_maxage = sc->sc_bridge_max_age >> 8; | | 1207 | param->ifbrp_maxage = sc->sc_bridge_max_age >> 8; |
1208 | | | 1208 | |
1209 | return 0; | | 1209 | return 0; |
1210 | } | | 1210 | } |
1211 | | | 1211 | |
1212 | static int | | 1212 | static int |
1213 | bridge_ioctl_sma(struct bridge_softc *sc, void *arg) | | 1213 | bridge_ioctl_sma(struct bridge_softc *sc, void *arg) |
1214 | { | | 1214 | { |
1215 | struct ifbrparam *param = arg; | | 1215 | struct ifbrparam *param = arg; |
1216 | | | 1216 | |
1217 | if (param->ifbrp_maxage == 0) | | 1217 | if (param->ifbrp_maxage == 0) |
1218 | return EINVAL; | | 1218 | return EINVAL; |
1219 | sc->sc_bridge_max_age = param->ifbrp_maxage << 8; | | 1219 | sc->sc_bridge_max_age = param->ifbrp_maxage << 8; |
1220 | | | 1220 | |
1221 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 1221 | if (sc->sc_if.if_flags & IFF_RUNNING) |
1222 | bstp_initialization(sc); | | 1222 | bstp_initialization(sc); |
1223 | | | 1223 | |
1224 | return 0; | | 1224 | return 0; |
1225 | } | | 1225 | } |
1226 | | | 1226 | |
1227 | static int | | 1227 | static int |
1228 | bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) | | 1228 | bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) |
1229 | { | | 1229 | { |
1230 | struct ifbreq *req = arg; | | 1230 | struct ifbreq *req = arg; |
1231 | struct bridge_iflist *bif; | | 1231 | struct bridge_iflist *bif; |
1232 | struct psref psref; | | 1232 | struct psref psref; |
1233 | | | 1233 | |
1234 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); | | 1234 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); |
1235 | if (bif == NULL) | | 1235 | if (bif == NULL) |
1236 | return ENOENT; | | 1236 | return ENOENT; |
1237 | | | 1237 | |
1238 | bif->bif_priority = req->ifbr_priority; | | 1238 | bif->bif_priority = req->ifbr_priority; |
1239 | | | 1239 | |
1240 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 1240 | if (sc->sc_if.if_flags & IFF_RUNNING) |
1241 | bstp_initialization(sc); | | 1241 | bstp_initialization(sc); |
1242 | | | 1242 | |
1243 | bridge_release_member(sc, bif, &psref); | | 1243 | bridge_release_member(sc, bif, &psref); |
1244 | | | 1244 | |
1245 | return 0; | | 1245 | return 0; |
1246 | } | | 1246 | } |
1247 | | | 1247 | |
1248 | #if defined(BRIDGE_IPF) | | 1248 | #if defined(BRIDGE_IPF) |
1249 | static int | | 1249 | static int |
1250 | bridge_ioctl_gfilt(struct bridge_softc *sc, void *arg) | | 1250 | bridge_ioctl_gfilt(struct bridge_softc *sc, void *arg) |
1251 | { | | 1251 | { |
1252 | struct ifbrparam *param = arg; | | 1252 | struct ifbrparam *param = arg; |
1253 | | | 1253 | |
1254 | param->ifbrp_filter = sc->sc_filter_flags; | | 1254 | param->ifbrp_filter = sc->sc_filter_flags; |
1255 | | | 1255 | |
1256 | return 0; | | 1256 | return 0; |
1257 | } | | 1257 | } |
1258 | | | 1258 | |
1259 | static int | | 1259 | static int |
1260 | bridge_ioctl_sfilt(struct bridge_softc *sc, void *arg) | | 1260 | bridge_ioctl_sfilt(struct bridge_softc *sc, void *arg) |
1261 | { | | 1261 | { |
1262 | struct ifbrparam *param = arg; | | 1262 | struct ifbrparam *param = arg; |
1263 | uint32_t nflags, oflags; | | 1263 | uint32_t nflags, oflags; |
1264 | | | 1264 | |
1265 | if (param->ifbrp_filter & ~IFBF_FILT_MASK) | | 1265 | if (param->ifbrp_filter & ~IFBF_FILT_MASK) |
1266 | return EINVAL; | | 1266 | return EINVAL; |
1267 | | | 1267 | |
1268 | nflags = param->ifbrp_filter; | | 1268 | nflags = param->ifbrp_filter; |
1269 | oflags = sc->sc_filter_flags; | | 1269 | oflags = sc->sc_filter_flags; |
1270 | | | 1270 | |
1271 | if ((nflags & IFBF_FILT_USEIPF) && !(oflags & IFBF_FILT_USEIPF)) { | | 1271 | if ((nflags & IFBF_FILT_USEIPF) && !(oflags & IFBF_FILT_USEIPF)) { |
1272 | pfil_add_hook((void *)bridge_ipf, NULL, PFIL_IN|PFIL_OUT, | | 1272 | pfil_add_hook((void *)bridge_ipf, NULL, PFIL_IN|PFIL_OUT, |
1273 | sc->sc_if.if_pfil); | | 1273 | sc->sc_if.if_pfil); |
1274 | } | | 1274 | } |
1275 | if (!(nflags & IFBF_FILT_USEIPF) && (oflags & IFBF_FILT_USEIPF)) { | | 1275 | if (!(nflags & IFBF_FILT_USEIPF) && (oflags & IFBF_FILT_USEIPF)) { |
1276 | pfil_remove_hook((void *)bridge_ipf, NULL, PFIL_IN|PFIL_OUT, | | 1276 | pfil_remove_hook((void *)bridge_ipf, NULL, PFIL_IN|PFIL_OUT, |
1277 | sc->sc_if.if_pfil); | | 1277 | sc->sc_if.if_pfil); |
1278 | } | | 1278 | } |
1279 | | | 1279 | |
1280 | sc->sc_filter_flags = nflags; | | 1280 | sc->sc_filter_flags = nflags; |
1281 | | | 1281 | |
1282 | return 0; | | 1282 | return 0; |
1283 | } | | 1283 | } |
1284 | #endif /* BRIDGE_IPF */ | | 1284 | #endif /* BRIDGE_IPF */ |
1285 | | | 1285 | |
1286 | static int | | 1286 | static int |
1287 | bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) | | 1287 | bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) |
1288 | { | | 1288 | { |
1289 | struct ifbreq *req = arg; | | 1289 | struct ifbreq *req = arg; |
1290 | struct bridge_iflist *bif; | | 1290 | struct bridge_iflist *bif; |
1291 | struct psref psref; | | 1291 | struct psref psref; |
1292 | | | 1292 | |
1293 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); | | 1293 | bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); |
1294 | if (bif == NULL) | | 1294 | if (bif == NULL) |
1295 | return ENOENT; | | 1295 | return ENOENT; |
1296 | | | 1296 | |
1297 | bif->bif_path_cost = req->ifbr_path_cost; | | 1297 | bif->bif_path_cost = req->ifbr_path_cost; |
1298 | | | 1298 | |
1299 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 1299 | if (sc->sc_if.if_flags & IFF_RUNNING) |
1300 | bstp_initialization(sc); | | 1300 | bstp_initialization(sc); |
1301 | | | 1301 | |
1302 | bridge_release_member(sc, bif, &psref); | | 1302 | bridge_release_member(sc, bif, &psref); |
1303 | | | 1303 | |
1304 | return 0; | | 1304 | return 0; |
1305 | } | | 1305 | } |
1306 | | | 1306 | |
1307 | /* | | 1307 | /* |
1308 | * bridge_ifdetach: | | 1308 | * bridge_ifdetach: |
1309 | * | | 1309 | * |
1310 | * Detach an interface from a bridge. Called when a member | | 1310 | * Detach an interface from a bridge. Called when a member |
1311 | * interface is detaching. | | 1311 | * interface is detaching. |
1312 | */ | | 1312 | */ |
1313 | void | | 1313 | void |
1314 | bridge_ifdetach(struct ifnet *ifp) | | 1314 | bridge_ifdetach(struct ifnet *ifp) |
1315 | { | | 1315 | { |
1316 | struct bridge_softc *sc = ifp->if_bridge; | | 1316 | struct bridge_softc *sc = ifp->if_bridge; |
1317 | struct ifbreq breq; | | 1317 | struct ifbreq breq; |
1318 | | | 1318 | |
1319 | /* ioctl_lock should prevent this from happening */ | | 1319 | /* ioctl_lock should prevent this from happening */ |
1320 | KASSERT(sc != NULL); | | 1320 | KASSERT(sc != NULL); |
1321 | | | 1321 | |
1322 | memset(&breq, 0, sizeof(breq)); | | 1322 | memset(&breq, 0, sizeof(breq)); |
1323 | strlcpy(breq.ifbr_ifsname, ifp->if_xname, sizeof(breq.ifbr_ifsname)); | | 1323 | strlcpy(breq.ifbr_ifsname, ifp->if_xname, sizeof(breq.ifbr_ifsname)); |
1324 | | | 1324 | |
1325 | (void) bridge_ioctl_del(sc, &breq); | | 1325 | (void) bridge_ioctl_del(sc, &breq); |
1326 | } | | 1326 | } |
1327 | | | 1327 | |
1328 | /* | | 1328 | /* |
1329 | * bridge_init: | | 1329 | * bridge_init: |
1330 | * | | 1330 | * |
1331 | * Initialize a bridge interface. | | 1331 | * Initialize a bridge interface. |
1332 | */ | | 1332 | */ |
1333 | static int | | 1333 | static int |
1334 | bridge_init(struct ifnet *ifp) | | 1334 | bridge_init(struct ifnet *ifp) |
1335 | { | | 1335 | { |
1336 | struct bridge_softc *sc = ifp->if_softc; | | 1336 | struct bridge_softc *sc = ifp->if_softc; |
1337 | | | 1337 | |
1338 | KASSERT((ifp->if_flags & IFF_RUNNING) == 0); | | 1338 | KASSERT((ifp->if_flags & IFF_RUNNING) == 0); |
1339 | | | 1339 | |
1340 | callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, | | 1340 | callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, |
1341 | bridge_timer, sc); | | 1341 | bridge_timer, sc); |
1342 | bstp_initialization(sc); | | 1342 | bstp_initialization(sc); |
1343 | | | 1343 | |
1344 | ifp->if_flags |= IFF_RUNNING; | | 1344 | ifp->if_flags |= IFF_RUNNING; |
1345 | return 0; | | 1345 | return 0; |
1346 | } | | 1346 | } |
1347 | | | 1347 | |
1348 | /* | | 1348 | /* |
1349 | * bridge_stop: | | 1349 | * bridge_stop: |
1350 | * | | 1350 | * |
1351 | * Stop the bridge interface. | | 1351 | * Stop the bridge interface. |
1352 | */ | | 1352 | */ |
1353 | static void | | 1353 | static void |
1354 | bridge_stop(struct ifnet *ifp, int disable) | | 1354 | bridge_stop(struct ifnet *ifp, int disable) |
1355 | { | | 1355 | { |
1356 | struct bridge_softc *sc = ifp->if_softc; | | 1356 | struct bridge_softc *sc = ifp->if_softc; |
1357 | | | 1357 | |
1358 | KASSERT((ifp->if_flags & IFF_RUNNING) != 0); | | 1358 | KASSERT((ifp->if_flags & IFF_RUNNING) != 0); |
1359 | ifp->if_flags &= ~IFF_RUNNING; | | 1359 | ifp->if_flags &= ~IFF_RUNNING; |
1360 | | | 1360 | |
1361 | callout_stop(&sc->sc_brcallout); | | 1361 | callout_halt(&sc->sc_brcallout, NULL); |
| | | 1362 | workqueue_wait(sc->sc_rtage_wq, &sc->sc_rtage_wk); |
1362 | bstp_stop(sc); | | 1363 | bstp_stop(sc); |
1363 | bridge_rtflush(sc, IFBF_FLUSHDYN); | | 1364 | bridge_rtflush(sc, IFBF_FLUSHDYN); |
1364 | } | | 1365 | } |
1365 | | | 1366 | |
1366 | /* | | 1367 | /* |
1367 | * bridge_enqueue: | | 1368 | * bridge_enqueue: |
1368 | * | | 1369 | * |
1369 | * Enqueue a packet on a bridge member interface. | | 1370 | * Enqueue a packet on a bridge member interface. |
1370 | */ | | 1371 | */ |
1371 | void | | 1372 | void |
1372 | bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m, | | 1373 | bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m, |
1373 | int runfilt) | | 1374 | int runfilt) |
1374 | { | | 1375 | { |
1375 | int len, error; | | 1376 | int len, error; |
1376 | short mflags; | | 1377 | short mflags; |
1377 | | | 1378 | |
1378 | /* | | 1379 | /* |
1379 | * Clear any in-bound checksum flags for this packet. | | 1380 | * Clear any in-bound checksum flags for this packet. |
1380 | */ | | 1381 | */ |
1381 | m->m_pkthdr.csum_flags = 0; | | 1382 | m->m_pkthdr.csum_flags = 0; |
1382 | | | 1383 | |
1383 | if (runfilt) { | | 1384 | if (runfilt) { |
1384 | if (pfil_run_hooks(sc->sc_if.if_pfil, &m, | | 1385 | if (pfil_run_hooks(sc->sc_if.if_pfil, &m, |
1385 | dst_ifp, PFIL_OUT) != 0) { | | 1386 | dst_ifp, PFIL_OUT) != 0) { |
1386 | if (m != NULL) | | 1387 | if (m != NULL) |
1387 | m_freem(m); | | 1388 | m_freem(m); |
1388 | return; | | 1389 | return; |
1389 | } | | 1390 | } |
1390 | if (m == NULL) | | 1391 | if (m == NULL) |
1391 | return; | | 1392 | return; |
1392 | } | | 1393 | } |
1393 | | | 1394 | |
1394 | #ifdef ALTQ | | 1395 | #ifdef ALTQ |
1395 | KERNEL_LOCK(1, NULL); | | 1396 | KERNEL_LOCK(1, NULL); |
1396 | /* | | 1397 | /* |
1397 | * If ALTQ is enabled on the member interface, do | | 1398 | * If ALTQ is enabled on the member interface, do |
1398 | * classification; the queueing discipline might | | 1399 | * classification; the queueing discipline might |
1399 | * not require classification, but might require | | 1400 | * not require classification, but might require |
1400 | * the address family/header pointer in the pktattr. | | 1401 | * the address family/header pointer in the pktattr. |
1401 | */ | | 1402 | */ |
1402 | if (ALTQ_IS_ENABLED(&dst_ifp->if_snd)) { | | 1403 | if (ALTQ_IS_ENABLED(&dst_ifp->if_snd)) { |
1403 | /* XXX IFT_ETHER */ | | 1404 | /* XXX IFT_ETHER */ |
1404 | altq_etherclassify(&dst_ifp->if_snd, m); | | 1405 | altq_etherclassify(&dst_ifp->if_snd, m); |
1405 | } | | 1406 | } |
1406 | KERNEL_UNLOCK_ONE(NULL); | | 1407 | KERNEL_UNLOCK_ONE(NULL); |
1407 | #endif /* ALTQ */ | | 1408 | #endif /* ALTQ */ |
1408 | | | 1409 | |
1409 | len = m->m_pkthdr.len; | | 1410 | len = m->m_pkthdr.len; |
1410 | mflags = m->m_flags; | | 1411 | mflags = m->m_flags; |
1411 | | | 1412 | |
1412 | error = if_transmit_lock(dst_ifp, m); | | 1413 | error = if_transmit_lock(dst_ifp, m); |
1413 | if (error) { | | 1414 | if (error) { |
1414 | /* mbuf is already freed */ | | 1415 | /* mbuf is already freed */ |
1415 | sc->sc_if.if_oerrors++; | | 1416 | sc->sc_if.if_oerrors++; |
1416 | return; | | 1417 | return; |
1417 | } | | 1418 | } |
1418 | | | 1419 | |
1419 | sc->sc_if.if_opackets++; | | 1420 | sc->sc_if.if_opackets++; |
1420 | sc->sc_if.if_obytes += len; | | 1421 | sc->sc_if.if_obytes += len; |
1421 | if (mflags & M_MCAST) | | 1422 | if (mflags & M_MCAST) |
1422 | sc->sc_if.if_omcasts++; | | 1423 | sc->sc_if.if_omcasts++; |
1423 | } | | 1424 | } |
1424 | | | 1425 | |
1425 | /* | | 1426 | /* |
1426 | * bridge_output: | | 1427 | * bridge_output: |
1427 | * | | 1428 | * |
1428 | * Send output from a bridge member interface. This | | 1429 | * Send output from a bridge member interface. This |
1429 | * performs the bridging function for locally originated | | 1430 | * performs the bridging function for locally originated |
1430 | * packets. | | 1431 | * packets. |
1431 | * | | 1432 | * |
1432 | * The mbuf has the Ethernet header already attached. We must | | 1433 | * The mbuf has the Ethernet header already attached. We must |
1433 | * enqueue or free the mbuf before returning. | | 1434 | * enqueue or free the mbuf before returning. |
1434 | */ | | 1435 | */ |
1435 | int | | 1436 | int |
1436 | bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, | | 1437 | bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, |
1437 | const struct rtentry *rt) | | 1438 | const struct rtentry *rt) |
1438 | { | | 1439 | { |
1439 | struct ether_header *eh; | | 1440 | struct ether_header *eh; |
1440 | struct ifnet *dst_if; | | 1441 | struct ifnet *dst_if; |
1441 | struct bridge_softc *sc; | | 1442 | struct bridge_softc *sc; |
1442 | int s; | | 1443 | int s; |
1443 | | | 1444 | |
1444 | /* | | 1445 | /* |
1445 | * bridge_output() is called from ether_output(), furthermore | | 1446 | * bridge_output() is called from ether_output(), furthermore |
1446 | * ifp argument doesn't point to bridge(4). So, don't assert | | 1447 | * ifp argument doesn't point to bridge(4). So, don't assert |
1447 | * IFEF_MPSAFE here. | | 1448 | * IFEF_MPSAFE here. |
1448 | */ | | 1449 | */ |
1449 | | | 1450 | |
1450 | if (m->m_len < ETHER_HDR_LEN) { | | 1451 | if (m->m_len < ETHER_HDR_LEN) { |
1451 | m = m_pullup(m, ETHER_HDR_LEN); | | 1452 | m = m_pullup(m, ETHER_HDR_LEN); |
1452 | if (m == NULL) | | 1453 | if (m == NULL) |
1453 | return 0; | | 1454 | return 0; |
1454 | } | | 1455 | } |
1455 | | | 1456 | |
1456 | eh = mtod(m, struct ether_header *); | | 1457 | eh = mtod(m, struct ether_header *); |
1457 | sc = ifp->if_bridge; | | 1458 | sc = ifp->if_bridge; |
1458 | | | 1459 | |
1459 | if (ETHER_IS_MULTICAST(eh->ether_dhost)) { | | 1460 | if (ETHER_IS_MULTICAST(eh->ether_dhost)) { |
1460 | if (memcmp(etherbroadcastaddr, | | 1461 | if (memcmp(etherbroadcastaddr, |
1461 | eh->ether_dhost, ETHER_ADDR_LEN) == 0) | | 1462 | eh->ether_dhost, ETHER_ADDR_LEN) == 0) |
1462 | m->m_flags |= M_BCAST; | | 1463 | m->m_flags |= M_BCAST; |
1463 | else | | 1464 | else |
1464 | m->m_flags |= M_MCAST; | | 1465 | m->m_flags |= M_MCAST; |
1465 | } | | 1466 | } |
1466 | | | 1467 | |
1467 | /* | | 1468 | /* |
1468 | * If bridge is down, but the original output interface is up, | | 1469 | * If bridge is down, but the original output interface is up, |
1469 | * go ahead and send out that interface. Otherwise, the packet | | 1470 | * go ahead and send out that interface. Otherwise, the packet |
1470 | * is dropped below. | | 1471 | * is dropped below. |
1471 | */ | | 1472 | */ |
1472 | if (__predict_false(sc == NULL) || | | 1473 | if (__predict_false(sc == NULL) || |
1473 | (sc->sc_if.if_flags & IFF_RUNNING) == 0) { | | 1474 | (sc->sc_if.if_flags & IFF_RUNNING) == 0) { |
1474 | dst_if = ifp; | | 1475 | dst_if = ifp; |
1475 | goto sendunicast; | | 1476 | goto sendunicast; |
1476 | } | | 1477 | } |
1477 | | | 1478 | |
1478 | /* | | 1479 | /* |
1479 | * If the packet is a multicast, or we don't know a better way to | | 1480 | * If the packet is a multicast, or we don't know a better way to |
1480 | * get there, send to all interfaces. | | 1481 | * get there, send to all interfaces. |
1481 | */ | | 1482 | */ |
1482 | if ((m->m_flags & (M_MCAST | M_BCAST)) != 0) | | 1483 | if ((m->m_flags & (M_MCAST | M_BCAST)) != 0) |
1483 | dst_if = NULL; | | 1484 | dst_if = NULL; |
1484 | else | | 1485 | else |
1485 | dst_if = bridge_rtlookup(sc, eh->ether_dhost); | | 1486 | dst_if = bridge_rtlookup(sc, eh->ether_dhost); |
1486 | if (dst_if == NULL) { | | 1487 | if (dst_if == NULL) { |
1487 | /* XXX Should call bridge_broadcast, but there are locking | | 1488 | /* XXX Should call bridge_broadcast, but there are locking |
1488 | * issues which need resolving first. */ | | 1489 | * issues which need resolving first. */ |
1489 | struct bridge_iflist *bif; | | 1490 | struct bridge_iflist *bif; |
1490 | struct mbuf *mc; | | 1491 | struct mbuf *mc; |
1491 | bool used = false; | | 1492 | bool used = false; |
1492 | | | 1493 | |
1493 | BRIDGE_PSZ_RENTER(s); | | 1494 | BRIDGE_PSZ_RENTER(s); |
1494 | BRIDGE_IFLIST_READER_FOREACH(bif, sc) { | | 1495 | BRIDGE_IFLIST_READER_FOREACH(bif, sc) { |
1495 | struct psref psref; | | 1496 | struct psref psref; |
1496 | | | 1497 | |
1497 | bridge_acquire_member(sc, bif, &psref); | | 1498 | bridge_acquire_member(sc, bif, &psref); |
1498 | BRIDGE_PSZ_REXIT(s); | | 1499 | BRIDGE_PSZ_REXIT(s); |
1499 | | | 1500 | |
1500 | dst_if = bif->bif_ifp; | | 1501 | dst_if = bif->bif_ifp; |
1501 | if ((dst_if->if_flags & IFF_RUNNING) == 0) | | 1502 | if ((dst_if->if_flags & IFF_RUNNING) == 0) |
1502 | goto next; | | 1503 | goto next; |
1503 | | | 1504 | |
1504 | /* | | 1505 | /* |
1505 | * If this is not the original output interface, | | 1506 | * If this is not the original output interface, |
1506 | * and the interface is participating in spanning | | 1507 | * and the interface is participating in spanning |
1507 | * tree, make sure the port is in a state that | | 1508 | * tree, make sure the port is in a state that |
1508 | * allows forwarding. | | 1509 | * allows forwarding. |
1509 | */ | | 1510 | */ |
1510 | if (dst_if != ifp && | | 1511 | if (dst_if != ifp && |
1511 | (bif->bif_flags & IFBIF_STP) != 0) { | | 1512 | (bif->bif_flags & IFBIF_STP) != 0) { |
1512 | switch (bif->bif_state) { | | 1513 | switch (bif->bif_state) { |
1513 | case BSTP_IFSTATE_BLOCKING: | | 1514 | case BSTP_IFSTATE_BLOCKING: |
1514 | case BSTP_IFSTATE_LISTENING: | | 1515 | case BSTP_IFSTATE_LISTENING: |
1515 | case BSTP_IFSTATE_DISABLED: | | 1516 | case BSTP_IFSTATE_DISABLED: |
1516 | goto next; | | 1517 | goto next; |
1517 | } | | 1518 | } |
1518 | } | | 1519 | } |
1519 | | | 1520 | |
1520 | if (PSLIST_READER_NEXT(bif, struct bridge_iflist, | | 1521 | if (PSLIST_READER_NEXT(bif, struct bridge_iflist, |
1521 | bif_next) == NULL && | | 1522 | bif_next) == NULL && |
1522 | ((m->m_flags & (M_MCAST | M_BCAST)) == 0 || | | 1523 | ((m->m_flags & (M_MCAST | M_BCAST)) == 0 || |
1523 | dst_if == ifp)) | | 1524 | dst_if == ifp)) |
1524 | { | | 1525 | { |
1525 | used = true; | | 1526 | used = true; |
1526 | mc = m; | | 1527 | mc = m; |
1527 | } else { | | 1528 | } else { |
1528 | mc = m_copym(m, 0, M_COPYALL, M_NOWAIT); | | 1529 | mc = m_copym(m, 0, M_COPYALL, M_NOWAIT); |
1529 | if (mc == NULL) { | | 1530 | if (mc == NULL) { |
1530 | sc->sc_if.if_oerrors++; | | 1531 | sc->sc_if.if_oerrors++; |
1531 | goto next; | | 1532 | goto next; |
1532 | } | | 1533 | } |
1533 | } | | 1534 | } |
1534 | | | 1535 | |
1535 | bridge_enqueue(sc, dst_if, mc, 0); | | 1536 | bridge_enqueue(sc, dst_if, mc, 0); |
1536 | | | 1537 | |
1537 | if ((m->m_flags & (M_MCAST | M_BCAST)) != 0 && | | 1538 | if ((m->m_flags & (M_MCAST | M_BCAST)) != 0 && |
1538 | dst_if != ifp) | | 1539 | dst_if != ifp) |
1539 | { | | 1540 | { |
1540 | if (PSLIST_READER_NEXT(bif, | | 1541 | if (PSLIST_READER_NEXT(bif, |
1541 | struct bridge_iflist, bif_next) == NULL) | | 1542 | struct bridge_iflist, bif_next) == NULL) |
1542 | { | | 1543 | { |
1543 | used = true; | | 1544 | used = true; |
1544 | mc = m; | | 1545 | mc = m; |
1545 | } else { | | 1546 | } else { |
1546 | mc = m_copym(m, 0, M_COPYALL, | | 1547 | mc = m_copym(m, 0, M_COPYALL, |
1547 | M_DONTWAIT); | | 1548 | M_DONTWAIT); |
1548 | if (mc == NULL) { | | 1549 | if (mc == NULL) { |
1549 | sc->sc_if.if_oerrors++; | | 1550 | sc->sc_if.if_oerrors++; |
1550 | goto next; | | 1551 | goto next; |
1551 | } | | 1552 | } |
1552 | } | | 1553 | } |
1553 | | | 1554 | |
1554 | m_set_rcvif(mc, dst_if); | | 1555 | m_set_rcvif(mc, dst_if); |
1555 | mc->m_flags &= ~M_PROMISC; | | 1556 | mc->m_flags &= ~M_PROMISC; |
1556 | | | 1557 | |
1557 | #ifndef NET_MPSAFE | | 1558 | #ifndef NET_MPSAFE |
1558 | s = splsoftnet(); | | 1559 | s = splsoftnet(); |
1559 | #endif | | 1560 | #endif |
1560 | ether_input(dst_if, mc); | | 1561 | ether_input(dst_if, mc); |
1561 | #ifndef NET_MPSAFE | | 1562 | #ifndef NET_MPSAFE |
1562 | splx(s); | | 1563 | splx(s); |
1563 | #endif | | 1564 | #endif |
1564 | } | | 1565 | } |
1565 | | | 1566 | |
1566 | next: | | 1567 | next: |
1567 | BRIDGE_PSZ_RENTER(s); | | 1568 | BRIDGE_PSZ_RENTER(s); |
1568 | bridge_release_member(sc, bif, &psref); | | 1569 | bridge_release_member(sc, bif, &psref); |
1569 | | | 1570 | |
1570 | /* Guarantee we don't re-enter the loop as we already | | 1571 | /* Guarantee we don't re-enter the loop as we already |
1571 | * decided we're at the end. */ | | 1572 | * decided we're at the end. */ |
1572 | if (used) | | 1573 | if (used) |
1573 | break; | | 1574 | break; |
1574 | } | | 1575 | } |
1575 | BRIDGE_PSZ_REXIT(s); | | 1576 | BRIDGE_PSZ_REXIT(s); |
1576 | | | 1577 | |
1577 | if (!used) | | 1578 | if (!used) |
1578 | m_freem(m); | | 1579 | m_freem(m); |
1579 | return 0; | | 1580 | return 0; |
1580 | } | | 1581 | } |
1581 | | | 1582 | |
1582 | sendunicast: | | 1583 | sendunicast: |
1583 | /* | | 1584 | /* |
1584 | * XXX Spanning tree consideration here? | | 1585 | * XXX Spanning tree consideration here? |
1585 | */ | | 1586 | */ |
1586 | | | 1587 | |
1587 | if ((dst_if->if_flags & IFF_RUNNING) == 0) { | | 1588 | if ((dst_if->if_flags & IFF_RUNNING) == 0) { |
1588 | m_freem(m); | | 1589 | m_freem(m); |
1589 | return 0; | | 1590 | return 0; |
1590 | } | | 1591 | } |
1591 | | | 1592 | |
1592 | bridge_enqueue(sc, dst_if, m, 0); | | 1593 | bridge_enqueue(sc, dst_if, m, 0); |
1593 | | | 1594 | |
1594 | return 0; | | 1595 | return 0; |
1595 | } | | 1596 | } |
1596 | | | 1597 | |
1597 | /* | | 1598 | /* |
1598 | * bridge_start: | | 1599 | * bridge_start: |
1599 | * | | 1600 | * |
1600 | * Start output on a bridge. | | 1601 | * Start output on a bridge. |
1601 | * | | 1602 | * |
1602 | * NOTE: This routine should never be called in this implementation. | | 1603 | * NOTE: This routine should never be called in this implementation. |
1603 | */ | | 1604 | */ |
1604 | static void | | 1605 | static void |
1605 | bridge_start(struct ifnet *ifp) | | 1606 | bridge_start(struct ifnet *ifp) |
1606 | { | | 1607 | { |
1607 | | | 1608 | |
1608 | printf("%s: bridge_start() called\n", ifp->if_xname); | | 1609 | printf("%s: bridge_start() called\n", ifp->if_xname); |
1609 | } | | 1610 | } |
1610 | | | 1611 | |
1611 | /* | | 1612 | /* |
1612 | * bridge_forward: | | 1613 | * bridge_forward: |
1613 | * | | 1614 | * |
1614 | * The forwarding function of the bridge. | | 1615 | * The forwarding function of the bridge. |
1615 | */ | | 1616 | */ |
1616 | static void | | 1617 | static void |
1617 | bridge_forward(struct bridge_softc *sc, struct mbuf *m) | | 1618 | bridge_forward(struct bridge_softc *sc, struct mbuf *m) |
1618 | { | | 1619 | { |
1619 | struct bridge_iflist *bif; | | 1620 | struct bridge_iflist *bif; |
1620 | struct ifnet *src_if, *dst_if; | | 1621 | struct ifnet *src_if, *dst_if; |
1621 | struct ether_header *eh; | | 1622 | struct ether_header *eh; |
1622 | struct psref psref; | | 1623 | struct psref psref; |
1623 | struct psref psref_src; | | 1624 | struct psref psref_src; |
1624 | DECLARE_LOCK_VARIABLE; | | 1625 | DECLARE_LOCK_VARIABLE; |
1625 | | | 1626 | |
1626 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) | | 1627 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
1627 | return; | | 1628 | return; |
1628 | | | 1629 | |
1629 | src_if = m_get_rcvif_psref(m, &psref_src); | | 1630 | src_if = m_get_rcvif_psref(m, &psref_src); |
1630 | if (src_if == NULL) { | | 1631 | if (src_if == NULL) { |
1631 | /* Interface is being destroyed? */ | | 1632 | /* Interface is being destroyed? */ |
1632 | m_freem(m); | | 1633 | m_freem(m); |
1633 | goto out; | | 1634 | goto out; |
1634 | } | | 1635 | } |
1635 | | | 1636 | |
1636 | sc->sc_if.if_ipackets++; | | 1637 | sc->sc_if.if_ipackets++; |
1637 | sc->sc_if.if_ibytes += m->m_pkthdr.len; | | 1638 | sc->sc_if.if_ibytes += m->m_pkthdr.len; |
1638 | | | 1639 | |
1639 | /* | | 1640 | /* |
1640 | * Look up the bridge_iflist. | | 1641 | * Look up the bridge_iflist. |
1641 | */ | | 1642 | */ |
1642 | bif = bridge_lookup_member_if(sc, src_if, &psref); | | 1643 | bif = bridge_lookup_member_if(sc, src_if, &psref); |
1643 | if (bif == NULL) { | | 1644 | if (bif == NULL) { |
1644 | /* Interface is not a bridge member (anymore?) */ | | 1645 | /* Interface is not a bridge member (anymore?) */ |
1645 | m_freem(m); | | 1646 | m_freem(m); |
1646 | goto out; | | 1647 | goto out; |
1647 | } | | 1648 | } |
1648 | | | 1649 | |
1649 | if (bif->bif_flags & IFBIF_STP) { | | 1650 | if (bif->bif_flags & IFBIF_STP) { |
1650 | switch (bif->bif_state) { | | 1651 | switch (bif->bif_state) { |
1651 | case BSTP_IFSTATE_BLOCKING: | | 1652 | case BSTP_IFSTATE_BLOCKING: |
1652 | case BSTP_IFSTATE_LISTENING: | | 1653 | case BSTP_IFSTATE_LISTENING: |
1653 | case BSTP_IFSTATE_DISABLED: | | 1654 | case BSTP_IFSTATE_DISABLED: |
1654 | m_freem(m); | | 1655 | m_freem(m); |
1655 | bridge_release_member(sc, bif, &psref); | | 1656 | bridge_release_member(sc, bif, &psref); |
1656 | goto out; | | 1657 | goto out; |
1657 | } | | 1658 | } |
1658 | } | | 1659 | } |
1659 | | | 1660 | |
1660 | eh = mtod(m, struct ether_header *); | | 1661 | eh = mtod(m, struct ether_header *); |
1661 | | | 1662 | |
1662 | /* | | 1663 | /* |
1663 | * If the interface is learning, and the source | | 1664 | * If the interface is learning, and the source |
1664 | * address is valid and not multicast, record | | 1665 | * address is valid and not multicast, record |
1665 | * the address. | | 1666 | * the address. |
1666 | */ | | 1667 | */ |
1667 | if ((bif->bif_flags & IFBIF_LEARNING) != 0 && | | 1668 | if ((bif->bif_flags & IFBIF_LEARNING) != 0 && |
1668 | ETHER_IS_MULTICAST(eh->ether_shost) == 0 && | | 1669 | ETHER_IS_MULTICAST(eh->ether_shost) == 0 && |
1669 | (eh->ether_shost[0] == 0 && | | 1670 | (eh->ether_shost[0] == 0 && |
1670 | eh->ether_shost[1] == 0 && | | 1671 | eh->ether_shost[1] == 0 && |
1671 | eh->ether_shost[2] == 0 && | | 1672 | eh->ether_shost[2] == 0 && |
1672 | eh->ether_shost[3] == 0 && | | 1673 | eh->ether_shost[3] == 0 && |
1673 | eh->ether_shost[4] == 0 && | | 1674 | eh->ether_shost[4] == 0 && |
1674 | eh->ether_shost[5] == 0) == 0) { | | 1675 | eh->ether_shost[5] == 0) == 0) { |
1675 | (void) bridge_rtupdate(sc, eh->ether_shost, | | 1676 | (void) bridge_rtupdate(sc, eh->ether_shost, |
1676 | src_if, 0, IFBAF_DYNAMIC); | | 1677 | src_if, 0, IFBAF_DYNAMIC); |
1677 | } | | 1678 | } |
1678 | | | 1679 | |
1679 | if ((bif->bif_flags & IFBIF_STP) != 0 && | | 1680 | if ((bif->bif_flags & IFBIF_STP) != 0 && |
1680 | bif->bif_state == BSTP_IFSTATE_LEARNING) { | | 1681 | bif->bif_state == BSTP_IFSTATE_LEARNING) { |
1681 | m_freem(m); | | 1682 | m_freem(m); |
1682 | bridge_release_member(sc, bif, &psref); | | 1683 | bridge_release_member(sc, bif, &psref); |
1683 | goto out; | | 1684 | goto out; |
1684 | } | | 1685 | } |
1685 | | | 1686 | |
1686 | bridge_release_member(sc, bif, &psref); | | 1687 | bridge_release_member(sc, bif, &psref); |
1687 | | | 1688 | |
1688 | /* | | 1689 | /* |
1689 | * At this point, the port either doesn't participate | | 1690 | * At this point, the port either doesn't participate |
1690 | * in spanning tree or it is in the forwarding state. | | 1691 | * in spanning tree or it is in the forwarding state. |
1691 | */ | | 1692 | */ |
1692 | | | 1693 | |
1693 | /* | | 1694 | /* |
1694 | * If the packet is unicast, destined for someone on | | 1695 | * If the packet is unicast, destined for someone on |
1695 | * "this" side of the bridge, drop it. | | 1696 | * "this" side of the bridge, drop it. |
1696 | */ | | 1697 | */ |
1697 | if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { | | 1698 | if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { |
1698 | dst_if = bridge_rtlookup(sc, eh->ether_dhost); | | 1699 | dst_if = bridge_rtlookup(sc, eh->ether_dhost); |
1699 | if (src_if == dst_if) { | | 1700 | if (src_if == dst_if) { |
1700 | m_freem(m); | | 1701 | m_freem(m); |
1701 | goto out; | | 1702 | goto out; |
1702 | } | | 1703 | } |
1703 | } else { | | 1704 | } else { |
1704 | /* ...forward it to all interfaces. */ | | 1705 | /* ...forward it to all interfaces. */ |
1705 | sc->sc_if.if_imcasts++; | | 1706 | sc->sc_if.if_imcasts++; |
1706 | dst_if = NULL; | | 1707 | dst_if = NULL; |
1707 | } | | 1708 | } |
1708 | | | 1709 | |
1709 | if (pfil_run_hooks(sc->sc_if.if_pfil, &m, src_if, PFIL_IN) != 0) { | | 1710 | if (pfil_run_hooks(sc->sc_if.if_pfil, &m, src_if, PFIL_IN) != 0) { |
1710 | if (m != NULL) | | 1711 | if (m != NULL) |
1711 | m_freem(m); | | 1712 | m_freem(m); |
1712 | goto out; | | 1713 | goto out; |
1713 | } | | 1714 | } |
1714 | if (m == NULL) | | 1715 | if (m == NULL) |
1715 | goto out; | | 1716 | goto out; |
1716 | | | 1717 | |
1717 | if (dst_if == NULL) { | | 1718 | if (dst_if == NULL) { |
1718 | bridge_broadcast(sc, src_if, m); | | 1719 | bridge_broadcast(sc, src_if, m); |
1719 | goto out; | | 1720 | goto out; |
1720 | } | | 1721 | } |
1721 | | | 1722 | |
1722 | m_put_rcvif_psref(src_if, &psref_src); | | 1723 | m_put_rcvif_psref(src_if, &psref_src); |
1723 | src_if = NULL; | | 1724 | src_if = NULL; |
1724 | | | 1725 | |
1725 | /* | | 1726 | /* |
1726 | * At this point, we're dealing with a unicast frame | | 1727 | * At this point, we're dealing with a unicast frame |
1727 | * going to a different interface. | | 1728 | * going to a different interface. |
1728 | */ | | 1729 | */ |
1729 | if ((dst_if->if_flags & IFF_RUNNING) == 0) { | | 1730 | if ((dst_if->if_flags & IFF_RUNNING) == 0) { |
1730 | m_freem(m); | | 1731 | m_freem(m); |
1731 | goto out; | | 1732 | goto out; |
1732 | } | | 1733 | } |
1733 | | | 1734 | |
1734 | bif = bridge_lookup_member_if(sc, dst_if, &psref); | | 1735 | bif = bridge_lookup_member_if(sc, dst_if, &psref); |
1735 | if (bif == NULL) { | | 1736 | if (bif == NULL) { |
1736 | /* Not a member of the bridge (anymore?) */ | | 1737 | /* Not a member of the bridge (anymore?) */ |
1737 | m_freem(m); | | 1738 | m_freem(m); |
1738 | goto out; | | 1739 | goto out; |
1739 | } | | 1740 | } |
1740 | | | 1741 | |
1741 | if (bif->bif_flags & IFBIF_STP) { | | 1742 | if (bif->bif_flags & IFBIF_STP) { |
1742 | switch (bif->bif_state) { | | 1743 | switch (bif->bif_state) { |
1743 | case BSTP_IFSTATE_DISABLED: | | 1744 | case BSTP_IFSTATE_DISABLED: |
1744 | case BSTP_IFSTATE_BLOCKING: | | 1745 | case BSTP_IFSTATE_BLOCKING: |
1745 | m_freem(m); | | 1746 | m_freem(m); |
1746 | bridge_release_member(sc, bif, &psref); | | 1747 | bridge_release_member(sc, bif, &psref); |
1747 | goto out; | | 1748 | goto out; |
1748 | } | | 1749 | } |
1749 | } | | 1750 | } |
1750 | | | 1751 | |
1751 | bridge_release_member(sc, bif, &psref); | | 1752 | bridge_release_member(sc, bif, &psref); |
1752 | | | 1753 | |
1753 | ACQUIRE_GLOBAL_LOCKS(); | | 1754 | ACQUIRE_GLOBAL_LOCKS(); |
1754 | bridge_enqueue(sc, dst_if, m, 1); | | 1755 | bridge_enqueue(sc, dst_if, m, 1); |
1755 | RELEASE_GLOBAL_LOCKS(); | | 1756 | RELEASE_GLOBAL_LOCKS(); |
1756 | out: | | 1757 | out: |
1757 | if (src_if != NULL) | | 1758 | if (src_if != NULL) |
1758 | m_put_rcvif_psref(src_if, &psref_src); | | 1759 | m_put_rcvif_psref(src_if, &psref_src); |
1759 | return; | | 1760 | return; |
1760 | } | | 1761 | } |
1761 | | | 1762 | |
1762 | static bool | | 1763 | static bool |
1763 | bstp_state_before_learning(struct bridge_iflist *bif) | | 1764 | bstp_state_before_learning(struct bridge_iflist *bif) |
1764 | { | | 1765 | { |
1765 | if (bif->bif_flags & IFBIF_STP) { | | 1766 | if (bif->bif_flags & IFBIF_STP) { |
1766 | switch (bif->bif_state) { | | 1767 | switch (bif->bif_state) { |
1767 | case BSTP_IFSTATE_BLOCKING: | | 1768 | case BSTP_IFSTATE_BLOCKING: |
1768 | case BSTP_IFSTATE_LISTENING: | | 1769 | case BSTP_IFSTATE_LISTENING: |
1769 | case BSTP_IFSTATE_DISABLED: | | 1770 | case BSTP_IFSTATE_DISABLED: |
1770 | return true; | | 1771 | return true; |
1771 | } | | 1772 | } |
1772 | } | | 1773 | } |
1773 | return false; | | 1774 | return false; |
1774 | } | | 1775 | } |
1775 | | | 1776 | |
1776 | static bool | | 1777 | static bool |
1777 | bridge_ourether(struct bridge_iflist *bif, struct ether_header *eh, int src) | | 1778 | bridge_ourether(struct bridge_iflist *bif, struct ether_header *eh, int src) |
1778 | { | | 1779 | { |
1779 | uint8_t *ether = src ? eh->ether_shost : eh->ether_dhost; | | 1780 | uint8_t *ether = src ? eh->ether_shost : eh->ether_dhost; |
1780 | | | 1781 | |
1781 | if (memcmp(CLLADDR(bif->bif_ifp->if_sadl), ether, ETHER_ADDR_LEN) == 0 | | 1782 | if (memcmp(CLLADDR(bif->bif_ifp->if_sadl), ether, ETHER_ADDR_LEN) == 0 |
1782 | #if NCARP > 0 | | 1783 | #if NCARP > 0 |
1783 | || (bif->bif_ifp->if_carp && | | 1784 | || (bif->bif_ifp->if_carp && |
1784 | carp_ourether(bif->bif_ifp->if_carp, eh, IFT_ETHER, src) != NULL) | | 1785 | carp_ourether(bif->bif_ifp->if_carp, eh, IFT_ETHER, src) != NULL) |
1785 | #endif /* NCARP > 0 */ | | 1786 | #endif /* NCARP > 0 */ |
1786 | ) | | 1787 | ) |
1787 | return true; | | 1788 | return true; |
1788 | | | 1789 | |
1789 | return false; | | 1790 | return false; |
1790 | } | | 1791 | } |
1791 | | | 1792 | |
1792 | /* | | 1793 | /* |
1793 | * bridge_input: | | 1794 | * bridge_input: |
1794 | * | | 1795 | * |
1795 | * Receive input from a member interface. Queue the packet for | | 1796 | * Receive input from a member interface. Queue the packet for |
1796 | * bridging if it is not for us. | | 1797 | * bridging if it is not for us. |
1797 | */ | | 1798 | */ |
1798 | static void | | 1799 | static void |
1799 | bridge_input(struct ifnet *ifp, struct mbuf *m) | | 1800 | bridge_input(struct ifnet *ifp, struct mbuf *m) |
1800 | { | | 1801 | { |
1801 | struct bridge_softc *sc = ifp->if_bridge; | | 1802 | struct bridge_softc *sc = ifp->if_bridge; |
1802 | struct bridge_iflist *bif; | | 1803 | struct bridge_iflist *bif; |
1803 | struct ether_header *eh; | | 1804 | struct ether_header *eh; |
1804 | struct psref psref; | | 1805 | struct psref psref; |
1805 | int bound; | | 1806 | int bound; |
1806 | DECLARE_LOCK_VARIABLE; | | 1807 | DECLARE_LOCK_VARIABLE; |
1807 | | | 1808 | |
1808 | KASSERT(!cpu_intr_p()); | | 1809 | KASSERT(!cpu_intr_p()); |
1809 | | | 1810 | |
1810 | if (__predict_false(sc == NULL) || | | 1811 | if (__predict_false(sc == NULL) || |
1811 | (sc->sc_if.if_flags & IFF_RUNNING) == 0) { | | 1812 | (sc->sc_if.if_flags & IFF_RUNNING) == 0) { |
1812 | ACQUIRE_GLOBAL_LOCKS(); | | 1813 | ACQUIRE_GLOBAL_LOCKS(); |
1813 | ether_input(ifp, m); | | 1814 | ether_input(ifp, m); |
1814 | RELEASE_GLOBAL_LOCKS(); | | 1815 | RELEASE_GLOBAL_LOCKS(); |
1815 | return; | | 1816 | return; |
1816 | } | | 1817 | } |
1817 | | | 1818 | |
1818 | bound = curlwp_bind(); | | 1819 | bound = curlwp_bind(); |
1819 | bif = bridge_lookup_member_if(sc, ifp, &psref); | | 1820 | bif = bridge_lookup_member_if(sc, ifp, &psref); |
1820 | if (bif == NULL) { | | 1821 | if (bif == NULL) { |
1821 | curlwp_bindx(bound); | | 1822 | curlwp_bindx(bound); |
1822 | ACQUIRE_GLOBAL_LOCKS(); | | 1823 | ACQUIRE_GLOBAL_LOCKS(); |
1823 | ether_input(ifp, m); | | 1824 | ether_input(ifp, m); |
1824 | RELEASE_GLOBAL_LOCKS(); | | 1825 | RELEASE_GLOBAL_LOCKS(); |
1825 | return; | | 1826 | return; |
1826 | } | | 1827 | } |
1827 | | | 1828 | |
1828 | eh = mtod(m, struct ether_header *); | | 1829 | eh = mtod(m, struct ether_header *); |
1829 | | | 1830 | |
1830 | if (ETHER_IS_MULTICAST(eh->ether_dhost)) { | | 1831 | if (ETHER_IS_MULTICAST(eh->ether_dhost)) { |
1831 | if (memcmp(etherbroadcastaddr, | | 1832 | if (memcmp(etherbroadcastaddr, |
1832 | eh->ether_dhost, ETHER_ADDR_LEN) == 0) | | 1833 | eh->ether_dhost, ETHER_ADDR_LEN) == 0) |
1833 | m->m_flags |= M_BCAST; | | 1834 | m->m_flags |= M_BCAST; |
1834 | else | | 1835 | else |
1835 | m->m_flags |= M_MCAST; | | 1836 | m->m_flags |= M_MCAST; |
1836 | } | | 1837 | } |
1837 | | | 1838 | |
1838 | /* | | 1839 | /* |
1839 | * A 'fast' path for packets addressed to interfaces that are | | 1840 | * A 'fast' path for packets addressed to interfaces that are |
1840 | * part of this bridge. | | 1841 | * part of this bridge. |
1841 | */ | | 1842 | */ |
1842 | if (!(m->m_flags & (M_BCAST|M_MCAST)) && | | 1843 | if (!(m->m_flags & (M_BCAST|M_MCAST)) && |
1843 | !bstp_state_before_learning(bif)) { | | 1844 | !bstp_state_before_learning(bif)) { |
1844 | struct bridge_iflist *_bif; | | 1845 | struct bridge_iflist *_bif; |
1845 | struct ifnet *_ifp = NULL; | | 1846 | struct ifnet *_ifp = NULL; |
1846 | int s; | | 1847 | int s; |
1847 | struct psref _psref; | | 1848 | struct psref _psref; |
1848 | | | 1849 | |
1849 | BRIDGE_PSZ_RENTER(s); | | 1850 | BRIDGE_PSZ_RENTER(s); |
1850 | BRIDGE_IFLIST_READER_FOREACH(_bif, sc) { | | 1851 | BRIDGE_IFLIST_READER_FOREACH(_bif, sc) { |
1851 | /* It is destined for us. */ | | 1852 | /* It is destined for us. */ |
1852 | if (bridge_ourether(_bif, eh, 0)) { | | 1853 | if (bridge_ourether(_bif, eh, 0)) { |
1853 | bridge_acquire_member(sc, _bif, &_psref); | | 1854 | bridge_acquire_member(sc, _bif, &_psref); |
1854 | BRIDGE_PSZ_REXIT(s); | | 1855 | BRIDGE_PSZ_REXIT(s); |
1855 | if (_bif->bif_flags & IFBIF_LEARNING) | | 1856 | if (_bif->bif_flags & IFBIF_LEARNING) |
1856 | (void) bridge_rtupdate(sc, | | 1857 | (void) bridge_rtupdate(sc, |
1857 | eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); | | 1858 | eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); |
1858 | m_set_rcvif(m, _bif->bif_ifp); | | 1859 | m_set_rcvif(m, _bif->bif_ifp); |
1859 | _ifp = _bif->bif_ifp; | | 1860 | _ifp = _bif->bif_ifp; |
1860 | bridge_release_member(sc, _bif, &_psref); | | 1861 | bridge_release_member(sc, _bif, &_psref); |
1861 | goto out; | | 1862 | goto out; |
1862 | } | | 1863 | } |
1863 | | | 1864 | |
1864 | /* We just received a packet that we sent out. */ | | 1865 | /* We just received a packet that we sent out. */ |
1865 | if (bridge_ourether(_bif, eh, 1)) | | 1866 | if (bridge_ourether(_bif, eh, 1)) |
1866 | break; | | 1867 | break; |
1867 | } | | 1868 | } |
1868 | BRIDGE_PSZ_REXIT(s); | | 1869 | BRIDGE_PSZ_REXIT(s); |
1869 | out: | | 1870 | out: |
1870 | | | 1871 | |
1871 | if (_bif != NULL) { | | 1872 | if (_bif != NULL) { |
1872 | bridge_release_member(sc, bif, &psref); | | 1873 | bridge_release_member(sc, bif, &psref); |
1873 | curlwp_bindx(bound); | | 1874 | curlwp_bindx(bound); |
1874 | if (_ifp != NULL) { | | 1875 | if (_ifp != NULL) { |
1875 | m->m_flags &= ~M_PROMISC; | | 1876 | m->m_flags &= ~M_PROMISC; |
1876 | ACQUIRE_GLOBAL_LOCKS(); | | 1877 | ACQUIRE_GLOBAL_LOCKS(); |
1877 | ether_input(_ifp, m); | | 1878 | ether_input(_ifp, m); |
1878 | RELEASE_GLOBAL_LOCKS(); | | 1879 | RELEASE_GLOBAL_LOCKS(); |
1879 | } else | | 1880 | } else |
1880 | m_freem(m); | | 1881 | m_freem(m); |
1881 | return; | | 1882 | return; |
1882 | } | | 1883 | } |
1883 | } | | 1884 | } |
1884 | | | 1885 | |
1885 | /* Tap off 802.1D packets; they do not get forwarded. */ | | 1886 | /* Tap off 802.1D packets; they do not get forwarded. */ |
1886 | if (bif->bif_flags & IFBIF_STP && | | 1887 | if (bif->bif_flags & IFBIF_STP && |
1887 | memcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) { | | 1888 | memcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) { |
1888 | bstp_input(sc, bif, m); | | 1889 | bstp_input(sc, bif, m); |
1889 | bridge_release_member(sc, bif, &psref); | | 1890 | bridge_release_member(sc, bif, &psref); |
1890 | curlwp_bindx(bound); | | 1891 | curlwp_bindx(bound); |
1891 | return; | | 1892 | return; |
1892 | } | | 1893 | } |
1893 | | | 1894 | |
1894 | /* | | 1895 | /* |
1895 | * A normal switch would discard the packet here, but that's not what | | 1896 | * A normal switch would discard the packet here, but that's not what |
1896 | * we've done historically. This also prevents some obnoxious behaviour. | | 1897 | * we've done historically. This also prevents some obnoxious behaviour. |
1897 | */ | | 1898 | */ |
1898 | if (bstp_state_before_learning(bif)) { | | 1899 | if (bstp_state_before_learning(bif)) { |
1899 | bridge_release_member(sc, bif, &psref); | | 1900 | bridge_release_member(sc, bif, &psref); |
1900 | curlwp_bindx(bound); | | 1901 | curlwp_bindx(bound); |
1901 | ACQUIRE_GLOBAL_LOCKS(); | | 1902 | ACQUIRE_GLOBAL_LOCKS(); |
1902 | ether_input(ifp, m); | | 1903 | ether_input(ifp, m); |
1903 | RELEASE_GLOBAL_LOCKS(); | | 1904 | RELEASE_GLOBAL_LOCKS(); |
1904 | return; | | 1905 | return; |
1905 | } | | 1906 | } |
1906 | | | 1907 | |
1907 | bridge_release_member(sc, bif, &psref); | | 1908 | bridge_release_member(sc, bif, &psref); |
1908 | | | 1909 | |
1909 | bridge_forward(sc, m); | | 1910 | bridge_forward(sc, m); |
1910 | | | 1911 | |
1911 | curlwp_bindx(bound); | | 1912 | curlwp_bindx(bound); |
1912 | } | | 1913 | } |
1913 | | | 1914 | |
1914 | /* | | 1915 | /* |
1915 | * bridge_broadcast: | | 1916 | * bridge_broadcast: |
1916 | * | | 1917 | * |
1917 | * Send a frame to all interfaces that are members of | | 1918 | * Send a frame to all interfaces that are members of |
1918 | * the bridge, except for the one on which the packet | | 1919 | * the bridge, except for the one on which the packet |
1919 | * arrived. | | 1920 | * arrived. |
1920 | */ | | 1921 | */ |
1921 | static void | | 1922 | static void |
1922 | bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, | | 1923 | bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, |
1923 | struct mbuf *m) | | 1924 | struct mbuf *m) |
1924 | { | | 1925 | { |
1925 | struct bridge_iflist *bif; | | 1926 | struct bridge_iflist *bif; |
1926 | struct mbuf *mc; | | 1927 | struct mbuf *mc; |
1927 | struct ifnet *dst_if; | | 1928 | struct ifnet *dst_if; |
1928 | bool bmcast; | | 1929 | bool bmcast; |
1929 | int s; | | 1930 | int s; |
1930 | DECLARE_LOCK_VARIABLE; | | 1931 | DECLARE_LOCK_VARIABLE; |
1931 | | | 1932 | |
1932 | bmcast = m->m_flags & (M_BCAST|M_MCAST); | | 1933 | bmcast = m->m_flags & (M_BCAST|M_MCAST); |
1933 | | | 1934 | |
1934 | BRIDGE_PSZ_RENTER(s); | | 1935 | BRIDGE_PSZ_RENTER(s); |
1935 | BRIDGE_IFLIST_READER_FOREACH(bif, sc) { | | 1936 | BRIDGE_IFLIST_READER_FOREACH(bif, sc) { |
1936 | struct psref psref; | | 1937 | struct psref psref; |
1937 | | | 1938 | |
1938 | bridge_acquire_member(sc, bif, &psref); | | 1939 | bridge_acquire_member(sc, bif, &psref); |
1939 | BRIDGE_PSZ_REXIT(s); | | 1940 | BRIDGE_PSZ_REXIT(s); |
1940 | | | 1941 | |
1941 | dst_if = bif->bif_ifp; | | 1942 | dst_if = bif->bif_ifp; |
1942 | | | 1943 | |
1943 | if (bif->bif_flags & IFBIF_STP) { | | 1944 | if (bif->bif_flags & IFBIF_STP) { |
1944 | switch (bif->bif_state) { | | 1945 | switch (bif->bif_state) { |
1945 | case BSTP_IFSTATE_BLOCKING: | | 1946 | case BSTP_IFSTATE_BLOCKING: |
1946 | case BSTP_IFSTATE_DISABLED: | | 1947 | case BSTP_IFSTATE_DISABLED: |
1947 | goto next; | | 1948 | goto next; |
1948 | } | | 1949 | } |
1949 | } | | 1950 | } |
1950 | | | 1951 | |
1951 | if ((bif->bif_flags & IFBIF_DISCOVER) == 0 && !bmcast) | | 1952 | if ((bif->bif_flags & IFBIF_DISCOVER) == 0 && !bmcast) |
1952 | goto next; | | 1953 | goto next; |
1953 | | | 1954 | |
1954 | if ((dst_if->if_flags & IFF_RUNNING) == 0) | | 1955 | if ((dst_if->if_flags & IFF_RUNNING) == 0) |
1955 | goto next; | | 1956 | goto next; |
1956 | | | 1957 | |
1957 | if (dst_if != src_if) { | | 1958 | if (dst_if != src_if) { |
1958 | mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT); | | 1959 | mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT); |
1959 | if (mc == NULL) { | | 1960 | if (mc == NULL) { |
1960 | sc->sc_if.if_oerrors++; | | 1961 | sc->sc_if.if_oerrors++; |
1961 | goto next; | | 1962 | goto next; |
1962 | } | | 1963 | } |
1963 | ACQUIRE_GLOBAL_LOCKS(); | | 1964 | ACQUIRE_GLOBAL_LOCKS(); |
1964 | bridge_enqueue(sc, dst_if, mc, 1); | | 1965 | bridge_enqueue(sc, dst_if, mc, 1); |
1965 | RELEASE_GLOBAL_LOCKS(); | | 1966 | RELEASE_GLOBAL_LOCKS(); |
1966 | } | | 1967 | } |
1967 | | | 1968 | |
1968 | if (bmcast) { | | 1969 | if (bmcast) { |
1969 | mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT); | | 1970 | mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT); |
1970 | if (mc == NULL) { | | 1971 | if (mc == NULL) { |
1971 | sc->sc_if.if_oerrors++; | | 1972 | sc->sc_if.if_oerrors++; |
1972 | goto next; | | 1973 | goto next; |
1973 | } | | 1974 | } |
1974 | | | 1975 | |
1975 | m_set_rcvif(mc, dst_if); | | 1976 | m_set_rcvif(mc, dst_if); |
1976 | mc->m_flags &= ~M_PROMISC; | | 1977 | mc->m_flags &= ~M_PROMISC; |
1977 | | | 1978 | |
1978 | ACQUIRE_GLOBAL_LOCKS(); | | 1979 | ACQUIRE_GLOBAL_LOCKS(); |
1979 | ether_input(dst_if, mc); | | 1980 | ether_input(dst_if, mc); |
1980 | RELEASE_GLOBAL_LOCKS(); | | 1981 | RELEASE_GLOBAL_LOCKS(); |
1981 | } | | 1982 | } |
1982 | next: | | 1983 | next: |
1983 | BRIDGE_PSZ_RENTER(s); | | 1984 | BRIDGE_PSZ_RENTER(s); |
1984 | bridge_release_member(sc, bif, &psref); | | 1985 | bridge_release_member(sc, bif, &psref); |
1985 | } | | 1986 | } |
1986 | BRIDGE_PSZ_REXIT(s); | | 1987 | BRIDGE_PSZ_REXIT(s); |
1987 | | | 1988 | |
1988 | m_freem(m); | | 1989 | m_freem(m); |
1989 | } | | 1990 | } |
1990 | | | 1991 | |
1991 | static int | | 1992 | static int |
1992 | bridge_rtalloc(struct bridge_softc *sc, const uint8_t *dst, | | 1993 | bridge_rtalloc(struct bridge_softc *sc, const uint8_t *dst, |
1993 | struct bridge_rtnode **brtp) | | 1994 | struct bridge_rtnode **brtp) |
1994 | { | | 1995 | { |
1995 | struct bridge_rtnode *brt; | | 1996 | struct bridge_rtnode *brt; |
1996 | int error; | | 1997 | int error; |
1997 | | | 1998 | |
1998 | if (sc->sc_brtcnt >= sc->sc_brtmax) | | 1999 | if (sc->sc_brtcnt >= sc->sc_brtmax) |
1999 | return ENOSPC; | | 2000 | return ENOSPC; |
2000 | | | 2001 | |
2001 | /* | | 2002 | /* |
2002 | * Allocate a new bridge forwarding node, and | | 2003 | * Allocate a new bridge forwarding node, and |
2003 | * initialize the expiration time and Ethernet | | 2004 | * initialize the expiration time and Ethernet |
2004 | * address. | | 2005 | * address. |
2005 | */ | | 2006 | */ |
2006 | brt = pool_get(&bridge_rtnode_pool, PR_NOWAIT); | | 2007 | brt = pool_get(&bridge_rtnode_pool, PR_NOWAIT); |
2007 | if (brt == NULL) | | 2008 | if (brt == NULL) |
2008 | return ENOMEM; | | 2009 | return ENOMEM; |
2009 | | | 2010 | |
2010 | memset(brt, 0, sizeof(*brt)); | | 2011 | memset(brt, 0, sizeof(*brt)); |
2011 | brt->brt_expire = time_uptime + sc->sc_brttimeout; | | 2012 | brt->brt_expire = time_uptime + sc->sc_brttimeout; |
2012 | brt->brt_flags = IFBAF_DYNAMIC; | | 2013 | brt->brt_flags = IFBAF_DYNAMIC; |
2013 | memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); | | 2014 | memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); |
2014 | | | 2015 | |
2015 | BRIDGE_RT_LOCK(sc); | | 2016 | BRIDGE_RT_LOCK(sc); |
2016 | error = bridge_rtnode_insert(sc, brt); | | 2017 | error = bridge_rtnode_insert(sc, brt); |
2017 | BRIDGE_RT_UNLOCK(sc); | | 2018 | BRIDGE_RT_UNLOCK(sc); |
2018 | | | 2019 | |
2019 | if (error != 0) { | | 2020 | if (error != 0) { |
2020 | pool_put(&bridge_rtnode_pool, brt); | | 2021 | pool_put(&bridge_rtnode_pool, brt); |
2021 | return error; | | 2022 | return error; |
2022 | } | | 2023 | } |
2023 | | | 2024 | |
2024 | *brtp = brt; | | 2025 | *brtp = brt; |
2025 | return 0; | | 2026 | return 0; |
2026 | } | | 2027 | } |
2027 | | | 2028 | |
2028 | /* | | 2029 | /* |
2029 | * bridge_rtupdate: | | 2030 | * bridge_rtupdate: |
2030 | * | | 2031 | * |
2031 | * Add a bridge routing entry. | | 2032 | * Add a bridge routing entry. |
2032 | */ | | 2033 | */ |
2033 | static int | | 2034 | static int |
2034 | bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, | | 2035 | bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, |
2035 | struct ifnet *dst_if, int setflags, uint8_t flags) | | 2036 | struct ifnet *dst_if, int setflags, uint8_t flags) |
2036 | { | | 2037 | { |
2037 | struct bridge_rtnode *brt; | | 2038 | struct bridge_rtnode *brt; |
2038 | int s; | | 2039 | int s; |
2039 | | | 2040 | |
2040 | again: | | 2041 | again: |
2041 | /* | | 2042 | /* |
2042 | * A route for this destination might already exist. If so, | | 2043 | * A route for this destination might already exist. If so, |
2043 | * update it, otherwise create a new one. | | 2044 | * update it, otherwise create a new one. |
2044 | */ | | 2045 | */ |
2045 | BRIDGE_RT_RENTER(s); | | 2046 | BRIDGE_RT_RENTER(s); |
2046 | brt = bridge_rtnode_lookup(sc, dst); | | 2047 | brt = bridge_rtnode_lookup(sc, dst); |
2047 | | | 2048 | |
2048 | if (brt != NULL) { | | 2049 | if (brt != NULL) { |
2049 | brt->brt_ifp = dst_if; | | 2050 | brt->brt_ifp = dst_if; |
2050 | if (setflags) { | | 2051 | if (setflags) { |
2051 | brt->brt_flags = flags; | | 2052 | brt->brt_flags = flags; |
2052 | if (flags & IFBAF_STATIC) | | 2053 | if (flags & IFBAF_STATIC) |
2053 | brt->brt_expire = 0; | | 2054 | brt->brt_expire = 0; |
2054 | else | | 2055 | else |
2055 | brt->brt_expire = time_uptime + sc->sc_brttimeout; | | 2056 | brt->brt_expire = time_uptime + sc->sc_brttimeout; |
2056 | } else { | | 2057 | } else { |
2057 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) | | 2058 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) |
2058 | brt->brt_expire = time_uptime + sc->sc_brttimeout; | | 2059 | brt->brt_expire = time_uptime + sc->sc_brttimeout; |
2059 | } | | 2060 | } |
2060 | } | | 2061 | } |
2061 | BRIDGE_RT_REXIT(s); | | 2062 | BRIDGE_RT_REXIT(s); |
2062 | | | 2063 | |
2063 | if (brt == NULL) { | | 2064 | if (brt == NULL) { |
2064 | int r; | | 2065 | int r; |
2065 | | | 2066 | |
2066 | r = bridge_rtalloc(sc, dst, &brt); | | 2067 | r = bridge_rtalloc(sc, dst, &brt); |
2067 | if (r != 0) | | 2068 | if (r != 0) |
2068 | return r; | | 2069 | return r; |
2069 | goto again; | | 2070 | goto again; |
2070 | } | | 2071 | } |
2071 | | | 2072 | |
2072 | return 0; | | 2073 | return 0; |
2073 | } | | 2074 | } |
2074 | | | 2075 | |
2075 | /* | | 2076 | /* |
2076 | * bridge_rtlookup: | | 2077 | * bridge_rtlookup: |
2077 | * | | 2078 | * |
2078 | * Lookup the destination interface for an address. | | 2079 | * Lookup the destination interface for an address. |
2079 | */ | | 2080 | */ |
2080 | static struct ifnet * | | 2081 | static struct ifnet * |
2081 | bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr) | | 2082 | bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr) |
2082 | { | | 2083 | { |
2083 | struct bridge_rtnode *brt; | | 2084 | struct bridge_rtnode *brt; |
2084 | struct ifnet *ifs = NULL; | | 2085 | struct ifnet *ifs = NULL; |
2085 | int s; | | 2086 | int s; |
2086 | | | 2087 | |
2087 | BRIDGE_RT_RENTER(s); | | 2088 | BRIDGE_RT_RENTER(s); |
2088 | brt = bridge_rtnode_lookup(sc, addr); | | 2089 | brt = bridge_rtnode_lookup(sc, addr); |
2089 | if (brt != NULL) | | 2090 | if (brt != NULL) |
2090 | ifs = brt->brt_ifp; | | 2091 | ifs = brt->brt_ifp; |
2091 | BRIDGE_RT_REXIT(s); | | 2092 | BRIDGE_RT_REXIT(s); |
2092 | | | 2093 | |
2093 | return ifs; | | 2094 | return ifs; |
2094 | } | | 2095 | } |
2095 | | | 2096 | |
2096 | typedef bool (*bridge_iterate_cb_t) | | 2097 | typedef bool (*bridge_iterate_cb_t) |
2097 | (struct bridge_softc *, struct bridge_rtnode *, bool *, void *); | | 2098 | (struct bridge_softc *, struct bridge_rtnode *, bool *, void *); |
2098 | | | 2099 | |
2099 | /* | | 2100 | /* |
2100 | * bridge_rtlist_iterate_remove: | | 2101 | * bridge_rtlist_iterate_remove: |
2101 | * | | 2102 | * |
2102 | * It iterates on sc->sc_rtlist and removes rtnodes of it which func | | 2103 | * It iterates on sc->sc_rtlist and removes rtnodes of it which func |
2103 | * callback judges to remove. Removals of rtnodes are done in a manner | | 2104 | * callback judges to remove. Removals of rtnodes are done in a manner |
2104 | * of pserialize. To this end, all kmem_* operations are placed out of | | 2105 | * of pserialize. To this end, all kmem_* operations are placed out of |
2105 | * mutexes. | | 2106 | * mutexes. |
2106 | */ | | 2107 | */ |
2107 | static void | | 2108 | static void |
2108 | bridge_rtlist_iterate_remove(struct bridge_softc *sc, bridge_iterate_cb_t func, void *arg) | | 2109 | bridge_rtlist_iterate_remove(struct bridge_softc *sc, bridge_iterate_cb_t func, void *arg) |
2109 | { | | 2110 | { |
2110 | struct bridge_rtnode *brt, *nbrt; | | 2111 | struct bridge_rtnode *brt, *nbrt; |
2111 | struct bridge_rtnode **brt_list; | | 2112 | struct bridge_rtnode **brt_list; |
2112 | int i, count; | | 2113 | int i, count; |
2113 | | | 2114 | |
2114 | retry: | | 2115 | retry: |
2115 | count = sc->sc_brtcnt; | | 2116 | count = sc->sc_brtcnt; |
2116 | if (count == 0) | | 2117 | if (count == 0) |
2117 | return; | | 2118 | return; |
2118 | brt_list = kmem_alloc(sizeof(*brt_list) * count, KM_SLEEP); | | 2119 | brt_list = kmem_alloc(sizeof(*brt_list) * count, KM_SLEEP); |
2119 | | | 2120 | |
2120 | BRIDGE_RT_LOCK(sc); | | 2121 | BRIDGE_RT_LOCK(sc); |
2121 | if (__predict_false(sc->sc_brtcnt > count)) { | | 2122 | if (__predict_false(sc->sc_brtcnt > count)) { |
2122 | /* The rtnodes increased, we need more memory */ | | 2123 | /* The rtnodes increased, we need more memory */ |
2123 | BRIDGE_RT_UNLOCK(sc); | | 2124 | BRIDGE_RT_UNLOCK(sc); |
2124 | kmem_free(brt_list, sizeof(*brt_list) * count); | | 2125 | kmem_free(brt_list, sizeof(*brt_list) * count); |
2125 | goto retry; | | 2126 | goto retry; |
2126 | } | | 2127 | } |
2127 | | | 2128 | |
2128 | i = 0; | | 2129 | i = 0; |
2129 | LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | | 2130 | LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { |
2130 | bool need_break = false; | | 2131 | bool need_break = false; |
2131 | if (func(sc, brt, &need_break, arg)) { | | 2132 | if (func(sc, brt, &need_break, arg)) { |
2132 | bridge_rtnode_remove(sc, brt); | | 2133 | bridge_rtnode_remove(sc, brt); |
2133 | brt_list[i++] = brt; | | 2134 | brt_list[i++] = brt; |
2134 | } | | 2135 | } |
2135 | if (need_break) | | 2136 | if (need_break) |
2136 | break; | | 2137 | break; |
2137 | } | | 2138 | } |
2138 | | | 2139 | |
2139 | if (i > 0) | | 2140 | if (i > 0) |
2140 | BRIDGE_RT_PSZ_PERFORM(sc); | | 2141 | BRIDGE_RT_PSZ_PERFORM(sc); |
2141 | BRIDGE_RT_UNLOCK(sc); | | 2142 | BRIDGE_RT_UNLOCK(sc); |
2142 | | | 2143 | |
2143 | while (--i >= 0) | | 2144 | while (--i >= 0) |
2144 | bridge_rtnode_destroy(brt_list[i]); | | 2145 | bridge_rtnode_destroy(brt_list[i]); |
2145 | | | 2146 | |
2146 | kmem_free(brt_list, sizeof(*brt_list) * count); | | 2147 | kmem_free(brt_list, sizeof(*brt_list) * count); |
2147 | } | | 2148 | } |
2148 | | | 2149 | |
2149 | static bool | | 2150 | static bool |
2150 | bridge_rttrim0_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, | | 2151 | bridge_rttrim0_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, |
2151 | bool *need_break, void *arg) | | 2152 | bool *need_break, void *arg) |
2152 | { | | 2153 | { |
2153 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { | | 2154 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { |
2154 | /* Take into account of the subsequent removal */ | | 2155 | /* Take into account of the subsequent removal */ |
2155 | if ((sc->sc_brtcnt - 1) <= sc->sc_brtmax) | | 2156 | if ((sc->sc_brtcnt - 1) <= sc->sc_brtmax) |
2156 | *need_break = true; | | 2157 | *need_break = true; |
2157 | return true; | | 2158 | return true; |
2158 | } else | | 2159 | } else |
2159 | return false; | | 2160 | return false; |
2160 | } | | 2161 | } |
2161 | | | 2162 | |
2162 | static void | | 2163 | static void |
2163 | bridge_rttrim0(struct bridge_softc *sc) | | 2164 | bridge_rttrim0(struct bridge_softc *sc) |
2164 | { | | 2165 | { |
2165 | bridge_rtlist_iterate_remove(sc, bridge_rttrim0_cb, NULL); | | 2166 | bridge_rtlist_iterate_remove(sc, bridge_rttrim0_cb, NULL); |
2166 | } | | 2167 | } |
2167 | | | 2168 | |
2168 | /* | | 2169 | /* |
2169 | * bridge_rttrim: | | 2170 | * bridge_rttrim: |
2170 | * | | 2171 | * |
2171 | * Trim the routine table so that we have a number | | 2172 | * Trim the routine table so that we have a number |
2172 | * of routing entries less than or equal to the | | 2173 | * of routing entries less than or equal to the |
2173 | * maximum number. | | 2174 | * maximum number. |
2174 | */ | | 2175 | */ |
2175 | static void | | 2176 | static void |
2176 | bridge_rttrim(struct bridge_softc *sc) | | 2177 | bridge_rttrim(struct bridge_softc *sc) |
2177 | { | | 2178 | { |
2178 | | | 2179 | |
2179 | /* Make sure we actually need to do this. */ | | 2180 | /* Make sure we actually need to do this. */ |
2180 | if (sc->sc_brtcnt <= sc->sc_brtmax) | | 2181 | if (sc->sc_brtcnt <= sc->sc_brtmax) |
2181 | return; | | 2182 | return; |
2182 | | | 2183 | |
2183 | /* Force an aging cycle; this might trim enough addresses. */ | | 2184 | /* Force an aging cycle; this might trim enough addresses. */ |
2184 | bridge_rtage(sc); | | 2185 | bridge_rtage(sc); |
2185 | if (sc->sc_brtcnt <= sc->sc_brtmax) | | 2186 | if (sc->sc_brtcnt <= sc->sc_brtmax) |
2186 | return; | | 2187 | return; |
2187 | | | 2188 | |
2188 | bridge_rttrim0(sc); | | 2189 | bridge_rttrim0(sc); |
2189 | | | 2190 | |
2190 | return; | | 2191 | return; |
2191 | } | | 2192 | } |
2192 | | | 2193 | |
2193 | /* | | 2194 | /* |
2194 | * bridge_timer: | | 2195 | * bridge_timer: |
2195 | * | | 2196 | * |
2196 | * Aging timer for the bridge. | | 2197 | * Aging timer for the bridge. |
2197 | */ | | 2198 | */ |
2198 | static void | | 2199 | static void |
2199 | bridge_timer(void *arg) | | 2200 | bridge_timer(void *arg) |
2200 | { | | 2201 | { |
2201 | struct bridge_softc *sc = arg; | | 2202 | struct bridge_softc *sc = arg; |
2202 | | | 2203 | |
2203 | workqueue_enqueue(sc->sc_rtage_wq, &sc->sc_rtage_wk, NULL); | | 2204 | workqueue_enqueue(sc->sc_rtage_wq, &sc->sc_rtage_wk, NULL); |
2204 | } | | 2205 | } |
2205 | | | 2206 | |
2206 | static void | | 2207 | static void |
2207 | bridge_rtage_work(struct work *wk, void *arg) | | 2208 | bridge_rtage_work(struct work *wk, void *arg) |
2208 | { | | 2209 | { |
2209 | struct bridge_softc *sc = arg; | | 2210 | struct bridge_softc *sc = arg; |
2210 | | | 2211 | |
2211 | KASSERT(wk == &sc->sc_rtage_wk); | | 2212 | KASSERT(wk == &sc->sc_rtage_wk); |
2212 | | | 2213 | |
2213 | bridge_rtage(sc); | | 2214 | bridge_rtage(sc); |
2214 | | | 2215 | |
2215 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 2216 | if (sc->sc_if.if_flags & IFF_RUNNING) |
2216 | callout_reset(&sc->sc_brcallout, | | 2217 | callout_reset(&sc->sc_brcallout, |
2217 | bridge_rtable_prune_period * hz, bridge_timer, sc); | | 2218 | bridge_rtable_prune_period * hz, bridge_timer, sc); |
2218 | } | | 2219 | } |
2219 | | | 2220 | |
2220 | static bool | | 2221 | static bool |
2221 | bridge_rtage_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, | | 2222 | bridge_rtage_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, |
2222 | bool *need_break, void *arg) | | 2223 | bool *need_break, void *arg) |
2223 | { | | 2224 | { |
2224 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && | | 2225 | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && |
2225 | time_uptime >= brt->brt_expire) | | 2226 | time_uptime >= brt->brt_expire) |
2226 | return true; | | 2227 | return true; |
2227 | else | | 2228 | else |
2228 | return false; | | 2229 | return false; |
2229 | } | | 2230 | } |
2230 | | | 2231 | |
2231 | /* | | 2232 | /* |
2232 | * bridge_rtage: | | 2233 | * bridge_rtage: |
2233 | * | | 2234 | * |
2234 | * Perform an aging cycle. | | 2235 | * Perform an aging cycle. |
2235 | */ | | 2236 | */ |
2236 | static void | | 2237 | static void |
2237 | bridge_rtage(struct bridge_softc *sc) | | 2238 | bridge_rtage(struct bridge_softc *sc) |
2238 | { | | 2239 | { |
2239 | bridge_rtlist_iterate_remove(sc, bridge_rtage_cb, NULL); | | 2240 | bridge_rtlist_iterate_remove(sc, bridge_rtage_cb, NULL); |
2240 | } | | 2241 | } |
2241 | | | 2242 | |
2242 | | | 2243 | |
2243 | static bool | | 2244 | static bool |
2244 | bridge_rtflush_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, | | 2245 | bridge_rtflush_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, |
2245 | bool *need_break, void *arg) | | 2246 | bool *need_break, void *arg) |
2246 | { | | 2247 | { |
2247 | int full = *(int*)arg; | | 2248 | int full = *(int*)arg; |
2248 | | | 2249 | |
2249 | if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) | | 2250 | if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) |
2250 | return true; | | 2251 | return true; |
2251 | else | | 2252 | else |
2252 | return false; | | 2253 | return false; |
2253 | } | | 2254 | } |
2254 | | | 2255 | |
2255 | /* | | 2256 | /* |
2256 | * bridge_rtflush: | | 2257 | * bridge_rtflush: |
2257 | * | | 2258 | * |
2258 | * Remove all dynamic addresses from the bridge. | | 2259 | * Remove all dynamic addresses from the bridge. |
2259 | */ | | 2260 | */ |
2260 | static void | | 2261 | static void |
2261 | bridge_rtflush(struct bridge_softc *sc, int full) | | 2262 | bridge_rtflush(struct bridge_softc *sc, int full) |
2262 | { | | 2263 | { |
2263 | bridge_rtlist_iterate_remove(sc, bridge_rtflush_cb, &full); | | 2264 | bridge_rtlist_iterate_remove(sc, bridge_rtflush_cb, &full); |
2264 | } | | 2265 | } |
2265 | | | 2266 | |
2266 | /* | | 2267 | /* |
2267 | * bridge_rtdaddr: | | 2268 | * bridge_rtdaddr: |
2268 | * | | 2269 | * |
2269 | * Remove an address from the table. | | 2270 | * Remove an address from the table. |
2270 | */ | | 2271 | */ |
2271 | static int | | 2272 | static int |
2272 | bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr) | | 2273 | bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr) |
2273 | { | | 2274 | { |
2274 | struct bridge_rtnode *brt; | | 2275 | struct bridge_rtnode *brt; |
2275 | | | 2276 | |
2276 | BRIDGE_RT_LOCK(sc); | | 2277 | BRIDGE_RT_LOCK(sc); |
2277 | if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL) { | | 2278 | if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL) { |
2278 | BRIDGE_RT_UNLOCK(sc); | | 2279 | BRIDGE_RT_UNLOCK(sc); |
2279 | return ENOENT; | | 2280 | return ENOENT; |
2280 | } | | 2281 | } |
2281 | bridge_rtnode_remove(sc, brt); | | 2282 | bridge_rtnode_remove(sc, brt); |
2282 | BRIDGE_RT_PSZ_PERFORM(sc); | | 2283 | BRIDGE_RT_PSZ_PERFORM(sc); |
2283 | BRIDGE_RT_UNLOCK(sc); | | 2284 | BRIDGE_RT_UNLOCK(sc); |
2284 | | | 2285 | |
2285 | bridge_rtnode_destroy(brt); | | 2286 | bridge_rtnode_destroy(brt); |
2286 | | | 2287 | |
2287 | return 0; | | 2288 | return 0; |
2288 | } | | 2289 | } |
2289 | | | 2290 | |
2290 | /* | | 2291 | /* |
2291 | * bridge_rtdelete: | | 2292 | * bridge_rtdelete: |
2292 | * | | 2293 | * |
2293 | * Delete routes to a speicifc member interface. | | 2294 | * Delete routes to a speicifc member interface. |
2294 | */ | | 2295 | */ |
2295 | static void | | 2296 | static void |
2296 | bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp) | | 2297 | bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp) |
2297 | { | | 2298 | { |
2298 | struct bridge_rtnode *brt; | | 2299 | struct bridge_rtnode *brt; |
2299 | | | 2300 | |
2300 | BRIDGE_RT_LOCK(sc); | | 2301 | BRIDGE_RT_LOCK(sc); |
2301 | LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { | | 2302 | LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { |
2302 | if (brt->brt_ifp == ifp) | | 2303 | if (brt->brt_ifp == ifp) |
2303 | break; | | 2304 | break; |
2304 | } | | 2305 | } |
2305 | if (brt == NULL) { | | 2306 | if (brt == NULL) { |
2306 | BRIDGE_RT_UNLOCK(sc); | | 2307 | BRIDGE_RT_UNLOCK(sc); |
2307 | return; | | 2308 | return; |
2308 | } | | 2309 | } |
2309 | bridge_rtnode_remove(sc, brt); | | 2310 | bridge_rtnode_remove(sc, brt); |
2310 | BRIDGE_RT_PSZ_PERFORM(sc); | | 2311 | BRIDGE_RT_PSZ_PERFORM(sc); |
2311 | BRIDGE_RT_UNLOCK(sc); | | 2312 | BRIDGE_RT_UNLOCK(sc); |
2312 | | | 2313 | |
2313 | bridge_rtnode_destroy(brt); | | 2314 | bridge_rtnode_destroy(brt); |
2314 | } | | 2315 | } |
2315 | | | 2316 | |
2316 | /* | | 2317 | /* |
2317 | * bridge_rtable_init: | | 2318 | * bridge_rtable_init: |
2318 | * | | 2319 | * |
2319 | * Initialize the route table for this bridge. | | 2320 | * Initialize the route table for this bridge. |
2320 | */ | | 2321 | */ |
2321 | static void | | 2322 | static void |
2322 | bridge_rtable_init(struct bridge_softc *sc) | | 2323 | bridge_rtable_init(struct bridge_softc *sc) |
2323 | { | | 2324 | { |
2324 | int i; | | 2325 | int i; |
2325 | | | 2326 | |
2326 | sc->sc_rthash = kmem_alloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, | | 2327 | sc->sc_rthash = kmem_alloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, |
2327 | KM_SLEEP); | | 2328 | KM_SLEEP); |
2328 | | | 2329 | |
2329 | for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) | | 2330 | for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) |
2330 | LIST_INIT(&sc->sc_rthash[i]); | | 2331 | LIST_INIT(&sc->sc_rthash[i]); |
2331 | | | 2332 | |
2332 | sc->sc_rthash_key = cprng_fast32(); | | 2333 | sc->sc_rthash_key = cprng_fast32(); |
2333 | | | 2334 | |
2334 | LIST_INIT(&sc->sc_rtlist); | | 2335 | LIST_INIT(&sc->sc_rtlist); |
2335 | | | 2336 | |
2336 | sc->sc_rtlist_psz = pserialize_create(); | | 2337 | sc->sc_rtlist_psz = pserialize_create(); |
2337 | sc->sc_rtlist_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET); | | 2338 | sc->sc_rtlist_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET); |
2338 | } | | 2339 | } |
2339 | | | 2340 | |
2340 | /* | | 2341 | /* |
2341 | * bridge_rtable_fini: | | 2342 | * bridge_rtable_fini: |
2342 | * | | 2343 | * |
2343 | * Deconstruct the route table for this bridge. | | 2344 | * Deconstruct the route table for this bridge. |
2344 | */ | | 2345 | */ |
2345 | static void | | 2346 | static void |
2346 | bridge_rtable_fini(struct bridge_softc *sc) | | 2347 | bridge_rtable_fini(struct bridge_softc *sc) |
2347 | { | | 2348 | { |
2348 | | | 2349 | |
2349 | kmem_free(sc->sc_rthash, sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE); | | 2350 | kmem_free(sc->sc_rthash, sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE); |
2350 | if (sc->sc_rtlist_lock) | | 2351 | if (sc->sc_rtlist_lock) |
2351 | mutex_obj_free(sc->sc_rtlist_lock); | | 2352 | mutex_obj_free(sc->sc_rtlist_lock); |
2352 | if (sc->sc_rtlist_psz) | | 2353 | if (sc->sc_rtlist_psz) |
2353 | pserialize_destroy(sc->sc_rtlist_psz); | | 2354 | pserialize_destroy(sc->sc_rtlist_psz); |
2354 | } | | 2355 | } |
2355 | | | 2356 | |
2356 | /* | | 2357 | /* |
2357 | * The following hash function is adapted from "Hash Functions" by Bob Jenkins | | 2358 | * The following hash function is adapted from "Hash Functions" by Bob Jenkins |
2358 | * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). | | 2359 | * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). |
2359 | */ | | 2360 | */ |
2360 | #define mix(a, b, c) \ | | 2361 | #define mix(a, b, c) \ |