Merge commit 'a058d1cc571af5fbcfe7f1d719df1abbfdb722f3' into merges
[unleashed.git] / usr / src / cmd / ldmad / ldma_device.c
blobda16405e3a24df3ba37e5e355489d22414a44b26
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Logical Domains Device Agent
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <libdladm.h>
34 #include <libdllink.h>
35 #include <libds.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <unistd.h>
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
44 #include "ldma.h"
46 #define LDMA_MODULE LDMA_NAME_DEVICE
48 #define LDMA_NVERSIONS (sizeof (ldma_versions) / sizeof (ds_ver_t))
49 #define LDMA_NHANDLERS (sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t))
51 static ldm_msg_func_t ldma_dev_validate_path;
52 static ldm_msg_func_t ldma_dev_validate_nic;
54 static ds_ver_t ldma_versions[] = { { 1, 0 } };
56 static ldma_msg_handler_t ldma_handlers[] = {
57 { LDMA_MSGDEV_VALIDATE_PATH, LDMA_MSGFLG_ACCESS_CONTROL,
58 ldma_dev_validate_path },
59 { LDMA_MSGDEV_VALIDATE_NIC, LDMA_MSGFLG_ACCESS_CONTROL,
60 ldma_dev_validate_nic }
63 ldma_agent_info_t ldma_device_info = {
64 LDMA_NAME_DEVICE,
65 ldma_versions, LDMA_NVERSIONS,
66 ldma_handlers, LDMA_NHANDLERS
69 /*ARGSUSED*/
70 static ldma_request_status_t
71 ldma_dev_validate_path(ds_ver_t *ver, ldma_message_header_t *request,
72 size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
74 ldma_message_header_t *reply = NULL;
75 ldma_request_status_t status;
76 struct stat st;
77 char *path = NULL;
78 uint32_t *path_type, reply_dlen;
79 uint32_t plen;
80 int fd;
82 plen = request->msg_info;
83 if (plen == 0 || plen > MAXPATHLEN || plen > request_dlen) {
84 status = LDMA_REQ_INVALID;
85 goto done;
88 path = malloc(plen + 1);
89 if (path == NULL) {
90 status = LDMA_REQ_FAILED;
91 goto done;
94 (void) strncpy(path, LDMA_HDR2DATA(request), plen);
95 path[plen] = '\0';
97 LDMA_DBG("VALIDATE_PATH(%s)", path);
99 reply_dlen = sizeof (uint32_t);
100 reply = ldma_alloc_result_msg(request, reply_dlen);
101 if (reply == NULL) {
102 status = LDMA_REQ_FAILED;
103 goto done;
106 /* LINTED E_BAD_PTR_CAST_ALIGN */
107 path_type = (uint32_t *)(LDMA_HDR2DATA(reply));
109 reply->msg_info = 0x0;
111 /* check if path exists */
112 if (stat(path, &st) != 0) {
114 LDMA_DBG("VALIDATE_PATH(%s): stat failed with error %d",
115 path, errno);
117 switch (errno) {
119 case EACCES:
120 case ELOOP:
121 case ENOENT:
122 case ENOLINK:
123 case ENOTDIR:
124 /* path is inaccessible, the request is completed */
125 status = LDMA_REQ_COMPLETED;
126 break;
128 case ENAMETOOLONG:
129 status = LDMA_REQ_INVALID;
130 break;
132 default:
133 /* request has failed */
134 status = LDMA_REQ_FAILED;
135 break;
138 goto done;
141 status = LDMA_REQ_COMPLETED;
143 reply->msg_info |= LDMA_DEVPATH_EXIST;
145 LDMA_DBG("VALIDATE_PATH(%s): file mode = 0x%lx", path, st.st_mode);
147 switch (st.st_mode & S_IFMT) {
149 case S_IFREG:
150 *path_type = LDMA_DEVPATH_TYPE_FILE;
151 break;
153 case S_IFCHR:
154 case S_IFBLK:
155 *path_type = LDMA_DEVPATH_TYPE_DEVICE;
156 break;
158 default:
159 /* we don't advertise other types (fifo, directory...) */
160 *path_type = 0;
163 /* check if path can be opened read/write */
164 if ((fd = open(path, O_RDWR)) != -1) {
165 reply->msg_info |= LDMA_DEVPATH_OPENRW | LDMA_DEVPATH_OPENRO;
166 (void) close(fd);
167 } else {
168 LDMA_DBG("VALIDATE_PATH(%s): open RDWR failed with error %d",
169 path, errno);
171 /* check if path can be opened read only */
172 if ((fd = open(path, O_RDONLY)) != -1) {
173 reply->msg_info |= LDMA_DEVPATH_OPENRO;
174 (void) close(fd);
175 } else {
176 LDMA_DBG("VALIDATE_PATH(%s): open RDONLY failed "
177 "with error %d", path, errno);
181 done:
182 if (status != LDMA_REQ_COMPLETED) {
184 * We don't provide a reply message if the request has not
185 * been completed. The LDoms agent daemon will send an
186 * appropriate reply based on the return code of this function.
188 free(reply);
189 reply = NULL;
190 reply_dlen = 0;
192 LDMA_DBG("VALIDATE_PATH(%s): return error %d",
193 (path)? path : "<none>", status);
194 } else {
195 LDMA_DBG("VALIDATE_PATH(%s): return status=0x%x type=0x%x",
196 path, reply->msg_info, *path_type);
199 free(path);
200 *replyp = reply;
201 *reply_dlenp = reply_dlen;
203 return (status);
207 * We check that the device is a network interface (NIC) using libdladm.
209 /*ARGSUSED*/
210 static ldma_request_status_t
211 ldma_dev_validate_nic(ds_ver_t *ver, ldma_message_header_t *request,
212 size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
214 dladm_handle_t dlhandle;
215 datalink_id_t linkid;
216 uint32_t flag, media;
217 datalink_class_t class;
218 ldma_message_header_t *reply = NULL;
219 ldma_request_status_t status;
220 char *nic = NULL;
221 uint32_t nlen, reply_dlen;
223 nlen = request->msg_info;
224 if (nlen == 0 || nlen > MAXPATHLEN || nlen > request_dlen) {
225 status = LDMA_REQ_INVALID;
226 goto done;
229 nic = malloc(nlen + 1);
230 if (nic == NULL) {
231 status = LDMA_REQ_FAILED;
232 goto done;
235 (void) strncpy(nic, LDMA_HDR2DATA(request), nlen);
236 nic[nlen] = '\0';
238 LDMA_DBG("VALIDATE_NIC(%s)", nic);
240 reply_dlen = 0;
241 reply = ldma_alloc_result_msg(request, reply_dlen);
242 if (reply == NULL) {
243 status = LDMA_REQ_FAILED;
244 goto done;
247 reply->msg_info = 0x0;
249 if (dladm_open(&dlhandle) != DLADM_STATUS_OK) {
250 status = LDMA_REQ_FAILED;
251 goto done;
254 if (dladm_name2info(dlhandle, nic, &linkid, &flag, &class,
255 &media) != DLADM_STATUS_OK) {
256 LDMA_DBG("VALIDATE_NIC(%s): name2info failed", nic);
257 } else {
258 LDMA_DBG("VALIDATE_NIC(%s): media=0x%x", nic, media);
259 reply->msg_info = LDMA_DEVNIC_EXIST;
262 dladm_close(dlhandle);
264 status = LDMA_REQ_COMPLETED;
266 done:
267 if (status != LDMA_REQ_COMPLETED) {
269 * We don't provide a reply message if the request has not
270 * been completed. The LDoms agent daemon will send an
271 * appropriate reply based on the return code of this function.
273 free(reply);
274 reply = NULL;
275 reply_dlen = 0;
277 LDMA_DBG("VALIDATE_NIC(%s): return error %d",
278 (nic)? nic : "<none>", status);
279 } else {
280 LDMA_DBG("VALIDATE_NIC(%s): return status=0x%x",
281 nic, reply->msg_info);
284 free(nic);
285 *replyp = reply;
286 *reply_dlenp = reply_dlen;
288 return (status);