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 /* 2349bfb42bSAlexandre Chartre * Copyright 2009 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[] = { 5749bfb42bSAlexandre Chartre { LDMA_MSGDEV_VALIDATE_PATH, ldma_dev_validate_path }, 5849bfb42bSAlexandre Chartre { LDMA_MSGDEV_VALIDATE_NIC, ldma_dev_validate_nic } 5949bfb42bSAlexandre Chartre }; 6049bfb42bSAlexandre Chartre 6149bfb42bSAlexandre Chartre ldma_agent_info_t ldma_device_info = { 6249bfb42bSAlexandre Chartre LDMA_NAME_DEVICE, 6349bfb42bSAlexandre Chartre ldma_versions, LDMA_NVERSIONS, 6449bfb42bSAlexandre Chartre ldma_handlers, LDMA_NHANDLERS 6549bfb42bSAlexandre Chartre }; 6649bfb42bSAlexandre Chartre 6749bfb42bSAlexandre Chartre /*ARGSUSED*/ 6849bfb42bSAlexandre Chartre static ldma_request_status_t 6949bfb42bSAlexandre Chartre ldma_dev_validate_path(ds_ver_t *ver, ldma_message_header_t *request, 7049bfb42bSAlexandre Chartre size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp) 7149bfb42bSAlexandre Chartre { 7249bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL; 7349bfb42bSAlexandre Chartre ldma_request_status_t status; 7449bfb42bSAlexandre Chartre struct stat st; 7549bfb42bSAlexandre Chartre char *path = NULL; 7649bfb42bSAlexandre Chartre uint32_t *path_type, reply_dlen; 7749bfb42bSAlexandre Chartre uint32_t plen; 7849bfb42bSAlexandre Chartre int fd; 7949bfb42bSAlexandre Chartre 8049bfb42bSAlexandre Chartre plen = request->msg_info; 8149bfb42bSAlexandre Chartre if (plen == 0 || plen > MAXPATHLEN || plen > request_dlen) { 8249bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID; 8349bfb42bSAlexandre Chartre goto done; 8449bfb42bSAlexandre Chartre } 8549bfb42bSAlexandre Chartre 8649bfb42bSAlexandre Chartre path = malloc(plen + 1); 8749bfb42bSAlexandre Chartre if (path == NULL) { 8849bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 8949bfb42bSAlexandre Chartre goto done; 9049bfb42bSAlexandre Chartre } 9149bfb42bSAlexandre Chartre 9249bfb42bSAlexandre Chartre (void) strncpy(path, LDMA_HDR2DATA(request), plen); 9349bfb42bSAlexandre Chartre path[plen] = '\0'; 9449bfb42bSAlexandre Chartre 9549bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s)", path); 9649bfb42bSAlexandre Chartre 9749bfb42bSAlexandre Chartre reply_dlen = sizeof (uint32_t); 9849bfb42bSAlexandre Chartre reply = ldma_alloc_result_msg(request, reply_dlen); 9949bfb42bSAlexandre Chartre if (reply == NULL) { 10049bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 10149bfb42bSAlexandre Chartre goto done; 10249bfb42bSAlexandre Chartre } 10349bfb42bSAlexandre Chartre 10449bfb42bSAlexandre Chartre /* LINTED E_BAD_PTR_CAST_ALIGN */ 10549bfb42bSAlexandre Chartre path_type = (uint32_t *)(LDMA_HDR2DATA(reply)); 10649bfb42bSAlexandre Chartre 10749bfb42bSAlexandre Chartre reply->msg_info = 0x0; 10849bfb42bSAlexandre Chartre 10949bfb42bSAlexandre Chartre /* check if path exists */ 11049bfb42bSAlexandre Chartre if (stat(path, &st) != 0) { 11149bfb42bSAlexandre Chartre 11249bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): stat failed with error %d", 11349bfb42bSAlexandre Chartre path, errno); 11449bfb42bSAlexandre Chartre 11549bfb42bSAlexandre Chartre switch (errno) { 11649bfb42bSAlexandre Chartre 11749bfb42bSAlexandre Chartre case EACCES: 11849bfb42bSAlexandre Chartre case ELOOP: 11949bfb42bSAlexandre Chartre case ENOENT: 12049bfb42bSAlexandre Chartre case ENOLINK: 12149bfb42bSAlexandre Chartre case ENOTDIR: 12249bfb42bSAlexandre Chartre /* path is inaccessible, the request is completed */ 12349bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 12449bfb42bSAlexandre Chartre break; 12549bfb42bSAlexandre Chartre 12649bfb42bSAlexandre Chartre case ENAMETOOLONG: 12749bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID; 12849bfb42bSAlexandre Chartre break; 12949bfb42bSAlexandre Chartre 13049bfb42bSAlexandre Chartre default: 13149bfb42bSAlexandre Chartre /* request has failed */ 13249bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 13349bfb42bSAlexandre Chartre break; 13449bfb42bSAlexandre Chartre } 13549bfb42bSAlexandre Chartre 13649bfb42bSAlexandre Chartre goto done; 13749bfb42bSAlexandre Chartre } 13849bfb42bSAlexandre Chartre 13949bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 14049bfb42bSAlexandre Chartre 14149bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_EXIST; 14249bfb42bSAlexandre Chartre 143*6b8303caSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): file mode = 0x%lx", path, st.st_mode); 14449bfb42bSAlexandre Chartre 14549bfb42bSAlexandre Chartre switch (st.st_mode & S_IFMT) { 14649bfb42bSAlexandre Chartre 14749bfb42bSAlexandre Chartre case S_IFREG: 14849bfb42bSAlexandre Chartre *path_type = LDMA_DEVPATH_TYPE_FILE; 14949bfb42bSAlexandre Chartre break; 15049bfb42bSAlexandre Chartre 15149bfb42bSAlexandre Chartre case S_IFCHR: 15249bfb42bSAlexandre Chartre case S_IFBLK: 15349bfb42bSAlexandre Chartre *path_type = LDMA_DEVPATH_TYPE_DEVICE; 15449bfb42bSAlexandre Chartre break; 15549bfb42bSAlexandre Chartre 15649bfb42bSAlexandre Chartre default: 15749bfb42bSAlexandre Chartre /* we don't advertise other types (fifo, directory...) */ 15849bfb42bSAlexandre Chartre *path_type = 0; 15949bfb42bSAlexandre Chartre } 16049bfb42bSAlexandre Chartre 16149bfb42bSAlexandre Chartre /* check if path can be opened read/write */ 16249bfb42bSAlexandre Chartre if ((fd = open(path, O_RDWR)) != -1) { 16349bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_OPENRW | LDMA_DEVPATH_OPENRO; 16449bfb42bSAlexandre Chartre (void) close(fd); 16549bfb42bSAlexandre Chartre } else { 16649bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): open RDWR failed with error %d", 16749bfb42bSAlexandre Chartre path, errno); 16849bfb42bSAlexandre Chartre 16949bfb42bSAlexandre Chartre /* check if path can be opened read only */ 17049bfb42bSAlexandre Chartre if ((fd = open(path, O_RDONLY)) != -1) { 17149bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_OPENRO; 17249bfb42bSAlexandre Chartre (void) close(fd); 17349bfb42bSAlexandre Chartre } else { 17449bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): open RDONLY failed " 17549bfb42bSAlexandre Chartre "with error %d", path, errno); 17649bfb42bSAlexandre Chartre } 17749bfb42bSAlexandre Chartre } 17849bfb42bSAlexandre Chartre 17949bfb42bSAlexandre Chartre done: 18049bfb42bSAlexandre Chartre if (status != LDMA_REQ_COMPLETED) { 18149bfb42bSAlexandre Chartre /* 18249bfb42bSAlexandre Chartre * We don't provide a reply message if the request has not 18349bfb42bSAlexandre Chartre * been completed. The LDoms agent daemon will send an 18449bfb42bSAlexandre Chartre * appropriate reply based on the return code of this function. 18549bfb42bSAlexandre Chartre */ 18649bfb42bSAlexandre Chartre free(reply); 18749bfb42bSAlexandre Chartre reply = NULL; 18849bfb42bSAlexandre Chartre reply_dlen = 0; 18949bfb42bSAlexandre Chartre 19049bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): return error %d", 19149bfb42bSAlexandre Chartre (path)? path : "<none>", status); 19249bfb42bSAlexandre Chartre } else { 19349bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): return status=0x%x type=0x%x", 19449bfb42bSAlexandre Chartre path, reply->msg_info, *path_type); 19549bfb42bSAlexandre Chartre } 19649bfb42bSAlexandre Chartre 19749bfb42bSAlexandre Chartre free(path); 19849bfb42bSAlexandre Chartre *replyp = reply; 19949bfb42bSAlexandre Chartre *reply_dlenp = reply_dlen; 20049bfb42bSAlexandre Chartre 20149bfb42bSAlexandre Chartre return (status); 20249bfb42bSAlexandre Chartre } 20349bfb42bSAlexandre Chartre 20449bfb42bSAlexandre Chartre /* 20549bfb42bSAlexandre Chartre * We check that the device is a network interface (NIC) using libdladm. 20649bfb42bSAlexandre Chartre */ 20749bfb42bSAlexandre Chartre /*ARGSUSED*/ 20849bfb42bSAlexandre Chartre static ldma_request_status_t 20949bfb42bSAlexandre Chartre ldma_dev_validate_nic(ds_ver_t *ver, ldma_message_header_t *request, 21049bfb42bSAlexandre Chartre size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp) 21149bfb42bSAlexandre Chartre { 21249bfb42bSAlexandre Chartre dladm_handle_t dlhandle; 21349bfb42bSAlexandre Chartre datalink_id_t linkid; 21449bfb42bSAlexandre Chartre uint32_t flag, media; 21549bfb42bSAlexandre Chartre datalink_class_t class; 21649bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL; 21749bfb42bSAlexandre Chartre ldma_request_status_t status; 21849bfb42bSAlexandre Chartre char *nic = NULL; 21949bfb42bSAlexandre Chartre uint32_t nlen, reply_dlen; 22049bfb42bSAlexandre Chartre 22149bfb42bSAlexandre Chartre nlen = request->msg_info; 22249bfb42bSAlexandre Chartre if (nlen == 0 || nlen > MAXPATHLEN || nlen > request_dlen) { 22349bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID; 22449bfb42bSAlexandre Chartre goto done; 22549bfb42bSAlexandre Chartre } 22649bfb42bSAlexandre Chartre 22749bfb42bSAlexandre Chartre nic = malloc(nlen + 1); 22849bfb42bSAlexandre Chartre if (nic == NULL) { 22949bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 23049bfb42bSAlexandre Chartre goto done; 23149bfb42bSAlexandre Chartre } 23249bfb42bSAlexandre Chartre 23349bfb42bSAlexandre Chartre (void) strncpy(nic, LDMA_HDR2DATA(request), nlen); 23449bfb42bSAlexandre Chartre nic[nlen] = '\0'; 23549bfb42bSAlexandre Chartre 23649bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s)", nic); 23749bfb42bSAlexandre Chartre 23849bfb42bSAlexandre Chartre reply_dlen = 0; 23949bfb42bSAlexandre Chartre reply = ldma_alloc_result_msg(request, reply_dlen); 24049bfb42bSAlexandre Chartre if (reply == NULL) { 24149bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 24249bfb42bSAlexandre Chartre goto done; 24349bfb42bSAlexandre Chartre } 24449bfb42bSAlexandre Chartre 24549bfb42bSAlexandre Chartre reply->msg_info = 0x0; 24649bfb42bSAlexandre Chartre 24749bfb42bSAlexandre Chartre if (dladm_open(&dlhandle) != DLADM_STATUS_OK) { 24849bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 24949bfb42bSAlexandre Chartre goto done; 25049bfb42bSAlexandre Chartre } 25149bfb42bSAlexandre Chartre 25249bfb42bSAlexandre Chartre if (dladm_name2info(dlhandle, nic, &linkid, &flag, &class, 25349bfb42bSAlexandre Chartre &media) != DLADM_STATUS_OK) { 25449bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): name2info failed", nic); 25549bfb42bSAlexandre Chartre } else { 25649bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): media=0x%x", nic, media); 25749bfb42bSAlexandre Chartre reply->msg_info = LDMA_DEVNIC_EXIST; 25849bfb42bSAlexandre Chartre } 25949bfb42bSAlexandre Chartre 26049bfb42bSAlexandre Chartre dladm_close(dlhandle); 26149bfb42bSAlexandre Chartre 26249bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 26349bfb42bSAlexandre Chartre 26449bfb42bSAlexandre Chartre done: 26549bfb42bSAlexandre Chartre if (status != LDMA_REQ_COMPLETED) { 26649bfb42bSAlexandre Chartre /* 26749bfb42bSAlexandre Chartre * We don't provide a reply message if the request has not 26849bfb42bSAlexandre Chartre * been completed. The LDoms agent daemon will send an 26949bfb42bSAlexandre Chartre * appropriate reply based on the return code of this function. 27049bfb42bSAlexandre Chartre */ 27149bfb42bSAlexandre Chartre free(reply); 27249bfb42bSAlexandre Chartre reply = NULL; 27349bfb42bSAlexandre Chartre reply_dlen = 0; 27449bfb42bSAlexandre Chartre 27549bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): return error %d", 27649bfb42bSAlexandre Chartre (nic)? nic : "<none>", status); 27749bfb42bSAlexandre Chartre } else { 27849bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): return status=0x%x", 27949bfb42bSAlexandre Chartre nic, reply->msg_info); 28049bfb42bSAlexandre Chartre } 28149bfb42bSAlexandre Chartre 28249bfb42bSAlexandre Chartre free(nic); 28349bfb42bSAlexandre Chartre *replyp = reply; 28449bfb42bSAlexandre Chartre *reply_dlenp = reply_dlen; 28549bfb42bSAlexandre Chartre 28649bfb42bSAlexandre Chartre return (status); 28749bfb42bSAlexandre Chartre } 288