xref: /onnv-gate/usr/src/cmd/ldmad/ldma_device.c (revision 11833:3b3fe296598b)
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