1 1.57 riastrad /* $NetBSD: if_agr.c,v 1.57 2024/06/29 12:11:12 riastradh Exp $ */ 2 1.1 yamt 3 1.1 yamt /*- 4 1.1 yamt * Copyright (c)2005 YAMAMOTO Takashi, 5 1.1 yamt * All rights reserved. 6 1.1 yamt * 7 1.1 yamt * Redistribution and use in source and binary forms, with or without 8 1.1 yamt * modification, are permitted provided that the following conditions 9 1.1 yamt * are met: 10 1.1 yamt * 1. Redistributions of source code must retain the above copyright 11 1.1 yamt * notice, this list of conditions and the following disclaimer. 12 1.1 yamt * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 yamt * notice, this list of conditions and the following disclaimer in the 14 1.1 yamt * documentation and/or other materials provided with the distribution. 15 1.1 yamt * 16 1.1 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 yamt * SUCH DAMAGE. 27 1.1 yamt */ 28 1.1 yamt 29 1.1 yamt #include <sys/cdefs.h> 30 1.57 riastrad __KERNEL_RCSID(0, "$NetBSD: if_agr.c,v 1.57 2024/06/29 12:11:12 riastradh Exp $"); 31 1.1 yamt 32 1.33 pooka #ifdef _KERNEL_OPT 33 1.1 yamt #include "opt_inet.h" 34 1.33 pooka #endif 35 1.1 yamt 36 1.1 yamt #include <sys/param.h> 37 1.2 yamt #include <sys/callout.h> 38 1.1 yamt #include <sys/malloc.h> 39 1.1 yamt #include <sys/mbuf.h> 40 1.1 yamt #include <sys/systm.h> 41 1.1 yamt #include <sys/types.h> 42 1.1 yamt #include <sys/queue.h> 43 1.1 yamt #include <sys/sockio.h> 44 1.1 yamt #include <sys/proc.h> /* XXX for curproc */ 45 1.5 yamt #include <sys/kauth.h> 46 1.26 dyoung #include <sys/xcall.h> 47 1.39 christos #include <sys/device.h> 48 1.39 christos #include <sys/module.h> 49 1.39 christos #include <sys/atomic.h> 50 1.1 yamt 51 1.1 yamt #include <net/bpf.h> 52 1.1 yamt #include <net/if.h> 53 1.1 yamt #include <net/if_dl.h> 54 1.1 yamt #include <net/if_types.h> 55 1.23 darran #include <net/if_ether.h> 56 1.44 maxv #include <net/if_vlanvar.h> 57 1.1 yamt 58 1.1 yamt #if defined(INET) 59 1.1 yamt #include <netinet/in.h> 60 1.1 yamt #include <netinet/if_inarp.h> 61 1.1 yamt #endif 62 1.1 yamt 63 1.1 yamt #include <net/agr/if_agrvar.h> 64 1.1 yamt #include <net/agr/if_agrvar_impl.h> 65 1.1 yamt #include <net/agr/if_agrioctl.h> 66 1.1 yamt #include <net/agr/if_agrsubr.h> 67 1.1 yamt #include <net/agr/if_agrethervar.h> 68 1.1 yamt 69 1.32 christos #include "ioconf.h" 70 1.1 yamt 71 1.1 yamt static int agr_clone_create(struct if_clone *, int); 72 1.1 yamt static int agr_clone_destroy(struct ifnet *); 73 1.1 yamt static void agr_start(struct ifnet *); 74 1.26 dyoung static int agr_setconfig(struct agr_softc *, const struct agrreq *); 75 1.26 dyoung static int agr_getconfig(struct agr_softc *, struct agrreq *); 76 1.26 dyoung static int agr_getportlist(struct agr_softc *, struct agrreq *); 77 1.1 yamt static int agr_addport(struct ifnet *, struct ifnet *); 78 1.1 yamt static int agr_remport(struct ifnet *, struct ifnet *); 79 1.1 yamt static int agrreq_copyin(const void *, struct agrreq *); 80 1.1 yamt static int agrreq_copyout(void *, struct agrreq *); 81 1.11 christos static int agr_ioctl(struct ifnet *, u_long, void *); 82 1.1 yamt static struct agr_port *agr_select_tx_port(struct agr_softc *, struct mbuf *); 83 1.11 christos static int agr_ioctl_filter(struct ifnet *, u_long, void *); 84 1.1 yamt static void agr_reset_iftype(struct ifnet *); 85 1.1 yamt static int agr_config_promisc(struct agr_softc *); 86 1.1 yamt static int agrport_config_promisc_callback(struct agr_port *, void *); 87 1.9 thorpej static int agrport_config_promisc(struct agr_port *, bool); 88 1.1 yamt static int agrport_cleanup(struct agr_softc *, struct agr_port *); 89 1.1 yamt 90 1.26 dyoung static int agr_enter(struct agr_softc *); 91 1.26 dyoung static void agr_exit(struct agr_softc *); 92 1.26 dyoung static int agr_pause(struct agr_softc *); 93 1.26 dyoung static void agr_evacuate(struct agr_softc *); 94 1.26 dyoung static void agr_sync(void); 95 1.26 dyoung static void agr_ports_lock(struct agr_softc *); 96 1.26 dyoung static void agr_ports_unlock(struct agr_softc *); 97 1.26 dyoung static bool agr_ports_enter(struct agr_softc *); 98 1.26 dyoung static void agr_ports_exit(struct agr_softc *); 99 1.26 dyoung 100 1.1 yamt static struct if_clone agr_cloner = 101 1.1 yamt IF_CLONE_INITIALIZER("agr", agr_clone_create, agr_clone_destroy); 102 1.1 yamt 103 1.39 christos static u_int agr_count; 104 1.39 christos 105 1.1 yamt /* 106 1.1 yamt * EXPORTED FUNCTIONS 107 1.1 yamt */ 108 1.1 yamt 109 1.1 yamt /* 110 1.1 yamt * agrattch: device attach routine. 111 1.1 yamt */ 112 1.1 yamt 113 1.1 yamt void 114 1.1 yamt agrattach(int count) 115 1.1 yamt { 116 1.1 yamt 117 1.39 christos /* 118 1.39 christos * Nothing to do here, initialization is handled by the 119 1.39 christos * module initialization code in agrinit() below). 120 1.39 christos */ 121 1.39 christos } 122 1.39 christos 123 1.39 christos static void 124 1.39 christos agrinit(void) 125 1.39 christos { 126 1.1 yamt if_clone_attach(&agr_cloner); 127 1.1 yamt } 128 1.1 yamt 129 1.39 christos static int 130 1.39 christos agrdetach(void) 131 1.39 christos { 132 1.39 christos int error = 0; 133 1.39 christos 134 1.39 christos if (agr_count != 0) 135 1.39 christos error = EBUSY; 136 1.39 christos 137 1.39 christos if (error == 0) 138 1.39 christos if_clone_detach(&agr_cloner); 139 1.39 christos 140 1.39 christos return error; 141 1.39 christos } 142 1.39 christos 143 1.1 yamt /* 144 1.1 yamt * agr_input: frame collector. 145 1.1 yamt */ 146 1.1 yamt 147 1.1 yamt void 148 1.1 yamt agr_input(struct ifnet *ifp_port, struct mbuf *m) 149 1.1 yamt { 150 1.44 maxv struct ethercom *ec = (struct ethercom *)ifp_port; 151 1.1 yamt struct agr_port *port; 152 1.1 yamt struct ifnet *ifp; 153 1.1 yamt 154 1.53 yamaguch port = ifp_port->if_lagg; 155 1.1 yamt KASSERT(port); 156 1.1 yamt ifp = port->port_agrifp; 157 1.1 yamt if ((port->port_flags & AGRPORT_COLLECTING) == 0) { 158 1.1 yamt m_freem(m); 159 1.51 thorpej if_statinc(ifp, if_ierrors); 160 1.1 yamt return; 161 1.1 yamt } 162 1.1 yamt 163 1.35 ozaki m_set_rcvif(m, ifp); 164 1.1 yamt 165 1.44 maxv /* 166 1.44 maxv * If VLANs are configured on the interface, check to 167 1.44 maxv * see if the device performed the decapsulation and 168 1.44 maxv * provided us with the tag. 169 1.44 maxv */ 170 1.55 yamaguch if (ec->ec_nvlans && vlan_has_tag(m) && 171 1.55 yamaguch EVL_VLANOFTAG(vlan_get_tag(m)) != 0) { 172 1.55 yamaguch MODULE_HOOK_CALL(if_vlan_vlan_input_hook, (ifp, m), 173 1.55 yamaguch m, m); 174 1.55 yamaguch if (m == NULL) 175 1.55 yamaguch return; 176 1.23 darran } 177 1.23 darran 178 1.34 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 179 1.1 yamt } 180 1.1 yamt 181 1.1 yamt /* 182 1.1 yamt * EXPORTED AGR-INTERNAL FUNCTIONS 183 1.1 yamt */ 184 1.1 yamt 185 1.12 yamt void 186 1.1 yamt agr_lock(struct agr_softc *sc) 187 1.1 yamt { 188 1.1 yamt 189 1.12 yamt mutex_enter(&sc->sc_lock); 190 1.1 yamt } 191 1.1 yamt 192 1.1 yamt void 193 1.12 yamt agr_unlock(struct agr_softc *sc) 194 1.1 yamt { 195 1.1 yamt 196 1.12 yamt mutex_exit(&sc->sc_lock); 197 1.1 yamt } 198 1.1 yamt 199 1.1 yamt /* 200 1.1 yamt * agr_xmit_frame: transmit a pre-built frame. 201 1.1 yamt */ 202 1.1 yamt 203 1.1 yamt int 204 1.1 yamt agr_xmit_frame(struct ifnet *ifp_port, struct mbuf *m) 205 1.1 yamt { 206 1.1 yamt int error; 207 1.1 yamt 208 1.1 yamt struct sockaddr_storage dst0; 209 1.1 yamt struct sockaddr *dst; 210 1.1 yamt int hdrlen; 211 1.1 yamt 212 1.1 yamt /* 213 1.1 yamt * trim off link level header and let if_output re-add it. 214 1.1 yamt * XXX better to introduce an API to transmit pre-built frames. 215 1.1 yamt */ 216 1.1 yamt 217 1.1 yamt hdrlen = ifp_port->if_hdrlen; 218 1.1 yamt if (m->m_pkthdr.len < hdrlen) { 219 1.1 yamt m_freem(m); 220 1.1 yamt return EINVAL; 221 1.1 yamt } 222 1.1 yamt memset(&dst0, 0, sizeof(dst0)); 223 1.1 yamt dst = (struct sockaddr *)&dst0; 224 1.1 yamt dst->sa_family = pseudo_AF_HDRCMPLT; 225 1.1 yamt dst->sa_len = hdrlen; 226 1.1 yamt m_copydata(m, 0, hdrlen, &dst->sa_data); 227 1.1 yamt m_adj(m, hdrlen); 228 1.1 yamt 229 1.36 knakahar error = if_output_lock(ifp_port, ifp_port, m, dst, NULL); 230 1.1 yamt 231 1.1 yamt return error; 232 1.1 yamt } 233 1.1 yamt 234 1.1 yamt int 235 1.11 christos agrport_ioctl(struct agr_port *port, u_long cmd, void *arg) 236 1.1 yamt { 237 1.1 yamt struct ifnet *ifp = port->port_ifp; 238 1.1 yamt 239 1.53 yamaguch KASSERT(ifp->if_lagg == (void *)port); 240 1.1 yamt KASSERT(ifp->if_ioctl == agr_ioctl_filter); 241 1.1 yamt 242 1.1 yamt return (*port->port_ioctl)(ifp, cmd, arg); 243 1.1 yamt } 244 1.1 yamt 245 1.1 yamt /* 246 1.1 yamt * INTERNAL FUNCTIONS 247 1.1 yamt */ 248 1.23 darran /* 249 1.23 darran * Check for vlan attach/detach. 250 1.23 darran * ec->ec_nvlans is directly modified by the vlan driver. 251 1.23 darran * We keep a local count in sc (sc->sc_nvlans) to detect 252 1.23 darran * when the vlan driver attaches or detaches. 253 1.23 darran * Note the agr interface must be up for this to work. 254 1.23 darran */ 255 1.23 darran static void 256 1.23 darran agr_vlan_check(struct ifnet *ifp, struct agr_softc *sc) 257 1.23 darran { 258 1.23 darran struct ethercom *ec = (void *)ifp; 259 1.23 darran 260 1.23 darran /* vlans in sync? */ 261 1.23 darran if (sc->sc_nvlans == ec->ec_nvlans) { 262 1.23 darran return; 263 1.23 darran } 264 1.23 darran 265 1.23 darran if (sc->sc_nvlans == 0) { 266 1.23 darran /* vlan added */ 267 1.31 martin agr_port_foreach(sc, agr_vlan_add, NULL); 268 1.23 darran sc->sc_nvlans = ec->ec_nvlans; 269 1.23 darran } else if (ec->ec_nvlans == 0) { 270 1.42 ozaki bool force_zero = false; 271 1.23 darran /* vlan removed */ 272 1.42 ozaki agr_port_foreach(sc, agr_vlan_del, &force_zero); 273 1.23 darran sc->sc_nvlans = 0; 274 1.23 darran } 275 1.23 darran } 276 1.23 darran 277 1.1 yamt static int 278 1.1 yamt agr_clone_create(struct if_clone *ifc, int unit) 279 1.1 yamt { 280 1.1 yamt struct agr_softc *sc; 281 1.1 yamt struct ifnet *ifp; 282 1.41 maya int error; 283 1.1 yamt 284 1.1 yamt sc = agr_alloc_softc(); 285 1.41 maya error = agrtimer_init(sc); 286 1.41 maya if (error) { 287 1.41 maya agr_free_softc(sc); 288 1.41 maya return error; 289 1.41 maya } 290 1.1 yamt TAILQ_INIT(&sc->sc_ports); 291 1.26 dyoung mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NET); 292 1.26 dyoung mutex_init(&sc->sc_entry_mtx, MUTEX_DEFAULT, IPL_NONE); 293 1.29 pgoyette cv_init(&sc->sc_insc_cv, "agrsoftc"); 294 1.26 dyoung cv_init(&sc->sc_ports_cv, "agrports"); 295 1.1 yamt ifp = &sc->sc_if; 296 1.1 yamt snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 297 1.1 yamt ifc->ifc_name, unit); 298 1.1 yamt 299 1.1 yamt ifp->if_softc = sc; 300 1.1 yamt ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 301 1.1 yamt ifp->if_start = agr_start; 302 1.1 yamt ifp->if_ioctl = agr_ioctl; 303 1.1 yamt IFQ_SET_READY(&ifp->if_snd); 304 1.1 yamt 305 1.1 yamt if_attach(ifp); 306 1.1 yamt 307 1.1 yamt agr_reset_iftype(ifp); 308 1.39 christos atomic_inc_uint(&agr_count); 309 1.1 yamt return 0; 310 1.1 yamt } 311 1.1 yamt 312 1.1 yamt static void 313 1.1 yamt agr_reset_iftype(struct ifnet *ifp) 314 1.1 yamt { 315 1.1 yamt 316 1.1 yamt ifp->if_type = IFT_OTHER; 317 1.1 yamt ifp->if_dlt = DLT_NULL; 318 1.1 yamt ifp->if_addrlen = 0; 319 1.1 yamt if_alloc_sadl(ifp); 320 1.1 yamt } 321 1.1 yamt 322 1.1 yamt static int 323 1.1 yamt agr_clone_destroy(struct ifnet *ifp) 324 1.1 yamt { 325 1.1 yamt struct agr_softc *sc = ifp->if_softc; 326 1.1 yamt int error; 327 1.1 yamt 328 1.26 dyoung if ((error = agr_pause(sc)) != 0) 329 1.26 dyoung return error; 330 1.1 yamt 331 1.26 dyoung if_detach(ifp); 332 1.26 dyoung agrtimer_destroy(sc); 333 1.26 dyoung /* Now that the ifnet has been detached, and our 334 1.26 dyoung * component ifnets are disconnected, there can be 335 1.26 dyoung * no new threads in the softc. Wait for every 336 1.26 dyoung * thread to get out of the softc. 337 1.26 dyoung */ 338 1.26 dyoung agr_evacuate(sc); 339 1.26 dyoung mutex_destroy(&sc->sc_lock); 340 1.26 dyoung mutex_destroy(&sc->sc_entry_mtx); 341 1.26 dyoung cv_destroy(&sc->sc_insc_cv); 342 1.26 dyoung cv_destroy(&sc->sc_ports_cv); 343 1.26 dyoung agr_free_softc(sc); 344 1.1 yamt 345 1.39 christos atomic_dec_uint(&agr_count); 346 1.26 dyoung return 0; 347 1.1 yamt } 348 1.1 yamt 349 1.1 yamt static struct agr_port * 350 1.1 yamt agr_select_tx_port(struct agr_softc *sc, struct mbuf *m) 351 1.1 yamt { 352 1.1 yamt 353 1.1 yamt return (*sc->sc_iftop->iftop_select_tx_port)(sc, m); 354 1.1 yamt } 355 1.1 yamt 356 1.1 yamt #if 0 /* "generic" version */ 357 1.1 yamt static struct agr_port * 358 1.1 yamt agr_select_tx_port(struct agr_softc *sc, struct mbuf *m) 359 1.1 yamt { 360 1.1 yamt struct agr_port *port; 361 1.1 yamt uint32_t hash; 362 1.1 yamt 363 1.1 yamt hash = (*sc->sc_iftop->iftop_hashmbuf)(sc, m); 364 1.1 yamt if (sc->sc_nports == 0) 365 1.1 yamt return NULL; 366 1.1 yamt hash %= sc->sc_nports; 367 1.1 yamt port = TAILQ_FIRST(&sc->sc_ports); 368 1.1 yamt KASSERT(port != NULL); 369 1.1 yamt while (hash--) { 370 1.1 yamt port = TAILQ_NEXT(port, port_q); 371 1.1 yamt KASSERT(port != NULL); 372 1.1 yamt } 373 1.1 yamt 374 1.1 yamt return port; 375 1.1 yamt } 376 1.1 yamt #endif /* 0 */ 377 1.1 yamt 378 1.1 yamt static void 379 1.1 yamt agr_start(struct ifnet *ifp) 380 1.1 yamt { 381 1.1 yamt struct agr_softc *sc = ifp->if_softc; 382 1.1 yamt struct mbuf *m; 383 1.1 yamt 384 1.12 yamt AGR_LOCK(sc); 385 1.1 yamt 386 1.1 yamt while (/* CONSTCOND */ 1) { 387 1.1 yamt struct agr_port *port; 388 1.1 yamt 389 1.1 yamt IFQ_DEQUEUE(&ifp->if_snd, m); 390 1.1 yamt if (m == NULL) { 391 1.1 yamt break; 392 1.1 yamt } 393 1.47 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 394 1.1 yamt port = agr_select_tx_port(sc, m); 395 1.51 thorpej net_stat_ref_t nsr = IF_STAT_GETREF(ifp); 396 1.1 yamt if (port) { 397 1.1 yamt int error; 398 1.1 yamt 399 1.1 yamt error = agr_xmit_frame(port->port_ifp, m); 400 1.1 yamt if (error) { 401 1.57 riastrad if_statinc_ref(ifp, nsr, if_oerrors); 402 1.1 yamt } else { 403 1.57 riastrad if_statinc_ref(ifp, nsr, if_opackets); 404 1.1 yamt } 405 1.1 yamt } else { 406 1.1 yamt m_freem(m); 407 1.57 riastrad if_statinc_ref(ifp, nsr, if_oerrors); 408 1.1 yamt } 409 1.51 thorpej IF_STAT_PUTREF(ifp); 410 1.1 yamt } 411 1.1 yamt 412 1.12 yamt AGR_UNLOCK(sc); 413 1.1 yamt } 414 1.1 yamt 415 1.1 yamt static int 416 1.26 dyoung agr_setconfig(struct agr_softc *sc, const struct agrreq *ar) 417 1.1 yamt { 418 1.26 dyoung struct ifnet *ifp = &sc->sc_if; 419 1.1 yamt int cmd = ar->ar_cmd; 420 1.1 yamt struct ifnet *ifp_port; 421 1.1 yamt int error = 0; 422 1.1 yamt char ifname[IFNAMSIZ]; 423 1.1 yamt 424 1.8 yamt memset(ifname, 0, sizeof(ifname)); 425 1.8 yamt error = copyin(ar->ar_buf, ifname, 426 1.8 yamt MIN(ar->ar_buflen, sizeof(ifname) - 1)); 427 1.1 yamt if (error) { 428 1.1 yamt return error; 429 1.1 yamt } 430 1.1 yamt ifp_port = ifunit(ifname); 431 1.1 yamt if (ifp_port == NULL) { 432 1.1 yamt return ENOENT; 433 1.1 yamt } 434 1.1 yamt 435 1.26 dyoung agr_ports_lock(sc); 436 1.1 yamt switch (cmd) { 437 1.1 yamt case AGRCMD_ADDPORT: 438 1.1 yamt error = agr_addport(ifp, ifp_port); 439 1.1 yamt break; 440 1.1 yamt 441 1.1 yamt case AGRCMD_REMPORT: 442 1.1 yamt error = agr_remport(ifp, ifp_port); 443 1.1 yamt break; 444 1.1 yamt 445 1.1 yamt default: 446 1.1 yamt error = EINVAL; 447 1.1 yamt break; 448 1.1 yamt } 449 1.26 dyoung agr_ports_unlock(sc); 450 1.1 yamt 451 1.1 yamt return error; 452 1.1 yamt } 453 1.1 yamt 454 1.1 yamt static int 455 1.26 dyoung agr_getportlist(struct agr_softc *sc, struct agrreq *ar) 456 1.1 yamt { 457 1.1 yamt struct agr_port *port; 458 1.1 yamt struct agrportlist apl; 459 1.1 yamt struct agrportinfo api; 460 1.1 yamt char *cp = ar->ar_buf; 461 1.1 yamt size_t bufleft = (cp == NULL) ? 0 : ar->ar_buflen; 462 1.1 yamt int error; 463 1.1 yamt 464 1.1 yamt if (cp != NULL) { 465 1.1 yamt memset(&apl, 0, sizeof(apl)); 466 1.1 yamt memset(&api, 0, sizeof(api)); 467 1.1 yamt 468 1.1 yamt if (bufleft < sizeof(apl)) { 469 1.1 yamt return E2BIG; 470 1.1 yamt } 471 1.1 yamt apl.apl_nports = sc->sc_nports; 472 1.1 yamt error = copyout(&apl, cp, sizeof(apl)); 473 1.1 yamt if (error) { 474 1.1 yamt return error; 475 1.1 yamt } 476 1.1 yamt cp += sizeof(apl); 477 1.1 yamt } 478 1.1 yamt bufleft -= sizeof(apl); 479 1.1 yamt 480 1.1 yamt TAILQ_FOREACH(port, &sc->sc_ports, port_q) { 481 1.1 yamt if (cp != NULL) { 482 1.1 yamt if (bufleft < sizeof(api)) { 483 1.1 yamt return E2BIG; 484 1.1 yamt } 485 1.1 yamt memcpy(api.api_ifname, port->port_ifp->if_xname, 486 1.1 yamt sizeof(api.api_ifname)); 487 1.1 yamt api.api_flags = 0; 488 1.1 yamt if (port->port_flags & AGRPORT_COLLECTING) { 489 1.1 yamt api.api_flags |= AGRPORTINFO_COLLECTING; 490 1.1 yamt } 491 1.1 yamt if (port->port_flags & AGRPORT_DISTRIBUTING) { 492 1.1 yamt api.api_flags |= AGRPORTINFO_DISTRIBUTING; 493 1.1 yamt } 494 1.1 yamt error = copyout(&api, cp, sizeof(api)); 495 1.1 yamt if (error) { 496 1.1 yamt return error; 497 1.1 yamt } 498 1.1 yamt cp += sizeof(api); 499 1.1 yamt } 500 1.1 yamt bufleft -= sizeof(api); 501 1.1 yamt } 502 1.1 yamt 503 1.1 yamt if (cp == NULL) { 504 1.1 yamt ar->ar_buflen = -bufleft; /* necessary buffer size */ 505 1.1 yamt } 506 1.1 yamt 507 1.1 yamt return 0; 508 1.1 yamt } 509 1.1 yamt 510 1.1 yamt static int 511 1.26 dyoung agr_getconfig(struct agr_softc *sc, struct agrreq *ar) 512 1.1 yamt { 513 1.1 yamt int cmd = ar->ar_cmd; 514 1.1 yamt int error; 515 1.1 yamt 516 1.26 dyoung (void)agr_ports_enter(sc); 517 1.1 yamt switch (cmd) { 518 1.1 yamt case AGRCMD_PORTLIST: 519 1.26 dyoung error = agr_getportlist(sc, ar); 520 1.1 yamt break; 521 1.1 yamt 522 1.1 yamt default: 523 1.1 yamt error = EINVAL; 524 1.1 yamt break; 525 1.1 yamt } 526 1.26 dyoung agr_ports_exit(sc); 527 1.1 yamt 528 1.1 yamt return error; 529 1.1 yamt } 530 1.1 yamt 531 1.1 yamt static int 532 1.1 yamt agr_addport(struct ifnet *ifp, struct ifnet *ifp_port) 533 1.1 yamt { 534 1.20 dyoung const struct ifaddr *ifa; 535 1.1 yamt struct agr_softc *sc = ifp->if_softc; 536 1.1 yamt struct agr_port *port = NULL; 537 1.1 yamt int error = 0; 538 1.38 ozaki int s; 539 1.1 yamt 540 1.1 yamt if (ifp_port->if_ioctl == NULL) { 541 1.1 yamt error = EOPNOTSUPP; 542 1.1 yamt goto out; 543 1.1 yamt } 544 1.1 yamt 545 1.53 yamaguch if (ifp_port->if_lagg) { 546 1.1 yamt error = EBUSY; 547 1.1 yamt goto out; 548 1.1 yamt } 549 1.1 yamt 550 1.1 yamt if (ifp_port->if_start == agr_start) { 551 1.1 yamt error = EINVAL; 552 1.1 yamt goto out; 553 1.1 yamt } 554 1.1 yamt 555 1.1 yamt port = malloc(sizeof(*port) + ifp_port->if_addrlen, M_DEVBUF, 556 1.1 yamt M_WAITOK | M_ZERO); 557 1.1 yamt if (port == NULL) { 558 1.1 yamt error = ENOMEM; 559 1.1 yamt goto out; 560 1.1 yamt } 561 1.1 yamt port->port_flags = AGRPORT_LARVAL; 562 1.1 yamt 563 1.38 ozaki s = pserialize_read_enter(); 564 1.37 ozaki IFADDR_READER_FOREACH(ifa, ifp_port) { 565 1.20 dyoung if (ifa->ifa_addr->sa_family != AF_LINK) { 566 1.38 ozaki pserialize_read_exit(s); 567 1.20 dyoung error = EBUSY; 568 1.20 dyoung goto out; 569 1.20 dyoung } 570 1.1 yamt } 571 1.38 ozaki pserialize_read_exit(s); 572 1.1 yamt 573 1.1 yamt if (sc->sc_nports == 0) { 574 1.1 yamt switch (ifp_port->if_type) { 575 1.1 yamt case IFT_ETHER: 576 1.1 yamt sc->sc_iftop = &agrether_ops; 577 1.1 yamt break; 578 1.1 yamt 579 1.1 yamt default: 580 1.1 yamt error = EPROTONOSUPPORT; /* XXX */ 581 1.1 yamt goto out; 582 1.1 yamt } 583 1.1 yamt 584 1.1 yamt error = (*sc->sc_iftop->iftop_ctor)(sc, ifp_port); 585 1.1 yamt if (error) 586 1.1 yamt goto out; 587 1.1 yamt agrtimer_start(sc); 588 1.1 yamt } else { 589 1.1 yamt if (ifp->if_type != ifp_port->if_type) { 590 1.1 yamt error = EINVAL; 591 1.1 yamt goto out; 592 1.1 yamt } 593 1.1 yamt if (ifp->if_addrlen != ifp_port->if_addrlen) { 594 1.1 yamt error = EINVAL; 595 1.1 yamt goto out; 596 1.1 yamt } 597 1.1 yamt } 598 1.1 yamt 599 1.14 dyoung memcpy(port->port_origlladdr, CLLADDR(ifp_port->if_sadl), 600 1.1 yamt ifp_port->if_addrlen); 601 1.1 yamt 602 1.1 yamt /* 603 1.1 yamt * start to modify ifp_port. 604 1.1 yamt */ 605 1.1 yamt 606 1.24 yamt /* 607 1.24 yamt * XXX this should probably be SIOCALIFADDR but that doesn't 608 1.23 darran * appear to work (ENOTTY). We want to change the mac address 609 1.23 darran * of each port to that of the first port. No need for arps 610 1.23 darran * since there are no inet addresses assigned to the ports. 611 1.23 darran */ 612 1.46 christos IFNET_LOCK(ifp_port); 613 1.30 dyoung error = if_addr_init(ifp_port, ifp->if_dl, true); 614 1.46 christos IFNET_UNLOCK(ifp_port); 615 1.1 yamt 616 1.1 yamt if (error) { 617 1.30 dyoung printf("%s: if_addr_init error %d\n", __func__, error); 618 1.1 yamt goto cleanup; 619 1.1 yamt } 620 1.1 yamt port->port_flags |= AGRPORT_LADDRCHANGED; 621 1.1 yamt 622 1.1 yamt ifp->if_type = ifp_port->if_type; 623 1.12 yamt AGR_LOCK(sc); 624 1.1 yamt 625 1.1 yamt port->port_ifp = ifp_port; 626 1.53 yamaguch ifp_port->if_lagg = port; 627 1.1 yamt port->port_agrifp = ifp; 628 1.1 yamt TAILQ_INSERT_TAIL(&sc->sc_ports, port, port_q); 629 1.1 yamt sc->sc_nports++; 630 1.1 yamt 631 1.1 yamt port->port_ioctl = ifp_port->if_ioctl; 632 1.1 yamt ifp_port->if_ioctl = agr_ioctl_filter; 633 1.1 yamt 634 1.1 yamt port->port_flags |= AGRPORT_ATTACHED; 635 1.1 yamt 636 1.12 yamt AGR_UNLOCK(sc); 637 1.1 yamt 638 1.1 yamt error = (*sc->sc_iftop->iftop_portinit)(sc, port); 639 1.1 yamt if (error) { 640 1.1 yamt printf("%s: portinit error %d\n", __func__, error); 641 1.1 yamt goto cleanup; 642 1.1 yamt } 643 1.1 yamt 644 1.1 yamt agrport_config_promisc(port, (ifp->if_flags & IFF_PROMISC) != 0); 645 1.10 thorpej error = (*sc->sc_iftop->iftop_configmulti_port)(sc, port, true); 646 1.1 yamt if (error) { 647 1.1 yamt printf("%s: configmulti error %d\n", __func__, error); 648 1.1 yamt goto cleanup; 649 1.1 yamt } 650 1.1 yamt 651 1.12 yamt AGR_LOCK(sc); 652 1.1 yamt port->port_flags &= ~AGRPORT_LARVAL; 653 1.12 yamt AGR_UNLOCK(sc); 654 1.1 yamt out: 655 1.1 yamt if (error && port) { 656 1.1 yamt free(port, M_DEVBUF); 657 1.1 yamt } 658 1.43 ozaki if (error == 0) 659 1.43 ozaki ifp->if_flags |= IFF_RUNNING; 660 1.1 yamt return error; 661 1.1 yamt 662 1.1 yamt cleanup: 663 1.1 yamt if (agrport_cleanup(sc, port)) { 664 1.1 yamt printf("%s: error on cleanup\n", __func__); 665 1.1 yamt 666 1.1 yamt port = NULL; /* XXX */ 667 1.1 yamt } 668 1.1 yamt 669 1.1 yamt if (sc->sc_nports == 0) { 670 1.1 yamt KASSERT(TAILQ_EMPTY(&sc->sc_ports)); 671 1.1 yamt agrtimer_stop(sc); 672 1.1 yamt (*sc->sc_iftop->iftop_dtor)(sc); 673 1.1 yamt sc->sc_iftop = NULL; 674 1.1 yamt agr_reset_iftype(ifp); 675 1.1 yamt } else { 676 1.1 yamt KASSERT(!TAILQ_EMPTY(&sc->sc_ports)); 677 1.1 yamt } 678 1.1 yamt 679 1.1 yamt goto out; 680 1.1 yamt } 681 1.1 yamt 682 1.1 yamt static int 683 1.1 yamt agr_remport(struct ifnet *ifp, struct ifnet *ifp_port) 684 1.1 yamt { 685 1.1 yamt struct agr_softc *sc = ifp->if_softc; 686 1.1 yamt struct agr_port *port; 687 1.1 yamt int error = 0; 688 1.1 yamt 689 1.53 yamaguch if (ifp_port->if_lagg == NULL) { 690 1.1 yamt error = ENOENT; 691 1.1 yamt return error; 692 1.1 yamt } 693 1.1 yamt 694 1.53 yamaguch port = ifp_port->if_lagg; 695 1.1 yamt if (port->port_agrifp != ifp) { 696 1.1 yamt error = EINVAL; 697 1.1 yamt return error; 698 1.1 yamt } 699 1.1 yamt 700 1.1 yamt KASSERT(sc->sc_nports > 0); 701 1.1 yamt 702 1.12 yamt AGR_LOCK(sc); 703 1.1 yamt port->port_flags |= AGRPORT_DETACHING; 704 1.12 yamt AGR_UNLOCK(sc); 705 1.1 yamt 706 1.1 yamt error = (*sc->sc_iftop->iftop_portfini)(sc, port); 707 1.1 yamt if (error) { 708 1.1 yamt /* XXX XXX */ 709 1.1 yamt printf("%s: portfini error %d\n", __func__, error); 710 1.1 yamt goto out; 711 1.1 yamt } 712 1.1 yamt 713 1.10 thorpej error = (*sc->sc_iftop->iftop_configmulti_port)(sc, port, false); 714 1.1 yamt if (error) { 715 1.1 yamt /* XXX XXX */ 716 1.1 yamt printf("%s: configmulti_port error %d\n", __func__, error); 717 1.1 yamt goto out; 718 1.1 yamt } 719 1.1 yamt 720 1.1 yamt error = agrport_cleanup(sc, port); 721 1.1 yamt if (error) { 722 1.1 yamt /* XXX XXX */ 723 1.1 yamt printf("%s: agrport_cleanup error %d\n", __func__, error); 724 1.1 yamt goto out; 725 1.1 yamt } 726 1.1 yamt 727 1.1 yamt free(port, M_DEVBUF); 728 1.1 yamt 729 1.1 yamt out: 730 1.1 yamt if (sc->sc_nports == 0) { 731 1.1 yamt KASSERT(TAILQ_EMPTY(&sc->sc_ports)); 732 1.1 yamt agrtimer_stop(sc); 733 1.1 yamt (*sc->sc_iftop->iftop_dtor)(sc); 734 1.1 yamt sc->sc_iftop = NULL; 735 1.1 yamt /* XXX should purge all addresses? */ 736 1.1 yamt agr_reset_iftype(ifp); 737 1.1 yamt } else { 738 1.1 yamt KASSERT(!TAILQ_EMPTY(&sc->sc_ports)); 739 1.1 yamt } 740 1.1 yamt 741 1.1 yamt return error; 742 1.1 yamt } 743 1.1 yamt 744 1.1 yamt static int 745 1.1 yamt agrport_cleanup(struct agr_softc *sc, struct agr_port *port) 746 1.1 yamt { 747 1.1 yamt struct ifnet *ifp_port = port->port_ifp; 748 1.1 yamt int error; 749 1.1 yamt int result = 0; 750 1.1 yamt 751 1.10 thorpej error = agrport_config_promisc(port, false); 752 1.1 yamt if (error) { 753 1.1 yamt printf("%s: config_promisc error %d\n", __func__, error); 754 1.1 yamt result = error; 755 1.1 yamt } 756 1.1 yamt 757 1.1 yamt if ((port->port_flags & AGRPORT_LADDRCHANGED)) { 758 1.1 yamt #if 0 759 1.1 yamt memcpy(LLADDR(ifp_port->if_sadl), port->port_origlladdr, 760 1.1 yamt ifp_port->if_addrlen); 761 1.1 yamt if (ifp_port->if_init != NULL) { 762 1.54 riastrad error = if_init(ifp_port); 763 1.1 yamt } 764 1.1 yamt #else 765 1.16 dyoung union { 766 1.16 dyoung struct sockaddr sa; 767 1.16 dyoung struct sockaddr_dl sdl; 768 1.16 dyoung struct sockaddr_storage ss; 769 1.16 dyoung } u; 770 1.1 yamt struct ifaddr ifa; 771 1.1 yamt 772 1.16 dyoung sockaddr_dl_init(&u.sdl, sizeof(u.ss), 773 1.16 dyoung 0, ifp_port->if_type, NULL, 0, 774 1.16 dyoung port->port_origlladdr, ifp_port->if_addrlen); 775 1.16 dyoung memset(&ifa, 0, sizeof(ifa)); 776 1.16 dyoung ifa.ifa_addr = &u.sa; 777 1.22 dyoung error = agrport_ioctl(port, SIOCINITIFADDR, &ifa); 778 1.1 yamt #endif 779 1.1 yamt if (error) { 780 1.1 yamt printf("%s: if_init error %d\n", __func__, error); 781 1.1 yamt result = error; 782 1.1 yamt } else { 783 1.1 yamt port->port_flags &= ~AGRPORT_LADDRCHANGED; 784 1.1 yamt } 785 1.1 yamt } 786 1.1 yamt 787 1.12 yamt AGR_LOCK(sc); 788 1.1 yamt if ((port->port_flags & AGRPORT_ATTACHED)) { 789 1.53 yamaguch ifp_port->if_lagg = NULL; 790 1.1 yamt 791 1.1 yamt TAILQ_REMOVE(&sc->sc_ports, port, port_q); 792 1.1 yamt sc->sc_nports--; 793 1.1 yamt 794 1.1 yamt KASSERT(ifp_port->if_ioctl == agr_ioctl_filter); 795 1.1 yamt ifp_port->if_ioctl = port->port_ioctl; 796 1.1 yamt 797 1.1 yamt port->port_flags &= ~AGRPORT_ATTACHED; 798 1.1 yamt } 799 1.12 yamt AGR_UNLOCK(sc); 800 1.1 yamt 801 1.1 yamt return result; 802 1.1 yamt } 803 1.1 yamt 804 1.1 yamt static int 805 1.1 yamt agr_ioctl_multi(struct ifnet *ifp, u_long cmd, struct ifreq *ifr) 806 1.1 yamt { 807 1.1 yamt struct agr_softc *sc = ifp->if_softc; 808 1.1 yamt int error; 809 1.1 yamt 810 1.1 yamt error = (*sc->sc_iftop->iftop_configmulti_ifreq)(sc, ifr, 811 1.1 yamt (cmd == SIOCADDMULTI)); 812 1.1 yamt 813 1.1 yamt return error; 814 1.1 yamt } 815 1.1 yamt 816 1.21 yamt /* 817 1.21 yamt * XXX an incomplete hack; can't filter ioctls handled ifioctl(). 818 1.21 yamt * 819 1.21 yamt * the intention here is to prevent operations on underlying interfaces 820 1.21 yamt * so that their states are not changed in the way that agr(4) doesn't 821 1.21 yamt * expect. cf. the BUGS section in the agr(4) manual page. 822 1.21 yamt */ 823 1.1 yamt static int 824 1.11 christos agr_ioctl_filter(struct ifnet *ifp, u_long cmd, void *arg) 825 1.1 yamt { 826 1.53 yamaguch struct agr_port *port = ifp->if_lagg; 827 1.1 yamt int error; 828 1.1 yamt 829 1.1 yamt KASSERT(port); 830 1.1 yamt 831 1.1 yamt switch (cmd) { 832 1.22 dyoung case SIOCADDMULTI: /* add m'cast addr */ 833 1.22 dyoung case SIOCAIFADDR: /* add/chg IF alias */ 834 1.22 dyoung case SIOCALIFADDR: /* add IF addr */ 835 1.22 dyoung case SIOCDELMULTI: /* del m'cast addr */ 836 1.22 dyoung case SIOCDIFADDR: /* delete IF addr */ 837 1.22 dyoung case SIOCDIFPHYADDR: /* delete gif addrs */ 838 1.22 dyoung case SIOCDLIFADDR: /* delete IF addr */ 839 1.22 dyoung case SIOCINITIFADDR: 840 1.22 dyoung case SIOCSDRVSPEC: /* set driver-specific parameters */ 841 1.22 dyoung case SIOCSIFADDR: /* set ifnet address */ 842 1.22 dyoung case SIOCSIFBRDADDR: /* set broadcast addr */ 843 1.22 dyoung case SIOCSIFDSTADDR: /* set p-p address */ 844 1.22 dyoung case SIOCSIFGENERIC: /* generic IF set op */ 845 1.22 dyoung case SIOCSIFMEDIA: /* set net media */ 846 1.22 dyoung case SIOCSIFMETRIC: /* set IF metric */ 847 1.22 dyoung case SIOCSIFMTU: /* set ifnet mtu */ 848 1.22 dyoung case SIOCSIFNETMASK: /* set net addr mask */ 849 1.52 andvar case SIOCSIFPHYADDR: /* set gif address */ 850 1.22 dyoung case SIOCSLIFPHYADDR: /* set gif addrs */ 851 1.22 dyoung case SIOCSVH: /* set carp param */ 852 1.22 dyoung error = EBUSY; 853 1.22 dyoung break; 854 1.22 dyoung case SIOCSIFCAP: /* XXX */ 855 1.1 yamt case SIOCSIFFLAGS: /* XXX */ 856 1.22 dyoung default: 857 1.1 yamt error = agrport_ioctl(port, cmd, arg); 858 1.1 yamt break; 859 1.1 yamt } 860 1.1 yamt return error; 861 1.1 yamt } 862 1.1 yamt 863 1.1 yamt static int 864 1.1 yamt agrreq_copyin(const void *ubuf, struct agrreq *ar) 865 1.1 yamt { 866 1.1 yamt int error; 867 1.1 yamt 868 1.1 yamt error = copyin(ubuf, ar, sizeof(*ar)); 869 1.1 yamt if (error) { 870 1.1 yamt return error; 871 1.1 yamt } 872 1.1 yamt 873 1.1 yamt if (ar->ar_version != AGRREQ_VERSION) { 874 1.1 yamt return EINVAL; 875 1.1 yamt } 876 1.1 yamt 877 1.1 yamt return 0; 878 1.1 yamt } 879 1.1 yamt 880 1.1 yamt static int 881 1.1 yamt agrreq_copyout(void *ubuf, struct agrreq *ar) 882 1.1 yamt { 883 1.1 yamt int error; 884 1.1 yamt 885 1.1 yamt KASSERT(ar->ar_version == AGRREQ_VERSION); 886 1.1 yamt 887 1.1 yamt error = copyout(ar, ubuf, sizeof(*ar)); 888 1.1 yamt if (error) { 889 1.1 yamt return error; 890 1.1 yamt } 891 1.1 yamt 892 1.1 yamt return 0; 893 1.1 yamt } 894 1.1 yamt 895 1.26 dyoung /* Make sure that if any interrupt handlers are out of the softc. */ 896 1.26 dyoung static void 897 1.26 dyoung agr_sync(void) 898 1.26 dyoung { 899 1.26 dyoung 900 1.26 dyoung if (!mp_online) 901 1.26 dyoung return; 902 1.26 dyoung 903 1.50 uwe xc_barrier(0); 904 1.26 dyoung } 905 1.26 dyoung 906 1.26 dyoung static int 907 1.26 dyoung agr_pause(struct agr_softc *sc) 908 1.26 dyoung { 909 1.26 dyoung int error; 910 1.26 dyoung 911 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 912 1.26 dyoung if ((error = sc->sc_noentry) != 0) 913 1.26 dyoung goto out; 914 1.26 dyoung 915 1.26 dyoung sc->sc_noentry = EBUSY; 916 1.26 dyoung 917 1.26 dyoung while (sc->sc_insc != 0) 918 1.26 dyoung cv_wait(&sc->sc_insc_cv, &sc->sc_entry_mtx); 919 1.26 dyoung 920 1.26 dyoung if (sc->sc_nports == 0) { 921 1.26 dyoung sc->sc_noentry = ENXIO; 922 1.26 dyoung } else { 923 1.26 dyoung sc->sc_noentry = 0; 924 1.26 dyoung error = EBUSY; 925 1.26 dyoung } 926 1.26 dyoung cv_broadcast(&sc->sc_insc_cv); 927 1.26 dyoung out: 928 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 929 1.26 dyoung return error; 930 1.26 dyoung } 931 1.26 dyoung 932 1.26 dyoung static void 933 1.26 dyoung agr_evacuate(struct agr_softc *sc) 934 1.26 dyoung { 935 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 936 1.26 dyoung cv_broadcast(&sc->sc_insc_cv); 937 1.26 dyoung while (sc->sc_insc != 0 || sc->sc_paused != 0) 938 1.26 dyoung cv_wait(&sc->sc_insc_cv, &sc->sc_entry_mtx); 939 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 940 1.26 dyoung 941 1.26 dyoung agr_sync(); 942 1.26 dyoung } 943 1.26 dyoung 944 1.26 dyoung static int 945 1.26 dyoung agr_enter(struct agr_softc *sc) 946 1.26 dyoung { 947 1.26 dyoung int error; 948 1.26 dyoung 949 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 950 1.26 dyoung sc->sc_paused++; 951 1.26 dyoung while ((error = sc->sc_noentry) == EBUSY) 952 1.26 dyoung cv_wait(&sc->sc_insc_cv, &sc->sc_entry_mtx); 953 1.26 dyoung sc->sc_paused--; 954 1.26 dyoung if (error == 0) 955 1.26 dyoung sc->sc_insc++; 956 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 957 1.26 dyoung 958 1.26 dyoung return error; 959 1.26 dyoung } 960 1.26 dyoung 961 1.26 dyoung static void 962 1.26 dyoung agr_exit(struct agr_softc *sc) 963 1.26 dyoung { 964 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 965 1.26 dyoung if (--sc->sc_insc == 0) 966 1.26 dyoung cv_signal(&sc->sc_insc_cv); 967 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 968 1.26 dyoung } 969 1.26 dyoung 970 1.26 dyoung static bool 971 1.26 dyoung agr_ports_enter(struct agr_softc *sc) 972 1.26 dyoung { 973 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 974 1.28 dyoung while (sc->sc_wrports) 975 1.26 dyoung cv_wait(&sc->sc_ports_cv, &sc->sc_entry_mtx); 976 1.26 dyoung sc->sc_rdports++; 977 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 978 1.26 dyoung 979 1.26 dyoung return true; 980 1.26 dyoung } 981 1.26 dyoung 982 1.26 dyoung static void 983 1.26 dyoung agr_ports_exit(struct agr_softc *sc) 984 1.26 dyoung { 985 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 986 1.26 dyoung if (--sc->sc_rdports == 0) 987 1.26 dyoung cv_signal(&sc->sc_ports_cv); 988 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 989 1.26 dyoung } 990 1.26 dyoung 991 1.26 dyoung static void 992 1.26 dyoung agr_ports_lock(struct agr_softc *sc) 993 1.26 dyoung { 994 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 995 1.26 dyoung while (sc->sc_rdports != 0) 996 1.26 dyoung cv_wait(&sc->sc_ports_cv, &sc->sc_entry_mtx); 997 1.26 dyoung sc->sc_wrports = true; 998 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 999 1.26 dyoung } 1000 1.26 dyoung 1001 1.26 dyoung static void 1002 1.26 dyoung agr_ports_unlock(struct agr_softc *sc) 1003 1.26 dyoung { 1004 1.26 dyoung mutex_enter(&sc->sc_entry_mtx); 1005 1.26 dyoung sc->sc_wrports = false; 1006 1.26 dyoung cv_signal(&sc->sc_ports_cv); 1007 1.26 dyoung mutex_exit(&sc->sc_entry_mtx); 1008 1.26 dyoung } 1009 1.26 dyoung 1010 1.1 yamt static int 1011 1.26 dyoung agr_ioctl(struct ifnet *ifp, const u_long cmd, void *data) 1012 1.1 yamt { 1013 1.1 yamt struct agr_softc *sc = ifp->if_softc; 1014 1.1 yamt struct ifreq *ifr = (struct ifreq *)data; 1015 1.1 yamt struct ifaddr *ifa = (struct ifaddr *)data; 1016 1.1 yamt struct agrreq ar; 1017 1.26 dyoung int error; 1018 1.26 dyoung bool in_ports = false; 1019 1.1 yamt int s; 1020 1.1 yamt 1021 1.26 dyoung if ((error = agr_enter(sc)) != 0) 1022 1.26 dyoung return error; 1023 1.1 yamt 1024 1.1 yamt s = splnet(); 1025 1.1 yamt 1026 1.1 yamt switch (cmd) { 1027 1.22 dyoung case SIOCINITIFADDR: 1028 1.26 dyoung in_ports = agr_ports_enter(sc); 1029 1.1 yamt if (sc->sc_nports == 0) { 1030 1.1 yamt error = EINVAL; 1031 1.1 yamt break; 1032 1.1 yamt } 1033 1.1 yamt ifp->if_flags |= IFF_UP; 1034 1.1 yamt switch (ifa->ifa_addr->sa_family) { 1035 1.1 yamt #if defined(INET) 1036 1.1 yamt case AF_INET: 1037 1.1 yamt arp_ifinit(ifp, ifa); 1038 1.1 yamt break; 1039 1.1 yamt #endif 1040 1.1 yamt default: 1041 1.1 yamt break; 1042 1.1 yamt } 1043 1.1 yamt break; 1044 1.1 yamt 1045 1.1 yamt #if 0 /* notyet */ 1046 1.1 yamt case SIOCSIFMTU: 1047 1.1 yamt #endif 1048 1.1 yamt 1049 1.1 yamt case SIOCSIFFLAGS: 1050 1.24 yamt /* 1051 1.24 yamt * Check for a change in vlan status. This ioctl is the 1052 1.23 darran * only way we can tell that a vlan has attached or detached. 1053 1.23 darran * Note the agr interface must be up. 1054 1.23 darran */ 1055 1.23 darran agr_vlan_check(ifp, sc); 1056 1.23 darran 1057 1.22 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 1058 1.22 dyoung break; 1059 1.1 yamt agr_config_promisc(sc); 1060 1.1 yamt break; 1061 1.1 yamt 1062 1.1 yamt case SIOCSETAGR: 1063 1.1 yamt splx(s); 1064 1.18 elad error = kauth_authorize_network(kauth_cred_get(), 1065 1.7 elad KAUTH_NETWORK_INTERFACE, 1066 1.7 elad KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 1067 1.7 elad NULL); 1068 1.1 yamt if (!error) { 1069 1.1 yamt error = agrreq_copyin(ifr->ifr_data, &ar); 1070 1.1 yamt } 1071 1.1 yamt if (!error) { 1072 1.26 dyoung error = agr_setconfig(sc, &ar); 1073 1.1 yamt } 1074 1.1 yamt s = splnet(); 1075 1.1 yamt break; 1076 1.1 yamt 1077 1.1 yamt case SIOCGETAGR: 1078 1.1 yamt splx(s); 1079 1.1 yamt error = agrreq_copyin(ifr->ifr_data, &ar); 1080 1.1 yamt if (!error) { 1081 1.26 dyoung error = agr_getconfig(sc, &ar); 1082 1.1 yamt } 1083 1.1 yamt if (!error) { 1084 1.1 yamt error = agrreq_copyout(ifr->ifr_data, &ar); 1085 1.1 yamt } 1086 1.1 yamt s = splnet(); 1087 1.1 yamt break; 1088 1.1 yamt 1089 1.1 yamt case SIOCADDMULTI: 1090 1.1 yamt case SIOCDELMULTI: 1091 1.26 dyoung in_ports = agr_ports_enter(sc); 1092 1.26 dyoung if (sc->sc_nports == 0) 1093 1.1 yamt error = EINVAL; 1094 1.26 dyoung else 1095 1.26 dyoung error = agr_ioctl_multi(ifp, cmd, ifr); 1096 1.1 yamt break; 1097 1.1 yamt 1098 1.1 yamt default: 1099 1.22 dyoung error = ifioctl_common(ifp, cmd, data); 1100 1.1 yamt break; 1101 1.1 yamt } 1102 1.1 yamt 1103 1.26 dyoung if (in_ports) 1104 1.26 dyoung agr_ports_exit(sc); 1105 1.26 dyoung 1106 1.1 yamt splx(s); 1107 1.1 yamt 1108 1.26 dyoung agr_exit(sc); 1109 1.1 yamt 1110 1.1 yamt return error; 1111 1.1 yamt } 1112 1.1 yamt 1113 1.1 yamt static int 1114 1.1 yamt agr_config_promisc(struct agr_softc *sc) 1115 1.1 yamt { 1116 1.1 yamt int error; 1117 1.1 yamt 1118 1.1 yamt agr_port_foreach(sc, agrport_config_promisc_callback, &error); 1119 1.1 yamt 1120 1.1 yamt return error; 1121 1.1 yamt } 1122 1.1 yamt 1123 1.1 yamt static int 1124 1.1 yamt agrport_config_promisc_callback(struct agr_port *port, void *arg) 1125 1.1 yamt { 1126 1.1 yamt struct agr_softc *sc = AGR_SC_FROM_PORT(port); 1127 1.1 yamt int *errorp = arg; 1128 1.1 yamt int error; 1129 1.9 thorpej bool promisc; 1130 1.1 yamt 1131 1.1 yamt promisc = (sc->sc_if.if_flags & IFF_PROMISC) != 0; 1132 1.1 yamt 1133 1.1 yamt error = agrport_config_promisc(port, promisc); 1134 1.1 yamt if (error) { 1135 1.1 yamt *errorp = error; 1136 1.1 yamt } 1137 1.1 yamt 1138 1.1 yamt return 0; 1139 1.1 yamt } 1140 1.1 yamt 1141 1.1 yamt static int 1142 1.9 thorpej agrport_config_promisc(struct agr_port *port, bool promisc) 1143 1.1 yamt { 1144 1.1 yamt int error; 1145 1.1 yamt 1146 1.1 yamt if (( promisc && (port->port_flags & AGRPORT_PROMISC) != 0) || 1147 1.1 yamt (!promisc && (port->port_flags & AGRPORT_PROMISC) == 0)) { 1148 1.1 yamt return 0; 1149 1.1 yamt } 1150 1.1 yamt 1151 1.1 yamt error = ifpromisc(port->port_ifp, promisc); 1152 1.1 yamt if (error == 0) { 1153 1.1 yamt if (promisc) { 1154 1.1 yamt port->port_flags |= AGRPORT_PROMISC; 1155 1.1 yamt } else { 1156 1.1 yamt port->port_flags &= ~AGRPORT_PROMISC; 1157 1.1 yamt } 1158 1.1 yamt } 1159 1.1 yamt 1160 1.1 yamt return error; 1161 1.1 yamt } 1162 1.39 christos 1163 1.39 christos /* 1164 1.39 christos * Module infrastructure 1165 1.39 christos */ 1166 1.39 christos #include <net/if_module.h> 1167 1.39 christos 1168 1.49 pgoyette IF_MODULE(MODULE_CLASS_DRIVER, agr, NULL) 1169