110480SAlexandre.Chartre@Sun.COM /*
210480SAlexandre.Chartre@Sun.COM * CDDL HEADER START
310480SAlexandre.Chartre@Sun.COM *
410480SAlexandre.Chartre@Sun.COM * The contents of this file are subject to the terms of the
510480SAlexandre.Chartre@Sun.COM * Common Development and Distribution License (the "License").
610480SAlexandre.Chartre@Sun.COM * You may not use this file except in compliance with the License.
710480SAlexandre.Chartre@Sun.COM *
810480SAlexandre.Chartre@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910480SAlexandre.Chartre@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010480SAlexandre.Chartre@Sun.COM * See the License for the specific language governing permissions
1110480SAlexandre.Chartre@Sun.COM * and limitations under the License.
1210480SAlexandre.Chartre@Sun.COM *
1310480SAlexandre.Chartre@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410480SAlexandre.Chartre@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510480SAlexandre.Chartre@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610480SAlexandre.Chartre@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710480SAlexandre.Chartre@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810480SAlexandre.Chartre@Sun.COM *
1910480SAlexandre.Chartre@Sun.COM * CDDL HEADER END
2010480SAlexandre.Chartre@Sun.COM */
2110480SAlexandre.Chartre@Sun.COM
2210480SAlexandre.Chartre@Sun.COM /*
23*11833SMichael.Christensen@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2410480SAlexandre.Chartre@Sun.COM * Use is subject to license terms.
2510480SAlexandre.Chartre@Sun.COM */
2610480SAlexandre.Chartre@Sun.COM
2710480SAlexandre.Chartre@Sun.COM /*
2810480SAlexandre.Chartre@Sun.COM * Logical Domains Device Agent
2910480SAlexandre.Chartre@Sun.COM */
3010480SAlexandre.Chartre@Sun.COM
3110480SAlexandre.Chartre@Sun.COM #include <errno.h>
3210480SAlexandre.Chartre@Sun.COM #include <fcntl.h>
3310480SAlexandre.Chartre@Sun.COM #include <libdladm.h>
3410480SAlexandre.Chartre@Sun.COM #include <libdllink.h>
3510480SAlexandre.Chartre@Sun.COM #include <libds.h>
3610480SAlexandre.Chartre@Sun.COM #include <stdio.h>
3710480SAlexandre.Chartre@Sun.COM #include <stdlib.h>
3810480SAlexandre.Chartre@Sun.COM #include <strings.h>
3910480SAlexandre.Chartre@Sun.COM #include <unistd.h>
4010480SAlexandre.Chartre@Sun.COM #include <sys/param.h>
4110480SAlexandre.Chartre@Sun.COM #include <sys/types.h>
4210480SAlexandre.Chartre@Sun.COM #include <sys/stat.h>
4310480SAlexandre.Chartre@Sun.COM
4410480SAlexandre.Chartre@Sun.COM #include "ldma.h"
4510480SAlexandre.Chartre@Sun.COM
4610480SAlexandre.Chartre@Sun.COM #define LDMA_MODULE LDMA_NAME_DEVICE
4710480SAlexandre.Chartre@Sun.COM
4810480SAlexandre.Chartre@Sun.COM #define LDMA_NVERSIONS (sizeof (ldma_versions) / sizeof (ds_ver_t))
4910480SAlexandre.Chartre@Sun.COM #define LDMA_NHANDLERS (sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t))
5010480SAlexandre.Chartre@Sun.COM
5110480SAlexandre.Chartre@Sun.COM static ldm_msg_func_t ldma_dev_validate_path;
5210480SAlexandre.Chartre@Sun.COM static ldm_msg_func_t ldma_dev_validate_nic;
5310480SAlexandre.Chartre@Sun.COM
5410480SAlexandre.Chartre@Sun.COM static ds_ver_t ldma_versions[] = { { 1, 0 } };
5510480SAlexandre.Chartre@Sun.COM
5610480SAlexandre.Chartre@Sun.COM static ldma_msg_handler_t ldma_handlers[] = {
57*11833SMichael.Christensen@Sun.COM { LDMA_MSGDEV_VALIDATE_PATH, LDMA_MSGFLG_ACCESS_CONTROL,
58*11833SMichael.Christensen@Sun.COM ldma_dev_validate_path },
59*11833SMichael.Christensen@Sun.COM { LDMA_MSGDEV_VALIDATE_NIC, LDMA_MSGFLG_ACCESS_CONTROL,
60*11833SMichael.Christensen@Sun.COM ldma_dev_validate_nic }
6110480SAlexandre.Chartre@Sun.COM };
6210480SAlexandre.Chartre@Sun.COM
6310480SAlexandre.Chartre@Sun.COM ldma_agent_info_t ldma_device_info = {
6410480SAlexandre.Chartre@Sun.COM LDMA_NAME_DEVICE,
6510480SAlexandre.Chartre@Sun.COM ldma_versions, LDMA_NVERSIONS,
6610480SAlexandre.Chartre@Sun.COM ldma_handlers, LDMA_NHANDLERS
6710480SAlexandre.Chartre@Sun.COM };
6810480SAlexandre.Chartre@Sun.COM
6910480SAlexandre.Chartre@Sun.COM /*ARGSUSED*/
7010480SAlexandre.Chartre@Sun.COM 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)7110480SAlexandre.Chartre@Sun.COM ldma_dev_validate_path(ds_ver_t *ver, ldma_message_header_t *request,
7210480SAlexandre.Chartre@Sun.COM size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
7310480SAlexandre.Chartre@Sun.COM {
7410480SAlexandre.Chartre@Sun.COM ldma_message_header_t *reply = NULL;
7510480SAlexandre.Chartre@Sun.COM ldma_request_status_t status;
7610480SAlexandre.Chartre@Sun.COM struct stat st;
7710480SAlexandre.Chartre@Sun.COM char *path = NULL;
7810480SAlexandre.Chartre@Sun.COM uint32_t *path_type, reply_dlen;
7910480SAlexandre.Chartre@Sun.COM uint32_t plen;
8010480SAlexandre.Chartre@Sun.COM int fd;
8110480SAlexandre.Chartre@Sun.COM
8210480SAlexandre.Chartre@Sun.COM plen = request->msg_info;
8310480SAlexandre.Chartre@Sun.COM if (plen == 0 || plen > MAXPATHLEN || plen > request_dlen) {
8410480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_INVALID;
8510480SAlexandre.Chartre@Sun.COM goto done;
8610480SAlexandre.Chartre@Sun.COM }
8710480SAlexandre.Chartre@Sun.COM
8810480SAlexandre.Chartre@Sun.COM path = malloc(plen + 1);
8910480SAlexandre.Chartre@Sun.COM if (path == NULL) {
9010480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_FAILED;
9110480SAlexandre.Chartre@Sun.COM goto done;
9210480SAlexandre.Chartre@Sun.COM }
9310480SAlexandre.Chartre@Sun.COM
9410480SAlexandre.Chartre@Sun.COM (void) strncpy(path, LDMA_HDR2DATA(request), plen);
9510480SAlexandre.Chartre@Sun.COM path[plen] = '\0';
9610480SAlexandre.Chartre@Sun.COM
9710480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_PATH(%s)", path);
9810480SAlexandre.Chartre@Sun.COM
9910480SAlexandre.Chartre@Sun.COM reply_dlen = sizeof (uint32_t);
10010480SAlexandre.Chartre@Sun.COM reply = ldma_alloc_result_msg(request, reply_dlen);
10110480SAlexandre.Chartre@Sun.COM if (reply == NULL) {
10210480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_FAILED;
10310480SAlexandre.Chartre@Sun.COM goto done;
10410480SAlexandre.Chartre@Sun.COM }
10510480SAlexandre.Chartre@Sun.COM
10610480SAlexandre.Chartre@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */
10710480SAlexandre.Chartre@Sun.COM path_type = (uint32_t *)(LDMA_HDR2DATA(reply));
10810480SAlexandre.Chartre@Sun.COM
10910480SAlexandre.Chartre@Sun.COM reply->msg_info = 0x0;
11010480SAlexandre.Chartre@Sun.COM
11110480SAlexandre.Chartre@Sun.COM /* check if path exists */
11210480SAlexandre.Chartre@Sun.COM if (stat(path, &st) != 0) {
11310480SAlexandre.Chartre@Sun.COM
11410480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_PATH(%s): stat failed with error %d",
11510480SAlexandre.Chartre@Sun.COM path, errno);
11610480SAlexandre.Chartre@Sun.COM
11710480SAlexandre.Chartre@Sun.COM switch (errno) {
11810480SAlexandre.Chartre@Sun.COM
11910480SAlexandre.Chartre@Sun.COM case EACCES:
12010480SAlexandre.Chartre@Sun.COM case ELOOP:
12110480SAlexandre.Chartre@Sun.COM case ENOENT:
12210480SAlexandre.Chartre@Sun.COM case ENOLINK:
12310480SAlexandre.Chartre@Sun.COM case ENOTDIR:
12410480SAlexandre.Chartre@Sun.COM /* path is inaccessible, the request is completed */
12510480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_COMPLETED;
12610480SAlexandre.Chartre@Sun.COM break;
12710480SAlexandre.Chartre@Sun.COM
12810480SAlexandre.Chartre@Sun.COM case ENAMETOOLONG:
12910480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_INVALID;
13010480SAlexandre.Chartre@Sun.COM break;
13110480SAlexandre.Chartre@Sun.COM
13210480SAlexandre.Chartre@Sun.COM default:
13310480SAlexandre.Chartre@Sun.COM /* request has failed */
13410480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_FAILED;
13510480SAlexandre.Chartre@Sun.COM break;
13610480SAlexandre.Chartre@Sun.COM }
13710480SAlexandre.Chartre@Sun.COM
13810480SAlexandre.Chartre@Sun.COM goto done;
13910480SAlexandre.Chartre@Sun.COM }
14010480SAlexandre.Chartre@Sun.COM
14110480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_COMPLETED;
14210480SAlexandre.Chartre@Sun.COM
14310480SAlexandre.Chartre@Sun.COM reply->msg_info |= LDMA_DEVPATH_EXIST;
14410480SAlexandre.Chartre@Sun.COM
14511029SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_PATH(%s): file mode = 0x%lx", path, st.st_mode);
14610480SAlexandre.Chartre@Sun.COM
14710480SAlexandre.Chartre@Sun.COM switch (st.st_mode & S_IFMT) {
14810480SAlexandre.Chartre@Sun.COM
14910480SAlexandre.Chartre@Sun.COM case S_IFREG:
15010480SAlexandre.Chartre@Sun.COM *path_type = LDMA_DEVPATH_TYPE_FILE;
15110480SAlexandre.Chartre@Sun.COM break;
15210480SAlexandre.Chartre@Sun.COM
15310480SAlexandre.Chartre@Sun.COM case S_IFCHR:
15410480SAlexandre.Chartre@Sun.COM case S_IFBLK:
15510480SAlexandre.Chartre@Sun.COM *path_type = LDMA_DEVPATH_TYPE_DEVICE;
15610480SAlexandre.Chartre@Sun.COM break;
15710480SAlexandre.Chartre@Sun.COM
15810480SAlexandre.Chartre@Sun.COM default:
15910480SAlexandre.Chartre@Sun.COM /* we don't advertise other types (fifo, directory...) */
16010480SAlexandre.Chartre@Sun.COM *path_type = 0;
16110480SAlexandre.Chartre@Sun.COM }
16210480SAlexandre.Chartre@Sun.COM
16310480SAlexandre.Chartre@Sun.COM /* check if path can be opened read/write */
16410480SAlexandre.Chartre@Sun.COM if ((fd = open(path, O_RDWR)) != -1) {
16510480SAlexandre.Chartre@Sun.COM reply->msg_info |= LDMA_DEVPATH_OPENRW | LDMA_DEVPATH_OPENRO;
16610480SAlexandre.Chartre@Sun.COM (void) close(fd);
16710480SAlexandre.Chartre@Sun.COM } else {
16810480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_PATH(%s): open RDWR failed with error %d",
16910480SAlexandre.Chartre@Sun.COM path, errno);
17010480SAlexandre.Chartre@Sun.COM
17110480SAlexandre.Chartre@Sun.COM /* check if path can be opened read only */
17210480SAlexandre.Chartre@Sun.COM if ((fd = open(path, O_RDONLY)) != -1) {
17310480SAlexandre.Chartre@Sun.COM reply->msg_info |= LDMA_DEVPATH_OPENRO;
17410480SAlexandre.Chartre@Sun.COM (void) close(fd);
17510480SAlexandre.Chartre@Sun.COM } else {
17610480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_PATH(%s): open RDONLY failed "
17710480SAlexandre.Chartre@Sun.COM "with error %d", path, errno);
17810480SAlexandre.Chartre@Sun.COM }
17910480SAlexandre.Chartre@Sun.COM }
18010480SAlexandre.Chartre@Sun.COM
18110480SAlexandre.Chartre@Sun.COM done:
18210480SAlexandre.Chartre@Sun.COM if (status != LDMA_REQ_COMPLETED) {
18310480SAlexandre.Chartre@Sun.COM /*
18410480SAlexandre.Chartre@Sun.COM * We don't provide a reply message if the request has not
18510480SAlexandre.Chartre@Sun.COM * been completed. The LDoms agent daemon will send an
18610480SAlexandre.Chartre@Sun.COM * appropriate reply based on the return code of this function.
18710480SAlexandre.Chartre@Sun.COM */
18810480SAlexandre.Chartre@Sun.COM free(reply);
18910480SAlexandre.Chartre@Sun.COM reply = NULL;
19010480SAlexandre.Chartre@Sun.COM reply_dlen = 0;
19110480SAlexandre.Chartre@Sun.COM
19210480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_PATH(%s): return error %d",
19310480SAlexandre.Chartre@Sun.COM (path)? path : "<none>", status);
19410480SAlexandre.Chartre@Sun.COM } else {
19510480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_PATH(%s): return status=0x%x type=0x%x",
19610480SAlexandre.Chartre@Sun.COM path, reply->msg_info, *path_type);
19710480SAlexandre.Chartre@Sun.COM }
19810480SAlexandre.Chartre@Sun.COM
19910480SAlexandre.Chartre@Sun.COM free(path);
20010480SAlexandre.Chartre@Sun.COM *replyp = reply;
20110480SAlexandre.Chartre@Sun.COM *reply_dlenp = reply_dlen;
20210480SAlexandre.Chartre@Sun.COM
20310480SAlexandre.Chartre@Sun.COM return (status);
20410480SAlexandre.Chartre@Sun.COM }
20510480SAlexandre.Chartre@Sun.COM
20610480SAlexandre.Chartre@Sun.COM /*
20710480SAlexandre.Chartre@Sun.COM * We check that the device is a network interface (NIC) using libdladm.
20810480SAlexandre.Chartre@Sun.COM */
20910480SAlexandre.Chartre@Sun.COM /*ARGSUSED*/
21010480SAlexandre.Chartre@Sun.COM 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)21110480SAlexandre.Chartre@Sun.COM ldma_dev_validate_nic(ds_ver_t *ver, ldma_message_header_t *request,
21210480SAlexandre.Chartre@Sun.COM size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
21310480SAlexandre.Chartre@Sun.COM {
21410480SAlexandre.Chartre@Sun.COM dladm_handle_t dlhandle;
21510480SAlexandre.Chartre@Sun.COM datalink_id_t linkid;
21610480SAlexandre.Chartre@Sun.COM uint32_t flag, media;
21710480SAlexandre.Chartre@Sun.COM datalink_class_t class;
21810480SAlexandre.Chartre@Sun.COM ldma_message_header_t *reply = NULL;
21910480SAlexandre.Chartre@Sun.COM ldma_request_status_t status;
22010480SAlexandre.Chartre@Sun.COM char *nic = NULL;
22110480SAlexandre.Chartre@Sun.COM uint32_t nlen, reply_dlen;
22210480SAlexandre.Chartre@Sun.COM
22310480SAlexandre.Chartre@Sun.COM nlen = request->msg_info;
22410480SAlexandre.Chartre@Sun.COM if (nlen == 0 || nlen > MAXPATHLEN || nlen > request_dlen) {
22510480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_INVALID;
22610480SAlexandre.Chartre@Sun.COM goto done;
22710480SAlexandre.Chartre@Sun.COM }
22810480SAlexandre.Chartre@Sun.COM
22910480SAlexandre.Chartre@Sun.COM nic = malloc(nlen + 1);
23010480SAlexandre.Chartre@Sun.COM if (nic == NULL) {
23110480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_FAILED;
23210480SAlexandre.Chartre@Sun.COM goto done;
23310480SAlexandre.Chartre@Sun.COM }
23410480SAlexandre.Chartre@Sun.COM
23510480SAlexandre.Chartre@Sun.COM (void) strncpy(nic, LDMA_HDR2DATA(request), nlen);
23610480SAlexandre.Chartre@Sun.COM nic[nlen] = '\0';
23710480SAlexandre.Chartre@Sun.COM
23810480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_NIC(%s)", nic);
23910480SAlexandre.Chartre@Sun.COM
24010480SAlexandre.Chartre@Sun.COM reply_dlen = 0;
24110480SAlexandre.Chartre@Sun.COM reply = ldma_alloc_result_msg(request, reply_dlen);
24210480SAlexandre.Chartre@Sun.COM if (reply == NULL) {
24310480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_FAILED;
24410480SAlexandre.Chartre@Sun.COM goto done;
24510480SAlexandre.Chartre@Sun.COM }
24610480SAlexandre.Chartre@Sun.COM
24710480SAlexandre.Chartre@Sun.COM reply->msg_info = 0x0;
24810480SAlexandre.Chartre@Sun.COM
24910480SAlexandre.Chartre@Sun.COM if (dladm_open(&dlhandle) != DLADM_STATUS_OK) {
25010480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_FAILED;
25110480SAlexandre.Chartre@Sun.COM goto done;
25210480SAlexandre.Chartre@Sun.COM }
25310480SAlexandre.Chartre@Sun.COM
25410480SAlexandre.Chartre@Sun.COM if (dladm_name2info(dlhandle, nic, &linkid, &flag, &class,
25510480SAlexandre.Chartre@Sun.COM &media) != DLADM_STATUS_OK) {
25610480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_NIC(%s): name2info failed", nic);
25710480SAlexandre.Chartre@Sun.COM } else {
25810480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_NIC(%s): media=0x%x", nic, media);
25910480SAlexandre.Chartre@Sun.COM reply->msg_info = LDMA_DEVNIC_EXIST;
26010480SAlexandre.Chartre@Sun.COM }
26110480SAlexandre.Chartre@Sun.COM
26210480SAlexandre.Chartre@Sun.COM dladm_close(dlhandle);
26310480SAlexandre.Chartre@Sun.COM
26410480SAlexandre.Chartre@Sun.COM status = LDMA_REQ_COMPLETED;
26510480SAlexandre.Chartre@Sun.COM
26610480SAlexandre.Chartre@Sun.COM done:
26710480SAlexandre.Chartre@Sun.COM if (status != LDMA_REQ_COMPLETED) {
26810480SAlexandre.Chartre@Sun.COM /*
26910480SAlexandre.Chartre@Sun.COM * We don't provide a reply message if the request has not
27010480SAlexandre.Chartre@Sun.COM * been completed. The LDoms agent daemon will send an
27110480SAlexandre.Chartre@Sun.COM * appropriate reply based on the return code of this function.
27210480SAlexandre.Chartre@Sun.COM */
27310480SAlexandre.Chartre@Sun.COM free(reply);
27410480SAlexandre.Chartre@Sun.COM reply = NULL;
27510480SAlexandre.Chartre@Sun.COM reply_dlen = 0;
27610480SAlexandre.Chartre@Sun.COM
27710480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_NIC(%s): return error %d",
27810480SAlexandre.Chartre@Sun.COM (nic)? nic : "<none>", status);
27910480SAlexandre.Chartre@Sun.COM } else {
28010480SAlexandre.Chartre@Sun.COM LDMA_DBG("VALIDATE_NIC(%s): return status=0x%x",
28110480SAlexandre.Chartre@Sun.COM nic, reply->msg_info);
28210480SAlexandre.Chartre@Sun.COM }
28310480SAlexandre.Chartre@Sun.COM
28410480SAlexandre.Chartre@Sun.COM free(nic);
28510480SAlexandre.Chartre@Sun.COM *replyp = reply;
28610480SAlexandre.Chartre@Sun.COM *reply_dlenp = reply_dlen;
28710480SAlexandre.Chartre@Sun.COM
28810480SAlexandre.Chartre@Sun.COM return (status);
28910480SAlexandre.Chartre@Sun.COM }
290