xref: /titanic_51/usr/src/cmd/ldmad/ldma_device.c (revision 82629e3015252bf18319ba3815c773df23e21436)
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
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
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