149bfb42bSAlexandre Chartre /*
249bfb42bSAlexandre Chartre * CDDL HEADER START
349bfb42bSAlexandre Chartre *
449bfb42bSAlexandre Chartre * The contents of this file are subject to the terms of the
549bfb42bSAlexandre Chartre * Common Development and Distribution License (the "License").
649bfb42bSAlexandre Chartre * You may not use this file except in compliance with the License.
749bfb42bSAlexandre Chartre *
849bfb42bSAlexandre Chartre * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
949bfb42bSAlexandre Chartre * or http://www.opensolaris.org/os/licensing.
1049bfb42bSAlexandre Chartre * See the License for the specific language governing permissions
1149bfb42bSAlexandre Chartre * and limitations under the License.
1249bfb42bSAlexandre Chartre *
1349bfb42bSAlexandre Chartre * When distributing Covered Code, include this CDDL HEADER in each
1449bfb42bSAlexandre Chartre * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1549bfb42bSAlexandre Chartre * If applicable, add the following below this CDDL HEADER, with the
1649bfb42bSAlexandre Chartre * fields enclosed by brackets "[]" replaced with your own identifying
1749bfb42bSAlexandre Chartre * information: Portions Copyright [yyyy] [name of copyright owner]
1849bfb42bSAlexandre Chartre *
1949bfb42bSAlexandre Chartre * CDDL HEADER END
2049bfb42bSAlexandre Chartre */
2149bfb42bSAlexandre Chartre
2249bfb42bSAlexandre Chartre /*
23*82629e30SMike Christensen * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2449bfb42bSAlexandre Chartre * Use is subject to license terms.
2549bfb42bSAlexandre Chartre */
2649bfb42bSAlexandre Chartre
2749bfb42bSAlexandre Chartre /*
2849bfb42bSAlexandre Chartre * Logical Domains Device Agent
2949bfb42bSAlexandre Chartre */
3049bfb42bSAlexandre Chartre
3149bfb42bSAlexandre Chartre #include <errno.h>
3249bfb42bSAlexandre Chartre #include <fcntl.h>
3349bfb42bSAlexandre Chartre #include <libdladm.h>
3449bfb42bSAlexandre Chartre #include <libdllink.h>
3549bfb42bSAlexandre Chartre #include <libds.h>
3649bfb42bSAlexandre Chartre #include <stdio.h>
3749bfb42bSAlexandre Chartre #include <stdlib.h>
3849bfb42bSAlexandre Chartre #include <strings.h>
3949bfb42bSAlexandre Chartre #include <unistd.h>
4049bfb42bSAlexandre Chartre #include <sys/param.h>
4149bfb42bSAlexandre Chartre #include <sys/types.h>
4249bfb42bSAlexandre Chartre #include <sys/stat.h>
4349bfb42bSAlexandre Chartre
4449bfb42bSAlexandre Chartre #include "ldma.h"
4549bfb42bSAlexandre Chartre
4649bfb42bSAlexandre Chartre #define LDMA_MODULE LDMA_NAME_DEVICE
4749bfb42bSAlexandre Chartre
4849bfb42bSAlexandre Chartre #define LDMA_NVERSIONS (sizeof (ldma_versions) / sizeof (ds_ver_t))
4949bfb42bSAlexandre Chartre #define LDMA_NHANDLERS (sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t))
5049bfb42bSAlexandre Chartre
5149bfb42bSAlexandre Chartre static ldm_msg_func_t ldma_dev_validate_path;
5249bfb42bSAlexandre Chartre static ldm_msg_func_t ldma_dev_validate_nic;
5349bfb42bSAlexandre Chartre
5449bfb42bSAlexandre Chartre static ds_ver_t ldma_versions[] = { { 1, 0 } };
5549bfb42bSAlexandre Chartre
5649bfb42bSAlexandre Chartre static ldma_msg_handler_t ldma_handlers[] = {
57*82629e30SMike Christensen { LDMA_MSGDEV_VALIDATE_PATH, LDMA_MSGFLG_ACCESS_CONTROL,
58*82629e30SMike Christensen ldma_dev_validate_path },
59*82629e30SMike Christensen { LDMA_MSGDEV_VALIDATE_NIC, LDMA_MSGFLG_ACCESS_CONTROL,
60*82629e30SMike Christensen ldma_dev_validate_nic }
6149bfb42bSAlexandre Chartre };
6249bfb42bSAlexandre Chartre
6349bfb42bSAlexandre Chartre ldma_agent_info_t ldma_device_info = {
6449bfb42bSAlexandre Chartre LDMA_NAME_DEVICE,
6549bfb42bSAlexandre Chartre ldma_versions, LDMA_NVERSIONS,
6649bfb42bSAlexandre Chartre ldma_handlers, LDMA_NHANDLERS
6749bfb42bSAlexandre Chartre };
6849bfb42bSAlexandre Chartre
6949bfb42bSAlexandre Chartre /*ARGSUSED*/
7049bfb42bSAlexandre Chartre static ldma_request_status_t
ldma_dev_validate_path(ds_ver_t * ver,ldma_message_header_t * request,size_t request_dlen,ldma_message_header_t ** replyp,size_t * reply_dlenp)7149bfb42bSAlexandre Chartre ldma_dev_validate_path(ds_ver_t *ver, ldma_message_header_t *request,
7249bfb42bSAlexandre Chartre size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
7349bfb42bSAlexandre Chartre {
7449bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL;
7549bfb42bSAlexandre Chartre ldma_request_status_t status;
7649bfb42bSAlexandre Chartre struct stat st;
7749bfb42bSAlexandre Chartre char *path = NULL;
7849bfb42bSAlexandre Chartre uint32_t *path_type, reply_dlen;
7949bfb42bSAlexandre Chartre uint32_t plen;
8049bfb42bSAlexandre Chartre int fd;
8149bfb42bSAlexandre Chartre
8249bfb42bSAlexandre Chartre plen = request->msg_info;
8349bfb42bSAlexandre Chartre if (plen == 0 || plen > MAXPATHLEN || plen > request_dlen) {
8449bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID;
8549bfb42bSAlexandre Chartre goto done;
8649bfb42bSAlexandre Chartre }
8749bfb42bSAlexandre Chartre
8849bfb42bSAlexandre Chartre path = malloc(plen + 1);
8949bfb42bSAlexandre Chartre if (path == NULL) {
9049bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED;
9149bfb42bSAlexandre Chartre goto done;
9249bfb42bSAlexandre Chartre }
9349bfb42bSAlexandre Chartre
9449bfb42bSAlexandre Chartre (void) strncpy(path, LDMA_HDR2DATA(request), plen);
9549bfb42bSAlexandre Chartre path[plen] = '\0';
9649bfb42bSAlexandre Chartre
9749bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s)", path);
9849bfb42bSAlexandre Chartre
9949bfb42bSAlexandre Chartre reply_dlen = sizeof (uint32_t);
10049bfb42bSAlexandre Chartre reply = ldma_alloc_result_msg(request, reply_dlen);
10149bfb42bSAlexandre Chartre if (reply == NULL) {
10249bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED;
10349bfb42bSAlexandre Chartre goto done;
10449bfb42bSAlexandre Chartre }
10549bfb42bSAlexandre Chartre
10649bfb42bSAlexandre Chartre /* LINTED E_BAD_PTR_CAST_ALIGN */
10749bfb42bSAlexandre Chartre path_type = (uint32_t *)(LDMA_HDR2DATA(reply));
10849bfb42bSAlexandre Chartre
10949bfb42bSAlexandre Chartre reply->msg_info = 0x0;
11049bfb42bSAlexandre Chartre
11149bfb42bSAlexandre Chartre /* check if path exists */
11249bfb42bSAlexandre Chartre if (stat(path, &st) != 0) {
11349bfb42bSAlexandre Chartre
11449bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): stat failed with error %d",
11549bfb42bSAlexandre Chartre path, errno);
11649bfb42bSAlexandre Chartre
11749bfb42bSAlexandre Chartre switch (errno) {
11849bfb42bSAlexandre Chartre
11949bfb42bSAlexandre Chartre case EACCES:
12049bfb42bSAlexandre Chartre case ELOOP:
12149bfb42bSAlexandre Chartre case ENOENT:
12249bfb42bSAlexandre Chartre case ENOLINK:
12349bfb42bSAlexandre Chartre case ENOTDIR:
12449bfb42bSAlexandre Chartre /* path is inaccessible, the request is completed */
12549bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED;
12649bfb42bSAlexandre Chartre break;
12749bfb42bSAlexandre Chartre
12849bfb42bSAlexandre Chartre case ENAMETOOLONG:
12949bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID;
13049bfb42bSAlexandre Chartre break;
13149bfb42bSAlexandre Chartre
13249bfb42bSAlexandre Chartre default:
13349bfb42bSAlexandre Chartre /* request has failed */
13449bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED;
13549bfb42bSAlexandre Chartre break;
13649bfb42bSAlexandre Chartre }
13749bfb42bSAlexandre Chartre
13849bfb42bSAlexandre Chartre goto done;
13949bfb42bSAlexandre Chartre }
14049bfb42bSAlexandre Chartre
14149bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED;
14249bfb42bSAlexandre Chartre
14349bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_EXIST;
14449bfb42bSAlexandre Chartre
1456b8303caSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): file mode = 0x%lx", path, st.st_mode);
14649bfb42bSAlexandre Chartre
14749bfb42bSAlexandre Chartre switch (st.st_mode & S_IFMT) {
14849bfb42bSAlexandre Chartre
14949bfb42bSAlexandre Chartre case S_IFREG:
15049bfb42bSAlexandre Chartre *path_type = LDMA_DEVPATH_TYPE_FILE;
15149bfb42bSAlexandre Chartre break;
15249bfb42bSAlexandre Chartre
15349bfb42bSAlexandre Chartre case S_IFCHR:
15449bfb42bSAlexandre Chartre case S_IFBLK:
15549bfb42bSAlexandre Chartre *path_type = LDMA_DEVPATH_TYPE_DEVICE;
15649bfb42bSAlexandre Chartre break;
15749bfb42bSAlexandre Chartre
15849bfb42bSAlexandre Chartre default:
15949bfb42bSAlexandre Chartre /* we don't advertise other types (fifo, directory...) */
16049bfb42bSAlexandre Chartre *path_type = 0;
16149bfb42bSAlexandre Chartre }
16249bfb42bSAlexandre Chartre
16349bfb42bSAlexandre Chartre /* check if path can be opened read/write */
16449bfb42bSAlexandre Chartre if ((fd = open(path, O_RDWR)) != -1) {
16549bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_OPENRW | LDMA_DEVPATH_OPENRO;
16649bfb42bSAlexandre Chartre (void) close(fd);
16749bfb42bSAlexandre Chartre } else {
16849bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): open RDWR failed with error %d",
16949bfb42bSAlexandre Chartre path, errno);
17049bfb42bSAlexandre Chartre
17149bfb42bSAlexandre Chartre /* check if path can be opened read only */
17249bfb42bSAlexandre Chartre if ((fd = open(path, O_RDONLY)) != -1) {
17349bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_OPENRO;
17449bfb42bSAlexandre Chartre (void) close(fd);
17549bfb42bSAlexandre Chartre } else {
17649bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): open RDONLY failed "
17749bfb42bSAlexandre Chartre "with error %d", path, errno);
17849bfb42bSAlexandre Chartre }
17949bfb42bSAlexandre Chartre }
18049bfb42bSAlexandre Chartre
18149bfb42bSAlexandre Chartre done:
18249bfb42bSAlexandre Chartre if (status != LDMA_REQ_COMPLETED) {
18349bfb42bSAlexandre Chartre /*
18449bfb42bSAlexandre Chartre * We don't provide a reply message if the request has not
18549bfb42bSAlexandre Chartre * been completed. The LDoms agent daemon will send an
18649bfb42bSAlexandre Chartre * appropriate reply based on the return code of this function.
18749bfb42bSAlexandre Chartre */
18849bfb42bSAlexandre Chartre free(reply);
18949bfb42bSAlexandre Chartre reply = NULL;
19049bfb42bSAlexandre Chartre reply_dlen = 0;
19149bfb42bSAlexandre Chartre
19249bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): return error %d",
19349bfb42bSAlexandre Chartre (path)? path : "<none>", status);
19449bfb42bSAlexandre Chartre } else {
19549bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): return status=0x%x type=0x%x",
19649bfb42bSAlexandre Chartre path, reply->msg_info, *path_type);
19749bfb42bSAlexandre Chartre }
19849bfb42bSAlexandre Chartre
19949bfb42bSAlexandre Chartre free(path);
20049bfb42bSAlexandre Chartre *replyp = reply;
20149bfb42bSAlexandre Chartre *reply_dlenp = reply_dlen;
20249bfb42bSAlexandre Chartre
20349bfb42bSAlexandre Chartre return (status);
20449bfb42bSAlexandre Chartre }
20549bfb42bSAlexandre Chartre
20649bfb42bSAlexandre Chartre /*
20749bfb42bSAlexandre Chartre * We check that the device is a network interface (NIC) using libdladm.
20849bfb42bSAlexandre Chartre */
20949bfb42bSAlexandre Chartre /*ARGSUSED*/
21049bfb42bSAlexandre Chartre static ldma_request_status_t
ldma_dev_validate_nic(ds_ver_t * ver,ldma_message_header_t * request,size_t request_dlen,ldma_message_header_t ** replyp,size_t * reply_dlenp)21149bfb42bSAlexandre Chartre ldma_dev_validate_nic(ds_ver_t *ver, ldma_message_header_t *request,
21249bfb42bSAlexandre Chartre size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
21349bfb42bSAlexandre Chartre {
21449bfb42bSAlexandre Chartre dladm_handle_t dlhandle;
21549bfb42bSAlexandre Chartre datalink_id_t linkid;
21649bfb42bSAlexandre Chartre uint32_t flag, media;
21749bfb42bSAlexandre Chartre datalink_class_t class;
21849bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL;
21949bfb42bSAlexandre Chartre ldma_request_status_t status;
22049bfb42bSAlexandre Chartre char *nic = NULL;
22149bfb42bSAlexandre Chartre uint32_t nlen, reply_dlen;
22249bfb42bSAlexandre Chartre
22349bfb42bSAlexandre Chartre nlen = request->msg_info;
22449bfb42bSAlexandre Chartre if (nlen == 0 || nlen > MAXPATHLEN || nlen > request_dlen) {
22549bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID;
22649bfb42bSAlexandre Chartre goto done;
22749bfb42bSAlexandre Chartre }
22849bfb42bSAlexandre Chartre
22949bfb42bSAlexandre Chartre nic = malloc(nlen + 1);
23049bfb42bSAlexandre Chartre if (nic == NULL) {
23149bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED;
23249bfb42bSAlexandre Chartre goto done;
23349bfb42bSAlexandre Chartre }
23449bfb42bSAlexandre Chartre
23549bfb42bSAlexandre Chartre (void) strncpy(nic, LDMA_HDR2DATA(request), nlen);
23649bfb42bSAlexandre Chartre nic[nlen] = '\0';
23749bfb42bSAlexandre Chartre
23849bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s)", nic);
23949bfb42bSAlexandre Chartre
24049bfb42bSAlexandre Chartre reply_dlen = 0;
24149bfb42bSAlexandre Chartre reply = ldma_alloc_result_msg(request, reply_dlen);
24249bfb42bSAlexandre Chartre if (reply == NULL) {
24349bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED;
24449bfb42bSAlexandre Chartre goto done;
24549bfb42bSAlexandre Chartre }
24649bfb42bSAlexandre Chartre
24749bfb42bSAlexandre Chartre reply->msg_info = 0x0;
24849bfb42bSAlexandre Chartre
24949bfb42bSAlexandre Chartre if (dladm_open(&dlhandle) != DLADM_STATUS_OK) {
25049bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED;
25149bfb42bSAlexandre Chartre goto done;
25249bfb42bSAlexandre Chartre }
25349bfb42bSAlexandre Chartre
25449bfb42bSAlexandre Chartre if (dladm_name2info(dlhandle, nic, &linkid, &flag, &class,
25549bfb42bSAlexandre Chartre &media) != DLADM_STATUS_OK) {
25649bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): name2info failed", nic);
25749bfb42bSAlexandre Chartre } else {
25849bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): media=0x%x", nic, media);
25949bfb42bSAlexandre Chartre reply->msg_info = LDMA_DEVNIC_EXIST;
26049bfb42bSAlexandre Chartre }
26149bfb42bSAlexandre Chartre
26249bfb42bSAlexandre Chartre dladm_close(dlhandle);
26349bfb42bSAlexandre Chartre
26449bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED;
26549bfb42bSAlexandre Chartre
26649bfb42bSAlexandre Chartre done:
26749bfb42bSAlexandre Chartre if (status != LDMA_REQ_COMPLETED) {
26849bfb42bSAlexandre Chartre /*
26949bfb42bSAlexandre Chartre * We don't provide a reply message if the request has not
27049bfb42bSAlexandre Chartre * been completed. The LDoms agent daemon will send an
27149bfb42bSAlexandre Chartre * appropriate reply based on the return code of this function.
27249bfb42bSAlexandre Chartre */
27349bfb42bSAlexandre Chartre free(reply);
27449bfb42bSAlexandre Chartre reply = NULL;
27549bfb42bSAlexandre Chartre reply_dlen = 0;
27649bfb42bSAlexandre Chartre
27749bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): return error %d",
27849bfb42bSAlexandre Chartre (nic)? nic : "<none>", status);
27949bfb42bSAlexandre Chartre } else {
28049bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): return status=0x%x",
28149bfb42bSAlexandre Chartre nic, reply->msg_info);
28249bfb42bSAlexandre Chartre }
28349bfb42bSAlexandre Chartre
28449bfb42bSAlexandre Chartre free(nic);
28549bfb42bSAlexandre Chartre *replyp = reply;
28649bfb42bSAlexandre Chartre *reply_dlenp = reply_dlen;
28749bfb42bSAlexandre Chartre
28849bfb42bSAlexandre Chartre return (status);
28949bfb42bSAlexandre Chartre }
290