1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * bridged - bridging control daemon.  This module provides the door-based
29  * interface used by user applications to gather bridge status information.
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <syslog.h>
39 #include <door.h>
40 #include <errno.h>
41 #include <alloca.h>
42 #include <libdlpi.h>
43 #include <libdlbridge.h>
44 #include <stp_in.h>
45 #include <net/bridge.h>
46 
47 #include "global.h"
48 
49 #define	DOOR_DIRMODE	0755
50 #define	DOOR_FILEMODE	0444
51 
52 static int door_fd = -1;
53 static char doorname[MAXPATHLEN];
54 
55 /*ARGSUSED*/
56 static void
bridge_door_server(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t ndesc)57 bridge_door_server(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
58     uint_t ndesc)
59 {
60 	/* LINTED: alignment */
61 	bridge_door_cmd_t *bdc = (bridge_door_cmd_t *)argp;
62 	int retv = EINVAL;
63 	bridge_door_cfg_t bdcf;
64 	UID_STP_STATE_T smstate;
65 	UID_STP_PORT_CFG_T portcfg;
66 	UID_STP_PORT_STATE_T portstate;
67 	struct portdata *pdp;
68 	int twoints[2];
69 
70 	if (arg_size < sizeof (*bdc) || lock_engine() != 0) {
71 		(void) door_return((char *)&retv, sizeof (retv), NULL, 0);
72 		return;
73 	}
74 
75 	switch (bdc->bdc_type) {
76 	case bdcBridgeGetConfig:
77 		if ((retv = STP_IN_stpm_get_cfg(0, &bdcf.bdcf_cfg)) != 0)
78 			break;
79 		bdcf.bdcf_prot = protect;
80 		unlock_engine();
81 		(void) door_return((char *)&bdcf, sizeof (bdcf), NULL, 0);
82 		return;
83 
84 	case bdcBridgeGetState:
85 		if ((retv = STP_IN_stpm_get_state(0, &smstate)) != 0)
86 			break;
87 		unlock_engine();
88 		(void) door_return((char *)&smstate, sizeof (smstate), NULL, 0);
89 		return;
90 
91 	case bdcBridgeGetPorts: {
92 		datalink_id_t *dlp;
93 		int *rbuf;
94 		size_t rlen;
95 		int i, nports;
96 
97 		if (nextport == 0) {
98 			twoints[0] = 0;
99 			rbuf = twoints;
100 			rlen = sizeof (twoints);
101 		} else {
102 			rlen = sizeof (int) + nextport * sizeof (datalink_id_t);
103 			rbuf = alloca(rlen);
104 			dlp = (datalink_id_t *)(rbuf + 1);
105 			for (i = nports = 0; i < nextport; i++) {
106 				if (allports[i]->kern_added)
107 					dlp[nports++] = allports[i]->linkid;
108 			}
109 			rbuf[0] = nports;
110 			rlen = sizeof (int) + nports * sizeof (datalink_id_t);
111 		}
112 		unlock_engine();
113 		(void) door_return((char *)rbuf, rlen, NULL, 0);
114 		return;
115 	}
116 
117 	case bdcBridgeGetRefreshCount:
118 		twoints[0] = refresh_count;
119 		twoints[1] = 0;
120 		unlock_engine();
121 		(void) door_return((char *)twoints, sizeof (twoints), NULL, 0);
122 		return;
123 
124 	case bdcPortGetConfig:
125 		if ((pdp = find_by_linkid(bdc->bdc_linkid)) == NULL)
126 			break;
127 		retv = STP_IN_port_get_cfg(0, pdp->port_index, &portcfg);
128 		if (retv != 0)
129 			break;
130 		unlock_engine();
131 		(void) door_return((char *)&portcfg, sizeof (portcfg), NULL, 0);
132 		return;
133 
134 	case bdcPortGetState:
135 		if ((pdp = find_by_linkid(bdc->bdc_linkid)) == NULL)
136 			break;
137 		portstate.port_no = pdp->port_index;
138 		if ((retv = STP_IN_port_get_state(0, &portstate)) != 0)
139 			break;
140 		if (pdp->sdu_failed)
141 			portstate.state = UID_PORT_BADSDU;
142 		else if (protect != DLADM_BRIDGE_PROT_STP)
143 			portstate.state = UID_PORT_NON_STP;
144 		else if (pdp->admin_non_stp && pdp->bpdu_protect)
145 			portstate.state = UID_PORT_DISABLED;
146 		unlock_engine();
147 		(void) door_return((char *)&portstate, sizeof (portstate),
148 		    NULL, 0);
149 		return;
150 
151 	case bdcPortGetForwarding:
152 		if ((pdp = find_by_linkid(bdc->bdc_linkid)) == NULL)
153 			break;
154 		twoints[0] = pdp->admin_status ? 1 : 0;
155 		twoints[1] = 0;
156 		unlock_engine();
157 		(void) door_return((char *)twoints, sizeof (twoints), NULL, 0);
158 		return;
159 	}
160 	unlock_engine();
161 	(void) door_return((char *)&retv, sizeof (retv), NULL, 0);
162 }
163 
164 static void
cleanup_door(void)165 cleanup_door(void)
166 {
167 	if (door_fd != -1) {
168 		(void) door_revoke(door_fd);
169 		door_fd = -1;
170 	}
171 	if (doorname[0] != '\0') {
172 		(void) unlink(doorname);
173 		doorname[0] = '\0';
174 	}
175 }
176 
177 void
init_door(void)178 init_door(void)
179 {
180 	int fd;
181 
182 	/* Make sure that the control directory exists */
183 	(void) mkdir(DOOR_DIRNAME, DOOR_DIRMODE);
184 
185 	/* Each instance gets a separate door. */
186 	(void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME,
187 	    instance_name);
188 
189 	/* Do a low-overhead "touch" on the file that will be the door node. */
190 	fd = open(doorname,
191 	    O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_NONBLOCK,
192 	    DOOR_FILEMODE);
193 	if (fd != -1) {
194 		(void) close(fd);
195 	} else if (errno != EEXIST) {
196 		syslog(LOG_ERR, "unable to create control door node: %m");
197 		exit(EXIT_FAILURE);
198 	}
199 
200 	(void) atexit(cleanup_door);
201 
202 	/* Create the door. */
203 	door_fd = door_create(bridge_door_server, NULL,
204 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
205 	if (door_fd == -1) {
206 		syslog(LOG_ERR, "unable to create control door: %m");
207 		exit(EXIT_FAILURE);
208 	}
209 
210 	/* Attach the door to the file. */
211 	(void) fdetach(doorname);
212 	if (fattach(door_fd, doorname) == -1) {
213 		syslog(LOG_ERR, "unable to attach control door: %m");
214 		exit(EXIT_FAILURE);
215 	}
216 }
217