if_agrsubr.c revision 1.8 1 /* $NetBSD: if_agrsubr.c,v 1.8 2007/09/01 03:07:24 dyoung 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.8 2007/09/01 03:07:24 dyoung Exp $");
31
32 #include "bpfilter.h"
33 #include "opt_inet.h"
34
35 #include <sys/param.h>
36 #include <sys/callout.h>
37 #include <sys/malloc.h>
38 #include <sys/systm.h>
39 #include <sys/types.h>
40 #include <sys/queue.h>
41 #include <sys/sockio.h>
42
43 #include <net/if.h>
44
45 #include <net/agr/if_agrvar_impl.h>
46 #include <net/agr/if_agrsubr.h>
47
48 struct agr_mc_entry {
49 TAILQ_ENTRY(agr_mc_entry) ame_q;
50 int ame_refcnt;
51 struct agr_ifreq ame_ifr; /* XXX waste */
52 };
53
54 static struct agr_mc_entry *agr_mc_lookup(struct agr_multiaddrs *,
55 const struct sockaddr *);
56 static int agrport_mc_add_callback(struct agr_port *, void *);
57 static int agrport_mc_del_callback(struct agr_port *, void *);
58 static int agrmc_mc_add_callback(struct agr_mc_entry *, void *);
59 static int agrmc_mc_del_callback(struct agr_mc_entry *, void *);
60
61 static int agr_mc_add(struct agr_multiaddrs *, const struct sockaddr *);
62 static int agr_mc_del(struct agr_multiaddrs *, const struct sockaddr *);
63
64 int
65 agr_mc_purgeall(struct agr_softc *sc, struct agr_multiaddrs *ama)
66 {
67 struct agr_mc_entry *ame;
68 int error = 0;
69
70 while ((ame = TAILQ_FIRST(&ama->ama_addrs)) != NULL) {
71 error = agr_port_foreach(sc,
72 agrport_mc_del_callback, &ame->ame_ifr);
73 if (error) {
74 /* XXX XXX */
75 printf("%s: error %d\n", __func__, error);
76 }
77 TAILQ_REMOVE(&ama->ama_addrs, ame, ame_q);
78 free(ame, M_DEVBUF);
79 }
80
81 return error;
82 }
83
84 int
85 agr_mc_init(struct agr_softc *sc, struct agr_multiaddrs *ama)
86 {
87
88 TAILQ_INIT(&ama->ama_addrs);
89
90 return 0;
91 }
92
93 /* ==================== */
94
95 static struct agr_mc_entry *
96 agr_mc_lookup(struct agr_multiaddrs *ama, const struct sockaddr *sa)
97 {
98 struct agr_mc_entry *ame;
99
100 TAILQ_FOREACH(ame, &ama->ama_addrs, ame_q) {
101 if (!memcmp(&ame->ame_ifr.ifr_ss, sa, sa->sa_len))
102 return ame;
103 }
104
105 return NULL;
106 }
107
108 int
109 agr_mc_foreach(struct agr_multiaddrs *ama,
110 int (*func)(struct agr_mc_entry *, void *), void *arg)
111 {
112 struct agr_mc_entry *ame;
113 int error = 0;
114
115 TAILQ_FOREACH(ame, &ama->ama_addrs, ame_q) {
116 error = (*func)(ame, arg);
117 if (error) {
118 /*
119 * XXX how to recover?
120 * we can try to restore setting, but it can also fail..
121 */
122 break;
123 }
124 }
125
126 return error;
127 }
128
129 static int
130 agr_mc_add(struct agr_multiaddrs *ama, const struct sockaddr *sa)
131 {
132 struct agr_mc_entry *ame;
133
134 ame = agr_mc_lookup(ama, sa);
135 if (ame) {
136 ame->ame_refcnt++;
137 return 0;
138 }
139
140 ame = malloc(sizeof(*ame), M_DEVBUF, M_NOWAIT | M_ZERO);
141 if (ame == NULL)
142 return ENOMEM;
143
144 memcpy(&ame->ame_ifr.ifr_ss, sa, sa->sa_len);
145 ame->ame_refcnt = 1;
146 TAILQ_INSERT_TAIL(&ama->ama_addrs, ame, ame_q);
147
148 return ENETRESET;
149 }
150
151 static int
152 agr_mc_del(struct agr_multiaddrs *ama, const struct sockaddr *sa)
153 {
154 struct agr_mc_entry *ame;
155
156 ame = agr_mc_lookup(ama, sa);
157 if (ame == NULL)
158 return ENOENT;
159
160 ame->ame_refcnt--;
161 if (ame->ame_refcnt > 0)
162 return 0;
163
164 TAILQ_REMOVE(&ama->ama_addrs, ame, ame_q);
165 free(ame, M_DEVBUF);
166
167 return ENETRESET;
168 }
169
170 /* ==================== */
171
172 int
173 agr_port_foreach(struct agr_softc *sc,
174 int (*func)(struct agr_port *, void *), void *arg)
175 {
176 struct agr_port *port;
177 int error = 0;
178
179 TAILQ_FOREACH(port, &sc->sc_ports, port_q) {
180 if ((port->port_flags & (AGRPORT_LARVAL | AGRPORT_DETACHING))) {
181 continue;
182 }
183 error = (func)(port, arg);
184 if (error) {
185 /*
186 * XXX how to recover?
187 * we can try to restore setting, but it can also fail..
188 */
189 break;
190 }
191 }
192
193 return error;
194 }
195
196 /* ==================== */
197
198 static int
199 agrmc_mc_add_callback(struct agr_mc_entry *ame, void *arg)
200 {
201
202 return agrport_mc_add_callback(arg, &ame->ame_ifr);
203 }
204
205 static int
206 agrmc_mc_del_callback(struct agr_mc_entry *ame, void *arg)
207 {
208
209 return agrport_mc_del_callback(arg, &ame->ame_ifr);
210 }
211
212 int
213 agr_configmulti_port(struct agr_multiaddrs *ama, struct agr_port *port,
214 bool add)
215 {
216
217 return agr_mc_foreach(ama,
218 add ? agrmc_mc_add_callback : agrmc_mc_del_callback, port);
219 }
220
221 /* -------------------- */
222
223 static int
224 agrport_mc_add_callback(struct agr_port *port, void *arg)
225 {
226
227 return agrport_ioctl(port, SIOCADDMULTI, arg);
228 }
229
230 static int
231 agrport_mc_del_callback(struct agr_port *port, void *arg)
232 {
233
234 return agrport_ioctl(port, SIOCDELMULTI, arg);
235 }
236
237 int
238 agr_configmulti_ifreq(struct agr_softc *sc, struct agr_multiaddrs *ama,
239 struct ifreq *ifr, bool add)
240 {
241 int error;
242
243 if (add)
244 error = agr_mc_add(ama, ifreq_getaddr(SIOCADDMULTI, ifr));
245 else
246 error = agr_mc_del(ama, ifreq_getaddr(SIOCDELMULTI, ifr));
247
248 if (error != ENETRESET)
249 return error;
250
251 return agr_port_foreach(sc,
252 add ? agrport_mc_add_callback : agrport_mc_del_callback, ifr);
253 }
254
255 /* ==================== */
256
257 int
258 agr_port_getmedia(struct agr_port *port, u_int *media, u_int *status)
259 {
260 struct ifmediareq ifmr;
261 int error;
262
263 memset(&ifmr, 0, sizeof(ifmr));
264 ifmr.ifm_count = 0;
265 error = agrport_ioctl(port, SIOCGIFMEDIA, (void *)&ifmr);
266
267 if (error == 0) {
268 *media = ifmr.ifm_active;
269 *status = ifmr.ifm_status;
270 }
271
272 return error;
273 }
274