1*4eaa4710SRishi Srivatsavai /*
2*4eaa4710SRishi Srivatsavai * CDDL HEADER START
3*4eaa4710SRishi Srivatsavai *
4*4eaa4710SRishi Srivatsavai * The contents of this file are subject to the terms of the
5*4eaa4710SRishi Srivatsavai * Common Development and Distribution License (the "License").
6*4eaa4710SRishi Srivatsavai * You may not use this file except in compliance with the License.
7*4eaa4710SRishi Srivatsavai *
8*4eaa4710SRishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4eaa4710SRishi Srivatsavai * or http://www.opensolaris.org/os/licensing.
10*4eaa4710SRishi Srivatsavai * See the License for the specific language governing permissions
11*4eaa4710SRishi Srivatsavai * and limitations under the License.
12*4eaa4710SRishi Srivatsavai *
13*4eaa4710SRishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each
14*4eaa4710SRishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4eaa4710SRishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the
16*4eaa4710SRishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying
17*4eaa4710SRishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner]
18*4eaa4710SRishi Srivatsavai *
19*4eaa4710SRishi Srivatsavai * CDDL HEADER END
20*4eaa4710SRishi Srivatsavai */
21*4eaa4710SRishi Srivatsavai
22*4eaa4710SRishi Srivatsavai /*
23*4eaa4710SRishi Srivatsavai * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24*4eaa4710SRishi Srivatsavai * Use is subject to license terms.
25*4eaa4710SRishi Srivatsavai */
26*4eaa4710SRishi Srivatsavai
27*4eaa4710SRishi Srivatsavai /*
28*4eaa4710SRishi Srivatsavai * bridged - bridging control daemon. This module provides DLPI-specific
29*4eaa4710SRishi Srivatsavai * functions for interface to libdlpi.
30*4eaa4710SRishi Srivatsavai */
31*4eaa4710SRishi Srivatsavai
32*4eaa4710SRishi Srivatsavai #include <stdio.h>
33*4eaa4710SRishi Srivatsavai #include <stdlib.h>
34*4eaa4710SRishi Srivatsavai #include <unistd.h>
35*4eaa4710SRishi Srivatsavai #include <string.h>
36*4eaa4710SRishi Srivatsavai #include <sys/types.h>
37*4eaa4710SRishi Srivatsavai #include <syslog.h>
38*4eaa4710SRishi Srivatsavai #include <stropts.h>
39*4eaa4710SRishi Srivatsavai #include <stp_in.h>
40*4eaa4710SRishi Srivatsavai #include <net/if_types.h>
41*4eaa4710SRishi Srivatsavai #include <net/if_dl.h>
42*4eaa4710SRishi Srivatsavai #include <sys/ethernet.h>
43*4eaa4710SRishi Srivatsavai #include <sys/pfmod.h>
44*4eaa4710SRishi Srivatsavai
45*4eaa4710SRishi Srivatsavai #include "global.h"
46*4eaa4710SRishi Srivatsavai
47*4eaa4710SRishi Srivatsavai static const uchar_t bridge_group_address[] = BRIDGE_GROUP_ADDRESS;
48*4eaa4710SRishi Srivatsavai
49*4eaa4710SRishi Srivatsavai static const ushort_t bpdu_filter[] = {
50*4eaa4710SRishi Srivatsavai ENF_PUSHWORD | 0, /* check for 1:80:c2:0:0:0 dest. */
51*4eaa4710SRishi Srivatsavai ENF_PUSHLIT | ENF_CAND,
52*4eaa4710SRishi Srivatsavai #ifdef _BIG_ENDIAN
53*4eaa4710SRishi Srivatsavai 0x0180,
54*4eaa4710SRishi Srivatsavai #else
55*4eaa4710SRishi Srivatsavai 0x8001,
56*4eaa4710SRishi Srivatsavai #endif
57*4eaa4710SRishi Srivatsavai ENF_PUSHWORD | 1,
58*4eaa4710SRishi Srivatsavai ENF_PUSHLIT | ENF_CAND,
59*4eaa4710SRishi Srivatsavai #ifdef _BIG_ENDIAN
60*4eaa4710SRishi Srivatsavai 0xC200,
61*4eaa4710SRishi Srivatsavai #else
62*4eaa4710SRishi Srivatsavai 0x00C2,
63*4eaa4710SRishi Srivatsavai #endif
64*4eaa4710SRishi Srivatsavai ENF_PUSHWORD | 2,
65*4eaa4710SRishi Srivatsavai ENF_PUSHZERO | ENF_CAND,
66*4eaa4710SRishi Srivatsavai ENF_PUSHWORD | 7, /* check for SSAP/DSAP 42 42 */
67*4eaa4710SRishi Srivatsavai ENF_PUSHLIT | ENF_CAND,
68*4eaa4710SRishi Srivatsavai 0x4242,
69*4eaa4710SRishi Srivatsavai };
70*4eaa4710SRishi Srivatsavai
71*4eaa4710SRishi Srivatsavai /*
72*4eaa4710SRishi Srivatsavai * Because we're called by dlpi_recv(), we're called with the engine lock held.
73*4eaa4710SRishi Srivatsavai */
74*4eaa4710SRishi Srivatsavai /*ARGSUSED*/
75*4eaa4710SRishi Srivatsavai static void
dlpi_notify(dlpi_handle_t dlpi,dlpi_notifyinfo_t * info,void * arg)76*4eaa4710SRishi Srivatsavai dlpi_notify(dlpi_handle_t dlpi, dlpi_notifyinfo_t *info, void *arg)
77*4eaa4710SRishi Srivatsavai {
78*4eaa4710SRishi Srivatsavai struct portdata *port = arg;
79*4eaa4710SRishi Srivatsavai int rc;
80*4eaa4710SRishi Srivatsavai
81*4eaa4710SRishi Srivatsavai switch (info->dni_note) {
82*4eaa4710SRishi Srivatsavai case DL_NOTE_SPEED:
83*4eaa4710SRishi Srivatsavai /* libdlpi gives us Kbps, and we want Mbps */
84*4eaa4710SRishi Srivatsavai if (port->speed == info->dni_speed / 1000)
85*4eaa4710SRishi Srivatsavai break;
86*4eaa4710SRishi Srivatsavai port->speed = info->dni_speed / 1000;
87*4eaa4710SRishi Srivatsavai if ((rc = STP_IN_changed_port_speed(port->port_index,
88*4eaa4710SRishi Srivatsavai port->speed)) != 0)
89*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "STP can't change port speed on %s: %s",
90*4eaa4710SRishi Srivatsavai port->name, STP_IN_get_error_explanation(rc));
91*4eaa4710SRishi Srivatsavai break;
92*4eaa4710SRishi Srivatsavai
93*4eaa4710SRishi Srivatsavai case DL_NOTE_PHYS_ADDR:
94*4eaa4710SRishi Srivatsavai if (memcmp(info->dni_physaddr, port->mac_addr, ETHERADDRL) != 0)
95*4eaa4710SRishi Srivatsavai rstp_change_mac(port, info->dni_physaddr);
96*4eaa4710SRishi Srivatsavai break;
97*4eaa4710SRishi Srivatsavai
98*4eaa4710SRishi Srivatsavai case DL_NOTE_LINK_DOWN:
99*4eaa4710SRishi Srivatsavai if (!port->phys_status)
100*4eaa4710SRishi Srivatsavai break;
101*4eaa4710SRishi Srivatsavai port->phys_status = B_FALSE;
102*4eaa4710SRishi Srivatsavai if (!port->admin_status || protect != DLADM_BRIDGE_PROT_STP ||
103*4eaa4710SRishi Srivatsavai port->sdu_failed)
104*4eaa4710SRishi Srivatsavai break;
105*4eaa4710SRishi Srivatsavai if ((rc = STP_IN_enable_port(port->port_index, False)) != 0)
106*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "STP can't disable port %s: %s",
107*4eaa4710SRishi Srivatsavai port->name, STP_IN_get_error_explanation(rc));
108*4eaa4710SRishi Srivatsavai break;
109*4eaa4710SRishi Srivatsavai
110*4eaa4710SRishi Srivatsavai case DL_NOTE_LINK_UP:
111*4eaa4710SRishi Srivatsavai if (port->phys_status)
112*4eaa4710SRishi Srivatsavai break;
113*4eaa4710SRishi Srivatsavai port->phys_status = B_TRUE;
114*4eaa4710SRishi Srivatsavai if (!port->admin_status || protect != DLADM_BRIDGE_PROT_STP ||
115*4eaa4710SRishi Srivatsavai port->sdu_failed) {
116*4eaa4710SRishi Srivatsavai port->bpdu_protect = B_FALSE;
117*4eaa4710SRishi Srivatsavai break;
118*4eaa4710SRishi Srivatsavai }
119*4eaa4710SRishi Srivatsavai /*
120*4eaa4710SRishi Srivatsavai * If we're not running STP, and the link state has just come
121*4eaa4710SRishi Srivatsavai * up, then clear out any protection shutdown state, and allow
122*4eaa4710SRishi Srivatsavai * us to forward again.
123*4eaa4710SRishi Srivatsavai */
124*4eaa4710SRishi Srivatsavai if (port->admin_non_stp && port->bpdu_protect) {
125*4eaa4710SRishi Srivatsavai port->bpdu_protect = B_FALSE;
126*4eaa4710SRishi Srivatsavai enable_forwarding(port);
127*4eaa4710SRishi Srivatsavai }
128*4eaa4710SRishi Srivatsavai if ((rc = STP_IN_enable_port(port->port_index, True)) != 0)
129*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "STP can't enable port %s: %s",
130*4eaa4710SRishi Srivatsavai port->name, STP_IN_get_error_explanation(rc));
131*4eaa4710SRishi Srivatsavai break;
132*4eaa4710SRishi Srivatsavai }
133*4eaa4710SRishi Srivatsavai }
134*4eaa4710SRishi Srivatsavai
135*4eaa4710SRishi Srivatsavai boolean_t
port_dlpi_open(const char * portname,struct portdata * port,datalink_class_t class)136*4eaa4710SRishi Srivatsavai port_dlpi_open(const char *portname, struct portdata *port,
137*4eaa4710SRishi Srivatsavai datalink_class_t class)
138*4eaa4710SRishi Srivatsavai {
139*4eaa4710SRishi Srivatsavai uchar_t addrbuf[DLPI_PHYSADDR_MAX];
140*4eaa4710SRishi Srivatsavai size_t alen = DLPI_PHYSADDR_MAX;
141*4eaa4710SRishi Srivatsavai int rc;
142*4eaa4710SRishi Srivatsavai char addrstr[ETHERADDRL * 3];
143*4eaa4710SRishi Srivatsavai
144*4eaa4710SRishi Srivatsavai /*
145*4eaa4710SRishi Srivatsavai * We use DLPI 'raw' mode so that we get access to the received
146*4eaa4710SRishi Srivatsavai * Ethernet 802 length field. libdlpi otherwise eats this value. Note
147*4eaa4710SRishi Srivatsavai * that 'raw' mode support is required in order to use snoop, so it's
148*4eaa4710SRishi Srivatsavai * expected to be common, even if it's not documented.
149*4eaa4710SRishi Srivatsavai */
150*4eaa4710SRishi Srivatsavai rc = dlpi_open(portname, &port->dlpi, DLPI_RAW);
151*4eaa4710SRishi Srivatsavai if (rc != DLPI_SUCCESS) {
152*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "can't open %s: %s", portname,
153*4eaa4710SRishi Srivatsavai dlpi_strerror(rc));
154*4eaa4710SRishi Srivatsavai return (B_FALSE);
155*4eaa4710SRishi Srivatsavai }
156*4eaa4710SRishi Srivatsavai
157*4eaa4710SRishi Srivatsavai port->phys_status = B_TRUE;
158*4eaa4710SRishi Srivatsavai port->sdu_failed = B_FALSE;
159*4eaa4710SRishi Srivatsavai port->bpdu_protect = B_FALSE;
160*4eaa4710SRishi Srivatsavai
161*4eaa4710SRishi Srivatsavai /*
162*4eaa4710SRishi Srivatsavai * Now that the driver is open, we can get at least the initial value
163*4eaa4710SRishi Srivatsavai * of the interface speed. We need to do this before establishing the
164*4eaa4710SRishi Srivatsavai * notify callback, so that it can update us later.
165*4eaa4710SRishi Srivatsavai */
166*4eaa4710SRishi Srivatsavai get_dladm_speed(port);
167*4eaa4710SRishi Srivatsavai
168*4eaa4710SRishi Srivatsavai /*
169*4eaa4710SRishi Srivatsavai * Save off the libdlpi port name, as it's dynamically allocated, and
170*4eaa4710SRishi Srivatsavai * the name we're passed is not.
171*4eaa4710SRishi Srivatsavai */
172*4eaa4710SRishi Srivatsavai port->name = dlpi_linkname(port->dlpi);
173*4eaa4710SRishi Srivatsavai
174*4eaa4710SRishi Srivatsavai /*
175*4eaa4710SRishi Srivatsavai * We can't bind SAP 0 or enable multicast on an etherstub. It's ok,
176*4eaa4710SRishi Srivatsavai * though, because there's no real hardware involved.
177*4eaa4710SRishi Srivatsavai */
178*4eaa4710SRishi Srivatsavai if (class != DATALINK_CLASS_ETHERSTUB) {
179*4eaa4710SRishi Srivatsavai if ((rc = dlpi_bind(port->dlpi, 0, NULL)) != DLPI_SUCCESS) {
180*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "can't bind %s: %s", portname,
181*4eaa4710SRishi Srivatsavai dlpi_strerror(rc));
182*4eaa4710SRishi Srivatsavai return (B_FALSE);
183*4eaa4710SRishi Srivatsavai }
184*4eaa4710SRishi Srivatsavai if ((rc = dlpi_enabmulti(port->dlpi, bridge_group_address,
185*4eaa4710SRishi Srivatsavai sizeof (bridge_group_address))) != DLPI_SUCCESS) {
186*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "can't enable multicast on %s: %s",
187*4eaa4710SRishi Srivatsavai portname, dlpi_strerror(rc));
188*4eaa4710SRishi Srivatsavai return (B_FALSE);
189*4eaa4710SRishi Srivatsavai }
190*4eaa4710SRishi Srivatsavai }
191*4eaa4710SRishi Srivatsavai
192*4eaa4710SRishi Srivatsavai if ((rc = dlpi_enabnotify(port->dlpi,
193*4eaa4710SRishi Srivatsavai DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_DOWN | DL_NOTE_LINK_UP |
194*4eaa4710SRishi Srivatsavai DL_NOTE_SPEED, dlpi_notify, port, &port->notifyid)) !=
195*4eaa4710SRishi Srivatsavai DLPI_SUCCESS) {
196*4eaa4710SRishi Srivatsavai syslog(LOG_WARNING, "no DLPI notification on %s: %s", portname,
197*4eaa4710SRishi Srivatsavai dlpi_strerror(rc));
198*4eaa4710SRishi Srivatsavai }
199*4eaa4710SRishi Srivatsavai
200*4eaa4710SRishi Srivatsavai rc = dlpi_get_physaddr(port->dlpi, DL_CURR_PHYS_ADDR, addrbuf, &alen);
201*4eaa4710SRishi Srivatsavai if (rc != DLPI_SUCCESS) {
202*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "unable to get MAC address on %s: %s",
203*4eaa4710SRishi Srivatsavai port->name, dlpi_strerror(rc));
204*4eaa4710SRishi Srivatsavai return (B_FALSE);
205*4eaa4710SRishi Srivatsavai }
206*4eaa4710SRishi Srivatsavai if (alen != ETHERADDRL) {
207*4eaa4710SRishi Srivatsavai syslog(LOG_ERR, "bad MAC address length %d on %s",
208*4eaa4710SRishi Srivatsavai alen, port->name);
209*4eaa4710SRishi Srivatsavai return (B_FALSE);
210*4eaa4710SRishi Srivatsavai }
211*4eaa4710SRishi Srivatsavai (void) memcpy(port->mac_addr, addrbuf, ETHERADDRL);
212*4eaa4710SRishi Srivatsavai
213*4eaa4710SRishi Srivatsavai if (class != DATALINK_CLASS_ETHERSTUB) {
214*4eaa4710SRishi Srivatsavai int fd = dlpi_fd(port->dlpi);
215*4eaa4710SRishi Srivatsavai int lowflag = 1;
216*4eaa4710SRishi Srivatsavai
217*4eaa4710SRishi Srivatsavai if (strioctl(fd, DLIOCLOWLINK, &lowflag, sizeof (lowflag)) != 0)
218*4eaa4710SRishi Srivatsavai syslog(LOG_WARNING, "low-link notify failed on %s: %m",
219*4eaa4710SRishi Srivatsavai portname);
220*4eaa4710SRishi Srivatsavai if (ioctl(fd, I_PUSH, "pfmod") == 0) {
221*4eaa4710SRishi Srivatsavai struct packetfilt pf;
222*4eaa4710SRishi Srivatsavai
223*4eaa4710SRishi Srivatsavai pf.Pf_Priority = 0;
224*4eaa4710SRishi Srivatsavai pf.Pf_FilterLen = sizeof (bpdu_filter) /
225*4eaa4710SRishi Srivatsavai sizeof (*bpdu_filter);
226*4eaa4710SRishi Srivatsavai (void) memcpy(pf.Pf_Filter, bpdu_filter,
227*4eaa4710SRishi Srivatsavai sizeof (bpdu_filter));
228*4eaa4710SRishi Srivatsavai if (strioctl(fd, PFIOCSETF, &pf, sizeof (pf)) == -1)
229*4eaa4710SRishi Srivatsavai syslog(LOG_WARNING,
230*4eaa4710SRishi Srivatsavai "pfil ioctl failed on %s: %m", portname);
231*4eaa4710SRishi Srivatsavai } else {
232*4eaa4710SRishi Srivatsavai syslog(LOG_WARNING, "pfil push failed on %s: %m",
233*4eaa4710SRishi Srivatsavai portname);
234*4eaa4710SRishi Srivatsavai }
235*4eaa4710SRishi Srivatsavai }
236*4eaa4710SRishi Srivatsavai
237*4eaa4710SRishi Srivatsavai if (debugging) {
238*4eaa4710SRishi Srivatsavai (void) _link_ntoa(port->mac_addr, addrstr, ETHERADDRL,
239*4eaa4710SRishi Srivatsavai IFT_OTHER);
240*4eaa4710SRishi Srivatsavai syslog(LOG_DEBUG, "got MAC address %s on %s", addrstr,
241*4eaa4710SRishi Srivatsavai port->name);
242*4eaa4710SRishi Srivatsavai }
243*4eaa4710SRishi Srivatsavai
244*4eaa4710SRishi Srivatsavai return (B_TRUE);
245*4eaa4710SRishi Srivatsavai }
246