xref: /netbsd-src/sys/net/agr/if_agrsubr.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: if_agrsubr.c,v 1.3 2005/12/11 12:24:54 christos 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.3 2005/12/11 12:24:54 christos 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 ifreq *);
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 ifreq *);
62 static int agr_mc_del(struct agr_multiaddrs *, const struct ifreq *);
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 
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 ifreq *ifr)
97 {
98 	struct agr_mc_entry *ame;
99 	const struct sockaddr *sa;
100 	sa = &ifr->ifr_addr;
101 
102 	TAILQ_FOREACH(ame, &ama->ama_addrs, ame_q) {
103 		if (!memcmp(&ame->ame_ifr.ifr_ss, sa, sa->sa_len))
104 			return ame;
105 	}
106 
107 	return NULL;
108 }
109 
110 int
111 agr_mc_foreach(struct agr_multiaddrs *ama,
112     int (*func)(struct agr_mc_entry *, void *), void *arg)
113 {
114 	struct agr_mc_entry *ame;
115 	int error = 0;
116 
117 	TAILQ_FOREACH(ame, &ama->ama_addrs, ame_q) {
118 		error = (*func)(ame, arg);
119 		if (error) {
120 			/*
121 			 * XXX how to recover?
122 			 * we can try to restore setting, but it can also fail..
123 			 */
124 			break;
125 		}
126 	}
127 
128 	return error;
129 }
130 
131 static int
132 agr_mc_add(struct agr_multiaddrs *ama, const struct ifreq *ifr)
133 {
134 	struct agr_mc_entry *ame;
135 	const struct sockaddr *sa;
136 
137 	ame = agr_mc_lookup(ama, ifr);
138 	if (ame) {
139 		ame->ame_refcnt++;
140 		return 0;
141 	}
142 
143 	ame = malloc(sizeof(*ame), M_DEVBUF, M_NOWAIT | M_ZERO);
144 	if (ame == NULL)
145 		return ENOMEM;
146 
147 	sa = &ifr->ifr_addr;
148 	memcpy(&ame->ame_ifr.ifr_ss, sa, sa->sa_len);
149 	ame->ame_refcnt = 1;
150 
151 	return ENETRESET;
152 }
153 
154 static int
155 agr_mc_del(struct agr_multiaddrs *ama, const struct ifreq *ifr)
156 {
157 	struct agr_mc_entry *ame;
158 
159 	ame = agr_mc_lookup(ama, ifr);
160 	if (ame == NULL)
161 		return ENOENT;
162 
163 	ame->ame_refcnt--;
164 	if (ame->ame_refcnt > 0)
165 		return 0;
166 
167 	free(ame, M_DEVBUF);
168 
169 	return ENETRESET;
170 }
171 
172 /* ==================== */
173 
174 int
175 agr_port_foreach(struct agr_softc *sc,
176     int (*func)(struct agr_port *, void *), void *arg)
177 {
178 	struct agr_port *port;
179 	int error = 0;
180 
181 	TAILQ_FOREACH(port, &sc->sc_ports, port_q) {
182 		if ((port->port_flags & (AGRPORT_LARVAL | AGRPORT_DETACHING))) {
183 			continue;
184 		}
185 		error = (func)(port, arg);
186 		if (error) {
187 			/*
188 			 * XXX how to recover?
189 			 * we can try to restore setting, but it can also fail..
190 			 */
191 			break;
192 		}
193 	}
194 
195 	return error;
196 }
197 
198 /* ==================== */
199 
200 static int
201 agrmc_mc_add_callback(struct agr_mc_entry *ame, void *arg)
202 {
203 
204 	return agrport_mc_add_callback(arg, &ame->ame_ifr);
205 }
206 
207 static int
208 agrmc_mc_del_callback(struct agr_mc_entry *ame, void *arg)
209 {
210 
211 	return agrport_mc_del_callback(arg, &ame->ame_ifr);
212 }
213 
214 int
215 agr_configmulti_port(struct agr_multiaddrs *ama, struct agr_port *port,
216     boolean_t add)
217 {
218 
219 	return agr_mc_foreach(ama,
220 	    add ? agrmc_mc_add_callback : agrmc_mc_del_callback, port);
221 }
222 
223 /* -------------------- */
224 
225 static int
226 agrport_mc_add_callback(struct agr_port *port, void *arg)
227 {
228 
229 	return agrport_ioctl(port, SIOCADDMULTI, arg);
230 }
231 
232 static int
233 agrport_mc_del_callback(struct agr_port *port, void *arg)
234 {
235 
236 	return agrport_ioctl(port, SIOCADDMULTI, arg);
237 }
238 
239 int
240 agr_configmulti_ifreq(struct agr_softc *sc, struct agr_multiaddrs *ama,
241     struct ifreq *ifr, boolean_t add)
242 {
243 	int error;
244 
245 	if (add)
246 		error = agr_mc_add(ama, ifr);
247 	else
248 		error = agr_mc_del(ama, ifr);
249 
250 	if (error != ENETRESET)
251 		return error;
252 
253 	return agr_port_foreach(sc,
254 	    add ? agrport_mc_add_callback : agrport_mc_del_callback, ifr);
255 }
256 
257 /* ==================== */
258 
259 int
260 agr_port_getmedia(struct agr_port *port, u_int *media, u_int *status)
261 {
262 	struct ifmediareq ifmr;
263 	int error;
264 
265 	memset(&ifmr, 0, sizeof(ifmr));
266 	ifmr.ifm_count = 0;
267 	error = agrport_ioctl(port, SIOCGIFMEDIA, (caddr_t)&ifmr);
268 
269 	if (error == 0) {
270 		*media = ifmr.ifm_active;
271 		*status = ifmr.ifm_status;
272 	}
273 
274 	return error;
275 }
276