1 | /* $NetBSD: if_agrsubr.c,v 1.10 2015/08/24 22:21:26 pooka Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c)2005 YAMAMOTO Takashi, |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: if_agrsubr.c,v 1.10 2015/08/24 22:21:26 pooka Exp $" ); |
31 | |
32 | #ifdef _KERNEL_OPT |
33 | #include "opt_inet.h" |
34 | #endif |
35 | |
36 | #include <sys/param.h> |
37 | #include <sys/callout.h> |
38 | #include <sys/malloc.h> |
39 | #include <sys/systm.h> |
40 | #include <sys/types.h> |
41 | #include <sys/queue.h> |
42 | #include <sys/sockio.h> |
43 | |
44 | #include <net/if.h> |
45 | |
46 | #include <net/agr/if_agrvar_impl.h> |
47 | #include <net/agr/if_agrsubr.h> |
48 | |
49 | struct agr_mc_entry { |
50 | TAILQ_ENTRY(agr_mc_entry) ame_q; |
51 | int ame_refcnt; |
52 | struct agr_ifreq ame_ifr; /* XXX waste */ |
53 | }; |
54 | |
55 | static struct agr_mc_entry *agr_mc_lookup(struct agr_multiaddrs *, |
56 | const struct sockaddr *); |
57 | static int agrport_mc_add_callback(struct agr_port *, void *); |
58 | static int agrport_mc_del_callback(struct agr_port *, void *); |
59 | static int agrmc_mc_add_callback(struct agr_mc_entry *, void *); |
60 | static int agrmc_mc_del_callback(struct agr_mc_entry *, void *); |
61 | |
62 | static int agr_mc_add(struct agr_multiaddrs *, const struct sockaddr *); |
63 | static int agr_mc_del(struct agr_multiaddrs *, const struct sockaddr *); |
64 | |
65 | int |
66 | agr_mc_purgeall(struct agr_softc *sc, struct agr_multiaddrs *ama) |
67 | { |
68 | struct agr_mc_entry *ame; |
69 | int error = 0; |
70 | |
71 | while ((ame = TAILQ_FIRST(&ama->ama_addrs)) != NULL) { |
72 | error = agr_port_foreach(sc, |
73 | agrport_mc_del_callback, &ame->ame_ifr); |
74 | if (error) { |
75 | /* XXX XXX */ |
76 | printf("%s: error %d\n" , __func__, error); |
77 | } |
78 | TAILQ_REMOVE(&ama->ama_addrs, ame, ame_q); |
79 | free(ame, M_DEVBUF); |
80 | } |
81 | |
82 | return error; |
83 | } |
84 | |
85 | int |
86 | agr_mc_init(struct agr_softc *sc, struct agr_multiaddrs *ama) |
87 | { |
88 | |
89 | TAILQ_INIT(&ama->ama_addrs); |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | /* ==================== */ |
95 | |
96 | static struct agr_mc_entry * |
97 | agr_mc_lookup(struct agr_multiaddrs *ama, const struct sockaddr *sa) |
98 | { |
99 | struct agr_mc_entry *ame; |
100 | |
101 | TAILQ_FOREACH(ame, &ama->ama_addrs, ame_q) { |
102 | if (!memcmp(&ame->ame_ifr.ifr_ss, sa, sa->sa_len)) |
103 | return ame; |
104 | } |
105 | |
106 | return NULL; |
107 | } |
108 | |
109 | int |
110 | agr_mc_foreach(struct agr_multiaddrs *ama, |
111 | int (*func)(struct agr_mc_entry *, void *), void *arg) |
112 | { |
113 | struct agr_mc_entry *ame; |
114 | int error = 0; |
115 | |
116 | TAILQ_FOREACH(ame, &ama->ama_addrs, ame_q) { |
117 | error = (*func)(ame, arg); |
118 | if (error) { |
119 | /* |
120 | * XXX how to recover? |
121 | * we can try to restore setting, but it can also fail.. |
122 | */ |
123 | break; |
124 | } |
125 | } |
126 | |
127 | return error; |
128 | } |
129 | |
130 | static int |
131 | agr_mc_add(struct agr_multiaddrs *ama, const struct sockaddr *sa) |
132 | { |
133 | struct agr_mc_entry *ame; |
134 | |
135 | ame = agr_mc_lookup(ama, sa); |
136 | if (ame) { |
137 | ame->ame_refcnt++; |
138 | return 0; |
139 | } |
140 | |
141 | ame = malloc(sizeof(*ame), M_DEVBUF, M_NOWAIT | M_ZERO); |
142 | if (ame == NULL) |
143 | return ENOMEM; |
144 | |
145 | memcpy(&ame->ame_ifr.ifr_ss, sa, sa->sa_len); |
146 | ame->ame_refcnt = 1; |
147 | TAILQ_INSERT_TAIL(&ama->ama_addrs, ame, ame_q); |
148 | |
149 | return ENETRESET; |
150 | } |
151 | |
152 | static int |
153 | agr_mc_del(struct agr_multiaddrs *ama, const struct sockaddr *sa) |
154 | { |
155 | struct agr_mc_entry *ame; |
156 | |
157 | ame = agr_mc_lookup(ama, sa); |
158 | if (ame == NULL) |
159 | return ENOENT; |
160 | |
161 | ame->ame_refcnt--; |
162 | if (ame->ame_refcnt > 0) |
163 | return 0; |
164 | |
165 | TAILQ_REMOVE(&ama->ama_addrs, ame, ame_q); |
166 | free(ame, M_DEVBUF); |
167 | |
168 | return ENETRESET; |
169 | } |
170 | |
171 | /* ==================== */ |
172 | |
173 | int |
174 | agr_port_foreach(struct agr_softc *sc, |
175 | int (*func)(struct agr_port *, void *), void *arg) |
176 | { |
177 | struct agr_port *port; |
178 | int error = 0; |
179 | |
180 | TAILQ_FOREACH(port, &sc->sc_ports, port_q) { |
181 | if ((port->port_flags & (AGRPORT_LARVAL | AGRPORT_DETACHING))) { |
182 | continue; |
183 | } |
184 | error = (func)(port, arg); |
185 | if (error) { |
186 | /* |
187 | * XXX how to recover? |
188 | * we can try to restore setting, but it can also fail.. |
189 | */ |
190 | break; |
191 | } |
192 | } |
193 | |
194 | return error; |
195 | } |
196 | |
197 | /* ==================== */ |
198 | |
199 | static int |
200 | agrmc_mc_add_callback(struct agr_mc_entry *ame, void *arg) |
201 | { |
202 | |
203 | return agrport_mc_add_callback(arg, &ame->ame_ifr); |
204 | } |
205 | |
206 | static int |
207 | agrmc_mc_del_callback(struct agr_mc_entry *ame, void *arg) |
208 | { |
209 | |
210 | return agrport_mc_del_callback(arg, &ame->ame_ifr); |
211 | } |
212 | |
213 | int |
214 | agr_configmulti_port(struct agr_multiaddrs *ama, struct agr_port *port, |
215 | bool add) |
216 | { |
217 | |
218 | return agr_mc_foreach(ama, |
219 | add ? agrmc_mc_add_callback : agrmc_mc_del_callback, port); |
220 | } |
221 | |
222 | /* -------------------- */ |
223 | |
224 | static int |
225 | agrport_mc_add_callback(struct agr_port *port, void *arg) |
226 | { |
227 | |
228 | return agrport_ioctl(port, SIOCADDMULTI, arg); |
229 | } |
230 | |
231 | static int |
232 | agrport_mc_del_callback(struct agr_port *port, void *arg) |
233 | { |
234 | |
235 | return agrport_ioctl(port, SIOCDELMULTI, arg); |
236 | } |
237 | |
238 | int |
239 | agr_configmulti_ifreq(struct agr_softc *sc, struct agr_multiaddrs *ama, |
240 | struct ifreq *ifr, bool add) |
241 | { |
242 | int error; |
243 | |
244 | if (add) |
245 | error = agr_mc_add(ama, ifreq_getaddr(SIOCADDMULTI, ifr)); |
246 | else |
247 | error = agr_mc_del(ama, ifreq_getaddr(SIOCDELMULTI, ifr)); |
248 | |
249 | if (error != ENETRESET) |
250 | return error; |
251 | |
252 | return agr_port_foreach(sc, |
253 | add ? agrport_mc_add_callback : agrport_mc_del_callback, ifr); |
254 | } |
255 | |
256 | /* ==================== */ |
257 | |
258 | int |
259 | agr_port_getmedia(struct agr_port *port, u_int *media, u_int *status) |
260 | { |
261 | struct ifmediareq ifmr; |
262 | int error; |
263 | |
264 | memset(&ifmr, 0, sizeof(ifmr)); |
265 | ifmr.ifm_count = 0; |
266 | error = agrport_ioctl(port, SIOCGIFMEDIA, (void *)&ifmr); |
267 | |
268 | if (error == 0) { |
269 | *media = ifmr.ifm_active; |
270 | *status = ifmr.ifm_status; |
271 | } |
272 | |
273 | return error; |
274 | } |
275 | |