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*b63861bbSAlexandre Chartre * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2449bfb42bSAlexandre Chartre */ 2549bfb42bSAlexandre Chartre 2649bfb42bSAlexandre Chartre /* 2749bfb42bSAlexandre Chartre * Logical Domains (LDoms) Agents Daemon 2849bfb42bSAlexandre Chartre * 2949bfb42bSAlexandre Chartre * The LDoms agents daemon (ldmad) runs on LDoms domains and provides 3049bfb42bSAlexandre Chartre * information to the control domain. It is composed of a set of agents 3149bfb42bSAlexandre Chartre * which can send and receive messages to and from the control domain. 3249bfb42bSAlexandre Chartre * Each agent is registered as a domain service using the libds library, 3349bfb42bSAlexandre Chartre * and is able to handle requests coming from the control domain. 3449bfb42bSAlexandre Chartre * 3549bfb42bSAlexandre Chartre * The control domain sends requests to an agent as messages on the 3649bfb42bSAlexandre Chartre * corresponding domain service (identified by the agent name). All requests 3749bfb42bSAlexandre Chartre * are received by the ldmad daemon which dispatches them to the appropriate 3849bfb42bSAlexandre Chartre * handler function of the agent depending on the type of the message. 3949bfb42bSAlexandre Chartre * 4049bfb42bSAlexandre Chartre * After the request has been processed by the handler, the ldmad daemon sent 4149bfb42bSAlexandre Chartre * a reply message back to the control domain. The reply is either a result 4249bfb42bSAlexandre Chartre * message if the request was successfully completed, or an error message 4349bfb42bSAlexandre Chartre * describing the failure. 4449bfb42bSAlexandre Chartre */ 4549bfb42bSAlexandre Chartre 4649bfb42bSAlexandre Chartre #include <dirent.h> 4749bfb42bSAlexandre Chartre #include <errno.h> 4849bfb42bSAlexandre Chartre #include <fcntl.h> 4949bfb42bSAlexandre Chartre #include <libds.h> 5049bfb42bSAlexandre Chartre #include <libgen.h> 5149bfb42bSAlexandre Chartre #include <signal.h> 5249bfb42bSAlexandre Chartre #include <stdio.h> 5349bfb42bSAlexandre Chartre #include <stdlib.h> 5449bfb42bSAlexandre Chartre #include <strings.h> 5582629e30SMike Christensen #include <synch.h> 5649bfb42bSAlexandre Chartre #include <syslog.h> 5782629e30SMike Christensen #include <thread.h> 5849bfb42bSAlexandre Chartre #include <unistd.h> 5982629e30SMike Christensen #include <sys/debug.h> 6082629e30SMike Christensen #include <sys/ldoms.h> 6149bfb42bSAlexandre Chartre #include <sys/types.h> 6249bfb42bSAlexandre Chartre #include <sys/stat.h> 6349bfb42bSAlexandre Chartre #include <sys/wait.h> 6449bfb42bSAlexandre Chartre 6549bfb42bSAlexandre Chartre #include "ldma.h" 6649bfb42bSAlexandre Chartre 6749bfb42bSAlexandre Chartre #define LDMA_MODULE "ldm-agent-daemon" 6849bfb42bSAlexandre Chartre 6949bfb42bSAlexandre Chartre #define LDMA_CONTROL_DOMAIN_DHDL 0 /* id of the control domain */ 7082629e30SMike Christensen 7182629e30SMike Christensen typedef struct ldma_connexion_t { 7282629e30SMike Christensen ds_hdl_t hdl; /* connexion handle */ 7382629e30SMike Christensen ds_domain_hdl_t dhdl; /* connexion domain handle */ 7482629e30SMike Christensen ds_ver_t ver; /* connexion version */ 7582629e30SMike Christensen } ldma_connexion_t; 7649bfb42bSAlexandre Chartre 7749bfb42bSAlexandre Chartre typedef struct ldma_agent { 7849bfb42bSAlexandre Chartre ldma_agent_info_t *info; /* agent information */ 7982629e30SMike Christensen mutex_t conn_lock; /* connexion table lock */ 8082629e30SMike Christensen ldma_connexion_t conn[LDOMS_MAX_DOMAINS]; /* connexions */ 8149bfb42bSAlexandre Chartre } ldma_agent_t; 8249bfb42bSAlexandre Chartre 8349bfb42bSAlexandre Chartre /* information about existing agents */ 8449bfb42bSAlexandre Chartre extern ldma_agent_info_t ldma_device_info; 8549bfb42bSAlexandre Chartre extern ldma_agent_info_t ldma_system_info; 86fc256490SJason Beloro extern ldma_agent_info_t ldma_dio_info; 8749bfb42bSAlexandre Chartre 8849bfb42bSAlexandre Chartre boolean_t ldma_debug = B_FALSE; 8949bfb42bSAlexandre Chartre boolean_t ldma_daemon = B_FALSE; 9049bfb42bSAlexandre Chartre 9149bfb42bSAlexandre Chartre static ldma_agent_info_t *ldma_agent_infos[] = { 9249bfb42bSAlexandre Chartre &ldma_device_info, 9349bfb42bSAlexandre Chartre &ldma_system_info, 94fc256490SJason Beloro &ldma_dio_info, 9549bfb42bSAlexandre Chartre NULL 9649bfb42bSAlexandre Chartre }; 9749bfb42bSAlexandre Chartre 9849bfb42bSAlexandre Chartre static char *cmdname; 996b8303caSAlexandre Chartre static pid_t daemon_pid = 0; 10049bfb42bSAlexandre Chartre 10149bfb42bSAlexandre Chartre /* 10282629e30SMike Christensen * Lookup connexion in agent connexion table. 10382629e30SMike Christensen */ 10482629e30SMike Christensen static ldma_connexion_t * 10582629e30SMike Christensen ldma_connexion_lookup(ldma_agent_t *agent, ds_hdl_t hdl) 10682629e30SMike Christensen { 10782629e30SMike Christensen ldma_connexion_t *connp; 10882629e30SMike Christensen int i; 10982629e30SMike Christensen 11082629e30SMike Christensen ASSERT(MUTEX_HELD(&agent->conn_lock)); 11182629e30SMike Christensen for (connp = agent->conn, i = 0; i < LDOMS_MAX_DOMAINS; i++, connp++) { 11282629e30SMike Christensen if (connp->hdl == hdl) 11382629e30SMike Christensen return (connp); 11482629e30SMike Christensen } 11582629e30SMike Christensen return (NULL); 11682629e30SMike Christensen } 11782629e30SMike Christensen 11882629e30SMike Christensen /* 11982629e30SMike Christensen * Add connextion to agent connexion table. 12082629e30SMike Christensen */ 12182629e30SMike Christensen static int 12282629e30SMike Christensen ldma_connexion_add(ldma_agent_t *agent, ds_hdl_t hdl, ds_domain_hdl_t dhdl, 12382629e30SMike Christensen ds_ver_t *verp) 12482629e30SMike Christensen { 12582629e30SMike Christensen ldma_connexion_t *connp; 12682629e30SMike Christensen ldma_connexion_t *availp = NULL; 12782629e30SMike Christensen int i; 12882629e30SMike Christensen 12982629e30SMike Christensen (void) mutex_lock(&agent->conn_lock); 13082629e30SMike Christensen for (connp = agent->conn, i = 0; i < LDOMS_MAX_DOMAINS; i++, connp++) { 13182629e30SMike Christensen if (connp->hdl == hdl) 13282629e30SMike Christensen break; 13382629e30SMike Christensen if (availp == NULL && connp->hdl == DS_INVALID_HDL) 13482629e30SMike Christensen availp = connp; 13582629e30SMike Christensen } 13682629e30SMike Christensen 13782629e30SMike Christensen if (i < LDOMS_MAX_DOMAINS) { 13882629e30SMike Christensen (void) mutex_unlock(&agent->conn_lock); 13982629e30SMike Christensen LDMA_INFO("agent %s hdl %llx already exists", agent->info->name, 14082629e30SMike Christensen hdl); 14182629e30SMike Christensen return (0); 14282629e30SMike Christensen } 14382629e30SMike Christensen 14482629e30SMike Christensen if (!availp) { 14582629e30SMike Christensen (void) mutex_unlock(&agent->conn_lock); 14682629e30SMike Christensen LDMA_INFO("agent %s too many connections", agent->info->name); 14782629e30SMike Christensen return (0); 14882629e30SMike Christensen } 14982629e30SMike Christensen 15082629e30SMike Christensen LDMA_DBG("agent %s adding connection (%x) %llx, %llx, %d.%d", 15182629e30SMike Christensen agent->info->name, availp, hdl, dhdl, verp->major, verp->minor); 15282629e30SMike Christensen 15382629e30SMike Christensen availp->hdl = hdl; 15482629e30SMike Christensen availp->dhdl = dhdl; 15582629e30SMike Christensen availp->ver = *verp; 15682629e30SMike Christensen (void) mutex_unlock(&agent->conn_lock); 15782629e30SMike Christensen return (1); 15882629e30SMike Christensen } 15982629e30SMike Christensen 16082629e30SMike Christensen /* 16182629e30SMike Christensen * Delete connexion from agent connexion table. 16282629e30SMike Christensen */ 16382629e30SMike Christensen static int 16482629e30SMike Christensen ldma_connexion_delete(ldma_agent_t *agent, ds_hdl_t hdl) 16582629e30SMike Christensen { 16682629e30SMike Christensen ldma_connexion_t *connp; 16782629e30SMike Christensen 16882629e30SMike Christensen (void) mutex_lock(&agent->conn_lock); 16982629e30SMike Christensen if ((connp = ldma_connexion_lookup(agent, hdl)) == NULL) { 17082629e30SMike Christensen (void) mutex_unlock(&agent->conn_lock); 17182629e30SMike Christensen LDMA_INFO("agent %s connection delete failed to find %llx", 17282629e30SMike Christensen agent->info->name, hdl); 17382629e30SMike Christensen return (0); 17482629e30SMike Christensen } 17582629e30SMike Christensen 17682629e30SMike Christensen LDMA_DBG("agent %s deleting connection (%x) %llx", agent->info->name, 17782629e30SMike Christensen connp, hdl); 17882629e30SMike Christensen 17982629e30SMike Christensen connp->hdl = DS_INVALID_HDL; 18082629e30SMike Christensen connp->dhdl = 0; 18182629e30SMike Christensen connp->ver.major = 0; 18282629e30SMike Christensen connp->ver.minor = 0; 18382629e30SMike Christensen (void) mutex_unlock(&agent->conn_lock); 18482629e30SMike Christensen return (1); 18582629e30SMike Christensen } 18682629e30SMike Christensen 18782629e30SMike Christensen /* 18882629e30SMike Christensen * Initialize connexion table. 18982629e30SMike Christensen */ 19082629e30SMike Christensen static void 19182629e30SMike Christensen ldma_connexion_init(ldma_agent_t *agent) 19282629e30SMike Christensen { 19382629e30SMike Christensen ldma_connexion_t *connp; 19482629e30SMike Christensen int i; 19582629e30SMike Christensen 19682629e30SMike Christensen for (connp = agent->conn, i = 0; i < LDOMS_MAX_DOMAINS; i++, connp++) { 19782629e30SMike Christensen connp->hdl = DS_INVALID_HDL; 19882629e30SMike Christensen } 19982629e30SMike Christensen } 20082629e30SMike Christensen 20182629e30SMike Christensen /* 20249bfb42bSAlexandre Chartre * Allocate a new message with the specified message number (msg_num), 20349bfb42bSAlexandre Chartre * message type (msg_type) and message data length (msg_dlen). Return 20449bfb42bSAlexandre Chartre * NULL if the allocation has failed. 20549bfb42bSAlexandre Chartre */ 20649bfb42bSAlexandre Chartre static ldma_message_header_t * 20749bfb42bSAlexandre Chartre ldma_alloc_msg(uint64_t msg_num, uint32_t msg_type, size_t msg_dlen) 20849bfb42bSAlexandre Chartre { 20949bfb42bSAlexandre Chartre ldma_message_header_t *msg; 21049bfb42bSAlexandre Chartre size_t msg_len; 21149bfb42bSAlexandre Chartre 21249bfb42bSAlexandre Chartre msg_len = LDMA_MESSAGE_SIZE(msg_dlen); 21349bfb42bSAlexandre Chartre msg = malloc(msg_len); 21449bfb42bSAlexandre Chartre if (msg == NULL) 21549bfb42bSAlexandre Chartre return (NULL); 21649bfb42bSAlexandre Chartre 21749bfb42bSAlexandre Chartre msg->msg_num = msg_num; 21849bfb42bSAlexandre Chartre msg->msg_type = msg_type; 21949bfb42bSAlexandre Chartre msg->msg_info = 0; 22049bfb42bSAlexandre Chartre 22149bfb42bSAlexandre Chartre return (msg); 22249bfb42bSAlexandre Chartre } 22349bfb42bSAlexandre Chartre 22449bfb42bSAlexandre Chartre /* 22549bfb42bSAlexandre Chartre * Allocate a result message (LDMA_MSG_REQ_RESULT) with the specified message 22649bfb42bSAlexandre Chartre * data length (msg_dlen). If the request argument is not NULL then the message 22749bfb42bSAlexandre Chartre * is created with the same message number as the request, otherwise the message 22849bfb42bSAlexandre Chartre * number is set to 0. Return NULL if the allocation has failed. 22949bfb42bSAlexandre Chartre */ 23049bfb42bSAlexandre Chartre ldma_message_header_t * 23149bfb42bSAlexandre Chartre ldma_alloc_result_msg(ldma_message_header_t *request, size_t msg_dlen) 23249bfb42bSAlexandre Chartre { 23349bfb42bSAlexandre Chartre uint64_t msg_num; 23449bfb42bSAlexandre Chartre 23549bfb42bSAlexandre Chartre msg_num = (request == NULL)? 0 : request->msg_num; 23649bfb42bSAlexandre Chartre 23749bfb42bSAlexandre Chartre return (ldma_alloc_msg(msg_num, LDMA_MSG_RESULT, msg_dlen)); 23849bfb42bSAlexandre Chartre } 23949bfb42bSAlexandre Chartre 24049bfb42bSAlexandre Chartre /* 24149bfb42bSAlexandre Chartre * Agent register callback. This callback is invoked when a client is registered 24249bfb42bSAlexandre Chartre * for using the service provided by an agent. An agent will only have one 24349bfb42bSAlexandre Chartre * consumer which is coming from the control domain. 24449bfb42bSAlexandre Chartre */ 24549bfb42bSAlexandre Chartre static void 24649bfb42bSAlexandre Chartre ldma_reg_cb(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver, 24749bfb42bSAlexandre Chartre ds_domain_hdl_t dhdl) 24849bfb42bSAlexandre Chartre { 24949bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 25082629e30SMike Christensen char dname[LDOMS_MAX_NAME_LEN]; 25149bfb42bSAlexandre Chartre 25282629e30SMike Christensen if (ds_dom_hdl_to_name(dhdl, dname, LDOMS_MAX_NAME_LEN) != 0) { 25349bfb42bSAlexandre Chartre (void) strcpy(dname, "<unknown>"); 25449bfb42bSAlexandre Chartre } 25549bfb42bSAlexandre Chartre 25649bfb42bSAlexandre Chartre LDMA_DBG("%s: REGISTER hdl=%llx, dhdl=%llx (%s) ver=%hd.%hd", 25749bfb42bSAlexandre Chartre agent->info->name, hdl, dhdl, dname, ver->major, ver->minor); 25849bfb42bSAlexandre Chartre 25949bfb42bSAlexandre Chartre /* 26082629e30SMike Christensen * Record client information. Access control is done on a 26182629e30SMike Christensen * message-by-message basis upon receipt of the message. 26249bfb42bSAlexandre Chartre */ 26382629e30SMike Christensen if (!ldma_connexion_add(agent, hdl, dhdl, ver)) { 26482629e30SMike Christensen LDMA_INFO("agent %s failed to add connection from " 26549bfb42bSAlexandre Chartre "domain %s", agent->info->name, dname); 26649bfb42bSAlexandre Chartre } 26749bfb42bSAlexandre Chartre } 26849bfb42bSAlexandre Chartre 26949bfb42bSAlexandre Chartre /* 27049bfb42bSAlexandre Chartre * Agent unregister callback. This callback is invoked when a client is 27149bfb42bSAlexandre Chartre * unregistered and stops using the service provided by an agent. 27249bfb42bSAlexandre Chartre */ 27349bfb42bSAlexandre Chartre static void 27449bfb42bSAlexandre Chartre ldma_unreg_cb(ds_hdl_t hdl, ds_cb_arg_t arg) 27549bfb42bSAlexandre Chartre { 27649bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 27749bfb42bSAlexandre Chartre 27849bfb42bSAlexandre Chartre LDMA_DBG("%s: UNREGISTER hdl=%llx", agent->info->name, hdl); 27949bfb42bSAlexandre Chartre 28082629e30SMike Christensen if (!ldma_connexion_delete(agent, hdl)) { 28182629e30SMike Christensen LDMA_INFO("agent %s failed to unregister handle %llx", 28282629e30SMike Christensen agent->info->name, hdl); 28349bfb42bSAlexandre Chartre } 28449bfb42bSAlexandre Chartre } 28549bfb42bSAlexandre Chartre 28649bfb42bSAlexandre Chartre /* 28749bfb42bSAlexandre Chartre * Agent data callback. This callback is invoked when an agent receives a new 28849bfb42bSAlexandre Chartre * message from a client. Any request from a client which is not the control 28949bfb42bSAlexandre Chartre * domain is immediatly rejected. Otherwise the message is forwarded to the 29049bfb42bSAlexandre Chartre * appropriate handler function provided by the agent, depending on the message 29149bfb42bSAlexandre Chartre * type. 29249bfb42bSAlexandre Chartre */ 29349bfb42bSAlexandre Chartre static void 29449bfb42bSAlexandre Chartre ldma_data_cb(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, size_t len) 29549bfb42bSAlexandre Chartre { 29649bfb42bSAlexandre Chartre ldma_agent_t *agent = (ldma_agent_t *)arg; 29749bfb42bSAlexandre Chartre ldma_msg_handler_t *handler; 29849bfb42bSAlexandre Chartre ldma_message_header_t *request = buf; 29949bfb42bSAlexandre Chartre ldma_message_header_t *reply = NULL; 30082629e30SMike Christensen ldma_connexion_t *connp; 30182629e30SMike Christensen ds_ver_t conn_ver; 30282629e30SMike Christensen ds_domain_hdl_t conn_dhdl; 30349bfb42bSAlexandre Chartre ldma_request_status_t status; 30449bfb42bSAlexandre Chartre size_t request_dlen, reply_len, reply_dlen = 0; 30549bfb42bSAlexandre Chartre int i; 30649bfb42bSAlexandre Chartre 30749bfb42bSAlexandre Chartre /* check the message size */ 30849bfb42bSAlexandre Chartre if (len < LDMA_MESSAGE_HEADER_SIZE) { 30949bfb42bSAlexandre Chartre LDMA_INFO("agent %s has ignored message with an invalid " 31049bfb42bSAlexandre Chartre "size of %d bytes", agent->info->name, len); 31149bfb42bSAlexandre Chartre return; 31249bfb42bSAlexandre Chartre } 31349bfb42bSAlexandre Chartre 31449bfb42bSAlexandre Chartre request_dlen = LDMA_MESSAGE_DLEN(len); 31549bfb42bSAlexandre Chartre 31649bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, request num=%llu type=0x%x info=0x%x " 31749bfb42bSAlexandre Chartre "dlen=%d", agent->info->name, hdl, request->msg_num, 31849bfb42bSAlexandre Chartre request->msg_type, request->msg_info, request_dlen); 31949bfb42bSAlexandre Chartre 32082629e30SMike Christensen (void) mutex_lock(&agent->conn_lock); 32182629e30SMike Christensen connp = ldma_connexion_lookup(agent, hdl); 32282629e30SMike Christensen if (connp != NULL) { 32382629e30SMike Christensen conn_dhdl = connp->dhdl; 32482629e30SMike Christensen conn_ver = connp->ver; 32582629e30SMike Christensen } 32682629e30SMike Christensen (void) mutex_unlock(&agent->conn_lock); 32782629e30SMike Christensen 32882629e30SMike Christensen /* reject any request which is not in the connexion table */ 32982629e30SMike Christensen if (connp == NULL) { 33049bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a " 33149bfb42bSAlexandre Chartre "distrusted domain", agent->info->name, hdl); 33249bfb42bSAlexandre Chartre status = LDMA_REQ_DENIED; 33349bfb42bSAlexandre Chartre goto do_reply; 33449bfb42bSAlexandre Chartre } 33549bfb42bSAlexandre Chartre 33649bfb42bSAlexandre Chartre handler = NULL; 33749bfb42bSAlexandre Chartre 33849bfb42bSAlexandre Chartre for (i = 0; i < agent->info->nhandlers; i++) { 33949bfb42bSAlexandre Chartre if (agent->info->handlers[i].msg_type == request->msg_type) { 34049bfb42bSAlexandre Chartre handler = &agent->info->handlers[i]; 34149bfb42bSAlexandre Chartre break; 34249bfb42bSAlexandre Chartre } 34349bfb42bSAlexandre Chartre } 34449bfb42bSAlexandre Chartre 34549bfb42bSAlexandre Chartre if (handler == NULL) { 34649bfb42bSAlexandre Chartre /* this type of message is not defined by the agent */ 34749bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, unknown message type %x", 34849bfb42bSAlexandre Chartre agent->info->name, hdl, request->msg_type); 34949bfb42bSAlexandre Chartre status = LDMA_REQ_NOTSUP; 35049bfb42bSAlexandre Chartre goto do_reply; 35149bfb42bSAlexandre Chartre } 35249bfb42bSAlexandre Chartre 35382629e30SMike Christensen /* reject any request from a guest which is not allowed */ 35482629e30SMike Christensen if ((conn_dhdl != LDMA_CONTROL_DOMAIN_DHDL) && 35582629e30SMike Christensen (handler->msg_flags & LDMA_MSGFLG_ACCESS_ANY) == 0) { 35682629e30SMike Christensen LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a " 35782629e30SMike Christensen "distrusted domain", agent->info->name, hdl); 35882629e30SMike Christensen status = LDMA_REQ_DENIED; 35982629e30SMike Christensen goto do_reply; 36082629e30SMike Christensen } 36182629e30SMike Christensen 36249bfb42bSAlexandre Chartre if (handler->msg_handler == NULL) { 36349bfb42bSAlexandre Chartre /* 36449bfb42bSAlexandre Chartre * This type of message is defined by the agent but it 36549bfb42bSAlexandre Chartre * has no handler. That means there is no processing to 36649bfb42bSAlexandre Chartre * do, the message is just ignored, but the request is 36749bfb42bSAlexandre Chartre * successfully completed. 36849bfb42bSAlexandre Chartre */ 36949bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, no handler", 37049bfb42bSAlexandre Chartre agent->info->name, hdl); 37149bfb42bSAlexandre Chartre status = LDMA_REQ_COMPLETED; 37249bfb42bSAlexandre Chartre goto do_reply; 37349bfb42bSAlexandre Chartre } 37449bfb42bSAlexandre Chartre 37549bfb42bSAlexandre Chartre /* invoke the message handler of the agent */ 37682629e30SMike Christensen status = (*handler->msg_handler)(&conn_ver, request, request_dlen, 37782629e30SMike Christensen &reply, &reply_dlen); 37849bfb42bSAlexandre Chartre 37949bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, handler stat=%d reply=%p rlen=%d", 38049bfb42bSAlexandre Chartre agent->info->name, hdl, status, (void *)reply, reply_dlen); 38149bfb42bSAlexandre Chartre 38249bfb42bSAlexandre Chartre do_reply: 38349bfb42bSAlexandre Chartre /* 38449bfb42bSAlexandre Chartre * If the handler has provided a reply message, we use it directly. 38549bfb42bSAlexandre Chartre * Otherwise, we build a reply depending on the status of the request. 38649bfb42bSAlexandre Chartre * In that case, we re-use the request buffer to build the reply 38749bfb42bSAlexandre Chartre * message. 38849bfb42bSAlexandre Chartre */ 38949bfb42bSAlexandre Chartre if (reply == NULL) { 39049bfb42bSAlexandre Chartre 39149bfb42bSAlexandre Chartre reply = request; 39249bfb42bSAlexandre Chartre reply_dlen = 0; 39349bfb42bSAlexandre Chartre 39449bfb42bSAlexandre Chartre if (status == LDMA_REQ_COMPLETED) { 39549bfb42bSAlexandre Chartre /* 39649bfb42bSAlexandre Chartre * The request was successful but no result message was 39749bfb42bSAlexandre Chartre * provided so we send an empty result message. 39849bfb42bSAlexandre Chartre */ 39949bfb42bSAlexandre Chartre reply->msg_type = LDMA_MSG_RESULT; 40049bfb42bSAlexandre Chartre reply->msg_info = 0; 40149bfb42bSAlexandre Chartre 40249bfb42bSAlexandre Chartre } else { 40349bfb42bSAlexandre Chartre /* 40449bfb42bSAlexandre Chartre * The request has failed but no error message was 40549bfb42bSAlexandre Chartre * provided so we send an error message based on the 40649bfb42bSAlexandre Chartre * request status. 40749bfb42bSAlexandre Chartre */ 40849bfb42bSAlexandre Chartre reply->msg_type = LDMA_MSG_ERROR; 40949bfb42bSAlexandre Chartre reply->msg_info = 41049bfb42bSAlexandre Chartre (status == LDMA_REQ_NOTSUP)? LDMA_MSGERR_NOTSUP : 41149bfb42bSAlexandre Chartre (status == LDMA_REQ_INVALID)? LDMA_MSGERR_INVALID : 41249bfb42bSAlexandre Chartre (status == LDMA_REQ_DENIED)? LDMA_MSGERR_DENY : 41349bfb42bSAlexandre Chartre LDMA_MSGERR_FAIL; 41449bfb42bSAlexandre Chartre } 41549bfb42bSAlexandre Chartre } 41649bfb42bSAlexandre Chartre 41749bfb42bSAlexandre Chartre reply_len = LDMA_MESSAGE_SIZE(reply_dlen); 41849bfb42bSAlexandre Chartre 41949bfb42bSAlexandre Chartre LDMA_DBG("%s: DATA hdl=%llx, reply num=%llu type=0x%x info=0x%x " 42049bfb42bSAlexandre Chartre "dlen=%d", agent->info->name, hdl, reply->msg_num, 42149bfb42bSAlexandre Chartre reply->msg_type, reply->msg_info, reply_dlen); 42249bfb42bSAlexandre Chartre 42349bfb42bSAlexandre Chartre if (ds_send_msg(hdl, reply, reply_len) != 0) { 42449bfb42bSAlexandre Chartre LDMA_ERR("agent %s has failed to send reply for request %llu", 42549bfb42bSAlexandre Chartre agent->info->name, request->msg_num); 42649bfb42bSAlexandre Chartre } 42749bfb42bSAlexandre Chartre 42849bfb42bSAlexandre Chartre if (reply != request) 42949bfb42bSAlexandre Chartre free(reply); 43049bfb42bSAlexandre Chartre } 43149bfb42bSAlexandre Chartre 43249bfb42bSAlexandre Chartre /* 43349bfb42bSAlexandre Chartre * Register an agent. Return 0 if the agent was successfully registered. 43449bfb42bSAlexandre Chartre */ 43549bfb42bSAlexandre Chartre static int 43649bfb42bSAlexandre Chartre ldma_register(ldma_agent_info_t *agent_info) 43749bfb42bSAlexandre Chartre { 43849bfb42bSAlexandre Chartre ldma_agent_t *agent; 43949bfb42bSAlexandre Chartre ds_capability_t ds_cap; 44049bfb42bSAlexandre Chartre ds_ops_t ds_ops; 44149bfb42bSAlexandre Chartre 44249bfb42bSAlexandre Chartre agent = malloc(sizeof (ldma_agent_t)); 44349bfb42bSAlexandre Chartre if (agent == NULL) 44449bfb42bSAlexandre Chartre goto register_fail; 44549bfb42bSAlexandre Chartre 44649bfb42bSAlexandre Chartre agent->info = agent_info; 44782629e30SMike Christensen (void) mutex_init(&agent->conn_lock, USYNC_THREAD, NULL); 44882629e30SMike Christensen ldma_connexion_init(agent); 44949bfb42bSAlexandre Chartre 45049bfb42bSAlexandre Chartre ds_cap.svc_id = agent_info->name; 45149bfb42bSAlexandre Chartre ds_cap.vers = agent_info->vers; 45249bfb42bSAlexandre Chartre ds_cap.nvers = agent_info->nvers; 45349bfb42bSAlexandre Chartre 45449bfb42bSAlexandre Chartre ds_ops.ds_reg_cb = ldma_reg_cb; 45549bfb42bSAlexandre Chartre ds_ops.ds_unreg_cb = ldma_unreg_cb; 45649bfb42bSAlexandre Chartre ds_ops.ds_data_cb = ldma_data_cb; 45749bfb42bSAlexandre Chartre ds_ops.cb_arg = agent; 45849bfb42bSAlexandre Chartre 45949bfb42bSAlexandre Chartre if (ds_svc_reg(&ds_cap, &ds_ops) == 0) { 46049bfb42bSAlexandre Chartre LDMA_INFO("agent %s registered", agent_info->name); 46149bfb42bSAlexandre Chartre return (0); 46249bfb42bSAlexandre Chartre } 46349bfb42bSAlexandre Chartre 46449bfb42bSAlexandre Chartre register_fail: 46549bfb42bSAlexandre Chartre 46649bfb42bSAlexandre Chartre LDMA_ERR("agent %s has failed to register", agent_info->name); 46749bfb42bSAlexandre Chartre free(agent); 46849bfb42bSAlexandre Chartre return (-1); 46949bfb42bSAlexandre Chartre } 47049bfb42bSAlexandre Chartre 47149bfb42bSAlexandre Chartre /* 47249bfb42bSAlexandre Chartre * Register all known agents. Return the number of agents successfully 47349bfb42bSAlexandre Chartre * registered. 47449bfb42bSAlexandre Chartre */ 47549bfb42bSAlexandre Chartre static int 47649bfb42bSAlexandre Chartre ldma_register_agents() 47749bfb42bSAlexandre Chartre { 47849bfb42bSAlexandre Chartre int count = 0; 47949bfb42bSAlexandre Chartre ldma_agent_info_t **agent_infop; 48049bfb42bSAlexandre Chartre 48149bfb42bSAlexandre Chartre for (agent_infop = ldma_agent_infos; 48249bfb42bSAlexandre Chartre *agent_infop != NULL; agent_infop++) { 48349bfb42bSAlexandre Chartre 48449bfb42bSAlexandre Chartre if (ldma_register(*agent_infop) == 0) 48549bfb42bSAlexandre Chartre count++; 48649bfb42bSAlexandre Chartre } 48749bfb42bSAlexandre Chartre 48849bfb42bSAlexandre Chartre return (count); 48949bfb42bSAlexandre Chartre } 49049bfb42bSAlexandre Chartre 49149bfb42bSAlexandre Chartre /*ARGSUSED*/ 49249bfb42bSAlexandre Chartre static void 49349bfb42bSAlexandre Chartre ldma_sigusr_handler(int sig, siginfo_t *sinfo, void *ucontext) 49449bfb42bSAlexandre Chartre { 4956b8303caSAlexandre Chartre /* 4966b8303caSAlexandre Chartre * The child process can send the signal before the fork() 4976b8303caSAlexandre Chartre * call has returned in the parent process. So daemon_pid 4986b8303caSAlexandre Chartre * may not be set yet, and we don't check the pid in that 4996b8303caSAlexandre Chartre * case. 5006b8303caSAlexandre Chartre */ 5016b8303caSAlexandre Chartre if (sig != SIGUSR1 || sinfo->si_code != SI_USER || 5026b8303caSAlexandre Chartre (daemon_pid > 0 && sinfo->si_pid != daemon_pid)) 50349bfb42bSAlexandre Chartre return; 50449bfb42bSAlexandre Chartre 50549bfb42bSAlexandre Chartre /* 50649bfb42bSAlexandre Chartre * The parent process has received a USR1 signal from the child. 50749bfb42bSAlexandre Chartre * This means that the daemon has correctly started and the parent 50849bfb42bSAlexandre Chartre * can exit. 50949bfb42bSAlexandre Chartre */ 51049bfb42bSAlexandre Chartre exit(0); 51149bfb42bSAlexandre Chartre } 51249bfb42bSAlexandre Chartre 51349bfb42bSAlexandre Chartre static void 51449bfb42bSAlexandre Chartre ldma_start(boolean_t standalone) 51549bfb42bSAlexandre Chartre { 51649bfb42bSAlexandre Chartre int stat, rv; 51749bfb42bSAlexandre Chartre struct sigaction action; 51849bfb42bSAlexandre Chartre 51949bfb42bSAlexandre Chartre if (!standalone) { 52049bfb42bSAlexandre Chartre /* 52149bfb42bSAlexandre Chartre * Some configuration of the daemon has to be done in the 52249bfb42bSAlexandre Chartre * child, but we want the parent to report if the daemon 52349bfb42bSAlexandre Chartre * has successfully started or not. So we setup a signal 52449bfb42bSAlexandre Chartre * handler, and the child will notify the parent using the 52549bfb42bSAlexandre Chartre * USR1 signal if the setup was successful. Otherwise the 52649bfb42bSAlexandre Chartre * child will exit. 52749bfb42bSAlexandre Chartre */ 52849bfb42bSAlexandre Chartre action.sa_sigaction = ldma_sigusr_handler; 52949bfb42bSAlexandre Chartre action.sa_flags = SA_SIGINFO; 53049bfb42bSAlexandre Chartre 53149bfb42bSAlexandre Chartre if (sigemptyset(&action.sa_mask) == -1) { 53249bfb42bSAlexandre Chartre LDMA_ERR("sigemptyset error (%d)", errno); 53349bfb42bSAlexandre Chartre exit(1); 53449bfb42bSAlexandre Chartre } 53549bfb42bSAlexandre Chartre 53649bfb42bSAlexandre Chartre if (sigaction(SIGUSR1, &action, NULL) == -1) { 53749bfb42bSAlexandre Chartre LDMA_ERR("sigaction() error (%d)", errno); 53849bfb42bSAlexandre Chartre exit(1); 53949bfb42bSAlexandre Chartre } 54049bfb42bSAlexandre Chartre 54149bfb42bSAlexandre Chartre if (sigrelse(SIGUSR1) == -1) { 54249bfb42bSAlexandre Chartre LDMA_ERR("sigrelse() error (%d)", errno); 54349bfb42bSAlexandre Chartre exit(1); 54449bfb42bSAlexandre Chartre } 54549bfb42bSAlexandre Chartre 54649bfb42bSAlexandre Chartre if ((daemon_pid = fork()) == -1) { 54749bfb42bSAlexandre Chartre LDMA_ERR("fork() error (%d)", errno); 54849bfb42bSAlexandre Chartre exit(1); 54949bfb42bSAlexandre Chartre } 55049bfb42bSAlexandre Chartre 55149bfb42bSAlexandre Chartre if (daemon_pid != 0) { 55249bfb42bSAlexandre Chartre /* 55349bfb42bSAlexandre Chartre * The parent process waits until the child exits (in 55449bfb42bSAlexandre Chartre * case of an error) or sends a USR1 signal (if the 55549bfb42bSAlexandre Chartre * daemon has correctly started). 55649bfb42bSAlexandre Chartre */ 55749bfb42bSAlexandre Chartre for (;;) { 55849bfb42bSAlexandre Chartre rv = waitpid(daemon_pid, &stat, 0); 55949bfb42bSAlexandre Chartre if ((rv == daemon_pid && WIFEXITED(stat)) || 56049bfb42bSAlexandre Chartre (rv == -1 && errno != EINTR)) { 56149bfb42bSAlexandre Chartre /* child has exited or error */ 56249bfb42bSAlexandre Chartre exit(1); 56349bfb42bSAlexandre Chartre } 56449bfb42bSAlexandre Chartre } 56549bfb42bSAlexandre Chartre } 56649bfb42bSAlexandre Chartre 56749bfb42bSAlexandre Chartre /* 56849bfb42bSAlexandre Chartre * Initialize child process 56949bfb42bSAlexandre Chartre */ 57049bfb42bSAlexandre Chartre if (sighold(SIGUSR1) == -1) { 57149bfb42bSAlexandre Chartre LDMA_ERR("sighold error (%d)", errno); 57249bfb42bSAlexandre Chartre exit(1); 57349bfb42bSAlexandre Chartre } 57449bfb42bSAlexandre Chartre 57549bfb42bSAlexandre Chartre if (sigignore(SIGUSR1) == -1) { 57649bfb42bSAlexandre Chartre LDMA_ERR("sigignore error (%d)", errno); 57749bfb42bSAlexandre Chartre exit(1); 57849bfb42bSAlexandre Chartre } 57949bfb42bSAlexandre Chartre 58049bfb42bSAlexandre Chartre if (setsid() == -1) { 58149bfb42bSAlexandre Chartre LDMA_ERR("setsid error (%d)", errno); 58249bfb42bSAlexandre Chartre exit(1); 58349bfb42bSAlexandre Chartre } 58449bfb42bSAlexandre Chartre 58549bfb42bSAlexandre Chartre if (chdir("/") == -1) { 58649bfb42bSAlexandre Chartre LDMA_ERR("chdir error (%d)", errno); 58749bfb42bSAlexandre Chartre exit(1); 58849bfb42bSAlexandre Chartre } 58949bfb42bSAlexandre Chartre (void) umask(0); 59049bfb42bSAlexandre Chartre 59149bfb42bSAlexandre Chartre /* 59249bfb42bSAlexandre Chartre * Initialize file descriptors. Do not touch stderr 59349bfb42bSAlexandre Chartre * which is initialized by SMF to point to the daemon 59449bfb42bSAlexandre Chartre * specific log file. 59549bfb42bSAlexandre Chartre */ 59649bfb42bSAlexandre Chartre (void) close(STDIN_FILENO); 59749bfb42bSAlexandre Chartre if (open("/dev/null", O_RDWR) == -1) { 59849bfb42bSAlexandre Chartre LDMA_ERR("open /dev/null error (%d)", errno); 59949bfb42bSAlexandre Chartre exit(1); 60049bfb42bSAlexandre Chartre } 60149bfb42bSAlexandre Chartre if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) { 60249bfb42bSAlexandre Chartre LDMA_ERR("dup2 error (%d)", errno); 60349bfb42bSAlexandre Chartre exit(1); 60449bfb42bSAlexandre Chartre } 60549bfb42bSAlexandre Chartre closefrom(STDERR_FILENO + 1); 60649bfb42bSAlexandre Chartre 60749bfb42bSAlexandre Chartre /* initialize logging */ 60849bfb42bSAlexandre Chartre openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON); 60949bfb42bSAlexandre Chartre 61049bfb42bSAlexandre Chartre ldma_daemon = B_TRUE; 61149bfb42bSAlexandre Chartre } 61249bfb42bSAlexandre Chartre 61349bfb42bSAlexandre Chartre /* 61449bfb42bSAlexandre Chartre * Register the agents. It would be easier to do this before 61549bfb42bSAlexandre Chartre * daemonizing so that any start error is directly reported. But 61649bfb42bSAlexandre Chartre * this can not be done because agents are registered using libds 61749bfb42bSAlexandre Chartre * and this will subscribe the daemon to some sysevents which is 61849bfb42bSAlexandre Chartre * a process based subscription. Instead we notify the parent process 61949bfb42bSAlexandre Chartre * either by exiting, or by sending a SIGUSR1 signal. 62049bfb42bSAlexandre Chartre */ 62149bfb42bSAlexandre Chartre if (ldma_register_agents() == 0) { 62249bfb42bSAlexandre Chartre /* no agent registered */ 6236b8303caSAlexandre Chartre LDMA_ERR("Unable to register any agent"); 62449bfb42bSAlexandre Chartre exit(1); 62549bfb42bSAlexandre Chartre } 62649bfb42bSAlexandre Chartre 62749bfb42bSAlexandre Chartre if (!standalone) { 62849bfb42bSAlexandre Chartre /* signal parent that startup was successful */ 62949bfb42bSAlexandre Chartre if (kill(getppid(), SIGUSR1) == -1) 63049bfb42bSAlexandre Chartre exit(1); 63149bfb42bSAlexandre Chartre } 63249bfb42bSAlexandre Chartre } 63349bfb42bSAlexandre Chartre 63449bfb42bSAlexandre Chartre static void 63549bfb42bSAlexandre Chartre ldma_usage() 63649bfb42bSAlexandre Chartre { 63749bfb42bSAlexandre Chartre (void) fprintf(stderr, "usage: %s\n", cmdname); 63849bfb42bSAlexandre Chartre } 63949bfb42bSAlexandre Chartre 64049bfb42bSAlexandre Chartre int 64149bfb42bSAlexandre Chartre main(int argc, char *argv[]) 64249bfb42bSAlexandre Chartre { 64349bfb42bSAlexandre Chartre int opt; 64449bfb42bSAlexandre Chartre boolean_t standalone = B_FALSE; 64549bfb42bSAlexandre Chartre 64649bfb42bSAlexandre Chartre cmdname = basename(argv[0]); 64749bfb42bSAlexandre Chartre 64849bfb42bSAlexandre Chartre /* disable getopt error messages */ 64949bfb42bSAlexandre Chartre opterr = 0; 65049bfb42bSAlexandre Chartre 65149bfb42bSAlexandre Chartre while ((opt = getopt(argc, argv, "ds")) != EOF) { 65249bfb42bSAlexandre Chartre 65349bfb42bSAlexandre Chartre switch (opt) { 65449bfb42bSAlexandre Chartre case 'd': 65549bfb42bSAlexandre Chartre ldma_debug = B_TRUE; 65649bfb42bSAlexandre Chartre break; 65749bfb42bSAlexandre Chartre case 's': 65849bfb42bSAlexandre Chartre standalone = B_TRUE; 65949bfb42bSAlexandre Chartre break; 66049bfb42bSAlexandre Chartre default: 66149bfb42bSAlexandre Chartre ldma_usage(); 66249bfb42bSAlexandre Chartre exit(1); 66349bfb42bSAlexandre Chartre } 66449bfb42bSAlexandre Chartre } 66549bfb42bSAlexandre Chartre 66649bfb42bSAlexandre Chartre ldma_start(standalone); 66749bfb42bSAlexandre Chartre 66849bfb42bSAlexandre Chartre /* 66949bfb42bSAlexandre Chartre * Loop forever. Any incoming message will be received by libds and 67049bfb42bSAlexandre Chartre * forwarded to the agent data callback (ldma_data_cb()) where it 67149bfb42bSAlexandre Chartre * will be processed. 67249bfb42bSAlexandre Chartre */ 67349bfb42bSAlexandre Chartre for (;;) { 67449bfb42bSAlexandre Chartre (void) pause(); 67549bfb42bSAlexandre Chartre } 67649bfb42bSAlexandre Chartre 67749bfb42bSAlexandre Chartre /*NOTREACHED*/ 67849bfb42bSAlexandre Chartre return (0); 67949bfb42bSAlexandre Chartre } 680