14eaa471Rishi Srivatsavai/*
24eaa471Rishi Srivatsavai * CDDL HEADER START
34eaa471Rishi Srivatsavai *
44eaa471Rishi Srivatsavai * The contents of this file are subject to the terms of the
54eaa471Rishi Srivatsavai * Common Development and Distribution License (the "License").
64eaa471Rishi Srivatsavai * You may not use this file except in compliance with the License.
74eaa471Rishi Srivatsavai *
84eaa471Rishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94eaa471Rishi Srivatsavai * or http://www.opensolaris.org/os/licensing.
104eaa471Rishi Srivatsavai * See the License for the specific language governing permissions
114eaa471Rishi Srivatsavai * and limitations under the License.
124eaa471Rishi Srivatsavai *
134eaa471Rishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each
144eaa471Rishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154eaa471Rishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the
164eaa471Rishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying
174eaa471Rishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner]
184eaa471Rishi Srivatsavai *
194eaa471Rishi Srivatsavai * CDDL HEADER END
204eaa471Rishi Srivatsavai */
214eaa471Rishi Srivatsavai
224eaa471Rishi Srivatsavai/*
234eaa471Rishi Srivatsavai * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
244eaa471Rishi Srivatsavai * Use is subject to license terms.
254eaa471Rishi Srivatsavai */
264eaa471Rishi Srivatsavai
274eaa471Rishi Srivatsavai/*
284eaa471Rishi Srivatsavai * bridged - bridging control daemon.  This module provides the door-based
294eaa471Rishi Srivatsavai * interface used by user applications to gather bridge status information.
304eaa471Rishi Srivatsavai */
314eaa471Rishi Srivatsavai
324eaa471Rishi Srivatsavai#include <stdio.h>
334eaa471Rishi Srivatsavai#include <stdlib.h>
344eaa471Rishi Srivatsavai#include <unistd.h>
354eaa471Rishi Srivatsavai#include <fcntl.h>
364eaa471Rishi Srivatsavai#include <sys/stat.h>
374eaa471Rishi Srivatsavai#include <sys/types.h>
384eaa471Rishi Srivatsavai#include <syslog.h>
394eaa471Rishi Srivatsavai#include <door.h>
404eaa471Rishi Srivatsavai#include <errno.h>
414eaa471Rishi Srivatsavai#include <alloca.h>
424eaa471Rishi Srivatsavai#include <libdlpi.h>
434eaa471Rishi Srivatsavai#include <libdlbridge.h>
444eaa471Rishi Srivatsavai#include <stp_in.h>
454eaa471Rishi Srivatsavai#include <net/bridge.h>
464eaa471Rishi Srivatsavai
474eaa471Rishi Srivatsavai#include "global.h"
484eaa471Rishi Srivatsavai
494eaa471Rishi Srivatsavai#define	DOOR_DIRMODE	0755
504eaa471Rishi Srivatsavai#define	DOOR_FILEMODE	0444
514eaa471Rishi Srivatsavai
524eaa471Rishi Srivatsavaistatic int door_fd = -1;
534eaa471Rishi Srivatsavaistatic char doorname[MAXPATHLEN];
544eaa471Rishi Srivatsavai
554eaa471Rishi Srivatsavai/*ARGSUSED*/
564eaa471Rishi Srivatsavaistatic void
574eaa471Rishi Srivatsavaibridge_door_server(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
584eaa471Rishi Srivatsavai    uint_t ndesc)
594eaa471Rishi Srivatsavai{
604eaa471Rishi Srivatsavai	/* LINTED: alignment */
614eaa471Rishi Srivatsavai	bridge_door_cmd_t *bdc = (bridge_door_cmd_t *)argp;
624eaa471Rishi Srivatsavai	int retv = EINVAL;
634eaa471Rishi Srivatsavai	bridge_door_cfg_t bdcf;
644eaa471Rishi Srivatsavai	UID_STP_STATE_T smstate;
654eaa471Rishi Srivatsavai	UID_STP_PORT_CFG_T portcfg;
664eaa471Rishi Srivatsavai	UID_STP_PORT_STATE_T portstate;
674eaa471Rishi Srivatsavai	struct portdata *pdp;
684eaa471Rishi Srivatsavai	int twoints[2];
694eaa471Rishi Srivatsavai
704eaa471Rishi Srivatsavai	if (arg_size < sizeof (*bdc) || lock_engine() != 0) {
714eaa471Rishi Srivatsavai		(void) door_return((char *)&retv, sizeof (retv), NULL, 0);
724eaa471Rishi Srivatsavai		return;
734eaa471Rishi Srivatsavai	}
744eaa471Rishi Srivatsavai
754eaa471Rishi Srivatsavai	switch (bdc->bdc_type) {
764eaa471Rishi Srivatsavai	case bdcBridgeGetConfig:
774eaa471Rishi Srivatsavai		if ((retv = STP_IN_stpm_get_cfg(0, &bdcf.bdcf_cfg)) != 0)
784eaa471Rishi Srivatsavai			break;
794eaa471Rishi Srivatsavai		bdcf.bdcf_prot = protect;
804eaa471Rishi Srivatsavai		unlock_engine();
814eaa471Rishi Srivatsavai		(void) door_return((char *)&bdcf, sizeof (bdcf), NULL, 0);
824eaa471Rishi Srivatsavai		return;
834eaa471Rishi Srivatsavai
844eaa471Rishi Srivatsavai	case bdcBridgeGetState:
854eaa471Rishi Srivatsavai		if ((retv = STP_IN_stpm_get_state(0, &smstate)) != 0)
864eaa471Rishi Srivatsavai			break;
874eaa471Rishi Srivatsavai		unlock_engine();
884eaa471Rishi Srivatsavai		(void) door_return((char *)&smstate, sizeof (smstate), NULL, 0);
894eaa471Rishi Srivatsavai		return;
904eaa471Rishi Srivatsavai
914eaa471Rishi Srivatsavai	case bdcBridgeGetPorts: {
924eaa471Rishi Srivatsavai		datalink_id_t *dlp;
934eaa471Rishi Srivatsavai		int *rbuf;
944eaa471Rishi Srivatsavai		size_t rlen;
954eaa471Rishi Srivatsavai		int i, nports;
964eaa471Rishi Srivatsavai
974eaa471Rishi Srivatsavai		if (nextport == 0) {
984eaa471Rishi Srivatsavai			twoints[0] = 0;
994eaa471Rishi Srivatsavai			rbuf = twoints;
1004eaa471Rishi Srivatsavai			rlen = sizeof (twoints);
1014eaa471Rishi Srivatsavai		} else {
1024eaa471Rishi Srivatsavai			rlen = sizeof (int) + nextport * sizeof (datalink_id_t);
1034eaa471Rishi Srivatsavai			rbuf = alloca(rlen);
1044eaa471Rishi Srivatsavai			dlp = (datalink_id_t *)(rbuf + 1);
1054eaa471Rishi Srivatsavai			for (i = nports = 0; i < nextport; i++) {
1064eaa471Rishi Srivatsavai				if (allports[i]->kern_added)
1074eaa471Rishi Srivatsavai					dlp[nports++] = allports[i]->linkid;
1084eaa471Rishi Srivatsavai			}
1094eaa471Rishi Srivatsavai			rbuf[0] = nports;
1104eaa471Rishi Srivatsavai			rlen = sizeof (int) + nports * sizeof (datalink_id_t);
1114eaa471Rishi Srivatsavai		}
1124eaa471Rishi Srivatsavai		unlock_engine();
1134eaa471Rishi Srivatsavai		(void) door_return((char *)rbuf, rlen, NULL, 0);
1144eaa471Rishi Srivatsavai		return;
1154eaa471Rishi Srivatsavai	}
1164eaa471Rishi Srivatsavai
1174eaa471Rishi Srivatsavai	case bdcBridgeGetRefreshCount:
1184eaa471Rishi Srivatsavai		twoints[0] = refresh_count;
1194eaa471Rishi Srivatsavai		twoints[1] = 0;
1204eaa471Rishi Srivatsavai		unlock_engine();
1214eaa471Rishi Srivatsavai		(void) door_return((char *)twoints, sizeof (twoints), NULL, 0);
1224eaa471Rishi Srivatsavai		return;
1234eaa471Rishi Srivatsavai
1244eaa471Rishi Srivatsavai	case bdcPortGetConfig:
1254eaa471Rishi Srivatsavai		if ((pdp = find_by_linkid(bdc->bdc_linkid)) == NULL)
1264eaa471Rishi Srivatsavai			break;
1274eaa471Rishi Srivatsavai		retv = STP_IN_port_get_cfg(0, pdp->port_index, &portcfg);
1284eaa471Rishi Srivatsavai		if (retv != 0)
1294eaa471Rishi Srivatsavai			break;
1304eaa471Rishi Srivatsavai		unlock_engine();
1314eaa471Rishi Srivatsavai		(void) door_return((char *)&portcfg, sizeof (portcfg), NULL, 0);
1324eaa471Rishi Srivatsavai		return;
1334eaa471Rishi Srivatsavai
1344eaa471Rishi Srivatsavai	case bdcPortGetState:
1354eaa471Rishi Srivatsavai		if ((pdp = find_by_linkid(bdc->bdc_linkid)) == NULL)
1364eaa471Rishi Srivatsavai			break;
1374eaa471Rishi Srivatsavai		portstate.port_no = pdp->port_index;
1384eaa471Rishi Srivatsavai		if ((retv = STP_IN_port_get_state(0, &portstate)) != 0)
1394eaa471Rishi Srivatsavai			break;
1404eaa471Rishi Srivatsavai		if (pdp->sdu_failed)
1414eaa471Rishi Srivatsavai			portstate.state = UID_PORT_BADSDU;
1424eaa471Rishi Srivatsavai		else if (protect != DLADM_BRIDGE_PROT_STP)
1434eaa471Rishi Srivatsavai			portstate.state = UID_PORT_NON_STP;
1444eaa471Rishi Srivatsavai		else if (pdp->admin_non_stp && pdp->bpdu_protect)
1454eaa471Rishi Srivatsavai			portstate.state = UID_PORT_DISABLED;
1464eaa471Rishi Srivatsavai		unlock_engine();
1474eaa471Rishi Srivatsavai		(void) door_return((char *)&portstate, sizeof (portstate),
1484eaa471Rishi Srivatsavai		    NULL, 0);
1494eaa471Rishi Srivatsavai		return;
1504eaa471Rishi Srivatsavai
1514eaa471Rishi Srivatsavai	case bdcPortGetForwarding:
1524eaa471Rishi Srivatsavai		if ((pdp = find_by_linkid(bdc->bdc_linkid)) == NULL)
1534eaa471Rishi Srivatsavai			break;
1544eaa471Rishi Srivatsavai		twoints[0] = pdp->admin_status ? 1 : 0;
1554eaa471Rishi Srivatsavai		twoints[1] = 0;
1564eaa471Rishi Srivatsavai		unlock_engine();
1574eaa471Rishi Srivatsavai		(void) door_return((char *)twoints, sizeof (twoints), NULL, 0);
1584eaa471Rishi Srivatsavai		return;
1594eaa471Rishi Srivatsavai	}
1604eaa471Rishi Srivatsavai	unlock_engine();
1614eaa471Rishi Srivatsavai	(void) door_return((char *)&retv, sizeof (retv), NULL, 0);
1624eaa471Rishi Srivatsavai}
1634eaa471Rishi Srivatsavai
1644eaa471Rishi Srivatsavaistatic void
1654eaa471Rishi Srivatsavaicleanup_door(void)
1664eaa471Rishi Srivatsavai{
1674eaa471Rishi Srivatsavai	if (door_fd != -1) {
1684eaa471Rishi Srivatsavai		(void) door_revoke(door_fd);
1694eaa471Rishi Srivatsavai		door_fd = -1;
1704eaa471Rishi Srivatsavai	}
1714eaa471Rishi Srivatsavai	if (doorname[0] != '\0') {
1724eaa471Rishi Srivatsavai		(void) unlink(doorname);
1734eaa471Rishi Srivatsavai		doorname[0] = '\0';
1744eaa471Rishi Srivatsavai	}
1754eaa471Rishi Srivatsavai}
1764eaa471Rishi Srivatsavai
1774eaa471Rishi Srivatsavaivoid
1784eaa471Rishi Srivatsavaiinit_door(void)
1794eaa471Rishi Srivatsavai{
1804eaa471Rishi Srivatsavai	int fd;
1814eaa471Rishi Srivatsavai
1824eaa471Rishi Srivatsavai	/* Make sure that the control directory exists */
1834eaa471Rishi Srivatsavai	(void) mkdir(DOOR_DIRNAME, DOOR_DIRMODE);
1844eaa471Rishi Srivatsavai
1854eaa471Rishi Srivatsavai	/* Each instance gets a separate door. */
1864eaa471Rishi Srivatsavai	(void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME,
1874eaa471Rishi Srivatsavai	    instance_name);
1884eaa471Rishi Srivatsavai
1894eaa471Rishi Srivatsavai	/* Do a low-overhead "touch" on the file that will be the door node. */
1904eaa471Rishi Srivatsavai	fd = open(doorname,
1914eaa471Rishi Srivatsavai	    O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_NONBLOCK,
1924eaa471Rishi Srivatsavai	    DOOR_FILEMODE);
1934eaa471Rishi Srivatsavai	if (fd != -1) {
1944eaa471Rishi Srivatsavai		(void) close(fd);
1954eaa471Rishi Srivatsavai	} else if (errno != EEXIST) {
1964eaa471Rishi Srivatsavai		syslog(LOG_ERR, "unable to create control door node: %m");
1974eaa471Rishi Srivatsavai		exit(EXIT_FAILURE);
1984eaa471Rishi Srivatsavai	}
1994eaa471Rishi Srivatsavai
2004eaa471Rishi Srivatsavai	(void) atexit(cleanup_door);
2014eaa471Rishi Srivatsavai
2024eaa471Rishi Srivatsavai	/* Create the door. */
2034eaa471Rishi Srivatsavai	door_fd = door_create(bridge_door_server, NULL,
2044eaa471Rishi Srivatsavai	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2054eaa471Rishi Srivatsavai	if (door_fd == -1) {
2064eaa471Rishi Srivatsavai		syslog(LOG_ERR, "unable to create control door: %m");
2074eaa471Rishi Srivatsavai		exit(EXIT_FAILURE);
2084eaa471Rishi Srivatsavai	}
2094eaa471Rishi Srivatsavai
2104eaa471Rishi Srivatsavai	/* Attach the door to the file. */
2114eaa471Rishi Srivatsavai	(void) fdetach(doorname);
2124eaa471Rishi Srivatsavai	if (fattach(door_fd, doorname) == -1) {
2134eaa471Rishi Srivatsavai		syslog(LOG_ERR, "unable to attach control door: %m");
2144eaa471Rishi Srivatsavai		exit(EXIT_FAILURE);
2154eaa471Rishi Srivatsavai	}
2164eaa471Rishi Srivatsavai}