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