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