1 /* $NetBSD: if_agrether.c,v 1.7 2009/05/29 04:57:05 darran Exp $ */
4 * Copyright (c)2005 YAMAMOTO Takashi,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: if_agrether.c,v 1.7 2009/05/29 04:57:05 darran Exp $");
32 #include <sys/param.h>
33 #include <sys/callout.h>
35 #include <sys/sockio.h>
38 #include <net/if_dl.h>
39 #include <net/if_ether.h>
40 #include <net/if_media.h>
42 #include <net/agr/if_agrvar_impl.h>
43 #include <net/agr/if_agrethervar.h>
44 #include <net/agr/if_agrsubr.h>
46 #include <net/agr/ieee8023_slowprotocols.h>
47 #include <net/agr/ieee8023_tlv.h>
48 #include <net/agr/ieee8023ad.h>
49 #include <net/agr/ieee8023ad_lacp.h>
50 #include <net/agr/ieee8023ad_lacp_impl.h>
51 #include <net/agr/ieee8023ad_impl.h>
53 static int agrether_ctor(struct agr_softc
*, struct ifnet
*);
54 static void agrether_dtor(struct agr_softc
*);
55 static int agrether_portinit(struct agr_softc
*, struct agr_port
*);
56 static int agrether_portfini(struct agr_softc
*, struct agr_port
*);
57 static struct agr_port
*agrether_select_tx_port(struct agr_softc
*,
59 static int agrether_configmulti_port(struct agr_softc
*, struct agr_port
*,
61 static int agrether_configmulti_ifreq(struct agr_softc
*, struct ifreq
*,
64 const struct agr_iftype_ops agrether_ops
= {
66 .iftop_porttick
= ieee8023ad_lacp_porttick
,
67 .iftop_portstate
= ieee8023ad_lacp_portstate
,
68 .iftop_ctor
= agrether_ctor
,
69 .iftop_dtor
= agrether_dtor
,
70 .iftop_portinit
= agrether_portinit
,
71 .iftop_portfini
= agrether_portfini
,
72 .iftop_hashmbuf
= agrether_hashmbuf
,
73 .iftop_select_tx_port
= agrether_select_tx_port
,
74 .iftop_configmulti_port
= agrether_configmulti_port
,
75 .iftop_configmulti_ifreq
= agrether_configmulti_ifreq
78 struct agrether_private
{
79 struct ieee8023ad_softc aep_ieee8023ad_softc
;
80 struct agr_multiaddrs aep_multiaddrs
;
83 struct agrether_port_private
{
84 struct ieee8023ad_port aepp_ieee8023ad_port
;
88 agrether_ctor(struct agr_softc
*sc
, struct ifnet
*ifp_port
)
90 struct ifnet
*ifp
= &sc
->sc_if
;
91 struct ethercom
*ec
= (void *)ifp
;
92 struct agrether_private
*priv
;
94 priv
= malloc(sizeof(*priv
), M_DEVBUF
, M_NOWAIT
| M_ZERO
);
98 agr_mc_init(sc
, &priv
->aep_multiaddrs
);
100 sc
->sc_iftprivate
= priv
;
102 * inherit ports capabilities
103 * XXX this really needs to be the intersection of all
104 * ports capabilities, not just the latest port.
105 * Okay if ports are the same.
107 ifp
->if_capabilities
= ifp_port
->if_capabilities
&
108 (IFCAP_TSOv4
| IFCAP_TSOv6
|
109 IFCAP_CSUM_IPv4_Tx
| IFCAP_CSUM_IPv4_Rx
|
110 IFCAP_CSUM_TCPv4_Tx
| IFCAP_CSUM_TCPv4_Rx
|
111 IFCAP_CSUM_UDPv4_Tx
| IFCAP_CSUM_UDPv4_Rx
|
112 IFCAP_CSUM_TCPv6_Tx
| IFCAP_CSUM_TCPv6_Rx
|
113 IFCAP_CSUM_UDPv6_Tx
| IFCAP_CSUM_UDPv6_Rx
);
115 ether_ifattach(ifp
, CLLADDR(ifp_port
->if_sadl
));
116 ec
->ec_capabilities
=
117 ETHERCAP_VLAN_MTU
| ETHERCAP_VLAN_HWTAGGING
| ETHERCAP_JUMBO_MTU
;
125 agrether_dtor(struct agr_softc
*sc
)
127 struct agrether_private
*priv
= sc
->sc_iftprivate
;
134 agr_mc_purgeall(sc
, &priv
->aep_multiaddrs
);
135 free(priv
, M_DEVBUF
);
136 sc
->sc_iftprivate
= NULL
;
140 agrether_portinit(struct agr_softc
*sc
, struct agr_port
*port
)
143 struct agrether_port_private
*priv
;
145 struct ethercom
*ec
= (void *)&sc
->sc_if
;
146 struct ethercom
*ec_port
= (void *)port
->port_ifp
;
148 port
->port_media
= IFM_ETHER
| IFM_NONE
;
151 * XXX it's better to always advertise ETHERCAP_VLAN_HWTAGGING
152 * and do tag insertion by ourselves if necessary,
153 * so that we can mix devices with different capabilities.
154 * ditto about if_capabilities.
157 if (ec
->ec_capabilities
&
158 ~ec_port
->ec_capabilities
&
159 (ETHERCAP_VLAN_MTU
| ETHERCAP_VLAN_HWTAGGING
)) {
160 if (ec
->ec_nvlans
> 0) {
163 ec
->ec_capabilities
&=
164 ec_port
->ec_capabilities
|
165 ~(ETHERCAP_VLAN_MTU
| ETHERCAP_VLAN_HWTAGGING
);
168 /* Enable vlan support */
169 if ((ec
->ec_nvlans
> 0) &&
170 ec_port
->ec_nvlans
++ == 0 &&
171 (ec_port
->ec_capabilities
& ETHERCAP_VLAN_MTU
) != 0) {
172 struct ifnet
*p
= port
->port_ifp
;
174 * Enable Tx/Rx of VLAN-sized frames.
176 ec_port
->ec_capenable
|= ETHERCAP_VLAN_MTU
;
177 if (p
->if_flags
& IFF_UP
) {
178 ifr
.ifr_flags
= p
->if_flags
;
179 error
= (*p
->if_ioctl
)(p
, SIOCSIFFLAGS
,
182 if (ec_port
->ec_nvlans
-- == 1)
183 ec_port
->ec_capenable
&=
189 /* XXX ETHERCAP_JUMBO_MTU */
191 priv
= malloc(sizeof(*priv
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
196 port
->port_iftprivate
= priv
;
198 memset(&ifr
, 0, sizeof(ifr
));
199 ifr
.ifr_addr
.sa_len
= sizeof(ifr
.ifr_addr
);
200 ifr
.ifr_addr
.sa_family
= AF_UNSPEC
;
201 KASSERT(sizeof(ifr
.ifr_addr
) >=
202 sizeof(ethermulticastaddr_slowprotocols
));
203 memcpy(&ifr
.ifr_addr
.sa_data
,
204 ðermulticastaddr_slowprotocols
,
205 sizeof(ethermulticastaddr_slowprotocols
));
206 error
= agrport_ioctl(port
, SIOCADDMULTI
, (void *)&ifr
);
208 free(port
->port_iftprivate
, M_DEVBUF
);
209 port
->port_iftprivate
= NULL
;
213 ieee8023ad_portinit(port
);
219 agrether_portfini(struct agr_softc
*sc
, struct agr_port
*port
)
222 struct ethercom
*ec_port
= (void *)port
->port_ifp
;
225 if (port
->port_iftprivate
== NULL
) {
229 if (ec_port
->ec_nvlans
> 0) {
230 /* Disable vlan support */
231 ec_port
->ec_nvlans
= 0;
233 * Disable Tx/Rx of VLAN-sized frames.
235 ec_port
->ec_capenable
&= ~ETHERCAP_VLAN_MTU
;
236 if (port
->port_ifp
->if_flags
& IFF_UP
) {
237 ifr
.ifr_flags
= port
->port_ifp
->if_flags
;
238 (void) (*port
->port_ifp
->if_ioctl
)(port
->port_ifp
,
239 SIOCSIFFLAGS
, (void *) &ifr
);
243 memset(&ifr
, 0, sizeof(ifr
));
244 ifr
.ifr_addr
.sa_len
= sizeof(ifr
.ifr_addr
);
245 ifr
.ifr_addr
.sa_family
= AF_UNSPEC
;
246 KASSERT(sizeof(ifr
.ifr_addr
) >=
247 sizeof(ethermulticastaddr_slowprotocols
));
248 memcpy(&ifr
.ifr_addr
.sa_data
,
249 ðermulticastaddr_slowprotocols
,
250 sizeof(ethermulticastaddr_slowprotocols
));
251 error
= agrport_ioctl(port
, SIOCDELMULTI
, (void *)&ifr
);
256 ieee8023ad_portfini(port
);
258 free(port
->port_iftprivate
, M_DEVBUF
);
259 port
->port_iftprivate
= NULL
;
265 agrether_configmulti_port(struct agr_softc
*sc
, struct agr_port
*port
,
268 struct agrether_private
*priv
= sc
->sc_iftprivate
;
270 return agr_configmulti_port(&priv
->aep_multiaddrs
, port
, add
);
274 agrether_configmulti_ifreq(struct agr_softc
*sc
, struct ifreq
*ifr
,
277 struct agrether_private
*priv
= sc
->sc_iftprivate
;
279 return agr_configmulti_ifreq(sc
, &priv
->aep_multiaddrs
, ifr
, add
);
282 /* -------------------- */
284 static struct agr_port
*
285 agrether_select_tx_port(struct agr_softc
*sc
, struct mbuf
*m
)
288 return ieee8023ad_select_tx_port(sc
, m
);