1*49bfb42bSAlexandre Chartre /* 2*49bfb42bSAlexandre Chartre * CDDL HEADER START 3*49bfb42bSAlexandre Chartre * 4*49bfb42bSAlexandre Chartre * The contents of this file are subject to the terms of the 5*49bfb42bSAlexandre Chartre * Common Development and Distribution License (the "License"). 6*49bfb42bSAlexandre Chartre * You may not use this file except in compliance with the License. 7*49bfb42bSAlexandre Chartre * 8*49bfb42bSAlexandre Chartre * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*49bfb42bSAlexandre Chartre * or http://www.opensolaris.org/os/licensing. 10*49bfb42bSAlexandre Chartre * See the License for the specific language governing permissions 11*49bfb42bSAlexandre Chartre * and limitations under the License. 12*49bfb42bSAlexandre Chartre * 13*49bfb42bSAlexandre Chartre * When distributing Covered Code, include this CDDL HEADER in each 14*49bfb42bSAlexandre Chartre * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*49bfb42bSAlexandre Chartre * If applicable, add the following below this CDDL HEADER, with the 16*49bfb42bSAlexandre Chartre * fields enclosed by brackets "[]" replaced with your own identifying 17*49bfb42bSAlexandre Chartre * information: Portions Copyright [yyyy] [name of copyright owner] 18*49bfb42bSAlexandre Chartre * 19*49bfb42bSAlexandre Chartre * CDDL HEADER END 20*49bfb42bSAlexandre Chartre */ 21*49bfb42bSAlexandre Chartre 22*49bfb42bSAlexandre Chartre /* 23*49bfb42bSAlexandre Chartre * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*49bfb42bSAlexandre Chartre * Use is subject to license terms. 25*49bfb42bSAlexandre Chartre */ 26*49bfb42bSAlexandre Chartre 27*49bfb42bSAlexandre Chartre /* 28*49bfb42bSAlexandre Chartre * Logical Domains Device Agent 29*49bfb42bSAlexandre Chartre */ 30*49bfb42bSAlexandre Chartre 31*49bfb42bSAlexandre Chartre #include <errno.h> 32*49bfb42bSAlexandre Chartre #include <fcntl.h> 33*49bfb42bSAlexandre Chartre #include <libdladm.h> 34*49bfb42bSAlexandre Chartre #include <libdllink.h> 35*49bfb42bSAlexandre Chartre #include <libds.h> 36*49bfb42bSAlexandre Chartre #include <stdio.h> 37*49bfb42bSAlexandre Chartre #include <stdlib.h> 38*49bfb42bSAlexandre Chartre #include <strings.h> 39*49bfb42bSAlexandre Chartre #include <unistd.h> 40*49bfb42bSAlexandre Chartre #include <sys/param.h> 41*49bfb42bSAlexandre Chartre #include <sys/types.h> 42*49bfb42bSAlexandre Chartre #include <sys/stat.h> 43*49bfb42bSAlexandre Chartre 44*49bfb42bSAlexandre Chartre #include "ldma.h" 45*49bfb42bSAlexandre Chartre 46*49bfb42bSAlexandre Chartre #define LDMA_MODULE LDMA_NAME_DEVICE 47*49bfb42bSAlexandre Chartre 48*49bfb42bSAlexandre Chartre #define LDMA_NVERSIONS (sizeof (ldma_versions) / sizeof (ds_ver_t)) 49*49bfb42bSAlexandre Chartre #define LDMA_NHANDLERS (sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t)) 50*49bfb42bSAlexandre Chartre 51*49bfb42bSAlexandre Chartre static ldm_msg_func_t ldma_dev_validate_path; 52*49bfb42bSAlexandre Chartre static ldm_msg_func_t ldma_dev_validate_nic; 53*49bfb42bSAlexandre Chartre 54*49bfb42bSAlexandre Chartre static ds_ver_t ldma_versions[] = { { 1, 0 } }; 55*49bfb42bSAlexandre Chartre 56*49bfb42bSAlexandre Chartre static ldma_msg_handler_t ldma_handlers[] = { 57*49bfb42bSAlexandre Chartre { LDMA_MSGDEV_VALIDATE_PATH, ldma_dev_validate_path }, 58*49bfb42bSAlexandre Chartre { LDMA_MSGDEV_VALIDATE_NIC, ldma_dev_validate_nic } 59*49bfb42bSAlexandre Chartre }; 60*49bfb42bSAlexandre Chartre 61*49bfb42bSAlexandre Chartre ldma_agent_info_t ldma_device_info = { 62*49bfb42bSAlexandre Chartre LDMA_NAME_DEVICE, 63*49bfb42bSAlexandre Chartre ldma_versions, LDMA_NVERSIONS, 64*49bfb42bSAlexandre Chartre ldma_handlers, LDMA_NHANDLERS 65*49bfb42bSAlexandre Chartre }; 66*49bfb42bSAlexandre Chartre 67*49bfb42bSAlexandre Chartre /*ARGSUSED*/ 68*49bfb42bSAlexandre Chartre static ldma_request_status_t 69*49bfb42bSAlexandre Chartre ldma_dev_validate_path(ds_ver_t *ver, ldma_message_header_t *request, 70*49bfb42bSAlexandre Chartre size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp) 71*49bfb42bSAlexandre Chartre { 72*49bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL; 73*49bfb42bSAlexandre Chartre ldma_request_status_t status; 74*49bfb42bSAlexandre Chartre struct stat st; 75*49bfb42bSAlexandre Chartre char *path = NULL; 76*49bfb42bSAlexandre Chartre uint32_t *path_type, reply_dlen; 77*49bfb42bSAlexandre Chartre uint32_t plen; 78*49bfb42bSAlexandre Chartre int fd; 79*49bfb42bSAlexandre Chartre 80*49bfb42bSAlexandre Chartre plen = request->msg_info; 81*49bfb42bSAlexandre Chartre if (plen == 0 || plen > MAXPATHLEN || plen > request_dlen) { 82*49bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID; 83*49bfb42bSAlexandre Chartre goto done; 84*49bfb42bSAlexandre Chartre } 85*49bfb42bSAlexandre Chartre 86*49bfb42bSAlexandre Chartre path = malloc(plen + 1); 87*49bfb42bSAlexandre Chartre if (path == NULL) { 88*49bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 89*49bfb42bSAlexandre Chartre goto done; 90*49bfb42bSAlexandre Chartre } 91*49bfb42bSAlexandre Chartre 92*49bfb42bSAlexandre Chartre (void) strncpy(path, LDMA_HDR2DATA(request), plen); 93*49bfb42bSAlexandre Chartre path[plen] = '\0'; 94*49bfb42bSAlexandre Chartre 95*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s)", path); 96*49bfb42bSAlexandre Chartre 97*49bfb42bSAlexandre Chartre reply_dlen = sizeof (uint32_t); 98*49bfb42bSAlexandre Chartre reply = ldma_alloc_result_msg(request, reply_dlen); 99*49bfb42bSAlexandre Chartre if (reply == NULL) { 100*49bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 101*49bfb42bSAlexandre Chartre goto done; 102*49bfb42bSAlexandre Chartre } 103*49bfb42bSAlexandre Chartre 104*49bfb42bSAlexandre Chartre /* LINTED E_BAD_PTR_CAST_ALIGN */ 105*49bfb42bSAlexandre Chartre path_type = (uint32_t *)(LDMA_HDR2DATA(reply)); 106*49bfb42bSAlexandre Chartre 107*49bfb42bSAlexandre Chartre reply->msg_info = 0x0; 108*49bfb42bSAlexandre Chartre 109*49bfb42bSAlexandre Chartre /* check if path exists */ 110*49bfb42bSAlexandre Chartre if (stat(path, &st) != 0) { 111*49bfb42bSAlexandre Chartre 112*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): stat failed with error %d", 113*49bfb42bSAlexandre Chartre path, errno); 114*49bfb42bSAlexandre Chartre 115*49bfb42bSAlexandre Chartre switch (errno) { 116*49bfb42bSAlexandre Chartre 117*49bfb42bSAlexandre Chartre case EACCES: 118*49bfb42bSAlexandre Chartre case ELOOP: 119*49bfb42bSAlexandre Chartre case ENOENT: 120*49bfb42bSAlexandre Chartre case ENOLINK: 121*49bfb42bSAlexandre Chartre case ENOTDIR: 122*49bfb42bSAlexandre Chartre /* path is inaccessible, the request is completed */ 123*49bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 124*49bfb42bSAlexandre Chartre break; 125*49bfb42bSAlexandre Chartre 126*49bfb42bSAlexandre Chartre case ENAMETOOLONG: 127*49bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID; 128*49bfb42bSAlexandre Chartre break; 129*49bfb42bSAlexandre Chartre 130*49bfb42bSAlexandre Chartre default: 131*49bfb42bSAlexandre Chartre /* request has failed */ 132*49bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 133*49bfb42bSAlexandre Chartre break; 134*49bfb42bSAlexandre Chartre } 135*49bfb42bSAlexandre Chartre 136*49bfb42bSAlexandre Chartre goto done; 137*49bfb42bSAlexandre Chartre } 138*49bfb42bSAlexandre Chartre 139*49bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 140*49bfb42bSAlexandre Chartre 141*49bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_EXIST; 142*49bfb42bSAlexandre Chartre 143*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): file mode = 0x%x", path, st.st_mode); 144*49bfb42bSAlexandre Chartre 145*49bfb42bSAlexandre Chartre switch (st.st_mode & S_IFMT) { 146*49bfb42bSAlexandre Chartre 147*49bfb42bSAlexandre Chartre case S_IFREG: 148*49bfb42bSAlexandre Chartre *path_type = LDMA_DEVPATH_TYPE_FILE; 149*49bfb42bSAlexandre Chartre break; 150*49bfb42bSAlexandre Chartre 151*49bfb42bSAlexandre Chartre case S_IFCHR: 152*49bfb42bSAlexandre Chartre case S_IFBLK: 153*49bfb42bSAlexandre Chartre *path_type = LDMA_DEVPATH_TYPE_DEVICE; 154*49bfb42bSAlexandre Chartre break; 155*49bfb42bSAlexandre Chartre 156*49bfb42bSAlexandre Chartre default: 157*49bfb42bSAlexandre Chartre /* we don't advertise other types (fifo, directory...) */ 158*49bfb42bSAlexandre Chartre *path_type = 0; 159*49bfb42bSAlexandre Chartre } 160*49bfb42bSAlexandre Chartre 161*49bfb42bSAlexandre Chartre /* check if path can be opened read/write */ 162*49bfb42bSAlexandre Chartre if ((fd = open(path, O_RDWR)) != -1) { 163*49bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_OPENRW | LDMA_DEVPATH_OPENRO; 164*49bfb42bSAlexandre Chartre (void) close(fd); 165*49bfb42bSAlexandre Chartre } else { 166*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): open RDWR failed with error %d", 167*49bfb42bSAlexandre Chartre path, errno); 168*49bfb42bSAlexandre Chartre 169*49bfb42bSAlexandre Chartre /* check if path can be opened read only */ 170*49bfb42bSAlexandre Chartre if ((fd = open(path, O_RDONLY)) != -1) { 171*49bfb42bSAlexandre Chartre reply->msg_info |= LDMA_DEVPATH_OPENRO; 172*49bfb42bSAlexandre Chartre (void) close(fd); 173*49bfb42bSAlexandre Chartre } else { 174*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): open RDONLY failed " 175*49bfb42bSAlexandre Chartre "with error %d", path, errno); 176*49bfb42bSAlexandre Chartre } 177*49bfb42bSAlexandre Chartre } 178*49bfb42bSAlexandre Chartre 179*49bfb42bSAlexandre Chartre done: 180*49bfb42bSAlexandre Chartre if (status != LDMA_REQ_COMPLETED) { 181*49bfb42bSAlexandre Chartre /* 182*49bfb42bSAlexandre Chartre * We don't provide a reply message if the request has not 183*49bfb42bSAlexandre Chartre * been completed. The LDoms agent daemon will send an 184*49bfb42bSAlexandre Chartre * appropriate reply based on the return code of this function. 185*49bfb42bSAlexandre Chartre */ 186*49bfb42bSAlexandre Chartre free(reply); 187*49bfb42bSAlexandre Chartre reply = NULL; 188*49bfb42bSAlexandre Chartre reply_dlen = 0; 189*49bfb42bSAlexandre Chartre 190*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): return error %d", 191*49bfb42bSAlexandre Chartre (path)? path : "<none>", status); 192*49bfb42bSAlexandre Chartre } else { 193*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_PATH(%s): return status=0x%x type=0x%x", 194*49bfb42bSAlexandre Chartre path, reply->msg_info, *path_type); 195*49bfb42bSAlexandre Chartre } 196*49bfb42bSAlexandre Chartre 197*49bfb42bSAlexandre Chartre free(path); 198*49bfb42bSAlexandre Chartre *replyp = reply; 199*49bfb42bSAlexandre Chartre *reply_dlenp = reply_dlen; 200*49bfb42bSAlexandre Chartre 201*49bfb42bSAlexandre Chartre return (status); 202*49bfb42bSAlexandre Chartre } 203*49bfb42bSAlexandre Chartre 204*49bfb42bSAlexandre Chartre /* 205*49bfb42bSAlexandre Chartre * We check that the device is a network interface (NIC) using libdladm. 206*49bfb42bSAlexandre Chartre */ 207*49bfb42bSAlexandre Chartre /*ARGSUSED*/ 208*49bfb42bSAlexandre Chartre static ldma_request_status_t 209*49bfb42bSAlexandre Chartre ldma_dev_validate_nic(ds_ver_t *ver, ldma_message_header_t *request, 210*49bfb42bSAlexandre Chartre size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp) 211*49bfb42bSAlexandre Chartre { 212*49bfb42bSAlexandre Chartre dladm_handle_t dlhandle; 213*49bfb42bSAlexandre Chartre datalink_id_t linkid; 214*49bfb42bSAlexandre Chartre uint32_t flag, media; 215*49bfb42bSAlexandre Chartre datalink_class_t class; 216*49bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL; 217*49bfb42bSAlexandre Chartre ldma_request_status_t status; 218*49bfb42bSAlexandre Chartre char *nic = NULL; 219*49bfb42bSAlexandre Chartre uint32_t nlen, reply_dlen; 220*49bfb42bSAlexandre Chartre 221*49bfb42bSAlexandre Chartre nlen = request->msg_info; 222*49bfb42bSAlexandre Chartre if (nlen == 0 || nlen > MAXPATHLEN || nlen > request_dlen) { 223*49bfb42bSAlexandre Chartre status = LDMA_REQ_INVALID; 224*49bfb42bSAlexandre Chartre goto done; 225*49bfb42bSAlexandre Chartre } 226*49bfb42bSAlexandre Chartre 227*49bfb42bSAlexandre Chartre nic = malloc(nlen + 1); 228*49bfb42bSAlexandre Chartre if (nic == NULL) { 229*49bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 230*49bfb42bSAlexandre Chartre goto done; 231*49bfb42bSAlexandre Chartre } 232*49bfb42bSAlexandre Chartre 233*49bfb42bSAlexandre Chartre (void) strncpy(nic, LDMA_HDR2DATA(request), nlen); 234*49bfb42bSAlexandre Chartre nic[nlen] = '\0'; 235*49bfb42bSAlexandre Chartre 236*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s)", nic); 237*49bfb42bSAlexandre Chartre 238*49bfb42bSAlexandre Chartre reply_dlen = 0; 239*49bfb42bSAlexandre Chartre reply = ldma_alloc_result_msg(request, reply_dlen); 240*49bfb42bSAlexandre Chartre if (reply == NULL) { 241*49bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 242*49bfb42bSAlexandre Chartre goto done; 243*49bfb42bSAlexandre Chartre } 244*49bfb42bSAlexandre Chartre 245*49bfb42bSAlexandre Chartre reply->msg_info = 0x0; 246*49bfb42bSAlexandre Chartre 247*49bfb42bSAlexandre Chartre if (dladm_open(&dlhandle) != DLADM_STATUS_OK) { 248*49bfb42bSAlexandre Chartre status = LDMA_REQ_FAILED; 249*49bfb42bSAlexandre Chartre goto done; 250*49bfb42bSAlexandre Chartre } 251*49bfb42bSAlexandre Chartre 252*49bfb42bSAlexandre Chartre if (dladm_name2info(dlhandle, nic, &linkid, &flag, &class, 253*49bfb42bSAlexandre Chartre &media) != DLADM_STATUS_OK) { 254*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): name2info failed", nic); 255*49bfb42bSAlexandre Chartre } else { 256*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): media=0x%x", nic, media); 257*49bfb42bSAlexandre Chartre reply->msg_info = LDMA_DEVNIC_EXIST; 258*49bfb42bSAlexandre Chartre } 259*49bfb42bSAlexandre Chartre 260*49bfb42bSAlexandre Chartre dladm_close(dlhandle); 261*49bfb42bSAlexandre Chartre 262*49bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 263*49bfb42bSAlexandre Chartre 264*49bfb42bSAlexandre Chartre done: 265*49bfb42bSAlexandre Chartre if (status != LDMA_REQ_COMPLETED) { 266*49bfb42bSAlexandre Chartre /* 267*49bfb42bSAlexandre Chartre * We don't provide a reply message if the request has not 268*49bfb42bSAlexandre Chartre * been completed. The LDoms agent daemon will send an 269*49bfb42bSAlexandre Chartre * appropriate reply based on the return code of this function. 270*49bfb42bSAlexandre Chartre */ 271*49bfb42bSAlexandre Chartre free(reply); 272*49bfb42bSAlexandre Chartre reply = NULL; 273*49bfb42bSAlexandre Chartre reply_dlen = 0; 274*49bfb42bSAlexandre Chartre 275*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): return error %d", 276*49bfb42bSAlexandre Chartre (nic)? nic : "<none>", status); 277*49bfb42bSAlexandre Chartre } else { 278*49bfb42bSAlexandre Chartre LDMA_DBG("VALIDATE_NIC(%s): return status=0x%x", 279*49bfb42bSAlexandre Chartre nic, reply->msg_info); 280*49bfb42bSAlexandre Chartre } 281*49bfb42bSAlexandre Chartre 282*49bfb42bSAlexandre Chartre free(nic); 283*49bfb42bSAlexandre Chartre *replyp = reply; 284*49bfb42bSAlexandre Chartre *reply_dlenp = reply_dlen; 285*49bfb42bSAlexandre Chartre 286*49bfb42bSAlexandre Chartre return (status); 287*49bfb42bSAlexandre Chartre } 288