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 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 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