4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * bridged - bridging control daemon. This module provides DLPI-specific
29 * functions for interface to libdlpi.
36 #include <sys/types.h>
40 #include <net/if_types.h>
41 #include <net/if_dl.h>
42 #include <sys/ethernet.h>
43 #include <sys/pfmod.h>
47 static const uchar_t bridge_group_address
[] = BRIDGE_GROUP_ADDRESS
;
49 static const ushort_t bpdu_filter
[] = {
50 ENF_PUSHWORD
| 0, /* check for 1:80:c2:0:0:0 dest. */
51 ENF_PUSHLIT
| ENF_CAND
,
58 ENF_PUSHLIT
| ENF_CAND
,
65 ENF_PUSHZERO
| ENF_CAND
,
66 ENF_PUSHWORD
| 7, /* check for SSAP/DSAP 42 42 */
67 ENF_PUSHLIT
| ENF_CAND
,
72 * Because we're called by dlpi_recv(), we're called with the engine lock held.
76 dlpi_notify(dlpi_handle_t dlpi
, dlpi_notifyinfo_t
*info
, void *arg
)
78 struct portdata
*port
= arg
;
81 switch (info
->dni_note
) {
83 /* libdlpi gives us Kbps, and we want Mbps */
84 if (port
->speed
== info
->dni_speed
/ 1000)
86 port
->speed
= info
->dni_speed
/ 1000;
87 if ((rc
= STP_IN_changed_port_speed(port
->port_index
,
89 syslog(LOG_ERR
, "STP can't change port speed on %s: %s",
90 port
->name
, STP_IN_get_error_explanation(rc
));
93 case DL_NOTE_PHYS_ADDR
:
94 if (memcmp(info
->dni_physaddr
, port
->mac_addr
, ETHERADDRL
) != 0)
95 rstp_change_mac(port
, info
->dni_physaddr
);
98 case DL_NOTE_LINK_DOWN
:
99 if (!port
->phys_status
)
101 port
->phys_status
= B_FALSE
;
102 if (!port
->admin_status
|| protect
!= DLADM_BRIDGE_PROT_STP
||
105 if ((rc
= STP_IN_enable_port(port
->port_index
, False
)) != 0)
106 syslog(LOG_ERR
, "STP can't disable port %s: %s",
107 port
->name
, STP_IN_get_error_explanation(rc
));
110 case DL_NOTE_LINK_UP
:
111 if (port
->phys_status
)
113 port
->phys_status
= B_TRUE
;
114 if (!port
->admin_status
|| protect
!= DLADM_BRIDGE_PROT_STP
||
116 port
->bpdu_protect
= B_FALSE
;
120 * If we're not running STP, and the link state has just come
121 * up, then clear out any protection shutdown state, and allow
122 * us to forward again.
124 if (port
->admin_non_stp
&& port
->bpdu_protect
) {
125 port
->bpdu_protect
= B_FALSE
;
126 enable_forwarding(port
);
128 if ((rc
= STP_IN_enable_port(port
->port_index
, True
)) != 0)
129 syslog(LOG_ERR
, "STP can't enable port %s: %s",
130 port
->name
, STP_IN_get_error_explanation(rc
));
136 port_dlpi_open(const char *portname
, struct portdata
*port
,
137 datalink_class_t
class)
139 uchar_t addrbuf
[DLPI_PHYSADDR_MAX
];
140 size_t alen
= DLPI_PHYSADDR_MAX
;
142 char addrstr
[ETHERADDRL
* 3];
145 * We use DLPI 'raw' mode so that we get access to the received
146 * Ethernet 802 length field. libdlpi otherwise eats this value. Note
147 * that 'raw' mode support is required in order to use snoop, so it's
148 * expected to be common, even if it's not documented.
150 rc
= dlpi_open(portname
, &port
->dlpi
, DLPI_RAW
);
151 if (rc
!= DLPI_SUCCESS
) {
152 syslog(LOG_ERR
, "can't open %s: %s", portname
,
157 port
->phys_status
= B_TRUE
;
158 port
->sdu_failed
= B_FALSE
;
159 port
->bpdu_protect
= B_FALSE
;
162 * Now that the driver is open, we can get at least the initial value
163 * of the interface speed. We need to do this before establishing the
164 * notify callback, so that it can update us later.
166 get_dladm_speed(port
);
169 * Save off the libdlpi port name, as it's dynamically allocated, and
170 * the name we're passed is not.
172 port
->name
= dlpi_linkname(port
->dlpi
);
175 * We can't bind SAP 0 or enable multicast on an etherstub. It's ok,
176 * though, because there's no real hardware involved.
178 if (class != DATALINK_CLASS_ETHERSTUB
) {
179 if ((rc
= dlpi_bind(port
->dlpi
, 0, NULL
)) != DLPI_SUCCESS
) {
180 syslog(LOG_ERR
, "can't bind %s: %s", portname
,
184 if ((rc
= dlpi_enabmulti(port
->dlpi
, bridge_group_address
,
185 sizeof (bridge_group_address
))) != DLPI_SUCCESS
) {
186 syslog(LOG_ERR
, "can't enable multicast on %s: %s",
187 portname
, dlpi_strerror(rc
));
192 if ((rc
= dlpi_enabnotify(port
->dlpi
,
193 DL_NOTE_PHYS_ADDR
| DL_NOTE_LINK_DOWN
| DL_NOTE_LINK_UP
|
194 DL_NOTE_SPEED
, dlpi_notify
, port
, &port
->notifyid
)) !=
196 syslog(LOG_WARNING
, "no DLPI notification on %s: %s", portname
,
200 rc
= dlpi_get_physaddr(port
->dlpi
, DL_CURR_PHYS_ADDR
, addrbuf
, &alen
);
201 if (rc
!= DLPI_SUCCESS
) {
202 syslog(LOG_ERR
, "unable to get MAC address on %s: %s",
203 port
->name
, dlpi_strerror(rc
));
206 if (alen
!= ETHERADDRL
) {
207 syslog(LOG_ERR
, "bad MAC address length %d on %s",
211 (void) memcpy(port
->mac_addr
, addrbuf
, ETHERADDRL
);
213 if (class != DATALINK_CLASS_ETHERSTUB
) {
214 int fd
= dlpi_fd(port
->dlpi
);
217 if (strioctl(fd
, DLIOCLOWLINK
, &lowflag
, sizeof (lowflag
)) != 0)
218 syslog(LOG_WARNING
, "low-link notify failed on %s: %m",
220 if (ioctl(fd
, I_PUSH
, "pfmod") == 0) {
221 struct packetfilt pf
;
224 pf
.Pf_FilterLen
= sizeof (bpdu_filter
) /
225 sizeof (*bpdu_filter
);
226 (void) memcpy(pf
.Pf_Filter
, bpdu_filter
,
227 sizeof (bpdu_filter
));
228 if (strioctl(fd
, PFIOCSETF
, &pf
, sizeof (pf
)) == -1)
230 "pfil ioctl failed on %s: %m", portname
);
232 syslog(LOG_WARNING
, "pfil push failed on %s: %m",
238 (void) _link_ntoa(port
->mac_addr
, addrstr
, ETHERADDRL
,
240 syslog(LOG_DEBUG
, "got MAC address %s on %s", addrstr
,