xref: /netbsd-src/sys/net/agr/if_agrsubr.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: if_agrsubr.c,v 1.12 2018/01/25 03:54:57 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.12 2018/01/25 03:54:57 christos 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 #include <net/if_ether.h>
46 
47 #include <net/agr/if_agrvar_impl.h>
48 #include <net/agr/if_agrsubr.h>
49 
50 struct agr_mc_entry {
51 	TAILQ_ENTRY(agr_mc_entry) ame_q;
52 	int ame_refcnt;
53 	struct agr_ifreq ame_ifr; /* XXX waste */
54 };
55 
56 static struct agr_mc_entry *agr_mc_lookup(struct agr_multiaddrs *,
57     const struct sockaddr *);
58 static int agrport_mc_add_callback(struct agr_port *, void *);
59 static int agrport_mc_del_callback(struct agr_port *, void *);
60 static int agrmc_mc_add_callback(struct agr_mc_entry *, void *);
61 static int agrmc_mc_del_callback(struct agr_mc_entry *, void *);
62 
63 static int agr_mc_add(struct agr_multiaddrs *, const struct sockaddr *);
64 static int agr_mc_del(struct agr_multiaddrs *, const struct sockaddr *);
65 
66 int
67 agr_mc_purgeall(struct agr_softc *sc, struct agr_multiaddrs *ama)
68 {
69 	struct agr_mc_entry *ame;
70 	int error = 0;
71 
72 	while ((ame = TAILQ_FIRST(&ama->ama_addrs)) != NULL) {
73 		error = agr_port_foreach(sc,
74 		    agrport_mc_del_callback, &ame->ame_ifr);
75 		if (error) {
76 			/* XXX XXX */
77 			printf("%s: error %d\n", __func__, error);
78 		}
79 		TAILQ_REMOVE(&ama->ama_addrs, ame, ame_q);
80 		free(ame, M_DEVBUF);
81 	}
82 
83 	return error;
84 }
85 
86 int
87 agr_mc_init(struct agr_softc *sc, struct agr_multiaddrs *ama)
88 {
89 
90 	TAILQ_INIT(&ama->ama_addrs);
91 
92 	return 0;
93 }
94 
95 /* ==================== */
96 
97 static struct agr_mc_entry *
98 agr_mc_lookup(struct agr_multiaddrs *ama, const struct sockaddr *sa)
99 {
100 	struct agr_mc_entry *ame;
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 sockaddr *sa)
133 {
134 	struct agr_mc_entry *ame;
135 
136 	ame = agr_mc_lookup(ama, sa);
137 	if (ame) {
138 		ame->ame_refcnt++;
139 		return 0;
140 	}
141 
142 	ame = malloc(sizeof(*ame), M_DEVBUF, M_NOWAIT | M_ZERO);
143 	if (ame == NULL)
144 		return ENOMEM;
145 
146 	memcpy(&ame->ame_ifr.ifr_ss, sa, sa->sa_len);
147 	ame->ame_refcnt = 1;
148 	TAILQ_INSERT_TAIL(&ama->ama_addrs, ame, ame_q);
149 
150 	return ENETRESET;
151 }
152 
153 static int
154 agr_mc_del(struct agr_multiaddrs *ama, const struct sockaddr *sa)
155 {
156 	struct agr_mc_entry *ame;
157 
158 	ame = agr_mc_lookup(ama, sa);
159 	if (ame == NULL)
160 		return ENOENT;
161 
162 	ame->ame_refcnt--;
163 	if (ame->ame_refcnt > 0)
164 		return 0;
165 
166 	TAILQ_REMOVE(&ama->ama_addrs, ame, ame_q);
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     bool 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, SIOCDELMULTI, arg);
237 }
238 
239 int
240 agr_configmulti_ifreq(struct agr_softc *sc, struct agr_multiaddrs *ama,
241     struct ifreq *ifr, bool add)
242 {
243 	int error;
244 
245 	if (add)
246 		error = agr_mc_add(ama, ifreq_getaddr(SIOCADDMULTI, ifr));
247 	else
248 		error = agr_mc_del(ama, ifreq_getaddr(SIOCDELMULTI, 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, (void *)&ifmr);
268 
269 	if (error == 0) {
270 		*media = ifmr.ifm_active;
271 		*status = ifmr.ifm_status;
272 	}
273 
274 	return error;
275 }
276 
277 /* ==================== */
278 
279 /*
280  * Enable vlan hardware assist for the specified port.
281  */
282 int
283 agr_vlan_add(struct agr_port *port, void *arg)
284 {
285 	struct ifnet *ifp = port->port_ifp;
286 	struct ethercom *ec_port = (void *)ifp;
287 	int error=0;
288 
289 	if (ec_port->ec_nvlans++ == 0 &&
290 	    (ec_port->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
291 		struct ifnet *p = port->port_ifp;
292 		/*
293 		 * Enable Tx/Rx of VLAN-sized frames.
294 		 */
295 		ec_port->ec_capenable |= ETHERCAP_VLAN_MTU;
296 		if (p->if_flags & IFF_UP) {
297 			IFNET_LOCK(p);
298 			error = if_flags_set(p, p->if_flags);
299 			IFNET_UNLOCK(p);
300 			if (error) {
301 				if (ec_port->ec_nvlans-- == 1)
302 					ec_port->ec_capenable &=
303 					    ~ETHERCAP_VLAN_MTU;
304 				return (error);
305 			}
306 		}
307 	}
308 
309 	return error;
310 }
311 
312 /*
313  * Disable vlan hardware assist for the specified port.
314  */
315 int
316 agr_vlan_del(struct agr_port *port, void *arg)
317 {
318 	struct ethercom *ec_port = (void *)port->port_ifp;
319 	bool *force_zero = (bool *)arg;
320 
321 	KASSERT(force_zero != NULL);
322 
323 	/* Disable vlan support */
324 	if ((*force_zero && ec_port->ec_nvlans > 0) ||
325 	    ec_port->ec_nvlans-- == 1) {
326 		struct ifnet *p = port->port_ifp;
327 		if (*force_zero)
328 			ec_port->ec_nvlans = 0;
329 		/*
330 		 * Disable Tx/Rx of VLAN-sized frames.
331 		 */
332 		ec_port->ec_capenable &= ~ETHERCAP_VLAN_MTU;
333 		if (p->if_flags & IFF_UP) {
334 			IFNET_LOCK(p);
335 			(void)if_flags_set(p, p->if_flags);
336 			IFNET_UNLOCK(p);
337 		}
338 	}
339 
340 	return 0;
341 }
342